From e1390801a3c1a2b6d12fa90be368efc19f5b9bfd Mon Sep 17 00:00:00 2001 From: Shinya Kuribayashi Date: Tue, 25 Mar 2008 11:39:29 +0900 Subject: [MIPS] Request for the 'mips_cache_lock()' removal The initial intension of having mips_cache_lock() was to use the cache as memory for temporary stack use so that a C environment can be set up as early as possible. But now mips_cache_lock() follow lowlevel_init(). We've already have the real memory initilaized at this point, therefore we could/should use it. No reason to lock at all. Other problems: Cache locking is not consistent across MIPS implementaions. Some imple- mentations don't support locking at all. The style of locking varies - some support per line locking, others per way, etc. Some parts use bits in status registers instead of cache ops. Current mips_cache_lock() is not necessarily general-purpose. And this is worthy of special mention; once U-Boot/MIPS locks the lines, they are never get unlocked, so the code relies on whatever gets loaded after U-Boot to re-initialize the cache and clear the locks. We're sup- posed to have CFG_INIT_RAM_LOCK and unlock_ram_in_cache() implemented, but leave the situation as it is for a long time. For these reasons, I proposed the removal of mips_cache_lock() from the global start-up code. This patch adds CFG_INIT_RAM_LOCK_MIPS to make existing users aware that *things have changed*. If he wants the same behavior as before, he needs to have CFG_INIT_RAM_LOCK_MIPS in his config file. If we don't have any regression report through several releases, then we'll remove codes entirely. Signed-off-by: Shinya Kuribayashi Acked-by: Andrew Dyer --- cpu/mips/cache.S | 2 ++ cpu/mips/start.S | 2 ++ 2 files changed, 4 insertions(+) (limited to 'cpu') diff --git a/cpu/mips/cache.S b/cpu/mips/cache.S index 443240e..67ee19f 100644 --- a/cpu/mips/cache.S +++ b/cpu/mips/cache.S @@ -238,6 +238,7 @@ dcache_disable: .end dcache_disable +#ifdef CFG_INIT_RAM_LOCK_MIPS /******************************************************************************* * * mips_cache_lock - lock RAM area pointed to by a0 in cache. @@ -263,3 +264,4 @@ mips_cache_lock: j ra .end mips_cache_lock +#endif /* CFG_INIT_RAM_LOCK_MIPS */ diff --git a/cpu/mips/start.S b/cpu/mips/start.S index c92b162..930f9b3 100644 --- a/cpu/mips/start.S +++ b/cpu/mips/start.S @@ -267,10 +267,12 @@ reset: /* Set up temporary stack. */ +#ifdef CFG_INIT_RAM_LOCK_MIPS li a0, CFG_INIT_SP_OFFSET la t9, mips_cache_lock jalr t9 nop +#endif li t0, CFG_SDRAM_BASE + CFG_INIT_SP_OFFSET la sp, 0(t0) -- cgit v1.1 From 2f5d414ccb4024dd0992ff6b22561732dbc73590 Mon Sep 17 00:00:00 2001 From: Shinya Kuribayashi Date: Tue, 25 Mar 2008 21:30:06 +0900 Subject: [MIPS] cpu/mips/cache.S: Introduce NESTED/LEAF/END macros This patch replaces the current function definitions with NESTED, LEAF and END macro. They specify some more additional information about the function; an alignment of symbol, type of symbol, stack frame usage, etc. These information explicitly tells the assembler and the debugger about the types of code we want to generate. Signed-off-by: Shinya Kuribayashi --- cpu/mips/cache.S | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) (limited to 'cpu') diff --git a/cpu/mips/cache.S b/cpu/mips/cache.S index 67ee19f..e2e1da0 100644 --- a/cpu/mips/cache.S +++ b/cpu/mips/cache.S @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -119,10 +120,7 @@ * RETURNS: N/A * */ - .globl mips_cache_reset - .ent mips_cache_reset -mips_cache_reset: - +NESTED(mips_cache_reset, 0, ra) li t2, CFG_ICACHE_SIZE li t3, CFG_DCACHE_SIZE li t4, CFG_CACHELINE_SIZE @@ -198,8 +196,7 @@ mips_cache_reset: icacheop(a0,a1,a2,a3,Index_Store_Tag_D) j ra - - .end mips_cache_reset + END(mips_cache_reset) /******************************************************************************* * @@ -208,15 +205,11 @@ mips_cache_reset: * RETURNS: 0 - cache disabled; 1 - cache enabled * */ - .globl dcache_status - .ent dcache_status -dcache_status: - +LEAF(dcache_status) mfc0 v0, CP0_CONFIG andi v0, v0, 1 j ra - - .end dcache_status + END(dcache_status) /******************************************************************************* * @@ -225,18 +218,14 @@ dcache_status: * RETURNS: N/A * */ - .globl dcache_disable - .ent dcache_disable -dcache_disable: - +LEAF(dcache_disable) mfc0 t0, CP0_CONFIG li t1, -8 and t0, t0, t1 ori t0, t0, CONF_CM_UNCACHED mtc0 t0, CP0_CONFIG j ra - - .end dcache_disable + END(dcache_disable) #ifdef CFG_INIT_RAM_LOCK_MIPS /******************************************************************************* -- cgit v1.1 From 1898840797c7f50799377bd5b285a8a93a82c419 Mon Sep 17 00:00:00 2001 From: Shinya Kuribayashi Date: Tue, 25 Mar 2008 21:30:06 +0900 Subject: [MIPS] Replace memory clearance code with f_fill64 This routine fills memory with zero by 64 bytes, and is 64-bit capable. Signed-off-by: Shinya Kuribayashi --- cpu/mips/cache.S | 43 ++++++++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 15 deletions(-) (limited to 'cpu') diff --git a/cpu/mips/cache.S b/cpu/mips/cache.S index e2e1da0..6d39ba9 100644 --- a/cpu/mips/cache.S +++ b/cpu/mips/cache.S @@ -104,6 +104,27 @@ #define icacheop(kva, n, cacheSize, cacheLineSize, op) \ icacheopn(kva, n, cacheSize, cacheLineSize, 1, (op)) + .macro f_fill64 dst, offset, val + LONG_S \val, (\offset + 0 * LONGSIZE)(\dst) + LONG_S \val, (\offset + 1 * LONGSIZE)(\dst) + LONG_S \val, (\offset + 2 * LONGSIZE)(\dst) + LONG_S \val, (\offset + 3 * LONGSIZE)(\dst) + LONG_S \val, (\offset + 4 * LONGSIZE)(\dst) + LONG_S \val, (\offset + 5 * LONGSIZE)(\dst) + LONG_S \val, (\offset + 6 * LONGSIZE)(\dst) + LONG_S \val, (\offset + 7 * LONGSIZE)(\dst) +#if LONGSIZE == 4 + LONG_S \val, (\offset + 8 * LONGSIZE)(\dst) + LONG_S \val, (\offset + 9 * LONGSIZE)(\dst) + LONG_S \val, (\offset + 10 * LONGSIZE)(\dst) + LONG_S \val, (\offset + 11 * LONGSIZE)(\dst) + LONG_S \val, (\offset + 12 * LONGSIZE)(\dst) + LONG_S \val, (\offset + 13 * LONGSIZE)(\dst) + LONG_S \val, (\offset + 14 * LONGSIZE)(\dst) + LONG_S \val, (\offset + 15 * LONGSIZE)(\dst) +#endif + .endm + /******************************************************************************* * * mips_cache_reset - low level initialisation of the primary caches @@ -128,22 +149,14 @@ NESTED(mips_cache_reset, 0, ra) li v0, MIPS_MAX_CACHE_SIZE - /* Now clear that much memory starting from zero. + /* + * Now clear that much memory starting from zero. */ - - li a0, KSEG1 - addu a1, a0, v0 -2: - sw zero, 0(a0) - sw zero, 4(a0) - sw zero, 8(a0) - sw zero, 12(a0) - sw zero, 16(a0) - sw zero, 20(a0) - sw zero, 24(a0) - sw zero, 28(a0) - addu a0, 32 - bltu a0, a1, 2b + PTR_LI a0, KSEG1 + PTR_ADDU a1, a0, v0 +2: PTR_ADDIU a0, 64 + f_fill64 a0, -64, zero + bne a0, a1, 2b /* Set invalid tag. */ -- cgit v1.1 From 2e0e5271aac917812a76c72030a2b2c6f1d3387d Mon Sep 17 00:00:00 2001 From: Shinya Kuribayashi Date: Tue, 25 Mar 2008 21:30:06 +0900 Subject: [MIPS] Fix I-/D-cache initialization loops Currently we do 1) Index_Store_Tag_I, 2) Fill and 3) Index_Store_Tag_I again per a loop for I-cache initialization. But according to 'See MIPS Run', we're encouraged to use three separate loops rather than combining them *for both I- and D-cache*. This patch tries to fix this. In accordance with fixing above, mips_init_[id]cache are separated from mips_cache_reset(), and rewrite cache loops are completely rewritten with useful macros. Signed-off-by: Shinya Kuribayashi --- cpu/mips/cache.S | 115 ++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 76 insertions(+), 39 deletions(-) (limited to 'cpu') diff --git a/cpu/mips/cache.S b/cpu/mips/cache.S index 6d39ba9..bb42616 100644 --- a/cpu/mips/cache.S +++ b/cpu/mips/cache.S @@ -30,11 +30,23 @@ #include #include +#define RA t8 + /* 16KB is the maximum size of instruction and data caches on * MIPS 4K. */ #define MIPS_MAX_CACHE_SIZE 0x4000 +#define INDEX_BASE KSEG0 + + .macro cache_op op addr + .set push + .set noreorder + .set mips3 + cache \op, 0(\addr) + .set pop + .endm + /* * cacheop macro to automate cache operations * first some helpers... @@ -125,6 +137,56 @@ #endif .endm +/* + * mips_init_icache(uint PRId, ulong icache_size, unchar icache_linesz) + */ +LEAF(mips_init_icache) + blez a1, 9f + mtc0 zero, CP0_TAGLO + /* clear tag to invalidate */ + PTR_LI t0, INDEX_BASE + PTR_ADDU t1, t0, a1 +1: cache_op Index_Store_Tag_I t0 + PTR_ADDU t0, a2 + bne t0, t1, 1b + /* fill once, so data field parity is correct */ + PTR_LI t0, INDEX_BASE +2: cache_op Fill t0 + PTR_ADDU t0, a2 + bne t0, t1, 2b + /* invalidate again - prudent but not strictly neccessary */ + PTR_LI t0, INDEX_BASE +1: cache_op Index_Store_Tag_I t0 + PTR_ADDU t0, a2 + bne t0, t1, 1b +9: jr ra + END(mips_init_icache) + +/* + * mips_init_dcache(uint PRId, ulong dcache_size, unchar dcache_linesz) + */ +LEAF(mips_init_dcache) + blez a1, 9f + mtc0 zero, CP0_TAGLO + /* clear all tags */ + PTR_LI t0, INDEX_BASE + PTR_ADDU t1, t0, a1 +1: cache_op Index_Store_Tag_D t0 + PTR_ADDU t0, a2 + bne t0, t1, 1b + /* load from each line (in cached space) */ + PTR_LI t0, INDEX_BASE +2: LONG_L zero, 0(t0) + PTR_ADDU t0, a2 + bne t0, t1, 2b + /* clear all tags */ + PTR_LI t0, INDEX_BASE +1: cache_op Index_Store_Tag_D t0 + PTR_ADDU t0, a2 + bne t0, t1, 1b +9: jr ra + END(mips_init_dcache) + /******************************************************************************* * * mips_cache_reset - low level initialisation of the primary caches @@ -142,6 +204,7 @@ * */ NESTED(mips_cache_reset, 0, ra) + move RA, ra li t2, CFG_ICACHE_SIZE li t3, CFG_DCACHE_SIZE li t4, CFG_CACHELINE_SIZE @@ -158,57 +221,31 @@ NESTED(mips_cache_reset, 0, ra) f_fill64 a0, -64, zero bne a0, a1, 2b - /* Set invalid tag. - */ - - mtc0 zero, CP0_TAGLO - /* * The caches are probably in an indeterminate state, * so we force good parity into them by doing an * invalidate, load/fill, invalidate for each line. */ - /* Assume bottom of RAM will generate good parity for the cache. - */ - - li a0, K0BASE - move a2, t2 # icacheSize - move a3, t4 # icacheLineSize - move a1, a2 - icacheopn(a0,a1,a2,a3,121,(Index_Store_Tag_I,Fill)) - - /* To support Orion/R4600, we initialise the data cache in 3 passes. - */ - - /* 1: initialise dcache tags. + /* + * Assume bottom of RAM will generate good parity for the cache. */ - li a0, K0BASE - move a2, t3 # dcacheSize - move a3, t5 # dcacheLineSize - move a1, a2 - icacheop(a0,a1,a2,a3,Index_Store_Tag_D) - - /* 2: fill dcache. + /* + * Initialize the I-cache first, */ + move a1, t2 + move a2, t4 + bal mips_init_icache - li a0, K0BASE - move a2, t3 # dcacheSize - move a3, t5 # dcacheLineSize - move a1, a2 - icacheopn(a0,a1,a2,a3,1lw,(dummy)) - - /* 3: clear dcache tags. + /* + * then initialize D-cache. */ + move a1, t3 + move a2, t5 + bal mips_init_dcache - li a0, K0BASE - move a2, t3 # dcacheSize - move a3, t5 # dcacheLineSize - move a1, a2 - icacheop(a0,a1,a2,a3,Index_Store_Tag_D) - - j ra + jr RA END(mips_cache_reset) /******************************************************************************* -- cgit v1.1 From ccf8f824ef67df028dedb29f8ea5d71a5a88d895 Mon Sep 17 00:00:00 2001 From: Shinya Kuribayashi Date: Tue, 25 Mar 2008 21:30:06 +0900 Subject: [MIPS] Implement flush_cache() We do Hit_Writeback_Inv_D and Hit_Invalidate_I. You might think that you don't need to do Hit_Invalidate_I, but flush_cache() needs it since this function is used not only in U-Boot specfic programs but also at loading target binaries. Signed-off-by: Shinya Kuribayashi --- cpu/mips/cpu.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'cpu') diff --git a/cpu/mips/cpu.c b/cpu/mips/cpu.c index 7559ac6..de70c4d 100644 --- a/cpu/mips/cpu.c +++ b/cpu/mips/cpu.c @@ -25,6 +25,17 @@ #include #include #include +#include + +#define cache_op(op,addr) \ + __asm__ __volatile__( \ + " .set push \n" \ + " .set noreorder \n" \ + " .set mips3\n\t \n" \ + " cache %0, %1 \n" \ + " .set pop \n" \ + : \ + : "i" (op), "R" (*(unsigned char *)(addr))) int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) { @@ -41,6 +52,17 @@ int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) void flush_cache(ulong start_addr, ulong size) { + unsigned long lsize = CFG_CACHELINE_SIZE; + unsigned long addr = start_addr & ~(lsize - 1); + unsigned long aend = (start_addr + size - 1) & ~(lsize - 1); + + while (1) { + cache_op(Hit_Writeback_Inv_D, start_addr); + cache_op(Hit_Invalidate_I, start_addr); + if (addr == aend) + break; + addr += lsize; + } } void write_one_tlb(int index, u32 pagemask, u32 hi, u32 low0, u32 low1) -- cgit v1.1 From 26138623230ca2bad3c78e05a65527ea70c8b688 Mon Sep 17 00:00:00 2001 From: Shinya Kuribayashi Date: Tue, 25 Mar 2008 21:30:07 +0900 Subject: [MIPS] INCA-IP: Move watchdog init code from start.S to lowlevel_init() Move things to appropriate place. Signed-off-by: Shinya Kuribayashi --- cpu/mips/start.S | 8 -------- 1 file changed, 8 deletions(-) (limited to 'cpu') diff --git a/cpu/mips/start.S b/cpu/mips/start.S index 930f9b3..fde2944 100644 --- a/cpu/mips/start.S +++ b/cpu/mips/start.S @@ -240,14 +240,6 @@ reset: 1: lw gp, 0(ra) -#ifdef CONFIG_INCA_IP - /* Disable INCA-IP Watchdog. - */ - la t9, disable_incaip_wdt - jalr t9 - nop -#endif - /* Initialize any external memory. */ la t9, lowlevel_init -- cgit v1.1 From d43d43ef2845af309c25a64bb9c2c5fb3261bc23 Mon Sep 17 00:00:00 2001 From: Shinya Kuribayashi Date: Tue, 25 Mar 2008 21:30:07 +0900 Subject: [MIPS] Initialize CP0 Cause before setting up CP0 Status register Without this change, we'll be suffering from deffered WATCH exception once Status.EXL is cleared. Make sure Cause.WP is cleared. Signed-off-by: Shinya Kuribayashi --- cpu/mips/start.S | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'cpu') diff --git a/cpu/mips/start.S b/cpu/mips/start.S index fde2944..0ecdd83 100644 --- a/cpu/mips/start.S +++ b/cpu/mips/start.S @@ -211,6 +211,9 @@ reset: mtc0 zero, CP0_WATCHLO mtc0 zero, CP0_WATCHHI + /* WP(Watch Pending), SW0/1 should be cleared. */ + mtc0 zero, CP0_CAUSE + /* STATUS register */ #ifdef CONFIG_TB0229 li k0, ST0_CU0 @@ -221,9 +224,6 @@ reset: and k0, k1 mtc0 k0, CP0_STATUS - /* CAUSE register */ - mtc0 zero, CP0_CAUSE - /* Init Timer */ mtc0 zero, CP0_COUNT mtc0 zero, CP0_COMPARE -- cgit v1.1 From decaba6f5cf386d569ac3997bebb871b966c6b18 Mon Sep 17 00:00:00 2001 From: Shinya Kuribayashi Date: Tue, 25 Mar 2008 21:30:07 +0900 Subject: [MIPS] Cleanup CP0 Status initialization Add setup_c0_status from Linux. For the moment we disable interrupts, set CU0, mark the kernel mode, and clear ERL and EXL. This is good enough for reset-time configuration and will work well across most processors. Signed-off-by: Shinya Kuribayashi --- cpu/mips/start.S | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) (limited to 'cpu') diff --git a/cpu/mips/start.S b/cpu/mips/start.S index 0ecdd83..baac2ce 100644 --- a/cpu/mips/start.S +++ b/cpu/mips/start.S @@ -27,6 +27,30 @@ #include #include + /* + * For the moment disable interrupts, mark the kernel mode and + * set ST0_KX so that the CPU does not spit fire when using + * 64-bit addresses. + */ + .macro setup_c0_status set clr + .set push + mfc0 t0, CP0_STATUS + or t0, ST0_CU0 | \set | 0x1f | \clr + xor t0, 0x1f | \clr + mtc0 t0, CP0_STATUS + .set noreorder + sll zero, 3 # ehb + .set pop + .endm + + .macro setup_c0_status_reset +#ifdef CONFIG_64BIT + setup_c0_status ST0_KX 0 +#else + setup_c0_status 0 0 +#endif + .endm + #define RVECENT(f,n) \ b f; nop #define XVECENT(f,bev) \ @@ -214,15 +238,7 @@ reset: /* WP(Watch Pending), SW0/1 should be cleared. */ mtc0 zero, CP0_CAUSE - /* STATUS register */ -#ifdef CONFIG_TB0229 - li k0, ST0_CU0 -#else - mfc0 k0, CP0_STATUS -#endif - li k1, ~ST0_IE - and k0, k1 - mtc0 k0, CP0_STATUS + setup_c0_status_reset /* Init Timer */ mtc0 zero, CP0_COUNT -- cgit v1.1 From b0c66af53ec9385ac2d1cc2e5d7d1ecdc81caf34 Mon Sep 17 00:00:00 2001 From: Shinya Kuribayashi Date: Tue, 25 Mar 2008 21:30:07 +0900 Subject: [MIPS] Introduce _machine_restart Handles machine specific functions by using weak functions. Signed-off-by: Shinya Kuribayashi --- cpu/mips/cpu.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'cpu') diff --git a/cpu/mips/cpu.c b/cpu/mips/cpu.c index de70c4d..8b43d8e 100644 --- a/cpu/mips/cpu.c +++ b/cpu/mips/cpu.c @@ -23,9 +23,9 @@ #include #include -#include #include #include +#include #define cache_op(op,addr) \ __asm__ __volatile__( \ @@ -37,15 +37,14 @@ : \ : "i" (op), "R" (*(unsigned char *)(addr))) +void __attribute__((weak)) _machine_restart(void) +{ +} + int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) { -#if defined(CONFIG_INCA_IP) - *INCA_IP_WDT_RST_REQ = 0x3f; -#elif defined(CONFIG_PURPLE) || defined(CONFIG_TB0229) - void (*f)(void) = (void *) 0xbfc00000; + _machine_restart(); - f(); -#endif fprintf(stderr, "*** reset failed ***\n"); return 0; } -- cgit v1.1 From d98e348e2ed5aab8f7a6471ff628ab0688b8a459 Mon Sep 17 00:00:00 2001 From: Shinya Kuribayashi Date: Tue, 25 Mar 2008 21:30:07 +0900 Subject: [MIPS] Fix dcache_status() You can't judge UNCACHED by Config.K0 LSB. Signed-off-by: Shinya Kuribayashi --- cpu/mips/cache.S | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'cpu') diff --git a/cpu/mips/cache.S b/cpu/mips/cache.S index bb42616..e6f3175 100644 --- a/cpu/mips/cache.S +++ b/cpu/mips/cache.S @@ -256,9 +256,13 @@ NESTED(mips_cache_reset, 0, ra) * */ LEAF(dcache_status) - mfc0 v0, CP0_CONFIG - andi v0, v0, 1 - j ra + mfc0 t0, CP0_CONFIG + li t1, CONF_CM_UNCACHED + andi t0, t0, CONF_CM_CMASK + move v0, zero + beq t0, t1, 2f + li v0, 1 +2: jr ra END(dcache_status) /******************************************************************************* -- cgit v1.1 From 373b16fc0c5ae34d28b9027f809ae3cbf45cdd15 Mon Sep 17 00:00:00 2001 From: Shinya Kuribayashi Date: Tue, 25 Mar 2008 21:30:07 +0900 Subject: [MIPS] Extend MIPS_MAX_CACHE_SIZE upto 64kB Signed-off-by: Shinya Kuribayashi --- cpu/mips/cache.S | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'cpu') diff --git a/cpu/mips/cache.S b/cpu/mips/cache.S index e6f3175..89ada71 100644 --- a/cpu/mips/cache.S +++ b/cpu/mips/cache.S @@ -1,5 +1,5 @@ /* - * Cache-handling routined for MIPS 4K CPUs + * Cache-handling routined for MIPS CPUs * * Copyright (c) 2003 Wolfgang Denk * @@ -32,10 +32,14 @@ #define RA t8 - /* 16KB is the maximum size of instruction and data caches on - * MIPS 4K. - */ -#define MIPS_MAX_CACHE_SIZE 0x4000 +/* + * 16kB is the maximum size of instruction and data caches on MIPS 4K, + * 64kB is on 4KE, 24K, 5K, etc. Set bigger size for convenience. + * + * Note that the above size is the maximum size of primary cache. U-Boot + * doesn't have L2 cache support for now. + */ +#define MIPS_MAX_CACHE_SIZE 0x10000 #define INDEX_BASE KSEG0 -- cgit v1.1