1*4882a593Smuzhiyun/* SPDX-License-Identifier: GPL-2.0-only */ 2*4882a593Smuzhiyun/* 3*4882a593Smuzhiyun * linux/arch/arm/mm/proc-xscale.S 4*4882a593Smuzhiyun * 5*4882a593Smuzhiyun * Author: Nicolas Pitre 6*4882a593Smuzhiyun * Created: November 2000 7*4882a593Smuzhiyun * Copyright: (C) 2000, 2001 MontaVista Software Inc. 8*4882a593Smuzhiyun * 9*4882a593Smuzhiyun * MMU functions for the Intel XScale CPUs 10*4882a593Smuzhiyun * 11*4882a593Smuzhiyun * 2001 Aug 21: 12*4882a593Smuzhiyun * some contributions by Brett Gaines <brett.w.gaines@intel.com> 13*4882a593Smuzhiyun * Copyright 2001 by Intel Corp. 14*4882a593Smuzhiyun * 15*4882a593Smuzhiyun * 2001 Sep 08: 16*4882a593Smuzhiyun * Completely revisited, many important fixes 17*4882a593Smuzhiyun * Nicolas Pitre <nico@fluxnic.net> 18*4882a593Smuzhiyun */ 19*4882a593Smuzhiyun 20*4882a593Smuzhiyun#include <linux/linkage.h> 21*4882a593Smuzhiyun#include <linux/init.h> 22*4882a593Smuzhiyun#include <linux/pgtable.h> 23*4882a593Smuzhiyun#include <asm/assembler.h> 24*4882a593Smuzhiyun#include <asm/hwcap.h> 25*4882a593Smuzhiyun#include <asm/pgtable-hwdef.h> 26*4882a593Smuzhiyun#include <asm/page.h> 27*4882a593Smuzhiyun#include <asm/ptrace.h> 28*4882a593Smuzhiyun#include "proc-macros.S" 29*4882a593Smuzhiyun 30*4882a593Smuzhiyun/* 31*4882a593Smuzhiyun * This is the maximum size of an area which will be flushed. If the area 32*4882a593Smuzhiyun * is larger than this, then we flush the whole cache 33*4882a593Smuzhiyun */ 34*4882a593Smuzhiyun#define MAX_AREA_SIZE 32768 35*4882a593Smuzhiyun 36*4882a593Smuzhiyun/* 37*4882a593Smuzhiyun * the cache line size of the I and D cache 38*4882a593Smuzhiyun */ 39*4882a593Smuzhiyun#define CACHELINESIZE 32 40*4882a593Smuzhiyun 41*4882a593Smuzhiyun/* 42*4882a593Smuzhiyun * the size of the data cache 43*4882a593Smuzhiyun */ 44*4882a593Smuzhiyun#define CACHESIZE 32768 45*4882a593Smuzhiyun 46*4882a593Smuzhiyun/* 47*4882a593Smuzhiyun * Virtual address used to allocate the cache when flushed 48*4882a593Smuzhiyun * 49*4882a593Smuzhiyun * This must be an address range which is _never_ used. It should 50*4882a593Smuzhiyun * apparently have a mapping in the corresponding page table for 51*4882a593Smuzhiyun * compatibility with future CPUs that _could_ require it. For instance we 52*4882a593Smuzhiyun * don't care. 53*4882a593Smuzhiyun * 54*4882a593Smuzhiyun * This must be aligned on a 2*CACHESIZE boundary. The code selects one of 55*4882a593Smuzhiyun * the 2 areas in alternance each time the clean_d_cache macro is used. 56*4882a593Smuzhiyun * Without this the XScale core exhibits cache eviction problems and no one 57*4882a593Smuzhiyun * knows why. 58*4882a593Smuzhiyun * 59*4882a593Smuzhiyun * Reminder: the vector table is located at 0xffff0000-0xffff0fff. 60*4882a593Smuzhiyun */ 61*4882a593Smuzhiyun#define CLEAN_ADDR 0xfffe0000 62*4882a593Smuzhiyun 63*4882a593Smuzhiyun/* 64*4882a593Smuzhiyun * This macro is used to wait for a CP15 write and is needed 65*4882a593Smuzhiyun * when we have to ensure that the last operation to the co-pro 66*4882a593Smuzhiyun * was completed before continuing with operation. 67*4882a593Smuzhiyun */ 68*4882a593Smuzhiyun .macro cpwait, rd 69*4882a593Smuzhiyun mrc p15, 0, \rd, c2, c0, 0 @ arbitrary read of cp15 70*4882a593Smuzhiyun mov \rd, \rd @ wait for completion 71*4882a593Smuzhiyun sub pc, pc, #4 @ flush instruction pipeline 72*4882a593Smuzhiyun .endm 73*4882a593Smuzhiyun 74*4882a593Smuzhiyun .macro cpwait_ret, lr, rd 75*4882a593Smuzhiyun mrc p15, 0, \rd, c2, c0, 0 @ arbitrary read of cp15 76*4882a593Smuzhiyun sub pc, \lr, \rd, LSR #32 @ wait for completion and 77*4882a593Smuzhiyun @ flush instruction pipeline 78*4882a593Smuzhiyun .endm 79*4882a593Smuzhiyun 80*4882a593Smuzhiyun/* 81*4882a593Smuzhiyun * This macro cleans the entire dcache using line allocate. 82*4882a593Smuzhiyun * The main loop has been unrolled to reduce loop overhead. 83*4882a593Smuzhiyun * rd and rs are two scratch registers. 84*4882a593Smuzhiyun */ 85*4882a593Smuzhiyun .macro clean_d_cache, rd, rs 86*4882a593Smuzhiyun ldr \rs, =clean_addr 87*4882a593Smuzhiyun ldr \rd, [\rs] 88*4882a593Smuzhiyun eor \rd, \rd, #CACHESIZE 89*4882a593Smuzhiyun str \rd, [\rs] 90*4882a593Smuzhiyun add \rs, \rd, #CACHESIZE 91*4882a593Smuzhiyun1: mcr p15, 0, \rd, c7, c2, 5 @ allocate D cache line 92*4882a593Smuzhiyun add \rd, \rd, #CACHELINESIZE 93*4882a593Smuzhiyun mcr p15, 0, \rd, c7, c2, 5 @ allocate D cache line 94*4882a593Smuzhiyun add \rd, \rd, #CACHELINESIZE 95*4882a593Smuzhiyun mcr p15, 0, \rd, c7, c2, 5 @ allocate D cache line 96*4882a593Smuzhiyun add \rd, \rd, #CACHELINESIZE 97*4882a593Smuzhiyun mcr p15, 0, \rd, c7, c2, 5 @ allocate D cache line 98*4882a593Smuzhiyun add \rd, \rd, #CACHELINESIZE 99*4882a593Smuzhiyun teq \rd, \rs 100*4882a593Smuzhiyun bne 1b 101*4882a593Smuzhiyun .endm 102*4882a593Smuzhiyun 103*4882a593Smuzhiyun .data 104*4882a593Smuzhiyun .align 2 105*4882a593Smuzhiyunclean_addr: .word CLEAN_ADDR 106*4882a593Smuzhiyun 107*4882a593Smuzhiyun .text 108*4882a593Smuzhiyun 109*4882a593Smuzhiyun/* 110*4882a593Smuzhiyun * cpu_xscale_proc_init() 111*4882a593Smuzhiyun * 112*4882a593Smuzhiyun * Nothing too exciting at the moment 113*4882a593Smuzhiyun */ 114*4882a593SmuzhiyunENTRY(cpu_xscale_proc_init) 115*4882a593Smuzhiyun @ enable write buffer coalescing. Some bootloader disable it 116*4882a593Smuzhiyun mrc p15, 0, r1, c1, c0, 1 117*4882a593Smuzhiyun bic r1, r1, #1 118*4882a593Smuzhiyun mcr p15, 0, r1, c1, c0, 1 119*4882a593Smuzhiyun ret lr 120*4882a593Smuzhiyun 121*4882a593Smuzhiyun/* 122*4882a593Smuzhiyun * cpu_xscale_proc_fin() 123*4882a593Smuzhiyun */ 124*4882a593SmuzhiyunENTRY(cpu_xscale_proc_fin) 125*4882a593Smuzhiyun mrc p15, 0, r0, c1, c0, 0 @ ctrl register 126*4882a593Smuzhiyun bic r0, r0, #0x1800 @ ...IZ........... 127*4882a593Smuzhiyun bic r0, r0, #0x0006 @ .............CA. 128*4882a593Smuzhiyun mcr p15, 0, r0, c1, c0, 0 @ disable caches 129*4882a593Smuzhiyun ret lr 130*4882a593Smuzhiyun 131*4882a593Smuzhiyun/* 132*4882a593Smuzhiyun * cpu_xscale_reset(loc) 133*4882a593Smuzhiyun * 134*4882a593Smuzhiyun * Perform a soft reset of the system. Put the CPU into the 135*4882a593Smuzhiyun * same state as it would be if it had been reset, and branch 136*4882a593Smuzhiyun * to what would be the reset vector. 137*4882a593Smuzhiyun * 138*4882a593Smuzhiyun * loc: location to jump to for soft reset 139*4882a593Smuzhiyun * 140*4882a593Smuzhiyun * Beware PXA270 erratum E7. 141*4882a593Smuzhiyun */ 142*4882a593Smuzhiyun .align 5 143*4882a593Smuzhiyun .pushsection .idmap.text, "ax" 144*4882a593SmuzhiyunENTRY(cpu_xscale_reset) 145*4882a593Smuzhiyun mov r1, #PSR_F_BIT|PSR_I_BIT|SVC_MODE 146*4882a593Smuzhiyun msr cpsr_c, r1 @ reset CPSR 147*4882a593Smuzhiyun mcr p15, 0, r1, c10, c4, 1 @ unlock I-TLB 148*4882a593Smuzhiyun mcr p15, 0, r1, c8, c5, 0 @ invalidate I-TLB 149*4882a593Smuzhiyun mrc p15, 0, r1, c1, c0, 0 @ ctrl register 150*4882a593Smuzhiyun bic r1, r1, #0x0086 @ ........B....CA. 151*4882a593Smuzhiyun bic r1, r1, #0x3900 @ ..VIZ..S........ 152*4882a593Smuzhiyun sub pc, pc, #4 @ flush pipeline 153*4882a593Smuzhiyun @ *** cache line aligned *** 154*4882a593Smuzhiyun mcr p15, 0, r1, c1, c0, 0 @ ctrl register 155*4882a593Smuzhiyun bic r1, r1, #0x0001 @ ...............M 156*4882a593Smuzhiyun mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches & BTB 157*4882a593Smuzhiyun mcr p15, 0, r1, c1, c0, 0 @ ctrl register 158*4882a593Smuzhiyun @ CAUTION: MMU turned off from this point. We count on the pipeline 159*4882a593Smuzhiyun @ already containing those two last instructions to survive. 160*4882a593Smuzhiyun mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs 161*4882a593Smuzhiyun ret r0 162*4882a593SmuzhiyunENDPROC(cpu_xscale_reset) 163*4882a593Smuzhiyun .popsection 164*4882a593Smuzhiyun 165*4882a593Smuzhiyun/* 166*4882a593Smuzhiyun * cpu_xscale_do_idle() 167*4882a593Smuzhiyun * 168*4882a593Smuzhiyun * Cause the processor to idle 169*4882a593Smuzhiyun * 170*4882a593Smuzhiyun * For now we do nothing but go to idle mode for every case 171*4882a593Smuzhiyun * 172*4882a593Smuzhiyun * XScale supports clock switching, but using idle mode support 173*4882a593Smuzhiyun * allows external hardware to react to system state changes. 174*4882a593Smuzhiyun */ 175*4882a593Smuzhiyun .align 5 176*4882a593Smuzhiyun 177*4882a593SmuzhiyunENTRY(cpu_xscale_do_idle) 178*4882a593Smuzhiyun mov r0, #1 179*4882a593Smuzhiyun mcr p14, 0, r0, c7, c0, 0 @ Go to IDLE 180*4882a593Smuzhiyun ret lr 181*4882a593Smuzhiyun 182*4882a593Smuzhiyun/* ================================= CACHE ================================ */ 183*4882a593Smuzhiyun 184*4882a593Smuzhiyun/* 185*4882a593Smuzhiyun * flush_icache_all() 186*4882a593Smuzhiyun * 187*4882a593Smuzhiyun * Unconditionally clean and invalidate the entire icache. 188*4882a593Smuzhiyun */ 189*4882a593SmuzhiyunENTRY(xscale_flush_icache_all) 190*4882a593Smuzhiyun mov r0, #0 191*4882a593Smuzhiyun mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache 192*4882a593Smuzhiyun ret lr 193*4882a593SmuzhiyunENDPROC(xscale_flush_icache_all) 194*4882a593Smuzhiyun 195*4882a593Smuzhiyun/* 196*4882a593Smuzhiyun * flush_user_cache_all() 197*4882a593Smuzhiyun * 198*4882a593Smuzhiyun * Invalidate all cache entries in a particular address 199*4882a593Smuzhiyun * space. 200*4882a593Smuzhiyun */ 201*4882a593SmuzhiyunENTRY(xscale_flush_user_cache_all) 202*4882a593Smuzhiyun /* FALLTHROUGH */ 203*4882a593Smuzhiyun 204*4882a593Smuzhiyun/* 205*4882a593Smuzhiyun * flush_kern_cache_all() 206*4882a593Smuzhiyun * 207*4882a593Smuzhiyun * Clean and invalidate the entire cache. 208*4882a593Smuzhiyun */ 209*4882a593SmuzhiyunENTRY(xscale_flush_kern_cache_all) 210*4882a593Smuzhiyun mov r2, #VM_EXEC 211*4882a593Smuzhiyun mov ip, #0 212*4882a593Smuzhiyun__flush_whole_cache: 213*4882a593Smuzhiyun clean_d_cache r0, r1 214*4882a593Smuzhiyun tst r2, #VM_EXEC 215*4882a593Smuzhiyun mcrne p15, 0, ip, c7, c5, 0 @ Invalidate I cache & BTB 216*4882a593Smuzhiyun mcrne p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer 217*4882a593Smuzhiyun ret lr 218*4882a593Smuzhiyun 219*4882a593Smuzhiyun/* 220*4882a593Smuzhiyun * flush_user_cache_range(start, end, vm_flags) 221*4882a593Smuzhiyun * 222*4882a593Smuzhiyun * Invalidate a range of cache entries in the specified 223*4882a593Smuzhiyun * address space. 224*4882a593Smuzhiyun * 225*4882a593Smuzhiyun * - start - start address (may not be aligned) 226*4882a593Smuzhiyun * - end - end address (exclusive, may not be aligned) 227*4882a593Smuzhiyun * - vma - vma_area_struct describing address space 228*4882a593Smuzhiyun */ 229*4882a593Smuzhiyun .align 5 230*4882a593SmuzhiyunENTRY(xscale_flush_user_cache_range) 231*4882a593Smuzhiyun mov ip, #0 232*4882a593Smuzhiyun sub r3, r1, r0 @ calculate total size 233*4882a593Smuzhiyun cmp r3, #MAX_AREA_SIZE 234*4882a593Smuzhiyun bhs __flush_whole_cache 235*4882a593Smuzhiyun 236*4882a593Smuzhiyun1: tst r2, #VM_EXEC 237*4882a593Smuzhiyun mcrne p15, 0, r0, c7, c5, 1 @ Invalidate I cache line 238*4882a593Smuzhiyun mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line 239*4882a593Smuzhiyun mcr p15, 0, r0, c7, c6, 1 @ Invalidate D cache line 240*4882a593Smuzhiyun add r0, r0, #CACHELINESIZE 241*4882a593Smuzhiyun cmp r0, r1 242*4882a593Smuzhiyun blo 1b 243*4882a593Smuzhiyun tst r2, #VM_EXEC 244*4882a593Smuzhiyun mcrne p15, 0, ip, c7, c5, 6 @ Invalidate BTB 245*4882a593Smuzhiyun mcrne p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer 246*4882a593Smuzhiyun ret lr 247*4882a593Smuzhiyun 248*4882a593Smuzhiyun/* 249*4882a593Smuzhiyun * coherent_kern_range(start, end) 250*4882a593Smuzhiyun * 251*4882a593Smuzhiyun * Ensure coherency between the Icache and the Dcache in the 252*4882a593Smuzhiyun * region described by start. If you have non-snooping 253*4882a593Smuzhiyun * Harvard caches, you need to implement this function. 254*4882a593Smuzhiyun * 255*4882a593Smuzhiyun * - start - virtual start address 256*4882a593Smuzhiyun * - end - virtual end address 257*4882a593Smuzhiyun * 258*4882a593Smuzhiyun * Note: single I-cache line invalidation isn't used here since 259*4882a593Smuzhiyun * it also trashes the mini I-cache used by JTAG debuggers. 260*4882a593Smuzhiyun */ 261*4882a593SmuzhiyunENTRY(xscale_coherent_kern_range) 262*4882a593Smuzhiyun bic r0, r0, #CACHELINESIZE - 1 263*4882a593Smuzhiyun1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry 264*4882a593Smuzhiyun add r0, r0, #CACHELINESIZE 265*4882a593Smuzhiyun cmp r0, r1 266*4882a593Smuzhiyun blo 1b 267*4882a593Smuzhiyun mov r0, #0 268*4882a593Smuzhiyun mcr p15, 0, r0, c7, c5, 0 @ Invalidate I cache & BTB 269*4882a593Smuzhiyun mcr p15, 0, r0, c7, c10, 4 @ Drain Write (& Fill) Buffer 270*4882a593Smuzhiyun ret lr 271*4882a593Smuzhiyun 272*4882a593Smuzhiyun/* 273*4882a593Smuzhiyun * coherent_user_range(start, end) 274*4882a593Smuzhiyun * 275*4882a593Smuzhiyun * Ensure coherency between the Icache and the Dcache in the 276*4882a593Smuzhiyun * region described by start. If you have non-snooping 277*4882a593Smuzhiyun * Harvard caches, you need to implement this function. 278*4882a593Smuzhiyun * 279*4882a593Smuzhiyun * - start - virtual start address 280*4882a593Smuzhiyun * - end - virtual end address 281*4882a593Smuzhiyun */ 282*4882a593SmuzhiyunENTRY(xscale_coherent_user_range) 283*4882a593Smuzhiyun bic r0, r0, #CACHELINESIZE - 1 284*4882a593Smuzhiyun1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry 285*4882a593Smuzhiyun mcr p15, 0, r0, c7, c5, 1 @ Invalidate I cache entry 286*4882a593Smuzhiyun add r0, r0, #CACHELINESIZE 287*4882a593Smuzhiyun cmp r0, r1 288*4882a593Smuzhiyun blo 1b 289*4882a593Smuzhiyun mov r0, #0 290*4882a593Smuzhiyun mcr p15, 0, r0, c7, c5, 6 @ Invalidate BTB 291*4882a593Smuzhiyun mcr p15, 0, r0, c7, c10, 4 @ Drain Write (& Fill) Buffer 292*4882a593Smuzhiyun ret lr 293*4882a593Smuzhiyun 294*4882a593Smuzhiyun/* 295*4882a593Smuzhiyun * flush_kern_dcache_area(void *addr, size_t size) 296*4882a593Smuzhiyun * 297*4882a593Smuzhiyun * Ensure no D cache aliasing occurs, either with itself or 298*4882a593Smuzhiyun * the I cache 299*4882a593Smuzhiyun * 300*4882a593Smuzhiyun * - addr - kernel address 301*4882a593Smuzhiyun * - size - region size 302*4882a593Smuzhiyun */ 303*4882a593SmuzhiyunENTRY(xscale_flush_kern_dcache_area) 304*4882a593Smuzhiyun add r1, r0, r1 305*4882a593Smuzhiyun1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry 306*4882a593Smuzhiyun mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry 307*4882a593Smuzhiyun add r0, r0, #CACHELINESIZE 308*4882a593Smuzhiyun cmp r0, r1 309*4882a593Smuzhiyun blo 1b 310*4882a593Smuzhiyun mov r0, #0 311*4882a593Smuzhiyun mcr p15, 0, r0, c7, c5, 0 @ Invalidate I cache & BTB 312*4882a593Smuzhiyun mcr p15, 0, r0, c7, c10, 4 @ Drain Write (& Fill) Buffer 313*4882a593Smuzhiyun ret lr 314*4882a593Smuzhiyun 315*4882a593Smuzhiyun/* 316*4882a593Smuzhiyun * dma_inv_range(start, end) 317*4882a593Smuzhiyun * 318*4882a593Smuzhiyun * Invalidate (discard) the specified virtual address range. 319*4882a593Smuzhiyun * May not write back any entries. If 'start' or 'end' 320*4882a593Smuzhiyun * are not cache line aligned, those lines must be written 321*4882a593Smuzhiyun * back. 322*4882a593Smuzhiyun * 323*4882a593Smuzhiyun * - start - virtual start address 324*4882a593Smuzhiyun * - end - virtual end address 325*4882a593Smuzhiyun */ 326*4882a593Smuzhiyunxscale_dma_inv_range: 327*4882a593Smuzhiyun tst r0, #CACHELINESIZE - 1 328*4882a593Smuzhiyun bic r0, r0, #CACHELINESIZE - 1 329*4882a593Smuzhiyun mcrne p15, 0, r0, c7, c10, 1 @ clean D entry 330*4882a593Smuzhiyun tst r1, #CACHELINESIZE - 1 331*4882a593Smuzhiyun mcrne p15, 0, r1, c7, c10, 1 @ clean D entry 332*4882a593Smuzhiyun1: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry 333*4882a593Smuzhiyun add r0, r0, #CACHELINESIZE 334*4882a593Smuzhiyun cmp r0, r1 335*4882a593Smuzhiyun blo 1b 336*4882a593Smuzhiyun mcr p15, 0, r0, c7, c10, 4 @ Drain Write (& Fill) Buffer 337*4882a593Smuzhiyun ret lr 338*4882a593Smuzhiyun 339*4882a593Smuzhiyun/* 340*4882a593Smuzhiyun * dma_clean_range(start, end) 341*4882a593Smuzhiyun * 342*4882a593Smuzhiyun * Clean the specified virtual address range. 343*4882a593Smuzhiyun * 344*4882a593Smuzhiyun * - start - virtual start address 345*4882a593Smuzhiyun * - end - virtual end address 346*4882a593Smuzhiyun */ 347*4882a593Smuzhiyunxscale_dma_clean_range: 348*4882a593Smuzhiyun bic r0, r0, #CACHELINESIZE - 1 349*4882a593Smuzhiyun1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry 350*4882a593Smuzhiyun add r0, r0, #CACHELINESIZE 351*4882a593Smuzhiyun cmp r0, r1 352*4882a593Smuzhiyun blo 1b 353*4882a593Smuzhiyun mcr p15, 0, r0, c7, c10, 4 @ Drain Write (& Fill) Buffer 354*4882a593Smuzhiyun ret lr 355*4882a593Smuzhiyun 356*4882a593Smuzhiyun/* 357*4882a593Smuzhiyun * dma_flush_range(start, end) 358*4882a593Smuzhiyun * 359*4882a593Smuzhiyun * Clean and invalidate the specified virtual address range. 360*4882a593Smuzhiyun * 361*4882a593Smuzhiyun * - start - virtual start address 362*4882a593Smuzhiyun * - end - virtual end address 363*4882a593Smuzhiyun */ 364*4882a593SmuzhiyunENTRY(xscale_dma_flush_range) 365*4882a593Smuzhiyun bic r0, r0, #CACHELINESIZE - 1 366*4882a593Smuzhiyun1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry 367*4882a593Smuzhiyun mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry 368*4882a593Smuzhiyun add r0, r0, #CACHELINESIZE 369*4882a593Smuzhiyun cmp r0, r1 370*4882a593Smuzhiyun blo 1b 371*4882a593Smuzhiyun mcr p15, 0, r0, c7, c10, 4 @ Drain Write (& Fill) Buffer 372*4882a593Smuzhiyun ret lr 373*4882a593Smuzhiyun 374*4882a593Smuzhiyun/* 375*4882a593Smuzhiyun * dma_map_area(start, size, dir) 376*4882a593Smuzhiyun * - start - kernel virtual start address 377*4882a593Smuzhiyun * - size - size of region 378*4882a593Smuzhiyun * - dir - DMA direction 379*4882a593Smuzhiyun */ 380*4882a593SmuzhiyunENTRY(xscale_dma_map_area) 381*4882a593Smuzhiyun add r1, r1, r0 382*4882a593Smuzhiyun cmp r2, #DMA_TO_DEVICE 383*4882a593Smuzhiyun beq xscale_dma_clean_range 384*4882a593Smuzhiyun bcs xscale_dma_inv_range 385*4882a593Smuzhiyun b xscale_dma_flush_range 386*4882a593SmuzhiyunENDPROC(xscale_dma_map_area) 387*4882a593Smuzhiyun 388*4882a593Smuzhiyun/* 389*4882a593Smuzhiyun * dma_map_area(start, size, dir) 390*4882a593Smuzhiyun * - start - kernel virtual start address 391*4882a593Smuzhiyun * - size - size of region 392*4882a593Smuzhiyun * - dir - DMA direction 393*4882a593Smuzhiyun */ 394*4882a593SmuzhiyunENTRY(xscale_80200_A0_A1_dma_map_area) 395*4882a593Smuzhiyun add r1, r1, r0 396*4882a593Smuzhiyun teq r2, #DMA_TO_DEVICE 397*4882a593Smuzhiyun beq xscale_dma_clean_range 398*4882a593Smuzhiyun b xscale_dma_flush_range 399*4882a593SmuzhiyunENDPROC(xscale_80200_A0_A1_dma_map_area) 400*4882a593Smuzhiyun 401*4882a593Smuzhiyun/* 402*4882a593Smuzhiyun * dma_unmap_area(start, size, dir) 403*4882a593Smuzhiyun * - start - kernel virtual start address 404*4882a593Smuzhiyun * - size - size of region 405*4882a593Smuzhiyun * - dir - DMA direction 406*4882a593Smuzhiyun */ 407*4882a593SmuzhiyunENTRY(xscale_dma_unmap_area) 408*4882a593Smuzhiyun ret lr 409*4882a593SmuzhiyunENDPROC(xscale_dma_unmap_area) 410*4882a593Smuzhiyun 411*4882a593Smuzhiyun .globl xscale_flush_kern_cache_louis 412*4882a593Smuzhiyun .equ xscale_flush_kern_cache_louis, xscale_flush_kern_cache_all 413*4882a593Smuzhiyun 414*4882a593Smuzhiyun @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S) 415*4882a593Smuzhiyun define_cache_functions xscale 416*4882a593Smuzhiyun 417*4882a593Smuzhiyun/* 418*4882a593Smuzhiyun * On stepping A0/A1 of the 80200, invalidating D-cache by line doesn't 419*4882a593Smuzhiyun * clear the dirty bits, which means that if we invalidate a dirty line, 420*4882a593Smuzhiyun * the dirty data can still be written back to external memory later on. 421*4882a593Smuzhiyun * 422*4882a593Smuzhiyun * The recommended workaround is to always do a clean D-cache line before 423*4882a593Smuzhiyun * doing an invalidate D-cache line, so on the affected processors, 424*4882a593Smuzhiyun * dma_inv_range() is implemented as dma_flush_range(). 425*4882a593Smuzhiyun * 426*4882a593Smuzhiyun * See erratum #25 of "Intel 80200 Processor Specification Update", 427*4882a593Smuzhiyun * revision January 22, 2003, available at: 428*4882a593Smuzhiyun * http://www.intel.com/design/iio/specupdt/273415.htm 429*4882a593Smuzhiyun */ 430*4882a593Smuzhiyun.macro a0_alias basename 431*4882a593Smuzhiyun .globl xscale_80200_A0_A1_\basename 432*4882a593Smuzhiyun .type xscale_80200_A0_A1_\basename , %function 433*4882a593Smuzhiyun .equ xscale_80200_A0_A1_\basename , xscale_\basename 434*4882a593Smuzhiyun.endm 435*4882a593Smuzhiyun 436*4882a593Smuzhiyun/* 437*4882a593Smuzhiyun * Most of the cache functions are unchanged for these processor revisions. 438*4882a593Smuzhiyun * Export suitable alias symbols for the unchanged functions: 439*4882a593Smuzhiyun */ 440*4882a593Smuzhiyun a0_alias flush_icache_all 441*4882a593Smuzhiyun a0_alias flush_user_cache_all 442*4882a593Smuzhiyun a0_alias flush_kern_cache_all 443*4882a593Smuzhiyun a0_alias flush_kern_cache_louis 444*4882a593Smuzhiyun a0_alias flush_user_cache_range 445*4882a593Smuzhiyun a0_alias coherent_kern_range 446*4882a593Smuzhiyun a0_alias coherent_user_range 447*4882a593Smuzhiyun a0_alias flush_kern_dcache_area 448*4882a593Smuzhiyun a0_alias dma_flush_range 449*4882a593Smuzhiyun a0_alias dma_unmap_area 450*4882a593Smuzhiyun 451*4882a593Smuzhiyun @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S) 452*4882a593Smuzhiyun define_cache_functions xscale_80200_A0_A1 453*4882a593Smuzhiyun 454*4882a593SmuzhiyunENTRY(cpu_xscale_dcache_clean_area) 455*4882a593Smuzhiyun1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry 456*4882a593Smuzhiyun add r0, r0, #CACHELINESIZE 457*4882a593Smuzhiyun subs r1, r1, #CACHELINESIZE 458*4882a593Smuzhiyun bhi 1b 459*4882a593Smuzhiyun ret lr 460*4882a593Smuzhiyun 461*4882a593Smuzhiyun/* =============================== PageTable ============================== */ 462*4882a593Smuzhiyun 463*4882a593Smuzhiyun/* 464*4882a593Smuzhiyun * cpu_xscale_switch_mm(pgd) 465*4882a593Smuzhiyun * 466*4882a593Smuzhiyun * Set the translation base pointer to be as described by pgd. 467*4882a593Smuzhiyun * 468*4882a593Smuzhiyun * pgd: new page tables 469*4882a593Smuzhiyun */ 470*4882a593Smuzhiyun .align 5 471*4882a593SmuzhiyunENTRY(cpu_xscale_switch_mm) 472*4882a593Smuzhiyun clean_d_cache r1, r2 473*4882a593Smuzhiyun mcr p15, 0, ip, c7, c5, 0 @ Invalidate I cache & BTB 474*4882a593Smuzhiyun mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer 475*4882a593Smuzhiyun mcr p15, 0, r0, c2, c0, 0 @ load page table pointer 476*4882a593Smuzhiyun mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs 477*4882a593Smuzhiyun cpwait_ret lr, ip 478*4882a593Smuzhiyun 479*4882a593Smuzhiyun/* 480*4882a593Smuzhiyun * cpu_xscale_set_pte_ext(ptep, pte, ext) 481*4882a593Smuzhiyun * 482*4882a593Smuzhiyun * Set a PTE and flush it out 483*4882a593Smuzhiyun * 484*4882a593Smuzhiyun * Errata 40: must set memory to write-through for user read-only pages. 485*4882a593Smuzhiyun */ 486*4882a593Smuzhiyuncpu_xscale_mt_table: 487*4882a593Smuzhiyun .long 0x00 @ L_PTE_MT_UNCACHED 488*4882a593Smuzhiyun .long PTE_BUFFERABLE @ L_PTE_MT_BUFFERABLE 489*4882a593Smuzhiyun .long PTE_CACHEABLE @ L_PTE_MT_WRITETHROUGH 490*4882a593Smuzhiyun .long PTE_CACHEABLE | PTE_BUFFERABLE @ L_PTE_MT_WRITEBACK 491*4882a593Smuzhiyun .long PTE_EXT_TEX(1) | PTE_BUFFERABLE @ L_PTE_MT_DEV_SHARED 492*4882a593Smuzhiyun .long 0x00 @ unused 493*4882a593Smuzhiyun .long PTE_EXT_TEX(1) | PTE_CACHEABLE @ L_PTE_MT_MINICACHE 494*4882a593Smuzhiyun .long PTE_EXT_TEX(1) | PTE_CACHEABLE | PTE_BUFFERABLE @ L_PTE_MT_WRITEALLOC 495*4882a593Smuzhiyun .long 0x00 @ unused 496*4882a593Smuzhiyun .long PTE_BUFFERABLE @ L_PTE_MT_DEV_WC 497*4882a593Smuzhiyun .long 0x00 @ unused 498*4882a593Smuzhiyun .long PTE_CACHEABLE | PTE_BUFFERABLE @ L_PTE_MT_DEV_CACHED 499*4882a593Smuzhiyun .long 0x00 @ L_PTE_MT_DEV_NONSHARED 500*4882a593Smuzhiyun .long 0x00 @ unused 501*4882a593Smuzhiyun .long 0x00 @ unused 502*4882a593Smuzhiyun .long 0x00 @ unused 503*4882a593Smuzhiyun 504*4882a593Smuzhiyun .align 5 505*4882a593SmuzhiyunENTRY(cpu_xscale_set_pte_ext) 506*4882a593Smuzhiyun xscale_set_pte_ext_prologue 507*4882a593Smuzhiyun 508*4882a593Smuzhiyun @ 509*4882a593Smuzhiyun @ Erratum 40: must set memory to write-through for user read-only pages 510*4882a593Smuzhiyun @ 511*4882a593Smuzhiyun and ip, r1, #(L_PTE_MT_MASK | L_PTE_USER | L_PTE_RDONLY) & ~(4 << 2) 512*4882a593Smuzhiyun teq ip, #L_PTE_MT_WRITEBACK | L_PTE_USER | L_PTE_RDONLY 513*4882a593Smuzhiyun 514*4882a593Smuzhiyun moveq r1, #L_PTE_MT_WRITETHROUGH 515*4882a593Smuzhiyun and r1, r1, #L_PTE_MT_MASK 516*4882a593Smuzhiyun adr ip, cpu_xscale_mt_table 517*4882a593Smuzhiyun ldr ip, [ip, r1] 518*4882a593Smuzhiyun bic r2, r2, #0x0c 519*4882a593Smuzhiyun orr r2, r2, ip 520*4882a593Smuzhiyun 521*4882a593Smuzhiyun xscale_set_pte_ext_epilogue 522*4882a593Smuzhiyun ret lr 523*4882a593Smuzhiyun 524*4882a593Smuzhiyun .ltorg 525*4882a593Smuzhiyun .align 526*4882a593Smuzhiyun 527*4882a593Smuzhiyun.globl cpu_xscale_suspend_size 528*4882a593Smuzhiyun.equ cpu_xscale_suspend_size, 4 * 6 529*4882a593Smuzhiyun#ifdef CONFIG_ARM_CPU_SUSPEND 530*4882a593SmuzhiyunENTRY(cpu_xscale_do_suspend) 531*4882a593Smuzhiyun stmfd sp!, {r4 - r9, lr} 532*4882a593Smuzhiyun mrc p14, 0, r4, c6, c0, 0 @ clock configuration, for turbo mode 533*4882a593Smuzhiyun mrc p15, 0, r5, c15, c1, 0 @ CP access reg 534*4882a593Smuzhiyun mrc p15, 0, r6, c13, c0, 0 @ PID 535*4882a593Smuzhiyun mrc p15, 0, r7, c3, c0, 0 @ domain ID 536*4882a593Smuzhiyun mrc p15, 0, r8, c1, c0, 1 @ auxiliary control reg 537*4882a593Smuzhiyun mrc p15, 0, r9, c1, c0, 0 @ control reg 538*4882a593Smuzhiyun bic r4, r4, #2 @ clear frequency change bit 539*4882a593Smuzhiyun stmia r0, {r4 - r9} @ store cp regs 540*4882a593Smuzhiyun ldmfd sp!, {r4 - r9, pc} 541*4882a593SmuzhiyunENDPROC(cpu_xscale_do_suspend) 542*4882a593Smuzhiyun 543*4882a593SmuzhiyunENTRY(cpu_xscale_do_resume) 544*4882a593Smuzhiyun ldmia r0, {r4 - r9} @ load cp regs 545*4882a593Smuzhiyun mov ip, #0 546*4882a593Smuzhiyun mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs 547*4882a593Smuzhiyun mcr p15, 0, ip, c7, c7, 0 @ invalidate I & D caches, BTB 548*4882a593Smuzhiyun mcr p14, 0, r4, c6, c0, 0 @ clock configuration, turbo mode. 549*4882a593Smuzhiyun mcr p15, 0, r5, c15, c1, 0 @ CP access reg 550*4882a593Smuzhiyun mcr p15, 0, r6, c13, c0, 0 @ PID 551*4882a593Smuzhiyun mcr p15, 0, r7, c3, c0, 0 @ domain ID 552*4882a593Smuzhiyun mcr p15, 0, r1, c2, c0, 0 @ translation table base addr 553*4882a593Smuzhiyun mcr p15, 0, r8, c1, c0, 1 @ auxiliary control reg 554*4882a593Smuzhiyun mov r0, r9 @ control register 555*4882a593Smuzhiyun b cpu_resume_mmu 556*4882a593SmuzhiyunENDPROC(cpu_xscale_do_resume) 557*4882a593Smuzhiyun#endif 558*4882a593Smuzhiyun 559*4882a593Smuzhiyun .type __xscale_setup, #function 560*4882a593Smuzhiyun__xscale_setup: 561*4882a593Smuzhiyun mcr p15, 0, ip, c7, c7, 0 @ invalidate I, D caches & BTB 562*4882a593Smuzhiyun mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer 563*4882a593Smuzhiyun mcr p15, 0, ip, c8, c7, 0 @ invalidate I, D TLBs 564*4882a593Smuzhiyun mov r0, #1 << 6 @ cp6 for IOP3xx and Bulverde 565*4882a593Smuzhiyun orr r0, r0, #1 << 13 @ Its undefined whether this 566*4882a593Smuzhiyun mcr p15, 0, r0, c15, c1, 0 @ affects USR or SVC modes 567*4882a593Smuzhiyun 568*4882a593Smuzhiyun adr r5, xscale_crval 569*4882a593Smuzhiyun ldmia r5, {r5, r6} 570*4882a593Smuzhiyun mrc p15, 0, r0, c1, c0, 0 @ get control register 571*4882a593Smuzhiyun bic r0, r0, r5 572*4882a593Smuzhiyun orr r0, r0, r6 573*4882a593Smuzhiyun ret lr 574*4882a593Smuzhiyun .size __xscale_setup, . - __xscale_setup 575*4882a593Smuzhiyun 576*4882a593Smuzhiyun /* 577*4882a593Smuzhiyun * R 578*4882a593Smuzhiyun * .RVI ZFRS BLDP WCAM 579*4882a593Smuzhiyun * ..11 1.01 .... .101 580*4882a593Smuzhiyun * 581*4882a593Smuzhiyun */ 582*4882a593Smuzhiyun .type xscale_crval, #object 583*4882a593Smuzhiyunxscale_crval: 584*4882a593Smuzhiyun crval clear=0x00003b07, mmuset=0x00003905, ucset=0x00001900 585*4882a593Smuzhiyun 586*4882a593Smuzhiyun __INITDATA 587*4882a593Smuzhiyun 588*4882a593Smuzhiyun @ define struct processor (see <asm/proc-fns.h> and proc-macros.S) 589*4882a593Smuzhiyun define_processor_functions xscale, dabort=v5t_early_abort, pabort=legacy_pabort, suspend=1 590*4882a593Smuzhiyun 591*4882a593Smuzhiyun .section ".rodata" 592*4882a593Smuzhiyun 593*4882a593Smuzhiyun string cpu_arch_name, "armv5te" 594*4882a593Smuzhiyun string cpu_elf_name, "v5" 595*4882a593Smuzhiyun 596*4882a593Smuzhiyun string cpu_80200_A0_A1_name, "XScale-80200 A0/A1" 597*4882a593Smuzhiyun string cpu_80200_name, "XScale-80200" 598*4882a593Smuzhiyun string cpu_80219_name, "XScale-80219" 599*4882a593Smuzhiyun string cpu_8032x_name, "XScale-IOP8032x Family" 600*4882a593Smuzhiyun string cpu_8033x_name, "XScale-IOP8033x Family" 601*4882a593Smuzhiyun string cpu_pxa250_name, "XScale-PXA250" 602*4882a593Smuzhiyun string cpu_pxa210_name, "XScale-PXA210" 603*4882a593Smuzhiyun string cpu_ixp42x_name, "XScale-IXP42x Family" 604*4882a593Smuzhiyun string cpu_ixp43x_name, "XScale-IXP43x Family" 605*4882a593Smuzhiyun string cpu_ixp46x_name, "XScale-IXP46x Family" 606*4882a593Smuzhiyun string cpu_ixp2400_name, "XScale-IXP2400" 607*4882a593Smuzhiyun string cpu_ixp2800_name, "XScale-IXP2800" 608*4882a593Smuzhiyun string cpu_pxa255_name, "XScale-PXA255" 609*4882a593Smuzhiyun string cpu_pxa270_name, "XScale-PXA270" 610*4882a593Smuzhiyun 611*4882a593Smuzhiyun .align 612*4882a593Smuzhiyun 613*4882a593Smuzhiyun .section ".proc.info.init", "a" 614*4882a593Smuzhiyun 615*4882a593Smuzhiyun.macro xscale_proc_info name:req, cpu_val:req, cpu_mask:req, cpu_name:req, cache 616*4882a593Smuzhiyun .type __\name\()_proc_info,#object 617*4882a593Smuzhiyun__\name\()_proc_info: 618*4882a593Smuzhiyun .long \cpu_val 619*4882a593Smuzhiyun .long \cpu_mask 620*4882a593Smuzhiyun .long PMD_TYPE_SECT | \ 621*4882a593Smuzhiyun PMD_SECT_BUFFERABLE | \ 622*4882a593Smuzhiyun PMD_SECT_CACHEABLE | \ 623*4882a593Smuzhiyun PMD_SECT_AP_WRITE | \ 624*4882a593Smuzhiyun PMD_SECT_AP_READ 625*4882a593Smuzhiyun .long PMD_TYPE_SECT | \ 626*4882a593Smuzhiyun PMD_SECT_AP_WRITE | \ 627*4882a593Smuzhiyun PMD_SECT_AP_READ 628*4882a593Smuzhiyun initfn __xscale_setup, __\name\()_proc_info 629*4882a593Smuzhiyun .long cpu_arch_name 630*4882a593Smuzhiyun .long cpu_elf_name 631*4882a593Smuzhiyun .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP 632*4882a593Smuzhiyun .long \cpu_name 633*4882a593Smuzhiyun .long xscale_processor_functions 634*4882a593Smuzhiyun .long v4wbi_tlb_fns 635*4882a593Smuzhiyun .long xscale_mc_user_fns 636*4882a593Smuzhiyun .ifb \cache 637*4882a593Smuzhiyun .long xscale_cache_fns 638*4882a593Smuzhiyun .else 639*4882a593Smuzhiyun .long \cache 640*4882a593Smuzhiyun .endif 641*4882a593Smuzhiyun .size __\name\()_proc_info, . - __\name\()_proc_info 642*4882a593Smuzhiyun.endm 643*4882a593Smuzhiyun 644*4882a593Smuzhiyun xscale_proc_info 80200_A0_A1, 0x69052000, 0xfffffffe, cpu_80200_name, \ 645*4882a593Smuzhiyun cache=xscale_80200_A0_A1_cache_fns 646*4882a593Smuzhiyun xscale_proc_info 80200, 0x69052000, 0xfffffff0, cpu_80200_name 647*4882a593Smuzhiyun xscale_proc_info 80219, 0x69052e20, 0xffffffe0, cpu_80219_name 648*4882a593Smuzhiyun xscale_proc_info 8032x, 0x69052420, 0xfffff7e0, cpu_8032x_name 649*4882a593Smuzhiyun xscale_proc_info 8033x, 0x69054010, 0xfffffd30, cpu_8033x_name 650*4882a593Smuzhiyun xscale_proc_info pxa250, 0x69052100, 0xfffff7f0, cpu_pxa250_name 651*4882a593Smuzhiyun xscale_proc_info pxa210, 0x69052120, 0xfffff3f0, cpu_pxa210_name 652*4882a593Smuzhiyun xscale_proc_info ixp2400, 0x69054190, 0xfffffff0, cpu_ixp2400_name 653*4882a593Smuzhiyun xscale_proc_info ixp2800, 0x690541a0, 0xfffffff0, cpu_ixp2800_name 654*4882a593Smuzhiyun xscale_proc_info ixp42x, 0x690541c0, 0xffffffc0, cpu_ixp42x_name 655*4882a593Smuzhiyun xscale_proc_info ixp43x, 0x69054040, 0xfffffff0, cpu_ixp43x_name 656*4882a593Smuzhiyun xscale_proc_info ixp46x, 0x69054200, 0xffffff00, cpu_ixp46x_name 657*4882a593Smuzhiyun xscale_proc_info pxa255, 0x69052d00, 0xfffffff0, cpu_pxa255_name 658*4882a593Smuzhiyun xscale_proc_info pxa270, 0x69054110, 0xfffffff0, cpu_pxa270_name 659