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.
> > 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_ */