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
34 ob_sbus_node_init(uint64_t base
)
38 push_str("/iommu/sbus");
43 PUSH(base
& 0xffffffff);
52 regs
= map_io(base
, SBUS_REGS
);
53 PUSH((unsigned long)regs
);
60 ob_le_init(unsigned int slot
, unsigned long leoffset
, unsigned long dmaoffset
)
62 push_str("/iommu/sbus/ledma");
75 push_str("/iommu/sbus/ledma/le");
89 uint16_t graphic_depth
;
92 ob_tcx_init(unsigned int slot
, const char *path
)
94 phandle_t chosen
, aliases
;
114 if (graphic_depth
== 24) {
128 if (graphic_depth
== 24) {
152 if (graphic_depth
== 24) {
166 if (graphic_depth
== 24) {
180 if (graphic_depth
== 24) {
204 if (graphic_depth
== 24) {
215 if (graphic_depth
== 24) {
222 if (graphic_depth
== 24) {
246 if (graphic_depth
== 24) {
260 if (graphic_depth
== 24) {
271 PUSH((int)graphic_depth
);
276 if (graphic_depth
== 8) {
278 fword("encode-string");
279 push_str("tcx-8-bit");
283 chosen
= find_dev("/chosen");
286 set_int_property(chosen
, "screen", POP());
288 aliases
= find_dev("/aliases");
289 set_property(aliases
, "screen", path
, strlen(path
) + 1);
293 ob_apc_init(unsigned int slot
, unsigned long base
)
295 push_str("/iommu/sbus");
296 fword("find-device");
299 push_str("power-management");
300 fword("device-name");
313 fword("finish-device");
317 ob_cs4231_init(unsigned int slot
)
319 push_str("/iommu/sbus");
320 fword("find-device");
323 push_str("SUNW,CS4231");
324 fword("device-name");
327 fword("device-type");
350 push_str("interrupts");
354 fword("encode-string");
358 fword("finish-device");
362 ob_macio_init(unsigned int slot
, uint64_t base
, unsigned long offset
)
364 // All devices were integrated to NCR89C100, see
365 // http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt
367 // NCR 53c9x, aka ESP. See
368 // http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR53C9X.txt
369 #ifdef CONFIG_DRIVER_ESP
370 ob_esp_init(slot
, base
, offset
+ MACIO_ESP
, offset
+ MACIO_ESPDMA
);
373 // NCR 92C990, Am7990, Lance. See http://www.amd.com
374 ob_le_init(slot
, offset
+ 0x00c00000, offset
+ 0x00400010);
381 sbus_probe_slot_ss5(unsigned int slot
, uint64_t base
)
383 // OpenBIOS and Qemu don't know how to do Sbus probing
386 ob_tcx_init(slot
, "/iommu/sbus/SUNW,tcx");
390 ob_cs4231_init(slot
);
391 // Power management (APC)
392 ob_apc_init(slot
, APC_OFFSET
);
394 case 5: // MACIO: le, esp, bpp
395 ob_macio_init(slot
, base
, 0x08000000);
403 sbus_probe_slot_ss10(unsigned int slot
, uint64_t base
)
405 // OpenBIOS and Qemu don't know how to do Sbus probing
408 ob_tcx_init(slot
, "/iommu/sbus/SUNW,tcx");
410 case 0xf: // le, esp, bpp, power-management
411 ob_macio_init(slot
, base
, 0);
412 // Power management (APC) XXX should not exist
413 ob_apc_init(slot
, APC_OFFSET
);
421 sbus_probe_slot_ss600mp(unsigned int slot
, uint64_t base
)
423 // OpenBIOS and Qemu don't know how to do Sbus probing
426 ob_tcx_init(slot
, "/iommu/sbus/SUNW,tcx");
428 case 0xf: // le, esp, bpp, power-management
429 #ifdef CONFIG_DRIVER_ESP
430 ob_esp_init(slot
, base
, SS600MP_ESP
, SS600MP_ESPDMA
);
432 // NCR 92C990, Am7990, Lance. See http://www.amd.com
433 ob_le_init(slot
, 0x00060000, SS600MP_LEBUFFER
);
434 // Power management (APC) XXX should not exist
435 ob_apc_init(slot
, APC_OFFSET
);
452 selfword("close-deblocker");
456 ob_sbus_initialize(void)
461 NODE_METHODS(ob_sbus_node
) = {
462 { NULL
, ob_sbus_initialize
},
463 { "open", ob_sbus_open
},
464 { "close", ob_sbus_close
},
473 static const struct sbus_offset sbus_offsets_ss5
[SBUS_SLOTS
] = {
474 { 0, 0, 0x20000000, 0x10000000,},
475 { 1, 0, 0x30000000, 0x10000000,},
476 { 2, 0, 0x40000000, 0x10000000,},
477 { 3, 0, 0x50000000, 0x10000000,},
478 { 4, 0, 0x60000000, 0x10000000,},
479 { 5, 0, 0x70000000, 0x10000000,},
482 /* Shared with ss600mp */
483 static const struct sbus_offset sbus_offsets_ss10
[SBUS_SLOTS
] = {
484 { 0, 0, 0xe00000000ULL
, 0x10000000,},
485 { 1, 0, 0xe10000000ULL
, 0x10000000,},
486 { 2, 0, 0xe20000000ULL
, 0x10000000,},
487 { 3, 0, 0xe30000000ULL
, 0x10000000,},
488 [0xf] = { 0xf, 0, 0xef0000000ULL
, 0x10000000,},
492 ob_add_sbus_range(const struct sbus_offset
*range
, int notfirst
)
495 push_str("/iommu/sbus");
496 fword("find-device");
505 PUSH(range
->base
>> 32);
508 PUSH(range
->base
& 0xffffffff);
517 ob_sbus_init_ss5(void)
522 for (slot
= 0; slot
< SBUS_SLOTS
; slot
++) {
523 if (sbus_offsets_ss5
[slot
].size
> 0)
524 ob_add_sbus_range(&sbus_offsets_ss5
[slot
], notfirst
++);
529 for (slot
= 0; slot
< SBUS_SLOTS
; slot
++) {
530 if (sbus_offsets_ss5
[slot
].size
> 0)
531 sbus_probe_slot_ss5(slot
, sbus_offsets_ss5
[slot
].base
);
538 ob_sbus_init_ss10(void)
543 for (slot
= 0; slot
< SBUS_SLOTS
; slot
++) {
544 if (sbus_offsets_ss10
[slot
].size
> 0)
545 ob_add_sbus_range(&sbus_offsets_ss10
[slot
], notfirst
++);
550 for (slot
= 0; slot
< SBUS_SLOTS
; slot
++) {
551 if (sbus_offsets_ss10
[slot
].size
> 0)
552 sbus_probe_slot_ss10(slot
, sbus_offsets_ss10
[slot
].base
);
559 ob_sbus_init_ss600mp(void)
564 for (slot
= 0; slot
< SBUS_SLOTS
; slot
++) {
565 if (sbus_offsets_ss10
[slot
].size
> 0)
566 ob_add_sbus_range(&sbus_offsets_ss10
[slot
], notfirst
++);
571 for (slot
= 0; slot
< SBUS_SLOTS
; slot
++) {
572 if (sbus_offsets_ss10
[slot
].size
> 0)
573 sbus_probe_slot_ss600mp(slot
, sbus_offsets_ss10
[slot
].base
);
579 int ob_sbus_init(uint64_t base
, int machine_id
)
581 ob_sbus_node_init(base
);
583 switch (machine_id
) {
585 return ob_sbus_init_ss600mp();
587 return ob_sbus_init_ss10();
589 return ob_sbus_init_ss5();