/* SPDX-License-Identifier: BSD-2-Clause */ /* * Copyright (c) 2014, STMicroelectronics International N.V. */ #include #include #include #include #include #define PL310_LOCKDOWN_NBREGS 8 #define PL310_LOCKDOWN_SZREG 4 #define PL310_8WAYS_MASK 0x00FF #define PL310_16WAYS_UPPERMASK 0xFF00 /* * void arm_cl2_lockallways(vaddr_t base) * * lock all L2 caches ways for data and instruction */ FUNC arm_cl2_lockallways , : UNWIND( .fnstart) add r1, r0, #PL310_DCACHE_LOCKDOWN_BASE ldr r2, [r0, #PL310_AUX_CTRL] tst r2, #PL310_AUX_16WAY_BIT mov r2, #PL310_8WAYS_MASK orrne r2, #PL310_16WAYS_UPPERMASK mov r0, #PL310_LOCKDOWN_NBREGS 1: /* lock Dcache and Icache */ str r2, [r1], #PL310_LOCKDOWN_SZREG str r2, [r1], #PL310_LOCKDOWN_SZREG subs r0, r0, #1 bne 1b mov pc, lr UNWIND( .fnend) END_FUNC arm_cl2_lockallways /* * Set sync operation mask according to ways associativity. * Preserve r0 = pl310 iomem base address */ .macro syncbyway_set_mask reg ldr \reg, [r0, #PL310_AUX_CTRL] tst \reg, #PL310_AUX_16WAY_BIT mov \reg, #PL310_8WAYS_MASK orrne \reg, \reg, #PL310_16WAYS_UPPERMASK .endm /* * void arm_cl2_cleaninvbyway(vaddr_t base) * clean & invalidate the whole L2 cache. */ FUNC arm_cl2_cleaninvbyway , : UNWIND( .fnstart) syncbyway_set_mask r1 str r1, [r0, #PL310_FLUSH_BY_WAY] /* Wait for all cache ways to be cleaned and invalidated */ loop_cli_way_done: ldr r2, [r0, #PL310_FLUSH_BY_WAY] and r2, r2, r1 cmp r2, #0 bne loop_cli_way_done /* Cache Sync */ /* * Wait for writing cache sync * To PL310, Cache sync is atomic opertion, no need to check * the status. For PL220, this check is needed. Keeping the loop * for PL310 is no harm for PL310. */ loop_cli_sync: ldr r1, [r0, #PL310_SYNC] cmp r1, #0 bne loop_cli_sync mov r1, #0 str r1, [r0, #PL310_SYNC] loop_cli_sync_done: ldr r1, [r0, #PL310_SYNC] cmp r1, #0 bne loop_cli_sync_done mov pc, lr UNWIND( .fnend) END_FUNC arm_cl2_cleaninvbyway /* void arm_cl2_invbyway(vaddr_t base) */ FUNC arm_cl2_invbyway , : UNWIND( .fnstart) syncbyway_set_mask r1 str r1, [r0, #PL310_INV_BY_WAY] loop_inv_way_done: ldr r2, [r0, #PL310_INV_BY_WAY] and r2, r2, r1 cmp r2, #0 bne loop_inv_way_done loop_inv_way_sync: ldr r1, [r0, #PL310_SYNC] cmp r1, #0 bne loop_inv_way_sync mov r1, #0 str r1, [r0, #PL310_SYNC] loop_inv_way_sync_done: ldr r1, [r0, #PL310_SYNC] cmp r1, #0 bne loop_inv_way_sync_done mov pc, lr UNWIND( .fnend) END_FUNC arm_cl2_invbyway /* void arm_cl2_cleanbyway(vaddr_t base) */ FUNC arm_cl2_cleanbyway , : UNWIND( .fnstart) syncbyway_set_mask r1 str r1, [r0, #PL310_CLEAN_BY_WAY] loop_cl_way_done: ldr r2, [r0, #PL310_CLEAN_BY_WAY] and r2, r2, r1 cmp r2, #0 bne loop_cl_way_done loop_cl_way_sync: ldr r1, [r0, #PL310_SYNC] cmp r1, #0 bne loop_cl_way_sync mov r1, #0 str r1, [r0, #PL310_SYNC] loop_cl_way_sync_done: ldr r1, [r0, #PL310_SYNC] cmp r1, #0 bne loop_cl_way_sync_done mov pc, lr UNWIND( .fnend) END_FUNC arm_cl2_cleanbyway /* * void _arm_cl2_xxxbypa(vaddr_t pl310_base, paddr_t start, paddr_t end, * int pl310value); * pl310value is one of PL310_CLEAN_BY_PA, PL310_INV_BY_PA or PL310_FLUSH_BY_PA */ LOCAL_FUNC _arm_cl2_xxxbypa , : UNWIND( .fnstart) /* Align start address on PL310 line size */ and r1, #(~(PL310_LINE_SIZE - 1)) #ifdef SCU_BASE /* * ARM ERRATA #764369 * Undocummented SCU Diagnostic Control Register */ /* * NOTE: * We're assuming that if mmu is enabled PL310_BASE and SCU_BASE * still have the same relative offsets from each other. */ sub r0, r0, #(PL310_BASE - SCU_BASE) mov r12, #1 str r12, [r0, #SCU_ERRATA744369] dsb add r0, r0, #(PL310_BASE - SCU_BASE) #endif loop_cl2_xxxbypa: str r1, [r0, r3] loop_xxx_pa_done: ldr r12, [r0, r3] and r12, r12, r1 cmp r12, #0 bne loop_xxx_pa_done add r1, r1, #PL310_LINE_SIZE cmp r2, r1 bpl loop_cl2_xxxbypa loop_xxx_pa_sync: ldr r12, [r0, #PL310_SYNC] cmp r12, #0 bne loop_xxx_pa_sync mov r12, #0 str r12, [r0, #PL310_SYNC] loop_xxx_pa_sync_done: ldr r12, [r0, #PL310_SYNC] cmp r12, #0 bne loop_xxx_pa_sync_done mov pc, lr UNWIND( .fnend) END_FUNC _arm_cl2_xxxbypa /* * void _arm_cl2_cleanbypa(vaddr_t pl310_base, paddr_t start, paddr_t end); * clean L2 cache by physical address range. */ FUNC arm_cl2_cleanbypa , : UNWIND( .fnstart) mov r3, #PL310_CLEAN_BY_PA b _arm_cl2_xxxbypa UNWIND( .fnend) END_FUNC arm_cl2_cleanbypa /* * void arm_cl2_invbypa(vaddr_t pl310_base, paddr_t start, paddr_t end); * invalidate L2 cache by physical address range. */ FUNC arm_cl2_invbypa , : UNWIND( .fnstart) mov r3, #PL310_INV_BY_PA b _arm_cl2_xxxbypa UNWIND( .fnend) END_FUNC arm_cl2_invbypa /* * void arm_cl2_cleaninvbypa(vaddr_t pl310_base, paddr_t start, paddr_t end); * clean and invalidate L2 cache by physical address range. */ FUNC arm_cl2_cleaninvbypa , : UNWIND( .fnstart) mov r3, #PL310_FLUSH_BY_PA b _arm_cl2_xxxbypa UNWIND( .fnend) END_FUNC arm_cl2_cleaninvbypa