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 */ 58ENTRY(cpu_arm946_reset) 59 mov ip, #0 60 mcr p15, 0, ip, c7, c5, 0 @ flush I cache 61 mcr p15, 0, ip, c7, c6, 0 @ flush D cache 62 mcr p15, 0, ip, c7, c10, 4 @ drain WB 63 mrc p15, 0, ip, c1, c0, 0 @ ctrl register 64 bic ip, ip, #0x00000005 @ .............c.p 65 bic ip, ip, #0x00001000 @ i-cache 66 mcr p15, 0, ip, c1, c0, 0 @ ctrl register 67 mov pc, r0 68 69/* 70 * cpu_arm946_do_idle() 71 */ 72 .align 5 73ENTRY(cpu_arm946_do_idle) 74 mcr p15, 0, r0, c7, c0, 4 @ Wait for interrupt 75 mov pc, lr 76 77/* 78 * flush_user_cache_all() 79 */ 80ENTRY(arm946_flush_user_cache_all) 81 /* FALLTHROUGH */ 82 83/* 84 * flush_kern_cache_all() 85 * 86 * Clean and invalidate the entire cache. 87 */ 88ENTRY(arm946_flush_kern_cache_all) 89 mov r2, #VM_EXEC 90 mov ip, #0 91__flush_whole_cache: 92#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH 93 mcr p15, 0, ip, c7, c6, 0 @ flush D cache 94#else 95 mov r1, #(CACHE_DSEGMENTS - 1) << 29 @ 4 segments 961: orr r3, r1, #(CACHE_DENTRIES - 1) << 4 @ n entries 972: mcr p15, 0, r3, c7, c14, 2 @ clean/flush D index 98 subs r3, r3, #1 << 4 99 bcs 2b @ entries n to 0 100 subs r1, r1, #1 << 29 101 bcs 1b @ segments 3 to 0 102#endif 103 tst r2, #VM_EXEC 104 mcrne p15, 0, ip, c7, c5, 0 @ flush I cache 105 mcrne p15, 0, ip, c7, c10, 4 @ drain WB 106 mov pc, lr 107 108/* 109 * flush_user_cache_range(start, end, flags) 110 * 111 * Clean and invalidate a range of cache entries in the 112 * specified address range. 113 * 114 * - start - start address (inclusive) 115 * - end - end address (exclusive) 116 * - flags - vm_flags describing address space 117 * (same as arm926) 118 */ 119ENTRY(arm946_flush_user_cache_range) 120 mov ip, #0 121 sub r3, r1, r0 @ calculate total size 122 cmp r3, #CACHE_DLIMIT 123 bhs __flush_whole_cache 124 1251: tst r2, #VM_EXEC 126#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH 127 mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry 128 mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry 129 add r0, r0, #CACHE_DLINESIZE 130 mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry 131 mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry 132 add r0, r0, #CACHE_DLINESIZE 133#else 134 mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry 135 mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry 136 add r0, r0, #CACHE_DLINESIZE 137 mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry 138 mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry 139 add r0, r0, #CACHE_DLINESIZE 140#endif 141 cmp r0, r1 142 blo 1b 143 tst r2, #VM_EXEC 144 mcrne p15, 0, ip, c7, c10, 4 @ drain WB 145 mov pc, lr 146 147/* 148 * coherent_kern_range(start, end) 149 * 150 * Ensure coherency between the Icache and the Dcache in the 151 * region described by start, end. If you have non-snooping 152 * Harvard caches, you need to implement this function. 153 * 154 * - start - virtual start address 155 * - end - virtual end address 156 */ 157ENTRY(arm946_coherent_kern_range) 158 /* FALLTHROUGH */ 159 160/* 161 * coherent_user_range(start, end) 162 * 163 * Ensure coherency between the Icache and the Dcache in the 164 * region described by start, end. If you have non-snooping 165 * Harvard caches, you need to implement this function. 166 * 167 * - start - virtual start address 168 * - end - virtual end address 169 * (same as arm926) 170 */ 171ENTRY(arm946_coherent_user_range) 172 bic r0, r0, #CACHE_DLINESIZE - 1 1731: mcr p15, 0, r0, c7, c10, 1 @ clean D entry 174 mcr p15, 0, r0, c7, c5, 1 @ invalidate I entry 175 add r0, r0, #CACHE_DLINESIZE 176 cmp r0, r1 177 blo 1b 178 mcr p15, 0, r0, c7, c10, 4 @ drain WB 179 mov pc, lr 180 181/* 182 * flush_kern_dcache_area(void *addr, size_t size) 183 * 184 * Ensure no D cache aliasing occurs, either with itself or 185 * the I cache 186 * 187 * - addr - kernel address 188 * - size - region size 189 * (same as arm926) 190 */ 191ENTRY(arm946_flush_kern_dcache_area) 192 add r1, r0, r1 1931: mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry 194 add r0, r0, #CACHE_DLINESIZE 195 cmp r0, r1 196 blo 1b 197 mov r0, #0 198 mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache 199 mcr p15, 0, r0, c7, c10, 4 @ drain WB 200 mov pc, lr 201 202/* 203 * dma_inv_range(start, end) 204 * 205 * Invalidate (discard) the specified virtual address range. 206 * May not write back any entries. If 'start' or 'end' 207 * are not cache line aligned, those lines must be written 208 * back. 209 * 210 * - start - virtual start address 211 * - end - virtual end address 212 * (same as arm926) 213 */ 214arm946_dma_inv_range: 215#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH 216 tst r0, #CACHE_DLINESIZE - 1 217 mcrne p15, 0, r0, c7, c10, 1 @ clean D entry 218 tst r1, #CACHE_DLINESIZE - 1 219 mcrne p15, 0, r1, c7, c10, 1 @ clean D entry 220#endif 221 bic r0, r0, #CACHE_DLINESIZE - 1 2221: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry 223 add r0, r0, #CACHE_DLINESIZE 224 cmp r0, r1 225 blo 1b 226 mcr p15, 0, r0, c7, c10, 4 @ drain WB 227 mov pc, lr 228 229/* 230 * dma_clean_range(start, end) 231 * 232 * Clean the specified virtual address range. 233 * 234 * - start - virtual start address 235 * - end - virtual end address 236 * 237 * (same as arm926) 238 */ 239arm946_dma_clean_range: 240#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH 241 bic r0, r0, #CACHE_DLINESIZE - 1 2421: mcr p15, 0, r0, c7, c10, 1 @ clean D entry 243 add r0, r0, #CACHE_DLINESIZE 244 cmp r0, r1 245 blo 1b 246#endif 247 mcr p15, 0, r0, c7, c10, 4 @ drain WB 248 mov pc, lr 249 250/* 251 * dma_flush_range(start, end) 252 * 253 * Clean and invalidate the specified virtual address range. 254 * 255 * - start - virtual start address 256 * - end - virtual end address 257 * 258 * (same as arm926) 259 */ 260ENTRY(arm946_dma_flush_range) 261 bic r0, r0, #CACHE_DLINESIZE - 1 2621: 263#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH 264 mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry 265#else 266 mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry 267#endif 268 add r0, r0, #CACHE_DLINESIZE 269 cmp r0, r1 270 blo 1b 271 mcr p15, 0, r0, c7, c10, 4 @ drain WB 272 mov pc, lr 273 274/* 275 * dma_map_area(start, size, dir) 276 * - start - kernel virtual start address 277 * - size - size of region 278 * - dir - DMA direction 279 */ 280ENTRY(arm946_dma_map_area) 281 add r1, r1, r0 282 cmp r2, #DMA_TO_DEVICE 283 beq arm946_dma_clean_range 284 bcs arm946_dma_inv_range 285 b arm946_dma_flush_range 286ENDPROC(arm946_dma_map_area) 287 288/* 289 * dma_unmap_area(start, size, dir) 290 * - start - kernel virtual start address 291 * - size - size of region 292 * - dir - DMA direction 293 */ 294ENTRY(arm946_dma_unmap_area) 295 mov pc, lr 296ENDPROC(arm946_dma_unmap_area) 297 298ENTRY(arm946_cache_fns) 299 .long arm946_flush_kern_cache_all 300 .long arm946_flush_user_cache_all 301 .long arm946_flush_user_cache_range 302 .long arm946_coherent_kern_range 303 .long arm946_coherent_user_range 304 .long arm946_flush_kern_dcache_area 305 .long arm946_dma_map_area 306 .long arm946_dma_unmap_area 307 .long arm946_dma_flush_range 308 309 310ENTRY(cpu_arm946_dcache_clean_area) 311#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH 3121: mcr p15, 0, r0, c7, c10, 1 @ clean D entry 313 add r0, r0, #CACHE_DLINESIZE 314 subs r1, r1, #CACHE_DLINESIZE 315 bhi 1b 316#endif 317 mcr p15, 0, r0, c7, c10, 4 @ drain WB 318 mov pc, lr 319 320 __CPUINIT 321 322 .type __arm946_setup, #function 323__arm946_setup: 324 mov r0, #0 325 mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache 326 mcr p15, 0, r0, c7, c6, 0 @ invalidate D cache 327 mcr p15, 0, r0, c7, c10, 4 @ drain WB 328 329 mcr p15, 0, r0, c6, c3, 0 @ disable memory region 3~7 330 mcr p15, 0, r0, c6, c4, 0 331 mcr p15, 0, r0, c6, c5, 0 332 mcr p15, 0, r0, c6, c6, 0 333 mcr p15, 0, r0, c6, c7, 0 334 335 mov r0, #0x0000003F @ base = 0, size = 4GB 336 mcr p15, 0, r0, c6, c0, 0 @ set region 0, default 337 338 ldr r0, =(CONFIG_DRAM_BASE & 0xFFFFF000) @ base[31:12] of RAM 339 ldr r1, =(CONFIG_DRAM_SIZE >> 12) @ size of RAM (must be >= 4KB) 340 mov r2, #10 @ 11 is the minimum (4KB) 3411: add r2, r2, #1 @ area size *= 2 342 mov r1, r1, lsr #1 343 bne 1b @ count not zero r-shift 344 orr r0, r0, r2, lsl #1 @ the region register value 345 orr r0, r0, #1 @ set enable bit 346 mcr p15, 0, r0, c6, c1, 0 @ set region 1, RAM 347 348 ldr r0, =(CONFIG_FLASH_MEM_BASE & 0xFFFFF000) @ base[31:12] of FLASH 349 ldr r1, =(CONFIG_FLASH_SIZE >> 12) @ size of FLASH (must be >= 4KB) 350 mov r2, #10 @ 11 is the minimum (4KB) 3511: add r2, r2, #1 @ area size *= 2 352 mov r1, r1, lsr #1 353 bne 1b @ count not zero r-shift 354 orr r0, r0, r2, lsl #1 @ the region register value 355 orr r0, r0, #1 @ set enable bit 356 mcr p15, 0, r0, c6, c2, 0 @ set region 2, ROM/FLASH 357 358 mov r0, #0x06 359 mcr p15, 0, r0, c2, c0, 0 @ region 1,2 d-cacheable 360 mcr p15, 0, r0, c2, c0, 1 @ region 1,2 i-cacheable 361#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH 362 mov r0, #0x00 @ disable whole write buffer 363#else 364 mov r0, #0x02 @ region 1 write bufferred 365#endif 366 mcr p15, 0, r0, c3, c0, 0 367 368/* 369 * Access Permission Settings for future permission control by PU. 370 * 371 * priv. user 372 * region 0 (whole) rw -- : b0001 373 * region 1 (RAM) rw rw : b0011 374 * region 2 (FLASH) rw r- : b0010 375 * region 3~7 (none) -- -- : b0000 376 */ 377 mov r0, #0x00000031 378 orr r0, r0, #0x00000200 379 mcr p15, 0, r0, c5, c0, 2 @ set data access permission 380 mcr p15, 0, r0, c5, c0, 3 @ set inst. access permission 381 382 mrc p15, 0, r0, c1, c0 @ get control register 383 orr r0, r0, #0x00001000 @ I-cache 384 orr r0, r0, #0x00000005 @ MPU/D-cache 385#ifdef CONFIG_CPU_CACHE_ROUND_ROBIN 386 orr r0, r0, #0x00004000 @ .1.. .... .... .... 387#endif 388 mov pc, lr 389 390 .size __arm946_setup, . - __arm946_setup 391 392 __INITDATA 393 394/* 395 * Purpose : Function pointers used to access above functions - all calls 396 * come through these 397 */ 398 .type arm946_processor_functions, #object 399ENTRY(arm946_processor_functions) 400 .word nommu_early_abort 401 .word legacy_pabort 402 .word cpu_arm946_proc_init 403 .word cpu_arm946_proc_fin 404 .word cpu_arm946_reset 405 .word cpu_arm946_do_idle 406 407 .word cpu_arm946_dcache_clean_area 408 .word cpu_arm946_switch_mm 409 .word 0 @ cpu_*_set_pte 410 .size arm946_processor_functions, . - arm946_processor_functions 411 412 .section ".rodata" 413 414 .type cpu_arch_name, #object 415cpu_arch_name: 416 .asciz "armv5te" 417 .size cpu_arch_name, . - cpu_arch_name 418 419 .type cpu_elf_name, #object 420cpu_elf_name: 421 .asciz "v5t" 422 .size cpu_elf_name, . - cpu_elf_name 423 424 .type cpu_arm946_name, #object 425cpu_arm946_name: 426 .ascii "ARM946E-S" 427 .size cpu_arm946_name, . - cpu_arm946_name 428 429 .align 430 431 .section ".proc.info.init", #alloc, #execinstr 432 .type __arm946_proc_info,#object 433__arm946_proc_info: 434 .long 0x41009460 435 .long 0xff00fff0 436 .long 0 437 b __arm946_setup 438 .long cpu_arch_name 439 .long cpu_elf_name 440 .long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB 441 .long cpu_arm946_name 442 .long arm946_processor_functions 443 .long 0 444 .long 0 445 .long arm940_cache_fns 446 .size __arm946_proc_info, . - __arm946_proc_info 447 448