1/* 2 * linux/arch/arm/mm/proc-arm920.S: MMU functions for ARM920 3 * 4 * Copyright (C) 1999,2000 ARM Limited 5 * Copyright (C) 2000 Deep Blue Solutions Ltd. 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 * 21 * 22 * These are the low level assembler for performing cache and TLB 23 * functions on the arm920. 24 * 25 * CONFIG_CPU_ARM920_CPU_IDLE -> nohlt 26 */ 27#include <linux/linkage.h> 28#include <linux/config.h> 29#include <linux/init.h> 30#include <asm/assembler.h> 31#include <asm/pgtable.h> 32#include <asm/procinfo.h> 33#include <asm/hardware.h> 34#include <asm/page.h> 35#include <asm/ptrace.h> 36#include "proc-macros.S" 37 38/* 39 * The size of one data cache line. 40 */ 41#define CACHE_DLINESIZE 32 42 43/* 44 * The number of data cache segments. 45 */ 46#define CACHE_DSEGMENTS 8 47 48/* 49 * The number of lines in a cache segment. 50 */ 51#define CACHE_DENTRIES 64 52 53/* 54 * This is the size at which it becomes more efficient to 55 * clean the whole cache, rather than using the individual 56 * cache line maintainence instructions. 57 */ 58#define CACHE_DLIMIT 65536 59 60 61 .text 62/* 63 * cpu_arm920_proc_init() 64 */ 65ENTRY(cpu_arm920_proc_init) 66 mov pc, lr 67 68/* 69 * cpu_arm920_proc_fin() 70 */ 71ENTRY(cpu_arm920_proc_fin) 72 stmfd sp!, {lr} 73 mov ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE 74 msr cpsr_c, ip 75#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH 76 bl arm920_flush_kern_cache_all 77#else 78 bl v4wt_flush_kern_cache_all 79#endif 80 mrc p15, 0, r0, c1, c0, 0 @ ctrl register 81 bic r0, r0, #0x1000 @ ...i............ 82 bic r0, r0, #0x000e @ ............wca. 83 mcr p15, 0, r0, c1, c0, 0 @ disable caches 84 ldmfd sp!, {pc} 85 86/* 87 * cpu_arm920_reset(loc) 88 * 89 * Perform a soft reset of the system. Put the CPU into the 90 * same state as it would be if it had been reset, and branch 91 * to what would be the reset vector. 92 * 93 * loc: location to jump to for soft reset 94 */ 95 .align 5 96ENTRY(cpu_arm920_reset) 97 mov ip, #0 98 mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches 99 mcr p15, 0, ip, c7, c10, 4 @ drain WB 100 mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs 101 mrc p15, 0, ip, c1, c0, 0 @ ctrl register 102 bic ip, ip, #0x000f @ ............wcam 103 bic ip, ip, #0x1100 @ ...i...s........ 104 mcr p15, 0, ip, c1, c0, 0 @ ctrl register 105 mov pc, r0 106 107/* 108 * cpu_arm920_do_idle() 109 */ 110 .align 5 111ENTRY(cpu_arm920_do_idle) 112 mcr p15, 0, r0, c7, c0, 4 @ Wait for interrupt 113 mov pc, lr 114 115 116#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH 117 118/* 119 * flush_user_cache_all() 120 * 121 * Invalidate all cache entries in a particular address 122 * space. 123 */ 124ENTRY(arm920_flush_user_cache_all) 125 /* FALLTHROUGH */ 126 127/* 128 * flush_kern_cache_all() 129 * 130 * Clean and invalidate the entire cache. 131 */ 132ENTRY(arm920_flush_kern_cache_all) 133 mov r2, #VM_EXEC 134 mov ip, #0 135__flush_whole_cache: 136 mov r1, #(CACHE_DSEGMENTS - 1) << 5 @ 8 segments 1371: orr r3, r1, #(CACHE_DENTRIES - 1) << 26 @ 64 entries 1382: mcr p15, 0, r3, c7, c14, 2 @ clean+invalidate D index 139 subs r3, r3, #1 << 26 140 bcs 2b @ entries 63 to 0 141 subs r1, r1, #1 << 5 142 bcs 1b @ segments 7 to 0 143 tst r2, #VM_EXEC 144 mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache 145 mcrne p15, 0, ip, c7, c10, 4 @ drain WB 146 mov pc, lr 147 148/* 149 * flush_user_cache_range(start, end, flags) 150 * 151 * Invalidate a range of cache entries in the specified 152 * address space. 153 * 154 * - start - start address (inclusive) 155 * - end - end address (exclusive) 156 * - flags - vm_flags for address space 157 */ 158ENTRY(arm920_flush_user_cache_range) 159 mov ip, #0 160 sub r3, r1, r0 @ calculate total size 161 cmp r3, #CACHE_DLIMIT 162 bhs __flush_whole_cache 163 1641: mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry 165 tst r2, #VM_EXEC 166 mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry 167 add r0, r0, #CACHE_DLINESIZE 168 cmp r0, r1 169 blo 1b 170 tst r2, #VM_EXEC 171 mcrne p15, 0, ip, c7, c10, 4 @ drain WB 172 mov pc, lr 173 174/* 175 * coherent_kern_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 */ 184ENTRY(arm920_coherent_kern_range) 185 /* FALLTHROUGH */ 186 187/* 188 * coherent_user_range(start, end) 189 * 190 * Ensure coherency between the Icache and the Dcache in the 191 * region described by start, end. If you have non-snooping 192 * Harvard caches, you need to implement this function. 193 * 194 * - start - virtual start address 195 * - end - virtual end address 196 */ 197ENTRY(arm920_coherent_user_range) 198 bic r0, r0, #CACHE_DLINESIZE - 1 1991: mcr p15, 0, r0, c7, c10, 1 @ clean D entry 200 mcr p15, 0, r0, c7, c5, 1 @ invalidate I entry 201 add r0, r0, #CACHE_DLINESIZE 202 cmp r0, r1 203 blo 1b 204 mcr p15, 0, r0, c7, c10, 4 @ drain WB 205 mov pc, lr 206 207/* 208 * flush_kern_dcache_page(void *page) 209 * 210 * Ensure no D cache aliasing occurs, either with itself or 211 * the I cache 212 * 213 * - addr - page aligned address 214 */ 215ENTRY(arm920_flush_kern_dcache_page) 216 add r1, r0, #PAGE_SZ 2171: mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry 218 add r0, r0, #CACHE_DLINESIZE 219 cmp r0, r1 220 blo 1b 221 mov r0, #0 222 mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache 223 mcr p15, 0, r0, c7, c10, 4 @ drain WB 224 mov pc, lr 225 226/* 227 * dma_inv_range(start, end) 228 * 229 * Invalidate (discard) the specified virtual address range. 230 * May not write back any entries. If 'start' or 'end' 231 * are not cache line aligned, those lines must be written 232 * back. 233 * 234 * - start - virtual start address 235 * - end - virtual end address 236 * 237 * (same as v4wb) 238 */ 239ENTRY(arm920_dma_inv_range) 240 tst r0, #CACHE_DLINESIZE - 1 241 bic r0, r0, #CACHE_DLINESIZE - 1 242 mcrne p15, 0, r0, c7, c10, 1 @ clean D entry 243 tst r1, #CACHE_DLINESIZE - 1 244 mcrne p15, 0, r1, c7, c10, 1 @ clean D entry 2451: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry 246 add r0, r0, #CACHE_DLINESIZE 247 cmp r0, r1 248 blo 1b 249 mcr p15, 0, r0, c7, c10, 4 @ drain WB 250 mov pc, lr 251 252/* 253 * dma_clean_range(start, end) 254 * 255 * Clean the specified virtual address range. 256 * 257 * - start - virtual start address 258 * - end - virtual end address 259 * 260 * (same as v4wb) 261 */ 262ENTRY(arm920_dma_clean_range) 263 bic r0, r0, #CACHE_DLINESIZE - 1 2641: mcr p15, 0, r0, c7, c10, 1 @ clean D entry 265 add r0, r0, #CACHE_DLINESIZE 266 cmp r0, r1 267 blo 1b 268 mcr p15, 0, r0, c7, c10, 4 @ drain WB 269 mov pc, lr 270 271/* 272 * dma_flush_range(start, end) 273 * 274 * Clean and invalidate the specified virtual address range. 275 * 276 * - start - virtual start address 277 * - end - virtual end address 278 */ 279ENTRY(arm920_dma_flush_range) 280 bic r0, r0, #CACHE_DLINESIZE - 1 2811: mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry 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 288ENTRY(arm920_cache_fns) 289 .long arm920_flush_kern_cache_all 290 .long arm920_flush_user_cache_all 291 .long arm920_flush_user_cache_range 292 .long arm920_coherent_kern_range 293 .long arm920_coherent_user_range 294 .long arm920_flush_kern_dcache_page 295 .long arm920_dma_inv_range 296 .long arm920_dma_clean_range 297 .long arm920_dma_flush_range 298 299#endif 300 301 302ENTRY(cpu_arm920_dcache_clean_area) 3031: mcr p15, 0, r0, c7, c10, 1 @ clean D entry 304 add r0, r0, #CACHE_DLINESIZE 305 subs r1, r1, #CACHE_DLINESIZE 306 bhi 1b 307 mov pc, lr 308 309/* =============================== PageTable ============================== */ 310 311/* 312 * cpu_arm920_switch_mm(pgd) 313 * 314 * Set the translation base pointer to be as described by pgd. 315 * 316 * pgd: new page tables 317 */ 318 .align 5 319ENTRY(cpu_arm920_switch_mm) 320 mov ip, #0 321#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH 322 mcr p15, 0, ip, c7, c6, 0 @ invalidate D cache 323#else 324@ && 'Clean & Invalidate whole DCache' 325@ && Re-written to use Index Ops. 326@ && Uses registers r1, r3 and ip 327 328 mov r1, #(CACHE_DSEGMENTS - 1) << 5 @ 8 segments 3291: orr r3, r1, #(CACHE_DENTRIES - 1) << 26 @ 64 entries 3302: mcr p15, 0, r3, c7, c14, 2 @ clean & invalidate D index 331 subs r3, r3, #1 << 26 332 bcs 2b @ entries 63 to 0 333 subs r1, r1, #1 << 5 334 bcs 1b @ segments 7 to 0 335#endif 336 mcr p15, 0, ip, c7, c5, 0 @ invalidate I cache 337 mcr p15, 0, ip, c7, c10, 4 @ drain WB 338 mcr p15, 0, r0, c2, c0, 0 @ load page table pointer 339 mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs 340 mov pc, lr 341 342/* 343 * cpu_arm920_set_pte(ptep, pte) 344 * 345 * Set a PTE and flush it out 346 */ 347 .align 5 348ENTRY(cpu_arm920_set_pte) 349 str r1, [r0], #-2048 @ linux version 350 351 eor r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY 352 353 bic r2, r1, #PTE_SMALL_AP_MASK 354 bic r2, r2, #PTE_TYPE_MASK 355 orr r2, r2, #PTE_TYPE_SMALL 356 357 tst r1, #L_PTE_USER @ User? 358 orrne r2, r2, #PTE_SMALL_AP_URO_SRW 359 360 tst r1, #L_PTE_WRITE | L_PTE_DIRTY @ Write and Dirty? 361 orreq r2, r2, #PTE_SMALL_AP_UNO_SRW 362 363 tst r1, #L_PTE_PRESENT | L_PTE_YOUNG @ Present and Young? 364 movne r2, #0 365 366#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH 367 eor r3, r2, #0x0a @ C & small page? 368 tst r3, #0x0b 369 biceq r2, r2, #4 370#endif 371 str r2, [r0] @ hardware version 372 mov r0, r0 373 mcr p15, 0, r0, c7, c10, 1 @ clean D entry 374 mcr p15, 0, r0, c7, c10, 4 @ drain WB 375 mov pc, lr 376 377 __INIT 378 379 .type __arm920_setup, #function 380__arm920_setup: 381 mov r0, #0 382 mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4 383 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4 384 mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4 385 mrc p15, 0, r0, c1, c0 @ get control register v4 386 ldr r5, arm920_cr1_clear 387 bic r0, r0, r5 388 ldr r5, arm920_cr1_set 389 orr r0, r0, r5 390 mov pc, lr 391 .size __arm920_setup, . - __arm920_setup 392 393 /* 394 * R 395 * .RVI ZFRS BLDP WCAM 396 * ..11 0001 ..11 0101 397 * 398 */ 399 .type arm920_cr1_clear, #object 400 .type arm920_cr1_set, #object 401arm920_cr1_clear: 402 .word 0x3f3f 403arm920_cr1_set: 404 .word 0x3135 405 406 __INITDATA 407 408/* 409 * Purpose : Function pointers used to access above functions - all calls 410 * come through these 411 */ 412 .type arm920_processor_functions, #object 413arm920_processor_functions: 414 .word v4t_early_abort 415 .word cpu_arm920_proc_init 416 .word cpu_arm920_proc_fin 417 .word cpu_arm920_reset 418 .word cpu_arm920_do_idle 419 .word cpu_arm920_dcache_clean_area 420 .word cpu_arm920_switch_mm 421 .word cpu_arm920_set_pte 422 .size arm920_processor_functions, . - arm920_processor_functions 423 424 .section ".rodata" 425 426 .type cpu_arch_name, #object 427cpu_arch_name: 428 .asciz "armv4t" 429 .size cpu_arch_name, . - cpu_arch_name 430 431 .type cpu_elf_name, #object 432cpu_elf_name: 433 .asciz "v4" 434 .size cpu_elf_name, . - cpu_elf_name 435 436 .type cpu_arm920_name, #object 437cpu_arm920_name: 438 .ascii "ARM920T" 439#ifndef CONFIG_CPU_ICACHE_DISABLE 440 .ascii "i" 441#endif 442#ifndef CONFIG_CPU_DCACHE_DISABLE 443 .ascii "d" 444#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH 445 .ascii "(wt)" 446#else 447 .ascii "(wb)" 448#endif 449#endif 450 .ascii "\0" 451 .size cpu_arm920_name, . - cpu_arm920_name 452 453 .align 454 455 .section ".proc.info.init", #alloc, #execinstr 456 457 .type __arm920_proc_info,#object 458__arm920_proc_info: 459 .long 0x41009200 460 .long 0xff00fff0 461 .long PMD_TYPE_SECT | \ 462 PMD_SECT_BUFFERABLE | \ 463 PMD_SECT_CACHEABLE | \ 464 PMD_BIT4 | \ 465 PMD_SECT_AP_WRITE | \ 466 PMD_SECT_AP_READ 467 b __arm920_setup 468 .long cpu_arch_name 469 .long cpu_elf_name 470 .long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB 471 .long cpu_arm920_name 472 .long arm920_processor_functions 473 .long v4wbi_tlb_fns 474 .long v4wb_user_fns 475#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH 476 .long arm920_cache_fns 477#else 478 .long v4wt_cache_fns 479#endif 480 .size __arm920_proc_info, . - __arm920_proc_info 481