On Mon, Dec 16, 2019 at 08:02:55PM +0100, Mark Kettenis wrote:
> > Date: Mon, 16 Dec 2019 12:37:51 +0100
> > From: Claudio Jeker <cje...@diehard.n-r-g.com>
> > 
> > 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
> 
> Looks good to me.  A few nits below.  Otherwise ok kettenis@
> 
> > 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;
> 
> Can this be called sc_is_hudson2 or maybe sc_is_fch instead?  It makes
> more sense to have this variable describe the oldest variant instead
> of the newest.  I actually think sc_is_fch is the best name.

Changed it to sc_is_fch.
 
> >  
> > -   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".
> >              */
> 
> I don't remember why we chose to immediately unmap the registers here.
> So this may cause some breakage.  Probably worth the risk.

If someone wants to write a watchdog driver then something would be needed
to allow both drivers access to this io range. Nothing else is using the
piixreg.h file so I doubt this is a big issue. If we hit it than we can
refactor the drivers.

> >             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)) {
> 
> Can you use a lower-case hex constant here?

Sure

> > +                   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
> 
> Might want to use a space instead of a tab here.
> 
> >  #endif     /* !_DEV_PCI_PIIXREG_H_ */
> > 
> > 
> 

Updated version appended.

-- 
: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 20:04:10 -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_fch;
 
-       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_fch = 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,22 +283,49 @@ 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;
+
+       if (!cold && !sc->sc_poll && !(flags & I2C_F_POLL))
+               if ((rc = rw_enter(&sc->sc_i2c_lock, RW_WRITE | RW_INTR)) != 0)
+                       return (rc);
+
+       if (sc->sc_is_fch) {
+               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 (0);
 }
 
 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_fch) {
+               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;
-
        rw_exit(&sc->sc_i2c_lock);
 }
 
@@ -259,12 +333,13 @@ 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;
 
-       DPRINTF(("%s: exec: op %d, addr 0x%02x, cmdlen %d, len %d, "
+       DPRINTF(("%s: exec: op %d, addr 0x%02x, cmdlen %zu, len %zu, "
            "flags 0x%02x\n", sc->sc_dev.dv_xname, op, addr, cmdlen,
            len, flags));
 
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 20:04:33 -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