1 /*
2  * Cache Ops For Loongson GS232
3  *
4  * Copyright (c) 2006-2021, RT-Thread Development Team
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  *
8  * Change Logs:
9  * Date           Author       Notes
10  * 2010-07-09     Bernard        first version
11  * 2011-08-08     lgnq             modified for LS1B
12  * 2015-07-08     chinesebear   modified for loongson 1c
13  */
14 
15 #include <rtthread.h>
16 #include <mips.h>
17 
18 #define K0BASE          0x80000000
19 #define PRID_LS1C       0x4220
20 
21 extern void Clear_TagLo (void);
22 extern void Invalidate_Icache_Ls1c(unsigned int);
23 extern void Invalidate_Dcache_ClearTag_Ls1c(unsigned int);
24 extern void Invalidate_Dcache_Fill_Ls1c(unsigned int);
25 extern void Writeback_Invalidate_Dcache(unsigned int);
26 extern void enable_cpu_cache(void);
27 
28 typedef struct cacheinfo_t
29 {
30     unsigned int    icache_size;
31     unsigned int    dcache_size;
32     unsigned int    icacheline_size;
33     unsigned int    dcacheline_size;
34 } cacheinfo_t ;
35 
36 typedef struct cacheop_t
37 {
38     void (*Clear_TagLo) (void);
39     void (*Invalidate_Icache) (unsigned int);
40     void (*Invalidate_Dcache_Fill) (unsigned int);
41     void (*Invalidate_Dcache_ClearTag) (unsigned int);
42     void (*Init_Cache)(void);
43 } cacheop_t ;
44 
45 static cacheop_t cacheop, *pcacheop;
46 static cacheinfo_t cacheinfo, *pcacheinfo;
47 
identify_cpu(void)48 int identify_cpu(void)
49 {
50     unsigned int cpu_id;
51 
52     pcacheop = &cacheop;
53     pcacheinfo = &cacheinfo;
54 
55     rt_kprintf("CPU configure: 0x%08x\n", read_c0_config());
56     cpu_id = read_c0_prid();
57     switch (cpu_id)
58     {
59     case PRID_LS1C:
60         rt_kprintf("CPU:Loongson 1C\n");
61         pcacheop->Clear_TagLo = Clear_TagLo;
62         pcacheop->Invalidate_Icache = Invalidate_Icache_Ls1c;
63         pcacheop->Invalidate_Dcache_Fill = Invalidate_Dcache_Fill_Ls1c;
64         pcacheop->Invalidate_Dcache_ClearTag = Invalidate_Dcache_ClearTag_Ls1c;
65         break;
66     default:
67         rt_kprintf("Unknown CPU type, system halted!\n");
68         while (1)
69         {
70             ;
71         }
72         break;
73     }
74 
75     return 0;
76 }
77 
probe_cache(void)78 void probe_cache(void)
79 {
80     unsigned int config1 = read_c0_config1();
81     unsigned int icache_size, icache_line_size, icache_sets, icache_ways;
82     unsigned int dcache_size, dcache_line_size, dcache_sets, dcache_ways;
83 
84     if ((icache_line_size = ((config1 >> 19) & 7)))
85         icache_line_size = 2 << icache_line_size;
86     else
87         icache_line_size = icache_line_size;
88     icache_sets = 64 << ((config1 >> 22) & 7);
89     icache_ways = 1 + ((config1 >> 16) & 7);
90     icache_size = icache_sets * icache_ways * icache_line_size;
91 
92     if ((dcache_line_size = ((config1 >> 10) & 7)))
93         dcache_line_size = 2 << dcache_line_size;
94     else
95         dcache_line_size = dcache_line_size;
96     dcache_sets = 64 << ((config1 >> 13) & 7);
97     dcache_ways = 1 + ((config1 >> 7) & 7);
98     dcache_size = dcache_sets * dcache_ways * dcache_line_size;
99 
100     rt_kprintf("DCache %2dkb, linesize %d bytes.\n", dcache_size >> 10, dcache_line_size);
101     rt_kprintf("ICache %2dkb, linesize %d bytes.\n", icache_size >> 10, icache_line_size);
102 
103     pcacheinfo->icache_size = icache_size;
104     pcacheinfo->dcache_size = dcache_size;
105     pcacheinfo->icacheline_size = icache_line_size;
106     pcacheinfo->dcacheline_size = dcache_line_size;
107 
108     return ;
109 }
110 
invalidate_writeback_dcache_all(void)111 void invalidate_writeback_dcache_all(void)
112 {
113     unsigned int start = K0BASE;
114     unsigned int end = (start + pcacheinfo->dcache_size);
115 
116     while (start < end)
117     {
118         Writeback_Invalidate_Dcache(start);  //hit writeback invalidate
119         start += pcacheinfo->dcacheline_size;
120     }
121 }
122 
invalidate_writeback_dcache(unsigned long addr,int size)123 void invalidate_writeback_dcache(unsigned long addr, int size)
124 {
125     unsigned long start, end;
126 
127     start = (addr + pcacheinfo->dcacheline_size -1) & (- pcacheinfo->dcacheline_size);
128     end = (addr + size + pcacheinfo->dcacheline_size -1) & ( -pcacheinfo->dcacheline_size);
129 
130     while (start <end)
131     {
132         Writeback_Invalidate_Dcache(start);
133         start += pcacheinfo->dcacheline_size;
134     }
135 }
136 
invalidate_icache_all(void)137 void invalidate_icache_all(void)
138 {
139     unsigned int start = K0BASE;
140     unsigned int end = (start + pcacheinfo->icache_size);
141 
142     while (start < end)
143     {
144         pcacheop->Invalidate_Icache(start);
145         start += pcacheinfo->icacheline_size;
146     }
147 }
148 
invalidate_dcache_all(void)149 void invalidate_dcache_all(void)
150 {
151     unsigned int start = K0BASE;
152     unsigned int end  = (start + pcacheinfo->dcache_size);
153     while (start <end)
154     {
155         Invalidate_Dcache_Fill_Ls1c(start);
156         start += pcacheinfo->icacheline_size;
157     }
158 }
159 
160 //with cache disabled
init_dcache(void)161 void init_dcache(void)
162 {
163     unsigned int start = K0BASE;
164     unsigned int end = (start + pcacheinfo->dcache_size);
165 
166     while (start < end)
167     {
168         pcacheop->Invalidate_Dcache_ClearTag(start);
169         start += pcacheinfo->dcacheline_size;
170     }
171 
172 }
173 
rt_hw_cache_init(void)174 void rt_hw_cache_init(void)
175 {
176     unsigned int start, end;
177 
178     /* 1. identify cpu and probe cache */
179     identify_cpu();
180     probe_cache();
181 
182     start = K0BASE;
183     end = (start + pcacheinfo->icache_size);
184 
185     /*
186      *  2. clear CP0 taglo/taghi register;
187      */
188     pcacheop->Clear_TagLo();
189 
190     /*
191      *  3. invalidate instruction cache;
192      */
193     while (start < end)
194     {
195         pcacheop->Invalidate_Icache(start); //index invalidate icache
196         start += pcacheinfo->icacheline_size;
197     }
198 
199     /*
200      *  4. invalidate data cache;
201      */
202     start = K0BASE;
203     end = (start + pcacheinfo->dcache_size);
204     while(start < end)
205     {
206         pcacheop->Invalidate_Dcache_ClearTag(start);
207         start += pcacheinfo->dcacheline_size;
208     }
209 
210     start = K0BASE;
211     while(start < end)
212     {
213         pcacheop->Invalidate_Dcache_Fill(start);  //index invalidate dcache
214         start += pcacheinfo->dcacheline_size;
215     }
216 
217     start = K0BASE;
218     while(start < end)
219     {
220         pcacheop->Invalidate_Dcache_ClearTag(start);
221         start += pcacheinfo->dcacheline_size;
222     }
223 
224     /* enable cache */
225     enable_cpu_cache();
226     rt_kprintf("enable cpu cache done\n");
227 
228     return ;
229 }
230 
231 
232