Home | History | Annotate | Download | only in lib
      1 // SPDX-License-Identifier: GPL-2.0+
      2 /*
      3  * Copyright (C) 2012 Andes Technology Corporation
      4  * Shawn Lin, Andes Technology Corporation <nobuhiro (at) andestech.com>
      5  * Macpaul Lin, Andes Technology Corporation <macpaul (at) andestech.com>
      6  */
      7 
      8 #include <common.h>
      9 #if (!defined(CONFIG_SYS_ICACHE_OFF) || !defined(CONFIG_SYS_DCACHE_OFF))
     10 static inline unsigned long CACHE_SET(unsigned char cache)
     11 {
     12 	if (cache == ICACHE)
     13 		return 64 << ((GET_ICM_CFG() & ICM_CFG_MSK_ISET) \
     14 			>> ICM_CFG_OFF_ISET);
     15 	else
     16 		return 64 << ((GET_DCM_CFG() & DCM_CFG_MSK_DSET) \
     17 			>> DCM_CFG_OFF_DSET);
     18 }
     19 
     20 static inline unsigned long CACHE_WAY(unsigned char cache)
     21 {
     22 	if (cache == ICACHE)
     23 		return 1 + ((GET_ICM_CFG() & ICM_CFG_MSK_IWAY) \
     24 			>> ICM_CFG_OFF_IWAY);
     25 	else
     26 		return 1 + ((GET_DCM_CFG() & DCM_CFG_MSK_DWAY) \
     27 			>> DCM_CFG_OFF_DWAY);
     28 }
     29 
     30 static inline unsigned long CACHE_LINE_SIZE(enum cache_t cache)
     31 {
     32 	if (cache == ICACHE)
     33 		return 8 << (((GET_ICM_CFG() & ICM_CFG_MSK_ISZ) \
     34 			>> ICM_CFG_OFF_ISZ) - 1);
     35 	else
     36 		return 8 << (((GET_DCM_CFG() & DCM_CFG_MSK_DSZ) \
     37 			>> DCM_CFG_OFF_DSZ) - 1);
     38 }
     39 #endif
     40 
     41 #ifndef CONFIG_SYS_ICACHE_OFF
     42 void invalidate_icache_all(void)
     43 {
     44 	unsigned long end, line_size;
     45 	line_size = CACHE_LINE_SIZE(ICACHE);
     46 	end = line_size * CACHE_WAY(ICACHE) * CACHE_SET(ICACHE);
     47 	do {
     48 		end -= line_size;
     49 		__asm__ volatile ("\n\tcctl %0, L1I_IX_INVAL" : : "r" (end));
     50 
     51 		end -= line_size;
     52 		__asm__ volatile ("\n\tcctl %0, L1I_IX_INVAL" : : "r" (end));
     53 
     54 		end -= line_size;
     55 		__asm__ volatile ("\n\tcctl %0, L1I_IX_INVAL" : : "r" (end));
     56 		end -= line_size;
     57 		__asm__ volatile ("\n\tcctl %0, L1I_IX_INVAL" : : "r" (end));
     58 	} while (end > 0);
     59 }
     60 
     61 void invalidate_icache_range(unsigned long start, unsigned long end)
     62 {
     63 	unsigned long line_size;
     64 
     65 	line_size = CACHE_LINE_SIZE(ICACHE);
     66 	while (end > start) {
     67 		asm volatile (
     68 			"\n\tcctl %0, L1I_VA_INVAL"
     69 			:
     70 			: "r"(start)
     71 		);
     72 		start += line_size;
     73 	}
     74 }
     75 
     76 void icache_enable(void)
     77 {
     78 	asm volatile (
     79 		"mfsr	$p0, $mr8\n\t"
     80 		"ori	$p0, $p0, 0x01\n\t"
     81 		"mtsr	$p0, $mr8\n\t"
     82 		"isb\n\t"
     83 	);
     84 }
     85 
     86 void icache_disable(void)
     87 {
     88 	asm volatile (
     89 		"mfsr	$p0, $mr8\n\t"
     90 		"li	$p1, ~0x01\n\t"
     91 		"and	$p0, $p0, $p1\n\t"
     92 		"mtsr	$p0, $mr8\n\t"
     93 		"isb\n\t"
     94 	);
     95 }
     96 
     97 int icache_status(void)
     98 {
     99 	int ret;
    100 
    101 	asm volatile (
    102 		"mfsr	$p0, $mr8\n\t"
    103 		"andi	%0,  $p0, 0x01\n\t"
    104 		: "=r" (ret)
    105 		:
    106 		: "memory"
    107 	);
    108 
    109 	return ret;
    110 }
    111 
    112 #else
    113 void invalidate_icache_all(void)
    114 {
    115 }
    116 
    117 void invalidate_icache_range(unsigned long start, unsigned long end)
    118 {
    119 }
    120 
    121 void icache_enable(void)
    122 {
    123 }
    124 
    125 void icache_disable(void)
    126 {
    127 }
    128 
    129 int icache_status(void)
    130 {
    131 	return 0;
    132 }
    133 
    134 #endif
    135 
    136 #ifndef CONFIG_SYS_DCACHE_OFF
    137 void dcache_wbinval_all(void)
    138 {
    139 	unsigned long end, line_size;
    140 	line_size = CACHE_LINE_SIZE(DCACHE);
    141 	end = line_size * CACHE_WAY(DCACHE) * CACHE_SET(DCACHE);
    142 	do {
    143 		end -= line_size;
    144 		__asm__ volatile ("\n\tcctl %0, L1D_IX_WB" : : "r" (end));
    145 		__asm__ volatile ("\n\tcctl %0, L1D_IX_INVAL" : : "r" (end));
    146 		end -= line_size;
    147 		__asm__ volatile ("\n\tcctl %0, L1D_IX_WB" : : "r" (end));
    148 		__asm__ volatile ("\n\tcctl %0, L1D_IX_INVAL" : : "r" (end));
    149 		end -= line_size;
    150 		__asm__ volatile ("\n\tcctl %0, L1D_IX_WB" : : "r" (end));
    151 		__asm__ volatile ("\n\tcctl %0, L1D_IX_INVAL" : : "r" (end));
    152 		end -= line_size;
    153 		__asm__ volatile ("\n\tcctl %0, L1D_IX_WB" : : "r" (end));
    154 		__asm__ volatile ("\n\tcctl %0, L1D_IX_INVAL" : : "r" (end));
    155 
    156 	} while (end > 0);
    157 }
    158 
    159 void flush_dcache_range(unsigned long start, unsigned long end)
    160 {
    161 	unsigned long line_size;
    162 
    163 	line_size = CACHE_LINE_SIZE(DCACHE);
    164 
    165 	while (end > start) {
    166 		asm volatile (
    167 			"\n\tcctl %0, L1D_VA_WB"
    168 			"\n\tcctl %0, L1D_VA_INVAL" : : "r" (start)
    169 		);
    170 		start += line_size;
    171 	}
    172 }
    173 
    174 void invalidate_dcache_range(unsigned long start, unsigned long end)
    175 {
    176 	unsigned long line_size;
    177 
    178 	line_size = CACHE_LINE_SIZE(DCACHE);
    179 	while (end > start) {
    180 		asm volatile (
    181 			"\n\tcctl %0, L1D_VA_INVAL" : : "r"(start)
    182 		);
    183 		start += line_size;
    184 	}
    185 }
    186 
    187 void dcache_enable(void)
    188 {
    189 	asm volatile (
    190 		"mfsr	$p0, $mr8\n\t"
    191 		"ori	$p0, $p0, 0x02\n\t"
    192 		"mtsr	$p0, $mr8\n\t"
    193 		"isb\n\t"
    194 	);
    195 }
    196 
    197 void dcache_disable(void)
    198 {
    199 	asm volatile (
    200 		"mfsr	$p0, $mr8\n\t"
    201 		"li	$p1, ~0x02\n\t"
    202 		"and	$p0, $p0, $p1\n\t"
    203 		"mtsr	$p0, $mr8\n\t"
    204 		"isb\n\t"
    205 	);
    206 }
    207 
    208 int dcache_status(void)
    209 {
    210 	int ret;
    211 	asm volatile (
    212 		"mfsr	$p0, $mr8\n\t"
    213 		"andi	%0, $p0, 0x02\n\t"
    214 		: "=r" (ret)
    215 		:
    216 		: "memory"
    217 	);
    218 	return ret;
    219 }
    220 
    221 #else
    222 void dcache_wbinval_all(void)
    223 {
    224 }
    225 
    226 void flush_dcache_range(unsigned long start, unsigned long end)
    227 {
    228 }
    229 
    230 void invalidate_dcache_range(unsigned long start, unsigned long end)
    231 {
    232 }
    233 
    234 void dcache_enable(void)
    235 {
    236 }
    237 
    238 void dcache_disable(void)
    239 {
    240 }
    241 
    242 int dcache_status(void)
    243 {
    244 	return 0;
    245 }
    246 
    247 #endif
    248 
    249 
    250 void flush_dcache_all(void)
    251 {
    252 	dcache_wbinval_all();
    253 }
    254 
    255 void cache_flush(void)
    256 {
    257 	flush_dcache_all();
    258 	invalidate_icache_all();
    259 }
    260 
    261 
    262 void flush_cache(unsigned long addr, unsigned long size)
    263 {
    264 	flush_dcache_range(addr, addr + size);
    265 	invalidate_icache_range(addr, addr + size);
    266 }
    267