lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <20240719080351.842848-1-carlos.song@nxp.com>
Date: Fri, 19 Jul 2024 16:03:51 +0800
From: carlos.song@....com
To: miquel.raynal@...tlin.com,
	conor.culhane@...vaco.com,
	alexandre.belloni@...tlin.com,
	frank.li@....com
Cc: linux-i3c@...ts.infradead.org,
	linux-kernel@...r.kernel.org,
	imx@...ts.linux.dev,
	linux-imx@....com
Subject: [PATCH v2] i3c: master: svc: adjust the first broadcast speed

From: Carlos Song <carlos.song@....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@....com>
---
Change for V2:
- use slow_speed instead of first_broadcast
- add default_speed variable in svc_i3c_xfer to avoid set default
  speed every time
- change start_xfer if else for easy understand
---
 drivers/i3c/master/svc-i3c-master.c | 55 +++++++++++++++++++++++++++++
 1 file changed, 55 insertions(+)

diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c
index 78116530f431..7cd3a9a4d7dd 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,11 @@ struct svc_i3c_master {
 	} ibi;
 	struct mutex lock;
 	int enabled_events;
+
+	unsigned long fclk_rate;
+	u32 mctrl_config;
+	bool slow_speed;
+	bool default_speed;
 };
 
 /**
@@ -531,6 +537,43 @@ 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 = false;
+}
+
+static void svc_i3c_master_set_default_speed(struct svc_i3c_master *master)
+{
+	/*
+	 * The bus mode is already determined when the bus is initialized, so setting initial
+	 * configuration back to the controller. No need to set it in every transfer, just
+	 * restore it once time.
+	 */
+	if (!master->default_speed) {
+		writel(master->mctrl_config, master->regs + SVC_I3C_MCONFIG);
+		master->default_speed = true;
+	}
+}
+
 static int svc_i3c_master_bus_init(struct i3c_master_controller *m)
 {
 	struct svc_i3c_master *master = to_svc_i3c_master(m);
@@ -624,6 +667,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->slow_speed = true;
+	master->fclk_rate = fclk_rate;
 	/* Master core's registration */
 	ret = i3c_master_get_free_addr(m, 0);
 	if (ret < 0)
@@ -1251,6 +1296,11 @@ 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);
+		else
+			svc_i3c_master_set_default_speed(master);
+
 		ret = svc_i3c_master_xfer(master, cmd->rnw, xfer->type,
 					  cmd->addr, cmd->in, cmd->out,
 					  cmd->len, &cmd->actual_len,
@@ -1346,6 +1396,11 @@ static int svc_i3c_master_send_bdcast_ccc_cmd(struct svc_i3c_master *master,
 	cmd->actual_len = 0;
 	cmd->continued = false;
 
+	if (master->slow_speed)
+		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


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