1/* $NetBSD: cpufunc_asm_xscale.S,v 1.25 2022/10/20 06:58:38 skrll Exp $ */ 2 3/* 4 * Copyright (c) 2001, 2002 Wasabi Systems, Inc. 5 * All rights reserved. 6 * 7 * Written by Allen Briggs and Jason R. Thorpe for Wasabi Systems, Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed for the NetBSD Project by 20 * Wasabi Systems, Inc. 21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 * or promote products derived from this software without specific prior 23 * written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38/* 39 * Copyright (c) 2001 Matt Thomas. 40 * Copyright (c) 1997,1998 Mark Brinicombe. 41 * Copyright (c) 1997 Causality Limited 42 * All rights reserved. 43 * 44 * Redistribution and use in source and binary forms, with or without 45 * modification, are permitted provided that the following conditions 46 * are met: 47 * 1. Redistributions of source code must retain the above copyright 48 * notice, this list of conditions and the following disclaimer. 49 * 2. Redistributions in binary form must reproduce the above copyright 50 * notice, this list of conditions and the following disclaimer in the 51 * documentation and/or other materials provided with the distribution. 52 * 3. All advertising materials mentioning features or use of this software 53 * must display the following acknowledgement: 54 * This product includes software developed by Causality Limited. 55 * 4. The name of Causality Limited may not be used to endorse or promote 56 * products derived from this software without specific prior written 57 * permission. 58 * 59 * THIS SOFTWARE IS PROVIDED BY CAUSALITY LIMITED ``AS IS'' AND ANY EXPRESS 60 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 61 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 62 * DISCLAIMED. IN NO EVENT SHALL CAUSALITY LIMITED BE LIABLE FOR ANY DIRECT, 63 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 64 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 65 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 66 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 67 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 68 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 69 * SUCH DAMAGE. 70 * 71 * XScale assembly functions for CPU / MMU / TLB specific operations 72 */ 73 74#include "assym.h" 75#include <arm/asm.h> 76#include <arm/locore.h> 77 78/* 79 * Size of the XScale core D-cache. 80 */ 81#define XSCALE_DCACHE_SIZE 0x00008000 82 83.Lblock_userspace_access: 84 .word _C_LABEL(block_userspace_access) 85 86/* 87 * CPWAIT -- Canonical method to wait for CP15 update. 88 * From: Intel 80200 manual, section 2.3.3. 89 * 90 * NOTE: Clobbers the specified temp reg. 91 */ 92#define CPWAIT_BRANCH \ 93 sub pc, pc, #4 94 95#define CPWAIT(tmp) \ 96 mrc p15, 0, tmp, c2, c0, 0 /* arbitrary read of CP15 */ ;\ 97 mov tmp, tmp /* wait for it to complete */ ;\ 98 CPWAIT_BRANCH /* branch to next insn */ 99 100#define CPWAIT_AND_RETURN_SHIFTER lsr #32 101 102#define CPWAIT_AND_RETURN(tmp) \ 103 mrc p15, 0, tmp, c2, c0, 0 /* arbitrary read of CP15 */ ;\ 104 /* Wait for it to complete and branch to the return address */ \ 105 sub pc, lr, tmp, CPWAIT_AND_RETURN_SHIFTER 106 107ENTRY(xscale_cpwait) 108 CPWAIT_AND_RETURN(r0) 109END(xscale_cpwait) 110 111/* 112 * We need a separate cpu_control() entry point, since we have to 113 * invalidate the Branch Target Buffer in the event the BPRD bit 114 * changes in the control register. 115 */ 116ENTRY(xscale_control) 117 mrc p15, 0, r3, c1, c0, 0 /* Read the control register */ 118 bic r2, r3, r0 /* Clear bits */ 119 eor r2, r2, r1 /* XOR bits */ 120 121 teq r2, r3 /* Only write if there was a change */ 122 mcrne p15, 0, r0, c7, c5, 6 /* Invalidate the BTB */ 123 mcrne p15, 0, r2, c1, c0, 0 /* Write new control register */ 124 mov r0, r3 /* Return old value */ 125 126 CPWAIT_AND_RETURN(r1) 127END(xscale_control) 128 129/* 130 * Functions to set the MMU Translation Table Base register 131 * 132 * We need to clean and flush the cache as it uses virtual 133 * addresses that are about to change. 134 */ 135ENTRY(xscale_setttb) 136#ifdef CACHE_CLEAN_BLOCK_INTR 137 mrs r3, cpsr 138 orr r2, r3, #(I32_bit | F32_bit) 139 msr cpsr_all, r2 140#else 141 ldr r3, .Lblock_userspace_access 142 ldr r2, [r3] 143 orr ip, r2, #1 144 str ip, [r3] 145#endif 146 cmp r1, #0 /* flush cache/TLB? */ 147 beq 1f /* nope, so don't */ 148 stmfd sp!, {r0-r3, lr} 149 bl _C_LABEL(xscale_cache_cleanID) 150 mcr p15, 0, r0, c7, c5, 0 /* invalidate I$ and BTB */ 151 mcr p15, 0, r0, c7, c10, 4 /* drain write and fill buffer */ 152 153 CPWAIT(r0) 154 155 ldmfd sp!, {r0-r3, lr} 156 cmp r0, #1 157 1581: /* Write the TTB */ 159 mcr p15, 0, r0, c2, c0, 0 160 161 beq 2f /* nope, so don't */ 162 163 /* If we have updated the TTB we must flush the TLB */ 164 mcr p15, 0, r0, c8, c7, 0 /* invalidate I+D TLB */ 165 166 /* The cleanID above means we only need to flush the I cache here */ 167 mcr p15, 0, r0, c7, c5, 0 /* invalidate I$ and BTB */ 168 169 CPWAIT(r0) 170 1712: 172#ifdef CACHE_CLEAN_BLOCK_INTR 173 msr cpsr_all, r3 174#else 175 str r2, [r3] 176#endif 177 RET 178END(xscale_setttb) 179 180/* 181 * TLB functions 182 * 183 * Note: We don't need to worry about issuing a CPWAIT after 184 * TLB operations, because we expect a pmap_update() to follow. 185 */ 186ENTRY(xscale_tlb_flushID_SE) 187 mcr p15, 0, r0, c8, c6, 1 /* flush D tlb single entry */ 188 mcr p15, 0, r0, c8, c5, 1 /* flush I tlb single entry */ 189#if PAGE_SIZE == 2 * L2_S_SIZE 190 add r0, r0, #L2_S_SIZE 191 mcr p15, 0, r0, c8, c6, 1 /* flush D tlb single entry */ 192 mcr p15, 0, r0, c8, c5, 1 /* flush I tlb single entry */ 193#endif 194 RET 195END(xscale_tlb_flushID_SE) 196 197/* 198 * Cache functions 199 */ 200ENTRY(xscale_cache_flushID) 201 mcr p15, 0, r0, c7, c7, 0 /* flush I+D cache */ 202 CPWAIT_AND_RETURN(r0) 203END(xscale_cache_flushID) 204 205ENTRY(xscale_cache_flushI) 206 mcr p15, 0, r0, c7, c5, 0 /* flush I cache */ 207 CPWAIT_AND_RETURN(r0) 208END(xscale_cache_flushI) 209 210ENTRY(xscale_cache_flushD) 211 mcr p15, 0, r0, c7, c6, 0 /* flush D cache */ 212 CPWAIT_AND_RETURN(r0) 213END(xscale_cache_flushD) 214 215ENTRY(xscale_cache_flushI_SE) 216 mcr p15, 0, r0, c7, c5, 1 /* flush I cache single entry */ 217 CPWAIT_AND_RETURN(r0) 218END(xscale_cache_flushI_SE) 219 220ENTRY(xscale_cache_flushD_SE) 221 /* 222 * Errata (rev < 2): Must clean-dcache-line to an address 223 * before invalidate-dcache-line to an address, or dirty 224 * bits will not be cleared in the dcache array. 225 */ 226 mcr p15, 0, r0, c7, c10, 1 227 mcr p15, 0, r0, c7, c6, 1 /* flush D cache single entry */ 228 CPWAIT_AND_RETURN(r0) 229END(xscale_cache_flushD_SE) 230 231ENTRY(xscale_cache_cleanD_E) 232 mcr p15, 0, r0, c7, c10, 1 /* clean D cache entry */ 233 CPWAIT_AND_RETURN(r0) 234END(xscale_cache_cleanD_E) 235 236/* 237 * Information for the XScale cache clean/purge functions: 238 * 239 * * Virtual address of the memory region to use 240 * * Size of memory region 241 * 242 * Note the virtual address for the Data cache clean operation 243 * does not need to be backed by physical memory, since no loads 244 * will actually be performed by the allocate-line operation. 245 * 246 * Note that the Mini-Data cache MUST be cleaned by executing 247 * loads from memory mapped into a region reserved exclusively 248 * for cleaning of the Mini-Data cache. 249 */ 250 .data 251 252 .global _C_LABEL(xscale_cache_clean_addr) 253_C_LABEL(xscale_cache_clean_addr): 254 .word 0x00000000 255 256 .global _C_LABEL(xscale_cache_clean_size) 257_C_LABEL(xscale_cache_clean_size): 258 .word XSCALE_DCACHE_SIZE 259 260 .global _C_LABEL(xscale_minidata_clean_addr) 261_C_LABEL(xscale_minidata_clean_addr): 262 .word 0x00000000 263 264 .global _C_LABEL(xscale_minidata_clean_size) 265_C_LABEL(xscale_minidata_clean_size): 266 .word 0x00000800 267 268 .text 269 270.Lxscale_cache_clean_addr: 271 .word _C_LABEL(xscale_cache_clean_addr) 272.Lxscale_cache_clean_size: 273 .word _C_LABEL(xscale_cache_clean_size) 274 275.Lxscale_minidata_clean_addr: 276 .word _C_LABEL(xscale_minidata_clean_addr) 277.Lxscale_minidata_clean_size: 278 .word _C_LABEL(xscale_minidata_clean_size) 279 280#ifdef CACHE_CLEAN_BLOCK_INTR 281#define XSCALE_CACHE_CLEAN_BLOCK \ 282 mrs r3, cpsr ; \ 283 orr r0, r3, #(I32_bit | F32_bit) ; \ 284 msr cpsr_all, r0 285 286#define XSCALE_CACHE_CLEAN_UNBLOCK \ 287 msr cpsr_all, r3 288#else 289#define XSCALE_CACHE_CLEAN_BLOCK \ 290 ldr r3, .Lblock_userspace_access ; \ 291 ldr ip, [r3] ; \ 292 orr r0, ip, #1 ; \ 293 str r0, [r3] 294 295#define XSCALE_CACHE_CLEAN_UNBLOCK \ 296 str ip, [r3] 297#endif /* CACHE_CLEAN_BLOCK_INTR */ 298 299#define XSCALE_CACHE_CLEAN_PROLOGUE \ 300 XSCALE_CACHE_CLEAN_BLOCK ; \ 301 ldr r2, .Lxscale_cache_clean_addr ; \ 302 ldmia r2, {r0, r1} ; \ 303 /* \ 304 * BUG ALERT! \ 305 * \ 306 * The XScale core has a strange cache eviction bug, which \ 307 * requires us to use 2x the cache size for the cache clean \ 308 * and for that area to be aligned to 2 * cache size. \ 309 * \ 310 * The work-around is to use 2 areas for cache clean, and to \ 311 * alternate between them whenever this is done. No one knows \ 312 * why the work-around works (mmm!). \ 313 */ \ 314 eor r0, r0, #(XSCALE_DCACHE_SIZE) ; \ 315 str r0, [r2] ; \ 316 add r0, r0, r1 317 318#define XSCALE_CACHE_CLEAN_EPILOGUE \ 319 XSCALE_CACHE_CLEAN_UNBLOCK 320 321ENTRY_NP(xscale_cache_syncI) 322ENTRY_NP(xscale_cache_purgeID) 323 mcr p15, 0, r0, c7, c5, 0 /* flush I cache (D cleaned below) */ 324ENTRY_NP(xscale_cache_cleanID) 325ENTRY_NP(xscale_cache_purgeD) 326ENTRY(xscale_cache_cleanD) 327 XSCALE_CACHE_CLEAN_PROLOGUE 328 3291: subs r0, r0, #32 330 mcr p15, 0, r0, c7, c2, 5 /* allocate cache line */ 331 subs r1, r1, #32 332 bne 1b 333 334 CPWAIT(r0) 335 336 mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */ 337 338 CPWAIT(r0) 339 340 XSCALE_CACHE_CLEAN_EPILOGUE 341 RET 342END(xscale_cache_cleanD) 343END(xscale_cache_purgeD) 344END(xscale_cache_cleanID) 345END(xscale_cache_purgeID) 346END(xscale_cache_syncI) 347 348/* 349 * Clean the mini-data cache. 350 * 351 * It's expected that we only use the mini-data cache for 352 * kernel addresses, so there is no need to purge it on 353 * context switch, and no need to prevent userspace access 354 * while we clean it. 355 */ 356ENTRY(xscale_cache_clean_minidata) 357 ldr r2, .Lxscale_minidata_clean_addr 358 ldmia r2, {r0, r1} 3591: ldr r3, [r0], #32 360 subs r1, r1, #32 361 bne 1b 362 363 mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */ 364 365 CPWAIT_AND_RETURN(r1) 366END(xscale_cache_clean_minidata) 367 368ENTRY(xscale_cache_purgeID_E) 369 mcr p15, 0, r0, c7, c10, 1 /* clean D cache entry */ 370 CPWAIT(r1) 371 mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */ 372 mcr p15, 0, r0, c7, c5, 1 /* flush I cache single entry */ 373 mcr p15, 0, r0, c7, c6, 1 /* flush D cache single entry */ 374 CPWAIT_AND_RETURN(r1) 375END(xscale_cache_purgeID_E) 376 377ENTRY(xscale_cache_purgeD_E) 378 mcr p15, 0, r0, c7, c10, 1 /* clean D cache entry */ 379 CPWAIT(r1) 380 mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */ 381 mcr p15, 0, r0, c7, c6, 1 /* flush D cache single entry */ 382 CPWAIT_AND_RETURN(r1) 383END(xscale_cache_purgeD_E) 384 385/* 386 * Soft functions 387 */ 388/* xscale_cache_syncI is identical to xscale_cache_purgeID */ 389 390ENTRY(xscale_cache_cleanID_rng) 391ENTRY(xscale_cache_cleanD_rng) 392 cmp r1, #0x4000 393 bcs _C_LABEL(xscale_cache_cleanID) 394 395 and r2, r0, #0x1f 396 add r1, r1, r2 397 bic r0, r0, #0x1f 398 3991: mcr p15, 0, r0, c7, c10, 1 /* clean D cache entry */ 400 add r0, r0, #32 401 subs r1, r1, #32 402 bhi 1b 403 404 CPWAIT(r0) 405 406 mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */ 407 408 CPWAIT_AND_RETURN(r0) 409END(xscale_cache_cleanD_rng) 410END(xscale_cache_cleanID_rng) 411 412ENTRY(xscale_cache_purgeID_rng) 413 cmp r1, #0x4000 414 bcs _C_LABEL(xscale_cache_purgeID) 415 416 and r2, r0, #0x1f 417 add r1, r1, r2 418 bic r0, r0, #0x1f 419 4201: mcr p15, 0, r0, c7, c10, 1 /* clean D cache entry */ 421 mcr p15, 0, r0, c7, c6, 1 /* flush D cache single entry */ 422 mcr p15, 0, r0, c7, c5, 1 /* flush I cache single entry */ 423 add r0, r0, #32 424 subs r1, r1, #32 425 bhi 1b 426 427 CPWAIT(r0) 428 429 mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */ 430 431 CPWAIT_AND_RETURN(r0) 432END(xscale_cache_purgeID_rng) 433 434ENTRY(xscale_cache_purgeD_rng) 435 cmp r1, #0x4000 436 bcs _C_LABEL(xscale_cache_purgeD) 437 438 and r2, r0, #0x1f 439 add r1, r1, r2 440 bic r0, r0, #0x1f 441 4421: mcr p15, 0, r0, c7, c10, 1 /* clean D cache entry */ 443 mcr p15, 0, r0, c7, c6, 1 /* flush D cache single entry */ 444 add r0, r0, #32 445 subs r1, r1, #32 446 bhi 1b 447 448 CPWAIT(r0) 449 450 mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */ 451 452 CPWAIT_AND_RETURN(r0) 453END(xscale_cache_purgeD_rng) 454 455ENTRY(xscale_cache_syncI_rng) 456 cmp r1, #0x4000 457 bcs _C_LABEL(xscale_cache_syncI) 458 459 and r2, r0, #0x1f 460 add r1, r1, r2 461 bic r0, r0, #0x1f 462 4631: mcr p15, 0, r0, c7, c10, 1 /* clean D cache entry */ 464 mcr p15, 0, r0, c7, c5, 1 /* flush I cache single entry */ 465 add r0, r0, #32 466 subs r1, r1, #32 467 bhi 1b 468 469 CPWAIT(r0) 470 471 mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */ 472 473 CPWAIT_AND_RETURN(r0) 474END(xscale_cache_syncI_rng) 475 476ENTRY(xscale_cache_flushD_rng) 477 and r2, r0, #0x1f 478 add r1, r1, r2 479 bic r0, r0, #0x1f 480 4811: mcr p15, 0, r0, c7, c6, 1 /* flush D cache single entry */ 482 add r0, r0, #32 483 subs r1, r1, #32 484 bhi 1b 485 486 mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */ 487 488 CPWAIT_AND_RETURN(r0) 489END(xscale_cache_flushD_rng) 490 491/* 492 * Context switch. 493 * 494 * These are the CPU-specific parts of the context switcher cpu_switch() 495 * These functions actually perform the TTB reload. 496 */ 497ENTRY(xscale_context_switch) 498 /* 499 * CF_CACHE_PURGE_ID will *ALWAYS* be called prior to this. 500 * Thus the data cache will contain only kernel data and the 501 * instruction cache will contain only kernel code, and all 502 * kernel mappings are shared by all processes. 503 */ 504 505 /* Write the TTB */ 506 mcr p15, 0, r0, c2, c0, 0 507 508 /* If we have updated the TTB we must flush the TLB */ 509 mcr p15, 0, r0, c8, c7, 0 /* flush the I+D tlb */ 510 511 CPWAIT_AND_RETURN(r0) 512END(xscale_context_switch) 513 514/* 515 * xscale_cpu_sleep 516 * 517 * This is called when there is nothing on any of the run queues. 518 * We go into IDLE mode so that any IRQ or FIQ will awaken us. 519 * 520 * If this is called with anything other than ARM_SLEEP_MODE_IDLE, 521 * ignore it. 522 */ 523ENTRY(xscale_cpu_sleep) 524 tst r0, #0x00000000 525 RETc(ne) 526 mov r0, #0x1 527 mcr p14, 0, r0, c7, c0, 0 528 RET 529END(xscale_cpu_sleep) 530