ppc64: Don't set Kp bit on SLB
[openbios/afaerber.git] / drivers / sbus.c
blob1107c1d6b774c518d551540528c5ce6116065763
1 /*
2 * OpenBIOS SBus driver
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
9 * version 2
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"
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
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
42 typedef struct le_private {
43 uint32_t *dmaregs;
44 uint32_t *regs;
45 } le_private_t;
47 static void
48 ob_sbus_node_init(uint64_t base)
50 void *regs;
52 push_str("/iommu/sbus");
53 fword("find-device");
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");
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");
73 static void
74 ob_le_init(unsigned int slot, uint64_t base, unsigned long leoffset, unsigned long dmaoffset)
76 le_private_t *le;
78 le = malloc(sizeof(le_private_t));
79 if (!le) {
80 DPRINTF("Can't allocate LANCE private structure\n");
81 return;
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;
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");
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");
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;
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");
138 uint16_t graphic_depth;
140 static void
141 ob_tcx_init(unsigned int slot, const char *path)
143 phandle_t chosen, aliases;
145 push_str(path);
146 fword("find-device");
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+");
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);
168 fword("encode-int");
169 fword("encode+");
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);
182 fword("encode-int");
183 fword("encode+");
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+");
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);
206 fword("encode-int");
207 fword("encode+");
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);
220 fword("encode-int");
221 fword("encode+");
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);
234 fword("encode-int");
235 fword("encode+");
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+");
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);
258 fword("encode-int");
259 fword("encode+");
261 PUSH(slot);
262 fword("encode-int");
263 fword("encode+");
264 if (graphic_depth == 24) {
265 PUSH(0x00301000);
266 } else {
267 PUSH(0x00300000);
269 fword("encode-int");
270 fword("encode+");
271 if (graphic_depth == 24) {
272 PUSH(0x00001000);
273 } else {
274 PUSH(0x0000081c);
276 fword("encode-int");
277 fword("encode+");
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+");
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);
300 fword("encode-int");
301 fword("encode+");
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);
314 fword("encode-int");
315 fword("encode+");
317 push_str("reg");
318 fword("property");
320 PUSH((int)graphic_depth);
321 fword("encode-int");
322 push_str("depth");
323 fword("property");
325 if (graphic_depth == 8) {
326 push_str("true");
327 fword("encode-string");
328 push_str("tcx-8-bit");
329 fword("property");
332 chosen = find_dev("/chosen");
333 push_str(path);
334 fword("open-dev");
335 set_int_property(chosen, "screen", POP());
337 aliases = find_dev("/aliases");
338 set_property(aliases, "screen", path, strlen(path) + 1);
341 static void
342 ob_apc_init(unsigned int slot, unsigned long base)
344 push_str("/iommu/sbus");
345 fword("find-device");
346 fword("new-device");
348 push_str("power-management");
349 fword("device-name");
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");
362 fword("finish-device");
365 static void
366 ob_cs4231_init(unsigned int slot)
368 push_str("/iommu/sbus");
369 fword("find-device");
370 fword("new-device");
372 push_str("SUNW,CS4231");
373 fword("device-name");
375 push_str("serial");
376 fword("device-type");
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");
389 PUSH(5);
390 fword("encode-int");
391 PUSH(0);
392 fword("encode-int");
393 fword("encode+");
394 push_str("intr");
395 fword("property");
397 PUSH(5);
398 fword("encode-int");
399 push_str("interrupts");
400 fword("property");
402 push_str("audio");
403 fword("encode-string");
404 push_str("alias");
405 fword("property");
407 fword("finish-device");
410 static void
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);
420 #endif
422 // NCR 92C990, Am7990, Lance. See http://www.amd.com
423 ob_le_init(slot, base, offset + 0x00c00000, offset + 0x00400010);
425 // Parallel port
426 //ob_bpp_init(base);
429 static void
430 sbus_probe_slot_ss5(unsigned int slot, uint64_t base)
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;
451 static void
452 sbus_probe_slot_ss10(unsigned int slot, uint64_t base)
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;
469 static void
470 sbus_probe_slot_ss600mp(unsigned int slot, uint64_t base)
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;
491 static void
492 ob_sbus_open(void)
494 int ret=1;
495 RET ( -ret );
498 static void
499 ob_sbus_close(void)
501 selfword("close-deblocker");
504 static void
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 },
516 struct sbus_offset {
517 int slot, type;
518 uint64_t base;
519 unsigned long size;
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,},
540 static void
541 ob_add_sbus_range(const struct sbus_offset *range, int notfirst)
543 if (!notfirst) {
544 push_str("/iommu/sbus");
545 fword("find-device");
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+");
565 static int
566 ob_sbus_init_ss5(void)
568 unsigned int slot;
569 int notfirst = 0;
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++);
575 push_str("ranges");
576 fword("property");
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);
583 return 0;
586 static int
587 ob_sbus_init_ss10(void)
589 unsigned int slot;
590 int notfirst = 0;
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++);
596 push_str("ranges");
597 fword("property");
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);
604 return 0;
607 static int
608 ob_sbus_init_ss600mp(void)
610 unsigned int slot;
611 int notfirst = 0;
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++);
617 push_str("ranges");
618 fword("property");
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);
625 return 0;
628 int ob_sbus_init(uint64_t base, int machine_id)
630 ob_sbus_node_init(base);
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;