blob: 77a48a5164ff5dd59ebe28ecf23224e2c94edaa3 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Macintosh Nubus Interface Code
3 *
4 * Originally by Alan Cox
5 *
6 * Mostly rewritten by David Huggins-Daines, C. Scott Ananian,
7 * and others.
8 */
9
Linus Torvalds1da177e2005-04-16 15:20:36 -070010#include <linux/types.h>
11#include <linux/kernel.h>
12#include <linux/string.h>
13#include <linux/nubus.h>
14#include <linux/errno.h>
15#include <linux/init.h>
16#include <linux/delay.h>
Adrian Bunk99ffab82008-02-04 22:30:23 -080017#include <linux/module.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090018#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070019#include <asm/setup.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070020#include <asm/page.h>
21#include <asm/hwtest.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070022#include <asm/mac_via.h>
23#include <asm/mac_oss.h>
24
25extern void via_nubus_init(void);
26extern void oss_nubus_init(void);
27
28/* Constants */
29
30/* This is, of course, the size in bytelanes, rather than the size in
31 actual bytes */
32#define FORMAT_BLOCK_SIZE 20
33#define ROM_DIR_OFFSET 0x24
34
35#define NUBUS_TEST_PATTERN 0x5A932BC7
36
37/* Define this if you like to live dangerously - it is known not to
38 work on pretty much every machine except the Quadra 630 and the LC
39 III. */
40#undef I_WANT_TO_PROBE_SLOT_ZERO
41
42/* This sometimes helps combat failure to boot */
43#undef TRY_TO_DODGE_WSOD
44
45/* Globals */
46
Finn Thainf42e5552017-04-08 19:51:15 -040047struct nubus_dev *nubus_devices;
48struct nubus_board *nubus_boards;
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
50/* Meaning of "bytelanes":
51
52 The card ROM may appear on any or all bytes of each long word in
53 NuBus memory. The low 4 bits of the "map" value found in the
54 format block (at the top of the slot address space, as well as at
55 the top of the MacOS ROM) tells us which bytelanes, i.e. which byte
56 offsets within each longword, are valid. Thus:
57
58 A map of 0x0f, as found in the MacOS ROM, means that all bytelanes
59 are valid.
60
61 A map of 0xf0 means that no bytelanes are valid (We pray that we
62 will never encounter this, but stranger things have happened)
63
64 A map of 0xe1 means that only the MSB of each long word is actually
65 part of the card ROM. (We hope to never encounter NuBus on a
66 little-endian machine. Again, stranger things have happened)
67
68 A map of 0x78 means that only the LSB of each long word is valid.
69
70 Etcetera, etcetera. Hopefully this clears up some confusion over
71 what the following code actually does. */
Finn Thainf42e5552017-04-08 19:51:15 -040072
Linus Torvalds1da177e2005-04-16 15:20:36 -070073static inline int not_useful(void *p, int map)
74{
Finn Thainf42e5552017-04-08 19:51:15 -040075 unsigned long pv = (unsigned long)p;
76
Linus Torvalds1da177e2005-04-16 15:20:36 -070077 pv &= 3;
Finn Thainf42e5552017-04-08 19:51:15 -040078 if (map & (1 << pv))
Linus Torvalds1da177e2005-04-16 15:20:36 -070079 return 0;
80 return 1;
81}
Finn Thainf42e5552017-04-08 19:51:15 -040082
Linus Torvalds1da177e2005-04-16 15:20:36 -070083static unsigned long nubus_get_rom(unsigned char **ptr, int len, int map)
84{
85 /* This will hold the result */
86 unsigned long v = 0;
87 unsigned char *p = *ptr;
88
Finn Thainf42e5552017-04-08 19:51:15 -040089 while (len) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070090 v <<= 8;
Finn Thainf42e5552017-04-08 19:51:15 -040091 while (not_useful(p, map))
Linus Torvalds1da177e2005-04-16 15:20:36 -070092 p++;
93 v |= *p++;
94 len--;
95 }
96 *ptr = p;
97 return v;
98}
99
100static void nubus_rewind(unsigned char **ptr, int len, int map)
101{
Finn Thainf42e5552017-04-08 19:51:15 -0400102 unsigned char *p = *ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103
104 /* Sanity check */
Finn Thainf42e5552017-04-08 19:51:15 -0400105 if (len > 65536)
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400106 pr_err("rewind of 0x%08x!\n", len);
Finn Thainf42e5552017-04-08 19:51:15 -0400107 while (len) {
108 do {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 p--;
Finn Thainf42e5552017-04-08 19:51:15 -0400110 } while (not_useful(p, map));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 len--;
112 }
Finn Thainf42e5552017-04-08 19:51:15 -0400113 *ptr = p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114}
115
116static void nubus_advance(unsigned char **ptr, int len, int map)
117{
118 unsigned char *p = *ptr;
Finn Thainf42e5552017-04-08 19:51:15 -0400119
120 if (len > 65536)
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400121 pr_err("advance of 0x%08x!\n", len);
Finn Thainf42e5552017-04-08 19:51:15 -0400122 while (len) {
123 while (not_useful(p, map))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124 p++;
Ilpo Järvinen2e0eb732008-10-15 22:01:31 -0700125 p++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126 len--;
127 }
128 *ptr = p;
129}
130
131static void nubus_move(unsigned char **ptr, int len, int map)
132{
Finn Thainf42e5552017-04-08 19:51:15 -0400133 if (len > 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134 nubus_advance(ptr, len, map);
Finn Thainf42e5552017-04-08 19:51:15 -0400135 else if (len < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 nubus_rewind(ptr, -len, map);
137}
138
139/* Now, functions to read the sResource tree */
140
141/* Each sResource entry consists of a 1-byte ID and a 3-byte data
142 field. If that data field contains an offset, then obviously we
143 have to expand it from a 24-bit signed number to a 32-bit signed
144 number. */
145
146static inline long nubus_expand32(long foo)
147{
Finn Thainf42e5552017-04-08 19:51:15 -0400148 if (foo & 0x00800000) /* 24bit negative */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 foo |= 0xFF000000;
150 return foo;
151}
152
153static inline void *nubus_rom_addr(int slot)
Finn Thainf42e5552017-04-08 19:51:15 -0400154{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 /*
156 * Returns the first byte after the card. We then walk
157 * backwards to get the lane register and the config
158 */
Finn Thainf42e5552017-04-08 19:51:15 -0400159 return (void *)(0xF1000000 + (slot << 24));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160}
161
162static unsigned char *nubus_dirptr(const struct nubus_dirent *nd)
163{
164 unsigned char *p = nd->base;
Finn Thainf42e5552017-04-08 19:51:15 -0400165
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 /* Essentially, just step over the bytelanes using whatever
167 offset we might have found */
168 nubus_move(&p, nubus_expand32(nd->data), nd->mask);
169 /* And return the value */
170 return p;
171}
172
173/* These two are for pulling resource data blocks (i.e. stuff that's
174 pointed to with offsets) out of the card ROM. */
175
Finn Thainf42e5552017-04-08 19:51:15 -0400176void nubus_get_rsrc_mem(void *dest, const struct nubus_dirent *dirent,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 int len)
178{
179 unsigned char *t = (unsigned char *)dest;
180 unsigned char *p = nubus_dirptr(dirent);
Finn Thainf42e5552017-04-08 19:51:15 -0400181
182 while (len) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183 *t++ = nubus_get_rom(&p, 1, dirent->mask);
184 len--;
185 }
186}
Adrian Bunk99ffab82008-02-04 22:30:23 -0800187EXPORT_SYMBOL(nubus_get_rsrc_mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188
Finn Thainf42e5552017-04-08 19:51:15 -0400189void nubus_get_rsrc_str(void *dest, const struct nubus_dirent *dirent,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190 int len)
191{
Finn Thainf42e5552017-04-08 19:51:15 -0400192 unsigned char *t = (unsigned char *)dest;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 unsigned char *p = nubus_dirptr(dirent);
Finn Thainf42e5552017-04-08 19:51:15 -0400194
195 while (len) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 *t = nubus_get_rom(&p, 1, dirent->mask);
Finn Thainf42e5552017-04-08 19:51:15 -0400197 if (!*t++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198 break;
199 len--;
200 }
201}
Adrian Bunk99ffab82008-02-04 22:30:23 -0800202EXPORT_SYMBOL(nubus_get_rsrc_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203
Finn Thainf42e5552017-04-08 19:51:15 -0400204int nubus_get_root_dir(const struct nubus_board *board,
205 struct nubus_dir *dir)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206{
207 dir->ptr = dir->base = board->directory;
208 dir->done = 0;
209 dir->mask = board->lanes;
210 return 0;
211}
Adrian Bunk99ffab82008-02-04 22:30:23 -0800212EXPORT_SYMBOL(nubus_get_root_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213
214/* This is a slyly renamed version of the above */
Finn Thainf42e5552017-04-08 19:51:15 -0400215int nubus_get_func_dir(const struct nubus_dev *dev,
216 struct nubus_dir *dir)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217{
218 dir->ptr = dir->base = dev->directory;
219 dir->done = 0;
220 dir->mask = dev->board->lanes;
221 return 0;
222}
Adrian Bunk99ffab82008-02-04 22:30:23 -0800223EXPORT_SYMBOL(nubus_get_func_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224
Finn Thainf42e5552017-04-08 19:51:15 -0400225int nubus_get_board_dir(const struct nubus_board *board,
226 struct nubus_dir *dir)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227{
228 struct nubus_dirent ent;
Finn Thainf42e5552017-04-08 19:51:15 -0400229
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 dir->ptr = dir->base = board->directory;
231 dir->done = 0;
232 dir->mask = board->lanes;
233
234 /* Now dereference it (the first directory is always the board
235 directory) */
236 if (nubus_readdir(dir, &ent) == -1)
237 return -1;
238 if (nubus_get_subdir(&ent, dir) == -1)
239 return -1;
240 return 0;
241}
Adrian Bunk99ffab82008-02-04 22:30:23 -0800242EXPORT_SYMBOL(nubus_get_board_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243
244int nubus_get_subdir(const struct nubus_dirent *ent,
245 struct nubus_dir *dir)
246{
247 dir->ptr = dir->base = nubus_dirptr(ent);
248 dir->done = 0;
249 dir->mask = ent->mask;
250 return 0;
251}
Adrian Bunk99ffab82008-02-04 22:30:23 -0800252EXPORT_SYMBOL(nubus_get_subdir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253
254int nubus_readdir(struct nubus_dir *nd, struct nubus_dirent *ent)
255{
256 u32 resid;
Finn Thainf42e5552017-04-08 19:51:15 -0400257
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 if (nd->done)
259 return -1;
260
261 /* Do this first, otherwise nubus_rewind & co are off by 4 */
262 ent->base = nd->ptr;
263
264 /* This moves nd->ptr forward */
265 resid = nubus_get_rom(&nd->ptr, 4, nd->mask);
266
267 /* EOL marker, as per the Apple docs */
Finn Thainf42e5552017-04-08 19:51:15 -0400268 if ((resid & 0xff000000) == 0xff000000) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 /* Mark it as done */
270 nd->done = 1;
271 return -1;
272 }
273
274 /* First byte is the resource ID */
Finn Thainf42e5552017-04-08 19:51:15 -0400275 ent->type = resid >> 24;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 /* Low 3 bytes might contain data (or might not) */
277 ent->data = resid & 0xffffff;
Finn Thainf42e5552017-04-08 19:51:15 -0400278 ent->mask = nd->mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 return 0;
280}
Adrian Bunk99ffab82008-02-04 22:30:23 -0800281EXPORT_SYMBOL(nubus_readdir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282
Finn Thainf42e5552017-04-08 19:51:15 -0400283int nubus_rewinddir(struct nubus_dir *dir)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284{
285 dir->ptr = dir->base;
David Huggins-Dainese36b9912017-04-08 19:51:15 -0400286 dir->done = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 return 0;
288}
Adrian Bunk99ffab82008-02-04 22:30:23 -0800289EXPORT_SYMBOL(nubus_rewinddir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290
291/* Driver interface functions, more or less like in pci.c */
292
293struct nubus_dev*
Finn Thainf42e5552017-04-08 19:51:15 -0400294nubus_find_device(unsigned short category, unsigned short type,
295 unsigned short dr_hw, unsigned short dr_sw,
296 const struct nubus_dev *from)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297{
Finn Thainf42e5552017-04-08 19:51:15 -0400298 struct nubus_dev *itor = from ? from->next : nubus_devices;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299
300 while (itor) {
Finn Thainf42e5552017-04-08 19:51:15 -0400301 if (itor->category == category && itor->type == type &&
302 itor->dr_hw == dr_hw && itor->dr_sw == dr_sw)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 return itor;
304 itor = itor->next;
305 }
306 return NULL;
307}
Adrian Bunk99ffab82008-02-04 22:30:23 -0800308EXPORT_SYMBOL(nubus_find_device);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309
310struct nubus_dev*
Finn Thainf42e5552017-04-08 19:51:15 -0400311nubus_find_type(unsigned short category, unsigned short type,
312 const struct nubus_dev *from)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313{
Finn Thainf42e5552017-04-08 19:51:15 -0400314 struct nubus_dev *itor = from ? from->next : nubus_devices;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315
316 while (itor) {
Finn Thainf42e5552017-04-08 19:51:15 -0400317 if (itor->category == category && itor->type == type)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 return itor;
319 itor = itor->next;
320 }
321 return NULL;
322}
Adrian Bunk99ffab82008-02-04 22:30:23 -0800323EXPORT_SYMBOL(nubus_find_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324
325struct nubus_dev*
Finn Thainf42e5552017-04-08 19:51:15 -0400326nubus_find_slot(unsigned int slot, const struct nubus_dev *from)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327{
Finn Thainf42e5552017-04-08 19:51:15 -0400328 struct nubus_dev *itor = from ? from->next : nubus_devices;
329
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 while (itor) {
331 if (itor->board->slot == slot)
332 return itor;
333 itor = itor->next;
334 }
335 return NULL;
336}
Adrian Bunk99ffab82008-02-04 22:30:23 -0800337EXPORT_SYMBOL(nubus_find_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338
339int
Finn Thainf42e5552017-04-08 19:51:15 -0400340nubus_find_rsrc(struct nubus_dir *dir, unsigned char rsrc_type,
341 struct nubus_dirent *ent)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342{
343 while (nubus_readdir(dir, ent) != -1) {
344 if (ent->type == rsrc_type)
345 return 0;
Finn Thainf42e5552017-04-08 19:51:15 -0400346 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 return -1;
348}
Adrian Bunk99ffab82008-02-04 22:30:23 -0800349EXPORT_SYMBOL(nubus_find_rsrc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350
351/* Initialization functions - decide which slots contain stuff worth
352 looking at, and print out lots and lots of information from the
353 resource blocks. */
354
355/* FIXME: A lot of this stuff will eventually be useful after
Joe Perches081985a2008-02-03 17:23:36 +0200356 initialization, for intelligently probing Ethernet and video chips,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 among other things. The rest of it should go in the /proc code.
358 For now, we just use it to give verbose boot logs. */
359
Finn Thainf42e5552017-04-08 19:51:15 -0400360static int __init nubus_show_display_resource(struct nubus_dev *dev,
361 const struct nubus_dirent *ent)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362{
363 switch (ent->type) {
364 case NUBUS_RESID_GAMMADIR:
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400365 pr_info(" gamma directory offset: 0x%06x\n", ent->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 break;
367 case 0x0080 ... 0x0085:
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400368 pr_info(" mode %02X info offset: 0x%06x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 ent->type, ent->data);
370 break;
371 default:
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400372 pr_info(" unknown resource %02X, data 0x%06x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 ent->type, ent->data);
374 }
375 return 0;
376}
377
Finn Thainf42e5552017-04-08 19:51:15 -0400378static int __init nubus_show_network_resource(struct nubus_dev *dev,
379 const struct nubus_dirent *ent)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380{
381 switch (ent->type) {
382 case NUBUS_RESID_MAC_ADDRESS:
383 {
384 char addr[6];
Finn Thainf42e5552017-04-08 19:51:15 -0400385
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 nubus_get_rsrc_mem(addr, ent, 6);
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400387 pr_info(" MAC address: %pM\n", addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 break;
389 }
390 default:
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400391 pr_info(" unknown resource %02X, data 0x%06x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 ent->type, ent->data);
393 }
394 return 0;
395}
396
Finn Thainf42e5552017-04-08 19:51:15 -0400397static int __init nubus_show_cpu_resource(struct nubus_dev *dev,
398 const struct nubus_dirent *ent)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399{
400 switch (ent->type) {
401 case NUBUS_RESID_MEMINFO:
402 {
403 unsigned long meminfo[2];
Finn Thainf42e5552017-04-08 19:51:15 -0400404
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 nubus_get_rsrc_mem(&meminfo, ent, 8);
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400406 pr_info(" memory: [ 0x%08lx 0x%08lx ]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 meminfo[0], meminfo[1]);
408 break;
409 }
410 case NUBUS_RESID_ROMINFO:
411 {
412 unsigned long rominfo[2];
Finn Thainf42e5552017-04-08 19:51:15 -0400413
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 nubus_get_rsrc_mem(&rominfo, ent, 8);
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400415 pr_info(" ROM: [ 0x%08lx 0x%08lx ]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 rominfo[0], rominfo[1]);
417 break;
418 }
419 default:
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400420 pr_info(" unknown resource %02X, data 0x%06x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 ent->type, ent->data);
422 }
423 return 0;
424}
425
Finn Thainf42e5552017-04-08 19:51:15 -0400426static int __init nubus_show_private_resource(struct nubus_dev *dev,
427 const struct nubus_dirent *ent)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428{
429 switch (dev->category) {
430 case NUBUS_CAT_DISPLAY:
431 nubus_show_display_resource(dev, ent);
432 break;
433 case NUBUS_CAT_NETWORK:
434 nubus_show_network_resource(dev, ent);
435 break;
436 case NUBUS_CAT_CPU:
437 nubus_show_cpu_resource(dev, ent);
438 break;
439 default:
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400440 pr_info(" unknown resource %02X, data 0x%06x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 ent->type, ent->data);
442 }
443 return 0;
444}
445
Finn Thainf42e5552017-04-08 19:51:15 -0400446static struct nubus_dev * __init
447nubus_get_functional_resource(struct nubus_board *board, int slot,
448 const struct nubus_dirent *parent)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449{
Finn Thainf42e5552017-04-08 19:51:15 -0400450 struct nubus_dir dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 struct nubus_dirent ent;
Finn Thainf42e5552017-04-08 19:51:15 -0400452 struct nubus_dev *dev;
453
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400454 pr_info(" Function 0x%02x:\n", parent->type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 nubus_get_subdir(parent, &dir);
456
457 /* Apple seems to have botched the ROM on the IIx */
458 if (slot == 0 && (unsigned long)dir.base % 2)
459 dir.base += 1;
Finn Thainf42e5552017-04-08 19:51:15 -0400460
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400461 pr_debug("%s: parent is 0x%p, dir is 0x%p\n",
462 __func__, parent->base, dir.base);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463
464 /* Actually we should probably panic if this fails */
Yoann Padioleaudd00cc42007-07-19 01:49:03 -0700465 if ((dev = kzalloc(sizeof(*dev), GFP_ATOMIC)) == NULL)
Finn Thainf42e5552017-04-08 19:51:15 -0400466 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 dev->resid = parent->type;
468 dev->directory = dir.base;
469 dev->board = board;
Finn Thainf42e5552017-04-08 19:51:15 -0400470
471 while (nubus_readdir(&dir, &ent) != -1) {
472 switch (ent.type) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 case NUBUS_RESID_TYPE:
474 {
475 unsigned short nbtdata[4];
Finn Thainf42e5552017-04-08 19:51:15 -0400476
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 nubus_get_rsrc_mem(nbtdata, &ent, 8);
478 dev->category = nbtdata[0];
479 dev->type = nbtdata[1];
480 dev->dr_sw = nbtdata[2];
481 dev->dr_hw = nbtdata[3];
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400482 pr_info(" type: [cat 0x%x type 0x%x sw 0x%x hw 0x%x]\n",
483 nbtdata[0], nbtdata[1], nbtdata[2], nbtdata[3]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 break;
485 }
486 case NUBUS_RESID_NAME:
487 {
488 nubus_get_rsrc_str(dev->name, &ent, 64);
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400489 pr_info(" name: %s\n", dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 break;
491 }
492 case NUBUS_RESID_DRVRDIR:
493 {
494 /* MacOS driver. If we were NetBSD we might
495 use this :-) */
496 struct nubus_dir drvr_dir;
497 struct nubus_dirent drvr_ent;
Finn Thainf42e5552017-04-08 19:51:15 -0400498
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 nubus_get_subdir(&ent, &drvr_dir);
500 nubus_readdir(&drvr_dir, &drvr_ent);
501 dev->driver = nubus_dirptr(&drvr_ent);
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400502 pr_info(" driver at: 0x%p\n", dev->driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 break;
504 }
505 case NUBUS_RESID_MINOR_BASEOS:
506 /* We will need this in order to support
507 multiple framebuffers. It might be handy
508 for Ethernet as well */
509 nubus_get_rsrc_mem(&dev->iobase, &ent, 4);
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400510 pr_info(" memory offset: 0x%08lx\n", dev->iobase);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 break;
512 case NUBUS_RESID_MINOR_LENGTH:
513 /* Ditto */
514 nubus_get_rsrc_mem(&dev->iosize, &ent, 4);
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400515 pr_info(" memory length: 0x%08lx\n", dev->iosize);
Finn Thainf42e5552017-04-08 19:51:15 -0400516 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 case NUBUS_RESID_FLAGS:
518 dev->flags = ent.data;
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400519 pr_info(" flags: 0x%06x\n", dev->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 break;
521 case NUBUS_RESID_HWDEVID:
522 dev->hwdevid = ent.data;
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400523 pr_info(" hwdevid: 0x%06x\n", dev->hwdevid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 break;
525 default:
526 /* Local/Private resources have their own
527 function */
528 nubus_show_private_resource(dev, &ent);
529 }
530 }
Finn Thainf42e5552017-04-08 19:51:15 -0400531
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 return dev;
533}
534
535/* This is cool. */
Finn Thainf42e5552017-04-08 19:51:15 -0400536static int __init nubus_get_vidnames(struct nubus_board *board,
537 const struct nubus_dirent *parent)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538{
Finn Thainf42e5552017-04-08 19:51:15 -0400539 struct nubus_dir dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 struct nubus_dirent ent;
Finn Thainf42e5552017-04-08 19:51:15 -0400541
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 /* FIXME: obviously we want to put this in a header file soon */
543 struct vidmode {
544 u32 size;
545 /* Don't know what this is yet */
546 u16 id;
547 /* Longest one I've seen so far is 26 characters */
548 char name[32];
549 };
550
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400551 pr_info(" video modes supported:\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 nubus_get_subdir(parent, &dir);
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400553 pr_debug("%s: parent is 0x%p, dir is 0x%p\n",
554 __func__, parent->base, dir.base);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555
Finn Thainf42e5552017-04-08 19:51:15 -0400556 while (nubus_readdir(&dir, &ent) != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 struct vidmode mode;
558 u32 size;
559
560 /* First get the length */
561 nubus_get_rsrc_mem(&size, &ent, 4);
Finn Thainf42e5552017-04-08 19:51:15 -0400562
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 /* Now clobber the whole thing */
564 if (size > sizeof(mode) - 1)
565 size = sizeof(mode) - 1;
566 memset(&mode, 0, sizeof(mode));
567 nubus_get_rsrc_mem(&mode, &ent, size);
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400568 pr_info(" %02X: (%02X) %s\n", ent.type,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 mode.id, mode.name);
570 }
571 return 0;
572}
573
574/* This is *really* cool. */
Finn Thainf42e5552017-04-08 19:51:15 -0400575static int __init nubus_get_icon(struct nubus_board *board,
576 const struct nubus_dirent *ent)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577{
578 /* Should be 32x32 if my memory serves me correctly */
579 unsigned char icon[128];
580 int x, y;
Finn Thainf42e5552017-04-08 19:51:15 -0400581
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 nubus_get_rsrc_mem(&icon, ent, 128);
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400583 pr_info(" icon:\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584
585 /* We should actually plot these somewhere in the framebuffer
586 init. This is just to demonstrate that they do, in fact,
587 exist */
588 for (y = 0; y < 32; y++) {
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400589 pr_info(" ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 for (x = 0; x < 32; x++) {
Finn Thainf42e5552017-04-08 19:51:15 -0400591 if (icon[y * 4 + x / 8] & (0x80 >> (x % 8)))
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400592 pr_cont("*");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 else
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400594 pr_cont(" ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 }
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400596 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 }
598 return 0;
599}
600
Finn Thainf42e5552017-04-08 19:51:15 -0400601static int __init nubus_get_vendorinfo(struct nubus_board *board,
602 const struct nubus_dirent *parent)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603{
Finn Thainf42e5552017-04-08 19:51:15 -0400604 struct nubus_dir dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 struct nubus_dirent ent;
Finn Thainf42e5552017-04-08 19:51:15 -0400606 static char *vendor_fields[6] = { "ID", "serial", "revision",
607 "part", "date", "unknown field" };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400609 pr_info(" vendor info:\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 nubus_get_subdir(parent, &dir);
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400611 pr_debug("%s: parent is 0x%p, dir is 0x%p\n",
612 __func__, parent->base, dir.base);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613
Finn Thainf42e5552017-04-08 19:51:15 -0400614 while (nubus_readdir(&dir, &ent) != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 char name[64];
Finn Thainf42e5552017-04-08 19:51:15 -0400616
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 /* These are all strings, we think */
618 nubus_get_rsrc_str(name, &ent, 64);
619 if (ent.type > 5)
620 ent.type = 5;
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400621 pr_info(" %s: %s\n", vendor_fields[ent.type - 1], name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 }
623 return 0;
624}
625
Finn Thainf42e5552017-04-08 19:51:15 -0400626static int __init nubus_get_board_resource(struct nubus_board *board, int slot,
627 const struct nubus_dirent *parent)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628{
Finn Thainf42e5552017-04-08 19:51:15 -0400629 struct nubus_dir dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 struct nubus_dirent ent;
Finn Thainf42e5552017-04-08 19:51:15 -0400631
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 nubus_get_subdir(parent, &dir);
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400633 pr_debug("%s: parent is 0x%p, dir is 0x%p\n",
634 __func__, parent->base, dir.base);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635
Finn Thainf42e5552017-04-08 19:51:15 -0400636 while (nubus_readdir(&dir, &ent) != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 switch (ent.type) {
638 case NUBUS_RESID_TYPE:
639 {
640 unsigned short nbtdata[4];
641 /* This type is always the same, and is not
642 useful except insofar as it tells us that
643 we really are looking at a board resource. */
644 nubus_get_rsrc_mem(nbtdata, &ent, 8);
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400645 pr_info(" type: [cat 0x%x type 0x%x sw 0x%x hw 0x%x]\n",
646 nbtdata[0], nbtdata[1], nbtdata[2], nbtdata[3]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 if (nbtdata[0] != 1 || nbtdata[1] != 0 ||
648 nbtdata[2] != 0 || nbtdata[3] != 0)
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400649 pr_err("this sResource is not a board resource!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 break;
651 }
652 case NUBUS_RESID_NAME:
653 nubus_get_rsrc_str(board->name, &ent, 64);
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400654 pr_info(" name: %s\n", board->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 break;
656 case NUBUS_RESID_ICON:
657 nubus_get_icon(board, &ent);
658 break;
659 case NUBUS_RESID_BOARDID:
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400660 pr_info(" board id: 0x%x\n", ent.data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 break;
662 case NUBUS_RESID_PRIMARYINIT:
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400663 pr_info(" primary init offset: 0x%06x\n", ent.data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 break;
665 case NUBUS_RESID_VENDORINFO:
666 nubus_get_vendorinfo(board, &ent);
667 break;
668 case NUBUS_RESID_FLAGS:
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400669 pr_info(" flags: 0x%06x\n", ent.data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 break;
671 case NUBUS_RESID_HWDEVID:
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400672 pr_info(" hwdevid: 0x%06x\n", ent.data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 break;
674 case NUBUS_RESID_SECONDINIT:
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400675 pr_info(" secondary init offset: 0x%06x\n", ent.data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 break;
Finn Thainf42e5552017-04-08 19:51:15 -0400677 /* WTF isn't this in the functional resources? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 case NUBUS_RESID_VIDNAMES:
679 nubus_get_vidnames(board, &ent);
680 break;
681 /* Same goes for this */
682 case NUBUS_RESID_VIDMODES:
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400683 pr_info(" video mode parameter directory offset: 0x%06x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 ent.data);
Finn Thainf42e5552017-04-08 19:51:15 -0400685 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 default:
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400687 pr_info(" unknown resource %02X, data 0x%06x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 ent.type, ent.data);
689 }
690 }
691 return 0;
692}
693
694/* Attempt to bypass the somewhat non-obvious arrangement of
695 sResources in the motherboard ROM */
696static void __init nubus_find_rom_dir(struct nubus_board* board)
697{
Finn Thainf42e5552017-04-08 19:51:15 -0400698 unsigned char *rp;
699 unsigned char *romdir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 struct nubus_dir dir;
701 struct nubus_dirent ent;
702
703 /* Check for the extra directory just under the format block */
704 rp = board->fblock;
705 nubus_rewind(&rp, 4, board->lanes);
706 if (nubus_get_rom(&rp, 4, board->lanes) != NUBUS_TEST_PATTERN) {
707 /* OK, the ROM was telling the truth */
708 board->directory = board->fblock;
709 nubus_move(&board->directory,
710 nubus_expand32(board->doffset),
711 board->lanes);
712 return;
713 }
714
715 /* On "slot zero", you have to walk down a few more
716 directories to get to the equivalent of a real card's root
717 directory. We don't know what they were smoking when they
718 came up with this. */
719 romdir = nubus_rom_addr(board->slot);
720 nubus_rewind(&romdir, ROM_DIR_OFFSET, board->lanes);
721 dir.base = dir.ptr = romdir;
722 dir.done = 0;
723 dir.mask = board->lanes;
724
725 /* This one points to an "Unknown Macintosh" directory */
726 if (nubus_readdir(&dir, &ent) == -1)
727 goto badrom;
728
Borislav Petkova8fe19e2014-06-04 16:11:46 -0700729 if (console_loglevel >= CONSOLE_LOGLEVEL_DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 printk(KERN_INFO "nubus_get_rom_dir: entry %02x %06x\n", ent.type, ent.data);
731 /* This one takes us to where we want to go. */
Finn Thainf42e5552017-04-08 19:51:15 -0400732 if (nubus_readdir(&dir, &ent) == -1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 goto badrom;
Borislav Petkova8fe19e2014-06-04 16:11:46 -0700734 if (console_loglevel >= CONSOLE_LOGLEVEL_DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 printk(KERN_DEBUG "nubus_get_rom_dir: entry %02x %06x\n", ent.type, ent.data);
736 nubus_get_subdir(&ent, &dir);
737
738 /* Resource ID 01, also an "Unknown Macintosh" */
Finn Thainf42e5552017-04-08 19:51:15 -0400739 if (nubus_readdir(&dir, &ent) == -1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 goto badrom;
Borislav Petkova8fe19e2014-06-04 16:11:46 -0700741 if (console_loglevel >= CONSOLE_LOGLEVEL_DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 printk(KERN_DEBUG "nubus_get_rom_dir: entry %02x %06x\n", ent.type, ent.data);
743
744 /* FIXME: the first one is *not* always the right one. We
745 suspect this has something to do with the ROM revision.
746 "The HORROR ROM" (LC-series) uses 0x7e, while "The HORROR
747 Continues" (Q630) uses 0x7b. The DAFB Macs evidently use
748 something else. Please run "Slots" on your Mac (see
749 include/linux/nubus.h for where to get this program) and
750 tell us where the 'SiDirPtr' for Slot 0 is. If you feel
751 brave, you should also use MacsBug to walk down the ROM
752 directories like this function does and try to find the
753 path to that address... */
754 if (nubus_readdir(&dir, &ent) == -1)
755 goto badrom;
Borislav Petkova8fe19e2014-06-04 16:11:46 -0700756 if (console_loglevel >= CONSOLE_LOGLEVEL_DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 printk(KERN_DEBUG "nubus_get_rom_dir: entry %02x %06x\n", ent.type, ent.data);
Finn Thainf42e5552017-04-08 19:51:15 -0400758
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 /* Bwahahahaha... */
760 nubus_get_subdir(&ent, &dir);
761 board->directory = dir.base;
762 return;
Finn Thainf42e5552017-04-08 19:51:15 -0400763
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 /* Even more evil laughter... */
765 badrom:
766 board->directory = board->fblock;
767 nubus_move(&board->directory, nubus_expand32(board->doffset), board->lanes);
768 printk(KERN_ERR "nubus_get_rom_dir: ROM weirdness! Notify the developers...\n");
769}
770
771/* Add a board (might be many devices) to the list */
Finn Thainf42e5552017-04-08 19:51:15 -0400772static struct nubus_board * __init nubus_add_board(int slot, int bytelanes)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773{
Finn Thainf42e5552017-04-08 19:51:15 -0400774 struct nubus_board *board;
775 struct nubus_board **boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 unsigned char *rp;
777 unsigned long dpat;
778 struct nubus_dir dir;
779 struct nubus_dirent ent;
780
781 /* Move to the start of the format block */
Finn Thainf42e5552017-04-08 19:51:15 -0400782 rp = nubus_rom_addr(slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 nubus_rewind(&rp, FORMAT_BLOCK_SIZE, bytelanes);
784
785 /* Actually we should probably panic if this fails */
Yoann Padioleaudd00cc42007-07-19 01:49:03 -0700786 if ((board = kzalloc(sizeof(*board), GFP_ATOMIC)) == NULL)
Finn Thainf42e5552017-04-08 19:51:15 -0400787 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 board->fblock = rp;
789
790 /* Dump the format block for debugging purposes */
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400791 pr_debug("Slot %X, format block at 0x%p:\n", slot, rp);
792 pr_debug("%02lx\n", nubus_get_rom(&rp, 1, bytelanes));
793 pr_debug("%02lx\n", nubus_get_rom(&rp, 1, bytelanes));
794 pr_debug("%08lx\n", nubus_get_rom(&rp, 4, bytelanes));
795 pr_debug("%02lx\n", nubus_get_rom(&rp, 1, bytelanes));
796 pr_debug("%02lx\n", nubus_get_rom(&rp, 1, bytelanes));
797 pr_debug("%08lx\n", nubus_get_rom(&rp, 4, bytelanes));
798 pr_debug("%08lx\n", nubus_get_rom(&rp, 4, bytelanes));
799 pr_debug("%08lx\n", nubus_get_rom(&rp, 4, bytelanes));
800 rp = board->fblock;
801
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 board->slot = slot;
Finn Thainf42e5552017-04-08 19:51:15 -0400803 board->slot_addr = (unsigned long)nubus_slot_addr(slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 board->doffset = nubus_get_rom(&rp, 4, bytelanes);
805 /* rom_length is *supposed* to be the total length of the
806 * ROM. In practice it is the "amount of ROM used to compute
807 * the CRC." So some jokers decide to set it to zero and
808 * set the crc to zero so they don't have to do any math.
809 * See the Performa 460 ROM, for example. Those Apple "engineers".
810 */
811 board->rom_length = nubus_get_rom(&rp, 4, bytelanes);
812 board->crc = nubus_get_rom(&rp, 4, bytelanes);
813 board->rev = nubus_get_rom(&rp, 1, bytelanes);
Finn Thainf42e5552017-04-08 19:51:15 -0400814 board->format = nubus_get_rom(&rp, 1, bytelanes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 board->lanes = bytelanes;
816
817 /* Directory offset should be small and negative... */
Finn Thainf42e5552017-04-08 19:51:15 -0400818 if (!(board->doffset & 0x00FF0000))
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400819 pr_warn("Dodgy doffset!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 dpat = nubus_get_rom(&rp, 4, bytelanes);
Finn Thainf42e5552017-04-08 19:51:15 -0400821 if (dpat != NUBUS_TEST_PATTERN)
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400822 pr_warn("Wrong test pattern %08lx!\n", dpat);
Finn Thainf42e5552017-04-08 19:51:15 -0400823
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 /*
825 * I wonder how the CRC is meant to work -
826 * any takers ?
827 * CSA: According to MAC docs, not all cards pass the CRC anyway,
828 * since the initial Macintosh ROM releases skipped the check.
829 */
830
831 /* Attempt to work around slot zero weirdness */
832 nubus_find_rom_dir(board);
Finn Thainf42e5552017-04-08 19:51:15 -0400833 nubus_get_root_dir(board, &dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834
835 /* We're ready to rock */
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400836 pr_info("Slot %X:\n", slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837
838 /* Each slot should have one board resource and any number of
839 functional resources. So we'll fill in some fields in the
840 struct nubus_board from the board resource, then walk down
841 the list of functional resources, spinning out a nubus_dev
842 for each of them. */
843 if (nubus_readdir(&dir, &ent) == -1) {
844 /* We can't have this! */
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400845 pr_err("Board resource not found!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 return NULL;
847 } else {
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400848 pr_info(" Board resource:\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 nubus_get_board_resource(board, slot, &ent);
850 }
851
852 /* Aaaarrrrgghh! The LC III motherboard has *two* board
853 resources. I have no idea WTF to do about this. */
854
855 while (nubus_readdir(&dir, &ent) != -1) {
Finn Thainf42e5552017-04-08 19:51:15 -0400856 struct nubus_dev *dev;
857 struct nubus_dev **devp;
858
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 dev = nubus_get_functional_resource(board, slot, &ent);
860 if (dev == NULL)
861 continue;
862
863 /* We zeroed this out above */
864 if (board->first_dev == NULL)
865 board->first_dev = dev;
Finn Thainf42e5552017-04-08 19:51:15 -0400866
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 /* Put it on the global NuBus device chain. Keep entries in order. */
Finn Thainf42e5552017-04-08 19:51:15 -0400868 for (devp = &nubus_devices; *devp != NULL;
869 devp = &((*devp)->next))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 /* spin */;
871 *devp = dev;
Finn Thainf42e5552017-04-08 19:51:15 -0400872 dev->next = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 }
874
875 /* Put it on the global NuBus board chain. Keep entries in order. */
Finn Thainf42e5552017-04-08 19:51:15 -0400876 for (boardp = &nubus_boards; *boardp != NULL;
877 boardp = &((*boardp)->next))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 /* spin */;
879 *boardp = board;
880 board->next = NULL;
Finn Thainf42e5552017-04-08 19:51:15 -0400881
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 return board;
883}
884
885void __init nubus_probe_slot(int slot)
886{
887 unsigned char dp;
Finn Thainf42e5552017-04-08 19:51:15 -0400888 unsigned char *rp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 int i;
890
Finn Thainf42e5552017-04-08 19:51:15 -0400891 rp = nubus_rom_addr(slot);
892 for (i = 4; i; i--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 int card_present;
894
895 rp--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 card_present = hwreg_present(rp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 if (!card_present)
898 continue;
899
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 dp = *rp;
901 if(dp == 0)
902 continue;
903
904 /* The last byte of the format block consists of two
905 nybbles which are "mirror images" of each other.
906 These show us the valid bytelanes */
Finn Thainf42e5552017-04-08 19:51:15 -0400907 if ((((dp >> 4) ^ dp) & 0x0F) != 0x0F)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 continue;
909 /* Check that this value is actually *on* one of the
910 bytelanes it claims are valid! */
Finn Thainf42e5552017-04-08 19:51:15 -0400911 if ((dp & 0x0F) >= (1 << i))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 continue;
913
914 /* Looks promising. Let's put it on the list. */
915 nubus_add_board(slot, dp);
916
917 return;
918 }
919}
920
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921void __init nubus_scan_bus(void)
922{
923 int slot;
Finn Thainf42e5552017-04-08 19:51:15 -0400924
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 /* This might not work on your machine */
926#ifdef I_WANT_TO_PROBE_SLOT_ZERO
927 nubus_probe_slot(0);
928#endif
Finn Thainf42e5552017-04-08 19:51:15 -0400929 for (slot = 9; slot < 15; slot++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 nubus_probe_slot(slot);
931 }
932}
933
934static int __init nubus_init(void)
935{
Finn Thainf42e5552017-04-08 19:51:15 -0400936 if (!MACH_IS_MAC)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 return 0;
938
939 /* Initialize the NuBus interrupts */
940 if (oss_present) {
941 oss_nubus_init();
942 } else {
943 via_nubus_init();
944 }
945
946#ifdef TRY_TO_DODGE_WSOD
947 /* Rogue Ethernet interrupts can kill the machine if we don't
948 do this. Obviously this is bogus. Hopefully the local VIA
949 gurus can fix the real cause of the problem. */
950 mdelay(1000);
951#endif
Finn Thainf42e5552017-04-08 19:51:15 -0400952
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 /* And probe */
David Huggins-Daines71ae40e2017-04-08 19:51:15 -0400954 pr_info("NuBus: Scanning NuBus slots.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955 nubus_devices = NULL;
Finn Thainf42e5552017-04-08 19:51:15 -0400956 nubus_boards = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 nubus_scan_bus();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 nubus_proc_init();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959 return 0;
960}
961
962subsys_initcall(nubus_init);