This adds support for SB800+ and is a little easier to understand, but it probably isn't very pretty.
Information obtained from AMD SB800 datasheets, 45481.pdf/45482.pdf/45483.pdf. Any comments? I'm not really sure if playing with non-pci I/O space in a PCI driver makes sense.. but there really isn't any choice with this chipset. -Bryan. Index: piixpm.c =================================================================== RCS file: /cvs/src/sys/dev/pci/piixpm.c,v retrieving revision 1.35 diff -u -r1.35 piixpm.c --- piixpm.c 9 Apr 2011 04:33:40 -0000 1.35 +++ piixpm.c 19 May 2011 04:39:29 -0000 @@ -114,50 +114,100 @@ { struct piixpm_softc *sc = (struct piixpm_softc *)self; struct pci_attach_args *pa = aux; - struct i2cbus_attach_args iba; - pcireg_t base, conf; + pcireg_t conf; + bus_space_handle_t pm_ioh; + u_int8_t smben_reg[2]; + bus_addr_t base; pci_intr_handle_t ih; const char *intrstr = NULL; + struct i2cbus_attach_args iba; + + if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_ATI && + PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ATI_SBX00_SMB && + PCI_REVISION(pa->pa_class) >= 0x40) { + /* + * AMD SB800+ + * PM_Reg is defined as 0xcd6(index), 0xcd7(data). + * Base addr + enabled bit in PM_Reg, I/O mapped. + */ + /* This could be mapped already, failure the only option? */ + if (bus_space_map(sc->sc_iot, 0xcd6, 2, 0, &pm_ioh) != 0) { + printf(": can't map i/o space\n"); + return; + } + + /* "SmBus0En" byte 1 */ + bus_space_write_1(sc->sc_iot, pm_ioh, 0, 0x2c); + smben_reg[0] = bus_space_read_1(sc->sc_iot, pm_ioh, 1); + if ((smben_reg[0] & 0x01) == 0) { + bus_space_unmap(sc->sc_iot, pm_ioh, 2); + printf(": SMBus disabled\n"); + return; + } + /* "SmBus0En" byte 2 */ + bus_space_write_1(sc->sc_iot, pm_ioh, 0, 0x2c + 1); + smben_reg[1] = bus_space_read_1(sc->sc_iot, pm_ioh, 1); + + /* XXX: PM_Reg may be mapped by other devices. */ + bus_space_unmap(sc->sc_iot, pm_ioh, 2); - /* Read configuration */ - conf = pci_conf_read(pa->pa_pc, pa->pa_tag, PIIX_SMB_HOSTC); - DPRINTF((": conf 0x%08x", conf)); - - if ((conf & PIIX_SMB_HOSTC_HSTEN) == 0) { - printf(": SMBus disabled\n"); - return; - } - - /* Map I/O space */ - sc->sc_iot = pa->pa_iot; - base = pci_conf_read(pa->pa_pc, pa->pa_tag, PIIX_SMB_BASE) & 0xffff; - if (PCI_MAPREG_IO_ADDR(base) == 0 || - bus_space_map(sc->sc_iot, PCI_MAPREG_IO_ADDR(base), - PIIX_SMB_SIZE, 0, &sc->sc_ioh)) { - printf(": can't map i/o space\n"); - return; - } - - sc->sc_poll = 1; - if ((conf & PIIX_SMB_HOSTC_INTMASK) == PIIX_SMB_HOSTC_SMI) { - /* No PCI IRQ */ + /* Retrieve base address. */ + base = ((smben_reg[1] << 8) | smben_reg[0]) & 0xffe0; + if (base == 0 || bus_space_map(sc->sc_iot, base, PIIX_SMB_SIZE, + 0, &sc->sc_ioh)) { + printf(": can't map i/o space"); + return; + } + + /* XXX: IRQ.. */ printf(": SMI"); + sc->sc_poll = 1; } else { - if ((conf & PIIX_SMB_HOSTC_INTMASK) == PIIX_SMB_HOSTC_IRQ) { + /* Read configuration */ + conf = pci_conf_read(pa->pa_pc, pa->pa_tag, PIIX_SMB_HOSTC); + DPRINTF((": conf 0x%08x", conf)); + + if ((conf & PIIX_SMB_HOSTC_HSTEN) == 0) { + printf(": SMBus disabled\n"); + return; + } + + /* Map I/O space */ + sc->sc_iot = pa->pa_iot; + base = pci_conf_read(pa->pa_pc, pa->pa_tag, PIIX_SMB_BASE) & + 0xffff; + if (PCI_MAPREG_IO_ADDR(base) == 0 || + bus_space_map(sc->sc_iot, PCI_MAPREG_IO_ADDR(base), + PIIX_SMB_SIZE, 0, &sc->sc_ioh)) { + printf(": can't map i/o space\n"); + return; + } + + sc->sc_poll = 1; + switch ((conf & PIIX_SMB_HOSTC_INTMASK)) { + /* No PCI IRQ */ + case PIIX_SMB_HOSTC_SMI: + printf(": SMI"); + break; /* Install interrupt handler */ - if (pci_intr_map(pa, &ih) == 0) { - intrstr = pci_intr_string(pa->pa_pc, ih); - sc->sc_ih = pci_intr_establish(pa->pa_pc, - ih, IPL_BIO, piixpm_intr, sc, - sc->sc_dev.dv_xname); - if (sc->sc_ih != NULL) { - printf(": %s", intrstr); - sc->sc_poll = 0; + case PIIX_SMB_HOSTC_IRQ: + if (pci_intr_map(pa, &ih) == 0) { + intrstr = pci_intr_string(pa->pa_pc, + ih); + sc->sc_ih = pci_intr_establish( + pa->pa_pc, ih, + IPL_BIO, piixpm_intr, sc, + sc->sc_dev.dv_xname); + if (sc->sc_ih != NULL) { + printf(": %s", intrstr); + sc->sc_poll = 0; + break; + } } - } + /* Try polling.. */ + default: + printf(": polling"); } - if (sc->sc_poll) - printf(": polling"); } printf("\n");