u-boot-brain/arch/arm/cpu/armv8/cache_v8.c
York Sun 1e6ad55c05 armv8/cache: Change cache invalidate and flush function
When SoC first boots up, we should invalidate the cache but not flush it.
We can use the same function for invalid and flush mostly, with a wrapper.

Invalidating large cache can ben slow on emulator, so we postpone doing
so until I-cache is enabled, and before enabling D-cache.

Signed-off-by: York Sun <yorksun@freescale.com>
CC: David Feng <fenghua@phytium.com.cn>
2014-04-07 17:43:41 +02:00

237 lines
4.4 KiB
C

/*
* (C) Copyright 2013
* David Feng <fenghua@phytium.com.cn>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <asm/system.h>
#include <asm/armv8/mmu.h>
DECLARE_GLOBAL_DATA_PTR;
#ifndef CONFIG_SYS_DCACHE_OFF
static void set_pgtable_section(u64 section, u64 memory_type)
{
u64 *page_table = (u64 *)gd->arch.tlb_addr;
u64 value;
value = (section << SECTION_SHIFT) | PMD_TYPE_SECT | PMD_SECT_AF;
value |= PMD_ATTRINDX(memory_type);
page_table[section] = value;
}
/* to activate the MMU we need to set up virtual memory */
static void mmu_setup(void)
{
int i, j, el;
bd_t *bd = gd->bd;
/* Setup an identity-mapping for all spaces */
for (i = 0; i < (PGTABLE_SIZE >> 3); i++)
set_pgtable_section(i, MT_DEVICE_NGNRNE);
/* Setup an identity-mapping for all RAM space */
for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
ulong start = bd->bi_dram[i].start;
ulong end = bd->bi_dram[i].start + bd->bi_dram[i].size;
for (j = start >> SECTION_SHIFT;
j < end >> SECTION_SHIFT; j++) {
set_pgtable_section(j, MT_NORMAL);
}
}
/* load TTBR0 */
el = current_el();
if (el == 1) {
asm volatile("msr ttbr0_el1, %0"
: : "r" (gd->arch.tlb_addr) : "memory");
asm volatile("msr tcr_el1, %0"
: : "r" (TCR_FLAGS | TCR_EL1_IPS_BITS)
: "memory");
asm volatile("msr mair_el1, %0"
: : "r" (MEMORY_ATTRIBUTES) : "memory");
} else if (el == 2) {
asm volatile("msr ttbr0_el2, %0"
: : "r" (gd->arch.tlb_addr) : "memory");
asm volatile("msr tcr_el2, %0"
: : "r" (TCR_FLAGS | TCR_EL2_IPS_BITS)
: "memory");
asm volatile("msr mair_el2, %0"
: : "r" (MEMORY_ATTRIBUTES) : "memory");
} else {
asm volatile("msr ttbr0_el3, %0"
: : "r" (gd->arch.tlb_addr) : "memory");
asm volatile("msr tcr_el3, %0"
: : "r" (TCR_FLAGS | TCR_EL2_IPS_BITS)
: "memory");
asm volatile("msr mair_el3, %0"
: : "r" (MEMORY_ATTRIBUTES) : "memory");
}
/* enable the mmu */
set_sctlr(get_sctlr() | CR_M);
}
/*
* Performs a invalidation of the entire data cache at all levels
*/
void invalidate_dcache_all(void)
{
__asm_invalidate_dcache_all();
}
/*
* Performs a clean & invalidation of the entire data cache at all levels
*/
void flush_dcache_all(void)
{
__asm_flush_dcache_all();
}
/*
* Invalidates range in all levels of D-cache/unified cache
*/
void invalidate_dcache_range(unsigned long start, unsigned long stop)
{
__asm_flush_dcache_range(start, stop);
}
/*
* Flush range(clean & invalidate) from all levels of D-cache/unified cache
*/
void flush_dcache_range(unsigned long start, unsigned long stop)
{
__asm_flush_dcache_range(start, stop);
}
void dcache_enable(void)
{
/* The data cache is not active unless the mmu is enabled */
if (!(get_sctlr() & CR_M)) {
invalidate_dcache_all();
__asm_invalidate_tlb_all();
mmu_setup();
}
set_sctlr(get_sctlr() | CR_C);
}
void dcache_disable(void)
{
uint32_t sctlr;
sctlr = get_sctlr();
/* if cache isn't enabled no need to disable */
if (!(sctlr & CR_C))
return;
set_sctlr(sctlr & ~(CR_C|CR_M));
flush_dcache_all();
__asm_invalidate_tlb_all();
}
int dcache_status(void)
{
return (get_sctlr() & CR_C) != 0;
}
#else /* CONFIG_SYS_DCACHE_OFF */
void invalidate_dcache_all(void)
{
}
void flush_dcache_all(void)
{
}
void invalidate_dcache_range(unsigned long start, unsigned long stop)
{
}
void flush_dcache_range(unsigned long start, unsigned long stop)
{
}
void dcache_enable(void)
{
}
void dcache_disable(void)
{
}
int dcache_status(void)
{
return 0;
}
#endif /* CONFIG_SYS_DCACHE_OFF */
#ifndef CONFIG_SYS_ICACHE_OFF
void icache_enable(void)
{
__asm_invalidate_icache_all();
set_sctlr(get_sctlr() | CR_I);
}
void icache_disable(void)
{
set_sctlr(get_sctlr() & ~CR_I);
}
int icache_status(void)
{
return (get_sctlr() & CR_I) != 0;
}
void invalidate_icache_all(void)
{
__asm_invalidate_icache_all();
}
#else /* CONFIG_SYS_ICACHE_OFF */
void icache_enable(void)
{
}
void icache_disable(void)
{
}
int icache_status(void)
{
return 0;
}
void invalidate_icache_all(void)
{
}
#endif /* CONFIG_SYS_ICACHE_OFF */
/*
* Enable dCache & iCache, whether cache is actually enabled
* depend on CONFIG_SYS_DCACHE_OFF and CONFIG_SYS_ICACHE_OFF
*/
void enable_caches(void)
{
icache_enable();
dcache_enable();
}
/*
* Flush range from all levels of d-cache/unified-cache
*/
void flush_cache(unsigned long start, unsigned long size)
{
flush_dcache_range(start, start + size);
}