Message ID | 20240718091329.3788619-1-carlos.song@nxp.com (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | [v2] i3c: master: svc: adjust SDR according to i3c spec | expand |
Please add imx@lists.linux.dev next time. On Thu, Jul 18, 2024 at 05:13:28PM +0800, carlos.song@nxp.com wrote: > From: Carlos Song <carlos.song@nxp.com> > > According to I3C Specification(Version 1.1) 5.1.2.4 "Use of Clock > Speed to Prevent Legacy I2C Devices From Seeing I3C traffic", when > slow i2c devices(FM/FM+ rate i2c frequency without 50ns filter) > works on i3c bus, i3c SDR should work at FM/FM+ rate. > > Adjust timing for difference mode. > > Signed-off-by: Clark Wang <xiaoning.wang@nxp.com> > Signed-off-by: Carlos Song <carlos.song@nxp.com> > Reviewed-by: Frank Li <frank.li@nxp.com> V1 have my signed of, please keep it. > --- > Change for V2: > - Correct I3C clk configuration and simplify the code: > Pure I3C mode and MIXED-FAST I3C mode just use the same i3c clk configuration: > 1. i3c push-pull timing is 40ns high and 40ns low at 12.5Mhz > 2. i3c open-darin timing is 40ns high and 200ns low at ~4Mhz > 3. i2cbaud should be different between Pure I3C mode and MIXED-FAST > I3C mode. V1 get Acked-by: Miquel Raynal <miquel.raynal@bootlin.com> If you drop it because big change, you should mention at change log, said not apply Miquel's ACK tag, because below change is quite big. > --- > drivers/i3c/master/svc-i3c-master.c | 31 ++++++++++++++++++++--------- > 1 file changed, 22 insertions(+), 9 deletions(-) > > diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c > index e80c002991f7..78116530f431 100644 > --- a/drivers/i3c/master/svc-i3c-master.c > +++ b/drivers/i3c/master/svc-i3c-master.c > @@ -127,6 +127,8 @@ > > /* This parameter depends on the implementation and may be tuned */ > #define SVC_I3C_FIFO_SIZE 16 > +#define SVC_I3C_PPBAUD_MAX 15 > +#define SVC_I3C_QUICK_I2C_CLK 4170000 > > #define SVC_I3C_EVENT_IBI BIT(0) > #define SVC_I3C_EVENT_HOTJOIN BIT(1) > @@ -535,6 +537,7 @@ static int svc_i3c_master_bus_init(struct i3c_master_controller *m) > struct i3c_bus *bus = i3c_master_get_bus(m); > struct i3c_device_info info = {}; > unsigned long fclk_rate, fclk_period_ns; > + unsigned long i2c_period_ns, i2c_scl_rate, i3c_scl_rate; > unsigned int high_period_ns, od_low_period_ns; > u32 ppbaud, pplow, odhpp, odbaud, odstop, i2cbaud, reg; > int ret; > @@ -555,12 +558,15 @@ static int svc_i3c_master_bus_init(struct i3c_master_controller *m) > } > > fclk_period_ns = DIV_ROUND_UP(1000000000, fclk_rate); > + i2c_period_ns = DIV_ROUND_UP(1000000000, bus->scl_rate.i2c); > + i2c_scl_rate = bus->scl_rate.i2c; > + i3c_scl_rate = bus->scl_rate.i3c; > > /* > * Using I3C Push-Pull mode, target is 12.5MHz/80ns period. > * Simplest configuration is using a 50% duty-cycle of 40ns. > */ > - ppbaud = DIV_ROUND_UP(40, fclk_period_ns) - 1; > + ppbaud = DIV_ROUND_UP(fclk_rate / 2, i3c_scl_rate) - 1; > pplow = 0; > > /* > @@ -570,7 +576,7 @@ static int svc_i3c_master_bus_init(struct i3c_master_controller *m) > */ > odhpp = 1; > high_period_ns = (ppbaud + 1) * fclk_period_ns; > - odbaud = DIV_ROUND_UP(240 - high_period_ns, high_period_ns) - 1; > + odbaud = DIV_ROUND_UP(fclk_rate, SVC_I3C_QUICK_I2C_CLK * (1 + ppbaud)) - 2; > od_low_period_ns = (odbaud + 1) * high_period_ns; > > switch (bus->mode) { > @@ -579,20 +585,27 @@ static int svc_i3c_master_bus_init(struct i3c_master_controller *m) > odstop = 0; > break; > case I3C_BUS_MODE_MIXED_FAST: > - case I3C_BUS_MODE_MIXED_LIMITED: > /* > * Using I2C Fm+ mode, target is 1MHz/1000ns, the difference > * between the high and low period does not really matter. > */ > - i2cbaud = DIV_ROUND_UP(1000, od_low_period_ns) - 2; > + i2cbaud = DIV_ROUND_UP(i2c_period_ns, od_low_period_ns) - 2; > odstop = 1; > break; > + case I3C_BUS_MODE_MIXED_LIMITED: > case I3C_BUS_MODE_MIXED_SLOW: > - /* > - * Using I2C Fm mode, target is 0.4MHz/2500ns, with the same > - * constraints as the FM+ mode. > - */ > - i2cbaud = DIV_ROUND_UP(2500, od_low_period_ns) - 2; > + /* I3C PP + I3C OP + I2C OP both use i2c clk rate */ > + if (ppbaud > SVC_I3C_PPBAUD_MAX) { > + ppbaud = SVC_I3C_PPBAUD_MAX; > + pplow = DIV_ROUND_UP(fclk_rate, i3c_scl_rate) - (2 + 2 * ppbaud); > + } > + > + high_period_ns = (ppbaud + 1) * fclk_period_ns; > + odhpp = 0; > + odbaud = DIV_ROUND_UP(fclk_rate, i2c_scl_rate * (2 + 2 * ppbaud)) - 1; > + > + od_low_period_ns = (odbaud + 1) * high_period_ns; > + i2cbaud = DIV_ROUND_UP(i2c_period_ns, od_low_period_ns) - 2; > odstop = 1; > break; > default: > -- > 2.34.1 >
> -----Original Message----- > From: Frank Li <frank.li@nxp.com> > Sent: Thursday, July 18, 2024 9:59 PM > To: Carlos Song <carlos.song@nxp.com> > Cc: miquel.raynal@bootlin.com; conor.culhane@silvaco.com; > alexandre.belloni@bootlin.com; linux-i3c@lists.infradead.org; > linux-kernel@vger.kernel.org; dl-linux-imx <linux-imx@nxp.com> > Subject: Re: [PATCH v2] i3c: master: svc: adjust SDR according to i3c spec > > Please add imx@lists.linux.dev next time. > Thank you! I will add it at V3. > On Thu, Jul 18, 2024 at 05:13:28PM +0800, carlos.song@nxp.com wrote: > > From: Carlos Song <carlos.song@nxp.com> > > > > According to I3C Specification(Version 1.1) 5.1.2.4 "Use of Clock > > Speed to Prevent Legacy I2C Devices From Seeing I3C traffic", when > > slow i2c devices(FM/FM+ rate i2c frequency without 50ns filter) works > > on i3c bus, i3c SDR should work at FM/FM+ rate. > > > > Adjust timing for difference mode. > > > > Signed-off-by: Clark Wang <xiaoning.wang@nxp.com> > > Signed-off-by: Carlos Song <carlos.song@nxp.com> > > Reviewed-by: Frank Li <frank.li@nxp.com> > > V1 have my signed of, please keep it. > So sorry for this! I will send V3 and keep it. > > --- > > Change for V2: > > - Correct I3C clk configuration and simplify the code: > > Pure I3C mode and MIXED-FAST I3C mode just use the same i3c clk > configuration: > > 1. i3c push-pull timing is 40ns high and 40ns low at 12.5Mhz > > 2. i3c open-darin timing is 40ns high and 200ns low at ~4Mhz > > 3. i2cbaud should be different between Pure I3C mode and MIXED-FAST > > I3C mode. > > V1 get Acked-by: Miquel Raynal <miquel.raynal@bootlin.com> If you drop it > because big change, you should mention at change log, said not apply Miquel's > ACK tag, because below change is quite big. > Do some code change and fix a bug, there is no big change. I will add back it at V3. > > --- > > drivers/i3c/master/svc-i3c-master.c | 31 > > ++++++++++++++++++++--------- > > 1 file changed, 22 insertions(+), 9 deletions(-) > > > > diff --git a/drivers/i3c/master/svc-i3c-master.c > > b/drivers/i3c/master/svc-i3c-master.c > > index e80c002991f7..78116530f431 100644 > > --- a/drivers/i3c/master/svc-i3c-master.c > > +++ b/drivers/i3c/master/svc-i3c-master.c > > @@ -127,6 +127,8 @@ > > > > /* This parameter depends on the implementation and may be tuned */ > > #define SVC_I3C_FIFO_SIZE 16 > > +#define SVC_I3C_PPBAUD_MAX 15 > > +#define SVC_I3C_QUICK_I2C_CLK 4170000 > > > > #define SVC_I3C_EVENT_IBI BIT(0) > > #define SVC_I3C_EVENT_HOTJOIN BIT(1) > > @@ -535,6 +537,7 @@ static int svc_i3c_master_bus_init(struct > i3c_master_controller *m) > > struct i3c_bus *bus = i3c_master_get_bus(m); > > struct i3c_device_info info = {}; > > unsigned long fclk_rate, fclk_period_ns; > > + unsigned long i2c_period_ns, i2c_scl_rate, i3c_scl_rate; > > unsigned int high_period_ns, od_low_period_ns; > > u32 ppbaud, pplow, odhpp, odbaud, odstop, i2cbaud, reg; > > int ret; > > @@ -555,12 +558,15 @@ static int svc_i3c_master_bus_init(struct > i3c_master_controller *m) > > } > > > > fclk_period_ns = DIV_ROUND_UP(1000000000, fclk_rate); > > + i2c_period_ns = DIV_ROUND_UP(1000000000, bus->scl_rate.i2c); > > + i2c_scl_rate = bus->scl_rate.i2c; > > + i3c_scl_rate = bus->scl_rate.i3c; > > > > /* > > * Using I3C Push-Pull mode, target is 12.5MHz/80ns period. > > * Simplest configuration is using a 50% duty-cycle of 40ns. > > */ > > - ppbaud = DIV_ROUND_UP(40, fclk_period_ns) - 1; > > + ppbaud = DIV_ROUND_UP(fclk_rate / 2, i3c_scl_rate) - 1; > > pplow = 0; > > > > /* > > @@ -570,7 +576,7 @@ static int svc_i3c_master_bus_init(struct > i3c_master_controller *m) > > */ > > odhpp = 1; > > high_period_ns = (ppbaud + 1) * fclk_period_ns; > > - odbaud = DIV_ROUND_UP(240 - high_period_ns, high_period_ns) - 1; > > + odbaud = DIV_ROUND_UP(fclk_rate, SVC_I3C_QUICK_I2C_CLK * (1 + > > +ppbaud)) - 2; > > od_low_period_ns = (odbaud + 1) * high_period_ns; > > > > switch (bus->mode) { > > @@ -579,20 +585,27 @@ static int svc_i3c_master_bus_init(struct > i3c_master_controller *m) > > odstop = 0; > > break; > > case I3C_BUS_MODE_MIXED_FAST: > > - case I3C_BUS_MODE_MIXED_LIMITED: > > /* > > * Using I2C Fm+ mode, target is 1MHz/1000ns, the difference > > * between the high and low period does not really matter. > > */ > > - i2cbaud = DIV_ROUND_UP(1000, od_low_period_ns) - 2; > > + i2cbaud = DIV_ROUND_UP(i2c_period_ns, od_low_period_ns) - 2; > > odstop = 1; > > break; > > + case I3C_BUS_MODE_MIXED_LIMITED: > > case I3C_BUS_MODE_MIXED_SLOW: > > - /* > > - * Using I2C Fm mode, target is 0.4MHz/2500ns, with the same > > - * constraints as the FM+ mode. > > - */ > > - i2cbaud = DIV_ROUND_UP(2500, od_low_period_ns) - 2; > > + /* I3C PP + I3C OP + I2C OP both use i2c clk rate */ > > + if (ppbaud > SVC_I3C_PPBAUD_MAX) { > > + ppbaud = SVC_I3C_PPBAUD_MAX; > > + pplow = DIV_ROUND_UP(fclk_rate, i3c_scl_rate) - (2 + 2 * > ppbaud); > > + } > > + > > + high_period_ns = (ppbaud + 1) * fclk_period_ns; > > + odhpp = 0; > > + odbaud = DIV_ROUND_UP(fclk_rate, i2c_scl_rate * (2 + 2 * ppbaud)) - > > +1; > > + > > + od_low_period_ns = (odbaud + 1) * high_period_ns; > > + i2cbaud = DIV_ROUND_UP(i2c_period_ns, od_low_period_ns) - 2; > > odstop = 1; > > break; > > default: > > -- > > 2.34.1 > >
diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c index e80c002991f7..78116530f431 100644 --- a/drivers/i3c/master/svc-i3c-master.c +++ b/drivers/i3c/master/svc-i3c-master.c @@ -127,6 +127,8 @@ /* This parameter depends on the implementation and may be tuned */ #define SVC_I3C_FIFO_SIZE 16 +#define SVC_I3C_PPBAUD_MAX 15 +#define SVC_I3C_QUICK_I2C_CLK 4170000 #define SVC_I3C_EVENT_IBI BIT(0) #define SVC_I3C_EVENT_HOTJOIN BIT(1) @@ -535,6 +537,7 @@ static int svc_i3c_master_bus_init(struct i3c_master_controller *m) struct i3c_bus *bus = i3c_master_get_bus(m); struct i3c_device_info info = {}; unsigned long fclk_rate, fclk_period_ns; + unsigned long i2c_period_ns, i2c_scl_rate, i3c_scl_rate; unsigned int high_period_ns, od_low_period_ns; u32 ppbaud, pplow, odhpp, odbaud, odstop, i2cbaud, reg; int ret; @@ -555,12 +558,15 @@ static int svc_i3c_master_bus_init(struct i3c_master_controller *m) } fclk_period_ns = DIV_ROUND_UP(1000000000, fclk_rate); + i2c_period_ns = DIV_ROUND_UP(1000000000, bus->scl_rate.i2c); + i2c_scl_rate = bus->scl_rate.i2c; + i3c_scl_rate = bus->scl_rate.i3c; /* * Using I3C Push-Pull mode, target is 12.5MHz/80ns period. * Simplest configuration is using a 50% duty-cycle of 40ns. */ - ppbaud = DIV_ROUND_UP(40, fclk_period_ns) - 1; + ppbaud = DIV_ROUND_UP(fclk_rate / 2, i3c_scl_rate) - 1; pplow = 0; /* @@ -570,7 +576,7 @@ static int svc_i3c_master_bus_init(struct i3c_master_controller *m) */ odhpp = 1; high_period_ns = (ppbaud + 1) * fclk_period_ns; - odbaud = DIV_ROUND_UP(240 - high_period_ns, high_period_ns) - 1; + odbaud = DIV_ROUND_UP(fclk_rate, SVC_I3C_QUICK_I2C_CLK * (1 + ppbaud)) - 2; od_low_period_ns = (odbaud + 1) * high_period_ns; switch (bus->mode) { @@ -579,20 +585,27 @@ static int svc_i3c_master_bus_init(struct i3c_master_controller *m) odstop = 0; break; case I3C_BUS_MODE_MIXED_FAST: - case I3C_BUS_MODE_MIXED_LIMITED: /* * Using I2C Fm+ mode, target is 1MHz/1000ns, the difference * between the high and low period does not really matter. */ - i2cbaud = DIV_ROUND_UP(1000, od_low_period_ns) - 2; + i2cbaud = DIV_ROUND_UP(i2c_period_ns, od_low_period_ns) - 2; odstop = 1; break; + case I3C_BUS_MODE_MIXED_LIMITED: case I3C_BUS_MODE_MIXED_SLOW: - /* - * Using I2C Fm mode, target is 0.4MHz/2500ns, with the same - * constraints as the FM+ mode. - */ - i2cbaud = DIV_ROUND_UP(2500, od_low_period_ns) - 2; + /* I3C PP + I3C OP + I2C OP both use i2c clk rate */ + if (ppbaud > SVC_I3C_PPBAUD_MAX) { + ppbaud = SVC_I3C_PPBAUD_MAX; + pplow = DIV_ROUND_UP(fclk_rate, i3c_scl_rate) - (2 + 2 * ppbaud); + } + + high_period_ns = (ppbaud + 1) * fclk_period_ns; + odhpp = 0; + odbaud = DIV_ROUND_UP(fclk_rate, i2c_scl_rate * (2 + 2 * ppbaud)) - 1; + + od_low_period_ns = (odbaud + 1) * high_period_ns; + i2cbaud = DIV_ROUND_UP(i2c_period_ns, od_low_period_ns) - 2; odstop = 1; break; default: