Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/sys/dev/pci/piixpm.c,v rcsdiff: /ftp/cvs/cvsroot/src/sys/dev/pci/piixpm.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.52 retrieving revision 1.52.6.4 diff -u -p -r1.52 -r1.52.6.4 --- src/sys/dev/pci/piixpm.c 2017/03/29 09:04:36 1.52 +++ src/sys/dev/pci/piixpm.c 2023/01/23 12:46:14 1.52.6.4 @@ -1,5 +1,5 @@ -/* $NetBSD: piixpm.c,v 1.52 2017/03/29 09:04:36 msaitoh Exp $ */ -/* $OpenBSD: piixpm.c,v 1.20 2006/02/27 08:25:02 grange Exp $ */ +/* $NetBSD: piixpm.c,v 1.52.6.4 2023/01/23 12:46:14 martin Exp $ */ +/* $OpenBSD: piixpm.c,v 1.39 2013/10/01 20:06:02 sf Exp $ */ /* * Copyright (c) 2005, 2006 Alexander Yurchenko @@ -22,7 +22,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: piixpm.c,v 1.52 2017/03/29 09:04:36 msaitoh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: piixpm.c,v 1.52.6.4 2023/01/23 12:46:14 martin Exp $"); #include #include @@ -49,32 +49,52 @@ __KERNEL_RCSID(0, "$NetBSD: piixpm.c,v 1 #define DPRINTF(x) #endif -#define PIIXPM_IS_CSB5(id) \ - (PCI_VENDOR((id)) == PCI_VENDOR_SERVERWORKS && \ - PCI_PRODUCT((id)) == PCI_PRODUCT_SERVERWORKS_CSB5) +#define PIIXPM_IS_CSB5(sc) \ + (PCI_VENDOR((sc)->sc_id) == PCI_VENDOR_SERVERWORKS && \ + PCI_PRODUCT((sc)->sc_id) == PCI_PRODUCT_SERVERWORKS_CSB5) #define PIIXPM_DELAY 200 #define PIIXPM_TIMEOUT 1 +#define PIIXPM_IS_SB800GRP(sc) \ + ((PCI_VENDOR((sc)->sc_id) == PCI_VENDOR_ATI) && \ + ((PCI_PRODUCT((sc)->sc_id) == PCI_PRODUCT_ATI_SB600_SMB) && \ + ((sc)->sc_rev >= 0x40))) + +#define PIIXPM_IS_HUDSON(sc) \ + ((PCI_VENDOR((sc)->sc_id) == PCI_VENDOR_AMD) && \ + (PCI_PRODUCT((sc)->sc_id) == PCI_PRODUCT_AMD_HUDSON_SMB)) + +#define PIIXPM_IS_KERNCZ(sc) \ + ((PCI_VENDOR((sc)->sc_id) == PCI_VENDOR_AMD) && \ + (PCI_PRODUCT((sc)->sc_id) == PCI_PRODUCT_AMD_KERNCZ_SMB)) + +#define PIIXPM_IS_FCHGRP(sc) (PIIXPM_IS_HUDSON(sc) || PIIXPM_IS_KERNCZ(sc)) + +#define PIIX_SB800_TIMEOUT 500 + struct piixpm_smbus { int sda; - struct piixpm_softc *softc; + int sda_save; + struct piixpm_softc *softc; }; struct piixpm_softc { device_t sc_dev; bus_space_tag_t sc_iot; -#define sc_pm_iot sc_iot -#define sc_smb_iot sc_iot + bus_space_tag_t sc_sb800_bt; bus_space_handle_t sc_pm_ioh; - bus_space_handle_t sc_sb800_ioh; + bus_space_handle_t sc_sb800_bh; bus_space_handle_t sc_smb_ioh; void * sc_smb_ih; int sc_poll; + bool sc_sb800_mmio; /* Use MMIO access */ + bool sc_sb800_selen; /* Use SMBUS0SEL */ pci_chipset_tag_t sc_pc; pcitag_t sc_pcitag; pcireg_t sc_id; + pcireg_t sc_rev; int sc_numbusses; device_t sc_i2c_device[4]; @@ -101,10 +121,13 @@ static void piixpm_chdet(device_t, devic static bool piixpm_suspend(device_t, const pmf_qual_t *); static bool piixpm_resume(device_t, const pmf_qual_t *); +static uint8_t piixpm_sb800_pmread(struct piixpm_softc *, bus_size_t); static int piixpm_sb800_init(struct piixpm_softc *); static void piixpm_csb5_reset(void *); -static int piixpm_i2c_acquire_bus(void *, int); -static void piixpm_i2c_release_bus(void *, int); +static int piixpm_i2c_sb600_acquire_bus(void *, int); +static void piixpm_i2c_sb600_release_bus(void *, int); +static int piixpm_i2c_sb800_acquire_bus(void *, int); +static void piixpm_i2c_sb800_release_bus(void *, int); static int piixpm_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t, void *, size_t, int); @@ -142,12 +165,14 @@ piixpm_match(device_t parent, cfdata_t m case PCI_PRODUCT_SERVERWORKS_CSB5: case PCI_PRODUCT_SERVERWORKS_CSB6: case PCI_PRODUCT_SERVERWORKS_HT1000SB: + case PCI_PRODUCT_SERVERWORKS_HT1100SB: return 1; } break; case PCI_VENDOR_AMD: switch (PCI_PRODUCT(pa->pa_id)) { case PCI_PRODUCT_AMD_HUDSON_SMB: + case PCI_PRODUCT_AMD_KERNCZ_SMB: return 1; } break; @@ -164,6 +189,7 @@ piixpm_attach(device_t parent, device_t pcireg_t base, conf; pcireg_t pmmisc; pci_intr_handle_t ih; + bool usesmi = false; const char *intrstr = NULL; int i, flags; char intrbuf[PCI_INTRSTR_LEN]; @@ -171,6 +197,7 @@ piixpm_attach(device_t parent, device_t sc->sc_dev = self; sc->sc_iot = pa->pa_iot; sc->sc_id = pa->pa_id; + sc->sc_rev = PCI_REVISION(pa->pa_class); sc->sc_pc = pa->pa_pc; sc->sc_pcitag = pa->pa_tag; sc->sc_numbusses = 1; @@ -180,10 +207,6 @@ piixpm_attach(device_t parent, device_t 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; @@ -195,7 +218,7 @@ piixpm_attach(device_t parent, device_t /* 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), + if (base == 0 || bus_space_map(sc->sc_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"); @@ -207,69 +230,80 @@ piixpm_attach(device_t parent, device_t * 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 ); + acpipmtimer_attach(self, sc->sc_iot, sc->sc_pm_ioh, PIIX_PM_PMTMR, + (PCI_REVISION(pa->pa_class) < 3) ? ACPIPMT_BADLATCH : 0); nopowermanagement: - /* SB800 rev 0x40+ and AMD HUDSON need special initialization */ - if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_AMD && - PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_AMD_HUDSON_SMB) { - if (piixpm_sb800_init(sc) == 0) { - goto attach_i2c; + /* SB800 rev 0x40+, AMD HUDSON and newer need special initialization */ + if (PIIXPM_IS_FCHGRP(sc) || PIIXPM_IS_SB800GRP(sc)) { + /* Newer chips don't support I/O access */ + if (PIIXPM_IS_KERNCZ(sc) && (sc->sc_rev >= 0x51)) { + sc->sc_sb800_mmio = true; + sc->sc_sb800_bt = pa->pa_memt; + } else { + sc->sc_sb800_mmio = false; + sc->sc_sb800_bt = pa->pa_iot; } - aprint_normal_dev(self, "SMBus initialization failed\n"); - return; - } - 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) { - sc->sc_numbusses = 4; - goto attach_i2c; + /* Read configuration */ + conf = bus_space_read_1(sc->sc_iot, + sc->sc_smb_ioh, SB800_SMB_HOSTC); + usesmi = ((conf & SB800_SMB_HOSTC_IRQ) == 0); + goto setintr; } aprint_normal_dev(self, "SMBus initialization failed\n"); return; } + /* Read configuration */ + conf = pci_conf_read(pa->pa_pc, pa->pa_tag, PIIX_SMB_HOSTC); + DPRINTF(("%s: conf 0x%08x\n", device_xname(self), conf)); + if ((conf & PIIX_SMB_HOSTC_HSTEN) == 0) { aprint_normal_dev(self, "SMBus disabled\n"); return; } + usesmi = (conf & PIIX_SMB_HOSTC_INTMASK) == PIIX_SMB_HOSTC_SMI; /* 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), + if (base == 0 || + bus_space_map(sc->sc_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; } +setintr: sc->sc_poll = 1; aprint_normal_dev(self, ""); - if ((conf & PIIX_SMB_HOSTC_INTMASK) == PIIX_SMB_HOSTC_SMI) { + if (usesmi) { /* 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, intrbuf, - sizeof(intrbuf)); - sc->sc_smb_ih = pci_intr_establish_xname(pa->pa_pc, ih, - IPL_BIO, piixpm_intr, sc, device_xname(sc->sc_dev)); - if (sc->sc_smb_ih != NULL) { - aprint_normal("interrupting at %s", intrstr); - sc->sc_poll = 0; + } 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, + intrbuf, sizeof(intrbuf)); + sc->sc_smb_ih = pci_intr_establish_xname( + pa->pa_pc, ih, IPL_BIO, piixpm_intr, + sc, device_xname(sc->sc_dev)); + if (sc->sc_smb_ih != NULL) { + aprint_normal("interrupting at %s", + intrstr); + sc->sc_poll = 0; + } } } + if (sc->sc_poll) + aprint_normal("polling"); } - if (sc->sc_poll) - aprint_normal("polling"); aprint_normal("\n"); -attach_i2c: for (i = 0; i < sc->sc_numbusses; i++) sc->sc_i2c_device[i] = NULL; @@ -279,6 +313,20 @@ attach_i2c: } static int +piixpm_iicbus_print(void *aux, const char *pnp) +{ + struct i2cbus_attach_args *iba = aux; + struct i2c_controller *tag = iba->iba_tag; + struct piixpm_smbus *bus = tag->ic_cookie; + struct piixpm_softc *sc = bus->softc; + + iicbus_print(aux, pnp); + if (sc->sc_numbusses != 0) + aprint_normal(" port %d", bus->sda); + + return UNCONF; +} +static int piixpm_rescan(device_t self, const char *ifattr, const int *flags) { struct piixpm_softc *sc = device_private(self); @@ -291,19 +339,26 @@ piixpm_rescan(device_t self, const char /* Attach I2C bus */ for (i = 0; i < sc->sc_numbusses; i++) { + struct i2c_controller *tag = &sc->sc_i2c_tags[i]; + if (sc->sc_i2c_device[i]) continue; 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; + tag->ic_cookie = &sc->sc_busses[i]; + if (PIIXPM_IS_SB800GRP(sc) || PIIXPM_IS_FCHGRP(sc)) { + tag->ic_acquire_bus = piixpm_i2c_sb800_acquire_bus; + tag->ic_release_bus = piixpm_i2c_sb800_release_bus; + } else { + tag->ic_acquire_bus = piixpm_i2c_sb600_acquire_bus; + tag->ic_release_bus = piixpm_i2c_sb600_release_bus; + } + tag->ic_exec = piixpm_i2c_exec; memset(&iba, 0, sizeof(iba)); iba.iba_type = I2C_TYPE_SMBUS; - iba.iba_tag = &sc->sc_i2c_tags[i]; + iba.iba_tag = tag; sc->sc_i2c_device[i] = config_found_ia(self, ifattr, &iba, - iicbus_print); + piixpm_iicbus_print); } return 0; @@ -350,51 +405,91 @@ piixpm_resume(device_t dv, const pmf_qua return true; } +static uint8_t +piixpm_sb800_pmread(struct piixpm_softc *sc, bus_size_t offset) +{ + bus_space_tag_t sbt = sc->sc_sb800_bt; + bus_space_handle_t sbh = sc->sc_sb800_bh; + uint8_t val; + + if (sc->sc_sb800_mmio) + val = bus_space_read_1(sbt, sbh, offset); + else { + bus_space_write_1(sbt, sbh, SB800_INDIRECTIO_INDEX, offset); + val = bus_space_read_1(sbt, sbh, SB800_INDIRECTIO_DATA); + } + + return val; +} + /* * Extract SMBus base address from SB800 Power Management (PM) registers. * The PM registers can be accessed either through indirect I/O (CD6/CD7) or - * direct mapping if AcpiMMioDecodeEn is enabled. Since this function is only - * called once it uses indirect I/O for simplicity. + * direct mapping if AcpiMMioDecodeEn is enabled. Newer devices support MMIO + * access only. */ static int piixpm_sb800_init(struct piixpm_softc *sc) { - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh; /* indirect I/O handle */ - uint16_t val, base_addr; - - /* Fetch SMB base address */ - if (bus_space_map(iot, - PIIXPM_INDIRECTIO_BASE, PIIXPM_INDIRECTIO_SIZE, 0, &ioh)) { - device_printf(sc->sc_dev, "couldn't map indirect I/O space\n"); + bus_space_tag_t sbt = sc->sc_sb800_bt; + bus_space_handle_t sbh; /* indirect memory or I/O handle */ + int rv; + uint16_t base_addr; + uint8_t lo, hi; + bool enabled; + + if (PIIXPM_IS_KERNCZ(sc) || + (PIIXPM_IS_HUDSON(sc) && (sc->sc_rev >= 0x1f))) + sc->sc_numbusses = 2; + else + sc->sc_numbusses = 4; + + /* Check SMBus enable bit and Fetch SMB base address */ + if (sc->sc_sb800_mmio) + rv = bus_space_map(sbt, SB800_FCH_PM_BASE, + SB800_FCH_PM_SIZE, 0, &sbh); + else + rv = bus_space_map(sbt, SB800_INDIRECTIO_BASE, + SB800_INDIRECTIO_SIZE, 0, &sbh); + if (rv != 0) { + device_printf(sc->sc_dev, "couldn't map indirect space\n"); return EBUSY; } - bus_space_write_1(iot, ioh, PIIXPM_INDIRECTIO_INDEX, - SB800_PM_SMBUS0EN_LO); - val = bus_space_read_1(iot, ioh, PIIXPM_INDIRECTIO_DATA); - bus_space_write_1(iot, ioh, PIIXPM_INDIRECTIO_INDEX, - SB800_PM_SMBUS0EN_HI); - val |= bus_space_read_1(iot, ioh, PIIXPM_INDIRECTIO_DATA) << 8; - sc->sc_sb800_ioh = ioh; - - if ((val & SB800_PM_SMBUS0EN_ENABLE) == 0) - return ENOENT; - - base_addr = val & SB800_PM_SMBUS0EN_BADDR; - - aprint_debug_dev(sc->sc_dev, "SMBus @ 0x%04x\n", base_addr); - - bus_space_write_1(iot, ioh, PIIXPM_INDIRECTIO_INDEX, - SB800_PM_SMBUS0SELEN); - bus_space_write_1(iot, ioh, PIIXPM_INDIRECTIO_DATA, 1); /* SMBUS0SEL */ + sc->sc_sb800_bh = sbh; + if (PIIXPM_IS_FCHGRP(sc)) { + lo = piixpm_sb800_pmread(sc, AMDFCH41_PM_DECODE_EN0); + enabled = lo & AMDFCH41_SMBUS_EN; + if (!enabled) + return ENOENT; - if (bus_space_map(iot, PCI_MAPREG_IO_ADDR(base_addr), - PIIX_SMB_SIZE, 0, &sc->sc_smb_ioh)) { + hi = piixpm_sb800_pmread(sc, AMDFCH41_PM_DECODE_EN1); + base_addr = (uint16_t)hi << 8; + } else { + uint8_t data; + + lo = piixpm_sb800_pmread(sc, SB800_PM_SMBUS0EN_LO); + enabled = lo & SB800_PM_SMBUS0EN_ENABLE; + if (!enabled) + return ENOENT; + + hi = piixpm_sb800_pmread(sc, SB800_PM_SMBUS0EN_HI); + base_addr = ((uint16_t)hi << 8) & SB800_PM_SMBUS0EN_BADDR; + + bus_space_write_1(sbt, sbh, SB800_INDIRECTIO_INDEX, + SB800_PM_SMBUS0SELEN); + data = bus_space_read_1(sbt, sbh, SB800_INDIRECTIO_DATA); + if ((data & SB800_PM_USE_SMBUS0SEL) != 0) + sc->sc_sb800_selen = true; + } + + aprint_debug_dev(sc->sc_dev, "SMBus %s access @ 0x%04x\n", + sc->sc_sb800_mmio ? "memory" : "I/O", base_addr); + + if (bus_space_map(sc->sc_iot, PCI_MAPREG_IO_ADDR(base_addr), + SB800_SMB_SIZE, 0, &sc->sc_smb_ioh)) { aprint_error_dev(sc->sc_dev, "can't map smbus I/O space\n"); return EBUSY; } - aprint_normal_dev(sc->sc_dev, "polling (SB800)\n"); - sc->sc_poll = 1; return 0; } @@ -421,43 +516,129 @@ piixpm_csb5_reset(void *arg) } static int -piixpm_i2c_acquire_bus(void *cookie, int flags) +piixpm_i2c_sb600_acquire_bus(void *cookie, int flags) +{ + struct piixpm_smbus *smbus = cookie; + struct piixpm_softc *sc = smbus->softc; + + if (!cold) + mutex_enter(&sc->sc_i2c_mutex); + + return 0; +} + +static void +piixpm_i2c_sb600_release_bus(void *cookie, int flags) +{ + struct piixpm_smbus *smbus = cookie; + struct piixpm_softc *sc = smbus->softc; + + if (!cold) + mutex_exit(&sc->sc_i2c_mutex); +} + +static int +piixpm_i2c_sb800_acquire_bus(void *cookie, int flags) { struct piixpm_smbus *smbus = cookie; struct piixpm_softc *sc = smbus->softc; + uint8_t sctl, old_sda, index, mask, reg; + int i; + if (!cold) mutex_enter(&sc->sc_i2c_mutex); - if (smbus->sda > 0) /* SB800 */ - { - bus_space_write_1(sc->sc_iot, sc->sc_sb800_ioh, - PIIXPM_INDIRECTIO_INDEX, SB800_PM_SMBUS0SEL); - bus_space_write_1(sc->sc_iot, sc->sc_sb800_ioh, - PIIXPM_INDIRECTIO_DATA, smbus->sda << 1); + sctl = bus_space_read_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_SC); + for (i = 0; i < PIIX_SB800_TIMEOUT; i++) { + /* Try to acquire the host semaphore */ + sctl &= ~PIIX_SMB_SC_SEMMASK; + bus_space_write_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_SC, + sctl | PIIX_SMB_SC_HOSTSEM); + + sctl = bus_space_read_1(sc->sc_iot, sc->sc_smb_ioh, + PIIX_SMB_SC); + if ((sctl & PIIX_SMB_SC_HOSTSEM) != 0) + break; + + delay(1000); + } + if (i >= PIIX_SB800_TIMEOUT) { + device_printf(sc->sc_dev, + "Failed to acquire the host semaphore\n"); + return -1; + } + + if (PIIXPM_IS_KERNCZ(sc) || + (PIIXPM_IS_HUDSON(sc) && (sc->sc_rev >= 0x1f))) { + index = AMDFCH41_PM_PORT_INDEX; + mask = AMDFCH41_SMBUS_PORTMASK; + } else if (sc->sc_sb800_selen) { + index = SB800_PM_SMBUS0SEL; + mask = SB800_PM_SMBUS0_MASK_E; + } else { + index = SB800_PM_SMBUS0EN_LO; + mask = SB800_PM_SMBUS0_MASK_C; + } + + reg = piixpm_sb800_pmread(sc, index); + + old_sda = __SHIFTOUT(reg, mask); + if (smbus->sda != old_sda) { + reg &= ~mask; + reg |= __SHIFTIN(smbus->sda, mask); + /* + * SB800_INDIRECTIO_INDEX is already set on I/O access, + * so it's not required to write it again. + */ + bus_space_write_1(sc->sc_sb800_bt, sc->sc_sb800_bh, + sc->sc_sb800_mmio ? index : SB800_INDIRECTIO_DATA, reg); } + /* Save the old port number */ + smbus->sda_save = old_sda; + return 0; } static void -piixpm_i2c_release_bus(void *cookie, int flags) +piixpm_i2c_sb800_release_bus(void *cookie, int flags) { struct piixpm_smbus *smbus = cookie; struct piixpm_softc *sc = smbus->softc; + uint8_t sctl, index, mask, reg; - if (smbus->sda > 0) /* SB800 */ - { + if (PIIXPM_IS_KERNCZ(sc) || + (PIIXPM_IS_HUDSON(sc) && (sc->sc_rev >= 0x1f))) { + index = AMDFCH41_PM_PORT_INDEX; + mask = AMDFCH41_SMBUS_PORTMASK; + } else if (sc->sc_sb800_selen) { + index = SB800_PM_SMBUS0SEL; + mask = SB800_PM_SMBUS0_MASK_E; + } else { + index = SB800_PM_SMBUS0EN_LO; + mask = SB800_PM_SMBUS0_MASK_C; + } + + if (smbus->sda != smbus->sda_save) { + /* Restore the port number */ + reg = piixpm_sb800_pmread(sc, index); + reg &= ~mask; + reg |= __SHIFTIN(smbus->sda_save, mask); /* - * HP Microserver hangs after reboot if not set to SDA0. - * Also add shutdown hook? + * SB800_INDIRECTIO_INDEX is already set on I/O access, + * so it's not required to write it again. */ - bus_space_write_1(sc->sc_iot, sc->sc_sb800_ioh, - PIIXPM_INDIRECTIO_INDEX, SB800_PM_SMBUS0SEL); - bus_space_write_1(sc->sc_iot, sc->sc_sb800_ioh, - PIIXPM_INDIRECTIO_DATA, 0); + bus_space_write_1(sc->sc_sb800_bt, sc->sc_sb800_bh, + sc->sc_sb800_mmio ? index : SB800_INDIRECTIO_DATA, reg); } + /* Release the host semaphore */ + sctl = bus_space_read_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_SC); + sctl &= ~PIIX_SMB_SC_SEMMASK; + bus_space_write_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_SC, + sctl | PIIX_SMB_SC_CLRHOSTSEM); + if (!cold) mutex_exit(&sc->sc_i2c_mutex); } @@ -468,23 +649,24 @@ piixpm_i2c_exec(void *cookie, i2c_op_t o { struct piixpm_smbus *smbus = cookie; struct piixpm_softc *sc = smbus->softc; - const u_int8_t *b; - u_int8_t ctl = 0, st; + const uint8_t *b; + uint8_t ctl = 0, st; int retries; - DPRINTF(("%s: exec: op %d, addr 0x%x, cmdlen %zu, len %zu, flags 0x%x\n", - device_xname(sc->sc_dev), op, addr, cmdlen, len, flags)); + DPRINTF(("%s: exec: op %d, addr 0x%02x, cmdlen %zu, len %zu, " + "flags 0x%x\n", + device_xname(sc->sc_dev), op, addr, cmdlen, len, flags)); /* Clear status bits */ - bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_HS, + bus_space_write_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_HS, PIIX_SMB_HS_INTR | PIIX_SMB_HS_DEVERR | PIIX_SMB_HS_BUSERR | PIIX_SMB_HS_FAILED); - bus_space_barrier(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_HS, 1, + bus_space_barrier(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_HS, 1, BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); /* Wait for bus to be idle */ for (retries = 100; retries > 0; retries--) { - st = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh, + st = bus_space_read_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_HS); if (!(st & PIIX_SMB_HS_BUSY)) break; @@ -509,27 +691,27 @@ piixpm_i2c_exec(void *cookie, i2c_op_t o sc->sc_i2c_xfer.error = 0; /* Set slave address and transfer direction */ - bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_TXSLVA, + bus_space_write_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_TXSLVA, PIIX_SMB_TXSLVA_ADDR(addr) | (I2C_OP_READ_P(op) ? PIIX_SMB_TXSLVA_READ : 0)); b = cmdbuf; if (cmdlen > 0) /* Set command byte */ - bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, + bus_space_write_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_HCMD, b[0]); if (I2C_OP_WRITE_P(op)) { /* Write data */ b = buf; if (cmdlen == 0 && len == 1) - bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, + bus_space_write_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_HCMD, b[0]); else if (len > 0) - bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, + bus_space_write_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_HD0, b[0]); if (len > 1) - bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, + bus_space_write_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_HD1, b[1]); } @@ -543,22 +725,24 @@ piixpm_i2c_exec(void *cookie, i2c_op_t o ctl = PIIX_SMB_HC_CMD_BDATA; else if (len == 2) ctl = PIIX_SMB_HC_CMD_WDATA; + else + panic("%s: unexpected len %zu", __func__, len); if ((flags & I2C_F_POLL) == 0) ctl |= PIIX_SMB_HC_INTREN; /* Start transaction */ ctl |= PIIX_SMB_HC_START; - bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_HC, ctl); + bus_space_write_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_HC, ctl); if (flags & I2C_F_POLL) { /* Poll for completion */ - if (PIIXPM_IS_CSB5(sc->sc_id)) + if (PIIXPM_IS_CSB5(sc)) DELAY(2*PIIXPM_DELAY); else DELAY(PIIXPM_DELAY); for (retries = 1000; retries > 0; retries--) { - st = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh, + st = bus_space_read_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_HS); if ((st & PIIX_SMB_HS_BUSY) == 0) break; @@ -569,7 +753,7 @@ piixpm_i2c_exec(void *cookie, i2c_op_t o piixpm_intr(sc); } else { /* Wait for interrupt */ - if (tsleep(sc, PRIBIO, "iicexec", PIIXPM_TIMEOUT * hz)) + if (tsleep(sc, PRIBIO, "piixpm", PIIXPM_TIMEOUT * hz)) goto timeout; } @@ -583,18 +767,18 @@ timeout: * Transfer timeout. Kill the transaction and clear status bits. */ aprint_error_dev(sc->sc_dev, "timeout, status 0x%x\n", st); - bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_HC, + bus_space_write_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_HC, PIIX_SMB_HC_KILL); DELAY(PIIXPM_DELAY); - st = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_HS); + st = bus_space_read_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_HS); if ((st & PIIX_SMB_HS_FAILED) == 0) aprint_error_dev(sc->sc_dev, "transaction abort failed, status 0x%x\n", st); - bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_HS, st); + bus_space_write_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_HS, st); /* * CSB5 needs hard reset to unlock the smbus after timeout. */ - if (PIIXPM_IS_CSB5(sc->sc_id)) + if (PIIXPM_IS_CSB5(sc)) piixpm_csb5_reset(sc); return (1); } @@ -603,12 +787,12 @@ static int piixpm_intr(void *arg) { struct piixpm_softc *sc = arg; - u_int8_t st; - u_int8_t *b; + uint8_t st; + uint8_t *b; size_t len; /* Read status */ - st = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_HS); + st = bus_space_read_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_HS); if ((st & PIIX_SMB_HS_BUSY) != 0 || (st & (PIIX_SMB_HS_INTR | PIIX_SMB_HS_DEVERR | PIIX_SMB_HS_BUSERR | PIIX_SMB_HS_FAILED)) == 0) @@ -618,7 +802,7 @@ piixpm_intr(void *arg) DPRINTF(("%s: intr st %#x\n", device_xname(sc->sc_dev), st & 0xff)); /* Clear status bits */ - bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_HS, st); + bus_space_write_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_HS, st); /* Check for errors */ if (st & (PIIX_SMB_HS_DEVERR | PIIX_SMB_HS_BUSERR | @@ -635,10 +819,10 @@ piixpm_intr(void *arg) b = sc->sc_i2c_xfer.buf; len = sc->sc_i2c_xfer.len; if (len > 0) - b[0] = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh, + b[0] = bus_space_read_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_HD0); if (len > 1) - b[1] = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh, + b[1] = bus_space_read_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_HD1); }