/* <:copyright-BRCM:2019:DUAL/GPL:standard Copyright (c) 2019 Broadcom All Rights Reserved This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as published by the Free Software Foundation (the "GPL"). This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. A copy of the GPL is available at http://www.broadcom.com/licenses/GPLv2.php, or by writing to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. :> */ #include #include #include .globl a9_mmu_set_ttbr .globl a9_mmu_invalidate_tlb .globl a9_mmu_set_scn .globl a9_mmu_enable .globl a9_l1cache_enable_d .globl a9_l1cache_enable_i .globl a9_gic_secure_init .globl a9_l1cache_inval_d func a9_mmu_set_ttbr push {r0-r12,r14} // Set the access control to client so AP is checked with tlb entry ldr r1, =0x55555555 mcr p15, 0, r1, c3, c0, 0 // Write Domain Access Control Register // Set Translation Table base address. r0 must be preserved mcr p15, 0, r0, c2, c0, 0 // Write Translation Table Base Register 0 isb dsb pop {r0-r12,r14} mov pc,lr endfunc a9_mmu_set_ttbr func a9_mmu_invalidate_tlb push {r0-r12,r14} mov r0,#0 mcr p15,0,r0,c8,c7,0 /* Invalidate TLB */ isb dsb pop {r0-r12,r14} mov pc,lr endfunc a9_mmu_invalidate_tlb /* map_set_scn - sets number (SCN_RNG) of L1 table entries. Operates on 1 MB sections r0 - L1 table paddr r1 - virtual address start r2 - address range in Megabytes r3 - Sections' attributes r4 - mapped physical start address Table max size 16K (4K*4) */ #define WORD_SIZE 4 /* bytes */ #define WORD_BITLEN 32 /*bitlen or shift*/ #define WORD_ALGN 2 /* word alignment shift*/ #define SCN_BITLEN 20 /*bitlen or shift */ #define L1TBL_PA r0 /* */ #define SCN_VA r1 #define SCN_RNG r2 #define SCN_ATTR r3 #define SCN_PA r4 #define SCN_ENTRY r5 #define L1TBL_LEN r6 /* NN (not nested) - meaning there are no calls to subroutine. LR is not preserved registers r0-r6 are not preserved and must not be relied upon */ func a9_mmu_set_scn push {r0-r12,r14} mov SCN_ENTRY,#0 /* adjust virt/phys addresses for the loop increment */ lsr SCN_VA, SCN_VA, #(SCN_BITLEN) lsr SCN_PA, SCN_PA, #(SCN_BITLEN) /* clear 12 msb of the section attribute */ bfc SCN_ATTR, #SCN_BITLEN, #(WORD_BITLEN-SCN_BITLEN) /* set max range not exceeding 0xfff */ add SCN_RNG, SCN_VA, SCN_RNG cmp SCN_RNG, L1TBL_LEN blt 1f mov SCN_RNG, L1TBL_LEN 1: orr SCN_ENTRY, SCN_ATTR, SCN_PA, lsl #(SCN_BITLEN) str SCN_ENTRY, [L1TBL_PA, SCN_VA, lsl #(WORD_ALGN)] add SCN_PA, SCN_PA, #1 add SCN_VA, SCN_VA, #1 cmp SCN_VA, SCN_RNG bne 1b pop {r0-r12,r14} mov pc,lr endfunc a9_mmu_set_scn /* * CR1 bits (CP#15 CR1) */ #define CR_M (1 << 0) /* MMU enable */ #define CR_C (1 << 2) /* Dcache enable */ #define CR_Z (1 << 11) /* Program Flow Prediction */ #define CR_I (1 << 12) /* Icache enable */ func a9_mmu_enable push {r0-r12,r14} mrc p15, 0, r0, c1, c0, 0 // Read CP15 System Control register orr r0, r0, #CR_M // Set M bit 0 to enable MMU mcr p15, 0, r0, c1, c0, 0 // Write CP15 System Control register isb pop {r0-r12,r14} mov pc, lr endfunc a9_mmu_enable func a9_l1cache_enable_i push {r0-r12,r14} mrc p15, 0, r0, c1, c0, 0 // Read Control Register configuration data orr r0, r0, #CR_I // Enable I Cache orr r0, r0, #CR_Z // Enable Prediction mcr p15, 0, r0, c1, c0, 0 // Write Control Register configuration data isb pop {r0-r12,r14} mov pc, lr endfunc a9_l1cache_enable_i func a9_l1cache_enable_d push {r0-r12,r14} mrc p15, 0, r0, c1, c0, 0 // Read Control Register configuration data orr r0, r0, #CR_C // Enable D Cache mcr p15, 0, r0, c1, c0, 0 // Write Control Register configuration data isb pop {r0-r12,r14} mov pc, lr endfunc a9_l1cache_enable_d func a9_gic_secure_init push {r0-r12,r14} /* setup the GIC for non secure world. group 0 secure state, group 1 non secure state */ /* enable interrupt for both groups */ ldr r0, =GICD_BASE ldr r1, =0x3 str r1, [r0, #GICD_CTLR_OFFSET] /* assign all the interrupt to group 1 */ ldr r2, [r0, #GICD_TYPER_OFFSET] and r2, r2, #0x1f add r2, r2, #1 ldr r1, =0xffffffff add r0, r0, #GICD_IGROUPR0_OFFSET setgroup: str r1, [r0] add r0, #4 subs r2, r2, #1 bne setgroup /* enable both group interrupt in the cpu interface */ ldr r0, =GICC_BASE ldr r1, [r0, #GICC_CTLR_OFFSET] orr r1, #0x3 str r1, [r0] /* set cpu priority mask view for nonsecure */ mov r1, #0x80 str r1, [r0, #GICC_PMR_OFFSET] pop {r0-r12,r14} mov pc, lr endfunc a9_gic_secure_init func a9_l1cache_inval_d push {r0-r12,r14} mrc p15, 1, r0, c0, c0, 1 @ read clidr ands r3, r0, #0x7000000 @ extract loc from clidr mov r3, r3, lsr #23 @ left align loc bit field beq invfinished @ if loc is 0, then no need to clean mov r10, #0 @ start clean at cache level 0 invloop1: add r2, r10, r10, lsr #1 @ work out 3x current cache level mov r1, r0, lsr r2 @ extract cache type bits from clidr and r1, r1, #7 @ mask of the bits for current cache only cmp r1, #2 @ see what cache we have at this level blt invskip @ skip if no cache, or just i-cache mcr p15, 2, r10, c0, c0, 0 @ select current cache level in cssr isb @ but we compile with armv5 mrc p15, 1, r1, c0, c0, 0 @ read the new csidr and r2, r1, #7 @ extract the length of the cache lines add r2, r2, #4 @ add 4 (line length offset) ldr r4, =0x3ff ands r4, r4, r1, lsr #3 @ find maximum number on the way size clz r5, r4 @ find bit position of way size increment ldr r7, =0x7fff ands r7, r7, r1, lsr #13 @ extract max number of the index size invloop2: mov r9, r4 @ create working copy of max way size invloop3: orr r6, r10, r9, lsl r5 @ factor way and cache number into r6 orr r6, r6, r7, lsl r2 @ factor index number into r6 mcr p15, 0, r6, c7, c6, 2 @ invalidate by set/way subs r9, r9, #1 @ decrement the way bge invloop3 subs r7, r7, #1 @ decrement the index bge invloop2 invskip: add r10, r10, #2 @ increment cache number cmp r3, r10 bgt invloop1 invfinished: mov r10, #0 @ swith back to cache level 0 mcr p15, 2, r10, c0, c0, 0 @ select current cache level in cssr isb pop {r0-r12,r14} mov pc, lr endfunc a9_l1cache_inval_d