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"
23 #define NO_QEMU_PROTOS
24 #include "arch/common/fw_cfg.h"
27 #define UUID_FMT "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x"
29 #define PROMDEV_KBD 0 /* input from keyboard */
30 #define PROMDEV_SCREEN 0 /* output to screen */
31 #define PROMDEV_TTYA 1 /* in/out to ttya */
33 /* "NCPU" is an historical name that's now a bit of a misnomer. The sun4m
34 * architecture registers NCPU CPU-specific interrupts along with one
35 * system-wide interrupt, regardless of the number of actual CPUs installed.
36 * See the comment on "NCPU" at <http://stuff.mit.edu/afs/athena/astaff/
37 * project/opssrc/sys.sunos/sun4m/devaddr.h>.
41 /* DECLARE data structures for the nodes. */
42 DECLARE_UNNAMED_NODE( ob_obio
, INSTALL_OPEN
, sizeof(int) );
45 ob_new_obio_device(const char *name
, const char *type
)
61 map_reg(uint64_t base
, uint64_t offset
, unsigned long size
, int map
,
78 addr
= (unsigned long)map_io(base
+ offset
, size
);
93 ob_reg(uint64_t base
, uint64_t offset
, unsigned long size
, int map
)
95 return map_reg(base
, offset
, size
, map
, 0);
111 ob_eccmemctl_init(uint64_t base
)
113 uint32_t version
, *regs
;
117 fword("find-device");
120 push_str("eccmemctl");
121 fword("device-name");
128 regs
= (uint32_t *)map_reg(ECC_BASE
, 0, ECC_SIZE
, 1, ECC_BASE
>> 32);
144 fword("encode-string");
148 fword("finish-device");
151 static unsigned char *nvram
;
153 #define NVRAM_OB_START (0)
154 #define NVRAM_OB_SIZE ((NVRAM_IDPROM - NVRAM_OB_START) & ~15)
157 arch_nvram_get(char *data
)
159 memcpy(data
, &nvram
[NVRAM_OB_START
], NVRAM_OB_SIZE
);
163 arch_nvram_put(char *data
)
165 memcpy(&nvram
[NVRAM_OB_START
], data
, NVRAM_OB_SIZE
);
169 arch_nvram_size(void)
171 return NVRAM_OB_SIZE
;
174 static void mb86904_init(void)
178 push_str("cache-line-size");
183 push_str("cache-nlines");
188 push_str("mask_rev");
192 static void tms390z55_init(void)
195 fword("encode-string");
196 push_str("ecache-parity?");
200 fword("encode-string");
205 fword("encode-string");
210 fword("encode-string");
211 push_str("cache-physical?");
256 static void rt625_init(void)
260 push_str("cache-line-size");
265 push_str("cache-nlines");
270 static void bad_cpu_init(void)
272 printk("This CPU is not supported yet, freezing.\n");
277 unsigned long iu_version
;
279 int psr_impl
, psr_vers
, impl
, vers
;
280 int dcache_line_size
, dcache_lines
, dcache_assoc
;
281 int icache_line_size
, icache_lines
, icache_assoc
;
282 int ecache_line_size
, ecache_lines
, ecache_assoc
;
284 void (*initfn
)(void);
287 static const struct cpudef sparc_defs
[] = {
289 .iu_version
= 0x00 << 24, /* Impl 0, ver 0 */
290 .name
= "FMI,MB86900",
291 .initfn
= bad_cpu_init
,
294 .iu_version
= 0x04 << 24, /* Impl 0, ver 4 */
295 .name
= "FMI,MB86904",
300 .dcache_line_size
= 0x10,
301 .dcache_lines
= 0x200,
303 .icache_line_size
= 0x20,
304 .icache_lines
= 0x200,
306 .ecache_line_size
= 0x20,
307 .ecache_lines
= 0x4000,
310 .initfn
= mb86904_init
,
313 .iu_version
= 0x05 << 24, /* Impl 0, ver 5 */
314 .name
= "FMI,MB86907",
319 .dcache_line_size
= 0x20,
320 .dcache_lines
= 0x200,
322 .icache_line_size
= 0x20,
323 .icache_lines
= 0x200,
325 .ecache_line_size
= 0x20,
326 .ecache_lines
= 0x4000,
329 .initfn
= mb86904_init
,
332 .iu_version
= 0x10 << 24, /* Impl 1, ver 0 */
333 .name
= "LSI,L64811",
334 .initfn
= bad_cpu_init
,
337 .iu_version
= 0x11 << 24, /* Impl 1, ver 1 */
338 .name
= "CY,CY7C601",
344 .initfn
= bad_cpu_init
,
347 .iu_version
= 0x13 << 24, /* Impl 1, ver 3 */
348 .name
= "CY,CY7C611",
349 .initfn
= bad_cpu_init
,
352 .iu_version
= 0x40000000,
353 .name
= "TI,TMS390Z55",
358 .dcache_line_size
= 0x20,
359 .dcache_lines
= 0x80,
361 .icache_line_size
= 0x40,
362 .icache_lines
= 0x40,
364 .ecache_line_size
= 0x20,
365 .ecache_lines
= 0x8000,
368 .initfn
= tms390z55_init
,
371 .iu_version
= 0x41000000,
372 .name
= "TI,TMS390S10",
377 .dcache_line_size
= 0x10,
378 .dcache_lines
= 0x80,
380 .icache_line_size
= 0x20,
381 .icache_lines
= 0x80,
383 .ecache_line_size
= 0x20,
384 .ecache_lines
= 0x8000,
387 .initfn
= tms390z55_init
,
390 .iu_version
= 0x42000000,
391 .name
= "TI,TMS390S10",
396 .dcache_line_size
= 0x10,
397 .dcache_lines
= 0x80,
399 .icache_line_size
= 0x20,
400 .icache_lines
= 0x80,
402 .ecache_line_size
= 0x20,
403 .ecache_lines
= 0x8000,
406 .initfn
= tms390z55_init
,
409 .iu_version
= 0x43000000,
410 .name
= "TI,TMS390S10",
415 .dcache_line_size
= 0x10,
416 .dcache_lines
= 0x80,
418 .icache_line_size
= 0x20,
419 .icache_lines
= 0x80,
421 .ecache_line_size
= 0x20,
422 .ecache_lines
= 0x8000,
425 .initfn
= tms390z55_init
,
428 .iu_version
= 0x44000000,
429 .name
= "TI,TMS390S10",
434 .dcache_line_size
= 0x10,
435 .dcache_lines
= 0x80,
437 .icache_line_size
= 0x20,
438 .icache_lines
= 0x80,
440 .ecache_line_size
= 0x20,
441 .ecache_lines
= 0x8000,
444 .initfn
= tms390z55_init
,
447 .iu_version
= 0x1e000000,
448 .name
= "Ross,RT625",
453 .dcache_line_size
= 0x20,
454 .dcache_lines
= 0x80,
456 .icache_line_size
= 0x40,
457 .icache_lines
= 0x40,
459 .ecache_line_size
= 0x20,
460 .ecache_lines
= 0x8000,
463 .initfn
= rt625_init
,
466 .iu_version
= 0x1f000000,
467 .name
= "Ross,RT620",
472 .dcache_line_size
= 0x20,
473 .dcache_lines
= 0x80,
475 .icache_line_size
= 0x40,
476 .icache_lines
= 0x40,
478 .ecache_line_size
= 0x20,
479 .ecache_lines
= 0x8000,
482 .initfn
= rt625_init
,
485 .iu_version
= 0x20000000,
487 .initfn
= bad_cpu_init
,
490 .iu_version
= 0x50000000,
491 .name
= "MC,MN10501",
492 .initfn
= bad_cpu_init
,
495 .iu_version
= 0x90 << 24, /* Impl 9, ver 0 */
496 .name
= "Weitek,W8601",
497 .initfn
= bad_cpu_init
,
500 .iu_version
= 0xf2000000,
502 .initfn
= bad_cpu_init
,
505 .iu_version
= 0xf3000000,
507 .initfn
= bad_cpu_init
,
511 static const struct cpudef
*
514 unsigned long iu_version
;
518 : "=r"(iu_version
) :);
519 iu_version
&= 0xff000000;
521 for (i
= 0; i
< sizeof(sparc_defs
)/sizeof(struct cpudef
); i
++) {
522 if (iu_version
== sparc_defs
[i
].iu_version
)
523 return &sparc_defs
[i
];
525 printk("Unknown cpu (psr %lx), freezing!\n", iu_version
);
529 static void dummy_mach_init(uint64_t base
)
534 ss5_init(uint64_t base
)
536 ob_new_obio_device("slavioconfig", NULL
);
538 ob_reg(base
, SLAVIO_SCONFIG
, SCONFIG_REGS
, 0);
540 fword("finish-device");
545 const char *banner_name
;
549 void (*initfn
)(uint64_t base
);
552 static const struct machdef sun4m_defs
[] = {
555 .banner_name
= "SPARCstation 5",
556 .model
= "SUNW,501-3059",
557 .name
= "SUNW,SPARCstation-5",
563 .banner_name
= "SPARCstation Voyager",
564 .model
= "SUNW,501-2581",
565 .name
= "SUNW,SPARCstation-Voyager",
567 .initfn
= dummy_mach_init
,
571 .banner_name
= "SPARCstation LX",
572 .model
= "SUNW,501-2031",
573 .name
= "SUNW,SPARCstation-LX",
575 .initfn
= dummy_mach_init
,
579 .banner_name
= "SPARCstation 4",
580 .model
= "SUNW,501-2572",
581 .name
= "SUNW,SPARCstation-4",
587 .banner_name
= "SPARCstation Classic",
588 .model
= "SUNW,501-2326",
589 .name
= "SUNW,SPARCstation-Classic",
591 .initfn
= dummy_mach_init
,
595 .banner_name
= "Tadpole S3 GX",
597 .name
= "Tadpole_S3GX",
603 .banner_name
= "SPARCstation 10 (1 X 390Z55)",
604 .model
= "SUNW,S10,501-2365",
605 .name
= "SUNW,SPARCstation-10",
607 .initfn
= ob_eccmemctl_init
,
611 .banner_name
= "SPARCstation 20 (1 X 390Z55)",
612 .model
= "SUNW,S20,501-2324",
613 .name
= "SUNW,SPARCstation-20",
615 .initfn
= ob_eccmemctl_init
,
619 .banner_name
= "SPARCsystem 600(1 X 390Z55)",
621 .name
= "SUNW,SPARCsystem-600",
623 .initfn
= ob_eccmemctl_init
,
627 static const struct machdef
*
628 id_machine(uint16_t machine_id
)
632 for (i
= 0; i
< sizeof(sun4m_defs
)/sizeof(struct machdef
); i
++) {
633 if (machine_id
== sun4m_defs
[i
].machine_id
)
634 return &sun4m_defs
[i
];
636 printk("Unknown machine (ID %d), freezing!\n", machine_id
);
640 static uint8_t qemu_uuid
[16];
643 ob_nvram_init(uint64_t base
, uint64_t offset
)
645 const char *stdin
, *stdout
;
649 const struct cpudef
*cpu
;
650 const struct machdef
*mach
;
655 ob_new_obio_device("eeprom", NULL
);
657 nvram
= (unsigned char *)ob_reg(base
, offset
, NVRAM_SIZE
, 1);
659 PUSH((unsigned long)nvram
);
667 fword("finish-device");
671 fw_cfg_read(FW_CFG_SIGNATURE
, buf
, 4);
674 printk("Configuration device id %s", buf
);
676 temp
= fw_cfg_read_i32(FW_CFG_ID
);
677 machine_id
= fw_cfg_read_i16(FW_CFG_MACHINE_ID
);
679 printk(" version %d machine id %d\n", temp
, machine_id
);
682 printk("Incompatible configuration device version, freezing\n");
686 fw_cfg_read(FW_CFG_NOGRAPHIC
, &nographic
, 1);
687 graphic_depth
= fw_cfg_read_i16(FW_CFG_SUN4M_DEPTH
);
690 fw_cfg_read(FW_CFG_UUID
, (char *)qemu_uuid
, 16);
692 printk("UUID: " UUID_FMT
"\n", qemu_uuid
[0], qemu_uuid
[1], qemu_uuid
[2],
693 qemu_uuid
[3], qemu_uuid
[4], qemu_uuid
[5], qemu_uuid
[6],
694 qemu_uuid
[7], qemu_uuid
[8], qemu_uuid
[9], qemu_uuid
[10],
695 qemu_uuid
[11], qemu_uuid
[12], qemu_uuid
[13], qemu_uuid
[14],
699 fword("find-device");
701 PUSH((long)&qemu_uuid
);
703 fword("encode-bytes");
709 fword("find-device");
711 PUSH((long)&nvram
[NVRAM_IDPROM
]);
713 fword("encode-bytes");
717 mach
= id_machine(machine_id
);
719 push_str(mach
->banner_name
);
720 fword("encode-string");
721 push_str("banner-name");
725 push_str(mach
->model
);
726 fword("encode-string");
730 push_str(mach
->name
);
731 fword("encode-string");
738 temp
= fw_cfg_read_i32(FW_CFG_NB_CPUS
);
740 printk("CPUs: %x", temp
);
742 printk(" x %s\n", cpu
->name
);
743 for (i
= 0; i
< temp
; i
++) {
745 fword("find-device");
750 fword("device-name");
753 fword("device-type");
757 push_str("psr-implementation");
762 push_str("psr-version");
767 push_str("implementation");
777 push_str("page-size");
780 PUSH(cpu
->dcache_line_size
);
782 push_str("dcache-line-size");
785 PUSH(cpu
->dcache_lines
);
787 push_str("dcache-nlines");
790 PUSH(cpu
->dcache_assoc
);
792 push_str("dcache-associativity");
795 PUSH(cpu
->icache_line_size
);
797 push_str("icache-line-size");
800 PUSH(cpu
->icache_lines
);
802 push_str("icache-nlines");
805 PUSH(cpu
->icache_assoc
);
807 push_str("icache-associativity");
810 PUSH(cpu
->ecache_line_size
);
812 push_str("ecache-line-size");
815 PUSH(cpu
->ecache_lines
);
817 push_str("ecache-nlines");
820 PUSH(cpu
->ecache_assoc
);
822 push_str("ecache-associativity");
832 push_str("mmu-nctx");
837 push_str("sparc-version");
841 fword("encode-string");
842 push_str("cache-coherence?");
845 PUSH(i
+ mach
->mid_offset
);
852 fword("finish-device");
856 obp_stdin
= PROMDEV_TTYA
;
857 obp_stdout
= PROMDEV_TTYA
;
861 obp_stdin
= PROMDEV_KBD
;
862 obp_stdout
= PROMDEV_SCREEN
;
868 fword("find-device");
871 fword("pathres-resolve-aliases");
872 fword("encode-string");
873 push_str("stdin-path");
877 fword("pathres-resolve-aliases");
878 fword("encode-string");
879 push_str("stdout-path");
882 chosen
= find_dev("/chosen");
885 set_int_property(chosen
, "stdin", POP());
887 chosen
= find_dev("/chosen");
890 set_int_property(chosen
, "stdout", POP());
893 push_str("input-device");
897 push_str("output-device");
903 obp_stdin_path
= stdin
;
904 obp_stdout_path
= stdout
;
908 ob_fd_init(uint64_t base
, uint64_t offset
, int intr
)
912 ob_new_obio_device("SUNW,fdtwo", "block");
914 addr
= ob_reg(base
, offset
, FD_REGS
, 1);
918 fword("is-deblocker");
920 ob_floppy_init("/obio", "SUNW,fdtwo", 0, addr
);
922 fword("finish-device");
926 ob_auxio_init(uint64_t base
, uint64_t offset
)
928 ob_new_obio_device("auxio", NULL
);
930 ob_reg(base
, offset
, AUXIO_REGS
, 0);
932 fword("finish-device");
935 volatile unsigned char *power_reg
;
936 volatile unsigned int *reset_reg
;
939 sparc32_reset_all(void)
944 // AUX 2 (Software Powerdown Control) and reset
946 ob_aux2_reset_init(uint64_t base
, uint64_t offset
, int intr
)
948 ob_new_obio_device("power", NULL
);
950 power_reg
= (void *)ob_reg(base
, offset
, AUXIO2_REGS
, 1);
952 // Not in device tree
953 reset_reg
= map_io(base
+ (uint64_t)SLAVIO_RESET
, RESET_REGS
);
955 bind_func("sparc32-reset-all", sparc32_reset_all
);
956 push_str("' sparc32-reset-all to reset-all");
961 fword("finish-device");
964 volatile struct sun4m_timer_regs
*counter_regs
;
967 ob_counter_init(uint64_t base
, unsigned long offset
)
971 ob_new_obio_device("counter", NULL
);
973 for (i
= 0; i
< SUN4M_NCPU
; i
++) {
976 if (i
!= 0) fword("encode+");
977 PUSH(offset
+ (i
* PAGE_SIZE
));
988 PUSH(offset
+ 0x10000);
999 counter_regs
= map_io(base
+ (uint64_t)offset
, sizeof(*counter_regs
));
1000 counter_regs
->cfg
= 0xffffffff;
1001 counter_regs
->l10_timer_limit
= (((1000000/100) + 1) << 10);
1002 counter_regs
->cpu_timers
[0].l14_timer_limit
= 0;
1003 counter_regs
->cpu_timers
[0].cntrl
= 1;
1005 for (i
= 0; i
< SUN4M_NCPU
; i
++) {
1006 PUSH((unsigned long)&counter_regs
->cpu_timers
[i
]);
1007 fword("encode-int");
1011 PUSH((unsigned long)&counter_regs
->l10_timer_limit
);
1012 fword("encode-int");
1014 push_str("address");
1017 fword("finish-device");
1020 static volatile struct sun4m_intregs
*intregs
;
1023 ob_interrupt_init(uint64_t base
, unsigned long offset
)
1027 ob_new_obio_device("interrupt", NULL
);
1029 for (i
= 0; i
< SUN4M_NCPU
; i
++) {
1031 fword("encode-int");
1032 if (i
!= 0) fword("encode+");
1033 PUSH(offset
+ (i
* PAGE_SIZE
));
1034 fword("encode-int");
1036 PUSH(INTERRUPT_REGS
);
1037 fword("encode-int");
1042 fword("encode-int");
1044 PUSH(offset
+ 0x10000);
1045 fword("encode-int");
1047 PUSH(INTERRUPT_REGS
);
1048 fword("encode-int");
1054 intregs
= map_io(base
| (uint64_t)offset
, sizeof(*intregs
));
1055 intregs
->clear
= ~SUN4M_INT_MASKALL
;
1056 intregs
->cpu_intregs
[0].clear
= ~0x17fff;
1058 for (i
= 0; i
< SUN4M_NCPU
; i
++) {
1059 PUSH((unsigned long)&intregs
->cpu_intregs
[i
]);
1060 fword("encode-int");
1064 PUSH((unsigned long)&intregs
->tbt
);
1065 fword("encode-int");
1067 push_str("address");
1070 fword("finish-device");
1073 /* SMP CPU boot structure */
1076 uint32_t smp_ctxtbl
;
1081 static struct smp_cfg
*smp_header
;
1084 start_cpu(unsigned int pc
, unsigned int context_ptr
, unsigned int context
, int cpu
)
1091 smp_header
->smp_entry
= pc
;
1092 smp_header
->smp_ctxtbl
= context_ptr
;
1093 smp_header
->smp_ctx
= context
;
1094 smp_header
->valid
= cpu
;
1096 intregs
->cpu_intregs
[cpu
].set
= SUN4M_SOFT_INT(14);
1104 unsigned long mem_size
;
1106 // See arch/sparc32/entry.S for memory layout
1107 mem_size
= fw_cfg_read_i32(FW_CFG_RAM_SIZE
);
1108 smp_header
= (struct smp_cfg
*)map_io((uint64_t)(mem_size
- 0x100),
1109 sizeof(struct smp_cfg
));
1113 ob_obio_open(__attribute__((unused
))int *idx
)
1120 ob_obio_close(__attribute__((unused
))int *idx
)
1122 selfword("close-deblocker");
1126 ob_obio_initialize(__attribute__((unused
))int *idx
)
1129 fword("find-device");
1130 fword("new-device");
1133 fword("device-name");
1135 push_str("hierarchical");
1136 fword("device-type");
1139 fword("encode-int");
1140 push_str("#address-cells");
1144 fword("encode-int");
1145 push_str("#size-cells");
1148 fword("finish-device");
1152 ob_set_obio_ranges(uint64_t base
)
1155 fword("find-device");
1157 fword("encode-int");
1159 fword("encode-int");
1162 fword("encode-int");
1164 PUSH(base
& 0xffffffff);
1165 fword("encode-int");
1168 fword("encode-int");
1175 ob_obio_decodeunit(__attribute__((unused
)) int *idx
)
1177 fword("decode-unit-sbus");
1182 ob_obio_encodeunit(__attribute__((unused
)) int *idx
)
1184 fword("encode-unit-sbus");
1187 NODE_METHODS(ob_obio
) = {
1188 { NULL
, ob_obio_initialize
},
1189 { "open", ob_obio_open
},
1190 { "close", ob_obio_close
},
1191 { "encode-unit", ob_obio_encodeunit
},
1192 { "decode-unit", ob_obio_decodeunit
},
1197 ob_obio_init(uint64_t slavio_base
, unsigned long fd_offset
,
1198 unsigned long counter_offset
, unsigned long intr_offset
,
1199 unsigned long aux1_offset
, unsigned long aux2_offset
)
1202 // All devices were integrated to NCR89C105, see
1203 // http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
1205 //printk("Initializing OBIO devices...\n");
1207 REGISTER_NAMED_NODE(ob_obio
, "/obio");
1210 ob_set_obio_ranges(slavio_base
);
1212 // Zilog Z8530 serial ports, see http://www.zilog.com
1213 // Must be before zs@0,0 or Linux won't boot
1214 ob_zs_init(slavio_base
, SLAVIO_ZS1
, ZS_INTR
, 0, 0);
1216 ob_zs_init(slavio_base
, SLAVIO_ZS
, ZS_INTR
, 1, 1);
1218 // M48T08 NVRAM, see http://www.st.com
1219 ob_nvram_init(slavio_base
, SLAVIO_NVRAM
);
1222 if (fd_offset
!= (unsigned long) -1)
1223 ob_fd_init(slavio_base
, fd_offset
, FD_INTR
);
1225 ob_auxio_init(slavio_base
, aux1_offset
);
1227 if (aux2_offset
!= (unsigned long) -1)
1228 ob_aux2_reset_init(slavio_base
, aux2_offset
, AUXIO2_INTR
);
1230 ob_counter_init(slavio_base
, counter_offset
);
1232 ob_interrupt_init(slavio_base
, intr_offset
);