1/* $NetBSD: cpufunc_asm_xscale.S,v 1.13 2002/04/09 23:44:00 thorpej 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 <machine/cpu.h> 75#include <machine/asm.h> 76 77/* 78 * Size of the XScale core D-cache. 79 */ 80#define DCACHE_SIZE 0x00008000 81 82Lblock_userspace_access: 83 .word _C_LABEL(block_userspace_access) 84 85/* 86 * CPWAIT -- Canonical method to wait for CP15 update. 87 * From: Intel 80200 manual, section 2.3.3. 88 * 89 * NOTE: Clobbers the specified temp reg. 90 */ 91#define CPWAIT_BRANCH \ 92 sub pc, pc, #4 93 94#define CPWAIT(tmp) \ 95 mrc p15, 0, tmp, c2, c0, 0 /* arbitrary read of CP15 */ ;\ 96 mov tmp, tmp /* wait for it to complete */ ;\ 97 CPWAIT_BRANCH /* branch to next insn */ 98 99#define CPWAIT_AND_RETURN_SHIFTER lsr #32 100 101#define CPWAIT_AND_RETURN(tmp) \ 102 mrc p15, 0, tmp, c2, c0, 0 /* arbitrary read of CP15 */ ;\ 103 /* Wait for it to complete and branch to the return address */ \ 104 sub pc, lr, tmp, CPWAIT_AND_RETURN_SHIFTER 105 106ENTRY(xscale_cpwait) 107 CPWAIT_AND_RETURN(r0) 108 109/* 110 * We need a separate cpu_control() entry point, since we have to 111 * invalidate the Branch Target Buffer in the event the BPRD bit 112 * changes in the control register. 113 */ 114ENTRY(xscale_control) 115 mrc p15, 0, r3, c1, c0, 0 /* Read the control register */ 116 bic r2, r3, r0 /* Clear bits */ 117 eor r2, r2, r1 /* XOR bits */ 118 119 teq r2, r3 /* Only write if there was a change */ 120 mcrne p15, 0, r0, c7, c5, 6 /* Invalidate the BTB */ 121 mcrne p15, 0, r2, c1, c0, 0 /* Write new control register */ 122 mov r0, r3 /* Return old value */ 123 124 CPWAIT_AND_RETURN(r1) 125 126/* 127 * Functions to set the MMU Translation Table Base register 128 * 129 * We need to clean and flush the cache as it uses virtual 130 * addresses that are about to change. 131 */ 132ENTRY(xscale_setttb) 133#ifdef CACHE_CLEAN_BLOCK_INTR 134 mrs r3, cpsr_all 135 orr r1, r3, #(I32_bit | F32_bit) 136 msr cpsr_all, r1 137#else 138 ldr r3, Lblock_userspace_access 139 ldr r2, [r3] 140 orr r1, r2, #1 141 str r1, [r3] 142#endif 143 stmfd sp!, {r0-r3, lr} 144 bl _C_LABEL(xscale_cache_cleanID) 145 mcr p15, 0, r0, c7, c5, 0 /* invalidate I$ and BTB */ 146 mcr p15, 0, r0, c7, c10, 4 /* drain write and fill buffer */ 147 148 CPWAIT(r0) 149 150 ldmfd sp!, {r0-r3, lr} 151 152 /* Write the TTB */ 153 mcr p15, 0, r0, c2, c0, 0 154 155 /* If we have updated the TTB we must flush the TLB */ 156 mcr p15, 0, r0, c8, c7, 0 /* invalidate I+D TLB */ 157 158 /* The cleanID above means we only need to flush the I cache here */ 159 mcr p15, 0, r0, c7, c5, 0 /* invalidate I$ and BTB */ 160 161 CPWAIT(r0) 162 163#ifdef CACHE_CLEAN_BLOCK_INTR 164 msr cpsr_all, r3 165#else 166 str r2, [r3] 167#endif 168 mov pc, lr 169 170/* 171 * TLB functions 172 * 173 * Note: We don't need to worry about issuing a CPWAIT after 174 * TLB operations, because we expect a pmap_update() to follow. 175 */ 176ENTRY(xscale_tlb_flushID_SE) 177 mcr p15, 0, r0, c8, c6, 1 /* flush D tlb single entry */ 178 mcr p15, 0, r0, c8, c5, 1 /* flush I tlb single entry */ 179 mov pc, lr 180 181/* 182 * Cache functions 183 */ 184ENTRY(xscale_cache_flushID) 185 mcr p15, 0, r0, c7, c7, 0 /* flush I+D cache */ 186 CPWAIT_AND_RETURN(r0) 187 188ENTRY(xscale_cache_flushI) 189 mcr p15, 0, r0, c7, c5, 0 /* flush I cache */ 190 CPWAIT_AND_RETURN(r0) 191 192ENTRY(xscale_cache_flushD) 193 mcr p15, 0, r0, c7, c6, 0 /* flush D cache */ 194 CPWAIT_AND_RETURN(r0) 195 196ENTRY(xscale_cache_flushI_SE) 197 mcr p15, 0, r0, c7, c5, 1 /* flush I cache single entry */ 198 CPWAIT_AND_RETURN(r0) 199 200ENTRY(xscale_cache_flushD_SE) 201 /* 202 * Errata (rev < 2): Must clean-dcache-line to an address 203 * before invalidate-dcache-line to an address, or dirty 204 * bits will not be cleared in the dcache array. 205 */ 206 mcr p15, 0, r0, c7, c10, 1 207 mcr p15, 0, r0, c7, c6, 1 /* flush D cache single entry */ 208 CPWAIT_AND_RETURN(r0) 209 210ENTRY(xscale_cache_cleanD_E) 211 mcr p15, 0, r0, c7, c10, 1 /* clean D cache entry */ 212 CPWAIT_AND_RETURN(r0) 213 214/* 215 * Information for the XScale cache clean/purge functions: 216 * 217 * * Virtual address of the memory region to use 218 * * Size of memory region 219 * 220 * Note the virtual address for the Data cache clean operation 221 * does not need to be backed by physical memory, since no loads 222 * will actually be performed by the allocate-line operation. 223 * 224 * Note that the Mini-Data cache MUST be cleaned by executing 225 * loads from memory mapped into a region reserved exclusively 226 * for cleaning of the Mini-Data cache. 227 */ 228 .data 229 230 .global _C_LABEL(xscale_cache_clean_addr) 231_C_LABEL(xscale_cache_clean_addr): 232 .word 0x00000000 233 234 .global _C_LABEL(xscale_cache_clean_size) 235_C_LABEL(xscale_cache_clean_size): 236 .word DCACHE_SIZE 237 238 .global _C_LABEL(xscale_minidata_clean_addr) 239_C_LABEL(xscale_minidata_clean_addr): 240 .word 0x00000000 241 242 .global _C_LABEL(xscale_minidata_clean_size) 243_C_LABEL(xscale_minidata_clean_size): 244 .word 0x00000800 245 246 .text 247 248Lxscale_cache_clean_addr: 249 .word _C_LABEL(xscale_cache_clean_addr) 250Lxscale_cache_clean_size: 251 .word _C_LABEL(xscale_cache_clean_size) 252 253Lxscale_minidata_clean_addr: 254 .word _C_LABEL(xscale_minidata_clean_addr) 255Lxscale_minidata_clean_size: 256 .word _C_LABEL(xscale_minidata_clean_size) 257 258#ifdef CACHE_CLEAN_BLOCK_INTR 259#define XSCALE_CACHE_CLEAN_BLOCK \ 260 mrs r3, cpsr_all ; \ 261 orr r0, r3, #(I32_bit | F32_bit) ; \ 262 msr cpsr_all, r0 263 264#define XSCALE_CACHE_CLEAN_UNBLOCK \ 265 msr cpsr_all, r3 266#else 267#define XSCALE_CACHE_CLEAN_BLOCK \ 268 ldr r3, Lblock_userspace_access ; \ 269 ldr ip, [r3] ; \ 270 orr r0, ip, #1 ; \ 271 str r0, [r3] 272 273#define XSCALE_CACHE_CLEAN_UNBLOCK \ 274 str ip, [r3] 275#endif /* CACHE_CLEAN_BLOCK_INTR */ 276 277#define XSCALE_CACHE_CLEAN_PROLOGUE \ 278 XSCALE_CACHE_CLEAN_BLOCK ; \ 279 ldr r2, Lxscale_cache_clean_addr ; \ 280 ldmia r2, {r0, r1} ; \ 281 /* \ 282 * BUG ALERT! \ 283 * \ 284 * The XScale core has a strange cache eviction bug, which \ 285 * requires us to use 2x the cache size for the cache clean \ 286 * and for that area to be aligned to 2 * cache size. \ 287 * \ 288 * The work-around is to use 2 areas for cache clean, and to \ 289 * alternate between them whenever this is done. No one knows \ 290 * why the work-around works (mmm!). \ 291 */ \ 292 eor r0, r0, #(DCACHE_SIZE) ; \ 293 str r0, [r2] ; \ 294 add r0, r0, r1 295 296#define XSCALE_CACHE_CLEAN_EPILOGUE \ 297 XSCALE_CACHE_CLEAN_UNBLOCK 298 299ENTRY_NP(xscale_cache_syncI) 300ENTRY_NP(xscale_cache_purgeID) 301 mcr p15, 0, r0, c7, c5, 0 /* flush I cache (D cleaned below) */ 302ENTRY_NP(xscale_cache_cleanID) 303ENTRY_NP(xscale_cache_purgeD) 304ENTRY(xscale_cache_cleanD) 305 XSCALE_CACHE_CLEAN_PROLOGUE 306 3071: subs r0, r0, #32 308 mcr p15, 0, r0, c7, c2, 5 /* allocate cache line */ 309 subs r1, r1, #32 310 bne 1b 311 312 CPWAIT(r0) 313 314 mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */ 315 316 CPWAIT(r0) 317 318 XSCALE_CACHE_CLEAN_EPILOGUE 319 mov pc, lr 320 321/* 322 * Clean the mini-data cache. 323 * 324 * It's expected that we only use the mini-data cache for 325 * kernel addresses, so there is no need to purge it on 326 * context switch, and no need to prevent userspace access 327 * while we clean it. 328 */ 329ENTRY(xscale_cache_clean_minidata) 330 ldr r2, Lxscale_minidata_clean_addr 331 ldmia r2, {r0, r1} 3321: ldr r3, [r0], #32 333 subs r1, r1, #32 334 bne 1b 335 mov pc, lr 336 337ENTRY(xscale_cache_purgeID_E) 338 mcr p15, 0, r0, c7, c10, 1 /* clean D cache entry */ 339 CPWAIT(r1) 340 mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */ 341 mcr p15, 0, r0, c7, c5, 1 /* flush I cache single entry */ 342 mcr p15, 0, r0, c7, c6, 1 /* flush D cache single entry */ 343 CPWAIT_AND_RETURN(r1) 344 345ENTRY(xscale_cache_purgeD_E) 346 mcr p15, 0, r0, c7, c10, 1 /* clean D cache entry */ 347 CPWAIT(r1) 348 mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */ 349 mcr p15, 0, r0, c7, c6, 1 /* flush D cache single entry */ 350 CPWAIT_AND_RETURN(r1) 351 352/* 353 * Soft functions 354 */ 355/* xscale_cache_syncI is identical to xscale_cache_purgeID */ 356 357ENTRY(xscale_cache_cleanID_rng) 358ENTRY(xscale_cache_cleanD_rng) 359 cmp r1, #0x4000 360 bcs _C_LABEL(xscale_cache_cleanID) 361 362 and r2, r0, #0x1f 363 add r1, r1, r2 364 bic r0, r0, #0x1f 365 3661: mcr p15, 0, r0, c7, c10, 1 /* clean D cache entry */ 367 add r0, r0, #32 368 subs r1, r1, #32 369 bpl 1b 370 371 CPWAIT(r0) 372 373 mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */ 374 375 CPWAIT_AND_RETURN(r0) 376 377ENTRY(xscale_cache_purgeID_rng) 378 cmp r1, #0x4000 379 bcs _C_LABEL(xscale_cache_purgeID) 380 381 and r2, r0, #0x1f 382 add r1, r1, r2 383 bic r0, r0, #0x1f 384 3851: mcr p15, 0, r0, c7, c10, 1 /* clean D cache entry */ 386 mcr p15, 0, r0, c7, c6, 1 /* flush D cache single entry */ 387 mcr p15, 0, r0, c7, c5, 1 /* flush I cache single entry */ 388 add r0, r0, #32 389 subs r1, r1, #32 390 bpl 1b 391 392 CPWAIT(r0) 393 394 mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */ 395 396 CPWAIT_AND_RETURN(r0) 397 398ENTRY(xscale_cache_purgeD_rng) 399 cmp r1, #0x4000 400 bcs _C_LABEL(xscale_cache_purgeD) 401 402 and r2, r0, #0x1f 403 add r1, r1, r2 404 bic r0, r0, #0x1f 405 4061: mcr p15, 0, r0, c7, c10, 1 /* clean D cache entry */ 407 mcr p15, 0, r0, c7, c6, 1 /* flush D cache single entry */ 408 add r0, r0, #32 409 subs r1, r1, #32 410 bpl 1b 411 412 CPWAIT(r0) 413 414 mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */ 415 416 CPWAIT_AND_RETURN(r0) 417 418ENTRY(xscale_cache_syncI_rng) 419 cmp r1, #0x4000 420 bcs _C_LABEL(xscale_cache_syncI) 421 422 and r2, r0, #0x1f 423 add r1, r1, r2 424 bic r0, r0, #0x1f 425 4261: mcr p15, 0, r0, c7, c10, 1 /* clean D cache entry */ 427 mcr p15, 0, r0, c7, c5, 1 /* flush I cache single entry */ 428 add r0, r0, #32 429 subs r1, r1, #32 430 bpl 1b 431 432 CPWAIT(r0) 433 434 mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */ 435 436 CPWAIT_AND_RETURN(r0) 437 438/* Used in write-through mode. */ 439ENTRY(xscale_cache_flushID_rng) 440 cmp r1, #0x4000 441 bcs _C_LABEL(xscale_cache_flushID) 442 443 and r2, r0, #0x1f 444 add r1, r1, r2 445 bic r0, r0, #0x1f 446 4471: mcr p15, 0, r0, c7, c6, 1 /* flush D cache single entry */ 448 mcr p15, 0, r0, c7, c5, 1 /* flush I cache single entry */ 449 add r0, r0, #32 450 subs r1, r1, #32 451 bpl 1b 452 453 mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */ 454 455 CPWAIT_AND_RETURN(r0) 456 457/* Used in write-though mode. */ 458ENTRY(xscale_cache_flushD_rng) 459 cmp r1, #0x4000 460 bcs _C_LABEL(xscale_cache_flushD) 461 462 and r2, r0, #0x1f 463 add r1, r1, r2 464 bic r0, r0, #0x1f 465 4661: mcr p15, 0, r0, c7, c6, 1 /* flush D cache single entry */ 467 add r0, r0, #32 468 subs r1, r1, #32 469 bpl 1b 470 471 mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */ 472 473 CPWAIT_AND_RETURN(r0) 474 475/* Used in write-through mode. */ 476ENTRY(xscale_cache_flushI_rng) 477 cmp r1, #0x4000 478 bcs _C_LABEL(xscale_cache_flushI) 479 480 and r2, r0, #0x1f 481 add r1, r1, r2 482 bic r0, r0, #0x1f 483 4841: mcr p15, 0, r0, c7, c5, 1 /* flush I cache single entry */ 485 add r0, r0, #32 486 subs r1, r1, #32 487 bpl 1b 488 489 mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */ 490 491 CPWAIT_AND_RETURN(r0) 492 493/* 494 * Context switch. 495 * 496 * These is the CPU-specific parts of the context switcher cpu_switch() 497 * These functions actually perform the TTB reload. 498 * 499 * NOTE: Special calling convention 500 * r1, r4-r13 must be preserved 501 */ 502ENTRY(xscale_context_switch) 503 /* 504 * CF_CACHE_PURGE_ID will *ALWAYS* be called prior to this. 505 * Thus the data cache will contain only kernel data and the 506 * instruction cache will contain only kernel code, and all 507 * kernel mappings are shared by all processes. 508 */ 509 510 /* Write the TTB */ 511 mcr p15, 0, r0, c2, c0, 0 512 513 /* If we have updated the TTB we must flush the TLB */ 514 mcr p15, 0, r0, c8, c7, 0 /* flush the I+D tlb */ 515 516 CPWAIT_AND_RETURN(r0) 517 518/* 519 * xscale_cpusleep 520 * 521 * This is called when there is nothing on any of the run queues. 522 * We go into IDLE mode so that any IRQ or FIQ will awaken us. 523 * 524 * If this is called with anything other than ARM_SLEEP_MODE_IDLE, 525 * ignore it. 526 */ 527ENTRY(xscale_cpu_sleep) 528 tst r0, #0x00000000 529 bne 1f 530 mov r0, #0x1 531 mcr p14, 0, r0, c7, c0, 0 532 5331: 534 mov pc, lr 535