870 lines
23 KiB
C
870 lines
23 KiB
C
/****************************************************************************
|
|
* arch/arm/src/armv7-r/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™ 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!
|
|
*/
|
|
|
|
/****************************************************************************
|
|
* Included Files
|
|
****************************************************************************/
|
|
|
|
#include <nuttx/config.h>
|
|
|
|
#include <stdint.h>
|
|
#include <assert.h>
|
|
#include <debug.h>
|
|
|
|
#include <nuttx/irq.h>
|
|
|
|
#include "arm_internal.h"
|
|
#include "l2cc.h"
|
|
#include "l2cc_pl310.h"
|
|
|
|
#ifdef CONFIG_ARMV7R_L2CC_PL310
|
|
|
|
/****************************************************************************
|
|
* Pre-processor Definitions
|
|
****************************************************************************/
|
|
|
|
/* Configuration ************************************************************/
|
|
|
|
/* Number of ways depends on ARM configuration */
|
|
|
|
#if defined(CONFIG_ARMV7R_ASSOCIATIVITY_8WAY)
|
|
# define PL310_NWAYS 8
|
|
# define PL310_WAY_MASK 0x000000ff
|
|
#elif defined(CONFIG_ARMV7R_ASSOCIATIVITY_8WAY)
|
|
# 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_ARMV7R_WAYSIZE_16KB)
|
|
# define PL310_WAYSIZE (16 * 1024)
|
|
#elif defined(CONFIG_ARMV7R_WAYSIZE_32KB)
|
|
# define PL310_WAYSIZE (32 * 1024)
|
|
#elif defined(CONFIG_ARMV7R_WAYSIZE_64KB)
|
|
# define PL310_WAYSIZE (64 * 1024)
|
|
#elif defined(CONFIG_ARMV7R_WAYSIZE_128KB)
|
|
# define PL310_WAYSIZE (128 * 1024)
|
|
#elif defined(CONFIG_ARMV7R_WAYSIZE_256KB)
|
|
# define PL310_WAYSIZE (256 * 1024)
|
|
#elif defined(CONFIG_ARMV7R_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
|
|
|
|
/* Data synchronization barrier */
|
|
|
|
#define dsb(a) __asm__ __volatile__ ("dsb " #a : : : "memory")
|
|
|
|
/****************************************************************************
|
|
* Private Functions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Name: pl310_flush_all
|
|
*
|
|
* Description:
|
|
* Flush all ways using the Clean Invalidate Way Register (CIWR).
|
|
*
|
|
* Input Parameters:
|
|
* None
|
|
*
|
|
* Returned Value:
|
|
* None
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void pl310_flush_all(void)
|
|
{
|
|
/* Flush all ways by writing the set of ways to be cleaned to the Clean
|
|
* Invalidate Way Register (CIWR).
|
|
*/
|
|
|
|
putreg32(PL310_WAY_MASK, L2CC_CIWR);
|
|
|
|
/* Wait for cache operation by way to complete */
|
|
|
|
while ((getreg32(L2CC_CIWR) & PL310_WAY_MASK) != 0);
|
|
|
|
/* Drain the STB. Operation complete when all buffers, LRB, LFB, STB, and
|
|
* EB, are empty.
|
|
*/
|
|
|
|
putreg32(0, L2CC_CSR);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Public Functions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Name: arm_l2ccinitialize
|
|
*
|
|
* Description:
|
|
* One time configuration of the L2 cache. The L2 cache will be enabled
|
|
* upon return.
|
|
*
|
|
* Input Parameters:
|
|
* None. The L2 cache configuration is controlled by configuration
|
|
* settings.
|
|
*
|
|
* Returned Value:
|
|
* None
|
|
*
|
|
****************************************************************************/
|
|
|
|
void arm_l2ccinitialize(void)
|
|
{
|
|
uint32_t regval;
|
|
int i;
|
|
|
|
/* Make sure that this is a PL310 cache, version r3p2.
|
|
*
|
|
* REVISIT: The SAMA5D4 is supposed to report its ID as 0x410000C8 which is
|
|
* r3p2, but the chip that I have actually* reports 0x410000C9 which is
|
|
* some later revision.
|
|
*/
|
|
|
|
/* DEBUGASSERT((getreg32(L2CC_IDR) &
|
|
* L2CC_IDR_REV_MASK) == L2CC_IDR_REV_R3P2);
|
|
*/
|
|
|
|
/* Make sure that actual cache configuration agrees with the configured
|
|
* cache configuration.
|
|
*/
|
|
|
|
#if defined(CONFIG_ARMV7R_ASSOCIATIVITY_8WAY)
|
|
DEBUGASSERT((getreg32(L2CC_ACR) & L2CC_ACR_ASS) == 0);
|
|
#elif defined(CONFIG_ARMV7R_ASSOCIATIVITY_16WAY)
|
|
DEBUGASSERT((getreg32(L2CC_ACR) & L2CC_ACR_ASS) == 1);
|
|
#else
|
|
# error No associativity selected
|
|
#endif
|
|
|
|
#if defined(CONFIG_ARMV7R_WAYSIZE_16KB)
|
|
DEBUGASSERT((getreg32(L2CC_ACR) &
|
|
L2CC_ACR_WAYSIZE_MASK) == L2CC_ACR_WAYSIZE_16KB);
|
|
#elif defined(CONFIG_ARMV7R_WAYSIZE_32KB)
|
|
DEBUGASSERT((getreg32(L2CC_ACR) &
|
|
L2CC_ACR_WAYSIZE_MASK) == L2CC_ACR_WAYSIZE_32KB);
|
|
#elif defined(CONFIG_ARMV7R_WAYSIZE_64KB)
|
|
DEBUGASSERT((getreg32(L2CC_ACR) &
|
|
L2CC_ACR_WAYSIZE_MASK) == L2CC_ACR_WAYSIZE_64KB);
|
|
#elif defined(CONFIG_ARMV7R_WAYSIZE_128KB)
|
|
DEBUGASSERT((getreg32(L2CC_ACR) &
|
|
L2CC_ACR_WAYSIZE_MASK) == L2CC_ACR_WAYSIZE_128KB);
|
|
#elif defined(CONFIG_ARMV7R_WAYSIZE_256KB)
|
|
DEBUGASSERT((getreg32(L2CC_ACR) &
|
|
L2CC_ACR_WAYSIZE_MASK) == L2CC_ACR_WAYSIZE_256KB);
|
|
#elif defined(CONFIG_ARMV7R_WAYSIZE_512KB)
|
|
DEBUGASSERT((getreg32(L2CC_ACR) &
|
|
L2CC_ACR_WAYSIZE_MASK) == L2CC_ACR_WAYSIZE_512KB);
|
|
#else
|
|
# error No way size selected
|
|
#endif
|
|
|
|
/* L2 configuration can only be changed if the cache is disabled,
|
|
*
|
|
* NOTE: This register access will fail if we are not in secure more.
|
|
*/
|
|
|
|
if ((getreg32(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);
|
|
putreg32(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);
|
|
putreg32(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;
|
|
putreg32(regval, L2CC_FLEND);
|
|
|
|
regval = (CONFIG_PL310_FLSTRT & L2CC_FLSTRT_MASK) | L2CC_FLSTRT_ENABLE;
|
|
putreg32(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++)
|
|
{
|
|
putreg32(0, L2CC_DLKR(i));
|
|
putreg32(0, L2CC_ILKR(i));
|
|
}
|
|
|
|
/* Configure the cache properties */
|
|
|
|
regval = getreg32(L2CC_ACR);
|
|
regval &= ~L2CC_ACR_CONFIGMASK;
|
|
regval |= L2CC_ACR_CONFIG;
|
|
putreg32(regval, L2CC_ACR);
|
|
|
|
/* Invalidate and enable the cache */
|
|
|
|
l2cc_invalidate_all();
|
|
putreg32(L2CC_CR_L2CEN, L2CC_CR);
|
|
}
|
|
|
|
sinfo("(%d ways) * (%d bytes/way) = %d bytes\n",
|
|
PL310_NWAYS, PL310_WAYSIZE, PL310_CACHE_SIZE);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: l2cc_enable
|
|
*
|
|
* Description:
|
|
* Re-enable the L2CC-P310 L2 cache by setting the enable bit in the
|
|
* Control Register (CR)
|
|
*
|
|
* Input Parameters:
|
|
* None
|
|
*
|
|
* Returned Value:
|
|
* None
|
|
*
|
|
****************************************************************************/
|
|
|
|
void l2cc_enable(void)
|
|
{
|
|
irqstate_t flags;
|
|
|
|
/* Invalidate and enable the cache (must be disabled to do this!) */
|
|
|
|
flags = enter_critical_section();
|
|
l2cc_invalidate_all();
|
|
putreg32(L2CC_CR_L2CEN, L2CC_CR);
|
|
leave_critical_section(flags);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: l2cc_disable
|
|
*
|
|
* Description:
|
|
* Disable the L2CC-P310 L2 cache by clearing the Control Register (CR)
|
|
*
|
|
* Input Parameters:
|
|
* None
|
|
*
|
|
* Returned Value:
|
|
* None
|
|
*
|
|
****************************************************************************/
|
|
|
|
void l2cc_disable(void)
|
|
{
|
|
irqstate_t flags;
|
|
|
|
/* Flush all ways using the Clean Invalidate Way Register (CIWR). */
|
|
|
|
flags = enter_critical_section();
|
|
pl310_flush_all();
|
|
|
|
/* Disable the L2CC-P310 L2 cache by clearing the Control Register (CR) */
|
|
|
|
putreg32(0, L2CC_CR);
|
|
dsb();
|
|
leave_critical_section(flags);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: l2cc_sync
|
|
*
|
|
* Description:
|
|
* Drain the STB. Operation complete when all buffers, LRB, LFB, STB, and
|
|
* EB, are empty.
|
|
*
|
|
* Input Parameters:
|
|
* None
|
|
*
|
|
* Returned Value:
|
|
* None
|
|
*
|
|
****************************************************************************/
|
|
|
|
void l2cc_sync(void)
|
|
{
|
|
irqstate_t flags;
|
|
|
|
/* Drain the STB. Operation complete when all buffers, LRB, LFB, STB, and
|
|
* EB, are empty.
|
|
*/
|
|
|
|
flags = enter_critical_section();
|
|
putreg32(0, L2CC_CSR);
|
|
leave_critical_section(flags);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: l2cc_invalidate_all
|
|
*
|
|
* Description:
|
|
* Invalidate all ways using the Invalidate Way Register (IWR).
|
|
*
|
|
* Input Parameters:
|
|
* None
|
|
*
|
|
* Returned Value:
|
|
* None
|
|
*
|
|
****************************************************************************/
|
|
|
|
void l2cc_invalidate_all(void)
|
|
{
|
|
irqstate_t flags;
|
|
uint32_t regval;
|
|
|
|
/* Invalidate all ways */
|
|
|
|
flags = enter_critical_section();
|
|
|
|
/* Disable the L2 cache while we invalidate it */
|
|
|
|
regval = getreg32(L2CC_CR);
|
|
l2cc_disable();
|
|
|
|
/* Invalidate all ways by writing the bit mask of ways to be invalidated
|
|
* the Invalidate Way Register (IWR).
|
|
*/
|
|
|
|
putreg32(PL310_WAY_MASK, L2CC_IWR);
|
|
|
|
/* Wait for cache operation by way to complete */
|
|
|
|
while ((getreg32(L2CC_IWR) & PL310_WAY_MASK) != 0);
|
|
|
|
/* Drain the STB. Operation complete when all buffers, LRB, LFB, STB, and
|
|
* EB, are empty.
|
|
*/
|
|
|
|
putreg32(0, L2CC_CSR);
|
|
|
|
/* Then re-enable the L2 cache if it was enabled before */
|
|
|
|
putreg32(regval, L2CC_CR);
|
|
leave_critical_section(flags);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: l2cc_invalidate
|
|
*
|
|
* Description:
|
|
* Invalidate a range of addresses by writing to the Invalidate Physical
|
|
* Address Line Register (IPALR) repeatedly.
|
|
*
|
|
* Input Parameters:
|
|
* startaddr - The first address to be invalidated
|
|
* endaddr - The last address to be invalidated
|
|
*
|
|
* Returned Value:
|
|
* None
|
|
*
|
|
****************************************************************************/
|
|
|
|
void l2cc_invalidate(uintptr_t startaddr, uintptr_t endaddr)
|
|
{
|
|
uintptr_t invalsize;
|
|
uintptr_t gulpend;
|
|
irqstate_t flags;
|
|
|
|
/* Check if the start address is aligned with a cacheline */
|
|
|
|
flags = enter_critical_section();
|
|
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;
|
|
putreg32(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;
|
|
putreg32(endaddr, L2CC_CIPALR);
|
|
}
|
|
|
|
leave_critical_section(flags);
|
|
|
|
/* 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 */
|
|
|
|
flags = enter_critical_section();
|
|
while (startaddr < gulpend)
|
|
{
|
|
/* Invalidate the cache line by writing the address to the
|
|
* Invalidate Physical Address Line Register (IPALR).
|
|
*/
|
|
|
|
putreg32(startaddr, L2CC_IPALR);
|
|
|
|
/* Start of the next cache line */
|
|
|
|
startaddr += PL310_CACHE_LINE_SIZE;
|
|
}
|
|
|
|
/* Enable interrupts momentarily */
|
|
|
|
leave_critical_section(flags);
|
|
}
|
|
|
|
/* Drain the STB. Operation complete when all buffers, LRB, LFB, STB, and
|
|
* EB, are empty.
|
|
*/
|
|
|
|
flags = enter_critical_section();
|
|
putreg32(0, L2CC_CSR);
|
|
leave_critical_section(flags);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: l2cc_clean_all
|
|
*
|
|
* Description:
|
|
* Clean all ways by using the Clean Ways Register (CWR).
|
|
*
|
|
* Input Parameters:
|
|
* None
|
|
*
|
|
* Returned Value:
|
|
* None
|
|
*
|
|
****************************************************************************/
|
|
|
|
void l2cc_clean_all(void)
|
|
{
|
|
irqstate_t flags;
|
|
|
|
/* Clean all ways by writing the set of ways to be cleaned to the Clean
|
|
* Ways Register (CWR).
|
|
*/
|
|
|
|
flags = enter_critical_section();
|
|
putreg32(PL310_WAY_MASK, L2CC_CWR);
|
|
|
|
/* Wait for cache operation by way to complete */
|
|
|
|
while ((getreg32(L2CC_CWR) & PL310_WAY_MASK) != 0);
|
|
|
|
/* Drain the STB. Operation complete when all buffers, LRB, LFB, STB, and
|
|
* EB, are empty.
|
|
*/
|
|
|
|
putreg32(0, L2CC_CSR);
|
|
leave_critical_section(flags);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: l2cc_clean
|
|
*
|
|
* Description:
|
|
* Clean the cache line over a range of addresses uing the Clean Physical
|
|
* Address Line Register (CPALR) repeatedly.
|
|
*
|
|
* Input Parameters:
|
|
* startaddr - The first address to be cleaned
|
|
* endaddr - The last address to be cleaned
|
|
*
|
|
* Returned Value:
|
|
* None
|
|
*
|
|
****************************************************************************/
|
|
|
|
void l2cc_clean(uintptr_t startaddr, uintptr_t endaddr)
|
|
{
|
|
uintptr_t cleansize;
|
|
uintptr_t gulpend;
|
|
irqstate_t flags;
|
|
|
|
/* 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)
|
|
{
|
|
l2cc_clean_all();
|
|
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 */
|
|
|
|
flags = enter_critical_section();
|
|
while (startaddr < gulpend)
|
|
{
|
|
/* Clean the cache line by writing the address to the Clean
|
|
* Physical Address Line Register (CPALR).
|
|
*/
|
|
|
|
putreg32(startaddr, L2CC_CPALR);
|
|
|
|
/* Start of the next cache line */
|
|
|
|
startaddr += PL310_CACHE_LINE_SIZE;
|
|
}
|
|
|
|
/* Enable interrupts momentarily */
|
|
|
|
leave_critical_section(flags);
|
|
}
|
|
|
|
/* Drain the STB. Operation complete when all buffers, LRB, LFB, STB, and
|
|
* EB, are empty.
|
|
*/
|
|
|
|
flags = enter_critical_section();
|
|
putreg32(0, L2CC_CSR);
|
|
leave_critical_section(flags);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: l2cc_flush_all
|
|
*
|
|
* Description:
|
|
* Flush all ways using the Clean Invalidate Way Register (CIWR).
|
|
*
|
|
* Input Parameters:
|
|
* None
|
|
*
|
|
* Returned Value:
|
|
* None
|
|
*
|
|
****************************************************************************/
|
|
|
|
void l2cc_flush_all(void)
|
|
{
|
|
irqstate_t flags;
|
|
|
|
/* Flush all ways using the Clean Invalidate Way Register (CIWR). */
|
|
|
|
flags = enter_critical_section();
|
|
pl310_flush_all();
|
|
leave_critical_section(flags);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: l2cc_flush
|
|
*
|
|
* Description:
|
|
* Flush a range of address by using the Clean Invalidate Physical Address
|
|
* Line Register (CIPALR) repeatedly.
|
|
*
|
|
* Input Parameters:
|
|
* startaddr - The first address to be flushed
|
|
* endaddr - The last address to be flushed
|
|
*
|
|
* Returned Value:
|
|
* None
|
|
*
|
|
****************************************************************************/
|
|
|
|
void l2cc_flush(uint32_t startaddr, uint32_t endaddr)
|
|
{
|
|
uintptr_t flushsize;
|
|
uintptr_t gulpend;
|
|
irqstate_t flags;
|
|
|
|
/* 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)
|
|
{
|
|
l2cc_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 */
|
|
|
|
flags = enter_critical_section();
|
|
while (startaddr < gulpend)
|
|
{
|
|
/* Flush the cache line by writing the address to the Clean
|
|
* Invalidate Physical Address Line Register (CIPALR).
|
|
*/
|
|
|
|
putreg32(startaddr, L2CC_CIPALR);
|
|
|
|
/* Start of the next cache line */
|
|
|
|
startaddr += PL310_CACHE_LINE_SIZE;
|
|
}
|
|
|
|
/* Enable interrupts momentarily */
|
|
|
|
leave_critical_section(flags);
|
|
}
|
|
|
|
/* Drain the STB. Operation complete when all buffers, LRB, LFB, STB, and
|
|
* EB, are empty.
|
|
*/
|
|
|
|
flags = enter_critical_section();
|
|
putreg32(0, L2CC_CSR);
|
|
leave_critical_section(flags);
|
|
}
|
|
|
|
#endif /* CONFIG_ARMV7R_L2CC_PL310 */
|