zoukankan      html  css  js  c++  java
  • ARM Cache Invalidate Flush

    https://github.com/FreeRTOS/FreeRTOS/blob/9c0c37ab9b56f2c90085b78df2f58b5833e473db/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo_bsp/ps7_cortexa9_0/libsrc/standalone_v6_6/src/xil_cache.c

    /******************************************************************************
    *
    * Copyright (C) 2010 - 2015 Xilinx, Inc.  All rights reserved.
    *
    * Permission is hereby granted, free of charge, to any person obtaining a copy
    * of this software and associated documentation files (the "Software"), to deal
    * in the Software without restriction, including without limitation the rights
    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    * copies of the Software, and to permit persons to whom the Software is
    * furnished to do so, subject to the following conditions:
    *
    * The above copyright notice and this permission notice shall be included in
    * all copies or substantial portions of the Software.
    *
    * Use of the Software is limited solely to applications:
    * (a) running on a Xilinx device, or
    * (b) that interact with a Xilinx device through a bus or interconnect.
    *
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
    * XILINX  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
    * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
    * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    * SOFTWARE.
    *
    * Except as contained in this notice, the name of the Xilinx shall not be used
    * in advertising or otherwise to promote the sale, use or other dealings in
    * this Software without prior written authorization from Xilinx.
    *
    ******************************************************************************/
    /*****************************************************************************/
    /**
    *
    * @file xil_cache.c
    *
    * Contains required functions for the ARM cache functionality.
    *
    * <pre>
    * MODIFICATION HISTORY:
    *
    * Ver    Who Date     Changes
    * ----- ---- -------- -----------------------------------------------
    * 1.00a  ecm 01/29/10 First release
    * 1.00a  ecm 06/24/10 Moved the L1 and L2 specific function prototypes
    *                        to xil_cache_mach.h to give access to sophisticated users
    * 3.02a  sdm 04/07/11 Updated Flush/InvalidateRange APIs to flush/invalidate
    *                        L1 and L2 caches in a single loop and used dsb, L2 sync
    *                        at the end of the loop.
    * 3.04a  sdm 01/02/12 Remove redundant dsb/dmb instructions in cache maintenance
    *                        APIs.
    * 3.07a  asa 07/16/12 Corrected the L1 and L2 cache invalidation order.
    * 3.07a  sgd 09/18/12 Corrected the L2 cache enable and disable sequence.
    * 3.10a  srt 04/18/13 Implemented ARM Erratas. Please refer to file
    *                        'xil_errata.h' for errata description
    * 3.10a  asa 05/13/13 Modified cache disable APIs. The L2 cache disable
    *                        operation was being done with L1 Data cache disabled. This is
    *                        fixed so that L2 cache disable operation happens independent of
    *                        L1 cache disable operation. This fixes CR #706464.
    *                        Changes are done to do a L2 cache sync (poll reg7_?cache_?sync).
    *                        This is done to fix the CR #700542.
    * 3.11a  asa 09/23/13 Modified the Xil_DCacheFlushRange and
    *                       Xil_DCacheInvalidateRange to fix potential issues. Fixed other
    *                       relevant cache APIs to disable and enable back the interrupts.
    *                       This fixes CR #663885.
    * 3.11a  asa 09/28/13 Made changes for L2 cache sync operation. It is found
    *                       out that for L2 cache flush/clean/invalidation by cache lines
    *                       does not need a cache sync as these are atomic nature. Similarly
    *                       figured out that for complete L2 cache flush/invalidation by way
    *                       we need to wait for some more time in a loop till the status
    *                       shows that the cache operation is completed.
    * 4.00     pkp 24/01/14 Modified Xil_DCacheInvalidateRange to fix the bug. Few
    *                       cache lines were missed to invalidate when unaligned address
    *                       invalidation was accommodated. That fixes CR #766768.
    *                       Also in Xil_L1DCacheInvalidate, while invalidating all L1D cache
    *                       stack memory which contains return address was invalidated. So
    *                       stack memory was flushed first and then L1D cache is invalidated.
    *                       This is done to fix CR #763829
    * 4.01   asa 05/09/14 Made changes in cortexa9/xil_cache.c to fix CR# 798230.
    * 4.02     pkp 06/27/14 Added notes to Xil_L1DCacheInvalidateRange function for
    *                      explanation of CR#785243
    * 5.00   kvn 12/15/14 Xil_L2CacheInvalidate was modified to fix CR# 838835. L2 Cache
    *                      has stack memory which has return address. Before invalidating
    *                      cache, stack memory was flushed first and L2 Cache is invalidated.
    * 5.01     pkp 05/12/15 Xil_DCacheInvalidateRange and Xil_DCacheFlushRange is modified
    *                      to remove unnecessary dsb in the APIs. Instead of using dsb
    *                      for L2 Cache, L2CacheSync has been used for each L2 cache line
    *                      and single dsb has been used for L1 cache. Also L2CacheSync is
    *                      added into Xil_L2CacheInvalidateRange API. Xil_L1DCacheInvalidate
    *                      and Xil_L2CacheInvalidate APIs are modified to flush the complete
    *                      stack instead of just System Stack
    * 5.03     pkp 10/07/15 L2 Cache functionalities are avoided for the OpenAMP slave
    *                      application(when USE_AMP flag is defined for BSP) as master CPU
    *                      would be utilizing L2 cache for its operation
    * 6.6    mus 12/07/17 Errata 753970 is not applicable for the PL130 cache controller
    *                     version r0p2, which is present in zynq. So,removed the handling
    *                     related to same.It fixes CR#989132.
    * 6.6    asa 16/01/18 Changes made in Xil_L1DCacheInvalidate and Xil_L2CacheInvalidate
    *                      routines to ensure the stack data flushed only when the respective
    *                      caches are enabled. This fixes CR-992023.
    *
    * </pre>
    *
    ******************************************************************************/
    
    /***************************** Include Files *********************************/
    
    #include "xil_cache.h"
    #include "xil_cache_l.h"
    #include "xil_io.h"
    #include "xpseudo_asm.h"
    #include "xparameters.h"
    #include "xreg_cortexa9.h"
    #include "xl2cc.h"
    #include "xil_errata.h"
    #include "xil_exception.h"
    
    /************************** Function Prototypes ******************************/
    
    /************************** Variable Definitions *****************************/
    
    #define IRQ_FIQ_MASK 0xC0U    /* Mask IRQ and FIQ interrupts in cpsr */
    
    #ifdef __GNUC__
        extern s32  _stack_end;
        extern s32  __undef_stack;
    #endif
    
    #ifndef USE_AMP
    /****************************************************************************
    *
    * Access L2 Debug Control Register.
    *
    * @param    Value, value to be written to Debug Control Register.
    *
    * @return    None.
    *
    * @note        None.
    *
    ****************************************************************************/
    #ifdef __GNUC__
    static inline void Xil_L2WriteDebugCtrl(u32 Value)
    #else
    static void Xil_L2WriteDebugCtrl(u32 Value)
    #endif
    {
    #if defined(CONFIG_PL310_ERRATA_588369) || defined(CONFIG_PL310_ERRATA_727915)
        Xil_Out32(XPS_L2CC_BASEADDR + XPS_L2CC_DEBUG_CTRL_OFFSET, Value);
    #else
        (void)(Value);
    #endif
    }
    
    /****************************************************************************
    *
    * Perform L2 Cache Sync Operation.
    *
    * @param    None.
    *
    * @return    None.
    *
    * @note        None.
    *
    ****************************************************************************/
    #ifdef __GNUC__
    static inline void Xil_L2CacheSync(void)
    #else
    static void Xil_L2CacheSync(void)
    #endif
    {
        Xil_Out32(XPS_L2CC_BASEADDR + XPS_L2CC_CACHE_SYNC_OFFSET, 0x0U);
    }
    #endif
    /****************************************************************************/
    /**
    * @brief    Enable the Data cache.
    *
    * @param    None.
    *
    * @return    None.
    *
    * @note        None.
    *
    ****************************************************************************/
    void Xil_DCacheEnable(void)
    {
        Xil_L1DCacheEnable();
    #ifndef USE_AMP
        Xil_L2CacheEnable();
    #endif
    }
    
    /****************************************************************************/
    /**
    * @brief    Disable the Data cache.
    *
    * @param    None.
    *
    * @return    None.
    *
    * @note        None.
    *
    ****************************************************************************/
    void Xil_DCacheDisable(void)
    {
    #ifndef USE_AMP
        Xil_L2CacheDisable();
    #endif
        Xil_L1DCacheDisable();
    }
    
    /****************************************************************************/
    /**
    * @brief    Invalidate the entire Data cache.
    *
    * @param    None.
    *
    * @return    None.
    *
    * @note        None.
    *
    ****************************************************************************/
    void Xil_DCacheInvalidate(void)
    {
        u32 currmask;
    
        currmask = mfcpsr();
        mtcpsr(currmask | IRQ_FIQ_MASK);
    #ifndef USE_AMP
        Xil_L2CacheInvalidate();
    #endif
        Xil_L1DCacheInvalidate();
    
        mtcpsr(currmask);
    }
    
    /*****************************************************************************/
    /**
    * @brief    Invalidate a Data cache line. If the byte specified by the address
    *             (adr) is cached by the Data cache, the cacheline containing that
    *             byte is invalidated. If the cacheline is modified (dirty), the
    *             modified contents are lost and are NOT written to the system memory
    *             before the line is invalidated.
    *
    * @param    adr: 32bit address of the data to be flushed.
    *
    * @return    None.
    *
    * @note        The bottom 4 bits are set to 0, forced by architecture.
    *
    ****************************************************************************/
    void Xil_DCacheInvalidateLine(u32 adr)
    {
        u32 currmask;
    
        currmask = mfcpsr();
        mtcpsr(currmask | IRQ_FIQ_MASK);
    #ifndef USE_AMP
        Xil_L2CacheInvalidateLine(adr);
    #endif
        Xil_L1DCacheInvalidateLine(adr);
    
        mtcpsr(currmask);
    }
    
    
    /*****************************************************************************/
    /**
    * @brief    Invalidate the Data cache for the given address range.
    *             If the bytes specified by the address range are cached by the Data
    *            cache, the cachelines containing those bytes are invalidated. If
    *            the cachelines are modified (dirty), the modified contents are lost
    *            and NOT written to the system memory before the lines are
    *            invalidated.
    *
    *             In this function, if start address or end address is not aligned to
    *             cache-line, particular cache-line containing unaligned start or end
    *             address is flush first and then invalidated the others as
    *             invalidating the same unaligned cache line may result into loss of
    *            data. This issue raises few possibilities.
    *
    *             If the address to be invalidated is not cache-line aligned, the
    *             following choices are available:
    *             1. Invalidate the cache line when required and do not bother much
    *             for the side effects. Though it sounds good, it can result in
    *             hard-to-debug issues. The problem is, if some other variable are
    *             allocated in the same cache line and had been recently updated
    *             (in cache), the invalidation would result in loss of data.
    *             2. Flush the cache line first. This will ensure that if any other
    *             variable present in the same cache line and updated recently are
    *             flushed out to memory. Then it can safely be invalidated. Again it
    *             sounds good, but this can result in issues. For example, when the
    *             invalidation happens in a typical ISR (after a DMA transfer has
    *             updated the memory), then flushing the cache line means, loosing
    *             data that were updated recently before the ISR got invoked.
    *
    *             Linux prefers the second one. To have uniform implementation
    *             (across standalone and Linux), the second option is implemented.
    *             This being the case, follwoing needs to be taken care of:
    *             1. Whenever possible, the addresses must be cache line aligned.
    *             Please nore that, not just start address, even the end address must
    *             be cache line aligned. If that is taken care of, this will always
    *            work.
    *             2. Avoid situations where invalidation has to be done after the
    *             data is updated by peripheral/DMA directly into the memory. It is
    *             not tough to achieve (may be a bit risky). The common use case to
    *             do invalidation is when a DMA happens. Generally for such use
    *            cases, buffers can be allocated first and then start the DMA. The
    *             practice that needs to be followed here is, immediately after
    *             buffer allocation and before starting the DMA, do the invalidation.
    *             With this approach, invalidation need not to be done after the DMA
    *            transfer is over.
    *
    *             This is going to always work if done carefully.
    *             However, the concern is, there is no guarantee that invalidate has
    *             not needed to be done after DMA is complete. For example, because
    *             of some reasons if the first cache line or last cache line
    *             (assuming the buffer in question comprises of multiple cache lines)
    *            are brought into cache (between the time it is invalidated and DMA
    *             completes) because of some speculative prefetching or reading data
    *             for a variable present in the same cache line, then we will have to
    *            invalidate the cache after DMA is complete.
    *
    *
    * @param    adr: 32bit start address of the range to be invalidated.
    * @param    len: Length of the range to be invalidated in bytes.
    *
    * @return    None.
    *
    * @note        None.
    *
    ****************************************************************************/
    void Xil_DCacheInvalidateRange(INTPTR adr, u32 len)
    {
        const u32 cacheline = 32U;
        u32 end;
        u32 tempadr = adr;
        u32 tempend;
        u32 currmask;
        volatile u32 *L2CCOffset = (volatile u32 *)(XPS_L2CC_BASEADDR +
                        XPS_L2CC_CACHE_INVLD_PA_OFFSET);
    
        currmask = mfcpsr();
        mtcpsr(currmask | IRQ_FIQ_MASK);
    
        if (len != 0U) {
            end = tempadr + len;
            tempend = end;
            /* Select L1 Data cache in CSSR */
            mtcp(XREG_CP15_CACHE_SIZE_SEL, 0U);
    
            if ((tempadr & (cacheline-1U)) != 0U) {
                tempadr &= (~(cacheline - 1U));
    
                Xil_L1DCacheFlushLine(tempadr);
    #ifndef USE_AMP
                /* Disable Write-back and line fills */
                Xil_L2WriteDebugCtrl(0x3U);
                Xil_L2CacheFlushLine(tempadr);
                /* Enable Write-back and line fills */
                Xil_L2WriteDebugCtrl(0x0U);
                Xil_L2CacheSync();
    #endif
                tempadr += cacheline;
            }
            if ((tempend & (cacheline-1U)) != 0U) {
                tempend &= (~(cacheline - 1U));
    
                Xil_L1DCacheFlushLine(tempend);
    #ifndef USE_AMP
                /* Disable Write-back and line fills */
                Xil_L2WriteDebugCtrl(0x3U);
                Xil_L2CacheFlushLine(tempend);
                /* Enable Write-back and line fills */
                Xil_L2WriteDebugCtrl(0x0U);
                Xil_L2CacheSync();
    #endif
            }
    
            while (tempadr < tempend) {
    #ifndef USE_AMP
                /* Invalidate L2 cache line */
                *L2CCOffset = tempadr;
                Xil_L2CacheSync();
    #endif
    
        /* Invalidate L1 Data cache line */
    #if defined (__GNUC__) || defined (__ICCARM__)
                asm_cp15_inval_dc_line_mva_poc(tempadr);
    #else
                { volatile register u32 Reg
                    __asm(XREG_CP15_INVAL_DC_LINE_MVA_POC);
                  Reg = tempadr; }
    #endif
                tempadr += cacheline;
            }
        }
    
        dsb();
        mtcpsr(currmask);
    }
    
    /****************************************************************************/
    /**
    * @brief    Flush the entire Data cache.
    *
    * @param    None.
    *
    * @return    None.
    *
    * @note        None.
    *
    ****************************************************************************/
    void Xil_DCacheFlush(void)
    {
        u32 currmask;
    
        currmask = mfcpsr();
        mtcpsr(currmask | IRQ_FIQ_MASK);
        Xil_L1DCacheFlush();
    #ifndef USE_AMP
        Xil_L2CacheFlush();
    #endif
        mtcpsr(currmask);
    }
    
    
    /****************************************************************************/
    /**
    * @brief    Flush a Data cache line. If the byte specified by the address (adr)
    *             is cached by the Data cache, the cacheline containing that byte is
    *             invalidated. If the cacheline is modified (dirty), the entire
    *             contents of the cacheline are written to system memory before the
    *             line is invalidated.
    *
    * @param    adr: 32bit address of the data to be flushed.
    *
    * @return    None.
    *
    * @note        The bottom 4 bits are set to 0, forced by architecture.
    *
    ****************************************************************************/
    void Xil_DCacheFlushLine(u32 adr)
    {
        u32 currmask;
    
        currmask = mfcpsr();
        mtcpsr(currmask | IRQ_FIQ_MASK);
        Xil_L1DCacheFlushLine(adr);
    #ifndef USE_AMP
        /* Disable Write-back and line fills */
        Xil_L2WriteDebugCtrl(0x3U);
    
        Xil_L2CacheFlushLine(adr);
    
        /* Enable Write-back and line fills */
        Xil_L2WriteDebugCtrl(0x0U);
        Xil_L2CacheSync();
    #endif
        mtcpsr(currmask);
    }
    
    /****************************************************************************/
    /**
    * @brief    Flush the Data cache for the given address range.
    *             If the bytes specified by the address range are cached by the
    *             data cache, the cachelines containing those bytes are invalidated.
    *             If the cachelines are modified (dirty), they are written to the
    *             system memory before the lines are invalidated.
    *
    * @param    adr: 32bit start address of the range to be flushed.
    * @param    len: Length of the range to be flushed in bytes.
    *
    * @return    None.
    *
    * @note        None.
    *
    ****************************************************************************/
    void Xil_DCacheFlushRange(INTPTR adr, u32 len)
    {
        u32 LocalAddr = adr;
        const u32 cacheline = 32U;
        u32 end;
        u32 currmask;
        volatile u32 *L2CCOffset = (volatile u32 *)(XPS_L2CC_BASEADDR +
                        XPS_L2CC_CACHE_INV_CLN_PA_OFFSET);
    
        currmask = mfcpsr();
        mtcpsr(currmask | IRQ_FIQ_MASK);
    
        if (len != 0U) {
            /* Back the starting address up to the start of a cache line
             * perform cache operations until adr+len
             */
            end = LocalAddr + len;
            LocalAddr &= ~(cacheline - 1U);
    
            while (LocalAddr < end) {
    
        /* Flush L1 Data cache line */
    #if defined (__GNUC__) || defined (__ICCARM__)
                asm_cp15_clean_inval_dc_line_mva_poc(LocalAddr);
    #else
                { volatile register u32 Reg
                    __asm(XREG_CP15_CLEAN_INVAL_DC_LINE_MVA_POC);
                  Reg = LocalAddr; }
    #endif
    #ifndef USE_AMP
                /* Flush L2 cache line */
                *L2CCOffset = LocalAddr;
                Xil_L2CacheSync();
    #endif
                LocalAddr += cacheline;
            }
        }
        dsb();
        mtcpsr(currmask);
    }
    /****************************************************************************/
    /**
    * @brief    Store a Data cache line. If the byte specified by the address (adr)
    *             is cached by the Data cache and the cacheline is modified (dirty),
    *             the entire contents of the cacheline are written to system memory.
    *             After the store completes, the cacheline is marked as unmodified
    *             (not dirty).
    *
    * @param    adr: 32bit address of the data to be stored.
    *
    * @return    None.
    *
    * @note        The bottom 4 bits are set to 0, forced by architecture.
    *
    ****************************************************************************/
    void Xil_DCacheStoreLine(u32 adr)
    {
        u32 currmask;
    
        currmask = mfcpsr();
        mtcpsr(currmask | IRQ_FIQ_MASK);
    
        Xil_L1DCacheStoreLine(adr);
    #ifndef USE_AMP
        Xil_L2CacheStoreLine(adr);
    #endif
        mtcpsr(currmask);
    }
    
    /***************************************************************************/
    /**
    * @brief    Enable the instruction cache.
    *
    * @param    None.
    *
    * @return    None.
    *
    * @note        None.
    *
    ****************************************************************************/
    void Xil_ICacheEnable(void)
    {
        Xil_L1ICacheEnable();
    #ifndef USE_AMP
        Xil_L2CacheEnable();
    #endif
    }
    
    /***************************************************************************/
    /**
    * @brief    Disable the instruction cache.
    *
    * @param    None.
    *
    * @return    None.
    *
    * @note        None.
    *
    ****************************************************************************/
    void Xil_ICacheDisable(void)
    {
    #ifndef USE_AMP
        Xil_L2CacheDisable();
    #endif
        Xil_L1ICacheDisable();
    }
    
    
    /****************************************************************************/
    /**
    * @brief    Invalidate the entire instruction cache.
    *
    * @param    None.
    *
    * @return    None.
    *
    * @note        None.
    *
    ****************************************************************************/
    void Xil_ICacheInvalidate(void)
    {
        u32 currmask;
    
        currmask = mfcpsr();
        mtcpsr(currmask | IRQ_FIQ_MASK);
    #ifndef USE_AMP
        Xil_L2CacheInvalidate();
    #endif
        Xil_L1ICacheInvalidate();
    
        mtcpsr(currmask);
    }
    
    /****************************************************************************/
    /**
    * @brief    Invalidate an instruction cache line. If the instruction specified
    *            by the address is cached by the instruction cache, the cacheline
    *            containing that instruction is invalidated.
    *
    * @param    adr: 32bit address of the instruction to be invalidated.
    *
    * @return    None.
    *
    * @note        The bottom 4 bits are set to 0, forced by architecture.
    *
    ****************************************************************************/
    void Xil_ICacheInvalidateLine(u32 adr)
    {
        u32 currmask;
    
        currmask = mfcpsr();
        mtcpsr(currmask | IRQ_FIQ_MASK);
    #ifndef USE_AMP
        Xil_L2CacheInvalidateLine(adr);
    #endif
        Xil_L1ICacheInvalidateLine(adr);
        mtcpsr(currmask);
    }
    
    /****************************************************************************/
    /**
    * @brief    Invalidate the instruction cache for the given address range.
    *             If the instructions specified by the address range are cached by
    *             the instrunction cache, the cachelines containing those
    *            instructions are invalidated.
    *
    * @param    adr: 32bit start address of the range to be invalidated.
    * @param    len: Length of the range to be invalidated in bytes.
    *
    * @return    None.
    *
    * @note        None.
    *
    ****************************************************************************/
    void Xil_ICacheInvalidateRange(INTPTR adr, u32 len)
    {
        u32 LocalAddr = adr;
        const u32 cacheline = 32U;
        u32 end;
        volatile u32 *L2CCOffset = (volatile u32 *)(XPS_L2CC_BASEADDR +
                        XPS_L2CC_CACHE_INVLD_PA_OFFSET);
    
        u32 currmask;
    
        currmask = mfcpsr();
        mtcpsr(currmask | IRQ_FIQ_MASK);
        if (len != 0U) {
            /* Back the starting address up to the start of a cache line
             * perform cache operations until adr+len
             */
            end = LocalAddr + len;
            LocalAddr = LocalAddr & ~(cacheline - 1U);
    
            /* Select cache L0 I-cache in CSSR */
            mtcp(XREG_CP15_CACHE_SIZE_SEL, 1U);
    
            while (LocalAddr < end) {
    #ifndef USE_AMP
            /* Invalidate L2 cache line */
            *L2CCOffset = LocalAddr;
            dsb();
    #endif
    
            /* Invalidate L1 I-cache line */
    #if defined (__GNUC__) || defined (__ICCARM__)
                asm_cp15_inval_ic_line_mva_pou(LocalAddr);
    #else
                { volatile register u32 Reg
                    __asm(XREG_CP15_INVAL_IC_LINE_MVA_POU);
                  Reg = LocalAddr; }
    #endif
    
                LocalAddr += cacheline;
            }
        }
    
        /* Wait for L1 and L2 invalidate to complete */
        dsb();
        mtcpsr(currmask);
    }
    
    /****************************************************************************/
    /**
    * @brief    Enable the level 1 Data cache.
    *
    * @param    None.
    *
    * @return    None.
    *
    * @note        None.
    *
    ****************************************************************************/
    void Xil_L1DCacheEnable(void)
    {
        register u32 CtrlReg;
    
        /* enable caches only if they are disabled */
    #ifdef __GNUC__
        CtrlReg = mfcp(XREG_CP15_SYS_CONTROL);
    #elif defined (__ICCARM__)
        mfcp(XREG_CP15_SYS_CONTROL, CtrlReg);
    #else
        { volatile register u32 Reg __asm(XREG_CP15_SYS_CONTROL);
          CtrlReg = Reg; }
    #endif
        if ((CtrlReg & (XREG_CP15_CONTROL_C_BIT)) != 0U) {
            return;
        }
    
        /* clean and invalidate the Data cache */
        Xil_L1DCacheInvalidate();
    
        /* enable the Data cache */
        CtrlReg |= (XREG_CP15_CONTROL_C_BIT);
    
        mtcp(XREG_CP15_SYS_CONTROL, CtrlReg);
    }
    
    /***************************************************************************/
    /**
    * @brief    Disable the level 1 Data cache.
    *
    * @param    None.
    *
    * @return    None.
    *
    * @note        None.
    *
    ****************************************************************************/
    void Xil_L1DCacheDisable(void)
    {
        register u32 CtrlReg;
    
        /* clean and invalidate the Data cache */
        Xil_L1DCacheFlush();
    
    #ifdef __GNUC__
        /* disable the Data cache */
        CtrlReg = mfcp(XREG_CP15_SYS_CONTROL);
    #elif defined (__ICCARM__)
        mfcp(XREG_CP15_SYS_CONTROL, CtrlReg);
    #else
        { volatile register u32 Reg __asm(XREG_CP15_SYS_CONTROL);
          CtrlReg = Reg; }
    #endif
    
        CtrlReg &= ~(XREG_CP15_CONTROL_C_BIT);
    
        mtcp(XREG_CP15_SYS_CONTROL, CtrlReg);
    }
    
    /****************************************************************************/
    /**
    * @brief    Invalidate the level 1 Data cache.
    *
    * @param    None.
    *
    * @return    None.
    *
    * @note        In Cortex A9, there is no cp instruction for invalidating
    *            the whole D-cache. This function invalidates each line by
    *            set/way.
    *
    ****************************************************************************/
    void Xil_L1DCacheInvalidate(void)
    {
        register u32 CsidReg, C7Reg;
        u32 CacheSize, LineSize, NumWays;
        u32 Way, WayIndex, Set, SetIndex, NumSet;
        u32 currmask;
    
    #ifdef __GNUC__
        u32 stack_start,stack_end,stack_size;
        register u32 CtrlReg;
    #endif
    
        currmask = mfcpsr();
        mtcpsr(currmask | IRQ_FIQ_MASK);
    
    #ifdef __GNUC__
        stack_end = (u32)&_stack_end;
        stack_start = (u32)&__undef_stack;
        stack_size=stack_start-stack_end;
    
        /* Check for the cache status. If cache is enabled, then only
         * flush stack memory to save return address. If cache is disabled,
         * dont flush anything as it might result in flushing stale date into
         * memory which is undesirable.
         * */
        CtrlReg = mfcp(XREG_CP15_SYS_CONTROL);
        if ((CtrlReg & (XREG_CP15_CONTROL_C_BIT)) != 0U) {
            Xil_DCacheFlushRange(stack_end, stack_size);
        }
    #endif
    
        /* Select cache level 0 and D cache in CSSR */
        mtcp(XREG_CP15_CACHE_SIZE_SEL, 0U);
    
    #ifdef __GNUC__
        CsidReg = mfcp(XREG_CP15_CACHE_SIZE_ID);
    #elif defined (__ICCARM__)
        mfcp(XREG_CP15_CACHE_SIZE_ID, CsidReg);
    #else
        { volatile register u32 Reg __asm(XREG_CP15_CACHE_SIZE_ID);
          CsidReg = Reg; }
    #endif
        /* Determine Cache Size */
        CacheSize = (CsidReg >> 13U) & 0x1FFU;
        CacheSize +=1U;
        CacheSize *=128U;    /* to get number of bytes */
    
        /* Number of Ways */
        NumWays = (CsidReg & 0x3ffU) >> 3U;
        NumWays += 1U;
    
        /* Get the cacheline size, way size, index size from csidr */
        LineSize = (CsidReg & 0x07U) + 4U;
    
        NumSet = CacheSize/NumWays;
        NumSet /= (0x00000001U << LineSize);
    
        Way = 0U;
        Set = 0U;
    
        /* Invalidate all the cachelines */
        for (WayIndex =0U; WayIndex < NumWays; WayIndex++) {
            for (SetIndex =0U; SetIndex < NumSet; SetIndex++) {
                C7Reg = Way | Set;
    
            /* Invalidate by Set/Way */
    #if defined (__GNUC__) || defined (__ICCARM__)
                asm_cp15_inval_dc_line_sw(C7Reg);
    #else
                /*mtcp(XREG_CP15_INVAL_DC_LINE_SW, C7Reg), */
                { volatile register u32 Reg
                    __asm(XREG_CP15_INVAL_DC_LINE_SW);
                  Reg = C7Reg; }
    #endif
                Set += (0x00000001U << LineSize);
            }
            Set=0U;
            Way += 0x40000000U;
        }
    
        /* Wait for L1 invalidate to complete */
        dsb();
        mtcpsr(currmask);
    }
    
    /****************************************************************************/
    /**
    * @brief    Invalidate a level 1 Data cache line. If the byte specified by the
    *             address (Addr) is cached by the Data cache, the cacheline
    *             containing that byte is invalidated. If the cacheline is modified
    *             (dirty), the modified contents are lost and are NOT written to
    *            system memory before the line is invalidated.
    *
    * @param    adr: 32bit address of the data to be invalidated.
    *
    * @return    None.
    *
    * @note        The bottom 5 bits are set to 0, forced by architecture.
    *
    ****************************************************************************/
    void Xil_L1DCacheInvalidateLine(u32 adr)
    {
        mtcp(XREG_CP15_CACHE_SIZE_SEL, 0U);
        mtcp(XREG_CP15_INVAL_DC_LINE_MVA_POC, (adr & (~0x1FU)));
    
        /* Wait for L1 invalidate to complete */
        dsb();
    }
    
    /****************************************************************************/
    /**
    * @brief    Invalidate the level 1 Data cache for the given address range.
    *             If the bytes specified by the address range are cached by the Data
    *             cache, the cachelines containing those bytes are invalidated. If the
    *             cachelines are modified (dirty), the modified contents are lost and
    *             NOT written to the system memory before the lines are invalidated.
    *
    * @param    adr: 32bit start address of the range to be invalidated.
    * @param    len: Length of the range to be invalidated in bytes.
    *
    * @return    None.
    *
    * @note        None.
    *
    ****************************************************************************/
    void Xil_L1DCacheInvalidateRange(u32 adr, u32 len)
    {
        u32 LocalAddr = adr;
        const u32 cacheline = 32U;
        u32 end;
        u32 currmask;
    
        currmask = mfcpsr();
        mtcpsr(currmask | IRQ_FIQ_MASK);
    
        if (len != 0U) {
            /* Back the starting address up to the start of a cache line
             * perform cache operations until adr+len
             */
            end = LocalAddr + len;
            LocalAddr = LocalAddr & ~(cacheline - 1U);
    
            /* Select cache L0 D-cache in CSSR */
            mtcp(XREG_CP15_CACHE_SIZE_SEL, 0);
    
            while (LocalAddr < end) {
    
    #if defined (__GNUC__) || defined (__ICCARM__)
                asm_cp15_inval_dc_line_mva_poc(LocalAddr);
    #else
                { volatile register u32 Reg
                    __asm(XREG_CP15_INVAL_DC_LINE_MVA_POC);
                  Reg = LocalAddr; }
    #endif
                LocalAddr += cacheline;
            }
        }
    
        /* Wait for L1 invalidate to complete */
        dsb();
        mtcpsr(currmask);
    }
    
    /****************************************************************************/
    /**
    * @brief    Flush the level 1 Data cache.
    *
    * @param    None.
    *
    * @return    None.
    *
    * @note        In Cortex A9, there is no cp instruction for flushing
    *            the whole D-cache. Need to flush each line.
    *
    ****************************************************************************/
    void Xil_L1DCacheFlush(void)
    {
        register u32 CsidReg, C7Reg;
        u32 CacheSize, LineSize, NumWays;
        u32 Way;
        u32 WayIndex, Set, SetIndex, NumSet;
        u32 currmask;
    
        currmask = mfcpsr();
        mtcpsr(currmask | IRQ_FIQ_MASK);
    
        /* Select cache level 0 and D cache in CSSR */
        mtcp(XREG_CP15_CACHE_SIZE_SEL, 0);
    
    #ifdef __GNUC__
        CsidReg = mfcp(XREG_CP15_CACHE_SIZE_ID);
    #elif defined (__ICCARM__)
        mfcp(XREG_CP15_CACHE_SIZE_ID, CsidReg);
    #else
        { volatile register u32 Reg __asm(XREG_CP15_CACHE_SIZE_ID);
          CsidReg = Reg; }
    #endif
    
        /* Determine Cache Size */
    
        CacheSize = (CsidReg >> 13U) & 0x1FFU;
        CacheSize +=1U;
        CacheSize *=128U;    /* to get number of bytes */
    
        /* Number of Ways */
        NumWays = (CsidReg & 0x3ffU) >> 3U;
        NumWays += 1U;
    
        /* Get the cacheline size, way size, index size from csidr */
        LineSize = (CsidReg & 0x07U) + 4U;
    
        NumSet = CacheSize/NumWays;
        NumSet /= (0x00000001U << LineSize);
    
        Way = 0U;
        Set = 0U;
    
        /* Invalidate all the cachelines */
        for (WayIndex =0U; WayIndex < NumWays; WayIndex++) {
            for (SetIndex =0U; SetIndex < NumSet; SetIndex++) {
                C7Reg = Way | Set;
                /* Flush by Set/Way */
    
    #if defined (__GNUC__) || defined (__ICCARM__)
                asm_cp15_clean_inval_dc_line_sw(C7Reg);
    #else
                { volatile register u32 Reg
                    __asm(XREG_CP15_CLEAN_INVAL_DC_LINE_SW);
                  Reg = C7Reg; }
    #endif
                Set += (0x00000001U << LineSize);
            }
            Set = 0U;
            Way += 0x40000000U;
        }
    
        /* Wait for L1 flush to complete */
        dsb();
        mtcpsr(currmask);
    }
    
    /****************************************************************************/
    /**
    * @brief    Flush a level 1 Data cache line. If the byte specified by the
    *            address (adr) is cached by the Data cache, the cacheline containing
    *            that byte is invalidated. If the cacheline is modified (dirty), the
    *             entire contents of the cacheline are written to system memory
    *            before the line is invalidated.
    *
    * @param    adr: 32bit address of the data to be flushed.
    *
    * @return    None.
    *
    * @note        The bottom 5 bits are set to 0, forced by architecture.
    *
    ****************************************************************************/
    void Xil_L1DCacheFlushLine(u32 adr)
    {
        mtcp(XREG_CP15_CACHE_SIZE_SEL, 0U);
        mtcp(XREG_CP15_CLEAN_INVAL_DC_LINE_MVA_POC, (adr & (~0x1FU)));
    
        /* Wait for L1 flush to complete */
        dsb();
    }
    
    /****************************************************************************/
    /**
    * @brief    Flush the level 1  Data cache for the given address range.
    *             If the bytes specified by the address range are cached by the Data
    *             cache, the cacheline containing those bytes are invalidated. If the
    *             cachelines are modified (dirty), they are written to system memory
    *             before the lines are invalidated.
    *
    * @param    adr: 32bit start address of the range to be flushed.
    * @param    len: Length of the range to be flushed in bytes.
    *
    * @return    None.
    *
    * @note        None.
    *
    ****************************************************************************/
    void Xil_L1DCacheFlushRange(u32 adr, u32 len)
    {
        u32 LocalAddr = adr;
        const u32 cacheline = 32U;
        u32 end;
        u32 currmask;
    
        currmask = mfcpsr();
        mtcpsr(currmask | IRQ_FIQ_MASK);
    
        if (len != 0U) {
            /* Back the starting address up to the start of a cache line
             * perform cache operations until adr+len
             */
            end = LocalAddr + len;
            LocalAddr = LocalAddr & ~(cacheline - 1U);
    
            /* Select cache L0 D-cache in CSSR */
            mtcp(XREG_CP15_CACHE_SIZE_SEL, 0U);
    
            while (LocalAddr < end) {
    
    #if defined (__GNUC__) || defined (__ICCARM__)
                asm_cp15_clean_inval_dc_line_mva_poc(LocalAddr);
    #else
                { volatile register u32 Reg
                    __asm(XREG_CP15_CLEAN_INVAL_DC_LINE_MVA_POC);
                  Reg = LocalAddr; }
    #endif
                LocalAddr += cacheline;
            }
        }
    
        /* Wait for L1 flush to complete */
        dsb();
        mtcpsr(currmask);
    }
    
    /****************************************************************************/
    /**
    * @brief    Store a level 1  Data cache line. If the byte specified by the
    *             address (adr) is cached by the Data cache and the cacheline is
    *             modified (dirty), the entire contents of the cacheline are written
    *             to system memory. After the store completes, the cacheline is
    *            marked as unmodified (not dirty).
    *
    * @param    Address to be stored.
    *
    * @return    None.
    *
    * @note        The bottom 5 bits are set to 0, forced by architecture.
    *
    ****************************************************************************/
    void Xil_L1DCacheStoreLine(u32 adr)
    {
        mtcp(XREG_CP15_CACHE_SIZE_SEL, 0U);
        mtcp(XREG_CP15_CLEAN_DC_LINE_MVA_POC, (adr & (~0x1FU)));
    
        /* Wait for L1 store to complete */
        dsb();
    }
    
    
    /****************************************************************************/
    /**
    * @brief    Enable the level 1 instruction cache.
    *
    * @param    None.
    *
    * @return    None.
    *
    * @note        None.
    *
    ****************************************************************************/
    void Xil_L1ICacheEnable(void)
    {
        register u32 CtrlReg;
    
        /* enable caches only if they are disabled */
    #ifdef __GNUC__
        CtrlReg = mfcp(XREG_CP15_SYS_CONTROL);
    #elif defined (__ICCARM__)
        mfcp(XREG_CP15_SYS_CONTROL, CtrlReg);
    #else
        { volatile register u32 Reg __asm(XREG_CP15_SYS_CONTROL);
          CtrlReg = Reg; }
    #endif
        if ((CtrlReg & (XREG_CP15_CONTROL_I_BIT)) != 0U) {
            return;
        }
    
        /* invalidate the instruction cache */
        mtcp(XREG_CP15_INVAL_IC_POU, 0U);
    
        /* enable the instruction cache */
        CtrlReg |= (XREG_CP15_CONTROL_I_BIT);
    
        mtcp(XREG_CP15_SYS_CONTROL, CtrlReg);
    }
    
    /****************************************************************************/
    /**
    * @brief    Disable level 1 the instruction cache.
    *
    * @param    None.
    *
    * @return    None.
    *
    * @note        None.
    *
    ****************************************************************************/
    void Xil_L1ICacheDisable(void)
    {
        register u32 CtrlReg;
    
        dsb();
    
        /* invalidate the instruction cache */
        mtcp(XREG_CP15_INVAL_IC_POU, 0U);
    
        /* disable the instruction cache */
    #ifdef __GNUC__
        CtrlReg = mfcp(XREG_CP15_SYS_CONTROL);
    #elif defined (__ICCARM__)
        mfcp(XREG_CP15_SYS_CONTROL, CtrlReg);
    #else
        { volatile register u32 Reg __asm(XREG_CP15_SYS_CONTROL);
          CtrlReg = Reg; }
    #endif
        CtrlReg &= ~(XREG_CP15_CONTROL_I_BIT);
    
        mtcp(XREG_CP15_SYS_CONTROL, CtrlReg);
    }
    
    /****************************************************************************/
    /**
    * @brief    Invalidate the entire level 1 instruction cache.
    *
    * @param    None.
    *
    * @return    None.
    *
    * @note        None.
    *
    ****************************************************************************/
    void Xil_L1ICacheInvalidate(void)
    {
        mtcp(XREG_CP15_CACHE_SIZE_SEL, 1U);
        /* invalidate the instruction cache */
        mtcp(XREG_CP15_INVAL_IC_POU, 0U);
    
        /* Wait for L1 invalidate to complete */
        dsb();
    }
    
    /****************************************************************************/
    /**
    * @brief    Invalidate a level 1  instruction cache line. If the instruction
    *            specified by the address is cached by the instruction cache, the
    *            cacheline containing that instruction is invalidated.
    *
    * @param    adr: 32bit address of the instruction to be invalidated.
    *
    * @return    None.
    *
    * @note        The bottom 5 bits are set to 0, forced by architecture.
    *
    ****************************************************************************/
    void Xil_L1ICacheInvalidateLine(u32 adr)
    {
        mtcp(XREG_CP15_CACHE_SIZE_SEL, 1U);
        mtcp(XREG_CP15_INVAL_IC_LINE_MVA_POU, (adr & (~0x1FU)));
    
        /* Wait for L1 invalidate to complete */
        dsb();
    }
    
    /****************************************************************************/
    /**
    * @brief    Invalidate the level 1 instruction cache for the given address
    *             range. If the instrucions specified by the address range are cached
    *            by the instruction cache, the cacheline containing those bytes are
    *            invalidated.
    *
    * @param    adr: 32bit start address of the range to be invalidated.
    * @param    len: Length of the range to be invalidated in bytes.
    *
    * @return    None.
    *
    * @note        None.
    *
    ****************************************************************************/
    void Xil_L1ICacheInvalidateRange(u32 adr, u32 len)
    {
        u32 LocalAddr = adr;
        const u32 cacheline = 32U;
        u32 end;
        u32 currmask;
    
        currmask = mfcpsr();
        mtcpsr(currmask | IRQ_FIQ_MASK);
    
        if (len != 0U) {
            /* Back the starting address up to the start of a cache line
             * perform cache operations until adr+len
             */
            end = LocalAddr + len;
            LocalAddr = LocalAddr & ~(cacheline - 1U);
    
            /* Select cache L0 I-cache in CSSR */
            mtcp(XREG_CP15_CACHE_SIZE_SEL, 1U);
    
            while (LocalAddr < end) {
    
    #if defined (__GNUC__) || defined (__ICCARM__)
                asm_cp15_inval_ic_line_mva_pou(LocalAddr);
    #else
                { volatile register u32 Reg
                    __asm(XREG_CP15_INVAL_IC_LINE_MVA_POU);
                  Reg = LocalAddr; }
    #endif
                LocalAddr += cacheline;
            }
        }
    
        /* Wait for L1 invalidate to complete */
        dsb();
        mtcpsr(currmask);
    }
    
    #ifndef USE_AMP
    /****************************************************************************/
    /**
    * @brief    Enable the L2 cache.
    *
    * @param    None.
    *
    * @return    None.
    *
    * @note        None.
    *
    ****************************************************************************/
    void Xil_L2CacheEnable(void)
    {
        register u32 L2CCReg;
    
        L2CCReg = Xil_In32(XPS_L2CC_BASEADDR + XPS_L2CC_CNTRL_OFFSET);
    
        /* only enable if L2CC is currently disabled */
        if ((L2CCReg & 0x01U) == 0U) {
            /* set up the way size and latencies */
            L2CCReg = Xil_In32(XPS_L2CC_BASEADDR +
                       XPS_L2CC_AUX_CNTRL_OFFSET);
            L2CCReg &= XPS_L2CC_AUX_REG_ZERO_MASK;
            L2CCReg |= XPS_L2CC_AUX_REG_DEFAULT_MASK;
            Xil_Out32(XPS_L2CC_BASEADDR + XPS_L2CC_AUX_CNTRL_OFFSET,
                  L2CCReg);
            Xil_Out32(XPS_L2CC_BASEADDR + XPS_L2CC_TAG_RAM_CNTRL_OFFSET,
                  XPS_L2CC_TAG_RAM_DEFAULT_MASK);
            Xil_Out32(XPS_L2CC_BASEADDR + XPS_L2CC_DATA_RAM_CNTRL_OFFSET,
                  XPS_L2CC_DATA_RAM_DEFAULT_MASK);
    
            /* Clear the pending interrupts */
            L2CCReg = Xil_In32(XPS_L2CC_BASEADDR +
                       XPS_L2CC_ISR_OFFSET);
            Xil_Out32(XPS_L2CC_BASEADDR + XPS_L2CC_IAR_OFFSET, L2CCReg);
    
            Xil_L2CacheInvalidate();
            /* Enable the L2CC */
            L2CCReg = Xil_In32(XPS_L2CC_BASEADDR +
                       XPS_L2CC_CNTRL_OFFSET);
            Xil_Out32(XPS_L2CC_BASEADDR + XPS_L2CC_CNTRL_OFFSET,
                  (L2CCReg | (0x01U)));
    
            Xil_L2CacheSync();
            /* synchronize the processor */
            dsb();
    
        }
    }
    
    /****************************************************************************/
    /**
    * @brief    Disable the L2 cache.
    *
    * @param    None.
    *
    * @return    None.
    *
    * @note        None.
    *
    ****************************************************************************/
    void Xil_L2CacheDisable(void)
    {
        register u32 L2CCReg;
    
        L2CCReg = Xil_In32(XPS_L2CC_BASEADDR + XPS_L2CC_CNTRL_OFFSET);
    
        if((L2CCReg & 0x1U) != 0U) {
    
            /* Clean and Invalidate L2 Cache */
            Xil_L2CacheFlush();
    
            /* Disable the L2CC */
        L2CCReg = Xil_In32(XPS_L2CC_BASEADDR + XPS_L2CC_CNTRL_OFFSET);
            Xil_Out32(XPS_L2CC_BASEADDR + XPS_L2CC_CNTRL_OFFSET,
                  (L2CCReg & (~0x01U)));
            /* Wait for the cache operations to complete */
    
            dsb();
        }
    }
    
    /*****************************************************************************/
    /**
    * @brief    Invalidate the entire level 2 cache.
    *
    * @param    None.
    *
    * @return    None.
    *
    * @note        None.
    *
    ****************************************************************************/
    void Xil_L2CacheInvalidate(void)
    {
        #ifdef __GNUC__
        u32 stack_start,stack_end,stack_size;
        register u32 L2CCReg;
        stack_end = (u32)&_stack_end;
        stack_start = (u32)&__undef_stack;
        stack_size=stack_start-stack_end;
    
        /* Check for the cache status. If cache is enabled, then only
         * flush stack memory to save return address. If cache is disabled,
         * dont flush anything as it might result in flushing stale date into
         * memory which is undesirable.
         */
        L2CCReg = Xil_In32(XPS_L2CC_BASEADDR + XPS_L2CC_CNTRL_OFFSET);
        if ((L2CCReg & 0x01U) != 0U) {
        /*Flush stack memory to save return address*/
            Xil_DCacheFlushRange(stack_end, stack_size);
        }
    
        #endif
        u32 ResultDCache;
        /* Invalidate the caches */
        Xil_Out32(XPS_L2CC_BASEADDR + XPS_L2CC_CACHE_INVLD_WAY_OFFSET,
              0x0000FFFFU);
        ResultDCache = Xil_In32(XPS_L2CC_BASEADDR + XPS_L2CC_CACHE_INVLD_WAY_OFFSET)
                                & 0x0000FFFFU;
        while(ResultDCache != (u32)0U) {
            ResultDCache = Xil_In32(XPS_L2CC_BASEADDR + XPS_L2CC_CACHE_INVLD_WAY_OFFSET)
                                & 0x0000FFFFU;
        }
    
        /* Wait for the invalidate to complete */
        Xil_L2CacheSync();
    
        /* synchronize the processor */
        dsb();
    }
    
    /*****************************************************************************/
    /**
    * @brief    Invalidate a level 2 cache line. If the byte specified by the
    *            address (adr) is cached by the Data cache, the cacheline containing
    *            that byte is invalidated. If the cacheline is modified (dirty),
    *            the modified contents are lost and are NOT written to system memory
    *            before the line is invalidated.
    *
    * @param    adr: 32bit address of the data/instruction to be invalidated.
    *
    * @return    None.
    *
    * @note        The bottom 4 bits are set to 0, forced by architecture.
    *
    ****************************************************************************/
    void Xil_L2CacheInvalidateLine(u32 adr)
    {
        Xil_Out32(XPS_L2CC_BASEADDR + XPS_L2CC_CACHE_INVLD_PA_OFFSET, (u32)adr);
        /* synchronize the processor */
        dsb();
    }
    
    /****************************************************************************/
    /**
    * @brief    Invalidate the level 2 cache for the given address range.
    *             If the bytes specified by the address range are cached by the L2
    *             cache, the cacheline containing those bytes are invalidated. If the
    *             cachelines are modified (dirty), the modified contents are lost and
    *             are NOT written to system memory before the lines are invalidated.
    *
    * @param    adr: 32bit start address of the range to be invalidated.
    * @param    len: Length of the range to be invalidated in bytes.
    *
    * @return    None.
    *
    * @note        None.
    *
    ****************************************************************************/
    void Xil_L2CacheInvalidateRange(u32 adr, u32 len)
    {
        u32 LocalAddr = adr;
        const u32 cacheline = 32U;
        u32 end;
        volatile u32 *L2CCOffset = (volatile u32 *)(XPS_L2CC_BASEADDR +
                        XPS_L2CC_CACHE_INVLD_PA_OFFSET);
    
        u32 currmask;
    
        currmask = mfcpsr();
        mtcpsr(currmask | IRQ_FIQ_MASK);
    
        if (len != 0U) {
            /* Back the starting address up to the start of a cache line
             * perform cache operations until adr+len
             */
            end = LocalAddr + len;
            LocalAddr = LocalAddr & ~(cacheline - 1U);
    
            /* Disable Write-back and line fills */
            Xil_L2WriteDebugCtrl(0x3U);
    
            while (LocalAddr < end) {
                *L2CCOffset = LocalAddr;
                Xil_L2CacheSync();
                LocalAddr += cacheline;
            }
    
            /* Enable Write-back and line fills */
            Xil_L2WriteDebugCtrl(0x0U);
        }
    
        /* synchronize the processor */
        dsb();
        mtcpsr(currmask);
    }
    
    /****************************************************************************/
    /**
    * @brief    Flush the entire level 2 cache.
    *
    * @param    None.
    *
    * @return    None.
    *
    * @note        None.
    *
    ****************************************************************************/
    void Xil_L2CacheFlush(void)
    {
        u32 ResultL2Cache;
    
        /* Flush the caches */
    
        /* Disable Write-back and line fills */
        Xil_L2WriteDebugCtrl(0x3U);
    
        Xil_Out32(XPS_L2CC_BASEADDR + XPS_L2CC_CACHE_INV_CLN_WAY_OFFSET,
              0x0000FFFFU);
        ResultL2Cache = Xil_In32(XPS_L2CC_BASEADDR + XPS_L2CC_CACHE_INV_CLN_WAY_OFFSET)
                                & 0x0000FFFFU;
    
        while(ResultL2Cache != (u32)0U) {
            ResultL2Cache = Xil_In32(XPS_L2CC_BASEADDR + XPS_L2CC_CACHE_INV_CLN_WAY_OFFSET)
                                        & 0x0000FFFFU;
        }
    
        Xil_L2CacheSync();
        /* Enable Write-back and line fills */
        Xil_L2WriteDebugCtrl(0x0U);
    
        /* synchronize the processor */
        dsb();
    }
    
    /****************************************************************************/
    /**
    * @brief    Flush a level 2 cache line. If the byte specified by the address
    *             (adr) is cached by the L2 cache, the cacheline containing that
    *             byte is invalidated. If the cacheline is modified (dirty), the
    *             entire contents of the cacheline are written to system memory
    *             before the line is invalidated.
    *
    * @param    adr: 32bit address of the data/instruction to be flushed.
    *
    * @return    None.
    *
    * @note        The bottom 4 bits are set to 0, forced by architecture.
    *
    ****************************************************************************/
    void Xil_L2CacheFlushLine(u32 adr)
    {
    #ifdef CONFIG_PL310_ERRATA_588369
        Xil_Out32(XPS_L2CC_BASEADDR + XPS_L2CC_CACHE_CLEAN_PA_OFFSET, adr);
        Xil_Out32(XPS_L2CC_BASEADDR + XPS_L2CC_CACHE_INVLD_PA_OFFSET, adr);
    #else
        Xil_Out32(XPS_L2CC_BASEADDR + XPS_L2CC_CACHE_INV_CLN_PA_OFFSET, adr);
    #endif
        /* synchronize the processor */
        dsb();
    }
    
    /****************************************************************************/
    /**
    * @brief    Flush the level 2 cache for the given address range.
    *             If the bytes specified by the address range are cached by the L2
    *             cache, the cacheline containing those bytes are invalidated. If the
    *             cachelines are modified (dirty), they are written to the system
    *             memory before the lines are invalidated.
    *
    * @param    adr: 32bit start address of the range to be flushed.
    * @param    len: Length of the range to be flushed in bytes.
    *
    * @return    None.
    *
    * @note        None.
    *
    ****************************************************************************/
    void Xil_L2CacheFlushRange(u32 adr, u32 len)
    {
        u32 LocalAddr = adr;
        const u32 cacheline = 32U;
        u32 end;
        volatile u32 *L2CCOffset = (volatile u32 *)(XPS_L2CC_BASEADDR +
                        XPS_L2CC_CACHE_INV_CLN_PA_OFFSET);
    
        u32 currmask;
    
        currmask = mfcpsr();
        mtcpsr(currmask | IRQ_FIQ_MASK);
        if (len != 0U) {
            /* Back the starting address up to the start of a cache line
             * perform cache operations until adr+len
             */
            end = LocalAddr + len;
            LocalAddr = LocalAddr & ~(cacheline - 1U);
    
            /* Disable Write-back and line fills */
            Xil_L2WriteDebugCtrl(0x3U);
    
            while (LocalAddr < end) {
                *L2CCOffset = LocalAddr;
                Xil_L2CacheSync();
                LocalAddr += cacheline;
            }
    
            /* Enable Write-back and line fills */
            Xil_L2WriteDebugCtrl(0x0U);
        }
        /* synchronize the processor */
        dsb();
        mtcpsr(currmask);
    }
    
    /****************************************************************************/
    /**
    * @brief    Store a level 2 cache line. If the byte specified by the address
    *             (adr) is cached by the L2 cache and the cacheline is modified
    *             (dirty), the entire contents of the cacheline are written to
    *            system memory. After the store completes, the cacheline is marked
    *            as unmodified (not dirty).
    *
    * @param    adr: 32bit address of the data/instruction to be stored.
    *
    * @return    None.
    *
    * @note        The bottom 4 bits are set to 0, forced by architecture.
    *
    ****************************************************************************/
    void Xil_L2CacheStoreLine(u32 adr)
    {
        Xil_Out32(XPS_L2CC_BASEADDR + XPS_L2CC_CACHE_CLEAN_PA_OFFSET, adr);
        /* synchronize the processor */
        dsb();
    }
    #endif
  • 相关阅读:
    sysybench-测试工具
    pip安装到指定目录的方案对比
    更好的创建构造函数的方式
    DeDeCMS-v5.7-漏洞分析
    DVWA靶场
    Fastadmin前台Getshell漏洞分析
    Yii反序列化漏洞分析
    SparkGraphX中的PR算法和pregel迭代算法
    关于linux下,ls vi等命令失效的解决方法(配置下环境变量出现问题)
    埋点的三种方式
  • 原文地址:https://www.cnblogs.com/sinferwu/p/13026418.html
Copyright © 2011-2022 走看看