1/* SPDX-License-Identifier: GPL-2.0-or-later */ 2/* 3 * linux/arch/arm/mm/proc-arm922.S: MMU functions for ARM922 4 * 5 * Copyright (C) 1999,2000 ARM Limited 6 * Copyright (C) 2000 Deep Blue Solutions Ltd. 7 * Copyright (C) 2001 Altera Corporation 8 * hacked for non-paged-MM by Hyok S. Choi, 2003. 9 * 10 * These are the low level assembler for performing cache and TLB 11 * functions on the arm922. 12 */ 13#include <linux/linkage.h> 14#include <linux/init.h> 15#include <linux/cfi_types.h> 16#include <linux/pgtable.h> 17#include <asm/assembler.h> 18#include <asm/hwcap.h> 19#include <asm/pgtable-hwdef.h> 20#include <asm/page.h> 21#include <asm/ptrace.h> 22#include "proc-macros.S" 23 24/* 25 * The size of one data cache line. 26 */ 27#define CACHE_DLINESIZE 32 28 29/* 30 * The number of data cache segments. 31 */ 32#define CACHE_DSEGMENTS 4 33 34/* 35 * The number of lines in a cache segment. 36 */ 37#define CACHE_DENTRIES 64 38 39/* 40 * This is the size at which it becomes more efficient to 41 * clean the whole cache, rather than using the individual 42 * cache line maintenance instructions. (I think this should 43 * be 32768). 44 */ 45#define CACHE_DLIMIT 8192 46 47 48 .text 49/* 50 * cpu_arm922_proc_init() 51 */ 52SYM_TYPED_FUNC_START(cpu_arm922_proc_init) 53 ret lr 54SYM_FUNC_END(cpu_arm922_proc_init) 55 56/* 57 * cpu_arm922_proc_fin() 58 */ 59SYM_TYPED_FUNC_START(cpu_arm922_proc_fin) 60 mrc p15, 0, r0, c1, c0, 0 @ ctrl register 61 bic r0, r0, #0x1000 @ ...i............ 62 bic r0, r0, #0x000e @ ............wca. 63 mcr p15, 0, r0, c1, c0, 0 @ disable caches 64 ret lr 65SYM_FUNC_END(cpu_arm922_proc_fin) 66 67/* 68 * cpu_arm922_reset(loc) 69 * 70 * Perform a soft reset of the system. Put the CPU into the 71 * same state as it would be if it had been reset, and branch 72 * to what would be the reset vector. 73 * 74 * loc: location to jump to for soft reset 75 */ 76 .align 5 77 .pushsection .idmap.text, "ax" 78SYM_TYPED_FUNC_START(cpu_arm922_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 ret r0 90SYM_FUNC_END(cpu_arm922_reset) 91 .popsection 92 93/* 94 * cpu_arm922_do_idle() 95 */ 96 .align 5 97SYM_TYPED_FUNC_START(cpu_arm922_do_idle) 98 mcr p15, 0, r0, c7, c0, 4 @ Wait for interrupt 99 ret lr 100SYM_FUNC_END(cpu_arm922_do_idle) 101 102#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH 103 104/* 105 * flush_icache_all() 106 * 107 * Unconditionally clean and invalidate the entire icache. 108 */ 109SYM_TYPED_FUNC_START(arm922_flush_icache_all) 110 mov r0, #0 111 mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache 112 ret lr 113SYM_FUNC_END(arm922_flush_icache_all) 114 115/* 116 * flush_user_cache_all() 117 * 118 * Clean and invalidate all cache entries in a particular 119 * address space. 120 */ 121SYM_FUNC_ALIAS(arm922_flush_user_cache_all, arm922_flush_kern_cache_all) 122 123/* 124 * flush_kern_cache_all() 125 * 126 * Clean and invalidate the entire cache. 127 */ 128SYM_TYPED_FUNC_START(arm922_flush_kern_cache_all) 129 mov r2, #VM_EXEC 130 mov ip, #0 131__flush_whole_cache: 132 mov r1, #(CACHE_DSEGMENTS - 1) << 5 @ 8 segments 1331: orr r3, r1, #(CACHE_DENTRIES - 1) << 26 @ 64 entries 1342: mcr p15, 0, r3, c7, c14, 2 @ clean+invalidate D index 135 subs r3, r3, #1 << 26 136 bcs 2b @ entries 63 to 0 137 subs r1, r1, #1 << 5 138 bcs 1b @ segments 7 to 0 139 tst r2, #VM_EXEC 140 mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache 141 mcrne p15, 0, ip, c7, c10, 4 @ drain WB 142 ret lr 143SYM_FUNC_END(arm922_flush_kern_cache_all) 144 145/* 146 * flush_user_cache_range(start, end, flags) 147 * 148 * Clean and invalidate a range of cache entries in the 149 * specified address range. 150 * 151 * - start - start address (inclusive) 152 * - end - end address (exclusive) 153 * - flags - vm_flags describing address space 154 */ 155SYM_TYPED_FUNC_START(arm922_flush_user_cache_range) 156 mov ip, #0 157 sub r3, r1, r0 @ calculate total size 158 cmp r3, #CACHE_DLIMIT 159 bhs __flush_whole_cache 160 1611: mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry 162 tst r2, #VM_EXEC 163 mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry 164 add r0, r0, #CACHE_DLINESIZE 165 cmp r0, r1 166 blo 1b 167 tst r2, #VM_EXEC 168 mcrne p15, 0, ip, c7, c10, 4 @ drain WB 169 ret lr 170SYM_FUNC_END(arm922_flush_user_cache_range) 171 172/* 173 * coherent_kern_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 */ 182SYM_TYPED_FUNC_START(arm922_coherent_kern_range) 183#ifdef CONFIG_CFI /* Fallthrough if !CFI */ 184 b arm922_coherent_user_range 185#endif 186SYM_FUNC_END(arm922_coherent_kern_range) 187 188/* 189 * coherent_user_range(start, end) 190 * 191 * Ensure coherency between the Icache and the Dcache in the 192 * region described by start, end. If you have non-snooping 193 * Harvard caches, you need to implement this function. 194 * 195 * - start - virtual start address 196 * - end - virtual end address 197 */ 198SYM_TYPED_FUNC_START(arm922_coherent_user_range) 199 bic r0, r0, #CACHE_DLINESIZE - 1 2001: mcr p15, 0, r0, c7, c10, 1 @ clean D entry 201 mcr p15, 0, r0, c7, c5, 1 @ invalidate I entry 202 add r0, r0, #CACHE_DLINESIZE 203 cmp r0, r1 204 blo 1b 205 mcr p15, 0, r0, c7, c10, 4 @ drain WB 206 mov r0, #0 207 ret lr 208SYM_FUNC_END(arm922_coherent_user_range) 209 210/* 211 * flush_kern_dcache_area(void *addr, size_t size) 212 * 213 * Ensure no D cache aliasing occurs, either with itself or 214 * the I cache 215 * 216 * - addr - kernel address 217 * - size - region size 218 */ 219SYM_TYPED_FUNC_START(arm922_flush_kern_dcache_area) 220 add r1, r0, r1 2211: mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry 222 add r0, r0, #CACHE_DLINESIZE 223 cmp r0, r1 224 blo 1b 225 mov r0, #0 226 mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache 227 mcr p15, 0, r0, c7, c10, 4 @ drain WB 228 ret lr 229SYM_FUNC_END(arm922_flush_kern_dcache_area) 230 231/* 232 * dma_inv_range(start, end) 233 * 234 * Invalidate (discard) the specified virtual address range. 235 * May not write back any entries. If 'start' or 'end' 236 * are not cache line aligned, those lines must be written 237 * back. 238 * 239 * - start - virtual start address 240 * - end - virtual end address 241 * 242 * (same as v4wb) 243 */ 244arm922_dma_inv_range: 245 tst r0, #CACHE_DLINESIZE - 1 246 bic r0, r0, #CACHE_DLINESIZE - 1 247 mcrne p15, 0, r0, c7, c10, 1 @ clean D entry 248 tst r1, #CACHE_DLINESIZE - 1 249 mcrne p15, 0, r1, c7, c10, 1 @ clean D entry 2501: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry 251 add r0, r0, #CACHE_DLINESIZE 252 cmp r0, r1 253 blo 1b 254 mcr p15, 0, r0, c7, c10, 4 @ drain WB 255 ret lr 256 257/* 258 * dma_clean_range(start, end) 259 * 260 * Clean the specified virtual address range. 261 * 262 * - start - virtual start address 263 * - end - virtual end address 264 * 265 * (same as v4wb) 266 */ 267arm922_dma_clean_range: 268 bic r0, r0, #CACHE_DLINESIZE - 1 2691: mcr p15, 0, r0, c7, c10, 1 @ clean D entry 270 add r0, r0, #CACHE_DLINESIZE 271 cmp r0, r1 272 blo 1b 273 mcr p15, 0, r0, c7, c10, 4 @ drain WB 274 ret lr 275 276/* 277 * dma_flush_range(start, end) 278 * 279 * Clean and invalidate the specified virtual address range. 280 * 281 * - start - virtual start address 282 * - end - virtual end address 283 */ 284SYM_TYPED_FUNC_START(arm922_dma_flush_range) 285 bic r0, r0, #CACHE_DLINESIZE - 1 2861: mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry 287 add r0, r0, #CACHE_DLINESIZE 288 cmp r0, r1 289 blo 1b 290 mcr p15, 0, r0, c7, c10, 4 @ drain WB 291 ret lr 292SYM_FUNC_END(arm922_dma_flush_range) 293 294/* 295 * dma_map_area(start, size, dir) 296 * - start - kernel virtual start address 297 * - size - size of region 298 * - dir - DMA direction 299 */ 300SYM_TYPED_FUNC_START(arm922_dma_map_area) 301 add r1, r1, r0 302 cmp r2, #DMA_TO_DEVICE 303 beq arm922_dma_clean_range 304 bcs arm922_dma_inv_range 305 b arm922_dma_flush_range 306SYM_FUNC_END(arm922_dma_map_area) 307 308/* 309 * dma_unmap_area(start, size, dir) 310 * - start - kernel virtual start address 311 * - size - size of region 312 * - dir - DMA direction 313 */ 314SYM_TYPED_FUNC_START(arm922_dma_unmap_area) 315 ret lr 316SYM_FUNC_END(arm922_dma_unmap_area) 317 318#endif /* !CONFIG_CPU_DCACHE_WRITETHROUGH */ 319 320SYM_TYPED_FUNC_START(cpu_arm922_dcache_clean_area) 321#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH 3221: mcr p15, 0, r0, c7, c10, 1 @ clean D entry 323 add r0, r0, #CACHE_DLINESIZE 324 subs r1, r1, #CACHE_DLINESIZE 325 bhi 1b 326#endif 327 ret lr 328SYM_FUNC_END(cpu_arm922_dcache_clean_area) 329 330/* =============================== PageTable ============================== */ 331 332/* 333 * cpu_arm922_switch_mm(pgd) 334 * 335 * Set the translation base pointer to be as described by pgd. 336 * 337 * pgd: new page tables 338 */ 339 .align 5 340SYM_TYPED_FUNC_START(cpu_arm922_switch_mm) 341#ifdef CONFIG_MMU 342 mov ip, #0 343#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH 344 mcr p15, 0, ip, c7, c6, 0 @ invalidate D cache 345#else 346@ && 'Clean & Invalidate whole DCache' 347@ && Re-written to use Index Ops. 348@ && Uses registers r1, r3 and ip 349 350 mov r1, #(CACHE_DSEGMENTS - 1) << 5 @ 4 segments 3511: orr r3, r1, #(CACHE_DENTRIES - 1) << 26 @ 64 entries 3522: mcr p15, 0, r3, c7, c14, 2 @ clean & invalidate D index 353 subs r3, r3, #1 << 26 354 bcs 2b @ entries 63 to 0 355 subs r1, r1, #1 << 5 356 bcs 1b @ segments 7 to 0 357#endif 358 mcr p15, 0, ip, c7, c5, 0 @ invalidate I cache 359 mcr p15, 0, ip, c7, c10, 4 @ drain WB 360 mcr p15, 0, r0, c2, c0, 0 @ load page table pointer 361 mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs 362#endif 363 ret lr 364SYM_FUNC_END(cpu_arm922_switch_mm) 365 366/* 367 * cpu_arm922_set_pte_ext(ptep, pte, ext) 368 * 369 * Set a PTE and flush it out 370 */ 371 .align 5 372SYM_TYPED_FUNC_START(cpu_arm922_set_pte_ext) 373#ifdef CONFIG_MMU 374 armv3_set_pte_ext 375 mov r0, r0 376 mcr p15, 0, r0, c7, c10, 1 @ clean D entry 377 mcr p15, 0, r0, c7, c10, 4 @ drain WB 378#endif /* CONFIG_MMU */ 379 ret lr 380SYM_FUNC_END(cpu_arm922_set_pte_ext) 381 382 .type __arm922_setup, #function 383__arm922_setup: 384 mov r0, #0 385 mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4 386 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4 387#ifdef CONFIG_MMU 388 mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4 389#endif 390 adr r5, arm922_crval 391 ldmia r5, {r5, r6} 392 mrc p15, 0, r0, c1, c0 @ get control register v4 393 bic r0, r0, r5 394 orr r0, r0, r6 395 ret lr 396 .size __arm922_setup, . - __arm922_setup 397 398 /* 399 * R 400 * .RVI ZFRS BLDP WCAM 401 * ..11 0001 ..11 0101 402 * 403 */ 404 .type arm922_crval, #object 405arm922_crval: 406 crval clear=0x00003f3f, mmuset=0x00003135, ucset=0x00001130 407 408 __INITDATA 409 @ define struct processor (see <asm/proc-fns.h> and proc-macros.S) 410 define_processor_functions arm922, dabort=v4t_early_abort, pabort=legacy_pabort 411 412 .section ".rodata" 413 414 string cpu_arch_name, "armv4t" 415 string cpu_elf_name, "v4" 416 string cpu_arm922_name, "ARM922T" 417 418 .align 419 420 .section ".proc.info.init", "a" 421 422 .type __arm922_proc_info,#object 423__arm922_proc_info: 424 .long 0x41009220 425 .long 0xff00fff0 426 .long PMD_TYPE_SECT | \ 427 PMD_SECT_BUFFERABLE | \ 428 PMD_SECT_CACHEABLE | \ 429 PMD_BIT4 | \ 430 PMD_SECT_AP_WRITE | \ 431 PMD_SECT_AP_READ 432 .long PMD_TYPE_SECT | \ 433 PMD_BIT4 | \ 434 PMD_SECT_AP_WRITE | \ 435 PMD_SECT_AP_READ 436 initfn __arm922_setup, __arm922_proc_info 437 .long cpu_arch_name 438 .long cpu_elf_name 439 .long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB 440 .long cpu_arm922_name 441 .long arm922_processor_functions 442 .long v4wbi_tlb_fns 443 .long v4wb_user_fns 444#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH 445 .long arm922_cache_fns 446#else 447 .long v4wt_cache_fns 448#endif 449 .size __arm922_proc_info, . - __arm922_proc_info 450