0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/linkage.h>
0010 #include <linux/init.h>
0011 #include <linux/pgtable.h>
0012 #include <asm/assembler.h>
0013 #include <asm/hwcap.h>
0014 #include <asm/pgtable-hwdef.h>
0015 #include <asm/page.h>
0016 #include <asm/ptrace.h>
0017 #include "proc-macros.S"
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027 #define CACHE_DLIMIT 16384
0028
0029
0030
0031
0032 #define CACHE_DLINESIZE 32
0033
0034 .bss
0035 .align 3
0036 __cache_params_loc:
0037 .space 8
0038
0039 .text
0040 __cache_params:
0041 .word __cache_params_loc
0042
0043
0044
0045
0046 ENTRY(cpu_feroceon_proc_init)
0047 mrc p15, 0, r0, c0, c0, 1 @ read cache type register
0048 ldr r1, __cache_params
0049 mov r2, #(16 << 5)
0050 tst r0, #(1 << 16) @ get way
0051 mov r0, r0, lsr #18 @ get cache size order
0052 movne r3, #((4 - 1) << 30) @ 4-way
0053 and r0, r0, #0xf
0054 moveq r3, #0 @ 1-way
0055 mov r2, r2, lsl r0 @ actual cache size
0056 movne r2, r2, lsr #2 @ turned into # of sets
0057 sub r2, r2, #(1 << 5)
0058 stmia r1, {r2, r3}
0059 ret lr
0060
0061
0062
0063
0064 ENTRY(cpu_feroceon_proc_fin)
0065 #if defined(CONFIG_CACHE_FEROCEON_L2) && \
0066 !defined(CONFIG_CACHE_FEROCEON_L2_WRITETHROUGH)
0067 mov r0, #0
0068 mcr p15, 1, r0, c15, c9, 0 @ clean L2
0069 mcr p15, 0, r0, c7, c10, 4 @ drain WB
0070 #endif
0071
0072 mrc p15, 0, r0, c1, c0, 0 @ ctrl register
0073 bic r0, r0, #0x1000 @ ...i............
0074 bic r0, r0, #0x000e @ ............wca.
0075 mcr p15, 0, r0, c1, c0, 0 @ disable caches
0076 ret lr
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087 .align 5
0088 .pushsection .idmap.text, "ax"
0089 ENTRY(cpu_feroceon_reset)
0090 mov ip, #0
0091 mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches
0092 mcr p15, 0, ip, c7, c10, 4 @ drain WB
0093 #ifdef CONFIG_MMU
0094 mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
0095 #endif
0096 mrc p15, 0, ip, c1, c0, 0 @ ctrl register
0097 bic ip, ip, #0x000f @ ............wcam
0098 bic ip, ip, #0x1100 @ ...i...s........
0099 mcr p15, 0, ip, c1, c0, 0 @ ctrl register
0100 ret r0
0101 ENDPROC(cpu_feroceon_reset)
0102 .popsection
0103
0104
0105
0106
0107
0108
0109 .align 5
0110 ENTRY(cpu_feroceon_do_idle)
0111 mov r0, #0
0112 mcr p15, 0, r0, c7, c10, 4 @ Drain write buffer
0113 mcr p15, 0, r0, c7, c0, 4 @ Wait for interrupt
0114 ret lr
0115
0116
0117
0118
0119
0120
0121 ENTRY(feroceon_flush_icache_all)
0122 mov r0, #0
0123 mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache
0124 ret lr
0125 ENDPROC(feroceon_flush_icache_all)
0126
0127
0128
0129
0130
0131
0132
0133 .align 5
0134 ENTRY(feroceon_flush_user_cache_all)
0135
0136
0137
0138
0139
0140
0141
0142 ENTRY(feroceon_flush_kern_cache_all)
0143 mov r2, #VM_EXEC
0144
0145 __flush_whole_cache:
0146 ldr r1, __cache_params
0147 ldmia r1, {r1, r3}
0148 1: orr ip, r1, r3
0149 2: mcr p15, 0, ip, c7, c14, 2 @ clean + invalidate D set/way
0150 subs ip, ip, #(1 << 30) @ next way
0151 bcs 2b
0152 subs r1, r1, #(1 << 5) @ next set
0153 bcs 1b
0154
0155 tst r2, #VM_EXEC
0156 mov ip, #0
0157 mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache
0158 mcrne p15, 0, ip, c7, c10, 4 @ drain WB
0159 ret lr
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171 .align 5
0172 ENTRY(feroceon_flush_user_cache_range)
0173 sub r3, r1, r0 @ calculate total size
0174 cmp r3, #CACHE_DLIMIT
0175 bgt __flush_whole_cache
0176 1: tst r2, #VM_EXEC
0177 mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry
0178 mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry
0179 add r0, r0, #CACHE_DLINESIZE
0180 mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry
0181 mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry
0182 add r0, r0, #CACHE_DLINESIZE
0183 cmp r0, r1
0184 blo 1b
0185 tst r2, #VM_EXEC
0186 mov ip, #0
0187 mcrne p15, 0, ip, c7, c10, 4 @ drain WB
0188 ret lr
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200 .align 5
0201 ENTRY(feroceon_coherent_kern_range)
0202
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212
0213
0214 ENTRY(feroceon_coherent_user_range)
0215 bic r0, r0, #CACHE_DLINESIZE - 1
0216 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
0217 mcr p15, 0, r0, c7, c5, 1 @ invalidate I entry
0218 add r0, r0, #CACHE_DLINESIZE
0219 cmp r0, r1
0220 blo 1b
0221 mcr p15, 0, r0, c7, c10, 4 @ drain WB
0222 mov r0, #0
0223 ret lr
0224
0225
0226
0227
0228
0229
0230
0231
0232
0233
0234 .align 5
0235 ENTRY(feroceon_flush_kern_dcache_area)
0236 add r1, r0, r1
0237 1: mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry
0238 add r0, r0, #CACHE_DLINESIZE
0239 cmp r0, r1
0240 blo 1b
0241 mov r0, #0
0242 mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache
0243 mcr p15, 0, r0, c7, c10, 4 @ drain WB
0244 ret lr
0245
0246 .align 5
0247 ENTRY(feroceon_range_flush_kern_dcache_area)
0248 mrs r2, cpsr
0249 add r1, r0, #PAGE_SZ - CACHE_DLINESIZE @ top addr is inclusive
0250 orr r3, r2, #PSR_I_BIT
0251 msr cpsr_c, r3 @ disable interrupts
0252 mcr p15, 5, r0, c15, c15, 0 @ D clean/inv range start
0253 mcr p15, 5, r1, c15, c15, 1 @ D clean/inv range top
0254 msr cpsr_c, r2 @ restore interrupts
0255 mov r0, #0
0256 mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache
0257 mcr p15, 0, r0, c7, c10, 4 @ drain WB
0258 ret lr
0259
0260
0261
0262
0263
0264
0265
0266
0267
0268
0269
0270
0271
0272
0273 .align 5
0274 feroceon_dma_inv_range:
0275 tst r0, #CACHE_DLINESIZE - 1
0276 bic r0, r0, #CACHE_DLINESIZE - 1
0277 mcrne p15, 0, r0, c7, c10, 1 @ clean D entry
0278 tst r1, #CACHE_DLINESIZE - 1
0279 mcrne p15, 0, r1, c7, c10, 1 @ clean D entry
0280 1: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry
0281 add r0, r0, #CACHE_DLINESIZE
0282 cmp r0, r1
0283 blo 1b
0284 mcr p15, 0, r0, c7, c10, 4 @ drain WB
0285 ret lr
0286
0287 .align 5
0288 feroceon_range_dma_inv_range:
0289 mrs r2, cpsr
0290 tst r0, #CACHE_DLINESIZE - 1
0291 mcrne p15, 0, r0, c7, c10, 1 @ clean D entry
0292 tst r1, #CACHE_DLINESIZE - 1
0293 mcrne p15, 0, r1, c7, c10, 1 @ clean D entry
0294 cmp r1, r0
0295 subne r1, r1, #1 @ top address is inclusive
0296 orr r3, r2, #PSR_I_BIT
0297 msr cpsr_c, r3 @ disable interrupts
0298 mcr p15, 5, r0, c15, c14, 0 @ D inv range start
0299 mcr p15, 5, r1, c15, c14, 1 @ D inv range top
0300 msr cpsr_c, r2 @ restore interrupts
0301 ret lr
0302
0303
0304
0305
0306
0307
0308
0309
0310
0311
0312
0313 .align 5
0314 feroceon_dma_clean_range:
0315 bic r0, r0, #CACHE_DLINESIZE - 1
0316 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
0317 add r0, r0, #CACHE_DLINESIZE
0318 cmp r0, r1
0319 blo 1b
0320 mcr p15, 0, r0, c7, c10, 4 @ drain WB
0321 ret lr
0322
0323 .align 5
0324 feroceon_range_dma_clean_range:
0325 mrs r2, cpsr
0326 cmp r1, r0
0327 subne r1, r1, #1 @ top address is inclusive
0328 orr r3, r2, #PSR_I_BIT
0329 msr cpsr_c, r3 @ disable interrupts
0330 mcr p15, 5, r0, c15, c13, 0 @ D clean range start
0331 mcr p15, 5, r1, c15, c13, 1 @ D clean range top
0332 msr cpsr_c, r2 @ restore interrupts
0333 mcr p15, 0, r0, c7, c10, 4 @ drain WB
0334 ret lr
0335
0336
0337
0338
0339
0340
0341
0342
0343
0344 .align 5
0345 ENTRY(feroceon_dma_flush_range)
0346 bic r0, r0, #CACHE_DLINESIZE - 1
0347 1: mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry
0348 add r0, r0, #CACHE_DLINESIZE
0349 cmp r0, r1
0350 blo 1b
0351 mcr p15, 0, r0, c7, c10, 4 @ drain WB
0352 ret lr
0353
0354 .align 5
0355 ENTRY(feroceon_range_dma_flush_range)
0356 mrs r2, cpsr
0357 cmp r1, r0
0358 subne r1, r1, #1 @ top address is inclusive
0359 orr r3, r2, #PSR_I_BIT
0360 msr cpsr_c, r3 @ disable interrupts
0361 mcr p15, 5, r0, c15, c15, 0 @ D clean/inv range start
0362 mcr p15, 5, r1, c15, c15, 1 @ D clean/inv range top
0363 msr cpsr_c, r2 @ restore interrupts
0364 mcr p15, 0, r0, c7, c10, 4 @ drain WB
0365 ret lr
0366
0367
0368
0369
0370
0371
0372
0373 ENTRY(feroceon_dma_map_area)
0374 add r1, r1, r0
0375 cmp r2, #DMA_TO_DEVICE
0376 beq feroceon_dma_clean_range
0377 bcs feroceon_dma_inv_range
0378 b feroceon_dma_flush_range
0379 ENDPROC(feroceon_dma_map_area)
0380
0381
0382
0383
0384
0385
0386
0387 ENTRY(feroceon_range_dma_map_area)
0388 add r1, r1, r0
0389 cmp r2, #DMA_TO_DEVICE
0390 beq feroceon_range_dma_clean_range
0391 bcs feroceon_range_dma_inv_range
0392 b feroceon_range_dma_flush_range
0393 ENDPROC(feroceon_range_dma_map_area)
0394
0395
0396
0397
0398
0399
0400
0401 ENTRY(feroceon_dma_unmap_area)
0402 ret lr
0403 ENDPROC(feroceon_dma_unmap_area)
0404
0405 .globl feroceon_flush_kern_cache_louis
0406 .equ feroceon_flush_kern_cache_louis, feroceon_flush_kern_cache_all
0407
0408 @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
0409 define_cache_functions feroceon
0410
0411 .macro range_alias basename
0412 .globl feroceon_range_\basename
0413 .type feroceon_range_\basename , %function
0414 .equ feroceon_range_\basename , feroceon_\basename
0415 .endm
0416
0417
0418
0419
0420
0421 range_alias flush_icache_all
0422 range_alias flush_user_cache_all
0423 range_alias flush_kern_cache_all
0424 range_alias flush_kern_cache_louis
0425 range_alias flush_user_cache_range
0426 range_alias coherent_kern_range
0427 range_alias coherent_user_range
0428 range_alias dma_unmap_area
0429
0430 define_cache_functions feroceon_range
0431
0432 .align 5
0433 ENTRY(cpu_feroceon_dcache_clean_area)
0434 #if defined(CONFIG_CACHE_FEROCEON_L2) && \
0435 !defined(CONFIG_CACHE_FEROCEON_L2_WRITETHROUGH)
0436 mov r2, r0
0437 mov r3, r1
0438 #endif
0439 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
0440 add r0, r0, #CACHE_DLINESIZE
0441 subs r1, r1, #CACHE_DLINESIZE
0442 bhi 1b
0443 #if defined(CONFIG_CACHE_FEROCEON_L2) && \
0444 !defined(CONFIG_CACHE_FEROCEON_L2_WRITETHROUGH)
0445 1: mcr p15, 1, r2, c15, c9, 1 @ clean L2 entry
0446 add r2, r2, #CACHE_DLINESIZE
0447 subs r3, r3, #CACHE_DLINESIZE
0448 bhi 1b
0449 #endif
0450 mcr p15, 0, r0, c7, c10, 4 @ drain WB
0451 ret lr
0452
0453
0454
0455
0456
0457
0458
0459
0460
0461
0462 .align 5
0463 ENTRY(cpu_feroceon_switch_mm)
0464 #ifdef CONFIG_MMU
0465
0466
0467
0468
0469
0470
0471 mov r2, lr @ abuse r2 to preserve lr
0472 bl __flush_whole_cache
0473 @ if r2 contains the VM_EXEC bit then the next 2 ops are done already
0474 tst r2, #VM_EXEC
0475 mcreq p15, 0, ip, c7, c5, 0 @ invalidate I cache
0476 mcreq p15, 0, ip, c7, c10, 4 @ drain WB
0477
0478 mcr p15, 0, r0, c2, c0, 0 @ load page table pointer
0479 mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
0480 ret r2
0481 #else
0482 ret lr
0483 #endif
0484
0485
0486
0487
0488
0489
0490 .align 5
0491 ENTRY(cpu_feroceon_set_pte_ext)
0492 #ifdef CONFIG_MMU
0493 armv3_set_pte_ext wc_disable=0
0494 mov r0, r0
0495 mcr p15, 0, r0, c7, c10, 1 @ clean D entry
0496 #if defined(CONFIG_CACHE_FEROCEON_L2) && \
0497 !defined(CONFIG_CACHE_FEROCEON_L2_WRITETHROUGH)
0498 mcr p15, 1, r0, c15, c9, 1 @ clean L2 entry
0499 #endif
0500 mcr p15, 0, r0, c7, c10, 4 @ drain WB
0501 #endif
0502 ret lr
0503
0504
0505 .globl cpu_feroceon_suspend_size
0506 .equ cpu_feroceon_suspend_size, 4 * 3
0507 #ifdef CONFIG_ARM_CPU_SUSPEND
0508 ENTRY(cpu_feroceon_do_suspend)
0509 stmfd sp!, {r4 - r6, lr}
0510 mrc p15, 0, r4, c13, c0, 0 @ PID
0511 mrc p15, 0, r5, c3, c0, 0 @ Domain ID
0512 mrc p15, 0, r6, c1, c0, 0 @ Control register
0513 stmia r0, {r4 - r6}
0514 ldmfd sp!, {r4 - r6, pc}
0515 ENDPROC(cpu_feroceon_do_suspend)
0516
0517 ENTRY(cpu_feroceon_do_resume)
0518 mov ip, #0
0519 mcr p15, 0, ip, c8, c7, 0 @ invalidate I+D TLBs
0520 mcr p15, 0, ip, c7, c7, 0 @ invalidate I+D caches
0521 ldmia r0, {r4 - r6}
0522 mcr p15, 0, r4, c13, c0, 0 @ PID
0523 mcr p15, 0, r5, c3, c0, 0 @ Domain ID
0524 mcr p15, 0, r1, c2, c0, 0 @ TTB address
0525 mov r0, r6 @ control register
0526 b cpu_resume_mmu
0527 ENDPROC(cpu_feroceon_do_resume)
0528 #endif
0529
0530 .type __feroceon_setup, #function
0531 __feroceon_setup:
0532 mov r0, #0
0533 mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4
0534 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4
0535 #ifdef CONFIG_MMU
0536 mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4
0537 #endif
0538
0539 adr r5, feroceon_crval
0540 ldmia r5, {r5, r6}
0541 mrc p15, 0, r0, c1, c0 @ get control register v4
0542 bic r0, r0, r5
0543 orr r0, r0, r6
0544 ret lr
0545 .size __feroceon_setup, . - __feroceon_setup
0546
0547
0548
0549
0550
0551
0552
0553
0554 .type feroceon_crval, #object
0555 feroceon_crval:
0556 crval clear=0x0000773f, mmuset=0x00003135, ucset=0x00001134
0557
0558 __INITDATA
0559
0560 @ define struct processor (see <asm/proc-fns.h> and proc-macros.S)
0561 define_processor_functions feroceon, dabort=v5t_early_abort, pabort=legacy_pabort
0562
0563 .section ".rodata"
0564
0565 string cpu_arch_name, "armv5te"
0566 string cpu_elf_name, "v5"
0567 string cpu_feroceon_name, "Feroceon"
0568 string cpu_88fr531_name, "Feroceon 88FR531-vd"
0569 string cpu_88fr571_name, "Feroceon 88FR571-vd"
0570 string cpu_88fr131_name, "Feroceon 88FR131"
0571
0572 .align
0573
0574 .section ".proc.info.init", "a"
0575
0576 .macro feroceon_proc_info name:req, cpu_val:req, cpu_mask:req, cpu_name:req, cache:req
0577 .type __\name\()_proc_info,#object
0578 __\name\()_proc_info:
0579 .long \cpu_val
0580 .long \cpu_mask
0581 .long PMD_TYPE_SECT | \
0582 PMD_SECT_BUFFERABLE | \
0583 PMD_SECT_CACHEABLE | \
0584 PMD_BIT4 | \
0585 PMD_SECT_AP_WRITE | \
0586 PMD_SECT_AP_READ
0587 .long PMD_TYPE_SECT | \
0588 PMD_BIT4 | \
0589 PMD_SECT_AP_WRITE | \
0590 PMD_SECT_AP_READ
0591 initfn __feroceon_setup, __\name\()_proc_info
0592 .long cpu_arch_name
0593 .long cpu_elf_name
0594 .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
0595 .long \cpu_name
0596 .long feroceon_processor_functions
0597 .long v4wbi_tlb_fns
0598 .long feroceon_user_fns
0599 .long \cache
0600 .size __\name\()_proc_info, . - __\name\()_proc_info
0601 .endm
0602
0603 #ifdef CONFIG_CPU_FEROCEON_OLD_ID
0604 feroceon_proc_info feroceon_old_id, 0x41009260, 0xff00fff0, \
0605 cpu_name=cpu_feroceon_name, cache=feroceon_cache_fns
0606 #endif
0607
0608 feroceon_proc_info 88fr531, 0x56055310, 0xfffffff0, cpu_88fr531_name, \
0609 cache=feroceon_cache_fns
0610 feroceon_proc_info 88fr571, 0x56155710, 0xfffffff0, cpu_88fr571_name, \
0611 cache=feroceon_range_cache_fns
0612 feroceon_proc_info 88fr131, 0x56251310, 0xfffffff0, cpu_88fr131_name, \
0613 cache=feroceon_range_cache_fns