/******************************************************************************* Copyright (C) Marvell International Ltd. and its affiliates ******************************************************************************** Marvell GPL License Option If you received this File from Marvell, you may opt to use, redistribute and/or modify this File in accordance with the terms and conditions of the General Public License Version 2, June 1991 (the "GPL License"), a copy of which is available along with the File in the license.txt file or by writing to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt. THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY DISCLAIMED. The GPL License provides additional details about this warranty disclaimer. *******************************************************************************/ /* Code for setting up pagetables or the protection unit, * and enabling the cache. */ #include #include #include #include #include "mvSysHwConfig.h" #if defined(MV_INCLUDE_MONT_EXT) && defined (MV_INCLUDE_MONT_MMU) #include "mvCpuIf.h" #include "cpu/mvCpu.h" int mpuMap(void); /* This file refers to the A.R.M.--The ARM Architecture Reference Manual */ enum access { NO_ACCESS, NO_USR_W, SVC_RW, ALL_ACCESS }; enum entrytype { INVALID, PAGE, SECTION }; #define U_BIT 16 #define C_BIT 8 #define B_BIT 4 #define WRITE_BACK (C_BIT|B_BIT) #define WRITE_THROUGH (C_BIT) #define L1Entry(type,addr,dom,ucb,acc) \ ( (type == SECTION) ? ( ((addr) & 0xfff00000) | \ ((acc) << 10) | ((dom) << 5) | \ (ucb) | (type) ) : \ (type == PAGE) ? ( ((addr) &0xfffffc00) | \ ((dom) << 5) | \ ((ucb) & U_BIT) | (type) ) : \ 0) #define L1EntryAddr(type, entry) \ ( (type == SECTION) ? ((entry) & 0xfff00000): \ (type == PAGE) ? ((entry) &0xfffffc00):0) #define L1EntryAcc(type, entry) \ (((entry) & 0xc00) >> 10) #define L1EntryUcb(type, entry) \ ((entry) & 0x1c) #define L1EntryType(type, entry) \ ((entry) & 0x3) static void detectPageTable(void) { int i; #if defined(MV78XX0) unsigned int *p = (unsigned int *)CFG_PT_BASE(whoAmI()); #else unsigned int *p = (unsigned int *)CFG_PT_BASE; #endif unsigned int entry; unsigned int ucb; unsigned int acc; unsigned int nextEntry; char* envCacheMode = getenv("cacheMode"); unsigned int startVirAddr = 0; unsigned int startPhyAddr = 0; if(envCacheMode && (strcmp(envCacheMode,"write-through") == 0)) { printf("Cache Mode - write-through\n"); } else /*"write-back"*/ { printf("Cache Mode - write-back\n"); } printf("page table:\n"); for (i = 0; i < 4096; i++) { entry = *p; nextEntry = *(++p); ucb = L1EntryUcb(SECTION, entry); acc = L1EntryAcc(SECTION, entry); if ( (ucb != L1EntryUcb(SECTION, nextEntry))|| (acc != L1EntryAcc(SECTION, nextEntry))|| (L1EntryAddr(SECTION, entry) > L1EntryAddr(SECTION, nextEntry)) || ((L1EntryAddr(SECTION, entry) + _1M) < L1EntryAddr(SECTION, nextEntry))) { printf("Section (0x%08x - 0x%08x) =>",startPhyAddr, ((i << 20)| 0xfffff)); printf(" (0x%08x - 0x%08x)",startVirAddr, (L1EntryAddr(SECTION, entry)| 0xfffff)); if (ucb & C_BIT) printf(" Cachable/Bufferable"); else printf(" Non-Cachable/Bufferable"); switch(acc){ case(NO_ACCESS): printf("\tNO_ACCESS"); break; case(NO_USR_W): printf("\tNO_USR_W"); break; case(SVC_RW): printf("\tSVC_RW"); break; case(ALL_ACCESS): printf("\tALL_ACCESS"); break; default: printf("\tALL_ACCESS"); break; } printf("\n"); startVirAddr = L1EntryAddr(SECTION, nextEntry); startPhyAddr = ((i+1) << 20); } } } static unsigned int createPageTable(void) { int i; unsigned int entry; char* envCacheMode = getenv("cacheMode"); unsigned int cacheMode; #if defined(MV78XX0) unsigned int *p = (unsigned int *)CFG_PT_BASE(whoAmI()); #else unsigned int *p = (unsigned int *)CFG_PT_BASE; #endif if(envCacheMode && (strcmp(envCacheMode,"write-through") == 0)) { setenv("cacheMode","write-through"); cacheMode = WRITE_THROUGH; } else /*"write-back"*/ { setenv("cacheMode","write-back"); cacheMode = WRITE_BACK; } /* first region 0 MB - 0x10000000(256MB) none cacheable/bufferable */ entry = L1Entry(SECTION, 0, 0, U_BIT, ALL_ACCESS); for (i = 0; i < 256; i++) { *p++ = (entry | (i << 20)); } /* second region 0x10000000 (256MB) - 0x80000000 (2GB) cacheable/bufferable */ entry = L1Entry(SECTION, 0, 0, U_BIT|cacheMode, ALL_ACCESS); for (; i < 2048 ; i++) { *p++ = (entry | (i << 20)); } /* 3rd region 0x80000000 (2GB) - 0x90000000 cacheable/ bufferable to 0x0*/ entry = L1Entry(SECTION, 0, 0, U_BIT|cacheMode, ALL_ACCESS); for (; i < 2304; i++) { *p++ = (entry | ((i - 2048) << 20)); } /* 4rd region 0x90000000 - 0xa0000000 not cacheable/not bufferable */ entry = L1Entry(SECTION, 0, 0, U_BIT, ALL_ACCESS); for (; i < 2560; i++) { *p++ = (entry | (i << 20)); } /* 5th region 0xa0000000 - 0xb0000000 cacheable/bufferable to 0x90000000 */ entry = L1Entry(SECTION, 0, 0, U_BIT|cacheMode, ALL_ACCESS); for (; i < 2816; i++) { *p++ = (entry | ((i - 256) << 20)); } /* 6th region 0xb0000000 - 0xe0000000 cacheable/bufferable */ entry = L1Entry(SECTION, 0, 0, U_BIT|cacheMode, ALL_ACCESS); for (; i < 3584; i++) { *p++ = (entry | (i << 20)); } /* 7th region 0xe0000000 - 0xf0000000 cacheable/bufferable to 0xf0000000 */ entry = L1Entry(SECTION, 0, 0, U_BIT|cacheMode, ALL_ACCESS); for (; i < 3840; i++) { *p++ = (entry | ((i+256) << 20)); } /* 8th region 0xf0000000 - 0xffffffff none cacheable/bufferable */ entry = L1Entry(SECTION, 0, 0, U_BIT, ALL_ACCESS); for (; i < 4096; i++) { *p++ = (entry | (i << 20)); } #if defined(MV78XX0) return CFG_PT_BASE(whoAmI()); #else return CFG_PT_BASE; #endif } extern int PTexist(void); int cpumap_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) { printf("CPU Memory mapping :\n"); if ((mvOsCpuPartGet() == CPU_PART_ARM926) || (mvOsCpuPartGet() == CPU_PART_MRVL131)) { if(enaMonExt()) { if(PTexist()) { detectPageTable(); } else printf("No page table. \n"); } else printf("No page table. \n"); } #ifndef MV_TINY_IMAGE #if defined(MV_INCLUDE_MONT_EXT) && defined (MV_INCLUDE_MONT_MPU) else if (mvOsCpuPartGet() == CPU_PART_ARM946) { mpuMap(); } #endif #endif return 1; } U_BOOT_CMD( cpumap, 1, 1, cpumap_cmd, "cpumap - Display CPU memory mapping settings.\n", " \n" "\tdisplay CPU memory mapping settings.\n" ); /* These are all the bits currently defined for the control register */ /* A.R.M. 7.4.2 */ #define MMU_V 0x2000 #define MMU_I 0x1000 #define MMU_Z 0x0800 #define MMU_F 0x0400 #define MMU_R 0x0200 #define MMU_S 0x0100 #define MMU_B 0x0080 #define MMU_RES 0x50078 /* reserved bits should be 1 */ #define MMU_C 0x0004 #define MMU_A 0x0002 #define MMU_M 0x0001 /* * The functions below take arguments to specify which "caches" the * action is to be directed at. For the I-cache, pass "MMU_I". For * the D-cache, "MMU_C". For both, pass "MMU_ID". For combined ID-Cache * processors, use "MMU_C" */ #define MMU_ID (MMU_I | MMU_C) /* * Inline functions for MMU functions */ /* Set the page tables base register: register 2 (A.R.M. 7.4.3) */ inline void mmuSetPageTabBase(unsigned int pagetab) { __asm__ __volatile__( "mcr p15, 0, %0, c2, c0\n" : : "r" (pagetab)); } /* Set the domain access-control register: register 3 (A.R.M. 7.4.4) */ inline void mmuSetDomainAccessControl(unsigned long flags) { __asm__ __volatile__( "mcr p15, 0, %0, c3, c0\n" : : "r" (flags)); } /* Flush the cache(s). */ inline void mmuInvCache(unsigned caches) { unsigned long dummy = 0; switch (caches) { case MMU_C: __asm__ __volatile__( "mcr p15, 0, %0, c7, c6, 0\n" : : "r" (dummy)); break; case MMU_I: __asm__ __volatile__( "mcr p15, 0, %0, c7, c5, 0\n" : : "r" (dummy)); break; case MMU_ID: __asm__ __volatile__( "mcr p15, 0, %0, c7, c7, 0\n" : : "r" (dummy)); break; } } /* Flush the TLB(s) */ inline void mmuFlushTLB( unsigned tlbs) { unsigned long dummy = 0; /* flush TLB(s): write to register 8, with flags (A.R.M. 7.4.9) */ switch (tlbs) { case MMU_C: __asm__ __volatile__( "mcr p15, 0, %0, c8, c6, 0\n" : : "r" (dummy)); break; case MMU_I: __asm__ __volatile__( "mcr p15, 0, %0, c8, c5, 0\n" : : "r" (dummy)); break; case MMU_ID: __asm__ __volatile__( "mcr p15, 0, %0, c8, c7, 0\n" : : "r" (dummy)); break; } } /* Enable the cache/MMU/TLB etc. */ inline void cpuCfgEnable(unsigned long flags, MV_BOOL enable) { unsigned long tmp; if (enable == MV_TRUE) { asm ("mrc p15, 0, %0, c1, c0, 0":"=r" (tmp)); tmp |= flags; asm ("mcr p15, 0, %0, c1, c0, 0": :"r" (tmp)); } else { asm ("mrc p15, 0, %0, c1, c0, 0":"=r" (tmp)); tmp &= ~flags; asm ("mcr p15, 0, %0, c1, c0, 0": :"r" (tmp)); } } /* Disable the I/D cache. */ inline void disableIDCache(void) { unsigned long tmp; asm ("mrc p15, 0, %0, c1, c0, 0":"=r" (tmp)); tmp &= ~MMU_ID; asm ("mcr p15, 0, %0, c1, c0, 0": :"r" (tmp)); /* invalidate I/D-cache */ tmp = 0; asm ("mcr p15, 0, %0, c7, c7, 0": :"r" (tmp)); } /* return 0 in case cache is absent */ inline unsigned long getDCacheAssociativity(void) { unsigned long tmp, dassoc, mul; /* Read cache type information */ /* Bit[11:0] - I cache size */ /* Bit[23:12] - D cache size */ /* Bit 24 - if '1' Seperate I-cache and D-cache */ /* bit[28:24] - ctype */ asm ("mrc p15, 0, %0, c0, c0, 1":"=r" (tmp)); /* D cache data only */ /* Bit[1:0] - cache line length */ /* Bit2 - M */ /* Bit[5:3] - cache associativity */ /* Bit[9:6] - cache size */ tmp = (tmp >> 12) & 0xfff; /* Detect cache associativity - the formulae are teken from ARM DDI reference manual */ mul = 2 + ((tmp >> 2) & 1); dassoc = ((tmp >> 3) & 0x7); if ((dassoc == 0) && (mul == 2)) dassoc = 1; else { if ((dassoc == 0) && (mul == 3)) dassoc = 0; else dassoc = mul << (dassoc - 1); } return dassoc; } inline unsigned long getDCacheSize(void) { unsigned long tmp, dsize, mul; /* Read cache type information */ /* Bit[11:0] - I cache size */ /* Bit[23:12] - D cache size */ /* Bit 24 - if '1' Seperate I-cache and D-cache */ /* bit[28:24] - ctype */ asm ("mrc p15, 0, %0, c0, c0, 1":"=r" (tmp)); /* D cache data only */ /* Bit[1:0] - cache line length */ /* Bit2 - M */ /* Bit[5:3] - cache associativity */ /* Bit[9:6] - cache size */ tmp = (tmp >> 12) & 0xfff; /* Detect cache size - the formulae are teken from ARM DDI reference manual */ mul = 2 + ((tmp >> 2) & 1); dsize = ((tmp >> 6) & 0xf); dsize = mul << (dsize + 8); return dsize; } inline unsigned long getDCacheLine(void) { unsigned long tmp, dline; /* Read cache type information */ /* Bit[11:0] - I cache size */ /* Bit[23:12] - D cache size */ /* Bit 24 - if '1' Seperate I-cache and D-cache */ /* bit[28:24] - ctype */ asm ("mrc p15, 0, %0, c0, c0, 1":"=r" (tmp)); /* D cache data only */ /* Bit[1:0] - cache line length */ /* Bit2 - M */ /* Bit[5:3] - cache associativity */ /* Bit[9:6] - cache size */ tmp = (tmp >> 12) & 0xfff; /* Detect cache line - the formulae are teken from ARM DDI reference manual */ dline = 1 << ((tmp & 0x3) + 3); return dline; } extern ulong _dcache_index_max; extern ulong _dcache_index_inc; extern ulong _dcache_set_max; extern ulong _dcache_set_index; void pageTableInit(void) { unsigned long dsize, dassoc, dline, log2Assoc, tmp; printf("D-Cache type information\n"); /* Detect cache size */ dsize = getDCacheSize(); /* Detect cache number of way */ dassoc = getDCacheAssociativity(); /* Detect cache number of way */ dline = getDCacheLine(); /* Detected cache absent */ if (dassoc == 0) { printf("DCache absent!\n"); return; } else { printf("DCache size: %dKB\n",dsize/1024); printf("DCache associativity: %d way\n",dassoc); printf("DCache line length: %dB\n",dline); } /* Calc num of digits for assoc representation */ log2Assoc = 0; tmp = dassoc - 1; do { log2Assoc++; tmp = tmp >> 1; }while (tmp > 0); printf("Intializing Page Table..."); /* The num of assoc is set in the ip address from bit 31 backward */ if (dassoc == 1) { _dcache_index_max = 0; _dcache_index_inc = 0; } else { _dcache_index_max = ~ ((1 << (31 - log2Assoc + 1)) - 1); _dcache_index_inc = (1 << (31 - log2Assoc + 1)); } _dcache_set_max = (dsize/dassoc) - dline; _dcache_set_index = dline; disableIDCache(); /* Disable D cache and MMU. */ cpuCfgEnable(MMU_C | MMU_M, MV_FALSE); /* set up the page table, domain control registers */ mmuSetPageTabBase(createPageTable()); mmuSetDomainAccessControl(3); /* flush caches and TLBs */ mmuInvCache(MMU_ID); mmuFlushTLB(MMU_ID); /* write to control register :- * I-cache on, 32-bit data and program space, * write-buffer on, D-cache on, MMU on */ cpuCfgEnable(MMU_I | MMU_RES | MMU_C | MMU_M, MV_TRUE); printf("Done \n"); return ; } #endif /* defined(MV_INCLUDE_MONT_EXT) */