[U-Boot] [RFC PATCH v1 4/9] sparc: Major rewrite of the PROM generation code
Francois Retief
fgretief at spaceteq.co.za
Wed Oct 29 09:53:02 CET 2014
Rewrote the PROM generation code to dynamically build the PROM from
the AMBA PnP data on the LEON3. Also combined the LEON2/LEON3 code
into one file and moved it to the arch/sparc/lib folder. The new code
generates the PROM data rather than having it embedded as data and
copying it over. The algorithm is also optimized to reduce the size of
the resulting PROM data, e.g. pointers is encoded into 16-bit values
and duplicate names point to the same copy of the string.
Also added a few more AMBA vendor/device ID pairs to cmd_ambapp.c.
Refactored the SRMMU handling code into a seperate file. Added a
function to build the default page tables instead of adding them at
compile time.
The bootm.c file were also updated to search for the kernel header,
instead of being a hard coded offset.
This code has been tested against a Linux v3.10.20 kernel.
Signed-off-by: Francois Retief <fgretief at spaceteq.co.za>
---
arch/sparc/cpu/leon2/Makefile | 2 +-
arch/sparc/cpu/leon2/prom.c | 1030 -------------------------------------
arch/sparc/cpu/leon3/Makefile | 5 +-
arch/sparc/cpu/leon3/prom.c | 2 +-
arch/sparc/include/asm/machines.h | 4 +-
arch/sparc/lib/Makefile | 4 +-
arch/sparc/lib/bootm.c | 81 +--
arch/sparc/lib/prom-no.c | 319 ++++++++++++
arch/sparc/lib/prom-no.h | 40 ++
arch/sparc/lib/prom.c | 960 ++++++++++++++++++++++++++++++++++
arch/sparc/lib/srmmu.c | 90 ++++
common/cmd_ambapp.c | 18 +-
include/ambapp.h | 27 +-
13 files changed, 1509 insertions(+), 1073 deletions(-)
delete mode 100644 arch/sparc/cpu/leon2/prom.c
create mode 100644 arch/sparc/lib/prom-no.c
create mode 100644 arch/sparc/lib/prom-no.h
create mode 100644 arch/sparc/lib/prom.c
create mode 100644 arch/sparc/lib/srmmu.c
diff --git a/arch/sparc/cpu/leon2/Makefile b/arch/sparc/cpu/leon2/Makefile
index 8c95ca5..1a2dae6 100644
--- a/arch/sparc/cpu/leon2/Makefile
+++ b/arch/sparc/cpu/leon2/Makefile
@@ -6,4 +6,4 @@
#
extra-y = start.o
-obj-y = cpu_init.o serial.o cpu.o interrupts.o prom.o
+obj-y = cpu_init.o serial.o cpu.o interrupts.o
diff --git a/arch/sparc/cpu/leon2/prom.c b/arch/sparc/cpu/leon2/prom.c
deleted file mode 100644
index cd2571f..0000000
--- a/arch/sparc/cpu/leon2/prom.c
+++ /dev/null
@@ -1,1030 +0,0 @@
-/* prom.c - emulates a sparc v0 PROM for the linux kernel.
- *
- * Copyright (C) 2003 Konrad Eisele <eiselekd at web.de>
- * Copyright (C) 2004 Stefan Holst <mail at s-holst.de>
- * Copyright (C) 2007 Daniel Hellstrom <daniel at gaisler.com>
- *
- * SPDX-License-Identifier: GPL-2.0+
- */
-
-#include <common.h>
-#include <asm/prom.h>
-#include <asm/machines.h>
-#include <asm/srmmu.h>
-#include <asm/processor.h>
-#include <asm/irq.h>
-#include <asm/leon.h>
-
-#include <config.h>
-/*
-#define PRINT_ROM_VEC
-*/
-extern struct linux_romvec *kernel_arg_promvec;
-
-#define PROM_PGT __attribute__ ((__section__ (".prom.pgt")))
-#define PROM_TEXT __attribute__ ((__section__ (".prom.text")))
-#define PROM_DATA __attribute__ ((__section__ (".prom.data")))
-
-/* for __va */
-extern int __prom_start;
-#define PAGE_OFFSET 0xf0000000
-#define phys_base CONFIG_SYS_SDRAM_BASE
-#define PROM_OFFS 8192
-#define PROM_SIZE_MASK (PROM_OFFS-1)
-#define __va(x) ( \
- (void *)( ((unsigned long)(x))-PROM_OFFS+ \
- (CONFIG_SYS_PROM_OFFSET-phys_base)+PAGE_OFFSET-CONFIG_SYS_TEXT_BASE ) \
- )
-#define __phy(x) ((void *)(((unsigned long)(x))-PROM_OFFS+CONFIG_SYS_PROM_OFFSET-CONFIG_SYS_TEXT_BASE))
-
-struct property {
- char *name;
- char *value;
- int length;
-};
-
-struct node {
- int level;
- struct property *properties;
-};
-
-static void leon_reboot(char *bcommand);
-static void leon_halt(void);
-static int leon_nbputchar(int c);
-static int leon_nbgetchar(void);
-
-static int no_nextnode(int node);
-static int no_child(int node);
-static int no_proplen(int node, char *name);
-static int no_getprop(int node, char *name, char *value);
-static int no_setprop(int node, char *name, char *value, int len);
-static char *no_nextprop(int node, char *name);
-
-static struct property PROM_TEXT *find_property(int node, char *name);
-static int PROM_TEXT leon_strcmp(const char *s1, const char *s2);
-static void *PROM_TEXT leon_memcpy(void *dest, const void *src, size_t n);
-static void PROM_TEXT leon_reboot_physical(char *bcommand);
-
-void __inline__ leon_flush_cache_all(void)
-{
- __asm__ __volatile__(" flush ");
- __asm__ __volatile__("sta %%g0, [%%g0] %0\n\t"::"i"(ASI_DFLUSH):"memory");
-}
-
-void __inline__ leon_flush_tlb_all(void)
-{
- leon_flush_cache_all();
- __asm__ __volatile__("sta %%g0, [%0] %1\n\t"::"r"(0x400),
- "i"(ASI_MMUFLUSH):"memory");
-}
-
-typedef struct {
- unsigned int ctx_table[256];
- unsigned int pgd_table[256];
-} sparc_srmmu_setup;
-
-sparc_srmmu_setup srmmu_tables PROM_PGT = {
- {0},
- {0x1e,
- 0x10001e,
- 0x20001e,
- 0x30001e,
- 0x40001e,
- 0x50001e,
- 0x60001e,
- 0x70001e,
- 0x80001e,
- 0x90001e,
- 0xa0001e,
- 0xb0001e,
- 0xc0001e,
- 0xd0001e,
- 0xe0001e,
- 0xf0001e,
- 0x100001e,
- 0x110001e,
- 0x120001e,
- 0x130001e,
- 0x140001e,
- 0x150001e,
- 0x160001e,
- 0x170001e,
- 0x180001e,
- 0x190001e,
- 0x1a0001e,
- 0x1b0001e,
- 0x1c0001e,
- 0x1d0001e,
- 0x1e0001e,
- 0x1f0001e,
- 0x200001e,
- 0x210001e,
- 0x220001e,
- 0x230001e,
- 0x240001e,
- 0x250001e,
- 0x260001e,
- 0x270001e,
- 0x280001e,
- 0x290001e,
- 0x2a0001e,
- 0x2b0001e,
- 0x2c0001e,
- 0x2d0001e,
- 0x2e0001e,
- 0x2f0001e,
- 0x300001e,
- 0x310001e,
- 0x320001e,
- 0x330001e,
- 0x340001e,
- 0x350001e,
- 0x360001e,
- 0x370001e,
- 0x380001e,
- 0x390001e,
- 0x3a0001e,
- 0x3b0001e,
- 0x3c0001e,
- 0x3d0001e,
- 0x3e0001e,
- 0x3f0001e,
- 0x400001e,
- 0x410001e,
- 0x420001e,
- 0x430001e,
- 0x440001e,
- 0x450001e,
- 0x460001e,
- 0x470001e,
- 0x480001e,
- 0x490001e,
- 0x4a0001e,
- 0x4b0001e,
- 0x4c0001e,
- 0x4d0001e,
- 0x4e0001e,
- 0x4f0001e,
- 0x500001e,
- 0x510001e,
- 0x520001e,
- 0x530001e,
- 0x540001e,
- 0x550001e,
- 0x560001e,
- 0x570001e,
- 0x580001e,
- 0x590001e,
- 0x5a0001e,
- 0x5b0001e,
- 0x5c0001e,
- 0x5d0001e,
- 0x5e0001e,
- 0x5f0001e,
- 0x600001e,
- 0x610001e,
- 0x620001e,
- 0x630001e,
- 0x640001e,
- 0x650001e,
- 0x660001e,
- 0x670001e,
- 0x680001e,
- 0x690001e,
- 0x6a0001e,
- 0x6b0001e,
- 0x6c0001e,
- 0x6d0001e,
- 0x6e0001e,
- 0x6f0001e,
- 0x700001e,
- 0x710001e,
- 0x720001e,
- 0x730001e,
- 0x740001e,
- 0x750001e,
- 0x760001e,
- 0x770001e,
- 0x780001e,
- 0x790001e,
- 0x7a0001e,
- 0x7b0001e,
- 0x7c0001e,
- 0x7d0001e,
- 0x7e0001e,
- 0x7f0001e,
- 0x800001e,
- 0x810001e,
- 0x820001e,
- 0x830001e,
- 0x840001e,
- 0x850001e,
- 0x860001e,
- 0x870001e,
- 0x880001e,
- 0x890001e,
- 0x8a0001e,
- 0x8b0001e,
- 0x8c0001e,
- 0x8d0001e,
- 0x8e0001e,
- 0x8f0001e,
- 0x900001e,
- 0x910001e,
- 0x920001e,
- 0x930001e,
- 0x940001e,
- 0x950001e,
- 0x960001e,
- 0x970001e,
- 0x980001e,
- 0x990001e,
- 0x9a0001e,
- 0x9b0001e,
- 0x9c0001e,
- 0x9d0001e,
- 0x9e0001e,
- 0x9f0001e,
- 0xa00001e,
- 0xa10001e,
- 0xa20001e,
- 0xa30001e,
- 0xa40001e,
- 0xa50001e,
- 0xa60001e,
- 0xa70001e,
- 0xa80001e,
- 0xa90001e,
- 0xaa0001e,
- 0xab0001e,
- 0xac0001e,
- 0xad0001e,
- 0xae0001e,
- 0xaf0001e,
- 0xb00001e,
- 0xb10001e,
- 0xb20001e,
- 0xb30001e,
- 0xb40001e,
- 0xb50001e,
- 0xb60001e,
- 0xb70001e,
- 0xb80001e,
- 0xb90001e,
- 0xba0001e,
- 0xbb0001e,
- 0xbc0001e,
- 0xbd0001e,
- 0xbe0001e,
- 0xbf0001e,
- 0xc00001e,
- 0xc10001e,
- 0xc20001e,
- 0xc30001e,
- 0xc40001e,
- 0xc50001e,
- 0xc60001e,
- 0xc70001e,
- 0xc80001e,
- 0xc90001e,
- 0xca0001e,
- 0xcb0001e,
- 0xcc0001e,
- 0xcd0001e,
- 0xce0001e,
- 0xcf0001e,
- 0xd00001e,
- 0xd10001e,
- 0xd20001e,
- 0xd30001e,
- 0xd40001e,
- 0xd50001e,
- 0xd60001e,
- 0xd70001e,
- 0xd80001e,
- 0xd90001e,
- 0xda0001e,
- 0xdb0001e,
- 0xdc0001e,
- 0xdd0001e,
- 0xde0001e,
- 0xdf0001e,
- 0xe00001e,
- 0xe10001e,
- 0xe20001e,
- 0xe30001e,
- 0xe40001e,
- 0xe50001e,
- 0xe60001e,
- 0xe70001e,
- 0xe80001e,
- 0xe90001e,
- 0xea0001e,
- 0xeb0001e,
- 0xec0001e,
- 0xed0001e,
- 0xee0001e,
- 0xef0001e,
- 0x400001e /* default */
- }
-};
-
-/* a self contained prom info structure */
-struct leon_reloc_func {
- struct property *(*find_property) (int node, char *name);
- int (*strcmp) (char *s1, char *s2);
- void *(*memcpy) (void *dest, const void *src, size_t n);
- void (*reboot_physical) (char *cmd);
-};
-
-struct leon_prom_info {
- int freq_khz;
- int leon_nctx;
- int mids[32];
- int baudrates[2];
- struct leon_reloc_func reloc_funcs;
- struct property root_properties[4];
- struct property cpu_properties[7];
-#undef CPUENTRY
-#define CPUENTRY(idx) struct property cpu_properties##idx[4]
- CPUENTRY(1);
- CPUENTRY(2);
- CPUENTRY(3);
- CPUENTRY(4);
- CPUENTRY(5);
- CPUENTRY(6);
- CPUENTRY(7);
- CPUENTRY(8);
- CPUENTRY(9);
- CPUENTRY(10);
- CPUENTRY(11);
- CPUENTRY(12);
- CPUENTRY(13);
- CPUENTRY(14);
- CPUENTRY(15);
- CPUENTRY(16);
- CPUENTRY(17);
- CPUENTRY(18);
- CPUENTRY(19);
- CPUENTRY(20);
- CPUENTRY(21);
- CPUENTRY(22);
- CPUENTRY(23);
- CPUENTRY(24);
- CPUENTRY(25);
- CPUENTRY(26);
- CPUENTRY(27);
- CPUENTRY(28);
- CPUENTRY(29);
- CPUENTRY(30);
- CPUENTRY(31);
- struct idprom idprom;
- struct linux_nodeops nodeops;
- struct linux_mlist_v0 *totphys_p;
- struct linux_mlist_v0 totphys;
- struct linux_mlist_v0 *avail_p;
- struct linux_mlist_v0 avail;
- struct linux_mlist_v0 *prommap_p;
- void (*synchook) (void);
- struct linux_arguments_v0 *bootargs_p;
- struct linux_arguments_v0 bootargs;
- struct linux_romvec romvec;
- struct node nodes[35];
- char s_device_type[12];
- char s_cpu[4];
- char s_mid[4];
- char s_idprom[7];
- char s_compatability[14];
- char s_leon2[6];
- char s_mmu_nctx[9];
- char s_frequency[16];
- char s_uart1_baud[11];
- char s_uart2_baud[11];
- char arg[256];
-};
-
-/* static prom info */
-static struct leon_prom_info PROM_DATA spi = {
- CONFIG_SYS_CLK_FREQ / 1000,
- 256,
- {
-#undef CPUENTRY
-#define CPUENTRY(idx) idx
- CPUENTRY(0),
- CPUENTRY(1),
- CPUENTRY(2),
- CPUENTRY(3),
- CPUENTRY(4),
- CPUENTRY(5),
- CPUENTRY(6),
- CPUENTRY(7),
- CPUENTRY(8),
- CPUENTRY(9),
- CPUENTRY(10),
- CPUENTRY(11),
- CPUENTRY(12),
- CPUENTRY(13),
- CPUENTRY(14),
- CPUENTRY(15),
- CPUENTRY(16),
- CPUENTRY(17),
- CPUENTRY(18),
- CPUENTRY(19),
- CPUENTRY(20),
- CPUENTRY(21),
- CPUENTRY(22),
- CPUENTRY(23),
- CPUENTRY(24),
- CPUENTRY(25),
- CPUENTRY(26),
- CPUENTRY(27),
- CPUENTRY(28),
- CPUENTRY(29),
- CPUENTRY(30),
- 31},
- {38400, 38400},
- {
- __va(find_property),
- __va(leon_strcmp),
- __va(leon_memcpy),
- __phy(leon_reboot_physical),
- },
- {
- {__va(spi.s_device_type), __va(spi.s_idprom), 4},
- {__va(spi.s_idprom), (char *)__va(&spi.idprom), sizeof(struct idprom)},
- {__va(spi.s_compatability), __va(spi.s_leon2), 5},
- {NULL, NULL, -1}
- },
- {
- {__va(spi.s_device_type), __va(spi.s_cpu), 4},
- {__va(spi.s_mid), __va(&spi.mids[0]), 4},
- {__va(spi.s_mmu_nctx), (char *)__va(&spi.leon_nctx), 4},
- {__va(spi.s_frequency), (char *)__va(&spi.freq_khz), 4},
- {__va(spi.s_uart1_baud), (char *)__va(&spi.baudrates[0]), 4},
- {__va(spi.s_uart2_baud), (char *)__va(&spi.baudrates[1]), 4},
- {NULL, NULL, -1}
- },
-#undef CPUENTRY
-#define CPUENTRY(idx) \
- { /* cpu_properties */ \
- {__va(spi.s_device_type), __va(spi.s_cpu), 4}, \
- {__va(spi.s_mid), __va(&spi.mids[idx]), 4}, \
- {__va(spi.s_frequency), (char *)__va(&spi.freq_khz), 4}, \
- {NULL, NULL, -1} \
- }
- CPUENTRY(1),
- CPUENTRY(2),
- CPUENTRY(3),
- CPUENTRY(4),
- CPUENTRY(5),
- CPUENTRY(6),
- CPUENTRY(7),
- CPUENTRY(8),
- CPUENTRY(9),
- CPUENTRY(10),
- CPUENTRY(11),
- CPUENTRY(12),
- CPUENTRY(13),
- CPUENTRY(14),
- CPUENTRY(15),
- CPUENTRY(16),
- CPUENTRY(17),
- CPUENTRY(18),
- CPUENTRY(19),
- CPUENTRY(20),
- CPUENTRY(21),
- CPUENTRY(22),
- CPUENTRY(23),
- CPUENTRY(24),
- CPUENTRY(25),
- CPUENTRY(26),
- CPUENTRY(27),
- CPUENTRY(28),
- CPUENTRY(29),
- CPUENTRY(30),
- CPUENTRY(31),
- {
- 0x01, /* format */
- M_LEON2 | M_LEON2_SOC, /* machine type */
- {0, 0, 0, 0, 0, 0}, /* eth */
- 0, /* date */
- 0, /* sernum */
- 0, /* checksum */
- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} /* reserved */
- },
- {
- __va(no_nextnode),
- __va(no_child),
- __va(no_proplen),
- __va(no_getprop),
- __va(no_setprop),
- __va(no_nextprop)
- },
- __va(&spi.totphys),
- {
- NULL,
- (char *)CONFIG_SYS_SDRAM_BASE,
- 0,
- },
- __va(&spi.avail),
- {
- NULL,
- (char *)CONFIG_SYS_SDRAM_BASE,
- 0,
- },
- NULL, /* prommap_p */
- NULL,
- __va(&spi.bootargs),
- {
- {NULL, __va(spi.arg), NULL /*... */ },
- /*... */
- },
- {
- 0,
- 0, /* sun4c v0 prom */
- 0, 0,
- {__va(&spi.totphys_p), __va(&spi.prommap_p), __va(&spi.avail_p)},
- __va(&spi.nodeops),
- NULL, {NULL /* ... */ },
- NULL, NULL,
- NULL, NULL, /* pv_getchar, pv_putchar */
- __va(leon_nbgetchar), __va(leon_nbputchar),
- NULL,
- __va(leon_reboot),
- NULL,
- NULL,
- NULL,
- __va(leon_halt),
- __va(&spi.synchook),
- {NULL},
- __va(&spi.bootargs_p)
- /*... */
- },
- {
- {0, __va(spi.root_properties + 3) /* NULL, NULL, -1 */ },
- {0, __va(spi.root_properties)},
- /* cpu 0, must be spi.nodes[2] see leon_prom_init() */
- {1, __va(spi.cpu_properties)},
-
-#undef CPUENTRY
-#define CPUENTRY(idx) \
- {1, __va(spi.cpu_properties##idx) } /* cpu <idx> */
- CPUENTRY(1),
- CPUENTRY(2),
- CPUENTRY(3),
- CPUENTRY(4),
- CPUENTRY(5),
- CPUENTRY(6),
- CPUENTRY(7),
- CPUENTRY(8),
- CPUENTRY(9),
- CPUENTRY(10),
- CPUENTRY(11),
- CPUENTRY(12),
- CPUENTRY(13),
- CPUENTRY(14),
- CPUENTRY(15),
- CPUENTRY(16),
- CPUENTRY(17),
- CPUENTRY(18),
- CPUENTRY(19),
- CPUENTRY(20),
- CPUENTRY(21),
- CPUENTRY(22),
- CPUENTRY(23),
- CPUENTRY(24),
- CPUENTRY(25),
- CPUENTRY(26),
- CPUENTRY(27),
- CPUENTRY(28),
- CPUENTRY(29),
- CPUENTRY(30),
- CPUENTRY(31),
- {-1, __va(spi.root_properties + 3) /* NULL, NULL, -1 */ }
- },
- "device_type",
- "cpu",
- "mid",
- "idprom",
- "compatability",
- "leon2",
- "mmu-nctx",
- "clock-frequency",
- "uart1_baud",
- "uart2_baud",
- CONFIG_DEFAULT_KERNEL_COMMAND_LINE
-};
-
-/* from arch/sparc/kernel/setup.c */
-#define RAMDISK_LOAD_FLAG 0x4000
-extern unsigned short root_flags;
-extern unsigned short root_dev;
-extern unsigned short ram_flags;
-extern unsigned int sparc_ramdisk_image;
-extern unsigned int sparc_ramdisk_size;
-extern int root_mountflags;
-
-extern char initrd_end, initrd_start;
-
-/* Reboot the CPU = jump to beginning of flash again.
- *
- * Make sure that all function are inlined here.
- */
-static void PROM_TEXT leon_reboot(char *bcommand)
-{
- register char *arg = bcommand;
- void __attribute__ ((noreturn)) (*reboot_physical) (char *cmd);
-
- /* get physical address */
- struct leon_prom_info *pspi =
- (void *)(CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables));
-
- unsigned int *srmmu_ctx_table;
-
- /* Turn of Interrupts */
- set_pil(0xf);
-
- /* Set kernel's context, context zero */
- srmmu_set_context(0);
-
- /* Get physical address of the MMU shutdown routine */
- reboot_physical = (void *)
- SPARC_BYPASS_READ(&pspi->reloc_funcs.reboot_physical);
-
- /* Now that we know the physical address of the function
- * we can make the MMU allow jumping to it.
- */
- srmmu_ctx_table = (unsigned int *)srmmu_get_ctable_ptr();
-
- srmmu_ctx_table = (unsigned int *)SPARC_BYPASS_READ(srmmu_ctx_table);
-
- /* get physical address of kernel's context table (assume ptd) */
- srmmu_ctx_table = (unsigned int *)
- (((unsigned int)srmmu_ctx_table & 0xfffffffc) << 4);
-
- /* enable access to physical address of MMU shutdown function */
- SPARC_BYPASS_WRITE(&srmmu_ctx_table
- [((unsigned int)reboot_physical) >> 24],
- (((unsigned int)reboot_physical & 0xff000000) >> 4) |
- 0x1e);
-
- /* flush TLB cache */
- leon_flush_tlb_all();
-
- /* flash instruction & data cache */
- sparc_icache_flush_all();
- sparc_dcache_flush_all();
-
- /* jump to physical address function
- * so that when the MMU is disabled
- * we can continue to execute
- */
- reboot_physical(arg);
-}
-
-static void PROM_TEXT leon_reboot_physical(char *bcommand)
-{
- void __attribute__ ((noreturn)) (*reset) (void);
-
- /* Turn off MMU */
- srmmu_set_mmureg(0);
-
- /* Hardcoded start address */
- reset = CONFIG_SYS_MONITOR_BASE;
-
- /* flush data cache */
- sparc_dcache_flush_all();
-
- /* flush instruction cache */
- sparc_icache_flush_all();
-
- /* Jump to start in Flash */
- reset();
-}
-
-static void PROM_TEXT leon_halt(void)
-{
- while (1) ;
-}
-
-/* get single char, don't care for blocking*/
-static int PROM_TEXT leon_nbgetchar(void)
-{
- return -1;
-}
-
-/* put single char, don't care for blocking*/
-static int PROM_TEXT leon_nbputchar(int c)
-{
- LEON2_regs *leon2 = (LEON2_regs *) LEON2_PREGS;
-
- /***** put char in buffer... ***********
- * Make sure all functions are inline! *
- ***************************************/
-
- /* Wait for last character to go. */
- while (!(SPARC_BYPASS_READ(&leon2->UART_Status_1)
- & LEON2_UART_STAT_THE)) ;
-
- /* Send data */
- SPARC_BYPASS_WRITE(&leon2->UART_Channel_1, c);
-
- /* Wait for data to be sent */
- while (!(SPARC_BYPASS_READ(&leon2->UART_Status_1)
- & LEON2_UART_STAT_TSE)) ;
-
- return 0;
-}
-
-/* node ops */
-
-/*#define nodes ((struct node *)__va(&pspi->nodes))*/
-#define nodes ((struct node *)(pspi->nodes))
-
-static int PROM_TEXT no_nextnode(int node)
-{
- /* get physical address */
- struct leon_prom_info *pspi =
- (void *)(CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables));
-
- /* convert into virtual address */
- pspi = (struct leon_prom_info *)
- (((unsigned int)pspi & 0x0fffffff) | PAGE_OFFSET);
-
- if (nodes[node].level == nodes[node + 1].level)
- return node + 1;
- return -1;
-}
-
-static int PROM_TEXT no_child(int node)
-{
- /* get physical address */
- struct leon_prom_info *pspi = (struct leon_prom_info *)
- (CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables));
-
- /* convert into virtual address */
- pspi = (struct leon_prom_info *)
- (((unsigned int)pspi & 0x0fffffff) | PAGE_OFFSET);
-
- if (nodes[node].level == nodes[node + 1].level - 1)
- return node + 1;
- return -1;
-}
-
-static struct property PROM_TEXT *find_property(int node, char *name)
-{
- /* get physical address */
- struct leon_prom_info *pspi = (struct leon_prom_info *)
- (CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables));
-
- /* convert into virtual address */
- pspi = (struct leon_prom_info *)
- (((unsigned int)pspi & 0x0fffffff) | PAGE_OFFSET);
-
- struct property *prop = &nodes[node].properties[0];
- while (prop && prop->name) {
- if (pspi->reloc_funcs.strcmp(prop->name, name) == 0)
- return prop;
- prop++;
- }
- return NULL;
-}
-
-static int PROM_TEXT no_proplen(int node, char *name)
-{
- /* get physical address */
- struct leon_prom_info *pspi = (struct leon_prom_info *)
- (CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables));
-
- /* convert into virtual address */
- pspi = (struct leon_prom_info *)
- (((unsigned int)pspi & 0x0fffffff) | PAGE_OFFSET);
-
- struct property *prop = pspi->reloc_funcs.find_property(node, name);
- if (prop)
- return prop->length;
- return -1;
-}
-
-static int PROM_TEXT no_getprop(int node, char *name, char *value)
-{
- /* get physical address */
- struct leon_prom_info *pspi = (struct leon_prom_info *)
- (CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables));
-
- /* convert into virtual address */
- pspi = (struct leon_prom_info *)
- (((unsigned int)pspi & 0x0fffffff) | PAGE_OFFSET);
-
- struct property *prop = pspi->reloc_funcs.find_property(node, name);
- if (prop) {
- pspi->reloc_funcs.memcpy(value, prop->value, prop->length);
- return 1;
- }
- return -1;
-}
-
-static int PROM_TEXT no_setprop(int node, char *name, char *value, int len)
-{
- return -1;
-}
-
-static char PROM_TEXT *no_nextprop(int node, char *name)
-{
- /* get physical address */
- struct leon_prom_info *pspi = (struct leon_prom_info *)
- (CONFIG_SYS_PROM_OFFSET + sizeof(srmmu_tables));
- struct property *prop;
-
- /* convert into virtual address */
- pspi = (struct leon_prom_info *)
- (((unsigned int)pspi & 0x0fffffff) | PAGE_OFFSET);
-
- if (!name || !name[0])
- return nodes[node].properties[0].name;
-
- prop = pspi->reloc_funcs.find_property(node, name);
- if (prop)
- return prop[1].name;
- return NULL;
-}
-
-static int PROM_TEXT leon_strcmp(const char *s1, const char *s2)
-{
- register char result;
-
- while (1) {
- result = *s1 - *s2;
- if (result || !*s1)
- break;
- s2++;
- s1++;
- }
-
- return result;
-}
-
-static void *PROM_TEXT leon_memcpy(void *dest, const void *src, size_t n)
-{
- char *dst = (char *)dest, *source = (char *)src;
-
- while (n--) {
- *dst = *source;
- dst++;
- source++;
- }
- return dest;
-}
-
-#define GETREGSP(sp) __asm__ __volatile__("mov %%sp, %0" : "=r" (sp))
-
-void leon_prom_init(struct leon_prom_info *pspi)
-{
- unsigned long i;
- unsigned char cksum, *ptr;
- char *addr_str, *end;
- unsigned long sp;
- GETREGSP(sp);
-
- pspi->freq_khz = CONFIG_SYS_CLK_FREQ / 1000;
-
- /* Set Available main memory size */
- pspi->totphys.num_bytes = CONFIG_SYS_PROM_OFFSET - CONFIG_SYS_SDRAM_BASE;
- pspi->avail.num_bytes = pspi->totphys.num_bytes;
-
-#undef nodes
- pspi->nodes[3].level = -1;
- pspi->nodes[3].properties = __va(spi.root_properties + 3);
-
- /* Set Ethernet MAC address from environment */
- if ((addr_str = getenv("ethaddr")) != NULL) {
- for (i = 0; i < 6; i++) {
- pspi->idprom.id_ethaddr[i] = addr_str ?
- simple_strtoul(addr_str, &end, 16) : 0;
- if (addr_str) {
- addr_str = (*end) ? end + 1 : end;
- }
- }
- } else {
- /* HW Address not found in environment,
- * Set default HW address
- */
- pspi->idprom.id_ethaddr[0] = 0;
- pspi->idprom.id_ethaddr[1] = 0;
- pspi->idprom.id_ethaddr[2] = 0;
- pspi->idprom.id_ethaddr[3] = 0;
- pspi->idprom.id_ethaddr[4] = 0;
- pspi->idprom.id_ethaddr[5] = 0;
- }
-
- ptr = (unsigned char *)&pspi->idprom;
- for (i = cksum = 0; i <= 0x0E; i++)
- cksum ^= *ptr++;
- pspi->idprom.id_cksum = cksum;
-}
-
-static inline void set_cache(unsigned long regval)
-{
- asm volatile ("sta %0, [%%g0] %1\n\t":: "r" (regval), "i"(2):"memory");
-}
-
-extern unsigned short bss_start, bss_end;
-
-/* mark as section .img.main.text, to be referenced in linker script */
-int prom_init(void)
-{
- struct leon_prom_info *pspi = (void *)
- ((((unsigned int)&spi) & PROM_SIZE_MASK) + CONFIG_SYS_PROM_OFFSET);
-
- /* disable mmu */
- srmmu_set_mmureg(0x00000000);
- __asm__ __volatile__("flush\n\t");
-
- /* init prom info struct */
- leon_prom_init(pspi);
-
- kernel_arg_promvec = &pspi->romvec;
-#ifdef PRINT_ROM_VEC
- printf("Kernel rom vec: 0x%lx\n", (unsigned int)(&pspi->romvec));
-#endif
- return 0;
-}
-
-/* Copy current kernel boot argument to ROMvec */
-void prepare_bootargs(char *bootargs)
-{
- struct leon_prom_info *pspi;
- char *src, *dst;
- int left;
-
- /* if no bootargs set, skip copying ==> default bootline */
- if (bootargs && (*bootargs != '\0')) {
- pspi = (void *)((((unsigned int)&spi) & PROM_SIZE_MASK) +
- CONFIG_SYS_PROM_OFFSET);
- src = bootargs;
- dst = &pspi->arg[0];
- left = 255; /* max len */
- while (*src && left > 0) {
- *dst++ = *src++;
- left--;
- }
- /* terminate kernel command line string */
- *dst = 0;
- }
-}
-
-void srmmu_init_cpu(unsigned int entry)
-{
- sparc_srmmu_setup *psrmmu_tables = (void *)
- ((((unsigned int)&srmmu_tables) & PROM_SIZE_MASK) +
- CONFIG_SYS_PROM_OFFSET);
-
- /* Make context 0 (kernel's context) point
- * to our prepared memory mapping
- */
-#define PTD 1
- psrmmu_tables->ctx_table[0] =
- ((unsigned int)&psrmmu_tables->pgd_table[0x00]) >> 4 | PTD;
-
- /* Set virtual kernel address 0xf0000000
- * to SRAM/SDRAM address.
- * Make it READ/WRITE/EXEC to SuperUser
- */
-#define PTE 2
-#define ACC_SU_ALL 0x1c
- psrmmu_tables->pgd_table[0xf0] =
- (CONFIG_SYS_SDRAM_BASE >> 4) | ACC_SU_ALL | PTE;
- psrmmu_tables->pgd_table[0xf1] =
- ((CONFIG_SYS_SDRAM_BASE + 0x1000000) >> 4) | ACC_SU_ALL | PTE;
- psrmmu_tables->pgd_table[0xf2] =
- ((CONFIG_SYS_SDRAM_BASE + 0x2000000) >> 4) | ACC_SU_ALL | PTE;
- psrmmu_tables->pgd_table[0xf3] =
- ((CONFIG_SYS_SDRAM_BASE + 0x3000000) >> 4) | ACC_SU_ALL | PTE;
- psrmmu_tables->pgd_table[0xf4] =
- ((CONFIG_SYS_SDRAM_BASE + 0x4000000) >> 4) | ACC_SU_ALL | PTE;
- psrmmu_tables->pgd_table[0xf5] =
- ((CONFIG_SYS_SDRAM_BASE + 0x5000000) >> 4) | ACC_SU_ALL | PTE;
- psrmmu_tables->pgd_table[0xf6] =
- ((CONFIG_SYS_SDRAM_BASE + 0x6000000) >> 4) | ACC_SU_ALL | PTE;
- psrmmu_tables->pgd_table[0xf7] =
- ((CONFIG_SYS_SDRAM_BASE + 0x7000000) >> 4) | ACC_SU_ALL | PTE;
-
- /* convert rom vec pointer to virtual address */
- kernel_arg_promvec = (struct linux_romvec *)
- (((unsigned int)kernel_arg_promvec & 0x0fffffff) | 0xf0000000);
-
- /* Set Context pointer to point to context table
- * 256 contexts supported.
- */
- srmmu_set_ctable_ptr((unsigned int)&psrmmu_tables->ctx_table[0]);
-
- /* Set kernel's context, context zero */
- srmmu_set_context(0);
-
- /* Invalidate all Cache */
- __asm__ __volatile__("flush\n\t");
-
- srmmu_set_mmureg(0x00000001);
- leon_flush_tlb_all();
- leon_flush_cache_all();
-}
diff --git a/arch/sparc/cpu/leon3/Makefile b/arch/sparc/cpu/leon3/Makefile
index 4f13ec3..0131f22 100644
--- a/arch/sparc/cpu/leon3/Makefile
+++ b/arch/sparc/cpu/leon3/Makefile
@@ -6,4 +6,7 @@
#
extra-y = start.o
-obj-y = cpu_init.o serial.o cpu.o ambapp.o interrupts.o prom.o usb_uhci.o
+
+obj-y = cpu_init.o serial.o cpu.o ambapp.o interrupts.o
+
+obj-$(CONFIG_USB_UHCI) += usb_uhci.o
diff --git a/arch/sparc/cpu/leon3/prom.c b/arch/sparc/cpu/leon3/prom.c
index b83776b..e9e9a71 100644
--- a/arch/sparc/cpu/leon3/prom.c
+++ b/arch/sparc/cpu/leon3/prom.c
@@ -695,7 +695,7 @@ static void PROM_TEXT leon_reboot_physical(char *bcommand)
srmmu_set_mmureg(0);
/* Hardcoded start address */
- reset = CONFIG_SYS_MONITOR_BASE;
+ reset = (void*)CONFIG_SYS_MONITOR_BASE;
/* flush data cache */
sparc_dcache_flush_all();
diff --git a/arch/sparc/include/asm/machines.h b/arch/sparc/include/asm/machines.h
index e209f3f..1abbd13 100644
--- a/arch/sparc/include/asm/machines.h
+++ b/arch/sparc/include/asm/machines.h
@@ -37,7 +37,7 @@ extern struct Sun_Machine_Models Sun_Machines[NUM_SUN_MACHINES];
#define SM_ARCH_MASK 0xf0
#define SM_SUN4 0x20
-#define M_LEON2 0x30
+#define M_LEON 0x30
#define SM_SUN4C 0x50
#define SM_SUN4M 0x70
#define SM_SUN4M_OBP 0x80
@@ -51,6 +51,8 @@ extern struct Sun_Machine_Models Sun_Machines[NUM_SUN_MACHINES];
/* Leon machines */
#define M_LEON2_SOC 0x01 /* Leon2 SoC */
+#define M_LEON3_SOC 0x02 /* Leon3 SoC */
+#define M_LEON4_SOC 0x03 /* Leon4 SoC */
/* Sun4c machines Full Name - PROM NAME */
#define SM_4C_SS1 0x01 /* Sun4c SparcStation 1 - Sun 4/60 */
diff --git a/arch/sparc/lib/Makefile b/arch/sparc/lib/Makefile
index 84c3ac2..bf2de51 100644
--- a/arch/sparc/lib/Makefile
+++ b/arch/sparc/lib/Makefile
@@ -5,7 +5,9 @@
# SPDX-License-Identifier: GPL-2.0+
#
-obj-y = cache.o interrupts.o time.o
+obj-y = cache.o interrupts.o time.o srmmu.o
+
+obj-y += prom.o prom-no.o
obj-$(CONFIG_CMD_BOOTM) += bootm.o
diff --git a/arch/sparc/lib/bootm.c b/arch/sparc/lib/bootm.c
index 9e2b784..1d38e43 100644
--- a/arch/sparc/lib/bootm.c
+++ b/arch/sparc/lib/bootm.c
@@ -15,32 +15,22 @@
#define PRINT_KERNEL_HEADER
-extern image_header_t header;
-extern void srmmu_init_cpu(unsigned int entry);
-extern void prepare_bootargs(char *bootargs);
+DECLARE_GLOBAL_DATA_PTR;
+
+extern void *srmmu_init_tlb_tables(void *table, size_t *table_len);
+extern void srmmu_init_cpu(void *ctx_table);
+extern struct linux_romvec *prom_init(void *prom_base);
#ifdef CONFIG_USB_UHCI
extern int usb_lowlevel_stop(int index);
#endif
-/* sparc kernel argument (the ROM vector) */
-struct linux_romvec *kernel_arg_promvec;
-
/* page szie is 4k */
#define PAGE_SIZE 0x1000
#define RAMDISK_IMAGE_START_MASK 0x07FF
#define RAMDISK_PROMPT_FLAG 0x8000
#define RAMDISK_LOAD_FLAG 0x4000
struct __attribute__ ((packed)) {
- char traptable[PAGE_SIZE];
- char swapper_pg_dir[PAGE_SIZE];
- char pg0[PAGE_SIZE];
- char pg1[PAGE_SIZE];
- char pg2[PAGE_SIZE];
- char pg3[PAGE_SIZE];
- char empty_bad_page[PAGE_SIZE];
- char empty_bad_page_table[PAGE_SIZE];
- char empty_zero_page[PAGE_SIZE];
unsigned char hdr[4]; /* ascii "HdrS" */
/* 00.02.06.0b is for Linux kernel 2.6.11 */
unsigned char linuxver_mega_major;
@@ -63,22 +53,52 @@ struct __attribute__ ((packed)) {
} hdr_input;
} *linux_hdr;
-/* temporary initrd image holder */
-image_header_t ihdr;
+#ifdef CONFIG_LMB
void arch_lmb_reserve(struct lmb *lmb)
{
+#if 0 /* disabled (why do we need this?) */
+
/* Reserve the space used by PROM and stack. This is done
* to avoid that the RAM image is copied over stack or
* PROM.
*/
lmb_reserve(lmb, CONFIG_SYS_RELOC_MONITOR_BASE, CONFIG_SYS_RAM_END);
+
+#endif
+}
+
+#endif /* CONFIG_LMB */
+
+static void *find_linux_hdr(void *base)
+{
+ const char hdr_token[4] = { 'H', 'd', 'r', 'S' };
+ void *end = base + 32 * PAGE_SIZE;
+
+ while (base < end) {
+ unsigned long * const hdr1 = (unsigned long *) base;
+ unsigned long * const hdr2 = (unsigned long *) hdr_token;
+
+ if (*hdr1 == *hdr2)
+ return base;
+
+ /* advance one page */
+ base += PAGE_SIZE;
+ }
+
+ /* no header found */
+ return NULL;
}
/* boot the linux kernel */
int do_bootm_linux(int flag, int argc, char * const argv[], bootm_headers_t * images)
{
- char *bootargs;
+ /* sparc kernel argument (the ROM vector) */
+ struct linux_romvec *kernel_arg_promvec;
+
+ size_t ctx_table_len;
+ void *ctx_table;
+
ulong rd_len;
void (*kernel) (struct linux_romvec *, void *);
int ret;
@@ -92,16 +112,13 @@ int do_bootm_linux(int flag, int argc, char * const argv[], bootm_headers_t * im
if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
return 1;
- /* Get virtual address of kernel start */
- linux_hdr = (void *)images->os.load;
-
- /* */
+ /* Kernel entry point */
kernel = (void (*)(struct linux_romvec *, void *))images->ep;
- /* check for a SPARC kernel */
- if ((linux_hdr->hdr[0] != 'H') ||
- (linux_hdr->hdr[1] != 'd') ||
- (linux_hdr->hdr[2] != 'r') || (linux_hdr->hdr[3] != 'S')) {
+ /* Search for the SPARC kernel header */
+ linux_hdr = find_linux_hdr((void *)images->os.load);
+
+ if (!linux_hdr) {
puts("Error reading header of SPARC Linux kernel, aborting\n");
goto error;
}
@@ -153,12 +170,14 @@ int do_bootm_linux(int flag, int argc, char * const argv[], bootm_headers_t * im
*/
}
- /* Copy bootargs from bootargs variable to kernel readable area */
- bootargs = getenv("bootargs");
- prepare_bootargs(bootargs);
+ /* Setup the context tables, returns table pointer and length */
+ ctx_table = srmmu_init_tlb_tables((void*)gd->ram_top, &ctx_table_len);
+
+ /* Turn on MMU and page tables for process 0 (kernel) */
+ srmmu_init_cpu(ctx_table);
- /* turn on mmu & setup context table & page table for process 0 (kernel) */
- srmmu_init_cpu((unsigned int)kernel);
+ /* Prepare the PROM and RomVector structures for Linux kernel*/
+ kernel_arg_promvec = prom_init(ctx_table + ctx_table_len);
/* Enter SPARC Linux kernel
* From now on the only code in u-boot that will be
diff --git a/arch/sparc/lib/prom-no.c b/arch/sparc/lib/prom-no.c
new file mode 100644
index 0000000..19f87bf
--- /dev/null
+++ b/arch/sparc/lib/prom-no.c
@@ -0,0 +1,319 @@
+#include <common.h>
+#include <asm/prom.h>
+#include "prom-no.h"
+
+#define PROM_TEXT __attribute__ ((__section__ (".prom.text")))
+#define PROM_DATA __attribute__ ((__section__ (".prom.data")))
+
+//------------------------------------------------------------------------------
+
+static inline void * PROM_TEXT prop_ptr(struct prom_prop *prop, int offset)
+{
+ return (void *)prop + offset * 4;
+}
+
+static inline void * PROM_TEXT prom_ptr(struct prom_node *node, int offset)
+{
+ if (offset == 0)
+ return NULL;
+
+ return (void *)node + offset * 4;
+}
+
+//------------------------------------------------------------------------------
+
+struct prom_priv PROM_DATA __prom_entry;
+
+static int PROM_TEXT prom_strcmp(const char *a, const char *b);
+
+//------------------------------------------------------------------------------
+
+/* This is here to fix a compiler issue that insert a GOT lookup with using the result */
+
+struct prom_prop * PROM_TEXT dummy(struct prom_node *n, const char *name)
+{
+ if (n && name && *name) {
+ struct prom_prop *p = &n->props[0];
+ struct prom_prop *e = &n->props[n->num_props];
+ for (; p < e; ++p) {
+ if (prom_strcmp(prop_ptr(p, p->name), name) == 0)
+ return p;
+ }
+ }
+
+ return NULL;
+}
+
+//------------------------------------------------------------------------------
+
+/* Retrieve pointer to prom_entry without using the GOT (relative to PC only) */
+struct prom_priv * PROM_TEXT prom_get_entry(void)
+{
+ register int link asm("%o7");
+ register int self asm("%o1");
+ register int entry asm("%o2");
+ /* I would dearly like to know how we can do this beter. */
+ asm("98: call 99f; nop");
+ asm(".word 98b");
+ asm(".word __prom_entry"); /* store address to prom_entry in code */
+ asm("99:");
+ asm("ld [%%o7 + 8], %0" : "=r"(self) : );
+ asm("ld [%%o7 + 12], %0" : "=r"(entry) : );
+ return (void *)(entry + (link - self));
+}
+
+//------------------------------------------------------------------------------
+
+/* Helper methods */
+
+static void *PROM_TEXT prom_memcpy(void *dest, void *source, size_t len)
+{
+ (void)dummy; // prevent compiler from optimizing out the dummy function
+
+ char *dst = dest;
+ char *src = source;
+ char *end = src + len;
+
+ while (src < end)
+ *dst++ = *src++;
+
+ return dest;
+}
+
+static int PROM_TEXT prom_strcmp(const char *a, const char *b)
+{
+ register char d = *a - *b;
+
+ while (d == 0 && *a != '\0')
+ d = *(++a) - *(++b);
+
+ return d;
+}
+
+static struct prom_prop * PROM_TEXT prop_find(struct prom_node *n, const char *name)
+{
+ if (n && name && *name) {
+ struct prom_prop *p = &n->props[0];
+ struct prom_prop *e = &n->props[n->num_props];
+ for (; p < e; ++p) {
+ if (prom_strcmp(prop_ptr(p, p->name), name) == 0)
+ return p;
+ }
+ }
+
+ return NULL;
+}
+
+//------------------------------------------------------------------------------
+
+int PROM_TEXT prom_no_nextnode(int node)
+{
+ struct prom_node *n = (struct prom_node *) node;
+
+ if (n)
+ return (int) prom_ptr(n, n->next);
+
+ /* retrieve pointer to root node */
+ n = prom_get_entry()->root_node;
+
+ if (n)
+ return (int) n;
+
+ return -1;
+}
+
+int PROM_TEXT prom_no_getchild(int node)
+{
+ struct prom_node *n = (struct prom_node *) node;
+
+ if (n)
+ return (int) prom_ptr(n, n->child);
+
+ return -1;
+}
+
+char * PROM_TEXT prom_no_nextprop(int node, char *name)
+{
+ struct prom_node *n = (struct prom_node *) node;
+ struct prom_prop *p = NULL;
+
+ if (name && *name) {
+ p = prop_find(n, name);
+
+ if (p) {
+ struct prom_prop *e = &n->props[n->num_props];
+ if (++p >= e) /* advance to next prop */
+ p = NULL; /* past end of list */
+ }
+ } else {
+ if (n->num_props > 0)
+ p = &n->props[0];
+ }
+
+ return p ? prop_ptr(p, p->name) : NULL;
+}
+
+int PROM_TEXT prom_no_proplen(int node, char *name)
+{
+ struct prom_node *n = (struct prom_node *) node;
+ struct prom_prop *p = prop_find(n, name);
+
+ return p ? p->length : -1;
+}
+
+int PROM_TEXT prom_no_getprop(int node, char *name, char *val)
+{
+ struct prom_node *n = (struct prom_node *) node;
+ struct prom_prop *p = prop_find(n, name);
+
+ if (p && p->length >= 0) {
+ if (val && p->length) {
+ if (p->length > sizeof(p->value)) {
+ prom_memcpy(val, prop_ptr(p, (int)p->value), p->length);
+ } else {
+ /* small values is encoded directly in the pointer */
+ unsigned int *dst = (void *)val;
+ unsigned int *src = (void *)&p->value;
+ *dst = *src; /* copy value */
+ }
+ }
+
+ return p->length;
+ }
+
+ return -1;
+}
+
+int PROM_TEXT prom_no_setprop(int node, char *name, char *val, int len)
+{
+ return -1; /* not implemented */
+}
+
+//------------------------------------------------------------------------------
+
+/* get single char, don't care for blocking*/
+int PROM_TEXT prom_nb_getchar(void)
+{
+ return -1; /* not implemented */
+}
+
+/* put single char, don't care for blocking*/
+int PROM_TEXT prom_nb_putchar(int c)
+{
+ ambapp_dev_apbuart *uart = prom_get_entry()->uart;
+
+ if (!uart)
+ return 0;
+
+ /* Wait for last character to go */
+ while (!(SPARC_BYPASS_READ(&uart->status) & LEON_REG_UART_STATUS_THE)) ;
+
+ /* Send data */
+ SPARC_BYPASS_WRITE(&uart->data, c);
+
+ return 1;
+}
+
+void PROM_TEXT prom_halt(void)
+{
+ // FIXME: not fully implemented yet
+ prom_nb_putchar('\r');
+ prom_nb_putchar('\n');
+ prom_nb_putchar('H');
+ prom_nb_putchar('A');
+ prom_nb_putchar('L');
+ prom_nb_putchar('T');
+ prom_nb_putchar('!');
+//#ifdef DEBUG
+ asm("mov 1, %g1; ta 0; nop");
+//#endif
+ while (1) ;
+ // TODO: go into low power mode
+}
+
+void PROM_TEXT prom_reboot(char *bcommand)
+{
+ prom_halt(); // FIXME: not implemented yet
+}
+
+//------------------------------------------------------------------------------
+
+#if 0
+
+/* Reboot the CPU = jump to beginning of flash again.
+ *
+ * Make sure that all function are inlined here.
+ */
+static void PROM_TEXT leon_reboot(char *bcommand)
+{
+ register char *arg = bcommand;
+ void __attribute__ ((noreturn)) (*reboot_physical) (char *cmd);
+
+ /* get physical address */
+ struct leon_prom_info *pspi =
+ (void *)(CONFIG_SYS_PROM_OFFSET + sizeof(sparc_srmmu_setup));
+
+ unsigned int *srmmu_ctx_table;
+
+ /* Turn of Interrupts */
+ set_pil(0xf);
+
+ /* Set kernel's context, context zero */
+ srmmu_set_context(0);
+
+ /* Get physical address of the MMU shutdown routine */
+ reboot_physical = (void *)
+ SPARC_BYPASS_READ(&pspi->reloc_funcs.reboot_physical);
+
+ /* Now that we know the physical address of the function
+ * we can make the MMU allow jumping to it.
+ */
+ srmmu_ctx_table = (unsigned int *)srmmu_get_ctable_ptr();
+
+ srmmu_ctx_table = (unsigned int *)SPARC_BYPASS_READ(srmmu_ctx_table);
+
+ /* get physical address of kernel's context table (assume ptd) */
+ srmmu_ctx_table = (unsigned int *)
+ (((unsigned int)srmmu_ctx_table & 0xfffffffc) << 4);
+
+ /* enable access to physical address of MMU shutdown function */
+ SPARC_BYPASS_WRITE(&srmmu_ctx_table
+ [((unsigned int)reboot_physical) >> 24],
+ (((unsigned int)reboot_physical & 0xff000000) >> 4) |
+ 0x1e);
+
+ /* flush TLB cache */
+ leon_flush_tlb_all();
+
+ /* flash instruction & data cache */
+ sparc_icache_flush_all();
+ sparc_dcache_flush_all();
+
+ /* jump to physical address function
+ * so that when the MMU is disabled
+ * we can continue to execute
+ */
+ reboot_physical(arg);
+}
+
+static void PROM_TEXT leon_reboot_physical(char *bcommand)
+{
+ void __attribute__ ((noreturn)) (*reset) (void);
+
+ /* Turn off MMU */
+ srmmu_set_mmureg(0);
+
+ /* Hardcoded start address */
+ reset = (void*)CONFIG_SYS_MONITOR_BASE;
+
+ /* flush data cache */
+ sparc_dcache_flush_all();
+
+ /* flush instruction cache */
+ sparc_icache_flush_all();
+
+ /* Jump to start in Flash */
+ reset();
+}
+
+#endif
diff --git a/arch/sparc/lib/prom-no.h b/arch/sparc/lib/prom-no.h
new file mode 100644
index 0000000..ef369a1
--- /dev/null
+++ b/arch/sparc/lib/prom-no.h
@@ -0,0 +1,40 @@
+#ifndef __PROM_NO_H__
+#define __PROM_NO_H__
+
+#include <ambapp.h>
+
+struct prom_prop {
+ short name;
+ short length;
+ void *value;
+};
+
+struct prom_node {
+ short next;
+ short child;
+ int num_props;
+ struct prom_prop props[0];
+};
+
+struct prom_priv {
+ struct prom_node *root_node;
+ ambapp_dev_apbuart *uart;
+};
+
+/* structure that holds entry pointers */
+extern struct prom_priv __prom_entry;
+
+extern int prom_no_nextnode(int);
+extern int prom_no_getchild(int);
+extern char *prom_no_nextprop(int, char *);
+extern int prom_no_proplen(int, char *);
+extern int prom_no_getprop(int, char *, char *);
+extern int prom_no_setprop(int, char *, char *, int);
+
+extern int prom_nb_getchar(void);
+extern int prom_nb_putchar(int);
+
+extern void prom_reboot(char *);
+extern void prom_halt(void);
+
+#endif /* __PROM_NO_H__ */
diff --git a/arch/sparc/lib/prom.c b/arch/sparc/lib/prom.c
new file mode 100644
index 0000000..2e6be41
--- /dev/null
+++ b/arch/sparc/lib/prom.c
@@ -0,0 +1,960 @@
+/* prom.c - Emulates a SPARC v0 PROM for the Linux kernel.
+ *
+ * Copyright (C) 2003 Konrad Eisele <eiselekd at web.de>
+ * Copyright (C) 2004 Stefan Holst <mail at s-holst.de>
+ * Copyright (C) 2007 Daniel Hellstrom <daniel at gaisler.com>
+ * Copyright (C) 2014 Francois Retief <fgretief at spaceteq.co.za>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <asm/leon.h>
+#include <asm/prom.h>
+#include <asm/machines.h>
+
+#include "prom-no.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Defined in arch/sparc/cpu/leon3/serial.c */
+extern ambapp_dev_apbuart *leon3_apbuart;
+
+//-----------------------------------------------------------------------------
+
+//#undef assert
+#ifndef assert
+
+static void prom_assert_fail(const char *file, int line, const char *func, const char *cond)
+{
+ serial_printf("## assert '%s' failed at %s:%d in %s.", cond, file, line, func);
+}
+
+#define assert(cond) do { \
+ if (!(cond)) \
+ prom_assert_fail(__FILE__, __LINE__, __func__, #cond); \
+} while(0)
+
+#endif
+
+//-----------------------------------------------------------------------------
+
+struct prop {
+ const char *name;
+ int length;
+ void *value;
+};
+
+struct node {
+ int num_props;
+ struct prop *props;
+ int num_nodes;
+ struct node *nodes;
+};
+
+#define PROP_ENTRY_DATA(n,d,l) { .name = prop_s_##n, .value = (d), .length = (l) }
+#define PROP_ENTRY(n,v) { .name = prop_s_##n, .value = &(v), .length = sizeof(v) }
+
+#define NODE_ENTRY(n) { \
+ .num_props = ARRAY_SIZE(n##_properties), \
+ .props = n##_properties, \
+ .num_nodes = 0, \
+ .nodes = NULL, \
+}
+
+#define NODE_ENTRY_L1(n) { \
+ .num_props = ARRAY_SIZE(n##_properties), \
+ .props = n##_properties, \
+ .num_nodes = ARRAY_SIZE(n##_child_nodes), \
+ .nodes = n##_child_nodes, \
+}
+
+//-----------------------------------------------------------------------------
+
+#define PROP_STRING(s) char prop_s_##s[] = #s
+
+static PROP_STRING(mid);
+static PROP_STRING(uart1_baud);
+static PROP_STRING(uart2_baud);
+static PROP_STRING(name);
+static PROP_STRING(device_type);
+static PROP_STRING(systemid);
+static PROP_STRING(ioarea);
+static PROP_STRING(ipl_num);
+static PROP_STRING(compatible);
+static PROP_STRING(compatability);
+static PROP_STRING(idprom);
+
+/* exceptions on the rule */
+static char prop_s_mmu_nctx[] = "mmu-nctx";
+static char prop_s_clock_frequency[] = "clock-frequency";
+
+//-----------------------------------------------------------------------------
+
+#ifdef CONFIG_USE_CUSTOM_AMBA_NODES
+
+static PROP_STRING(vendor);
+static PROP_STRING(device);
+static PROP_STRING(version);
+static PROP_STRING(reg);
+static PROP_STRING(interrupts);
+static PROP_STRING(freq);
+
+static char apbuart_name[] = "GAISLER_APBUART";
+static unsigned long apbuart_vendor = 1;
+static unsigned long apbuart_device = 12;
+static unsigned long apbuart_reg[] = { 0x80000100, 0x100 };
+static unsigned long apbuart_irq[] = { 2 };
+static unsigned long apbuart_freq = CONFIG_SYS_CLK_FREQ;
+
+static struct prop apbuart_properties[] = {
+ PROP_ENTRY(name, apbuart_name),
+ PROP_ENTRY(vendor, apbuart_vendor),
+ PROP_ENTRY(device, apbuart_device),
+ PROP_ENTRY(reg, apbuart_reg),
+ PROP_ENTRY(interrupts, apbuart_irq),
+ PROP_ENTRY(freq, apbuart_freq),
+};
+
+static char irqmp_name[] = "GAISLER_IRQMP";
+static unsigned long irqmp_vendor = 1;
+static unsigned long irqmp_device = 13;
+static unsigned long irqmp_reg[] = { 0x80000200, 0x100 };
+
+static struct prop irqmp_properties[] = {
+ PROP_ENTRY(name, irqmp_name),
+ PROP_ENTRY(vendor, irqmp_vendor),
+ PROP_ENTRY(device, irqmp_device),
+ PROP_ENTRY(reg, irqmp_reg),
+};
+
+static char gptimer_name[] = "GAISLER_GPTIMER";
+static unsigned long gptimer_vendor = 1;
+static unsigned long gptimer_device = 17;
+static unsigned long gptimer_reg[] = { 0x80000300, 0x100 };
+static unsigned long gptimer_irq[] = { 8, 9, 10, 11 };
+
+static struct prop gptimer_properties[] = {
+ PROP_ENTRY(name, gptimer_name),
+ PROP_ENTRY(vendor, gptimer_vendor),
+ PROP_ENTRY(device, gptimer_device),
+ PROP_ENTRY(reg, gptimer_reg),
+ PROP_ENTRY(interrupts, gptimer_irq),
+};
+
+static char ethmac_name[] = "GAISLER_ETHMAC";
+static unsigned long ethmac_vendor = 1;
+static unsigned long ethmac_device = 0x01d;
+static unsigned long ethmac_reg[] = { 0x80000e00, 0x100 };
+static unsigned long ethmac_irq[] = { 14 };
+
+static struct prop ethmac_properties[] = {
+ PROP_ENTRY(name, ethmac_name),
+ PROP_ENTRY(vendor, ethmac_vendor),
+ PROP_ENTRY(device, ethmac_device),
+ PROP_ENTRY(reg, ethmac_reg),
+ PROP_ENTRY(interrupts, ethmac_irq),
+};
+
+#endif /* CONFIG_USE_CUSTOM_AMBA_NODES */
+
+//-----------------------------------------------------------------------------
+
+static char ambapp_device_type[] = "ambapp";
+static char ambapp_name[] = "ambapp0";
+static unsigned long ambapp_systemid = 0x07120e70;
+static unsigned long ambapp_ioarea = 0xFFF00000;
+static unsigned long ambapp_ipl_num = 0;
+
+static struct prop ambapp_properties[] = {
+ PROP_ENTRY(device_type, ambapp_device_type),
+ PROP_ENTRY(name, ambapp_name),
+ PROP_ENTRY(systemid, ambapp_systemid),
+ PROP_ENTRY(ioarea, ambapp_ioarea),
+ PROP_ENTRY(ipl_num, ambapp_ipl_num),
+};
+
+static struct node ambapp_child_nodes[] = {
+#ifdef CONFIG_USE_CUSTOM_AMBA_NODES
+ NODE_ENTRY(apbuart),
+ NODE_ENTRY(irqmp),
+ NODE_ENTRY(gptimer),
+ NODE_ENTRY(ethmac),
+#endif
+};
+
+//-----------------------------------------------------------------------------
+
+static char cpu0_device_type[] = "cpu";
+static char cpu0_name[6] = "cpu0"; /* length must be 6 for cpu15 */
+static unsigned long cpu0_mid = 0; /* processor ID */
+static unsigned long cpu0_mmu_nctx = 256;
+static unsigned long cpu0_freq_kHz = CONFIG_SYS_CLK_FREQ / 1000;
+static unsigned long cpu0_baudrate[] = { CONFIG_BAUDRATE, CONFIG_BAUDRATE };
+
+static struct prop cpu0_properties[] = {
+ PROP_ENTRY(device_type, cpu0_device_type),
+ PROP_ENTRY(name, cpu0_name),
+ PROP_ENTRY(mid, cpu0_mid),
+ PROP_ENTRY(mmu_nctx, cpu0_mmu_nctx),
+ PROP_ENTRY(clock_frequency, cpu0_freq_kHz),
+ PROP_ENTRY(uart1_baud, cpu0_baudrate[0]),
+ PROP_ENTRY(uart2_baud, cpu0_baudrate[1]),
+};
+
+//-----------------------------------------------------------------------------
+
+static char serial_device_type[] = "serial";
+static char serial_name[] = "a:";
+
+static struct prop serial_properties[] = {
+ PROP_ENTRY(device_type, serial_device_type),
+ PROP_ENTRY(name, serial_name),
+};
+
+//-----------------------------------------------------------------------------
+
+static char root_device_type[] = "idprom";
+static char root_leon[] = "leon";
+static struct idprom root_idprom = { };
+
+static struct prop root_properties[] = {
+ PROP_ENTRY(device_type, root_device_type),
+ PROP_ENTRY(idprom, root_idprom),
+ PROP_ENTRY(compatible, root_leon),
+ PROP_ENTRY(compatability, root_leon),
+};
+
+static struct node root_child_nodes[] = {
+ NODE_ENTRY(cpu0),
+ NODE_ENTRY(serial),
+ NODE_ENTRY_L1(ambapp),
+};
+
+//-----------------------------------------------------------------------------
+
+static struct node root_node = {
+ .num_props = ARRAY_SIZE(root_properties),
+ .props = root_properties,
+ .num_nodes = ARRAY_SIZE(root_child_nodes),
+ .nodes = root_child_nodes,
+};
+
+//-----------------------------------------------------------------------------
+
+void prom_reloc_prop(struct prop *p)
+{
+ if (gd->flags & GD_FLG_RELOC) {
+ if (p->name)
+ p->name = (void *)p->name + gd->reloc_off;
+ if (p->value)
+ p->value = (void *)p->value + gd->reloc_off;
+ }
+}
+
+void prom_reloc_node(struct node *n)
+{
+ int i;
+
+ if (gd->flags & GD_FLG_RELOC) {
+ if (n->props)
+ n->props = (void *)n->props + gd->reloc_off;
+ if (n->nodes)
+ n->nodes = (void *)n->nodes + gd->reloc_off;
+ }
+
+ for (i = 0; i < n->num_props; ++i) {
+ prom_reloc_prop( &n->props[i] );
+ }
+
+ for (i = 0; i < n->num_nodes; ++i) {
+ prom_reloc_node( &n->nodes[i] );
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+/* These two variables are defined in the linker script */
+extern unsigned long __prom_start;
+extern unsigned long __prom_end;
+
+static unsigned long prom_malloc_end;
+static unsigned long prom_va_base;
+
+#define _va(x) ((void*)( (unsigned long)(x) - (unsigned long)&__prom_start + prom_va_base ))
+
+static void prom_set_malloc_base(void *base)
+{
+ assert(base != NULL);
+
+ prom_malloc_end = ((unsigned long)base + 3) & ~3;
+ prom_va_base = prom_malloc_end;
+}
+
+static inline void *prom_malloc(int size)
+{
+ void *result = (void *)prom_malloc_end;
+
+ prom_malloc_end = (prom_malloc_end + size + 3) & ~3;
+ return result;
+}
+
+static void *prom_calloc(int size)
+{
+ void *result = (void *)prom_malloc_end;
+
+ unsigned long *ptr = (void *)prom_malloc_end;
+ unsigned long *end = (void *)ptr + size;
+
+ while (ptr < end)
+ *ptr++ = 0;
+
+ prom_malloc_end = (unsigned long)ptr;
+ return result;
+}
+
+static void *prom_malloc_string(const char *s)
+{
+ void *result = (void *)prom_malloc_end;
+
+ char *dst = (char *)prom_malloc_end;
+
+ /* copy string to destination */
+ while (*s)
+ *dst++ = *s++;
+ *dst++ = '\0';
+
+ prom_malloc_end = ((unsigned long)dst + 3) & ~3;
+ return result;
+}
+
+static void *prom_malloc_data(void *data, int length)
+{
+ void *result = (void *)prom_malloc_end;
+
+ char *dst = (char *)prom_malloc_end;
+ const char *src = data;
+ const char *end = data + length;
+
+ /* copy data to destination */
+ while (src < end)
+ *dst++ = *src++;
+
+ prom_malloc_end = ((unsigned long)dst + 3) & ~3;
+ return result;
+}
+
+static char *prom_malloc_byte(char value)
+{
+ void *result = (void *)prom_malloc_end;
+
+ char *dst = (char *)prom_malloc_end;
+
+ /* copy value to destination */
+ *dst++ = value;
+
+ prom_malloc_end = ((unsigned long)dst + 3) & ~3;
+ return result;
+}
+
+//-----------------------------------------------------------------------------
+
+/* This section implements a small string cache for the names. This helps us
+ * find duplicates, reducing the PROM size by quite a bit.
+ */
+static const char **str_cache;
+static int str_cache_len = 0;
+
+static void prom_cache_init(void)
+{
+ str_cache = (const char **)calloc(256, sizeof(str_cache[0]));
+}
+
+static void prom_cache_free(void)
+{
+ free(str_cache);
+}
+
+static const char *prom_cache_find(const char *name)
+{
+ if (name && *name) {
+ const char **ptr = str_cache;
+ const char **end = &ptr[256];
+
+ while (ptr < end && *ptr) {
+ if (strcmp(name, *ptr) == 0)
+ break;
+ ptr++;
+ }
+
+ return *ptr;
+ }
+
+ return NULL;
+}
+
+static const char *prom_cache_append(const char *name)
+{
+ str_cache[str_cache_len] = name;
+ str_cache_len += 1;
+ return name;
+}
+
+static const char *prom_cache_or_malloc(const char *name)
+{
+ const char *entry = prom_cache_find(name);
+
+ if (entry == NULL) {
+ entry = prom_malloc_string(name);
+ prom_cache_append(entry);
+ }
+
+ return entry;
+}
+
+//-----------------------------------------------------------------------------
+
+struct amba_dev {
+ void *source;
+ unsigned int type;
+ unsigned int index;
+ unsigned int vendor;
+ unsigned int device;
+ unsigned int version;
+ unsigned int irq;
+ unsigned int addr;
+};
+
+static int amba_apb_foreach(unsigned long apb_base, void (*action)(struct amba_dev *dev, void *ctx), void *ctx)
+{
+ int i;
+ apbctrl_pp_dev *apb = (apbctrl_pp_dev *)(apb_base | LEON3_CONF_AREA);
+
+ for (i = 0; i < 16; ++i, ++apb) {
+ if (apb->conf == 0)
+ continue;
+
+ struct amba_dev dev;
+
+ dev.type = 4; /* APB Slave */
+ dev.index = i;
+ dev.source = apb;
+
+ dev.vendor = amba_vendor(apb->conf);
+ dev.device = amba_device(apb->conf);
+ dev.version = amba_ver(apb->conf);
+ dev.irq = amba_irq(apb->conf);
+
+ dev.addr = amba_iobar_start(apb_base, apb->bar);
+
+ action(&dev, ctx);
+ }
+
+ return 0;
+}
+
+static int amba_ahb_foreach(int type, void (*action)(struct amba_dev *dev, void *ctx), void *ctx)
+{
+ int i = 0;
+ int num = (64+64); /* Both Master and Slave */
+ ahbctrl_pp_dev *ahb = (ahbctrl_pp_dev *)(LEON3_IO_AREA | LEON3_CONF_AREA);
+
+ if ((type & 7) == 0)
+ return 0; /* Nothing to do */
+ if ((type & 3) == 1)
+ num = 64; /* Only Master */
+ if ((type & 3) == 2)
+ i = 64; /* Only Slave */
+
+ for (; i < num; ++i) {
+ if (ahb[i].conf == 0)
+ continue;
+
+ if (type & 3) {
+ struct amba_dev dev;
+
+ dev.type = (i < 64) ? 1 : 2; /* Master or Slave */
+ dev.index = i % 64;
+ dev.source = &ahb[i];
+
+ dev.vendor = amba_vendor(ahb[i].conf);
+ dev.device = amba_device(ahb[i].conf);
+ dev.version = amba_ver(ahb[i].conf);
+ dev.irq = amba_irq(ahb[i].conf);
+
+ dev.addr = amba_membar_start(ahb[i].bars[0]);
+
+ action(&dev, ctx);
+ }
+
+ if (type & 4) {
+ /* Check for AMBA APB Master */
+ if (amba_vendor(ahb[i].conf) == VENDOR_GAISLER &&
+ amba_device(ahb[i].conf) == GAISLER_APBMST) {
+ amba_apb_foreach(amba_membar_start(ahb[i].bars[0]), action, ctx);
+ }
+ }
+ }
+
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+
+static inline int prop_offset(struct prom_prop *prop, void *target)
+{
+ assert(((int)prop & 3) == 0);
+ assert(((int)target & 3) == 0);
+ return ( (int)target - (int)prop ) / 4;
+}
+
+static inline int prom_offset(struct prom_node *node, void *target)
+{
+ assert(((int)node & 3) == 0);
+ assert(((int)target & 3) == 0);
+
+ if (target == NULL)
+ return 0;
+
+ return ( (int)target - (int)node ) / 4;
+}
+
+//-----------------------------------------------------------------------------
+
+static void prom_build_prop(struct prom_prop *prop, struct prop *p)
+{
+ prop->name = prop_offset(prop, (void *)prom_cache_or_malloc(p->name));
+
+ prop->length = p->length;
+
+ if (p->length > sizeof(p->value)) {
+ prop->value = (void *)prop_offset(prop, prom_malloc_data(p->value, p->length));
+ } else {
+ /* small values is encoded directly in the pointer */
+ unsigned int *dst = (void *)&prop->value;
+ unsigned int *src = (void *)p->value;
+ *dst = *src; /* copy value */
+ }
+}
+
+static struct prom_node *prom_create_node(struct prop *p, int num_props)
+{
+ struct prom_node *node;
+ int i, size = sizeof(node[0]) + num_props * sizeof(node->props[0]);
+
+ node = (struct prom_node *) prom_malloc(size);
+
+ node->next = 0;
+ node->child = 0;
+
+ node->num_props = num_props;
+ for (i = 0; i < num_props; ++i)
+ prom_build_prop( &node->props[i], &p[i] );
+
+ return node;
+}
+
+static struct prom_node *prom_build_leaf_node(struct prom_node *sibling, struct prop *props, int num_props)
+{
+ struct prom_node *node = prom_create_node(props, num_props);
+
+ if (sibling)
+ sibling->next = prom_offset(sibling, node);
+
+ return node;
+}
+
+static struct prom_node *prom_build_node(struct prom_node *prev_node, struct node *n)
+{
+ struct prom_node *node = prom_create_node(n->props, n->num_props);
+
+ if (prev_node)
+ prev_node->next = prom_offset(prev_node, node);
+
+ if (n->num_nodes > 0) {
+ int i;
+ struct prom_node *prev = prom_build_node(NULL, &n->nodes[0]);
+
+ node->child = prom_offset(node, prev);
+
+ for (i = 1; i < n->num_nodes; ++i)
+ prev = prom_build_node(prev, &n->nodes[i]);
+ }
+
+ return node;
+}
+
+struct nlist {
+ struct prom_node *first;
+ struct prom_node *last;
+};
+
+static void prom_create_amba_node_iter(struct amba_dev *dev, void *ctx)
+{
+ struct nlist *list = ctx;
+
+#ifdef CONFIG_MINIMAL_CORES
+ if (dev->vendor != VENDOR_GAISLER)
+ return;
+ if (dev->device != GAISLER_IRQMP &&
+ dev->device != GAISLER_GPTIMER &&
+ dev->device != GAISLER_APBUART &&
+ dev->device != GAISLER_ETHMAC)
+ return;
+ //if (dev->device == GAISLER_APBUART && dev->addr != 0x80000100)
+ // return;
+#endif
+ if (dev->type == 1)
+ return; // skip AHB Master nodes
+ if (dev->type == 2 && !(dev->vendor == VENDOR_GAISLER && dev->device == GAISLER_APBMST))
+ return; // skip AHB Slave nodes, except APBMST
+
+ int dummy = 0;
+
+ int i2cmst_reg_shift = 2;
+ int gpio_num_cells = 2;
+ int cpu_freq = CONFIG_SYS_CLK_FREQ;
+
+ unsigned int dev_reg[2] = { (unsigned int)dev->addr, 0x100 };
+
+ static char s_spictrl_compatible[] = "aeroflexgaisler,spictrl";
+ static char s_i2cmst_compatible[] = "aeroflexgaisler,i2cmst";
+ static char s_canahb_compatible[] = "aeroflexgaisler,can_oc\0nxp,sja1000";
+
+ char sbuf[9];
+ char *nameStr;
+#ifdef CONFIG_CMD_AMBAPP
+ nameStr = ambapp_device_id2str(dev->vendor, dev->device);
+ if (!nameStr || !nameStr[0])
+#endif
+ {
+ sprintf(sbuf, "%02x_%03x", dev->vendor, dev->device);
+ nameStr = &sbuf[0];
+ }
+
+ struct prop props[16];
+ struct node n = { .props = &props[0], .num_props = 0 };
+
+#define PROP_ADD(m,v,l) do { \
+ struct prop *_p = &n.props[n.num_props++]; \
+ _p->name = (m); _p->value = (v); _p->length = (l); \
+} while(0)
+#define PROP_ADD_STRING(n,s) PROP_ADD((n), (s), 1+strlen(s))
+#define PROP_ADD_DATA(n,d) PROP_ADD((n), &(d), sizeof(d))
+
+ PROP_ADD_STRING("name", nameStr);
+ PROP_ADD_DATA("vendor", dev->vendor);
+ PROP_ADD_DATA("device", dev->device);
+ PROP_ADD_DATA("version", dev->version);
+
+ if (dev->irq != 0)
+ PROP_ADD_DATA("interrupts", dev->irq);
+
+ if (dev->addr != 0)
+ PROP_ADD_DATA("reg", dev_reg);
+
+ //PROP_ADD("devmsk", ...); // TODO
+ //PROP_ADD("userdef", ...); // TODO
+
+ if (dev->vendor == VENDOR_GAISLER && dev->device == GAISLER_APBUART) {
+ PROP_ADD_DATA("freq", cpu_freq);
+ }
+
+ if (dev->vendor == VENDOR_GAISLER && dev->device == GAISLER_I2CMST) {
+ PROP_ADD_DATA("compatible", s_i2cmst_compatible);
+ PROP_ADD_DATA("clock-frequency", cpu_freq);
+ PROP_ADD_DATA("reg-shift", i2cmst_reg_shift);
+ }
+
+ if (dev->vendor == VENDOR_GAISLER && dev->device == GAISLER_SPICTRL) {
+ PROP_ADD_DATA("compatible", s_spictrl_compatible);
+ PROP_ADD_DATA("clock-frequency", cpu_freq);
+ }
+
+ if (dev->vendor == VENDOR_GAISLER && dev->device == GAISLER_CANAHB) {
+ PROP_ADD_DATA("compatible", s_canahb_compatible);
+ PROP_ADD_DATA("nxp,external-clock-frequency", cpu_freq);
+ }
+
+ if (dev->vendor == VENDOR_GAISLER && dev->device == GAISLER_GPIO) {
+ PROP_ADD("nbits", &dummy, sizeof(dummy)); // gp->nbits
+ PROP_ADD("irqmap", &dummy, sizeof(dummy)); // fixme: array of something
+ PROP_ADD("gpiocontroller", NULL, 0); /* empty array */
+ PROP_ADD("#gpio-cells", &gpio_num_cells, sizeof(gpio_num_cells));
+ }
+
+ PROP_ADD_DATA("index", dev->index);
+ //PROP_ADD("ampopts", ...) // TODO
+ //PROP_ADD("description", ...); // TODO
+
+#undef PROP_ADD_DATA
+#undef PROP_ADD_STRING
+#undef PROP_ADD
+
+ /* Create a leaf node */
+ struct prom_node *node = prom_build_leaf_node(list->last, &n.props[0], n.num_props);
+ /* Register node in link list */
+ list->last = node;
+ if (list->first == NULL)
+ list->first = node;
+
+ /* Here we branch into the APB bus and add child nodes to that node */
+ if (dev->vendor == VENDOR_GAISLER && dev->device == GAISLER_APBMST) {
+ struct nlist apb_list = { NULL, NULL };
+ amba_apb_foreach(dev->addr, prom_create_amba_node_iter, &apb_list);
+ node->child = prom_offset(node, apb_list.first);
+ }
+}
+
+#if 0
+static void prom_create_amba_node_iter_DBUG(struct amba_dev *dev, void *ctx)
+{
+ printf("PROM:%02d: vendor=%x, device = %03x, version=%02d, irq=%02d, addr=%08x\n",
+ dev->index, dev->vendor, dev->device, dev->version, dev->irq, dev->addr);
+ prom_create_amba_node_iter(dev, ctx);
+}
+#endif
+
+static struct prom_node *prom_build_amba_nodes(struct prom_node *sibling, struct node *n)
+{
+ struct prom_node *node = prom_build_leaf_node(sibling, n->props, n->num_props);
+
+#ifdef CONFIG_USE_CUSTOM_AMBA_NODES
+ if (n->num_nodes > 0) {
+ int i;
+ struct prom_node *prev = prom_build_node(NULL, &n->nodes[0]);
+
+ node->child = prom_offset(node, prev);
+
+ for (i = 1; i < n->num_nodes; ++i) {
+ prev = prom_build_node(prev, &n->nodes[i]);
+ }
+ }
+#else
+ struct nlist list = { NULL, NULL };
+ amba_ahb_foreach(4, prom_create_amba_node_iter, &list);
+ node->child = prom_offset(node, list.first);
+#endif
+
+ return node;
+}
+
+static struct prom_node *prom_build_root_node(void)
+{
+ struct prom_node *prev, *node;
+ struct node *n = &root_node;
+ int i, ncpu = 1;
+
+#ifdef CONFIG_SMP
+ ambapp_apbdev apbdev;
+ if (ambapp_apb_first(VENDOR_GAISLER, GAISLER_IRQMP, &apbdev) == 1) {
+ ambapp_dev_irqmp *irqmp = (ambapp_dev_irqmp *) apbdev.address;
+ /* Determine the number of CPUs in the SoC */
+ ncpu += (irqmp->mstatus >> 28) & 0x0f;
+ }
+#endif
+
+ node = prom_create_node(n->props, n->num_props);
+
+ /* Add cpu0 node */
+ prev = prom_build_node(NULL, &n->nodes[0]);
+
+ node->child = prom_offset(node, prev);
+
+ /* Add the rest of the cpuN nodes */
+ n->nodes[0].num_props -= 2; /* remove UART entries */
+ for (i = 1; i < ncpu; ++i) {
+ /* Update properties for cpuN node */
+ cpu0_mid = i;
+ snprintf(cpu0_name, 6, "cpu%d", i);
+ /* Add cpuN nodes */
+ prev = prom_build_node(prev, &n->nodes[0]);
+ }
+
+#ifdef CONFIG_LEON2
+ (void)prom_build_amba_nodes; /* silence compiler warning */
+#else
+
+ /* Add serial node */
+ prev = prom_build_node(prev, &n->nodes[1]);
+
+ /* Add ambapp0 node */
+ prev = prom_build_amba_nodes(prev, &n->nodes[2]);
+
+#endif
+ return node;
+}
+
+static void *prom_init_nodes_init(void)
+{
+ void *prom_root;
+ void *prom_base = (void *)prom_malloc_end;
+
+ prom_reloc_node(&root_node);
+
+ prom_cache_init();
+ prom_root = prom_build_root_node();
+ prom_cache_free();
+
+ int size = (int)prom_malloc_end - (int)prom_base;
+ printf("PROM cached had %d entries\n", str_cache_len);
+ printf("PROM allocated %d bytes\n", size);
+ printf("PROM ended at %p\n", (void*)prom_malloc_end);
+ printf("SDRAM ends at %p\n", (void*)(CONFIG_SYS_SDRAM_END|0xF0000000));
+
+ assert(prom_malloc_end < (CONFIG_SYS_SDRAM_END|0xF0000000));
+ return prom_root;
+}
+
+//-----------------------------------------------------------------------------
+
+static unsigned char prom_calc_checksum(void *buf, size_t len)
+{
+ unsigned char *ptr = (unsigned char *)buf;
+ unsigned char *end = ptr + len;
+ unsigned char cksum = 0;
+ while (ptr < end)
+ cksum ^= *ptr++;
+ return cksum;
+}
+
+static void *prom_init_idprom(struct idprom *idprom)
+{
+ assert(idprom != NULL);
+ memset(idprom, 0, sizeof(idprom[0]));
+
+ idprom->id_format = 0x01;
+#ifdef CONFIG_LEON2
+ idprom->id_machtype = M_LEON | M_LEON2_SOC;
+#else
+ idprom->id_machtype = M_LEON | M_LEON3_SOC;
+#endif
+
+#ifdef CONFIG_CMD_NET
+ /* Set Ethernet MAC address from environment */
+ eth_getenv_enetaddr("ethaddr", idprom->id_ethaddr);
+#endif
+
+ /* Calculate the checksum for the IDPROM structure */
+ idprom->id_cksum = prom_calc_checksum(idprom, 0x0E);
+
+ return idprom;
+}
+
+//-----------------------------------------------------------------------------
+
+static void *prom_init_linux_mem_v0(struct linux_mem_v0 *mem)
+{
+ struct linux_mlist_v0 **entry;
+
+ mem->v0_prommap = prom_malloc(sizeof(struct linux_mlist_v0 *));
+ mem->v0_prommap[0] = NULL;
+
+ /* Set total main memory */
+
+ mem->v0_totphys = entry = prom_malloc(sizeof(struct linux_mlist_v0 *));
+ mem->v0_totphys[0] = prom_malloc(sizeof(struct linux_mlist_v0));
+ mem->v0_totphys[0]->start_adr = (void *)CONFIG_SYS_SDRAM_BASE;
+ mem->v0_totphys[0]->num_bytes = (int)gd->ram_top - (int)CONFIG_SYS_SDRAM_BASE;
+ mem->v0_totphys[0]->theres_more = NULL;
+
+ /* Set available main memory */
+
+ mem->v0_available = prom_malloc(sizeof(struct linux_mlist_v0 *));
+ mem->v0_available[0] = prom_malloc(sizeof(struct linux_mlist_v0));
+ mem->v0_available[0]->start_adr = (void *)CONFIG_SYS_SDRAM_BASE;
+ mem->v0_available[0]->num_bytes = (int)gd->ram_top - (int)CONFIG_SYS_SDRAM_BASE;
+ mem->v0_available[0]->theres_more = NULL;
+
+ return (void *)mem;
+}
+
+static void *prom_init_linux_arguments_v0(const char *bootargs)
+{
+ struct linux_arguments_v0 *args = prom_calloc(sizeof(struct linux_arguments_v0));
+
+ if (bootargs && *bootargs) {
+ const char **argv = (const char **)&(args->argv[0]);
+
+ argv[1] = prom_malloc_string(bootargs);
+ }
+
+ return prom_malloc_data(&args, sizeof(args));
+}
+
+static void *prom_init_romvec(struct linux_romvec *rv)
+{
+ assert(rv != NULL);
+ memset(rv, 0, sizeof(rv[0]));
+
+ /* Version numbers. */
+ rv->pv_magic_cookie = 0;
+ rv->pv_romvers = 0; /* sun4c v0 prom */
+ rv->pv_plugin_revision = 0;
+ rv->pv_printrev = 0;
+
+ rv->pv_stdin = rv->pv_stdout = prom_malloc_byte(PROMDEV_TTYA);
+
+ /* Functions */
+ rv->pv_nbgetchar = _va(prom_nb_getchar);
+ rv->pv_nbputchar = _va(prom_nb_putchar);
+ rv->pv_halt = _va(prom_halt);
+ rv->pv_reboot = _va(prom_reboot);
+
+ /* Allocate memory where a pointer can be stored */
+ rv->pv_synchook = prom_malloc(sizeof(void *));
+
+ /* Node operations. */
+ rv->pv_nodeops = prom_malloc(sizeof(struct linux_nodeops));
+ rv->pv_nodeops->no_nextnode = _va(prom_no_nextnode);
+ rv->pv_nodeops->no_child = _va(prom_no_getchild);
+ rv->pv_nodeops->no_nextprop = _va(prom_no_nextprop);
+ rv->pv_nodeops->no_proplen = _va(prom_no_proplen);
+ rv->pv_nodeops->no_getprop = _va(prom_no_getprop);
+ rv->pv_nodeops->no_setprop = _va(prom_no_setprop);
+
+ /* Version 0 memory descriptors. */
+ prom_init_linux_mem_v0(&rv->pv_v0mem);
+
+ /* Linux boot arguments */
+ rv->pv_v0bootargs = prom_init_linux_arguments_v0( getenv("bootargs") );
+
+ return rv;
+}
+
+//-----------------------------------------------------------------------------
+
+struct linux_romvec *prom_init(void *prom_base)
+{
+ struct prom_priv *prom_entry_va;
+ size_t prom_size = (int)&__prom_end - (int)&__prom_start;
+
+ /* Set the virtual PROM base address */
+ prom_set_malloc_base((void *)((unsigned long)prom_base|0xF0000000));
+
+ /* Copy PROM code/data to virtual memory */
+ memcpy(prom_malloc(prom_size), (void *)&__prom_start, prom_size);
+
+ /* Initialise the ROM vector */
+ struct linux_romvec *prom_romvec =
+ prom_init_romvec(prom_malloc(sizeof(struct linux_romvec)));
+
+ /* Initialise the root IDPROM structure */
+ prom_init_idprom(&root_idprom);
+
+ /* Setup entry pointer for PROM functions */
+ prom_entry_va = _va(&__prom_entry);
+
+ /* Create the PROM node tree */
+ prom_entry_va->root_node = prom_init_nodes_init();
+
+ /* Set UART address for getc/putc functions */
+#ifdef CONFIG_LEON2
+ prom_entry_va->uart = (void *) &((LEON2_regs *)LEON2_PREGS)->UART_Channel_1;
+#else
+ prom_entry_va->uart = leon3_apbuart;
+#endif
+
+ return prom_romvec;
+}
diff --git a/arch/sparc/lib/srmmu.c b/arch/sparc/lib/srmmu.c
new file mode 100644
index 0000000..fbff9db
--- /dev/null
+++ b/arch/sparc/lib/srmmu.c
@@ -0,0 +1,90 @@
+#include <common.h>
+#include <asm/srmmu.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static void __inline__ leon_flush_cache_all(void)
+{
+ __asm__ __volatile__(" flush ");
+ __asm__ __volatile__("sta %%g0, [%%g0] %0\n\t"::"i"(ASI_DFLUSH):"memory");
+}
+
+static void __inline__ leon_flush_tlb_all(void)
+{
+ leon_flush_cache_all();
+ __asm__ __volatile__("sta %%g0, [%0] %1\n\t"::"r"(0x400), "i"(ASI_MMUFLUSH):"memory");
+}
+
+/* The code below sets up the virtual address space as follows:
+ *
+ * Only context 0 is valid. Context 0 address map using 1 levels:
+ *
+ * 0x00000000 - 0xEFFFFFFF : 1:1 mapping to physical memory
+ * 0xF0000000 - 0xFBFFFFFF : Maps to main memory (low 192MiB memory only)
+ * 0xFC000000 - 0xFFFFFFFF : Not mapped
+ */
+void *srmmu_init_tlb_tables(void *table, size_t *table_len)
+{
+ int i;
+
+ assert(((unsigned long)table & (0x2000-1)) == 0); /* must be 8KiB aligned */
+
+ /* SRMMU as alignment requirements on tables that must be fulfilled:
+ * - Context Table: align 0x2000, size 0x400, 256 entries
+ * - Level 1 Table: align 0x0400, size 0x400, 256 entries
+ */
+ unsigned long *_mmu_ctx_table = (void *)(((unsigned long)table + (0x2000-1)) & ~(0x2000-1));
+ unsigned long *_mmu_ctx0_level1 = &_mmu_ctx_table[256];
+
+ /* Setup context table: context 0 point to level 1 table */
+ _mmu_ctx_table[0] = (((unsigned long)&_mmu_ctx0_level1[0] >> 4) & ~SRMMU_ET_MASK) | SRMMU_ET_PTD;
+ for (i = 1; i < 256; ++i) {
+ _mmu_ctx_table[i] = SRMMU_ET_INVALID;
+ }
+
+ /* Setup level 1 address space, 16MiB/entry
+ *
+ * 0x00000000-0xF0000000: 1:1 mapping (non-cachable)
+ * 0xF0000000-0xFC000000: Map to RAM memory (low memory only)
+ * 0xFC000000-0xFEFFFFFF: INVALID
+ * 0xFF000000-0xFFFFFFFF: 1:1 mapping (non-cachable)
+ */
+ for (i = 0; i < 240; ++i) {
+ _mmu_ctx0_level1[i] = (i << 20) |
+ SRMMU_NOREAD | SRMMU_EXEC | SRMMU_WRITE | SRMMU_ET_PTE;
+ }
+ for (; i < 252; i++) {
+ _mmu_ctx0_level1[i] = ((CONFIG_SYS_SDRAM_BASE >> 4) | ((i-240)<<20)) |
+ SRMMU_CACHE | SRMMU_NOREAD | SRMMU_EXEC | SRMMU_WRITE | SRMMU_ET_PTE;
+ }
+ for (; i < 256; i++) {
+ _mmu_ctx0_level1[i] = SRMMU_ET_INVALID;
+ }
+
+ /* AMBA Configuration area */
+ _mmu_ctx0_level1[255] = ((0xFF000000 >> 4) | (0x0F<<20)) |
+ SRMMU_NOREAD | SRMMU_EXEC | SRMMU_WRITE | SRMMU_ET_PTE;
+
+ if (table_len)
+ *table_len = (unsigned long)&_mmu_ctx0_level1[256] - (unsigned long)_mmu_ctx_table;
+
+ return (void *)_mmu_ctx_table;
+}
+
+void srmmu_init_cpu(void *ctx_table)
+{
+ /* alignment check, must be aligned on 8KiB boundary */
+ assert(((unsigned long)ctx_table & (0x2000-1)) == 0);
+ /* Set the MMU page tables */
+ srmmu_set_ctable_ptr((unsigned long)ctx_table);
+ /* Set kernel's context, context zero */
+ srmmu_set_context(0);
+ /* Invalidate all Cache */
+ __asm__ __volatile__("flush\n\t");
+ /* Flush TLB */
+ leon_flush_tlb_all();
+ /* Enable MMU */
+ srmmu_set_mmureg(0x00000001);
+ /* Flush all cache */
+ leon_flush_cache_all();
+}
diff --git a/common/cmd_ambapp.c b/common/cmd_ambapp.c
index 2a1995a..aa32234 100644
--- a/common/cmd_ambapp.c
+++ b/common/cmd_ambapp.c
@@ -50,7 +50,7 @@ static ambapp_device_name gaisler_devices[] = {
{GAISLER_PCITRACE, "GAISLER_PCITRACE"},
{GAISLER_AHBTRACE, "GAISLER_AHBTRACE"},
{GAISLER_ETHDSU, "GAISLER_ETHDSU"},
- {GAISLER_PIOPORT, "GAISLER_PIOPORT"},
+ {GAISLER_GPIO, "GAISLER_GPIO"},
{GAISLER_AHBJTAG, "GAISLER_AHBJTAG"},
{GAISLER_ATACTRL, "GAISLER_ATACTRL"},
{GAISLER_VGA, "GAISLER_VGA"},
@@ -62,9 +62,25 @@ static ambapp_device_name gaisler_devices[] = {
{GAISLER_SPW2, "GAISLER_SPW2"},
{GAISLER_EHCI, "GAISLER_EHCI"},
{GAISLER_UHCI, "GAISLER_UHCI"},
+ {GAISLER_I2CMST, "GAISLER_I2CMST"},
+ {GAISLER_SPICTRL, "GAISLER_SPICTRL"},
{GAISLER_AHBSTAT, "GAISLER_AHBSTAT"},
{GAISLER_DDR2SPA, "GAISLER_DDR2SPA"},
{GAISLER_DDRSPA, "GAISLER_DDRSPA"},
+ {GAISLER_LEON3FT, "GAISLER_LEON3FT"},
+ {GAISLER_FTMCTRL, "GAISLER_FTMCTRL"},
+ {GAISLER_B1553BRM, "GAISLER_B1553BRM"},
+ {GAISLER_FTAHBRAM, "GAISLER_FTAHBRAM"},
+ {GAISLER_CANAHB, "GAISLER_CANAHB"},
+ {GAISLER_SATCAN, "GAISLER_SATCAN"},
+ {GAISLER_CANMUX, "GAISLER_CANMUX"},
+ {GAISLER_SLINK, "GAISLER_SLINK"},
+ {GAISLER_GRTM, "GAISLER_GRTM"},
+ {GAISLER_GRTC, "GAISLER_GRTC"},
+ {GAISLER_GRTIMER, "GAISLER_GRTIMER"},
+ {GAISLER_CLKGATE, "GAISLER_CLKGATE"},
+ {GAISLER_GPREG, "GAISLER_GPREG"},
+ {GAISLER_ASCS, "GAISLER_ASCS"},
{0, NULL}
};
diff --git a/include/ambapp.h b/include/ambapp.h
index 405637d..dfd6fa9 100644
--- a/include/ambapp.h
+++ b/include/ambapp.h
@@ -62,20 +62,35 @@
#define GAISLER_PCIDMA 0x016
#define GAISLER_AHBTRACE 0x017
#define GAISLER_ETHDSU 0x018
-#define GAISLER_PIOPORT 0x01A
-#define GAISLER_AHBJTAG 0x01c
-#define GAISLER_SPW 0x01f
-#define GAISLER_ATACTRL 0x024
-#define GAISLER_VGA 0x061
-#define GAISLER_KBD 0X060
+#define GAISLER_CANAHB 0x019
+#define GAISLER_GPIO 0x01A
+#define GAISLER_AHBJTAG 0x01C
#define GAISLER_ETHMAC 0x01D
+#define GAISLER_SPW 0x01F
+#define GAISLER_ATACTRL 0x024
#define GAISLER_DDRSPA 0x025
#define GAISLER_EHCI 0x026
#define GAISLER_UHCI 0x027
+#define GAISLER_I2CMST 0x028
#define GAISLER_SPW2 0x029
+#define GAISLER_CLKGATE 0x02C
+#define GAISLER_SPICTRL 0x02D
#define GAISLER_DDR2SPA 0x02E
+#define GAISLER_SLINK 0x02F
+#define GAISLER_GRTM 0x030
+#define GAISLER_GRTC 0x031
+#define GAISLER_GRTIMER 0x038
+#define GAISLER_ASCS 0x043
+#define GAISLER_FTAHBRAM 0x050
#define GAISLER_AHBSTAT 0x052
+#define GAISLER_LEON3FT 0x053
#define GAISLER_FTMCTRL 0x054
+#define GAISLER_KBD 0x060
+#define GAISLER_VGA 0x061
+#define GAISLER_B1553BRM 0x072
+#define GAISLER_SATCAN 0x080
+#define GAISLER_CANMUX 0x081
+#define GAISLER_GPREG 0x087
#define GAISLER_L2TIME 0xffd /* internal device: leon2 timer */
#define GAISLER_L2C 0xffe /* internal device: leon2compat */
--
1.9.3
________________________________
Disclaimer and confidentiality note – refer to our website for further details: www.spaceteq.co.za <http://www.spaceteq.co.za/home/emaildisclaimer/>
More information about the U-Boot
mailing list