1 /* tag: openbios forth environment, executable code
3 * Copyright (C) 2003 Patrick Mauritz, Stefan Reinauer
5 * See the file "COPYING" for further information about
6 * the copyright and warranty status of this work.
10 #include "libopenbios/openbios.h"
11 #include "libopenbios/bindings.h"
12 #include "libopenbios/console.h"
13 #include "drivers/drivers.h"
15 #include "arch/common/nvram.h"
16 #include "packages/nvram.h"
17 #include "libopenbios/sys_info.h"
19 #include "drivers/pci.h"
22 #include "../../drivers/timer.h" // XXX
23 #define NO_QEMU_PROTOS
24 #include "arch/common/fw_cfg.h"
25 #include "arch/sparc64/ofmem_sparc64.h"
28 #define UUID_FMT "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x"
30 #define APB_SPECIAL_BASE 0x1fe00000000ULL
31 #define APB_MEM_BASE 0x1ff00000000ULL
33 #define MEMORY_SIZE (512*1024) /* 512K ram for hosted system */
36 #define NVRAM_BASE 0x2000
37 #define NVRAM_SIZE 0x2000
38 #define NVRAM_IDPROM 0x1fd8
39 #define NVRAM_IDPROM_SIZE 32
40 #define NVRAM_OB_START (0)
41 #define NVRAM_OB_SIZE ((NVRAM_IDPROM - NVRAM_OB_START) & ~15)
43 static uint8_t idprom[NVRAM_IDPROM_SIZE];
47 uint16_t machine_id_low, machine_id_high;
50 static const struct hwdef hwdefs[] = {
54 .vendor_id = PCI_VENDOR_ID_SUN,
55 .device_id = PCI_DEVICE_ID_SUN_SABRE,
56 .cfg_addr = APB_SPECIAL_BASE + 0x1000000ULL, // PCI bus configuration space
57 .cfg_data = APB_MEM_BASE, // PCI bus memory space
58 .cfg_base = APB_SPECIAL_BASE,
60 .host_pci_base = APB_MEM_BASE,
61 .pci_mem_base = 0x100000, /* avoid VGA at 0xa0000 */
62 .mem_len = 0x10000000,
63 .io_base = APB_SPECIAL_BASE + 0x2000000ULL, // PCI Bus I/O space
65 .irqs = { 0, 1, 2, 3 },
68 .machine_id_high = 255,
73 unsigned long iu_version;
75 unsigned long ecache_associativity;
76 unsigned long ecache_line_size;
77 unsigned long ecache_size;
78 unsigned long num_dtlb_entries;
79 unsigned long dcache_associativity;
80 unsigned long dcache_line_size;
81 unsigned long dcache_size;
82 unsigned long num_itlb_entries;
83 unsigned long icache_associativity;
84 unsigned long icache_line_size;
85 unsigned long icache_size;
92 extern volatile uint64_t client_tba;
101 /* Update client_tba to be updated on CIF exit */
105 /* Reset control register is defined in 17.2.7.3 of US IIi User Manual */
107 sparc64_reset_all(void)
109 unsigned long addr = 0x1fe0000f020ULL;
110 unsigned long val = 1 << 29;
112 asm("stxa %0, [%1] 0x15\n\t"
113 : : "r" (val), "r" (addr) : "memory");
116 /* PCI Target Address Space Register (see UltraSPARC IIi User's Manual
118 #define PBM_PCI_TARGET_AS 0x2028
119 #define PBM_PCI_TARGET_AS_CD_ENABLE 0x40
122 sparc64_set_tas_register(unsigned long val)
124 unsigned long addr = APB_SPECIAL_BASE + PBM_PCI_TARGET_AS;
126 asm("stxa %0, [%1] 0x15\n\t"
127 : : "r" (val), "r" (addr) : "memory");
130 static void cpu_generic_init(const struct cpudef *cpu, uint32_t clock_frequency)
132 unsigned long iu_version;
135 fword("find-device");
140 fword("device-name");
143 fword("device-type");
145 asm("rdpr %%ver, %0\n"
146 : "=r"(iu_version) :);
148 PUSH((iu_version >> 48) & 0xff);
150 push_str("manufacturer#");
153 PUSH((iu_version >> 32) & 0xff);
155 push_str("implementation#");
158 PUSH((iu_version >> 24) & 0xff);
165 push_str("sparc-version");
175 push_str("upa-portid");
178 PUSH(clock_frequency);
180 push_str("clock-frequency");
183 PUSH(cpu->ecache_associativity);
185 push_str("ecache-associativity");
188 PUSH(cpu->ecache_line_size);
190 push_str("ecache-line-size");
193 PUSH(cpu->ecache_size);
195 push_str("ecache-size");
198 PUSH(cpu->dcache_associativity);
200 push_str("dcache-associativity");
203 PUSH(cpu->dcache_line_size);
205 push_str("dcache-line-size");
208 PUSH(cpu->dcache_size);
210 push_str("dcache-size");
213 PUSH(cpu->icache_associativity);
215 push_str("icache-associativity");
218 PUSH(cpu->ecache_line_size);
220 push_str("icache-line-size");
223 PUSH(cpu->ecache_size);
225 push_str("icache-size");
228 PUSH(cpu->num_itlb_entries);
230 push_str("#itlb-entries");
233 PUSH(cpu->num_dtlb_entries);
235 push_str("#dtlb-entries");
238 fword("finish-device");
241 push_str("/openprom/client-services");
242 fword("find-device");
243 bind_func("SUNW,set-trap-table", set_trap_table);
246 bind_func("sparc64-reset-all", sparc64_reset_all);
247 push_str("' sparc64-reset-all to reset-all");
251 static const struct cpudef sparc_defs[] = {
253 .iu_version = (0x04ULL << 48) | (0x02ULL << 32),
257 .iu_version = (0x04ULL << 48) | (0x03ULL << 32),
258 .name = "FJSV,GPUSK",
261 .iu_version = (0x04ULL << 48) | (0x04ULL << 32),
262 .name = "FJSV,GPUSC",
265 .iu_version = (0x04ULL << 48) | (0x05ULL << 32),
266 .name = "FJSV,GPUZC",
269 .iu_version = (0x17ULL << 48) | (0x10ULL << 32),
270 .name = "SUNW,UltraSPARC",
271 .ecache_associativity = 1, .ecache_line_size = 0x40, .ecache_size = 0x100000,
272 .dcache_associativity = 1, .dcache_line_size = 0x20, .dcache_size = 0x4000,
273 .icache_associativity = 2, .icache_line_size = 0x20, .icache_size = 0x4000,
274 .num_dtlb_entries = 0x40, .num_itlb_entries = 0x40,
277 .iu_version = (0x17ULL << 48) | (0x11ULL << 32),
278 .name = "SUNW,UltraSPARC-II",
279 .ecache_associativity = 1, .ecache_line_size = 0x40, .ecache_size = 0x100000,
280 .dcache_associativity = 1, .dcache_line_size = 0x20, .dcache_size = 0x4000,
281 .icache_associativity = 2, .icache_line_size = 0x20, .icache_size = 0x4000,
282 .num_dtlb_entries = 0x40, .num_itlb_entries = 0x40,
285 .iu_version = (0x17ULL << 48) | (0x12ULL << 32),
286 .name = "SUNW,UltraSPARC-IIi",
287 .ecache_associativity = 1, .ecache_line_size = 0x40, .ecache_size = 0x40000,
288 .dcache_associativity = 1, .dcache_line_size = 0x20, .dcache_size = 0x4000,
289 .icache_associativity = 2, .icache_line_size = 0x20, .icache_size = 0x4000,
290 .num_dtlb_entries = 0x40, .num_itlb_entries = 0x40,
293 .iu_version = (0x17ULL << 48) | (0x13ULL << 32),
294 .name = "SUNW,UltraSPARC-IIe",
297 .iu_version = (0x3eULL << 48) | (0x14ULL << 32),
298 .name = "SUNW,UltraSPARC-III",
301 .iu_version = (0x3eULL << 48) | (0x15ULL << 32),
302 .name = "SUNW,UltraSPARC-III+",
305 .iu_version = (0x3eULL << 48) | (0x16ULL << 32),
306 .name = "SUNW,UltraSPARC-IIIi",
309 .iu_version = (0x3eULL << 48) | (0x18ULL << 32),
310 .name = "SUNW,UltraSPARC-IV",
313 .iu_version = (0x3eULL << 48) | (0x19ULL << 32),
314 .name = "SUNW,UltraSPARC-IV+",
317 .iu_version = (0x3eULL << 48) | (0x22ULL << 32),
318 .name = "SUNW,UltraSPARC-IIIi+",
321 .iu_version = (0x3eULL << 48) | (0x23ULL << 32),
322 .name = "SUNW,UltraSPARC-T1",
325 .iu_version = (0x3eULL << 48) | (0x24ULL << 32),
326 .name = "SUNW,UltraSPARC-T2",
329 .iu_version = (0x22ULL << 48) | (0x10ULL << 32),
330 .name = "SUNW,UltraSPARC",
334 static const struct cpudef *
337 unsigned long iu_version;
340 asm("rdpr %%ver, %0\n"
341 : "=r"(iu_version) :);
342 iu_version &= 0xffffffff00000000ULL;
344 for (i = 0; i < sizeof(sparc_defs)/sizeof(struct cpudef); i++) {
345 if (iu_version == sparc_defs[i].iu_version)
346 return &sparc_defs[i];
348 printk("Unknown cpu (psr %lx), freezing!\n", iu_version);
352 static void nvram_read(uint16_t offset, char *buf, unsigned int nbytes)
356 for (i = 0; i < nbytes; i++) {
357 buf[i] = inb(NVRAM_BASE + offset + i);
361 static void nvram_write(uint16_t offset, const char *buf, unsigned int nbytes)
365 for (i = 0; i < nbytes; i++) {
366 outb(buf[i], NVRAM_BASE + offset + i);
370 static uint8_t qemu_uuid[16];
372 void arch_nvram_get(char *data)
376 const struct cpudef *cpu;
380 uint32_t clock_frequency;
382 const char *stdin_path, *stdout_path;
386 fw_cfg_read(FW_CFG_SIGNATURE, buf, 4);
389 printk("Configuration device id %s", buf);
391 temp = fw_cfg_read_i32(FW_CFG_ID);
392 machine_id = fw_cfg_read_i16(FW_CFG_MACHINE_ID);
394 printk(" version %d machine id %d\n", temp, machine_id);
397 printk("Incompatible configuration device version, freezing\n");
401 kernel_size = fw_cfg_read_i32(FW_CFG_KERNEL_SIZE);
403 kernel_image = fw_cfg_read_i64(FW_CFG_KERNEL_ADDR);
405 size = fw_cfg_read_i32(FW_CFG_CMDLINE_SIZE);
407 obio_cmdline = (char *)malloc(size + 1);
408 fw_cfg_read(FW_CFG_CMDLINE_DATA, obio_cmdline, size);
409 obio_cmdline[size] = '\0';
411 obio_cmdline = strdup("");
413 qemu_cmdline = (uint64_t)obio_cmdline;
415 boot_device = fw_cfg_read_i16(FW_CFG_BOOT_DEVICE);
418 printk("kernel addr %llx size %llx\n", kernel_image, kernel_size);
420 printk("kernel cmdline %s\n", obio_cmdline);
422 nvram_read(NVRAM_OB_START, data, NVRAM_OB_SIZE);
424 temp = fw_cfg_read_i32(FW_CFG_NB_CPUS);
426 printk("CPUs: %x", temp);
428 clock_frequency = 100000000;
432 cpu_generic_init(cpu, clock_frequency);
433 printk(" x %s\n", cpu->name);
436 fw_cfg_read(FW_CFG_UUID, (char *)qemu_uuid, 16);
438 printk("UUID: " UUID_FMT "\n", qemu_uuid[0], qemu_uuid[1], qemu_uuid[2],
439 qemu_uuid[3], qemu_uuid[4], qemu_uuid[5], qemu_uuid[6],
440 qemu_uuid[7], qemu_uuid[8], qemu_uuid[9], qemu_uuid[10],
441 qemu_uuid[11], qemu_uuid[12], qemu_uuid[13], qemu_uuid[14],
445 fword("find-device");
447 PUSH((long)&qemu_uuid);
449 fword("encode-bytes");
454 nvram_read(NVRAM_IDPROM, (char *)idprom, NVRAM_IDPROM_SIZE);
458 fword("encode-bytes");
462 PUSH(500 * 1000 * 1000);
464 push_str("clock-frequency");
467 ram_size = fw_cfg_read_i64(FW_CFG_RAM_SIZE);
469 ob_mmu_init(cpu->name, ram_size);
471 /* Setup nvram variables */
472 push_str("/options");
473 fword("find-device");
475 switch (boot_device) {
477 push_str("/obio/SUNW,fdtwo");
484 push_str("cdrom:f cdrom");
491 fword("encode-string");
492 push_str("boot-device");
495 push_str(obio_cmdline);
496 fword("encode-string");
497 push_str("boot-file");
500 /* Set up other properties */
502 fword("find-device");
504 if (fw_cfg_read_i16(FW_CFG_NOGRAPHIC)) {
505 stdin_path = stdout_path = "ttya";
507 stdin_path = "keyboard";
508 stdout_path = "screen";
511 push_str(stdin_path);
512 push_str("input-device");
515 push_str(stdout_path);
516 push_str("output-device");
520 void arch_nvram_put(char *data)
522 nvram_write(0, data, NVRAM_OB_SIZE);
525 int arch_nvram_size(void)
527 return NVRAM_OB_SIZE;
530 void setup_timers(void)
534 void udelay(unsigned int usecs)
538 for (i = 0; i < usecs * 100; i++);
541 static void init_memory(void)
546 /* Claim the memory from OFMEM (align to 512K so we only take 1 TLB slot) */
547 phys = ofmem_claim_phys(-1, MEMORY_SIZE, PAGE_SIZE_512K);
549 printk("panic: not enough physical memory on host system.\n");
551 virt = ofmem_claim_virt(-1, MEMORY_SIZE, PAGE_SIZE_512K);
553 printk("panic: not enough virtual memory on host system.\n");
555 /* Generate the mapping (and lock translation into the TLBs) */
556 ofmem_map(phys, virt, MEMORY_SIZE, ofmem_arch_default_translation_mode(phys) | SPITFIRE_TTE_LOCKED);
558 /* we push start and end of memory to the stack
559 * so that it can be used by the forth word QUIT
560 * to initialize the memory allocator
564 PUSH(virt + MEMORY_SIZE);
567 extern volatile uint64_t *obp_ticks_pointer;
574 #ifdef CONFIG_DRIVER_PCI
577 /* Set TAS register to match the virtual-dma properties
578 set during sabre configure */
579 sparc64_set_tas_register(PBM_PCI_TARGET_AS_CD_ENABLE);
584 /* Point to the Forth obp-ticks variable */
586 obp_ticks_pointer = cell2pointer(POP());
588 bind_func("platform-boot", boot );
589 bind_func("(go)", go);
592 unsigned long isa_io_base;
594 extern struct _console_ops arch_console_ops;
600 const struct hwdef *hwdef = NULL;
603 for (i = 0; i < sizeof(hwdefs) / sizeof(struct hwdef); i++) {
604 isa_io_base = hwdefs[i].pci.io_base;
605 machine_id = fw_cfg_read_i16(FW_CFG_MACHINE_ID);
606 if (hwdefs[i].machine_id_low <= machine_id &&
607 hwdefs[i].machine_id_high >= machine_id) {
609 arch = &hwdefs[i].pci;
614 for(;;); // Internal inconsistency, hang
616 #ifdef CONFIG_DEBUG_CONSOLE
617 init_console(arch_console_ops);
618 #ifdef CONFIG_DEBUG_CONSOLE_SERIAL
619 uart_init(CONFIG_SERIAL_PORT, CONFIG_SERIAL_SPEED);
621 printk("OpenBIOS for Sparc64\n");
626 collect_sys_info(&sys_info);
628 dict = (unsigned char *)sys_info.dict_start;
629 dicthead = (cell)sys_info.dict_end;
630 last = sys_info.dict_last;
631 dictlimit = sys_info.dict_limit;
635 #ifdef CONFIG_DEBUG_BOOT
636 printk("forth started.\n");
637 printk("initializing memory...");
642 #ifdef CONFIG_DEBUG_BOOT
646 PUSH_xt( bind_noname_func(arch_init) );
647 fword("PREPOST-initializer");
649 PC = (ucell)findword("initialize-of");
652 printk("panic: no dictionary entry point.\n");
655 #ifdef CONFIG_DEBUG_DICTIONARY
656 printk("done (%d bytes).\n", dicthead);
657 printk("Jumping to dictionary...\n");
660 enterforth((xt_t)PC);
661 printk("falling off...\n");