1 /* $NetBSD: bcu_vrip.c,v 1.29 2009/03/18 10:22:29 cegger Exp $ */ 2 3 /*- 4 * Copyright (c) 1999-2001 SATO Kazumi. All rights reserved. 5 * Copyright (c) 1999, 2002 PocketBSD Project. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the PocketBSD project 18 * and its contributors. 19 * 4. Neither the name of the project nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 */ 36 37 #include <sys/cdefs.h> 38 __KERNEL_RCSID(0, "$NetBSD: bcu_vrip.c,v 1.29 2009/03/18 10:22:29 cegger Exp $"); 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/device.h> 43 #include <sys/reboot.h> 44 45 #include <machine/bus.h> 46 #include <machine/debug.h> 47 #include <machine/platid.h> 48 #include <machine/platid_mask.h> 49 50 #include <mips/cpuregs.h> 51 52 #include "opt_vr41xx.h" 53 #include <hpcmips/vr/vr.h> 54 #include <hpcmips/vr/vrcpudef.h> 55 #include <hpcmips/vr/vripif.h> 56 #include <hpcmips/vr/vripvar.h> 57 #include <hpcmips/vr/vripreg.h> 58 #include <hpcmips/vr/bcureg.h> 59 #include <hpcmips/vr/bcuvar.h> 60 61 static int vrbcu_match(struct device *, struct cfdata *, void *); 62 static void vrbcu_attach(struct device *, struct device *, void *); 63 64 static void vrbcu_write(struct vrbcu_softc *, int, unsigned short); 65 static unsigned short vrbcu_read(struct vrbcu_softc *, int); 66 67 static void vrbcu_dump_regs(void); 68 69 const char *vr_cpuname=NULL; 70 int vr_major=-1; 71 int vr_minor=-1; 72 int vr_cpuid=-1; 73 74 CFATTACH_DECL(vrbcu, sizeof(struct vrbcu_softc), 75 vrbcu_match, vrbcu_attach, NULL, NULL); 76 77 struct vrbcu_softc *the_bcu_sc = NULL; 78 79 #ifdef SINGLE_VRIP_BASE 80 #define vrbcu_addr() VRIP_BCU_ADDR 81 #else 82 static bus_addr_t vrbcu_addr(void); 83 static bus_addr_t 84 vrbcu_addr(void) 85 { 86 static bus_addr_t addr = 0; 87 static struct platid_data addrs[] = { 88 { &platid_mask_CPU_MIPS_VR_4102, (void *)VR4102_BCU_ADDR }, 89 { &platid_mask_CPU_MIPS_VR_4111, (void *)VR4102_BCU_ADDR }, 90 { &platid_mask_CPU_MIPS_VR_4121, (void *)VR4102_BCU_ADDR }, 91 { &platid_mask_CPU_MIPS_VR_4122, (void *)VR4122_BCU_ADDR }, 92 { &platid_mask_CPU_MIPS_VR_4131, (void *)VR4122_BCU_ADDR }, 93 { &platid_mask_CPU_MIPS_VR_4181, (void *)VR4181_BCU_ADDR }, 94 { NULL, NULL } /* terminator, don't delete */ 95 }; 96 struct platid_data *p; 97 98 if (addr == 0) { 99 if ((p = platid_search_data(&platid, addrs)) == NULL) 100 panic("%s: can't find VR BCU address", __func__); 101 addr = (bus_addr_t)p->data; 102 } 103 104 return (addr); 105 } 106 #endif /* SINGLE_VRIP_BASE */ 107 108 static inline void 109 vrbcu_write(struct vrbcu_softc *sc, int port, unsigned short val) 110 { 111 112 bus_space_write_2(sc->sc_iot, sc->sc_ioh, port, val); 113 } 114 115 static inline unsigned short 116 vrbcu_read(struct vrbcu_softc *sc, int port) 117 { 118 119 return (bus_space_read_2(sc->sc_iot, sc->sc_ioh, port)); 120 } 121 122 static int 123 vrbcu_match(struct device *parent, struct cfdata *cf, void *aux) 124 { 125 126 return (2); 127 } 128 129 static void 130 vrbcu_attach(struct device *parent, struct device *self, void *aux) 131 { 132 struct vrip_attach_args *va = aux; 133 struct vrbcu_softc *sc = (struct vrbcu_softc *)self; 134 135 sc->sc_iot = va->va_iot; 136 bus_space_map(sc->sc_iot, va->va_addr, va->va_size, 137 0, /* no flags */ 138 &sc->sc_ioh); 139 140 printf("\n"); 141 the_bcu_sc = sc; 142 vrbcu_dump_regs(); 143 } 144 145 static void 146 vrbcu_dump_regs(void) 147 { 148 struct vrbcu_softc *sc = the_bcu_sc; 149 int cpuclock = 0, tclock = 0, vtclock = 0, cpuid; 150 #if !defined(ONLY_VR4102) 151 int spdreg = 0; /* XXX gcc doesn't stand a chance of tracking this! */ 152 #endif 153 #ifdef VRBCUDEBUG 154 int reg; 155 #endif /* VRBCUDEBUG */ 156 157 cpuid = vrbcu_vrip_getcpuid(); 158 #if !defined(ONLY_VR4181) && !defined(ONLY_VR4102) 159 if (cpuid != BCUREVID_FIXRID_4181 160 && cpuid <= BCUREVID_RID_4131 161 && cpuid >= BCUREVID_RID_4111) { 162 spdreg = vrbcu_read(sc, BCUCLKSPEED_REG_W); 163 #ifdef VRBCUDEBUG 164 printf("vrbcu: CLKSPEED %x: \n", spdreg); 165 #endif /* VRBCUDEBUG */ 166 } 167 #endif 168 #if defined VR4181 169 if (cpuid == BCUREVID_FIXRID_4181){ 170 spdreg = vrbcu_read(sc, BCU81CLKSPEED_REG_W); 171 #ifdef VRBCUDEBUG 172 printf("vrbcu: CLKSPEED %x: \n", spdreg); 173 #endif /* VRBCUDEBUG */ 174 } 175 #endif 176 177 cpuclock = vrbcu_vrip_getcpuclock(); 178 179 switch (cpuid) { 180 #if defined VR4181 181 case BCUREVID_FIXRID_4181: 182 switch ((spdreg & BCU81CLKSPEED_DIVTMASK) >> 183 BCU81CLKSPEED_DIVTSHFT){ 184 case BCU81CLKSPEED_DIVT1: 185 vtclock = tclock = cpuclock; 186 break; 187 case BCU81CLKSPEED_DIVT2: 188 vtclock = tclock = cpuclock/2; 189 break; 190 case BCU81CLKSPEED_DIVT3: 191 vtclock = tclock = cpuclock/3; 192 break; 193 case BCU81CLKSPEED_DIVT4: 194 vtclock = tclock = cpuclock/4; 195 break; 196 default: 197 vtclock = tclock = 0; 198 } 199 break; 200 #endif /* VR4181 */ 201 case BCUREVID_RID_4101: 202 case BCUREVID_RID_4102: 203 vtclock = tclock = cpuclock/2; 204 break; 205 #if defined VR4111 206 case BCUREVID_RID_4111: 207 if ((spdreg&BCUCLKSPEED_DIVT2B) == 0) 208 vtclock = tclock = cpuclock/2; 209 else if ((spdreg&BCUCLKSPEED_DIVT3B) == 0) 210 vtclock = tclock = cpuclock/3; 211 else if ((spdreg&BCUCLKSPEED_DIVT4B) == 0) 212 vtclock = tclock = cpuclock/4; 213 else 214 vtclock = tclock = 0; /* XXX */ 215 break; 216 #endif /* VR4111 */ 217 #if defined VR4121 218 case BCUREVID_RID_4121: 219 { 220 int vt; 221 tclock = cpuclock / ((spdreg & BCUCLKSPEED_DIVTMASK) >> 222 BCUCLKSPEED_DIVTSHFT); 223 vt = ((spdreg & BCUCLKSPEED_DIVVTMASK) >> 224 BCUCLKSPEED_DIVVTSHFT); 225 if (vt == 0) 226 vtclock = 0; /* XXX */ 227 else if (vt < 0x9) 228 vtclock = cpuclock / vt; 229 else 230 vtclock = cpuclock / ((vt - 8)*2+1) * 2; 231 } 232 break; 233 #endif /* VR4121 */ 234 #if defined VR4122 || defined VR4131 235 case BCUREVID_RID_4122: 236 case BCUREVID_RID_4131: 237 { 238 int vtdiv; 239 240 vtdiv = ((spdreg & BCUCLKSPEED_VTDIVMODE) >> 241 BCUCLKSPEED_VTDIVSHFT); 242 if (vtdiv == 0 || vtdiv > BCUCLKSPEED_VTDIV6) 243 vtclock = 0; /* XXX */ 244 else 245 vtclock = cpuclock / vtdiv; 246 tclock = vtclock / 247 (((spdreg & BCUCLKSPEED_TDIVMODE) >> 248 BCUCLKSPEED_TDIVSHFT) ? 4 : 2); 249 } 250 break; 251 #endif /* VR4122 || VR4131 */ 252 default: 253 break; 254 } 255 if (tclock) 256 printf("%s: CPU %d.%03dMHz, bus %d.%03dMHz, ram %d.%03dMHz\n", 257 sc->sc_dev.dv_xname, 258 cpuclock/1000000, (cpuclock%1000000)/1000, 259 tclock/1000000, (tclock%1000000)/1000, 260 vtclock/1000000, (vtclock%1000000)/1000); 261 else { 262 printf("%s: CPU %d.%03dMHz\n", 263 sc->sc_dev.dv_xname, 264 cpuclock/1000000, (cpuclock%1000000)/1000); 265 printf("%s: UNKNOWN BUS CLOCK SPEED:" 266 " CPU is UNKNOWN or NOT CONFIGURED\n", 267 sc->sc_dev.dv_xname); 268 } 269 #ifdef VRBCUDEBUG 270 reg = vrbcu_read(sc, BCUCNT1_REG_W); 271 printf("vrbcu: CNT1 %x: ", reg); 272 dbg_bit_print(reg); 273 #if !defined(ONLY_VR4181) 274 if (cpuid != BCUREVID_FIXRID_4181 275 && cpuid <= BCUREVID_RID_4121 276 && cpuid >= BCUREVID_RID_4102) { 277 reg = vrbcu_read(sc, BCUCNT2_REG_W); 278 printf("vrbcu: CNT2 %x: ", reg); 279 dbg_bit_print(reg); 280 } 281 #endif /* !defined ONLY_VR4181 */ 282 #if !defined(ONLY_VR4181) || !defined(ONLY_VR4122_4131) 283 if (cpuid != BCUREVID_FIXRID_4181 284 && cpuid <= BCUREVID_RID_4121 285 && cpuid >= BCUREVID_RID_4102) { 286 reg = vrbcu_read(sc, BCUSPEED_REG_W); 287 printf("vrbcu: SPEED %x: ", reg); 288 dbg_bit_print(reg); 289 reg = vrbcu_read(sc, BCUERRST_REG_W); 290 printf("vrbcu: ERRST %x: ", reg); 291 dbg_bit_print(reg); 292 reg = vrbcu_read(sc, BCURFCNT_REG_W); 293 printf("vrbcu: RFCNT %x\n", reg); 294 reg = vrbcu_read(sc, BCUREFCOUNT_REG_W); 295 printf("vrbcu: RFCOUNT %x\n", reg); 296 } 297 #endif /* !defined(ONLY_VR4181) || !defined(ONLY_VR4122_4131) */ 298 #if !defined(ONLY_VR4181) 299 if (cpuid != BCUREVID_FIXRID_4181 300 && cpuid <= BCUREVID_RID_4131 301 && cpuid >= BCUREVID_RID_4111) 302 { 303 reg = vrbcu_read(sc, BCUCNT3_REG_W); 304 printf("vrbcu: CNT3 %x: ", reg); 305 dbg_bit_print(reg); 306 } 307 #endif /* !defined ONLY_VR4181 */ 308 #endif /* VRBCUDEBUG */ 309 310 } 311 312 static const char *cpuname[] = { 313 "VR4101", /* 0 */ 314 "VR4102", /* 1 */ 315 "VR4111", /* 2 */ 316 "VR4121", /* 3 */ 317 "VR4122", /* 4 */ 318 "VR4131", /* 5 */ 319 "UNKNOWN", 320 "UNKNOWN", 321 "UNKNOWN", 322 "UNKNOWN", 323 "UNKNOWN", 324 "UNKNOWN", 325 "UNKNOWN", 326 "UNKNOWN", 327 "UNKNOWN", 328 "UNKNOWN", 329 "VR4181", /* 0x10 + 0 */ 330 }; 331 332 int 333 vrbcu_vrip_getcpuid(void) 334 { 335 volatile u_int16_t *revreg; 336 337 if (vr_cpuid != -1) 338 return (vr_cpuid); 339 340 if (vr_cpuid == -1) { 341 if (vrbcu_addr() == VR4181_BCU_ADDR) 342 revreg = (u_int16_t *)MIPS_PHYS_TO_KSEG1 343 ((vrbcu_addr() + BCU81REVID_REG_W)); 344 else 345 revreg = (u_int16_t *)MIPS_PHYS_TO_KSEG1 346 ((vrbcu_addr() + BCUREVID_REG_W)); 347 348 vr_cpuid = *revreg; 349 vr_cpuid = (vr_cpuid&BCUREVID_RIDMASK)>>BCUREVID_RIDSHFT; 350 if (vrbcu_addr() == VR4181_BCU_ADDR 351 && vr_cpuid == BCUREVID_RID_4181) /* conflict vr4101 */ 352 vr_cpuid = BCUREVID_FIXRID_4181; 353 } 354 return (vr_cpuid); 355 } 356 357 const char * 358 vrbcu_vrip_getcpuname(void) 359 { 360 int cpuid; 361 362 if (vr_cpuname != NULL) 363 return (vr_cpuname); 364 365 cpuid = vrbcu_vrip_getcpuid(); 366 vr_cpuname = cpuname[cpuid]; 367 368 return (vr_cpuname); 369 } 370 371 372 int 373 vrbcu_vrip_getcpumajor(void) 374 { 375 volatile u_int16_t *revreg; 376 377 if (vr_major != -1) 378 return (vr_major); 379 380 revreg = (u_int16_t *)MIPS_PHYS_TO_KSEG1 381 ((vrbcu_addr() + BCUREVID_REG_W)); 382 383 vr_major = *revreg; 384 vr_major = (vr_major&BCUREVID_MJREVMASK)>>BCUREVID_MJREVSHFT; 385 386 return (vr_major); 387 } 388 389 int 390 vrbcu_vrip_getcpuminor(void) 391 { 392 volatile u_int16_t *revreg; 393 394 if (vr_minor != -1) 395 return (vr_minor); 396 397 revreg = (u_int16_t *)MIPS_PHYS_TO_KSEG1 398 ((vrbcu_addr() + BCUREVID_REG_W)); 399 400 vr_minor = *revreg; 401 vr_minor = (vr_minor&BCUREVID_MNREVMASK)>>BCUREVID_MNREVSHFT; 402 403 return (vr_minor); 404 } 405 406 #define CLKX 18432000 /* CLKX1,CLKX2: 18.432MHz */ 407 #define MHZ 1000000 408 409 int 410 vrbcu_vrip_getcpuclock(void) 411 { 412 u_int16_t clksp = 0; 413 int cpuid, cpuclock; 414 415 cpuid = vrbcu_vrip_getcpuid(); 416 if (cpuid != BCUREVID_FIXRID_4181 && cpuid >= BCUREVID_RID_4111) { 417 clksp = *(u_int16_t *)MIPS_PHYS_TO_KSEG1 418 ((vrbcu_addr() + BCUCLKSPEED_REG_W)) & 419 BCUCLKSPEED_CLKSPMASK; 420 } else if (cpuid == BCUREVID_FIXRID_4181) { 421 clksp = *(u_int16_t *)MIPS_PHYS_TO_KSEG1 422 ((vrbcu_addr() + BCU81CLKSPEED_REG_W)) & 423 BCUCLKSPEED_CLKSPMASK; 424 } 425 426 switch (cpuid) { 427 case BCUREVID_FIXRID_4181: 428 cpuclock = CLKX / clksp * 64; 429 /* branch delay is 1 clock; 2 clock/loop */ 430 cpuspeed = (cpuclock / 2 + MHZ / 2) / MHZ; 431 break; 432 case BCUREVID_RID_4101: 433 /* assume 33MHz */ 434 cpuclock = 33000000; 435 /* branch delay is 1 clock; 2 clock/loop */ 436 cpuspeed = (cpuclock / 2 + MHZ / 2) / MHZ; 437 break; 438 case BCUREVID_RID_4102: 439 cpuclock = CLKX / clksp * 32; 440 /* branch delay is 1 clock; 2 clock/loop */ 441 cpuspeed = (cpuclock / 2 + MHZ / 2) / MHZ; 442 break; 443 case BCUREVID_RID_4111: 444 cpuclock = CLKX / clksp * 64; 445 /* branch delay is 1 clock; 2 clock/loop */ 446 cpuspeed = (cpuclock / 2 + MHZ / 2) / MHZ; 447 break; 448 case BCUREVID_RID_4121: 449 cpuclock = CLKX / clksp * 64; 450 /* branch delay is 2 clock; 3 clock/loop */ 451 cpuspeed = (cpuclock / 3 + MHZ / 2) / MHZ; 452 break; 453 case BCUREVID_RID_4122: 454 cpuclock = CLKX / clksp * 98; 455 /* branch delay is 2 clock; 3 clock/loop */ 456 cpuspeed = (cpuclock / 3 + MHZ / 2) / MHZ; 457 break; 458 case BCUREVID_RID_4131: 459 cpuclock = CLKX / clksp * 98; 460 /* branch delay is 2 clock; 3 clock/loop */ 461 cpuspeed = (cpuclock / 3 + MHZ / 2) / MHZ; 462 break; 463 default: 464 panic("unknown CPU type %d", cpuid); 465 break; 466 } 467 468 return (cpuclock); 469 } 470