]> CyberLeo.Net >> Repos - FreeBSD/releng/8.2.git/blob - sys/mips/mips/cpu.c
Copy stable/8 to releng/8.2 in preparation for FreeBSD-8.2 release.
[FreeBSD/releng/8.2.git] / sys / mips / mips / cpu.c
1 /*-
2  * Copyright (c) 2004 Juli Mallett.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  *
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include "opt_cputype.h"
31
32 #include <sys/param.h>
33 #include <sys/kernel.h>
34 #include <sys/module.h>
35 #include <sys/stdint.h>
36
37 #include <sys/bus.h>
38 #include <sys/rman.h>
39 #include <sys/sysctl.h>
40 #include <sys/systm.h>
41
42 #include <vm/vm.h>
43 #include <vm/vm_page.h>
44
45 #include <machine/cache.h>
46 #include <machine/cpufunc.h>
47 #include <machine/cpuinfo.h>
48 #include <machine/cpuregs.h>
49 #include <machine/intr_machdep.h>
50 #include <machine/locore.h>
51 #include <machine/pte.h>
52 #include <machine/tlb.h>
53 #include <machine/hwfunc.h>
54
55 static void cpu_identify(void);
56
57 struct mips_cpuinfo cpuinfo;
58
59 /*
60  * Attempt to identify the MIPS CPU as much as possible.
61  *
62  * XXX: Assumes the CPU is MIPS{32,64}{,r2} compliant.
63  * XXX: For now, skip config register selections 2 and 3
64  * as we don't currently use L2/L3 cache or additional
65  * MIPS32 processor features.
66  */
67 static void
68 mips_get_identity(struct mips_cpuinfo *cpuinfo)
69 {
70         u_int32_t prid;
71         u_int32_t cfg0;
72         u_int32_t cfg1;
73         u_int32_t tmp;
74
75         memset(cpuinfo, 0, sizeof(struct mips_cpuinfo));
76
77         /* Read and store the PrID ID for CPU identification. */
78         prid = mips_rd_prid();
79         cpuinfo->cpu_vendor = MIPS_PRID_CID(prid);
80         cpuinfo->cpu_rev = MIPS_PRID_REV(prid);
81         cpuinfo->cpu_impl = MIPS_PRID_IMPL(prid);
82
83         /* Read config register selection 0 to learn TLB type. */
84         cfg0 = mips_rd_config();
85
86         cpuinfo->tlb_type = 
87             ((cfg0 & MIPS_CONFIG0_MT_MASK) >> MIPS_CONFIG0_MT_SHIFT);
88         cpuinfo->icache_virtual = cfg0 & MIPS_CONFIG0_VI;
89
90         /* If config register selection 1 does not exist, exit. */
91         if (!(cfg0 & MIPS3_CONFIG_CM))
92                 return;
93
94         /* Learn TLB size and L1 cache geometry. */
95         cfg1 = mips_rd_config1();
96         cpuinfo->tlb_nentries = 
97             ((cfg1 & MIPS_CONFIG1_TLBSZ_MASK) >> MIPS_CONFIG1_TLBSZ_SHIFT) + 1;
98
99         /* L1 instruction cache. */
100         tmp = (cfg1 & MIPS_CONFIG1_IL_MASK) >> MIPS_CONFIG1_IL_SHIFT;
101         if (tmp != 0) {
102                 cpuinfo->l1.ic_linesize = 1 << (tmp + 1);
103                 cpuinfo->l1.ic_nways = (((cfg1 & MIPS_CONFIG1_IA_MASK) >> MIPS_CONFIG1_IA_SHIFT)) + 1;
104                 cpuinfo->l1.ic_nsets = 
105                         1 << (((cfg1 & MIPS_CONFIG1_IS_MASK) >> MIPS_CONFIG1_IS_SHIFT) + 6);
106                 cpuinfo->l1.ic_size = 
107                     cpuinfo->l1.ic_linesize * cpuinfo->l1.ic_nsets * cpuinfo->l1.ic_nways;
108         }
109
110         /* L1 data cache. */
111         tmp = (cfg1 & MIPS_CONFIG1_DL_MASK) >> MIPS_CONFIG1_DL_SHIFT;
112         if (tmp != 0) {
113                 cpuinfo->l1.dc_linesize = 1 << (tmp + 1);
114                 cpuinfo->l1.dc_nways = 
115                     (((cfg1 & MIPS_CONFIG1_DA_MASK) >> MIPS_CONFIG1_DA_SHIFT)) + 1;
116                 cpuinfo->l1.dc_nsets = 
117                     1 << (((cfg1 & MIPS_CONFIG1_DS_MASK) >> MIPS_CONFIG1_DS_SHIFT) + 6);
118         }
119 #ifdef CPU_CNMIPS
120         /*
121          * Octeon does 128 byte line-size. But Config-Sel1 doesn't show
122          * 128 line-size, 1 Set, 64 ways.
123          */
124         cpuinfo->l1.dc_linesize = 128;
125         cpuinfo->l1.dc_nsets = 1;
126         cpuinfo->l1.dc_nways = 64;
127 #endif
128         cpuinfo->l1.dc_size = cpuinfo->l1.dc_linesize 
129             * cpuinfo->l1.dc_nsets * cpuinfo->l1.dc_nways;
130 }
131
132 void
133 mips_cpu_init(void)
134 {
135         platform_cpu_init();
136         mips_get_identity(&cpuinfo);
137         num_tlbentries = cpuinfo.tlb_nentries;
138         mips_wr_wired(0);
139         tlb_invalidate_all();
140         mips_wr_wired(VMWIRED_ENTRIES);
141         mips_config_cache(&cpuinfo);
142         mips_vector_init();
143
144         mips_icache_sync_all();
145         mips_dcache_wbinv_all();
146         /* Print some info about CPU */
147         cpu_identify();
148 }
149
150 static void
151 cpu_identify(void)
152 {
153         uint32_t cfg0, cfg1, cfg2, cfg3;
154         printf("cpu%d: ", 0);   /* XXX per-cpu */
155         switch (cpuinfo.cpu_vendor) {
156         case MIPS_PRID_CID_MTI:
157                 printf("MIPS Technologies");
158                 break;
159         case MIPS_PRID_CID_BROADCOM:
160         case MIPS_PRID_CID_SIBYTE:
161                 printf("Broadcom");
162                 break;
163         case MIPS_PRID_CID_ALCHEMY:
164                 printf("AMD");
165                 break;
166         case MIPS_PRID_CID_SANDCRAFT:
167                 printf("Sandcraft");
168                 break;
169         case MIPS_PRID_CID_PHILIPS:
170                 printf("Philips");
171                 break;
172         case MIPS_PRID_CID_TOSHIBA:
173                 printf("Toshiba");
174                 break;
175         case MIPS_PRID_CID_LSI:
176                 printf("LSI");
177                 break;
178         case MIPS_PRID_CID_LEXRA:
179                 printf("Lexra");
180                 break;
181         case MIPS_PRID_CID_RMI:
182                 printf("RMI");
183                 break;
184         case MIPS_PRID_CID_CAVIUM:
185                 printf("Cavium");
186                 break;
187         case MIPS_PRID_CID_PREHISTORIC:
188         default:
189                 printf("Unknown cid %#x", cpuinfo.cpu_vendor);
190                 break;
191         }
192         printf(" processor v%d.%d\n", cpuinfo.cpu_rev, cpuinfo.cpu_impl);
193
194         printf("  MMU: ");
195         if (cpuinfo.tlb_type == MIPS_MMU_NONE) {
196                 printf("none present\n");
197         } else {
198                 if (cpuinfo.tlb_type == MIPS_MMU_TLB) {
199                         printf("Standard TLB");
200                 } else if (cpuinfo.tlb_type == MIPS_MMU_BAT) {
201                         printf("Standard BAT");
202                 } else if (cpuinfo.tlb_type == MIPS_MMU_FIXED) {
203                         printf("Fixed mapping");
204                 }
205                 printf(", %d entries\n", cpuinfo.tlb_nentries);
206         }
207
208         printf("  L1 i-cache: ");
209         if (cpuinfo.l1.ic_linesize == 0) {
210                 printf("disabled");
211         } else {
212                 if (cpuinfo.l1.ic_nways == 1) {
213                         printf("direct-mapped with");
214                 } else {
215                         printf ("%d ways of", cpuinfo.l1.ic_nways);
216                 }
217                 printf(" %d sets, %d bytes per line\n", 
218                     cpuinfo.l1.ic_nsets, cpuinfo.l1.ic_linesize);
219         }
220
221         printf("  L1 d-cache: ");
222         if (cpuinfo.l1.dc_linesize == 0) {
223                 printf("disabled");
224         } else {
225                 if (cpuinfo.l1.dc_nways == 1) {
226                         printf("direct-mapped with");
227                 } else {
228                         printf ("%d ways of", cpuinfo.l1.dc_nways);
229                 }
230                 printf(" %d sets, %d bytes per line\n", 
231                     cpuinfo.l1.dc_nsets, cpuinfo.l1.dc_linesize);
232         }
233
234         cfg0 = mips_rd_config();
235         /* If config register selection 1 does not exist, exit. */
236         if (!(cfg0 & MIPS3_CONFIG_CM))
237                 return;
238
239         cfg1 = mips_rd_config1();
240         printf("  Config1=0x%b\n", cfg1, 
241             "\20\7COP2\6MDMX\5PerfCount\4WatchRegs\3MIPS16\2EJTAG\1FPU");
242
243         /* If config register selection 2 does not exist, exit. */
244         if (!(cfg1 & MIPS3_CONFIG_CM))
245                 return;
246         cfg2 = mips_rd_config2();
247         /* 
248          * Config2 contains no useful information other then Config3 
249          * existence flag
250          */
251
252         /* If config register selection 3 does not exist, exit. */
253         if (!(cfg2 & MIPS3_CONFIG_CM))
254                 return;
255         cfg3 = mips_rd_config3();
256
257         /* Print Config3 if it contains any useful info */
258         if (cfg3 & ~(0x80000000))
259                 printf("  Config3=0x%b\n", cfg3, "\20\2SmartMIPS\1TraceLogic");
260 }
261
262 static struct rman cpu_hardirq_rman;
263
264 static devclass_t cpu_devclass;
265
266 /*
267  * Device methods
268  */
269 static int cpu_probe(device_t);
270 static int cpu_attach(device_t);
271 static struct resource *cpu_alloc_resource(device_t, device_t, int, int *,
272                                            u_long, u_long, u_long, u_int);
273 static int cpu_setup_intr(device_t, device_t, struct resource *, int,
274                           driver_filter_t *f, driver_intr_t *, void *, 
275                           void **);
276
277 static device_method_t cpu_methods[] = {
278         /* Device interface */
279         DEVMETHOD(device_probe,         cpu_probe),
280         DEVMETHOD(device_attach,        cpu_attach),
281         DEVMETHOD(device_detach,        bus_generic_detach),
282         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
283
284         /* Bus interface */
285         DEVMETHOD(bus_alloc_resource,   cpu_alloc_resource),
286         DEVMETHOD(bus_setup_intr,       cpu_setup_intr),
287         DEVMETHOD(bus_teardown_intr,    bus_generic_teardown_intr),
288
289         { 0, 0 }
290 };
291
292 static driver_t cpu_driver = {
293         "cpu", cpu_methods, 1
294 };
295
296 static int
297 cpu_probe(device_t dev)
298 {
299         return (0);
300 }
301
302 static int
303 cpu_attach(device_t dev)
304 {
305         int error;
306 #ifdef notyet
307         device_t clock;
308 #endif
309
310         cpu_hardirq_rman.rm_start = 0;
311         cpu_hardirq_rman.rm_end = 5;
312         cpu_hardirq_rman.rm_type = RMAN_ARRAY;
313         cpu_hardirq_rman.rm_descr = "CPU Hard Interrupts";
314
315         error = rman_init(&cpu_hardirq_rman);
316         if (error != 0) {
317                 device_printf(dev, "failed to initialize irq resources\n");
318                 return (error);
319         }
320         /* XXX rman_manage_all. */
321         error = rman_manage_region(&cpu_hardirq_rman,
322                                    cpu_hardirq_rman.rm_start,
323                                    cpu_hardirq_rman.rm_end);
324         if (error != 0) {
325                 device_printf(dev, "failed to manage irq resources\n");
326                 return (error);
327         }
328
329         if (device_get_unit(dev) != 0)
330                 panic("can't attach more cpus");
331         device_set_desc(dev, "MIPS32 processor");
332
333 #ifdef notyet
334         clock = device_add_child(dev, "clock", device_get_unit(dev));
335         if (clock == NULL)
336                 device_printf(dev, "clock failed to attach");
337 #endif
338
339         return (bus_generic_attach(dev));
340 }
341
342 static struct resource *
343 cpu_alloc_resource(device_t dev, device_t child, int type, int *rid,
344                    u_long start, u_long end, u_long count, u_int flags)
345 {
346         struct resource *res;
347
348         if (type != SYS_RES_IRQ)
349                 return (NULL);
350         res = rman_reserve_resource(&cpu_hardirq_rman, start, end, count, 0,
351                                     child);
352         return (res);
353 }
354
355 static int
356 cpu_setup_intr(device_t dev, device_t child, struct resource *res, int flags,
357                driver_filter_t *filt, driver_intr_t *handler, void *arg, 
358                void **cookiep)
359 {
360         int error;
361         int intr;
362
363         error = rman_activate_resource(res);
364         if (error != 0) {
365                 device_printf(child, "could not activate irq\n");
366                 return (error);
367         }
368
369         intr = rman_get_start(res);
370
371         cpu_establish_hardintr(device_get_nameunit(child), filt, handler, arg, 
372             intr, flags, cookiep);
373         device_printf(child, "established CPU interrupt %d\n", intr);
374         return (0);
375 }
376
377 DRIVER_MODULE(cpu, root, cpu_driver, cpu_devclass, 0, 0);