1 /* $NetBSD: obio.c,v 1.54 2025/08/20 07:53:33 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.54 2025/08/20 07:53:33 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 #include <sys/kthread.h> 43 44 #include <dev/pci/pcivar.h> 45 #include <dev/pci/pcidevs.h> 46 #include <dev/sysmon/sysmonvar.h> 47 48 #include <dev/ofw/openfirm.h> 49 50 #include <machine/autoconf.h> 51 52 #include <macppc/dev/obiovar.h> 53 54 #include <powerpc/cpu.h> 55 #include <sys/cpufreq.h> 56 #include <dev/led.h> 57 #include <macppc/dev/fancontrolvar.h> 58 59 #include "opt_obio.h" 60 61 #ifdef OBIO_DEBUG 62 # define DPRINTF printf 63 #else 64 # define DPRINTF while (0) printf 65 #endif 66 67 static void obio_attach(device_t, device_t, void *); 68 static int obio_match(device_t, cfdata_t, void *); 69 static int obio_print(void *, const char *); 70 71 struct obio_softc { 72 device_t sc_dev; 73 bus_space_tag_t sc_tag; 74 bus_space_handle_t sc_bh; 75 int sc_node; 76 int sc_voltage; 77 int sc_busspeed; 78 int sc_spd_hi, sc_spd_lo; 79 struct cpufreq sc_cf; 80 /* Xserve G4 pwm fan control */ 81 fancontrol_zone_t sc_zones[2]; 82 int sc_duty[2]; 83 int sc_target[2]; 84 int sc_pwm; 85 lwp_t *sc_thread; 86 int sc_dying; 87 }; 88 89 static struct obio_softc *obio0 = NULL; 90 91 static void obio_setup_gpios(struct obio_softc *, int); 92 static void obio_set_cpu_speed(struct obio_softc *, int); 93 static int obio_get_cpu_speed(struct obio_softc *); 94 static int sysctl_cpuspeed_temp(SYSCTLFN_ARGS); 95 static int sysctl_cpuspeed_cur(SYSCTLFN_ARGS); 96 static int sysctl_cpuspeed_available(SYSCTLFN_ARGS); 97 static int sysctl_gpio(SYSCTLFN_ARGS); 98 #ifdef OBIO_GPIO_DEBUG 99 static int sysctl_level(SYSCTLFN_ARGS); 100 #endif 101 static int sysctl_pwm(SYSCTLFN_ARGS); 102 static void obio_get_freq(void *, void *); 103 static void obio_set_freq(void *, void *); 104 static int gpio_get(void *); 105 static void gpio_set(void *, int); 106 107 static bool is_cpu(const envsys_data_t *); 108 static bool is_case(const envsys_data_t *); 109 110 static int obio_set_rpm(void *, int, int); 111 static int obio_get_rpm(void *, int); 112 static int obio_get_pwm(int); 113 static void obio_set_pwm(int, int); 114 115 static void obio_adjust(void *); 116 117 static const char *keylargo[] = {"Keylargo", 118 "AAPL,Keylargo", 119 "K2-Keylargo", 120 NULL}; 121 122 static const char *xserve[] = {"RackMac1,2", 123 NULL}; 124 125 126 CFATTACH_DECL_NEW(obio, sizeof(struct obio_softc), 127 obio_match, obio_attach, NULL, NULL); 128 129 int 130 obio_match(device_t parent, cfdata_t cf, void *aux) 131 { 132 struct pci_attach_args *pa = aux; 133 134 if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_APPLE) 135 switch (PCI_PRODUCT(pa->pa_id)) { 136 case PCI_PRODUCT_APPLE_GC: 137 case PCI_PRODUCT_APPLE_OHARE: 138 case PCI_PRODUCT_APPLE_HEATHROW: 139 case PCI_PRODUCT_APPLE_PADDINGTON: 140 case PCI_PRODUCT_APPLE_KEYLARGO: 141 case PCI_PRODUCT_APPLE_PANGEA_MACIO: 142 case PCI_PRODUCT_APPLE_INTREPID: 143 case PCI_PRODUCT_APPLE_K2: 144 case PCI_PRODUCT_APPLE_SHASTA: 145 return 1; 146 } 147 148 return 0; 149 } 150 151 /* 152 * Attach all the sub-devices we can find 153 */ 154 void 155 obio_attach(device_t parent, device_t self, void *aux) 156 { 157 struct obio_softc *sc = device_private(self); 158 struct pci_attach_args *pa = aux; 159 struct confargs ca; 160 bus_space_handle_t bsh; 161 int node, child, namelen, error, root, is_xserve = 0; 162 u_int reg[20]; 163 int intr[6], parent_intr = 0, parent_nintr = 0; 164 int map_size = 0x1000; 165 char name[32]; 166 char compat[32]; 167 168 sc->sc_dev = self; 169 sc->sc_voltage = -1; 170 sc->sc_busspeed = -1; 171 sc->sc_spd_lo = 600; 172 sc->sc_spd_hi = 800; 173 sc->sc_dying = 0; 174 root = OF_finddevice("/"); 175 is_xserve = of_compatible(root, xserve); 176 177 switch (PCI_PRODUCT(pa->pa_id)) { 178 179 case PCI_PRODUCT_APPLE_GC: 180 case PCI_PRODUCT_APPLE_OHARE: 181 case PCI_PRODUCT_APPLE_HEATHROW: 182 case PCI_PRODUCT_APPLE_PADDINGTON: 183 case PCI_PRODUCT_APPLE_KEYLARGO: 184 case PCI_PRODUCT_APPLE_PANGEA_MACIO: 185 case PCI_PRODUCT_APPLE_INTREPID: 186 node = pcidev_to_ofdev(pa->pa_pc, pa->pa_tag); 187 if (node == -1) 188 node = OF_finddevice("mac-io"); 189 if (node == -1) 190 node = OF_finddevice("/pci/mac-io"); 191 break; 192 case PCI_PRODUCT_APPLE_K2: 193 case PCI_PRODUCT_APPLE_SHASTA: 194 node = OF_finddevice("mac-io"); 195 map_size = 0x10000; 196 break; 197 198 default: 199 node = -1; 200 break; 201 } 202 if (node == -1) 203 panic("macio not found or unknown"); 204 205 sc->sc_node = node; 206 207 #if defined (PMAC_G5) 208 if (OF_getprop(node, "assigned-addresses", reg, sizeof(reg)) < 20) 209 { 210 return; 211 } 212 #else 213 if (OF_getprop(node, "assigned-addresses", reg, sizeof(reg)) < 12) 214 return; 215 #endif /* PMAC_G5 */ 216 217 /* 218 * XXX 219 * This relies on the primary obio always attaching first which is 220 * true on the PowerBook 3400c and similar machines but may or may 221 * not work on others. We can't rely on the node name since Apple 222 * didn't follow anything remotely resembling a consistent naming 223 * scheme. 224 */ 225 if (obio0 == NULL) 226 obio0 = sc; 227 228 ca.ca_baseaddr = reg[2]; 229 ca.ca_tag = pa->pa_memt; 230 sc->sc_tag = pa->pa_memt; 231 error = bus_space_map (pa->pa_memt, ca.ca_baseaddr, map_size, 0, &bsh); 232 if (error) 233 panic(": failed to map mac-io %#x", ca.ca_baseaddr); 234 sc->sc_bh = bsh; 235 236 printf(": addr 0x%x\n", ca.ca_baseaddr); 237 238 /* Enable internal modem (KeyLargo) */ 239 if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_KEYLARGO) { 240 aprint_normal("%s: enabling KeyLargo internal modem\n", 241 device_xname(self)); 242 bus_space_write_4(ca.ca_tag, bsh, 0x40, 243 bus_space_read_4(ca.ca_tag, bsh, 0x40) & ~(1<<25)); 244 } 245 246 /* Enable internal modem (Pangea) */ 247 if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_PANGEA_MACIO) { 248 /* set reset */ 249 bus_space_write_1(ca.ca_tag, bsh, 0x006a + 0x03, 0x04); 250 /* power modem on */ 251 bus_space_write_1(ca.ca_tag, bsh, 0x006a + 0x02, 0x04); 252 /* unset reset */ 253 bus_space_write_1(ca.ca_tag, bsh, 0x006a + 0x03, 0x05); 254 } 255 256 /* Gatwick and Paddington use same product ID */ 257 namelen = OF_getprop(node, "compatible", compat, sizeof(compat)); 258 259 if (strcmp(compat, "gatwick") == 0) { 260 parent_nintr = OF_getprop(node, "AAPL,interrupts", intr, 261 sizeof(intr)); 262 parent_intr = intr[0]; 263 } else { 264 /* Enable CD and microphone sound input. */ 265 if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_PADDINGTON) 266 bus_space_write_1(ca.ca_tag, bsh, 0x37, 0x03); 267 } 268 269 devhandle_t selfh = device_handle(self); 270 for (child = OF_child(node); child; child = OF_peer(child)) { 271 namelen = OF_getprop(child, "name", name, sizeof(name)); 272 if (namelen < 0) 273 continue; 274 if (namelen >= sizeof(name)) 275 continue; 276 277 if (strcmp(name, "gpio") == 0) { 278 279 obio_setup_gpios(sc, child); 280 continue; 281 } 282 283 name[namelen] = 0; 284 ca.ca_name = name; 285 ca.ca_node = child; 286 ca.ca_tag = pa->pa_memt; 287 288 ca.ca_nreg = OF_getprop(child, "reg", reg, sizeof(reg)); 289 290 if (strcmp(compat, "gatwick") != 0) { 291 ca.ca_nintr = OF_getprop(child, "AAPL,interrupts", intr, 292 sizeof(intr)); 293 if (ca.ca_nintr == -1) 294 ca.ca_nintr = OF_getprop(child, "interrupts", intr, 295 sizeof(intr)); 296 } else { 297 intr[0] = parent_intr; 298 ca.ca_nintr = parent_nintr; 299 } 300 ca.ca_reg = reg; 301 ca.ca_intr = intr; 302 303 config_found(self, &ca, obio_print, 304 CFARGS(.devhandle = devhandle_from_of(selfh, child))); 305 } 306 if (is_xserve) { 307 struct sysctlnode *me; 308 309 printf("starting Xserve fan control\n"); 310 311 sysctl_createv(NULL, 0, NULL, (void *) &me, 312 CTLFLAG_READWRITE, 313 CTLTYPE_NODE, device_xname(sc->sc_dev), NULL, 314 NULL, 0, NULL, 0, 315 CTL_MACHDEP, CTL_CREATE, CTL_EOL); 316 317 sc->sc_zones[0].name = "CPU"; 318 sc->sc_zones[0].filter = is_cpu; 319 sc->sc_zones[0].cookie = sc; 320 sc->sc_zones[0].get_rpm = obio_get_rpm; 321 sc->sc_zones[0].set_rpm = obio_set_rpm; 322 sc->sc_zones[0].Tmin = 30; 323 sc->sc_zones[0].Tmax = 60; 324 sc->sc_zones[0].nfans = 1; 325 sc->sc_zones[0].fans[0].name = "CPU fan"; 326 sc->sc_zones[0].fans[0].num = 0; 327 sc->sc_zones[0].fans[0].min_rpm = 800; 328 sc->sc_zones[0].fans[0].max_rpm = 6000; 329 sc->sc_duty[0] = obio_get_pwm(0); 330 fancontrol_init_zone(&sc->sc_zones[0], me); 331 332 sc->sc_zones[1].name = "Case"; 333 sc->sc_zones[1].filter = is_case; 334 sc->sc_zones[1].cookie = sc; 335 sc->sc_zones[1].get_rpm = obio_get_rpm; 336 sc->sc_zones[1].set_rpm = obio_set_rpm; 337 sc->sc_zones[1].Tmin = 30; 338 sc->sc_zones[1].Tmax = 50; 339 sc->sc_zones[1].nfans = 1; 340 sc->sc_zones[1].fans[0].name = "Case fan"; 341 sc->sc_zones[1].fans[0].num = 1; 342 sc->sc_zones[1].fans[0].min_rpm = 800; 343 sc->sc_zones[1].fans[0].max_rpm = 6000; 344 sc->sc_duty[1] = obio_get_pwm(1); 345 fancontrol_init_zone(&sc->sc_zones[1], me); 346 347 kthread_create(PRI_NONE, 0, curcpu(), obio_adjust, sc, 348 &sc->sc_thread, "fan control"); 349 } 350 } 351 352 static const char * const skiplist[] = { 353 "interrupt-controller", 354 "chrp,open-pic", 355 "open-pic", 356 "mpic", 357 "gpio", 358 "escc-legacy", 359 "timer", 360 "i2c", 361 "power-mgt", 362 "escc", 363 "battery", 364 "backlight" 365 366 }; 367 368 #define N_LIST (sizeof(skiplist) / sizeof(skiplist[0])) 369 370 int 371 obio_print(void *aux, const char *obio) 372 { 373 struct confargs *ca = aux; 374 int i; 375 376 for (i = 0; i < N_LIST; i++) 377 if (strcmp(ca->ca_name, skiplist[i]) == 0) 378 return QUIET; 379 380 if (obio) 381 aprint_normal("%s at %s", ca->ca_name, obio); 382 383 if (ca->ca_nreg > 0) 384 aprint_normal(" offset 0x%x", ca->ca_reg[0]); 385 386 return UNCONF; 387 } 388 389 void obio_write_4(int offset, uint32_t value) 390 { 391 if (obio0 == NULL) 392 return; 393 bus_space_write_4(obio0->sc_tag, obio0->sc_bh, offset, value); 394 } 395 396 void obio_write_1(int offset, uint8_t value) 397 { 398 if (obio0 == NULL) 399 return; 400 bus_space_write_1(obio0->sc_tag, obio0->sc_bh, offset, value); 401 } 402 403 uint32_t obio_read_4(int offset) 404 { 405 if (obio0 == NULL) 406 return 0xffffffff; 407 return bus_space_read_4(obio0->sc_tag, obio0->sc_bh, offset); 408 } 409 410 uint8_t obio_read_1(int offset) 411 { 412 if (obio0 == NULL) 413 return 0xff; 414 return bus_space_read_1(obio0->sc_tag, obio0->sc_bh, offset); 415 } 416 417 int 418 obio_space_map(bus_addr_t addr, bus_size_t size, bus_space_handle_t *bh) 419 { 420 if (obio0 == NULL) 421 return 0xff; 422 return bus_space_subregion(obio0->sc_tag, obio0->sc_bh, 423 addr & 0xfffff, size, bh); 424 } 425 426 static void 427 obio_setup_cpufreq(device_t dev) 428 { 429 struct obio_softc *sc = device_private(dev); 430 int ret; 431 432 ret = cpufreq_register(&sc->sc_cf); 433 if (ret != 0) 434 aprint_error_dev(sc->sc_dev, "cpufreq_register() failed, error %d\n", ret); 435 } 436 437 static void 438 obio_setup_gpios(struct obio_softc *sc, int node) 439 { 440 uint32_t gpio_base, reg[6]; 441 const struct sysctlnode *sysctl_node, *me, *freq, *gpio; 442 struct cpufreq *cf = &sc->sc_cf; 443 char name[32]; 444 int child, use_dfs, cpunode, hiclock; 445 446 if (! of_compatible(sc->sc_node, keylargo)) 447 return; 448 449 if (OF_getprop(node, "reg", reg, sizeof(reg)) < 4) 450 return; 451 452 gpio_base = reg[0]; 453 DPRINTF("gpio_base: %02x\n", gpio_base); 454 455 if (sysctl_createv(NULL, 0, NULL, 456 &gpio, 457 CTLFLAG_READWRITE, CTLTYPE_NODE, "gpio", NULL, NULL, 458 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL) != 0) 459 printf("couldn't create 'gpio' node\n"); 460 #ifdef OBIO_GPIO_DEBUG 461 sysctl_createv(NULL, 0, NULL, &me, 462 CTLFLAG_READWRITE, CTLTYPE_INT, "level0", NULL, 463 sysctl_level, 1, (void *)0x50, 0, CTL_HW, 464 gpio->sysctl_num, CTL_CREATE, CTL_EOL); 465 sysctl_createv(NULL, 0, NULL, &me, 466 CTLFLAG_READWRITE, CTLTYPE_INT, "level1", NULL, 467 sysctl_level, 1, (void *)0x54, 0, CTL_HW, 468 gpio->sysctl_num, CTL_CREATE, CTL_EOL); 469 #endif 470 sysctl_createv(NULL, 0, NULL, &me, 471 CTLFLAG_READWRITE, CTLTYPE_INT, "pwm0", NULL, 472 sysctl_pwm, 1, (void *)0, 0, CTL_HW, 473 gpio->sysctl_num, CTL_CREATE, CTL_EOL); 474 sysctl_createv(NULL, 0, NULL, &me, 475 CTLFLAG_READWRITE, CTLTYPE_INT, "pwm1", NULL, 476 sysctl_pwm, 1, (void *)1, 0, CTL_HW, 477 gpio->sysctl_num, CTL_CREATE, CTL_EOL); 478 sysctl_createv(NULL, 0, NULL, &me, 479 CTLFLAG_READWRITE, CTLTYPE_INT, "pwm2", NULL, 480 sysctl_pwm, 1, (void *)2, 0, CTL_HW, 481 gpio->sysctl_num, CTL_CREATE, CTL_EOL); 482 sysctl_createv(NULL, 0, NULL, &me, 483 CTLFLAG_READWRITE, CTLTYPE_INT, "pwm3", NULL, 484 sysctl_pwm, 1, (void *)3, 0, CTL_HW, 485 gpio->sysctl_num, CTL_CREATE, CTL_EOL); 486 #ifdef OBIO_GPIO_DEBUG 487 sysctl_createv(NULL, 0, NULL, &me, 488 CTLFLAG_READWRITE, CTLTYPE_INT, "prescale", NULL, 489 sysctl_level, 1, (void *)0x4c, 0, CTL_HW, 490 gpio->sysctl_num, CTL_CREATE, CTL_EOL); 491 sysctl_createv(NULL, 0, NULL, &me, 492 CTLFLAG_READWRITE, CTLTYPE_INT, "tach0", NULL, 493 sysctl_level, 1, (void *)0x34, 0, CTL_HW, 494 gpio->sysctl_num, CTL_CREATE, CTL_EOL); 495 sysctl_createv(NULL, 0, NULL, &me, 496 CTLFLAG_READWRITE, CTLTYPE_INT, "tach1", NULL, 497 sysctl_level, 1, (void *)0x2c, 0, CTL_HW, 498 gpio->sysctl_num, CTL_CREATE, CTL_EOL); 499 #endif 500 /* now look for voltage and bus speed gpios */ 501 use_dfs = 0; 502 for (child = OF_child(node); child; child = OF_peer(child)) { 503 504 if (OF_getprop(child, "name", name, sizeof(name)) < 1) 505 continue; 506 507 if (OF_getprop(child, "reg", reg, sizeof(reg)) < 4) 508 continue; 509 510 /* 511 * These register offsets either have to be added to the obio 512 * base address or to the gpio base address. This differs 513 * even in the same OF-tree! So we guess the offset is 514 * based on obio when it is larger than the gpio_base. 515 */ 516 if (reg[0] >= gpio_base) 517 reg[0] -= gpio_base; 518 519 if (strcmp(name, "frequency-gpio") == 0) { 520 DPRINTF("found frequency_gpio at %02x\n", reg[0]); 521 sc->sc_busspeed = gpio_base + reg[0]; 522 } else 523 if (strcmp(name, "voltage-gpio") == 0) { 524 DPRINTF("found voltage_gpio at %02x\n", reg[0]); 525 sc->sc_voltage = gpio_base + reg[0]; 526 } else 527 if (strcmp(name, "cpu-vcore-select") == 0) { 528 DPRINTF("found cpu-vcore-select at %02x\n", reg[0]); 529 sc->sc_voltage = gpio_base + reg[0]; 530 /* frequency gpio is not needed, we use cpu's DFS */ 531 use_dfs = 1; 532 } else if (strcmp(name, "indicatorLED-gpio") == 0) { 533 led_attach("indicator", (void *)(gpio_base + reg[0]), 534 gpio_get, gpio_set); 535 } else { 536 /* attach a sysctl node */ 537 if (sysctl_createv(NULL, 0, NULL, &me, 538 CTLFLAG_READWRITE, CTLTYPE_INT, name, NULL, 539 sysctl_gpio, 1, (void *)(reg[0] + gpio_base), 0, CTL_HW, 540 gpio->sysctl_num, CTL_CREATE, CTL_EOL) != 0) { 541 printf("failed to create %s node\n", name); 542 } 543 } 544 } 545 546 if ((sc->sc_voltage < 0) || (sc->sc_busspeed < 0 && !use_dfs)) 547 return; 548 549 printf("%s: enabling Intrepid CPU speed control\n", 550 device_xname(sc->sc_dev)); 551 552 sc->sc_spd_lo = curcpu()->ci_khz / 1000; 553 hiclock = 0; 554 cpunode = OF_finddevice("/cpus/@0"); 555 OF_getprop(cpunode, "clock-frequency", &hiclock, 4); 556 if (hiclock != 0) 557 sc->sc_spd_hi = (hiclock + 500000) / 1000000; 558 printf("hiclock: %d\n", sc->sc_spd_hi); 559 if (use_dfs) sc->sc_spd_lo = sc->sc_spd_hi / 2; 560 561 sysctl_node = NULL; 562 563 if (sysctl_createv(NULL, 0, NULL, 564 &me, 565 CTLFLAG_READWRITE, CTLTYPE_NODE, "cpu", NULL, NULL, 566 0, NULL, 0, CTL_MACHDEP, CTL_CREATE, CTL_EOL) != 0) 567 printf("couldn't create 'cpu' node\n"); 568 569 if (sysctl_createv(NULL, 0, NULL, 570 &freq, 571 CTLFLAG_READWRITE, CTLTYPE_NODE, "frequency", NULL, NULL, 572 0, NULL, 0, CTL_MACHDEP, me->sysctl_num, CTL_CREATE, CTL_EOL) != 0) 573 printf("couldn't create 'frequency' node\n"); 574 575 if (sysctl_createv(NULL, 0, NULL, 576 &sysctl_node, 577 CTLFLAG_READWRITE | CTLFLAG_OWNDESC, 578 CTLTYPE_INT, "target", "CPU speed", sysctl_cpuspeed_temp, 579 0, (void *)sc, 0, CTL_MACHDEP, me->sysctl_num, freq->sysctl_num, 580 CTL_CREATE, CTL_EOL) == 0) { 581 } else 582 printf("couldn't create 'target' node\n"); 583 584 if (sysctl_createv(NULL, 0, NULL, 585 &sysctl_node, 586 CTLFLAG_READWRITE, 587 CTLTYPE_INT, "current", NULL, sysctl_cpuspeed_cur, 588 1, (void *)sc, 0, CTL_MACHDEP, me->sysctl_num, freq->sysctl_num, 589 CTL_CREATE, CTL_EOL) == 0) { 590 } else 591 printf("couldn't create 'current' node\n"); 592 593 if (sysctl_createv(NULL, 0, NULL, 594 &sysctl_node, 595 CTLFLAG_READWRITE, 596 CTLTYPE_STRING, "available", NULL, sysctl_cpuspeed_available, 597 2, (void *)sc, 0, CTL_MACHDEP, me->sysctl_num, freq->sysctl_num, 598 CTL_CREATE, CTL_EOL) == 0) { 599 } else 600 printf("couldn't create 'available' node\n"); 601 printf("speed: %d\n", curcpu()->ci_khz); 602 603 /* support cpufreq */ 604 snprintf(cf->cf_name, CPUFREQ_NAME_MAX, "Intrepid"); 605 cf->cf_state[0].cfs_freq = sc->sc_spd_hi; 606 cf->cf_state[1].cfs_freq = sc->sc_spd_lo; 607 cf->cf_state_count = 2; 608 cf->cf_mp = FALSE; 609 cf->cf_cookie = sc; 610 cf->cf_get_freq = obio_get_freq; 611 cf->cf_set_freq = obio_set_freq; 612 /* 613 * XXX 614 * cpufreq_register() calls xc_broadcast() which relies on kthreads 615 * running so we need to postpone it 616 */ 617 config_interrupts(sc->sc_dev, obio_setup_cpufreq); 618 } 619 620 static void 621 obio_set_cpu_speed(struct obio_softc *sc, int fast) 622 { 623 624 if (sc->sc_voltage < 0) 625 return; 626 627 if (sc->sc_busspeed >= 0) { 628 /* set voltage and speed via gpio */ 629 if (fast) { 630 bus_space_write_1(sc->sc_tag, sc->sc_bh, 631 sc->sc_voltage, 5); 632 bus_space_write_1(sc->sc_tag, sc->sc_bh, 633 sc->sc_busspeed, 5); 634 } else { 635 bus_space_write_1(sc->sc_tag, sc->sc_bh, 636 sc->sc_busspeed, 4); 637 bus_space_write_1(sc->sc_tag, sc->sc_bh, 638 sc->sc_voltage, 4); 639 } 640 } 641 else { 642 /* set voltage via gpio and speed via the 7447A's DFS bit */ 643 if (fast) { 644 bus_space_write_1(sc->sc_tag, sc->sc_bh, 645 sc->sc_voltage, 5); 646 DELAY(1000); 647 } 648 649 /* set DFS for all cpus */ 650 cpu_set_dfs(fast ? 1 : 2); 651 DELAY(100); 652 653 if (!fast) { 654 bus_space_write_1(sc->sc_tag, sc->sc_bh, 655 sc->sc_voltage, 4); 656 DELAY(1000); 657 } 658 } 659 } 660 661 static int 662 obio_get_cpu_speed(struct obio_softc *sc) 663 { 664 665 if (sc->sc_voltage < 0) 666 return 0; 667 668 if (sc->sc_busspeed >= 0) { 669 if (bus_space_read_1(sc->sc_tag, sc->sc_bh, sc->sc_busspeed) 670 & 1) 671 return 1; 672 } 673 else 674 return cpu_get_dfs() == 1; 675 676 return 0; 677 } 678 679 static void 680 obio_get_freq(void *cookie, void *spd) 681 { 682 struct obio_softc *sc = cookie; 683 uint32_t *freq; 684 685 freq = spd; 686 if (obio_get_cpu_speed(sc) == 0) { 687 *freq = sc->sc_spd_lo; 688 } else 689 *freq = sc->sc_spd_hi; 690 } 691 692 static void 693 obio_set_freq(void *cookie, void *spd) 694 { 695 struct obio_softc *sc = cookie; 696 uint32_t *freq; 697 698 freq = spd; 699 if (*freq == sc->sc_spd_lo) { 700 obio_set_cpu_speed(sc, 0); 701 } else if (*freq == sc->sc_spd_hi) { 702 obio_set_cpu_speed(sc, 1); 703 } else 704 aprint_error_dev(sc->sc_dev, "%s(%d) bogus CPU speed\n", __func__, *freq); 705 } 706 707 static int 708 sysctl_cpuspeed_temp(SYSCTLFN_ARGS) 709 { 710 struct sysctlnode node = *rnode; 711 struct obio_softc *sc = node.sysctl_data; 712 int speed, mhz; 713 714 speed = obio_get_cpu_speed(sc); 715 switch (speed) { 716 case 0: 717 mhz = sc->sc_spd_lo; 718 break; 719 case 1: 720 mhz = sc->sc_spd_hi; 721 break; 722 default: 723 speed = -1; 724 } 725 node.sysctl_data = &mhz; 726 if (sysctl_lookup(SYSCTLFN_CALL(&node)) == 0) { 727 int new_reg; 728 729 new_reg = *(int *)node.sysctl_data; 730 if (new_reg == sc->sc_spd_lo) { 731 obio_set_cpu_speed(sc, 0); 732 } else if (new_reg == sc->sc_spd_hi) { 733 obio_set_cpu_speed(sc, 1); 734 } else { 735 printf("%s: new_reg %d\n", __func__, new_reg); 736 return EINVAL; 737 } 738 return 0; 739 } 740 return EINVAL; 741 } 742 743 static int 744 sysctl_cpuspeed_cur(SYSCTLFN_ARGS) 745 { 746 struct sysctlnode node = *rnode; 747 struct obio_softc *sc = node.sysctl_data; 748 int speed, mhz; 749 750 speed = obio_get_cpu_speed(sc); 751 switch (speed) { 752 case 0: 753 mhz = sc->sc_spd_lo; 754 break; 755 case 1: 756 mhz = sc->sc_spd_hi; 757 break; 758 default: 759 speed = -1; 760 } 761 node.sysctl_data = &mhz; 762 return sysctl_lookup(SYSCTLFN_CALL(&node)); 763 } 764 765 static int 766 sysctl_cpuspeed_available(SYSCTLFN_ARGS) 767 { 768 struct sysctlnode node = *rnode; 769 struct obio_softc *sc = node.sysctl_data; 770 char buf[128]; 771 772 snprintf(buf, 128, "%d %d", sc->sc_spd_lo, sc->sc_spd_hi); 773 node.sysctl_data = buf; 774 return(sysctl_lookup(SYSCTLFN_CALL(&node))); 775 } 776 777 static int 778 sysctl_gpio(SYSCTLFN_ARGS) 779 { 780 struct sysctlnode node = *rnode; 781 int reg = (int)node.sysctl_data; 782 uint32_t val, ret; 783 DPRINTF("%s: reg %x\n", __func__, reg); 784 val = obio_read_1(reg); 785 if (val & GPIO_DDR_OUTPUT) { 786 ret = (val & GPIO_DATA) != 0; 787 } else 788 ret = (val & GPIO_LEVEL) != 0; 789 node.sysctl_data = &ret; 790 node.sysctl_size = 4; 791 return(sysctl_lookup(SYSCTLFN_CALL(&node))); 792 } 793 794 #ifdef OBIO_GPIO_DEBUG 795 static int 796 sysctl_level(SYSCTLFN_ARGS) 797 { 798 struct sysctlnode node = *rnode; 799 int reg = (int)node.sysctl_data; 800 uint32_t val; 801 val = obio_read_4(reg); 802 DPRINTF("%s: reg %x %08x\n", __func__, reg, val); 803 node.sysctl_data = &val; 804 node.sysctl_size = 4; 805 return(sysctl_lookup(SYSCTLFN_CALL(&node))); 806 } 807 #endif 808 809 static int 810 sysctl_pwm(SYSCTLFN_ARGS) 811 { 812 struct sysctlnode node = *rnode; 813 int which = (int)node.sysctl_data; 814 uint32_t pwm; 815 816 pwm = obio_get_pwm(which); 817 818 if (newp) { 819 /* we're asked to write */ 820 node.sysctl_data = &pwm; 821 if (sysctl_lookup(SYSCTLFN_CALL(&node)) == 0) { 822 823 pwm = *(int *)node.sysctl_data; 824 obio_set_pwm(which, pwm); 825 return 0; 826 } 827 return EINVAL; 828 } 829 node.sysctl_data = &pwm; 830 node.sysctl_size = 4; 831 return(sysctl_lookup(SYSCTLFN_CALL(&node))); 832 } 833 834 SYSCTL_SETUP(sysctl_ams_setup, "sysctl obio subtree setup") 835 { 836 837 sysctl_createv(NULL, 0, NULL, NULL, 838 CTLFLAG_PERMANENT, 839 CTLTYPE_NODE, "machdep", NULL, 840 NULL, 0, NULL, 0, 841 CTL_MACHDEP, CTL_EOL); 842 sysctl_createv(NULL, 0, NULL, NULL, 843 CTLFLAG_PERMANENT, 844 CTLTYPE_NODE, "hw", NULL, 845 NULL, 0, NULL, 0, 846 CTL_HW, CTL_EOL); 847 } 848 849 static int 850 gpio_get(void *cookie) 851 { 852 uint32_t reg = (uint32_t)cookie; 853 854 return ((obio_read_1(reg) & GPIO_LEVEL) != 0); 855 } 856 857 static void 858 gpio_set(void *cookie, int val) 859 { 860 uint32_t reg = (uint32_t)cookie; 861 uint8_t gpio = obio_read_1(reg); 862 863 if (val) { 864 gpio |= GPIO_DATA; 865 } else 866 gpio &= ~GPIO_DATA; 867 obio_write_1(reg, gpio); 868 } 869 870 /* Xserve fan control */ 871 static bool 872 is_cpu(const envsys_data_t *edata) 873 { 874 if (edata->units != ENVSYS_STEMP) 875 return false; 876 if ((strstr(edata->desc, "CPU") != NULL) || 877 (strstr(edata->desc, "ternal") != NULL)) 878 return TRUE; 879 return false; 880 } 881 882 static bool 883 is_case(const envsys_data_t *edata) 884 { 885 if (edata->units != ENVSYS_STEMP) 886 return false; 887 if ((strstr(edata->desc, "CASE") != NULL) || 888 (strstr(edata->desc, "monitor") != NULL)) 889 return TRUE; 890 return false; 891 } 892 893 static bool 894 is_fan0(const envsys_data_t *edata) 895 { 896 if (edata->units != ENVSYS_SFANRPM) 897 return false; 898 if (strstr(edata->desc, "FAN1") != NULL) 899 return TRUE; 900 return false; 901 } 902 903 static bool 904 is_fan1(const envsys_data_t *edata) 905 { 906 if (edata->units != ENVSYS_SFANRPM) 907 return false; 908 if (strstr(edata->desc, "FAN2") != NULL) 909 return TRUE; 910 return false; 911 } 912 913 static int 914 obio_get_pwm(int which) 915 { 916 uint32_t reg, mask; 917 int shift; 918 919 shift = (3 - which) * 8; 920 mask = 0xff << shift; 921 reg = obio_read_4(0x30); 922 return (reg & mask) >> shift; 923 } 924 925 static void 926 obio_set_pwm(int which, int pwm) 927 { 928 uint32_t reg, mask; 929 int shift; 930 931 shift = (3 - which) * 8; 932 mask = 0xff << shift; 933 reg = obio_read_4(0x30); 934 reg &= ~mask; 935 reg |= (pwm & 0xff) << shift; 936 obio_write_4(0x30, reg); 937 } 938 939 static int 940 obio_get_rpm(void *cookie, int which) 941 { 942 int rpm = 0; 943 944 if (which == 0) { 945 rpm = sysmon_envsys_get_max_value(is_fan0, true); 946 } else 947 rpm = sysmon_envsys_get_max_value(is_fan1, true); 948 return rpm; 949 } 950 951 static int 952 obio_set_rpm(void *cookie, int which, int speed) 953 { 954 struct obio_softc *sc = cookie; 955 int diff; 956 unsigned int nduty = sc->sc_duty[which]; 957 int current_speed; 958 959 sc->sc_target[which] = speed; 960 current_speed = obio_get_rpm(sc, which); 961 diff = current_speed - speed; 962 DPRINTF("d %d s %d t %d diff %d ", nduty, current_speed, speed, diff); 963 if (diff > 200) { 964 /* slow down */ 965 nduty += 2; 966 if (nduty > 200) nduty = 200; 967 } 968 if (diff < -200) { 969 /* speed up */ 970 nduty -= 2; 971 if (nduty < 50) nduty = 50; 972 } 973 if (nduty != sc->sc_duty[which]) { 974 sc->sc_duty[which] = nduty; 975 obio_set_pwm(which, nduty); 976 sc->sc_pwm = TRUE; 977 } 978 return 0; 979 } 980 981 static void 982 obio_adjust(void *cookie) 983 { 984 struct obio_softc *sc = cookie; 985 986 while (!sc->sc_dying) { 987 sc->sc_pwm = FALSE; 988 fancontrol_adjust_zone(&sc->sc_zones[0]); 989 fancontrol_adjust_zone(&sc->sc_zones[1]); 990 /* 991 * take a shorter nap if we're in the process of adjusting a 992 * PWM fan, which relies on measuring speed and then changing 993 * its duty cycle until we're reasonable close to the target 994 * speed 995 */ 996 kpause("fanctrl", true, mstohz(sc->sc_pwm ? 1000 : 2000), NULL); 997 } 998 kthread_exit(0); 999 } 1000