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/elf.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 .text 48/* 49 * cpu_feroceon_proc_init() 50 */ 51ENTRY(cpu_feroceon_proc_init) 52 mov pc, lr 53 54/* 55 * cpu_feroceon_proc_fin() 56 */ 57ENTRY(cpu_feroceon_proc_fin) 58 stmfd sp!, {lr} 59 mov ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE 60 msr cpsr_c, ip 61 bl feroceon_flush_kern_cache_all 62 mrc p15, 0, r0, c1, c0, 0 @ ctrl register 63 bic r0, r0, #0x1000 @ ...i............ 64 bic r0, r0, #0x000e @ ............wca. 65 mcr p15, 0, r0, c1, c0, 0 @ disable caches 66 ldmfd sp!, {pc} 67 68/* 69 * cpu_feroceon_reset(loc) 70 * 71 * Perform a soft reset of the system. Put the CPU into the 72 * same state as it would be if it had been reset, and branch 73 * to what would be the reset vector. 74 * 75 * loc: location to jump to for soft reset 76 */ 77 .align 5 78ENTRY(cpu_feroceon_reset) 79 mov ip, #0 80 mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches 81 mcr p15, 0, ip, c7, c10, 4 @ drain WB 82#ifdef CONFIG_MMU 83 mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs 84#endif 85 mrc p15, 0, ip, c1, c0, 0 @ ctrl register 86 bic ip, ip, #0x000f @ ............wcam 87 bic ip, ip, #0x1100 @ ...i...s........ 88 mcr p15, 0, ip, c1, c0, 0 @ ctrl register 89 mov pc, r0 90 91/* 92 * cpu_feroceon_do_idle() 93 * 94 * Called with IRQs disabled 95 */ 96 .align 10 97ENTRY(cpu_feroceon_do_idle) 98 mov r0, #0 99 mcr p15, 0, r0, c7, c10, 4 @ Drain write buffer 100 mcr p15, 0, r0, c7, c0, 4 @ Wait for interrupt 101 mov pc, lr 102 103/* 104 * flush_user_cache_all() 105 * 106 * Clean and invalidate all cache entries in a particular 107 * address space. 108 */ 109ENTRY(feroceon_flush_user_cache_all) 110 /* FALLTHROUGH */ 111 112/* 113 * flush_kern_cache_all() 114 * 115 * Clean and invalidate the entire cache. 116 */ 117ENTRY(feroceon_flush_kern_cache_all) 118 mov r2, #VM_EXEC 119 mov ip, #0 120__flush_whole_cache: 121#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH 122 mcr p15, 0, ip, c7, c6, 0 @ invalidate D cache 123#else 1241: mrc p15, 0, r15, c7, c14, 3 @ test,clean,invalidate 125 bne 1b 126#endif 127 tst r2, #VM_EXEC 128 mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache 129 mcrne p15, 0, ip, c7, c10, 4 @ drain WB 130 mov pc, lr 131 132/* 133 * flush_user_cache_range(start, end, flags) 134 * 135 * Clean and invalidate a range of cache entries in the 136 * specified address range. 137 * 138 * - start - start address (inclusive) 139 * - end - end address (exclusive) 140 * - flags - vm_flags describing address space 141 */ 142ENTRY(feroceon_flush_user_cache_range) 143 mov ip, #0 144 sub r3, r1, r0 @ calculate total size 145 cmp r3, #CACHE_DLIMIT 146 bgt __flush_whole_cache 1471: tst r2, #VM_EXEC 148#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH 149 mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry 150 mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry 151 add r0, r0, #CACHE_DLINESIZE 152 mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry 153 mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry 154 add r0, r0, #CACHE_DLINESIZE 155#else 156 mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry 157 mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry 158 add r0, r0, #CACHE_DLINESIZE 159 mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry 160 mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry 161 add r0, r0, #CACHE_DLINESIZE 162#endif 163 cmp r0, r1 164 blo 1b 165 tst r2, #VM_EXEC 166 mcrne p15, 0, ip, c7, c10, 4 @ drain WB 167 mov pc, lr 168 169/* 170 * coherent_kern_range(start, end) 171 * 172 * Ensure coherency between the Icache and the Dcache in the 173 * region described by start, end. If you have non-snooping 174 * Harvard caches, you need to implement this function. 175 * 176 * - start - virtual start address 177 * - end - virtual end address 178 */ 179ENTRY(feroceon_coherent_kern_range) 180 /* FALLTHROUGH */ 181 182/* 183 * coherent_user_range(start, end) 184 * 185 * Ensure coherency between the Icache and the Dcache in the 186 * region described by start, end. If you have non-snooping 187 * Harvard caches, you need to implement this function. 188 * 189 * - start - virtual start address 190 * - end - virtual end address 191 */ 192ENTRY(feroceon_coherent_user_range) 193 bic r0, r0, #CACHE_DLINESIZE - 1 1941: mcr p15, 0, r0, c7, c10, 1 @ clean D entry 195 mcr p15, 0, r0, c7, c5, 1 @ invalidate I entry 196 add r0, r0, #CACHE_DLINESIZE 197 cmp r0, r1 198 blo 1b 199 mcr p15, 0, r0, c7, c10, 4 @ drain WB 200 mov pc, lr 201 202/* 203 * flush_kern_dcache_page(void *page) 204 * 205 * Ensure no D cache aliasing occurs, either with itself or 206 * the I cache 207 * 208 * - addr - page aligned address 209 */ 210ENTRY(feroceon_flush_kern_dcache_page) 211 add r1, r0, #PAGE_SZ 2121: mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry 213 add r0, r0, #CACHE_DLINESIZE 214 cmp r0, r1 215 blo 1b 216 mov r0, #0 217 mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache 218 mcr p15, 0, r0, c7, c10, 4 @ drain WB 219 mov pc, lr 220 221/* 222 * dma_inv_range(start, end) 223 * 224 * Invalidate (discard) the specified virtual address range. 225 * May not write back any entries. If 'start' or 'end' 226 * are not cache line aligned, those lines must be written 227 * back. 228 * 229 * - start - virtual start address 230 * - end - virtual end address 231 * 232 * (same as v4wb) 233 */ 234ENTRY(feroceon_dma_inv_range) 235#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH 236 tst r0, #CACHE_DLINESIZE - 1 237 mcrne p15, 0, r0, c7, c10, 1 @ clean D entry 238 tst r1, #CACHE_DLINESIZE - 1 239 mcrne p15, 0, r1, c7, c10, 1 @ clean D entry 240#endif 241 bic r0, r0, #CACHE_DLINESIZE - 1 2421: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry 243 add r0, r0, #CACHE_DLINESIZE 244 cmp r0, r1 245 blo 1b 246 mcr p15, 0, r0, c7, c10, 4 @ drain WB 247 mov pc, lr 248 249/* 250 * dma_clean_range(start, end) 251 * 252 * Clean the specified virtual address range. 253 * 254 * - start - virtual start address 255 * - end - virtual end address 256 * 257 * (same as v4wb) 258 */ 259ENTRY(feroceon_dma_clean_range) 260#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH 261 bic r0, r0, #CACHE_DLINESIZE - 1 2621: mcr p15, 0, r0, c7, c10, 1 @ clean D entry 263 add r0, r0, #CACHE_DLINESIZE 264 cmp r0, r1 265 blo 1b 266#endif 267 mcr p15, 0, r0, c7, c10, 4 @ drain WB 268 mov pc, lr 269 270/* 271 * dma_flush_range(start, end) 272 * 273 * Clean and invalidate the specified virtual address range. 274 * 275 * - start - virtual start address 276 * - end - virtual end address 277 */ 278ENTRY(feroceon_dma_flush_range) 279 bic r0, r0, #CACHE_DLINESIZE - 1 2801: 281#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH 282 mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry 283#else 284 mcr p15, 0, r0, c7, c10, 1 @ clean D entry 285#endif 286 add r0, r0, #CACHE_DLINESIZE 287 cmp r0, r1 288 blo 1b 289 mcr p15, 0, r0, c7, c10, 4 @ drain WB 290 mov pc, lr 291 292ENTRY(feroceon_cache_fns) 293 .long feroceon_flush_kern_cache_all 294 .long feroceon_flush_user_cache_all 295 .long feroceon_flush_user_cache_range 296 .long feroceon_coherent_kern_range 297 .long feroceon_coherent_user_range 298 .long feroceon_flush_kern_dcache_page 299 .long feroceon_dma_inv_range 300 .long feroceon_dma_clean_range 301 .long feroceon_dma_flush_range 302 303ENTRY(cpu_feroceon_dcache_clean_area) 304#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH 3051: mcr p15, 0, r0, c7, c10, 1 @ clean D entry 306 add r0, r0, #CACHE_DLINESIZE 307 subs r1, r1, #CACHE_DLINESIZE 308 bhi 1b 309#endif 310 mcr p15, 0, r0, c7, c10, 4 @ drain WB 311 mov pc, lr 312 313/* =============================== PageTable ============================== */ 314 315/* 316 * cpu_feroceon_switch_mm(pgd) 317 * 318 * Set the translation base pointer to be as described by pgd. 319 * 320 * pgd: new page tables 321 */ 322 .align 5 323ENTRY(cpu_feroceon_switch_mm) 324#ifdef CONFIG_MMU 325 mov ip, #0 326#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH 327 mcr p15, 0, ip, c7, c6, 0 @ invalidate D cache 328#else 329@ && 'Clean & Invalidate whole DCache' 3301: mrc p15, 0, r15, c7, c14, 3 @ test,clean,invalidate 331 bne 1b 332#endif 333 mcr p15, 0, ip, c7, c5, 0 @ invalidate I cache 334 mcr p15, 0, ip, c7, c10, 4 @ drain WB 335 mcr p15, 0, r0, c2, c0, 0 @ load page table pointer 336 mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs 337#endif 338 mov pc, lr 339 340/* 341 * cpu_feroceon_set_pte_ext(ptep, pte, ext) 342 * 343 * Set a PTE and flush it out 344 */ 345 .align 5 346ENTRY(cpu_feroceon_set_pte_ext) 347#ifdef CONFIG_MMU 348 str r1, [r0], #-2048 @ linux version 349 350 eor r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY 351 352 bic r2, r1, #PTE_SMALL_AP_MASK 353 bic r2, r2, #PTE_TYPE_MASK 354 orr r2, r2, #PTE_TYPE_SMALL 355 356 tst r1, #L_PTE_USER @ User? 357 orrne r2, r2, #PTE_SMALL_AP_URO_SRW 358 359 tst r1, #L_PTE_WRITE | L_PTE_DIRTY @ Write and Dirty? 360 orreq r2, r2, #PTE_SMALL_AP_UNO_SRW 361 362 tst r1, #L_PTE_PRESENT | L_PTE_YOUNG @ Present and Young? 363 movne r2, #0 364 365#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH 366 eor r3, r2, #0x0a @ C & small page? 367 tst r3, #0x0b 368 biceq r2, r2, #4 369#endif 370 str r2, [r0] @ hardware version 371 mov r0, r0 372#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH 373 mcr p15, 0, r0, c7, c10, 1 @ clean D entry 374#endif 375 mcr p15, 0, r0, c7, c10, 4 @ drain WB 376#endif 377 mov pc, lr 378 379 __INIT 380 381 .type __feroceon_setup, #function 382__feroceon_setup: 383 mov r0, #0 384 mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4 385 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4 386#ifdef CONFIG_MMU 387 mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4 388#endif 389 390 391#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH 392 mov r0, #4 @ disable write-back on caches explicitly 393 mcr p15, 7, r0, c15, c0, 0 394#endif 395 396 adr r5, feroceon_crval 397 ldmia r5, {r5, r6} 398 mrc p15, 0, r0, c1, c0 @ get control register v4 399 bic r0, r0, r5 400 orr r0, r0, r6 401#ifdef CONFIG_CPU_CACHE_ROUND_ROBIN 402 orr r0, r0, #0x4000 @ .1.. .... .... .... 403#endif 404 mov pc, lr 405 .size __feroceon_setup, . - __feroceon_setup 406 407 /* 408 * R 409 * .RVI ZFRS BLDP WCAM 410 * .011 0001 ..11 0101 411 * 412 */ 413 .type feroceon_crval, #object 414feroceon_crval: 415 crval clear=0x00007f3f, mmuset=0x00003135, ucset=0x00001134 416 417 __INITDATA 418 419/* 420 * Purpose : Function pointers used to access above functions - all calls 421 * come through these 422 */ 423 .type feroceon_processor_functions, #object 424feroceon_processor_functions: 425 .word v5t_early_abort 426 .word cpu_feroceon_proc_init 427 .word cpu_feroceon_proc_fin 428 .word cpu_feroceon_reset 429 .word cpu_feroceon_do_idle 430 .word cpu_feroceon_dcache_clean_area 431 .word cpu_feroceon_switch_mm 432 .word cpu_feroceon_set_pte_ext 433 .size feroceon_processor_functions, . - feroceon_processor_functions 434 435 .section ".rodata" 436 437 .type cpu_arch_name, #object 438cpu_arch_name: 439 .asciz "armv5te" 440 .size cpu_arch_name, . - cpu_arch_name 441 442 .type cpu_elf_name, #object 443cpu_elf_name: 444 .asciz "v5" 445 .size cpu_elf_name, . - cpu_elf_name 446 447 .type cpu_feroceon_name, #object 448cpu_feroceon_name: 449 .asciz "Feroceon" 450 .size cpu_feroceon_name, . - cpu_feroceon_name 451 452 .align 453 454 .section ".proc.info.init", #alloc, #execinstr 455 456 .type __feroceon_proc_info,#object 457__feroceon_proc_info: 458 .long 0x56055310 459 .long 0xfffffff0 460 .long PMD_TYPE_SECT | \ 461 PMD_SECT_BUFFERABLE | \ 462 PMD_SECT_CACHEABLE | \ 463 PMD_BIT4 | \ 464 PMD_SECT_AP_WRITE | \ 465 PMD_SECT_AP_READ 466 .long PMD_TYPE_SECT | \ 467 PMD_BIT4 | \ 468 PMD_SECT_AP_WRITE | \ 469 PMD_SECT_AP_READ 470 b __feroceon_setup 471 .long cpu_arch_name 472 .long cpu_elf_name 473 .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP 474 .long cpu_feroceon_name 475 .long feroceon_processor_functions 476 .long v4wbi_tlb_fns 477 .long v4wb_user_fns 478 .long feroceon_cache_fns 479 .size __feroceon_proc_info, . - __feroceon_proc_info 480