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 * See file CREDITS for list of people who contributed to this
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License as
12 * published by the Free Software Foundation; either version 2 of
13 * the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
29 #include <asm/machines.h>
30 #include <asm/srmmu.h>
31 #include <asm/processor.h>
40 extern struct linux_romvec *kernel_arg_promvec;
41 extern ambapp_dev_apbuart *leon3_apbuart;
43 #define PROM_PGT __attribute__ ((__section__ (".prom.pgt")))
44 #define PROM_TEXT __attribute__ ((__section__ (".prom.text")))
45 #define PROM_DATA __attribute__ ((__section__ (".prom.data")))
47 ambapp_dev_gptimer *gptimer;
50 extern int __prom_start;
51 #define PAGE_OFFSET 0xf0000000
52 #define phys_base CFG_SDRAM_BASE
53 #define PROM_OFFS 8192
54 #define PROM_SIZE_MASK (PROM_OFFS-1)
56 (void *)( ((unsigned long)(x))-PROM_OFFS+ \
57 (CFG_PROM_OFFSET-phys_base)+PAGE_OFFSET-TEXT_BASE ) \
59 #define __phy(x) ((void *)(((unsigned long)(x))-PROM_OFFS+CFG_PROM_OFFSET-TEXT_BASE))
69 struct property *properties;
72 static void leon_reboot(char *bcommand);
73 static void leon_halt(void);
74 static int leon_nbputchar(int c);
75 static int leon_nbgetchar(void);
77 static int no_nextnode(int node);
78 static int no_child(int node);
79 static int no_proplen(int node, char *name);
80 static int no_getprop(int node, char *name, char *value);
81 static int no_setprop(int node, char *name, char *value, int len);
82 static char *no_nextprop(int node, char *name);
84 static struct property PROM_TEXT *find_property(int node, char *name);
85 static int PROM_TEXT leon_strcmp(const char *s1, const char *s2);
86 static void *PROM_TEXT leon_memcpy(void *dest, const void *src, size_t n);
87 static void PROM_TEXT leon_reboot_physical(char *bcommand);
89 void __inline__ leon_flush_cache_all(void)
91 __asm__ __volatile__(" flush ");
92 __asm__ __volatile__("sta %%g0, [%%g0] %0\n\t"::"i"(ASI_DFLUSH):"memory");
95 void __inline__ leon_flush_tlb_all(void)
97 leon_flush_cache_all();
98 __asm__ __volatile__("sta %%g0, [%0] %1\n\t"::"r"(0x400),
99 "i"(ASI_MMUFLUSH):"memory");
103 unsigned int ctx_table[256];
104 unsigned int pgd_table[256];
107 sparc_srmmu_setup srmmu_tables PROM_PGT = {
349 0x400001e /* default */
353 /* a self contained prom info structure */
354 struct leon_reloc_func {
355 struct property *(*find_property) (int node, char *name);
356 int (*strcmp) (char *s1, char *s2);
357 void *(*memcpy) (void *dest, const void *src, size_t n);
358 void (*reboot_physical) (char *cmd);
359 ambapp_dev_apbuart *leon3_apbuart;
362 struct leon_prom_info {
367 struct leon_reloc_func reloc_funcs;
368 struct property root_properties[4];
369 struct property cpu_properties[7];
371 #define CPUENTRY(idx) struct property cpu_properties##idx[4]
403 struct idprom idprom;
404 struct linux_nodeops nodeops;
405 struct linux_mlist_v0 *totphys_p;
406 struct linux_mlist_v0 totphys;
407 struct linux_mlist_v0 *avail_p;
408 struct linux_mlist_v0 avail;
409 struct linux_mlist_v0 *prommap_p;
410 void (*synchook) (void);
411 struct linux_arguments_v0 *bootargs_p;
412 struct linux_arguments_v0 bootargs;
413 struct linux_romvec romvec;
414 struct node nodes[35];
415 char s_device_type[12];
419 char s_compatability[14];
422 char s_frequency[16];
423 char s_uart1_baud[11];
424 char s_uart2_baud[11];
428 /* static prom info */
429 static struct leon_prom_info PROM_DATA spi = {
430 CONFIG_SYS_CLK_FREQ / 1000,
434 #define CPUENTRY(idx) idx
472 __phy(leon_reboot_physical),
475 {__va(spi.s_device_type), __va(spi.s_idprom), 4},
476 {__va(spi.s_idprom), (char *)__va(&spi.idprom), sizeof(struct idprom)},
477 {__va(spi.s_compatability), __va(spi.s_leon2), 5},
481 {__va(spi.s_device_type), __va(spi.s_cpu), 4},
482 {__va(spi.s_mid), __va(&spi.mids[0]), 4},
483 {__va(spi.s_mmu_nctx), (char *)__va(&spi.leon_nctx), 4},
484 {__va(spi.s_frequency), (char *)__va(&spi.freq_khz), 4},
485 {__va(spi.s_uart1_baud), (char *)__va(&spi.baudrates[0]), 4},
486 {__va(spi.s_uart2_baud), (char *)__va(&spi.baudrates[1]), 4},
490 #define CPUENTRY(idx) \
491 { /* cpu_properties */ \
492 {__va(spi.s_device_type), __va(spi.s_cpu), 4}, \
493 {__va(spi.s_mid), __va(&spi.mids[idx]), 4}, \
494 {__va(spi.s_frequency), (char *)__va(&spi.freq_khz), 4}, \
530 M_LEON2 | M_LEON2_SOC, /* machine type */
531 {0, 0, 0, 0, 0, 0}, /* eth */
535 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} /* reserved */
548 (char *)CFG_SDRAM_BASE,
554 (char *)CFG_SDRAM_BASE,
557 NULL, /* prommap_p */
561 {NULL, __va(spi.arg), NULL /*... */ },
566 0, /* sun4c v0 prom */
568 {__va(&spi.totphys_p), __va(&spi.prommap_p), __va(&spi.avail_p)},
570 NULL, {NULL /* ... */ },
572 NULL, NULL, /* pv_getchar, pv_putchar */
573 __va(leon_nbgetchar), __va(leon_nbputchar),
582 __va(&spi.bootargs_p)
586 {0, __va(spi.root_properties + 3) /* NULL, NULL, -1 */ },
587 {0, __va(spi.root_properties)},
588 /* cpu 0, must be spi.nodes[2] see leon_prom_init() */
589 {1, __va(spi.cpu_properties)},
592 #define CPUENTRY(idx) \
593 {1, __va(spi.cpu_properties##idx) } /* cpu <idx> */
625 {-1, __va(spi.root_properties + 3) /* NULL, NULL, -1 */ }
637 CONFIG_DEFAULT_KERNEL_COMMAND_LINE
640 /* from arch/sparc/kernel/setup.c */
641 #define RAMDISK_LOAD_FLAG 0x4000
642 extern unsigned short root_flags;
643 extern unsigned short root_dev;
644 extern unsigned short ram_flags;
645 extern unsigned int sparc_ramdisk_image;
646 extern unsigned int sparc_ramdisk_size;
647 extern int root_mountflags;
649 extern char initrd_end, initrd_start;
651 /* Reboot the CPU = jump to beginning of flash again.
653 * Make sure that all function are inlined here.
655 static void PROM_TEXT leon_reboot(char *bcommand)
657 register char *arg = bcommand;
658 void __attribute__ ((noreturn)) (*reboot_physical) (char *cmd);
660 /* get physical address */
661 struct leon_prom_info *pspi =
662 (void *)(CFG_PROM_OFFSET + sizeof(srmmu_tables));
664 unsigned int *srmmu_ctx_table;
666 /* Turn of Interrupts */
669 /* Set kernel's context, context zero */
670 srmmu_set_context(0);
672 /* Get physical address of the MMU shutdown routine */
673 reboot_physical = (void *)
674 SPARC_BYPASS_READ(&pspi->reloc_funcs.reboot_physical);
676 /* Now that we know the physical address of the function
677 * we can make the MMU allow jumping to it.
679 srmmu_ctx_table = (unsigned int *)srmmu_get_ctable_ptr();
681 srmmu_ctx_table = (unsigned int *)SPARC_BYPASS_READ(srmmu_ctx_table);
683 /* get physical address of kernel's context table (assume ptd) */
684 srmmu_ctx_table = (unsigned int *)
685 (((unsigned int)srmmu_ctx_table & 0xfffffffc) << 4);
687 /* enable access to physical address of MMU shutdown function */
688 SPARC_BYPASS_WRITE(&srmmu_ctx_table
689 [((unsigned int)reboot_physical) >> 24],
690 (((unsigned int)reboot_physical & 0xff000000) >> 4) |
693 /* flush TLB cache */
694 leon_flush_tlb_all();
696 /* flash instruction & data cache */
697 sparc_icache_flush_all();
698 sparc_dcache_flush_all();
700 /* jump to physical address function
701 * so that when the MMU is disabled
702 * we can continue to execute
704 reboot_physical(arg);
707 static void PROM_TEXT leon_reboot_physical(char *bcommand)
709 void __attribute__ ((noreturn)) (*reset) (void);
714 /* Hardcoded start address */
715 reset = CFG_MONITOR_BASE;
717 /* flush data cache */
718 sparc_dcache_flush_all();
720 /* flush instruction cache */
721 sparc_icache_flush_all();
723 /* Jump to start in Flash */
727 static void PROM_TEXT leon_halt(void)
732 /* get single char, don't care for blocking*/
733 static int PROM_TEXT leon_nbgetchar(void)
738 /* put single char, don't care for blocking*/
739 static int PROM_TEXT leon_nbputchar(int c)
741 ambapp_dev_apbuart *uart;
743 /* get physical address */
744 struct leon_prom_info *pspi =
745 (void *)(CFG_PROM_OFFSET + sizeof(srmmu_tables));
747 uart = (ambapp_dev_apbuart *)
748 SPARC_BYPASS_READ(&pspi->reloc_funcs.leon3_apbuart);
754 /***** put char in buffer... ***********
755 * Make sure all functions are inline! *
756 ***************************************/
758 /* Wait for last character to go. */
759 while (!(SPARC_BYPASS_READ(&uart->status)
760 & LEON_REG_UART_STATUS_THE)) ;
763 SPARC_BYPASS_WRITE(&uart->data, c);
765 /* Wait for data to be sent */
766 while (!(SPARC_BYPASS_READ(&uart->status)
767 & LEON_REG_UART_STATUS_TSE)) ;
774 /*#define nodes ((struct node *)__va(&pspi->nodes))*/
775 #define nodes ((struct node *)(pspi->nodes))
777 static int PROM_TEXT no_nextnode(int node)
779 /* get physical address */
780 struct leon_prom_info *pspi =
781 (void *)(CFG_PROM_OFFSET + sizeof(srmmu_tables));
783 /* convert into virtual address */
784 pspi = (struct leon_prom_info *)
785 (((unsigned int)pspi & 0x0fffffff) | PAGE_OFFSET);
787 if (nodes[node].level == nodes[node + 1].level)
792 static int PROM_TEXT no_child(int node)
794 /* get physical address */
795 struct leon_prom_info *pspi = (struct leon_prom_info *)
796 (CFG_PROM_OFFSET + sizeof(srmmu_tables));
798 /* convert into virtual address */
799 pspi = (struct leon_prom_info *)
800 (((unsigned int)pspi & 0x0fffffff) | PAGE_OFFSET);
802 if (nodes[node].level == nodes[node + 1].level - 1)
807 static struct property PROM_TEXT *find_property(int node, char *name)
809 /* get physical address */
810 struct leon_prom_info *pspi = (struct leon_prom_info *)
811 (CFG_PROM_OFFSET + sizeof(srmmu_tables));
813 /* convert into virtual address */
814 pspi = (struct leon_prom_info *)
815 (((unsigned int)pspi & 0x0fffffff) | PAGE_OFFSET);
817 struct property *prop = &nodes[node].properties[0];
818 while (prop && prop->name) {
819 if (pspi->reloc_funcs.strcmp(prop->name, name) == 0)
826 static int PROM_TEXT no_proplen(int node, char *name)
828 /* get physical address */
829 struct leon_prom_info *pspi = (struct leon_prom_info *)
830 (CFG_PROM_OFFSET + sizeof(srmmu_tables));
832 /* convert into virtual address */
833 pspi = (struct leon_prom_info *)
834 (((unsigned int)pspi & 0x0fffffff) | PAGE_OFFSET);
836 struct property *prop = pspi->reloc_funcs.find_property(node, name);
842 static int PROM_TEXT no_getprop(int node, char *name, char *value)
844 /* get physical address */
845 struct leon_prom_info *pspi = (struct leon_prom_info *)
846 (CFG_PROM_OFFSET + sizeof(srmmu_tables));
848 /* convert into virtual address */
849 pspi = (struct leon_prom_info *)
850 (((unsigned int)pspi & 0x0fffffff) | PAGE_OFFSET);
852 struct property *prop = pspi->reloc_funcs.find_property(node, name);
854 pspi->reloc_funcs.memcpy(value, prop->value, prop->length);
860 static int PROM_TEXT no_setprop(int node, char *name, char *value, int len)
865 static char PROM_TEXT *no_nextprop(int node, char *name)
867 /* get physical address */
868 struct leon_prom_info *pspi = (struct leon_prom_info *)
869 (CFG_PROM_OFFSET + sizeof(srmmu_tables));
870 struct property *prop;
872 /* convert into virtual address */
873 pspi = (struct leon_prom_info *)
874 (((unsigned int)pspi & 0x0fffffff) | PAGE_OFFSET);
876 if (!name || !name[0])
877 return nodes[node].properties[0].name;
879 prop = pspi->reloc_funcs.find_property(node, name);
885 static int PROM_TEXT leon_strcmp(const char *s1, const char *s2)
887 register char result;
900 static void *PROM_TEXT leon_memcpy(void *dest, const void *src, size_t n)
902 char *dst = (char *)dest, *source = (char *)src;
912 #define GETREGSP(sp) __asm__ __volatile__("mov %%sp, %0" : "=r" (sp))
914 void leon_prom_init(struct leon_prom_info *pspi)
917 unsigned char cksum, *ptr;
918 char *addr_str, *end;
922 pspi->freq_khz = CONFIG_SYS_CLK_FREQ / 1000;
924 /* Set Available main memory size */
925 pspi->totphys.num_bytes = CFG_PROM_OFFSET - CFG_SDRAM_BASE;
926 pspi->avail.num_bytes = pspi->totphys.num_bytes;
928 /* Set the pointer to the Console UART in romvec */
929 pspi->reloc_funcs.leon3_apbuart = leon3_apbuart;
935 b = (ambapp_dev_irqmp *) leon3_getapbbase(VENDOR_GAISLER,
938 j = 1 + ((LEON3_BYPASS_LOAD_PA(&(b->mpstatus))
939 >> LEON3_IRQMPSTATUS_CPUNR) & 0xf);
943 pspi->nodes[2 + j].level = -1;
944 pspi->nodes[2 + j].properties = __va(spi.root_properties + 3);
947 /* Set Ethernet MAC address from environment */
948 if ((addr_str = getenv("ethaddr")) != NULL) {
949 for (i = 0; i < 6; i++) {
950 pspi->idprom.id_ethaddr[i] = addr_str ?
951 simple_strtoul(addr_str, &end, 16) : 0;
953 addr_str = (*end) ? end + 1 : end;
957 /* HW Address not found in environment,
958 * Set default HW address
960 pspi->idprom.id_ethaddr[0] = 0;
961 pspi->idprom.id_ethaddr[1] = 0;
962 pspi->idprom.id_ethaddr[2] = 0;
963 pspi->idprom.id_ethaddr[3] = 0;
964 pspi->idprom.id_ethaddr[4] = 0;
965 pspi->idprom.id_ethaddr[5] = 0;
968 ptr = (unsigned char *)&pspi->idprom;
969 for (i = cksum = 0; i <= 0x0E; i++)
971 pspi->idprom.id_cksum = cksum;
974 static inline void set_cache(unsigned long regval)
976 asm volatile ("sta %0, [%%g0] %1\n\t":: "r" (regval), "i"(2):"memory");
979 extern unsigned short bss_start, bss_end;
981 /* mark as section .img.main.text, to be referenced in linker script */
984 struct leon_prom_info *pspi = (void *)
985 ((((unsigned int)&spi) & PROM_SIZE_MASK) + CFG_PROM_OFFSET);
988 srmmu_set_mmureg(0x00000000);
989 __asm__ __volatile__("flush\n\t");
991 /* init prom info struct */
992 leon_prom_init(pspi);
994 kernel_arg_promvec = &pspi->romvec;
996 printf("Kernel rom vec: 0x%lx\n", (unsigned int)(&pspi->romvec));
1001 /* Copy current kernel boot argument to ROMvec */
1002 void prepare_bootargs(char *bootargs)
1004 struct leon_prom_info *pspi;
1008 /* if no bootargs set, skip copying ==> default bootline */
1009 if (bootargs && (*bootargs != '\0')) {
1010 pspi = (void *)((((unsigned int)&spi) & PROM_SIZE_MASK) +
1013 dst = &pspi->arg[0];
1014 left = 255; /* max len */
1015 while (*src && left > 0) {
1019 /* terminate kernel command line string */
1024 void srmmu_init_cpu(unsigned int entry)
1026 sparc_srmmu_setup *psrmmu_tables = (void *)
1027 ((((unsigned int)&srmmu_tables) & PROM_SIZE_MASK) +
1030 /* Make context 0 (kernel's context) point
1031 * to our prepared memory mapping
1034 psrmmu_tables->ctx_table[0] =
1035 ((unsigned int)&psrmmu_tables->pgd_table[0x00]) >> 4 | PTD;
1037 /* Set virtual kernel address 0xf0000000
1038 * to SRAM/SDRAM address.
1039 * Make it READ/WRITE/EXEC to SuperUser
1042 #define ACC_SU_ALL 0x1c
1043 psrmmu_tables->pgd_table[0xf0] =
1044 (CFG_SDRAM_BASE >> 4) | ACC_SU_ALL | PTE;
1045 psrmmu_tables->pgd_table[0xf1] =
1046 ((CFG_SDRAM_BASE + 0x1000000) >> 4) | ACC_SU_ALL | PTE;
1047 psrmmu_tables->pgd_table[0xf2] =
1048 ((CFG_SDRAM_BASE + 0x2000000) >> 4) | ACC_SU_ALL | PTE;
1049 psrmmu_tables->pgd_table[0xf3] =
1050 ((CFG_SDRAM_BASE + 0x3000000) >> 4) | ACC_SU_ALL | PTE;
1051 psrmmu_tables->pgd_table[0xf4] =
1052 ((CFG_SDRAM_BASE + 0x4000000) >> 4) | ACC_SU_ALL | PTE;
1053 psrmmu_tables->pgd_table[0xf5] =
1054 ((CFG_SDRAM_BASE + 0x5000000) >> 4) | ACC_SU_ALL | PTE;
1055 psrmmu_tables->pgd_table[0xf6] =
1056 ((CFG_SDRAM_BASE + 0x6000000) >> 4) | ACC_SU_ALL | PTE;
1057 psrmmu_tables->pgd_table[0xf7] =
1058 ((CFG_SDRAM_BASE + 0x7000000) >> 4) | ACC_SU_ALL | PTE;
1060 /* convert rom vec pointer to virtual address */
1061 kernel_arg_promvec = (struct linux_romvec *)
1062 (((unsigned int)kernel_arg_promvec & 0x0fffffff) | 0xf0000000);
1064 /* Set Context pointer to point to context table
1065 * 256 contexts supported.
1067 srmmu_set_ctable_ptr((unsigned int)&psrmmu_tables->ctx_table[0]);
1069 /* Set kernel's context, context zero */
1070 srmmu_set_context(0);
1072 /* Invalidate all Cache */
1073 __asm__ __volatile__("flush\n\t");
1075 srmmu_set_mmureg(0x00000001);
1076 leon_flush_tlb_all();
1077 leon_flush_cache_all();