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-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250702133450.64257-2-akhilrajeev@nvidia.com>
Date: Wed, 2 Jul 2025 19:04:48 +0530
From: Akhil R <akhilrajeev@...dia.com>
To: <andriy.shevchenko@...ux.intel.com>, <andi.shyti@...nel.org>,
	<digetx@...il.com>, <jonathanh@...dia.com>, <linux-i2c@...r.kernel.org>,
	<linux-kernel@...r.kernel.org>, <linux-tegra@...r.kernel.org>,
	<p.zabel@...gutronix.de>, <thierry.reding@...il.com>
CC: <akhilrajeev@...dia.com>, <conor+dt@...nel.org>,
	<devicetree@...r.kernel.org>, <krzk+dt@...nel.org>, <ldewangan@...dia.com>,
	<robh@...nel.org>
Subject: [PATCH v5 2/3] i2c: tegra: make reset an optional property

For controllers that has an internal software reset, make the reset
property optional. This provides an option to use Tegra I2C in systems
that choose to restrict reset control from Linux or not to implement
the ACPI _RST method.

Internal reset was not required when the reset control was mandatory.
But on platforms where the resets are outside the control of Linux,
this had to be implemented by just returning success from BPMP or with
an empty _RST method in the ACPI table, basically ignoring the reset.

While the internal reset is not identical to the hard reset of the
controller, this will reset all the internal state of the controller
including FIFOs. This may slightly alter the behaviour in systems
which were ignoring the reset but it should not cause any functional
difference since all the required I2C registers are configured after
this reset, just as in boot. Considering that this sequence is hit
during the boot or during the I2C recovery path from an error, the
internal reset provides a better alternative than just ignoring the
reset.

Signed-off-by: Akhil R <akhilrajeev@...dia.com>
---
v4->v5:
  * Added check for ACPI _RST method.
  * Updated commit message.
v2->v4: No change
v1->v2:
  * Call devm_reset_control_get_optional_exclusive() unconditionally.

 drivers/i2c/busses/i2c-tegra.c | 35 +++++++++++++++++++++++++++++++---
 1 file changed, 32 insertions(+), 3 deletions(-)

diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index 6f3d770c5a67..b24882b76c6d 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -134,6 +134,8 @@
 #define I2C_MST_FIFO_STATUS_TX			GENMASK(23, 16)
 #define I2C_MST_FIFO_STATUS_RX			GENMASK(7, 0)
 
+#define I2C_MASTER_RESET_CNTRL			0x0a8
+
 /* configuration load timeout in microseconds */
 #define I2C_CONFIG_LOAD_TIMEOUT			1000000
 
