/****************************************************************************** * Copyright (c) 2014 - 2021 Xilinx, Inc. All rights reserved. * SPDX-License-Identifier: MIT ******************************************************************************/ /*****************************************************************************/ /** * * @file xil_cache.c * * Contains required functions for the ARM cache functionality. * *
* MODIFICATION HISTORY: * * Ver Who Date Changes * ----- ---- -------- ----------------------------------------------- * 5.0 pkp 05/29/14 First release * 5.5 pkp 04/15/16 Updated the Xil_DCacheInvalidate, * Xil_DCacheInvalidateLine and Xil_DCacheInvalidateRange * functions description for proper explanation * 6.2 pkp 01/22/17 Added support for EL1 non-secure * 6.2 asa 01/31/17 The existing Xil_DCacheDisable API first flushes the * D caches and then disables it. The problem with that is, * potentially there will be a small window after the cache * flush operation and before the we disable D caches where * we might have valid data in cache lines. In such a * scenario disabling the D cache can lead to unknown behavior. * The ideal solution to this is to use assembly code for * the complete API and avoid any memory accesses. But with * that we will end up having a huge amount on assembly code * which is not maintainable. Changes are done to use a mix * of assembly and C code. All local variables are put in * registers. Also function calls are avoided in the API to * avoid using stack memory. * These changes fix CR#966220. * 6.2 mus 02/13/17 The new api Xil_ConfigureL1Prefetch is added to disable pre-fetching/configure * the maximum number of outstanding data prefetches allowed in * L1 cache system.It fixes CR#967864. * 6.6 mus 02/27/18 Updated Xil_DCacheInvalidateRange and * Xil_ICacheInvalidateRange APIs to change the data type of * "cacheline" variable as "INTPTR", This change has been done * to avoid the truncation of upper DDR addresses to 32 bit.It * fixes CR#995581. * 6.6 mus 03/15/18 By default CPUACTLR_EL1 is accessible only from EL3, it * results into abort if accessed from EL1 non secure privilege * level. Updated Xil_ConfigureL1Prefetch function to access * CPUACTLR_EL1 only for EL3. * 6.8 mn 08/01/18 Optimize the Xil_DCacheInvalidateRange() function to remove * redundant operations * 6.8 asa 09/15/18 Fix bug in the Xil_DCacheInvalidateRange API introduced while * making optimizations in the previous patch. This change fixes * CR-1008926. * 7.0 mus 10/12/18 Updated Xil_DCacheInvalidateLine and Xil_DCacheInvalidateRange * APIs to replace IVAC instruction with CIVAC. So that, these * APIs will always do flush + invalidate in case of Cortexa53 as * well as Cortexa72 processor. * 7.1 mus 09/17/19 Xil_DCacheFlushRange and Xil_DCacheInvalidateRange are executing * same functionality (clean + validate). Removed * Xil_DCacheFlushRange function implementation and defined it as * macro. Xil_DCacheFlushRange macro points to the * Xil_DCacheInvalidateRange API to avoid code duplication. * ** ******************************************************************************/ /***************************** Include Files *********************************/ #include "xil_cache.h" #include "xil_io.h" #include "xpseudo_asm.h" #include "xparameters.h" #include "xreg_cortexa53.h" #include "xil_exception.h" #include "bspconfig.h" /************************** Function Prototypes ******************************/ /************************** Variable Definitions *****************************/ #define IRQ_FIQ_MASK 0xC0U /* Mask IRQ and FIQ interrupts in cpsr */ /****************************************************************************/ /** * @brief Enable the Data cache. * * @return None. * ****************************************************************************/ void Xil_DCacheEnable(void) { u32 CtrlReg; if (EL3 == 1) { CtrlReg = mfcp(SCTLR_EL3); } else if (EL1_NONSECURE == 1) { CtrlReg = mfcp(SCTLR_EL1); } else { CtrlReg = 0U; } /* enable caches only if they are disabled */ if((CtrlReg & XREG_CONTROL_DCACHE_BIT) == 0X00000000U){ /* invalidate the Data cache */ Xil_DCacheInvalidate(); CtrlReg |= XREG_CONTROL_DCACHE_BIT; if (EL3 == 1) { /* enable the Data cache for el3*/ mtcp(SCTLR_EL3,CtrlReg); } else if (EL1_NONSECURE == 1) { /* enable the Data cache for el1*/ mtcp(SCTLR_EL1,CtrlReg); } } } /****************************************************************************/ /** * @brief Disable the Data cache. * * @return None. * ****************************************************************************/ void Xil_DCacheDisable(void) { register u32 CsidReg; register u32 C7Reg; register u32 LineSize; register u32 NumWays; register u32 Way; register u32 WayIndex; register u32 WayAdjust; register u32 Set; register u32 SetIndex; register u32 NumSet; register u32 CacheLevel; dsb(); asm( "mov x0, #0\n\t" #if EL3==1 "mrs x0, sctlr_el3 \n\t" "and w0, w0, #0xfffffffb\n\t" "msr sctlr_el3, x0\n\t" #elif EL1_NONSECURE==1 "mrs x0, sctlr_el1 \n\t" "and w0, w0, #0xfffffffb\n\t" "msr sctlr_el1, x0\n\t" #endif "dsb sy\n\t" ); /* Number of level of cache*/ CacheLevel = 0U; /* Select cache level 0 and D cache in CSSR */ mtcp(CSSELR_EL1,CacheLevel); isb(); CsidReg = mfcp(CCSIDR_EL1); /* Get the cacheline size, way size, index size from csidr */ LineSize = (CsidReg & 0x00000007U) + 0x00000004U; /* Number of Ways */ NumWays = (CsidReg & 0x00001FFFU) >> 3U; NumWays += 0x00000001U; /*Number of Set*/ NumSet = (CsidReg >> 13U) & 0x00007FFFU; NumSet += 0x00000001U; WayAdjust = clz(NumWays) - (u32)0x0000001FU; Way = 0U; Set = 0U; /* Flush all the cachelines */ for (WayIndex = 0U; WayIndex < NumWays; WayIndex++) { for (SetIndex = 0U; SetIndex < NumSet; SetIndex++) { C7Reg = Way | Set | CacheLevel; mtcpdc(CISW,C7Reg); Set += (0x00000001U << LineSize); } Set = 0U; Way += (0x00000001U << WayAdjust); } /* Wait for Flush to complete */ dsb(); /* Select cache level 1 and D cache in CSSR */ CacheLevel += (0x00000001U << 1U); mtcp(CSSELR_EL1,CacheLevel); isb(); CsidReg = mfcp(CCSIDR_EL1); /* Get the cacheline size, way size, index size from csidr */ LineSize = (CsidReg & 0x00000007U) + 0x00000004U; /* Number of Ways */ NumWays = (CsidReg & 0x00001FFFU) >> 3U; NumWays += 0x00000001U; /* Number of Sets */ NumSet = (CsidReg >> 13U) & 0x00007FFFU; NumSet += 0x00000001U; WayAdjust=clz(NumWays) - (u32)0x0000001FU; Way = 0U; Set = 0U; /* Flush all the cachelines */ for (WayIndex =0U; WayIndex < NumWays; WayIndex++) { for (SetIndex =0U; SetIndex < NumSet; SetIndex++) { C7Reg = Way | Set | CacheLevel; mtcpdc(CISW,C7Reg); Set += (0x00000001U << LineSize); } Set=0U; Way += (0x00000001U<