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

Reply via email to