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: 1211: mrc p15, 0, r15, c7, c14, 3 @ test,clean,invalidate 122 bne 1b 123 tst r2, #VM_EXEC 124 mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache 125 mcrne p15, 0, ip, c7, c10, 4 @ drain WB 126 mov pc, lr 127 128/* 129 * flush_user_cache_range(start, end, flags) 130 * 131 * Clean and invalidate a range of cache entries in the 132 * specified address range. 133 * 134 * - start - start address (inclusive) 135 * - end - end address (exclusive) 136 * - flags - vm_flags describing address space 137 */ 138ENTRY(feroceon_flush_user_cache_range) 139 mov ip, #0 140 sub r3, r1, r0 @ calculate total size 141 cmp r3, #CACHE_DLIMIT 142 bgt __flush_whole_cache 1431: tst r2, #VM_EXEC 144 mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry 145 mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry 146 add r0, r0, #CACHE_DLINESIZE 147 mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry 148 mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry 149 add r0, r0, #CACHE_DLINESIZE 150 cmp r0, r1 151 blo 1b 152 tst r2, #VM_EXEC 153 mcrne p15, 0, ip, c7, c10, 4 @ drain WB 154 mov pc, lr 155 156/* 157 * coherent_kern_range(start, end) 158 * 159 * Ensure coherency between the Icache and the Dcache in the 160 * region described by start, end. If you have non-snooping 161 * Harvard caches, you need to implement this function. 162 * 163 * - start - virtual start address 164 * - end - virtual end address 165 */ 166ENTRY(feroceon_coherent_kern_range) 167 /* FALLTHROUGH */ 168 169/* 170 * coherent_user_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_user_range) 180 bic r0, r0, #CACHE_DLINESIZE - 1 1811: mcr p15, 0, r0, c7, c10, 1 @ clean D entry 182 mcr p15, 0, r0, c7, c5, 1 @ invalidate I entry 183 add r0, r0, #CACHE_DLINESIZE 184 cmp r0, r1 185 blo 1b 186 mcr p15, 0, r0, c7, c10, 4 @ drain WB 187 mov pc, lr 188 189/* 190 * flush_kern_dcache_page(void *page) 191 * 192 * Ensure no D cache aliasing occurs, either with itself or 193 * the I cache 194 * 195 * - addr - page aligned address 196 */ 197ENTRY(feroceon_flush_kern_dcache_page) 198 add r1, r0, #PAGE_SZ 1991: mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry 200 add r0, r0, #CACHE_DLINESIZE 201 cmp r0, r1 202 blo 1b 203 mov r0, #0 204 mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache 205 mcr p15, 0, r0, c7, c10, 4 @ drain WB 206 mov pc, lr 207 208/* 209 * dma_inv_range(start, end) 210 * 211 * Invalidate (discard) the specified virtual address range. 212 * May not write back any entries. If 'start' or 'end' 213 * are not cache line aligned, those lines must be written 214 * back. 215 * 216 * - start - virtual start address 217 * - end - virtual end address 218 * 219 * (same as v4wb) 220 */ 221ENTRY(feroceon_dma_inv_range) 222 tst r0, #CACHE_DLINESIZE - 1 223 mcrne p15, 0, r0, c7, c10, 1 @ clean D entry 224 tst r1, #CACHE_DLINESIZE - 1 225 mcrne p15, 0, r1, c7, c10, 1 @ clean D entry 226 bic r0, r0, #CACHE_DLINESIZE - 1 2271: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry 228 add r0, r0, #CACHE_DLINESIZE 229 cmp r0, r1 230 blo 1b 231 mcr p15, 0, r0, c7, c10, 4 @ drain WB 232 mov pc, lr 233 234/* 235 * dma_clean_range(start, end) 236 * 237 * Clean the specified virtual address range. 238 * 239 * - start - virtual start address 240 * - end - virtual end address 241 * 242 * (same as v4wb) 243 */ 244ENTRY(feroceon_dma_clean_range) 245 bic r0, r0, #CACHE_DLINESIZE - 1 2461: mcr p15, 0, r0, c7, c10, 1 @ clean D entry 247 add r0, r0, #CACHE_DLINESIZE 248 cmp r0, r1 249 blo 1b 250 mcr p15, 0, r0, c7, c10, 4 @ drain WB 251 mov pc, lr 252 253/* 254 * dma_flush_range(start, end) 255 * 256 * Clean and invalidate the specified virtual address range. 257 * 258 * - start - virtual start address 259 * - end - virtual end address 260 */ 261ENTRY(feroceon_dma_flush_range) 262 bic r0, r0, #CACHE_DLINESIZE - 1 2631: 264 mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate 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 271ENTRY(feroceon_cache_fns) 272 .long feroceon_flush_kern_cache_all 273 .long feroceon_flush_user_cache_all 274 .long feroceon_flush_user_cache_range 275 .long feroceon_coherent_kern_range 276 .long feroceon_coherent_user_range 277 .long feroceon_flush_kern_dcache_page 278 .long feroceon_dma_inv_range 279 .long feroceon_dma_clean_range 280 .long feroceon_dma_flush_range 281 282ENTRY(cpu_feroceon_dcache_clean_area) 2831: mcr p15, 0, r0, c7, c10, 1 @ clean D entry 284 add r0, r0, #CACHE_DLINESIZE 285 subs r1, r1, #CACHE_DLINESIZE 286 bhi 1b 287 mcr p15, 0, r0, c7, c10, 4 @ drain WB 288 mov pc, lr 289 290/* =============================== PageTable ============================== */ 291 292/* 293 * cpu_feroceon_switch_mm(pgd) 294 * 295 * Set the translation base pointer to be as described by pgd. 296 * 297 * pgd: new page tables 298 */ 299 .align 5 300ENTRY(cpu_feroceon_switch_mm) 301#ifdef CONFIG_MMU 302 mov ip, #0 303@ && 'Clean & Invalidate whole DCache' 3041: mrc p15, 0, r15, c7, c14, 3 @ test,clean,invalidate 305 bne 1b 306 mcr p15, 0, ip, c7, c5, 0 @ invalidate I cache 307 mcr p15, 0, ip, c7, c10, 4 @ drain WB 308 mcr p15, 0, r0, c2, c0, 0 @ load page table pointer 309 mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs 310#endif 311 mov pc, lr 312 313/* 314 * cpu_feroceon_set_pte_ext(ptep, pte, ext) 315 * 316 * Set a PTE and flush it out 317 */ 318 .align 5 319ENTRY(cpu_feroceon_set_pte_ext) 320#ifdef CONFIG_MMU 321 str r1, [r0], #-2048 @ linux version 322 323 eor r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY 324 325 bic r2, r1, #PTE_SMALL_AP_MASK 326 bic r2, r2, #PTE_TYPE_MASK 327 orr r2, r2, #PTE_TYPE_SMALL 328 329 tst r1, #L_PTE_USER @ User? 330 orrne r2, r2, #PTE_SMALL_AP_URO_SRW 331 332 tst r1, #L_PTE_WRITE | L_PTE_DIRTY @ Write and Dirty? 333 orreq r2, r2, #PTE_SMALL_AP_UNO_SRW 334 335 tst r1, #L_PTE_PRESENT | L_PTE_YOUNG @ Present and Young? 336 movne r2, #0 337 338 str r2, [r0] @ hardware version 339 mov r0, r0 340 mcr p15, 0, r0, c7, c10, 1 @ clean D entry 341 mcr p15, 0, r0, c7, c10, 4 @ drain WB 342#endif 343 mov pc, lr 344 345 __INIT 346 347 .type __feroceon_setup, #function 348__feroceon_setup: 349 mov r0, #0 350 mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4 351 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4 352#ifdef CONFIG_MMU 353 mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4 354#endif 355 356 adr r5, feroceon_crval 357 ldmia r5, {r5, r6} 358 mrc p15, 0, r0, c1, c0 @ get control register v4 359 bic r0, r0, r5 360 orr r0, r0, r6 361#ifdef CONFIG_CPU_CACHE_ROUND_ROBIN 362 orr r0, r0, #0x4000 @ .1.. .... .... .... 363#endif 364 mov pc, lr 365 .size __feroceon_setup, . - __feroceon_setup 366 367 /* 368 * R 369 * .RVI ZFRS BLDP WCAM 370 * .011 0001 ..11 0101 371 * 372 */ 373 .type feroceon_crval, #object 374feroceon_crval: 375 crval clear=0x00007f3f, mmuset=0x00003135, ucset=0x00001134 376 377 __INITDATA 378 379/* 380 * Purpose : Function pointers used to access above functions - all calls 381 * come through these 382 */ 383 .type feroceon_processor_functions, #object 384feroceon_processor_functions: 385 .word v5t_early_abort 386 .word pabort_noifar 387 .word cpu_feroceon_proc_init 388 .word cpu_feroceon_proc_fin 389 .word cpu_feroceon_reset 390 .word cpu_feroceon_do_idle 391 .word cpu_feroceon_dcache_clean_area 392 .word cpu_feroceon_switch_mm 393 .word cpu_feroceon_set_pte_ext 394 .size feroceon_processor_functions, . - feroceon_processor_functions 395 396 .section ".rodata" 397 398 .type cpu_arch_name, #object 399cpu_arch_name: 400 .asciz "armv5te" 401 .size cpu_arch_name, . - cpu_arch_name 402 403 .type cpu_elf_name, #object 404cpu_elf_name: 405 .asciz "v5" 406 .size cpu_elf_name, . - cpu_elf_name 407 408 .type cpu_feroceon_name, #object 409cpu_feroceon_name: 410 .asciz "Feroceon" 411 .size cpu_feroceon_name, . - cpu_feroceon_name 412 413 .align 414 415 .section ".proc.info.init", #alloc, #execinstr 416 417#ifdef CONFIG_CPU_FEROCEON_OLD_ID 418 .type __feroceon_old_id_proc_info,#object 419__feroceon_old_id_proc_info: 420 .long 0x41069260 421 .long 0xfffffff0 422 .long PMD_TYPE_SECT | \ 423 PMD_SECT_BUFFERABLE | \ 424 PMD_SECT_CACHEABLE | \ 425 PMD_BIT4 | \ 426 PMD_SECT_AP_WRITE | \ 427 PMD_SECT_AP_READ 428 .long PMD_TYPE_SECT | \ 429 PMD_BIT4 | \ 430 PMD_SECT_AP_WRITE | \ 431 PMD_SECT_AP_READ 432 b __feroceon_setup 433 .long cpu_arch_name 434 .long cpu_elf_name 435 .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP 436 .long cpu_feroceon_name 437 .long feroceon_processor_functions 438 .long v4wbi_tlb_fns 439 .long v4wb_user_fns 440 .long feroceon_cache_fns 441 .size __feroceon_old_id_proc_info, . - __feroceon_old_id_proc_info 442#endif 443 444 .type __feroceon_proc_info,#object 445__feroceon_proc_info: 446 .long 0x56055310 447 .long 0xfffffff0 448 .long PMD_TYPE_SECT | \ 449 PMD_SECT_BUFFERABLE | \ 450 PMD_SECT_CACHEABLE | \ 451 PMD_BIT4 | \ 452 PMD_SECT_AP_WRITE | \ 453 PMD_SECT_AP_READ 454 .long PMD_TYPE_SECT | \ 455 PMD_BIT4 | \ 456 PMD_SECT_AP_WRITE | \ 457 PMD_SECT_AP_READ 458 b __feroceon_setup 459 .long cpu_arch_name 460 .long cpu_elf_name 461 .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP 462 .long cpu_feroceon_name 463 .long feroceon_processor_functions 464 .long v4wbi_tlb_fns 465 .long v4wb_user_fns 466 .long feroceon_cache_fns 467 .size __feroceon_proc_info, . - __feroceon_proc_info 468