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 r0, #0 236 mov pc, lr 237 238/* 239 * flush_kern_dcache_area(void *addr, size_t size) 240 * 241 * Ensure no D cache aliasing occurs, either with itself or 242 * the I cache 243 * 244 * - addr - kernel address 245 * - size - region size 246 */ 247 .align 5 248ENTRY(feroceon_flush_kern_dcache_area) 249 add r1, r0, r1 2501: mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry 251 add r0, r0, #CACHE_DLINESIZE 252 cmp r0, r1 253 blo 1b 254 mov r0, #0 255 mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache 256 mcr p15, 0, r0, c7, c10, 4 @ drain WB 257 mov pc, lr 258 259 .align 5 260ENTRY(feroceon_range_flush_kern_dcache_area) 261 mrs r2, cpsr 262 add r1, r0, #PAGE_SZ - CACHE_DLINESIZE @ top addr is inclusive 263 orr r3, r2, #PSR_I_BIT 264 msr cpsr_c, r3 @ disable interrupts 265 mcr p15, 5, r0, c15, c15, 0 @ D clean/inv range start 266 mcr p15, 5, r1, c15, c15, 1 @ D clean/inv range top 267 msr cpsr_c, r2 @ restore interrupts 268 mov r0, #0 269 mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache 270 mcr p15, 0, r0, c7, c10, 4 @ drain WB 271 mov pc, lr 272 273/* 274 * dma_inv_range(start, end) 275 * 276 * Invalidate (discard) the specified virtual address range. 277 * May not write back any entries. If 'start' or 'end' 278 * are not cache line aligned, those lines must be written 279 * back. 280 * 281 * - start - virtual start address 282 * - end - virtual end address 283 * 284 * (same as v4wb) 285 */ 286 .align 5 287feroceon_dma_inv_range: 288 tst r0, #CACHE_DLINESIZE - 1 289 bic r0, r0, #CACHE_DLINESIZE - 1 290 mcrne p15, 0, r0, c7, c10, 1 @ clean D entry 291 tst r1, #CACHE_DLINESIZE - 1 292 mcrne p15, 0, r1, c7, c10, 1 @ clean D entry 2931: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry 294 add r0, r0, #CACHE_DLINESIZE 295 cmp r0, r1 296 blo 1b 297 mcr p15, 0, r0, c7, c10, 4 @ drain WB 298 mov pc, lr 299 300 .align 5 301feroceon_range_dma_inv_range: 302 mrs r2, cpsr 303 tst r0, #CACHE_DLINESIZE - 1 304 mcrne p15, 0, r0, c7, c10, 1 @ clean D entry 305 tst r1, #CACHE_DLINESIZE - 1 306 mcrne p15, 0, r1, c7, c10, 1 @ clean D entry 307 cmp r1, r0 308 subne r1, r1, #1 @ top address is inclusive 309 orr r3, r2, #PSR_I_BIT 310 msr cpsr_c, r3 @ disable interrupts 311 mcr p15, 5, r0, c15, c14, 0 @ D inv range start 312 mcr p15, 5, r1, c15, c14, 1 @ D inv range top 313 msr cpsr_c, r2 @ restore interrupts 314 mov pc, lr 315 316/* 317 * dma_clean_range(start, end) 318 * 319 * Clean the specified virtual address range. 320 * 321 * - start - virtual start address 322 * - end - virtual end address 323 * 324 * (same as v4wb) 325 */ 326 .align 5 327feroceon_dma_clean_range: 328 bic r0, r0, #CACHE_DLINESIZE - 1 3291: mcr p15, 0, r0, c7, c10, 1 @ clean D entry 330 add r0, r0, #CACHE_DLINESIZE 331 cmp r0, r1 332 blo 1b 333 mcr p15, 0, r0, c7, c10, 4 @ drain WB 334 mov pc, lr 335 336 .align 5 337feroceon_range_dma_clean_range: 338 mrs r2, cpsr 339 cmp r1, r0 340 subne r1, r1, #1 @ top address is inclusive 341 orr r3, r2, #PSR_I_BIT 342 msr cpsr_c, r3 @ disable interrupts 343 mcr p15, 5, r0, c15, c13, 0 @ D clean range start 344 mcr p15, 5, r1, c15, c13, 1 @ D clean range top 345 msr cpsr_c, r2 @ restore interrupts 346 mcr p15, 0, r0, c7, c10, 4 @ drain WB 347 mov pc, lr 348 349/* 350 * dma_flush_range(start, end) 351 * 352 * Clean and invalidate the specified virtual address range. 353 * 354 * - start - virtual start address 355 * - end - virtual end address 356 */ 357 .align 5 358ENTRY(feroceon_dma_flush_range) 359 bic r0, r0, #CACHE_DLINESIZE - 1 3601: mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry 361 add r0, r0, #CACHE_DLINESIZE 362 cmp r0, r1 363 blo 1b 364 mcr p15, 0, r0, c7, c10, 4 @ drain WB 365 mov pc, lr 366 367 .align 5 368ENTRY(feroceon_range_dma_flush_range) 369 mrs r2, cpsr 370 cmp r1, r0 371 subne r1, r1, #1 @ top address is inclusive 372 orr r3, r2, #PSR_I_BIT 373 msr cpsr_c, r3 @ disable interrupts 374 mcr p15, 5, r0, c15, c15, 0 @ D clean/inv range start 375 mcr p15, 5, r1, c15, c15, 1 @ D clean/inv range top 376 msr cpsr_c, r2 @ restore interrupts 377 mcr p15, 0, r0, c7, c10, 4 @ drain WB 378 mov pc, lr 379 380/* 381 * dma_map_area(start, size, dir) 382 * - start - kernel virtual start address 383 * - size - size of region 384 * - dir - DMA direction 385 */ 386ENTRY(feroceon_dma_map_area) 387 add r1, r1, r0 388 cmp r2, #DMA_TO_DEVICE 389 beq feroceon_dma_clean_range 390 bcs feroceon_dma_inv_range 391 b feroceon_dma_flush_range 392ENDPROC(feroceon_dma_map_area) 393 394/* 395 * dma_map_area(start, size, dir) 396 * - start - kernel virtual start address 397 * - size - size of region 398 * - dir - DMA direction 399 */ 400ENTRY(feroceon_range_dma_map_area) 401 add r1, r1, r0 402 cmp r2, #DMA_TO_DEVICE 403 beq feroceon_range_dma_clean_range 404 bcs feroceon_range_dma_inv_range 405 b feroceon_range_dma_flush_range 406ENDPROC(feroceon_range_dma_map_area) 407 408/* 409 * dma_unmap_area(start, size, dir) 410 * - start - kernel virtual start address 411 * - size - size of region 412 * - dir - DMA direction 413 */ 414ENTRY(feroceon_dma_unmap_area) 415 mov pc, lr 416ENDPROC(feroceon_dma_unmap_area) 417 418 @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S) 419 define_cache_functions feroceon 420 421.macro range_alias basename 422 .globl feroceon_range_\basename 423 .type feroceon_range_\basename , %function 424 .equ feroceon_range_\basename , feroceon_\basename 425.endm 426 427/* 428 * Most of the cache functions are unchanged for this case. 429 * Export suitable alias symbols for the unchanged functions: 430 */ 431 range_alias flush_icache_all 432 range_alias flush_user_cache_all 433 range_alias flush_kern_cache_all 434 range_alias flush_user_cache_range 435 range_alias coherent_kern_range 436 range_alias coherent_user_range 437 range_alias dma_unmap_area 438 439 define_cache_functions feroceon_range 440 441 .align 5 442ENTRY(cpu_feroceon_dcache_clean_area) 443#if defined(CONFIG_CACHE_FEROCEON_L2) && \ 444 !defined(CONFIG_CACHE_FEROCEON_L2_WRITETHROUGH) 445 mov r2, r0 446 mov r3, r1 447#endif 4481: mcr p15, 0, r0, c7, c10, 1 @ clean D entry 449 add r0, r0, #CACHE_DLINESIZE 450 subs r1, r1, #CACHE_DLINESIZE 451 bhi 1b 452#if defined(CONFIG_CACHE_FEROCEON_L2) && \ 453 !defined(CONFIG_CACHE_FEROCEON_L2_WRITETHROUGH) 4541: mcr p15, 1, r2, c15, c9, 1 @ clean L2 entry 455 add r2, r2, #CACHE_DLINESIZE 456 subs r3, r3, #CACHE_DLINESIZE 457 bhi 1b 458#endif 459 mcr p15, 0, r0, c7, c10, 4 @ drain WB 460 mov pc, lr 461 462/* =============================== PageTable ============================== */ 463 464/* 465 * cpu_feroceon_switch_mm(pgd) 466 * 467 * Set the translation base pointer to be as described by pgd. 468 * 469 * pgd: new page tables 470 */ 471 .align 5 472ENTRY(cpu_feroceon_switch_mm) 473#ifdef CONFIG_MMU 474 /* 475 * Note: we wish to call __flush_whole_cache but we need to preserve 476 * lr to do so. The only way without touching main memory is to 477 * use r2 which is normally used to test the VM_EXEC flag, and 478 * compensate locally for the skipped ops if it is not set. 479 */ 480 mov r2, lr @ abuse r2 to preserve lr 481 bl __flush_whole_cache 482 @ if r2 contains the VM_EXEC bit then the next 2 ops are done already 483 tst r2, #VM_EXEC 484 mcreq p15, 0, ip, c7, c5, 0 @ invalidate I cache 485 mcreq p15, 0, ip, c7, c10, 4 @ drain WB 486 487 mcr p15, 0, r0, c2, c0, 0 @ load page table pointer 488 mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs 489 mov pc, r2 490#else 491 mov pc, lr 492#endif 493 494/* 495 * cpu_feroceon_set_pte_ext(ptep, pte, ext) 496 * 497 * Set a PTE and flush it out 498 */ 499 .align 5 500ENTRY(cpu_feroceon_set_pte_ext) 501#ifdef CONFIG_MMU 502 armv3_set_pte_ext wc_disable=0 503 mov r0, r0 504 mcr p15, 0, r0, c7, c10, 1 @ clean D entry 505#if defined(CONFIG_CACHE_FEROCEON_L2) && \ 506 !defined(CONFIG_CACHE_FEROCEON_L2_WRITETHROUGH) 507 mcr p15, 1, r0, c15, c9, 1 @ clean L2 entry 508#endif 509 mcr p15, 0, r0, c7, c10, 4 @ drain WB 510#endif 511 mov pc, lr 512 513 __CPUINIT 514 515 .type __feroceon_setup, #function 516__feroceon_setup: 517 mov r0, #0 518 mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4 519 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4 520#ifdef CONFIG_MMU 521 mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4 522#endif 523 524 adr r5, feroceon_crval 525 ldmia r5, {r5, r6} 526 mrc p15, 0, r0, c1, c0 @ get control register v4 527 bic r0, r0, r5 528 orr r0, r0, r6 529 mov pc, lr 530 .size __feroceon_setup, . - __feroceon_setup 531 532 /* 533 * B 534 * R P 535 * .RVI UFRS BLDP WCAM 536 * .011 .001 ..11 0101 537 * 538 */ 539 .type feroceon_crval, #object 540feroceon_crval: 541 crval clear=0x0000773f, mmuset=0x00003135, ucset=0x00001134 542 543 __INITDATA 544 545 @ define struct processor (see <asm/proc-fns.h> and proc-macros.S) 546 define_processor_functions feroceon, dabort=v5t_early_abort, pabort=legacy_pabort 547 548 .section ".rodata" 549 550 string cpu_arch_name, "armv5te" 551 string cpu_elf_name, "v5" 552 string cpu_feroceon_name, "Feroceon" 553 string cpu_88fr531_name, "Feroceon 88FR531-vd" 554 string cpu_88fr571_name, "Feroceon 88FR571-vd" 555 string cpu_88fr131_name, "Feroceon 88FR131" 556 557 .align 558 559 .section ".proc.info.init", #alloc, #execinstr 560 561.macro feroceon_proc_info name:req, cpu_val:req, cpu_mask:req, cpu_name:req, cache:req 562 .type __\name\()_proc_info,#object 563__\name\()_proc_info: 564 .long \cpu_val 565 .long \cpu_mask 566 .long PMD_TYPE_SECT | \ 567 PMD_SECT_BUFFERABLE | \ 568 PMD_SECT_CACHEABLE | \ 569 PMD_BIT4 | \ 570 PMD_SECT_AP_WRITE | \ 571 PMD_SECT_AP_READ 572 .long PMD_TYPE_SECT | \ 573 PMD_BIT4 | \ 574 PMD_SECT_AP_WRITE | \ 575 PMD_SECT_AP_READ 576 b __feroceon_setup 577 .long cpu_arch_name 578 .long cpu_elf_name 579 .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP 580 .long \cpu_name 581 .long feroceon_processor_functions 582 .long v4wbi_tlb_fns 583 .long feroceon_user_fns 584 .long \cache 585 .size __\name\()_proc_info, . - __\name\()_proc_info 586.endm 587 588#ifdef CONFIG_CPU_FEROCEON_OLD_ID 589 feroceon_proc_info feroceon_old_id, 0x41009260, 0xff00fff0, \ 590 cpu_name=cpu_feroceon_name, cache=feroceon_cache_fns 591#endif 592 593 feroceon_proc_info 88fr531, 0x56055310, 0xfffffff0, cpu_88fr531_name, \ 594 cache=feroceon_cache_fns 595 feroceon_proc_info 88fr571, 0x56155710, 0xfffffff0, cpu_88fr571_name, \ 596 cache=feroceon_range_cache_fns 597 feroceon_proc_info 88fr131, 0x56251310, 0xfffffff0, cpu_88fr131_name, \ 598 cache=feroceon_range_cache_fns 599