Message ID | 20240802130143.26908-1-ahuang12@lenovo.com |
---|---|
State | New |
Headers | show |
Series | [v2,1/1] i2c: designware: Fix wrong setting for {ss,fs,hs}_{h,l}cnt registers | expand |
On 8/2/24 4:01 PM, Adrian Huang wrote: > From: Adrian Huang <ahuang12@lenovo.com> > > When disabling CONFIG_X86_AMD_PLATFORM_DEVICE option, the driver > 'drivers/acpi/acpi_apd.c' won't be compiled. This leads to a situation > where BMC (Baseboard Management Controller) cannot retrieve the memory > temperature via the i2c interface after i2c DW driver is loaded. Note > that BMC can retrieve the memory temperature before booting into OS. > > [Debugging Detail] > 1. dev->pclk and dev->clk are NULL when calling devm_clk_get_optional() > in dw_i2c_plat_probe(). > > 2. The callings of i2c_dw_scl_hcnt() in i2c_dw_set_timings_master() > return 65528 (-8 in integer format) or 65533 (-3 in integer format). > The following log shows SS's HCNT/LCNT: > > i2c_designware AMDI0010:01: Standard Mode HCNT:LCNT = 65533:65535 > > 3. The callings of i2c_dw_scl_lcnt() in i2c_dw_set_timings_master() > return 65535 (-1 in integer format). The following log shows SS's > HCNT/LCNT: > > i2c_designware AMDI0010:01: Fast Mode HCNT:LCNT = 65533:65535 > > 4. i2c_dw_init_master() configures the register IC_SS_SCL_HCNT with > the value 65533. However, the DW i2c databook mentioned the value > cannot be higher than 65525. Quote from the DW i2c databook: > > NOTE: This register must not be programmed to a value higher than > 65525, because DW_apb_i2c uses a 16-bit counter to flag an > I2C bus idle condition when this counter reaches a value of > IC_SS_SCL_HCNT + 10. > > 5. Since ss_hcnt, ss_lcnt, fs_hcnt, and fs_lcnt are the invalid > values, we should not write the corresponding registers. > > Fix the issue by reading dev->{ss,fs,hs}_hcnt and dev->{ss,fs,hs}_lcnt > from HW registers if ic_clk is not set. > > Link: https://lore.kernel.org/linux-i2c/8295cbe1-a7c5-4a35-a189-5d0bff51ede6@linux.intel.com/ > Suggested-by: Jarkko Nikula <jarkko.nikula@linux.intel.com> > Signed-off-by: Adrian Huang <ahuang12@lenovo.com> > Reported-by: Dong Wang <wangdong28@lenovo.com> > Tested-by: Dong Wang <wangdong28@lenovo.com> > Acked-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
Hi Adrian, > Link: https://lore.kernel.org/linux-i2c/8295cbe1-a7c5-4a35-a189-5d0bff51ede6@linux.intel.com/ > Suggested-by: Jarkko Nikula <jarkko.nikula@linux.intel.com> > Signed-off-by: Adrian Huang <ahuang12@lenovo.com> > Reported-by: Dong Wang <wangdong28@lenovo.com> > Tested-by: Dong Wang <wangdong28@lenovo.com> At first I thought that we need a Fixes tag, but on a second thought I judged this more as a behavioural fix. Please, let me konw if you think we want to have the Fixes tag here. Meantime, I'm going to re-arrange the tag section. It's common to sort the tags in a chronological order: Reported-by: (it first gets reported) Suggested-by: (then someone suggested the fix) Signed-off-by: (then someone implemented the fix) Tested-by: (finally someone tested it) Link: (as reference) I will also appreciate that the Reviewed-by and Tested-by and Acked-by happen transparently and openly in the mailing list rather behind the curtains. Said that, thanks for your patch, I merged it into i2c/i2c-host. Andi
Hi Andi, On Tue, Aug 6, 2024 at 1:27 AM Andi Shyti <andi.shyti@kernel.org> wrote: > > Hi Adrian, > > > Link: https://lore.kernel.org/linux-i2c/8295cbe1-a7c5-4a35-a189-5d0bff51ede6@linux.intel.com/ > > Suggested-by: Jarkko Nikula <jarkko.nikula@linux.intel.com> > > Signed-off-by: Adrian Huang <ahuang12@lenovo.com> > > Reported-by: Dong Wang <wangdong28@lenovo.com> > > Tested-by: Dong Wang <wangdong28@lenovo.com> > > At first I thought that we need a Fixes tag, but on a second > thought I judged this more as a behavioural fix. Please, let me > konw if you think we want to have the Fixes tag here. Agree with your second thought, so no need to add the Fixes tag. > Meantime, I'm going to re-arrange the tag section. It's common to > sort the tags in a chronological order: > > Reported-by: (it first gets reported) > Suggested-by: (then someone suggested the fix) > Signed-off-by: (then someone implemented the fix) > Tested-by: (finally someone tested it) > Link: (as reference) > > I will also appreciate that the Reviewed-by and Tested-by and > Acked-by happen transparently and openly in the mailing list > rather behind the curtains. I'm sorry for the inconvenience. Wil pay more attention in the future. > Said that, thanks for your patch, I merged it into i2c/i2c-host. Thank you. -- Adrian
On Mon, Aug 05, 2024 at 07:26:55PM +0200, Andi Shyti wrote: > Hi Adrian, > > > Link: https://lore.kernel.org/linux-i2c/8295cbe1-a7c5-4a35-a189-5d0bff51ede6@linux.intel.com/ > > Suggested-by: Jarkko Nikula <jarkko.nikula@linux.intel.com> > > Signed-off-by: Adrian Huang <ahuang12@lenovo.com> > > Reported-by: Dong Wang <wangdong28@lenovo.com> > > Tested-by: Dong Wang <wangdong28@lenovo.com> > > At first I thought that we need a Fixes tag, but on a second > thought I judged this more as a behavioural fix. Please, let me > konw if you think we want to have the Fixes tag here. > > Meantime, I'm going to re-arrange the tag section. It's common to > sort the tags in a chronological order: > > Reported-by: (it first gets reported) > Suggested-by: (then someone suggested the fix) > Signed-off-by: (then someone implemented the fix) > Tested-by: (finally someone tested it) > Link: (as reference) If you use `b4`, you may configure it to do this automatically and keep nice with contributors :-)
diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c index e8a688d04aee..4160c5e57df4 100644 --- a/drivers/i2c/busses/i2c-designware-common.c +++ b/drivers/i2c/busses/i2c-designware-common.c @@ -332,8 +332,27 @@ void i2c_dw_adjust_bus_speed(struct dw_i2c_dev *dev) } EXPORT_SYMBOL_GPL(i2c_dw_adjust_bus_speed); -u32 i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset) +static u32 i2c_dw_read_scl_reg(struct dw_i2c_dev *dev, u32 reg) { + u32 val; + int ret; + + ret = i2c_dw_acquire_lock(dev); + if (ret) + return 0; + + ret = regmap_read(dev->map, reg, &val); + i2c_dw_release_lock(dev); + + return ret ? 0 : val; +} + +u32 i2c_dw_scl_hcnt(struct dw_i2c_dev *dev, unsigned int reg, u32 ic_clk, + u32 tSYMBOL, u32 tf, int cond, int offset) +{ + if (!ic_clk) + return i2c_dw_read_scl_reg(dev, reg); + /* * DesignWare I2C core doesn't seem to have solid strategy to meet * the tHD;STA timing spec. Configuring _HCNT based on tHIGH spec @@ -372,8 +391,12 @@ u32 i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset) 3 + offset; } -u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset) +u32 i2c_dw_scl_lcnt(struct dw_i2c_dev *dev, unsigned int reg, u32 ic_clk, + u32 tLOW, u32 tf, int offset) { + if (!ic_clk) + return i2c_dw_read_scl_reg(dev, reg); + /* * Conditional expression: * diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index e9606c00b8d1..3e48f446ce53 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -329,8 +329,10 @@ struct i2c_dw_semaphore_callbacks { }; int i2c_dw_init_regmap(struct dw_i2c_dev *dev); -u32 i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset); -u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset); +u32 i2c_dw_scl_hcnt(struct dw_i2c_dev *dev, unsigned int reg, u32 ic_clk, + u32 tSYMBOL, u32 tf, int cond, int offset); +u32 i2c_dw_scl_lcnt(struct dw_i2c_dev *dev, unsigned int reg, u32 ic_clk, + u32 tLOW, u32 tf, int offset); int i2c_dw_set_sda_hold(struct dw_i2c_dev *dev); u32 i2c_dw_clk_rate(struct dw_i2c_dev *dev); int i2c_dw_prepare_clk(struct dw_i2c_dev *dev, bool prepare); diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c index c7e56002809a..d3b466592be4 100644 --- a/drivers/i2c/busses/i2c-designware-master.c +++ b/drivers/i2c/busses/i2c-designware-master.c @@ -64,13 +64,17 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev) if (!dev->ss_hcnt || !dev->ss_lcnt) { ic_clk = i2c_dw_clk_rate(dev); dev->ss_hcnt = - i2c_dw_scl_hcnt(ic_clk, + i2c_dw_scl_hcnt(dev, + DW_IC_SS_SCL_HCNT, + ic_clk, 4000, /* tHD;STA = tHIGH = 4.0 us */ sda_falling_time, 0, /* 0: DW default, 1: Ideal */ 0); /* No offset */ dev->ss_lcnt = - i2c_dw_scl_lcnt(ic_clk, + i2c_dw_scl_lcnt(dev, + DW_IC_SS_SCL_LCNT, + ic_clk, 4700, /* tLOW = 4.7 us */ scl_falling_time, 0); /* No offset */ @@ -94,13 +98,17 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev) } else { ic_clk = i2c_dw_clk_rate(dev); dev->fs_hcnt = - i2c_dw_scl_hcnt(ic_clk, + i2c_dw_scl_hcnt(dev, + DW_IC_FS_SCL_HCNT, + ic_clk, 260, /* tHIGH = 260 ns */ sda_falling_time, 0, /* DW default */ 0); /* No offset */ dev->fs_lcnt = - i2c_dw_scl_lcnt(ic_clk, + i2c_dw_scl_lcnt(dev, + DW_IC_FS_SCL_LCNT, + ic_clk, 500, /* tLOW = 500 ns */ scl_falling_time, 0); /* No offset */ @@ -114,13 +122,17 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev) if (!dev->fs_hcnt || !dev->fs_lcnt) { ic_clk = i2c_dw_clk_rate(dev); dev->fs_hcnt = - i2c_dw_scl_hcnt(ic_clk, + i2c_dw_scl_hcnt(dev, + DW_IC_FS_SCL_HCNT, + ic_clk, 600, /* tHD;STA = tHIGH = 0.6 us */ sda_falling_time, 0, /* 0: DW default, 1: Ideal */ 0); /* No offset */ dev->fs_lcnt = - i2c_dw_scl_lcnt(ic_clk, + i2c_dw_scl_lcnt(dev, + DW_IC_FS_SCL_LCNT, + ic_clk, 1300, /* tLOW = 1.3 us */ scl_falling_time, 0); /* No offset */ @@ -142,13 +154,17 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev) } else if (!dev->hs_hcnt || !dev->hs_lcnt) { ic_clk = i2c_dw_clk_rate(dev); dev->hs_hcnt = - i2c_dw_scl_hcnt(ic_clk, + i2c_dw_scl_hcnt(dev, + DW_IC_HS_SCL_HCNT, + ic_clk, 160, /* tHIGH = 160 ns */ sda_falling_time, 0, /* DW default */ 0); /* No offset */ dev->hs_lcnt = - i2c_dw_scl_lcnt(ic_clk, + i2c_dw_scl_lcnt(dev, + DW_IC_HS_SCL_LCNT, + ic_clk, 320, /* tLOW = 320 ns */ scl_falling_time, 0); /* No offset */