1 /* $NetBSD: wbsio.c,v 1.30 2022/12/16 00:02:28 msaitoh Exp $ */ 2 /* $OpenBSD: wbsio.c,v 1.10 2015/03/14 03:38:47 jsg Exp $ */ 3 /* 4 * Copyright (c) 2008 Mark Kettenis <kettenis@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /* 20 * Winbond LPC Super I/O driver. 21 */ 22 23 #include <sys/cdefs.h> 24 #include <sys/param.h> 25 #include <sys/device.h> 26 #include <sys/kernel.h> 27 #include <sys/module.h> 28 #include <sys/systm.h> 29 #include <sys/mutex.h> 30 #include <sys/gpio.h> 31 32 #include <sys/bus.h> 33 34 #include <dev/isa/isareg.h> 35 #include <dev/isa/isavar.h> 36 #include <dev/isa/wbsioreg.h> 37 #include <dev/sysmon/sysmonvar.h> 38 39 /* Don't use gpio for now in the module */ 40 #if !defined(_MODULE) && defined(WBSIO_GPIO) 41 #include "gpio.h" 42 #endif 43 44 #if NGPIO > 0 45 #include <dev/gpio/gpiovar.h> 46 #endif 47 48 struct wbsio_softc { 49 device_t sc_dev; 50 device_t sc_lm_dev; 51 #if NGPIO > 0 52 device_t sc_gpio_dev; 53 #endif 54 55 bus_space_tag_t sc_iot; 56 bus_space_handle_t sc_ioh; 57 kmutex_t sc_conf_lock; 58 59 struct isa_attach_args sc_ia; 60 struct isa_io sc_io; 61 62 #if NGPIO > 0 63 bus_space_handle_t sc_gpio_ioh; 64 kmutex_t sc_gpio_lock; 65 struct gpio_chipset_tag sc_gpio_gc; 66 struct gpio_pin sc_gpio_pins[WBSIO_GPIO_NPINS]; 67 bool sc_gpio_rt; 68 #endif 69 70 struct sysmon_wdog sc_smw; 71 bool sc_smw_valid; 72 }; 73 74 static const struct wbsio_product { 75 uint16_t id; 76 int idbits; 77 const char *str; 78 } wbsio_products[] = { 79 { WBSIO_ID_W83627HF, 8, "W83627HF" }, 80 { WBSIO_ID_W83697HF, 8, "W83697HF" }, 81 { WBSIO_ID_W83637HF, 8, "W83637HF" }, 82 { WBSIO_ID_W83627THF, 8, "W83627THF" }, 83 { WBSIO_ID_W83687THF, 8, "W83687THF" }, 84 { WBSIO_ID_W83627DHG, 12, "W83627DHG" }, 85 { WBSIO_ID_W83627DHGP, 12, "W83627DHG-P" }, 86 { WBSIO_ID_W83627EHF, 12, "W83627EHF" }, 87 { WBSIO_ID_W83627SF, 12, "W83627SF" }, 88 { WBSIO_ID_W83627UHG, 12, "W83627UHG" }, 89 { WBSIO_ID_W83667HG, 12, "W83667HG" }, 90 { WBSIO_ID_W83667HGB, 12, "W83667HGB" }, 91 { WBSIO_ID_W83697UG, 12, "W83697UG" }, 92 { WBSIO_ID_NCT6775F, 12, "NCT6775F" }, 93 { WBSIO_ID_NCT6776F, 12, "NCT6776F" }, 94 { WBSIO_ID_NCT5104D, 12, "NCT5104D or 610[246]D" }, 95 { WBSIO_ID_NCT6779D, 12, "NCT6779D" }, 96 { WBSIO_ID_NCT6791D, 12, "NCT6791D" }, 97 { WBSIO_ID_NCT6792D, 12, "NCT6792D" }, 98 { WBSIO_ID_NCT6793D, 12, "NCT6793D" }, 99 { WBSIO_ID_NCT6795D, 12, "NCT6795D" }, 100 { WBSIO_ID_NCT6796D, 13, "NCT6796D" }, 101 { WBSIO_ID_NCT6797D, 13, "NCT6797D" }, 102 { WBSIO_ID_NCT6798D, 13, "NCT6798D" }, 103 { WBSIO_ID_NCT6799D, 13, "NCT6799D" }, 104 }; 105 106 static const struct wbsio_product *wbsio_lookup(uint8_t id, uint8_t rev); 107 static int wbsio_match(device_t, cfdata_t, void *); 108 static void wbsio_attach(device_t, device_t, void *); 109 static int wbsio_detach(device_t, int); 110 static int wbsio_rescan(device_t, const char *, const int *); 111 static void wbsio_childdet(device_t, device_t); 112 static int wbsio_print(void *, const char *); 113 static int wbsio_search(device_t, cfdata_t, const int *, void *); 114 static bool wbsio_suspend(device_t, const pmf_qual_t *); 115 #if NGPIO > 0 116 static int wbsio_gpio_search(device_t, cfdata_t, const int *, void *); 117 static int wbsio_gpio_rt_init(struct wbsio_softc *); 118 static int wbsio_gpio_rt_read(struct wbsio_softc *, int, int); 119 static void wbsio_gpio_rt_write(struct wbsio_softc *, int, int, int); 120 static int wbsio_gpio_rt_pin_read(void *, int); 121 static void wbsio_gpio_rt_pin_write(void *, int, int); 122 static void wbsio_gpio_rt_pin_ctl(void *, int, int); 123 static void wbsio_gpio_enable_nct6779d(device_t); 124 static void wbsio_gpio_pinconfig_nct6779d(device_t); 125 #endif 126 static void wbsio_wdog_attach(device_t); 127 static int wbsio_wdog_detach(device_t); 128 static int wbsio_wdog_setmode(struct sysmon_wdog *); 129 static int wbsio_wdog_tickle(struct sysmon_wdog *); 130 static void wbsio_wdog_setcounter(struct wbsio_softc *, uint8_t); 131 static void wbsio_wdog_clear_timeout(struct wbsio_softc *); 132 133 CFATTACH_DECL2_NEW(wbsio, sizeof(struct wbsio_softc), 134 wbsio_match, wbsio_attach, wbsio_detach, NULL, 135 wbsio_rescan, wbsio_childdet); 136 137 static __inline void 138 wbsio_conf_enable(kmutex_t *lock, bus_space_tag_t iot, bus_space_handle_t ioh) 139 { 140 if (lock) 141 mutex_enter(lock); 142 143 bus_space_write_1(iot, ioh, WBSIO_INDEX, WBSIO_CONF_EN_MAGIC); 144 bus_space_write_1(iot, ioh, WBSIO_INDEX, WBSIO_CONF_EN_MAGIC); 145 } 146 147 static __inline void 148 wbsio_conf_disable(kmutex_t *lock, bus_space_tag_t iot, bus_space_handle_t ioh) 149 { 150 151 bus_space_write_1(iot, ioh, WBSIO_INDEX, WBSIO_CONF_DS_MAGIC); 152 153 if (lock) 154 mutex_exit(lock); 155 } 156 157 static __inline uint8_t 158 wbsio_conf_read(bus_space_tag_t iot, bus_space_handle_t ioh, uint8_t index) 159 { 160 bus_space_write_1(iot, ioh, WBSIO_INDEX, index); 161 return (bus_space_read_1(iot, ioh, WBSIO_DATA)); 162 } 163 164 static __inline void 165 wbsio_conf_write(bus_space_tag_t iot, bus_space_handle_t ioh, uint8_t index, 166 uint8_t data) 167 { 168 bus_space_write_1(iot, ioh, WBSIO_INDEX, index); 169 bus_space_write_1(iot, ioh, WBSIO_DATA, data); 170 } 171 172 static const struct wbsio_product * 173 wbsio_lookup(uint8_t id, uint8_t rev) 174 { 175 int i; 176 177 for (i = 0; i < __arraycount(wbsio_products); i++) { 178 const struct wbsio_product *ent = &wbsio_products[i]; 179 switch (ent->idbits) { 180 case 13: 181 case 12: 182 case 8: 183 if (ent->id == WBSIO_MAKEID(id, rev, ent->idbits)) 184 return ent; 185 break; 186 default: 187 break; 188 } 189 } 190 191 /* Not found */ 192 return NULL; 193 } 194 195 int 196 wbsio_match(device_t parent, cfdata_t match, void *aux) 197 { 198 struct isa_attach_args *ia = aux; 199 const struct wbsio_product *product; 200 bus_space_tag_t iot; 201 bus_space_handle_t ioh; 202 uint8_t id, rev; 203 204 /* Must supply an address */ 205 if (ia->ia_nio < 1) 206 return 0; 207 208 if (ISA_DIRECT_CONFIG(ia)) 209 return 0; 210 211 if (ia->ia_io[0].ir_addr == ISA_UNKNOWN_PORT) 212 return 0; 213 214 /* Match by device ID */ 215 iot = ia->ia_iot; 216 if (bus_space_map(iot, ia->ia_io[0].ir_addr, WBSIO_IOSIZE, 0, &ioh)) 217 return 0; 218 wbsio_conf_enable(NULL, iot, ioh); 219 id = wbsio_conf_read(iot, ioh, WBSIO_ID); 220 rev = wbsio_conf_read(iot, ioh, WBSIO_REV); 221 aprint_debug("wbsio_probe: id 0x%02x, rev 0x%02x\n", id, rev); 222 wbsio_conf_disable(NULL, iot, ioh); 223 bus_space_unmap(iot, ioh, WBSIO_IOSIZE); 224 225 if ((product = wbsio_lookup(id, rev)) == NULL) 226 return 0; 227 228 ia->ia_nio = 1; 229 ia->ia_io[0].ir_size = WBSIO_IOSIZE; 230 ia->ia_niomem = 0; 231 ia->ia_nirq = 0; 232 ia->ia_ndrq = 0; 233 return 1; 234 } 235 236 void 237 wbsio_attach(device_t parent, device_t self, void *aux) 238 { 239 struct wbsio_softc *sc = device_private(self); 240 struct isa_attach_args *ia = aux; 241 const struct wbsio_product *product; 242 const char *desc; 243 const char *vendor; 244 uint8_t id, rev; 245 246 sc->sc_dev = self; 247 248 sc->sc_ia = *ia; 249 250 /* Map ISA I/O space */ 251 sc->sc_iot = ia->ia_iot; 252 if (bus_space_map(sc->sc_iot, ia->ia_io[0].ir_addr, 253 WBSIO_IOSIZE, 0, &sc->sc_ioh)) { 254 aprint_error(": can't map i/o space\n"); 255 return; 256 } 257 258 mutex_init(&sc->sc_conf_lock, MUTEX_DEFAULT, IPL_NONE); 259 260 /* Enter configuration mode */ 261 wbsio_conf_enable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); 262 263 /* Read device ID */ 264 id = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_ID); 265 /* Read device revision */ 266 rev = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_REV); 267 268 /* Escape from configuration mode */ 269 wbsio_conf_disable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); 270 271 if ((product = wbsio_lookup(id, rev)) == NULL) { 272 aprint_error_dev(self, "Unknown device. Failed to attach\n"); 273 return; 274 } 275 rev = WBSIO_MAKEREV(rev, product->idbits); 276 277 desc = product->str; 278 if (desc[0] == 'W') 279 vendor = "Winbond"; 280 else 281 vendor = "Nuvoton"; 282 aprint_naive("\n"); 283 aprint_normal(": %s LPC Super I/O %s rev ", vendor, desc); 284 if (product->idbits >= 12) { 285 /* Revision filed is 4 or 3bits */ 286 aprint_normal("%c\n", 'A' + rev); 287 } else 288 aprint_normal("0x%02x\n", rev); 289 290 if (!pmf_device_register(self, wbsio_suspend, NULL)) 291 aprint_error_dev(self, "couldn't establish power handler\n"); 292 293 sc->sc_smw_valid = false; 294 wbsio_rescan(self, "wbsio", NULL); 295 296 #if NGPIO > 0 297 298 wbsio_rescan(self, "gpiobus", NULL); 299 #endif 300 } 301 302 int 303 wbsio_detach(device_t self, int flags) 304 { 305 struct wbsio_softc *sc = device_private(self); 306 int rc; 307 308 if ((rc = wbsio_wdog_detach(self)) != 0) 309 return rc; 310 311 if ((rc = config_detach_children(self, flags)) != 0) 312 return rc; 313 bus_space_unmap(sc->sc_iot, sc->sc_ioh, WBSIO_IOSIZE); 314 pmf_device_deregister(self); 315 316 #if NGPIO > 0 317 if (sc->sc_gpio_dev) { 318 bus_space_unmap(sc->sc_iot, sc->sc_gpio_ioh, 319 WBSIO_GPIO_IOSIZE); 320 } 321 322 if (sc->sc_gpio_rt) { 323 mutex_destroy(&sc->sc_gpio_lock); 324 } 325 #endif 326 327 mutex_destroy(&sc->sc_conf_lock); 328 return 0; 329 } 330 331 int 332 wbsio_rescan(device_t self, const char *ifattr, const int *locators) 333 { 334 335 #if NGPIO > 0 336 if (ifattr_match(ifattr, "gpiobus")) { 337 config_search(self, NULL, 338 CFARGS(.search = wbsio_gpio_search, 339 .iattr = ifattr, 340 .locators = locators)); 341 return 0; 342 } 343 #endif 344 config_search(self, NULL, 345 CFARGS(.search = wbsio_search, 346 .iattr = ifattr, 347 .locators = locators)); 348 349 wbsio_wdog_attach(self); 350 351 return 0; 352 } 353 354 void 355 wbsio_childdet(device_t self, device_t child) 356 { 357 struct wbsio_softc *sc = device_private(self); 358 359 if (sc->sc_lm_dev == child) 360 sc->sc_lm_dev = NULL; 361 } 362 363 static int 364 wbsio_search(device_t parent, cfdata_t cf, const int *slocs, void *aux) 365 { 366 struct wbsio_softc *sc = device_private(parent); 367 const struct wbsio_product *product; 368 uint16_t iobase; 369 uint16_t devid; 370 uint8_t reg0, reg1, rev; 371 372 /* Enter configuration mode */ 373 wbsio_conf_enable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); 374 375 /* Select HM logical device */ 376 wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_LDN, WBSIO_LDN_HM); 377 378 /* 379 * The address should be 8-byte aligned, but it seems some 380 * BIOSes ignore this. They get away with it, because 381 * Apparently the hardware simply ignores the lower three 382 * bits. We do the same here. 383 */ 384 reg0 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_HM_ADDR_LSB); 385 reg1 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_HM_ADDR_MSB); 386 387 /* Escape from configuration mode */ 388 wbsio_conf_disable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); 389 390 iobase = (reg1 << 8) | (reg0 & ~0x7); 391 392 if (iobase == 0) 393 return -1; 394 395 /* Enter configuration mode */ 396 wbsio_conf_enable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); 397 /* Read device ID and revision */ 398 devid = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_ID); 399 rev = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_REV); 400 /* Escape from configuration mode */ 401 wbsio_conf_disable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); 402 403 if ((product = wbsio_lookup(devid, rev)) == NULL) { 404 aprint_error_dev(parent, "%s: Unknown device.\n", __func__); 405 return -1; 406 } 407 devid = WBSIO_MAKEID(devid, rev, product->idbits); 408 409 sc->sc_ia.ia_nio = 1; 410 sc->sc_ia.ia_io = &sc->sc_io; 411 sc->sc_ia.ia_io[0].ir_addr = iobase; 412 sc->sc_ia.ia_io[0].ir_size = 8; 413 sc->sc_ia.ia_niomem = 0; 414 sc->sc_ia.ia_nirq = 0; 415 sc->sc_ia.ia_ndrq = 0; 416 /* Store device-id to ia_aux */ 417 sc->sc_ia.ia_aux = (void *)(uintptr_t)devid; 418 sc->sc_lm_dev = config_attach(parent, cf, &sc->sc_ia, wbsio_print, 419 CFARGS_NONE); 420 421 return 0; 422 } 423 424 int 425 wbsio_print(void *aux, const char *pnp) 426 { 427 struct isa_attach_args *ia = aux; 428 429 if (pnp) 430 aprint_normal("%s", pnp); 431 if (ia->ia_io[0].ir_size) 432 aprint_normal(" port 0x%x", ia->ia_io[0].ir_addr); 433 if (ia->ia_io[0].ir_size > 1) 434 aprint_normal("-0x%x", ia->ia_io[0].ir_addr + 435 ia->ia_io[0].ir_size - 1); 436 return (UNCONF); 437 } 438 439 static bool 440 wbsio_suspend(device_t self, const pmf_qual_t *qual) 441 { 442 struct wbsio_softc *sc = device_private(self); 443 444 if (sc->sc_smw_valid) { 445 if ((sc->sc_smw.smw_mode & WDOG_MODE_MASK) 446 != WDOG_MODE_DISARMED) 447 return false; 448 } 449 450 return true; 451 } 452 453 #if NGPIO > 0 454 static int 455 wbsio_gpio_search(device_t parent, cfdata_t cf, const int *slocs, void *aux) 456 { 457 struct wbsio_softc *sc = device_private(parent); 458 const struct wbsio_product *product; 459 struct gpiobus_attach_args gba; 460 uint16_t devid; 461 uint8_t rev; 462 int i; 463 464 /* Enter configuration mode */ 465 wbsio_conf_enable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); 466 /* Read device ID and revision */ 467 devid = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_ID); 468 rev = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_REV); 469 /* Escape from configuration mode */ 470 wbsio_conf_disable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); 471 472 if ((product = wbsio_lookup(devid, rev)) == NULL) { 473 aprint_error_dev(parent, "%s: Unknown device.\n", __func__); 474 return -1; 475 } 476 477 sc->sc_gpio_rt = false; 478 479 switch (product->id) { 480 case WBSIO_ID_NCT6779D: 481 wbsio_gpio_enable_nct6779d(parent); 482 sc->sc_gpio_rt = true; 483 break; 484 default: 485 aprint_error_dev(parent, "%s's GPIO is not supported yet\n", 486 product->str); 487 return -1; 488 } 489 490 if (sc->sc_gpio_rt) { 491 if (wbsio_gpio_rt_init(sc) != 0) { 492 sc->sc_gpio_rt = false; 493 return -1; 494 } 495 sc->sc_gpio_gc.gp_cookie = sc; 496 sc->sc_gpio_gc.gp_pin_read = wbsio_gpio_rt_pin_read; 497 sc->sc_gpio_gc.gp_pin_write = wbsio_gpio_rt_pin_write; 498 sc->sc_gpio_gc.gp_pin_ctl = wbsio_gpio_rt_pin_ctl; 499 } else { 500 aprint_error_dev(parent, 501 "GPIO indirect access is not supported\n"); 502 return -1; 503 } 504 505 for (i = 0; i < WBSIO_GPIO_NPINS; i++) { 506 sc->sc_gpio_pins[i].pin_num = i; 507 sc->sc_gpio_pins[i].pin_caps = GPIO_PIN_INPUT | 508 GPIO_PIN_OUTPUT | GPIO_PIN_INVIN | GPIO_PIN_INVOUT; 509 510 /* safe defaults */ 511 sc->sc_gpio_pins[i].pin_flags = GPIO_PIN_INPUT; 512 sc->sc_gpio_pins[i].pin_state = GPIO_PIN_LOW; 513 sc->sc_gpio_gc.gp_pin_ctl(sc, i, sc->sc_gpio_pins[i].pin_flags); 514 sc->sc_gpio_gc.gp_pin_write(sc, i, sc->sc_gpio_pins[i].pin_state); 515 } 516 517 switch (product->id) { 518 case WBSIO_ID_NCT6779D: 519 wbsio_gpio_pinconfig_nct6779d(parent); 520 break; 521 } 522 523 gba.gba_gc = &sc->sc_gpio_gc; 524 gba.gba_pins = sc->sc_gpio_pins; 525 gba.gba_npins = WBSIO_GPIO_NPINS; 526 527 sc->sc_gpio_dev = config_attach(parent, cf, &gba, gpiobus_print, 528 CFARGS_NONE); 529 530 return 0; 531 } 532 533 static int 534 wbsio_gpio_rt_init(struct wbsio_softc *sc) 535 { 536 uint16_t iobase; 537 uint8_t reg0, reg1; 538 539 /* Enter configuration mode */ 540 wbsio_conf_enable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); 541 542 /* Get GPIO Register Table address */ 543 wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_LDN, WBSIO_LDN_GPIO0); 544 reg0 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_GPIO_ADDR_LSB); 545 reg1 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_GPIO_ADDR_MSB); 546 iobase = (reg1 << 8) | (reg0 & ~0x7); 547 548 /* Escape from configuration mode */ 549 wbsio_conf_disable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); 550 551 if (bus_space_map(sc->sc_iot, iobase, WBSIO_GPIO_IOSIZE, 552 0, &sc->sc_gpio_ioh)) { 553 aprint_error_dev(sc->sc_dev, 554 "can't map gpio to i/o space\n"); 555 return -1; 556 } 557 558 aprint_normal_dev(sc->sc_dev, "GPIO: port 0x%x-0x%x\n", 559 iobase, iobase + WBSIO_GPIO_IOSIZE); 560 561 mutex_init(&sc->sc_gpio_lock, MUTEX_DEFAULT, IPL_VM); 562 563 return 0; 564 } 565 566 static int 567 wbsio_gpio_rt_read(struct wbsio_softc *sc, int port, int reg) 568 { 569 int v; 570 571 mutex_enter(&sc->sc_gpio_lock); 572 573 bus_space_write_1(sc->sc_iot, sc->sc_gpio_ioh, 574 WBSIO_GPIO_GSR, port); 575 v = bus_space_read_1(sc->sc_iot, sc->sc_gpio_ioh, reg); 576 577 mutex_exit(&sc->sc_gpio_lock); 578 579 return v; 580 } 581 582 static void 583 wbsio_gpio_rt_write(struct wbsio_softc *sc, int port, int reg, int value) 584 { 585 586 mutex_enter(&sc->sc_gpio_lock); 587 588 bus_space_write_1(sc->sc_iot, sc->sc_gpio_ioh, 589 WBSIO_GPIO_GSR, port); 590 bus_space_write_1(sc->sc_iot, sc->sc_gpio_ioh, 591 reg, value); 592 593 mutex_exit(&sc->sc_gpio_lock); 594 } 595 596 static int 597 wbsio_gpio_rt_pin_read(void *aux, int pin) 598 { 599 struct wbsio_softc *sc = (struct wbsio_softc *)aux; 600 int port, shift, data; 601 602 port = (pin >> 3) & 0x07; 603 shift = pin & 0x07; 604 605 data = wbsio_gpio_rt_read(sc, port, WBSIO_GPIO_DAT); 606 607 return ((data >> shift) & 0x01); 608 } 609 610 static void 611 wbsio_gpio_rt_pin_write(void *aux, int pin, int v) 612 { 613 struct wbsio_softc *sc = (struct wbsio_softc *)aux; 614 int port, shift, data; 615 616 port = (pin >> 3) & 0x07; 617 shift = pin & 0x07; 618 619 data = wbsio_gpio_rt_read(sc, port, WBSIO_GPIO_DAT); 620 621 if (v == 0) 622 data &= ~(1 << shift); 623 else if (v == 1) 624 data |= (1 << shift); 625 626 wbsio_gpio_rt_write(sc, port, WBSIO_GPIO_DAT, data); 627 } 628 629 static void 630 wbsio_gpio_rt_pin_ctl(void *aux, int pin, int flags) 631 { 632 struct wbsio_softc *sc = (struct wbsio_softc *)aux; 633 uint8_t ior, inv; 634 int port, shift; 635 636 port = (pin >> 3) & 0x07; 637 shift = pin & 0x07; 638 639 ior = wbsio_gpio_rt_read(sc, port, WBSIO_GPIO_IOR); 640 inv = wbsio_gpio_rt_read(sc, port, WBSIO_GPIO_INV); 641 642 if (flags & GPIO_PIN_INPUT) { 643 ior |= (1 << shift); 644 inv &= ~(1 << shift); 645 } else if (flags & GPIO_PIN_OUTPUT) { 646 ior &= ~(1 << shift); 647 inv &= ~(1 << shift); 648 } else if (flags & GPIO_PIN_INVIN) { 649 ior |= (1 << shift); 650 inv |= (1 << shift); 651 } else if (flags & GPIO_PIN_INVOUT) { 652 ior &= ~(1 << shift); 653 inv |= (1 << shift); 654 } 655 656 wbsio_gpio_rt_write(sc, port, WBSIO_GPIO_IOR, ior); 657 wbsio_gpio_rt_write(sc, port, WBSIO_GPIO_INV, inv); 658 } 659 660 static void 661 wbsio_gpio_enable_nct6779d(device_t parent) 662 { 663 struct wbsio_softc *sc = device_private(parent); 664 uint8_t reg, conf; 665 666 /* Enter configuration mode */ 667 wbsio_conf_enable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); 668 669 wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_LDN, WBSIO_LDN_GPIO0); 670 reg = WBSIO_GPIO_CONF; 671 conf = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, reg); 672 /* Activate Register Table access */ 673 conf |= WBSIO_GPIO_BASEADDR; 674 675 conf |= WBSIO_GPIO0_ENABLE; 676 wbsio_conf_write(sc->sc_iot, sc->sc_ioh, reg, conf); 677 678 wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_LDN, WBSIO_LDN_GPIO1); 679 reg = WBSIO_GPIO_CONF; 680 conf = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, reg); 681 conf |= WBSIO_GPIO1_ENABLE; 682 conf |= WBSIO_GPIO2_ENABLE; 683 conf |= WBSIO_GPIO3_ENABLE; 684 conf |= WBSIO_GPIO4_ENABLE; 685 conf |= WBSIO_GPIO5_ENABLE; 686 conf |= WBSIO_GPIO6_ENABLE; 687 conf |= WBSIO_GPIO7_ENABLE; 688 wbsio_conf_write(sc->sc_iot, sc->sc_ioh, reg, conf); 689 690 /* Escape from configuration mode */ 691 wbsio_conf_disable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); 692 } 693 694 static void 695 wbsio_gpio_pinconfig_nct6779d(device_t parent) 696 { 697 struct wbsio_softc *sc = device_private(parent); 698 uint8_t sfr, mfs0, mfs1, mfs2, mfs3; 699 uint8_t mfs4, mfs5, mfs6, gopt2, hm_conf; 700 701 /* Enter configuration mode */ 702 wbsio_conf_enable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); 703 704 /* Strapping Function Result */ 705 sfr = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_SFR); 706 sfr &= ~(WBSIO_SFR_LPT | WBSIO_SFR_DSW | WBSIO_SFR_AMDPWR); 707 708 /* Read current configuration */ 709 mfs0 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_MFS0); 710 mfs1 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_MFS1); 711 mfs2 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_MFS2); 712 mfs3 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_MFS3); 713 mfs4 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_MFS4); 714 mfs5 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_MFS5); 715 mfs6 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_MFS6); 716 gopt2 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_GOPT2); 717 718 wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_LDN, WBSIO_LDN_HM); 719 hm_conf = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_HM_CONF); 720 721 /* GPIO0 pin configs */ 722 mfs2 |= WBSIO_NCT6779D_MFS2_GP00; 723 mfs2 |= WBSIO_NCT6779D_MFS2_GP01; 724 mfs2 |= WBSIO_NCT6779D_MFS2_GP02; 725 mfs2 &= ~WBSIO_NCT6779D_MFS2_GP03_MASK; 726 mfs2 |= WBSIO_NCT6779D_MFS2_GP04; 727 mfs2 |= WBSIO_NCT6779D_MFS2_GP05; 728 mfs2 |= WBSIO_NCT6779D_MFS2_GP06; 729 mfs3 &= ~WBSIO_NCT6779D_MFS3_GP07_MASK; 730 731 /* GPIO1 pin configs */ 732 mfs4 |= WBSIO_NCT6779D_MFS4_GP10_GP17; 733 734 /* GPIO2 pin configs */ 735 mfs4 |= WBSIO_NCT6779D_MFS4_GP20_GP21; 736 mfs4 |= WBSIO_NCT6779D_MFS4_GP22_GP23; 737 mfs1 &= ~WBSIO_NCT6779D_MFS1_GP24_MASK; 738 gopt2 &= ~WBSIO_NCT6779D_GOPT2_GP24_MASK; 739 mfs4 &= ~WBSIO_NCT6779D_MFS4_GP25_MASK; 740 gopt2 &= ~WBSIO_NCT6779D_GOPT2_GP25_MASK; 741 mfs6 |= WBSIO_NCT6779D_MFS6_GP26; 742 mfs6 &= ~WBSIO_NCT6779D_MFS6_GP27_MASK; 743 744 /* GPIO3 pin configs */ 745 mfs0 &= ~WBSIO_NCT6779D_MFS0_GP30_MASK; 746 mfs0 |= WBSIO_NCT6779D_MFS0_GP30; 747 mfs1 &= ~WBSIO_NCT6779D_MFS1_GP31_MASK; 748 mfs0 |= WBSIO_NCT6779D_MFS0_GP31; 749 mfs1 &= ~WBSIO_NCT6779D_MFS1_GP32_MASK; 750 mfs0 |= WBSIO_NCT6779D_MFS0_GP32; 751 mfs6 &= ~WBSIO_NCT6779D_MFS6_GP33_MASK; 752 mfs6 |= WBSIO_NCT6779D_MFS6_GP33; 753 /* GP34, 35 and 36 are enabled by LPT_EN=0 */ 754 /* GP37 is not existed */ 755 756 /* GPIO4 pin configs */ 757 mfs1 |= WBSIO_NCT6779D_MFS1_GP40; 758 /* GP41 to GP46 requires LPT_EN=0 */ 759 mfs0 &= ~WBSIO_NCT6779D_MFS0_GP41_MASK; 760 mfs0 |= WBSIO_NCT6779D_MFS0_GP41; 761 mfs1 |= WBSIO_NCT6779D_MFS1_GP42; 762 mfs1 |= WBSIO_NCT6779D_MFS1_GP42; 763 gopt2 |= WBSIO_NCT6779D_GOPT2_GP43; 764 mfs1 &= ~WBSIO_NCT6779D_MFS1_GP44_GP45_MASK; 765 gopt2 &= ~WBSIO_NCT6779D_GOPT2_GP46_MASK; 766 mfs1 |= WBSIO_NCT6779D_MFS1_GP47; 767 768 /* GPIO5 pin configs */ 769 /* GP50 to GP55 requires DSW_EN=0 */ 770 hm_conf &= ~WBSIO_NCT6779D_HM_GP50_MASK; 771 /* GP51 is enabled by DSW_EN=0 */ 772 hm_conf &= ~WBSIO_NCT6779D_HM_GP52_MASK; 773 /* GP53 and GP54 are enabled by DSW_EN=0 */ 774 hm_conf &= ~WBSIO_NCT6779D_HM_GP55_MASK; 775 /* GP56 and GP57 are enabled by AMDPWR_EN=0 */ 776 777 /* GPIO6 pin configs are shared with GP43 */ 778 779 /* GPIO7 pin configs */ 780 /* GP70 to GP73 are enabled by TEST_MODE_EN */ 781 mfs5 |= WBSIO_NCT6779D_MFS5_GP74; 782 mfs5 |= WBSIO_NCT6779D_MFS5_GP75; 783 mfs5 |= WBSIO_NCT6779D_MFS5_GP76; 784 /* GP77 is not existed */ 785 786 /* Write all pin configs */ 787 wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_SFR, sfr); 788 wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_MFS0, mfs0); 789 wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_MFS1, mfs1); 790 wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_MFS2, mfs2); 791 wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_MFS3, mfs3); 792 wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_MFS4, mfs4); 793 wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_MFS5, mfs5); 794 wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_MFS6, mfs6); 795 wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_GOPT2, gopt2); 796 797 wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_LDN, WBSIO_LDN_HM); 798 wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_HM_CONF, hm_conf); 799 800 /* Escape from configuration mode */ 801 wbsio_conf_disable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); 802 } 803 804 #endif /* NGPIO > 0 */ 805 806 static void 807 wbsio_wdog_attach(device_t self) 808 { 809 struct wbsio_softc *sc = device_private(self); 810 const struct wbsio_product *product; 811 uint8_t gpio, mode; 812 uint16_t devid; 813 uint8_t rev; 814 815 if (sc->sc_smw_valid) 816 return; /* watchdog already attached */ 817 818 wbsio_conf_enable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); 819 devid = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_ID); 820 rev = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_REV); 821 wbsio_conf_disable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); 822 823 if ((product = wbsio_lookup(devid, rev)) == NULL) { 824 return; 825 } 826 827 switch (product->id) { 828 case WBSIO_ID_NCT6779D: 829 break; 830 default: 831 /* WDT is not supported */ 832 return; 833 } 834 835 wbsio_wdog_setcounter(sc, WBSIO_WDT_CNTR_STOP); 836 837 wbsio_conf_enable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); 838 wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_LDN, WBSIO_LDN_GPIO0); 839 840 gpio = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_GPIO_CONF); 841 mode = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_WDT_MODE); 842 843 gpio |= WBSIO_GPIO0_WDT1; 844 845 mode &= ~WBSIO_WDT_MODE_FASTER; 846 mode &= ~WBSIO_WDT_MODE_MINUTES; 847 mode &= ~WBSIO_WDT_MODE_KBCRST; 848 mode &= ~WBSIO_WDT_MODE_LEVEL; 849 850 /* initialize WDT mode */ 851 wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_WDT_MODE, mode); 852 /* Activate WDT1 function */ 853 wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_GPIO_CONF, gpio); 854 855 wbsio_conf_disable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); 856 857 sc->sc_smw.smw_name = device_xname(self); 858 sc->sc_smw.smw_cookie = sc; 859 sc->sc_smw.smw_setmode = wbsio_wdog_setmode; 860 sc->sc_smw.smw_tickle = wbsio_wdog_tickle; 861 sc->sc_smw.smw_period = WBSIO_WDT_CNTR_MAX; 862 863 if (sysmon_wdog_register(&sc->sc_smw)) 864 aprint_error_dev(self, "couldn't register with sysmon\n"); 865 else 866 sc->sc_smw_valid = true; 867 } 868 869 static int 870 wbsio_wdog_detach(device_t self) 871 { 872 struct wbsio_softc *sc = device_private(self); 873 int error; 874 875 error = 0; 876 877 if (sc->sc_smw_valid) { 878 if ((sc->sc_smw.smw_mode & WDOG_MODE_MASK) 879 != WDOG_MODE_DISARMED) 880 return EBUSY; 881 882 error = sysmon_wdog_unregister(&sc->sc_smw); 883 } 884 885 if (!error) 886 sc->sc_smw_valid = false; 887 888 return error; 889 } 890 891 static int 892 wbsio_wdog_setmode(struct sysmon_wdog *smw) 893 { 894 895 switch(smw->smw_mode & WDOG_MODE_MASK) { 896 case WDOG_MODE_DISARMED: 897 wbsio_wdog_setcounter(smw->smw_cookie, WBSIO_WDT_CNTR_STOP); 898 wbsio_wdog_clear_timeout(smw->smw_cookie); 899 break; 900 default: 901 if (smw->smw_period > WBSIO_WDT_CNTR_MAX 902 || smw->smw_period == 0) 903 return EINVAL; 904 905 wbsio_wdog_setcounter(smw->smw_cookie, smw->smw_period); 906 } 907 908 return 0; 909 } 910 911 static void 912 wbsio_wdog_setcounter(struct wbsio_softc *sc, uint8_t period) 913 { 914 915 KASSERT(!mutex_owned(&sc->sc_conf_lock)); 916 917 wbsio_conf_enable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); 918 919 wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_LDN, WBSIO_LDN_GPIO0); 920 wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_WDT_CNTR, period); 921 922 wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_LDN, WBSIO_LDN_GPIO0); 923 924 925 wbsio_conf_disable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); 926 } 927 928 static void 929 wbsio_wdog_clear_timeout(struct wbsio_softc *sc) 930 { 931 uint8_t st; 932 933 KASSERT(!mutex_owned(&sc->sc_conf_lock)); 934 935 wbsio_conf_enable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); 936 937 st = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_WDT_STAT); 938 st &= ~WBSIO_WDT_STAT_TIMEOUT; 939 wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_WDT_STAT, st); 940 941 wbsio_conf_disable(&sc->sc_conf_lock, sc->sc_iot, sc->sc_ioh); 942 } 943 944 static int 945 wbsio_wdog_tickle(struct sysmon_wdog *smw) 946 { 947 948 wbsio_wdog_setcounter(smw->smw_cookie, smw->smw_period); 949 950 return 0; 951 } 952 953 954 MODULE(MODULE_CLASS_DRIVER, wbsio, "sysmon_wdog"); 955 956 #ifdef _MODULE 957 #include "ioconf.c" 958 #endif 959 960 static int 961 wbsio_modcmd(modcmd_t cmd, void *opaque) 962 { 963 switch (cmd) { 964 case MODULE_CMD_INIT: 965 #ifdef _MODULE 966 return config_init_component(cfdriver_ioconf_wbsio, 967 cfattach_ioconf_wbsio, cfdata_ioconf_wbsio); 968 #else 969 return 0; 970 #endif 971 case MODULE_CMD_FINI: 972 #ifdef _MODULE 973 return config_fini_component(cfdriver_ioconf_wbsio, 974 cfattach_ioconf_wbsio, cfdata_ioconf_wbsio); 975 #else 976 return 0; 977 #endif 978 default: 979 return ENOTTY; 980 } 981 } 982