xref: /OK3568_Linux_fs/kernel/drivers/tc/tc.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  *	TURBOchannel bus services.
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  *	Copyright (c) Harald Koerfgen, 1998
5*4882a593Smuzhiyun  *	Copyright (c) 2001, 2003, 2005, 2006, 2018  Maciej W. Rozycki
6*4882a593Smuzhiyun  *	Copyright (c) 2005  James Simmons
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  *	This file is subject to the terms and conditions of the GNU
9*4882a593Smuzhiyun  *	General Public License.  See the file "COPYING" in the main
10*4882a593Smuzhiyun  *	directory of this archive for more details.
11*4882a593Smuzhiyun  */
12*4882a593Smuzhiyun #include <linux/compiler.h>
13*4882a593Smuzhiyun #include <linux/dma-mapping.h>
14*4882a593Smuzhiyun #include <linux/errno.h>
15*4882a593Smuzhiyun #include <linux/init.h>
16*4882a593Smuzhiyun #include <linux/ioport.h>
17*4882a593Smuzhiyun #include <linux/kernel.h>
18*4882a593Smuzhiyun #include <linux/list.h>
19*4882a593Smuzhiyun #include <linux/module.h>
20*4882a593Smuzhiyun #include <linux/slab.h>
21*4882a593Smuzhiyun #include <linux/string.h>
22*4882a593Smuzhiyun #include <linux/tc.h>
23*4882a593Smuzhiyun #include <linux/types.h>
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun #include <asm/io.h>
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun static struct tc_bus tc_bus = {
28*4882a593Smuzhiyun 	.name = "TURBOchannel",
29*4882a593Smuzhiyun };
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun /*
32*4882a593Smuzhiyun  * Probing for TURBOchannel modules.
33*4882a593Smuzhiyun  */
tc_bus_add_devices(struct tc_bus * tbus)34*4882a593Smuzhiyun static void __init tc_bus_add_devices(struct tc_bus *tbus)
35*4882a593Smuzhiyun {
36*4882a593Smuzhiyun 	resource_size_t slotsize = tbus->info.slot_size << 20;
37*4882a593Smuzhiyun 	resource_size_t extslotsize = tbus->ext_slot_size;
38*4882a593Smuzhiyun 	resource_size_t slotaddr;
39*4882a593Smuzhiyun 	resource_size_t extslotaddr;
40*4882a593Smuzhiyun 	resource_size_t devsize;
41*4882a593Smuzhiyun 	void __iomem *module;
42*4882a593Smuzhiyun 	struct tc_dev *tdev;
43*4882a593Smuzhiyun 	int i, slot, err;
44*4882a593Smuzhiyun 	u8 pattern[4];
45*4882a593Smuzhiyun 	long offset;
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun 	for (slot = 0; slot < tbus->num_tcslots; slot++) {
48*4882a593Smuzhiyun 		slotaddr = tbus->slot_base + slot * slotsize;
49*4882a593Smuzhiyun 		extslotaddr = tbus->ext_slot_base + slot * extslotsize;
50*4882a593Smuzhiyun 		module = ioremap(slotaddr, slotsize);
51*4882a593Smuzhiyun 		BUG_ON(!module);
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun 		offset = TC_OLDCARD;
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun 		err = 0;
56*4882a593Smuzhiyun 		err |= tc_preadb(pattern + 0, module + offset + TC_PATTERN0);
57*4882a593Smuzhiyun 		err |= tc_preadb(pattern + 1, module + offset + TC_PATTERN1);
58*4882a593Smuzhiyun 		err |= tc_preadb(pattern + 2, module + offset + TC_PATTERN2);
59*4882a593Smuzhiyun 		err |= tc_preadb(pattern + 3, module + offset + TC_PATTERN3);
60*4882a593Smuzhiyun 		if (err)
61*4882a593Smuzhiyun 			goto out_err;
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun 		if (pattern[0] != 0x55 || pattern[1] != 0x00 ||
64*4882a593Smuzhiyun 		    pattern[2] != 0xaa || pattern[3] != 0xff) {
65*4882a593Smuzhiyun 			offset = TC_NEWCARD;
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun 			err = 0;
68*4882a593Smuzhiyun 			err |= tc_preadb(pattern + 0,
69*4882a593Smuzhiyun 					 module + offset + TC_PATTERN0);
70*4882a593Smuzhiyun 			err |= tc_preadb(pattern + 1,
71*4882a593Smuzhiyun 					 module + offset + TC_PATTERN1);
72*4882a593Smuzhiyun 			err |= tc_preadb(pattern + 2,
73*4882a593Smuzhiyun 					 module + offset + TC_PATTERN2);
74*4882a593Smuzhiyun 			err |= tc_preadb(pattern + 3,
75*4882a593Smuzhiyun 					 module + offset + TC_PATTERN3);
76*4882a593Smuzhiyun 			if (err)
77*4882a593Smuzhiyun 				goto out_err;
78*4882a593Smuzhiyun 		}
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun 		if (pattern[0] != 0x55 || pattern[1] != 0x00 ||
81*4882a593Smuzhiyun 		    pattern[2] != 0xaa || pattern[3] != 0xff)
82*4882a593Smuzhiyun 			goto out_err;
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun 		/* Found a board, allocate it an entry in the list */
85*4882a593Smuzhiyun 		tdev = kzalloc(sizeof(*tdev), GFP_KERNEL);
86*4882a593Smuzhiyun 		if (!tdev) {
87*4882a593Smuzhiyun 			pr_err("tc%x: unable to allocate tc_dev\n", slot);
88*4882a593Smuzhiyun 			goto out_err;
89*4882a593Smuzhiyun 		}
90*4882a593Smuzhiyun 		dev_set_name(&tdev->dev, "tc%x", slot);
91*4882a593Smuzhiyun 		tdev->bus = tbus;
92*4882a593Smuzhiyun 		tdev->dev.parent = &tbus->dev;
93*4882a593Smuzhiyun 		tdev->dev.bus = &tc_bus_type;
94*4882a593Smuzhiyun 		tdev->slot = slot;
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 		/* TURBOchannel has 34-bit DMA addressing (16GiB space). */
97*4882a593Smuzhiyun 		tdev->dma_mask = DMA_BIT_MASK(34);
98*4882a593Smuzhiyun 		tdev->dev.dma_mask = &tdev->dma_mask;
99*4882a593Smuzhiyun 		tdev->dev.coherent_dma_mask = DMA_BIT_MASK(34);
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun 		for (i = 0; i < 8; i++) {
102*4882a593Smuzhiyun 			tdev->firmware[i] =
103*4882a593Smuzhiyun 				readb(module + offset + TC_FIRM_VER + 4 * i);
104*4882a593Smuzhiyun 			tdev->vendor[i] =
105*4882a593Smuzhiyun 				readb(module + offset + TC_VENDOR + 4 * i);
106*4882a593Smuzhiyun 			tdev->name[i] =
107*4882a593Smuzhiyun 				readb(module + offset + TC_MODULE + 4 * i);
108*4882a593Smuzhiyun 		}
109*4882a593Smuzhiyun 		tdev->firmware[8] = 0;
110*4882a593Smuzhiyun 		tdev->vendor[8] = 0;
111*4882a593Smuzhiyun 		tdev->name[8] = 0;
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 		pr_info("%s: %s %s %s\n", dev_name(&tdev->dev), tdev->vendor,
114*4882a593Smuzhiyun 			tdev->name, tdev->firmware);
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun 		devsize = readb(module + offset + TC_SLOT_SIZE);
117*4882a593Smuzhiyun 		devsize <<= 22;
118*4882a593Smuzhiyun 		if (devsize <= slotsize) {
119*4882a593Smuzhiyun 			tdev->resource.start = slotaddr;
120*4882a593Smuzhiyun 			tdev->resource.end = slotaddr + devsize - 1;
121*4882a593Smuzhiyun 		} else if (devsize <= extslotsize) {
122*4882a593Smuzhiyun 			tdev->resource.start = extslotaddr;
123*4882a593Smuzhiyun 			tdev->resource.end = extslotaddr + devsize - 1;
124*4882a593Smuzhiyun 		} else {
125*4882a593Smuzhiyun 			pr_err("%s: Cannot provide slot space "
126*4882a593Smuzhiyun 			       "(%ldMiB required, up to %ldMiB supported)\n",
127*4882a593Smuzhiyun 			       dev_name(&tdev->dev), (long)(devsize >> 20),
128*4882a593Smuzhiyun 			       (long)(max(slotsize, extslotsize) >> 20));
129*4882a593Smuzhiyun 			kfree(tdev);
130*4882a593Smuzhiyun 			goto out_err;
131*4882a593Smuzhiyun 		}
132*4882a593Smuzhiyun 		tdev->resource.name = tdev->name;
133*4882a593Smuzhiyun 		tdev->resource.flags = IORESOURCE_MEM;
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 		tc_device_get_irq(tdev);
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun 		if (device_register(&tdev->dev)) {
138*4882a593Smuzhiyun 			put_device(&tdev->dev);
139*4882a593Smuzhiyun 			goto out_err;
140*4882a593Smuzhiyun 		}
141*4882a593Smuzhiyun 		list_add_tail(&tdev->node, &tbus->devices);
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun out_err:
144*4882a593Smuzhiyun 		iounmap(module);
145*4882a593Smuzhiyun 	}
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun /*
149*4882a593Smuzhiyun  * The main entry.
150*4882a593Smuzhiyun  */
tc_init(void)151*4882a593Smuzhiyun static int __init tc_init(void)
152*4882a593Smuzhiyun {
153*4882a593Smuzhiyun 	/* Initialize the TURBOchannel bus */
154*4882a593Smuzhiyun 	if (tc_bus_get_info(&tc_bus))
155*4882a593Smuzhiyun 		goto out_err;
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun 	INIT_LIST_HEAD(&tc_bus.devices);
158*4882a593Smuzhiyun 	dev_set_name(&tc_bus.dev, "tc");
159*4882a593Smuzhiyun 	if (device_register(&tc_bus.dev))
160*4882a593Smuzhiyun 		goto out_err_device;
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun 	if (tc_bus.info.slot_size) {
163*4882a593Smuzhiyun 		unsigned int tc_clock = tc_get_speed(&tc_bus) / 100000;
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 		pr_info("tc: TURBOchannel rev. %d at %d.%d MHz "
166*4882a593Smuzhiyun 			"(with%s parity)\n", tc_bus.info.revision,
167*4882a593Smuzhiyun 			tc_clock / 10, tc_clock % 10,
168*4882a593Smuzhiyun 			tc_bus.info.parity ? "" : "out");
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 		tc_bus.resource[0].start = tc_bus.slot_base;
171*4882a593Smuzhiyun 		tc_bus.resource[0].end = tc_bus.slot_base +
172*4882a593Smuzhiyun 					 (tc_bus.info.slot_size << 20) *
173*4882a593Smuzhiyun 					 tc_bus.num_tcslots - 1;
174*4882a593Smuzhiyun 		tc_bus.resource[0].name = tc_bus.name;
175*4882a593Smuzhiyun 		tc_bus.resource[0].flags = IORESOURCE_MEM;
176*4882a593Smuzhiyun 		if (request_resource(&iomem_resource,
177*4882a593Smuzhiyun 				     &tc_bus.resource[0]) < 0) {
178*4882a593Smuzhiyun 			pr_err("tc: Cannot reserve resource\n");
179*4882a593Smuzhiyun 			goto out_err_device;
180*4882a593Smuzhiyun 		}
181*4882a593Smuzhiyun 		if (tc_bus.ext_slot_size) {
182*4882a593Smuzhiyun 			tc_bus.resource[1].start = tc_bus.ext_slot_base;
183*4882a593Smuzhiyun 			tc_bus.resource[1].end = tc_bus.ext_slot_base +
184*4882a593Smuzhiyun 						 tc_bus.ext_slot_size *
185*4882a593Smuzhiyun 						 tc_bus.num_tcslots - 1;
186*4882a593Smuzhiyun 			tc_bus.resource[1].name = tc_bus.name;
187*4882a593Smuzhiyun 			tc_bus.resource[1].flags = IORESOURCE_MEM;
188*4882a593Smuzhiyun 			if (request_resource(&iomem_resource,
189*4882a593Smuzhiyun 					     &tc_bus.resource[1]) < 0) {
190*4882a593Smuzhiyun 				pr_err("tc: Cannot reserve resource\n");
191*4882a593Smuzhiyun 				goto out_err_resource;
192*4882a593Smuzhiyun 			}
193*4882a593Smuzhiyun 		}
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun 		tc_bus_add_devices(&tc_bus);
196*4882a593Smuzhiyun 	}
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun 	return 0;
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun out_err_resource:
201*4882a593Smuzhiyun 	release_resource(&tc_bus.resource[0]);
202*4882a593Smuzhiyun out_err_device:
203*4882a593Smuzhiyun 	put_device(&tc_bus.dev);
204*4882a593Smuzhiyun out_err:
205*4882a593Smuzhiyun 	return 0;
206*4882a593Smuzhiyun }
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun subsys_initcall(tc_init);
209