|
|
1.1 root 1: /*
2: * OpenBIOS SBus driver
3: *
4: * (C) 2004 Stefan Reinauer <[email protected]>
5: * (C) 2005 Ed Schouten <[email protected]>
6: *
7: * This program is free software; you can redistribute it and/or
8: * modify it under the terms of the GNU General Public License
9: * version 2
10: *
11: */
12:
13: #include "config.h"
14: #include "libopenbios/bindings.h"
15: #include "kernel/kernel.h"
16: #include "libc/byteorder.h"
17: #include "libc/vsprintf.h"
18: #include "drivers/drivers.h"
19: #include "libopenbios/ofmem.h"
20:
21: #define SBUS_REGS 0x28
22: #define SBUS_SLOTS 16
23: #define APC_REGS 0x10
24: #define APC_OFFSET 0x0a000000ULL
25: #define CS4231_REGS 0x40
26: #define CS4231_OFFSET 0x0c000000ULL
27: #define MACIO_ESPDMA 0x00400000ULL /* ESP DMA controller */
28: #define MACIO_ESP 0x00800000ULL /* ESP SCSI */
29: #define SS600MP_ESPDMA 0x00081000ULL
30: #define SS600MP_ESP 0x00080000ULL
31: #define SS600MP_LEBUFFER (SS600MP_ESPDMA + 0x10) // XXX should be 0x40000
32: #define LEDMA_REGS 0x4
33: #define LE_REGS 0x20
34:
35: #ifdef CONFIG_DEBUG_SBUS
36: #define DPRINTF(fmt, args...) \
37: do { printk(fmt , ##args); } while (0)
38: #else
39: #define DPRINTF(fmt, args...)
40: #endif
41:
42: typedef struct le_private {
43: uint32_t *dmaregs;
44: uint32_t *regs;
45: } le_private_t;
46:
47: static void
48: ob_sbus_node_init(uint64_t base)
49: {
50: void *regs;
51:
52: push_str("/iommu/sbus");
53: fword("find-device");
54:
55: PUSH(base >> 32);
56: fword("encode-int");
57: PUSH(base & 0xffffffff);
58: fword("encode-int");
59: fword("encode+");
60: PUSH(SBUS_REGS);
61: fword("encode-int");
62: fword("encode+");
63: push_str("reg");
64: fword("property");
65:
66: regs = (void *)ofmem_map_io(base, SBUS_REGS);
67: PUSH((unsigned long)regs);
68: fword("encode-int");
69: push_str("address");
70: fword("property");
71: }
72:
73: static void
74: ob_le_init(unsigned int slot, uint64_t base, unsigned long leoffset, unsigned long dmaoffset)
75: {
76: le_private_t *le;
77:
78: le = malloc(sizeof(le_private_t));
79: if (!le) {
80: DPRINTF("Can't allocate LANCE private structure\n");
81: return;
82: }
83:
84: /* Get the IO region for DMA registers */
85: le->dmaregs = (void *)ofmem_map_io(base + (uint64_t)dmaoffset, LEDMA_REGS);
86: if (le->dmaregs == NULL) {
87: DPRINTF("Can't map LANCE DMA registers\n");
88: return;
89: }
90:
91: /* Now it appears that the Solaris kernel forgets to set up the LANCE DMA mapping
92: and so it must inherit the one from OpenBIOS. The symptom of this is that the
93: LANCE DMA base addr register is still zero, and so we start sending network
94: packets containing random areas of memory.
95:
96: The correct fix for this should be to use dvma_alloc() to grab a section of
97: memory and point the LANCE DMA buffers to use that instead; this gets
98: slightly further but still crashes. Time-consuming investigation on various
99: hacked versions of QEMU seems to indicate that Solaris always assumes the LANCE
100: DMA base address is fixed 0xff000000 when setting up the IOMMU for the LANCE
101: card. Hence we imitate this behaviour here. */
102: le->dmaregs[3] = 0xff000000;
103:
104: push_str("/iommu/sbus/ledma");
105: fword("find-device");
106: PUSH(slot);
107: fword("encode-int");
108: PUSH(dmaoffset);
109: fword("encode-int");
110: fword("encode+");
111: PUSH(0x00000020);
112: fword("encode-int");
113: fword("encode+");
114: push_str("reg");
115: fword("property");
116:
117: /* Get the IO region for Lance registers */
118: le->regs = (void *)ofmem_map_io(base + (uint64_t)leoffset, LE_REGS);
119: if (le->regs == NULL) {
120: DPRINTF("Can't map LANCE registers\n");
121: return;
122: }
123:
124: push_str("/iommu/sbus/ledma/le");
125: fword("find-device");
126: PUSH(slot);
127: fword("encode-int");
128: PUSH(leoffset);
129: fword("encode-int");
130: fword("encode+");
131: PUSH(0x00000004);
132: fword("encode-int");
133: fword("encode+");
134: push_str("reg");
135: fword("property");
136: }
137:
138: uint16_t graphic_depth;
139:
140: static void
141: ob_tcx_init(unsigned int slot, const char *path)
142: {
143: phandle_t chosen, aliases;
144:
145: push_str(path);
146: fword("find-device");
147:
148: PUSH(slot);
149: fword("encode-int");
150: PUSH(0x00800000);
151: fword("encode-int");
152: fword("encode+");
153: PUSH(0x00100000);
154: fword("encode-int");
155: fword("encode+");
156:
157: PUSH(slot);
158: fword("encode-int");
159: fword("encode+");
160: PUSH(0x02000000);
161: fword("encode-int");
162: fword("encode+");
163: if (graphic_depth == 24) {
164: PUSH(0x00400000);
165: } else {
166: PUSH(0x00000001);
167: }
168: fword("encode-int");
169: fword("encode+");
170:
171: PUSH(slot);
172: fword("encode-int");
173: fword("encode+");
174: PUSH(0x04000000);
175: fword("encode-int");
176: fword("encode+");
177: if (graphic_depth == 24) {
178: PUSH(0x00400000);
179: } else {
180: PUSH(0x00000001);
181: }
182: fword("encode-int");
183: fword("encode+");
184:
185: PUSH(slot);
186: fword("encode-int");
187: fword("encode+");
188: PUSH(0x06000000);
189: fword("encode-int");
190: fword("encode+");
191: PUSH(0x00800000);
192: fword("encode-int");
193: fword("encode+");
194:
195: PUSH(slot);
196: fword("encode-int");
197: fword("encode+");
198: PUSH(0x0a000000);
199: fword("encode-int");
200: fword("encode+");
201: if (graphic_depth == 24) {
202: PUSH(0x00400000);
203: } else {
204: PUSH(0x00000001);
205: }
206: fword("encode-int");
207: fword("encode+");
208:
209: PUSH(slot);
210: fword("encode-int");
211: fword("encode+");
212: PUSH(0x0c000000);
213: fword("encode-int");
214: fword("encode+");
215: if (graphic_depth == 24) {
216: PUSH(0x00800000);
217: } else {
218: PUSH(0x00000001);
219: }
220: fword("encode-int");
221: fword("encode+");
222:
223: PUSH(slot);
224: fword("encode-int");
225: fword("encode+");
226: PUSH(0x0e000000);
227: fword("encode-int");
228: fword("encode+");
229: if (graphic_depth == 24) {
230: PUSH(0x00800000);
231: } else {
232: PUSH(0x00000001);
233: }
234: fword("encode-int");
235: fword("encode+");
236:
237: PUSH(slot);
238: fword("encode-int");
239: fword("encode+");
240: PUSH(0x00700000);
241: fword("encode-int");
242: fword("encode+");
243: PUSH(0x00001000);
244: fword("encode-int");
245: fword("encode+");
246:
247: PUSH(slot);
248: fword("encode-int");
249: fword("encode+");
250: PUSH(0x00200000);
251: fword("encode-int");
252: fword("encode+");
253: if (graphic_depth == 24) {
254: PUSH(0x00004000);
255: } else {
256: PUSH(0x00000004);
257: }
258: fword("encode-int");
259: fword("encode+");
260:
261: PUSH(slot);
262: fword("encode-int");
263: fword("encode+");
264: if (graphic_depth == 24) {
265: PUSH(0x00301000);
266: } else {
267: PUSH(0x00300000);
268: }
269: fword("encode-int");
270: fword("encode+");
271: if (graphic_depth == 24) {
272: PUSH(0x00001000);
273: } else {
274: PUSH(0x0000081c);
275: }
276: fword("encode-int");
277: fword("encode+");
278:
279: PUSH(slot);
280: fword("encode-int");
281: fword("encode+");
282: PUSH(0x00000000);
283: fword("encode-int");
284: fword("encode+");
285: PUSH(0x00010000);
286: fword("encode-int");
287: fword("encode+");
288:
289: PUSH(slot);
290: fword("encode-int");
291: fword("encode+");
292: PUSH(0x00240000);
293: fword("encode-int");
294: fword("encode+");
295: if (graphic_depth == 24) {
296: PUSH(0x00004000);
297: } else {
298: PUSH(0x00000004);
299: }
300: fword("encode-int");
301: fword("encode+");
302:
303: PUSH(slot);
304: fword("encode-int");
305: fword("encode+");
306: PUSH(0x00280000);
307: fword("encode-int");
308: fword("encode+");
309: if (graphic_depth == 24) {
310: PUSH(0x00008000);
311: } else {
312: PUSH(0x00000001);
313: }
314: fword("encode-int");
315: fword("encode+");
316:
317: push_str("reg");
318: fword("property");
319:
320: PUSH((int)graphic_depth);
321: fword("encode-int");
322: push_str("depth");
323: fword("property");
324:
325: if (graphic_depth == 8) {
326: push_str("true");
327: fword("encode-string");
328: push_str("tcx-8-bit");
329: fword("property");
330: }
331:
332: chosen = find_dev("/chosen");
333: push_str(path);
334: fword("open-dev");
335: set_int_property(chosen, "screen", POP());
336:
337: aliases = find_dev("/aliases");
338: set_property(aliases, "screen", path, strlen(path) + 1);
339: }
340:
341: static void
342: ob_apc_init(unsigned int slot, unsigned long base)
343: {
344: push_str("/iommu/sbus");
345: fword("find-device");
346: fword("new-device");
347:
348: push_str("power-management");
349: fword("device-name");
350:
351: PUSH(slot);
352: fword("encode-int");
353: PUSH(base);
354: fword("encode-int");
355: fword("encode+");
356: PUSH(APC_REGS);
357: fword("encode-int");
358: fword("encode+");
359: push_str("reg");
360: fword("property");
361:
362: fword("finish-device");
363: }
364:
365: static void
366: ob_cs4231_init(unsigned int slot)
367: {
368: push_str("/iommu/sbus");
369: fword("find-device");
370: fword("new-device");
371:
372: push_str("SUNW,CS4231");
373: fword("device-name");
374:
375: push_str("serial");
376: fword("device-type");
377:
378: PUSH(slot);
379: fword("encode-int");
380: PUSH(CS4231_OFFSET);
381: fword("encode-int");
382: fword("encode+");
383: PUSH(CS4231_REGS);
384: fword("encode-int");
385: fword("encode+");
386: push_str("reg");
387: fword("property");
388:
389: PUSH(5);
390: fword("encode-int");
391: PUSH(0);
392: fword("encode-int");
393: fword("encode+");
394: push_str("intr");
395: fword("property");
396:
397: PUSH(5);
398: fword("encode-int");
399: push_str("interrupts");
400: fword("property");
401:
402: push_str("audio");
403: fword("encode-string");
404: push_str("alias");
405: fword("property");
406:
407: fword("finish-device");
408: }
409:
410: static void
411: ob_macio_init(unsigned int slot, uint64_t base, unsigned long offset)
412: {
413: // All devices were integrated to NCR89C100, see
414: // http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt
415:
416: // NCR 53c9x, aka ESP. See
417: // http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR53C9X.txt
418: #ifdef CONFIG_DRIVER_ESP
419: ob_esp_init(slot, base, offset + MACIO_ESP, offset + MACIO_ESPDMA);
420: #endif
421:
422: // NCR 92C990, Am7990, Lance. See http://www.amd.com
423: ob_le_init(slot, base, offset + 0x00c00000, offset + 0x00400010);
424:
425: // Parallel port
426: //ob_bpp_init(base);
427: }
428:
429: static void
430: sbus_probe_slot_ss5(unsigned int slot, uint64_t base)
431: {
432: // OpenBIOS and Qemu don't know how to do Sbus probing
433: switch(slot) {
434: case 3: // SUNW,tcx
435: ob_tcx_init(slot, "/iommu/sbus/SUNW,tcx");
436: break;
437: case 4:
438: // SUNW,CS4231
439: ob_cs4231_init(slot);
440: // Power management (APC)
441: ob_apc_init(slot, APC_OFFSET);
442: break;
443: case 5: // MACIO: le, esp, bpp
444: ob_macio_init(slot, base, 0x08000000);
445: break;
446: default:
447: break;
448: }
449: }
450:
451: static void
452: sbus_probe_slot_ss10(unsigned int slot, uint64_t base)
453: {
454: // OpenBIOS and Qemu don't know how to do Sbus probing
455: switch(slot) {
456: case 2: // SUNW,tcx
457: ob_tcx_init(slot, "/iommu/sbus/SUNW,tcx");
458: break;
459: case 0xf: // le, esp, bpp, power-management
460: ob_macio_init(slot, base, 0);
461: // Power management (APC) XXX should not exist
462: ob_apc_init(slot, APC_OFFSET);
463: break;
464: default:
465: break;
466: }
467: }
468:
469: static void
470: sbus_probe_slot_ss600mp(unsigned int slot, uint64_t base)
471: {
472: // OpenBIOS and Qemu don't know how to do Sbus probing
473: switch(slot) {
474: case 2: // SUNW,tcx
475: ob_tcx_init(slot, "/iommu/sbus/SUNW,tcx");
476: break;
477: case 0xf: // le, esp, bpp, power-management
478: #ifdef CONFIG_DRIVER_ESP
479: ob_esp_init(slot, base, SS600MP_ESP, SS600MP_ESPDMA);
480: #endif
481: // NCR 92C990, Am7990, Lance. See http://www.amd.com
482: ob_le_init(slot, base, 0x00060000, SS600MP_LEBUFFER);
483: // Power management (APC) XXX should not exist
484: ob_apc_init(slot, APC_OFFSET);
485: break;
486: default:
487: break;
488: }
489: }
490:
491: static void
492: ob_sbus_open(void)
493: {
494: int ret=1;
495: RET ( -ret );
496: }
497:
498: static void
499: ob_sbus_close(void)
500: {
501: selfword("close-deblocker");
502: }
503:
504: static void
505: ob_sbus_initialize(void)
506: {
507: }
508:
509:
510: NODE_METHODS(ob_sbus_node) = {
511: { NULL, ob_sbus_initialize },
512: { "open", ob_sbus_open },
513: { "close", ob_sbus_close },
514: };
515:
516: struct sbus_offset {
517: int slot, type;
518: uint64_t base;
519: unsigned long size;
520: };
521:
522: static const struct sbus_offset sbus_offsets_ss5[SBUS_SLOTS] = {
523: { 0, 0, 0x20000000, 0x10000000,},
524: { 1, 0, 0x30000000, 0x10000000,},
525: { 2, 0, 0x40000000, 0x10000000,},
526: { 3, 0, 0x50000000, 0x10000000,},
527: { 4, 0, 0x60000000, 0x10000000,},
528: { 5, 0, 0x70000000, 0x10000000,},
529: };
530:
531: /* Shared with ss600mp */
532: static const struct sbus_offset sbus_offsets_ss10[SBUS_SLOTS] = {
533: { 0, 0, 0xe00000000ULL, 0x10000000,},
534: { 1, 0, 0xe10000000ULL, 0x10000000,},
535: { 2, 0, 0xe20000000ULL, 0x10000000,},
536: { 3, 0, 0xe30000000ULL, 0x10000000,},
537: [0xf] = { 0xf, 0, 0xef0000000ULL, 0x10000000,},
538: };
539:
540: static void
541: ob_add_sbus_range(const struct sbus_offset *range, int notfirst)
542: {
543: if (!notfirst) {
544: push_str("/iommu/sbus");
545: fword("find-device");
546: }
547: PUSH(range->slot);
548: fword("encode-int");
549: if (notfirst)
550: fword("encode+");
551: PUSH(range->type);
552: fword("encode-int");
553: fword("encode+");
554: PUSH(range->base >> 32);
555: fword("encode-int");
556: fword("encode+");
557: PUSH(range->base & 0xffffffff);
558: fword("encode-int");
559: fword("encode+");
560: PUSH(range->size);
561: fword("encode-int");
562: fword("encode+");
563: }
564:
565: static int
566: ob_sbus_init_ss5(void)
567: {
568: unsigned int slot;
569: int notfirst = 0;
570:
571: for (slot = 0; slot < SBUS_SLOTS; slot++) {
572: if (sbus_offsets_ss5[slot].size > 0)
573: ob_add_sbus_range(&sbus_offsets_ss5[slot], notfirst++);
574: }
575: push_str("ranges");
576: fword("property");
577:
578: for (slot = 0; slot < SBUS_SLOTS; slot++) {
579: if (sbus_offsets_ss5[slot].size > 0)
580: sbus_probe_slot_ss5(slot, sbus_offsets_ss5[slot].base);
581: }
582:
583: return 0;
584: }
585:
586: static int
587: ob_sbus_init_ss10(void)
588: {
589: unsigned int slot;
590: int notfirst = 0;
591:
592: for (slot = 0; slot < SBUS_SLOTS; slot++) {
593: if (sbus_offsets_ss10[slot].size > 0)
594: ob_add_sbus_range(&sbus_offsets_ss10[slot], notfirst++);
595: }
596: push_str("ranges");
597: fword("property");
598:
599: for (slot = 0; slot < SBUS_SLOTS; slot++) {
600: if (sbus_offsets_ss10[slot].size > 0)
601: sbus_probe_slot_ss10(slot, sbus_offsets_ss10[slot].base);
602: }
603:
604: return 0;
605: }
606:
607: static int
608: ob_sbus_init_ss600mp(void)
609: {
610: unsigned int slot;
611: int notfirst = 0;
612:
613: for (slot = 0; slot < SBUS_SLOTS; slot++) {
614: if (sbus_offsets_ss10[slot].size > 0)
615: ob_add_sbus_range(&sbus_offsets_ss10[slot], notfirst++);
616: }
617: push_str("ranges");
618: fword("property");
619:
620: for (slot = 0; slot < SBUS_SLOTS; slot++) {
621: if (sbus_offsets_ss10[slot].size > 0)
622: sbus_probe_slot_ss600mp(slot, sbus_offsets_ss10[slot].base);
623: }
624:
625: return 0;
626: }
627:
628: int ob_sbus_init(uint64_t base, int machine_id)
629: {
630: ob_sbus_node_init(base);
631:
632: switch (machine_id) {
633: case 66:
634: return ob_sbus_init_ss600mp();
635: case 64 ... 65:
636: return ob_sbus_init_ss10();
637: case 32 ... 63:
638: return ob_sbus_init_ss5();
639: default:
640: return -1;
641: }
642: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.