intpm: add support for smbus controller found in AMD SB700
According to the specifications AMD/ATI SMBus controller is very similar to SMBus controller found in PIIX4. Some notable differences: o different bit for enabling/signalling regular interrupt mode o in practice seems to support only polling mode Thus, intpm driver is modified to support polling-only mode and to recognize SB700 PCI ID and differences. Tested on: SB700 and PIIX4E platforms Reviewed by: jhb MFC after: 2 weeks X-Perhaps-ToDo: rename the driver to reflect its function and supported hardware
This commit is contained in:
parent
34d1dd53a4
commit
b6e33c9dd0
@ -53,6 +53,8 @@ struct intsmb_softc {
|
||||
void *irq_hand;
|
||||
device_t smbus;
|
||||
int isbusy;
|
||||
int cfg_irq9;
|
||||
int poll;
|
||||
struct mtx lock;
|
||||
};
|
||||
|
||||
@ -96,6 +98,10 @@ intsmb_probe(device_t dev)
|
||||
#endif
|
||||
device_set_desc(dev, "Intel PIIX4 SMBUS Interface");
|
||||
break;
|
||||
case 0x43851002:
|
||||
device_set_desc(dev, "AMD SB600/700/710/750 SMBus Controller");
|
||||
/* XXX Maybe force polling right here? */
|
||||
break;
|
||||
default:
|
||||
return (ENXIO);
|
||||
}
|
||||
@ -108,12 +114,24 @@ intsmb_attach(device_t dev)
|
||||
{
|
||||
struct intsmb_softc *sc = device_get_softc(dev);
|
||||
int error, rid, value;
|
||||
int intr;
|
||||
char *str;
|
||||
|
||||
sc->dev = 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)) {
|
||||
case 0x71138086: /* Intel 82371AB */
|
||||
case 0x719b8086: /* Intel 82443MX */
|
||||
/* Changing configuration is allowed. */
|
||||
sc->cfg_irq9 = 1;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
rid = PCI_BASE_ADDR_SMB;
|
||||
sc->io_res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid,
|
||||
RF_ACTIVE);
|
||||
@ -123,27 +141,36 @@ intsmb_attach(device_t dev)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
#ifndef NO_CHANGE_PCICONF
|
||||
pci_write_config(dev, PCIR_INTLINE, 0x9, 1);
|
||||
pci_write_config(dev, PCI_HST_CFG_SMB,
|
||||
PCI_INTR_SMB_IRQ9 | PCI_INTR_SMB_ENABLE, 1);
|
||||
#endif
|
||||
if (sc->cfg_irq9) {
|
||||
pci_write_config(dev, PCIR_INTLINE, 0x9, 1);
|
||||
pci_write_config(dev, PCI_HST_CFG_SMB,
|
||||
PCI_INTR_SMB_IRQ9 | PCI_INTR_SMB_ENABLE, 1);
|
||||
}
|
||||
value = pci_read_config(dev, PCI_HST_CFG_SMB, 1);
|
||||
switch (value & 0xe) {
|
||||
sc->poll = (value & PCI_INTR_SMB_ENABLE) == 0;
|
||||
intr = value & PCI_INTR_SMB_MASK;
|
||||
switch (intr) {
|
||||
case PCI_INTR_SMB_SMI:
|
||||
str = "SMI";
|
||||
break;
|
||||
case PCI_INTR_SMB_IRQ9:
|
||||
str = "IRQ 9";
|
||||
break;
|
||||
case PCI_INTR_SMB_IRQ_PCI:
|
||||
str = "PCI IRQ";
|
||||
break;
|
||||
default:
|
||||
str = "BOGUS";
|
||||
}
|
||||
|
||||
device_printf(dev, "intr %s %s ", str,
|
||||
(value & 1) ? "enabled" : "disabled");
|
||||
sc->poll == 0 ? "enabled" : "disabled");
|
||||
printf("revision %d\n", pci_read_config(dev, PCI_REVID_SMB, 1));
|
||||
|
||||
if ((value & 0xe) != PCI_INTR_SMB_IRQ9) {
|
||||
if (sc->poll)
|
||||
goto no_intr;
|
||||
|
||||
if (intr != PCI_INTR_SMB_IRQ9 && intr != PCI_INTR_SMB_IRQ_PCI) {
|
||||
device_printf(dev, "Unsupported interrupt mode\n");
|
||||
error = ENXIO;
|
||||
goto fail;
|
||||
@ -151,7 +178,9 @@ intsmb_attach(device_t dev)
|
||||
|
||||
/* Force IRQ 9. */
|
||||
rid = 0;
|
||||
bus_set_resource(dev, SYS_RES_IRQ, rid, 9, 1);
|
||||
if (sc->cfg_irq9)
|
||||
bus_set_resource(dev, SYS_RES_IRQ, rid, 9, 1);
|
||||
|
||||
sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
|
||||
RF_SHAREABLE | RF_ACTIVE);
|
||||
if (sc->irq_res == NULL) {
|
||||
@ -167,6 +196,7 @@ intsmb_attach(device_t dev)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
no_intr:
|
||||
sc->isbusy = 0;
|
||||
sc->smbus = device_add_child(dev, "smbus", -1);
|
||||
if (sc->smbus == NULL) {
|
||||
@ -361,7 +391,7 @@ intsmb_start(struct intsmb_softc *sc, unsigned char cmd, int nointr)
|
||||
tmp |= PIIX4_SMBHSTCNT_START;
|
||||
|
||||
/* While not in autoconfiguration enable interrupts. */
|
||||
if (!cold && !nointr)
|
||||
if (!sc->poll && !cold && !nointr)
|
||||
tmp |= PIIX4_SMBHSTCNT_INTREN;
|
||||
bus_write_1(sc->io_res, PIIX4_SMBHSTCNT, tmp);
|
||||
}
|
||||
@ -411,8 +441,6 @@ intsmb_stop_poll(struct intsmb_softc *sc)
|
||||
if (!(status & PIIX4_SMBHSTSTAT_BUSY)) {
|
||||
sc->isbusy = 0;
|
||||
error = intsmb_error(sc->dev, status);
|
||||
if (error == 0 && !(status & PIIX4_SMBHSTSTAT_INTR))
|
||||
device_printf(sc->dev, "unknown cause why?\n");
|
||||
return (error);
|
||||
}
|
||||
}
|
||||
@ -434,7 +462,7 @@ intsmb_stop(struct intsmb_softc *sc)
|
||||
|
||||
INTSMB_LOCK_ASSERT(sc);
|
||||
|
||||
if (cold)
|
||||
if (sc->poll || cold)
|
||||
/* So that it can use device during device probe on SMBus. */
|
||||
return (intsmb_stop_poll(sc));
|
||||
|
||||
|
@ -35,7 +35,9 @@
|
||||
#define PCI_BASE_ADDR_SMB 0x90 /* IO BAR. */
|
||||
#define PCI_BASE_ADDR_PM 0x40
|
||||
#define PCI_HST_CFG_SMB 0xd2 /* Host Configuration */
|
||||
#define PCI_INTR_SMB_MASK 0xe
|
||||
#define PCI_INTR_SMB_SMI 0
|
||||
#define PCI_INTR_SMB_IRQ_PCI 2
|
||||
#define PCI_INTR_SMB_IRQ9 8
|
||||
#define PCI_INTR_SMB_ENABLE 1
|
||||
#define PCI_SLV_CMD_SMB 0xd3 /*SLAVE COMMAND*/
|
||||
|
Loading…
Reference in New Issue
Block a user