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*939a255aSPaul Burton #ifdef CONFIG_MIPS_L2_CACHE 114baa0ab6SPaul Burton #include <asm/cm.h> 12*939a255aSPaul Burton #endif 1330374f98SPaul Burton #include <asm/mipsregs.h> 1430374f98SPaul Burton 158cb4817dSPaul Burton DECLARE_GLOBAL_DATA_PTR; 1637228621SPaul Burton 174baa0ab6SPaul Burton static void probe_l2(void) 184baa0ab6SPaul Burton { 194baa0ab6SPaul Burton #ifdef CONFIG_MIPS_L2_CACHE 204baa0ab6SPaul Burton unsigned long conf2, sl; 214baa0ab6SPaul Burton bool l2c = false; 224baa0ab6SPaul Burton 234baa0ab6SPaul Burton if (!(read_c0_config1() & MIPS_CONF_M)) 244baa0ab6SPaul Burton return; 254baa0ab6SPaul Burton 264baa0ab6SPaul Burton conf2 = read_c0_config2(); 274baa0ab6SPaul Burton 284baa0ab6SPaul Burton if (__mips_isa_rev >= 6) { 294baa0ab6SPaul Burton l2c = conf2 & MIPS_CONF_M; 304baa0ab6SPaul Burton if (l2c) 314baa0ab6SPaul Burton l2c = read_c0_config3() & MIPS_CONF_M; 324baa0ab6SPaul Burton if (l2c) 334baa0ab6SPaul Burton l2c = read_c0_config4() & MIPS_CONF_M; 344baa0ab6SPaul Burton if (l2c) 354baa0ab6SPaul Burton l2c = read_c0_config5() & MIPS_CONF5_L2C; 364baa0ab6SPaul Burton } 374baa0ab6SPaul Burton 384baa0ab6SPaul Burton if (l2c && config_enabled(CONFIG_MIPS_CM)) { 394baa0ab6SPaul Burton gd->arch.l2_line_size = mips_cm_l2_line_size(); 404baa0ab6SPaul Burton } else if (l2c) { 414baa0ab6SPaul Burton /* We don't know how to retrieve L2 config on this system */ 424baa0ab6SPaul Burton BUG(); 434baa0ab6SPaul Burton } else { 444baa0ab6SPaul Burton sl = (conf2 & MIPS_CONF2_SL) >> MIPS_CONF2_SL_SHF; 454baa0ab6SPaul Burton gd->arch.l2_line_size = sl ? (2 << sl) : 0; 464baa0ab6SPaul Burton } 474baa0ab6SPaul Burton #endif 484baa0ab6SPaul Burton } 494baa0ab6SPaul Burton 508cb4817dSPaul Burton void mips_cache_probe(void) 518cb4817dSPaul Burton { 528cb4817dSPaul Burton #ifdef CONFIG_SYS_CACHE_SIZE_AUTO 538cb4817dSPaul Burton unsigned long conf1, il, dl; 5437228621SPaul Burton 5530374f98SPaul Burton conf1 = read_c0_config1(); 568cb4817dSPaul Burton 57a3ab2ae7SDaniel Schwierzeck il = (conf1 & MIPS_CONF1_IL) >> MIPS_CONF1_IL_SHF; 588cb4817dSPaul Burton dl = (conf1 & MIPS_CONF1_DL) >> MIPS_CONF1_DL_SHF; 598cb4817dSPaul Burton 608cb4817dSPaul Burton gd->arch.l1i_line_size = il ? (2 << il) : 0; 618cb4817dSPaul Burton gd->arch.l1d_line_size = dl ? (2 << dl) : 0; 628cb4817dSPaul Burton #endif 634baa0ab6SPaul Burton probe_l2(); 648cb4817dSPaul Burton } 658cb4817dSPaul Burton 668cb4817dSPaul Burton static inline unsigned long icache_line_size(void) 678cb4817dSPaul Burton { 688cb4817dSPaul Burton #ifdef CONFIG_SYS_CACHE_SIZE_AUTO 698cb4817dSPaul Burton return gd->arch.l1i_line_size; 708cb4817dSPaul Burton #else 718cb4817dSPaul Burton return CONFIG_SYS_ICACHE_LINE_SIZE; 728cb4817dSPaul Burton #endif 7330374f98SPaul Burton } 7430374f98SPaul Burton 7530374f98SPaul Burton static inline unsigned long dcache_line_size(void) 7630374f98SPaul Burton { 778cb4817dSPaul Burton #ifdef CONFIG_SYS_CACHE_SIZE_AUTO 788cb4817dSPaul Burton return gd->arch.l1d_line_size; 798cb4817dSPaul Burton #else 8037228621SPaul Burton return CONFIG_SYS_DCACHE_LINE_SIZE; 818cb4817dSPaul Burton #endif 8230374f98SPaul Burton } 8330374f98SPaul Burton 844baa0ab6SPaul Burton static inline unsigned long scache_line_size(void) 854baa0ab6SPaul Burton { 864baa0ab6SPaul Burton #ifdef CONFIG_MIPS_L2_CACHE 874baa0ab6SPaul Burton return gd->arch.l2_line_size; 884baa0ab6SPaul Burton #else 894baa0ab6SPaul Burton return 0; 904baa0ab6SPaul Burton #endif 914baa0ab6SPaul Burton } 924baa0ab6SPaul Burton 93fb64cda5SPaul Burton #define cache_loop(start, end, lsize, ops...) do { \ 94fb64cda5SPaul Burton const void *addr = (const void *)(start & ~(lsize - 1)); \ 95fb64cda5SPaul Burton const void *aend = (const void *)((end - 1) & ~(lsize - 1)); \ 96fb64cda5SPaul Burton const unsigned int cache_ops[] = { ops }; \ 97fb64cda5SPaul Burton unsigned int i; \ 98fb64cda5SPaul Burton \ 99fb64cda5SPaul Burton for (; addr <= aend; addr += lsize) { \ 100fb64cda5SPaul Burton for (i = 0; i < ARRAY_SIZE(cache_ops); i++) \ 101fb64cda5SPaul Burton mips_cache(cache_ops[i], addr); \ 102fb64cda5SPaul Burton } \ 103fb64cda5SPaul Burton } while (0) 104fb64cda5SPaul Burton 10530374f98SPaul Burton void flush_cache(ulong start_addr, ulong size) 10630374f98SPaul Burton { 10730374f98SPaul Burton unsigned long ilsize = icache_line_size(); 10830374f98SPaul Burton unsigned long dlsize = dcache_line_size(); 1094baa0ab6SPaul Burton unsigned long slsize = scache_line_size(); 11030374f98SPaul Burton 11130374f98SPaul Burton /* aend will be miscalculated when size is zero, so we return here */ 11230374f98SPaul Burton if (size == 0) 11330374f98SPaul Burton return; 11430374f98SPaul Burton 1154baa0ab6SPaul Burton if ((ilsize == dlsize) && !slsize) { 11630374f98SPaul Burton /* flush I-cache & D-cache simultaneously */ 117fb64cda5SPaul Burton cache_loop(start_addr, start_addr + size, ilsize, 118fb64cda5SPaul Burton HIT_WRITEBACK_INV_D, HIT_INVALIDATE_I); 11930374f98SPaul Burton return; 12030374f98SPaul Burton } 12130374f98SPaul Burton 12230374f98SPaul Burton /* flush D-cache */ 123fb64cda5SPaul Burton cache_loop(start_addr, start_addr + size, dlsize, HIT_WRITEBACK_INV_D); 12430374f98SPaul Burton 1254baa0ab6SPaul Burton /* flush L2 cache */ 1264baa0ab6SPaul Burton if (slsize) 1274baa0ab6SPaul Burton cache_loop(start_addr, start_addr + size, slsize, 1284baa0ab6SPaul Burton HIT_WRITEBACK_INV_SD); 1294baa0ab6SPaul Burton 13030374f98SPaul Burton /* flush I-cache */ 131fb64cda5SPaul Burton cache_loop(start_addr, start_addr + size, ilsize, HIT_INVALIDATE_I); 13230374f98SPaul Burton } 13330374f98SPaul Burton 13430374f98SPaul Burton void flush_dcache_range(ulong start_addr, ulong stop) 13530374f98SPaul Burton { 13630374f98SPaul Burton unsigned long lsize = dcache_line_size(); 1374baa0ab6SPaul Burton unsigned long slsize = scache_line_size(); 13830374f98SPaul Burton 139fbb0de08SMarek Vasut /* aend will be miscalculated when size is zero, so we return here */ 140fbb0de08SMarek Vasut if (start_addr == stop) 141fbb0de08SMarek Vasut return; 142fbb0de08SMarek Vasut 143fb64cda5SPaul Burton cache_loop(start_addr, stop, lsize, HIT_WRITEBACK_INV_D); 1444baa0ab6SPaul Burton 1454baa0ab6SPaul Burton /* flush L2 cache */ 1464baa0ab6SPaul Burton if (slsize) 1474baa0ab6SPaul Burton cache_loop(start_addr, stop, slsize, HIT_WRITEBACK_INV_SD); 14830374f98SPaul Burton } 14930374f98SPaul Burton 15030374f98SPaul Burton void invalidate_dcache_range(ulong start_addr, ulong stop) 15130374f98SPaul Burton { 15230374f98SPaul Burton unsigned long lsize = dcache_line_size(); 1534baa0ab6SPaul Burton unsigned long slsize = scache_line_size(); 15430374f98SPaul Burton 155fbb0de08SMarek Vasut /* aend will be miscalculated when size is zero, so we return here */ 156fbb0de08SMarek Vasut if (start_addr == stop) 157fbb0de08SMarek Vasut return; 158fbb0de08SMarek Vasut 1594baa0ab6SPaul Burton /* invalidate L2 cache */ 1604baa0ab6SPaul Burton if (slsize) 1614baa0ab6SPaul Burton cache_loop(start_addr, stop, slsize, HIT_INVALIDATE_SD); 1624baa0ab6SPaul Burton 163a95800e8SPaul Burton cache_loop(start_addr, stop, lsize, HIT_INVALIDATE_D); 16430374f98SPaul Burton } 165