svn commit: r304674 - head/sys/dev/intpm
Andriy Gapon
avg at FreeBSD.org
Tue Aug 23 10:40:54 UTC 2016
Author: avg
Date: Tue Aug 23 10:40:53 2016
New Revision: 304674
URL: https://svnweb.freebsd.org/changeset/base/304674
Log:
intpm: add support for SB800
This code should be able to support later AMD chipsets as well, but that
hasn't been tested.
SB800 supports accessing several different SMBus buses using the same
set of constrol registeirs plus special PMIO registers that control which
bus is selected. This could be exposed to consumers as several smb devices
each talking to its bus. This feature is not implemented yet.
MFC after: 2 weeks
Modified:
head/sys/dev/intpm/intpm.c
Modified: head/sys/dev/intpm/intpm.c
==============================================================================
--- head/sys/dev/intpm/intpm.c Tue Aug 23 08:13:08 2016 (r304673)
+++ head/sys/dev/intpm/intpm.c Tue Aug 23 10:40:53 2016 (r304674)
@@ -52,8 +52,10 @@ struct intsmb_softc {
struct resource *irq_res;
void *irq_hand;
device_t smbus;
+ int io_rid;
int isbusy;
int cfg_irq9;
+ int sb8xx;
int poll;
struct mtx lock;
};
@@ -102,10 +104,8 @@ intsmb_probe(device_t dev)
device_set_desc(dev, "ATI IXP400 SMBus Controller");
break;
case 0x43851002:
- /* SB800 and newer can not be configured in a compatible way. */
- if (pci_get_revid(dev) >= 0x40)
- return (ENXIO);
- device_set_desc(dev, "AMD SB600/700/710/750 SMBus Controller");
+ case 0x780b1022: /* AMD Hudson */
+ device_set_desc(dev, "AMD SB600/7xx/8xx SMBus Controller");
/* XXX Maybe force polling right here? */
break;
default:
@@ -115,6 +115,87 @@ intsmb_probe(device_t dev)
return (BUS_PROBE_DEFAULT);
}
+static uint8_t
+sb8xx_pmio_read(struct resource *res, uint8_t reg)
+{
+ bus_write_1(res, 0, reg); /* Index */
+ return (bus_read_1(res, 1)); /* Data */
+}
+
+static int
+sb8xx_attach(device_t dev)
+{
+ static const int AMDSB_PMIO_INDEX = 0xcd6;
+ static const int AMDSB_PMIO_WIDTH = 2;
+ static const int AMDSB8_SMBUS_ADDR = 0x2c;
+ static const int AMDSB8_SMBUS_EN = 0x01;
+ static const int AMDSB8_SMBUS_ADDR_MASK = ~0x1fu;
+ static const int AMDSB_SMBIO_WIDTH = 0x14;
+ static const int AMDSB_SMBUS_CFG = 0x10;
+ static const int AMDSB_SMBUS_IRQ = 0x01;
+ static const int AMDSB_SMBUS_REV_MASK = ~0x0fu;
+ static const int AMDSB_SMBUS_REV_SHIFT = 4;
+ static const int AMDSB_IO_RID = 0;
+
+ struct intsmb_softc *sc;
+ struct resource *res;
+ uint16_t addr;
+ uint8_t cfg;
+ int rid;
+ int rc;
+
+ sc = device_get_softc(dev);
+ rid = AMDSB_IO_RID;
+ rc = bus_set_resource(dev, SYS_RES_IOPORT, rid, AMDSB_PMIO_INDEX,
+ 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,
+ RF_ACTIVE | RF_SHAREABLE);
+ if (res == NULL) {
+ device_printf(dev, "bus_alloc_resource for PM IO failed\n");
+ return (ENXIO);
+ }
+
+ addr = sb8xx_pmio_read(res, AMDSB8_SMBUS_ADDR + 1);
+ addr <<= 8;
+ addr |= sb8xx_pmio_read(res, AMDSB8_SMBUS_ADDR);
+
+ bus_release_resource(dev, SYS_RES_IOPORT, rid, res);
+ bus_delete_resource(dev, SYS_RES_IOPORT, rid);
+
+ if ((addr & AMDSB8_SMBUS_EN) == 0) {
+ device_printf(dev, "SB8xx SMBus not enabled\n");
+ return (ENXIO);
+ }
+
+ addr &= AMDSB8_SMBUS_ADDR_MASK;
+ sc->io_rid = AMDSB_IO_RID;
+ rc = bus_set_resource(dev, SYS_RES_IOPORT, sc->io_rid, addr,
+ AMDSB_SMBIO_WIDTH);
+ if (rc != 0) {
+ device_printf(dev, "bus_set_resource for SMBus IO failed\n");
+ return (ENXIO);
+ }
+ if (res == NULL) {
+ device_printf(dev, "bus_alloc_resource for SMBus IO failed\n");
+ return (ENXIO);
+ }
+ sc->io_res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &sc->io_rid,
+ RF_ACTIVE | RF_SHAREABLE);
+ cfg = bus_read_1(sc->io_res, AMDSB_SMBUS_CFG);
+
+ sc->poll = 1;
+ device_printf(dev, "intr %s disabled ",
+ (cfg & AMDSB_SMBUS_IRQ) != 0 ? "IRQ" : "SMI");
+ printf("revision %d\n",
+ (cfg & AMDSB_SMBUS_REV_MASK) >> AMDSB_SMBUS_REV_SHIFT);
+
+ return (0);
+}
+
static int
intsmb_attach(device_t dev)
{
@@ -128,18 +209,31 @@ intsmb_attach(device_t dev)
mtx_init(&sc->lock, device_get_nameunit(dev), "intsmb", MTX_DEF);
sc->cfg_irq9 = 0;
-#ifndef NO_CHANGE_PCICONF
switch (pci_get_devid(dev)) {
+#ifndef NO_CHANGE_PCICONF
case 0x71138086: /* Intel 82371AB */
case 0x719b8086: /* Intel 82443MX */
/* Changing configuration is allowed. */
sc->cfg_irq9 = 1;
break;
- }
#endif
+ case 0x43851002:
+ case 0x780b1022:
+ if (pci_get_revid(dev) >= 0x40)
+ sc->sb8xx = 1;
+ break;
+ }
+
+ if (sc->sb8xx) {
+ error = sb8xx_attach(dev);
+ if (error != 0)
+ goto fail;
+ else
+ goto no_intr;
+ }
- rid = PCI_BASE_ADDR_SMB;
- sc->io_res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid,
+ sc->io_rid = PCI_BASE_ADDR_SMB;
+ sc->io_res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &sc->io_rid,
RF_ACTIVE);
if (sc->io_res == NULL) {
device_printf(dev, "Could not allocate I/O space\n");
@@ -247,7 +341,7 @@ intsmb_detach(device_t dev)
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, PCI_BASE_ADDR_SMB,
+ bus_release_resource(dev, SYS_RES_IOPORT, sc->io_rid,
sc->io_res);
mtx_destroy(&sc->lock);
return (0);
More information about the svn-src-head
mailing list