1 /* 2 * (C) Copyright 2002 3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 4 * 5 * See file CREDITS for list of people who contributed to this 6 * project. 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License as 10 * published by the Free Software Foundation; either version 2 of 11 * the License, or (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 21 * MA 02111-1307 USA 22 */ 23 24 #include <common.h> 25 #include <asm/system.h> 26 #include <asm/cache.h> 27 #include <linux/compiler.h> 28 29 #if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF)) 30 31 DECLARE_GLOBAL_DATA_PTR; 32 33 void __arm_init_before_mmu(void) 34 { 35 } 36 void arm_init_before_mmu(void) 37 __attribute__((weak, alias("__arm_init_before_mmu"))); 38 39 static void cp_delay (void) 40 { 41 volatile int i; 42 43 /* copro seems to need some delay between reading and writing */ 44 for (i = 0; i < 100; i++) 45 nop(); 46 asm volatile("" : : : "memory"); 47 } 48 49 void set_section_dcache(int section, enum dcache_option option) 50 { 51 u32 *page_table = (u32 *)gd->arch.tlb_addr; 52 u32 value; 53 54 value = (section << MMU_SECTION_SHIFT) | (3 << 10); 55 value |= option; 56 page_table[section] = value; 57 } 58 59 void __mmu_page_table_flush(unsigned long start, unsigned long stop) 60 { 61 debug("%s: Warning: not implemented\n", __func__); 62 } 63 64 void mmu_page_table_flush(unsigned long start, unsigned long stop) 65 __attribute__((weak, alias("__mmu_page_table_flush"))); 66 67 void mmu_set_region_dcache_behaviour(u32 start, int size, 68 enum dcache_option option) 69 { 70 u32 *page_table = (u32 *)gd->arch.tlb_addr; 71 u32 upto, end; 72 73 end = ALIGN(start + size, MMU_SECTION_SIZE) >> MMU_SECTION_SHIFT; 74 start = start >> MMU_SECTION_SHIFT; 75 debug("%s: start=%x, size=%x, option=%d\n", __func__, start, size, 76 option); 77 for (upto = start; upto < end; upto++) 78 set_section_dcache(upto, option); 79 mmu_page_table_flush((u32)&page_table[start], (u32)&page_table[end]); 80 } 81 82 __weak void dram_bank_mmu_setup(int bank) 83 { 84 bd_t *bd = gd->bd; 85 int i; 86 87 debug("%s: bank: %d\n", __func__, bank); 88 for (i = bd->bi_dram[bank].start >> 20; 89 i < (bd->bi_dram[bank].start + bd->bi_dram[bank].size) >> 20; 90 i++) { 91 #if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH) 92 set_section_dcache(i, DCACHE_WRITETHROUGH); 93 #else 94 set_section_dcache(i, DCACHE_WRITEBACK); 95 #endif 96 } 97 } 98 99 /* to activate the MMU we need to set up virtual memory: use 1M areas */ 100 static inline void mmu_setup(void) 101 { 102 int i; 103 u32 reg; 104 105 arm_init_before_mmu(); 106 /* Set up an identity-mapping for all 4GB, rw for everyone */ 107 for (i = 0; i < 4096; i++) 108 set_section_dcache(i, DCACHE_OFF); 109 110 for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { 111 dram_bank_mmu_setup(i); 112 } 113 114 /* Copy the page table address to cp15 */ 115 asm volatile("mcr p15, 0, %0, c2, c0, 0" 116 : : "r" (gd->arch.tlb_addr) : "memory"); 117 /* Set the access control to all-supervisor */ 118 asm volatile("mcr p15, 0, %0, c3, c0, 0" 119 : : "r" (~0)); 120 /* and enable the mmu */ 121 reg = get_cr(); /* get control reg. */ 122 cp_delay(); 123 set_cr(reg | CR_M); 124 } 125 126 static int mmu_enabled(void) 127 { 128 return get_cr() & CR_M; 129 } 130 131 /* cache_bit must be either CR_I or CR_C */ 132 static void cache_enable(uint32_t cache_bit) 133 { 134 uint32_t reg; 135 136 /* The data cache is not active unless the mmu is enabled too */ 137 if ((cache_bit == CR_C) && !mmu_enabled()) 138 mmu_setup(); 139 reg = get_cr(); /* get control reg. */ 140 cp_delay(); 141 set_cr(reg | cache_bit); 142 } 143 144 /* cache_bit must be either CR_I or CR_C */ 145 static void cache_disable(uint32_t cache_bit) 146 { 147 uint32_t reg; 148 149 reg = get_cr(); 150 cp_delay(); 151 152 if (cache_bit == CR_C) { 153 /* if cache isn;t enabled no need to disable */ 154 if ((reg & CR_C) != CR_C) 155 return; 156 /* if disabling data cache, disable mmu too */ 157 cache_bit |= CR_M; 158 } 159 reg = get_cr(); 160 cp_delay(); 161 if (cache_bit == (CR_C | CR_M)) 162 flush_dcache_all(); 163 set_cr(reg & ~cache_bit); 164 } 165 #endif 166 167 #ifdef CONFIG_SYS_ICACHE_OFF 168 void icache_enable (void) 169 { 170 return; 171 } 172 173 void icache_disable (void) 174 { 175 return; 176 } 177 178 int icache_status (void) 179 { 180 return 0; /* always off */ 181 } 182 #else 183 void icache_enable(void) 184 { 185 cache_enable(CR_I); 186 } 187 188 void icache_disable(void) 189 { 190 cache_disable(CR_I); 191 } 192 193 int icache_status(void) 194 { 195 return (get_cr() & CR_I) != 0; 196 } 197 #endif 198 199 #ifdef CONFIG_SYS_DCACHE_OFF 200 void dcache_enable (void) 201 { 202 return; 203 } 204 205 void dcache_disable (void) 206 { 207 return; 208 } 209 210 int dcache_status (void) 211 { 212 return 0; /* always off */ 213 } 214 #else 215 void dcache_enable(void) 216 { 217 cache_enable(CR_C); 218 } 219 220 void dcache_disable(void) 221 { 222 cache_disable(CR_C); 223 } 224 225 int dcache_status(void) 226 { 227 return (get_cr() & CR_C) != 0; 228 } 229 #endif 230