aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/intpm/intpm.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/intpm/intpm.c')
-rw-r--r--sys/dev/intpm/intpm.c51
1 files changed, 36 insertions, 15 deletions
diff --git a/sys/dev/intpm/intpm.c b/sys/dev/intpm/intpm.c
index 90994f8053f6..fd3838bbcc14 100644
--- a/sys/dev/intpm/intpm.c
+++ b/sys/dev/intpm/intpm.c
@@ -55,6 +55,7 @@ struct intsmb_softc {
int cfg_irq9;
int sb8xx;
int poll;
+ int type;
struct mtx lock;
};
@@ -135,28 +136,44 @@ sb8xx_attach(device_t dev)
struct resource *res;
uint32_t devid;
uint8_t revid;
- uint16_t addr;
+ uint32_t addr;
int rid;
int rc;
bool enabled;
sc = device_get_softc(dev);
+ devid = pci_get_devid(dev);
+ revid = pci_get_revid(dev);
+
+ /*
+ * Comment from Linux i2c-piix4.c:
+ *
+ * cd6h/cd7h port I/O accesses can be disabled on AMD processors
+ * w/ SMBus PCI revision ID 0x51 or greater. MMIO is supported on
+ * the same processors and is the recommended access method.
+ */
+ if (devid == AMDCZ_SMBUS_DEVID && revid >= AMDCZ51_SMBUS_REVID) {
+ sc->type = SYS_RES_MEMORY;
+ addr = AMDFCH41_MMIO_ADDR + AMDFCH41_MMIO_PM_OFF;
+ } else {
+ sc->type = SYS_RES_IOPORT;
+ addr = AMDSB_PMIO_INDEX;
+ }
+
rid = 0;
- rc = bus_set_resource(dev, SYS_RES_IOPORT, rid, AMDSB_PMIO_INDEX,
+ rc = bus_set_resource(dev, sc->type, rid, addr,
AMDSB_PMIO_WIDTH);
if (rc != 0) {
device_printf(dev, "bus_set_resource for PM IO failed\n");
return (ENXIO);
}
- res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid,
+ res = bus_alloc_resource_any(dev, sc->type, &rid,
RF_ACTIVE);
if (res == NULL) {
device_printf(dev, "bus_alloc_resource for PM IO failed\n");
return (ENXIO);
}
- devid = pci_get_devid(dev);
- revid = pci_get_revid(dev);
if (devid == AMDSB_SMBUS_DEVID ||
(devid == AMDFCH_SMBUS_DEVID && revid < AMDFCH41_SMBUS_REVID) ||
(devid == AMDCZ_SMBUS_DEVID && revid < AMDCZ49_SMBUS_REVID)) {
@@ -165,6 +182,10 @@ sb8xx_attach(device_t dev)
addr |= amd_pmio_read(res, AMDSB8_PM_SMBUS_EN);
enabled = (addr & AMDSB8_SMBUS_EN) != 0;
addr &= AMDSB8_SMBUS_ADDR_MASK;
+ } else if (devid == AMDCZ_SMBUS_DEVID && revid >= AMDCZ51_SMBUS_REVID) {
+ addr = bus_read_1(res, AMDFCH41_PM_DECODE_EN0);
+ enabled = (addr & AMDFCH41_SMBUS_EN) != 0;
+ addr = AMDFCH41_MMIO_ADDR + AMDFCH41_MMIO_SMBUS_OFF;
} else {
addr = amd_pmio_read(res, AMDFCH41_PM_DECODE_EN0);
enabled = (addr & AMDFCH41_SMBUS_EN) != 0;
@@ -172,8 +193,8 @@ sb8xx_attach(device_t dev)
addr <<= 8;
}
- bus_release_resource(dev, SYS_RES_IOPORT, rid, res);
- bus_delete_resource(dev, SYS_RES_IOPORT, rid);
+ bus_release_resource(dev, sc->type, rid, res);
+ bus_delete_resource(dev, sc->type, rid);
if (!enabled) {
device_printf(dev, "SB8xx/SB9xx/FCH SMBus not enabled\n");
@@ -181,13 +202,13 @@ sb8xx_attach(device_t dev)
}
sc->io_rid = 0;
- rc = bus_set_resource(dev, SYS_RES_IOPORT, sc->io_rid, addr,
+ rc = bus_set_resource(dev, sc->type, sc->io_rid, addr,
AMDSB_SMBIO_WIDTH);
if (rc != 0) {
device_printf(dev, "bus_set_resource for SMBus IO failed\n");
return (ENXIO);
}
- sc->io_res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &sc->io_rid,
+ sc->io_res = bus_alloc_resource_any(dev, sc->type, &sc->io_rid,
RF_ACTIVE);
if (sc->io_res == NULL) {
device_printf(dev, "Could not allocate I/O space\n");
@@ -202,14 +223,13 @@ intsmb_release_resources(device_t dev)
{
struct intsmb_softc *sc = device_get_softc(dev);
- if (sc->smbus)
- device_delete_child(dev, sc->smbus);
+ device_delete_children(dev);
if (sc->irq_hand)
bus_teardown_intr(dev, sc->irq_res, sc->irq_hand);
if (sc->irq_res)
bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
if (sc->io_res)
- bus_release_resource(dev, SYS_RES_IOPORT, sc->io_rid,
+ bus_release_resource(dev, sc->type, sc->io_rid,
sc->io_res);
mtx_destroy(&sc->lock);
}
@@ -227,6 +247,7 @@ intsmb_attach(device_t dev)
mtx_init(&sc->lock, device_get_nameunit(dev), "intsmb", MTX_DEF);
sc->cfg_irq9 = 0;
+ sc->type = SYS_RES_IOPORT;
switch (pci_get_devid(dev)) {
#ifndef NO_CHANGE_PCICONF
case 0x71138086: /* Intel 82371AB */
@@ -255,7 +276,7 @@ intsmb_attach(device_t dev)
}
sc->io_rid = PCI_BASE_ADDR_SMB;
- sc->io_res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &sc->io_rid,
+ sc->io_res = bus_alloc_resource_any(dev, sc->type, &sc->io_rid,
RF_ACTIVE);
if (sc->io_res == NULL) {
device_printf(dev, "Could not allocate I/O space\n");
@@ -326,7 +347,7 @@ intsmb_attach(device_t dev)
no_intr:
sc->isbusy = 0;
- sc->smbus = device_add_child(dev, "smbus", -1);
+ sc->smbus = device_add_child(dev, "smbus", DEVICE_UNIT_ANY);
if (sc->smbus == NULL) {
device_printf(dev, "failed to add smbus child\n");
error = ENXIO;
@@ -858,7 +879,7 @@ intsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf)
if (nread != 0 && nread <= SMBBLOCKTRANS_MAX) {
*count = nread;
for (i = 0; i < nread; i++)
- bus_read_1(sc->io_res, PIIX4_SMBBLKDAT);
+ buf[i] = bus_read_1(sc->io_res, PIIX4_SMBBLKDAT);
} else
error = SMB_EBUSERR;
}