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 .globl feroceon_flush_kern_cache_louis 419 .equ feroceon_flush_kern_cache_louis, feroceon_flush_kern_cache_all 420 421 @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S) 422 define_cache_functions feroceon 423 424.macro range_alias basename 425 .globl feroceon_range_\basename 426 .type feroceon_range_\basename , %function 427 .equ feroceon_range_\basename , feroceon_\basename 428.endm 429 430/* 431 * Most of the cache functions are unchanged for this case. 432 * Export suitable alias symbols for the unchanged functions: 433 */ 434 range_alias flush_icache_all 435 range_alias flush_user_cache_all 436 range_alias flush_kern_cache_all 437 range_alias flush_kern_cache_louis 438 range_alias flush_user_cache_range 439 range_alias coherent_kern_range 440 range_alias coherent_user_range 441 range_alias dma_unmap_area 442 443 define_cache_functions feroceon_range 444 445 .align 5 446ENTRY(cpu_feroceon_dcache_clean_area) 447#if defined(CONFIG_CACHE_FEROCEON_L2) && \ 448 !defined(CONFIG_CACHE_FEROCEON_L2_WRITETHROUGH) 449 mov r2, r0 450 mov r3, r1 451#endif 4521: mcr p15, 0, r0, c7, c10, 1 @ clean D entry 453 add r0, r0, #CACHE_DLINESIZE 454 subs r1, r1, #CACHE_DLINESIZE 455 bhi 1b 456#if defined(CONFIG_CACHE_FEROCEON_L2) && \ 457 !defined(CONFIG_CACHE_FEROCEON_L2_WRITETHROUGH) 4581: mcr p15, 1, r2, c15, c9, 1 @ clean L2 entry 459 add r2, r2, #CACHE_DLINESIZE 460 subs r3, r3, #CACHE_DLINESIZE 461 bhi 1b 462#endif 463 mcr p15, 0, r0, c7, c10, 4 @ drain WB 464 mov pc, lr 465 466/* =============================== PageTable ============================== */ 467 468/* 469 * cpu_feroceon_switch_mm(pgd) 470 * 471 * Set the translation base pointer to be as described by pgd. 472 * 473 * pgd: new page tables 474 */ 475 .align 5 476ENTRY(cpu_feroceon_switch_mm) 477#ifdef CONFIG_MMU 478 /* 479 * Note: we wish to call __flush_whole_cache but we need to preserve 480 * lr to do so. The only way without touching main memory is to 481 * use r2 which is normally used to test the VM_EXEC flag, and 482 * compensate locally for the skipped ops if it is not set. 483 */ 484 mov r2, lr @ abuse r2 to preserve lr 485 bl __flush_whole_cache 486 @ if r2 contains the VM_EXEC bit then the next 2 ops are done already 487 tst r2, #VM_EXEC 488 mcreq p15, 0, ip, c7, c5, 0 @ invalidate I cache 489 mcreq p15, 0, ip, c7, c10, 4 @ drain WB 490 491 mcr p15, 0, r0, c2, c0, 0 @ load page table pointer 492 mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs 493 mov pc, r2 494#else 495 mov pc, lr 496#endif 497 498/* 499 * cpu_feroceon_set_pte_ext(ptep, pte, ext) 500 * 501 * Set a PTE and flush it out 502 */ 503 .align 5 504ENTRY(cpu_feroceon_set_pte_ext) 505#ifdef CONFIG_MMU 506 armv3_set_pte_ext wc_disable=0 507 mov r0, r0 508 mcr p15, 0, r0, c7, c10, 1 @ clean D entry 509#if defined(CONFIG_CACHE_FEROCEON_L2) && \ 510 !defined(CONFIG_CACHE_FEROCEON_L2_WRITETHROUGH) 511 mcr p15, 1, r0, c15, c9, 1 @ clean L2 entry 512#endif 513 mcr p15, 0, r0, c7, c10, 4 @ drain WB 514#endif 515 mov pc, lr 516 517 __CPUINIT 518 519 .type __feroceon_setup, #function 520__feroceon_setup: 521 mov r0, #0 522 mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4 523 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4 524#ifdef CONFIG_MMU 525 mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4 526#endif 527 528 adr r5, feroceon_crval 529 ldmia r5, {r5, r6} 530 mrc p15, 0, r0, c1, c0 @ get control register v4 531 bic r0, r0, r5 532 orr r0, r0, r6 533 mov pc, lr 534 .size __feroceon_setup, . - __feroceon_setup 535 536 /* 537 * B 538 * R P 539 * .RVI UFRS BLDP WCAM 540 * .011 .001 ..11 0101 541 * 542 */ 543 .type feroceon_crval, #object 544feroceon_crval: 545 crval clear=0x0000773f, mmuset=0x00003135, ucset=0x00001134 546 547 __INITDATA 548 549 @ define struct processor (see <asm/proc-fns.h> and proc-macros.S) 550 define_processor_functions feroceon, dabort=v5t_early_abort, pabort=legacy_pabort 551 552 .section ".rodata" 553 554 string cpu_arch_name, "armv5te" 555 string cpu_elf_name, "v5" 556 string cpu_feroceon_name, "Feroceon" 557 string cpu_88fr531_name, "Feroceon 88FR531-vd" 558 string cpu_88fr571_name, "Feroceon 88FR571-vd" 559 string cpu_88fr131_name, "Feroceon 88FR131" 560 561 .align 562 563 .section ".proc.info.init", #alloc, #execinstr 564 565.macro feroceon_proc_info name:req, cpu_val:req, cpu_mask:req, cpu_name:req, cache:req 566 .type __\name\()_proc_info,#object 567__\name\()_proc_info: 568 .long \cpu_val 569 .long \cpu_mask 570 .long PMD_TYPE_SECT | \ 571 PMD_SECT_BUFFERABLE | \ 572 PMD_SECT_CACHEABLE | \ 573 PMD_BIT4 | \ 574 PMD_SECT_AP_WRITE | \ 575 PMD_SECT_AP_READ 576 .long PMD_TYPE_SECT | \ 577 PMD_BIT4 | \ 578 PMD_SECT_AP_WRITE | \ 579 PMD_SECT_AP_READ 580 b __feroceon_setup 581 .long cpu_arch_name 582 .long cpu_elf_name 583 .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP 584 .long \cpu_name 585 .long feroceon_processor_functions 586 .long v4wbi_tlb_fns 587 .long feroceon_user_fns 588 .long \cache 589 .size __\name\()_proc_info, . - __\name\()_proc_info 590.endm 591 592#ifdef CONFIG_CPU_FEROCEON_OLD_ID 593 feroceon_proc_info feroceon_old_id, 0x41009260, 0xff00fff0, \ 594 cpu_name=cpu_feroceon_name, cache=feroceon_cache_fns 595#endif 596 597 feroceon_proc_info 88fr531, 0x56055310, 0xfffffff0, cpu_88fr531_name, \ 598 cache=feroceon_cache_fns 599 feroceon_proc_info 88fr571, 0x56155710, 0xfffffff0, cpu_88fr571_name, \ 600 cache=feroceon_range_cache_fns 601 feroceon_proc_info 88fr131, 0x56251310, 0xfffffff0, cpu_88fr131_name, \ 602 cache=feroceon_range_cache_fns 603