diff options
Diffstat (limited to 'arch/nios2/cpu')
-rw-r--r-- | arch/nios2/cpu/Makefile | 2 | ||||
-rw-r--r-- | arch/nios2/cpu/cpu.c | 128 | ||||
-rw-r--r-- | arch/nios2/cpu/interrupts.c | 144 | ||||
-rw-r--r-- | arch/nios2/cpu/start.S | 186 | ||||
-rw-r--r-- | arch/nios2/cpu/sysid.c | 46 | ||||
-rw-r--r-- | arch/nios2/cpu/u-boot.lds | 14 |
6 files changed, 193 insertions, 327 deletions
diff --git a/arch/nios2/cpu/Makefile b/arch/nios2/cpu/Makefile index 3fe7847..185ca3c 100644 --- a/arch/nios2/cpu/Makefile +++ b/arch/nios2/cpu/Makefile @@ -7,5 +7,5 @@ extra-y = start.o obj-y = exceptions.o -obj-y += cpu.o interrupts.o sysid.o traps.o +obj-y += cpu.o interrupts.o traps.o obj-y += fdt.o diff --git a/arch/nios2/cpu/cpu.c b/arch/nios2/cpu/cpu.c index 39ae972..ff0fa20 100644 --- a/arch/nios2/cpu/cpu.c +++ b/arch/nios2/cpu/cpu.c @@ -6,25 +6,18 @@ */ #include <common.h> -#include <asm/nios2.h> +#include <cpu.h> +#include <dm.h> +#include <errno.h> #include <asm/cache.h> DECLARE_GLOBAL_DATA_PTR; -#if defined (CONFIG_SYS_NIOS_SYSID_BASE) -extern void display_sysid (void); -#endif /* CONFIG_SYS_NIOS_SYSID_BASE */ - #ifdef CONFIG_DISPLAY_CPUINFO int print_cpuinfo(void) { - printf ("CPU : Nios-II\n"); -#if !defined(CONFIG_SYS_NIOS_SYSID_BASE) - printf ("SYSID : <unknown>\n"); -#else - display_sysid (); -#endif - return (0); + printf("CPU: Nios-II\n"); + return 0; } #endif /* CONFIG_DISPLAY_CPUINFO */ @@ -32,29 +25,120 @@ int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { disable_interrupts(); /* indirect call to go beyond 256MB limitation of toolchain */ - nios2_callr(CONFIG_SYS_RESET_ADDR); + nios2_callr(gd->arch.reset_addr); return 0; } -int dcache_status(void) +/* + * COPY EXCEPTION TRAMPOLINE -- copy the tramp to the + * exception address. Define CONFIG_ROM_STUBS to prevent + * the copy (e.g. exception in flash or in other + * softare/firmware component). + */ +#ifndef CONFIG_ROM_STUBS +static void copy_exception_trampoline(void) { - return 1; + extern int _except_start, _except_end; + void *except_target = (void *)gd->arch.exception_addr; + + if (&_except_start != except_target) { + memcpy(except_target, &_except_start, + &_except_end - &_except_start); + flush_cache(gd->arch.exception_addr, + &_except_end - &_except_start); + } } +#endif -void dcache_enable(void) +int arch_cpu_init_dm(void) { - flush_dcache(CONFIG_SYS_DCACHE_SIZE, CONFIG_SYS_DCACHELINE_SIZE); + struct udevice *dev; + int ret; + + ret = uclass_first_device(UCLASS_CPU, &dev); + if (ret) + return ret; + if (!dev) + return -ENODEV; + + gd->ram_size = CONFIG_SYS_SDRAM_SIZE; +#ifndef CONFIG_ROM_STUBS + copy_exception_trampoline(); +#endif + + return 0; } -void dcache_disable(void) +static int altera_nios2_get_desc(struct udevice *dev, char *buf, int size) { - flush_dcache(CONFIG_SYS_DCACHE_SIZE, CONFIG_SYS_DCACHELINE_SIZE); + const char *cpu_name = "Nios-II"; + + if (size < strlen(cpu_name)) + return -ENOSPC; + strcpy(buf, cpu_name); + + return 0; } -int arch_cpu_init(void) +static int altera_nios2_get_info(struct udevice *dev, struct cpu_info *info) { - gd->cpu_clk = CONFIG_SYS_CLK_FREQ; - gd->ram_size = CONFIG_SYS_SDRAM_SIZE; + info->cpu_freq = gd->cpu_clk; + info->features = (1 << CPU_FEAT_L1_CACHE) | + (gd->arch.has_mmu ? (1 << CPU_FEAT_MMU) : 0); return 0; } + +static int altera_nios2_get_count(struct udevice *dev) +{ + return 1; +} + +static int altera_nios2_probe(struct udevice *dev) +{ + const void *blob = gd->fdt_blob; + int node = dev->of_offset; + + gd->cpu_clk = fdtdec_get_int(blob, node, + "clock-frequency", 0); + gd->arch.dcache_line_size = fdtdec_get_int(blob, node, + "dcache-line-size", 0); + gd->arch.icache_line_size = fdtdec_get_int(blob, node, + "icache-line-size", 0); + gd->arch.dcache_size = fdtdec_get_int(blob, node, + "dcache-size", 0); + gd->arch.icache_size = fdtdec_get_int(blob, node, + "icache-size", 0); + gd->arch.reset_addr = fdtdec_get_int(blob, node, + "altr,reset-addr", 0); + gd->arch.exception_addr = fdtdec_get_int(blob, node, + "altr,exception-addr", 0); + gd->arch.has_initda = fdtdec_get_int(blob, node, + "altr,has-initda", 0); + gd->arch.has_mmu = fdtdec_get_int(blob, node, + "altr,has-mmu", 0); + gd->arch.io_region_base = gd->arch.has_mmu ? 0xe0000000 : 0x8000000; + + return 0; +} + +static const struct cpu_ops altera_nios2_ops = { + .get_desc = altera_nios2_get_desc, + .get_info = altera_nios2_get_info, + .get_count = altera_nios2_get_count, +}; + +static const struct udevice_id altera_nios2_ids[] = { + { .compatible = "altr,nios2-1.0" }, + { .compatible = "altr,nios2-1.1" }, + { } +}; + +U_BOOT_DRIVER(altera_nios2) = { + .name = "altera_nios2", + .id = UCLASS_CPU, + .of_match = altera_nios2_ids, + .probe = altera_nios2_probe, + .ops = &altera_nios2_ops, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/arch/nios2/cpu/interrupts.c b/arch/nios2/cpu/interrupts.c index 9d7e193..1599674 100644 --- a/arch/nios2/cpu/interrupts.c +++ b/arch/nios2/cpu/interrupts.c @@ -8,43 +8,14 @@ * SPDX-License-Identifier: GPL-2.0+ */ - +#include <common.h> +#include <command.h> #include <asm/nios2.h> #include <asm/types.h> #include <asm/io.h> #include <asm/ptrace.h> -#include <common.h> -#include <command.h> -#include <watchdog.h> -#ifdef CONFIG_STATUS_LED -#include <status_led.h> -#endif - -typedef volatile struct { - unsigned status; /* Timer status reg */ - unsigned control; /* Timer control reg */ - unsigned periodl; /* Timeout period low */ - unsigned periodh; /* Timeout period high */ - unsigned snapl; /* Snapshot low */ - unsigned snaph; /* Snapshot high */ -} nios_timer_t; - -/* status register */ -#define NIOS_TIMER_TO (1 << 0) /* Timeout */ -#define NIOS_TIMER_RUN (1 << 1) /* Timer running */ - -/* control register */ -#define NIOS_TIMER_ITO (1 << 0) /* Timeout int ena */ -#define NIOS_TIMER_CONT (1 << 1) /* Continuous mode */ -#define NIOS_TIMER_START (1 << 2) /* Start timer */ -#define NIOS_TIMER_STOP (1 << 3) /* Stop timer */ - -#if defined(CONFIG_SYS_NIOS_TMRBASE) && !defined(CONFIG_SYS_NIOS_TMRIRQ) -#error CONFIG_SYS_NIOS_TMRIRQ not defined (see documentation) -#endif - -/****************************************************************************/ +/*************************************************************************/ struct irq_action { interrupt_handler_t *handler; void *arg; @@ -53,111 +24,6 @@ struct irq_action { static struct irq_action vecs[32]; -/*************************************************************************/ -volatile ulong timestamp = 0; - -void reset_timer (void) -{ - nios_timer_t *tmr =(nios_timer_t *)CONFIG_SYS_NIOS_TMRBASE; - - /* From Embedded Peripherals Handbook: - * - * "When the hardware is configured with Writeable period - * disabled, writing to one of the period_n registers causes - * the counter to reset to the fixed Timeout Period specified - * at system generation time." - * - * Here we force a reload to prevent early timeouts from - * get_timer() when the interrupt period is greater than - * than 1 msec. - * - * Simply write to periodl with its own value to force an - * internal counter reload, THEN reset the timestamp. - */ - writel (readl (&tmr->periodl), &tmr->periodl); - timestamp = 0; - - /* From Embedded Peripherals Handbook: - * - * "Writing to one of the period_n registers stops the internal - * counter, except when the hardware is configured with Start/Stop - * control bits off. If Start/Stop control bits is off, writing - * either register does not stop the counter." - * - * In order to accomodate either configuration, the control - * register is re-written. If the counter is stopped, it will - * be restarted. If it is running, the write is essentially - * a nop. - */ - writel (NIOS_TIMER_ITO | NIOS_TIMER_CONT | NIOS_TIMER_START, - &tmr->control); - -} - -ulong get_timer (ulong base) -{ - WATCHDOG_RESET (); - return (timestamp - base); -} - -/* - * This function is derived from Blackfin code (read timebase as long long). - * On Nios2 it just returns the timer value. - */ -unsigned long long get_ticks(void) -{ - return get_timer(0); -} - -/* - * This function is derived from Blackfin code. - * On Nios2 it returns the number of timer ticks per second. - */ -ulong get_tbclk(void) -{ - ulong tbclk; - - tbclk = CONFIG_SYS_HZ; - return tbclk; -} - -/* The board must handle this interrupt if a timer is not - * provided. - */ -#if defined(CONFIG_SYS_NIOS_TMRBASE) -void tmr_isr (void *arg) -{ - nios_timer_t *tmr = (nios_timer_t *)arg; - /* Interrupt is cleared by writing anything to the - * status register. - */ - writel (0, &tmr->status); - timestamp += CONFIG_SYS_NIOS_TMRMS; -#ifdef CONFIG_STATUS_LED - status_led_tick(timestamp); -#endif -} - -static void tmr_init (void) -{ - nios_timer_t *tmr =(nios_timer_t *)CONFIG_SYS_NIOS_TMRBASE; - - writel (0, &tmr->status); - writel (0, &tmr->control); - writel (NIOS_TIMER_STOP, &tmr->control); - -#if defined(CONFIG_SYS_NIOS_TMRCNT) - writel (CONFIG_SYS_NIOS_TMRCNT & 0xffff, &tmr->periodl); - writel ((CONFIG_SYS_NIOS_TMRCNT >> 16) & 0xffff, &tmr->periodh); -#endif - writel (NIOS_TIMER_ITO | NIOS_TIMER_CONT | NIOS_TIMER_START, - &tmr->control); - irq_install_handler (CONFIG_SYS_NIOS_TMRIRQ, tmr_isr, (void *)tmr); -} - -#endif /* CONFIG_SYS_NIOS_TMRBASE */ - -/*************************************************************************/ int disable_interrupts (void) { int val = rdctl (CTL_STATUS); @@ -245,10 +111,6 @@ int interrupt_init (void) vecs[i].count = 0; } -#if defined(CONFIG_SYS_NIOS_TMRBASE) - tmr_init (); -#endif - enable_interrupts (); return (0); } diff --git a/arch/nios2/cpu/start.S b/arch/nios2/cpu/start.S index 6af9b4e..8758e7e 100644 --- a/arch/nios2/cpu/start.S +++ b/arch/nios2/cpu/start.S @@ -9,30 +9,38 @@ #include <config.h> #include <version.h> -/************************************************************************* - * RESTART - ************************************************************************/ +/* + * icache and dcache configuration used only for start.S. + * the values are chosen so that it will work for all configuration. + */ +#define ICACHE_LINE_SIZE 32 /* fixed 32 */ +#define ICACHE_SIZE_MAX 0x10000 /* 64k max */ +#define DCACHE_LINE_SIZE_MIN 4 /* 4, 16, 32 */ +#define DCACHE_SIZE_MAX 0x10000 /* 64k max */ + /* RESTART */ .text - .global _start + .global _start, _except_start, _except_end _start: wrctl status, r0 /* Disable interrupts */ - /* ICACHE INIT -- only the icache line at the reset address + /* + * ICACHE INIT -- only the icache line at the reset address * is invalidated at reset. So the init must stay within * the cache line size (8 words). If GERMS is used, we'll * just be invalidating the cache a second time. If cache * is not implemented initi behaves as nop. */ - ori r4, r0, %lo(CONFIG_SYS_ICACHELINE_SIZE) - movhi r5, %hi(CONFIG_SYS_ICACHE_SIZE) - ori r5, r5, %lo(CONFIG_SYS_ICACHE_SIZE) + ori r4, r0, %lo(ICACHE_LINE_SIZE) + movhi r5, %hi(ICACHE_SIZE_MAX) + ori r5, r5, %lo(ICACHE_SIZE_MAX) 0: initi r5 sub r5, r5, r4 bgt r5, r0, 0b br _except_end /* Skip the tramp */ - /* EXCEPTION TRAMPOLINE -- the following gets copied + /* + * EXCEPTION TRAMPOLINE -- the following gets copied * to the exception address (below), but is otherwise at the * default exception vector offset (0x0020). */ @@ -42,24 +50,26 @@ _except_start: jmp et _except_end: - /* INTERRUPTS -- for now, all interrupts masked and globally + /* + * INTERRUPTS -- for now, all interrupts masked and globally * disabled. */ wrctl ienable, r0 /* All disabled */ - /* DCACHE INIT -- if dcache not implemented, initd behaves as + /* + * DCACHE INIT -- if dcache not implemented, initd behaves as * nop. */ - movhi r4, %hi(CONFIG_SYS_DCACHELINE_SIZE) - ori r4, r4, %lo(CONFIG_SYS_DCACHELINE_SIZE) - movhi r5, %hi(CONFIG_SYS_DCACHE_SIZE) - ori r5, r5, %lo(CONFIG_SYS_DCACHE_SIZE) + ori r4, r0, %lo(DCACHE_LINE_SIZE_MIN) + movhi r5, %hi(DCACHE_SIZE_MAX) + ori r5, r5, %lo(DCACHE_SIZE_MAX) mov r6, r0 1: initd 0(r6) add r6, r6, r4 bltu r6, r5, 1b - /* RELOCATE CODE, DATA & COMMAND TABLE -- the following code + /* + * RELOCATE CODE, DATA & COMMAND TABLE -- the following code * assumes code, data and the command table are all * contiguous. This lets us relocate everything as a single * block. Make sure the linker script matches this ;-) @@ -73,8 +83,9 @@ _cur: movhi r5, %hi(_cur - _start) ori r5, r5, %lo(_start) /* r5 <- linked _start */ beq r4, r5, 3f - movhi r6, %hi(_edata) - ori r6, r6, %lo(_edata) + movhi r6, %hi(CONFIG_SYS_MONITOR_LEN) + ori r6, r6, %lo(CONFIG_SYS_MONITOR_LEN) + add r6, r6, r5 2: ldwio r7, 0(r4) addi r4, r4, 4 stwio r7, 0(r5) @@ -82,50 +93,13 @@ _cur: movhi r5, %hi(_cur - _start) bne r5, r6, 2b 3: - /* ZERO BSS/SBSS -- bss and sbss are assumed to be adjacent - * and between __bss_start and __bss_end. - */ - movhi r5, %hi(__bss_start) - ori r5, r5, %lo(__bss_start) - movhi r6, %hi(__bss_end) - ori r6, r6, %lo(__bss_end) - beq r5, r6, 5f - -4: stwio r0, 0(r5) - addi r5, r5, 4 - bne r5, r6, 4b -5: - /* JUMP TO RELOC ADDR */ movhi r4, %hi(_reloc) ori r4, r4, %lo(_reloc) jmp r4 _reloc: - /* COPY EXCEPTION TRAMPOLINE -- copy the tramp to the - * exception address. Define CONFIG_ROM_STUBS to prevent - * the copy (e.g. exception in flash or in other - * softare/firmware component). - */ -#if !defined(CONFIG_ROM_STUBS) - movhi r4, %hi(_except_start) - ori r4, r4, %lo(_except_start) - movhi r5, %hi(_except_end) - ori r5, r5, %lo(_except_end) - movhi r6, %hi(CONFIG_SYS_EXCEPTION_ADDR) - ori r6, r6, %lo(CONFIG_SYS_EXCEPTION_ADDR) - beq r4, r6, 7f /* Skip if at proper addr */ - -6: ldwio r7, 0(r4) - stwio r7, 0(r6) - addi r4, r4, 4 - addi r6, r6, 4 - bne r4, r5, 6b -7: -#endif - - /* STACK INIT -- zero top two words for call back chain. - */ + /* STACK INIT -- zero top two words for call back chain. */ movhi sp, %hi(CONFIG_SYS_INIT_SP) ori sp, sp, %lo(CONFIG_SYS_INIT_SP) addi sp, sp, -8 @@ -133,80 +107,64 @@ _reloc: stw r0, 4(sp) mov fp, sp - /* - * Call board_init_f -- never returns - */ + /* Allocate and zero GD, update SP */ + mov r4, sp + movhi r2, %hi(board_init_f_mem@h) + ori r2, r2, %lo(board_init_f_mem@h) + callr r2 + + /* Update stack- and frame-pointers */ + mov sp, r2 + mov fp, sp + + /* Call board_init_f -- never returns */ mov r4, r0 movhi r2, %hi(board_init_f@h) ori r2, r2, %lo(board_init_f@h) callr r2 - /* NEVER RETURNS -- but branch to the _start just + /* + * NEVER RETURNS -- but branch to the _start just * in case ;-) */ br _start - - -/* - * relocate_code -- Nios2 handles the relocation above. But - * the generic board code monkeys with the heap, stack, etc. - * (it makes some assumptions that may not be appropriate - * for Nios). Nevertheless, we capitulate here. - * - * We'll call the board_init_r from here since this isn't - * supposed to return. - * - * void relocate_code (ulong sp, gd_t *global_data, - * ulong reloc_addr) - * __attribute__ ((noreturn)); - */ + /* + * relocate_code -- Nios2 handles the relocation above. But + * the generic board code monkeys with the heap, stack, etc. + * (it makes some assumptions that may not be appropriate + * for Nios). Nevertheless, we capitulate here. + * + * We'll call the board_init_r from here since this isn't + * supposed to return. + * + * void relocate_code (ulong sp, gd_t *global_data, + * ulong reloc_addr) + * __attribute__ ((noreturn)); + */ .text .global relocate_code relocate_code: mov sp, r4 /* Set the new sp */ mov r4, r5 - movhi r8, %hi(board_init_r@h) - ori r8, r8, %lo(board_init_r@h) - callr r8 - ret -/* - * dly_clks -- Nios2 (like Nios1) doesn't have a timebase in - * the core. For simple delay loops, we do our best by counting - * instruction cycles. - * - * Instruction performance varies based on the core. For cores - * with icache and static/dynamic branch prediction (II/f, II/s): - * - * Normal ALU (e.g. add, cmp, etc): 1 cycle - * Branch (correctly predicted, taken): 2 cycles - * Negative offset is predicted (II/s). - * - * For cores without icache and no branch prediction (II/e): - * - * Normal ALU (e.g. add, cmp, etc): 6 cycles - * Branch (no prediction): 6 cycles - * - * For simplicity, if an instruction cache is implemented we - * assume II/f or II/s. Otherwise, we use the II/e. - * - */ - .globl dly_clks + /* + * ZERO BSS/SBSS -- bss and sbss are assumed to be adjacent + * and between __bss_start and __bss_end. + */ + movhi r5, %hi(__bss_start) + ori r5, r5, %lo(__bss_start) + movhi r6, %hi(__bss_end) + ori r6, r6, %lo(__bss_end) + beq r5, r6, 5f -dly_clks: +4: stwio r0, 0(r5) + addi r5, r5, 4 + bne r5, r6, 4b +5: -#if (CONFIG_SYS_ICACHE_SIZE > 0) - subi r4, r4, 3 /* 3 clocks/loop */ -#else - subi r4, r4, 12 /* 12 clocks/loop */ -#endif - bge r4, r0, dly_clks + movhi r8, %hi(board_init_r@h) + ori r8, r8, %lo(board_init_r@h) + callr r8 ret - - .data - .globl version_string - -version_string: - .ascii U_BOOT_VERSION_STRING, "\0" diff --git a/arch/nios2/cpu/sysid.c b/arch/nios2/cpu/sysid.c deleted file mode 100644 index 50819b2..0000000 --- a/arch/nios2/cpu/sysid.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * (C) Copyright 2004, Psyent Corporation <www.psyent.com> - * Scott McNutt <smcnutt@psyent.com> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> - -#if defined (CONFIG_SYS_NIOS_SYSID_BASE) - -#include <command.h> -#include <asm/io.h> -#include <linux/time.h> - -typedef volatile struct { - unsigned id; /* The system build id */ - unsigned timestamp; /* Timestamp */ -} nios_sysid_t; - -void display_sysid (void) -{ - nios_sysid_t *sysid = (nios_sysid_t *)CONFIG_SYS_NIOS_SYSID_BASE; - struct tm t; - char asc[32]; - time_t stamp; - - stamp = readl (&sysid->timestamp); - localtime_r (&stamp, &t); - asctime_r (&t, asc); - printf ("SYSID : %08lx, %s", readl (&sysid->id), asc); - -} - -int do_sysid (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) -{ - display_sysid (); - return (0); -} - -U_BOOT_CMD( - sysid, 1, 1, do_sysid, - "display Nios-II system id", - "" -); -#endif /* CONFIG_SYS_NIOS_SYSID_BASE */ diff --git a/arch/nios2/cpu/u-boot.lds b/arch/nios2/cpu/u-boot.lds index 6e174be..3bd3f2c 100644 --- a/arch/nios2/cpu/u-boot.lds +++ b/arch/nios2/cpu/u-boot.lds @@ -50,9 +50,11 @@ SECTIONS *(.gnu.linkonce.d*) } - . = ALIGN(16); - _gp = .; /* Global pointer addr */ - PROVIDE (gp = .); + /* + * gp - Since we don't use gp for small data with option "-G0", + * we will use gp as global data pointer. The _gp location is + * not needed. + */ .sdata : { @@ -65,6 +67,12 @@ SECTIONS _edata = .; PROVIDE (edata = .); + /* + * _end - This is end of u-boot.bin image. + * dtb will be appended here to make u-boot-dtb.bin + */ + _end = .; + /* UNINIT DATA - Small uninitialized data is first so it's * adjacent to sdata and can be referenced via gp. The normal * bss follows. We keep it adjacent to simplify init code. |