1 /* prom.c - emulates a sparc v0 PROM for the linux kernel.
3 * Copyright (C) 2003 Konrad Eisele <eiselekd@web.de>
4 * Copyright (C) 2004 Stefan Holst <mail@s-holst.de>
5 * Copyright (C) 2007 Daniel Hellstrom <daniel@gaisler.com>
7 * SPDX-License-Identifier: GPL-2.0+
12 #include <asm/machines.h>
13 #include <asm/srmmu.h>
14 #include <asm/processor.h>
22 extern struct linux_romvec *kernel_arg_promvec;
24 #define PROM_PGT __attribute__ ((__section__ (".prom.pgt")))
25 #define PROM_TEXT __attribute__ ((__section__ (".prom.text")))
26 #define PROM_DATA __attribute__ ((__section__ (".prom.data")))
28 void *__prom_start_reloc; /* relocated prom_start address */
31 extern int __prom_start;
32 #define PAGE_OFFSET 0xf0000000
33 #define phys_base CONFIG_SYS_SDRAM_BASE
34 #define PROM_OFFS 8192
35 #define PROM_SIZE_MASK (PROM_OFFS-1)
37 (void *)( ((unsigned long)(x))-PROM_OFFS+ \
38 (CONFIG_SYS_PROM_OFFSET-phys_base)+PAGE_OFFSET-CONFIG_SYS_TEXT_BASE ) \
40 #define __phy(x) ((void *)(((unsigned long)(x))-PROM_OFFS+CONFIG_SYS_PROM_OFFSET-CONFIG_SYS_TEXT_BASE))
50 struct property *properties;
53 static void leon_reboot(char *bcommand);
54 static void leon_halt(void);
55 static int leon_nbputchar(int c);
56 static int leon_nbgetchar(void);
58 static int no_nextnode(int node);
59 static int no_child(int node);
60 static int no_proplen(int node, char *name);
61 static int no_getprop(int node, char *name, char *value);
62 static int no_setprop(int node, char *name, char *value, int len);
63 static char *no_nextprop(int node, char *name);
65 static struct property PROM_TEXT *find_property(int node, char *name);
66 static int PROM_TEXT leon_strcmp(const char *s1, const char *s2);
67 static void *PROM_TEXT leon_memcpy(void *dest, const void *src, size_t n);
68 static void PROM_TEXT leon_reboot_physical(char *bcommand);
70 void __inline__ leon_flush_cache_all(void)
72 __asm__ __volatile__(" flush ");
73 __asm__ __volatile__("sta %%g0, [%%g0] %0\n\t"::"i"(ASI_DFLUSH):"memory");
76 void __inline__ leon_flush_tlb_all(void)
78 leon_flush_cache_all();
79 __asm__ __volatile__("sta %%g0, [%0] %1\n\t"::"r"(0x400),
80 "i"(ASI_MMUFLUSH):"memory");
84 unsigned int ctx_table[256];
85 unsigned int pgd_table[256];
88 sparc_srmmu_setup srmmu_tables PROM_PGT = {
330 0x400001e /* default */
334 /* a self contained prom info structure */
335 struct leon_reloc_func {
336 struct property *(*find_property) (int node, char *name);
337 int (*strcmp) (char *s1, char *s2);
338 void *(*memcpy) (void *dest, const void *src, size_t n);
339 void (*reboot_physical) (char *cmd);
342 struct leon_prom_info {
347 struct leon_reloc_func reloc_funcs;
348 struct property root_properties[4];
349 struct property cpu_properties[7];
351 #define CPUENTRY(idx) struct property cpu_properties##idx[4]
383 struct idprom idprom;
384 struct linux_nodeops nodeops;
385 struct linux_mlist_v0 *totphys_p;
386 struct linux_mlist_v0 totphys;
387 struct linux_mlist_v0 *avail_p;
388 struct linux_mlist_v0 avail;
389 struct linux_mlist_v0 *prommap_p;
390 void (*synchook) (void);
391 struct linux_arguments_v0 *bootargs_p;
392 struct linux_arguments_v0 bootargs;
393 struct linux_romvec romvec;
394 struct node nodes[35];
395 char s_device_type[12];
399 char s_compatability[14];
402 char s_frequency[16];
403 char s_uart1_baud[11];
404 char s_uart2_baud[11];
408 /* static prom info */
409 static struct leon_prom_info PROM_DATA spi = {
410 CONFIG_SYS_CLK_FREQ / 1000,
414 #define CPUENTRY(idx) idx
452 __phy(leon_reboot_physical),
455 {__va(spi.s_device_type), __va(spi.s_idprom), 4},
456 {__va(spi.s_idprom), (char *)__va(&spi.idprom), sizeof(struct idprom)},
457 {__va(spi.s_compatability), __va(spi.s_leon2), 5},
461 {__va(spi.s_device_type), __va(spi.s_cpu), 4},
462 {__va(spi.s_mid), __va(&spi.mids[0]), 4},
463 {__va(spi.s_mmu_nctx), (char *)__va(&spi.leon_nctx), 4},
464 {__va(spi.s_frequency), (char *)__va(&spi.freq_khz), 4},
465 {__va(spi.s_uart1_baud), (char *)__va(&spi.baudrates[0]), 4},
466 {__va(spi.s_uart2_baud), (char *)__va(&spi.baudrates[1]), 4},
470 #define CPUENTRY(idx) \
471 { /* cpu_properties */ \
472 {__va(spi.s_device_type), __va(spi.s_cpu), 4}, \
473 {__va(spi.s_mid), __va(&spi.mids[idx]), 4}, \
474 {__va(spi.s_frequency), (char *)__va(&spi.freq_khz), 4}, \
510 M_LEON2 | M_LEON2_SOC, /* machine type */
511 {0, 0, 0, 0, 0, 0}, /* eth */
515 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} /* reserved */
528 (char *)CONFIG_SYS_SDRAM_BASE,
534 (char *)CONFIG_SYS_SDRAM_BASE,
537 NULL, /* prommap_p */
541 {NULL, __va(spi.arg), NULL /*... */ },
546 0, /* sun4c v0 prom */
548 {__va(&spi.totphys_p), __va(&spi.prommap_p), __va(&spi.avail_p)},
550 NULL, {NULL /* ... */ },
552 NULL, NULL, /* pv_getchar, pv_putchar */
553 __va(leon_nbgetchar), __va(leon_nbputchar),
562 __va(&spi.bootargs_p)
566 {0, __va(spi.root_properties + 3) /* NULL, NULL, -1 */ },
567 {0, __va(spi.root_properties)},
568 /* cpu 0, must be spi.nodes[2] see leon_prom_init() */
569 {1, __va(spi.cpu_properties)},
572 #define CPUENTRY(idx) \
573 {1, __va(spi.cpu_properties##idx) } /* cpu <idx> */
605 {-1, __va(spi.root_properties + 3) /* NULL, NULL, -1 */ }
617 CONFIG_DEFAULT_KERNEL_COMMAND_LINE
620 /* from arch/sparc/kernel/setup.c */
621 #define RAMDISK_LOAD_FLAG 0x4000
622 extern unsigned short root_flags;
623 extern unsigned short root_dev;
624 extern unsigned short ram_flags;
625 extern unsigned int sparc_ramdisk_image;
626 extern unsigned int sparc_ramdisk_size;
627 extern int root_mountflags;
629 extern char initrd_end, initrd_start;
631 /* Reboot the CPU = jump to beginning of flash again.
633 * Make sure that all function are inlined here.
635 static void PROM_TEXT leon_reboot(char *bcommand)
637 register char *arg = bcommand;
638 void __attribute__ ((noreturn)) (*reboot_physical) (char *cmd);
640 /* get physical address */
641 struct leon_prom_info *pspi =
642 (void *)(CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables));
644 unsigned int *srmmu_ctx_table;
646 /* Turn of Interrupts */
649 /* Set kernel's context, context zero */
650 srmmu_set_context(0);
652 /* Get physical address of the MMU shutdown routine */
653 reboot_physical = (void *)
654 SPARC_BYPASS_READ(&pspi->reloc_funcs.reboot_physical);
656 /* Now that we know the physical address of the function
657 * we can make the MMU allow jumping to it.
659 srmmu_ctx_table = (unsigned int *)srmmu_get_ctable_ptr();
661 srmmu_ctx_table = (unsigned int *)SPARC_BYPASS_READ(srmmu_ctx_table);
663 /* get physical address of kernel's context table (assume ptd) */
664 srmmu_ctx_table = (unsigned int *)
665 (((unsigned int)srmmu_ctx_table & 0xfffffffc) << 4);
667 /* enable access to physical address of MMU shutdown function */
668 SPARC_BYPASS_WRITE(&srmmu_ctx_table
669 [((unsigned int)reboot_physical) >> 24],
670 (((unsigned int)reboot_physical & 0xff000000) >> 4) |
673 /* flush TLB cache */
674 leon_flush_tlb_all();
676 /* flash instruction & data cache */
677 sparc_icache_flush_all();
678 sparc_dcache_flush_all();
680 /* jump to physical address function
681 * so that when the MMU is disabled
682 * we can continue to execute
684 reboot_physical(arg);
687 static void PROM_TEXT leon_reboot_physical(char *bcommand)
689 void __attribute__ ((noreturn)) (*reset) (void);
694 /* Hardcoded start address */
695 reset = CONFIG_SYS_MONITOR_BASE;
697 /* flush data cache */
698 sparc_dcache_flush_all();
700 /* flush instruction cache */
701 sparc_icache_flush_all();
703 /* Jump to start in Flash */
707 static void PROM_TEXT leon_halt(void)
712 /* get single char, don't care for blocking*/
713 static int PROM_TEXT leon_nbgetchar(void)
718 /* put single char, don't care for blocking*/
719 static int PROM_TEXT leon_nbputchar(int c)
721 LEON2_regs *leon2 = (LEON2_regs *) LEON2_PREGS;
723 /***** put char in buffer... ***********
724 * Make sure all functions are inline! *
725 ***************************************/
727 /* Wait for last character to go. */
728 while (!(SPARC_BYPASS_READ(&leon2->UART_Status_1)
729 & LEON2_UART_STAT_THE)) ;
732 SPARC_BYPASS_WRITE(&leon2->UART_Channel_1, c);
734 /* Wait for data to be sent */
735 while (!(SPARC_BYPASS_READ(&leon2->UART_Status_1)
736 & LEON2_UART_STAT_TSE)) ;
743 /*#define nodes ((struct node *)__va(&pspi->nodes))*/
744 #define nodes ((struct node *)(pspi->nodes))
746 static int PROM_TEXT no_nextnode(int node)
748 /* get physical address */
749 struct leon_prom_info *pspi =
750 (void *)(CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables));
752 /* convert into virtual address */
753 pspi = (struct leon_prom_info *)
754 (((unsigned int)pspi & 0x0fffffff) | PAGE_OFFSET);
756 if (nodes[node].level == nodes[node + 1].level)
761 static int PROM_TEXT no_child(int node)
763 /* get physical address */
764 struct leon_prom_info *pspi = (struct leon_prom_info *)
765 (CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables));
767 /* convert into virtual address */
768 pspi = (struct leon_prom_info *)
769 (((unsigned int)pspi & 0x0fffffff) | PAGE_OFFSET);
771 if (nodes[node].level == nodes[node + 1].level - 1)
776 static struct property PROM_TEXT *find_property(int node, char *name)
778 /* get physical address */
779 struct leon_prom_info *pspi = (struct leon_prom_info *)
780 (CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables));
782 /* convert into virtual address */
783 pspi = (struct leon_prom_info *)
784 (((unsigned int)pspi & 0x0fffffff) | PAGE_OFFSET);
786 struct property *prop = &nodes[node].properties[0];
787 while (prop && prop->name) {
788 if (pspi->reloc_funcs.strcmp(prop->name, name) == 0)
795 static int PROM_TEXT no_proplen(int node, char *name)
797 /* get physical address */
798 struct leon_prom_info *pspi = (struct leon_prom_info *)
799 (CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables));
801 /* convert into virtual address */
802 pspi = (struct leon_prom_info *)
803 (((unsigned int)pspi & 0x0fffffff) | PAGE_OFFSET);
805 struct property *prop = pspi->reloc_funcs.find_property(node, name);
811 static int PROM_TEXT no_getprop(int node, char *name, char *value)
813 /* get physical address */
814 struct leon_prom_info *pspi = (struct leon_prom_info *)
815 (CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables));
817 /* convert into virtual address */
818 pspi = (struct leon_prom_info *)
819 (((unsigned int)pspi & 0x0fffffff) | PAGE_OFFSET);
821 struct property *prop = pspi->reloc_funcs.find_property(node, name);
823 pspi->reloc_funcs.memcpy(value, prop->value, prop->length);
829 static int PROM_TEXT no_setprop(int node, char *name, char *value, int len)
834 static char PROM_TEXT *no_nextprop(int node, char *name)
836 /* get physical address */
837 struct leon_prom_info *pspi = (struct leon_prom_info *)
838 (CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables));
839 struct property *prop;
841 /* convert into virtual address */
842 pspi = (struct leon_prom_info *)
843 (((unsigned int)pspi & 0x0fffffff) | PAGE_OFFSET);
845 if (!name || !name[0])
846 return nodes[node].properties[0].name;
848 prop = pspi->reloc_funcs.find_property(node, name);
854 static int PROM_TEXT leon_strcmp(const char *s1, const char *s2)
856 register char result;
869 static void *PROM_TEXT leon_memcpy(void *dest, const void *src, size_t n)
871 char *dst = (char *)dest, *source = (char *)src;
881 #define GETREGSP(sp) __asm__ __volatile__("mov %%sp, %0" : "=r" (sp))
883 void leon_prom_init(struct leon_prom_info *pspi)
886 unsigned char cksum, *ptr;
887 char *addr_str, *end;
891 pspi->freq_khz = CONFIG_SYS_CLK_FREQ / 1000;
893 /* Set Available main memory size */
894 pspi->totphys.num_bytes = CONFIG_SYS_PROM_OFFSET - CONFIG_SYS_SDRAM_BASE;
895 pspi->avail.num_bytes = pspi->totphys.num_bytes;
898 pspi->nodes[3].level = -1;
899 pspi->nodes[3].properties = __va(spi.root_properties + 3);
901 /* Set Ethernet MAC address from environment */
902 if ((addr_str = getenv("ethaddr")) != NULL) {
903 for (i = 0; i < 6; i++) {
904 pspi->idprom.id_ethaddr[i] = addr_str ?
905 simple_strtoul(addr_str, &end, 16) : 0;
907 addr_str = (*end) ? end + 1 : end;
911 /* HW Address not found in environment,
912 * Set default HW address
914 pspi->idprom.id_ethaddr[0] = 0;
915 pspi->idprom.id_ethaddr[1] = 0;
916 pspi->idprom.id_ethaddr[2] = 0;
917 pspi->idprom.id_ethaddr[3] = 0;
918 pspi->idprom.id_ethaddr[4] = 0;
919 pspi->idprom.id_ethaddr[5] = 0;
922 ptr = (unsigned char *)&pspi->idprom;
923 for (i = cksum = 0; i <= 0x0E; i++)
925 pspi->idprom.id_cksum = cksum;
928 static inline void set_cache(unsigned long regval)
930 asm volatile ("sta %0, [%%g0] %1\n\t":: "r" (regval), "i"(2):"memory");
933 extern unsigned short bss_start, bss_end;
935 /* mark as section .img.main.text, to be referenced in linker script */
938 struct leon_prom_info *pspi = (void *)
939 ((((unsigned int)&spi) & PROM_SIZE_MASK) + CONFIG_SYS_PROM_OFFSET);
942 srmmu_set_mmureg(0x00000000);
943 __asm__ __volatile__("flush\n\t");
945 /* init prom info struct */
946 leon_prom_init(pspi);
948 kernel_arg_promvec = &pspi->romvec;
950 printf("Kernel rom vec: 0x%lx\n", (unsigned int)(&pspi->romvec));
955 /* Copy current kernel boot argument to ROMvec */
956 void prepare_bootargs(char *bootargs)
958 struct leon_prom_info *pspi;
962 /* if no bootargs set, skip copying ==> default bootline */
963 if (bootargs && (*bootargs != '\0')) {
964 pspi = (void *)((((unsigned int)&spi) & PROM_SIZE_MASK) +
965 CONFIG_SYS_PROM_OFFSET);
968 left = 255; /* max len */
969 while (*src && left > 0) {
973 /* terminate kernel command line string */
978 void srmmu_init_cpu(unsigned int entry)
980 sparc_srmmu_setup *psrmmu_tables = (void *)
981 ((((unsigned int)&srmmu_tables) & PROM_SIZE_MASK) +
982 CONFIG_SYS_PROM_OFFSET);
984 /* Make context 0 (kernel's context) point
985 * to our prepared memory mapping
988 psrmmu_tables->ctx_table[0] =
989 ((unsigned int)&psrmmu_tables->pgd_table[0x00]) >> 4 | PTD;
991 /* Set virtual kernel address 0xf0000000
992 * to SRAM/SDRAM address.
993 * Make it READ/WRITE/EXEC to SuperUser
996 #define ACC_SU_ALL 0x1c
997 psrmmu_tables->pgd_table[0xf0] =
998 (CONFIG_SYS_SDRAM_BASE >> 4) | ACC_SU_ALL | PTE;
999 psrmmu_tables->pgd_table[0xf1] =
1000 ((CONFIG_SYS_SDRAM_BASE + 0x1000000) >> 4) | ACC_SU_ALL | PTE;
1001 psrmmu_tables->pgd_table[0xf2] =
1002 ((CONFIG_SYS_SDRAM_BASE + 0x2000000) >> 4) | ACC_SU_ALL | PTE;
1003 psrmmu_tables->pgd_table[0xf3] =
1004 ((CONFIG_SYS_SDRAM_BASE + 0x3000000) >> 4) | ACC_SU_ALL | PTE;
1005 psrmmu_tables->pgd_table[0xf4] =
1006 ((CONFIG_SYS_SDRAM_BASE + 0x4000000) >> 4) | ACC_SU_ALL | PTE;
1007 psrmmu_tables->pgd_table[0xf5] =
1008 ((CONFIG_SYS_SDRAM_BASE + 0x5000000) >> 4) | ACC_SU_ALL | PTE;
1009 psrmmu_tables->pgd_table[0xf6] =
1010 ((CONFIG_SYS_SDRAM_BASE + 0x6000000) >> 4) | ACC_SU_ALL | PTE;
1011 psrmmu_tables->pgd_table[0xf7] =
1012 ((CONFIG_SYS_SDRAM_BASE + 0x7000000) >> 4) | ACC_SU_ALL | PTE;
1014 /* convert rom vec pointer to virtual address */
1015 kernel_arg_promvec = (struct linux_romvec *)
1016 (((unsigned int)kernel_arg_promvec & 0x0fffffff) | 0xf0000000);
1018 /* Set Context pointer to point to context table
1019 * 256 contexts supported.
1021 srmmu_set_ctable_ptr((unsigned int)&psrmmu_tables->ctx_table[0]);
1023 /* Set kernel's context, context zero */
1024 srmmu_set_context(0);
1026 /* Invalidate all Cache */
1027 __asm__ __volatile__("flush\n\t");
1029 srmmu_set_mmureg(0x00000001);
1030 leon_flush_tlb_all();
1031 leon_flush_cache_all();