diff options
Diffstat (limited to 'arch/mips/cpu')
-rw-r--r-- | arch/mips/cpu/Makefile | 2 | ||||
-rw-r--r-- | arch/mips/cpu/cm_init.S | 45 | ||||
-rw-r--r-- | arch/mips/cpu/cpu.c | 7 | ||||
-rw-r--r-- | arch/mips/cpu/start.S | 93 | ||||
-rw-r--r-- | arch/mips/cpu/u-boot.lds | 2 |
5 files changed, 113 insertions, 36 deletions
diff --git a/arch/mips/cpu/Makefile b/arch/mips/cpu/Makefile index fc6b455c68..429fd3a50c 100644 --- a/arch/mips/cpu/Makefile +++ b/arch/mips/cpu/Makefile @@ -7,3 +7,5 @@ extra-y = start.o obj-y += time.o obj-y += interrupts.o obj-y += cpu.o + +obj-$(CONFIG_MIPS_CM) += cm_init.o diff --git a/arch/mips/cpu/cm_init.S b/arch/mips/cpu/cm_init.S new file mode 100644 index 0000000000..ddcaa4947f --- /dev/null +++ b/arch/mips/cpu/cm_init.S @@ -0,0 +1,45 @@ +/* + * MIPS Coherence Manager (CM) Initialisation + * + * Copyright (c) 2016 Imagination Technologies Ltd. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <asm/addrspace.h> +#include <asm/asm.h> +#include <asm/cm.h> +#include <asm/mipsregs.h> +#include <asm/regdef.h> + +LEAF(mips_cm_map) + /* Config3 must exist for a CM to be present */ + mfc0 t0, CP0_CONFIG, 1 + bgez t0, 2f + mfc0 t0, CP0_CONFIG, 2 + bgez t0, 2f + + /* Check Config3.CMGCR to determine CM presence */ + mfc0 t0, CP0_CONFIG, 3 + and t0, t0, MIPS_CONF3_CMGCR + beqz t0, 2f + + /* Find the current physical GCR base address */ +1: MFC0 t0, CP0_CMGCRBASE + PTR_SLL t0, t0, 4 + + /* If the GCRs are where we want, we're done */ + PTR_LI t1, CONFIG_MIPS_CM_BASE + beq t0, t1, 2f + + /* Move the GCRs to our configured base address */ + PTR_LI t2, CKSEG1 + PTR_ADDU t0, t0, t2 + sw zero, GCR_BASE_UPPER(t0) + sw t1, GCR_BASE(t0) + + /* Re-check the GCR base */ + b 1b + +2: jr ra + END(mips_cm_map) diff --git a/arch/mips/cpu/cpu.c b/arch/mips/cpu/cpu.c index 391feb3250..1b919ed822 100644 --- a/arch/mips/cpu/cpu.c +++ b/arch/mips/cpu/cpu.c @@ -8,6 +8,7 @@ #include <common.h> #include <command.h> #include <linux/compiler.h> +#include <asm/cache.h> #include <asm/mipsregs.h> #include <asm/reboot.h> @@ -35,3 +36,9 @@ void write_one_tlb(int index, u32 pagemask, u32 hi, u32 low0, u32 low1) write_c0_index(index); tlb_write_indexed(); } + +int arch_cpu_init(void) +{ + mips_cache_probe(); + return 0; +} diff --git a/arch/mips/cpu/start.S b/arch/mips/cpu/start.S index fc6dd66aa6..3f0fc12547 100644 --- a/arch/mips/cpu/start.S +++ b/arch/mips/cpu/start.S @@ -12,10 +12,6 @@ #include <asm/regdef.h> #include <asm/mipsregs.h> -#ifndef CONFIG_SYS_MIPS_CACHE_MODE -#define CONFIG_SYS_MIPS_CACHE_MODE CONF_CM_CACHABLE_NONCOHERENT -#endif - #ifndef CONFIG_SYS_INIT_SP_ADDR #define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_SDRAM_BASE + \ CONFIG_SYS_INIT_SP_OFFSET) @@ -112,9 +108,28 @@ ENTRY(_start) .align 4 reset: +#if __mips_isa_rev >= 6 + mfc0 t0, CP0_CONFIG, 5 + and t0, t0, MIPS_CONF5_VP + beqz t0, 1f + nop + + b 2f + mfc0 t0, CP0_GLOBALNUMBER +#endif + +1: mfc0 t0, CP0_EBASE + and t0, t0, EBASE_CPUNUM + + /* Hang if this isn't the first CPU in the system */ +2: beqz t0, 4f + nop +3: wait + b 3b + nop /* Clear watch registers */ - MTC0 zero, CP0_WATCHLO +4: MTC0 zero, CP0_WATCHLO mtc0 zero, CP0_WATCHHI /* WP(Watch Pending), SW0/1 should be cleared */ @@ -127,9 +142,11 @@ reset: mtc0 zero, CP0_COMPARE #ifndef CONFIG_SKIP_LOWLEVEL_INIT - /* CONFIG0 register */ - li t0, CONF_CM_UNCACHED + mfc0 t0, CP0_CONFIG + and t0, t0, MIPS_CONF_IMPL + or t0, t0, CONF_CM_UNCACHED mtc0 t0, CP0_CONFIG + ehb #endif /* @@ -144,20 +161,31 @@ reset: 1: PTR_L gp, 0(ra) +#ifdef CONFIG_MIPS_CM + PTR_LA t9, mips_cm_map + jalr t9 + nop +#endif + #ifndef CONFIG_SKIP_LOWLEVEL_INIT +# ifdef CONFIG_SYS_MIPS_CACHE_INIT_RAM_LOAD /* Initialize any external memory */ PTR_LA t9, lowlevel_init jalr t9 nop +# endif /* Initialize caches... */ PTR_LA t9, mips_cache_reset jalr t9 nop - /* ... and enable them */ - li t0, CONFIG_SYS_MIPS_CACHE_MODE - mtc0 t0, CP0_CONFIG +# ifndef CONFIG_SYS_MIPS_CACHE_INIT_RAM_LOAD + /* Initialize any external memory */ + PTR_LA t9, lowlevel_init + jalr t9 + nop +# endif #endif /* Set up temporary stack */ @@ -214,12 +242,9 @@ ENTRY(relocate_code) PTR_LI t0, CONFIG_SYS_MONITOR_BASE PTR_SUB s1, s2, t0 # s1 <-- relocation offset - PTR_LA t3, in_ram - PTR_L t2, -(3 * PTRSIZE)(t3) # t2 <-- __image_copy_end + PTR_LA t2, __image_copy_end move t1, a2 - PTR_ADD gp, s1 # adjust gp - /* * t0 = source address * t1 = target address @@ -232,32 +257,14 @@ ENTRY(relocate_code) blt t0, t2, 1b PTR_ADDU t1, PTRSIZE - /* If caches were enabled, we would have to flush them here. */ - PTR_SUB a1, t1, s2 # a1 <-- size - PTR_LA t9, flush_cache - jalr t9 - move a0, s2 # a0 <-- destination address - - /* Jump to where we've relocated ourselves */ - PTR_ADDIU t0, s2, in_ram - _start - jr t0 - nop - - PTR __rel_dyn_end - PTR __rel_dyn_start - PTR __image_copy_end - PTR _GLOBAL_OFFSET_TABLE_ - PTR num_got_entries - -in_ram: /* * Now we want to update GOT. * * GOT[0] is reserved. GOT[1] is also reserved for the dynamic object * generated by GNU ld. Skip these reserved entries from relocation. */ - PTR_L t3, -(1 * PTRSIZE)(t0) # t3 <-- num_got_entries - PTR_L t8, -(2 * PTRSIZE)(t0) # t8 <-- _GLOBAL_OFFSET_TABLE_ + PTR_LA t3, num_got_entries + PTR_LA t8, _GLOBAL_OFFSET_TABLE_ PTR_ADD t8, s1 # t8 now holds relocated _G_O_T_ PTR_ADDIU t8, t8, 2 * PTRSIZE # skipping first two entries PTR_LI t2, 2 @@ -272,8 +279,8 @@ in_ram: PTR_ADDIU t8, PTRSIZE /* Update dynamic relocations */ - PTR_L t1, -(4 * PTRSIZE)(t0) # t1 <-- __rel_dyn_start - PTR_L t2, -(5 * PTRSIZE)(t0) # t2 <-- __rel_dyn_end + PTR_LA t1, __rel_dyn_start + PTR_LA t2, __rel_dyn_end b 2f # skip first reserved entry PTR_ADDIU t1, 2 * PTRSIZE @@ -298,6 +305,20 @@ in_ram: PTR_ADDIU t1, 2 * PTRSIZE # each rel.dyn entry is 2*PTRSIZE bytes /* + * Flush caches to ensure our newly modified instructions are visible + * to the instruction cache. We're still running with the old GOT, so + * apply the reloc offset to the start address. + */ + PTR_LA a0, __text_start + PTR_LA a1, __text_end + PTR_SUB a1, a1, a0 + PTR_LA t9, flush_cache + jalr t9 + PTR_ADD a0, s1 + + PTR_ADD gp, s1 # adjust gp + + /* * Clear BSS * * GOT is now relocated. Thus __bss_start and __bss_end can be diff --git a/arch/mips/cpu/u-boot.lds b/arch/mips/cpu/u-boot.lds index 7d71c11ae4..0129c99611 100644 --- a/arch/mips/cpu/u-boot.lds +++ b/arch/mips/cpu/u-boot.lds @@ -19,7 +19,9 @@ SECTIONS . = ALIGN(4); .text : { + __text_start = .; *(.text*) + __text_end = .; } . = ALIGN(4); |