/* * File : cache.c * This file is part of RT-Thread RTOS * COPYRIGHT (C) 2006 - 2011, RT-Thread Development Team * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at * http://www.rt-thread.org/license/LICENSE * * Change Logs: * Date Author Notes * 2010-07-09 Bernard first version * 2011-08-08 lgnq modified for LS1B * 2015-07-08 chinesebear modified for loongson 1c */ #include #include "../common/mipsregs.h" #define K0BASE 0x80000000 #define PRID_LS1C 0x4220 extern void Clear_TagLo (void); extern void Invalidate_Icache_Ls1c(unsigned int); extern void Invalidate_Dcache_ClearTag_Ls1c(unsigned int); extern void Invalidate_Dcache_Fill_Ls1c(unsigned int); extern void Writeback_Invalidate_Dcache(unsigned int); extern void enable_cpu_cache(void); typedef struct cacheinfo_t { unsigned int icache_size; unsigned int dcache_size; unsigned int icacheline_size; unsigned int dcacheline_size; } cacheinfo_t ; typedef struct cacheop_t { void (*Clear_TagLo) (void); void (*Invalidate_Icache) (unsigned int); void (*Invalidate_Dcache_Fill) (unsigned int); void (*Invalidate_Dcache_ClearTag) (unsigned int); void (*Init_Cache)(void); } cacheop_t ; static cacheop_t cacheop, *pcacheop; static cacheinfo_t cacheinfo, *pcacheinfo; int identify_cpu(void) { unsigned int cpu_id; pcacheop = &cacheop; pcacheinfo = &cacheinfo; rt_kprintf("CPU configure: 0x%08x\n", read_c0_config()); cpu_id = read_c0_prid(); switch (cpu_id) { case PRID_LS1C: rt_kprintf("CPU:Loongson 1C\n"); pcacheop->Clear_TagLo = Clear_TagLo; pcacheop->Invalidate_Icache = Invalidate_Icache_Ls1c; pcacheop->Invalidate_Dcache_Fill = Invalidate_Dcache_Fill_Ls1c; pcacheop->Invalidate_Dcache_ClearTag = Invalidate_Dcache_ClearTag_Ls1c; break; default: rt_kprintf("Unknown CPU type, system halted!\n"); while (1) { ; } break; } return 0; } void probe_cache(void) { unsigned int config1 = read_c0_config1(); unsigned int icache_size, icache_line_size, icache_sets, icache_ways; unsigned int dcache_size, dcache_line_size, dcache_sets, dcache_ways; if ((icache_line_size = ((config1 >> 19) & 7))) icache_line_size = 2 << icache_line_size; else icache_line_size = icache_line_size; icache_sets = 64 << ((config1 >> 22) & 7); icache_ways = 1 + ((config1 >> 16) & 7); icache_size = icache_sets * icache_ways * icache_line_size; if ((dcache_line_size = ((config1 >> 10) & 7))) dcache_line_size = 2 << dcache_line_size; else dcache_line_size = dcache_line_size; dcache_sets = 64 << ((config1 >> 13) & 7); dcache_ways = 1 + ((config1 >> 7) & 7); dcache_size = dcache_sets * dcache_ways * dcache_line_size; rt_kprintf("DCache %2dkb, linesize %d bytes.\n", dcache_size >> 10, dcache_line_size); rt_kprintf("ICache %2dkb, linesize %d bytes.\n", icache_size >> 10, icache_line_size); pcacheinfo->icache_size = icache_size; pcacheinfo->dcache_size = dcache_size; pcacheinfo->icacheline_size = icache_line_size; pcacheinfo->dcacheline_size = dcache_line_size; return ; } void invalidate_writeback_dcache_all(void) { unsigned int start = K0BASE; unsigned int end = (start + pcacheinfo->dcache_size); while (start < end) { Writeback_Invalidate_Dcache(start); //hit writeback invalidate start += pcacheinfo->dcacheline_size; } } void invalidate_writeback_dcache(unsigned long addr, int size) { unsigned long start, end; start = (addr +pcacheinfo->dcacheline_size -1) & (- pcacheinfo->dcacheline_size); end = (end + size + pcacheinfo->dcacheline_size -1) & ( -pcacheinfo->dcacheline_size); while (start dcacheline_size; } } void invalidate_icache_all(void) { unsigned int start = K0BASE; unsigned int end = (start + pcacheinfo->icache_size); while (start < end) { pcacheop->Invalidate_Icache(start); start += pcacheinfo->icacheline_size; } } void invalidate_dcache_all(void) { unsigned int start = K0BASE; unsigned int end = (start + pcacheinfo->dcache_size); while (start icacheline_size; } } //with cache disabled void init_dcache(void) { unsigned int start = K0BASE; unsigned int end = (start + pcacheinfo->dcache_size); while (start < end) { pcacheop->Invalidate_Dcache_ClearTag(start); start += pcacheinfo->dcacheline_size; } } void rt_hw_cache_init(void) { unsigned int start, end; /* 1. identify cpu and probe cache */ identify_cpu(); probe_cache(); start = K0BASE; end = (start + pcacheinfo->icache_size); /* * 2. clear CP0 taglo/taghi register; */ pcacheop->Clear_TagLo(); /* * 3. invalidate instruction cache; */ while (start < end) { pcacheop->Invalidate_Icache(start); //index invalidate icache start += pcacheinfo->icacheline_size; } /* * 4. invalidate data cache; */ start = K0BASE; end = (start + pcacheinfo->dcache_size); while(start < end) { pcacheop->Invalidate_Dcache_ClearTag(start); start += pcacheinfo->dcacheline_size; } start = K0BASE; while(start < end) { pcacheop->Invalidate_Dcache_Fill(start); //index invalidate dcache start += pcacheinfo->dcacheline_size; } start = K0BASE; while(start < end) { pcacheop->Invalidate_Dcache_ClearTag(start); start += pcacheinfo->dcacheline_size; } /* enable cache */ enable_cpu_cache(); rt_kprintf("enable cpu cache done\n"); return ; }