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