1 1.73 jmcneill /* $NetBSD: piixpm.c,v 1.73 2025/02/24 21:31:32 jmcneill Exp $ */ 2 1.54 msaitoh /* $OpenBSD: piixpm.c,v 1.39 2013/10/01 20:06:02 sf Exp $ */ 3 1.1 jmcneill 4 1.1 jmcneill /* 5 1.1 jmcneill * Copyright (c) 2005, 2006 Alexander Yurchenko <grange (at) openbsd.org> 6 1.1 jmcneill * 7 1.1 jmcneill * Permission to use, copy, modify, and distribute this software for any 8 1.1 jmcneill * purpose with or without fee is hereby granted, provided that the above 9 1.1 jmcneill * copyright notice and this permission notice appear in all copies. 10 1.1 jmcneill * 11 1.1 jmcneill * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 1.1 jmcneill * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 1.1 jmcneill * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 1.1 jmcneill * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 1.1 jmcneill * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 1.1 jmcneill * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 1.1 jmcneill * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 1.1 jmcneill */ 19 1.1 jmcneill 20 1.1 jmcneill /* 21 1.1 jmcneill * Intel PIIX and compatible Power Management controller driver. 22 1.1 jmcneill */ 23 1.1 jmcneill 24 1.19 lukem #include <sys/cdefs.h> 25 1.73 jmcneill __KERNEL_RCSID(0, "$NetBSD: piixpm.c,v 1.73 2025/02/24 21:31:32 jmcneill Exp $"); 26 1.19 lukem 27 1.1 jmcneill #include <sys/param.h> 28 1.1 jmcneill #include <sys/systm.h> 29 1.1 jmcneill #include <sys/device.h> 30 1.1 jmcneill #include <sys/kernel.h> 31 1.40 pgoyette #include <sys/mutex.h> 32 1.60 thorpej #include <sys/condvar.h> 33 1.1 jmcneill #include <sys/proc.h> 34 1.1 jmcneill 35 1.17 ad #include <sys/bus.h> 36 1.1 jmcneill 37 1.1 jmcneill #include <dev/pci/pcidevs.h> 38 1.1 jmcneill #include <dev/pci/pcireg.h> 39 1.1 jmcneill #include <dev/pci/pcivar.h> 40 1.1 jmcneill 41 1.1 jmcneill #include <dev/pci/piixpmreg.h> 42 1.1 jmcneill 43 1.1 jmcneill #include <dev/i2c/i2cvar.h> 44 1.1 jmcneill 45 1.5 drochner #include <dev/ic/acpipmtimer.h> 46 1.4 jmcneill 47 1.1 jmcneill #ifdef PIIXPM_DEBUG 48 1.1 jmcneill #define DPRINTF(x) printf x 49 1.1 jmcneill #else 50 1.1 jmcneill #define DPRINTF(x) 51 1.1 jmcneill #endif 52 1.1 jmcneill 53 1.54 msaitoh #define PIIXPM_IS_CSB5(sc) \ 54 1.54 msaitoh (PCI_VENDOR((sc)->sc_id) == PCI_VENDOR_SERVERWORKS && \ 55 1.68 msaitoh PCI_PRODUCT((sc)->sc_id) == PCI_PRODUCT_SERVERWORKS_CSB5) 56 1.1 jmcneill #define PIIXPM_DELAY 200 57 1.1 jmcneill #define PIIXPM_TIMEOUT 1 58 1.1 jmcneill 59 1.54 msaitoh #define PIIXPM_IS_SB800GRP(sc) \ 60 1.54 msaitoh ((PCI_VENDOR((sc)->sc_id) == PCI_VENDOR_ATI) && \ 61 1.54 msaitoh ((PCI_PRODUCT((sc)->sc_id) == PCI_PRODUCT_ATI_SB600_SMB) && \ 62 1.54 msaitoh ((sc)->sc_rev >= 0x40))) 63 1.54 msaitoh 64 1.54 msaitoh #define PIIXPM_IS_HUDSON(sc) \ 65 1.54 msaitoh ((PCI_VENDOR((sc)->sc_id) == PCI_VENDOR_AMD) && \ 66 1.54 msaitoh (PCI_PRODUCT((sc)->sc_id) == PCI_PRODUCT_AMD_HUDSON_SMB)) 67 1.54 msaitoh 68 1.54 msaitoh #define PIIXPM_IS_KERNCZ(sc) \ 69 1.54 msaitoh ((PCI_VENDOR((sc)->sc_id) == PCI_VENDOR_AMD) && \ 70 1.54 msaitoh (PCI_PRODUCT((sc)->sc_id) == PCI_PRODUCT_AMD_KERNCZ_SMB)) 71 1.54 msaitoh 72 1.54 msaitoh #define PIIXPM_IS_FCHGRP(sc) (PIIXPM_IS_HUDSON(sc) || PIIXPM_IS_KERNCZ(sc)) 73 1.54 msaitoh 74 1.61 msaitoh #define PIIX_SB800_TIMEOUT 500 75 1.61 msaitoh 76 1.42 soren struct piixpm_smbus { 77 1.42 soren int sda; 78 1.63 msaitoh int sda_save; 79 1.68 msaitoh struct piixpm_softc *softc; 80 1.42 soren }; 81 1.36 jmcneill 82 1.1 jmcneill struct piixpm_softc { 83 1.25 joerg device_t sc_dev; 84 1.1 jmcneill 85 1.42 soren bus_space_tag_t sc_iot; 86 1.71 msaitoh bus_space_tag_t sc_sb800_bt; 87 1.42 soren bus_space_handle_t sc_pm_ioh; 88 1.69 msaitoh bus_space_handle_t sc_sb800_bh; 89 1.4 jmcneill bus_space_handle_t sc_smb_ioh; 90 1.4 jmcneill void * sc_smb_ih; 91 1.1 jmcneill int sc_poll; 92 1.71 msaitoh bool sc_sb800_mmio; /* Use MMIO access */ 93 1.59 msaitoh bool sc_sb800_selen; /* Use SMBUS0SEL */ 94 1.1 jmcneill 95 1.3 jmcneill pci_chipset_tag_t sc_pc; 96 1.3 jmcneill pcitag_t sc_pcitag; 97 1.35 hannken pcireg_t sc_id; 98 1.54 msaitoh pcireg_t sc_rev; 99 1.3 jmcneill 100 1.46 pgoyette int sc_numbusses; 101 1.46 pgoyette device_t sc_i2c_device[4]; 102 1.42 soren struct piixpm_smbus sc_busses[4]; 103 1.42 soren struct i2c_controller sc_i2c_tags[4]; 104 1.42 soren 105 1.60 thorpej kmutex_t sc_exec_lock; 106 1.60 thorpej kcondvar_t sc_exec_wait; 107 1.60 thorpej 108 1.1 jmcneill struct { 109 1.42 soren i2c_op_t op; 110 1.42 soren void * buf; 111 1.42 soren size_t len; 112 1.42 soren int flags; 113 1.60 thorpej int error; 114 1.60 thorpej bool done; 115 1.1 jmcneill } sc_i2c_xfer; 116 1.3 jmcneill 117 1.3 jmcneill pcireg_t sc_devact[2]; 118 1.1 jmcneill }; 119 1.1 jmcneill 120 1.25 joerg static int piixpm_match(device_t, cfdata_t, void *); 121 1.25 joerg static void piixpm_attach(device_t, device_t, void *); 122 1.46 pgoyette static int piixpm_rescan(device_t, const char *, const int *); 123 1.46 pgoyette static void piixpm_chdet(device_t, device_t); 124 1.1 jmcneill 125 1.32 dyoung static bool piixpm_suspend(device_t, const pmf_qual_t *); 126 1.32 dyoung static bool piixpm_resume(device_t, const pmf_qual_t *); 127 1.3 jmcneill 128 1.71 msaitoh static uint8_t piixpm_sb800_pmread(struct piixpm_softc *, bus_size_t); 129 1.42 soren static int piixpm_sb800_init(struct piixpm_softc *); 130 1.35 hannken static void piixpm_csb5_reset(void *); 131 1.61 msaitoh static int piixpm_i2c_sb800_acquire_bus(void *, int); 132 1.61 msaitoh static void piixpm_i2c_sb800_release_bus(void *, int); 133 1.25 joerg static int piixpm_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, 134 1.25 joerg size_t, void *, size_t, int); 135 1.1 jmcneill 136 1.25 joerg static int piixpm_intr(void *); 137 1.1 jmcneill 138 1.46 pgoyette CFATTACH_DECL3_NEW(piixpm, sizeof(struct piixpm_softc), 139 1.46 pgoyette piixpm_match, piixpm_attach, NULL, NULL, piixpm_rescan, piixpm_chdet, 0); 140 1.1 jmcneill 141 1.25 joerg static int 142 1.25 joerg piixpm_match(device_t parent, cfdata_t match, void *aux) 143 1.1 jmcneill { 144 1.1 jmcneill struct pci_attach_args *pa; 145 1.1 jmcneill 146 1.1 jmcneill pa = (struct pci_attach_args *)aux; 147 1.1 jmcneill switch (PCI_VENDOR(pa->pa_id)) { 148 1.1 jmcneill case PCI_VENDOR_INTEL: 149 1.1 jmcneill switch (PCI_PRODUCT(pa->pa_id)) { 150 1.1 jmcneill case PCI_PRODUCT_INTEL_82371AB_PMC: 151 1.1 jmcneill case PCI_PRODUCT_INTEL_82440MX_PMC: 152 1.1 jmcneill return 1; 153 1.1 jmcneill } 154 1.1 jmcneill break; 155 1.1 jmcneill case PCI_VENDOR_ATI: 156 1.1 jmcneill switch (PCI_PRODUCT(pa->pa_id)) { 157 1.1 jmcneill case PCI_PRODUCT_ATI_SB200_SMB: 158 1.10 toshii case PCI_PRODUCT_ATI_SB300_SMB: 159 1.10 toshii case PCI_PRODUCT_ATI_SB400_SMB: 160 1.23 jmcneill case PCI_PRODUCT_ATI_SB600_SMB: /* matches SB600/SB700/SB800 */ 161 1.1 jmcneill return 1; 162 1.1 jmcneill } 163 1.1 jmcneill break; 164 1.14 martin case PCI_VENDOR_SERVERWORKS: 165 1.14 martin switch (PCI_PRODUCT(pa->pa_id)) { 166 1.14 martin case PCI_PRODUCT_SERVERWORKS_OSB4: 167 1.14 martin case PCI_PRODUCT_SERVERWORKS_CSB5: 168 1.14 martin case PCI_PRODUCT_SERVERWORKS_CSB6: 169 1.14 martin case PCI_PRODUCT_SERVERWORKS_HT1000SB: 170 1.53 msaitoh case PCI_PRODUCT_SERVERWORKS_HT1100SB: 171 1.14 martin return 1; 172 1.14 martin } 173 1.50 pgoyette break; 174 1.48 pgoyette case PCI_VENDOR_AMD: 175 1.48 pgoyette switch (PCI_PRODUCT(pa->pa_id)) { 176 1.48 pgoyette case PCI_PRODUCT_AMD_HUDSON_SMB: 177 1.54 msaitoh case PCI_PRODUCT_AMD_KERNCZ_SMB: 178 1.48 pgoyette return 1; 179 1.48 pgoyette } 180 1.50 pgoyette break; 181 1.1 jmcneill } 182 1.1 jmcneill 183 1.1 jmcneill return 0; 184 1.1 jmcneill } 185 1.1 jmcneill 186 1.25 joerg static void 187 1.25 joerg piixpm_attach(device_t parent, device_t self, void *aux) 188 1.1 jmcneill { 189 1.25 joerg struct piixpm_softc *sc = device_private(self); 190 1.1 jmcneill struct pci_attach_args *pa = aux; 191 1.1 jmcneill pcireg_t base, conf; 192 1.5 drochner pcireg_t pmmisc; 193 1.1 jmcneill pci_intr_handle_t ih; 194 1.54 msaitoh bool usesmi = false; 195 1.1 jmcneill const char *intrstr = NULL; 196 1.64 thorpej int i; 197 1.44 christos char intrbuf[PCI_INTRSTR_LEN]; 198 1.1 jmcneill 199 1.25 joerg sc->sc_dev = self; 200 1.42 soren sc->sc_iot = pa->pa_iot; 201 1.35 hannken sc->sc_id = pa->pa_id; 202 1.54 msaitoh sc->sc_rev = PCI_REVISION(pa->pa_class); 203 1.3 jmcneill sc->sc_pc = pa->pa_pc; 204 1.3 jmcneill sc->sc_pcitag = pa->pa_tag; 205 1.46 pgoyette sc->sc_numbusses = 1; 206 1.3 jmcneill 207 1.39 drochner pci_aprint_devinfo(pa, NULL); 208 1.3 jmcneill 209 1.60 thorpej mutex_init(&sc->sc_exec_lock, MUTEX_DEFAULT, IPL_BIO); 210 1.60 thorpej cv_init(&sc->sc_exec_wait, device_xname(self)); 211 1.60 thorpej 212 1.18 jmcneill if (!pmf_device_register(self, piixpm_suspend, piixpm_resume)) 213 1.18 jmcneill aprint_error_dev(self, "couldn't establish power handler\n"); 214 1.3 jmcneill 215 1.5 drochner if ((PCI_VENDOR(pa->pa_id) != PCI_VENDOR_INTEL) || 216 1.5 drochner (PCI_PRODUCT(pa->pa_id) != PCI_PRODUCT_INTEL_82371AB_PMC)) 217 1.5 drochner goto nopowermanagement; 218 1.5 drochner 219 1.5 drochner /* check whether I/O access to PM regs is enabled */ 220 1.5 drochner pmmisc = pci_conf_read(pa->pa_pc, pa->pa_tag, PIIX_PMREGMISC); 221 1.5 drochner if (!(pmmisc & 1)) 222 1.5 drochner goto nopowermanagement; 223 1.5 drochner 224 1.4 jmcneill /* Map I/O space */ 225 1.5 drochner base = pci_conf_read(pa->pa_pc, pa->pa_tag, PIIX_PM_BASE); 226 1.69 msaitoh if (base == 0 || bus_space_map(sc->sc_iot, PCI_MAPREG_IO_ADDR(base), 227 1.4 jmcneill PIIX_PM_SIZE, 0, &sc->sc_pm_ioh)) { 228 1.49 msaitoh aprint_error_dev(self, 229 1.49 msaitoh "can't map power management I/O space\n"); 230 1.4 jmcneill goto nopowermanagement; 231 1.4 jmcneill } 232 1.4 jmcneill 233 1.5 drochner /* 234 1.5 drochner * Revision 0 and 1 are PIIX4, 2 is PIIX4E, 3 is PIIX4M. 235 1.5 drochner * PIIX4 and PIIX4E have a bug in the timer latch, see Errata #20 236 1.5 drochner * in the "Specification update" (document #297738). 237 1.5 drochner */ 238 1.69 msaitoh acpipmtimer_attach(self, sc->sc_iot, sc->sc_pm_ioh, PIIX_PM_PMTMR, 239 1.54 msaitoh (PCI_REVISION(pa->pa_class) < 3) ? ACPIPMT_BADLATCH : 0); 240 1.4 jmcneill 241 1.5 drochner nopowermanagement: 242 1.36 jmcneill 243 1.54 msaitoh /* SB800 rev 0x40+, AMD HUDSON and newer need special initialization */ 244 1.54 msaitoh if (PIIXPM_IS_FCHGRP(sc) || PIIXPM_IS_SB800GRP(sc)) { 245 1.71 msaitoh /* Newer chips don't support I/O access */ 246 1.71 msaitoh if (PIIXPM_IS_KERNCZ(sc) && (sc->sc_rev >= 0x51)) { 247 1.71 msaitoh sc->sc_sb800_mmio = true; 248 1.71 msaitoh sc->sc_sb800_bt = pa->pa_memt; 249 1.71 msaitoh } else { 250 1.71 msaitoh sc->sc_sb800_mmio = false; 251 1.71 msaitoh sc->sc_sb800_bt = pa->pa_iot; 252 1.71 msaitoh } 253 1.71 msaitoh 254 1.42 soren if (piixpm_sb800_init(sc) == 0) { 255 1.54 msaitoh /* Read configuration */ 256 1.58 msaitoh conf = bus_space_read_1(sc->sc_iot, 257 1.58 msaitoh sc->sc_smb_ioh, SB800_SMB_HOSTC); 258 1.58 msaitoh usesmi = ((conf & SB800_SMB_HOSTC_IRQ) == 0); 259 1.54 msaitoh goto setintr; 260 1.42 soren } 261 1.48 pgoyette aprint_normal_dev(self, "SMBus initialization failed\n"); 262 1.36 jmcneill return; 263 1.36 jmcneill } 264 1.36 jmcneill 265 1.54 msaitoh /* Read configuration */ 266 1.54 msaitoh conf = pci_conf_read(pa->pa_pc, pa->pa_tag, PIIX_SMB_HOSTC); 267 1.54 msaitoh DPRINTF(("%s: conf 0x%08x\n", device_xname(self), conf)); 268 1.54 msaitoh 269 1.1 jmcneill if ((conf & PIIX_SMB_HOSTC_HSTEN) == 0) { 270 1.25 joerg aprint_normal_dev(self, "SMBus disabled\n"); 271 1.1 jmcneill return; 272 1.1 jmcneill } 273 1.54 msaitoh usesmi = (conf & PIIX_SMB_HOSTC_INTMASK) == PIIX_SMB_HOSTC_SMI; 274 1.1 jmcneill 275 1.1 jmcneill /* Map I/O space */ 276 1.1 jmcneill base = pci_conf_read(pa->pa_pc, pa->pa_tag, PIIX_SMB_BASE) & 0xffff; 277 1.54 msaitoh if (base == 0 || 278 1.69 msaitoh bus_space_map(sc->sc_iot, PCI_MAPREG_IO_ADDR(base), 279 1.4 jmcneill PIIX_SMB_SIZE, 0, &sc->sc_smb_ioh)) { 280 1.25 joerg aprint_error_dev(self, "can't map smbus I/O space\n"); 281 1.1 jmcneill return; 282 1.1 jmcneill } 283 1.1 jmcneill 284 1.54 msaitoh setintr: 285 1.1 jmcneill sc->sc_poll = 1; 286 1.28 pgoyette aprint_normal_dev(self, ""); 287 1.54 msaitoh if (usesmi) { 288 1.1 jmcneill /* No PCI IRQ */ 289 1.28 pgoyette aprint_normal("interrupting at SMI, "); 290 1.53 msaitoh } else { 291 1.53 msaitoh if ((conf & PIIX_SMB_HOSTC_INTMASK) == PIIX_SMB_HOSTC_IRQ) { 292 1.53 msaitoh /* Install interrupt handler */ 293 1.53 msaitoh if (pci_intr_map(pa, &ih) == 0) { 294 1.53 msaitoh intrstr = pci_intr_string(pa->pa_pc, ih, 295 1.53 msaitoh intrbuf, sizeof(intrbuf)); 296 1.60 thorpej pci_intr_setattr(pa->pa_pc, &ih, 297 1.60 thorpej PCI_INTR_MPSAFE, true); 298 1.53 msaitoh sc->sc_smb_ih = pci_intr_establish_xname( 299 1.53 msaitoh pa->pa_pc, ih, IPL_BIO, piixpm_intr, 300 1.53 msaitoh sc, device_xname(sc->sc_dev)); 301 1.53 msaitoh if (sc->sc_smb_ih != NULL) { 302 1.53 msaitoh aprint_normal("interrupting at %s", 303 1.53 msaitoh intrstr); 304 1.53 msaitoh sc->sc_poll = 0; 305 1.53 msaitoh } 306 1.1 jmcneill } 307 1.1 jmcneill } 308 1.1 jmcneill } 309 1.73 jmcneill if (sc->sc_poll) 310 1.73 jmcneill aprint_normal("polling"); 311 1.1 jmcneill 312 1.3 jmcneill aprint_normal("\n"); 313 1.1 jmcneill 314 1.46 pgoyette for (i = 0; i < sc->sc_numbusses; i++) 315 1.46 pgoyette sc->sc_i2c_device[i] = NULL; 316 1.46 pgoyette 317 1.64 thorpej piixpm_rescan(self, NULL, NULL); 318 1.46 pgoyette } 319 1.46 pgoyette 320 1.46 pgoyette static int 321 1.54 msaitoh piixpm_iicbus_print(void *aux, const char *pnp) 322 1.54 msaitoh { 323 1.54 msaitoh struct i2cbus_attach_args *iba = aux; 324 1.54 msaitoh struct i2c_controller *tag = iba->iba_tag; 325 1.54 msaitoh struct piixpm_smbus *bus = tag->ic_cookie; 326 1.54 msaitoh struct piixpm_softc *sc = bus->softc; 327 1.54 msaitoh 328 1.54 msaitoh iicbus_print(aux, pnp); 329 1.54 msaitoh if (sc->sc_numbusses != 0) 330 1.54 msaitoh aprint_normal(" port %d", bus->sda); 331 1.54 msaitoh 332 1.54 msaitoh return UNCONF; 333 1.54 msaitoh } 334 1.64 thorpej 335 1.54 msaitoh static int 336 1.64 thorpej piixpm_rescan(device_t self, const char *ifattr, const int *locators) 337 1.46 pgoyette { 338 1.46 pgoyette struct piixpm_softc *sc = device_private(self); 339 1.46 pgoyette struct i2cbus_attach_args iba; 340 1.46 pgoyette int i; 341 1.46 pgoyette 342 1.1 jmcneill /* Attach I2C bus */ 343 1.1 jmcneill 344 1.46 pgoyette for (i = 0; i < sc->sc_numbusses; i++) { 345 1.61 msaitoh struct i2c_controller *tag = &sc->sc_i2c_tags[i]; 346 1.61 msaitoh 347 1.64 thorpej if (sc->sc_i2c_device[i] != NULL) 348 1.46 pgoyette continue; 349 1.42 soren sc->sc_busses[i].sda = i; 350 1.42 soren sc->sc_busses[i].softc = sc; 351 1.61 msaitoh iic_tag_init(tag); 352 1.61 msaitoh tag->ic_cookie = &sc->sc_busses[i]; 353 1.61 msaitoh if (PIIXPM_IS_SB800GRP(sc) || PIIXPM_IS_FCHGRP(sc)) { 354 1.61 msaitoh tag->ic_acquire_bus = piixpm_i2c_sb800_acquire_bus; 355 1.61 msaitoh tag->ic_release_bus = piixpm_i2c_sb800_release_bus; 356 1.61 msaitoh } else { 357 1.61 msaitoh tag->ic_acquire_bus = NULL; 358 1.61 msaitoh tag->ic_release_bus = NULL; 359 1.61 msaitoh } 360 1.61 msaitoh tag->ic_exec = piixpm_i2c_exec; 361 1.42 soren memset(&iba, 0, sizeof(iba)); 362 1.61 msaitoh iba.iba_tag = tag; 363 1.64 thorpej sc->sc_i2c_device[i] = 364 1.65 thorpej config_found(self, &iba, piixpm_iicbus_print, CFARGS_NONE); 365 1.67 pgoyette if (sc->sc_i2c_device[i] == NULL) 366 1.67 pgoyette iic_tag_fini(tag); 367 1.42 soren } 368 1.46 pgoyette 369 1.46 pgoyette return 0; 370 1.1 jmcneill } 371 1.1 jmcneill 372 1.46 pgoyette static void 373 1.46 pgoyette piixpm_chdet(device_t self, device_t child) 374 1.46 pgoyette { 375 1.46 pgoyette struct piixpm_softc *sc = device_private(self); 376 1.46 pgoyette int i; 377 1.46 pgoyette 378 1.46 pgoyette for (i = 0; i < sc->sc_numbusses; i++) { 379 1.46 pgoyette if (sc->sc_i2c_device[i] == child) { 380 1.67 pgoyette 381 1.67 pgoyette struct i2c_controller *tag = &sc->sc_i2c_tags[i]; 382 1.67 pgoyette 383 1.67 pgoyette iic_tag_fini(tag); 384 1.46 pgoyette sc->sc_i2c_device[i] = NULL; 385 1.46 pgoyette break; 386 1.46 pgoyette } 387 1.46 pgoyette } 388 1.46 pgoyette } 389 1.46 pgoyette 390 1.46 pgoyette 391 1.18 jmcneill static bool 392 1.32 dyoung piixpm_suspend(device_t dv, const pmf_qual_t *qual) 393 1.18 jmcneill { 394 1.18 jmcneill struct piixpm_softc *sc = device_private(dv); 395 1.18 jmcneill 396 1.18 jmcneill sc->sc_devact[0] = pci_conf_read(sc->sc_pc, sc->sc_pcitag, 397 1.18 jmcneill PIIX_DEVACTA); 398 1.18 jmcneill sc->sc_devact[1] = pci_conf_read(sc->sc_pc, sc->sc_pcitag, 399 1.18 jmcneill PIIX_DEVACTB); 400 1.18 jmcneill 401 1.18 jmcneill return true; 402 1.18 jmcneill } 403 1.18 jmcneill 404 1.18 jmcneill static bool 405 1.32 dyoung piixpm_resume(device_t dv, const pmf_qual_t *qual) 406 1.3 jmcneill { 407 1.18 jmcneill struct piixpm_softc *sc = device_private(dv); 408 1.3 jmcneill 409 1.18 jmcneill pci_conf_write(sc->sc_pc, sc->sc_pcitag, PIIX_DEVACTA, 410 1.18 jmcneill sc->sc_devact[0]); 411 1.18 jmcneill pci_conf_write(sc->sc_pc, sc->sc_pcitag, PIIX_DEVACTB, 412 1.18 jmcneill sc->sc_devact[1]); 413 1.3 jmcneill 414 1.18 jmcneill return true; 415 1.3 jmcneill } 416 1.3 jmcneill 417 1.71 msaitoh static uint8_t 418 1.71 msaitoh piixpm_sb800_pmread(struct piixpm_softc *sc, bus_size_t offset) 419 1.71 msaitoh { 420 1.71 msaitoh bus_space_tag_t sbt = sc->sc_sb800_bt; 421 1.71 msaitoh bus_space_handle_t sbh = sc->sc_sb800_bh; 422 1.71 msaitoh uint8_t val; 423 1.71 msaitoh 424 1.71 msaitoh if (sc->sc_sb800_mmio) 425 1.71 msaitoh val = bus_space_read_1(sbt, sbh, offset); 426 1.71 msaitoh else { 427 1.71 msaitoh bus_space_write_1(sbt, sbh, SB800_INDIRECTIO_INDEX, offset); 428 1.71 msaitoh val = bus_space_read_1(sbt, sbh, SB800_INDIRECTIO_DATA); 429 1.71 msaitoh } 430 1.71 msaitoh 431 1.71 msaitoh return val; 432 1.71 msaitoh } 433 1.71 msaitoh 434 1.36 jmcneill /* 435 1.36 jmcneill * Extract SMBus base address from SB800 Power Management (PM) registers. 436 1.36 jmcneill * The PM registers can be accessed either through indirect I/O (CD6/CD7) or 437 1.71 msaitoh * direct mapping if AcpiMMioDecodeEn is enabled. Newer devices support MMIO 438 1.71 msaitoh * access only. 439 1.36 jmcneill */ 440 1.36 jmcneill static int 441 1.42 soren piixpm_sb800_init(struct piixpm_softc *sc) 442 1.36 jmcneill { 443 1.71 msaitoh bus_space_tag_t sbt = sc->sc_sb800_bt; 444 1.71 msaitoh bus_space_handle_t sbh; /* indirect memory or I/O handle */ 445 1.71 msaitoh int rv; 446 1.71 msaitoh uint16_t base_addr; 447 1.71 msaitoh uint8_t lo, hi; 448 1.54 msaitoh bool enabled; 449 1.36 jmcneill 450 1.57 msaitoh if (PIIXPM_IS_KERNCZ(sc) || 451 1.57 msaitoh (PIIXPM_IS_HUDSON(sc) && (sc->sc_rev >= 0x1f))) 452 1.57 msaitoh sc->sc_numbusses = 2; 453 1.57 msaitoh else 454 1.57 msaitoh sc->sc_numbusses = 4; 455 1.57 msaitoh 456 1.68 msaitoh /* Check SMBus enable bit and Fetch SMB base address */ 457 1.71 msaitoh if (sc->sc_sb800_mmio) 458 1.71 msaitoh rv = bus_space_map(sbt, SB800_FCH_PM_BASE, 459 1.71 msaitoh SB800_FCH_PM_SIZE, 0, &sbh); 460 1.71 msaitoh else 461 1.71 msaitoh rv = bus_space_map(sbt, SB800_INDIRECTIO_BASE, 462 1.71 msaitoh SB800_INDIRECTIO_SIZE, 0, &sbh); 463 1.71 msaitoh if (rv != 0) { 464 1.72 msaitoh device_printf(sc->sc_dev, "couldn't map indirect space\n"); 465 1.36 jmcneill return EBUSY; 466 1.36 jmcneill } 467 1.71 msaitoh sc->sc_sb800_bh = sbh; 468 1.54 msaitoh if (PIIXPM_IS_FCHGRP(sc)) { 469 1.71 msaitoh lo = piixpm_sb800_pmread(sc, AMDFCH41_PM_DECODE_EN0); 470 1.71 msaitoh enabled = lo & AMDFCH41_SMBUS_EN; 471 1.54 msaitoh if (!enabled) 472 1.54 msaitoh return ENOENT; 473 1.54 msaitoh 474 1.71 msaitoh hi = piixpm_sb800_pmread(sc, AMDFCH41_PM_DECODE_EN1); 475 1.71 msaitoh base_addr = (uint16_t)hi << 8; 476 1.54 msaitoh } else { 477 1.59 msaitoh uint8_t data; 478 1.59 msaitoh 479 1.71 msaitoh lo = piixpm_sb800_pmread(sc, SB800_PM_SMBUS0EN_LO); 480 1.71 msaitoh enabled = lo & SB800_PM_SMBUS0EN_ENABLE; 481 1.54 msaitoh if (!enabled) 482 1.54 msaitoh return ENOENT; 483 1.54 msaitoh 484 1.71 msaitoh hi = piixpm_sb800_pmread(sc, SB800_PM_SMBUS0EN_HI); 485 1.71 msaitoh base_addr = ((uint16_t)hi << 8) & SB800_PM_SMBUS0EN_BADDR; 486 1.54 msaitoh 487 1.70 msaitoh bus_space_write_1(sbt, sbh, SB800_INDIRECTIO_INDEX, 488 1.54 msaitoh SB800_PM_SMBUS0SELEN); 489 1.70 msaitoh data = bus_space_read_1(sbt, sbh, SB800_INDIRECTIO_DATA); 490 1.59 msaitoh if ((data & SB800_PM_USE_SMBUS0SEL) != 0) 491 1.59 msaitoh sc->sc_sb800_selen = true; 492 1.54 msaitoh } 493 1.54 msaitoh 494 1.71 msaitoh aprint_debug_dev(sc->sc_dev, "SMBus %s access @ 0x%04x\n", 495 1.71 msaitoh sc->sc_sb800_mmio ? "memory" : "I/O", base_addr); 496 1.36 jmcneill 497 1.71 msaitoh if (bus_space_map(sc->sc_iot, PCI_MAPREG_IO_ADDR(base_addr), 498 1.58 msaitoh SB800_SMB_SIZE, 0, &sc->sc_smb_ioh)) { 499 1.36 jmcneill aprint_error_dev(sc->sc_dev, "can't map smbus I/O space\n"); 500 1.36 jmcneill return EBUSY; 501 1.36 jmcneill } 502 1.36 jmcneill 503 1.36 jmcneill return 0; 504 1.36 jmcneill } 505 1.36 jmcneill 506 1.35 hannken static void 507 1.35 hannken piixpm_csb5_reset(void *arg) 508 1.35 hannken { 509 1.35 hannken struct piixpm_softc *sc = arg; 510 1.35 hannken pcireg_t base, hostc, pmbase; 511 1.35 hannken 512 1.35 hannken base = pci_conf_read(sc->sc_pc, sc->sc_pcitag, PIIX_SMB_BASE); 513 1.35 hannken hostc = pci_conf_read(sc->sc_pc, sc->sc_pcitag, PIIX_SMB_HOSTC); 514 1.35 hannken 515 1.35 hannken pmbase = pci_conf_read(sc->sc_pc, sc->sc_pcitag, PIIX_PM_BASE); 516 1.35 hannken pmbase |= PIIX_PM_BASE_CSB5_RESET; 517 1.35 hannken pci_conf_write(sc->sc_pc, sc->sc_pcitag, PIIX_PM_BASE, pmbase); 518 1.35 hannken pmbase &= ~PIIX_PM_BASE_CSB5_RESET; 519 1.35 hannken pci_conf_write(sc->sc_pc, sc->sc_pcitag, PIIX_PM_BASE, pmbase); 520 1.35 hannken 521 1.35 hannken pci_conf_write(sc->sc_pc, sc->sc_pcitag, PIIX_SMB_BASE, base); 522 1.35 hannken pci_conf_write(sc->sc_pc, sc->sc_pcitag, PIIX_SMB_HOSTC, hostc); 523 1.35 hannken 524 1.35 hannken (void) tsleep(&sc, PRIBIO, "csb5reset", hz/2); 525 1.35 hannken } 526 1.35 hannken 527 1.25 joerg static int 528 1.61 msaitoh piixpm_i2c_sb800_acquire_bus(void *cookie, int flags) 529 1.1 jmcneill { 530 1.42 soren struct piixpm_smbus *smbus = cookie; 531 1.42 soren struct piixpm_softc *sc = smbus->softc; 532 1.63 msaitoh uint8_t sctl, old_sda, index, mask, reg; 533 1.61 msaitoh int i; 534 1.61 msaitoh 535 1.69 msaitoh sctl = bus_space_read_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_SC); 536 1.61 msaitoh for (i = 0; i < PIIX_SB800_TIMEOUT; i++) { 537 1.61 msaitoh /* Try to acquire the host semaphore */ 538 1.61 msaitoh sctl &= ~PIIX_SMB_SC_SEMMASK; 539 1.69 msaitoh bus_space_write_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_SC, 540 1.61 msaitoh sctl | PIIX_SMB_SC_HOSTSEM); 541 1.61 msaitoh 542 1.69 msaitoh sctl = bus_space_read_1(sc->sc_iot, sc->sc_smb_ioh, 543 1.61 msaitoh PIIX_SMB_SC); 544 1.61 msaitoh if ((sctl & PIIX_SMB_SC_HOSTSEM) != 0) 545 1.61 msaitoh break; 546 1.61 msaitoh 547 1.61 msaitoh delay(1000); 548 1.61 msaitoh } 549 1.61 msaitoh if (i >= PIIX_SB800_TIMEOUT) { 550 1.61 msaitoh device_printf(sc->sc_dev, 551 1.61 msaitoh "Failed to acquire the host semaphore\n"); 552 1.61 msaitoh return -1; 553 1.61 msaitoh } 554 1.1 jmcneill 555 1.63 msaitoh if (PIIXPM_IS_KERNCZ(sc) || 556 1.63 msaitoh (PIIXPM_IS_HUDSON(sc) && (sc->sc_rev >= 0x1f))) { 557 1.63 msaitoh index = AMDFCH41_PM_PORT_INDEX; 558 1.63 msaitoh mask = AMDFCH41_SMBUS_PORTMASK; 559 1.62 msaitoh } else if (sc->sc_sb800_selen) { 560 1.63 msaitoh index = SB800_PM_SMBUS0SEL; 561 1.63 msaitoh mask = SB800_PM_SMBUS0_MASK_E; 562 1.61 msaitoh } else { 563 1.63 msaitoh index = SB800_PM_SMBUS0EN_LO; 564 1.63 msaitoh mask = SB800_PM_SMBUS0_MASK_C; 565 1.63 msaitoh } 566 1.63 msaitoh 567 1.71 msaitoh reg = piixpm_sb800_pmread(sc, index); 568 1.59 msaitoh 569 1.63 msaitoh old_sda = __SHIFTOUT(reg, mask); 570 1.63 msaitoh if (smbus->sda != old_sda) { 571 1.63 msaitoh reg &= ~mask; 572 1.63 msaitoh reg |= __SHIFTIN(smbus->sda, mask); 573 1.71 msaitoh /* 574 1.71 msaitoh * SB800_INDIRECTIO_INDEX is already set on I/O access, 575 1.71 msaitoh * so it's not required to write it again. 576 1.71 msaitoh */ 577 1.71 msaitoh bus_space_write_1(sc->sc_sb800_bt, sc->sc_sb800_bh, 578 1.71 msaitoh sc->sc_sb800_mmio ? index : SB800_INDIRECTIO_DATA, reg); 579 1.42 soren } 580 1.42 soren 581 1.63 msaitoh /* Save the old port number */ 582 1.63 msaitoh smbus->sda_save = old_sda; 583 1.63 msaitoh 584 1.16 xtraeme return 0; 585 1.1 jmcneill } 586 1.1 jmcneill 587 1.25 joerg static void 588 1.61 msaitoh piixpm_i2c_sb800_release_bus(void *cookie, int flags) 589 1.1 jmcneill { 590 1.42 soren struct piixpm_smbus *smbus = cookie; 591 1.42 soren struct piixpm_softc *sc = smbus->softc; 592 1.63 msaitoh uint8_t sctl, index, mask, reg; 593 1.42 soren 594 1.63 msaitoh if (PIIXPM_IS_KERNCZ(sc) || 595 1.63 msaitoh (PIIXPM_IS_HUDSON(sc) && (sc->sc_rev >= 0x1f))) { 596 1.63 msaitoh index = AMDFCH41_PM_PORT_INDEX; 597 1.63 msaitoh mask = AMDFCH41_SMBUS_PORTMASK; 598 1.62 msaitoh } else if (sc->sc_sb800_selen) { 599 1.63 msaitoh index = SB800_PM_SMBUS0SEL; 600 1.63 msaitoh mask = SB800_PM_SMBUS0_MASK_E; 601 1.61 msaitoh } else { 602 1.63 msaitoh index = SB800_PM_SMBUS0EN_LO; 603 1.63 msaitoh mask = SB800_PM_SMBUS0_MASK_C; 604 1.63 msaitoh } 605 1.59 msaitoh 606 1.63 msaitoh if (smbus->sda != smbus->sda_save) { 607 1.63 msaitoh /* Restore the port number */ 608 1.71 msaitoh reg = piixpm_sb800_pmread(sc, index); 609 1.63 msaitoh reg &= ~mask; 610 1.63 msaitoh reg |= __SHIFTIN(smbus->sda_save, mask); 611 1.71 msaitoh /* 612 1.71 msaitoh * SB800_INDIRECTIO_INDEX is already set on I/O access, 613 1.71 msaitoh * so it's not required to write it again. 614 1.71 msaitoh */ 615 1.71 msaitoh bus_space_write_1(sc->sc_sb800_bt, sc->sc_sb800_bh, 616 1.71 msaitoh sc->sc_sb800_mmio ? index : SB800_INDIRECTIO_DATA, reg); 617 1.42 soren } 618 1.61 msaitoh 619 1.66 andvar /* Release the host semaphore */ 620 1.69 msaitoh sctl = bus_space_read_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_SC); 621 1.61 msaitoh sctl &= ~PIIX_SMB_SC_SEMMASK; 622 1.69 msaitoh bus_space_write_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_SC, 623 1.61 msaitoh sctl | PIIX_SMB_SC_CLRHOSTSEM); 624 1.1 jmcneill } 625 1.1 jmcneill 626 1.25 joerg static int 627 1.1 jmcneill piixpm_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, 628 1.1 jmcneill const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags) 629 1.1 jmcneill { 630 1.42 soren struct piixpm_smbus *smbus = cookie; 631 1.42 soren struct piixpm_softc *sc = smbus->softc; 632 1.54 msaitoh const uint8_t *b; 633 1.54 msaitoh uint8_t ctl = 0, st; 634 1.1 jmcneill int retries; 635 1.1 jmcneill 636 1.53 msaitoh DPRINTF(("%s: exec: op %d, addr 0x%02x, cmdlen %zu, len %zu, " 637 1.53 msaitoh "flags 0x%x\n", 638 1.53 msaitoh device_xname(sc->sc_dev), op, addr, cmdlen, len, flags)); 639 1.1 jmcneill 640 1.60 thorpej mutex_enter(&sc->sc_exec_lock); 641 1.60 thorpej 642 1.41 soren /* Clear status bits */ 643 1.69 msaitoh bus_space_write_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_HS, 644 1.49 msaitoh PIIX_SMB_HS_INTR | PIIX_SMB_HS_DEVERR | 645 1.41 soren PIIX_SMB_HS_BUSERR | PIIX_SMB_HS_FAILED); 646 1.69 msaitoh bus_space_barrier(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_HS, 1, 647 1.41 soren BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); 648 1.41 soren 649 1.1 jmcneill /* Wait for bus to be idle */ 650 1.1 jmcneill for (retries = 100; retries > 0; retries--) { 651 1.69 msaitoh st = bus_space_read_1(sc->sc_iot, sc->sc_smb_ioh, 652 1.4 jmcneill PIIX_SMB_HS); 653 1.1 jmcneill if (!(st & PIIX_SMB_HS_BUSY)) 654 1.1 jmcneill break; 655 1.1 jmcneill DELAY(PIIXPM_DELAY); 656 1.1 jmcneill } 657 1.52 msaitoh DPRINTF(("%s: exec: st %#x\n", device_xname(sc->sc_dev), st & 0xff)); 658 1.60 thorpej if (st & PIIX_SMB_HS_BUSY) { 659 1.60 thorpej mutex_exit(&sc->sc_exec_lock); 660 1.60 thorpej return (EBUSY); 661 1.60 thorpej } 662 1.1 jmcneill 663 1.56 thorpej if (sc->sc_poll) 664 1.1 jmcneill flags |= I2C_F_POLL; 665 1.1 jmcneill 666 1.34 hannken if (!I2C_OP_STOP_P(op) || cmdlen > 1 || len > 2 || 667 1.60 thorpej (cmdlen == 0 && len > 1)) { 668 1.60 thorpej mutex_exit(&sc->sc_exec_lock); 669 1.60 thorpej return (EINVAL); 670 1.60 thorpej } 671 1.1 jmcneill 672 1.1 jmcneill /* Setup transfer */ 673 1.1 jmcneill sc->sc_i2c_xfer.op = op; 674 1.1 jmcneill sc->sc_i2c_xfer.buf = buf; 675 1.1 jmcneill sc->sc_i2c_xfer.len = len; 676 1.1 jmcneill sc->sc_i2c_xfer.flags = flags; 677 1.1 jmcneill sc->sc_i2c_xfer.error = 0; 678 1.60 thorpej sc->sc_i2c_xfer.done = false; 679 1.1 jmcneill 680 1.1 jmcneill /* Set slave address and transfer direction */ 681 1.69 msaitoh bus_space_write_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_TXSLVA, 682 1.1 jmcneill PIIX_SMB_TXSLVA_ADDR(addr) | 683 1.1 jmcneill (I2C_OP_READ_P(op) ? PIIX_SMB_TXSLVA_READ : 0)); 684 1.1 jmcneill 685 1.1 jmcneill b = cmdbuf; 686 1.1 jmcneill if (cmdlen > 0) 687 1.1 jmcneill /* Set command byte */ 688 1.69 msaitoh bus_space_write_1(sc->sc_iot, sc->sc_smb_ioh, 689 1.4 jmcneill PIIX_SMB_HCMD, b[0]); 690 1.1 jmcneill 691 1.1 jmcneill if (I2C_OP_WRITE_P(op)) { 692 1.1 jmcneill /* Write data */ 693 1.1 jmcneill b = buf; 694 1.34 hannken if (cmdlen == 0 && len == 1) 695 1.69 msaitoh bus_space_write_1(sc->sc_iot, sc->sc_smb_ioh, 696 1.34 hannken PIIX_SMB_HCMD, b[0]); 697 1.34 hannken else if (len > 0) 698 1.69 msaitoh bus_space_write_1(sc->sc_iot, sc->sc_smb_ioh, 699 1.1 jmcneill PIIX_SMB_HD0, b[0]); 700 1.1 jmcneill if (len > 1) 701 1.69 msaitoh bus_space_write_1(sc->sc_iot, sc->sc_smb_ioh, 702 1.1 jmcneill PIIX_SMB_HD1, b[1]); 703 1.1 jmcneill } 704 1.1 jmcneill 705 1.1 jmcneill /* Set SMBus command */ 706 1.34 hannken if (cmdlen == 0) { 707 1.34 hannken if (len == 0) 708 1.27 pgoyette ctl = PIIX_SMB_HC_CMD_QUICK; 709 1.27 pgoyette else 710 1.27 pgoyette ctl = PIIX_SMB_HC_CMD_BYTE; 711 1.27 pgoyette } else if (len == 1) 712 1.1 jmcneill ctl = PIIX_SMB_HC_CMD_BDATA; 713 1.1 jmcneill else if (len == 2) 714 1.1 jmcneill ctl = PIIX_SMB_HC_CMD_WDATA; 715 1.54 msaitoh else 716 1.54 msaitoh panic("%s: unexpected len %zu", __func__, len); 717 1.1 jmcneill 718 1.1 jmcneill if ((flags & I2C_F_POLL) == 0) 719 1.1 jmcneill ctl |= PIIX_SMB_HC_INTREN; 720 1.1 jmcneill 721 1.1 jmcneill /* Start transaction */ 722 1.1 jmcneill ctl |= PIIX_SMB_HC_START; 723 1.69 msaitoh bus_space_write_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_HC, ctl); 724 1.1 jmcneill 725 1.1 jmcneill if (flags & I2C_F_POLL) { 726 1.1 jmcneill /* Poll for completion */ 727 1.54 msaitoh if (PIIXPM_IS_CSB5(sc)) 728 1.35 hannken DELAY(2*PIIXPM_DELAY); 729 1.35 hannken else 730 1.35 hannken DELAY(PIIXPM_DELAY); 731 1.1 jmcneill for (retries = 1000; retries > 0; retries--) { 732 1.69 msaitoh st = bus_space_read_1(sc->sc_iot, sc->sc_smb_ioh, 733 1.1 jmcneill PIIX_SMB_HS); 734 1.1 jmcneill if ((st & PIIX_SMB_HS_BUSY) == 0) 735 1.1 jmcneill break; 736 1.1 jmcneill DELAY(PIIXPM_DELAY); 737 1.1 jmcneill } 738 1.1 jmcneill if (st & PIIX_SMB_HS_BUSY) 739 1.1 jmcneill goto timeout; 740 1.45 hannken piixpm_intr(sc); 741 1.1 jmcneill } else { 742 1.1 jmcneill /* Wait for interrupt */ 743 1.60 thorpej while (! sc->sc_i2c_xfer.done) { 744 1.60 thorpej if (cv_timedwait(&sc->sc_exec_wait, &sc->sc_exec_lock, 745 1.60 thorpej PIIXPM_TIMEOUT * hz)) 746 1.60 thorpej goto timeout; 747 1.60 thorpej } 748 1.1 jmcneill } 749 1.1 jmcneill 750 1.60 thorpej int error = sc->sc_i2c_xfer.error; 751 1.60 thorpej mutex_exit(&sc->sc_exec_lock); 752 1.1 jmcneill 753 1.60 thorpej return (error); 754 1.1 jmcneill 755 1.1 jmcneill timeout: 756 1.1 jmcneill /* 757 1.1 jmcneill * Transfer timeout. Kill the transaction and clear status bits. 758 1.1 jmcneill */ 759 1.25 joerg aprint_error_dev(sc->sc_dev, "timeout, status 0x%x\n", st); 760 1.69 msaitoh bus_space_write_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_HC, 761 1.1 jmcneill PIIX_SMB_HC_KILL); 762 1.1 jmcneill DELAY(PIIXPM_DELAY); 763 1.69 msaitoh st = bus_space_read_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_HS); 764 1.1 jmcneill if ((st & PIIX_SMB_HS_FAILED) == 0) 765 1.49 msaitoh aprint_error_dev(sc->sc_dev, 766 1.49 msaitoh "transaction abort failed, status 0x%x\n", st); 767 1.69 msaitoh bus_space_write_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_HS, st); 768 1.35 hannken /* 769 1.35 hannken * CSB5 needs hard reset to unlock the smbus after timeout. 770 1.35 hannken */ 771 1.54 msaitoh if (PIIXPM_IS_CSB5(sc)) 772 1.35 hannken piixpm_csb5_reset(sc); 773 1.60 thorpej mutex_exit(&sc->sc_exec_lock); 774 1.60 thorpej return (ETIMEDOUT); 775 1.1 jmcneill } 776 1.1 jmcneill 777 1.25 joerg static int 778 1.1 jmcneill piixpm_intr(void *arg) 779 1.1 jmcneill { 780 1.45 hannken struct piixpm_softc *sc = arg; 781 1.54 msaitoh uint8_t st; 782 1.54 msaitoh uint8_t *b; 783 1.1 jmcneill size_t len; 784 1.1 jmcneill 785 1.1 jmcneill /* Read status */ 786 1.69 msaitoh st = bus_space_read_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_HS); 787 1.1 jmcneill if ((st & PIIX_SMB_HS_BUSY) != 0 || (st & (PIIX_SMB_HS_INTR | 788 1.1 jmcneill PIIX_SMB_HS_DEVERR | PIIX_SMB_HS_BUSERR | 789 1.1 jmcneill PIIX_SMB_HS_FAILED)) == 0) 790 1.1 jmcneill /* Interrupt was not for us */ 791 1.1 jmcneill return (0); 792 1.1 jmcneill 793 1.52 msaitoh DPRINTF(("%s: intr st %#x\n", device_xname(sc->sc_dev), st & 0xff)); 794 1.1 jmcneill 795 1.60 thorpej if ((sc->sc_i2c_xfer.flags & I2C_F_POLL) == 0) 796 1.60 thorpej mutex_enter(&sc->sc_exec_lock); 797 1.60 thorpej 798 1.1 jmcneill /* Clear status bits */ 799 1.69 msaitoh bus_space_write_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_HS, st); 800 1.1 jmcneill 801 1.1 jmcneill /* Check for errors */ 802 1.1 jmcneill if (st & (PIIX_SMB_HS_DEVERR | PIIX_SMB_HS_BUSERR | 803 1.1 jmcneill PIIX_SMB_HS_FAILED)) { 804 1.60 thorpej sc->sc_i2c_xfer.error = EIO; 805 1.1 jmcneill goto done; 806 1.1 jmcneill } 807 1.1 jmcneill 808 1.1 jmcneill if (st & PIIX_SMB_HS_INTR) { 809 1.1 jmcneill if (I2C_OP_WRITE_P(sc->sc_i2c_xfer.op)) 810 1.1 jmcneill goto done; 811 1.1 jmcneill 812 1.1 jmcneill /* Read data */ 813 1.1 jmcneill b = sc->sc_i2c_xfer.buf; 814 1.1 jmcneill len = sc->sc_i2c_xfer.len; 815 1.1 jmcneill if (len > 0) 816 1.69 msaitoh b[0] = bus_space_read_1(sc->sc_iot, sc->sc_smb_ioh, 817 1.1 jmcneill PIIX_SMB_HD0); 818 1.1 jmcneill if (len > 1) 819 1.69 msaitoh b[1] = bus_space_read_1(sc->sc_iot, sc->sc_smb_ioh, 820 1.1 jmcneill PIIX_SMB_HD1); 821 1.1 jmcneill } 822 1.1 jmcneill 823 1.1 jmcneill done: 824 1.60 thorpej sc->sc_i2c_xfer.done = true; 825 1.60 thorpej if ((sc->sc_i2c_xfer.flags & I2C_F_POLL) == 0) { 826 1.60 thorpej cv_signal(&sc->sc_exec_wait); 827 1.60 thorpej mutex_exit(&sc->sc_exec_lock); 828 1.60 thorpej } 829 1.1 jmcneill return (1); 830 1.1 jmcneill } 831