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/elf.h> 17#include <asm/pgtable-hwdef.h> 18#include <asm/pgtable.h> 19#include <asm/ptrace.h> 20 21/* 22 * ARM946E-S is synthesizable to have 0KB to 1MB sized D-Cache, 23 * comprising 256 lines of 32 bytes (8 words). 24 */ 25#define CACHE_DSIZE (CONFIG_CPU_DCACHE_SIZE) /* typically 8KB. */ 26#define CACHE_DLINESIZE 32 /* fixed */ 27#define CACHE_DSEGMENTS 4 /* fixed */ 28#define CACHE_DENTRIES (CACHE_DSIZE / CACHE_DSEGMENTS / CACHE_DLINESIZE) 29#define CACHE_DLIMIT (CACHE_DSIZE * 4) /* benchmark needed */ 30 31 .text 32/* 33 * cpu_arm946_proc_init() 34 * cpu_arm946_switch_mm() 35 * 36 * These are not required. 37 */ 38ENTRY(cpu_arm946_proc_init) 39ENTRY(cpu_arm946_switch_mm) 40 mov pc, lr 41 42/* 43 * cpu_arm946_proc_fin() 44 */ 45ENTRY(cpu_arm946_proc_fin) 46 stmfd sp!, {lr} 47 mov ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE 48 msr cpsr_c, ip 49 bl arm946_flush_kern_cache_all 50 mrc p15, 0, r0, c1, c0, 0 @ ctrl register 51 bic r0, r0, #0x00001000 @ i-cache 52 bic r0, r0, #0x00000004 @ d-cache 53 mcr p15, 0, r0, c1, c0, 0 @ disable caches 54 ldmfd sp!, {pc} 55 56/* 57 * cpu_arm946_reset(loc) 58 * Params : r0 = address to jump to 59 * Notes : This sets up everything for a reset 60 */ 61ENTRY(cpu_arm946_reset) 62 mov ip, #0 63 mcr p15, 0, ip, c7, c5, 0 @ flush I cache 64 mcr p15, 0, ip, c7, c6, 0 @ flush D cache 65 mcr p15, 0, ip, c7, c10, 4 @ drain WB 66 mrc p15, 0, ip, c1, c0, 0 @ ctrl register 67 bic ip, ip, #0x00000005 @ .............c.p 68 bic ip, ip, #0x00001000 @ i-cache 69 mcr p15, 0, ip, c1, c0, 0 @ ctrl register 70 mov pc, r0 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_user_cache_all() 82 */ 83ENTRY(arm946_flush_user_cache_all) 84 /* FALLTHROUGH */ 85 86/* 87 * flush_kern_cache_all() 88 * 89 * Clean and invalidate the entire cache. 90 */ 91ENTRY(arm946_flush_kern_cache_all) 92 mov r2, #VM_EXEC 93 mov ip, #0 94__flush_whole_cache: 95#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH 96 mcr p15, 0, ip, c7, c6, 0 @ flush D cache 97#else 98 mov r1, #(CACHE_DSEGMENTS - 1) << 29 @ 4 segments 991: orr r3, r1, #(CACHE_DENTRIES - 1) << 4 @ n entries 1002: mcr p15, 0, r3, c7, c14, 2 @ clean/flush D index 101 subs r3, r3, #1 << 4 102 bcs 2b @ entries n to 0 103 subs r1, r1, #1 << 29 104 bcs 1b @ segments 3 to 0 105#endif 106 tst r2, #VM_EXEC 107 mcrne p15, 0, ip, c7, c5, 0 @ flush I cache 108 mcrne p15, 0, ip, c7, c10, 4 @ drain WB 109 mov pc, lr 110 111/* 112 * flush_user_cache_range(start, end, flags) 113 * 114 * Clean and invalidate a range of cache entries in the 115 * specified address range. 116 * 117 * - start - start address (inclusive) 118 * - end - end address (exclusive) 119 * - flags - vm_flags describing address space 120 * (same as arm926) 121 */ 122ENTRY(arm946_flush_user_cache_range) 123 mov ip, #0 124 sub r3, r1, r0 @ calculate total size 125 cmp r3, #CACHE_DLIMIT 126 bhs __flush_whole_cache 127 1281: tst r2, #VM_EXEC 129#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH 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 mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry 134 mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry 135 add r0, r0, #CACHE_DLINESIZE 136#else 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 mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry 141 mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry 142 add r0, r0, #CACHE_DLINESIZE 143#endif 144 cmp r0, r1 145 blo 1b 146 tst r2, #VM_EXEC 147 mcrne p15, 0, ip, c7, c10, 4 @ drain WB 148 mov pc, lr 149 150/* 151 * coherent_kern_range(start, end) 152 * 153 * Ensure coherency between the Icache and the Dcache in the 154 * region described by start, end. If you have non-snooping 155 * Harvard caches, you need to implement this function. 156 * 157 * - start - virtual start address 158 * - end - virtual end address 159 */ 160ENTRY(arm946_coherent_kern_range) 161 /* FALLTHROUGH */ 162 163/* 164 * coherent_user_range(start, end) 165 * 166 * Ensure coherency between the Icache and the Dcache in the 167 * region described by start, end. If you have non-snooping 168 * Harvard caches, you need to implement this function. 169 * 170 * - start - virtual start address 171 * - end - virtual end address 172 * (same as arm926) 173 */ 174ENTRY(arm946_coherent_user_range) 175 bic r0, r0, #CACHE_DLINESIZE - 1 1761: mcr p15, 0, r0, c7, c10, 1 @ clean D entry 177 mcr p15, 0, r0, c7, c5, 1 @ invalidate I entry 178 add r0, r0, #CACHE_DLINESIZE 179 cmp r0, r1 180 blo 1b 181 mcr p15, 0, r0, c7, c10, 4 @ drain WB 182 mov pc, lr 183 184/* 185 * flush_kern_dcache_page(void *page) 186 * 187 * Ensure no D cache aliasing occurs, either with itself or 188 * the I cache 189 * 190 * - addr - page aligned address 191 * (same as arm926) 192 */ 193ENTRY(arm946_flush_kern_dcache_page) 194 add r1, r0, #PAGE_SZ 1951: mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry 196 add r0, r0, #CACHE_DLINESIZE 197 cmp r0, r1 198 blo 1b 199 mov r0, #0 200 mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache 201 mcr p15, 0, r0, c7, c10, 4 @ drain WB 202 mov pc, lr 203 204/* 205 * dma_inv_range(start, end) 206 * 207 * Invalidate (discard) the specified virtual address range. 208 * May not write back any entries. If 'start' or 'end' 209 * are not cache line aligned, those lines must be written 210 * back. 211 * 212 * - start - virtual start address 213 * - end - virtual end address 214 * (same as arm926) 215 */ 216ENTRY(arm946_dma_inv_range) 217#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH 218 tst r0, #CACHE_DLINESIZE - 1 219 mcrne p15, 0, r0, c7, c10, 1 @ clean D entry 220 tst r1, #CACHE_DLINESIZE - 1 221 mcrne p15, 0, r1, c7, c10, 1 @ clean D entry 222#endif 223 bic r0, r0, #CACHE_DLINESIZE - 1 2241: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry 225 add r0, r0, #CACHE_DLINESIZE 226 cmp r0, r1 227 blo 1b 228 mcr p15, 0, r0, c7, c10, 4 @ drain WB 229 mov pc, lr 230 231/* 232 * dma_clean_range(start, end) 233 * 234 * Clean the specified virtual address range. 235 * 236 * - start - virtual start address 237 * - end - virtual end address 238 * 239 * (same as arm926) 240 */ 241ENTRY(arm946_dma_clean_range) 242#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH 243 bic r0, r0, #CACHE_DLINESIZE - 1 2441: mcr p15, 0, r0, c7, c10, 1 @ clean D entry 245 add r0, r0, #CACHE_DLINESIZE 246 cmp r0, r1 247 blo 1b 248#endif 249 mcr p15, 0, r0, c7, c10, 4 @ drain WB 250 mov pc, lr 251 252/* 253 * dma_flush_range(start, end) 254 * 255 * Clean and invalidate the specified virtual address range. 256 * 257 * - start - virtual start address 258 * - end - virtual end address 259 * 260 * (same as arm926) 261 */ 262ENTRY(arm946_dma_flush_range) 263 bic r0, r0, #CACHE_DLINESIZE - 1 2641: 265#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH 266 mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry 267#else 268 mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry 269#endif 270 add r0, r0, #CACHE_DLINESIZE 271 cmp r0, r1 272 blo 1b 273 mcr p15, 0, r0, c7, c10, 4 @ drain WB 274 mov pc, lr 275 276ENTRY(arm946_cache_fns) 277 .long arm946_flush_kern_cache_all 278 .long arm946_flush_user_cache_all 279 .long arm946_flush_user_cache_range 280 .long arm946_coherent_kern_range 281 .long arm946_coherent_user_range 282 .long arm946_flush_kern_dcache_page 283 .long arm946_dma_inv_range 284 .long arm946_dma_clean_range 285 .long arm946_dma_flush_range 286 287 288ENTRY(cpu_arm946_dcache_clean_area) 289#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH 2901: mcr p15, 0, r0, c7, c10, 1 @ clean D entry 291 add r0, r0, #CACHE_DLINESIZE 292 subs r1, r1, #CACHE_DLINESIZE 293 bhi 1b 294#endif 295 mcr p15, 0, r0, c7, c10, 4 @ drain WB 296 mov pc, lr 297 298 __INIT 299 300 .type __arm946_setup, #function 301__arm946_setup: 302 mov r0, #0 303 mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache 304 mcr p15, 0, r0, c7, c6, 0 @ invalidate D cache 305 mcr p15, 0, r0, c7, c10, 4 @ drain WB 306 307 mcr p15, 0, r0, c6, c3, 0 @ disable memory region 3~7 308 mcr p15, 0, r0, c6, c4, 0 309 mcr p15, 0, r0, c6, c5, 0 310 mcr p15, 0, r0, c6, c6, 0 311 mcr p15, 0, r0, c6, c7, 0 312 313 mov r0, #0x0000003F @ base = 0, size = 4GB 314 mcr p15, 0, r0, c6, c0, 0 @ set region 0, default 315 316 ldr r0, =(CONFIG_DRAM_BASE & 0xFFFFF000) @ base[31:12] of RAM 317 ldr r1, =(CONFIG_DRAM_SIZE >> 12) @ size of RAM (must be >= 4KB) 318 mov r2, #10 @ 11 is the minimum (4KB) 3191: add r2, r2, #1 @ area size *= 2 320 mov r1, r1, lsr #1 321 bne 1b @ count not zero r-shift 322 orr r0, r0, r2, lsl #1 @ the region register value 323 orr r0, r0, #1 @ set enable bit 324 mcr p15, 0, r0, c6, c1, 0 @ set region 1, RAM 325 326 ldr r0, =(CONFIG_FLASH_MEM_BASE & 0xFFFFF000) @ base[31:12] of FLASH 327 ldr r1, =(CONFIG_FLASH_SIZE >> 12) @ size of FLASH (must be >= 4KB) 328 mov r2, #10 @ 11 is the minimum (4KB) 3291: add r2, r2, #1 @ area size *= 2 330 mov r1, r1, lsr #1 331 bne 1b @ count not zero r-shift 332 orr r0, r0, r2, lsl #1 @ the region register value 333 orr r0, r0, #1 @ set enable bit 334 mcr p15, 0, r0, c6, c2, 0 @ set region 2, ROM/FLASH 335 336 mov r0, #0x06 337 mcr p15, 0, r0, c2, c0, 0 @ region 1,2 d-cacheable 338 mcr p15, 0, r0, c2, c0, 1 @ region 1,2 i-cacheable 339#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH 340 mov r0, #0x00 @ disable whole write buffer 341#else 342 mov r0, #0x02 @ region 1 write bufferred 343#endif 344 mcr p15, 0, r0, c3, c0, 0 345 346/* 347 * Access Permission Settings for future permission control by PU. 348 * 349 * priv. user 350 * region 0 (whole) rw -- : b0001 351 * region 1 (RAM) rw rw : b0011 352 * region 2 (FLASH) rw r- : b0010 353 * region 3~7 (none) -- -- : b0000 354 */ 355 mov r0, #0x00000031 356 orr r0, r0, #0x00000200 357 mcr p15, 0, r0, c5, c0, 2 @ set data access permission 358 mcr p15, 0, r0, c5, c0, 3 @ set inst. access permission 359 360 mrc p15, 0, r0, c1, c0 @ get control register 361 orr r0, r0, #0x00001000 @ I-cache 362 orr r0, r0, #0x00000005 @ MPU/D-cache 363#ifdef CONFIG_CPU_CACHE_ROUND_ROBIN 364 orr r0, r0, #0x00004000 @ .1.. .... .... .... 365#endif 366 mov pc, lr 367 368 .size __arm946_setup, . - __arm946_setup 369 370 __INITDATA 371 372/* 373 * Purpose : Function pointers used to access above functions - all calls 374 * come through these 375 */ 376 .type arm946_processor_functions, #object 377ENTRY(arm946_processor_functions) 378 .word nommu_early_abort 379 .word pabort_noifar 380 .word cpu_arm946_proc_init 381 .word cpu_arm946_proc_fin 382 .word cpu_arm946_reset 383 .word cpu_arm946_do_idle 384 385 .word cpu_arm946_dcache_clean_area 386 .word cpu_arm946_switch_mm 387 .word 0 @ cpu_*_set_pte 388 .size arm946_processor_functions, . - arm946_processor_functions 389 390 .section ".rodata" 391 392 .type cpu_arch_name, #object 393cpu_arch_name: 394 .asciz "armv5te" 395 .size cpu_arch_name, . - cpu_arch_name 396 397 .type cpu_elf_name, #object 398cpu_elf_name: 399 .asciz "v5t" 400 .size cpu_elf_name, . - cpu_elf_name 401 402 .type cpu_arm946_name, #object 403cpu_arm946_name: 404 .ascii "ARM946E-S" 405 .size cpu_arm946_name, . - cpu_arm946_name 406 407 .align 408 409 .section ".proc.info.init", #alloc, #execinstr 410 .type __arm946_proc_info,#object 411__arm946_proc_info: 412 .long 0x41009460 413 .long 0xff00fff0 414 .long 0 415 b __arm946_setup 416 .long cpu_arch_name 417 .long cpu_elf_name 418 .long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB 419 .long cpu_arm946_name 420 .long arm946_processor_functions 421 .long 0 422 .long 0 423 .long arm940_cache_fns 424 .size __arm946_proc_info, . - __arm946_proc_info 425 426