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