1/* 2 * linux/arch/arm/mm/proc-v6.S 3 * 4 * Copyright (C) 2001 Deep Blue Solutions Ltd. 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. 9 * 10 * This is the "shell" of the ARMv6 processor support. 11 */ 12#include <linux/linkage.h> 13#include <asm/assembler.h> 14#include <asm/asm-offsets.h> 15#include <asm/hardware/arm_scu.h> 16#include <asm/procinfo.h> 17#include <asm/pgtable.h> 18 19#include "proc-macros.S" 20 21#define D_CACHE_LINE_SIZE 32 22 23 .macro cpsie, flags 24 .ifc \flags, f 25 .long 0xf1080040 26 .exitm 27 .endif 28 .ifc \flags, i 29 .long 0xf1080080 30 .exitm 31 .endif 32 .ifc \flags, if 33 .long 0xf10800c0 34 .exitm 35 .endif 36 .err 37 .endm 38 39 .macro cpsid, flags 40 .ifc \flags, f 41 .long 0xf10c0040 42 .exitm 43 .endif 44 .ifc \flags, i 45 .long 0xf10c0080 46 .exitm 47 .endif 48 .ifc \flags, if 49 .long 0xf10c00c0 50 .exitm 51 .endif 52 .err 53 .endm 54 55ENTRY(cpu_v6_proc_init) 56 mov pc, lr 57 58ENTRY(cpu_v6_proc_fin) 59 stmfd sp!, {lr} 60 cpsid if @ disable interrupts 61 bl v6_flush_kern_cache_all 62 mrc p15, 0, r0, c1, c0, 0 @ ctrl register 63 bic r0, r0, #0x1000 @ ...i............ 64 bic r0, r0, #0x0006 @ .............ca. 65 mcr p15, 0, r0, c1, c0, 0 @ disable caches 66 ldmfd sp!, {pc} 67 68/* 69 * cpu_v6_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 * It is assumed that: 78 */ 79 .align 5 80ENTRY(cpu_v6_reset) 81 mov pc, r0 82 83/* 84 * cpu_v6_do_idle() 85 * 86 * Idle the processor (eg, wait for interrupt). 87 * 88 * IRQs are already disabled. 89 */ 90ENTRY(cpu_v6_do_idle) 91 mcr p15, 0, r1, c7, c0, 4 @ wait for interrupt 92 mov pc, lr 93 94ENTRY(cpu_v6_dcache_clean_area) 95#ifndef TLB_CAN_READ_FROM_L1_CACHE 961: mcr p15, 0, r0, c7, c10, 1 @ clean D entry 97 add r0, r0, #D_CACHE_LINE_SIZE 98 subs r1, r1, #D_CACHE_LINE_SIZE 99 bhi 1b 100#endif 101 mov pc, lr 102 103/* 104 * cpu_arm926_switch_mm(pgd_phys, tsk) 105 * 106 * Set the translation table base pointer to be pgd_phys 107 * 108 * - pgd_phys - physical address of new TTB 109 * 110 * It is assumed that: 111 * - we are not using split page tables 112 */ 113ENTRY(cpu_v6_switch_mm) 114 mov r2, #0 115 ldr r1, [r1, #MM_CONTEXT_ID] @ get mm->context.id 116#ifdef CONFIG_SMP 117 orr r0, r0, #2 @ set shared pgtable 118#endif 119 mcr p15, 0, r2, c7, c5, 6 @ flush BTAC/BTB 120 mcr p15, 0, r2, c7, c10, 4 @ drain write buffer 121 mcr p15, 0, r0, c2, c0, 0 @ set TTB 0 122 mcr p15, 0, r1, c13, c0, 1 @ set context ID 123 mov pc, lr 124 125/* 126 * cpu_v6_set_pte(ptep, pte) 127 * 128 * Set a level 2 translation table entry. 129 * 130 * - ptep - pointer to level 2 translation table entry 131 * (hardware version is stored at -1024 bytes) 132 * - pte - PTE value to store 133 * 134 * Permissions: 135 * YUWD APX AP1 AP0 SVC User 136 * 0xxx 0 0 0 no acc no acc 137 * 100x 1 0 1 r/o no acc 138 * 10x0 1 0 1 r/o no acc 139 * 1011 0 0 1 r/w no acc 140 * 110x 0 1 0 r/w r/o 141 * 11x0 0 1 0 r/w r/o 142 * 1111 0 1 1 r/w r/w 143 */ 144ENTRY(cpu_v6_set_pte) 145 str r1, [r0], #-2048 @ linux version 146 147 bic r2, r1, #0x000003f0 148 bic r2, r2, #0x00000003 149 orr r2, r2, #PTE_EXT_AP0 | 2 150 151 tst r1, #L_PTE_WRITE 152 tstne r1, #L_PTE_DIRTY 153 orreq r2, r2, #PTE_EXT_APX 154 155 tst r1, #L_PTE_USER 156 orrne r2, r2, #PTE_EXT_AP1 157 tstne r2, #PTE_EXT_APX 158 bicne r2, r2, #PTE_EXT_APX | PTE_EXT_AP0 159 160 tst r1, #L_PTE_YOUNG 161 biceq r2, r2, #PTE_EXT_APX | PTE_EXT_AP_MASK 162 163@ tst r1, #L_PTE_EXEC 164@ orreq r2, r2, #PTE_EXT_XN 165 166 tst r1, #L_PTE_PRESENT 167 moveq r2, #0 168 169 str r2, [r0] 170 mcr p15, 0, r0, c7, c10, 1 @ flush_pte 171 mov pc, lr 172 173 174 175 176cpu_v6_name: 177 .asciz "Some Random V6 Processor" 178 .align 179 180 .section ".text.init", #alloc, #execinstr 181 182/* 183 * __v6_setup 184 * 185 * Initialise TLB, Caches, and MMU state ready to switch the MMU 186 * on. Return in r0 the new CP15 C1 control register setting. 187 * 188 * We automatically detect if we have a Harvard cache, and use the 189 * Harvard cache control instructions insead of the unified cache 190 * control instructions. 191 * 192 * This should be able to cover all ARMv6 cores. 193 * 194 * It is assumed that: 195 * - cache type register is implemented 196 */ 197__v6_setup: 198#ifdef CONFIG_SMP 199 /* Set up the SCU on core 0 only */ 200 mrc p15, 0, r0, c0, c0, 5 @ CPU core number 201 ands r0, r0, #15 202 moveq r0, #0x10000000 @ SCU_BASE 203 orreq r0, r0, #0x00100000 204 ldreq r5, [r0, #SCU_CTRL] 205 orreq r5, r5, #1 206 streq r5, [r0, #SCU_CTRL] 207 208#ifndef CONFIG_CPU_DCACHE_DISABLE 209 mrc p15, 0, r0, c1, c0, 1 @ Enable SMP/nAMP mode 210 orr r0, r0, #0x20 211 mcr p15, 0, r0, c1, c0, 1 212#endif 213#endif 214 215 mov r0, #0 216 mcr p15, 0, r0, c7, c14, 0 @ clean+invalidate D cache 217 mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache 218 mcr p15, 0, r0, c7, c15, 0 @ clean+invalidate cache 219 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer 220 mcr p15, 0, r0, c8, c7, 0 @ invalidate I + D TLBs 221 mcr p15, 0, r0, c2, c0, 2 @ TTB control register 222#ifdef CONFIG_SMP 223 orr r4, r4, #2 @ set shared pgtable 224#endif 225 mcr p15, 0, r4, c2, c0, 1 @ load TTB1 226#ifdef CONFIG_VFP 227 mrc p15, 0, r0, c1, c0, 2 228 orr r0, r0, #(0xf << 20) 229 mcr p15, 0, r0, c1, c0, 2 @ Enable full access to VFP 230#endif 231 mrc p15, 0, r0, c1, c0, 0 @ read control register 232 ldr r5, v6_cr1_clear @ get mask for bits to clear 233 bic r0, r0, r5 @ clear bits them 234 ldr r5, v6_cr1_set @ get mask for bits to set 235 orr r0, r0, r5 @ set them 236 mov pc, lr @ return to head.S:__ret 237 238 /* 239 * V X F I D LR 240 * .... ...E PUI. .T.T 4RVI ZFRS BLDP WCAM 241 * rrrr rrrx xxx0 0101 xxxx xxxx x111 xxxx < forced 242 * 0 110 0011 1.00 .111 1101 < we want 243 */ 244 .type v6_cr1_clear, #object 245 .type v6_cr1_set, #object 246v6_cr1_clear: 247 .word 0x01e0fb7f 248v6_cr1_set: 249 .word 0x00c0387d 250 251 .type v6_processor_functions, #object 252ENTRY(v6_processor_functions) 253 .word v6_early_abort 254 .word cpu_v6_proc_init 255 .word cpu_v6_proc_fin 256 .word cpu_v6_reset 257 .word cpu_v6_do_idle 258 .word cpu_v6_dcache_clean_area 259 .word cpu_v6_switch_mm 260 .word cpu_v6_set_pte 261 .size v6_processor_functions, . - v6_processor_functions 262 263 .type cpu_arch_name, #object 264cpu_arch_name: 265 .asciz "armv6" 266 .size cpu_arch_name, . - cpu_arch_name 267 268 .type cpu_elf_name, #object 269cpu_elf_name: 270 .asciz "v6" 271 .size cpu_elf_name, . - cpu_elf_name 272 .align 273 274 .section ".proc.info.init", #alloc, #execinstr 275 276 /* 277 * Match any ARMv6 processor core. 278 */ 279 .type __v6_proc_info, #object 280__v6_proc_info: 281 .long 0x0007b000 282 .long 0x0007f000 283 .long PMD_TYPE_SECT | \ 284 PMD_SECT_BUFFERABLE | \ 285 PMD_SECT_CACHEABLE | \ 286 PMD_SECT_AP_WRITE | \ 287 PMD_SECT_AP_READ 288 b __v6_setup 289 .long cpu_arch_name 290 .long cpu_elf_name 291 .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_VFP|HWCAP_EDSP|HWCAP_JAVA 292 .long cpu_v6_name 293 .long v6_processor_functions 294 .long v6wbi_tlb_fns 295 .long v6_user_fns 296 .long v6_cache_fns 297 .size __v6_proc_info, . - __v6_proc_info 298