1 /* $NetBSD: obio.c,v 1.33 2011/06/18 08:08:28 matt Exp $ */ 2 3 /*- 4 * Copyright (C) 1998 Internet Research Institute, Inc. 5 * 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 18 * Internet Research Institute, Inc. 19 * 4. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <sys/cdefs.h> 35 __KERNEL_RCSID(0, "$NetBSD: obio.c,v 1.33 2011/06/18 08:08:28 matt Exp $"); 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/kernel.h> 40 #include <sys/device.h> 41 #include <sys/sysctl.h> 42 43 #include <dev/pci/pcivar.h> 44 #include <dev/pci/pcidevs.h> 45 46 #include <dev/ofw/openfirm.h> 47 48 #include <machine/autoconf.h> 49 50 #include <macppc/dev/obiovar.h> 51 52 #include <powerpc/cpu.h> 53 54 #include "opt_obio.h" 55 56 #ifdef OBIO_DEBUG 57 # define DPRINTF printf 58 #else 59 # define DPRINTF while (0) printf 60 #endif 61 62 static void obio_attach(device_t, device_t, void *); 63 static int obio_match(device_t, cfdata_t, void *); 64 static int obio_print(void *, const char *); 65 66 struct obio_softc { 67 struct device sc_dev; 68 bus_space_tag_t sc_tag; 69 bus_space_handle_t sc_bh; 70 int sc_node; 71 #ifdef OBIO_SPEED_CONTROL 72 int sc_voltage; 73 int sc_busspeed; 74 int sc_spd_hi, sc_spd_lo; 75 #endif 76 }; 77 78 static struct obio_softc *obio0 = NULL; 79 80 #ifdef OBIO_SPEED_CONTROL 81 static void obio_setup_gpios(struct obio_softc *, int); 82 static void obio_set_cpu_speed(struct obio_softc *, int); 83 static int obio_get_cpu_speed(struct obio_softc *); 84 static int sysctl_cpuspeed_temp(SYSCTLFN_ARGS); 85 static int sysctl_cpuspeed_cur(SYSCTLFN_ARGS); 86 static int sysctl_cpuspeed_available(SYSCTLFN_ARGS); 87 88 static const char *keylargo[] = {"Keylargo", 89 "AAPL,Keylargo", 90 NULL}; 91 92 #endif 93 94 CFATTACH_DECL(obio, sizeof(struct obio_softc), 95 obio_match, obio_attach, NULL, NULL); 96 97 int 98 obio_match(device_t parent, cfdata_t cf, void *aux) 99 { 100 struct pci_attach_args *pa = aux; 101 102 if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_APPLE) 103 switch (PCI_PRODUCT(pa->pa_id)) { 104 case PCI_PRODUCT_APPLE_GC: 105 case PCI_PRODUCT_APPLE_OHARE: 106 case PCI_PRODUCT_APPLE_HEATHROW: 107 case PCI_PRODUCT_APPLE_PADDINGTON: 108 case PCI_PRODUCT_APPLE_KEYLARGO: 109 case PCI_PRODUCT_APPLE_PANGEA_MACIO: 110 case PCI_PRODUCT_APPLE_INTREPID: 111 case PCI_PRODUCT_APPLE_K2: 112 return 1; 113 } 114 115 return 0; 116 } 117 118 /* 119 * Attach all the sub-devices we can find 120 */ 121 void 122 obio_attach(device_t parent, device_t self, void *aux) 123 { 124 struct obio_softc *sc = device_private(self); 125 struct pci_attach_args *pa = aux; 126 struct confargs ca; 127 bus_space_handle_t bsh; 128 int node, child, namelen, error; 129 u_int reg[20]; 130 int intr[6], parent_intr = 0, parent_nintr = 0; 131 char name[32]; 132 char compat[32]; 133 134 #ifdef OBIO_SPEED_CONTROL 135 sc->sc_voltage = -1; 136 sc->sc_busspeed = -1; 137 sc->sc_spd_lo = 600; 138 sc->sc_spd_hi = 800; 139 #endif 140 141 switch (PCI_PRODUCT(pa->pa_id)) { 142 143 case PCI_PRODUCT_APPLE_GC: 144 case PCI_PRODUCT_APPLE_OHARE: 145 case PCI_PRODUCT_APPLE_HEATHROW: 146 case PCI_PRODUCT_APPLE_PADDINGTON: 147 case PCI_PRODUCT_APPLE_KEYLARGO: 148 case PCI_PRODUCT_APPLE_PANGEA_MACIO: 149 case PCI_PRODUCT_APPLE_INTREPID: 150 node = pcidev_to_ofdev(pa->pa_pc, pa->pa_tag); 151 if (node == -1) 152 node = OF_finddevice("mac-io"); 153 if (node == -1) 154 node = OF_finddevice("/pci/mac-io"); 155 break; 156 case PCI_PRODUCT_APPLE_K2: 157 node = OF_finddevice("mac-io"); 158 break; 159 160 default: 161 node = -1; 162 break; 163 } 164 if (node == -1) 165 panic("macio not found or unknown"); 166 167 sc->sc_node = node; 168 169 #if defined (PMAC_G5) 170 if (OF_getprop(node, "assigned-addresses", reg, sizeof(reg)) < 20) 171 { 172 return; 173 } 174 #else 175 if (OF_getprop(node, "assigned-addresses", reg, sizeof(reg)) < 12) 176 return; 177 #endif /* PMAC_G5 */ 178 179 /* 180 * XXX 181 * This relies on the primary obio always attaching first which is 182 * true on the PowerBook 3400c and similar machines but may or may 183 * not work on others. We can't rely on the node name since Apple 184 * didn't follow anything remotely resembling a consistent naming 185 * scheme. 186 */ 187 if (obio0 == NULL) 188 obio0 = sc; 189 190 ca.ca_baseaddr = reg[2]; 191 ca.ca_tag = pa->pa_memt; 192 sc->sc_tag = pa->pa_memt; 193 error = bus_space_map (pa->pa_memt, ca.ca_baseaddr, 0x80, 0, &bsh); 194 if (error) 195 panic(": failed to map mac-io %#x", ca.ca_baseaddr); 196 sc->sc_bh = bsh; 197 198 printf(": addr 0x%x\n", ca.ca_baseaddr); 199 200 /* Enable internal modem (KeyLargo) */ 201 if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_KEYLARGO) { 202 aprint_normal("%s: enabling KeyLargo internal modem\n", 203 self->dv_xname); 204 bus_space_write_4(ca.ca_tag, bsh, 0x40, 205 bus_space_read_4(ca.ca_tag, bsh, 0x40) & ~(1<<25)); 206 } 207 208 /* Enable internal modem (Pangea) */ 209 if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_PANGEA_MACIO) { 210 /* set reset */ 211 bus_space_write_1(ca.ca_tag, bsh, 0x006a + 0x03, 0x04); 212 /* power modem on */ 213 bus_space_write_1(ca.ca_tag, bsh, 0x006a + 0x02, 0x04); 214 /* unset reset */ 215 bus_space_write_1(ca.ca_tag, bsh, 0x006a + 0x03, 0x05); 216 } 217 218 /* Gatwick and Paddington use same product ID */ 219 namelen = OF_getprop(node, "compatible", compat, sizeof(compat)); 220 221 if (strcmp(compat, "gatwick") == 0) { 222 parent_nintr = OF_getprop(node, "AAPL,interrupts", intr, 223 sizeof(intr)); 224 parent_intr = intr[0]; 225 } else { 226 /* Enable CD and microphone sound input. */ 227 if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_PADDINGTON) 228 bus_space_write_1(ca.ca_tag, bsh, 0x37, 0x03); 229 } 230 231 for (child = OF_child(node); child; child = OF_peer(child)) { 232 namelen = OF_getprop(child, "name", name, sizeof(name)); 233 if (namelen < 0) 234 continue; 235 if (namelen >= sizeof(name)) 236 continue; 237 238 #ifdef OBIO_SPEED_CONTROL 239 if (strcmp(name, "gpio") == 0) { 240 241 obio_setup_gpios(sc, child); 242 continue; 243 } 244 #endif 245 246 name[namelen] = 0; 247 ca.ca_name = name; 248 ca.ca_node = child; 249 ca.ca_tag = pa->pa_memt; 250 251 ca.ca_nreg = OF_getprop(child, "reg", reg, sizeof(reg)); 252 253 if (strcmp(compat, "gatwick") != 0) { 254 ca.ca_nintr = OF_getprop(child, "AAPL,interrupts", intr, 255 sizeof(intr)); 256 if (ca.ca_nintr == -1) 257 ca.ca_nintr = OF_getprop(child, "interrupts", intr, 258 sizeof(intr)); 259 } else { 260 intr[0] = parent_intr; 261 ca.ca_nintr = parent_nintr; 262 } 263 ca.ca_reg = reg; 264 ca.ca_intr = intr; 265 266 config_found(self, &ca, obio_print); 267 } 268 } 269 270 static const char * const skiplist[] = { 271 "interrupt-controller", 272 "gpio", 273 "escc-legacy", 274 "timer", 275 "i2c", 276 "power-mgt", 277 "escc", 278 "battery", 279 "backlight" 280 281 }; 282 283 #define N_LIST (sizeof(skiplist) / sizeof(skiplist[0])) 284 285 int 286 obio_print(void *aux, const char *obio) 287 { 288 struct confargs *ca = aux; 289 int i; 290 291 for (i = 0; i < N_LIST; i++) 292 if (strcmp(ca->ca_name, skiplist[i]) == 0) 293 return QUIET; 294 295 if (obio) 296 aprint_normal("%s at %s", ca->ca_name, obio); 297 298 if (ca->ca_nreg > 0) 299 aprint_normal(" offset 0x%x", ca->ca_reg[0]); 300 301 return UNCONF; 302 } 303 304 void obio_write_4(int offset, uint32_t value) 305 { 306 if (obio0 == NULL) 307 return; 308 bus_space_write_4(obio0->sc_tag, obio0->sc_bh, offset, value); 309 } 310 311 void obio_write_1(int offset, uint8_t value) 312 { 313 if (obio0 == NULL) 314 return; 315 bus_space_write_1(obio0->sc_tag, obio0->sc_bh, offset, value); 316 } 317 318 uint32_t obio_read_4(int offset) 319 { 320 if (obio0 == NULL) 321 return 0xffffffff; 322 return bus_space_read_4(obio0->sc_tag, obio0->sc_bh, offset); 323 } 324 325 uint8_t obio_read_1(int offset) 326 { 327 if (obio0 == NULL) 328 return 0xff; 329 return bus_space_read_1(obio0->sc_tag, obio0->sc_bh, offset); 330 } 331 332 #ifdef OBIO_SPEED_CONTROL 333 334 static void 335 obio_setup_gpios(struct obio_softc *sc, int node) 336 { 337 uint32_t gpio_base, reg[6]; 338 struct sysctlnode *sysctl_node, *me, *freq; 339 char name[32]; 340 int child, use_dfs, cpunode, hiclock; 341 342 if (of_compatible(sc->sc_node, keylargo) == -1) 343 return; 344 345 if (OF_getprop(node, "reg", reg, sizeof(reg)) < 4) 346 return; 347 348 gpio_base = reg[0]; 349 DPRINTF("gpio_base: %02x\n", gpio_base); 350 351 /* now look for voltage and bus speed gpios */ 352 use_dfs = 0; 353 for (child = OF_child(node); child; child = OF_peer(child)) { 354 355 if (OF_getprop(child, "name", name, sizeof(name)) < 1) 356 continue; 357 358 if (OF_getprop(child, "reg", reg, sizeof(reg)) < 4) 359 continue; 360 361 /* 362 * These register offsets either have to be added to the obio 363 * base address or to the gpio base address. This differs 364 * even in the same OF-tree! So we guess the offset is 365 * based on obio when it is larger than the gpio_base. 366 */ 367 if (reg[0] >= gpio_base) 368 reg[0] -= gpio_base; 369 370 if (strcmp(name, "frequency-gpio") == 0) { 371 DPRINTF("found frequency_gpio at %02x\n", reg[0]); 372 sc->sc_busspeed = gpio_base + reg[0]; 373 } 374 if (strcmp(name, "voltage-gpio") == 0) { 375 DPRINTF("found voltage_gpio at %02x\n", reg[0]); 376 sc->sc_voltage = gpio_base + reg[0]; 377 } 378 if (strcmp(name, "cpu-vcore-select") == 0) { 379 DPRINTF("found cpu-vcore-select at %02x\n", reg[0]); 380 sc->sc_voltage = gpio_base + reg[0]; 381 /* frequency gpio is not needed, we use cpu's DFS */ 382 use_dfs = 1; 383 } 384 } 385 386 if ((sc->sc_voltage < 0) || (sc->sc_busspeed < 0 && !use_dfs)) 387 return; 388 389 printf("%s: enabling Intrepid CPU speed control\n", 390 sc->sc_dev.dv_xname); 391 392 sc->sc_spd_lo = curcpu()->ci_khz / 1000; 393 hiclock = 0; 394 cpunode = OF_finddevice("/cpus/@0"); 395 OF_getprop(cpunode, "clock-frequency", &hiclock, 4); 396 printf("hiclock: %d\n", (hiclock + 500000) / 1000000); 397 sysctl_node = NULL; 398 399 if (sysctl_createv(NULL, 0, NULL, 400 (const struct sysctlnode **)&me, 401 CTLFLAG_READWRITE, CTLTYPE_NODE, "intrepid", NULL, NULL, 402 0, NULL, 0, CTL_MACHDEP, CTL_CREATE, CTL_EOL) != 0) 403 printf("couldn't create 'interpid' node\n"); 404 405 if (sysctl_createv(NULL, 0, NULL, 406 (const struct sysctlnode **)&freq, 407 CTLFLAG_READWRITE, CTLTYPE_NODE, "frequency", NULL, NULL, 408 0, NULL, 0, CTL_MACHDEP, me->sysctl_num, CTL_CREATE, CTL_EOL) != 0) 409 printf("couldn't create 'frequency' node\n"); 410 411 if (sysctl_createv(NULL, 0, NULL, 412 (const struct sysctlnode **)&sysctl_node, 413 CTLFLAG_READWRITE | CTLFLAG_OWNDESC | CTLFLAG_IMMEDIATE, 414 CTLTYPE_INT, "target", "CPU speed", sysctl_cpuspeed_temp, 415 0, NULL, 0, CTL_MACHDEP, me->sysctl_num, freq->sysctl_num, 416 CTL_CREATE, CTL_EOL) == 0) { 417 sysctl_node->sysctl_data = (void *)sc; 418 } else 419 printf("couldn't create 'target' node\n"); 420 421 if (sysctl_createv(NULL, 0, NULL, 422 (const struct sysctlnode **)&sysctl_node, 423 CTLFLAG_READWRITE | CTLFLAG_IMMEDIATE, 424 CTLTYPE_INT, "current", NULL, sysctl_cpuspeed_cur, 425 1, NULL, 0, CTL_MACHDEP, me->sysctl_num, freq->sysctl_num, 426 CTL_CREATE, CTL_EOL) == 0) { 427 sysctl_node->sysctl_data = (void *)sc; 428 } else 429 printf("couldn't create 'current' node\n"); 430 431 if (sysctl_createv(NULL, 0, NULL, 432 (const struct sysctlnode **)&sysctl_node, 433 CTLFLAG_READWRITE, 434 CTLTYPE_STRING, "available", NULL, sysctl_cpuspeed_available, 435 2, NULL, 0, CTL_MACHDEP, me->sysctl_num, freq->sysctl_num, 436 CTL_CREATE, CTL_EOL) == 0) { 437 sysctl_node->sysctl_data = (void *)sc; 438 } else 439 printf("couldn't create 'available' node\n"); 440 printf("speed: %d\n", curcpu()->ci_khz); 441 } 442 443 static void 444 obio_set_cpu_speed(struct obio_softc *sc, int fast) 445 { 446 447 if (sc->sc_voltage < 0) 448 return; 449 450 if (sc->sc_busspeed >= 0) { 451 /* set voltage and speed via gpio */ 452 if (fast) { 453 bus_space_write_1(sc->sc_tag, sc->sc_bh, 454 sc->sc_voltage, 5); 455 bus_space_write_1(sc->sc_tag, sc->sc_bh, 456 sc->sc_busspeed, 5); 457 } else { 458 bus_space_write_1(sc->sc_tag, sc->sc_bh, 459 sc->sc_busspeed, 4); 460 bus_space_write_1(sc->sc_tag, sc->sc_bh, 461 sc->sc_voltage, 4); 462 } 463 } 464 else { 465 /* set voltage via gpio and speed via the 7447A's DFS bit */ 466 if (fast) { 467 bus_space_write_1(sc->sc_tag, sc->sc_bh, 468 sc->sc_voltage, 5); 469 DELAY(1000); 470 } 471 472 /* set DFS for all cpus */ 473 cpu_set_dfs(fast ? 1 : 2); 474 DELAY(100); 475 476 if (!fast) { 477 bus_space_write_1(sc->sc_tag, sc->sc_bh, 478 sc->sc_voltage, 4); 479 DELAY(1000); 480 } 481 } 482 } 483 484 static int 485 obio_get_cpu_speed(struct obio_softc *sc) 486 { 487 488 if (sc->sc_voltage < 0) 489 return 0; 490 491 if (sc->sc_busspeed >= 0) { 492 if (bus_space_read_1(sc->sc_tag, sc->sc_bh, sc->sc_busspeed) 493 & 1) 494 return 1; 495 } 496 else 497 return cpu_get_dfs() == 1; 498 499 return 0; 500 } 501 502 static int 503 sysctl_cpuspeed_temp(SYSCTLFN_ARGS) 504 { 505 struct sysctlnode node = *rnode; 506 struct obio_softc *sc = node.sysctl_data; 507 int speed, mhz; 508 509 speed = obio_get_cpu_speed(sc); 510 switch (speed) { 511 case 0: 512 mhz = sc->sc_spd_lo; 513 break; 514 case 1: 515 mhz = sc->sc_spd_hi; 516 break; 517 default: 518 speed = -1; 519 } 520 node.sysctl_idata = mhz; 521 node.sysctl_data = &mhz; 522 if (sysctl_lookup(SYSCTLFN_CALL(&node)) == 0) { 523 int new_reg; 524 525 new_reg = node.sysctl_idata; 526 if (new_reg == sc->sc_spd_lo) { 527 obio_set_cpu_speed(sc, 0); 528 } else if (new_reg == sc->sc_spd_hi) { 529 obio_set_cpu_speed(sc, 1); 530 } else { 531 printf("%s: new_reg %d\n", __func__, new_reg); 532 return EINVAL; 533 } 534 return 0; 535 } 536 return EINVAL; 537 } 538 539 static int 540 sysctl_cpuspeed_cur(SYSCTLFN_ARGS) 541 { 542 struct sysctlnode node = *rnode; 543 struct obio_softc *sc = node.sysctl_data; 544 int speed, mhz; 545 546 speed = obio_get_cpu_speed(sc); 547 switch (speed) { 548 case 0: 549 mhz = sc->sc_spd_lo; 550 break; 551 case 1: 552 mhz = sc->sc_spd_hi; 553 break; 554 default: 555 speed = -1; 556 } 557 node.sysctl_idata = mhz; 558 node.sysctl_data = &mhz; 559 return sysctl_lookup(SYSCTLFN_CALL(&node)); 560 } 561 562 static int 563 sysctl_cpuspeed_available(SYSCTLFN_ARGS) 564 { 565 struct sysctlnode node = *rnode; 566 struct obio_softc *sc = node.sysctl_data; 567 char buf[128]; 568 int speed; 569 570 speed = obio_get_cpu_speed(sc); 571 snprintf(buf, 128, "%d %d", sc->sc_spd_lo, sc->sc_spd_hi); 572 node.sysctl_data = buf; 573 return(sysctl_lookup(SYSCTLFN_CALL(&node))); 574 } 575 576 SYSCTL_SETUP(sysctl_ams_setup, "sysctl obio subtree setup") 577 { 578 579 sysctl_createv(NULL, 0, NULL, NULL, 580 CTLFLAG_PERMANENT, 581 CTLTYPE_NODE, "machdep", NULL, 582 NULL, 0, NULL, 0, 583 CTL_MACHDEP, CTL_EOL); 584 } 585 586 #endif /* OBIO_SPEEDCONTROL */ 587