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
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"
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>.
37 /* DECLARE data structures for the nodes. */
38 DECLARE_UNNAMED_NODE( ob_obio
, INSTALL_OPEN
, sizeof(int) );
41 ob_new_obio_device(const char *name
, const char *type
)
57 map_reg(uint64_t base
, uint64_t offset
, unsigned long size
, int map
,
74 addr
= (unsigned long)ofmem_map_io(base
+ offset
, size
);
86 ob_reg(uint64_t base
, uint64_t offset
, unsigned long size
, int map
)
88 return map_reg(base
, offset
, size
, map
, 0);
104 ob_eccmemctl_init(uint64_t base
)
106 uint32_t version
, *regs
;
110 fword("find-device");
113 push_str("eccmemctl");
114 fword("device-name");
121 regs
= (uint32_t *)map_reg(ECC_BASE
, 0, ECC_SIZE
, 1, ECC_BASE
>> 32);
137 fword("encode-string");
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)
150 arch_nvram_get(char *data
)
152 memcpy(data
, &nvram
[NVRAM_OB_START
], NVRAM_OB_SIZE
);
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
;
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");
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
);
192 fword("finish-device");
196 fword("find-device");
198 PUSH((long)&nvram
[NVRAM_IDPROM
]);
200 fword("encode-bytes");
206 ob_fd_init(uint64_t base
, uint64_t offset
, int intr
)
210 ob_new_obio_device("SUNW,fdtwo", "block");
212 addr
= ob_reg(base
, offset
, FD_REGS
, 1);
216 fword("is-deblocker");
218 ob_floppy_init("/obio", "SUNW,fdtwo", 0, addr
);
220 fword("finish-device");
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
;
237 sparc32_reset_all(void)
242 // AUX 2 (Software Powerdown Control) and reset
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");
259 fword("finish-device");
262 volatile struct sun4m_timer_regs
*counter_regs
;
265 ob_counter_init(uint64_t base
, unsigned long offset
)
269 ob_new_obio_device("counter", NULL
);
271 for (i
= 0; i
< SUN4M_NCPU
; i
++) {
274 if (i
!= 0) fword("encode+");
275 PUSH(offset
+ (i
* PAGE_SIZE
));
286 PUSH(offset
+ 0x10000);
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
]);
309 PUSH((unsigned long)&counter_regs
->l10_timer_limit
);
315 fword("finish-device");
318 static volatile struct sun4m_intregs
*intregs
;
321 ob_interrupt_init(uint64_t base
, unsigned long offset
)
325 ob_new_obio_device("interrupt", NULL
);
327 for (i
= 0; i
< SUN4M_NCPU
; i
++) {
330 if (i
!= 0) fword("encode+");
331 PUSH(offset
+ (i
* PAGE_SIZE
));
334 PUSH(INTERRUPT_REGS
);
342 PUSH(offset
+ 0x10000);
345 PUSH(INTERRUPT_REGS
);
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
]);
362 PUSH((unsigned long)&intregs
->tbt
);
368 fword("finish-device");
371 /* SMP CPU boot structure */
379 static struct smp_cfg
*smp_header
;
382 start_cpu(unsigned int pc
, unsigned int context_ptr
, unsigned int context
, int cpu
)
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);
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
));
408 ob_obio_open(__attribute__((unused
))int *idx
)
415 ob_obio_close(__attribute__((unused
))int *idx
)
417 selfword("close-deblocker");
421 ob_obio_initialize(__attribute__((unused
))int *idx
)
424 fword("find-device");
428 fword("device-name");
430 push_str("hierarchical");
431 fword("device-type");
435 push_str("#address-cells");
440 push_str("#size-cells");
443 fword("finish-device");
447 ob_set_obio_ranges(uint64_t base
)
450 fword("find-device");
459 PUSH(base
& 0xffffffff);
470 ob_obio_decodeunit(__attribute__((unused
)) int *idx
)
472 fword("decode-unit-sbus");
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");
503 REGISTER_NAMED_NODE(ob_obio
, "/obio");
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
);
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
);