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");