On Mon, Dec 16, 2019 at 09:05:47PM +0100, Claudio Jeker wrote:
> 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 <[email protected]>
> > >
> > > 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.
Yes, I did this because I wasn't sure if some other driver might end
up needing to access those registers. The 0xcd6/0xcd7 pair were only
used to find the SMBus address, as the PCI device had no BARs.
I'm ok with this (and the rest).
> > > 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_ */
>
>