1/* 2 * linux/arch/arm/mm/proc-feroceon.S: MMU functions for Feroceon 3 * 4 * Heavily based on proc-arm926.S 5 * Maintainer: Assaf Hoffman <hoffman@marvell.com> 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#include <linux/linkage.h> 23#include <linux/init.h> 24#include <asm/assembler.h> 25#include <asm/hwcap.h> 26#include <asm/pgtable-hwdef.h> 27#include <asm/pgtable.h> 28#include <asm/page.h> 29#include <asm/ptrace.h> 30#include "proc-macros.S" 31 32/* 33 * This is the maximum size of an area which will be invalidated 34 * using the single invalidate entry instructions. Anything larger 35 * than this, and we go for the whole cache. 36 * 37 * This value should be chosen such that we choose the cheapest 38 * alternative. 39 */ 40#define CACHE_DLIMIT 16384 41 42/* 43 * the cache line size of the I and D cache 44 */ 45#define CACHE_DLINESIZE 32 46 47 .bss 48 .align 3 49__cache_params_loc: 50 .space 8 51 52 .text 53__cache_params: 54 .word __cache_params_loc 55 56/* 57 * cpu_feroceon_proc_init() 58 */ 59ENTRY(cpu_feroceon_proc_init) 60 mrc p15, 0, r0, c0, c0, 1 @ read cache type register 61 ldr r1, __cache_params 62 mov r2, #(16 << 5) 63 tst r0, #(1 << 16) @ get way 64 mov r0, r0, lsr #18 @ get cache size order 65 movne r3, #((4 - 1) << 30) @ 4-way 66 and r0, r0, #0xf 67 moveq r3, #0 @ 1-way 68 mov r2, r2, lsl r0 @ actual cache size 69 movne r2, r2, lsr #2 @ turned into # of sets 70 sub r2, r2, #(1 << 5) 71 stmia r1, {r2, r3} 72 mov pc, lr 73 74/* 75 * cpu_feroceon_proc_fin() 76 */ 77ENTRY(cpu_feroceon_proc_fin) 78#if defined(CONFIG_CACHE_FEROCEON_L2) && \ 79 !defined(CONFIG_CACHE_FEROCEON_L2_WRITETHROUGH) 80 mov r0, #0 81 mcr p15, 1, r0, c15, c9, 0 @ clean L2 82 mcr p15, 0, r0, c7, c10, 4 @ drain WB 83#endif 84 85 mrc p15, 0, r0, c1, c0, 0 @ ctrl register 86 bic r0, r0, #0x1000 @ ...i............ 87 bic r0, r0, #0x000e @ ............wca. 88 mcr p15, 0, r0, c1, c0, 0 @ disable caches 89 mov pc, lr 90 91/* 92 * cpu_feroceon_reset(loc) 93 * 94 * Perform a soft reset of the system. Put the CPU into the 95 * same state as it would be if it had been reset, and branch 96 * to what would be the reset vector. 97 * 98 * loc: location to jump to for soft reset 99 */ 100 .align 5 101 .pushsection .idmap.text, "ax" 102ENTRY(cpu_feroceon_reset) 103 mov ip, #0 104 mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches 105 mcr p15, 0, ip, c7, c10, 4 @ drain WB 106#ifdef CONFIG_MMU 107 mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs 108#endif 109 mrc p15, 0, ip, c1, c0, 0 @ ctrl register 110 bic ip, ip, #0x000f @ ............wcam 111 bic ip, ip, #0x1100 @ ...i...s........ 112 mcr p15, 0, ip, c1, c0, 0 @ ctrl register 113 mov pc, r0 114ENDPROC(cpu_feroceon_reset) 115 .popsection 116 117/* 118 * cpu_feroceon_do_idle() 119 * 120 * Called with IRQs disabled 121 */ 122 .align 5 123ENTRY(cpu_feroceon_do_idle) 124 mov r0, #0 125 mcr p15, 0, r0, c7, c10, 4 @ Drain write buffer 126 mcr p15, 0, r0, c7, c0, 4 @ Wait for interrupt 127 mov pc, lr 128 129/* 130 * flush_icache_all() 131 * 132 * Unconditionally clean and invalidate the entire icache. 133 */ 134ENTRY(feroceon_flush_icache_all) 135 mov r0, #0 136 mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache 137 mov pc, lr 138ENDPROC(feroceon_flush_icache_all) 139 140/* 141 * flush_user_cache_all() 142 * 143 * Clean and invalidate all cache entries in a particular 144 * address space. 145 */ 146 .align 5 147ENTRY(feroceon_flush_user_cache_all) 148 /* FALLTHROUGH */ 149 150/* 151 * flush_kern_cache_all() 152 * 153 * Clean and invalidate the entire cache. 154 */ 155ENTRY(feroceon_flush_kern_cache_all) 156 mov r2, #VM_EXEC 157 158__flush_whole_cache: 159 ldr r1, __cache_params 160 ldmia r1, {r1, r3} 1611: orr ip, r1, r3 1622: mcr p15, 0, ip, c7, c14, 2 @ clean + invalidate D set/way 163 subs ip, ip, #(1 << 30) @ next way 164 bcs 2b 165 subs r1, r1, #(1 << 5) @ next set 166 bcs 1b 167 168 tst r2, #VM_EXEC 169 mov ip, #0 170 mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache 171 mcrne p15, 0, ip, c7, c10, 4 @ drain WB 172 mov pc, lr 173 174/* 175 * flush_user_cache_range(start, end, flags) 176 * 177 * Clean and invalidate a range of cache entries in the 178 * specified address range. 179 * 180 * - start - start address (inclusive) 181 * - end - end address (exclusive) 182 * - flags - vm_flags describing address space 183 */ 184 .align 5 185ENTRY(feroceon_flush_user_cache_range) 186 sub r3, r1, r0 @ calculate total size 187 cmp r3, #CACHE_DLIMIT 188 bgt __flush_whole_cache 1891: tst r2, #VM_EXEC 190 mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry 191 mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry 192 add r0, r0, #CACHE_DLINESIZE 193 mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry 194 mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry 195 add r0, r0, #CACHE_DLINESIZE 196 cmp r0, r1 197 blo 1b 198 tst r2, #VM_EXEC 199 mov ip, #0 200 mcrne p15, 0, ip, c7, c10, 4 @ drain WB 201 mov pc, lr 202 203/* 204 * coherent_kern_range(start, end) 205 * 206 * Ensure coherency between the Icache and the Dcache in the 207 * region described by start, end. If you have non-snooping 208 * Harvard caches, you need to implement this function. 209 * 210 * - start - virtual start address 211 * - end - virtual end address 212 */ 213 .align 5 214ENTRY(feroceon_coherent_kern_range) 215 /* FALLTHROUGH */ 216 217/* 218 * coherent_user_range(start, end) 219 * 220 * Ensure coherency between the Icache and the Dcache in the 221 * region described by start, end. If you have non-snooping 222 * Harvard caches, you need to implement this function. 223 * 224 * - start - virtual start address 225 * - end - virtual end address 226 */ 227ENTRY(feroceon_coherent_user_range) 228 bic r0, r0, #CACHE_DLINESIZE - 1 2291: mcr p15, 0, r0, c7, c10, 1 @ clean D entry 230 mcr p15, 0, r0, c7, c5, 1 @ invalidate I entry 231 add r0, r0, #CACHE_DLINESIZE 232 cmp r0, r1 233 blo 1b 234 mcr p15, 0, r0, c7, c10, 4 @ drain WB 235 mov pc, lr 236 237/* 238 * flush_kern_dcache_area(void *addr, size_t size) 239 * 240 * Ensure no D cache aliasing occurs, either with itself or 241 * the I cache 242 * 243 * - addr - kernel address 244 * - size - region size 245 */ 246 .align 5 247ENTRY(feroceon_flush_kern_dcache_area) 248 add r1, r0, r1 2491: mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry 250 add r0, r0, #CACHE_DLINESIZE 251 cmp r0, r1 252 blo 1b 253 mov r0, #0 254 mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache 255 mcr p15, 0, r0, c7, c10, 4 @ drain WB 256 mov pc, lr 257 258 .align 5 259ENTRY(feroceon_range_flush_kern_dcache_area) 260 mrs r2, cpsr 261 add r1, r0, #PAGE_SZ - CACHE_DLINESIZE @ top addr is inclusive 262 orr r3, r2, #PSR_I_BIT 263 msr cpsr_c, r3 @ disable interrupts 264 mcr p15, 5, r0, c15, c15, 0 @ D clean/inv range start 265 mcr p15, 5, r1, c15, c15, 1 @ D clean/inv range top 266 msr cpsr_c, r2 @ restore interrupts 267 mov r0, #0 268 mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache 269 mcr p15, 0, r0, c7, c10, 4 @ drain WB 270 mov pc, lr 271 272/* 273 * dma_inv_range(start, end) 274 * 275 * Invalidate (discard) the specified virtual address range. 276 * May not write back any entries. If 'start' or 'end' 277 * are not cache line aligned, those lines must be written 278 * back. 279 * 280 * - start - virtual start address 281 * - end - virtual end address 282 * 283 * (same as v4wb) 284 */ 285 .align 5 286feroceon_dma_inv_range: 287 tst r0, #CACHE_DLINESIZE - 1 288 bic r0, r0, #CACHE_DLINESIZE - 1 289 mcrne p15, 0, r0, c7, c10, 1 @ clean D entry 290 tst r1, #CACHE_DLINESIZE - 1 291 mcrne p15, 0, r1, c7, c10, 1 @ clean D entry 2921: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry 293 add r0, r0, #CACHE_DLINESIZE 294 cmp r0, r1 295 blo 1b 296 mcr p15, 0, r0, c7, c10, 4 @ drain WB 297 mov pc, lr 298 299 .align 5 300feroceon_range_dma_inv_range: 301 mrs r2, cpsr 302 tst r0, #CACHE_DLINESIZE - 1 303 mcrne p15, 0, r0, c7, c10, 1 @ clean D entry 304 tst r1, #CACHE_DLINESIZE - 1 305 mcrne p15, 0, r1, c7, c10, 1 @ clean D entry 306 cmp r1, r0 307 subne r1, r1, #1 @ top address is inclusive 308 orr r3, r2, #PSR_I_BIT 309 msr cpsr_c, r3 @ disable interrupts 310 mcr p15, 5, r0, c15, c14, 0 @ D inv range start 311 mcr p15, 5, r1, c15, c14, 1 @ D inv range top 312 msr cpsr_c, r2 @ restore interrupts 313 mov pc, lr 314 315/* 316 * dma_clean_range(start, end) 317 * 318 * Clean the specified virtual address range. 319 * 320 * - start - virtual start address 321 * - end - virtual end address 322 * 323 * (same as v4wb) 324 */ 325 .align 5 326feroceon_dma_clean_range: 327 bic r0, r0, #CACHE_DLINESIZE - 1 3281: mcr p15, 0, r0, c7, c10, 1 @ clean D entry 329 add r0, r0, #CACHE_DLINESIZE 330 cmp r0, r1 331 blo 1b 332 mcr p15, 0, r0, c7, c10, 4 @ drain WB 333 mov pc, lr 334 335 .align 5 336feroceon_range_dma_clean_range: 337 mrs r2, cpsr 338 cmp r1, r0 339 subne r1, r1, #1 @ top address is inclusive 340 orr r3, r2, #PSR_I_BIT 341 msr cpsr_c, r3 @ disable interrupts 342 mcr p15, 5, r0, c15, c13, 0 @ D clean range start 343 mcr p15, 5, r1, c15, c13, 1 @ D clean range top 344 msr cpsr_c, r2 @ restore interrupts 345 mcr p15, 0, r0, c7, c10, 4 @ drain WB 346 mov pc, lr 347 348/* 349 * dma_flush_range(start, end) 350 * 351 * Clean and invalidate the specified virtual address range. 352 * 353 * - start - virtual start address 354 * - end - virtual end address 355 */ 356 .align 5 357ENTRY(feroceon_dma_flush_range) 358 bic r0, r0, #CACHE_DLINESIZE - 1 3591: mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry 360 add r0, r0, #CACHE_DLINESIZE 361 cmp r0, r1 362 blo 1b 363 mcr p15, 0, r0, c7, c10, 4 @ drain WB 364 mov pc, lr 365 366 .align 5 367ENTRY(feroceon_range_dma_flush_range) 368 mrs r2, cpsr 369 cmp r1, r0 370 subne r1, r1, #1 @ top address is inclusive 371 orr r3, r2, #PSR_I_BIT 372 msr cpsr_c, r3 @ disable interrupts 373 mcr p15, 5, r0, c15, c15, 0 @ D clean/inv range start 374 mcr p15, 5, r1, c15, c15, 1 @ D clean/inv range top 375 msr cpsr_c, r2 @ restore interrupts 376 mcr p15, 0, r0, c7, c10, 4 @ drain WB 377 mov pc, lr 378 379/* 380 * dma_map_area(start, size, dir) 381 * - start - kernel virtual start address 382 * - size - size of region 383 * - dir - DMA direction 384 */ 385ENTRY(feroceon_dma_map_area) 386 add r1, r1, r0 387 cmp r2, #DMA_TO_DEVICE 388 beq feroceon_dma_clean_range 389 bcs feroceon_dma_inv_range 390 b feroceon_dma_flush_range 391ENDPROC(feroceon_dma_map_area) 392 393/* 394 * dma_map_area(start, size, dir) 395 * - start - kernel virtual start address 396 * - size - size of region 397 * - dir - DMA direction 398 */ 399ENTRY(feroceon_range_dma_map_area) 400 add r1, r1, r0 401 cmp r2, #DMA_TO_DEVICE 402 beq feroceon_range_dma_clean_range 403 bcs feroceon_range_dma_inv_range 404 b feroceon_range_dma_flush_range 405ENDPROC(feroceon_range_dma_map_area) 406 407/* 408 * dma_unmap_area(start, size, dir) 409 * - start - kernel virtual start address 410 * - size - size of region 411 * - dir - DMA direction 412 */ 413ENTRY(feroceon_dma_unmap_area) 414 mov pc, lr 415ENDPROC(feroceon_dma_unmap_area) 416 417 @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S) 418 define_cache_functions feroceon 419 420.macro range_alias basename 421 .globl feroceon_range_\basename 422 .type feroceon_range_\basename , %function 423 .equ feroceon_range_\basename , feroceon_\basename 424.endm 425 426/* 427 * Most of the cache functions are unchanged for this case. 428 * Export suitable alias symbols for the unchanged functions: 429 */ 430 range_alias flush_icache_all 431 range_alias flush_user_cache_all 432 range_alias flush_kern_cache_all 433 range_alias flush_user_cache_range 434 range_alias coherent_kern_range 435 range_alias coherent_user_range 436 range_alias dma_unmap_area 437 438 define_cache_functions feroceon_range 439 440 .align 5 441ENTRY(cpu_feroceon_dcache_clean_area) 442#if defined(CONFIG_CACHE_FEROCEON_L2) && \ 443 !defined(CONFIG_CACHE_FEROCEON_L2_WRITETHROUGH) 444 mov r2, r0 445 mov r3, r1 446#endif 4471: mcr p15, 0, r0, c7, c10, 1 @ clean D entry 448 add r0, r0, #CACHE_DLINESIZE 449 subs r1, r1, #CACHE_DLINESIZE 450 bhi 1b 451#if defined(CONFIG_CACHE_FEROCEON_L2) && \ 452 !defined(CONFIG_CACHE_FEROCEON_L2_WRITETHROUGH) 4531: mcr p15, 1, r2, c15, c9, 1 @ clean L2 entry 454 add r2, r2, #CACHE_DLINESIZE 455 subs r3, r3, #CACHE_DLINESIZE 456 bhi 1b 457#endif 458 mcr p15, 0, r0, c7, c10, 4 @ drain WB 459 mov pc, lr 460 461/* =============================== PageTable ============================== */ 462 463/* 464 * cpu_feroceon_switch_mm(pgd) 465 * 466 * Set the translation base pointer to be as described by pgd. 467 * 468 * pgd: new page tables 469 */ 470 .align 5 471ENTRY(cpu_feroceon_switch_mm) 472#ifdef CONFIG_MMU 473 /* 474 * Note: we wish to call __flush_whole_cache but we need to preserve 475 * lr to do so. The only way without touching main memory is to 476 * use r2 which is normally used to test the VM_EXEC flag, and 477 * compensate locally for the skipped ops if it is not set. 478 */ 479 mov r2, lr @ abuse r2 to preserve lr 480 bl __flush_whole_cache 481 @ if r2 contains the VM_EXEC bit then the next 2 ops are done already 482 tst r2, #VM_EXEC 483 mcreq p15, 0, ip, c7, c5, 0 @ invalidate I cache 484 mcreq p15, 0, ip, c7, c10, 4 @ drain WB 485 486 mcr p15, 0, r0, c2, c0, 0 @ load page table pointer 487 mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs 488 mov pc, r2 489#else 490 mov pc, lr 491#endif 492 493/* 494 * cpu_feroceon_set_pte_ext(ptep, pte, ext) 495 * 496 * Set a PTE and flush it out 497 */ 498 .align 5 499ENTRY(cpu_feroceon_set_pte_ext) 500#ifdef CONFIG_MMU 501 armv3_set_pte_ext wc_disable=0 502 mov r0, r0 503 mcr p15, 0, r0, c7, c10, 1 @ clean D entry 504#if defined(CONFIG_CACHE_FEROCEON_L2) && \ 505 !defined(CONFIG_CACHE_FEROCEON_L2_WRITETHROUGH) 506 mcr p15, 1, r0, c15, c9, 1 @ clean L2 entry 507#endif 508 mcr p15, 0, r0, c7, c10, 4 @ drain WB 509#endif 510 mov pc, lr 511 512 __CPUINIT 513 514 .type __feroceon_setup, #function 515__feroceon_setup: 516 mov r0, #0 517 mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4 518 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4 519#ifdef CONFIG_MMU 520 mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4 521#endif 522 523 adr r5, feroceon_crval 524 ldmia r5, {r5, r6} 525 mrc p15, 0, r0, c1, c0 @ get control register v4 526 bic r0, r0, r5 527 orr r0, r0, r6 528 mov pc, lr 529 .size __feroceon_setup, . - __feroceon_setup 530 531 /* 532 * B 533 * R P 534 * .RVI UFRS BLDP WCAM 535 * .011 .001 ..11 0101 536 * 537 */ 538 .type feroceon_crval, #object 539feroceon_crval: 540 crval clear=0x0000773f, mmuset=0x00003135, ucset=0x00001134 541 542 __INITDATA 543 544 @ define struct processor (see <asm/proc-fns.h> and proc-macros.S) 545 define_processor_functions feroceon, dabort=v5t_early_abort, pabort=legacy_pabort 546 547 .section ".rodata" 548 549 string cpu_arch_name, "armv5te" 550 string cpu_elf_name, "v5" 551 string cpu_feroceon_name, "Feroceon" 552 string cpu_88fr531_name, "Feroceon 88FR531-vd" 553 string cpu_88fr571_name, "Feroceon 88FR571-vd" 554 string cpu_88fr131_name, "Feroceon 88FR131" 555 556 .align 557 558 .section ".proc.info.init", #alloc, #execinstr 559 560.macro feroceon_proc_info name:req, cpu_val:req, cpu_mask:req, cpu_name:req, cache:req 561 .type __\name\()_proc_info,#object 562__\name\()_proc_info: 563 .long \cpu_val 564 .long \cpu_mask 565 .long PMD_TYPE_SECT | \ 566 PMD_SECT_BUFFERABLE | \ 567 PMD_SECT_CACHEABLE | \ 568 PMD_BIT4 | \ 569 PMD_SECT_AP_WRITE | \ 570 PMD_SECT_AP_READ 571 .long PMD_TYPE_SECT | \ 572 PMD_BIT4 | \ 573 PMD_SECT_AP_WRITE | \ 574 PMD_SECT_AP_READ 575 b __feroceon_setup 576 .long cpu_arch_name 577 .long cpu_elf_name 578 .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP 579 .long \cpu_name 580 .long feroceon_processor_functions 581 .long v4wbi_tlb_fns 582 .long feroceon_user_fns 583 .long \cache 584 .size __\name\()_proc_info, . - __\name\()_proc_info 585.endm 586 587#ifdef CONFIG_CPU_FEROCEON_OLD_ID 588 feroceon_proc_info feroceon_old_id, 0x41009260, 0xff00fff0, \ 589 cpu_name=cpu_feroceon_name, cache=feroceon_cache_fns 590#endif 591 592 feroceon_proc_info 88fr531, 0x56055310, 0xfffffff0, cpu_88fr531_name, \ 593 cache=feroceon_cache_fns 594 feroceon_proc_info 88fr571, 0x56155710, 0xfffffff0, cpu_88fr571_name, \ 595 cache=feroceon_range_cache_fns 596 feroceon_proc_info 88fr131, 0x56251310, 0xfffffff0, cpu_88fr131_name, \ 597 cache=feroceon_range_cache_fns 598