]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/mips/mips/cpu.c
add -n option to suppress clearing the build tree and add -DNO_CLEAN
[FreeBSD/FreeBSD.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  * $FreeBSD$
26  */
27
28 #include <sys/param.h>
29 #include <sys/kernel.h>
30 #include <sys/module.h>
31 #include <sys/stdint.h>
32
33 #include <sys/bus.h>
34 #include <sys/rman.h>
35 #include <sys/sysctl.h>
36 #include <sys/systm.h>
37
38 #include <vm/vm.h>
39 #include <vm/vm_page.h>
40
41 #include <machine/cache.h>
42 #include <machine/cpufunc.h>
43 #include <machine/cpuinfo.h>
44 #include <machine/cpuregs.h>
45 #include <machine/intr_machdep.h>
46 #include <machine/locore.h>
47 #include <machine/pte.h>
48
49 static struct mips_cpuinfo cpuinfo;
50
51 union   cpuprid cpu_id;
52 union   cpuprid fpu_id;
53
54 /*
55  * Attempt to identify the MIPS CPU as much as possible.
56  *
57  * XXX: Assumes the CPU is MIPS32 compliant.
58  * XXX: For now, skip config register selections 2 and 3
59  * as we don't currently use L2/L3 cache or additional
60  * MIPS32 processor features.
61  */
62 static void
63 mips_get_identity(struct mips_cpuinfo *cpuinfo)
64 {
65     u_int32_t prid;
66     u_int32_t cfg0;
67     u_int32_t cfg1;
68     u_int32_t tmp;
69
70     memset(cpuinfo, 0, sizeof(struct mips_cpuinfo));
71
72     /* Read and store the PrID ID for CPU identification. */
73     prid = mips_rd_prid();
74     cpuinfo->cpu_vendor = MIPS_PRID_CID(prid);
75     cpuinfo->cpu_rev = MIPS_PRID_REV(prid);
76     cpuinfo->cpu_impl = MIPS_PRID_IMPL(prid);
77
78     /* Read config register selection 0 to learn TLB type. */
79     cfg0 = mips_rd_config();
80
81     cpuinfo->tlb_type = ((cfg0 & MIPS_CONFIG0_MT_MASK) >> MIPS_CONFIG0_MT_SHIFT);
82     cpuinfo->icache_virtual = cfg0 & MIPS_CONFIG0_VI;
83
84     /* If config register selection 1 does not exist, exit. */
85     if (!(cfg0 & MIPS3_CONFIG_CM))
86         return;
87
88     /* Learn TLB size and L1 cache geometry. */
89     cfg1 = mips_rd_config_sel1();
90     cpuinfo->tlb_nentries = ((cfg1 & MIPS_CONFIG1_TLBSZ_MASK) >> MIPS_CONFIG1_TLBSZ_SHIFT) + 1;
91
92     /* L1 instruction cache. */
93     tmp = 1 << (((cfg1 & MIPS_CONFIG1_IL_MASK) >> MIPS_CONFIG1_IL_SHIFT) + 1);
94     if (tmp != 0) {
95         cpuinfo->l1.ic_linesize = tmp;
96         cpuinfo->l1.ic_nways = (((cfg1 & MIPS_CONFIG1_IA_MASK) >> MIPS_CONFIG1_IA_SHIFT)) + 1;
97         cpuinfo->l1.ic_nsets = 1 << (((cfg1 & MIPS_CONFIG1_IS_MASK) >> MIPS_CONFIG1_IS_SHIFT) + 6);
98         cpuinfo->l1.ic_size = cpuinfo->l1.ic_linesize * cpuinfo->l1.ic_nsets 
99             * cpuinfo->l1.ic_nways;
100     }
101
102     /* L1 data cache. */
103     tmp = 1 << (((cfg1 & MIPS_CONFIG1_DL_MASK) >> MIPS_CONFIG1_DL_SHIFT) + 1);
104     if (tmp != 0) {
105         cpuinfo->l1.dc_linesize = tmp;
106         cpuinfo->l1.dc_nways = (((cfg1 & MIPS_CONFIG1_DA_MASK) >> MIPS_CONFIG1_DA_SHIFT)) + 1;
107         cpuinfo->l1.dc_nsets = 1 << (((cfg1 & MIPS_CONFIG1_DS_MASK) >> MIPS_CONFIG1_DS_SHIFT) + 6);
108 #ifdef TARGET_OCTEON
109         /*
110          * Octeon does 128 byte line-size. But Config-Sel1 doesn't show
111          * 128 line-size, 1 Set, 64 ways.
112          */
113         cpuinfo->l1.dc_linesize = 128;
114         cpuinfo->l1.dc_nsets = 1;
115         cpuinfo->l1.dc_nways = 64;
116 #endif
117         cpuinfo->l1.dc_size = cpuinfo->l1.dc_linesize * cpuinfo->l1.dc_nsets 
118             * cpuinfo->l1.dc_nways;
119     }
120 }
121
122 void
123 mips_cpu_init(void)
124 {
125         mips_get_identity(&cpuinfo);
126         num_tlbentries = cpuinfo.tlb_nentries;
127         Mips_SetWIRED(0);
128         Mips_TLBFlush(num_tlbentries);
129         Mips_SetWIRED(VMWIRED_ENTRIES);
130         mips_config_cache(&cpuinfo);
131         mips_vector_init();
132
133         mips_icache_sync_all();
134         mips_dcache_wbinv_all();
135 }
136
137 void
138 cpu_identify(void)
139 {
140     printf("cpu%d: ", 0);   /* XXX per-cpu */
141     switch (cpuinfo.cpu_vendor) {
142     case MIPS_PRID_CID_MTI:
143         printf("MIPS Technologies");
144         break;
145     case MIPS_PRID_CID_BROADCOM:
146     case MIPS_PRID_CID_SIBYTE:
147         printf("Broadcom");
148         break;
149     case MIPS_PRID_CID_ALCHEMY:
150         printf("AMD");
151         break;
152     case MIPS_PRID_CID_SANDCRAFT:
153         printf("Sandcraft");
154         break;
155     case MIPS_PRID_CID_PHILIPS:
156         printf("Philips");
157         break;
158     case MIPS_PRID_CID_TOSHIBA:
159         printf("Toshiba");
160         break;
161     case MIPS_PRID_CID_LSI:
162         printf("LSI");
163         break;
164     case MIPS_PRID_CID_LEXRA:
165         printf("Lexra");
166         break;
167     case MIPS_PRID_CID_PREHISTORIC:
168     default:
169         printf("Unknown");
170         break;
171     }
172     printf(" processor v%d.%d\n", cpuinfo.cpu_rev, cpuinfo.cpu_impl);
173
174     printf("  MMU: ");
175     if (cpuinfo.tlb_type == MIPS_MMU_NONE) {
176         printf("none present\n");
177     } else {
178         if (cpuinfo.tlb_type == MIPS_MMU_TLB) {
179             printf("Standard TLB");
180         } else if (cpuinfo.tlb_type == MIPS_MMU_BAT) {
181             printf("Standard BAT");
182         } else if (cpuinfo.tlb_type == MIPS_MMU_FIXED) {
183             printf("Fixed mapping");
184         }
185         printf(", %d entries\n", cpuinfo.tlb_nentries);
186     }
187
188     printf("  L1 i-cache: ");
189     if (cpuinfo.l1.ic_linesize == 0) {
190         printf("disabled");
191     } else {
192         if (cpuinfo.l1.ic_nways == 1) {
193             printf("direct-mapped with");
194         } else {
195             printf ("%d ways of", cpuinfo.l1.ic_nways);
196         }
197         printf(" %d sets, %d bytes per line\n", cpuinfo.l1.ic_nsets, cpuinfo.l1.ic_linesize);
198     }
199
200     printf("  L1 d-cache: ");
201     if (cpuinfo.l1.dc_linesize == 0) {
202         printf("disabled");
203     } else {
204         if (cpuinfo.l1.dc_nways == 1) {
205             printf("direct-mapped with");
206         } else {
207             printf ("%d ways of", cpuinfo.l1.dc_nways);
208         }
209         printf(" %d sets, %d bytes per line\n", cpuinfo.l1.dc_nsets, cpuinfo.l1.dc_linesize);
210     }
211 }
212
213 static struct rman cpu_hardirq_rman;
214
215 static devclass_t cpu_devclass;
216
217 /*
218  * Device methods
219  */
220 static int cpu_probe(device_t);
221 static int cpu_attach(device_t);
222 static struct resource *cpu_alloc_resource(device_t, device_t, int, int *,
223                                            u_long, u_long, u_long, u_int);
224 static int cpu_setup_intr(device_t, device_t, struct resource *, int,
225                           driver_filter_t *f, driver_intr_t *, void *, 
226                           void **);
227
228 static device_method_t cpu_methods[] = {
229         /* Device interface */
230         DEVMETHOD(device_probe,         cpu_probe),
231         DEVMETHOD(device_attach,        cpu_attach),
232         DEVMETHOD(device_detach,        bus_generic_detach),
233         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
234
235         /* Bus interface */
236         DEVMETHOD(bus_alloc_resource,   cpu_alloc_resource),
237         DEVMETHOD(bus_setup_intr,       cpu_setup_intr),
238         DEVMETHOD(bus_teardown_intr,    bus_generic_teardown_intr),
239
240         { 0, 0 }
241 };
242
243 static driver_t cpu_driver = {
244         "cpu", cpu_methods, 1
245 };
246
247 static int
248 cpu_probe(device_t dev)
249 {
250         return (0);
251 }
252
253 static int
254 cpu_attach(device_t dev)
255 {
256         int error;
257 #ifdef notyet
258         device_t clock;
259 #endif
260
261         cpu_hardirq_rman.rm_start = 0;
262         cpu_hardirq_rman.rm_end = 5;
263         cpu_hardirq_rman.rm_type = RMAN_ARRAY;
264         cpu_hardirq_rman.rm_descr = "CPU Hard Interrupts";
265
266         error = rman_init(&cpu_hardirq_rman);
267         if (error != 0) {
268                 device_printf(dev, "failed to initialize irq resources\n");
269                 return (error);
270         }
271         /* XXX rman_manage_all. */
272         error = rman_manage_region(&cpu_hardirq_rman,
273                                    cpu_hardirq_rman.rm_start,
274                                    cpu_hardirq_rman.rm_end);
275         if (error != 0) {
276                 device_printf(dev, "failed to manage irq resources\n");
277                 return (error);
278         }
279
280         if (device_get_unit(dev) != 0)
281                 panic("can't attach more cpus");
282         device_set_desc(dev, "MIPS32 processor");
283
284 #ifdef notyet
285         clock = device_add_child(dev, "clock", device_get_unit(dev));
286         if (clock == NULL)
287                 device_printf(dev, "clock failed to attach");
288 #endif
289
290         return (bus_generic_attach(dev));
291 }
292
293 static struct resource *
294 cpu_alloc_resource(device_t dev, device_t child, int type, int *rid,
295                    u_long start, u_long end, u_long count, u_int flags)
296 {
297         struct resource *res;
298
299         if (type != SYS_RES_IRQ)
300                 return (NULL);
301         res = rman_reserve_resource(&cpu_hardirq_rman, start, end, count, 0,
302                                     child);
303         return (res);
304 }
305
306 static int
307 cpu_setup_intr(device_t dev, device_t child, struct resource *res, int flags,
308                driver_filter_t *filt, driver_intr_t *handler, void *arg, 
309                void **cookiep)
310 {
311         int error;
312         int intr;
313
314         error = rman_activate_resource(res);
315         if (error != 0) {
316                 device_printf(child, "could not activate irq\n");
317                 return (error);
318         }
319
320         intr = rman_get_start(res);
321
322         cpu_establish_hardintr(device_get_nameunit(child), filt, handler, arg, 
323             intr, flags, cookiep);
324         device_printf(child, "established CPU interrupt %d\n", intr);
325         return (0);
326 }
327
328 DRIVER_MODULE(cpu, root, cpu_driver, cpu_devclass, 0, 0);