This diff should add support for newer smbus controllers used on newer AMD
chipsets. Especially Hudson-2 and Kerncz based chipsets. On my Ryzen 5 the
iic(4) busses attach but there is nothing detected on them (well possible
that I missed something). I also implemented the up to 4 busses available
on chipsets of the SBx00 series (on Hudson-2 and Kerncz only 2 ports).

I would be interested if on systems with Ryzen CPUs something attaches to
those iic(4) busses. Could be that I missed something and fail to properly
access the bus.
-- 
:wq Claudio


Index: piixpm.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/piixpm.c,v
retrieving revision 1.39
diff -u -p -r1.39 piixpm.c
--- piixpm.c    1 Oct 2013 20:06:02 -0000       1.39
+++ piixpm.c    16 Dec 2019 11:26:11 -0000
@@ -45,15 +45,24 @@
 #define PIIXPM_DELAY   200
 #define PIIXPM_TIMEOUT 1
 
+struct piixpm_smbus {
+       int                      sb_bus;
+       struct piixpm_softc     *sb_sc;
+};
+
 struct piixpm_softc {
        struct device           sc_dev;
 
        bus_space_tag_t         sc_iot;
        bus_space_handle_t      sc_ioh;
+       bus_space_handle_t      sc_sb800_ioh;
        void *                  sc_ih;
        int                     sc_poll;
+       int                     sc_is_sb800;
+       int                     sc_is_kerncz;
 
-       struct i2c_controller   sc_i2c_tag;
+       struct piixpm_smbus     sc_busses[4];
+       struct i2c_controller   sc_i2c_tag[4];
        struct rwlock           sc_i2c_lock;
        struct {
                i2c_op_t     op;
@@ -86,6 +95,7 @@ struct cfdriver piixpm_cd = {
 
 const struct pci_matchid piixpm_ids[] = {
        { PCI_VENDOR_AMD, PCI_PRODUCT_AMD_HUDSON2_SMB },
+       { PCI_VENDOR_AMD, PCI_PRODUCT_AMD_KERNCZ_SMB },
 
        { PCI_VENDOR_ATI, PCI_PRODUCT_ATI_SB200_SMB },
        { PCI_VENDOR_ATI, PCI_PRODUCT_ATI_SB300_SMB },
@@ -117,17 +127,21 @@ piixpm_attach(struct device *parent, str
        struct piixpm_softc *sc = (struct piixpm_softc *)self;
        struct pci_attach_args *pa = aux;
        bus_space_handle_t ioh;
-       u_int16_t smb0en;
+       u_int16_t val, smb0en;
        bus_addr_t base;
        pcireg_t conf;
        pci_intr_handle_t ih;
        const char *intrstr = NULL;
        struct i2cbus_attach_args iba;
+       int numbusses, i;
 
        sc->sc_iot = pa->pa_iot;
+       numbusses = 1;
 
        if ((PCI_VENDOR(pa->pa_id) == PCI_VENDOR_AMD &&
            PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_AMD_HUDSON2_SMB) ||
+           (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_AMD &&
+           PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_AMD_KERNCZ_SMB) ||
            (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_ATI &&
            PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ATI_SBX00_SMB &&
            PCI_REVISION(pa->pa_class) >= 0x40)) {
@@ -136,10 +150,7 @@ piixpm_attach(struct device *parent, str
                 * hidden.  We need to look at the "SMBus0En" Power
                 * Management register to find out where they live.
                 * We use indirect IO access through the index/data
-                * pair at 0xcd6/0xcd7 to access "SMBus0En".  Since
-                * the index/data pair may be needed by other drivers,
-                * we only map them for the duration that we actually
-                * need them.
+                * pair at 0xcd6/0xcd7 to access "SMBus0En".
                 */
                if (bus_space_map(sc->sc_iot, SB800_PMREG_BASE,
                    SB800_PMREG_SIZE, 0, &ioh) != 0) {
@@ -147,29 +158,61 @@ piixpm_attach(struct device *parent, str
                        return;
                }
 
-               /* Read "SmBus0En" */
-               bus_space_write_1(sc->sc_iot, ioh, 0, SB800_PMREG_SMB0EN);
-               smb0en = bus_space_read_1(sc->sc_iot, ioh, 1);
-               bus_space_write_1(sc->sc_iot, ioh, 0, SB800_PMREG_SMB0EN + 1);
-               smb0en |= (bus_space_read_1(sc->sc_iot, ioh, 1) << 8);
-
-               bus_space_unmap(sc->sc_iot, ioh, SB800_PMREG_SIZE);
+               if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_AMD &&
+                   (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_AMD_HUDSON2_SMB ||
+                   PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_AMD_KERNCZ_SMB)) {
+                       bus_space_write_1(sc->sc_iot, ioh, 0,
+                           AMDFCH41_PM_DECODE_EN);
+                       val = bus_space_read_1(sc->sc_iot, ioh, 1);
+                       smb0en = val & AMDFCH41_SMBUS_EN;
+
+                       bus_space_write_1(sc->sc_iot, ioh, 0,
+                           AMDFCH41_PM_DECODE_EN + 1);
+                       val = bus_space_read_1(sc->sc_iot, ioh, 1) << 8;
+                       base = val;
+               } else {
+                       /* Read "SmBus0En" */
+                       bus_space_write_1(sc->sc_iot, ioh, 0,
+                           SB800_PMREG_SMB0EN);
+                       val = bus_space_read_1(sc->sc_iot, ioh, 1);
+
+                       bus_space_write_1(sc->sc_iot, ioh, 0,
+                           SB800_PMREG_SMB0EN + 1);
+                       val |= (bus_space_read_1(sc->sc_iot, ioh, 1) << 8);
+                       smb0en = val & SB800_SMB0EN_EN;
+                       base = val & SB800_SMB0EN_BASE_MASK;
+               }
 
-               if ((smb0en & SB800_SMB0EN_EN) == 0) {
+               if (smb0en == 0) {
                        printf(": SMBus disabled\n");
+                       bus_space_unmap(sc->sc_iot, ioh, SB800_PMREG_SIZE);
                        return;
                }
 
+               sc->sc_sb800_ioh = ioh;
+               if ((PCI_VENDOR(pa->pa_id) == PCI_VENDOR_AMD &&
+                   PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_AMD_KERNCZ_SMB) ||
+                   (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_AMD &&
+                   PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_AMD_HUDSON2_SMB &&
+                   PCI_REVISION(pa->pa_class) >= 0x1F)) {
+                       sc->sc_is_kerncz = 1;
+                       numbusses = 2;
+               } else {
+                       sc->sc_is_sb800 = 1;
+                       numbusses = 4;
+               }
+
                /* Map I/O space */
-               base = smb0en & SB800_SMB0EN_BASE_MASK;
                if (base == 0 || bus_space_map(sc->sc_iot, base,
                    SB800_SMB_SIZE, 0, &sc->sc_ioh)) {
                        printf(": can't map i/o space");
+                       bus_space_unmap(sc->sc_iot, ioh, SB800_PMREG_SIZE);
                        return;
                }
 
                /* Read configuration */
-               conf = bus_space_read_1(sc->sc_iot, sc->sc_ioh, 
SB800_SMB_HOSTC);
+               conf = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
+                   SB800_SMB_HOSTC);
                if (conf & SB800_SMB_HOSTC_SMI)
                        conf = PIIX_SMB_HOSTC_SMI;
                else
@@ -220,15 +263,19 @@ piixpm_attach(struct device *parent, str
 
        /* Attach I2C bus */
        rw_init(&sc->sc_i2c_lock, "iiclk");
-       sc->sc_i2c_tag.ic_cookie = sc;
-       sc->sc_i2c_tag.ic_acquire_bus = piixpm_i2c_acquire_bus;
-       sc->sc_i2c_tag.ic_release_bus = piixpm_i2c_release_bus;
-       sc->sc_i2c_tag.ic_exec = piixpm_i2c_exec;
-
-       bzero(&iba, sizeof(iba));
-       iba.iba_name = "iic";
-       iba.iba_tag = &sc->sc_i2c_tag;
-       config_found(self, &iba, iicbus_print);
+       for (i = 0; i < numbusses; i++) {
+               sc->sc_busses[i].sb_bus = i;
+               sc->sc_busses[i].sb_sc = sc;
+               sc->sc_i2c_tag[i].ic_cookie = &sc->sc_busses[i];
+               sc->sc_i2c_tag[i].ic_acquire_bus = piixpm_i2c_acquire_bus;
+               sc->sc_i2c_tag[i].ic_release_bus = piixpm_i2c_release_bus;
+               sc->sc_i2c_tag[i].ic_exec = piixpm_i2c_exec;
+
+               bzero(&iba, sizeof(iba));
+               iba.iba_name = "iic";
+               iba.iba_tag = &sc->sc_i2c_tag[i];
+               config_found(self, &iba, iicbus_print);
+       }
 
        return;
 }
@@ -236,18 +283,45 @@ piixpm_attach(struct device *parent, str
 int
 piixpm_i2c_acquire_bus(void *cookie, int flags)
 {
-       struct piixpm_softc *sc = cookie;
-
-       if (cold || sc->sc_poll || (flags & I2C_F_POLL))
-               return (0);
+       struct piixpm_smbus *smbus = cookie;
+       struct piixpm_softc *sc = smbus->sb_sc;
+       int rc = 0;
+
+       if (!cold && !sc->sc_poll && !(flags & I2C_F_POLL))
+               rc = rw_enter(&sc->sc_i2c_lock, RW_WRITE | RW_INTR);
+
+       if (sc->sc_is_kerncz) {
+               bus_space_write_1(sc->sc_iot, sc->sc_sb800_ioh, 0,
+                   AMDFCH41_PM_PORT_INDEX);
+               bus_space_write_1(sc->sc_iot, sc->sc_sb800_ioh, 1,
+                   smbus->sb_bus << 3);
+       } else if (sc->sc_is_sb800) {
+               bus_space_write_1(sc->sc_iot, sc->sc_sb800_ioh, 0,
+                   SB800_PMREG_SMB0SEL);
+               bus_space_write_1(sc->sc_iot, sc->sc_sb800_ioh, 1,
+                   smbus->sb_bus << 1);
+       }
 
-       return (rw_enter(&sc->sc_i2c_lock, RW_WRITE | RW_INTR));
+       return (rc);
 }
 
 void
 piixpm_i2c_release_bus(void *cookie, int flags)
 {
-       struct piixpm_softc *sc = cookie;
+       struct piixpm_smbus *smbus = cookie;
+       struct piixpm_softc *sc = smbus->sb_sc;
+
+       if (sc->sc_is_kerncz) {
+               bus_space_write_1(sc->sc_iot, sc->sc_sb800_ioh, 0,
+                   AMDFCH41_PM_PORT_INDEX);
+               bus_space_write_1(sc->sc_iot, sc->sc_sb800_ioh, 1,
+                   0);
+       } else if (sc->sc_is_sb800) {
+               bus_space_write_1(sc->sc_iot, sc->sc_sb800_ioh, 0,
+                   SB800_PMREG_SMB0SEL);
+               bus_space_write_1(sc->sc_iot, sc->sc_sb800_ioh, 1,
+                   0);
+       }
 
        if (cold || sc->sc_poll || (flags & I2C_F_POLL))
                return;
@@ -259,7 +333,8 @@ int
 piixpm_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr,
     const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
 {
-       struct piixpm_softc *sc = cookie;
+       struct piixpm_smbus *smbus = cookie;
+       struct piixpm_softc *sc = smbus->sb_sc;
        u_int8_t *b;
        u_int8_t ctl, st;
        int retries;
Index: piixreg.h
===================================================================
RCS file: /cvs/src/sys/dev/pci/piixreg.h,v
retrieving revision 1.4
diff -u -p -r1.4 piixreg.h
--- piixreg.h   28 May 2011 14:56:32 -0000      1.4
+++ piixreg.h   16 Dec 2019 10:49:28 -0000
@@ -69,6 +69,7 @@
 #define SB800_PMREG_BASE       0xcd6
 #define SB800_PMREG_SIZE       2       /* index/data pair */
 #define SB800_PMREG_SMB0EN     0x2c    /* 16-bit register */
+#define SB800_PMREG_SMB0SEL    0x2e    /* bus selection */
 #define SB800_SMB0EN_EN                0x0001
 #define SB800_SMB0EN_BASE_MASK 0xffe0
 
@@ -76,5 +77,13 @@
 #define SB800_SMB_HOSTC_SMI    (1 << 0)        /* SMI */
 
 #define SB800_SMB_SIZE 0x14            /* SMBus I/O space size */
+
+/*
+ * Newer FCH registers in the PMIO space.
+ * See BKDG for Family 16h Models 30h-3Fh 3.26.13 PMx00 and PMx04.
+ */
+#define        AMDFCH41_PM_DECODE_EN   0x00    /* 16-bit register */
+#define        AMDFCH41_PM_PORT_INDEX  0x02
+#define        AMDFCH41_SMBUS_EN       0x10
 
 #endif /* !_DEV_PCI_PIIXREG_H_ */

Reply via email to