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 107 ENTRY(xscale_cpwait) 108 CPWAIT_AND_RETURN(r0) 109 END(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 */ 116 ENTRY(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) 127 END(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 */ 135 ENTRY(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 158 1: /* 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 171 2: 172 #ifdef CACHE_CLEAN_BLOCK_INTR 173 msr cpsr_all, r3 174 #else 175 str r2, [r3] 176 #endif 177 RET 178 END(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 */ 186 ENTRY(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 195 END(xscale_tlb_flushID_SE) 196 197 /* 198 * Cache functions 199 */ 200 ENTRY(xscale_cache_flushID) 201 mcr p15, 0, r0, c7, c7, 0 /* flush I+D cache */ 202 CPWAIT_AND_RETURN(r0) 203 END(xscale_cache_flushID) 204 205 ENTRY(xscale_cache_flushI) 206 mcr p15, 0, r0, c7, c5, 0 /* flush I cache */ 207 CPWAIT_AND_RETURN(r0) 208 END(xscale_cache_flushI) 209 210 ENTRY(xscale_cache_flushD) 211 mcr p15, 0, r0, c7, c6, 0 /* flush D cache */ 212 CPWAIT_AND_RETURN(r0) 213 END(xscale_cache_flushD) 214 215 ENTRY(xscale_cache_flushI_SE) 216 mcr p15, 0, r0, c7, c5, 1 /* flush I cache single entry */ 217 CPWAIT_AND_RETURN(r0) 218 END(xscale_cache_flushI_SE) 219 220 ENTRY(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) 229 END(xscale_cache_flushD_SE) 230 231 ENTRY(xscale_cache_cleanD_E) 232 mcr p15, 0, r0, c7, c10, 1 /* clean D cache entry */ 233 CPWAIT_AND_RETURN(r0) 234 END(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 321 ENTRY_NP(xscale_cache_syncI) 322 ENTRY_NP(xscale_cache_purgeID) 323 mcr p15, 0, r0, c7, c5, 0 /* flush I cache (D cleaned below) */ 324 ENTRY_NP(xscale_cache_cleanID) 325 ENTRY_NP(xscale_cache_purgeD) 326 ENTRY(xscale_cache_cleanD) 327 XSCALE_CACHE_CLEAN_PROLOGUE 328 329 1: 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 342 END(xscale_cache_cleanD) 343 END(xscale_cache_purgeD) 344 END(xscale_cache_cleanID) 345 END(xscale_cache_purgeID) 346 END(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 */ 356 ENTRY(xscale_cache_clean_minidata) 357 ldr r2, .Lxscale_minidata_clean_addr 358 ldmia r2, {r0, r1} 359 1: 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) 366 END(xscale_cache_clean_minidata) 367 368 ENTRY(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) 375 END(xscale_cache_purgeID_E) 376 377 ENTRY(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) 383 END(xscale_cache_purgeD_E) 384 385 /* 386 * Soft functions 387 */ 388 /* xscale_cache_syncI is identical to xscale_cache_purgeID */ 389 390 ENTRY(xscale_cache_cleanID_rng) 391 ENTRY(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 399 1: 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) 409 END(xscale_cache_cleanD_rng) 410 END(xscale_cache_cleanID_rng) 411 412 ENTRY(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 420 1: 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) 432 END(xscale_cache_purgeID_rng) 433 434 ENTRY(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 442 1: 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) 453 END(xscale_cache_purgeD_rng) 454 455 ENTRY(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 463 1: 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) 474 END(xscale_cache_syncI_rng) 475 476 ENTRY(xscale_cache_flushD_rng) 477 and r2, r0, #0x1f 478 add r1, r1, r2 479 bic r0, r0, #0x1f 480 481 1: 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) 489 END(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 */ 497 ENTRY(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) 512 END(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 */ 523 ENTRY(xscale_cpu_sleep) 524 tst r0, #0x00000000 525 RETc(ne) 526 mov r0, #0x1 527 mcr p14, 0, r0, c7, c0, 0 528 RET 529 END(xscale_cpu_sleep) 530