1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright (C) 2017, STMicroelectronics - All Rights Reserved 4 * Author(s): Vikas Manocha, <vikas.manocha@st.com> for STMicroelectronics. 5 */ 6 7#include <common.h> 8#include <cpu_func.h> 9#include <errno.h> 10#include <log.h> 11#include <asm/armv7m.h> 12#include <asm/cache.h> 13#include <asm/io.h> 14#include <linux/bitops.h> 15 16/* Cache maintenance operation registers */ 17 18#define V7M_CACHE_REG_ICIALLU ((u32 *)(V7M_CACHE_MAINT_BASE + 0x00)) 19#define INVAL_ICACHE_POU 0 20#define V7M_CACHE_REG_ICIMVALU ((u32 *)(V7M_CACHE_MAINT_BASE + 0x08)) 21#define V7M_CACHE_REG_DCIMVAC ((u32 *)(V7M_CACHE_MAINT_BASE + 0x0C)) 22#define V7M_CACHE_REG_DCISW ((u32 *)(V7M_CACHE_MAINT_BASE + 0x10)) 23#define V7M_CACHE_REG_DCCMVAU ((u32 *)(V7M_CACHE_MAINT_BASE + 0x14)) 24#define V7M_CACHE_REG_DCCMVAC ((u32 *)(V7M_CACHE_MAINT_BASE + 0x18)) 25#define V7M_CACHE_REG_DCCSW ((u32 *)(V7M_CACHE_MAINT_BASE + 0x1C)) 26#define V7M_CACHE_REG_DCCIMVAC ((u32 *)(V7M_CACHE_MAINT_BASE + 0x20)) 27#define V7M_CACHE_REG_DCCISW ((u32 *)(V7M_CACHE_MAINT_BASE + 0x24)) 28#define WAYS_SHIFT 30 29#define SETS_SHIFT 5 30 31/* armv7m processor feature registers */ 32 33#define V7M_PROC_REG_CLIDR ((u32 *)(V7M_PROC_FTR_BASE + 0x00)) 34#define V7M_PROC_REG_CTR ((u32 *)(V7M_PROC_FTR_BASE + 0x04)) 35#define V7M_PROC_REG_CCSIDR ((u32 *)(V7M_PROC_FTR_BASE + 0x08)) 36#define MASK_NUM_WAYS GENMASK(12, 3) 37#define MASK_NUM_SETS GENMASK(27, 13) 38#define CLINE_SIZE_MASK GENMASK(2, 0) 39#define NUM_WAYS_SHIFT 3 40#define NUM_SETS_SHIFT 13 41#define V7M_PROC_REG_CSSELR ((u32 *)(V7M_PROC_FTR_BASE + 0x0C)) 42#define SEL_I_OR_D BIT(0) 43 44enum cache_type { 45 DCACHE, 46 ICACHE, 47}; 48 49/* PoU : Point of Unification, Poc: Point of Coherency */ 50enum cache_action { 51 INVALIDATE_POU, /* i-cache invalidate by address */ 52 INVALIDATE_POC, /* d-cache invalidate by address */ 53 INVALIDATE_SET_WAY, /* d-cache invalidate by sets/ways */ 54 FLUSH_POU, /* d-cache clean by address to the PoU */ 55 FLUSH_POC, /* d-cache clean by address to the PoC */ 56 FLUSH_SET_WAY, /* d-cache clean by sets/ways */ 57 FLUSH_INVAL_POC, /* d-cache clean & invalidate by addr to PoC */ 58 FLUSH_INVAL_SET_WAY, /* d-cache clean & invalidate by set/ways */ 59}; 60 61#if !CONFIG_IS_ENABLED(SYS_DCACHE_OFF) 62struct dcache_config { 63 u32 ways; 64 u32 sets; 65}; 66 67static void get_cache_ways_sets(struct dcache_config *cache) 68{ 69 u32 cache_size_id = readl(V7M_PROC_REG_CCSIDR); 70 71 cache->ways = (cache_size_id & MASK_NUM_WAYS) >> NUM_WAYS_SHIFT; 72 cache->sets = (cache_size_id & MASK_NUM_SETS) >> NUM_SETS_SHIFT; 73} 74 75/* 76 * Return the io register to perform required cache action like clean or clean 77 * & invalidate by sets/ways. 78 */ 79static u32 *get_action_reg_set_ways(enum cache_action action) 80{ 81 switch (action) { 82 case INVALIDATE_SET_WAY: 83 return V7M_CACHE_REG_DCISW; 84 case FLUSH_SET_WAY: 85 return V7M_CACHE_REG_DCCSW; 86 case FLUSH_INVAL_SET_WAY: 87 return V7M_CACHE_REG_DCCISW; 88 default: 89 break; 90 }; 91 92 return NULL; 93} 94 95/* 96 * Return the io register to perform required cache action like clean or clean 97 * & invalidate by adddress or range. 98 */ 99static u32 *get_action_reg_range(enum cache_action action) 100{ 101 switch (action) { 102 case INVALIDATE_POU: 103 return V7M_CACHE_REG_ICIMVALU; 104 case INVALIDATE_POC: 105 return V7M_CACHE_REG_DCIMVAC; 106 case FLUSH_POU: 107 return V7M_CACHE_REG_DCCMVAU; 108 case FLUSH_POC: 109 return V7M_CACHE_REG_DCCMVAC; 110 case FLUSH_INVAL_POC: 111 return V7M_CACHE_REG_DCCIMVAC; 112 default: 113 break; 114 } 115 116 return NULL; 117} 118 119static u32 get_cline_size(enum cache_type type) 120{ 121 u32 size; 122 123 if (type == DCACHE) 124 clrbits_le32(V7M_PROC_REG_CSSELR, BIT(SEL_I_OR_D)); 125 else if (type == ICACHE) 126 setbits_le32(V7M_PROC_REG_CSSELR, BIT(SEL_I_OR_D)); 127 /* Make sure cache selection is effective for next memory access */ 128 dsb(); 129 130 size = readl(V7M_PROC_REG_CCSIDR) & CLINE_SIZE_MASK; 131 /* Size enocoded as 2 less than log(no_of_words_in_cache_line) base 2 */ 132 size = 1 << (size + 2); 133 debug("cache line size is %d\n", size); 134 135 return size; 136} 137 138/* Perform the action like invalidate/clean on a range of cache addresses */ 139static int action_cache_range(enum cache_action action, u32 start_addr, 140 int64_t size) 141{ 142 u32 cline_size; 143 u32 *action_reg; 144 enum cache_type type; 145 146 action_reg = get_action_reg_range(action); 147 if (!action_reg) 148 return -EINVAL; 149 if (action == INVALIDATE_POU) 150 type = ICACHE; 151 else 152 type = DCACHE; 153 154 /* Cache line size is minium size for the cache action */ 155 cline_size = get_cline_size(type); 156 /* Align start address to cache line boundary */ 157 start_addr &= ~(cline_size - 1); 158 debug("total size for cache action = %llx\n", size); 159 do { 160 writel(start_addr, action_reg); 161 size -= cline_size; 162 start_addr += cline_size; 163 } while (size > cline_size); 164 165 /* Make sure cache action is effective for next memory access */ 166 dsb(); 167 isb(); /* Make sure instruction stream sees it */ 168 debug("cache action on range done\n"); 169 170 return 0; 171} 172 173/* Perform the action like invalidate/clean on all cached addresses */ 174static int action_dcache_all(enum cache_action action) 175{ 176 struct dcache_config cache; 177 u32 *action_reg; 178 int i, j; 179 180 action_reg = get_action_reg_set_ways(action); 181 if (!action_reg) 182 return -EINVAL; 183 184 clrbits_le32(V7M_PROC_REG_CSSELR, BIT(SEL_I_OR_D)); 185 /* Make sure cache selection is effective for next memory access */ 186 dsb(); 187 188 get_cache_ways_sets(&cache); /* Get number of ways & sets */ 189 debug("cache: ways= %d, sets= %d\n", cache.ways + 1, cache.sets + 1); 190 for (i = cache.sets; i >= 0; i--) { 191 for (j = cache.ways; j >= 0; j--) { 192 writel((j << WAYS_SHIFT) | (i << SETS_SHIFT), 193 action_reg); 194 } 195 } 196 197 /* Make sure cache action is effective for next memory access */ 198 dsb(); 199 isb(); /* Make sure instruction stream sees it */ 200 201 return 0; 202} 203 204void dcache_enable(void) 205{ 206 if (dcache_status()) /* return if cache already enabled */ 207 return; 208 209 if (action_dcache_all(INVALIDATE_SET_WAY)) { 210 printf("ERR: D-cache not enabled\n"); 211 return; 212 } 213 214 setbits_le32(&V7M_SCB->ccr, BIT(V7M_CCR_DCACHE)); 215 216 /* Make sure cache action is effective for next memory access */ 217 dsb(); 218 isb(); /* Make sure instruction stream sees it */ 219} 220 221void dcache_disable(void) 222{ 223 if (!dcache_status()) 224 return; 225 226 /* if dcache is enabled-> dcache disable & then flush */ 227 if (action_dcache_all(FLUSH_SET_WAY)) { 228 printf("ERR: D-cache not flushed\n"); 229 return; 230 } 231 232 clrbits_le32(&V7M_SCB->ccr, BIT(V7M_CCR_DCACHE)); 233 234 /* Make sure cache action is effective for next memory access */ 235 dsb(); 236 isb(); /* Make sure instruction stream sees it */ 237} 238 239int dcache_status(void) 240{ 241 return (readl(&V7M_SCB->ccr) & BIT(V7M_CCR_DCACHE)) != 0; 242} 243 244void invalidate_dcache_range(unsigned long start, unsigned long stop) 245{ 246 if (action_cache_range(INVALIDATE_POC, start, stop - start)) { 247 printf("ERR: D-cache not invalidated\n"); 248 return; 249 } 250} 251 252void flush_dcache_range(unsigned long start, unsigned long stop) 253{ 254 if (action_cache_range(FLUSH_POC, start, stop - start)) { 255 printf("ERR: D-cache not flushed\n"); 256 return; 257 } 258} 259void flush_dcache_all(void) 260{ 261 if (action_dcache_all(FLUSH_SET_WAY)) { 262 printf("ERR: D-cache not flushed\n"); 263 return; 264 } 265} 266 267void invalidate_dcache_all(void) 268{ 269 if (action_dcache_all(INVALIDATE_SET_WAY)) { 270 printf("ERR: D-cache not invalidated\n"); 271 return; 272 } 273} 274#else 275void dcache_enable(void) 276{ 277 return; 278} 279 280void dcache_disable(void) 281{ 282 return; 283} 284 285int dcache_status(void) 286{ 287 return 0; 288} 289 290void flush_dcache_all(void) 291{ 292} 293 294void invalidate_dcache_all(void) 295{ 296} 297 298void mmu_set_region_dcache_behaviour(phys_addr_t start, size_t size, 299 enum dcache_option option) 300{ 301} 302 303#endif 304 305#if !CONFIG_IS_ENABLED(SYS_ICACHE_OFF) 306 307void invalidate_icache_all(void) 308{ 309 writel(INVAL_ICACHE_POU, V7M_CACHE_REG_ICIALLU); 310 311 /* Make sure cache action is effective for next memory access */ 312 dsb(); 313 isb(); /* Make sure instruction stream sees it */ 314} 315 316void icache_enable(void) 317{ 318 if (icache_status()) 319 return; 320 321 invalidate_icache_all(); 322 setbits_le32(&V7M_SCB->ccr, BIT(V7M_CCR_ICACHE)); 323 324 /* Make sure cache action is effective for next memory access */ 325 dsb(); 326 isb(); /* Make sure instruction stream sees it */ 327} 328 329int icache_status(void) 330{ 331 return (readl(&V7M_SCB->ccr) & BIT(V7M_CCR_ICACHE)) != 0; 332} 333 334void icache_disable(void) 335{ 336 if (!icache_status()) 337 return; 338 339 isb(); /* flush pipeline */ 340 clrbits_le32(&V7M_SCB->ccr, BIT(V7M_CCR_ICACHE)); 341 isb(); /* subsequent instructions fetch see cache disable effect */ 342} 343#else 344void invalidate_icache_all(void) 345{ 346 return; 347} 348 349void icache_enable(void) 350{ 351 return; 352} 353 354void icache_disable(void) 355{ 356 return; 357} 358 359int icache_status(void) 360{ 361 return 0; 362} 363#endif 364 365void enable_caches(void) 366{ 367#if !CONFIG_IS_ENABLED(SYS_ICACHE_OFF) 368 icache_enable(); 369#endif 370#if !CONFIG_IS_ENABLED(SYS_DCACHE_OFF) 371 dcache_enable(); 372#endif 373} 374