1/* 2 * linux/arch/arm/mm/arm946.S: utility functions for ARM946E-S 3 * 4 * Copyright (C) 2004-2006 Hyok S. Choi (hyok.choi@samsung.com) 5 * 6 * (Many of cache codes are from proc-arm926.S) 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License version 2 as 10 * published by the Free Software Foundation. 11 * 12 */ 13#include <linux/linkage.h> 14#include <linux/init.h> 15#include <asm/assembler.h> 16#include <asm/hwcap.h> 17#include <asm/pgtable-hwdef.h> 18#include <asm/pgtable.h> 19#include <asm/ptrace.h> 20#include "proc-macros.S" 21 22/* 23 * ARM946E-S is synthesizable to have 0KB to 1MB sized D-Cache, 24 * comprising 256 lines of 32 bytes (8 words). 25 */ 26#define CACHE_DSIZE (CONFIG_CPU_DCACHE_SIZE) /* typically 8KB. */ 27#define CACHE_DLINESIZE 32 /* fixed */ 28#define CACHE_DSEGMENTS 4 /* fixed */ 29#define CACHE_DENTRIES (CACHE_DSIZE / CACHE_DSEGMENTS / CACHE_DLINESIZE) 30#define CACHE_DLIMIT (CACHE_DSIZE * 4) /* benchmark needed */ 31 32 .text 33/* 34 * cpu_arm946_proc_init() 35 * cpu_arm946_switch_mm() 36 * 37 * These are not required. 38 */ 39ENTRY(cpu_arm946_proc_init) 40ENTRY(cpu_arm946_switch_mm) 41 mov pc, lr 42 43/* 44 * cpu_arm946_proc_fin() 45 */ 46ENTRY(cpu_arm946_proc_fin) 47 mrc p15, 0, r0, c1, c0, 0 @ ctrl register 48 bic r0, r0, #0x00001000 @ i-cache 49 bic r0, r0, #0x00000004 @ d-cache 50 mcr p15, 0, r0, c1, c0, 0 @ disable caches 51 mov pc, lr 52 53/* 54 * cpu_arm946_reset(loc) 55 * Params : r0 = address to jump to 56 * Notes : This sets up everything for a reset 57 */ 58 .pushsection .idmap.text, "ax" 59ENTRY(cpu_arm946_reset) 60 mov ip, #0 61 mcr p15, 0, ip, c7, c5, 0 @ flush I cache 62 mcr p15, 0, ip, c7, c6, 0 @ flush D cache 63 mcr p15, 0, ip, c7, c10, 4 @ drain WB 64 mrc p15, 0, ip, c1, c0, 0 @ ctrl register 65 bic ip, ip, #0x00000005 @ .............c.p 66 bic ip, ip, #0x00001000 @ i-cache 67 mcr p15, 0, ip, c1, c0, 0 @ ctrl register 68 mov pc, r0 69ENDPROC(cpu_arm946_reset) 70 .popsection 71 72/* 73 * cpu_arm946_do_idle() 74 */ 75 .align 5 76ENTRY(cpu_arm946_do_idle) 77 mcr p15, 0, r0, c7, c0, 4 @ Wait for interrupt 78 mov pc, lr 79 80/* 81 * flush_icache_all() 82 * 83 * Unconditionally clean and invalidate the entire icache. 84 */ 85ENTRY(arm946_flush_icache_all) 86 mov r0, #0 87 mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache 88 mov pc, lr 89ENDPROC(arm946_flush_icache_all) 90 91/* 92 * flush_user_cache_all() 93 */ 94ENTRY(arm946_flush_user_cache_all) 95 /* FALLTHROUGH */ 96 97/* 98 * flush_kern_cache_all() 99 * 100 * Clean and invalidate the entire cache. 101 */ 102ENTRY(arm946_flush_kern_cache_all) 103 mov r2, #VM_EXEC 104 mov ip, #0 105__flush_whole_cache: 106#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH 107 mcr p15, 0, ip, c7, c6, 0 @ flush D cache 108#else 109 mov r1, #(CACHE_DSEGMENTS - 1) << 29 @ 4 segments 1101: orr r3, r1, #(CACHE_DENTRIES - 1) << 4 @ n entries 1112: mcr p15, 0, r3, c7, c14, 2 @ clean/flush D index 112 subs r3, r3, #1 << 4 113 bcs 2b @ entries n to 0 114 subs r1, r1, #1 << 29 115 bcs 1b @ segments 3 to 0 116#endif 117 tst r2, #VM_EXEC 118 mcrne p15, 0, ip, c7, c5, 0 @ flush I cache 119 mcrne p15, 0, ip, c7, c10, 4 @ drain WB 120 mov pc, lr 121 122/* 123 * flush_user_cache_range(start, end, flags) 124 * 125 * Clean and invalidate a range of cache entries in the 126 * specified address range. 127 * 128 * - start - start address (inclusive) 129 * - end - end address (exclusive) 130 * - flags - vm_flags describing address space 131 * (same as arm926) 132 */ 133ENTRY(arm946_flush_user_cache_range) 134 mov ip, #0 135 sub r3, r1, r0 @ calculate total size 136 cmp r3, #CACHE_DLIMIT 137 bhs __flush_whole_cache 138 1391: tst r2, #VM_EXEC 140#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH 141 mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry 142 mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry 143 add r0, r0, #CACHE_DLINESIZE 144 mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry 145 mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry 146 add r0, r0, #CACHE_DLINESIZE 147#else 148 mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry 149 mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry 150 add r0, r0, #CACHE_DLINESIZE 151 mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry 152 mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry 153 add r0, r0, #CACHE_DLINESIZE 154#endif 155 cmp r0, r1 156 blo 1b 157 tst r2, #VM_EXEC 158 mcrne p15, 0, ip, c7, c10, 4 @ drain WB 159 mov pc, lr 160 161/* 162 * coherent_kern_range(start, end) 163 * 164 * Ensure coherency between the Icache and the Dcache in the 165 * region described by start, end. If you have non-snooping 166 * Harvard caches, you need to implement this function. 167 * 168 * - start - virtual start address 169 * - end - virtual end address 170 */ 171ENTRY(arm946_coherent_kern_range) 172 /* FALLTHROUGH */ 173 174/* 175 * coherent_user_range(start, end) 176 * 177 * Ensure coherency between the Icache and the Dcache in the 178 * region described by start, end. If you have non-snooping 179 * Harvard caches, you need to implement this function. 180 * 181 * - start - virtual start address 182 * - end - virtual end address 183 * (same as arm926) 184 */ 185ENTRY(arm946_coherent_user_range) 186 bic r0, r0, #CACHE_DLINESIZE - 1 1871: mcr p15, 0, r0, c7, c10, 1 @ clean D entry 188 mcr p15, 0, r0, c7, c5, 1 @ invalidate I entry 189 add r0, r0, #CACHE_DLINESIZE 190 cmp r0, r1 191 blo 1b 192 mcr p15, 0, r0, c7, c10, 4 @ drain WB 193 mov pc, lr 194 195/* 196 * flush_kern_dcache_area(void *addr, size_t size) 197 * 198 * Ensure no D cache aliasing occurs, either with itself or 199 * the I cache 200 * 201 * - addr - kernel address 202 * - size - region size 203 * (same as arm926) 204 */ 205ENTRY(arm946_flush_kern_dcache_area) 206 add r1, r0, r1 2071: mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry 208 add r0, r0, #CACHE_DLINESIZE 209 cmp r0, r1 210 blo 1b 211 mov r0, #0 212 mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache 213 mcr p15, 0, r0, c7, c10, 4 @ drain WB 214 mov pc, lr 215 216/* 217 * dma_inv_range(start, end) 218 * 219 * Invalidate (discard) the specified virtual address range. 220 * May not write back any entries. If 'start' or 'end' 221 * are not cache line aligned, those lines must be written 222 * back. 223 * 224 * - start - virtual start address 225 * - end - virtual end address 226 * (same as arm926) 227 */ 228arm946_dma_inv_range: 229#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH 230 tst r0, #CACHE_DLINESIZE - 1 231 mcrne p15, 0, r0, c7, c10, 1 @ clean D entry 232 tst r1, #CACHE_DLINESIZE - 1 233 mcrne p15, 0, r1, c7, c10, 1 @ clean D entry 234#endif 235 bic r0, r0, #CACHE_DLINESIZE - 1 2361: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry 237 add r0, r0, #CACHE_DLINESIZE 238 cmp r0, r1 239 blo 1b 240 mcr p15, 0, r0, c7, c10, 4 @ drain WB 241 mov pc, lr 242 243/* 244 * dma_clean_range(start, end) 245 * 246 * Clean the specified virtual address range. 247 * 248 * - start - virtual start address 249 * - end - virtual end address 250 * 251 * (same as arm926) 252 */ 253arm946_dma_clean_range: 254#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH 255 bic r0, r0, #CACHE_DLINESIZE - 1 2561: mcr p15, 0, r0, c7, c10, 1 @ clean D entry 257 add r0, r0, #CACHE_DLINESIZE 258 cmp r0, r1 259 blo 1b 260#endif 261 mcr p15, 0, r0, c7, c10, 4 @ drain WB 262 mov pc, lr 263 264/* 265 * dma_flush_range(start, end) 266 * 267 * Clean and invalidate the specified virtual address range. 268 * 269 * - start - virtual start address 270 * - end - virtual end address 271 * 272 * (same as arm926) 273 */ 274ENTRY(arm946_dma_flush_range) 275 bic r0, r0, #CACHE_DLINESIZE - 1 2761: 277#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH 278 mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry 279#else 280 mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry 281#endif 282 add r0, r0, #CACHE_DLINESIZE 283 cmp r0, r1 284 blo 1b 285 mcr p15, 0, r0, c7, c10, 4 @ drain WB 286 mov pc, lr 287 288/* 289 * dma_map_area(start, size, dir) 290 * - start - kernel virtual start address 291 * - size - size of region 292 * - dir - DMA direction 293 */ 294ENTRY(arm946_dma_map_area) 295 add r1, r1, r0 296 cmp r2, #DMA_TO_DEVICE 297 beq arm946_dma_clean_range 298 bcs arm946_dma_inv_range 299 b arm946_dma_flush_range 300ENDPROC(arm946_dma_map_area) 301 302/* 303 * dma_unmap_area(start, size, dir) 304 * - start - kernel virtual start address 305 * - size - size of region 306 * - dir - DMA direction 307 */ 308ENTRY(arm946_dma_unmap_area) 309 mov pc, lr 310ENDPROC(arm946_dma_unmap_area) 311 312 @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S) 313 define_cache_functions arm946 314 315ENTRY(cpu_arm946_dcache_clean_area) 316#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH 3171: mcr p15, 0, r0, c7, c10, 1 @ clean D entry 318 add r0, r0, #CACHE_DLINESIZE 319 subs r1, r1, #CACHE_DLINESIZE 320 bhi 1b 321#endif 322 mcr p15, 0, r0, c7, c10, 4 @ drain WB 323 mov pc, lr 324 325 __CPUINIT 326 327 .type __arm946_setup, #function 328__arm946_setup: 329 mov r0, #0 330 mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache 331 mcr p15, 0, r0, c7, c6, 0 @ invalidate D cache 332 mcr p15, 0, r0, c7, c10, 4 @ drain WB 333 334 mcr p15, 0, r0, c6, c3, 0 @ disable memory region 3~7 335 mcr p15, 0, r0, c6, c4, 0 336 mcr p15, 0, r0, c6, c5, 0 337 mcr p15, 0, r0, c6, c6, 0 338 mcr p15, 0, r0, c6, c7, 0 339 340 mov r0, #0x0000003F @ base = 0, size = 4GB 341 mcr p15, 0, r0, c6, c0, 0 @ set region 0, default 342 343 ldr r0, =(CONFIG_DRAM_BASE & 0xFFFFF000) @ base[31:12] of RAM 344 ldr r1, =(CONFIG_DRAM_SIZE >> 12) @ size of RAM (must be >= 4KB) 345 mov r2, #10 @ 11 is the minimum (4KB) 3461: add r2, r2, #1 @ area size *= 2 347 mov r1, r1, lsr #1 348 bne 1b @ count not zero r-shift 349 orr r0, r0, r2, lsl #1 @ the region register value 350 orr r0, r0, #1 @ set enable bit 351 mcr p15, 0, r0, c6, c1, 0 @ set region 1, RAM 352 353 ldr r0, =(CONFIG_FLASH_MEM_BASE & 0xFFFFF000) @ base[31:12] of FLASH 354 ldr r1, =(CONFIG_FLASH_SIZE >> 12) @ size of FLASH (must be >= 4KB) 355 mov r2, #10 @ 11 is the minimum (4KB) 3561: add r2, r2, #1 @ area size *= 2 357 mov r1, r1, lsr #1 358 bne 1b @ count not zero r-shift 359 orr r0, r0, r2, lsl #1 @ the region register value 360 orr r0, r0, #1 @ set enable bit 361 mcr p15, 0, r0, c6, c2, 0 @ set region 2, ROM/FLASH 362 363 mov r0, #0x06 364 mcr p15, 0, r0, c2, c0, 0 @ region 1,2 d-cacheable 365 mcr p15, 0, r0, c2, c0, 1 @ region 1,2 i-cacheable 366#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH 367 mov r0, #0x00 @ disable whole write buffer 368#else 369 mov r0, #0x02 @ region 1 write bufferred 370#endif 371 mcr p15, 0, r0, c3, c0, 0 372 373/* 374 * Access Permission Settings for future permission control by PU. 375 * 376 * priv. user 377 * region 0 (whole) rw -- : b0001 378 * region 1 (RAM) rw rw : b0011 379 * region 2 (FLASH) rw r- : b0010 380 * region 3~7 (none) -- -- : b0000 381 */ 382 mov r0, #0x00000031 383 orr r0, r0, #0x00000200 384 mcr p15, 0, r0, c5, c0, 2 @ set data access permission 385 mcr p15, 0, r0, c5, c0, 3 @ set inst. access permission 386 387 mrc p15, 0, r0, c1, c0 @ get control register 388 orr r0, r0, #0x00001000 @ I-cache 389 orr r0, r0, #0x00000005 @ MPU/D-cache 390#ifdef CONFIG_CPU_CACHE_ROUND_ROBIN 391 orr r0, r0, #0x00004000 @ .1.. .... .... .... 392#endif 393 mov pc, lr 394 395 .size __arm946_setup, . - __arm946_setup 396 397 __INITDATA 398 399 @ define struct processor (see <asm/proc-fns.h> and proc-macros.S) 400 define_processor_functions arm946, dabort=nommu_early_abort, pabort=legacy_pabort, nommu=1 401 402 .section ".rodata" 403 404 string cpu_arch_name, "armv5te" 405 string cpu_elf_name, "v5t" 406 string cpu_arm946_name, "ARM946E-S" 407 408 .align 409 410 .section ".proc.info.init", #alloc, #execinstr 411 .type __arm946_proc_info,#object 412__arm946_proc_info: 413 .long 0x41009460 414 .long 0xff00fff0 415 .long 0 416 .long 0 417 b __arm946_setup 418 .long cpu_arch_name 419 .long cpu_elf_name 420 .long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB 421 .long cpu_arm946_name 422 .long arm946_processor_functions 423 .long 0 424 .long 0 425 .long arm946_cache_fns 426 .size __arm946_proc_info, . - __arm946_proc_info 427 428