forked from xuos/xiuos
704 lines
20 KiB
C
704 lines
20 KiB
C
/****************************************************************************
|
||
* arch/arm/src/armv7-a/arm_l2cc_pl310.c
|
||
*
|
||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||
* contributor license agreements. See the NOTICE file distributed with
|
||
* this work for additional information regarding copyright ownership. The
|
||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||
* "License"); you may not use this file except in compliance with the
|
||
* License. You may obtain a copy of the License at
|
||
*
|
||
* http://www.apache.org/licenses/LICENSE-2.0
|
||
*
|
||
* Unless required by applicable law or agreed to in writing, software
|
||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||
* License for the specific language governing permissions and limitations
|
||
* under the License.
|
||
*
|
||
****************************************************************************/
|
||
/* Reference: "CoreLink<6E> Level 2 Cache Controller L2C-310", Revision r3p2,
|
||
* Technical Reference Manual, ARM DDI 0246F (ID011711), ARM
|
||
*
|
||
* NOTE: This logic is incompatible with older versions of the PL310!
|
||
*/
|
||
|
||
/**
|
||
* @file l2_cache.c
|
||
* @brief the general management of L2 cache
|
||
* @version 3.0
|
||
* @author AIIT XUOS Lab
|
||
* @date 2023/08/10
|
||
*/
|
||
|
||
/*************************************************
|
||
File name: l2_cache.c
|
||
Description: the general management of L2 cache
|
||
Others:
|
||
History:
|
||
1. Date: 2023-04-27
|
||
Author: AIIT XUOS Lab
|
||
Modification:
|
||
1. support xiuos cache interface
|
||
2. implementations are modifications of imx6 SDK package
|
||
*************************************************/
|
||
|
||
#include "l2_cache.h"
|
||
#include "core.h"
|
||
#include "l2cc_pl310.h"
|
||
|
||
#define CONFIG_ARMV7A_ASSOCIATIVITY_16WAY
|
||
#define CONFIG_ARMV7A_WAYSIZE_16KB
|
||
|
||
#define read32(a) (*(volatile uint32_t*)(a))
|
||
#define write32(v, a) (*(volatile uint32_t*)(a) = (v))
|
||
|
||
#define PANIC() panic()
|
||
|
||
#define ASSERT(f) do { if (!(f)) PANIC(); } while (0)
|
||
#define VERIFY(f) do { if ((f) < 0) PANIC(); } while (0)
|
||
|
||
#ifdef CONFIG_DEBUG_ASSERTIONS
|
||
# define DEBUGPANIC() PANIC()
|
||
# define DEBUGASSERT(f) ASSERT(f)
|
||
# define DEBUGVERIFY(f) VERIFY(f)
|
||
#else
|
||
# define DEBUGPANIC()
|
||
# define DEBUGASSERT(f) ((void)(1 || (f)))
|
||
# define DEBUGVERIFY(f) ((void)(f))
|
||
#endif
|
||
|
||
/****************************************************************************
|
||
* Pre-processor Definitions
|
||
****************************************************************************/
|
||
|
||
/* Configuration ************************************************************/
|
||
|
||
/* Number of ways depends on ARM configuration */
|
||
|
||
#if defined(CONFIG_ARMV7A_ASSOCIATIVITY_8WAY)
|
||
# define PL310_NWAYS 8
|
||
# define PL310_WAY_MASK 0x000000ff
|
||
#elif defined(CONFIG_ARMV7A_ASSOCIATIVITY_16WAY)
|
||
# define PL310_NWAYS 16
|
||
# define PL310_WAY_MASK 0x0000ffff
|
||
#else
|
||
# error "Number of ways not selected"
|
||
#endif
|
||
|
||
/* The size of one depends on ARM configuration */
|
||
|
||
#if defined(CONFIG_ARMV7A_WAYSIZE_16KB)
|
||
# define PL310_WAYSIZE (16 * 1024)
|
||
#elif defined(CONFIG_ARMV7A_WAYSIZE_32KB)
|
||
# define PL310_WAYSIZE (32 * 1024)
|
||
#elif defined(CONFIG_ARMV7A_WAYSIZE_64KB)
|
||
# define PL310_WAYSIZE (64 * 1024)
|
||
#elif defined(CONFIG_ARMV7A_WAYSIZE_128KB)
|
||
# define PL310_WAYSIZE (128 * 1024)
|
||
#elif defined(CONFIG_ARMV7A_WAYSIZE_256KB)
|
||
# define PL310_WAYSIZE (256 * 1024)
|
||
#elif defined(CONFIG_ARMV7A_WAYSIZE_512KB)
|
||
# define PL310_WAYSIZE (512 * 1024)
|
||
#else
|
||
# error "Way size not selected"
|
||
#endif
|
||
|
||
/* The size of the cache is then the product of the number of ways times
|
||
* the size of each way.
|
||
*/
|
||
|
||
#define PL310_CACHE_SIZE (PL310_NWAYS * PL310_WAYSIZE)
|
||
|
||
/* Use for aligning addresses to a cache line boundary */
|
||
|
||
#define PL310_CACHE_LINE_MASK (PL310_CACHE_LINE_SIZE - 1)
|
||
|
||
/* Configurable options
|
||
*
|
||
* REVISIT: Currently there are not configuration options. All values
|
||
* are just set to the default.
|
||
*/
|
||
|
||
/* Bit 0: Full line zero enable
|
||
*
|
||
* Default: 0=Full line of write zero behavior disabled
|
||
*/
|
||
|
||
#define L2CC_ACR_FLZE_CONFIG (0) /* 0=Full line of write zero behavior disabled */
|
||
|
||
/* Bit 10: High Priority for SO and Dev Reads Enable
|
||
*
|
||
* Default: 0=Strongly Ordered and Device reads have lower priority than
|
||
* cacheable accesses
|
||
*/
|
||
|
||
#define L2CC_ACR_HPSO_CONFIG (0) /* 0=Have lower priority than cache */
|
||
|
||
/* Bit 11: Store Buffer Device Limitation Enable
|
||
*
|
||
* Default: 0=Store buffer device limitation disabled
|
||
*/
|
||
|
||
#define L2CC_ACR_SBDLE_CONFIG (0) /* 0=Store buffer device limitation disabled */
|
||
|
||
/* Bit 12: Exclusive Cache Configuration
|
||
*
|
||
* Default: 0=Disabled
|
||
*/
|
||
|
||
#define L2CC_ACR_EXCC_CONFIG (0) /* 0=Disabled */
|
||
|
||
/* Bit 13: Shared Attribute Invalidate Enable
|
||
*
|
||
* Default: 0=Shared invalidate behavior disabled
|
||
*/
|
||
|
||
#define L2CC_ACR_SAIE_CONFIG (0) /* 0=Shared invalidate behavior disabled */
|
||
|
||
/* Bit 20: Event Monitor Bus Enable
|
||
*
|
||
* Default: 0=Disabled
|
||
*/
|
||
|
||
#define L2CC_ACR_EMBEN_CONFIG (0) /* 0=Disabled */
|
||
|
||
/* Bit 21: Parity Enable
|
||
*
|
||
* Default: 0=Disabled
|
||
*/
|
||
|
||
#define L2CC_ACR_PEN_CONFIG (0) /* 0=Disabled */
|
||
|
||
/* Bit 22: Shared Attribute Override Enable
|
||
*
|
||
* Default: 0=Treats shared accesses as specified in the TRM
|
||
*/
|
||
|
||
#define L2CC_ACR_SAOEN_CONFIG (0) /* 0=As specified in the TRM */
|
||
|
||
/* Bits 23-24: Force Write Allocate
|
||
*
|
||
* Default: 0=Use AWCACHE attributes for WA
|
||
*/
|
||
|
||
#define L2CC_ACR_FWA_CONFIG L2CC_ACR_FWA_AWCACHE /* Use AWCACHE attributes for WA */
|
||
|
||
/* Bit 25: Cache Replacement Policy
|
||
*
|
||
* Default: 1=Round robin replacement policy
|
||
*/
|
||
|
||
#define L2CC_ACR_CRPOL_CONFIG L2CC_ACR_CRPOL /* 1=Round robin replacement policy */
|
||
|
||
/* Bit 26: Non-Secure Lockdown Enable
|
||
*
|
||
* Default: 0=Lockdown registers cannot be modified using non-secure accesses
|
||
*/
|
||
|
||
#define L2CC_ACR_NSLEN_CONFIG (0) /* 0=Secure access only */
|
||
|
||
/* Bit 27: Non-Secure Interrupt Access Control
|
||
*
|
||
* Default: 0=Interrupt Clear and Mask can only be modified or read with
|
||
* secure accesses
|
||
*/
|
||
|
||
#define L2CC_ACR_NSIAC_CONFIG (0) /* 0=Secure access only */
|
||
|
||
/* Bit 28: Data Prefetch Enable
|
||
*
|
||
* Default: 0=Data prefetching disabled
|
||
*/
|
||
|
||
#define L2CC_ACR_DPEN_CONFIG (0) /* 0=Data prefetching disabled */
|
||
|
||
/* Bit 29: Instruction Prefetch Enable
|
||
*
|
||
* Default: 0=Instruction prefetching disabled
|
||
*/
|
||
|
||
#define L2CC_ACR_IPEN_CONFIG (0) /* 0=Instruction prefetching disabled */
|
||
|
||
/* Bit 30: Early BRESP enable
|
||
*
|
||
* Default: 0=Early BRESP disabled
|
||
*/
|
||
|
||
#define L2CC_ACR_EBRESP_CONFIG (0) /* 0=Early BRESP disabled */
|
||
|
||
#define L2CC_ACR_CONFIG \
|
||
(L2CC_ACR_FLZE_CONFIG | L2CC_ACR_HPSO_CONFIG | L2CC_ACR_SBDLE_CONFIG | \
|
||
L2CC_ACR_EXCC_CONFIG | L2CC_ACR_SAIE_CONFIG | L2CC_ACR_EMBEN_CONFIG | \
|
||
L2CC_ACR_PEN_CONFIG | L2CC_ACR_SAOEN_CONFIG | L2CC_ACR_FWA_CONFIG | \
|
||
L2CC_ACR_CRPOL_CONFIG | L2CC_ACR_NSLEN_CONFIG | L2CC_ACR_NSIAC_CONFIG | \
|
||
L2CC_ACR_DPEN_CONFIG | L2CC_ACR_IPEN_CONFIG | L2CC_ACR_EBRESP_CONFIG)
|
||
|
||
#define L2CC_ACR_ALLCONFIGS (0x7f303c01)
|
||
#define L2CC_ACR_CONFIGMASK (L2CC_ACR_SBZ | L2CC_ACR_ALLCONFIGS)
|
||
|
||
/* Filter end address */
|
||
|
||
#define CONFIG_PL310_FLEND (CONFIG_PL310_FLSTRT + CONFIG_PL310_FLSIZE)
|
||
|
||
/* Block size. Used to break up long operations so that interrupts are not
|
||
* disabled for a long time.
|
||
*/
|
||
|
||
#define PL310_GULP_SIZE 4096
|
||
|
||
/* Misc commoly defined and re-defined things */
|
||
|
||
#ifndef MIN
|
||
# define MIN(a,b) (((a) < (b)) ? (a) : (b))
|
||
#endif
|
||
|
||
#ifndef MAX
|
||
# define MAX(a,b) (((a) > (b)) ? (a) : (b))
|
||
#endif
|
||
|
||
#ifndef OK
|
||
# define OK 0
|
||
#endif
|
||
|
||
/****************************************************************************
|
||
* Private Functions
|
||
****************************************************************************/
|
||
|
||
|
||
/****************************************************************************
|
||
* Name: pl310_flush_all
|
||
*
|
||
* Description:
|
||
* Flush all ways using the Clean Invalidate Way Register (CIWR).
|
||
*
|
||
****************************************************************************/
|
||
|
||
void pl310_flush_all(void)
|
||
{
|
||
DSB();
|
||
/* Flush all ways by writing the set of ways to be cleaned to the Clean
|
||
* Invalidate Way Register (CIWR).
|
||
*/
|
||
write32(PL310_WAY_MASK, L2CC_CIWR);
|
||
|
||
/* Wait for cache operation by way to complete */
|
||
while ((read32(L2CC_CIWR) & PL310_WAY_MASK) != 0)
|
||
;
|
||
|
||
/* Drain the STB. Operation complete when all buffers, LRB, LFB, STB, and
|
||
* EB, are empty.
|
||
*/
|
||
|
||
write32(0, L2CC_CSR);
|
||
DSB();
|
||
}
|
||
|
||
/****************************************************************************
|
||
* Public Functions
|
||
****************************************************************************/
|
||
|
||
/****************************************************************************
|
||
* Name: arm_l2ccinitialize
|
||
*
|
||
* Description:
|
||
* One time configuration of the L2 cache. The L2 cache will be enabled
|
||
* upon return.
|
||
*
|
||
****************************************************************************/
|
||
|
||
void arm_l2ccinitialize(void)
|
||
{
|
||
uint32_t regval;
|
||
int i;
|
||
#if defined(CONFIG_ARMV7A_ASSOCIATIVITY_8WAY)
|
||
DEBUGASSERT((read32(L2CC_ACR) & L2CC_ACR_ASS) == 0);
|
||
#elif defined(CONFIG_ARMV7A_ASSOCIATIVITY_16WAY)
|
||
DEBUGASSERT((read32(L2CC_ACR) & L2CC_ACR_ASS) == L2CC_ACR_ASS);
|
||
#else
|
||
# error No associativity selected
|
||
#endif
|
||
|
||
#if defined(CONFIG_ARMV7A_WAYSIZE_16KB)
|
||
DEBUGASSERT((read32(L2CC_ACR) & L2CC_ACR_WAYSIZE_MASK) == L2CC_ACR_WAYSIZE_16KB);
|
||
#elif defined(CONFIG_ARMV7A_WAYSIZE_32KB)
|
||
DEBUGASSERT((read32(L2CC_ACR) & L2CC_ACR_WAYSIZE_MASK) == L2CC_ACR_WAYSIZE_32KB);
|
||
#elif defined(CONFIG_ARMV7A_WAYSIZE_64KB)
|
||
DEBUGASSERT((read32(L2CC_ACR) & L2CC_ACR_WAYSIZE_MASK) == L2CC_ACR_WAYSIZE_64KB);
|
||
#elif defined(CONFIG_ARMV7A_WAYSIZE_128KB)
|
||
DEBUGASSERT((read32(L2CC_ACR) & L2CC_ACR_WAYSIZE_MASK) == L2CC_ACR_WAYSIZE_128KB);
|
||
#elif defined(CONFIG_ARMV7A_WAYSIZE_256KB)
|
||
DEBUGASSERT((read32(L2CC_ACR) & L2CC_ACR_WAYSIZE_MASK) == L2CC_ACR_WAYSIZE_256KB);
|
||
#elif defined(CONFIG_ARMV7A_WAYSIZE_512KB)
|
||
DEBUGASSERT((read32(L2CC_ACR) & L2CC_ACR_WAYSIZE_MASK) == L2CC_ACR_WAYSIZE_512KB);
|
||
#else
|
||
# error No way size selected
|
||
#endif
|
||
|
||
if ((read32(L2CC_CR) & L2CC_CR_L2CEN) == 0) {
|
||
#if defined(CONFIG_PL310_TRCR_TSETLAT) && defined(CONFIG_PL310_TRCR_TRDLAT) && defined(CONFIG_PL310_TRCR_TWRLAT)
|
||
/* Configure Tag RAM control */
|
||
|
||
regval = ((CONFIG_PL310_TRCR_TSETLAT - 1) << L2CC_TRCR_TSETLAT_SHIFT)((CONFIG_PL310_TRCR_TRDLAT - 1) << L2CC_TRCR_TRDLAT_SHIFT) | ((CONFIG_PL310_TRCR_TWRLAT - 1) << L2CC_TRCR_TWRLAT_SHIFT);
|
||
write32(regval, L2CC_TRCR);
|
||
#endif
|
||
|
||
#if defined(CONFIG_PL310_DRCR_DSETLAT) && defined(CONFIG_PL310_DRCR_DRDLAT) && defined(CONFIG_PL310_DRCR_DWRLAT)
|
||
/* Configure Data RAM control */
|
||
regval = ((CONFIG_PL310_DRCR_DSETLAT - 1) << L2CC_DRCR_DSETLAT_SHIFT) | ((CONFIG_PL310_DRCR_DRDLAT - 1) << L2CC_DRCR_DRDLAT_SHIFT) | ((CONFIG_PL310_DRCR_DWRLAT - 1) << L2CC_DRCR_DWRLAT_SHIFT);
|
||
write32(regval, L2CC_DRCR);
|
||
#endif
|
||
|
||
#ifdef PL310_ADDRESS_FILTERING
|
||
#if defined(CONFIG_PL310_FLSTRT) && defined(CONFIG_PL310_FLSIZE)
|
||
/* Configure the address filter */
|
||
regval = (CONFIG_PL310_FLEND + ~L2CC_FLEND_MASK) & L2CC_FLEND_MASK;
|
||
write32(regval, L2CC_FLEND);
|
||
|
||
regval = (CONFIG_PL310_FLSTRT & L2CC_FLSTRT_MASK) | L2CC_FLSTRT_ENABLE;
|
||
write32(regval | L2X0_ADDR_FILTER_EN, L2CC_FLSTRT);
|
||
#endif
|
||
#endif
|
||
/* Make sure that the memory is not locked down */
|
||
|
||
for (i = 0; i < PL310_NLOCKREGS; i++) {
|
||
write32(0, L2CC_DLKR(i));
|
||
write32(0, L2CC_ILKR(i));
|
||
}
|
||
|
||
/* Configure the cache properties */
|
||
|
||
regval = read32(L2CC_ACR);
|
||
regval &= ~L2CC_ACR_CONFIGMASK;
|
||
regval |= L2CC_ACR_CONFIG;
|
||
write32(regval, L2CC_ACR);
|
||
|
||
/* Invalidate and enable the cache */
|
||
|
||
InvalidateL2CacheAll();
|
||
write32(L2CC_CR_L2CEN, L2CC_CR);
|
||
}
|
||
}
|
||
|
||
/****************************************************************************
|
||
* Name: l2cc_enable
|
||
*
|
||
* Description:
|
||
* Re-enable the L2CC-P310 L2 cache by setting the enable bit in the
|
||
* Control Register (CR)
|
||
*
|
||
****************************************************************************/
|
||
|
||
void EnableL2Cache(void)
|
||
{
|
||
|
||
InvalidateL2CacheAll();
|
||
write32(L2CC_CR_L2CEN, L2CC_CR);
|
||
}
|
||
|
||
/****************************************************************************
|
||
* Name: l2cc_disable
|
||
*
|
||
* Description:
|
||
* Disable the L2CC-P310 L2 cache by clearing the Control Register (CR)
|
||
*
|
||
*
|
||
****************************************************************************/
|
||
|
||
void DisableL2Cache(void)
|
||
{
|
||
write32(0, L2CC_CR);
|
||
DSB();
|
||
}
|
||
|
||
/****************************************************************************
|
||
* Name: l2cc_sync
|
||
*
|
||
* Description:
|
||
* Drain the STB. Operation complete when all buffers, LRB, LFB, STB, and
|
||
* EB, are empty.
|
||
*
|
||
****************************************************************************/
|
||
|
||
void SyncL2Cache(void)
|
||
{
|
||
write32(0, L2CC_CSR);
|
||
}
|
||
|
||
/****************************************************************************
|
||
* Name: l2cc_invalidate_all
|
||
*
|
||
* Description:
|
||
* Invalidate all ways using the Invalidate Way Register (IWR).
|
||
*
|
||
****************************************************************************/
|
||
|
||
void InvalidateL2CacheAll(void)
|
||
{
|
||
|
||
uint32_t regval;
|
||
|
||
/* Invalidate all ways */
|
||
/* Disable the L2 cache while we invalidate it */
|
||
|
||
regval = read32(L2CC_CR);
|
||
DisableL2Cache();
|
||
|
||
/* Invalidate all ways by writing the bit mask of ways to be invalidated
|
||
* the Invalidate Way Register (IWR).
|
||
*/
|
||
|
||
write32(PL310_WAY_MASK, L2CC_IWR);
|
||
|
||
while ((read32(L2CC_IWR) & PL310_WAY_MASK) != 0)
|
||
;
|
||
|
||
/* Drain the STB. Operation complete when all buffers, LRB, LFB, STB, and
|
||
* EB, are empty.
|
||
*/
|
||
|
||
write32(0, L2CC_CSR);
|
||
|
||
/* Then re-enable the L2 cache if it was enabled before */
|
||
|
||
write32(regval, L2CC_CR);
|
||
}
|
||
|
||
/****************************************************************************
|
||
* Name: l2cc_invalidate
|
||
*
|
||
* Description:
|
||
* Invalidate a range of addresses by writing to the Invalidate Physical
|
||
* Address Line Register (IPALR) repeatedly.
|
||
*
|
||
****************************************************************************/
|
||
|
||
void InvalidateL2Cache(uintptr_t startaddr, uintptr_t endaddr)
|
||
{
|
||
uintptr_t invalsize;
|
||
uintptr_t gulpend;
|
||
|
||
/* Check if the start address is aligned with a cacheline */
|
||
if ((startaddr & PL310_CACHE_LINE_MASK) != 0) {
|
||
/* No.. align down and flush the cache line by writing the address to
|
||
* the Clean Invalidate Physical Address Line Register (CIPALR).
|
||
*/
|
||
|
||
startaddr &= ~PL310_CACHE_LINE_MASK;
|
||
write32(startaddr, L2CC_CIPALR);
|
||
|
||
/* Then start invalidating at the next cache line */
|
||
|
||
startaddr += PL310_CACHE_LINE_SIZE;
|
||
}
|
||
|
||
/* Check if the end address is aligned with a cache line */
|
||
|
||
if ((endaddr & PL310_CACHE_LINE_MASK) != 0) {
|
||
/* No.. align down and flush cache line by writing the address to
|
||
* the Clean Invalidate Physical Address Line Register (CIPALR).
|
||
*/
|
||
|
||
endaddr &= ~PL310_CACHE_LINE_MASK;
|
||
write32(endaddr, L2CC_CIPALR);
|
||
}
|
||
|
||
/* Loop, invalidated the address range by cache line. Interrupts are re-
|
||
* enabled momentarily every PL310_GULP_SIZE bytes.
|
||
*/
|
||
|
||
while (startaddr < endaddr) {
|
||
/* Get the size of the next gulp of cache lines to invalidate. We do
|
||
* this in small chunks so that we do not have to keep interrupts
|
||
* disabled throughout the whole flush.
|
||
*/
|
||
|
||
invalsize = endaddr - startaddr;
|
||
gulpend = startaddr + MIN(invalsize, PL310_GULP_SIZE);
|
||
|
||
/* Disable interrupts and invalidate the gulp */
|
||
while (startaddr < gulpend) {
|
||
/* Invalidate the cache line by writing the address to the
|
||
* Invalidate Physical Address Line Register (IPALR).
|
||
*/
|
||
write32(startaddr, L2CC_IPALR);
|
||
|
||
/* Start of the next cache line */
|
||
|
||
startaddr += PL310_CACHE_LINE_SIZE;
|
||
}
|
||
/* Enable interrupts momentarily */
|
||
}
|
||
|
||
/* Drain the STB. Operation complete when all buffers, LRB, LFB, STB, and
|
||
* EB, are empty.
|
||
*/
|
||
write32(0, L2CC_CSR);
|
||
}
|
||
|
||
/****************************************************************************
|
||
* Name: l2cc_clean_all
|
||
*
|
||
* Description:
|
||
* Clean all ways by using the Clean Ways Register (CWR).
|
||
*
|
||
****************************************************************************/
|
||
|
||
void CleanL2CacheAll(void)
|
||
{
|
||
write32(PL310_WAY_MASK, L2CC_CWR);
|
||
|
||
/* Wait for cache operation by way to complete */
|
||
|
||
while ((read32(L2CC_CWR) & PL310_WAY_MASK) != 0)
|
||
;
|
||
|
||
/* Drain the STB. Operation complete when all buffers, LRB, LFB, STB, and
|
||
* EB, are empty.
|
||
*/
|
||
|
||
write32(0, L2CC_CSR);
|
||
}
|
||
|
||
/****************************************************************************
|
||
* Name: l2cc_clean
|
||
*
|
||
* Description:
|
||
* Clean the cache line over a range of addresses uing the Clean Physical
|
||
* Address Line Register (CPALR) repeatedly.
|
||
*
|
||
****************************************************************************/
|
||
|
||
void CleanL2Cache(uintptr_t startaddr, uintptr_t endaddr)
|
||
{
|
||
uintptr_t cleansize;
|
||
uintptr_t gulpend;
|
||
|
||
/* If the range of addresses to clean is as large or larger the L2 cache,
|
||
* then just clean the whole thing.
|
||
*/
|
||
|
||
cleansize = endaddr - startaddr;
|
||
if (cleansize >= PL310_CACHE_SIZE) {
|
||
CleanL2CacheAll();
|
||
return;
|
||
}
|
||
|
||
/* Align the starting address to a cache line boundary */
|
||
|
||
startaddr &= ~PL310_CACHE_LINE_MASK;
|
||
|
||
/* Clean the L2 cache by cache line, enabling interrupts momentarily
|
||
* every PL310_GULP_SIZE bytes.
|
||
*/
|
||
|
||
while (startaddr < endaddr) {
|
||
/* Get the size of the next gulp of cache lines to flush. We do
|
||
* this in small chunks so that we do not have to keep interrupts
|
||
* disabled throughout the whole flush.
|
||
*/
|
||
|
||
cleansize = endaddr - startaddr;
|
||
gulpend = startaddr + MIN(cleansize, PL310_GULP_SIZE);
|
||
|
||
/* Disable interrupts and clean the gulp */
|
||
while (startaddr < gulpend) {
|
||
/* Clean the cache line by writing the address to the Clean
|
||
* Physical Address Line Register (CPALR).
|
||
*/
|
||
|
||
write32(startaddr, L2CC_CPALR);
|
||
|
||
/* Start of the next cache line */
|
||
|
||
startaddr += PL310_CACHE_LINE_SIZE;
|
||
}
|
||
|
||
/* Enable interrupts momentarily */
|
||
}
|
||
|
||
/* Drain the STB. Operation complete when all buffers, LRB, LFB, STB, and
|
||
* EB, are empty.
|
||
*/
|
||
write32(0, L2CC_CSR);
|
||
}
|
||
|
||
/****************************************************************************
|
||
* Name: l2cc_flush_all
|
||
*
|
||
* Description:
|
||
* Flush all ways using the Clean Invalidate Way Register (CIWR).
|
||
*
|
||
****************************************************************************/
|
||
|
||
void FlushL2CacheAll(void)
|
||
{
|
||
/* Flush all ways using the Clean Invalidate Way Register (CIWR). */
|
||
pl310_flush_all();
|
||
}
|
||
|
||
/****************************************************************************
|
||
* Name: l2cc_flush
|
||
*
|
||
* Description:
|
||
* Flush a range of address by using the Clean Invalidate Physical Address
|
||
* Line Register (CIPALR) repeatedly.
|
||
*
|
||
****************************************************************************/
|
||
|
||
void FlushL2Cache(uint32_t startaddr, uint32_t endaddr)
|
||
{
|
||
uintptr_t flushsize;
|
||
uintptr_t gulpend;
|
||
/* If the range of addresses to flush is as large or larger the L2 cache,
|
||
* then just flush the whole thing.
|
||
*/
|
||
|
||
flushsize = endaddr - startaddr;
|
||
if (flushsize >= PL310_CACHE_SIZE)
|
||
{
|
||
pl310_flush_all();
|
||
return;
|
||
}
|
||
|
||
/* Align the starting address to a cache line boundary */
|
||
|
||
startaddr &= ~PL310_CACHE_LINE_MASK;
|
||
|
||
/* Flush the L2 cache by cache line, enabling interrupts momentarily
|
||
* every PL310_GULP_SIZE bytes.
|
||
*/
|
||
|
||
while (startaddr < endaddr)
|
||
{
|
||
/* Get the size of the next gulp of cache lines to flush. We do
|
||
* this in small chunks so that we do not have to keep interrupts
|
||
* disabled throughout the whole flush.
|
||
*/
|
||
|
||
flushsize = endaddr - startaddr;
|
||
gulpend = startaddr + MIN(flushsize, PL310_GULP_SIZE);
|
||
|
||
/* Disable interrupts and flush the gulp */
|
||
while (startaddr < gulpend)
|
||
{
|
||
/* Flush the cache line by writing the address to the Clean
|
||
* Invalidate Physical Address Line Register (CIPALR).
|
||
*/
|
||
write32(startaddr, L2CC_CIPALR);
|
||
|
||
/* Start of the next cache line */
|
||
startaddr += PL310_CACHE_LINE_SIZE;
|
||
}
|
||
|
||
/* Enable interrupts momentarily */
|
||
}
|
||
|
||
/* Drain the STB. Operation complete when all buffers, LRB, LFB, STB, and
|
||
* EB, are empty.
|
||
*/
|
||
write32(0, L2CC_CSR);
|
||
}
|
||
|
||
|