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