xref: /OK3568_Linux_fs/kernel/drivers/dio/dio.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /* Code to support devices on the DIO and DIO-II bus
3*4882a593Smuzhiyun  * Copyright (C) 05/1998 Peter Maydell <pmaydell@chiark.greenend.org.uk>
4*4882a593Smuzhiyun  * Copyright (C) 2004 Jochen Friedrich <jochen@scram.de>
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * This code has basically these routines at the moment:
7*4882a593Smuzhiyun  * int dio_find(u_int deviceid)
8*4882a593Smuzhiyun  *    Search the list of DIO devices and return the select code
9*4882a593Smuzhiyun  *    of the next unconfigured device found that matches the given device ID.
10*4882a593Smuzhiyun  *    Note that the deviceid parameter should be the encoded ID.
11*4882a593Smuzhiyun  *    This means that framebuffers should pass it as
12*4882a593Smuzhiyun  *    DIO_ENCODE_ID(DIO_ID_FBUFFER,DIO_ID2_TOPCAT)
13*4882a593Smuzhiyun  *    (or whatever); everybody else just uses DIO_ID_FOOBAR.
14*4882a593Smuzhiyun  * unsigned long dio_scodetophysaddr(int scode)
15*4882a593Smuzhiyun  *    Return the physical address corresponding to the given select code.
16*4882a593Smuzhiyun  * int dio_scodetoipl(int scode)
17*4882a593Smuzhiyun  *    Every DIO card has a fixed interrupt priority level. This function
18*4882a593Smuzhiyun  *    returns it, whatever it is.
19*4882a593Smuzhiyun  * const char *dio_scodetoname(int scode)
20*4882a593Smuzhiyun  *    Return a character string describing this board [might be "" if
21*4882a593Smuzhiyun  *    not CONFIG_DIO_CONSTANTS]
22*4882a593Smuzhiyun  * void dio_config_board(int scode)     mark board as configured in the list
23*4882a593Smuzhiyun  * void dio_unconfig_board(int scode)   mark board as no longer configured
24*4882a593Smuzhiyun  *
25*4882a593Smuzhiyun  * This file is based on the way the Amiga port handles Zorro II cards,
26*4882a593Smuzhiyun  * although we aren't so complicated...
27*4882a593Smuzhiyun  */
28*4882a593Smuzhiyun #include <linux/module.h>
29*4882a593Smuzhiyun #include <linux/string.h>
30*4882a593Smuzhiyun #include <linux/types.h>
31*4882a593Smuzhiyun #include <linux/kernel.h>
32*4882a593Smuzhiyun #include <linux/init.h>
33*4882a593Smuzhiyun #include <linux/dio.h>
34*4882a593Smuzhiyun #include <linux/slab.h>                         /* kmalloc() */
35*4882a593Smuzhiyun #include <linux/uaccess.h>
36*4882a593Smuzhiyun #include <asm/io.h>                             /* readb() */
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun struct dio_bus dio_bus = {
39*4882a593Smuzhiyun 	.resources = {
40*4882a593Smuzhiyun 		/* DIO range */
41*4882a593Smuzhiyun 		{ .name = "DIO mem", .start = 0x00600000, .end = 0x007fffff },
42*4882a593Smuzhiyun 		/* DIO-II range */
43*4882a593Smuzhiyun 		{ .name = "DIO-II mem", .start = 0x01000000, .end = 0x1fffffff }
44*4882a593Smuzhiyun 	},
45*4882a593Smuzhiyun 	.name = "DIO bus"
46*4882a593Smuzhiyun };
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun /* not a real config option yet! */
49*4882a593Smuzhiyun #define CONFIG_DIO_CONSTANTS
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun #ifdef CONFIG_DIO_CONSTANTS
52*4882a593Smuzhiyun /* We associate each numeric ID with an appropriate descriptive string
53*4882a593Smuzhiyun  * using a constant array of these structs.
54*4882a593Smuzhiyun  * FIXME: we should be able to arrange to throw away most of the strings
55*4882a593Smuzhiyun  * using the initdata stuff. Then we wouldn't need to worry about
56*4882a593Smuzhiyun  * carrying them around...
57*4882a593Smuzhiyun  * I think we do this by copying them into newly kmalloc()ed memory and
58*4882a593Smuzhiyun  * marking the names[] array as .initdata ?
59*4882a593Smuzhiyun  */
60*4882a593Smuzhiyun struct dioname
61*4882a593Smuzhiyun {
62*4882a593Smuzhiyun         int id;
63*4882a593Smuzhiyun         const char *name;
64*4882a593Smuzhiyun };
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun /* useful macro */
67*4882a593Smuzhiyun #define DIONAME(x) { DIO_ID_##x, DIO_DESC_##x }
68*4882a593Smuzhiyun #define DIOFBNAME(x) { DIO_ENCODE_ID( DIO_ID_FBUFFER, DIO_ID2_##x), DIO_DESC2_##x }
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun static struct dioname names[] =
71*4882a593Smuzhiyun {
72*4882a593Smuzhiyun         DIONAME(DCA0), DIONAME(DCA0REM), DIONAME(DCA1), DIONAME(DCA1REM),
73*4882a593Smuzhiyun         DIONAME(DCM), DIONAME(DCMREM),
74*4882a593Smuzhiyun         DIONAME(LAN),
75*4882a593Smuzhiyun         DIONAME(FHPIB), DIONAME(NHPIB),
76*4882a593Smuzhiyun         DIONAME(SCSI0), DIONAME(SCSI1), DIONAME(SCSI2), DIONAME(SCSI3),
77*4882a593Smuzhiyun         DIONAME(FBUFFER),
78*4882a593Smuzhiyun         DIONAME(PARALLEL), DIONAME(VME), DIONAME(DCL), DIONAME(DCLREM),
79*4882a593Smuzhiyun         DIONAME(MISC0), DIONAME(MISC1), DIONAME(MISC2), DIONAME(MISC3),
80*4882a593Smuzhiyun         DIONAME(MISC4), DIONAME(MISC5), DIONAME(MISC6), DIONAME(MISC7),
81*4882a593Smuzhiyun         DIONAME(MISC8), DIONAME(MISC9), DIONAME(MISC10), DIONAME(MISC11),
82*4882a593Smuzhiyun         DIONAME(MISC12), DIONAME(MISC13),
83*4882a593Smuzhiyun         DIOFBNAME(GATORBOX), DIOFBNAME(TOPCAT), DIOFBNAME(RENAISSANCE),
84*4882a593Smuzhiyun         DIOFBNAME(LRCATSEYE), DIOFBNAME(HRCCATSEYE), DIOFBNAME(HRMCATSEYE),
85*4882a593Smuzhiyun         DIOFBNAME(DAVINCI), DIOFBNAME(XXXCATSEYE), DIOFBNAME(HYPERION),
86*4882a593Smuzhiyun         DIOFBNAME(XGENESIS), DIOFBNAME(TIGER), DIOFBNAME(YGENESIS)
87*4882a593Smuzhiyun };
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun #undef DIONAME
90*4882a593Smuzhiyun #undef DIOFBNAME
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun static const char unknowndioname[]
93*4882a593Smuzhiyun 	= "unknown DIO board, please email linux-m68k@lists.linux-m68k.org";
94*4882a593Smuzhiyun 
dio_getname(int id)95*4882a593Smuzhiyun static const char *dio_getname(int id)
96*4882a593Smuzhiyun {
97*4882a593Smuzhiyun         /* return pointer to a constant string describing the board with given ID */
98*4882a593Smuzhiyun 	unsigned int i;
99*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(names); i++)
100*4882a593Smuzhiyun                 if (names[i].id == id)
101*4882a593Smuzhiyun                         return names[i].name;
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun         return unknowndioname;
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun #else
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun static char dio_no_name[] = { 0 };
109*4882a593Smuzhiyun #define dio_getname(_id)	(dio_no_name)
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun #endif /* CONFIG_DIO_CONSTANTS */
112*4882a593Smuzhiyun 
dio_find(int deviceid)113*4882a593Smuzhiyun int __init dio_find(int deviceid)
114*4882a593Smuzhiyun {
115*4882a593Smuzhiyun 	/* Called to find a DIO device before the full bus scan has run.
116*4882a593Smuzhiyun 	 * Only used by the console driver.
117*4882a593Smuzhiyun 	 */
118*4882a593Smuzhiyun 	int scode, id;
119*4882a593Smuzhiyun 	u_char prid, secid, i;
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun 	for (scode = 0; scode < DIO_SCMAX; scode++) {
122*4882a593Smuzhiyun 		void *va;
123*4882a593Smuzhiyun 		unsigned long pa;
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun                 if (DIO_SCINHOLE(scode))
126*4882a593Smuzhiyun                         continue;
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun                 pa = dio_scodetophysaddr(scode);
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 		if (!pa)
131*4882a593Smuzhiyun 			continue;
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 		if (scode < DIOII_SCBASE)
134*4882a593Smuzhiyun 			va = (void *)(pa + DIO_VIRADDRBASE);
135*4882a593Smuzhiyun 		else
136*4882a593Smuzhiyun 			va = ioremap(pa, PAGE_SIZE);
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 		if (copy_from_kernel_nofault(&i,
139*4882a593Smuzhiyun 				(unsigned char *)va + DIO_IDOFF, 1)) {
140*4882a593Smuzhiyun 			if (scode >= DIOII_SCBASE)
141*4882a593Smuzhiyun 				iounmap(va);
142*4882a593Smuzhiyun                         continue;             /* no board present at that select code */
143*4882a593Smuzhiyun 		}
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 		prid = DIO_ID(va);
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun                 if (DIO_NEEDSSECID(prid)) {
148*4882a593Smuzhiyun                         secid = DIO_SECID(va);
149*4882a593Smuzhiyun                         id = DIO_ENCODE_ID(prid, secid);
150*4882a593Smuzhiyun                 } else
151*4882a593Smuzhiyun 			id = prid;
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun 		if (id == deviceid) {
154*4882a593Smuzhiyun 			if (scode >= DIOII_SCBASE)
155*4882a593Smuzhiyun 				iounmap(va);
156*4882a593Smuzhiyun 			return scode;
157*4882a593Smuzhiyun 		}
158*4882a593Smuzhiyun 	}
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 	return -1;
161*4882a593Smuzhiyun }
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun /* This is the function that scans the DIO space and works out what
164*4882a593Smuzhiyun  * hardware is actually present.
165*4882a593Smuzhiyun  */
dio_init(void)166*4882a593Smuzhiyun static int __init dio_init(void)
167*4882a593Smuzhiyun {
168*4882a593Smuzhiyun 	int scode;
169*4882a593Smuzhiyun 	int i;
170*4882a593Smuzhiyun 	struct dio_dev *dev;
171*4882a593Smuzhiyun 	int error;
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun 	if (!MACH_IS_HP300)
174*4882a593Smuzhiyun 		return 0;
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun         printk(KERN_INFO "Scanning for DIO devices...\n");
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 	/* Initialize the DIO bus */
179*4882a593Smuzhiyun 	INIT_LIST_HEAD(&dio_bus.devices);
180*4882a593Smuzhiyun 	dev_set_name(&dio_bus.dev, "dio");
181*4882a593Smuzhiyun 	error = device_register(&dio_bus.dev);
182*4882a593Smuzhiyun 	if (error) {
183*4882a593Smuzhiyun 		pr_err("DIO: Error registering dio_bus\n");
184*4882a593Smuzhiyun 		return error;
185*4882a593Smuzhiyun 	}
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	/* Request all resources */
188*4882a593Smuzhiyun 	dio_bus.num_resources = (hp300_model == HP_320 ? 1 : 2);
189*4882a593Smuzhiyun 	for (i = 0; i < dio_bus.num_resources; i++)
190*4882a593Smuzhiyun 		request_resource(&iomem_resource, &dio_bus.resources[i]);
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 	/* Register all devices */
193*4882a593Smuzhiyun         for (scode = 0; scode < DIO_SCMAX; ++scode)
194*4882a593Smuzhiyun         {
195*4882a593Smuzhiyun                 u_char prid, secid = 0;        /* primary, secondary ID bytes */
196*4882a593Smuzhiyun                 u_char *va;
197*4882a593Smuzhiyun 		unsigned long pa;
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun                 if (DIO_SCINHOLE(scode))
200*4882a593Smuzhiyun                         continue;
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun 		pa = dio_scodetophysaddr(scode);
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun 		if (!pa)
205*4882a593Smuzhiyun 			continue;
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 		if (scode < DIOII_SCBASE)
208*4882a593Smuzhiyun 			va = (void *)(pa + DIO_VIRADDRBASE);
209*4882a593Smuzhiyun 		else
210*4882a593Smuzhiyun 			va = ioremap(pa, PAGE_SIZE);
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun 		if (copy_from_kernel_nofault(&i,
213*4882a593Smuzhiyun 				(unsigned char *)va + DIO_IDOFF, 1)) {
214*4882a593Smuzhiyun 			if (scode >= DIOII_SCBASE)
215*4882a593Smuzhiyun 				iounmap(va);
216*4882a593Smuzhiyun                         continue;              /* no board present at that select code */
217*4882a593Smuzhiyun 		}
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun                 /* Found a board, allocate it an entry in the list */
220*4882a593Smuzhiyun 		dev = kzalloc(sizeof(struct dio_dev), GFP_KERNEL);
221*4882a593Smuzhiyun 		if (!dev)
222*4882a593Smuzhiyun 			return 0;
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun 		dev->bus = &dio_bus;
225*4882a593Smuzhiyun 		dev->dev.parent = &dio_bus.dev;
226*4882a593Smuzhiyun 		dev->dev.bus = &dio_bus_type;
227*4882a593Smuzhiyun 		dev->scode = scode;
228*4882a593Smuzhiyun 		dev->resource.start = pa;
229*4882a593Smuzhiyun 		dev->resource.end = pa + DIO_SIZE(scode, va);
230*4882a593Smuzhiyun 		dev_set_name(&dev->dev, "%02x", scode);
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun                 /* read the ID byte(s) and encode if necessary. */
233*4882a593Smuzhiyun 		prid = DIO_ID(va);
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun                 if (DIO_NEEDSSECID(prid)) {
236*4882a593Smuzhiyun                         secid = DIO_SECID(va);
237*4882a593Smuzhiyun                         dev->id = DIO_ENCODE_ID(prid, secid);
238*4882a593Smuzhiyun                 } else
239*4882a593Smuzhiyun                         dev->id = prid;
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun                 dev->ipl = DIO_IPL(va);
242*4882a593Smuzhiyun                 strcpy(dev->name,dio_getname(dev->id));
243*4882a593Smuzhiyun                 printk(KERN_INFO "select code %3d: ipl %d: ID %02X", dev->scode, dev->ipl, prid);
244*4882a593Smuzhiyun                 if (DIO_NEEDSSECID(prid))
245*4882a593Smuzhiyun                         printk(":%02X", secid);
246*4882a593Smuzhiyun                 printk(": %s\n", dev->name);
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun 		if (scode >= DIOII_SCBASE)
249*4882a593Smuzhiyun 			iounmap(va);
250*4882a593Smuzhiyun 		error = device_register(&dev->dev);
251*4882a593Smuzhiyun 		if (error) {
252*4882a593Smuzhiyun 			pr_err("DIO: Error registering device %s\n",
253*4882a593Smuzhiyun 			       dev->name);
254*4882a593Smuzhiyun 			continue;
255*4882a593Smuzhiyun 		}
256*4882a593Smuzhiyun 		error = dio_create_sysfs_dev_files(dev);
257*4882a593Smuzhiyun 		if (error)
258*4882a593Smuzhiyun 			dev_err(&dev->dev, "Error creating sysfs files\n");
259*4882a593Smuzhiyun         }
260*4882a593Smuzhiyun 	return 0;
261*4882a593Smuzhiyun }
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun subsys_initcall(dio_init);
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun /* Bear in mind that this is called in the very early stages of initialisation
266*4882a593Smuzhiyun  * in order to get the address of the serial port for the console...
267*4882a593Smuzhiyun  */
dio_scodetophysaddr(int scode)268*4882a593Smuzhiyun unsigned long dio_scodetophysaddr(int scode)
269*4882a593Smuzhiyun {
270*4882a593Smuzhiyun         if (scode >= DIOII_SCBASE) {
271*4882a593Smuzhiyun                 return (DIOII_BASE + (scode - 132) * DIOII_DEVSIZE);
272*4882a593Smuzhiyun         } else if (scode > DIO_SCMAX || scode < 0)
273*4882a593Smuzhiyun                 return 0;
274*4882a593Smuzhiyun         else if (DIO_SCINHOLE(scode))
275*4882a593Smuzhiyun                 return 0;
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun         return (DIO_BASE + scode * DIO_DEVSIZE);
278*4882a593Smuzhiyun }
279