diff mbox series

i3c: master: svc: adjust the first broadcast speed

Message ID 20240718091329.3788619-2-carlos.song@nxp.com (mailing list archive)
State Superseded
Headers show
Series i3c: master: svc: adjust the first broadcast speed | expand

Commit Message

Carlos Song July 18, 2024, 9:13 a.m. UTC
From: Carlos Song <carlos.song@nxp.com>

According to the i3c spec 6.2 Timing Specification, the first
broadcast open drain timing should be adjust to High Period
of SCL Clock is 200ns at least. I3C device working as a i2c
device will see the broadcast to close its Spike Filter to
change to i3c mode. After that I3C open drain SCL high level
should be adjust to 32ns~45ns.

Signed-off-by: Carlos Song <carlos.song@nxp.com>
---
 drivers/i3c/master/svc-i3c-master.c | 47 +++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)

Comments

Frank Li July 18, 2024, 2:08 p.m. UTC | #1
On Thu, Jul 18, 2024 at 05:13:29PM +0800, carlos.song@nxp.com wrote:
> From: Carlos Song <carlos.song@nxp.com>
> 
> According to the i3c spec 6.2 Timing Specification, the first
> broadcast open drain timing should be adjust to High Period
> of SCL Clock is 200ns at least. I3C device working as a i2c
> device will see the broadcast to close its Spike Filter to
> change to i3c mode. After that I3C open drain SCL high level
> should be adjust to 32ns~45ns.
> 
> Signed-off-by: Carlos Song <carlos.song@nxp.com>


If you sent two patch together, it should use "git format -n2", need
1/2, 2/2 in subject.

If create patch seperately, send patch one by one to avoid combine into
one email thread.

> ---
>  drivers/i3c/master/svc-i3c-master.c | 47 +++++++++++++++++++++++++++++
>  1 file changed, 47 insertions(+)
> 
> diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c
> index 78116530f431..2d68c8d34089 100644
> --- a/drivers/i3c/master/svc-i3c-master.c
> +++ b/drivers/i3c/master/svc-i3c-master.c
> @@ -142,6 +142,7 @@ struct svc_i3c_cmd {
>  	unsigned int actual_len;
>  	struct i3c_priv_xfer *xfer;
>  	bool continued;
> +	bool slow_address;
>  };
>  
>  struct svc_i3c_xfer {
> @@ -214,6 +215,10 @@ struct svc_i3c_master {
>  	} ibi;
>  	struct mutex lock;
>  	int enabled_events;
> +
> +	unsigned long fclk_rate;
> +	u32 mctrl_config;
> +	bool first_broadcast;

	slow_speed may be better?
>  };
>  
>  /**
> @@ -531,6 +536,36 @@ static irqreturn_t svc_i3c_master_irq_handler(int irq, void *dev_id)
>  	return IRQ_HANDLED;
>  }
>  
> +static void svc_i3c_master_set_slow_address_speed(struct svc_i3c_master *master)
> +{
> +	struct i3c_bus *bus = i3c_master_get_bus(&master->base);
> +	u32 ppbaud, odbaud, odhpp, mconfig;
> +
> +	master->mctrl_config = readl(master->regs + SVC_I3C_MCONFIG);
> +	mconfig = master->mctrl_config;
> +
> +	/*
> +	 * Set the I3C OPEN-DRAIN mode to the FM speed of 50% duty-cycle(400K/2500ns),
> +	 * so that the first broadcast is visible to all devices on the i3c bus.
> +	 * I3C device with 50ns filter will turn off the filter.
> +	 */
> +
> +	ppbaud = FIELD_GET(GENMASK(11, 8), mconfig);
> +	odhpp = 0;
> +	odbaud = DIV_ROUND_UP(master->fclk_rate, bus->scl_rate.i2c * (2 + 2 * ppbaud)) - 1;
> +	mconfig &= ~GENMASK(24, 16);
> +	mconfig |= SVC_I3C_MCONFIG_ODBAUD(odbaud) | SVC_I3C_MCONFIG_ODHPP(odhpp);
> +
> +	writel(mconfig, master->regs + SVC_I3C_MCONFIG);

	master->slow_speed = true;
> +}
> +
> +static void svc_i3c_master_set_default_speed(struct svc_i3c_master *master)
> +{
	if (master->slow_speed)
		writel()
		master->slow_speed = false
	}
	
to avoid set default speed every time.

