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 */
31 ob_new_obio_device(const char *name, const char *type)
47 map_reg(uint64_t base, uint64_t offset, unsigned long size, int map,
64 addr = (unsigned long)ofmem_map_io(base + offset, size);
76 ob_reg(uint64_t base, uint64_t offset, unsigned long size, int map)
78 return map_reg(base, offset, size, map, 0);
94 ob_eccmemctl_init(uint64_t base)
96 uint32_t version, *regs;
100 fword("find-device");
103 push_str("eccmemctl");
104 fword("device-name");
111 regs = (uint32_t *)map_reg(ECC_BASE, 0, ECC_SIZE, 1, ECC_BASE >> 32);
127 fword("encode-string");
131 fword("finish-device");
134 static unsigned char *nvram;
136 #define NVRAM_OB_START (0)
137 #define NVRAM_OB_SIZE ((NVRAM_IDPROM - NVRAM_OB_START) & ~15)
140 arch_nvram_get(char *data)
142 memcpy(data, &nvram[NVRAM_OB_START], NVRAM_OB_SIZE);
146 arch_nvram_put(char *data)
148 memcpy(&nvram[NVRAM_OB_START], data, NVRAM_OB_SIZE);
152 arch_nvram_size(void)
154 return NVRAM_OB_SIZE;
158 ss5_init(uint64_t base)
160 ob_new_obio_device("slavioconfig", NULL);
162 ob_reg(base, SLAVIO_SCONFIG, SCONFIG_REGS, 0);
164 fword("finish-device");
168 ob_nvram_init(uint64_t base, uint64_t offset)
170 ob_new_obio_device("eeprom", NULL);
172 nvram = (unsigned char *)ob_reg(base, offset, NVRAM_SIZE, 1);
174 PUSH((unsigned long)nvram);
182 fword("finish-device");
186 fword("find-device");
188 PUSH((long)&nvram[NVRAM_IDPROM]);
190 fword("encode-bytes");
196 ob_fd_init(uint64_t base, uint64_t offset, int intr)
200 ob_new_obio_device("SUNW,fdtwo", "block");
202 addr = ob_reg(base, offset, FD_REGS, 1);
206 fword("is-deblocker");
208 ob_floppy_init("/obio", "SUNW,fdtwo", 0, addr);
210 fword("finish-device");
214 ob_auxio_init(uint64_t base, uint64_t offset)
216 ob_new_obio_device("auxio", NULL);
218 ob_reg(base, offset, AUXIO_REGS, 1);
220 fword("finish-device");
223 volatile unsigned char *power_reg;
224 volatile unsigned int *reset_reg;
227 sparc32_reset_all(void)
232 // AUX 2 (Software Powerdown Control) and reset
234 ob_aux2_reset_init(uint64_t base, uint64_t offset, int intr)
236 ob_new_obio_device("power", NULL);
238 power_reg = (void *)ob_reg(base, offset, AUXIO2_REGS, 1);
240 // Not in device tree
241 reset_reg = (unsigned int *)ofmem_map_io(base + (uint64_t)SLAVIO_RESET, RESET_REGS);
243 bind_func("sparc32-reset-all", sparc32_reset_all);
244 push_str("' sparc32-reset-all to reset-all");
249 fword("finish-device");
252 volatile struct sun4m_timer_regs *counter_regs;
255 ob_counter_init(uint64_t base, unsigned long offset, int ncpu)
259 ob_new_obio_device("counter", NULL);
261 for (i = 0; i < ncpu; i++) {
264 if (i != 0) fword("encode+");
265 PUSH(offset + (i * PAGE_SIZE));
276 PUSH(offset + 0x10000);
287 counter_regs = (struct sun4m_timer_regs *)ofmem_map_io(base + (uint64_t)offset, sizeof(*counter_regs));
288 counter_regs->cfg = 0xfffffffe;
289 counter_regs->l10_timer_limit = 0;
290 counter_regs->cpu_timers[0].l14_timer_limit = 0x9c4000; /* see comment in obio.h */
291 counter_regs->cpu_timers[0].cntrl = 1;
293 for (i = 0; i < ncpu; i++) {
294 PUSH((unsigned long)&counter_regs->cpu_timers[i]);
299 PUSH((unsigned long)&counter_regs->l10_timer_limit);
305 fword("finish-device");
308 static volatile struct sun4m_intregs *intregs;
311 ob_interrupt_init(uint64_t base, unsigned long offset, int ncpu)
315 ob_new_obio_device("interrupt", NULL);
317 for (i = 0; i < ncpu; i++) {
320 if (i != 0) fword("encode+");
321 PUSH(offset + (i * PAGE_SIZE));
324 PUSH(INTERRUPT_REGS);
332 PUSH(offset + 0x10000);
335 PUSH(INTERRUPT_REGS);
342 intregs = (struct sun4m_intregs *)ofmem_map_io(base | (uint64_t)offset, sizeof(*intregs));
343 intregs->clear = ~SUN4M_INT_MASKALL;
344 intregs->cpu_intregs[0].clear = ~0x17fff;
346 for (i = 0; i < ncpu; i++) {
347 PUSH((unsigned long)&intregs->cpu_intregs[i]);
352 PUSH((unsigned long)&intregs->tbt);
358 fword("finish-device");
361 /* SMP CPU boot structure */
369 static struct smp_cfg *smp_header;
372 start_cpu(unsigned int pc, unsigned int context_ptr, unsigned int context, int cpu)
379 smp_header->smp_entry = pc;
380 smp_header->smp_ctxtbl = context_ptr;
381 smp_header->smp_ctx = context;
382 smp_header->valid = cpu;
384 intregs->cpu_intregs[cpu].set = SUN4M_SOFT_INT(14);
390 ob_smp_init(unsigned long mem_size)
392 // See arch/sparc32/entry.S for memory layout
393 smp_header = (struct smp_cfg *)ofmem_map_io((uint64_t)(mem_size - 0x100),
394 sizeof(struct smp_cfg));
398 ob_set_obio_ranges(uint64_t base)
401 fword("find-device");
410 PUSH(base & 0xffffffff);
422 ob_obio_init(uint64_t slavio_base, unsigned long fd_offset,
423 unsigned long counter_offset, unsigned long intr_offset,
424 int intr_ncpu, unsigned long aux1_offset, unsigned long aux2_offset,
425 unsigned long mem_size)
428 // All devices were integrated to NCR89C105, see
429 // http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
431 //printk("Initializing OBIO devices...\n");
432 ob_set_obio_ranges(slavio_base);
434 // Zilog Z8530 serial ports, see http://www.zilog.com
435 // Must be before zs@0,0 or Linux won't boot
436 ob_zs_init(slavio_base, SLAVIO_ZS1, ZS_INTR, 0, 0);
438 ob_zs_init(slavio_base, SLAVIO_ZS, ZS_INTR, 1, 1);
440 // M48T08 NVRAM, see http://www.st.com
441 ob_nvram_init(slavio_base, SLAVIO_NVRAM);
444 if (fd_offset != (unsigned long) -1)
445 ob_fd_init(slavio_base, fd_offset, FD_INTR);
447 ob_auxio_init(slavio_base, aux1_offset);
449 if (aux2_offset != (unsigned long) -1)
450 ob_aux2_reset_init(slavio_base, aux2_offset, AUXIO2_INTR);
452 ob_counter_init(slavio_base, counter_offset, intr_ncpu);
454 ob_interrupt_init(slavio_base, intr_offset, intr_ncpu);
456 ob_smp_init(mem_size);