ARM: cp15: setup mmu and enable dcache
PATCH 3/26 ARM: cp15: setup mmu and enable dcache
This has been tested on at91sam9263 and STN8815. Again, I didn't check if it has bad effects
on non-arm926 cores.
Initially I had a "done" bit to only set up page tables at the beginning. However, since the aligmnent requirement was for the whole object file, this extra integer tool 16kB in BSS, so I chose to remove it.
Also, note not all boards use PHYS_SDRAM, but it looks like it's the most used name (more than CONFIG_SYS_DRAM_BASE for example).
---
- changes since v1:
- add possibilty to use dcache in write_through mode, as Nick Thompson suggested.
- use the ram setup info in bd_t to setup the TLB
- added my Signed-off-by upon consultation with Alessandro
- changes since v2:
- changed commit message
- moved cache patches before relocation patches
arch/arm/lib/cache-cp15.c | 51 +++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 51 insertions(+), 0 deletions(-)
arch/arm/lib/cache-cp15.c +51 -0
@@ -25,6 +25,15 @@#include <asm/system.h> #if !(defined(CONFIG_SYS_NO_ICACHE ) && defined(CONFIG_SYS_NO_DCACHE )) + +#if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH ) +#define CACHE_SETUP 0x1a +#else +#define CACHE_SETUP 0x1e +#endif + +DECLARE_GLOBAL_DATA_PTR ; +static void cp_delay (void ) {volatile int i;
@@ -32,6 +41,40 @@ static void cp_delay (void)/* copro seems to need some delay between reading and writing */ for (i =0 ; i <100 ; i++)nop (); + asmvolatile ("" : : :"memory" ); +} + +/* to activate the MMU we need to set up virtual memory: use 1M areas in bss */ +static inline void mmu_setup (void ) +{ +static u32 __attribute__((aligned (16384 ))) page_table[4096 ]; +bd_t *bd = gd->bd; +int i, j; +u32 reg; + +/* Set up an identity-mapping for all 4GB, rw for everyone */ +for (i =0 ; i <4096 ; i++) + page_table[i] = i <<20 | (3 <<10 ) |0x12 ; +/* Then, enable cacheable and bufferable for RAM only */ +for (j =0 ; j <CONFIG_NR_DRAM_BANKS ; j++) { +for (i = bd->bi_dram[j].start >>20 ; + i < (bd->bi_dram[j].start + bd->bi_dram[j].size) >>20 ; + i++) { + page_table[i] = i <<20 | (3 <<10 ) |CACHE_SETUP ; + } + } + +/* Copy the page table address to cp15 */ + asmvolatile ("mcr p15, 0, %0, c2, c0, 0" + : :"r" (page_table) :"memory" ); +/* Set the access control to all-supervisor */ + asmvolatile ("mcr p15, 0, %0, c3, c0, 0" + : :"r" (~0 )); +/* and enable the mmu */ + reg =get_cr ();/* get control reg. */ +cp_delay (); +set_cr (reg |CR_M ); + }/* cache_bit must be either CR_I or CR_C */
@@ -39,6 +82,9 @@ static void cache_enable(uint32_t cache_bit) {uint32_t reg; +/* The data cache is not active unless the mmu is enabled too */ +if (cache_bit ==CR_C ) +mmu_setup (); reg =get_cr ();/* get control reg. */ cp_delay ();set_cr (reg | cache_bit);
@@ -49,6 +95,11 @@ static void cache_disable(uint32_t cache_bit) {uint32_t reg; +if (cache_bit ==CR_C ) { +/* if disabling data cache, disable mmu too */ + cache_bit |=CR_M ; +flush_cache (0 , ~0 ); + } reg =get_cr ();cp_delay ();set_cr (reg & ~cache_bit);
Signature · 5 lines
1.6.2.5 -- DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
V
PATCH 3/26 ARM: cp15: setup mmu and enable dcache
Hello Heiko Schocher,
Quoted 21 lines
bounces at lists.denx.de] On Behalf Of Heiko Schocher
arch/arm/lib/cache-cp15.c +14
-0+static inline void mmu_setup (void ) +{ +static u32 __attribute__((aligned (16384 ))) page_table[4096 ]; +bd_t *bd = gd->bd; +int i, j; +u32 reg; + +/* Set up an identity-mapping for all 4GB, rw for everyone */ +for (i =0 ; i <4096 ; i++) + page_table[i] = i <<20 | (3 <<10 ) |0x12 ; +/* Then, enable cacheable and bufferable for RAM only */ +for (j =0 ; j <CONFIG_NR_DRAM_BANKS ; j++) { + for (i = bd->bi_dram[j].start >> 20; + i < (bd->bi_dram[j].start + bd->bi_dram[j].size)Quoted 1 line
Quoted 1 line
20;
arch/arm/lib/cache-cp15.c +5
-0+ i++) { + page_table[i] = i <<20 | (3 <<10 ) |CACHE_SETUP ; + } + } +
arch/arm/lib/cache-cp15.c static void cp_delay (void) · line 76
Quoted 10 lines
arch/arm/lib/cache-cp15.c +10
-0+/* Copy the page table address to cp15 */ + asmvolatile ("mcr p15, 0, %0, c2, c0, 0" + : :"r" (page_table) :"memory" ); +/* Set the access control to all-supervisor */ + asmvolatile ("mcr p15, 0, %0, c3, c0, 0" + : :"r" (~0 )); +/* and enable the mmu */ + reg =get_cr ();/* get control reg. */ +cp_delay (); +set_cr (reg |CR_M );
I think you need to invalidate caches, TLB, branch-prediction array etc before enabling MMU. I don't think the caches are guaranteed to be invalidated at power on reset.
Please find below some experimental(but working) code I had written for enabling MMU and caches for an internal project. It's written for the ARM RVCT tool chain. So, it will not compile straight away on GCC.
It has code for invalidating caches, TLB, Branch prediction array etc. Also, it uses macros for the bit fields in the SCTLR register. However, the L1 D$ cleaning is not generic. It assumes the size and organization of the L1 cache. arch/arm/cpu/armv7/omap3/cache.S has a more generic implementation of invalidating the entire L1 D$.
In case you find it useful, you are welcome to reuse any part of this code. If you want me to create a patch myself I am open to do that too.
Best regards,
Aneesh
Mmu.c:
/*
* (C) Copyright 2008
* Texas Instruments, <www.ti.com>
* Author:
* Aneesh V <[email protected]>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation's version 2 of
* the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <utils.h>
#ifdef MMU_ENABLED
extern unsigned int pagetable[1024*4];
extern unsigned int Vector(void);
#define PAGE_TAB_SECTION_CONSTANTS 0x40002
#define NS_BIT_1 0x80000
#define nG_0 0
#define S_BIT_1 0x010000
#define AP_FULL_ACCESS 0x00C00
#define DOMAIN_0 0
#define XN_1 0x10
#define TEX_C_B_NORMAL_I_WBWA_O_WBWA 0x05004
#define TEX_C_B_NORMAL_I_WBWA_O_NC 0x04004
#define TEX_C_B_NORMAL_I_NC_O_NC 0x01002
#define TEX_C_B_NORMAL_SHARABLE_DEVICE 0x4
#define SECTION_ENTRY_FULL_ACCESS_FULL_CACHED (PAGE_TAB_SECTION_CONSTANTS|NS_BIT_1|nG_0|S_BIT_1|AP_FULL_ACCESS|DOMAIN_0|TEX_C_B_NORMAL_I_WBWA_O_WBWA) #define SECTION_ENTRY_FULL_ACCESS_FULL_CACHED_NON_SHARED (PAGE_TAB_SECTION_CONSTANTS|NS_BIT_1|nG_0|AP_FULL_ACCESS|DOMAIN_0|TEX_C_B_NORMAL_I_WBWA_O_WBWA) #define SECTION_ENTRY_FULL_ACCESS_NORMAL_NC (PAGE_TAB_SECTION_CONSTANTS|NS_BIT_1|nG_0|S_BIT_1|AP_FULL_ACCESS|DOMAIN_0|TEX_C_B_NORMAL_I_NC_O_NC) #define SECTION_ENTRY_FULL_ACCESS_SHARED_DEVICE (PAGE_TAB_SECTION_CONSTANTS|NS_BIT_1|nG_0|S_BIT_1|AP_FULL_ACCESS|DOMAIN_0|TEX_C_B_NORMAL_SHARABLE_DEVICE)
#define M_BIT_1 0x1
#define C_BIT_1 0x4 #define Z_BIT_1 0x800 #define I_BIT_1 0x1000 #define V_BIT_1 0x2000
#define SCTRL_VALUE (M_BIT_1|C_BIT_1|Z_BIT_1|I_BIT_1|V_BIT_1) //#define SCTRL_VALUE (M_BIT_1|Z_BIT_1|I_BIT_1|V_BIT_1)
__asm void setvector(void);
void setup_pagetable(unsigned int *pagetable, unsigned int devicemem_attr, unsigned int code_and_data); __asm unsigned int setup_vector(unsigned int (*vector)(void));__asm unsigned int setup_ttbr0(unsigned int ttbr0value);__asm unsigned int setup_ttbr1(unsigned int ttbr1value);__asm unsigned int setup_ttbrc(unsigned int ttbrc_value);__asm unsigned int setup_dacr(unsigned int dacr_value);__asm unsigned int setup_sctlr(unsigned int sctlrr_value);__asm void invalidate_caches(void);__asm void barriers(void);__asm void enable_pl310(void);
void invalidate_dcache_setway(unsigned int setway);
void stresstestaftermmu(void);
__asm unsigned int setup_prrr(unsigned int prrr_value)
{
MCR p15,0,r0,c10,c2,0 ; Read CP15 Primary Region Remap Register
bx lr
}__asm unsigned int setup_nmrr(unsigned int nmrr_value)
{
MCR p15,0,r0,c10,c2,1 ; Read CP15 Normal Memory Remap Register
bx lr
}void enablemmu(void)
{
int set, way, setway;
volatile int i = 10;
setup_pagetable(pagetable, SECTION_ENTRY_FULL_ACCESS_SHARED_DEVICE, SECTION_ENTRY_FULL_ACCESS_FULL_CACHED);
printf("page table address 0x%08x\r\n", pagetable);
invalidate_caches();
printf("Cache and TLB invalidation done..\r\n");
//All TTBR permission values(RGN etc) are 0's. So nothing else to be done for TTBR0 value.
setup_ttbr0(((unsigned int)pagetable) | 0x48);
setup_ttbr1(((unsigned int)pagetable) | 0x48);
//TTBRC is 1(N=1)
setup_ttbrc(1);
setup_dacr(1);
setup_vector(Vector);
//Only I and M bit set in SCR
for(set=0; set<256; set++)
{
for(way=0; way<4; way++)
{
setway = way << 30;
setway |= set << 5;
invalidate_dcache_setway(setway);
}
}
printf("Data cache invalidation done..\r\n");
//Enable L2
enable_pl310();
barriers();
setup_sctlr(SCTRL_VALUE); //Enable everything except I$ and D$
printf("mmu enabled..\r\n");
printf("If you are seeing this mmu and caches are working fine..\r\n");
}__asm void invalidate_dcache_setway(unsigned int setway) {
MCR p15, 0, r0, c7, c6, 2 ; invalidate (aka purge) by set/way
bx lr
}
__asm void barriers(void)
{
DCD 0xF57FF04F ; DSBSY (full system DSB)
DCD 0xF57FF06F ; ISBSY (full system ISB)
bx lr
}
//__asm int setuppagetables
__asm void invalidate_caches(void)
{
mov r1, #0
mcr p15, 0, r1, c8, c7, 0 ; Invalidate entire unified TLB
mcr p15, 0, r1, c8, c6, 0 ; Invalidate entire data TLB
mcr p15, 0, r1, c8, c5, 0 ; Invalidate entire instruction TLB
mcr p15, 0, r1, c7, c5, 6 ; Invalidate entire branch prediction array
mcr p15, 0, r1, c7, c5, 0 ; Invalidate icache bx lr
}
__asm unsigned int setup_dacr(unsigned int dacr_value)
{
MCR p15,0,r0,c3,c0,0 ; Write CP15 Domain Access Control Register MRC p15,0,r0,c3,c0,0 ; Read CP15 Domain Access Control Register bx lr
}
__asm unsigned int setup_ttbrc(unsigned int ttbrc_value) {
MCR p15, 0, r0, c2, c0, 2 //Write TTBRC - N=0
MRC p15, 0, r0, c2, c0, 2 //Write TTBRC - N=0
bx lr
}__asm unsigned int setup_ttbr0(unsigned int ttbr0value) {
//Only TTBR0 is used.
MCR p15, 0, r0, c2, c0, 0 //Write TTBR0
MRC p15, 0, r0, c2, c0, 0 //Write TTBR0
bx lr
}__asm unsigned int setup_ttbr1(unsigned int ttbr1value) {
//Only TTBR0 is used.
MCR p15, 0,r0, c2, c0, 1 ;Write Translation Table Base Register 1
MRC p15, 0,r0, c2, c0, 1 ;Read Translation Table Base Register 1
bx lr
}
__asm unsigned int setup_vector(unsigned int (*vector)(void))
{
MCR p15,0,r0,c12,c0,0 ; Set VBAR
MRC p15,0,r0,c12,c0,0 ; Read VBAR
bx lr}
__asm unsigned int setup_sctlr(unsigned int sctlr_value)
{
MCR p15,0,r0,c1,c0,0 ; Write CP15 System Control Register
DCD 0xF57FF04F ; DSBSY (full system DSB)
DCD 0xF57FF06F ; ISBSY (full system ISB)
MRC p15,0,r0,c1,c0,0 ; Read CP15 System Control Register
bx lr
}__asm void enable_pl310(void)
{
STMFD sp!, {r4-r12,lr}
MOV r0, #1
LDR r12, =0x102
DCD 0xE1600070 ; call ROM Code API to enable PL310 on ZEBU/Si
ldmfd sp!, {r4-r12,pc}
}void setup_pagetable(unsigned int *pagetable, unsigned int devicemem_attr, unsigned int code_and_data)
{
int i;
//volatile int j=10;
printf(">setup_pagetable - device mem: 0x%x code_data: 0x%x\r\n", devicemem_attr, code_and_data);
// while(j);
for (i=0; i<2*1024; i++)
{
pagetable[i] = (i << 20) | devicemem_attr;
}
#if 1
for(; i<2*1024+256; i++)
{
pagetable[i] = (i << 20) | code_and_data;
}
for(; i<2*1024+512; i++)
{
pagetable[i] = (i << 20) | code_and_data;
}#endif
for (; i<4*1024; i++)
{
pagetable[i] = (i << 20) | code_and_data;
}
pagetable[0x403] = (0x403 << 20) | code_and_data;
printf("section entry for 0x00000000 - 0x%08x\r\n", pagetable[0]);
printf("section entry for 0x80000000 - 0x%08x\r\n", pagetable[0x800]);
}#endif
PATCH 3/26 ARM: cp15: setup mmu and enable dcache
Hello V, Aneesh,
Quoted 36 lines · Aneesh
Hello Heiko Schocher,
Quoted 21 lines
bounces at lists.denx.de] On Behalf Of Heiko Schocher
arch/arm/lib/cache-cp15.c +14
-0+static inline void mmu_setup (void ) +{ +static u32 __attribute__((aligned (16384 ))) page_table[4096 ]; +bd_t *bd = gd->bd; +int i, j; +u32 reg; + +/* Set up an identity-mapping for all 4GB, rw for everyone */ +for (i =0 ; i <4096 ; i++) + page_table[i] = i <<20 | (3 <<10 ) |0x12 ; +/* Then, enable cacheable and bufferable for RAM only */ +for (j =0 ; j <CONFIG_NR_DRAM_BANKS ; j++) { + for (i = bd->bi_dram[j].start >> 20; + i < (bd->bi_dram[j].start + bd->bi_dram[j].size)Quoted 1 line
Quoted 1 line
20;
arch/arm/lib/cache-cp15.c +5
-0+ i++) { + page_table[i] = i <<20 | (3 <<10 ) |CACHE_SETUP ; + } + } +arch/arm/lib/cache-cp15.c static void cp_delay (void) · line 76
Quoted 10 lines
arch/arm/lib/cache-cp15.c +10
-0+/* Copy the page table address to cp15 */ + asmvolatile ("mcr p15, 0, %0, c2, c0, 0" + : :"r" (page_table) :"memory" ); +/* Set the access control to all-supervisor */ + asmvolatile ("mcr p15, 0, %0, c3, c0, 0" + : :"r" (~0 )); +/* and enable the mmu */ + reg =get_cr ();/* get control reg. */ +cp_delay (); +set_cr (reg |CR_M );I think you need to invalidate caches, TLB, branch-prediction array etc before enabling MMU. I don't think the caches are guaranteed to be invalidated at power on reset.
Quoted 6 lines
Please find below some experimental(but working) code I had written for enabling MMU and caches for an internal project. It's written for the ARM RVCT tool chain. So, it will not compile straight away on GCC.
It has code for invalidating caches, TLB, Branch prediction array etc. Also, it uses macros for the bit fields in the SCTLR register. However, the L1 D$ cleaning is not generic. It assumes the size and organization of the L1 cache.
arch/arm/cpu/armv7/omap3/cache.Shas a more generic implementation of invalidating the entire L1 D$.In case you find it useful, you are welcome to reuse any part of this code. If you want me to create a patch myself I am open to do that too.
Thanks!
I try to try out your suggestions, if you can make a patch (and try it on a plattform it would be great ;-)
bye,
Heiko
Signature · 2 lines
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
V
PATCH 3/26 ARM: cp15: setup mmu and enable dcache
Hello Heiko,
Quoted 61 lines
-----Original Message-----
From: Heiko Schocher [mailto:hs at denx.de]
Sent: Wednesday, September 01, 2010 4:56 PM
To: V, Aneesh
Cc: U-Boot user list; Alessandro Rubini
Subject: Re: [U-Boot] [PATCH 03/26] ARM: cp15: setup mmu and enable dcacheHello V, Aneesh,
Quoted 27 lines · Aneesh
Hello Heiko Schocher,
Quoted 25 lines
bounces at lists.denx.de] On Behalf Of Heiko Schocher
arch/arm/lib/cache-cp15.c +14
-0+static inline void mmu_setup (void ) +{ +static u32 __attribute__((aligned (16384 ))) page_table[4096 ]; +bd_t *bd = gd->bd; +int i, j; +u32 reg; + +/* Set up an identity-mapping for all 4GB, rw for everyone */ +for (i =0 ; i <4096 ; i++) + page_table[i] = i <<20 | (3 <<10 ) |0x12 ; +/* Then, enable cacheable and bufferable for RAM only */ +for (j =0 ; j <CONFIG_NR_DRAM_BANKS ; j++) { + for (i = bd->bi_dram[j].start >> 20; + i < (bd->bi_dram[j].start + bd->bi_dram[j].size)Quoted 1 line
Quoted 1 line
20;
arch/arm/lib/cache-cp15.c +9
-0+ i++) { + page_table[i] = i <<20 | (3 <<10 ) |CACHE_SETUP ; + } + } + +/* Copy the page table address to cp15 */ + asmvolatile ("mcr p15, 0, %0, c2, c0, 0" + : :"r" (page_table) :"memory" ); +/* Set the access control to all-supervisor */ Quoted 8 lines
arch/arm/lib/cache-cp15.c static void cp_delay (void) · line 76
Quoted 6 lines
arch/arm/lib/cache-cp15.c +6
-0+ asmvolatile ("mcr p15, 0, %0, c3, c0, 0" + : :"r" (~0 )); +/* and enable the mmu */ + reg =get_cr ();/* get control reg. */ +cp_delay (); +set_cr (reg |CR_M );I think you need to invalidate caches, TLB, branch-prediction
array etc before enabling MMU. I don't think the caches are guaranteed to be invalidated at power on reset.
Quoted 2 lines
Please find below some experimental(but working) code I had
written for enabling MMU and caches for an internal project. It's written for the ARM RVCT tool chain. So, it will not compile straight away on GCC.
Quoted 2 lines
It has code for invalidating caches, TLB, Branch prediction array
etc. Also, it uses macros for the bit fields in the SCTLR register. However, the L1 D$ cleaning is not generic. It assumes the size and organization of the L1 cache.
Quoted 1 line
arch/arm/cpu/armv7/omap3/cache.Shas a more generic implementationof invalidating the entire L1 D$.
Quoted 1 line
Quoted 8 lines
Quoted 1 line
In case you find it useful, you are welcome to reuse any part of
this code. If you want me to create a patch myself I am open to do that too.
Thanks!
I try to try out your suggestions, if you can make a patch (and try it on a plattform it would be great ;-)
I will try this out as time permits. I should be able to test it on OMAP3430(Cortex-A8) and OMAP4430(Cortex-A9).
Thanks,
Aneesh
V
PATCH 3/26 ARM: cp15: setup mmu and enable dcache
In reply to Heiko SchocherHello Heiko,
Quoted 9 lines
-----Original Message-----
From: u-boot-bounces at lists.denx.de [mailto:u-boot- bounces at lists.denx.de] On Behalf Of Heiko Schocher
Sent: Wednesday, August 11, 2010 11:46 PM
To: U-Boot user list
Cc: Alessandro Rubini
Subject: [U-Boot] [PATCH 03/26] ARM: cp15: setup mmu and enable dcache
Quoted 8 lines
This has been tested on at91sam9263 and STN8815. Again, I didn't check if it has bad effects
on non-arm926 cores.Initially I had a "done" bit to only set up page tables at the beginning. However, since the aligmnent requirement was for the whole object file, this extra integer tool 16kB in BSS, so I chose to remove it.
This is rather strange. I thought the linker would have done better. However, I could overcome this problem by making 'done' a non-zero initialized variable. Can't you try that?
I think the 'done' bit is quite useful. I see that the dcache_enable() is called from multiple places.
I tested your patch on OMAP4430(Cortex-A9). It works fine
Best regards,
Aneesh
PATCH 3/26 ARM: cp15: setup mmu and enable dcache
Dear "V, Aneesh",
Quoted 9 lines · In message <[email protected]> you…
Quoted 5 lines
Initially I had a "done" bit to only set up page tables at the beginning. However, since the aligmnent requirement was for the whole object file, this extra integer tool 16kB in BSS, so I chose to remove it.
This is rather strange. I thought the linker would have done better. However, I could overcome this problem by making 'done' a non-zero initialized variable. Can't you try that?
"non-zero initialized variable" means you moved the storage location from the bss into the data segment.
The same can be done by using something like
int done __attribute__ ((section (".data"))) = 0;This is a better approach because 1) a non-zero value will be easily misinterpreted as "already done", and 2) this clearly documents what is going on and why.
Best regards,
Wolfgang Denk
Signature · 4 lines
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de I must follow the people. Am I not their leader? - Benjamin Disraeli