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 <sys/param.h> 31#include <sys/kernel.h> 32#include <sys/module.h> 33#include <sys/stdint.h> 34 35#include <sys/bus.h> 36#include <sys/rman.h> 37#include <sys/sysctl.h> 38#include <sys/systm.h> 39 40#include <vm/vm.h> 41#include <vm/vm_page.h> 42 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> 52 53#if defined(CPU_CNMIPS) 54#include <contrib/octeon-sdk/cvmx.h> 55#include <contrib/octeon-sdk/octeon-model.h> 56#endif 57 58static void cpu_identify(void); 59 60struct mips_cpuinfo cpuinfo; 61 62/* 63 * Attempt to identify the MIPS CPU as much as possible. 64 * 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. 69 */ 70static void 71mips_get_identity(struct mips_cpuinfo *cpuinfo) 72{ 73 u_int32_t prid; 74 u_int32_t cfg0; 75 u_int32_t cfg1; 76#if defined(CPU_CNMIPS) 77 u_int32_t cfg4; 78#endif 79 u_int32_t tmp; 80 81 memset(cpuinfo, 0, sizeof(struct mips_cpuinfo)); 82 83 /* Read and store the PrID ID for CPU identification. */ 84 prid = mips_rd_prid(); 85 cpuinfo->cpu_vendor = MIPS_PRID_CID(prid); 86 cpuinfo->cpu_rev = MIPS_PRID_REV(prid); 87 cpuinfo->cpu_impl = MIPS_PRID_IMPL(prid); 88 89 /* Read config register selection 0 to learn TLB type. */ 90 cfg0 = mips_rd_config(); 91 92 cpuinfo->tlb_type = 93 ((cfg0 & MIPS_CONFIG0_MT_MASK) >> MIPS_CONFIG0_MT_SHIFT); 94 cpuinfo->icache_virtual = cfg0 & MIPS_CONFIG0_VI; 95 96 /* If config register selection 1 does not exist, exit. */ 97 if (!(cfg0 & MIPS_CONFIG_CM)) 98 return; 99 100 /* Learn TLB size and L1 cache geometry. */ 101 cfg1 = mips_rd_config1(); 102 103#if defined(CPU_NLM) 104 /* Account for Extended TLB entries in XLP */ 105 tmp = mips_rd_config6(); 106 cpuinfo->tlb_nentries = ((tmp >> 16) & 0xffff) + 1; 107#elif defined(BERI_LARGE_TLB) 108 /* Check if we support extended TLB entries and if so activate. */ 109 tmp = mips_rd_config5(); 110#define BERI_CP5_LTLB_SUPPORTED 0x1 111 if (tmp & BERI_CP5_LTLB_SUPPORTED) { 112 /* See how many extra TLB entries we have. */ 113 tmp = mips_rd_config6(); 114 cpuinfo->tlb_nentries = (tmp >> 16) + 1; 115 /* Activate the extended entries. */ 116 mips_wr_config6(tmp|0x4); 117 } else 118#endif 119#if !defined(CPU_NLM) 120 cpuinfo->tlb_nentries = 121 ((cfg1 & MIPS_CONFIG1_TLBSZ_MASK) >> MIPS_CONFIG1_TLBSZ_SHIFT) + 1; 122#endif 123#if defined(CPU_CNMIPS) 124 /* Add extended TLB size information from config4. */ 125 cfg4 = mips_rd_config4(); 126 if ((cfg4 & MIPS_CONFIG4_MMUEXTDEF) == MIPS_CONFIG4_MMUEXTDEF_MMUSIZEEXT) 127 cpuinfo->tlb_nentries += (cfg4 & MIPS_CONFIG4_MMUSIZEEXT) * 0x40; 128#endif 129 130 /* L1 instruction cache. */ 131#ifdef MIPS_DISABLE_L1_CACHE 132 cpuinfo->l1.ic_linesize = 0; 133#else 134 tmp = (cfg1 & MIPS_CONFIG1_IL_MASK) >> MIPS_CONFIG1_IL_SHIFT; 135 if (tmp != 0) { 136 cpuinfo->l1.ic_linesize = 1 << (tmp + 1); 137 cpuinfo->l1.ic_nways = (((cfg1 & MIPS_CONFIG1_IA_MASK) >> MIPS_CONFIG1_IA_SHIFT)) + 1; 138 cpuinfo->l1.ic_nsets = 139 1 << (((cfg1 & MIPS_CONFIG1_IS_MASK) >> MIPS_CONFIG1_IS_SHIFT) + 6); 140 } 141#endif 142 143 /* L1 data cache. */ 144#ifdef MIPS_DISABLE_L1_CACHE 145 cpuinfo->l1.dc_linesize = 0; 146#else 147#ifndef CPU_CNMIPS 148 tmp = (cfg1 & MIPS_CONFIG1_DL_MASK) >> MIPS_CONFIG1_DL_SHIFT; 149 if (tmp != 0) { 150 cpuinfo->l1.dc_linesize = 1 << (tmp + 1); 151 cpuinfo->l1.dc_nways = 152 (((cfg1 & MIPS_CONFIG1_DA_MASK) >> MIPS_CONFIG1_DA_SHIFT)) + 1; 153 cpuinfo->l1.dc_nsets = 154 1 << (((cfg1 & MIPS_CONFIG1_DS_MASK) >> MIPS_CONFIG1_DS_SHIFT) + 6); 155 } 156#else 157 /* 158 * Some Octeon cache configuration parameters are by model family, not 159 * config1. 160 */ 161 if (OCTEON_IS_MODEL(OCTEON_CN3XXX)) { 162 /* Octeon and Octeon XL. */ 163 cpuinfo->l1.dc_nsets = 1; 164 cpuinfo->l1.dc_nways = 64; 165 } else if (OCTEON_IS_MODEL(OCTEON_CN5XXX)) { 166 /* Octeon Plus. */ 167 cpuinfo->l1.dc_nsets = 2; 168 cpuinfo->l1.dc_nways = 64; 169 } else if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) { 170 /* Octeon II. */ 171 cpuinfo->l1.dc_nsets = 8; 172 cpuinfo->l1.dc_nways = 32; 173 174 cpuinfo->l1.ic_nsets = 8; 175 cpuinfo->l1.ic_nways = 37; 176 } else { 177 panic("%s: unsupported Cavium Networks CPU.", __func__); 178 } 179 180 /* All Octeon models use 128 byte line size. */ 181 cpuinfo->l1.dc_linesize = 128; 182#endif 183#endif 184 185 cpuinfo->l1.ic_size = cpuinfo->l1.ic_linesize 186 * cpuinfo->l1.ic_nsets * cpuinfo->l1.ic_nways; 187 cpuinfo->l1.dc_size = cpuinfo->l1.dc_linesize 188 * cpuinfo->l1.dc_nsets * cpuinfo->l1.dc_nways; 189} 190 191void 192mips_cpu_init(void) 193{ 194 platform_cpu_init(); 195 mips_get_identity(&cpuinfo); 196 num_tlbentries = cpuinfo.tlb_nentries; 197 mips_wr_wired(0); 198 tlb_invalidate_all(); 199 mips_wr_wired(VMWIRED_ENTRIES); 200 mips_config_cache(&cpuinfo); 201 mips_vector_init(); 202 203 mips_icache_sync_all(); 204 mips_dcache_wbinv_all(); 205 /* Print some info about CPU */ 206 cpu_identify(); 207} 208 209static void 210cpu_identify(void) 211{ 212 uint32_t cfg0, cfg1, cfg2, cfg3; 213 printf("cpu%d: ", 0); /* XXX per-cpu */ 214 switch (cpuinfo.cpu_vendor) { 215 case MIPS_PRID_CID_MTI: 216 printf("MIPS Technologies"); 217 break; 218 case MIPS_PRID_CID_BROADCOM: 219 case MIPS_PRID_CID_SIBYTE: 220 printf("Broadcom"); 221 break; 222 case MIPS_PRID_CID_ALCHEMY: 223 printf("AMD"); 224 break; 225 case MIPS_PRID_CID_SANDCRAFT: 226 printf("Sandcraft"); 227 break; 228 case MIPS_PRID_CID_PHILIPS: 229 printf("Philips"); 230 break; 231 case MIPS_PRID_CID_TOSHIBA: 232 printf("Toshiba"); 233 break; 234 case MIPS_PRID_CID_LSI: 235 printf("LSI"); 236 break; 237 case MIPS_PRID_CID_LEXRA: 238 printf("Lexra"); 239 break; 240 case MIPS_PRID_CID_RMI: 241 printf("RMI"); 242 break; 243 case MIPS_PRID_CID_CAVIUM: 244 printf("Cavium"); 245 break; 246 case MIPS_PRID_CID_PREHISTORIC: 247 default: 248 printf("Unknown cid %#x", cpuinfo.cpu_vendor); 249 break; 250 } 251 printf(" processor v%d.%d\n", cpuinfo.cpu_rev, cpuinfo.cpu_impl); 252 253 printf(" MMU: "); 254 if (cpuinfo.tlb_type == MIPS_MMU_NONE) { 255 printf("none present\n"); 256 } else { 257 if (cpuinfo.tlb_type == MIPS_MMU_TLB) { 258 printf("Standard TLB"); 259 } else if (cpuinfo.tlb_type == MIPS_MMU_BAT) { 260 printf("Standard BAT"); 261 } else if (cpuinfo.tlb_type == MIPS_MMU_FIXED) { 262 printf("Fixed mapping"); 263 } 264 printf(", %d entries\n", cpuinfo.tlb_nentries); 265 } 266 267 printf(" L1 i-cache: "); 268 if (cpuinfo.l1.ic_linesize == 0) { 269 printf("disabled"); 270 } else { 271 if (cpuinfo.l1.ic_nways == 1) { 272 printf("direct-mapped with"); 273 } else { 274 printf ("%d ways of", cpuinfo.l1.ic_nways); 275 } 276 printf(" %d sets, %d bytes per line\n", 277 cpuinfo.l1.ic_nsets, cpuinfo.l1.ic_linesize); 278 } 279 280 printf(" L1 d-cache: "); 281 if (cpuinfo.l1.dc_linesize == 0) { 282 printf("disabled"); 283 } else { 284 if (cpuinfo.l1.dc_nways == 1) { 285 printf("direct-mapped with"); 286 } else { 287 printf ("%d ways of", cpuinfo.l1.dc_nways); 288 } 289 printf(" %d sets, %d bytes per line\n", 290 cpuinfo.l1.dc_nsets, cpuinfo.l1.dc_linesize); 291 } 292 293 cfg0 = mips_rd_config(); 294 /* If config register selection 1 does not exist, exit. */ 295 if (!(cfg0 & MIPS_CONFIG_CM)) 296 return; 297 298 cfg1 = mips_rd_config1(); 299 printf(" Config1=0x%b\n", cfg1, 300 "\20\7COP2\6MDMX\5PerfCount\4WatchRegs\3MIPS16\2EJTAG\1FPU"); 301 302 /* If config register selection 2 does not exist, exit. */ 303 if (!(cfg1 & MIPS_CONFIG_CM)) 304 return; 305 cfg2 = mips_rd_config2(); 306 /* 307 * Config2 contains no useful information other then Config3 308 * existence flag 309 */ 310 311 /* If config register selection 3 does not exist, exit. */ 312 if (!(cfg2 & MIPS_CONFIG_CM)) 313 return; 314 cfg3 = mips_rd_config3(); 315 316 /* Print Config3 if it contains any useful info */ 317 if (cfg3 & ~(0x80000000)) 318 printf(" Config3=0x%b\n", cfg3, "\20\2SmartMIPS\1TraceLogic"); 319} 320 321static struct rman cpu_hardirq_rman; 322 323static devclass_t cpu_devclass; 324 325/* 326 * Device methods 327 */ 328static int cpu_probe(device_t); 329static int cpu_attach(device_t); 330static struct resource *cpu_alloc_resource(device_t, device_t, int, int *, 331 u_long, u_long, u_long, u_int); 332static int cpu_setup_intr(device_t, device_t, struct resource *, int, 333 driver_filter_t *f, driver_intr_t *, void *, 334 void **); 335 336static device_method_t cpu_methods[] = { 337 /* Device interface */ 338 DEVMETHOD(device_probe, cpu_probe), 339 DEVMETHOD(device_attach, cpu_attach), 340 DEVMETHOD(device_detach, bus_generic_detach), 341 DEVMETHOD(device_shutdown, bus_generic_shutdown), 342 343 /* Bus interface */ 344 DEVMETHOD(bus_alloc_resource, cpu_alloc_resource), 345 DEVMETHOD(bus_setup_intr, cpu_setup_intr), 346 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 347 348 { 0, 0 } 349}; 350 351static driver_t cpu_driver = { 352 "cpu", cpu_methods, 1 353}; 354 355static int 356cpu_probe(device_t dev) 357{ 358 return (0); 359} 360 361static int 362cpu_attach(device_t dev) 363{ 364 int error; 365#ifdef notyet 366 device_t clock; 367#endif 368 369 cpu_hardirq_rman.rm_start = 0; 370 cpu_hardirq_rman.rm_end = 5; 371 cpu_hardirq_rman.rm_type = RMAN_ARRAY; 372 cpu_hardirq_rman.rm_descr = "CPU Hard Interrupts"; 373 374 error = rman_init(&cpu_hardirq_rman); 375 if (error != 0) { 376 device_printf(dev, "failed to initialize irq resources\n"); 377 return (error); 378 } 379 /* XXX rman_manage_all. */ 380 error = rman_manage_region(&cpu_hardirq_rman, 381 cpu_hardirq_rman.rm_start, 382 cpu_hardirq_rman.rm_end); 383 if (error != 0) { 384 device_printf(dev, "failed to manage irq resources\n"); 385 return (error); 386 } 387 388 if (device_get_unit(dev) != 0) 389 panic("can't attach more cpus"); 390 device_set_desc(dev, "MIPS32 processor"); 391 392#ifdef notyet 393 clock = device_add_child(dev, "clock", device_get_unit(dev)); 394 if (clock == NULL) 395 device_printf(dev, "clock failed to attach"); 396#endif 397 398 return (bus_generic_attach(dev)); 399} 400 401static struct resource * 402cpu_alloc_resource(device_t dev, device_t child, int type, int *rid, 403 u_long start, u_long end, u_long count, u_int flags) 404{ 405 struct resource *res; 406 407 if (type != SYS_RES_IRQ) 408 return (NULL); 409 res = rman_reserve_resource(&cpu_hardirq_rman, start, end, count, 0, 410 child); 411 return (res); 412} 413 414static int 415cpu_setup_intr(device_t dev, device_t child, struct resource *res, int flags, 416 driver_filter_t *filt, driver_intr_t *handler, void *arg, 417 void **cookiep) 418{ 419 int error; 420 int intr; 421 422 error = rman_activate_resource(res); 423 if (error != 0) { 424 device_printf(child, "could not activate irq\n"); 425 return (error); 426 } 427 428 intr = rman_get_start(res); 429 430 cpu_establish_hardintr(device_get_nameunit(child), filt, handler, arg, 431 intr, flags, cookiep); 432 device_printf(child, "established CPU interrupt %d\n", intr); 433 return (0); 434} 435 436DRIVER_MODULE(cpu, root, cpu_driver, cpu_devclass, 0, 0); 437