1 /* $NetBSD: obio.c,v 1.36 2011/10/19 21:12:50 macallan 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.36 2011/10/19 21:12:50 macallan 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 #include <sys/cpufreq.h> 54 55 #include "opt_obio.h" 56 57 #ifdef OBIO_DEBUG 58 # define DPRINTF printf 59 #else 60 # define DPRINTF while (0) printf 61 #endif 62 63 static void obio_attach(device_t, device_t, void *); 64 static int obio_match(device_t, cfdata_t, void *); 65 static int obio_print(void *, const char *); 66 67 struct obio_softc { 68 device_t sc_dev; 69 bus_space_tag_t sc_tag; 70 bus_space_handle_t sc_bh; 71 int sc_node; 72 #ifdef OBIO_SPEED_CONTROL 73 int sc_voltage; 74 int sc_busspeed; 75 int sc_spd_hi, sc_spd_lo; 76 struct cpufreq sc_cf; 77 #endif 78 }; 79 80 static struct obio_softc *obio0 = NULL; 81 82 #ifdef OBIO_SPEED_CONTROL 83 static void obio_setup_gpios(struct obio_softc *, int); 84 static void obio_set_cpu_speed(struct obio_softc *, int); 85 static int obio_get_cpu_speed(struct obio_softc *); 86 static int sysctl_cpuspeed_temp(SYSCTLFN_ARGS); 87 static int sysctl_cpuspeed_cur(SYSCTLFN_ARGS); 88 static int sysctl_cpuspeed_available(SYSCTLFN_ARGS); 89 static void obio_get_freq(void *, void *); 90 static void obio_set_freq(void *, void *); 91 static const char *keylargo[] = {"Keylargo", 92 "AAPL,Keylargo", 93 NULL}; 94 95 #endif 96 97 CFATTACH_DECL_NEW(obio, sizeof(struct obio_softc), 98 obio_match, obio_attach, NULL, NULL); 99 100 int 101 obio_match(device_t parent, cfdata_t cf, void *aux) 102 { 103 struct pci_attach_args *pa = aux; 104 105 if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_APPLE) 106 switch (PCI_PRODUCT(pa->pa_id)) { 107 case PCI_PRODUCT_APPLE_GC: 108 case PCI_PRODUCT_APPLE_OHARE: 109 case PCI_PRODUCT_APPLE_HEATHROW: 110 case PCI_PRODUCT_APPLE_PADDINGTON: 111 case PCI_PRODUCT_APPLE_KEYLARGO: 112 case PCI_PRODUCT_APPLE_PANGEA_MACIO: 113 case PCI_PRODUCT_APPLE_INTREPID: 114 case PCI_PRODUCT_APPLE_K2: 115 return 1; 116 } 117 118 return 0; 119 } 120 121 /* 122 * Attach all the sub-devices we can find 123 */ 124 void 125 obio_attach(device_t parent, device_t self, void *aux) 126 { 127 struct obio_softc *sc = device_private(self); 128 struct pci_attach_args *pa = aux; 129 struct confargs ca; 130 bus_space_handle_t bsh; 131 int node, child, namelen, error; 132 u_int reg[20]; 133 int intr[6], parent_intr = 0, parent_nintr = 0; 134 char name[32]; 135 char compat[32]; 136 137 sc->sc_dev = self; 138 #ifdef OBIO_SPEED_CONTROL 139 sc->sc_voltage = -1; 140 sc->sc_busspeed = -1; 141 sc->sc_spd_lo = 600; 142 sc->sc_spd_hi = 800; 143 #endif 144 145 switch (PCI_PRODUCT(pa->pa_id)) { 146 147 case PCI_PRODUCT_APPLE_GC: 148 case PCI_PRODUCT_APPLE_OHARE: 149 case PCI_PRODUCT_APPLE_HEATHROW: 150 case PCI_PRODUCT_APPLE_PADDINGTON: 151 case PCI_PRODUCT_APPLE_KEYLARGO: 152 case PCI_PRODUCT_APPLE_PANGEA_MACIO: 153 case PCI_PRODUCT_APPLE_INTREPID: 154 node = pcidev_to_ofdev(pa->pa_pc, pa->pa_tag); 155 if (node == -1) 156 node = OF_finddevice("mac-io"); 157 if (node == -1) 158 node = OF_finddevice("/pci/mac-io"); 159 break; 160 case PCI_PRODUCT_APPLE_K2: 161 node = OF_finddevice("mac-io"); 162 break; 163 164 default: 165 node = -1; 166 break; 167 } 168 if (node == -1) 169 panic("macio not found or unknown"); 170 171 sc->sc_node = node; 172 173 #if defined (PMAC_G5) 174 if (OF_getprop(node, "assigned-addresses", reg, sizeof(reg)) < 20) 175 { 176 return; 177 } 178 #else 179 if (OF_getprop(node, "assigned-addresses", reg, sizeof(reg)) < 12) 180 return; 181 #endif /* PMAC_G5 */ 182 183 /* 184 * XXX 185 * This relies on the primary obio always attaching first which is 186 * true on the PowerBook 3400c and similar machines but may or may 187 * not work on others. We can't rely on the node name since Apple 188 * didn't follow anything remotely resembling a consistent naming 189 * scheme. 190 */ 191 if (obio0 == NULL) 192 obio0 = sc; 193 194 ca.ca_baseaddr = reg[2]; 195 ca.ca_tag = pa->pa_memt; 196 sc->sc_tag = pa->pa_memt; 197 error = bus_space_map (pa->pa_memt, ca.ca_baseaddr, 0x80, 0, &bsh); 198 if (error) 199 panic(": failed to map mac-io %#x", ca.ca_baseaddr); 200 sc->sc_bh = bsh; 201 202 printf(": addr 0x%x\n", ca.ca_baseaddr); 203 204 /* Enable internal modem (KeyLargo) */ 205 if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_KEYLARGO) { 206 aprint_normal("%s: enabling KeyLargo internal modem\n", 207 self->dv_xname); 208 bus_space_write_4(ca.ca_tag, bsh, 0x40, 209 bus_space_read_4(ca.ca_tag, bsh, 0x40) & ~(1<<25)); 210 } 211 212 /* Enable internal modem (Pangea) */ 213 if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_PANGEA_MACIO) { 214 /* set reset */ 215 bus_space_write_1(ca.ca_tag, bsh, 0x006a + 0x03, 0x04); 216 /* power modem on */ 217 bus_space_write_1(ca.ca_tag, bsh, 0x006a + 0x02, 0x04); 218 /* unset reset */ 219 bus_space_write_1(ca.ca_tag, bsh, 0x006a + 0x03, 0x05); 220 } 221 222 /* Gatwick and Paddington use same product ID */ 223 namelen = OF_getprop(node, "compatible", compat, sizeof(compat)); 224 225 if (strcmp(compat, "gatwick") == 0) { 226 parent_nintr = OF_getprop(node, "AAPL,interrupts", intr, 227 sizeof(intr)); 228 parent_intr = intr[0]; 229 } else { 230 /* Enable CD and microphone sound input. */ 231 if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_PADDINGTON) 232 bus_space_write_1(ca.ca_tag, bsh, 0x37, 0x03); 233 } 234 235 for (child = OF_child(node); child; child = OF_peer(child)) { 236 namelen = OF_getprop(child, "name", name, sizeof(name)); 237 if (namelen < 0) 238 continue; 239 if (namelen >= sizeof(name)) 240 continue; 241 242 #ifdef OBIO_SPEED_CONTROL 243 if (strcmp(name, "gpio") == 0) { 244 245 obio_setup_gpios(sc, child); 246 continue; 247 } 248 #endif 249 250 name[namelen] = 0; 251 ca.ca_name = name; 252 ca.ca_node = child; 253 ca.ca_tag = pa->pa_memt; 254 255 ca.ca_nreg = OF_getprop(child, "reg", reg, sizeof(reg)); 256 257 if (strcmp(compat, "gatwick") != 0) { 258 ca.ca_nintr = OF_getprop(child, "AAPL,interrupts", intr, 259 sizeof(intr)); 260 if (ca.ca_nintr == -1) 261 ca.ca_nintr = OF_getprop(child, "interrupts", intr, 262 sizeof(intr)); 263 } else { 264 intr[0] = parent_intr; 265 ca.ca_nintr = parent_nintr; 266 } 267 ca.ca_reg = reg; 268 ca.ca_intr = intr; 269 270 config_found(self, &ca, obio_print); 271 } 272 } 273 274 static const char * const skiplist[] = { 275 "interrupt-controller", 276 "gpio", 277 "escc-legacy", 278 "timer", 279 "i2c", 280 "power-mgt", 281 "escc", 282 "battery", 283 "backlight" 284 285 }; 286 287 #define N_LIST (sizeof(skiplist) / sizeof(skiplist[0])) 288 289 int 290 obio_print(void *aux, const char *obio) 291 { 292 struct confargs *ca = aux; 293 int i; 294 295 for (i = 0; i < N_LIST; i++) 296 if (strcmp(ca->ca_name, skiplist[i]) == 0) 297 return QUIET; 298 299 if (obio) 300 aprint_normal("%s at %s", ca->ca_name, obio); 301 302 if (ca->ca_nreg > 0) 303 aprint_normal(" offset 0x%x", ca->ca_reg[0]); 304 305 return UNCONF; 306 } 307 308 void obio_write_4(int offset, uint32_t value) 309 { 310 if (obio0 == NULL) 311 return; 312 bus_space_write_4(obio0->sc_tag, obio0->sc_bh, offset, value); 313 } 314 315 void obio_write_1(int offset, uint8_t value) 316 { 317 if (obio0 == NULL) 318 return; 319 bus_space_write_1(obio0->sc_tag, obio0->sc_bh, offset, value); 320 } 321 322 uint32_t obio_read_4(int offset) 323 { 324 if (obio0 == NULL) 325 return 0xffffffff; 326 return bus_space_read_4(obio0->sc_tag, obio0->sc_bh, offset); 327 } 328 329 uint8_t obio_read_1(int offset) 330 { 331 if (obio0 == NULL) 332 return 0xff; 333 return bus_space_read_1(obio0->sc_tag, obio0->sc_bh, offset); 334 } 335 336 #ifdef OBIO_SPEED_CONTROL 337 338 static void 339 obio_setup_cpufreq(device_t dev) 340 { 341 struct obio_softc *sc = device_private(dev); 342 int ret; 343 344 ret = cpufreq_register(&sc->sc_cf); 345 if (ret != 0) 346 aprint_error_dev(sc->sc_dev, "cpufreq_register() failed, error %d\n", ret); 347 } 348 349 static void 350 obio_setup_gpios(struct obio_softc *sc, int node) 351 { 352 uint32_t gpio_base, reg[6]; 353 const struct sysctlnode *sysctl_node, *me, *freq; 354 struct cpufreq *cf = &sc->sc_cf; 355 char name[32]; 356 int child, use_dfs, cpunode, hiclock; 357 358 if (of_compatible(sc->sc_node, keylargo) == -1) 359 return; 360 361 if (OF_getprop(node, "reg", reg, sizeof(reg)) < 4) 362 return; 363 364 gpio_base = reg[0]; 365 DPRINTF("gpio_base: %02x\n", gpio_base); 366 367 /* now look for voltage and bus speed gpios */ 368 use_dfs = 0; 369 for (child = OF_child(node); child; child = OF_peer(child)) { 370 371 if (OF_getprop(child, "name", name, sizeof(name)) < 1) 372 continue; 373 374 if (OF_getprop(child, "reg", reg, sizeof(reg)) < 4) 375 continue; 376 377 /* 378 * These register offsets either have to be added to the obio 379 * base address or to the gpio base address. This differs 380 * even in the same OF-tree! So we guess the offset is 381 * based on obio when it is larger than the gpio_base. 382 */ 383 if (reg[0] >= gpio_base) 384 reg[0] -= gpio_base; 385 386 if (strcmp(name, "frequency-gpio") == 0) { 387 DPRINTF("found frequency_gpio at %02x\n", reg[0]); 388 sc->sc_busspeed = gpio_base + reg[0]; 389 } 390 if (strcmp(name, "voltage-gpio") == 0) { 391 DPRINTF("found voltage_gpio at %02x\n", reg[0]); 392 sc->sc_voltage = gpio_base + reg[0]; 393 } 394 if (strcmp(name, "cpu-vcore-select") == 0) { 395 DPRINTF("found cpu-vcore-select at %02x\n", reg[0]); 396 sc->sc_voltage = gpio_base + reg[0]; 397 /* frequency gpio is not needed, we use cpu's DFS */ 398 use_dfs = 1; 399 } 400 } 401 402 if ((sc->sc_voltage < 0) || (sc->sc_busspeed < 0 && !use_dfs)) 403 return; 404 405 printf("%s: enabling Intrepid CPU speed control\n", 406 device_xname(sc->sc_dev)); 407 408 sc->sc_spd_lo = curcpu()->ci_khz / 1000; 409 hiclock = 0; 410 cpunode = OF_finddevice("/cpus/@0"); 411 OF_getprop(cpunode, "clock-frequency", &hiclock, 4); 412 if (hiclock != 0) 413 sc->sc_spd_hi = (hiclock + 500000) / 1000000; 414 printf("hiclock: %d\n", sc->sc_spd_hi); 415 416 sysctl_node = NULL; 417 418 if (sysctl_createv(NULL, 0, NULL, 419 &me, 420 CTLFLAG_READWRITE, CTLTYPE_NODE, "intrepid", NULL, NULL, 421 0, NULL, 0, CTL_MACHDEP, CTL_CREATE, CTL_EOL) != 0) 422 printf("couldn't create 'intrepid' node\n"); 423 424 if (sysctl_createv(NULL, 0, NULL, 425 &freq, 426 CTLFLAG_READWRITE, CTLTYPE_NODE, "frequency", NULL, NULL, 427 0, NULL, 0, CTL_MACHDEP, me->sysctl_num, CTL_CREATE, CTL_EOL) != 0) 428 printf("couldn't create 'frequency' node\n"); 429 430 if (sysctl_createv(NULL, 0, NULL, 431 &sysctl_node, 432 CTLFLAG_READWRITE | CTLFLAG_OWNDESC, 433 CTLTYPE_INT, "target", "CPU speed", sysctl_cpuspeed_temp, 434 0, sc, 0, CTL_MACHDEP, me->sysctl_num, freq->sysctl_num, 435 CTL_CREATE, CTL_EOL) == 0) { 436 } else 437 printf("couldn't create 'target' node\n"); 438 439 if (sysctl_createv(NULL, 0, NULL, 440 &sysctl_node, 441 CTLFLAG_READWRITE, 442 CTLTYPE_INT, "current", NULL, sysctl_cpuspeed_cur, 443 1, sc, 0, CTL_MACHDEP, me->sysctl_num, freq->sysctl_num, 444 CTL_CREATE, CTL_EOL) == 0) { 445 } else 446 printf("couldn't create 'current' node\n"); 447 448 if (sysctl_createv(NULL, 0, NULL, 449 &sysctl_node, 450 CTLFLAG_READWRITE, 451 CTLTYPE_STRING, "available", NULL, sysctl_cpuspeed_available, 452 2, sc, 0, CTL_MACHDEP, me->sysctl_num, freq->sysctl_num, 453 CTL_CREATE, CTL_EOL) == 0) { 454 } else 455 printf("couldn't create 'available' node\n"); 456 printf("speed: %d\n", curcpu()->ci_khz); 457 458 /* support cpufreq */ 459 snprintf(cf->cf_name, CPUFREQ_NAME_MAX, "Intrepid"); 460 cf->cf_state[0].cfs_freq = sc->sc_spd_hi; 461 cf->cf_state[1].cfs_freq = sc->sc_spd_lo; 462 cf->cf_state_count = 2; 463 cf->cf_mp = FALSE; 464 cf->cf_cookie = sc; 465 cf->cf_get_freq = obio_get_freq; 466 cf->cf_set_freq = obio_set_freq; 467 /* 468 * XXX 469 * cpufreq_register() calls xc_broadcast() which relies on kthreads 470 * running so we need to postpone it 471 */ 472 config_interrupts(sc->sc_dev, obio_setup_cpufreq); 473 } 474 475 static void 476 obio_set_cpu_speed(struct obio_softc *sc, int fast) 477 { 478 479 if (sc->sc_voltage < 0) 480 return; 481 482 if (sc->sc_busspeed >= 0) { 483 /* set voltage and speed via gpio */ 484 if (fast) { 485 bus_space_write_1(sc->sc_tag, sc->sc_bh, 486 sc->sc_voltage, 5); 487 bus_space_write_1(sc->sc_tag, sc->sc_bh, 488 sc->sc_busspeed, 5); 489 } else { 490 bus_space_write_1(sc->sc_tag, sc->sc_bh, 491 sc->sc_busspeed, 4); 492 bus_space_write_1(sc->sc_tag, sc->sc_bh, 493 sc->sc_voltage, 4); 494 } 495 } 496 else { 497 /* set voltage via gpio and speed via the 7447A's DFS bit */ 498 if (fast) { 499 bus_space_write_1(sc->sc_tag, sc->sc_bh, 500 sc->sc_voltage, 5); 501 DELAY(1000); 502 } 503 504 /* set DFS for all cpus */ 505 cpu_set_dfs(fast ? 1 : 2); 506 DELAY(100); 507 508 if (!fast) { 509 bus_space_write_1(sc->sc_tag, sc->sc_bh, 510 sc->sc_voltage, 4); 511 DELAY(1000); 512 } 513 } 514 } 515 516 static int 517 obio_get_cpu_speed(struct obio_softc *sc) 518 { 519 520 if (sc->sc_voltage < 0) 521 return 0; 522 523 if (sc->sc_busspeed >= 0) { 524 if (bus_space_read_1(sc->sc_tag, sc->sc_bh, sc->sc_busspeed) 525 & 1) 526 return 1; 527 } 528 else 529 return cpu_get_dfs() == 1; 530 531 return 0; 532 } 533 534 static void 535 obio_get_freq(void *cookie, void *spd) 536 { 537 struct obio_softc *sc = cookie; 538 uint32_t *freq; 539 540 freq = spd; 541 if (obio_get_cpu_speed(sc) == 0) { 542 *freq = sc->sc_spd_lo; 543 } else 544 *freq = sc->sc_spd_hi; 545 } 546 547 static void 548 obio_set_freq(void *cookie, void *spd) 549 { 550 struct obio_softc *sc = cookie; 551 uint32_t *freq; 552 553 freq = spd; 554 if (*freq == sc->sc_spd_lo) { 555 obio_set_cpu_speed(sc, 0); 556 } else if (*freq == sc->sc_spd_hi) { 557 obio_set_cpu_speed(sc, 1); 558 } else 559 aprint_error_dev(sc->sc_dev, "%s(%d) bogus CPU speed\n", __func__, *freq); 560 } 561 562 static int 563 sysctl_cpuspeed_temp(SYSCTLFN_ARGS) 564 { 565 struct sysctlnode node = *rnode; 566 struct obio_softc *sc = node.sysctl_data; 567 int speed, mhz; 568 569 speed = obio_get_cpu_speed(sc); 570 switch (speed) { 571 case 0: 572 mhz = sc->sc_spd_lo; 573 break; 574 case 1: 575 mhz = sc->sc_spd_hi; 576 break; 577 default: 578 speed = -1; 579 } 580 node.sysctl_data = &mhz; 581 if (sysctl_lookup(SYSCTLFN_CALL(&node)) == 0) { 582 int new_reg; 583 584 new_reg = *(int *)node.sysctl_data; 585 if (new_reg == sc->sc_spd_lo) { 586 obio_set_cpu_speed(sc, 0); 587 } else if (new_reg == sc->sc_spd_hi) { 588 obio_set_cpu_speed(sc, 1); 589 } else { 590 printf("%s: new_reg %d\n", __func__, new_reg); 591 return EINVAL; 592 } 593 return 0; 594 } 595 return EINVAL; 596 } 597 598 static int 599 sysctl_cpuspeed_cur(SYSCTLFN_ARGS) 600 { 601 struct sysctlnode node = *rnode; 602 struct obio_softc *sc = node.sysctl_data; 603 int speed, mhz; 604 605 speed = obio_get_cpu_speed(sc); 606 switch (speed) { 607 case 0: 608 mhz = sc->sc_spd_lo; 609 break; 610 case 1: 611 mhz = sc->sc_spd_hi; 612 break; 613 default: 614 speed = -1; 615 } 616 node.sysctl_data = &mhz; 617 return sysctl_lookup(SYSCTLFN_CALL(&node)); 618 } 619 620 static int 621 sysctl_cpuspeed_available(SYSCTLFN_ARGS) 622 { 623 struct sysctlnode node = *rnode; 624 struct obio_softc *sc = node.sysctl_data; 625 char buf[128]; 626 int speed; 627 628 speed = obio_get_cpu_speed(sc); 629 snprintf(buf, 128, "%d %d", sc->sc_spd_lo, sc->sc_spd_hi); 630 node.sysctl_data = buf; 631 return(sysctl_lookup(SYSCTLFN_CALL(&node))); 632 } 633 634 SYSCTL_SETUP(sysctl_ams_setup, "sysctl obio subtree setup") 635 { 636 637 sysctl_createv(NULL, 0, NULL, NULL, 638 CTLFLAG_PERMANENT, 639 CTLTYPE_NODE, "machdep", NULL, 640 NULL, 0, NULL, 0, 641 CTL_MACHDEP, CTL_EOL); 642 } 643 644 #endif /* OBIO_SPEEDCONTROL */ 645