231 lines
5.6 KiB
C
231 lines
5.6 KiB
C
/*
|
|
* 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
|
|
*/
|
|
|
|
#include <rtthread.h>
|
|
#include "../common/mipsregs.h"
|
|
|
|
#define K0BASE 0x80000000
|
|
#define PRID_LS1B 0x4220
|
|
|
|
extern void Clear_TagLo (void);
|
|
extern void Invalidate_Icache_Ls1b(unsigned int);
|
|
extern void Invalidate_Dcache_ClearTag_Ls1b(unsigned int);
|
|
extern void Invalidate_Dcache_Fill_Ls1b(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_LS1B:
|
|
rt_kprintf("CPU:LS1B\n");
|
|
pcacheop->Clear_TagLo = Clear_TagLo;
|
|
pcacheop->Invalidate_Icache = Invalidate_Icache_Ls1b;
|
|
pcacheop->Invalidate_Dcache_Fill = Invalidate_Dcache_Fill_Ls1b;
|
|
pcacheop->Invalidate_Dcache_ClearTag = Invalidate_Dcache_ClearTag_Ls1b;
|
|
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 <end)
|
|
{
|
|
Writeback_Invalidate_Dcache(start);
|
|
start += pcacheinfo->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 <end)
|
|
{
|
|
Invalidate_Dcache_Fill_Ls1b(start);
|
|
start += pcacheinfo->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 ;
|
|
}
|