2 * Copyright (c) 2004 Juli Mallett. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/param.h>
31 #include <sys/kernel.h>
32 #include <sys/module.h>
33 #include <sys/stdint.h>
37 #include <sys/sysctl.h>
38 #include <sys/systm.h>
41 #include <vm/vm_page.h>
43 #include <machine/cache.h>
44 #include <machine/cpufunc.h>
45 #include <machine/cpuinfo.h>
46 #include <machine/cpuregs.h>
47 #include <machine/intr_machdep.h>
48 #include <machine/locore.h>
49 #include <machine/pte.h>
50 #include <machine/tlb.h>
51 #include <machine/hwfunc.h>
53 #if defined(CPU_CNMIPS)
54 #include <contrib/octeon-sdk/cvmx.h>
55 #include <contrib/octeon-sdk/octeon-model.h>
58 static void cpu_identify(void);
60 struct mips_cpuinfo cpuinfo;
63 * Attempt to identify the MIPS CPU as much as possible.
65 * XXX: Assumes the CPU is MIPS{32,64}{,r2} compliant.
66 * XXX: For now, skip config register selections 2 and 3
67 * as we don't currently use L2/L3 cache or additional
68 * MIPS32 processor features.
71 mips_get_identity(struct mips_cpuinfo *cpuinfo)
77 #if defined(CPU_CNMIPS)
82 memset(cpuinfo, 0, sizeof(struct mips_cpuinfo));
84 /* Read and store the PrID ID for CPU identification. */
85 prid = mips_rd_prid();
86 cpuinfo->cpu_vendor = MIPS_PRID_CID(prid);
87 cpuinfo->cpu_rev = MIPS_PRID_REV(prid);
88 cpuinfo->cpu_impl = MIPS_PRID_IMPL(prid);
90 /* Read config register selection 0 to learn TLB type. */
91 cfg0 = mips_rd_config();
94 ((cfg0 & MIPS_CONFIG0_MT_MASK) >> MIPS_CONFIG0_MT_SHIFT);
95 cpuinfo->icache_virtual = cfg0 & MIPS_CONFIG0_VI;
97 /* If config register selection 1 does not exist, exit. */
98 if (!(cfg0 & MIPS_CONFIG_CM))
101 /* Learn TLB size and L1 cache geometry. */
102 cfg1 = mips_rd_config1();
105 /* Account for Extended TLB entries in XLP */
106 tmp = mips_rd_config6();
107 cpuinfo->tlb_nentries = ((tmp >> 16) & 0xffff) + 1;
108 #elif defined(BERI_LARGE_TLB)
109 /* Check if we support extended TLB entries and if so activate. */
110 tmp = mips_rd_config5();
111 #define BERI_CP5_LTLB_SUPPORTED 0x1
112 if (tmp & BERI_CP5_LTLB_SUPPORTED) {
113 /* See how many extra TLB entries we have. */
114 tmp = mips_rd_config6();
115 cpuinfo->tlb_nentries = (tmp >> 16) + 1;
116 /* Activate the extended entries. */
117 mips_wr_config6(tmp|0x4);
120 #if !defined(CPU_NLM)
121 cpuinfo->tlb_nentries =
122 ((cfg1 & MIPS_CONFIG1_TLBSZ_MASK) >> MIPS_CONFIG1_TLBSZ_SHIFT) + 1;
124 #if defined(CPU_CNMIPS)
125 /* Add extended TLB size information from config4. */
126 cfg4 = mips_rd_config4();
127 if ((cfg4 & MIPS_CONFIG4_MMUEXTDEF) == MIPS_CONFIG4_MMUEXTDEF_MMUSIZEEXT)
128 cpuinfo->tlb_nentries += (cfg4 & MIPS_CONFIG4_MMUSIZEEXT) * 0x40;
131 /* L1 instruction cache. */
132 #ifdef MIPS_DISABLE_L1_CACHE
133 cpuinfo->l1.ic_linesize = 0;
135 tmp = (cfg1 & MIPS_CONFIG1_IL_MASK) >> MIPS_CONFIG1_IL_SHIFT;
137 cpuinfo->l1.ic_linesize = 1 << (tmp + 1);
138 cpuinfo->l1.ic_nways = (((cfg1 & MIPS_CONFIG1_IA_MASK) >> MIPS_CONFIG1_IA_SHIFT)) + 1;
139 cpuinfo->l1.ic_nsets =
140 1 << (((cfg1 & MIPS_CONFIG1_IS_MASK) >> MIPS_CONFIG1_IS_SHIFT) + 6);
145 #ifdef MIPS_DISABLE_L1_CACHE
146 cpuinfo->l1.dc_linesize = 0;
149 tmp = (cfg1 & MIPS_CONFIG1_DL_MASK) >> MIPS_CONFIG1_DL_SHIFT;
151 cpuinfo->l1.dc_linesize = 1 << (tmp + 1);
152 cpuinfo->l1.dc_nways =
153 (((cfg1 & MIPS_CONFIG1_DA_MASK) >> MIPS_CONFIG1_DA_SHIFT)) + 1;
154 cpuinfo->l1.dc_nsets =
155 1 << (((cfg1 & MIPS_CONFIG1_DS_MASK) >> MIPS_CONFIG1_DS_SHIFT) + 6);
159 * Some Octeon cache configuration parameters are by model family, not
162 if (OCTEON_IS_MODEL(OCTEON_CN3XXX)) {
163 /* Octeon and Octeon XL. */
164 cpuinfo->l1.dc_nsets = 1;
165 cpuinfo->l1.dc_nways = 64;
166 } else if (OCTEON_IS_MODEL(OCTEON_CN5XXX)) {
168 cpuinfo->l1.dc_nsets = 2;
169 cpuinfo->l1.dc_nways = 64;
170 } else if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) {
172 cpuinfo->l1.dc_nsets = 8;
173 cpuinfo->l1.dc_nways = 32;
175 cpuinfo->l1.ic_nsets = 8;
176 cpuinfo->l1.ic_nways = 37;
178 panic("%s: unsupported Cavium Networks CPU.", __func__);
181 /* All Octeon models use 128 byte line size. */
182 cpuinfo->l1.dc_linesize = 128;
186 cpuinfo->l1.ic_size = cpuinfo->l1.ic_linesize
187 * cpuinfo->l1.ic_nsets * cpuinfo->l1.ic_nways;
188 cpuinfo->l1.dc_size = cpuinfo->l1.dc_linesize
189 * cpuinfo->l1.dc_nsets * cpuinfo->l1.dc_nways;
193 if (!(cfg1 & MIPS_CONFIG_CM)) {
194 /* We don't have valid cfg2 register */
198 cfg2 = mips_rd_config2();
200 tmp = (cfg2 >> MIPS_CONFIG2_SL_SHIFT) & MIPS_CONFIG2_SL_MASK;
201 if (0 < tmp && tmp <= 7)
202 cpuinfo->l2.dc_linesize = 2 << tmp;
204 tmp = (cfg2 >> MIPS_CONFIG2_SS_SHIFT) & MIPS_CONFIG2_SS_MASK;
205 if (0 <= tmp && tmp <= 7)
206 cpuinfo->l2.dc_nsets = 64 << tmp;
208 tmp = (cfg2 >> MIPS_CONFIG2_SA_SHIFT) & MIPS_CONFIG2_SA_MASK;
209 if (0 <= tmp && tmp <= 7)
210 cpuinfo->l2.dc_nways = tmp + 1;
212 cpuinfo->l2.dc_size = cpuinfo->l2.dc_linesize
213 * cpuinfo->l2.dc_nsets * cpuinfo->l2.dc_nways;
221 mips_get_identity(&cpuinfo);
222 num_tlbentries = cpuinfo.tlb_nentries;
224 tlb_invalidate_all();
225 mips_wr_wired(VMWIRED_ENTRIES);
226 mips_config_cache(&cpuinfo);
229 mips_icache_sync_all();
230 mips_dcache_wbinv_all();
231 /* Print some info about CPU */
238 uint32_t cfg0, cfg1, cfg2, cfg3;
239 printf("cpu%d: ", 0); /* XXX per-cpu */
240 switch (cpuinfo.cpu_vendor) {
241 case MIPS_PRID_CID_MTI:
242 printf("MIPS Technologies");
244 case MIPS_PRID_CID_BROADCOM:
245 case MIPS_PRID_CID_SIBYTE:
248 case MIPS_PRID_CID_ALCHEMY:
251 case MIPS_PRID_CID_SANDCRAFT:
254 case MIPS_PRID_CID_PHILIPS:
257 case MIPS_PRID_CID_TOSHIBA:
260 case MIPS_PRID_CID_LSI:
263 case MIPS_PRID_CID_LEXRA:
266 case MIPS_PRID_CID_RMI:
269 case MIPS_PRID_CID_CAVIUM:
272 case MIPS_PRID_CID_PREHISTORIC:
274 printf("Unknown cid %#x", cpuinfo.cpu_vendor);
277 printf(" processor v%d.%d\n", cpuinfo.cpu_rev, cpuinfo.cpu_impl);
280 if (cpuinfo.tlb_type == MIPS_MMU_NONE) {
281 printf("none present\n");
283 if (cpuinfo.tlb_type == MIPS_MMU_TLB) {
284 printf("Standard TLB");
285 } else if (cpuinfo.tlb_type == MIPS_MMU_BAT) {
286 printf("Standard BAT");
287 } else if (cpuinfo.tlb_type == MIPS_MMU_FIXED) {
288 printf("Fixed mapping");
290 printf(", %d entries\n", cpuinfo.tlb_nentries);
293 printf(" L1 i-cache: ");
294 if (cpuinfo.l1.ic_linesize == 0) {
297 if (cpuinfo.l1.ic_nways == 1) {
298 printf("direct-mapped with");
300 printf ("%d ways of", cpuinfo.l1.ic_nways);
302 printf(" %d sets, %d bytes per line\n",
303 cpuinfo.l1.ic_nsets, cpuinfo.l1.ic_linesize);
306 printf(" L1 d-cache: ");
307 if (cpuinfo.l1.dc_linesize == 0) {
310 if (cpuinfo.l1.dc_nways == 1) {
311 printf("direct-mapped with");
313 printf ("%d ways of", cpuinfo.l1.dc_nways);
315 printf(" %d sets, %d bytes per line\n",
316 cpuinfo.l1.dc_nsets, cpuinfo.l1.dc_linesize);
319 cfg0 = mips_rd_config();
320 /* If config register selection 1 does not exist, exit. */
321 if (!(cfg0 & MIPS_CONFIG_CM))
324 cfg1 = mips_rd_config1();
325 printf(" Config1=0x%b\n", cfg1,
326 "\20\7COP2\6MDMX\5PerfCount\4WatchRegs\3MIPS16\2EJTAG\1FPU");
328 /* If config register selection 2 does not exist, exit. */
329 if (!(cfg1 & MIPS_CONFIG_CM))
331 cfg2 = mips_rd_config2();
333 * Config2 contains no useful information other then Config3
337 /* If config register selection 3 does not exist, exit. */
338 if (!(cfg2 & MIPS_CONFIG_CM))
340 cfg3 = mips_rd_config3();
342 /* Print Config3 if it contains any useful info */
343 if (cfg3 & ~(0x80000000))
344 printf(" Config3=0x%b\n", cfg3, "\20\2SmartMIPS\1TraceLogic");
347 static struct rman cpu_hardirq_rman;
349 static devclass_t cpu_devclass;
354 static int cpu_probe(device_t);
355 static int cpu_attach(device_t);
356 static struct resource *cpu_alloc_resource(device_t, device_t, int, int *,
357 u_long, u_long, u_long, u_int);
358 static int cpu_setup_intr(device_t, device_t, struct resource *, int,
359 driver_filter_t *f, driver_intr_t *, void *,
362 static device_method_t cpu_methods[] = {
363 /* Device interface */
364 DEVMETHOD(device_probe, cpu_probe),
365 DEVMETHOD(device_attach, cpu_attach),
366 DEVMETHOD(device_detach, bus_generic_detach),
367 DEVMETHOD(device_shutdown, bus_generic_shutdown),
370 DEVMETHOD(bus_alloc_resource, cpu_alloc_resource),
371 DEVMETHOD(bus_setup_intr, cpu_setup_intr),
372 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
377 static driver_t cpu_driver = {
378 "cpu", cpu_methods, 1
382 cpu_probe(device_t dev)
389 cpu_attach(device_t dev)
396 cpu_hardirq_rman.rm_start = 0;
397 cpu_hardirq_rman.rm_end = 5;
398 cpu_hardirq_rman.rm_type = RMAN_ARRAY;
399 cpu_hardirq_rman.rm_descr = "CPU Hard Interrupts";
401 error = rman_init(&cpu_hardirq_rman);
403 device_printf(dev, "failed to initialize irq resources\n");
406 /* XXX rman_manage_all. */
407 error = rman_manage_region(&cpu_hardirq_rman,
408 cpu_hardirq_rman.rm_start,
409 cpu_hardirq_rman.rm_end);
411 device_printf(dev, "failed to manage irq resources\n");
415 if (device_get_unit(dev) != 0)
416 panic("can't attach more cpus");
417 device_set_desc(dev, "MIPS32 processor");
420 clock = device_add_child(dev, "clock", device_get_unit(dev));
422 device_printf(dev, "clock failed to attach");
425 return (bus_generic_attach(dev));
428 static struct resource *
429 cpu_alloc_resource(device_t dev, device_t child, int type, int *rid,
430 u_long start, u_long end, u_long count, u_int flags)
432 struct resource *res;
434 if (type != SYS_RES_IRQ)
436 res = rman_reserve_resource(&cpu_hardirq_rman, start, end, count, 0,
442 cpu_setup_intr(device_t dev, device_t child, struct resource *res, int flags,
443 driver_filter_t *filt, driver_intr_t *handler, void *arg,
449 error = rman_activate_resource(res);
451 device_printf(child, "could not activate irq\n");
455 intr = rman_get_start(res);
457 cpu_establish_hardintr(device_get_nameunit(child), filt, handler, arg,
458 intr, flags, cookiep);
459 device_printf(child, "established CPU interrupt %d\n", intr);
463 DRIVER_MODULE(cpu, root, cpu_driver, cpu_devclass, 0, 0);