diff options
Diffstat (limited to 'roms/u-boot/arch/microblaze/cpu')
-rw-r--r-- | roms/u-boot/arch/microblaze/cpu/Makefile | 9 | ||||
-rw-r--r-- | roms/u-boot/arch/microblaze/cpu/cache.c | 74 | ||||
-rw-r--r-- | roms/u-boot/arch/microblaze/cpu/exception.c | 64 | ||||
-rw-r--r-- | roms/u-boot/arch/microblaze/cpu/interrupts.c | 216 | ||||
-rw-r--r-- | roms/u-boot/arch/microblaze/cpu/irq.S | 79 | ||||
-rw-r--r-- | roms/u-boot/arch/microblaze/cpu/spl.c | 59 | ||||
-rw-r--r-- | roms/u-boot/arch/microblaze/cpu/start.S | 328 | ||||
-rw-r--r-- | roms/u-boot/arch/microblaze/cpu/timer.c | 123 | ||||
-rw-r--r-- | roms/u-boot/arch/microblaze/cpu/u-boot-spl.lds | 62 | ||||
-rw-r--r-- | roms/u-boot/arch/microblaze/cpu/u-boot.lds | 60 |
10 files changed, 1074 insertions, 0 deletions
diff --git a/roms/u-boot/arch/microblaze/cpu/Makefile b/roms/u-boot/arch/microblaze/cpu/Makefile new file mode 100644 index 000000000..f7a83d07b --- /dev/null +++ b/roms/u-boot/arch/microblaze/cpu/Makefile @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. + +extra-y = start.o +obj-y = irq.o +obj-y += interrupts.o cache.o exception.o timer.o +obj-$(CONFIG_SPL_BUILD) += spl.o diff --git a/roms/u-boot/arch/microblaze/cpu/cache.c b/roms/u-boot/arch/microblaze/cpu/cache.c new file mode 100644 index 000000000..aa832d6be --- /dev/null +++ b/roms/u-boot/arch/microblaze/cpu/cache.c @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2007 Michal Simek + * + * Michal SIMEK <monstr@monstr.eu> + */ + +#include <common.h> +#include <cpu_func.h> +#include <asm/asm.h> +#include <asm/cache.h> + +int dcache_status(void) +{ + int i = 0; + int mask = 0x80; + __asm__ __volatile__ ("mfs %0,rmsr"::"r" (i):"memory"); + /* i&=0x80 */ + __asm__ __volatile__ ("and %0,%0,%1"::"r" (i), "r" (mask):"memory"); + return i; +} + +int icache_status(void) +{ + int i = 0; + int mask = 0x20; + __asm__ __volatile__ ("mfs %0,rmsr"::"r" (i):"memory"); + /* i&=0x20 */ + __asm__ __volatile__ ("and %0,%0,%1"::"r" (i), "r" (mask):"memory"); + return i; +} + +void icache_enable(void) +{ + MSRSET(0x20); +} + +void icache_disable(void) +{ + /* we are not generate ICACHE size -> flush whole cache */ + flush_cache(0, 32768); + MSRCLR(0x20); +} + +void dcache_enable(void) +{ + MSRSET(0x80); +} + +void dcache_disable(void) +{ +#ifdef XILINX_USE_DCACHE + flush_cache(0, XILINX_DCACHE_BYTE_SIZE); +#endif + MSRCLR(0x80); +} + +void flush_cache(ulong addr, ulong size) +{ + int i; + for (i = 0; i < size; i += 4) + asm volatile ( +#ifdef CONFIG_ICACHE + "wic %0, r0;" +#endif + "nop;" +#ifdef CONFIG_DCACHE + "wdc.flush %0, r0;" +#endif + "nop;" + : + : "r" (addr + i) + : "memory"); +} diff --git a/roms/u-boot/arch/microblaze/cpu/exception.c b/roms/u-boot/arch/microblaze/cpu/exception.c new file mode 100644 index 000000000..b8dedc4e1 --- /dev/null +++ b/roms/u-boot/arch/microblaze/cpu/exception.c @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2007 Michal Simek + * + * Michal SIMEK <monstr@monstr.eu> + */ + +#include <common.h> +#include <hang.h> +#include <asm/asm.h> + +void _hw_exception_handler (void) +{ + int address = 0; + int state = 0; + + /* loading address of exception EAR */ + MFS(address, rear); + /* loading excetpion state register ESR */ + MFS(state, resr); + printf("Hardware exception at 0x%x address\n", address); + R17(address); + printf("Return address from exception 0x%x\n", address); + switch (state & 0x1f) { /* mask on exception cause */ + case 0x1: + puts("Unaligned data access exception\n"); + break; + case 0x2: + puts("Illegal op-code exception\n"); + break; + case 0x3: + puts("Instruction bus error exception\n"); + break; + case 0x4: + puts("Data bus error exception\n"); + break; + case 0x5: + puts("Divide by zero exception\n"); + break; +#ifdef MICROBLAZE_V5 + case 0x7: + puts("Priviledged or stack protection violation exception\n"); + break; + case 0x1000: + puts("Exception in delay slot\n"); + break; +#endif + default: + puts("Undefined cause\n"); + break; + } + printf("Unaligned %sword access\n", ((state & 0x800) ? "" : "half")); + printf("Unaligned %s access\n", ((state & 0x400) ? "store" : "load")); + printf("Register R%x\n", (state & 0x3E) >> 5); + hang(); +} + +#ifdef CONFIG_SYS_USR_EXCEP +void _exception_handler (void) +{ + puts("User vector_exception\n"); + hang(); +} +#endif diff --git a/roms/u-boot/arch/microblaze/cpu/interrupts.c b/roms/u-boot/arch/microblaze/cpu/interrupts.c new file mode 100644 index 000000000..fe65f3728 --- /dev/null +++ b/roms/u-boot/arch/microblaze/cpu/interrupts.c @@ -0,0 +1,216 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2007 Michal Simek + * (C) Copyright 2004 Atmark Techno, Inc. + * + * Michal SIMEK <monstr@monstr.eu> + * Yasushi SHOJI <yashi@atmark-techno.com> + */ + +#include <common.h> +#include <command.h> +#include <fdtdec.h> +#include <irq_func.h> +#include <log.h> +#include <malloc.h> +#include <asm/global_data.h> +#include <asm/microblaze_intc.h> +#include <asm/asm.h> + +DECLARE_GLOBAL_DATA_PTR; + +void enable_interrupts(void) +{ + debug("Enable interrupts for the whole CPU\n"); + MSRSET(0x2); +} + +int disable_interrupts(void) +{ + unsigned int msr; + + MFS(msr, rmsr); + MSRCLR(0x2); + return (msr & 0x2) != 0; +} + +static struct irq_action *vecs; +static u32 irq_no; + +/* mapping structure to interrupt controller */ +microblaze_intc_t *intc; + +/* default handler */ +static void def_hdlr(void) +{ + puts("def_hdlr\n"); +} + +static void enable_one_interrupt(int irq) +{ + int mask; + int offset = 1; + + offset <<= irq; + mask = intc->ier; + intc->ier = (mask | offset); + + debug("Enable one interrupt irq %x - mask %x,ier %x\n", offset, mask, + intc->ier); + debug("INTC isr %x, ier %x, iar %x, mer %x\n", intc->isr, intc->ier, + intc->iar, intc->mer); +} + +static void disable_one_interrupt(int irq) +{ + int mask; + int offset = 1; + + offset <<= irq; + mask = intc->ier; + intc->ier = (mask & ~offset); + + debug("Disable one interrupt irq %x - mask %x,ier %x\n", irq, mask, + intc->ier); + debug("INTC isr %x, ier %x, iar %x, mer %x\n", intc->isr, intc->ier, + intc->iar, intc->mer); +} + +int install_interrupt_handler(int irq, interrupt_handler_t *hdlr, void *arg) +{ + struct irq_action *act; + + /* irq out of range */ + if ((irq < 0) || (irq > irq_no)) { + puts("IRQ out of range\n"); + return -1; + } + act = &vecs[irq]; + if (hdlr) { /* enable */ + act->handler = hdlr; + act->arg = arg; + act->count = 0; + enable_one_interrupt(irq); + return 0; + } + + /* Disable */ + act->handler = (interrupt_handler_t *)def_hdlr; + act->arg = (void *)irq; + disable_one_interrupt(irq); + return 1; +} + +/* initialization interrupt controller - hardware */ +static void intc_init(void) +{ + intc->mer = 0; + intc->ier = 0; + intc->iar = 0xFFFFFFFF; + /* XIntc_Start - hw_interrupt enable and all interrupt enable */ + intc->mer = 0x3; + + debug("INTC isr %x, ier %x, iar %x, mer %x\n", intc->isr, intc->ier, + intc->iar, intc->mer); +} + +int interrupt_init(void) +{ + int i; + const void *blob = gd->fdt_blob; + int node = 0; + + debug("INTC: Initialization\n"); + + node = fdt_node_offset_by_compatible(blob, node, + "xlnx,xps-intc-1.00.a"); + if (node != -1) { + fdt_addr_t base = fdtdec_get_addr(blob, node, "reg"); + if (base == FDT_ADDR_T_NONE) + return -1; + + debug("INTC: Base addr %lx\n", base); + intc = (microblaze_intc_t *)base; + irq_no = fdtdec_get_int(blob, node, "xlnx,num-intr-inputs", 0); + debug("INTC: IRQ NO %x\n", irq_no); + } else { + return node; + } + + if (irq_no) { + vecs = calloc(1, sizeof(struct irq_action) * irq_no); + if (vecs == NULL) { + puts("Interrupt vector allocation failed\n"); + return -1; + } + + /* initialize irq list */ + for (i = 0; i < irq_no; i++) { + vecs[i].handler = (interrupt_handler_t *)def_hdlr; + vecs[i].arg = (void *)i; + vecs[i].count = 0; + } + /* initialize intc controller */ + intc_init(); + enable_interrupts(); + } else { + puts("Undefined interrupt controller\n"); + } + return 0; +} + +void interrupt_handler(void) +{ + int irqs = intc->ivr; /* find active interrupt */ + int mask = 1; + int value; + struct irq_action *act = vecs + irqs; + + debug("INTC isr %x, ier %x, iar %x, mer %x\n", intc->isr, intc->ier, + intc->iar, intc->mer); +#ifdef DEBUG + R14(value); +#endif + debug("Interrupt handler on %x line, r14 %x\n", irqs, value); + + debug("Jumping to interrupt handler rutine addr %x,count %x,arg %x\n", + (u32)act->handler, act->count, (u32)act->arg); + act->handler(act->arg); + act->count++; + + intc->iar = mask << irqs; + + debug("Dump INTC reg, isr %x, ier %x, iar %x, mer %x\n", intc->isr, + intc->ier, intc->iar, intc->mer); +#ifdef DEBUG + R14(value); +#endif + debug("Interrupt handler on %x line, r14 %x\n", irqs, value); +} + +#if defined(CONFIG_CMD_IRQ) +int do_irqinfo(struct cmd_tbl *cmdtp, int flag, int argc, const char *argv[]) +{ + int i; + struct irq_action *act = vecs; + + if (irq_no) { + puts("\nInterrupt-Information:\n\n" + "Nr Routine Arg Count\n" + "-----------------------------\n"); + + for (i = 0; i < irq_no; i++) { + if (act->handler != (interrupt_handler_t *)def_hdlr) { + printf("%02d %08x %08x %d\n", i, + (int)act->handler, (int)act->arg, + act->count); + } + act++; + } + puts("\n"); + } else { + puts("Undefined interrupt controller\n"); + } + return 0; +} +#endif diff --git a/roms/u-boot/arch/microblaze/cpu/irq.S b/roms/u-boot/arch/microblaze/cpu/irq.S new file mode 100644 index 000000000..ff3e6af91 --- /dev/null +++ b/roms/u-boot/arch/microblaze/cpu/irq.S @@ -0,0 +1,79 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2007 Michal Simek + * + * Michal SIMEK <monstr@monstr.eu> + */ + +#include <config.h> +#include <asm/asm.h> + .text + .global _interrupt_handler +_interrupt_handler: + addik r1, r1, -124 + swi r2, r1, 4 + swi r3, r1, 8 + swi r4, r1, 12 + swi r5, r1, 16 + swi r6, r1, 20 + swi r7, r1, 24 + swi r8, r1, 28 + swi r9, r1, 32 + swi r10, r1, 36 + swi r11, r1, 40 + swi r12, r1, 44 + swi r13, r1, 48 + swi r14, r1, 52 + swi r15, r1, 56 + swi r16, r1, 60 + swi r17, r1, 64 + swi r18, r1, 68 + swi r19, r1, 72 + swi r20, r1, 76 + swi r21, r1, 80 + swi r22, r1, 84 + swi r23, r1, 88 + swi r24, r1, 92 + swi r25, r1, 96 + swi r26, r1, 100 + swi r27, r1, 104 + swi r28, r1, 108 + swi r29, r1, 112 + swi r30, r1, 116 + swi r31, r1, 120 + brlid r15, interrupt_handler + nop + lwi r31, r1, 120 + lwi r30, r1, 116 + lwi r29, r1, 112 + lwi r28, r1, 108 + lwi r27, r1, 104 + lwi r26, r1, 100 + lwi r25, r1, 96 + lwi r24, r1, 92 + lwi r23, r1, 88 + lwi r22, r1, 84 + lwi r21, r1, 80 + lwi r20, r1, 76 + lwi r19, r1, 72 + lwi r18, r1, 68 + lwi r17, r1, 64 + lwi r16, r1, 60 + lwi r15, r1, 56 + lwi r14, r1, 52 + lwi r13, r1, 48 + lwi r12, r1, 44 + lwi r11, r1, 40 + lwi r10, r1, 36 + lwi r9, r1, 32 + lwi r8, r1, 28 + lwi r7, r1, 24 + lwi r6, r1, 20 + lwi r5, r1, 16 + lwi r4, r1, 12 + lwi r3, r1, 8 + lwi r2, r1, 4 + addik r1, r1, 124 + rtid r14, 0 + nop + .size _interrupt_handler,.-_interrupt_handler diff --git a/roms/u-boot/arch/microblaze/cpu/spl.c b/roms/u-boot/arch/microblaze/cpu/spl.c new file mode 100644 index 000000000..86522f844 --- /dev/null +++ b/roms/u-boot/arch/microblaze/cpu/spl.c @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2013 - 2014 Xilinx, Inc + * + * Michal Simek <michal.simek@xilinx.com> + */ + +#include <common.h> +#include <command.h> +#include <image.h> +#include <log.h> +#include <spl.h> +#include <asm/io.h> +#include <asm/u-boot.h> + +bool boot_linux; + +u32 spl_boot_device(void) +{ + return BOOT_DEVICE_NOR; +} + +/* Board initialization after bss clearance */ +void spl_board_init(void) +{ + /* enable console uart printing */ + preloader_console_init(); +} + +#ifdef CONFIG_SPL_OS_BOOT +void __noreturn jump_to_image_linux(struct spl_image_info *spl_image) +{ + debug("Entering kernel arg pointer: 0x%p\n", spl_image->arg); + typedef void (*image_entry_arg_t)(char *, ulong, ulong) + __attribute__ ((noreturn)); + image_entry_arg_t image_entry = + (image_entry_arg_t)spl_image->entry_point; + + image_entry(NULL, 0, (ulong)spl_image->arg); +} +#endif /* CONFIG_SPL_OS_BOOT */ + +int spl_start_uboot(void) +{ +#ifdef CONFIG_SPL_OS_BOOT + if (boot_linux) + return 0; +#endif + + return 1; +} + +int do_reset(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) +{ + __asm__ __volatile__ ("mts rmsr, r0;" \ + "bra r0"); + + return 0; +} diff --git a/roms/u-boot/arch/microblaze/cpu/start.S b/roms/u-boot/arch/microblaze/cpu/start.S new file mode 100644 index 000000000..9479737aa --- /dev/null +++ b/roms/u-boot/arch/microblaze/cpu/start.S @@ -0,0 +1,328 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2007 Michal Simek + * (C) Copyright 2004 Atmark Techno, Inc. + * + * Michal SIMEK <monstr@monstr.eu> + * Yasushi SHOJI <yashi@atmark-techno.com> + */ + +#include <asm-offsets.h> +#include <config.h> + + .text + .global _start +_start: + mts rmsr, r0 /* disable cache */ + + addi r8, r0, __end + mts rslr, r8 + +#if defined(CONFIG_SPL_BUILD) + addi r1, r0, CONFIG_SPL_STACK_ADDR +#else + addi r1, r0, CONFIG_SYS_INIT_SP_OFFSET +#endif + + addi r1, r1, -4 /* Decrement SP to top of memory */ + + /* Call board_init_f_alloc_reserve with the current stack pointer as + * parameter. */ + add r5, r0, r1 + bralid r15, board_init_f_alloc_reserve + nop + + /* board_init_f_alloc_reserve returns a pointer to the allocated area + * in r3. Set the new stack pointer below this area. */ + add r1, r0, r3 + mts rshr, r1 + addi r1, r1, -4 + + /* Call board_init_f_init_reserve with the address returned by + * board_init_f_alloc_reserve as parameter. */ + add r5, r0, r3 + bralid r15, board_init_f_init_reserve + nop + +#if !defined(CONFIG_SPL_BUILD) + /* Setup vectors with pre-relocation symbols */ + or r5, r0, r0 + bralid r15, __setup_exceptions + nop +#endif + + /* Flush cache before enable cache */ + addik r5, r0, 0 + addik r6, r0, XILINX_DCACHE_BYTE_SIZE + bralid r15, flush_cache + nop + + /* enable instruction and data cache */ + mfs r12, rmsr + ori r12, r12, 0x1a0 + mts rmsr, r12 + +clear_bss: + /* clear BSS segments */ + addi r5, r0, __bss_start + addi r4, r0, __bss_end + cmp r6, r5, r4 + beqi r6, 3f +2: + swi r0, r5, 0 /* write zero to loc */ + addi r5, r5, 4 /* increment to next loc */ + cmp r6, r5, r4 /* check if we have reach the end */ + bnei r6, 2b +3: /* jumping to board_init */ +#ifdef CONFIG_DEBUG_UART + bralid r15, debug_uart_init + nop +#endif +#ifndef CONFIG_SPL_BUILD + or r5, r0, r0 /* flags - empty */ + brai board_init_f +#else + brai board_init_r +#endif +1: bri 1b + +#ifndef CONFIG_SPL_BUILD + .text + .ent __setup_exceptions + .align 2 +/* + * Set up reset, interrupt, user exception and hardware exception vectors. + * + * Parameters: + * r5 - relocation offset (zero when setting up vectors before + * relocation, and gd->reloc_off when setting up vectors after + * relocation) + * - the relocation offset is added to the _exception_handler, + * _interrupt_handler and _hw_exception_handler symbols to reflect the + * post-relocation memory addresses + * + * Reserve registers: + * r10: Stores little/big endian offset for vectors + * r2: Stores imm opcode + * r3: Stores brai opcode + */ +__setup_exceptions: + addik r1, r1, -28 + swi r2, r1, 4 + swi r3, r1, 8 + swi r6, r1, 12 + swi r7, r1, 16 + swi r8, r1, 20 + swi r10, r1, 24 + + /* Find-out if u-boot is running on BIG/LITTLE endian platform + * There are some steps which is necessary to keep in mind: + * 1. Setup offset value to r6 + * 2. Store word offset value to address 0x0 + * 3. Load just byte from address 0x0 + * 4a) LITTLE endian - r10 contains 0x2 because it is the smallest + * value that's why is on address 0x0 + * 4b) BIG endian - r10 contains 0x0 because 0x2 offset is on addr 0x3 + */ + addik r6, r0, 0x2 /* BIG/LITTLE endian offset */ + lwi r7, r0, 0x28 + swi r6, r0, 0x28 /* used first unused MB vector */ + lbui r10, r0, 0x28 /* used first unused MB vector */ + swi r7, r0, 0x28 + + /* add opcode instruction for 32bit jump - 2 instruction imm & brai */ + addi r2, r0, 0xb0000000 /* hex b000 opcode imm */ + addi r3, r0, 0xb8080000 /* hew b808 opcode brai */ + +#ifdef CONFIG_SYS_RESET_ADDRESS + /* reset address */ + swi r2, r0, 0x0 /* reset address - imm opcode */ + swi r3, r0, 0x4 /* reset address - brai opcode */ + + addik r6, r0, CONFIG_SYS_RESET_ADDRESS + sw r6, r1, r0 + lhu r7, r1, r10 + rsubi r8, r10, 0x2 + sh r7, r0, r8 + rsubi r8, r10, 0x6 + sh r6, r0, r8 +#endif + +#ifdef CONFIG_SYS_USR_EXCEP + /* user_vector_exception */ + swi r2, r0, 0x8 /* user vector exception - imm opcode */ + swi r3, r0, 0xC /* user vector exception - brai opcode */ + + addik r6, r5, _exception_handler + sw r6, r1, r0 + /* + * BIG ENDIAN memory map for user exception + * 0x8: 0xB000XXXX + * 0xC: 0xB808XXXX + * + * then it is necessary to count address for storing the most significant + * 16bits from _exception_handler address and copy it to + * 0xa address. Big endian use offset in r10=0 that's why is it just + * 0xa address. The same is done for the least significant 16 bits + * for 0xe address. + * + * LITTLE ENDIAN memory map for user exception + * 0x8: 0xXXXX00B0 + * 0xC: 0xXXXX08B8 + * + * Offset is for little endian setup to 0x2. rsubi instruction decrease + * address value to ensure that points to proper place which is + * 0x8 for the most significant 16 bits and + * 0xC for the least significant 16 bits + */ + lhu r7, r1, r10 + rsubi r8, r10, 0xa + sh r7, r0, r8 + rsubi r8, r10, 0xe + sh r6, r0, r8 +#endif + + /* interrupt_handler */ + swi r2, r0, 0x10 /* interrupt - imm opcode */ + swi r3, r0, 0x14 /* interrupt - brai opcode */ + + addik r6, r5, _interrupt_handler + sw r6, r1, r0 + lhu r7, r1, r10 + rsubi r8, r10, 0x12 + sh r7, r0, r8 + rsubi r8, r10, 0x16 + sh r6, r0, r8 + + /* hardware exception */ + swi r2, r0, 0x20 /* hardware exception - imm opcode */ + swi r3, r0, 0x24 /* hardware exception - brai opcode */ + + addik r6, r5, _hw_exception_handler + sw r6, r1, r0 + lhu r7, r1, r10 + rsubi r8, r10, 0x22 + sh r7, r0, r8 + rsubi r8, r10, 0x26 + sh r6, r0, r8 + + lwi r10, r1, 24 + lwi r8, r1, 20 + lwi r7, r1, 16 + lwi r6, r1, 12 + lwi r3, r1, 8 + lwi r2, r1, 4 + addik r1, r1, 28 + + rtsd r15, 8 + or r0, r0, r0 + .end __setup_exceptions + +/* + * Read 16bit little endian + */ + .text + .global in16 + .ent in16 + .align 2 +in16: lhu r3, r0, r5 + bslli r4, r3, 8 + bsrli r3, r3, 8 + andi r4, r4, 0xffff + or r3, r3, r4 + rtsd r15, 8 + sext16 r3, r3 + .end in16 + +/* + * Write 16bit little endian + * first parameter(r5) - address, second(r6) - short value + */ + .text + .global out16 + .ent out16 + .align 2 +out16: bslli r3, r6, 8 + bsrli r6, r6, 8 + andi r3, r3, 0xffff + or r3, r3, r6 + sh r3, r0, r5 + rtsd r15, 8 + or r0, r0, r0 + .end out16 + +/* + * Relocate u-boot + */ + .text + .global relocate_code + .ent relocate_code + .align 2 +relocate_code: + /* + * r5 - start_addr_sp + * r6 - new_gd + * r7 - reloc_addr + */ + addi r1, r5, 0 /* Start to use new SP */ + addi r31, r6, 0 /* Start to use new GD */ + + add r23, r0, r7 /* Move reloc addr to r23 */ + /* Relocate text and data - r12 temp value */ + addi r21, r0, _start + addi r22, r0, __end - 4 /* Include BSS too */ + + rsub r6, r21, r22 + or r5, r0, r0 +1: lw r12, r21, r5 /* Load u-boot data */ + sw r12, r23, r5 /* Write zero to loc */ + cmp r12, r5, r6 /* Check if we have reach the end */ + bneid r12, 1b + addi r5, r5, 4 /* Increment to next loc - relocate code */ + + /* R23 points to the base address. */ + add r23, r0, r7 /* Move reloc addr to r23 */ + addi r24, r0, CONFIG_SYS_TEXT_BASE /* Get reloc offset */ + rsub r23, r24, r23 /* keep - this is already here gd->reloc_off */ + + /* Setup vectors with post-relocation symbols */ + add r5, r0, r23 /* load gd->reloc_off to r5 */ + bralid r15, __setup_exceptions + nop + + /* Check if GOT exist */ + addik r21, r23, _got_start + addik r22, r23, _got_end + cmpu r12, r21, r22 + beqi r12, 2f /* No GOT table - jump over */ + + /* Skip last 3 entries plus 1 because of loop boundary below */ + addik r22, r22, -0x10 + + /* Relocate the GOT. */ +3: lw r12, r21, r0 /* Load entry */ + addk r12, r12, r23 /* Add reloc offset */ + sw r12, r21, r0 /* Save entry back */ + + cmpu r12, r21, r22 /* Check if this cross boundary */ + bneid r12, 3b + addik r21. r21, 4 + + /* Update pointer to GOT */ + mfs r20, rpc + addik r20, r20, _GLOBAL_OFFSET_TABLE_ + 8 + addk r20, r20, r23 + + /* Flush caches to ensure consistency */ + addik r5, r0, 0 + addik r6, r0, XILINX_DCACHE_BYTE_SIZE + bralid r15, flush_cache + nop + +2: addi r5, r31, 0 /* gd is initialized in board_r.c */ + addi r6, r0, CONFIG_SYS_TEXT_BASE + addi r12, r23, board_init_r + bra r12 /* Jump to relocated code */ + + .end relocate_code +#endif diff --git a/roms/u-boot/arch/microblaze/cpu/timer.c b/roms/u-boot/arch/microblaze/cpu/timer.c new file mode 100644 index 000000000..647bdcd5b --- /dev/null +++ b/roms/u-boot/arch/microblaze/cpu/timer.c @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2007 Michal Simek + * + * Michal SIMEK <monstr@monstr.eu> + */ + +#include <common.h> +#include <fdtdec.h> +#include <init.h> +#include <log.h> +#include <time.h> +#include <asm/global_data.h> +#include <asm/microblaze_timer.h> +#include <asm/microblaze_intc.h> +#include <linux/delay.h> + +DECLARE_GLOBAL_DATA_PTR; + +volatile int timestamp = 0; +microblaze_timer_t *tmr; + +ulong get_timer (ulong base) +{ + if (tmr) + return timestamp - base; + return timestamp++ - base; +} + +void __udelay(unsigned long usec) +{ + u32 i; + + if (tmr) { + i = get_timer(0); + while ((get_timer(0) - i) < (usec / 1000)) + ; + } +} + +#ifndef CONFIG_SPL_BUILD +static void timer_isr(void *arg) +{ + timestamp++; + tmr->control = tmr->control | TIMER_INTERRUPT; +} + +int timer_init (void) +{ + int irq = -1; + u32 preload = 0; + u32 ret = 0; + const void *blob = gd->fdt_blob; + int node = 0; + u32 cell[2]; + + debug("TIMER: Initialization\n"); + + /* Do not init before relocation */ + if (!(gd->flags & GD_FLG_RELOC)) + return 0; + + node = fdt_node_offset_by_compatible(blob, node, + "xlnx,xps-timer-1.00.a"); + if (node != -1) { + fdt_addr_t base = fdtdec_get_addr(blob, node, "reg"); + if (base == FDT_ADDR_T_NONE) + return -1; + + debug("TIMER: Base addr %lx\n", base); + tmr = (microblaze_timer_t *)base; + + ret = fdtdec_get_int_array(blob, node, "interrupts", + cell, ARRAY_SIZE(cell)); + if (ret) + return ret; + + irq = cell[0]; + debug("TIMER: IRQ %x\n", irq); + + preload = fdtdec_get_int(blob, node, "clock-frequency", 0); + preload /= CONFIG_SYS_HZ; + } else { + return node; + } + + if (tmr && preload && irq >= 0) { + tmr->loadreg = preload; + tmr->control = TIMER_INTERRUPT | TIMER_RESET; + tmr->control = TIMER_ENABLE | TIMER_ENABLE_INTR |\ + TIMER_RELOAD | TIMER_DOWN_COUNT; + timestamp = 0; + ret = install_interrupt_handler (irq, timer_isr, (void *)tmr); + if (ret) + tmr = NULL; + } + /* No problem if timer is not found/initialized */ + return 0; +} +#else +int timer_init(void) +{ + return 0; +} +#endif + +/* + * This function is derived from PowerPC code (read timebase as long long). + * On Microblaze it just returns the timer value. + */ +unsigned long long get_ticks(void) +{ + return get_timer(0); +} + +/* + * This function is derived from PowerPC code (timebase clock frequency). + * On Microblaze it returns the number of timer ticks per second. + */ +ulong get_tbclk(void) +{ + return CONFIG_SYS_HZ; +} diff --git a/roms/u-boot/arch/microblaze/cpu/u-boot-spl.lds b/roms/u-boot/arch/microblaze/cpu/u-boot-spl.lds new file mode 100644 index 000000000..3387eb718 --- /dev/null +++ b/roms/u-boot/arch/microblaze/cpu/u-boot-spl.lds @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2013 - 2014 Xilinx, Inc + * + * Michal Simek <michal.simek@xilinx.com> + */ + +#include <asm-offsets.h> + +OUTPUT_ARCH(microblaze) +ENTRY(_start) + +SECTIONS +{ + .text ALIGN(0x4): + { + __text_start = .; + arch/microblaze/cpu/start.o (.text) + *(.text) + *(.text.*) + __text_end = .; + } + + .rodata ALIGN(0x4): + { + __rodata_start = .; + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) + __rodata_end = .; + } + + .data ALIGN(0x4): + { + __data_start = .; + *(.data) + *(.data.*) + __data_end = .; + } + + . = ALIGN(4); + .u_boot_list : { + KEEP(*(SORT(.u_boot_list*))); + } + __init_end = . ; + + .bss ALIGN(0x4): + { + __bss_start = .; + *(.sbss) + *(.scommon) + *(.bss) + *(.bss.*) + *(COMMON) + . = ALIGN(4); + __bss_end = .; + } + __end = . ; +} + +#if defined(CONFIG_SPL_MAX_FOOTPRINT) +ASSERT(__end - _start <= (CONFIG_SPL_MAX_FOOTPRINT), \ + "SPL image plus BSS too big"); +#endif diff --git a/roms/u-boot/arch/microblaze/cpu/u-boot.lds b/roms/u-boot/arch/microblaze/cpu/u-boot.lds new file mode 100644 index 000000000..5dc09dbad --- /dev/null +++ b/roms/u-boot/arch/microblaze/cpu/u-boot.lds @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2004 Atmark Techno, Inc. + * + * Yasushi SHOJI <yashi@atmark-techno.com> + */ + +OUTPUT_ARCH(microblaze) +ENTRY(_start) + +SECTIONS +{ + .text ALIGN(0x4): + { + __text_start = .; + arch/microblaze/cpu/start.o (.text) + *(.text*) + __text_end = .; + } + + .rodata ALIGN(0x4): + { + __rodata_start = .; + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) + __rodata_end = .; + } + + .data ALIGN(0x4): + { + __data_start = .; + *(.data*) + __data_end = .; + } + + .got ALIGN(4): + { + _got_start = .; + *(.got*) + . = ALIGN(4); + _got_end = .; + } + + . = ALIGN(4); + .u_boot_list : { + KEEP(*(SORT(.u_boot_list*))); + } + __init_end = . ; + + .bss ALIGN(0x4): + { + __bss_start = .; + *(.sbss) + *(.scommon) + *(.bss*) + *(COMMON) + . = ALIGN(4); + __bss_end = .; + } + __end = . ; +} |