static void piixpm_attach(device_t parent, device_t self, void *aux) { struct piixpm_softc *sc = device_private(self); struct pci_attach_args *pa = aux; struct i2cbus_attach_args iba; pcireg_t base, conf; pcireg_t pmmisc; pci_intr_handle_t ih; const char *intrstr = NULL; int i, numbusses = 1; sc->sc_dev = self; sc->sc_iot = pa->pa_iot; sc->sc_id = pa->pa_id; sc->sc_pc = pa->pa_pc; sc->sc_pcitag = pa->pa_tag; pci_aprint_devinfo(pa, NULL); if (!pmf_device_register(self, piixpm_suspend, piixpm_resume)) aprint_error_dev(self, "couldn't establish power handler\n"); /* Read configuration */ conf = pci_conf_read(pa->pa_pc, pa->pa_tag, PIIX_SMB_HOSTC); DPRINTF(("%s: conf 0x%x\n", device_xname(self), conf)); if ((PCI_VENDOR(pa->pa_id) != PCI_VENDOR_INTEL) || (PCI_PRODUCT(pa->pa_id) != PCI_PRODUCT_INTEL_82371AB_PMC)) goto nopowermanagement; /* check whether I/O access to PM regs is enabled */ pmmisc = pci_conf_read(pa->pa_pc, pa->pa_tag, PIIX_PMREGMISC); if (!(pmmisc & 1)) goto nopowermanagement; /* Map I/O space */ base = pci_conf_read(pa->pa_pc, pa->pa_tag, PIIX_PM_BASE); if (bus_space_map(sc->sc_pm_iot, PCI_MAPREG_IO_ADDR(base), PIIX_PM_SIZE, 0, &sc->sc_pm_ioh)) { aprint_error_dev(self, "can't map power management I/O space\n"); goto nopowermanagement; } /* * Revision 0 and 1 are PIIX4, 2 is PIIX4E, 3 is PIIX4M. * PIIX4 and PIIX4E have a bug in the timer latch, see Errata #20 * in the "Specification update" (document #297738). */ acpipmtimer_attach(self, sc->sc_pm_iot, sc->sc_pm_ioh, PIIX_PM_PMTMR, (PCI_REVISION(pa->pa_class) < 3) ? ACPIPMT_BADLATCH : 0 ); nopowermanagement: /* SB800 rev 0x40+ needs special initialization */ if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_ATI && PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ATI_SB600_SMB && PCI_REVISION(pa->pa_class) >= 0x40) { if (piixpm_sb800_init(sc) == 0) { numbusses = 4; goto attach_i2c; } aprint_normal_dev(self, "SMBus disabled\n"); return; } if ((conf & PIIX_SMB_HOSTC_HSTEN) == 0) { aprint_normal_dev(self, "SMBus disabled\n"); return; } /* Map I/O space */ base = pci_conf_read(pa->pa_pc, pa->pa_tag, PIIX_SMB_BASE) & 0xffff; if (bus_space_map(sc->sc_smb_iot, PCI_MAPREG_IO_ADDR(base), PIIX_SMB_SIZE, 0, &sc->sc_smb_ioh)) { aprint_error_dev(self, "can't map smbus I/O space\n"); return; } sc->sc_poll = 1; aprint_normal_dev(self, ""); if ((conf & PIIX_SMB_HOSTC_INTMASK) == PIIX_SMB_HOSTC_SMI) { /* No PCI IRQ */ aprint_normal("interrupting at SMI, "); } else if ((conf & PIIX_SMB_HOSTC_INTMASK) == PIIX_SMB_HOSTC_IRQ) { /* Install interrupt handler */ if (pci_intr_map(pa, &ih) == 0) { intrstr = pci_intr_string(pa->pa_pc, ih); sc->sc_smb_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO, piixpm_intr, sc); if (sc->sc_smb_ih != NULL) { aprint_normal("interrupting at %s", intrstr); sc->sc_poll = 0; } } } if (sc->sc_poll) aprint_normal("polling"); aprint_normal("\n"); attach_i2c: /* Attach I2C bus */ mutex_init(&sc->sc_i2c_mutex, MUTEX_DEFAULT, IPL_NONE); for (i = 0; i < numbusses; i++) { sc->sc_busses[i].sda = i; sc->sc_busses[i].softc = sc; sc->sc_i2c_tags[i].ic_cookie = &sc->sc_busses[i]; sc->sc_i2c_tags[i].ic_acquire_bus = piixpm_i2c_acquire_bus; sc->sc_i2c_tags[i].ic_release_bus = piixpm_i2c_release_bus; sc->sc_i2c_tags[i].ic_exec = piixpm_i2c_exec; memset(&iba, 0, sizeof(iba)); iba.iba_type = I2C_TYPE_SMBUS; iba.iba_tag = &sc->sc_i2c_tags[i]; config_found_ia(self, "i2cbus", &iba, iicbus_print); } }
static void piixpm_attach(device_t parent, device_t self, void *aux) { struct piixpm_softc *sc = device_private(self); struct pci_attach_args *pa = aux; struct i2cbus_attach_args iba; pcireg_t base, conf; pcireg_t pmmisc; pci_intr_handle_t ih; char devinfo[256]; const char *intrstr = NULL; sc->sc_dev = self; sc->sc_pc = pa->pa_pc; sc->sc_pcitag = pa->pa_tag; aprint_naive("\n"); aprint_normal("\n"); pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo, sizeof(devinfo)); aprint_normal_dev(self, "%s (rev. 0x%02x)\n", devinfo, PCI_REVISION(pa->pa_class)); if (!pmf_device_register(self, piixpm_suspend, piixpm_resume)) aprint_error_dev(self, "couldn't establish power handler\n"); /* Read configuration */ conf = pci_conf_read(pa->pa_pc, pa->pa_tag, PIIX_SMB_HOSTC); DPRINTF(("%s: conf 0x%x\n", device_xname(self), conf)); if ((PCI_VENDOR(pa->pa_id) != PCI_VENDOR_INTEL) || (PCI_PRODUCT(pa->pa_id) != PCI_PRODUCT_INTEL_82371AB_PMC)) goto nopowermanagement; /* check whether I/O access to PM regs is enabled */ pmmisc = pci_conf_read(pa->pa_pc, pa->pa_tag, PIIX_PMREGMISC); if (!(pmmisc & 1)) goto nopowermanagement; sc->sc_pm_iot = pa->pa_iot; /* Map I/O space */ base = pci_conf_read(pa->pa_pc, pa->pa_tag, PIIX_PM_BASE); if (bus_space_map(sc->sc_pm_iot, PCI_MAPREG_IO_ADDR(base), PIIX_PM_SIZE, 0, &sc->sc_pm_ioh)) { aprint_error_dev(self, "can't map power management I/O space\n"); goto nopowermanagement; } /* * Revision 0 and 1 are PIIX4, 2 is PIIX4E, 3 is PIIX4M. * PIIX4 and PIIX4E have a bug in the timer latch, see Errata #20 * in the "Specification update" (document #297738). */ acpipmtimer_attach(self, sc->sc_pm_iot, sc->sc_pm_ioh, PIIX_PM_PMTMR, (PCI_REVISION(pa->pa_class) < 3) ? ACPIPMT_BADLATCH : 0 ); nopowermanagement: if ((conf & PIIX_SMB_HOSTC_HSTEN) == 0) { aprint_normal_dev(self, "SMBus disabled\n"); return; } /* Map I/O space */ sc->sc_smb_iot = pa->pa_iot; base = pci_conf_read(pa->pa_pc, pa->pa_tag, PIIX_SMB_BASE) & 0xffff; if (bus_space_map(sc->sc_smb_iot, PCI_MAPREG_IO_ADDR(base), PIIX_SMB_SIZE, 0, &sc->sc_smb_ioh)) { aprint_error_dev(self, "can't map smbus I/O space\n"); return; } sc->sc_poll = 1; if ((conf & PIIX_SMB_HOSTC_INTMASK) == PIIX_SMB_HOSTC_SMI) { /* No PCI IRQ */ aprint_normal_dev(self, "interrupting at SMI"); } else if ((conf & PIIX_SMB_HOSTC_INTMASK) == PIIX_SMB_HOSTC_IRQ) { /* Install interrupt handler */ if (pci_intr_map(pa, &ih) == 0) { intrstr = pci_intr_string(pa->pa_pc, ih); sc->sc_smb_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO, piixpm_intr, sc); if (sc->sc_smb_ih != NULL) { aprint_normal_dev(self, "interrupting at %s", intrstr); sc->sc_poll = 0; } } } if (sc->sc_poll) aprint_normal_dev(self, "polling"); aprint_normal("\n"); /* Attach I2C bus */ rw_init(&sc->sc_i2c_rwlock); sc->sc_i2c_tag.ic_cookie = sc; sc->sc_i2c_tag.ic_acquire_bus = piixpm_i2c_acquire_bus; sc->sc_i2c_tag.ic_release_bus = piixpm_i2c_release_bus; sc->sc_i2c_tag.ic_exec = piixpm_i2c_exec; bzero(&iba, sizeof(iba)); iba.iba_tag = &sc->sc_i2c_tag; config_found_ia(self, "i2cbus", &iba, iicbus_print); return; }