130374f98SPaul Burton /* 230374f98SPaul Burton * (C) Copyright 2003 330374f98SPaul Burton * Wolfgang Denk, DENX Software Engineering, <wd@denx.de> 430374f98SPaul Burton * 530374f98SPaul Burton * SPDX-License-Identifier: GPL-2.0+ 630374f98SPaul Burton */ 730374f98SPaul Burton 830374f98SPaul Burton #include <common.h> 930374f98SPaul Burton #include <asm/cacheops.h> 10*4baa0ab6SPaul Burton #include <asm/cm.h> 1130374f98SPaul Burton #include <asm/mipsregs.h> 1230374f98SPaul Burton 138cb4817dSPaul Burton DECLARE_GLOBAL_DATA_PTR; 1437228621SPaul Burton 15*4baa0ab6SPaul Burton static void probe_l2(void) 16*4baa0ab6SPaul Burton { 17*4baa0ab6SPaul Burton #ifdef CONFIG_MIPS_L2_CACHE 18*4baa0ab6SPaul Burton unsigned long conf2, sl; 19*4baa0ab6SPaul Burton bool l2c = false; 20*4baa0ab6SPaul Burton 21*4baa0ab6SPaul Burton if (!(read_c0_config1() & MIPS_CONF_M)) 22*4baa0ab6SPaul Burton return; 23*4baa0ab6SPaul Burton 24*4baa0ab6SPaul Burton conf2 = read_c0_config2(); 25*4baa0ab6SPaul Burton 26*4baa0ab6SPaul Burton if (__mips_isa_rev >= 6) { 27*4baa0ab6SPaul Burton l2c = conf2 & MIPS_CONF_M; 28*4baa0ab6SPaul Burton if (l2c) 29*4baa0ab6SPaul Burton l2c = read_c0_config3() & MIPS_CONF_M; 30*4baa0ab6SPaul Burton if (l2c) 31*4baa0ab6SPaul Burton l2c = read_c0_config4() & MIPS_CONF_M; 32*4baa0ab6SPaul Burton if (l2c) 33*4baa0ab6SPaul Burton l2c = read_c0_config5() & MIPS_CONF5_L2C; 34*4baa0ab6SPaul Burton } 35*4baa0ab6SPaul Burton 36*4baa0ab6SPaul Burton if (l2c && config_enabled(CONFIG_MIPS_CM)) { 37*4baa0ab6SPaul Burton gd->arch.l2_line_size = mips_cm_l2_line_size(); 38*4baa0ab6SPaul Burton } else if (l2c) { 39*4baa0ab6SPaul Burton /* We don't know how to retrieve L2 config on this system */ 40*4baa0ab6SPaul Burton BUG(); 41*4baa0ab6SPaul Burton } else { 42*4baa0ab6SPaul Burton sl = (conf2 & MIPS_CONF2_SL) >> MIPS_CONF2_SL_SHF; 43*4baa0ab6SPaul Burton gd->arch.l2_line_size = sl ? (2 << sl) : 0; 44*4baa0ab6SPaul Burton } 45*4baa0ab6SPaul Burton #endif 46*4baa0ab6SPaul Burton } 47*4baa0ab6SPaul Burton 488cb4817dSPaul Burton void mips_cache_probe(void) 498cb4817dSPaul Burton { 508cb4817dSPaul Burton #ifdef CONFIG_SYS_CACHE_SIZE_AUTO 518cb4817dSPaul Burton unsigned long conf1, il, dl; 5237228621SPaul Burton 5330374f98SPaul Burton conf1 = read_c0_config1(); 548cb4817dSPaul Burton 55a3ab2ae7SDaniel Schwierzeck il = (conf1 & MIPS_CONF1_IL) >> MIPS_CONF1_IL_SHF; 568cb4817dSPaul Burton dl = (conf1 & MIPS_CONF1_DL) >> MIPS_CONF1_DL_SHF; 578cb4817dSPaul Burton 588cb4817dSPaul Burton gd->arch.l1i_line_size = il ? (2 << il) : 0; 598cb4817dSPaul Burton gd->arch.l1d_line_size = dl ? (2 << dl) : 0; 608cb4817dSPaul Burton #endif 61*4baa0ab6SPaul Burton probe_l2(); 628cb4817dSPaul Burton } 638cb4817dSPaul Burton 648cb4817dSPaul Burton static inline unsigned long icache_line_size(void) 658cb4817dSPaul Burton { 668cb4817dSPaul Burton #ifdef CONFIG_SYS_CACHE_SIZE_AUTO 678cb4817dSPaul Burton return gd->arch.l1i_line_size; 688cb4817dSPaul Burton #else 698cb4817dSPaul Burton return CONFIG_SYS_ICACHE_LINE_SIZE; 708cb4817dSPaul Burton #endif 7130374f98SPaul Burton } 7230374f98SPaul Burton 7330374f98SPaul Burton static inline unsigned long dcache_line_size(void) 7430374f98SPaul Burton { 758cb4817dSPaul Burton #ifdef CONFIG_SYS_CACHE_SIZE_AUTO 768cb4817dSPaul Burton return gd->arch.l1d_line_size; 778cb4817dSPaul Burton #else 7837228621SPaul Burton return CONFIG_SYS_DCACHE_LINE_SIZE; 798cb4817dSPaul Burton #endif 8030374f98SPaul Burton } 8130374f98SPaul Burton 82*4baa0ab6SPaul Burton static inline unsigned long scache_line_size(void) 83*4baa0ab6SPaul Burton { 84*4baa0ab6SPaul Burton #ifdef CONFIG_MIPS_L2_CACHE 85*4baa0ab6SPaul Burton return gd->arch.l2_line_size; 86*4baa0ab6SPaul Burton #else 87*4baa0ab6SPaul Burton return 0; 88*4baa0ab6SPaul Burton #endif 89*4baa0ab6SPaul Burton } 90*4baa0ab6SPaul Burton 91fb64cda5SPaul Burton #define cache_loop(start, end, lsize, ops...) do { \ 92fb64cda5SPaul Burton const void *addr = (const void *)(start & ~(lsize - 1)); \ 93fb64cda5SPaul Burton const void *aend = (const void *)((end - 1) & ~(lsize - 1)); \ 94fb64cda5SPaul Burton const unsigned int cache_ops[] = { ops }; \ 95fb64cda5SPaul Burton unsigned int i; \ 96fb64cda5SPaul Burton \ 97fb64cda5SPaul Burton for (; addr <= aend; addr += lsize) { \ 98fb64cda5SPaul Burton for (i = 0; i < ARRAY_SIZE(cache_ops); i++) \ 99fb64cda5SPaul Burton mips_cache(cache_ops[i], addr); \ 100fb64cda5SPaul Burton } \ 101fb64cda5SPaul Burton } while (0) 102fb64cda5SPaul Burton 10330374f98SPaul Burton void flush_cache(ulong start_addr, ulong size) 10430374f98SPaul Burton { 10530374f98SPaul Burton unsigned long ilsize = icache_line_size(); 10630374f98SPaul Burton unsigned long dlsize = dcache_line_size(); 107*4baa0ab6SPaul Burton unsigned long slsize = scache_line_size(); 10830374f98SPaul Burton 10930374f98SPaul Burton /* aend will be miscalculated when size is zero, so we return here */ 11030374f98SPaul Burton if (size == 0) 11130374f98SPaul Burton return; 11230374f98SPaul Burton 113*4baa0ab6SPaul Burton if ((ilsize == dlsize) && !slsize) { 11430374f98SPaul Burton /* flush I-cache & D-cache simultaneously */ 115fb64cda5SPaul Burton cache_loop(start_addr, start_addr + size, ilsize, 116fb64cda5SPaul Burton HIT_WRITEBACK_INV_D, HIT_INVALIDATE_I); 11730374f98SPaul Burton return; 11830374f98SPaul Burton } 11930374f98SPaul Burton 12030374f98SPaul Burton /* flush D-cache */ 121fb64cda5SPaul Burton cache_loop(start_addr, start_addr + size, dlsize, HIT_WRITEBACK_INV_D); 12230374f98SPaul Burton 123*4baa0ab6SPaul Burton /* flush L2 cache */ 124*4baa0ab6SPaul Burton if (slsize) 125*4baa0ab6SPaul Burton cache_loop(start_addr, start_addr + size, slsize, 126*4baa0ab6SPaul Burton HIT_WRITEBACK_INV_SD); 127*4baa0ab6SPaul Burton 12830374f98SPaul Burton /* flush I-cache */ 129fb64cda5SPaul Burton cache_loop(start_addr, start_addr + size, ilsize, HIT_INVALIDATE_I); 13030374f98SPaul Burton } 13130374f98SPaul Burton 13230374f98SPaul Burton void flush_dcache_range(ulong start_addr, ulong stop) 13330374f98SPaul Burton { 13430374f98SPaul Burton unsigned long lsize = dcache_line_size(); 135*4baa0ab6SPaul Burton unsigned long slsize = scache_line_size(); 13630374f98SPaul Burton 137fbb0de08SMarek Vasut /* aend will be miscalculated when size is zero, so we return here */ 138fbb0de08SMarek Vasut if (start_addr == stop) 139fbb0de08SMarek Vasut return; 140fbb0de08SMarek Vasut 141fb64cda5SPaul Burton cache_loop(start_addr, stop, lsize, HIT_WRITEBACK_INV_D); 142*4baa0ab6SPaul Burton 143*4baa0ab6SPaul Burton /* flush L2 cache */ 144*4baa0ab6SPaul Burton if (slsize) 145*4baa0ab6SPaul Burton cache_loop(start_addr, stop, slsize, HIT_WRITEBACK_INV_SD); 14630374f98SPaul Burton } 14730374f98SPaul Burton 14830374f98SPaul Burton void invalidate_dcache_range(ulong start_addr, ulong stop) 14930374f98SPaul Burton { 15030374f98SPaul Burton unsigned long lsize = dcache_line_size(); 151*4baa0ab6SPaul Burton unsigned long slsize = scache_line_size(); 15230374f98SPaul Burton 153fbb0de08SMarek Vasut /* aend will be miscalculated when size is zero, so we return here */ 154fbb0de08SMarek Vasut if (start_addr == stop) 155fbb0de08SMarek Vasut return; 156fbb0de08SMarek Vasut 157*4baa0ab6SPaul Burton /* invalidate L2 cache */ 158*4baa0ab6SPaul Burton if (slsize) 159*4baa0ab6SPaul Burton cache_loop(start_addr, stop, slsize, HIT_INVALIDATE_SD); 160*4baa0ab6SPaul Burton 161a95800e8SPaul Burton cache_loop(start_addr, stop, lsize, HIT_INVALIDATE_D); 16230374f98SPaul Burton } 163