blob: ef241d5173529013ea883d5b9e56bec8af04e0a1 [file] [log] [blame]
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* Copyright (c) 2014, STMicroelectronics International N.V.
*/
#include <asm.S>
#include <kernel/tz_proc_def.h>
#include <kernel/tz_ssvce_def.h>
#include <kernel/unwind.h>
#include <platform_config.h>
#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