diff mbox series

[v2] i3c: master: svc: adjust SDR according to i3c spec

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

Commit Message

Carlos Song July 18, 2024, 9:13 a.m. UTC
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>
---
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.
---
 drivers/i3c/master/svc-i3c-master.c | 31 ++++++++++++++++++++---------
 1 file changed, 22 insertions(+), 9 deletions(-)

Comments

Frank Li July 18, 2024, 1:58 p.m. UTC | #1
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
>
Carlos Song July 19, 2024, 2:01 a.m. UTC | #2
> -----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 mbox series

Patch

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: