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