/**************************************************************************** * arch/arm/src/armv7-a/arm_l2cc_pl310.c * * SPDX-License-Identifier: Apache-2.0 * * 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 #include #include #include #include #include #include #include #include "arm_internal.h" #include "l2cc.h" #include "l2cc_pl310.h" #ifdef CONFIG_ARMV7A_L2CC_PL310 /**************************************************************************** * 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 /**************************************************************************** * Private Data ****************************************************************************/ static spinlock_t g_l2cc_lock = SP_UNLOCKED; /**************************************************************************** * 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); } /**************************************************************************** * Name: l2cc_disable_nolock * * Description: * Disable the L2CC-P310 L2 cache by clearing the Control Register (CR) * * Input Parameters: * None * * Returned Value: * None * ****************************************************************************/ static void l2cc_disable_nolock(void) { /* Flush all ways using the Clean Invalidate Way Register (CIWR). */ pl310_flush_all(); /* Disable the L2CC-P310 L2 cache by clearing the Control Register (CR) */ putreg32(0, L2CC_CR); UP_MB(); } /**************************************************************************** * Name: l2cc_invalidate_all_nolock * * Description: * Invalidate all ways using the Invalidate Way Register (IWR). * * Input Parameters: * None * * Returned Value: * None * ****************************************************************************/ static void l2cc_invalidate_all_nolock(void) { /* 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); } /**************************************************************************** * 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_ARMV7A_ASSOCIATIVITY_8WAY) DEBUGASSERT((getreg32(L2CC_ACR) & L2CC_ACR_ASS) == 0); #elif defined(CONFIG_ARMV7A_ASSOCIATIVITY_16WAY) DEBUGASSERT((getreg32(L2CC_ACR) & L2CC_ACR_ASS) == L2CC_ACR_ASS); #else # error No associativity selected #endif #if defined(CONFIG_ARMV7A_WAYSIZE_16KB) DEBUGASSERT((getreg32(L2CC_ACR) & L2CC_ACR_WAYSIZE_MASK) == L2CC_ACR_WAYSIZE_16KB); #elif defined(CONFIG_ARMV7A_WAYSIZE_32KB) DEBUGASSERT((getreg32(L2CC_ACR) & L2CC_ACR_WAYSIZE_MASK) == L2CC_ACR_WAYSIZE_32KB); #elif defined(CONFIG_ARMV7A_WAYSIZE_64KB) DEBUGASSERT((getreg32(L2CC_ACR) & L2CC_ACR_WAYSIZE_MASK) == L2CC_ACR_WAYSIZE_64KB); #elif defined(CONFIG_ARMV7A_WAYSIZE_128KB) DEBUGASSERT((getreg32(L2CC_ACR) & L2CC_ACR_WAYSIZE_MASK) == L2CC_ACR_WAYSIZE_128KB); #elif defined(CONFIG_ARMV7A_WAYSIZE_256KB) DEBUGASSERT((getreg32(L2CC_ACR) & L2CC_ACR_WAYSIZE_MASK) == L2CC_ACR_WAYSIZE_256KB); #elif defined(CONFIG_ARMV7A_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); UP_MB(); } sinfo("(%d ways) * (%d bytes/way) = %d bytes\n", PL310_NWAYS, PL310_WAYSIZE, PL310_CACHE_SIZE); } /**************************************************************************** * Name: l2cc_linesize * * Description: * Get L2CC-P310 L2 cache linesize * * Input Parameters: * None * * Returned Value: * L2 cache linesize * ****************************************************************************/ uint32_t l2cc_linesize(void) { return PL310_CACHE_LINE_SIZE; } /**************************************************************************** * Name: l2cc_size * * Description: * Get L2CC-P310 L2 cache size * * Input Parameters: * None * * Returned Value: * L2 cache size * ****************************************************************************/ uint32_t l2cc_size(void) { return 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 = spin_lock_irqsave(&g_l2cc_lock); if ((getreg32(L2CC_CR) & L2CC_CR_L2CEN) != 0) { l2cc_disable_nolock(); } l2cc_invalidate_all_nolock(); putreg32(L2CC_CR_L2CEN, L2CC_CR); UP_MB(); spin_unlock_irqrestore(&g_l2cc_lock, 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; flags = spin_lock_irqsave(&g_l2cc_lock); l2cc_disable_nolock(); spin_unlock_irqrestore(&g_l2cc_lock, 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 = spin_lock_irqsave(&g_l2cc_lock); putreg32(0, L2CC_CSR); spin_unlock_irqrestore(&g_l2cc_lock, 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; flags = spin_lock_irqsave(&g_l2cc_lock); l2cc_invalidate_all_nolock(); spin_unlock_irqrestore(&g_l2cc_lock, 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 = spin_lock_irqsave(&g_l2cc_lock); 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); } spin_unlock_irqrestore(&g_l2cc_lock, 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 = spin_lock_irqsave(&g_l2cc_lock); 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 */ spin_unlock_irqrestore(&g_l2cc_lock, flags); } /* Drain the STB. Operation complete when all buffers, LRB, LFB, STB, and * EB, are empty. */ flags = spin_lock_irqsave(&g_l2cc_lock); putreg32(0, L2CC_CSR); spin_unlock_irqrestore(&g_l2cc_lock, 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 = spin_lock_irqsave(&g_l2cc_lock); 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); spin_unlock_irqrestore(&g_l2cc_lock, 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 = spin_lock_irqsave(&g_l2cc_lock); 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 */ spin_unlock_irqrestore(&g_l2cc_lock, flags); } /* Drain the STB. Operation complete when all buffers, LRB, LFB, STB, and * EB, are empty. */ flags = spin_lock_irqsave(&g_l2cc_lock); putreg32(0, L2CC_CSR); spin_unlock_irqrestore(&g_l2cc_lock, 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 = spin_lock_irqsave(&g_l2cc_lock); pl310_flush_all(); spin_unlock_irqrestore(&g_l2cc_lock, 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 = spin_lock_irqsave(&g_l2cc_lock); 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 */ spin_unlock_irqrestore(&g_l2cc_lock, flags); } /* Drain the STB. Operation complete when all buffers, LRB, LFB, STB, and * EB, are empty. */ flags = spin_lock_irqsave(&g_l2cc_lock); putreg32(0, L2CC_CSR); spin_unlock_irqrestore(&g_l2cc_lock, flags); } #endif /* CONFIG_ARMV7A_L2CC_PL310 */