1129198Scognet/* $NetBSD: cpufunc_asm_arm10.S,v 1.1 2003/09/06 09:12:29 rearnsha Exp $ */ 2129198Scognet 3139735Simp/*- 4129198Scognet * Copyright (c) 2002 ARM Limited 5129198Scognet * All rights reserved. 6129198Scognet * 7129198Scognet * Redistribution and use in source and binary forms, with or without 8129198Scognet * modification, are permitted provided that the following conditions 9129198Scognet * are met: 10129198Scognet * 1. Redistributions of source code must retain the above copyright 11129198Scognet * notice, this list of conditions and the following disclaimer. 12129198Scognet * 2. Redistributions in binary form must reproduce the above copyright 13129198Scognet * notice, this list of conditions and the following disclaimer in the 14129198Scognet * documentation and/or other materials provided with the distribution. 15129198Scognet * 3. The name of the company may not be used to endorse or promote 16129198Scognet * products derived from this software without specific prior written 17129198Scognet * permission. 18129198Scognet * 19129198Scognet * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 20129198Scognet * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21129198Scognet * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22129198Scognet * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 23129198Scognet * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24129198Scognet * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25129198Scognet * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26129198Scognet * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27129198Scognet * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28129198Scognet * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29129198Scognet * SUCH DAMAGE. 30129198Scognet * 31129198Scognet * ARM10 assembly functions for CPU / MMU / TLB specific operations 32129198Scognet * 33129198Scognet */ 34236991Simp 35129198Scognet#include <machine/asm.h> 36129198Scognet__FBSDID("$FreeBSD$"); 37129198Scognet 38129198Scognet/* 39129198Scognet * Functions to set the MMU Translation Table Base register 40129198Scognet * 41129198Scognet * We need to clean and flush the cache as it uses virtual 42129198Scognet * addresses that are about to change. 43129198Scognet */ 44129198ScognetENTRY(arm10_setttb) 45129198Scognet stmfd sp!, {r0, lr} 46129198Scognet bl _C_LABEL(arm10_idcache_wbinv_all) 47129198Scognet ldmfd sp!, {r0, lr} 48129198Scognet 49129198Scognet mcr p15, 0, r0, c2, c0, 0 /* load new TTB */ 50129198Scognet 51129198Scognet mcr p15, 0, r0, c8, c7, 0 /* invalidate I+D TLBs */ 52129198Scognet bx lr 53248361SandrewEND(arm10_setttb) 54129198Scognet 55129198Scognet/* 56129198Scognet * TLB functions 57129198Scognet */ 58129198ScognetENTRY(arm10_tlb_flushID_SE) 59129198Scognet mcr p15, 0, r0, c8, c6, 1 /* flush D tlb single entry */ 60129198Scognet mcr p15, 0, r0, c8, c5, 1 /* flush I tlb single entry */ 61129198Scognet bx lr 62248361SandrewEND(arm10_tlb_flushID_SE) 63129198Scognet 64129198ScognetENTRY(arm10_tlb_flushI_SE) 65129198Scognet mcr p15, 0, r0, c8, c5, 1 /* flush I tlb single entry */ 66129198Scognet bx lr 67248361SandrewEND(arm10_tlb_flushI_SE) 68129198Scognet 69129198Scognet/* 70129198Scognet * Cache operations. For the entire cache we use the set/index 71129198Scognet * operations. 72129198Scognet */ 73129198Scognet s_max .req r0 74129198Scognet i_max .req r1 75129198Scognet s_inc .req r2 76129198Scognet i_inc .req r3 77129198Scognet 78129198ScognetENTRY_NP(arm10_icache_sync_range) 79129198Scognet ldr ip, .Larm10_line_size 80129198Scognet cmp r1, #0x4000 81129198Scognet bcs .Larm10_icache_sync_all 82129198Scognet ldr ip, [ip] 83129198Scognet sub r3, ip, #1 84129198Scognet and r2, r0, r3 85129198Scognet add r1, r1, r2 86129198Scognet bic r0, r0, r3 87129198Scognet.Larm10_sync_next: 88129198Scognet mcr p15, 0, r0, c7, c5, 1 /* Invalidate I cache SE with VA */ 89129198Scognet mcr p15, 0, r0, c7, c10, 1 /* Clean D cache SE with VA */ 90129198Scognet add r0, r0, ip 91129198Scognet subs r1, r1, ip 92246001Sian bhi .Larm10_sync_next 93129198Scognet mcr p15, 0, r0, c7, c10, 4 /* drain the write buffer */ 94129198Scognet bx lr 95248361SandrewEND(arm10_icache_sync_range) 96129198Scognet 97129198ScognetENTRY_NP(arm10_icache_sync_all) 98129198Scognet.Larm10_icache_sync_all: 99129198Scognet /* 100129198Scognet * We assume that the code here can never be out of sync with the 101129198Scognet * dcache, so that we can safely flush the Icache and fall through 102129198Scognet * into the Dcache cleaning code. 103129198Scognet */ 104129198Scognet mcr p15, 0, r0, c7, c5, 0 /* Flush I cache */ 105129198Scognet /* Fall through to clean Dcache. */ 106129198Scognet 107129198Scognet.Larm10_dcache_wb: 108129198Scognet ldr ip, .Larm10_cache_data 109129198Scognet ldmia ip, {s_max, i_max, s_inc, i_inc} 110129198Scognet.Lnext_set: 111129198Scognet orr ip, s_max, i_max 112129198Scognet.Lnext_index: 113129198Scognet mcr p15, 0, ip, c7, c10, 2 /* Clean D cache SE with Set/Index */ 114246001Sian subs ip, ip, i_inc 115246001Sian bhs .Lnext_index /* Next index */ 116129198Scognet subs s_max, s_max, s_inc 117246001Sian bhs .Lnext_set /* Next set */ 118129198Scognet mcr p15, 0, r0, c7, c10, 4 /* drain the write buffer */ 119129198Scognet bx lr 120248361SandrewEND(arm10_icache_sync_all) 121129198Scognet 122129198Scognet.Larm10_line_size: 123129198Scognet .word _C_LABEL(arm_pdcache_line_size) 124129198Scognet 125129198ScognetENTRY(arm10_dcache_wb_range) 126129198Scognet ldr ip, .Larm10_line_size 127129198Scognet cmp r1, #0x4000 128129198Scognet bcs .Larm10_dcache_wb 129129198Scognet ldr ip, [ip] 130129198Scognet sub r3, ip, #1 131129198Scognet and r2, r0, r3 132129198Scognet add r1, r1, r2 133129198Scognet bic r0, r0, r3 134129198Scognet.Larm10_wb_next: 135129198Scognet mcr p15, 0, r0, c7, c10, 1 /* Clean D cache SE with VA */ 136129198Scognet add r0, r0, ip 137129198Scognet subs r1, r1, ip 138246001Sian bhi .Larm10_wb_next 139129198Scognet mcr p15, 0, r0, c7, c10, 4 /* drain the write buffer */ 140129198Scognet bx lr 141248361SandrewEND(arm10_dcache_wb_range) 142129198Scognet 143129198ScognetENTRY(arm10_dcache_wbinv_range) 144129198Scognet ldr ip, .Larm10_line_size 145129198Scognet cmp r1, #0x4000 146129198Scognet bcs .Larm10_dcache_wbinv_all 147129198Scognet ldr ip, [ip] 148129198Scognet sub r3, ip, #1 149129198Scognet and r2, r0, r3 150129198Scognet add r1, r1, r2 151129198Scognet bic r0, r0, r3 152129198Scognet.Larm10_wbinv_next: 153129198Scognet mcr p15, 0, r0, c7, c14, 1 /* Purge D cache SE with VA */ 154129198Scognet add r0, r0, ip 155129198Scognet subs r1, r1, ip 156246001Sian bhi .Larm10_wbinv_next 157129198Scognet mcr p15, 0, r0, c7, c10, 4 /* drain the write buffer */ 158129198Scognet bx lr 159248361SandrewEND(arm10_dcache_wbinv_range) 160129198Scognet 161129198Scognet/* 162129198Scognet * Note, we must not invalidate everything. If the range is too big we 163129198Scognet * must use wb-inv of the entire cache. 164129198Scognet */ 165129198ScognetENTRY(arm10_dcache_inv_range) 166129198Scognet ldr ip, .Larm10_line_size 167129198Scognet cmp r1, #0x4000 168129198Scognet bcs .Larm10_dcache_wbinv_all 169129198Scognet ldr ip, [ip] 170129198Scognet sub r3, ip, #1 171129198Scognet and r2, r0, r3 172129198Scognet add r1, r1, r2 173129198Scognet bic r0, r0, r3 174129198Scognet.Larm10_inv_next: 175129198Scognet mcr p15, 0, r0, c7, c6, 1 /* Invalidate D cache SE with VA */ 176129198Scognet add r0, r0, ip 177129198Scognet subs r1, r1, ip 178246001Sian bhi .Larm10_inv_next 179129198Scognet mcr p15, 0, r0, c7, c10, 4 /* drain the write buffer */ 180129198Scognet bx lr 181248361SandrewEND(arm10_dcache_inv_range) 182129198Scognet 183129198ScognetENTRY(arm10_idcache_wbinv_range) 184129198Scognet ldr ip, .Larm10_line_size 185129198Scognet cmp r1, #0x4000 186129198Scognet bcs .Larm10_idcache_wbinv_all 187129198Scognet ldr ip, [ip] 188129198Scognet sub r3, ip, #1 189129198Scognet and r2, r0, r3 190129198Scognet add r1, r1, r2 191129198Scognet bic r0, r0, r3 192129198Scognet.Larm10_id_wbinv_next: 193129198Scognet mcr p15, 0, r0, c7, c5, 1 /* Invalidate I cache SE with VA */ 194129198Scognet mcr p15, 0, r0, c7, c14, 1 /* Purge D cache SE with VA */ 195129198Scognet add r0, r0, ip 196129198Scognet subs r1, r1, ip 197246001Sian bhi .Larm10_id_wbinv_next 198129198Scognet mcr p15, 0, r0, c7, c10, 4 /* drain the write buffer */ 199129198Scognet bx lr 200248361SandrewEND(arm10_idcache_wbinv_range) 201129198Scognet 202129198ScognetENTRY_NP(arm10_idcache_wbinv_all) 203129198Scognet.Larm10_idcache_wbinv_all: 204129198Scognet /* 205129198Scognet * We assume that the code here can never be out of sync with the 206129198Scognet * dcache, so that we can safely flush the Icache and fall through 207129198Scognet * into the Dcache purging code. 208129198Scognet */ 209129198Scognet mcr p15, 0, r0, c7, c5, 0 /* Flush I cache */ 210129198Scognet /* Fall through to purge Dcache. */ 211129198Scognet 212269796SianEENTRY(arm10_dcache_wbinv_all) 213129198Scognet.Larm10_dcache_wbinv_all: 214129198Scognet ldr ip, .Larm10_cache_data 215129198Scognet ldmia ip, {s_max, i_max, s_inc, i_inc} 216129198Scognet.Lnext_set_inv: 217129198Scognet orr ip, s_max, i_max 218129198Scognet.Lnext_index_inv: 219129198Scognet mcr p15, 0, ip, c7, c14, 2 /* Purge D cache SE with Set/Index */ 220246001Sian subs ip, ip, i_inc 221246001Sian bhs .Lnext_index_inv /* Next index */ 222129198Scognet subs s_max, s_max, s_inc 223246001Sian bhs .Lnext_set_inv /* Next set */ 224129198Scognet mcr p15, 0, r0, c7, c10, 4 /* drain the write buffer */ 225129198Scognet bx lr 226269796SianEEND(arm10_dcache_wbinv_all) 227248361SandrewEND(arm10_idcache_wbinv_all) 228129198Scognet 229129198Scognet.Larm10_cache_data: 230129198Scognet .word _C_LABEL(arm10_dcache_sets_max) 231129198Scognet 232129198Scognet/* 233129198Scognet * Context switch. 234129198Scognet * 235129198Scognet * These is the CPU-specific parts of the context switcher cpu_switch() 236129198Scognet * These functions actually perform the TTB reload. 237129198Scognet * 238129198Scognet * NOTE: Special calling convention 239129198Scognet * r1, r4-r13 must be preserved 240129198Scognet */ 241129198ScognetENTRY(arm10_context_switch) 242129198Scognet /* 243129198Scognet * We can assume that the caches will only contain kernel addresses 244129198Scognet * at this point. So no need to flush them again. 245129198Scognet */ 246129198Scognet mcr p15, 0, r0, c7, c10, 4 /* drain the write buffer */ 247129198Scognet mcr p15, 0, r0, c2, c0, 0 /* set the new TTB */ 248129198Scognet mcr p15, 0, r0, c8, c7, 0 /* and flush the I+D tlbs */ 249129198Scognet 250129198Scognet /* Paranoia -- make sure the pipeline is empty. */ 251129198Scognet nop 252129198Scognet nop 253129198Scognet nop 254129198Scognet bx lr 255248361SandrewEND(arm10_context_switch) 256129198Scognet 257129198Scognet .bss 258129198Scognet 259129198Scognet/* XXX The following macros should probably be moved to asm.h */ 260129198Scognet#define _DATA_OBJECT(x) .globl x; .type x,_ASM_TYPE_OBJECT; x: 261129198Scognet#define C_OBJECT(x) _DATA_OBJECT(_C_LABEL(x)) 262129198Scognet 263129198Scognet/* 264129198Scognet * Parameters for the cache cleaning code. Note that the order of these 265236991Simp * four variables is assumed in the code above. Hence the reason for 266129198Scognet * declaring them in the assembler file. 267129198Scognet */ 268129198Scognet .align 0 269129198ScognetC_OBJECT(arm10_dcache_sets_max) 270129198Scognet .space 4 271129198ScognetC_OBJECT(arm10_dcache_index_max) 272129198Scognet .space 4 273129198ScognetC_OBJECT(arm10_dcache_sets_inc) 274129198Scognet .space 4 275129198ScognetC_OBJECT(arm10_dcache_index_inc) 276129198Scognet .space 4 277