> +	/* Whatever, setting the controller to initial configuration */
> +	writel(master->mctrl_config, master->regs + SVC_I3C_MCONFIG);
> +	master->first_broadcast = false;
> +}
> +
>  static int svc_i3c_master_bus_init(struct i3c_master_controller *m)
>  {
>  	struct svc_i3c_master *master = to_svc_i3c_master(m);
> @@ -624,6 +659,8 @@ static int svc_i3c_master_bus_init(struct i3c_master_controller *m)
>  	      SVC_I3C_MCONFIG_I2CBAUD(i2cbaud);
>  	writel(reg, master->regs + SVC_I3C_MCONFIG);
>  
> +	master->first_broadcast = true;
> +	master->fclk_rate = fclk_rate;
>  	/* Master core's registration */
>  	ret = i3c_master_get_free_addr(m, 0);
>  	if (ret < 0)
> @@ -1250,6 +1287,8 @@ static void svc_i3c_master_start_xfer_locked(struct svc_i3c_master *master)
>  
>  	for (i = 0; i < xfer->ncmds; i++) {
>  		struct svc_i3c_cmd *cmd = &xfer->cmds[i];
> +		if (cmd->slow_address)
> +			svc_i3c_master_set_slow_address_speed(master);


		if (cmd->slow_address)
			svc_i3c_master_set_slow_address_speed(master);
		else
			svc_i3c_master_set_default_speed(master);

will be easy understand

>  
>  		ret = svc_i3c_master_xfer(master, cmd->rnw, xfer->type,
>  					  cmd->addr, cmd->in, cmd->out,
> @@ -1259,6 +1298,9 @@ static void svc_i3c_master_start_xfer_locked(struct svc_i3c_master *master)
>  		if (cmd->xfer)
>  			cmd->xfer->actual_len = cmd->actual_len;
>  
> +		if (cmd->slow_address)
> +			svc_i3c_master_set_default_speed(master);
> +
>  		if (ret)
>  			break;
>  	}
> @@ -1346,6 +1388,11 @@ static int svc_i3c_master_send_bdcast_ccc_cmd(struct svc_i3c_master *master,
>  	cmd->actual_len = 0;
>  	cmd->continued = false;
>  
> +	if (master->first_broadcast)
> +		cmd->slow_address = true;
> +	else
> +		cmd->slow_address = false;
> +
>  	mutex_lock(&master->lock);
>  	svc_i3c_master_enqueue_xfer(master, xfer);
>  	if (!wait_for_completion_timeout(&xfer->comp, msecs_to_jiffies(1000)))
> -- 
> 2.34.1
>
Carlos Song July 19, 2024, 2:11 a.m. UTC | #2
> -----Original Message-----
> From: Frank Li <frank.li@nxp.com>
> Sent: Thursday, July 18, 2024 10:08 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] i3c: master: svc: adjust the first broadcast speed
> 
> On Thu, Jul 18, 2024 at 05:13:29PM +0800, carlos.song@nxp.com wrote:
> > From: Carlos Song <carlos.song@nxp.com>
> >
> > According to the i3c spec 6.2 Timing Specification, the first
> > broadcast open drain timing should be adjust to High Period of SCL
> > Clock is 200ns at least. I3C device working as a i2c device will see
> > the broadcast to close its Spike Filter to change to i3c mode. After
> > that I3C open drain SCL high level should be adjust to 32ns~45ns.
> >
> > Signed-off-by: Carlos Song <carlos.song@nxp.com>
> 
> 
> If you sent two patch together, it should use "git format -n2", need 1/2, 2/2 in
> subject.
> 
> If create patch seperately, send patch one by one to avoid combine into one email
> thread.
> 

Sorry, I will keep the steps in the future.
> > ---
> >  drivers/i3c/master/svc-i3c-master.c | 47
> > +++++++++++++++++++++++++++++
> >  1 file changed, 47 insertions(+)
> >
> > diff --git a/drivers/i3c/master/svc-i3c-master.c
> > b/drivers/i3c/master/svc-i3c-master.c
> > index 78116530f431..2d68c8d34089 100644
> > --- a/drivers/i3c/master/svc-i3c-master.c
> > +++ b/drivers/i3c/master/svc-i3c-master.c
> > @@ -142,6 +142,7 @@ struct svc_i3c_cmd {
> >  	unsigned int actual_len;
> >  	struct i3c_priv_xfer *xfer;
> >  	bool continued;
> > +	bool slow_address;
> >  };
> >
> >  struct svc_i3c_xfer {
> > @@ -214,6 +215,10 @@ struct svc_i3c_master {
> >  	} ibi;
> >  	struct mutex lock;
> >  	int enabled_events;
> > +
> > +	unsigned long fclk_rate;
> > +	u32 mctrl_config;
> > +	bool first_broadcast;
> 
> 	slow_speed may be better?

I agree about it.
> >  };
> >
> >  /**
> > @@ -531,6 +536,36 @@ static irqreturn_t svc_i3c_master_irq_handler(int irq,
> void *dev_id)
> >  	return IRQ_HANDLED;
> >  }
> >
> > +static void svc_i3c_master_set_slow_address_speed(struct
> > +svc_i3c_master *master) {
> > +	struct i3c_bus *bus = i3c_master_get_bus(&master->base);
> > +	u32 ppbaud, odbaud, odhpp, mconfig;
> > +
> > +	master->mctrl_config = readl(master->regs + SVC_I3C_MCONFIG);
> > +	mconfig = master->mctrl_config;
> > +
> > +	/*
> > +	 * Set the I3C OPEN-DRAIN mode to the FM speed of 50%
> duty-cycle(400K/2500ns),
> > +	 * so that the first broadcast is visible to all devices on the i3c bus.
> > +	 * I3C device with 50ns filter will turn off the filter.
> > +	 */
> > +
> > +	ppbaud = FIELD_GET(GENMASK(11, 8), mconfig);
> > +	odhpp = 0;
> > +	odbaud = DIV_ROUND_UP(master->fclk_rate, bus->scl_rate.i2c * (2 + 2 *
> ppbaud)) - 1;
> > +	mconfig &= ~GENMASK(24, 16);
> > +	mconfig |= SVC_I3C_MCONFIG_ODBAUD(odbaud) |
> > +SVC_I3C_MCONFIG_ODHPP(odhpp);
> > +
> > +	writel(mconfig, master->regs + SVC_I3C_MCONFIG);
> 
> 	master->slow_speed = true;
> > +}
> > +
> > +static void svc_i3c_master_set_default_speed(struct svc_i3c_master
> > +*master) {
> 	if (master->slow_speed)
> 		writel()
> 		master->slow_speed = false
> 	}
> 
> to avoid set default speed every time.
> 
Will do it
> > +	/* Whatever, setting the controller to initial configuration */
> > +	writel(master->mctrl_config, master->regs + SVC_I3C_MCONFIG);
> > +	master->first_broadcast = false;
> > +}
> > +
> >  static int svc_i3c_master_bus_init(struct i3c_master_controller *m)
> > {
> >  	struct svc_i3c_master *master = to_svc_i3c_master(m); @@ -624,6
> > +659,8 @@ static int svc_i3c_master_bus_init(struct i3c_master_controller *m)
> >  	      SVC_I3C_MCONFIG_I2CBAUD(i2cbaud);
> >  	writel(reg, master->regs + SVC_I3C_MCONFIG);
> >
> > +	master->first_broadcast = true;
> > +	master->fclk_rate = fclk_rate;
> >  	/* Master core's registration */
> >  	ret = i3c_master_get_free_addr(m, 0);
> >  	if (ret < 0)
> > @@ -1250,6 +1287,8 @@ static void
> > svc_i3c_master_start_xfer_locked(struct svc_i3c_master *master)
> >
> >  	for (i = 0; i < xfer->ncmds; i++) {
> >  		struct svc_i3c_cmd *cmd = &xfer->cmds[i];
> > +		if (cmd->slow_address)
> > +			svc_i3c_master_set_slow_address_speed(master);
> 
> 
> 		if (cmd->slow_address)
> 			svc_i3c_master_set_slow_address_speed(master);
> 		else
> 			svc_i3c_master_set_default_speed(master);
> 
> will be easy understand
> 

I will try to do it and will send V2
> >
> >  		ret = svc_i3c_master_xfer(master, cmd->rnw, xfer->type,
> >  					  cmd->addr, cmd->in, cmd->out,
> > @@ -1259,6 +1298,9 @@ static void svc_i3c_master_start_xfer_locked(struct
> svc_i3c_master *master)
> >  		if (cmd->xfer)
> >  			cmd->xfer->actual_len = cmd->actual_len;
> >
> > +		if (cmd->slow_address)
> > +			svc_i3c_master_set_default_speed(master);
> > +
> >  		if (ret)
> >  			break;
> >  	}
> > @@ -1346,6 +1388,11 @@ static int
> svc_i3c_master_send_bdcast_ccc_cmd(struct svc_i3c_master *master,
> >  	cmd->actual_len = 0;
> >  	cmd->continued = false;
> >
> > +	if (master->first_broadcast)
> > +		cmd->slow_address = true;
> > +	else
> > +		cmd->slow_address = false;
> > +
> >  	mutex_lock(&master->lock);
> >  	svc_i3c_master_enqueue_xfer(master, xfer);
> >  	if (!wait_for_completion_timeout(&xfer->comp,
> > msecs_to_jiffies(1000)))
> > --
> > 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 78116530f431..2d68c8d34089 100644
--- a/drivers/i3c/master/svc-i3c-master.c
+++ b/drivers/i3c/master/svc-i3c-master.c
@@ -142,6 +142,7 @@  struct svc_i3c_cmd {
 	unsigned int actual_len;
 	struct i3c_priv_xfer *xfer;
 	bool continued;
+	bool slow_address;
 };
 
 struct svc_i3c_xfer {
@@ -214,6 +215,10 @@  struct svc_i3c_master {
 	} ibi;
 	struct mutex lock;
 	int enabled_events;
+
+	unsigned long fclk_rate;
+	u32 mctrl_config;
+	bool first_broadcast;
 };
 
 /**
@@ -531,6 +536,36 @@  static irqreturn_t svc_i3c_master_irq_handler(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
+static void svc_i3c_master_set_slow_address_speed(struct svc_i3c_master *master)
+{
+	struct i3c_bus *bus = i3c_master_get_bus(&master->base);
+	u32 ppbaud, odbaud, odhpp, mconfig;
+
+	master->mctrl_config = readl(master->regs + SVC_I3C_MCONFIG);
+	mconfig = master->mctrl_config;
+
+	/*
+	 * Set the I3C OPEN-DRAIN mode to the FM speed of 50% duty-cycle(400K/2500ns),
+	 * so that the first broadcast is visible to all devices on the i3c bus.
+	 * I3C device with 50ns filter will turn off the filter.
+	 */
+
+	ppbaud = FIELD_GET(GENMASK(11, 8), mconfig);
+	odhpp = 0;
+	odbaud = DIV_ROUND_UP(master->fclk_rate, bus->scl_rate.i2c * (2 + 2 * ppbaud)) - 1;
+	mconfig &= ~GENMASK(24, 16);
+	mconfig |= SVC_I3C_MCONFIG_ODBAUD(odbaud) | SVC_I3C_MCONFIG_ODHPP(odhpp);
+
+	writel(mconfig, master->regs + SVC_I3C_MCONFIG);
+}
+
+static void svc_i3c_master_set_default_speed(struct svc_i3c_master *master)
+{
+	/* Whatever, setting the controller to initial configuration */
+	writel(master->mctrl_config, master->regs + SVC_I3C_MCONFIG);
+	master->first_broadcast = false;
+}
+
 static int svc_i3c_master_bus_init(struct i3c_master_controller *m)
 {
 	struct svc_i3c_master *master = to_svc_i3c_master(m);
@@ -624,6 +659,8 @@  static int svc_i3c_master_bus_init(struct i3c_master_controller *m)
 	      SVC_I3C_MCONFIG_I2CBAUD(i2cbaud);
 	writel(reg, master->regs + SVC_I3C_MCONFIG);
 
+	master->first_broadcast = true;
+	master->fclk_rate = fclk_rate;
 	/* Master core's registration */
 	ret = i3c_master_get_free_addr(m, 0);
 	if (ret < 0)
@@ -1250,6 +1287,8 @@  static void svc_i3c_master_start_xfer_locked(struct svc_i3c_master *master)
 
 	for (i = 0; i < xfer->ncmds; i++) {
 		struct svc_i3c_cmd *cmd = &xfer->cmds[i];
+		if (cmd->slow_address)
+			svc_i3c_master_set_slow_address_speed(master);
 
 		ret = svc_i3c_master_xfer(master, cmd->rnw, xfer->type,
 					  cmd->addr, cmd->in, cmd->out,
@@ -1259,6 +1298,9 @@  static void svc_i3c_master_start_xfer_locked(struct svc_i3c_master *master)
 		if (cmd->xfer)
 			cmd->xfer->actual_len = cmd->actual_len;
 
+		if (cmd->slow_address)
+			svc_i3c_master_set_default_speed(master);
+
 		if (ret)
 			break;
 	}
@@ -1346,6 +1388,11 @@  static int svc_i3c_master_send_bdcast_ccc_cmd(struct svc_i3c_master *master,
 	cmd->actual_len = 0;
 	cmd->continued = false;
 
+	if (master->first_broadcast)
+		cmd->slow_address = true;
+	else
+		cmd->slow_address = false;
+
 	mutex_lock(&master->lock);
 	svc_i3c_master_enqueue_xfer(master, xfer);
 	if (!wait_for_completion_timeout(&xfer->comp, msecs_to_jiffies(1000)))