4 * (C) 2004 Stefan Reinauer <stepan@openbios.org>
5 * (C) 2005 Ed Schouten <ed@fxq.nl>
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
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"
21 #define SBUS_REGS 0x28
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
35 #ifdef CONFIG_DEBUG_SBUS
36 #define DPRINTF(fmt, args...) \
37 do { printk(fmt , ##args); } while (0)
39 #define DPRINTF(fmt, args...)
42 typedef struct le_private
{
48 ob_sbus_node_init(uint64_t base
)
52 push_str("/iommu/sbus");
57 PUSH(base
& 0xffffffff);
66 regs
= (void *)ofmem_map_io(base
, SBUS_REGS
);
67 PUSH((unsigned long)regs
);
74 ob_le_init(unsigned int slot
, uint64_t base
, unsigned long leoffset
, unsigned long dmaoffset
)
78 le
= malloc(sizeof(le_private_t
));
80 DPRINTF("Can't allocate LANCE private structure\n");
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");
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.
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;
104 push_str("/iommu/sbus/ledma");
105 fword("find-device");
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");
124 push_str("/iommu/sbus/ledma/le");
125 fword("find-device");
138 uint16_t graphic_depth
;
141 ob_tcx_init(unsigned int slot
, const char *path
)
143 phandle_t chosen
, aliases
;
146 fword("find-device");
163 if (graphic_depth
== 24) {
177 if (graphic_depth
== 24) {
201 if (graphic_depth
== 24) {
215 if (graphic_depth
== 24) {
229 if (graphic_depth
== 24) {
253 if (graphic_depth
== 24) {
264 if (graphic_depth
== 24) {
271 if (graphic_depth
== 24) {
295 if (graphic_depth
== 24) {
309 if (graphic_depth
== 24) {
320 PUSH((int)graphic_depth
);
325 if (graphic_depth
== 8) {
327 fword("encode-string");
328 push_str("tcx-8-bit");
332 chosen
= find_dev("/chosen");
335 set_int_property(chosen
, "screen", POP());
337 aliases
= find_dev("/aliases");
338 set_property(aliases
, "screen", path
, strlen(path
) + 1);
342 ob_apc_init(unsigned int slot
, unsigned long base
)
344 push_str("/iommu/sbus");
345 fword("find-device");
348 push_str("power-management");
349 fword("device-name");
362 fword("finish-device");
366 ob_cs4231_init(unsigned int slot
)
368 push_str("/iommu/sbus");
369 fword("find-device");
372 push_str("SUNW,CS4231");
373 fword("device-name");
376 fword("device-type");
399 push_str("interrupts");
403 fword("encode-string");
407 fword("finish-device");
411 ob_macio_init(unsigned int slot
, uint64_t base
, unsigned long offset
)
413 // All devices were integrated to NCR89C100, see
414 // http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt
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
);
422 // NCR 92C990, Am7990, Lance. See http://www.amd.com
423 ob_le_init(slot
, base
, offset
+ 0x00c00000, offset
+ 0x00400010);
430 sbus_probe_slot_ss5(unsigned int slot
, uint64_t base
)
432 // OpenBIOS and Qemu don't know how to do Sbus probing
435 ob_tcx_init(slot
, "/iommu/sbus/SUNW,tcx");
439 ob_cs4231_init(slot
);
440 // Power management (APC)
441 ob_apc_init(slot
, APC_OFFSET
);
443 case 5: // MACIO: le, esp, bpp
444 ob_macio_init(slot
, base
, 0x08000000);
452 sbus_probe_slot_ss10(unsigned int slot
, uint64_t base
)
454 // OpenBIOS and Qemu don't know how to do Sbus probing
457 ob_tcx_init(slot
, "/iommu/sbus/SUNW,tcx");
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
);
470 sbus_probe_slot_ss600mp(unsigned int slot
, uint64_t base
)
472 // OpenBIOS and Qemu don't know how to do Sbus probing
475 ob_tcx_init(slot
, "/iommu/sbus/SUNW,tcx");
477 case 0xf: // le, esp, bpp, power-management
478 #ifdef CONFIG_DRIVER_ESP
479 ob_esp_init(slot
, base
, SS600MP_ESP
, SS600MP_ESPDMA
);
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
);
501 selfword("close-deblocker");
505 ob_sbus_initialize(void)
510 NODE_METHODS(ob_sbus_node
) = {
511 { NULL
, ob_sbus_initialize
},
512 { "open", ob_sbus_open
},
513 { "close", ob_sbus_close
},
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,},
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,},
541 ob_add_sbus_range(const struct sbus_offset
*range
, int notfirst
)
544 push_str("/iommu/sbus");
545 fword("find-device");
554 PUSH(range
->base
>> 32);
557 PUSH(range
->base
& 0xffffffff);
566 ob_sbus_init_ss5(void)
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
++);
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
);
587 ob_sbus_init_ss10(void)
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
++);
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
);
608 ob_sbus_init_ss600mp(void)
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
++);
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
);
628 int ob_sbus_init(uint64_t base
, int machine_id
)
630 ob_sbus_node_init(base
);
632 switch (machine_id
) {
634 return ob_sbus_init_ss600mp();
636 return ob_sbus_init_ss10();
638 return ob_sbus_init_ss5();