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