ppc64: Don't set Kp bit on SLB
[openbios/afaerber.git] / drivers / obio.c
blob3adf9ac803cecdfc7c9ba4f40626efab7d6d7566
1 /*
2 * OpenBIOS Sparc OBIO 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"
19 #include "drivers/drivers.h"
20 #include "arch/common/nvram.h"
21 #include "libopenbios/ofmem.h"
22 #include "obio.h"
23 #include "escc.h"
25 #define PROMDEV_KBD 0 /* input from keyboard */
26 #define PROMDEV_SCREEN 0 /* output to screen */
27 #define PROMDEV_TTYA 1 /* in/out to ttya */
29 /* "NCPU" is an historical name that's now a bit of a misnomer. The sun4m
30 * architecture registers NCPU CPU-specific interrupts along with one
31 * system-wide interrupt, regardless of the number of actual CPUs installed.
32 * See the comment on "NCPU" at <http://stuff.mit.edu/afs/athena/astaff/
33 * project/opssrc/sys.sunos/sun4m/devaddr.h>.
35 #define SUN4M_NCPU 4
37 /* DECLARE data structures for the nodes. */
38 DECLARE_UNNAMED_NODE( ob_obio, INSTALL_OPEN, sizeof(int) );
40 void
41 ob_new_obio_device(const char *name, const char *type)
43 push_str("/obio");
44 fword("find-device");
45 fword("new-device");
47 push_str(name);
48 fword("device-name");
50 if (type) {
51 push_str(type);
52 fword("device-type");
56 static unsigned long
57 map_reg(uint64_t base, uint64_t offset, unsigned long size, int map,
58 int phys_hi)
60 PUSH(phys_hi);
61 fword("encode-int");
62 PUSH(offset);
63 fword("encode-int");
64 fword("encode+");
65 PUSH(size);
66 fword("encode-int");
67 fword("encode+");
68 push_str("reg");
69 fword("property");
71 if (map) {
72 unsigned long addr;
74 addr = (unsigned long)ofmem_map_io(base + offset, size);
76 PUSH(addr);
77 fword("encode-int");
78 push_str("address");
79 fword("property");
80 return addr;
82 return 0;
85 unsigned long
86 ob_reg(uint64_t base, uint64_t offset, unsigned long size, int map)
88 return map_reg(base, offset, size, map, 0);
91 void
92 ob_intr(int intr)
94 PUSH(intr);
95 fword("encode-int");
96 PUSH(0);
97 fword("encode-int");
98 fword("encode+");
99 push_str("intr");
100 fword("property");
103 void
104 ob_eccmemctl_init(uint64_t base)
106 uint32_t version, *regs;
107 const char *mc_type;
109 push_str("/");
110 fword("find-device");
111 fword("new-device");
113 push_str("eccmemctl");
114 fword("device-name");
116 PUSH(0x20);
117 fword("encode-int");
118 push_str("width");
119 fword("property");
121 regs = (uint32_t *)map_reg(ECC_BASE, 0, ECC_SIZE, 1, ECC_BASE >> 32);
123 version = regs[0];
124 switch (version) {
125 case 0x00000000:
126 mc_type = "MCC";
127 break;
128 case 0x10000000:
129 mc_type = "EMC";
130 break;
131 default:
132 case 0x20000000:
133 mc_type = "SMC";
134 break;
136 push_str(mc_type);
137 fword("encode-string");
138 push_str("mc-type");
139 fword("property");
141 fword("finish-device");
144 static unsigned char *nvram;
146 #define NVRAM_OB_START (0)
147 #define NVRAM_OB_SIZE ((NVRAM_IDPROM - NVRAM_OB_START) & ~15)
149 void
150 arch_nvram_get(char *data)
152 memcpy(data, &nvram[NVRAM_OB_START], NVRAM_OB_SIZE);
155 void
156 arch_nvram_put(char *data)
158 memcpy(&nvram[NVRAM_OB_START], data, NVRAM_OB_SIZE);
162 arch_nvram_size(void)
164 return NVRAM_OB_SIZE;
167 void
168 ss5_init(uint64_t base)
170 ob_new_obio_device("slavioconfig", NULL);
172 ob_reg(base, SLAVIO_SCONFIG, SCONFIG_REGS, 0);
174 fword("finish-device");
177 static void
178 ob_nvram_init(uint64_t base, uint64_t offset)
180 ob_new_obio_device("eeprom", NULL);
182 nvram = (unsigned char *)ob_reg(base, offset, NVRAM_SIZE, 1);
184 PUSH((unsigned long)nvram);
185 fword("encode-int");
186 push_str("address");
187 fword("property");
189 push_str("mk48t08");
190 fword("model");
192 fword("finish-device");
194 // Add /idprom
195 push_str("/");
196 fword("find-device");
198 PUSH((long)&nvram[NVRAM_IDPROM]);
199 PUSH(32);
200 fword("encode-bytes");
201 push_str("idprom");
202 fword("property");
205 static void
206 ob_fd_init(uint64_t base, uint64_t offset, int intr)
208 unsigned long addr;
210 ob_new_obio_device("SUNW,fdtwo", "block");
212 addr = ob_reg(base, offset, FD_REGS, 1);
214 ob_intr(intr);
216 fword("is-deblocker");
218 ob_floppy_init("/obio", "SUNW,fdtwo", 0, addr);
220 fword("finish-device");
223 static void
224 ob_auxio_init(uint64_t base, uint64_t offset)
226 ob_new_obio_device("auxio", NULL);
228 ob_reg(base, offset, AUXIO_REGS, 1);
230 fword("finish-device");
233 volatile unsigned char *power_reg;
234 volatile unsigned int *reset_reg;
236 static void
237 sparc32_reset_all(void)
239 *reset_reg = 1;
242 // AUX 2 (Software Powerdown Control) and reset
243 static void
244 ob_aux2_reset_init(uint64_t base, uint64_t offset, int intr)
246 ob_new_obio_device("power", NULL);
248 power_reg = (void *)ob_reg(base, offset, AUXIO2_REGS, 1);
250 // Not in device tree
251 reset_reg = (unsigned int *)ofmem_map_io(base + (uint64_t)SLAVIO_RESET, RESET_REGS);
253 bind_func("sparc32-reset-all", sparc32_reset_all);
254 push_str("' sparc32-reset-all to reset-all");
255 fword("eval");
257 ob_intr(intr);
259 fword("finish-device");
262 volatile struct sun4m_timer_regs *counter_regs;
264 static void
265 ob_counter_init(uint64_t base, unsigned long offset)
267 int i;
269 ob_new_obio_device("counter", NULL);
271 for (i = 0; i < SUN4M_NCPU; i++) {
272 PUSH(0);
273 fword("encode-int");
274 if (i != 0) fword("encode+");
275 PUSH(offset + (i * PAGE_SIZE));
276 fword("encode-int");
277 fword("encode+");
278 PUSH(COUNTER_REGS);
279 fword("encode-int");
280 fword("encode+");
283 PUSH(0);
284 fword("encode-int");
285 fword("encode+");
286 PUSH(offset + 0x10000);
287 fword("encode-int");
288 fword("encode+");
289 PUSH(COUNTER_REGS);
290 fword("encode-int");
291 fword("encode+");
293 push_str("reg");
294 fword("property");
297 counter_regs = (struct sun4m_timer_regs *)ofmem_map_io(base + (uint64_t)offset, sizeof(*counter_regs));
298 counter_regs->cfg = 0xffffffff;
299 counter_regs->l10_timer_limit = 0;
300 counter_regs->cpu_timers[0].l14_timer_limit = 0x9c4000; /* see comment in obio.h */
301 counter_regs->cpu_timers[0].cntrl = 1;
303 for (i = 0; i < SUN4M_NCPU; i++) {
304 PUSH((unsigned long)&counter_regs->cpu_timers[i]);
305 fword("encode-int");
306 if (i != 0)
307 fword("encode+");
309 PUSH((unsigned long)&counter_regs->l10_timer_limit);
310 fword("encode-int");
311 fword("encode+");
312 push_str("address");
313 fword("property");
315 fword("finish-device");
318 static volatile struct sun4m_intregs *intregs;
320 static void
321 ob_interrupt_init(uint64_t base, unsigned long offset)
323 int i;
325 ob_new_obio_device("interrupt", NULL);
327 for (i = 0; i < SUN4M_NCPU; i++) {
328 PUSH(0);
329 fword("encode-int");
330 if (i != 0) fword("encode+");
331 PUSH(offset + (i * PAGE_SIZE));
332 fword("encode-int");
333 fword("encode+");
334 PUSH(INTERRUPT_REGS);
335 fword("encode-int");
336 fword("encode+");
339 PUSH(0);
340 fword("encode-int");
341 fword("encode+");
342 PUSH(offset + 0x10000);
343 fword("encode-int");
344 fword("encode+");
345 PUSH(INTERRUPT_REGS);
346 fword("encode-int");
347 fword("encode+");
349 push_str("reg");
350 fword("property");
352 intregs = (struct sun4m_intregs *)ofmem_map_io(base | (uint64_t)offset, sizeof(*intregs));
353 intregs->clear = ~SUN4M_INT_MASKALL;
354 intregs->cpu_intregs[0].clear = ~0x17fff;
356 for (i = 0; i < SUN4M_NCPU; i++) {
357 PUSH((unsigned long)&intregs->cpu_intregs[i]);
358 fword("encode-int");
359 if (i != 0)
360 fword("encode+");
362 PUSH((unsigned long)&intregs->tbt);
363 fword("encode-int");
364 fword("encode+");
365 push_str("address");
366 fword("property");
368 fword("finish-device");
371 /* SMP CPU boot structure */
372 struct smp_cfg {
373 uint32_t smp_ctx;
374 uint32_t smp_ctxtbl;
375 uint32_t smp_entry;
376 uint32_t valid;
379 static struct smp_cfg *smp_header;
382 start_cpu(unsigned int pc, unsigned int context_ptr, unsigned int context, int cpu)
384 if (!cpu)
385 return -1;
387 cpu &= 7;
389 smp_header->smp_entry = pc;
390 smp_header->smp_ctxtbl = context_ptr;
391 smp_header->smp_ctx = context;
392 smp_header->valid = cpu;
394 intregs->cpu_intregs[cpu].set = SUN4M_SOFT_INT(14);
396 return 0;
399 static void
400 ob_smp_init(unsigned long mem_size)
402 // See arch/sparc32/entry.S for memory layout
403 smp_header = (struct smp_cfg *)ofmem_map_io((uint64_t)(mem_size - 0x100),
404 sizeof(struct smp_cfg));
407 static void
408 ob_obio_open(__attribute__((unused))int *idx)
410 int ret=1;
411 RET ( -ret );
414 static void
415 ob_obio_close(__attribute__((unused))int *idx)
417 selfword("close-deblocker");
420 static void
421 ob_obio_initialize(__attribute__((unused))int *idx)
423 push_str("/");
424 fword("find-device");
425 fword("new-device");
427 push_str("obio");
428 fword("device-name");
430 push_str("hierarchical");
431 fword("device-type");
433 PUSH(2);
434 fword("encode-int");
435 push_str("#address-cells");
436 fword("property");
438 PUSH(1);
439 fword("encode-int");
440 push_str("#size-cells");
441 fword("property");
443 fword("finish-device");
446 static void
447 ob_set_obio_ranges(uint64_t base)
449 push_str("/obio");
450 fword("find-device");
451 PUSH(0);
452 fword("encode-int");
453 PUSH(0);
454 fword("encode-int");
455 fword("encode+");
456 PUSH(base >> 32);
457 fword("encode-int");
458 fword("encode+");
459 PUSH(base & 0xffffffff);
460 fword("encode-int");
461 fword("encode+");
462 PUSH(SLAVIO_SIZE);
463 fword("encode-int");
464 fword("encode+");
465 push_str("ranges");
466 fword("property");
469 static void
470 ob_obio_decodeunit(__attribute__((unused)) int *idx)
472 fword("decode-unit-sbus");
476 static void
477 ob_obio_encodeunit(__attribute__((unused)) int *idx)
479 fword("encode-unit-sbus");
482 NODE_METHODS(ob_obio) = {
483 { NULL, ob_obio_initialize },
484 { "open", ob_obio_open },
485 { "close", ob_obio_close },
486 { "encode-unit", ob_obio_encodeunit },
487 { "decode-unit", ob_obio_decodeunit },
492 ob_obio_init(uint64_t slavio_base, unsigned long fd_offset,
493 unsigned long counter_offset, unsigned long intr_offset,
494 unsigned long aux1_offset, unsigned long aux2_offset,
495 unsigned long mem_size)
498 // All devices were integrated to NCR89C105, see
499 // http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
501 //printk("Initializing OBIO devices...\n");
502 #if 0 // XXX
503 REGISTER_NAMED_NODE(ob_obio, "/obio");
504 device_end();
505 #endif
506 ob_set_obio_ranges(slavio_base);
508 // Zilog Z8530 serial ports, see http://www.zilog.com
509 // Must be before zs@0,0 or Linux won't boot
510 ob_zs_init(slavio_base, SLAVIO_ZS1, ZS_INTR, 0, 0);
512 ob_zs_init(slavio_base, SLAVIO_ZS, ZS_INTR, 1, 1);
514 // M48T08 NVRAM, see http://www.st.com
515 ob_nvram_init(slavio_base, SLAVIO_NVRAM);
517 // 82078 FDC
518 if (fd_offset != (unsigned long) -1)
519 ob_fd_init(slavio_base, fd_offset, FD_INTR);
521 ob_auxio_init(slavio_base, aux1_offset);
523 if (aux2_offset != (unsigned long) -1)
524 ob_aux2_reset_init(slavio_base, aux2_offset, AUXIO2_INTR);
526 ob_counter_init(slavio_base, counter_offset);
528 ob_interrupt_init(slavio_base, intr_offset);
530 ob_smp_init(mem_size);
532 return 0;