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

From: Frank Li
Date: Thu Jul 18 2024 - 09:59:14 EST


Please add imx@xxxxxxxxxxxxxxx next time.

On Thu, Jul 18, 2024 at 05:13:28PM +0800, carlos.song@xxxxxxx wrote:
> From: Carlos Song <carlos.song@xxxxxxx>
>
> 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@xxxxxxx>
> Signed-off-by: Carlos Song <carlos.song@xxxxxxx>
> Reviewed-by: Frank Li <frank.li@xxxxxxx>

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@xxxxxxxxxxx>
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
>