@@ -184,6 +186,9 @@ enum msg_end_type {
  * @has_mst_fifo: The I2C controller contains the new MST FIFO interface that
  *		provides additional features and allows for longer messages to
  *		be transferred in one go.
+ * @has_mst_reset: The I2C controller contains MASTER_RESET_CTRL register which
+ *		provides an alternative to controller reset when configured as
+ *		I2C master
  * @quirks: I2C adapter quirks for limiting write/read transfer size and not
  *		allowing 0 length transfers.
  * @supports_bus_clear: Bus Clear support to recover from bus hang during
@@ -213,6 +218,7 @@ struct tegra_i2c_hw_feature {
 	bool has_multi_master_mode;
 	bool has_slcg_override_reg;
 	bool has_mst_fifo;
+	bool has_mst_reset;
 	const struct i2c_adapter_quirks *quirks;
 	bool supports_bus_clear;
 	bool has_apb_dma;
@@ -603,13 +609,27 @@ static int tegra_i2c_wait_for_config_load(struct tegra_i2c_dev *i2c_dev)
 
 	return 0;
 }
+
+static int tegra_i2c_master_reset(struct tegra_i2c_dev *i2c_dev)
+{
+	if (!i2c_dev->hw->has_mst_reset)
+		return -EOPNOTSUPP;
+
+	i2c_writel(i2c_dev, 0x1, I2C_MASTER_RESET_CNTRL);
+	udelay(2);
+
+	i2c_writel(i2c_dev, 0x0, I2C_MASTER_RESET_CNTRL);
+	udelay(2);
+
+	return 0;
+}
 
 static int tegra_i2c_reset(struct tegra_i2c_dev *i2c_dev)
 {
 	acpi_handle handle = ACPI_HANDLE(i2c_dev->dev);
 	int err;
 
-	if (handle) {
+	if (handle && acpi_has_method(handle, "_RST")) {
 		err = acpi_evaluate_object(handle, "_RST", NULL, NULL);
 		if (ACPI_FAILURE(err))
 			return -EIO;
@@ -617,7 +637,10 @@ static int tegra_i2c_reset(struct tegra_i2c_dev *i2c_dev)
 		return 0;
 	}
 
-	return reset_control_reset(i2c_dev->rst);
+	if (i2c_dev->rst)
+		return reset_control_reset(i2c_dev->rst);
+
+	return tegra_i2c_master_reset(i2c_dev);
 }
 
 static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
@@ -1483,6 +1506,7 @@ static const struct tegra_i2c_hw_feature tegra20_i2c_hw = {
 	.has_multi_master_mode = false,
 	.has_slcg_override_reg = false,
 	.has_mst_fifo = false,
+	.has_mst_reset = false,
 	.quirks = &tegra_i2c_quirks,
 	.supports_bus_clear = false,
 	.has_apb_dma = true,
@@ -1507,6 +1531,7 @@ static const struct tegra_i2c_hw_feature tegra30_i2c_hw = {
 	.has_multi_master_mode = false,
 	.has_slcg_override_reg = false,
 	.has_mst_fifo = false,
+	.has_mst_reset = false,
 	.quirks = &tegra_i2c_quirks,
 	.supports_bus_clear = false,
 	.has_apb_dma = true,
@@ -1531,6 +1556,7 @@ static const struct tegra_i2c_hw_feature tegra114_i2c_hw = {
 	.has_multi_master_mode = false,
 	.has_slcg_override_reg = false,
 	.has_mst_fifo = false,
+	.has_mst_reset = false,
 	.quirks = &tegra_i2c_quirks,
 	.supports_bus_clear = true,
 	.has_apb_dma = true,
@@ -1555,6 +1581,7 @@ static const struct tegra_i2c_hw_feature tegra124_i2c_hw = {
 	.has_multi_master_mode = false,
 	.has_slcg_override_reg = true,
 	.has_mst_fifo = false,
+	.has_mst_reset = false,
 	.quirks = &tegra_i2c_quirks,
 	.supports_bus_clear = true,
 	.has_apb_dma = true,
@@ -1579,6 +1606,7 @@ static const struct tegra_i2c_hw_feature tegra210_i2c_hw = {
 	.has_multi_master_mode = false,
 	.has_slcg_override_reg = true,
 	.has_mst_fifo = false,
+	.has_mst_reset = false,
 	.quirks = &tegra_i2c_quirks,
 	.supports_bus_clear = true,
 	.has_apb_dma = true,
@@ -1603,6 +1631,7 @@ static const struct tegra_i2c_hw_feature tegra186_i2c_hw = {
 	.has_multi_master_mode = false,
 	.has_slcg_override_reg = true,
 	.has_mst_fifo = false,
+	.has_mst_reset = false,
 	.quirks = &tegra_i2c_quirks,
 	.supports_bus_clear = true,
 	.has_apb_dma = false,
@@ -1627,6 +1656,7 @@ static const struct tegra_i2c_hw_feature tegra194_i2c_hw = {
 	.has_multi_master_mode = true,
 	.has_slcg_override_reg = true,
 	.has_mst_fifo = true,
+	.has_mst_reset = true,
 	.quirks = &tegra194_i2c_quirks,
 	.supports_bus_clear = true,
 	.has_apb_dma = false,
@@ -1682,7 +1712,7 @@ static int tegra_i2c_init_reset(struct tegra_i2c_dev *i2c_dev)
 	if (ACPI_HANDLE(i2c_dev->dev))
 		return 0;
 
-	i2c_dev->rst = devm_reset_control_get_exclusive(i2c_dev->dev, "i2c");
+	i2c_dev->rst = devm_reset_control_get_optional_exclusive(i2c_dev->dev, "i2c");
 	if (IS_ERR(i2c_dev->rst))
 		return dev_err_probe(i2c_dev->dev, PTR_ERR(i2c_dev->rst),
 				      "failed to get reset control\n");
-- 
2.49.0


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