234 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			234 lines
		
	
	
		
			5.7 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
 | 
						|
 * 2015-07-08     chinesebear   modified for loongson 1c
 | 
						|
 */
 | 
						|
 
 | 
						|
#include <rtthread.h>
 | 
						|
#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 <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_Ls1c(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 ;
 | 
						|
}
 | 
						|
 | 
						|
 |