/* * Copyright (c) 2006 - 2021, RT-Thread Development Team * Copyright (c) 2014 - 2020 Xilinx, Inc. All rights reserved. * Copyright (c) 2021 WangHuachen. All rights reserved. * SPDX-License-Identifier: MIT * * Change Logs: * Date Author Notes * 2020-03-19 WangHuachen first version * 2021-05-10 WangHuachen add more functions */ #include <stdint.h> #include <rthw.h> #include <rtdef.h> #include "xpseudo_asm_gcc.h" #include "xreg_cortexr5.h" #define IRQ_FIQ_MASK 0xC0 /* Mask IRQ and FIQ interrupts in cpsr */ typedef intptr_t INTPTR; typedef rt_uint32_t u32; #if defined (__GNUC__) #define asm_inval_dc_line_mva_poc(param) __asm__ __volatile__("mcr " \ XREG_CP15_INVAL_DC_LINE_MVA_POC :: "r" (param)) #define asm_clean_inval_dc_line_sw(param) __asm__ __volatile__("mcr " \ XREG_CP15_CLEAN_INVAL_DC_LINE_SW :: "r" (param)) #define asm_clean_inval_dc_line_mva_poc(param) __asm__ __volatile__("mcr " \ XREG_CP15_CLEAN_INVAL_DC_LINE_MVA_POC :: "r" (param)) #define asm_inval_ic_line_mva_pou(param) __asm__ __volatile__("mcr " \ XREG_CP15_INVAL_IC_LINE_MVA_POU :: "r" (param)) #elif defined (__ICCARM__) #define asm_inval_dc_line_mva_poc(param) __asm volatile("mcr " \ XREG_CP15_INVAL_DC_LINE_MVA_POC :: "r" (param)) #define asm_clean_inval_dc_line_sw(param) __asm volatile("mcr " \ XREG_CP15_CLEAN_INVAL_DC_LINE_SW :: "r" (param)) #define asm_clean_inval_dc_line_mva_poc(param) __asm volatile("mcr " \ XREG_CP15_CLEAN_INVAL_DC_LINE_MVA_POC :: "r" (param)) #define asm_inval_ic_line_mva_pou(param) __asm volatile("mcr " \ XREG_CP15_INVAL_IC_LINE_MVA_POU :: "r" (param)) #endif void Xil_DCacheEnable(void); void Xil_DCacheDisable(void); void Xil_DCacheInvalidate(void); void Xil_DCacheInvalidateRange(INTPTR adr, u32 len); void Xil_DCacheFlush(void); void Xil_DCacheFlushRange(INTPTR adr, u32 len); void Xil_DCacheInvalidateLine(INTPTR adr); void Xil_DCacheFlushLine(INTPTR adr); void Xil_DCacheStoreLine(INTPTR adr); void Xil_ICacheEnable(void); void Xil_ICacheDisable(void); void Xil_ICacheInvalidate(void); void Xil_ICacheInvalidateRange(INTPTR adr, u32 len); void Xil_ICacheInvalidateLine(INTPTR adr); void Xil_DCacheEnable(void) { register u32 CtrlReg; /* enable caches only if they are disabled */ #if defined (__GNUC__) CtrlReg = mfcp(XREG_CP15_SYS_CONTROL); #elif defined (__ICCARM__) mfcp(XREG_CP15_SYS_CONTROL, CtrlReg); #endif if ((CtrlReg & XREG_CP15_CONTROL_C_BIT) == 0x00000000U) { /* invalidate the Data cache */ Xil_DCacheInvalidate(); /* enable the Data cache */ CtrlReg |= (XREG_CP15_CONTROL_C_BIT); mtcp(XREG_CP15_SYS_CONTROL, CtrlReg); } } void Xil_DCacheDisable(void) { register u32 CtrlReg; /* clean and invalidate the Data cache */ Xil_DCacheFlush(); /* disable the Data cache */ #if defined (__GNUC__) CtrlReg = mfcp(XREG_CP15_SYS_CONTROL); #elif defined (__ICCARM__) mfcp(XREG_CP15_SYS_CONTROL, CtrlReg); #endif CtrlReg &= ~(XREG_CP15_CONTROL_C_BIT); mtcp(XREG_CP15_SYS_CONTROL, CtrlReg); } void Xil_DCacheInvalidate(void) { u32 currmask; currmask = mfcpsr(); mtcpsr(currmask | IRQ_FIQ_MASK); mtcp(XREG_CP15_CACHE_SIZE_SEL, 0); /*invalidate all D cache*/ mtcp(XREG_CP15_INVAL_DC_ALL, 0); mtcpsr(currmask); } void Xil_DCacheInvalidateLine(INTPTR adr) { u32 currmask; currmask = mfcpsr(); mtcpsr(currmask | IRQ_FIQ_MASK); mtcp(XREG_CP15_CACHE_SIZE_SEL, 0); mtcp(XREG_CP15_INVAL_DC_LINE_MVA_POC, (adr & (~0x1F))); /* Wait for invalidate to complete */ dsb(); mtcpsr(currmask); } void Xil_DCacheInvalidateRange(INTPTR adr, u32 len) { const u32 cacheline = 32U; u32 end; u32 tempadr = adr; u32 tempend; u32 currmask; 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_DCacheFlushLine(tempadr); } if ((tempend & (cacheline - 1U)) != 0U) { tempend &= (~(cacheline - 1U)); Xil_DCacheFlushLine(tempend); } while (tempadr < tempend) { /* Invalidate Data cache line */ asm_inval_dc_line_mva_poc(tempadr); tempadr += cacheline; } } dsb(); mtcpsr(currmask); } void Xil_DCacheFlush(void) { register u32 CsidReg, C7Reg; u32 CacheSize, LineSize, NumWays; u32 Way, 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); #if defined (__GNUC__) CsidReg = mfcp(XREG_CP15_CACHE_SIZE_ID); #elif defined (__ICCARM__) mfcp(XREG_CP15_CACHE_SIZE_ID, CsidReg); #endif /* Determine Cache Size */ CacheSize = (CsidReg >> 13U) & 0x000001FFU; CacheSize += 0x00000001U; CacheSize *= (u32)128; /* to get number of bytes */ /* Number of Ways */ NumWays = (CsidReg & 0x000003ffU) >> 3U; NumWays += 0x00000001U; /* Get the cacheline size, way size, index size from csidr */ LineSize = (CsidReg & 0x00000007U) + 0x00000004U; 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 */ asm_clean_inval_dc_line_sw(C7Reg); Set += (0x00000001U << LineSize); } Set = 0U; Way += 0x40000000U; } /* Wait for flush to complete */ dsb(); mtcpsr(currmask); mtcpsr(currmask); } void Xil_DCacheFlushLine(INTPTR adr) { u32 currmask; currmask = mfcpsr(); mtcpsr(currmask | IRQ_FIQ_MASK); mtcp(XREG_CP15_CACHE_SIZE_SEL, 0); mtcp(XREG_CP15_CLEAN_INVAL_DC_LINE_MVA_POC, (adr & (~0x1F))); /* Wait for flush to complete */ dsb(); mtcpsr(currmask); } void Xil_DCacheFlushRange(INTPTR adr, u32 len) { u32 LocalAddr = adr; const u32 cacheline = 32U; u32 end; u32 currmask; currmask = mfcpsr(); mtcpsr(currmask | IRQ_FIQ_MASK); if (len != 0x00000000U) { /* 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 Data cache line */ asm_clean_inval_dc_line_mva_poc(LocalAddr); LocalAddr += cacheline; } } dsb(); mtcpsr(currmask); } void Xil_DCacheStoreLine(INTPTR adr) { u32 currmask; currmask = mfcpsr(); mtcpsr(currmask | IRQ_FIQ_MASK); mtcp(XREG_CP15_CACHE_SIZE_SEL, 0); mtcp(XREG_CP15_CLEAN_DC_LINE_MVA_POC, (adr & (~0x1F))); /* Wait for store to complete */ dsb(); isb(); mtcpsr(currmask); } void Xil_ICacheEnable(void) { register u32 CtrlReg; /* enable caches only if they are disabled */ #if defined (__GNUC__) CtrlReg = mfcp(XREG_CP15_SYS_CONTROL); #elif defined (__ICCARM__) mfcp(XREG_CP15_SYS_CONTROL, CtrlReg); #endif if ((CtrlReg & XREG_CP15_CONTROL_I_BIT) == 0x00000000U) { /* invalidate the instruction cache */ mtcp(XREG_CP15_INVAL_IC_POU, 0); /* enable the instruction cache */ CtrlReg |= (XREG_CP15_CONTROL_I_BIT); mtcp(XREG_CP15_SYS_CONTROL, CtrlReg); } } void Xil_ICacheDisable(void) { register u32 CtrlReg; dsb(); /* invalidate the instruction cache */ mtcp(XREG_CP15_INVAL_IC_POU, 0); /* disable the instruction cache */ #if defined (__GNUC__) CtrlReg = mfcp(XREG_CP15_SYS_CONTROL); #elif defined (__ICCARM__) mfcp(XREG_CP15_SYS_CONTROL, CtrlReg); #endif CtrlReg &= ~(XREG_CP15_CONTROL_I_BIT); mtcp(XREG_CP15_SYS_CONTROL, CtrlReg); } void Xil_ICacheInvalidate(void) { u32 currmask; currmask = mfcpsr(); mtcpsr(currmask | IRQ_FIQ_MASK); mtcp(XREG_CP15_CACHE_SIZE_SEL, 1); /* invalidate the instruction cache */ mtcp(XREG_CP15_INVAL_IC_POU, 0); /* Wait for invalidate to complete */ dsb(); mtcpsr(currmask); } void Xil_ICacheInvalidateLine(INTPTR adr) { u32 currmask; currmask = mfcpsr(); mtcpsr(currmask | IRQ_FIQ_MASK); mtcp(XREG_CP15_CACHE_SIZE_SEL, 1); mtcp(XREG_CP15_INVAL_IC_LINE_MVA_POU, (adr & (~0x1F))); /* Wait for invalidate to complete */ dsb(); mtcpsr(currmask); } void Xil_ICacheInvalidateRange(INTPTR adr, u32 len) { u32 LocalAddr = adr; const u32 cacheline = 32U; u32 end; u32 currmask; currmask = mfcpsr(); mtcpsr(currmask | IRQ_FIQ_MASK); if (len != 0x00000000U) { /* 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) { /* Invalidate L1 I-cache line */ asm_inval_ic_line_mva_pou(LocalAddr); LocalAddr += cacheline; } } /* Wait for invalidate to complete */ dsb(); mtcpsr(currmask); } void rt_hw_cpu_icache_ops(int ops, void *addr, int size) { if (ops == RT_HW_CACHE_INVALIDATE) Xil_ICacheInvalidateRange((INTPTR)addr, size); } void rt_hw_cpu_dcache_ops(int ops, void *addr, int size) { if (ops == RT_HW_CACHE_FLUSH) Xil_DCacheFlushRange((intptr_t)addr, size); else if (ops == RT_HW_CACHE_INVALIDATE) Xil_DCacheInvalidateRange((intptr_t)addr, size); } rt_base_t rt_hw_cpu_icache_status(void) { register u32 CtrlReg; #if defined (__GNUC__) CtrlReg = mfcp(XREG_CP15_SYS_CONTROL); #elif defined (__ICCARM__) mfcp(XREG_CP15_SYS_CONTROL, CtrlReg); #endif return CtrlReg & XREG_CP15_CONTROL_I_BIT; } rt_base_t rt_hw_cpu_dcache_status(void) { register u32 CtrlReg; #if defined (__GNUC__) CtrlReg = mfcp(XREG_CP15_SYS_CONTROL); #elif defined (__ICCARM__) mfcp(XREG_CP15_SYS_CONTROL, CtrlReg); #endif return CtrlReg & XREG_CP15_CONTROL_C_BIT; }