Devicetree
 help / color / mirror / Atom feed
* [PATCH 0/4] Add UFS host controller support for NVIDIA Tegra264
@ 2026-09-09 10:41 Kartik Rajput
  2026-09-09 10:41 ` [PATCH 1/4] dt-bindings: ufs: Add nvidia,tegra264-ufs Kartik Rajput
                   ` (3 more replies)
  0 siblings, 4 replies; 13+ messages in thread
From: Kartik Rajput @ 2026-09-09 10:41 UTC (permalink / raw)
  To: Alim Akhtar, Avri Altman, Bart Van Assche, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Thierry Reding,
	Jonathan Hunter, James E.J. Bottomley, Martin K. Petersen,
	Philipp Zabel
  Cc: Thierry Reding, linux-scsi, devicetree, linux-tegra, linux-kernel,
	Kartik Rajput

Add UFS host controller support for NVIDIA Tegra264 SoCs. The controller
supports UFS 3.1 up to HS-G4B on two data lanes.

This series depends on the Tegra264 M-PHY series: the binding example
uses include/dt-bindings/phy/nvidia,tegra264-mphy.h, and
drivers/ufs/host/Kconfig selects PHY_TEGRA_MPHY. The driver itself has
no build dependency on the M-PHY driver; it consumes the generic PHY
API.

Signed-off-by: Kartik Rajput <kkartik@nvidia.com>
---
Kartik Rajput (4):
      dt-bindings: ufs: Add nvidia,tegra264-ufs
      scsi: ufs: Add UIC DEBUGSAVECONFIGTIME attribute and its field masks
      scsi: ufs: hisi: Use VS_DEBUGSAVECONFIGTIME instead of a literal address
      scsi: ufs: tegra: Add Tegra264 UFS host controller driver

 .../bindings/ufs/nvidia,tegra264-ufs.yaml          | 124 ++++
 drivers/ufs/host/Kconfig                           |  13 +
 drivers/ufs/host/Makefile                          |   1 +
 drivers/ufs/host/ufs-hisi.c                        |   6 +-
 drivers/ufs/host/ufs-tegra.c                       | 687 +++++++++++++++++++++
 include/ufs/unipro.h                               |   6 +
 6 files changed, 833 insertions(+), 4 deletions(-)
---
base-commit: a9d7ced84989ec05be09b4b8428759ef60450a0f
change-id: 20260909-tegra264-ufs-92edda57c75a
prerequisite-change-id: 20260909-tegra264-mphy-f3edf6fa4321:v1
prerequisite-patch-id: 1c46e1bce9f6106dbabf81e50cd366d3d2da01fc
prerequisite-patch-id: d367971b99f7308cef032b436c054d005b94eded

Best regards,
--  
Kartik Rajput <kkartik@nvidia.com>


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH 1/4] dt-bindings: ufs: Add nvidia,tegra264-ufs
  2026-09-09 10:41 [PATCH 0/4] Add UFS host controller support for NVIDIA Tegra264 Kartik Rajput
@ 2026-09-09 10:41 ` Kartik Rajput
  2026-09-09 10:51   ` sashiko-bot
  2026-09-13  8:40   ` Krzysztof Kozlowski
  2026-09-09 10:41 ` [PATCH 2/4] scsi: ufs: Add UIC DEBUGSAVECONFIGTIME attribute and its field masks Kartik Rajput
                   ` (2 subsequent siblings)
  3 siblings, 2 replies; 13+ messages in thread
From: Kartik Rajput @ 2026-09-09 10:41 UTC (permalink / raw)
  To: Alim Akhtar, Avri Altman, Bart Van Assche, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Thierry Reding,
	Jonathan Hunter, James E.J. Bottomley, Martin K. Petersen,
	Philipp Zabel
  Cc: Thierry Reding, linux-scsi, devicetree, linux-tegra, linux-kernel,
	Kartik Rajput

Add binding for the UFS host controller on NVIDIA Tegra264 SoCs. The
controller supports UFS 3.1 up to HS-G4B on two data lanes.

Signed-off-by: Kartik Rajput <kkartik@nvidia.com>
---
 .../bindings/ufs/nvidia,tegra264-ufs.yaml          | 124 +++++++++++++++++++++
 1 file changed, 124 insertions(+)

diff --git a/Documentation/devicetree/bindings/ufs/nvidia,tegra264-ufs.yaml b/Documentation/devicetree/bindings/ufs/nvidia,tegra264-ufs.yaml
new file mode 100644
index 000000000000..5a9837cb43dd
--- /dev/null
+++ b/Documentation/devicetree/bindings/ufs/nvidia,tegra264-ufs.yaml
@@ -0,0 +1,124 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/ufs/nvidia,tegra264-ufs.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NVIDIA Tegra264 UFS Host Controller
+
+maintainers:
+  - Kartik Rajput <kkartik@nvidia.com>
+  - Thierry Reding <treding@nvidia.com>
+
+properties:
+  compatible:
+    const: nvidia,tegra264-ufs
+
+  reg:
+    items:
+      - description: UFS Host Controller registers
+      - description: UFS auxiliary registers
+
+  reg-names:
+    items:
+      - const: ufs
+      - const: aux
+
+  clocks:
+    items:
+      - description: UFS host controller functional clock
+      - description: UFS host controller divider clock
+      - description: UFS reference clock (PLLREFUFS output)
+      - description: UFS device-side reference clock
+      - description: M-PHY reference clock (UPHY0 PLL4 digital output)
+
+  clock-names:
+    items:
+      - const: ufs
+      - const: div
+      - const: ref
+      - const: ref-dev
+      - const: phy
+
+  resets:
+    items:
+      - description: UFS host controller reset
+      - description: UFS host controller AXI-master reset
+      - description: UFS host controller low-power sequencer reset
+
+  reset-names:
+    items:
+      - const: ufs
+      - const: axi
+      - const: lp
+
+  phys:
+    items:
+      - description: M-PHY lane 0 transmit
+      - description: M-PHY lane 0 receive
+      - description: M-PHY lane 1 transmit
+      - description: M-PHY lane 1 receive
+
+  phy-names:
+    items:
+      - const: mphy-l0-tx
+      - const: mphy-l0-rx
+      - const: mphy-l1-tx
+      - const: mphy-l1-rx
+
+  iommus:
+    maxItems: 1
+
+  dma-coherent: true
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - clocks
+  - clock-names
+  - resets
+  - reset-names
+  - phys
+  - phy-names
+  - iommus
+  - dma-coherent
+
+allOf:
+  - $ref: ufs-common.yaml
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/nvidia,tegra264.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/phy/nvidia,tegra264-mphy.h>
+    #include <dt-bindings/reset/nvidia,tegra264.h>
+
+    ufs@b8d0000 {
+        compatible = "nvidia,tegra264-ufs";
+        reg = <0xb8d0000 0x10000>,
+              <0xb8e0000 0x8000>;
+        reg-names = "ufs", "aux";
+        interrupts = <GIC_SPI 951 IRQ_TYPE_LEVEL_HIGH>;
+        clocks = <&bpmp TEGRA264_CLK_UFSHC_CG_SYS>,
+                 <&bpmp TEGRA264_CLK_UFSHC_CG_SYS_DIV>,
+                 <&bpmp TEGRA264_CLK_PLLREFUFS_CLKOUT624>,
+                 <&bpmp TEGRA264_CLK_PLLREFUFS_UFSDEV_REFCLKOUT>,
+                 <&bpmp TEGRA264_CLK_UPHY0_PLL4_XDIG>;
+        clock-names = "ufs", "div", "ref", "ref-dev", "phy";
+        resets = <&bpmp TEGRA264_RESET_UFSHC>,
+                 <&bpmp TEGRA264_RESET_UFSHC_AXI_M>,
+                 <&bpmp TEGRA264_RESET_UFSHC_LP_SEQ>;
+        reset-names = "ufs", "axi", "lp";
+        phys = <&mphy TEGRA_MPHY_L0_TX>,
+               <&mphy TEGRA_MPHY_L0_RX>,
+               <&mphy TEGRA_MPHY_L1_TX>,
+               <&mphy TEGRA_MPHY_L1_RX>;
+        phy-names = "mphy-l0-tx", "mphy-l0-rx",
+                    "mphy-l1-tx", "mphy-l1-rx";
+        iommus = <&smmu 0x20>;
+        dma-coherent;
+    };
+...

-- 
2.43.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 2/4] scsi: ufs: Add UIC DEBUGSAVECONFIGTIME attribute and its field masks
  2026-09-09 10:41 [PATCH 0/4] Add UFS host controller support for NVIDIA Tegra264 Kartik Rajput
  2026-09-09 10:41 ` [PATCH 1/4] dt-bindings: ufs: Add nvidia,tegra264-ufs Kartik Rajput
@ 2026-09-09 10:41 ` Kartik Rajput
  2026-09-09 10:41 ` [PATCH 3/4] scsi: ufs: hisi: Use VS_DEBUGSAVECONFIGTIME instead of a literal address Kartik Rajput
  2026-09-09 10:41 ` [PATCH 4/4] scsi: ufs: tegra: Add Tegra264 UFS host controller driver Kartik Rajput
  3 siblings, 0 replies; 13+ messages in thread
From: Kartik Rajput @ 2026-09-09 10:41 UTC (permalink / raw)
  To: Alim Akhtar, Avri Altman, Bart Van Assche, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Thierry Reding,
	Jonathan Hunter, James E.J. Bottomley, Martin K. Petersen,
	Philipp Zabel
  Cc: Thierry Reding, linux-scsi, devicetree, linux-tegra, linux-kernel,
	Kartik Rajput

Add the UniPro vendor-specific save-config-time attribute and masks for
the two fields within it:

  VS_DEBUGSAVECONFIGTIME       Save-config-time attribute (0xD0A0)
  VS_DEBUGSAVECONFIGTIME_TREF  Field masks within that attribute, for
  VS_DEBUGSAVECONFIGTIME_SCT   use with FIELD_PREP()

ufs-hisi already writes this attribute by its literal address, so name
it in the shared header rather than in the driver. Add it here in
preparation for the Tegra264 UFS host controller driver, which also
programs the two fields.

Signed-off-by: Kartik Rajput <kkartik@nvidia.com>
---
 include/ufs/unipro.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/include/ufs/unipro.h b/include/ufs/unipro.h
index 9c168703b104..f6d83878f2a6 100644
--- a/include/ufs/unipro.h
+++ b/include/ufs/unipro.h
@@ -6,6 +6,8 @@
 #ifndef _UNIPRO_H_
 #define _UNIPRO_H_
 
+#include <linux/bits.h>
+
 /*
  * M-TX Configuration Attributes
  */
@@ -232,8 +234,12 @@
 #define VS_POWERSTATE		0xD083
 #define VS_MPHYCFGUPDT		0xD085
 #define VS_DEBUGOMC		0xD09E
+#define VS_DEBUGSAVECONFIGTIME	0xD0A0
 #define VS_MPHYDISABLE		0xD0C1
 
+#define VS_DEBUGSAVECONFIGTIME_TREF	GENMASK(4, 2)
+#define VS_DEBUGSAVECONFIGTIME_SCT	GENMASK(1, 0)
+
 #define PA_GRANULARITY_MIN_VAL	1
 #define PA_GRANULARITY_MAX_VAL	6
 

-- 
2.43.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 3/4] scsi: ufs: hisi: Use VS_DEBUGSAVECONFIGTIME instead of a literal address
  2026-09-09 10:41 [PATCH 0/4] Add UFS host controller support for NVIDIA Tegra264 Kartik Rajput
  2026-09-09 10:41 ` [PATCH 1/4] dt-bindings: ufs: Add nvidia,tegra264-ufs Kartik Rajput
  2026-09-09 10:41 ` [PATCH 2/4] scsi: ufs: Add UIC DEBUGSAVECONFIGTIME attribute and its field masks Kartik Rajput
@ 2026-09-09 10:41 ` Kartik Rajput
  2026-09-09 10:41 ` [PATCH 4/4] scsi: ufs: tegra: Add Tegra264 UFS host controller driver Kartik Rajput
  3 siblings, 0 replies; 13+ messages in thread
From: Kartik Rajput @ 2026-09-09 10:41 UTC (permalink / raw)
  To: Alim Akhtar, Avri Altman, Bart Van Assche, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Thierry Reding,
	Jonathan Hunter, James E.J. Bottomley, Martin K. Petersen,
	Philipp Zabel
  Cc: Thierry Reding, linux-scsi, devicetree, linux-tegra, linux-kernel,
	Kartik Rajput

ufs-hisi writes the VS_DebugSaveConfigTime UIC attribute twice by its
literal address, with a comment naming it each time. The attribute now
has a name in the shared UniPro header, so use it and drop the comments
and the redundant (u32) cast.

No functional change.

Signed-off-by: Kartik Rajput <kkartik@nvidia.com>
---
 drivers/ufs/host/ufs-hisi.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/ufs/host/ufs-hisi.c b/drivers/ufs/host/ufs-hisi.c
index 993e20ac211d..79417c16c627 100644
--- a/drivers/ufs/host/ufs-hisi.c
+++ b/drivers/ufs/host/ufs-hisi.c
@@ -318,8 +318,7 @@ static void ufs_hisi_pwr_change_pre_change(struct ufs_hba *hba)
 		 * Boston platform need to set SaveConfigTime to 0x13,
 		 * and change sync length to maximum value
 		 */
-		/* VS_DebugSaveConfigTime */
-		ufshcd_dme_set(hba, UIC_ARG_MIB((u32)0xD0A0), 0x13);
+		ufshcd_dme_set(hba, UIC_ARG_MIB(VS_DEBUGSAVECONFIGTIME), 0x13);
 		/* g1 sync length */
 		ufshcd_dme_set(hba, UIC_ARG_MIB((u32)0x1552), 0x4f);
 		/* g2 sync length */
@@ -335,8 +334,7 @@ static void ufs_hisi_pwr_change_pre_change(struct ufs_hba *hba)
 
 	if (hba->dev_quirks & UFS_DEVICE_QUIRK_HOST_VS_DEBUGSAVECONFIGTIME) {
 		pr_info("ufs flash device must set VS_DebugSaveConfigTime 0x10\n");
-		/* VS_DebugSaveConfigTime */
-		ufshcd_dme_set(hba, UIC_ARG_MIB(0xD0A0), 0x10);
+		ufshcd_dme_set(hba, UIC_ARG_MIB(VS_DEBUGSAVECONFIGTIME), 0x10);
 		/* sync length */
 		ufshcd_dme_set(hba, UIC_ARG_MIB(0x1556), 0x48);
 	}

-- 
2.43.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 4/4] scsi: ufs: tegra: Add Tegra264 UFS host controller driver
  2026-09-09 10:41 [PATCH 0/4] Add UFS host controller support for NVIDIA Tegra264 Kartik Rajput
                   ` (2 preceding siblings ...)
  2026-09-09 10:41 ` [PATCH 3/4] scsi: ufs: hisi: Use VS_DEBUGSAVECONFIGTIME instead of a literal address Kartik Rajput
@ 2026-09-09 10:41 ` Kartik Rajput
  2026-09-09 11:02   ` sashiko-bot
  2026-09-09 14:20   ` Uwe Kleine-König
  3 siblings, 2 replies; 13+ messages in thread
From: Kartik Rajput @ 2026-09-09 10:41 UTC (permalink / raw)
  To: Alim Akhtar, Avri Altman, Bart Van Assche, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Thierry Reding,
	Jonathan Hunter, James E.J. Bottomley, Martin K. Petersen,
	Philipp Zabel
  Cc: Thierry Reding, linux-scsi, devicetree, linux-tegra, linux-kernel,
	Kartik Rajput

Add a driver for the UFS host controller found on NVIDIA Tegra264 SoCs.
The controller has Tegra-specific auxiliary registers, clocks and resets,
and it drives the four M-PHY lane directions exposed by the Tegra264
M-PHY driver.

Co-developed-by: Thierry Reding <treding@nvidia.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>
Signed-off-by: Kartik Rajput <kkartik@nvidia.com>
---
 drivers/ufs/host/Kconfig     |  13 +
 drivers/ufs/host/Makefile    |   1 +
 drivers/ufs/host/ufs-tegra.c | 687 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 701 insertions(+)

diff --git a/drivers/ufs/host/Kconfig b/drivers/ufs/host/Kconfig
index ff170c0b6da0..e4c565fce53c 100644
--- a/drivers/ufs/host/Kconfig
+++ b/drivers/ufs/host/Kconfig
@@ -168,3 +168,16 @@ config SCSI_UFS_AMD_VERSAL2
 
 	  Select this if you have UFS controller on AMD Versal Gen 2 SoC.
 	  If unsure, say N.
+
+config SCSI_UFS_TEGRA
+	tristate "NVIDIA Tegra264 UFS controller platform driver"
+	depends on SCSI_UFSHCD_PLATFORM && (ARCH_TEGRA_264_SOC || COMPILE_TEST)
+	select PHY_TEGRA_MPHY
+	help
+	  Enable support for the UFS host controller on NVIDIA Tegra264
+	  SoCs. The driver relies on the Tegra264 M-PHY driver
+	  (PHY_TEGRA_MPHY) for the two data lanes and implements the
+	  vendor register programming required for HS-mode transitions
+	  and system suspend/resume.
+
+	  If unsure, say N.
diff --git a/drivers/ufs/host/Makefile b/drivers/ufs/host/Makefile
index 7d8db67eb23c..1459a081cc9d 100644
--- a/drivers/ufs/host/Makefile
+++ b/drivers/ufs/host/Makefile
@@ -14,5 +14,6 @@ obj-$(CONFIG_SCSI_UFS_MEDIATEK) += ufs-mediatek.o
 obj-$(CONFIG_SCSI_UFS_RENESAS) += ufs-renesas.o
 obj-$(CONFIG_SCSI_UFS_ROCKCHIP) += ufs-rockchip.o
 obj-$(CONFIG_SCSI_UFS_SPRD) += ufs-sprd.o
+obj-$(CONFIG_SCSI_UFS_TEGRA) += ufs-tegra.o ufshcd-dwc.o
 obj-$(CONFIG_SCSI_UFS_TI_J721E) += ti-j721e-ufs.o
 obj-$(CONFIG_SCSI_UFS_AMD_VERSAL2) += ufs-amd-versal2.o ufshcd-dwc.o
diff --git a/drivers/ufs/host/ufs-tegra.c b/drivers/ufs/host/ufs-tegra.c
new file mode 100644
index 000000000000..859fe0af66e5
--- /dev/null
+++ b/drivers/ufs/host/ufs-tegra.c
@@ -0,0 +1,687 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// NVIDIA Tegra264 UFS host controller driver.
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/mod_devicetable.h>
+#include <linux/of.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+
+#include <ufs/ufshcd.h>
+#include <ufs/ufshci.h>
+#include <ufs/unipro.h>
+
+#include "ufshcd-dwc.h"
+#include "ufshcd-pltfrm.h"
+#include "ufshci-dwc.h"
+
+#define UFSHC_DWC_BLOCK_BUSTHRTL		0xc0
+#define MBL(x)					(((x) & 0x7) << 13)
+#define MBL_MASK				(0x7 << 13)
+
+#define HCLKDIV(x)				((x) & 0xff)
+
+#define UFSHC_AUX_SW_EN_CLK_SLCG		0x08
+#define CLK_OVR_ON				BIT(0)
+
+#define UFSHC_AUX_DEV_CTRL			0x14
+#define DEV_CTRL_CLK_EN				BIT(0)
+#define DEV_CTRL_RESET				BIT(1)
+
+#define UFS_TEGRA_PHY_CLK_HS_RATE_HZ		5840000000UL
+
+/* DWC UFSHC BUSTHRTL max AXI burst length. */
+#define UFS_TEGRA_MBL_MAX			0x5
+
+/* DWC UniPro save-config-time reference and value fields. */
+#define UFS_TEGRA_SAVECONFIGTIME_TREF		0x6
+#define UFS_TEGRA_SAVECONFIGTIME_SCT		0x3
+
+/* HS G1..G4 sync burst length advertised to the peer. */
+#define UFS_TEGRA_HSG_SYNC_LEN			0x4f
+
+/* Local UniPro DME timeout values sent to the peer via PA_PWRMODEUSERDATA. */
+#define UFS_TEGRA_FC0_TIMEOUT			0x1fff
+#define UFS_TEGRA_TC0_TIMEOUT			0xffff
+#define UFS_TEGRA_AFC0_TIMEOUT			0x7fff
+
+struct ufs_tegra {
+	void __iomem *aux;
+
+	struct reset_control_bulk_data *resets;
+	unsigned int num_resets;
+
+	struct clk *ufs_clk;
+	struct clk *phy_clk;
+
+	struct phy *mphy_l0_rx;
+	struct phy *mphy_l0_tx;
+	struct phy *mphy_l1_rx;
+	struct phy *mphy_l1_tx;
+
+	bool mphy_on;
+
+	struct ufs_host_params host_params;
+};
+
+static int ufs_tegra_init_resources(struct ufs_hba *hba)
+{
+	struct platform_device *pdev = to_platform_device(hba->dev);
+	struct ufs_tegra *ufs = ufshcd_get_variant(hba);
+
+	ufs->aux = devm_platform_ioremap_resource_byname(pdev, "aux");
+	if (IS_ERR(ufs->aux))
+		return PTR_ERR(ufs->aux);
+
+	return 0;
+}
+
+static const struct reset_control_bulk_data ufs_tegra_resets[] = {
+	{ .id = "ufs" },
+	{ .id = "axi" },
+	{ .id = "lp" },
+};
+
+static int ufs_tegra_parse_reset_info(struct ufs_hba *hba)
+{
+	struct ufs_tegra *ufs = ufshcd_get_variant(hba);
+	struct device *dev = hba->dev;
+
+	ufs->num_resets = ARRAY_SIZE(ufs_tegra_resets);
+
+	ufs->resets = devm_kmemdup(dev, ufs_tegra_resets, sizeof(ufs_tegra_resets), GFP_KERNEL);
+	if (!ufs->resets)
+		return -ENOMEM;
+
+	return devm_reset_control_bulk_get_exclusive(dev, ufs->num_resets, ufs->resets);
+}
+
+static int ufs_tegra_parse_clock_info(struct ufs_hba *hba)
+{
+	struct ufs_tegra *ufs = ufshcd_get_variant(hba);
+	struct ufs_clk_info *clki;
+
+	list_for_each_entry(clki, &hba->clk_list_head, list) {
+		if (!strcmp(clki->name, "ufs"))
+			ufs->ufs_clk = clki->clk;
+
+		if (!strcmp(clki->name, "phy"))
+			ufs->phy_clk = clki->clk;
+	}
+
+	if (!ufs->ufs_clk || !ufs->phy_clk)
+		return -ENODEV;
+
+	return 0;
+}
+
+static int ufs_tegra_parse_phy_info(struct ufs_hba *hba)
+{
+	struct ufs_tegra *ufs = ufshcd_get_variant(hba);
+	struct device *dev = hba->dev;
+
+	ufs->mphy_l0_rx = devm_phy_get(dev, "mphy-l0-rx");
+	if (IS_ERR(ufs->mphy_l0_rx))
+		return PTR_ERR(ufs->mphy_l0_rx);
+
+	ufs->mphy_l0_tx = devm_phy_get(dev, "mphy-l0-tx");
+	if (IS_ERR(ufs->mphy_l0_tx))
+		return PTR_ERR(ufs->mphy_l0_tx);
+
+	ufs->mphy_l1_rx = devm_phy_get(dev, "mphy-l1-rx");
+	if (IS_ERR(ufs->mphy_l1_rx))
+		return PTR_ERR(ufs->mphy_l1_rx);
+
+	ufs->mphy_l1_tx = devm_phy_get(dev, "mphy-l1-tx");
+	if (IS_ERR(ufs->mphy_l1_tx))
+		return PTR_ERR(ufs->mphy_l1_tx);
+
+	return 0;
+}
+
+static void ufs_tegra_set_caps(struct ufs_hba *hba)
+{
+	hba->caps |= UFSHCD_CAP_INTR_AGGR;
+	hba->caps |= UFSHCD_CAP_WB_EN;
+
+	hba->spm_lvl = UFS_PM_LVL_5;
+}
+
+static void ufs_tegra_configure_aux(struct ufs_hba *hba)
+{
+	struct ufs_tegra *ufs = ufshcd_get_variant(hba);
+	u32 value;
+
+	value = readl(ufs->aux + UFSHC_AUX_DEV_CTRL);
+	value |= DEV_CTRL_CLK_EN;
+	writel(value, ufs->aux + UFSHC_AUX_DEV_CTRL);
+
+	/* Let the reference clock stabilise before deasserting device reset. */
+	usleep_range(1000, 2000);
+
+	value |= DEV_CTRL_RESET;
+	writel(value, ufs->aux + UFSHC_AUX_DEV_CTRL);
+}
+
+static void ufs_tegra_aux_init(struct ufs_hba *hba)
+{
+	struct ufs_tegra *ufs = ufshcd_get_variant(hba);
+	u32 value;
+
+	value = readl(ufs->aux + UFSHC_AUX_DEV_CTRL);
+	value &= ~(DEV_CTRL_CLK_EN | DEV_CTRL_RESET);
+	writel(value, ufs->aux + UFSHC_AUX_DEV_CTRL);
+
+	/* Ensure the clear is observed before we re-enable. */
+	usleep_range(100, 200);
+
+	ufs_tegra_configure_aux(hba);
+}
+
+static void ufs_tegra_update_hclk_div(struct ufs_hba *hba)
+{
+	struct ufs_tegra *ufs = ufshcd_get_variant(hba);
+	u32 ufs_clk_mhz;
+
+	ufs_clk_mhz = clk_get_rate(ufs->ufs_clk) / USEC_PER_SEC;
+	ufshcd_writel(hba, HCLKDIV(ufs_clk_mhz), DWC_UFS_REG_HCLKDIV);
+}
+
+static int ufs_tegra_init(struct ufs_hba *hba)
+{
+	struct platform_device *pdev = to_platform_device(hba->dev);
+	struct device *dev = &pdev->dev;
+	struct ufs_tegra *ufs;
+	int err;
+
+	ufs = devm_kzalloc(dev, sizeof(*ufs), GFP_KERNEL);
+	if (!ufs)
+		return -ENOMEM;
+
+	ufshcd_set_variant(hba, ufs);
+
+	err = ufs_tegra_init_resources(hba);
+	if (err)
+		return err;
+
+	err = ufs_tegra_parse_clock_info(hba);
+	if (err)
+		return err;
+
+	err = ufs_tegra_parse_reset_info(hba);
+	if (err)
+		return err;
+
+	err = ufs_tegra_parse_phy_info(hba);
+	if (err)
+		return err;
+
+	ufs_tegra_set_caps(hba);
+
+	ufshcd_init_host_params(&ufs->host_params);
+	ufs->host_params.hs_rx_gear = UFS_HS_G4;
+	ufs->host_params.hs_tx_gear = UFS_HS_G4;
+
+	err = reset_control_bulk_deassert(ufs->num_resets, ufs->resets);
+	if (err)
+		return err;
+
+	ufs_tegra_aux_init(hba);
+	ufs_tegra_update_hclk_div(hba);
+
+	return 0;
+}
+
+static int ufs_tegra_mphy_init(struct ufs_hba *hba)
+{
+	struct ufs_tegra *ufs = ufshcd_get_variant(hba);
+	int err;
+
+	err = phy_init(ufs->mphy_l0_rx);
+	if (err) {
+		dev_err(hba->dev, "failed to initialize mphy-l0-rx\n");
+		return err;
+	}
+
+	err = phy_init(ufs->mphy_l0_tx);
+	if (err) {
+		dev_err(hba->dev, "failed to initialize mphy-l0-tx\n");
+		goto out_exit_l0_rx;
+	}
+
+	err = phy_init(ufs->mphy_l1_rx);
+	if (err) {
+		dev_err(hba->dev, "failed to initialize mphy-l1-rx\n");
+		goto out_exit_l0_tx;
+	}
+
+	err = phy_init(ufs->mphy_l1_tx);
+	if (err) {
+		dev_err(hba->dev, "failed to initialize mphy-l1-tx\n");
+		goto out_exit_l1_rx;
+	}
+
+	return 0;
+
+out_exit_l1_rx:
+	phy_exit(ufs->mphy_l1_rx);
+out_exit_l0_tx:
+	phy_exit(ufs->mphy_l0_tx);
+out_exit_l0_rx:
+	phy_exit(ufs->mphy_l0_rx);
+
+	return err;
+}
+
+static void ufs_tegra_mphy_exit(struct ufs_hba *hba)
+{
+	struct ufs_tegra *ufs = ufshcd_get_variant(hba);
+
+	phy_exit(ufs->mphy_l0_rx);
+	phy_exit(ufs->mphy_l0_tx);
+	phy_exit(ufs->mphy_l1_rx);
+	phy_exit(ufs->mphy_l1_tx);
+}
+
+static int ufs_tegra_mphy_power_on(struct ufs_hba *hba)
+{
+	struct ufs_tegra *ufs = ufshcd_get_variant(hba);
+	int err;
+
+	err = phy_power_on(ufs->mphy_l0_rx);
+	if (err) {
+		dev_err(hba->dev, "failed to power on mphy-l0-rx\n");
+		return err;
+	}
+
+	err = phy_power_on(ufs->mphy_l0_tx);
+	if (err) {
+		dev_err(hba->dev, "failed to power on mphy-l0-tx\n");
+		goto out_power_off_l0_rx;
+	}
+
+	err = phy_power_on(ufs->mphy_l1_rx);
+	if (err) {
+		dev_err(hba->dev, "failed to power on mphy-l1-rx\n");
+		goto out_power_off_l0_tx;
+	}
+
+	err = phy_power_on(ufs->mphy_l1_tx);
+	if (err) {
+		dev_err(hba->dev, "failed to power on mphy-l1-tx\n");
+		goto out_power_off_l1_rx;
+	}
+
+	return 0;
+
+out_power_off_l1_rx:
+	phy_power_off(ufs->mphy_l1_rx);
+out_power_off_l0_tx:
+	phy_power_off(ufs->mphy_l0_tx);
+out_power_off_l0_rx:
+	phy_power_off(ufs->mphy_l0_rx);
+
+	return err;
+}
+
+static void ufs_tegra_mphy_power_off(struct ufs_hba *hba)
+{
+	struct ufs_tegra *ufs = ufshcd_get_variant(hba);
+
+	phy_power_off(ufs->mphy_l0_rx);
+	phy_power_off(ufs->mphy_l0_tx);
+	phy_power_off(ufs->mphy_l1_rx);
+	phy_power_off(ufs->mphy_l1_tx);
+}
+
+static int ufs_tegra_mphy_enable(struct ufs_hba *hba)
+{
+	struct ufs_tegra *ufs = ufshcd_get_variant(hba);
+	int err;
+
+	if (ufs->mphy_on)
+		return 0;
+
+	err = ufs_tegra_mphy_init(hba);
+	if (err)
+		return err;
+
+	err = ufs_tegra_mphy_power_on(hba);
+	if (err) {
+		ufs_tegra_mphy_exit(hba);
+		return err;
+	}
+
+	ufs->mphy_on = true;
+
+	/* Allow M-PHY to settle after power-on. */
+	usleep_range(500, 600);
+
+	return 0;
+}
+
+static void ufs_tegra_mphy_disable(struct ufs_hba *hba)
+{
+	struct ufs_tegra *ufs = ufshcd_get_variant(hba);
+
+	if (!ufs->mphy_on)
+		return;
+
+	ufs_tegra_mphy_power_off(hba);
+	ufs_tegra_mphy_exit(hba);
+
+	ufs->mphy_on = false;
+}
+
+static int ufs_tegra_mphy_configure_tx(struct ufs_hba *hba)
+{
+	struct ufs_tegra *ufs = ufshcd_get_variant(hba);
+	int err;
+
+	err = phy_configure(ufs->mphy_l0_tx, NULL);
+	if (err)
+		return err;
+
+	return phy_configure(ufs->mphy_l1_tx, NULL);
+}
+
+static int ufs_tegra_mphy_calibrate_tx(struct ufs_hba *hba)
+{
+	struct ufs_tegra *ufs = ufshcd_get_variant(hba);
+	int err;
+
+	err = phy_calibrate(ufs->mphy_l0_tx);
+	if (err)
+		return err;
+
+	return phy_calibrate(ufs->mphy_l1_tx);
+}
+
+static int ufs_tegra_mphy_calibrate_rx(struct ufs_hba *hba)
+{
+	struct ufs_tegra *ufs = ufshcd_get_variant(hba);
+	int err;
+
+	err = phy_configure(ufs->mphy_l1_rx, NULL);
+	if (err)
+		return err;
+
+	err = phy_configure(ufs->mphy_l0_rx, NULL);
+	if (err)
+		return err;
+
+	err = phy_calibrate(ufs->mphy_l1_rx);
+	if (err)
+		return err;
+
+	return phy_calibrate(ufs->mphy_l0_rx);
+}
+
+static void ufs_tegra_exit(struct ufs_hba *hba)
+{
+	ufs_tegra_mphy_disable(hba);
+}
+
+static int ufs_tegra_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op,
+			     enum ufs_notify_change_status status)
+{
+	if (status == PRE_CHANGE)
+		return 0;
+
+	/* Runtime H8 park keeps the M-PHY powered; only tear it down
+	 * on the full-teardown paths (system suspend, shutdown, or
+	 * runtime PM with LINK_OFF).
+	 */
+	if (pm_op == UFS_RUNTIME_PM && !ufshcd_is_link_off(hba))
+		return 0;
+
+	ufs_tegra_mphy_disable(hba);
+
+	if (pm_op != UFS_RUNTIME_PM)
+		ufshcd_set_link_off(hba);
+
+	return 0;
+}
+
+static int ufs_tegra_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
+{
+	/* Skip when the M-PHY was left powered by the suspend path. */
+	if (ufshcd_is_link_active(hba) || ufshcd_is_link_hibern8(hba))
+		return 0;
+
+	return ufs_tegra_mphy_enable(hba);
+}
+
+static int ufs_tegra_reset(struct ufs_tegra *ufs)
+{
+	int err;
+
+	err = reset_control_bulk_assert(ufs->num_resets, ufs->resets);
+	if (err)
+		return err;
+
+	usleep_range(100, 200);
+
+	err = reset_control_bulk_deassert(ufs->num_resets, ufs->resets);
+	if (err)
+		return err;
+
+	usleep_range(500, 600);
+
+	return 0;
+}
+
+static int ufs_tegra_power_up_sequence(struct ufs_hba *hba)
+{
+	struct ufs_tegra *ufs = ufshcd_get_variant(hba);
+	int err;
+
+	err = ufs_tegra_reset(ufs);
+	if (err)
+		return err;
+
+	return ufs_tegra_mphy_enable(hba);
+}
+
+static void ufs_tegra_setup(struct ufs_hba *hba)
+{
+	ufs_tegra_configure_aux(hba);
+	ufs_tegra_update_hclk_div(hba);
+	ufshcd_rmwl(hba, MBL_MASK, MBL(UFS_TEGRA_MBL_MAX), UFSHC_DWC_BLOCK_BUSTHRTL);
+}
+
+static int ufs_tegra_hce_enable_notify(struct ufs_hba *hba, enum ufs_notify_change_status status)
+{
+	struct ufs_tegra *ufs = ufshcd_get_variant(hba);
+	u32 value;
+	int err;
+
+	switch (status) {
+	case PRE_CHANGE:
+		err = ufs_tegra_power_up_sequence(hba);
+		if (err)
+			return err;
+
+		/* Assert device reset; POST_CHANGE releases it via
+		 * ufs_tegra_configure_aux() so the HCE toggle pulses it.
+		 */
+		value = readl(ufs->aux + UFSHC_AUX_DEV_CTRL);
+		value &= ~DEV_CTRL_RESET;
+		writel(value, ufs->aux + UFSHC_AUX_DEV_CTRL);
+		break;
+	case POST_CHANGE:
+		value = readl(ufs->aux + UFSHC_AUX_SW_EN_CLK_SLCG);
+		value &= ~CLK_OVR_ON;
+		writel(value, ufs->aux + UFSHC_AUX_SW_EN_CLK_SLCG);
+
+		ufs_tegra_setup(hba);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int ufs_tegra_link_startup_notify(struct ufs_hba *hba, enum ufs_notify_change_status status)
+{
+	static const struct ufshcd_dme_attr_val post_change_attrs[] = {
+		{ UIC_ARG_MIB(T_CONNECTIONSTATE), 0x1, DME_LOCAL },
+		{ UIC_ARG_MIB(PA_TXHSG1SYNCLENGTH), UFS_TEGRA_HSG_SYNC_LEN, DME_LOCAL },
+		{ UIC_ARG_MIB(PA_TXHSG2SYNCLENGTH), UFS_TEGRA_HSG_SYNC_LEN, DME_LOCAL },
+		{ UIC_ARG_MIB(PA_TXHSG3SYNCLENGTH), UFS_TEGRA_HSG_SYNC_LEN, DME_LOCAL },
+		{ UIC_ARG_MIB(PA_TXHSG4SYNCLENGTH), UFS_TEGRA_HSG_SYNC_LEN, DME_LOCAL },
+		{ UIC_ARG_MIB(DME_LocalFC0ProtectionTimeOutVal), UFS_TEGRA_FC0_TIMEOUT, DME_LOCAL },
+		{ UIC_ARG_MIB(DME_LocalTC0ReplayTimeOutVal), UFS_TEGRA_TC0_TIMEOUT, DME_LOCAL },
+		{ UIC_ARG_MIB(DME_LocalAFC0ReqTimeOutVal), UFS_TEGRA_AFC0_TIMEOUT, DME_LOCAL },
+		{ UIC_ARG_MIB(PA_PWRMODEUSERDATA0), UFS_TEGRA_FC0_TIMEOUT, DME_LOCAL },
+		{ UIC_ARG_MIB(PA_PWRMODEUSERDATA1), UFS_TEGRA_TC0_TIMEOUT, DME_LOCAL },
+		{ UIC_ARG_MIB(PA_PWRMODEUSERDATA2), UFS_TEGRA_AFC0_TIMEOUT, DME_LOCAL },
+	};
+	int err;
+
+	switch (status) {
+	case PRE_CHANGE:
+		/* Arm TX calibration; RX capabilities are advertised in
+		 * tegra_mphy_rx_power_on().
+		 */
+		err = ufs_tegra_mphy_configure_tx(hba);
+		if (err)
+			return err;
+		break;
+
+	case POST_CHANGE:
+		err = ufs_tegra_mphy_calibrate_tx(hba);
+		if (err)
+			return err;
+
+		err = ufshcd_dwc_dme_set_attrs(hba, post_change_attrs,
+					       ARRAY_SIZE(post_change_attrs));
+		if (err)
+			return err;
+
+		err = ufs_tegra_mphy_calibrate_rx(hba);
+		if (err)
+			return err;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int ufs_tegra_negotiate_pwr_mode(struct ufs_hba *hba,
+					const struct ufs_pa_layer_attr *dev_max_params,
+					struct ufs_pa_layer_attr *dev_req_params)
+{
+	struct ufs_tegra *ufs = ufshcd_get_variant(hba);
+
+	return ufshcd_negotiate_pwr_params(&ufs->host_params, dev_max_params, dev_req_params);
+}
+
+static int ufs_tegra_pwr_change_notify(struct ufs_hba *hba,
+				       enum ufs_notify_change_status status,
+				       struct ufs_pa_layer_attr *dev_req_params)
+{
+	struct ufs_tegra *ufs = ufshcd_get_variant(hba);
+	u32 value;
+	int err;
+
+	if (status != PRE_CHANGE)
+		return 0;
+
+	err = ufshcd_dme_get(hba, UIC_ARG_MIB(VS_DEBUGSAVECONFIGTIME), &value);
+	if (err)
+		return err;
+
+	value &= ~VS_DEBUGSAVECONFIGTIME_TREF;
+	value |= FIELD_PREP(VS_DEBUGSAVECONFIGTIME_TREF, UFS_TEGRA_SAVECONFIGTIME_TREF);
+	value &= ~VS_DEBUGSAVECONFIGTIME_SCT;
+	value |= FIELD_PREP(VS_DEBUGSAVECONFIGTIME_SCT, UFS_TEGRA_SAVECONFIGTIME_SCT);
+
+	err = ufshcd_dme_set(hba, UIC_ARG_MIB(VS_DEBUGSAVECONFIGTIME), value);
+	if (err)
+		return err;
+
+	if (dev_req_params->hs_rate == PA_HS_MODE_A ||
+	    dev_req_params->hs_rate == PA_HS_MODE_B) {
+		err = clk_set_rate(ufs->phy_clk, UFS_TEGRA_PHY_CLK_HS_RATE_HZ);
+		if (err)
+			return err;
+	}
+
+	err = ufshcd_dme_configure_adapt(hba, dev_req_params->gear_tx, PA_INITIAL_ADAPT);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+static int ufs_tegra_set_dma_mask(struct ufs_hba *hba)
+{
+	return dma_set_mask_and_coherent(hba->dev, DMA_BIT_MASK(32));
+}
+
+static const struct ufs_hba_variant_ops ufs_tegra_vops = {
+	.name = "ufs-tegra",
+	.init = ufs_tegra_init,
+	.exit = ufs_tegra_exit,
+	.suspend = ufs_tegra_suspend,
+	.resume = ufs_tegra_resume,
+	.hce_enable_notify = ufs_tegra_hce_enable_notify,
+	.negotiate_pwr_mode = ufs_tegra_negotiate_pwr_mode,
+	.pwr_change_notify = ufs_tegra_pwr_change_notify,
+	.link_startup_notify = ufs_tegra_link_startup_notify,
+	.set_dma_mask = ufs_tegra_set_dma_mask,
+};
+
+static int ufs_tegra_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	int err;
+
+	err = ufshcd_pltfrm_init(pdev, &ufs_tegra_vops);
+	if (err)
+		return dev_err_probe(dev, err, "ufshcd platform init failed\n");
+
+	return 0;
+}
+
+static void ufs_tegra_remove(struct platform_device *pdev)
+{
+	ufshcd_pltfrm_remove(pdev);
+}
+
+static const struct dev_pm_ops ufs_tegra_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(ufshcd_system_suspend, ufshcd_system_resume)
+	SET_RUNTIME_PM_OPS(ufshcd_runtime_suspend, ufshcd_runtime_resume, NULL)
+};
+
+static const struct of_device_id ufs_tegra_of_match[] = {
+	{ .compatible = "nvidia,tegra264-ufs", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, ufs_tegra_of_match);
+
+static struct platform_driver ufs_tegra_driver = {
+	.probe = ufs_tegra_probe,
+	.remove = ufs_tegra_remove,
+	.driver = {
+		.name = "ufs-tegra",
+		.pm = &ufs_tegra_pm_ops,
+		.of_match_table = ufs_tegra_of_match,
+	},
+};
+module_platform_driver(ufs_tegra_driver);
+
+MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>");
+MODULE_AUTHOR("Kartik Rajput <kkartik@nvidia.com>");
+MODULE_DESCRIPTION("NVIDIA Tegra UFS host controller driver");
+MODULE_LICENSE("GPL");

-- 
2.43.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH 1/4] dt-bindings: ufs: Add nvidia,tegra264-ufs
  2026-09-09 10:41 ` [PATCH 1/4] dt-bindings: ufs: Add nvidia,tegra264-ufs Kartik Rajput
@ 2026-09-09 10:51   ` sashiko-bot
  2026-09-13  8:40   ` Krzysztof Kozlowski
  1 sibling, 0 replies; 13+ messages in thread
From: sashiko-bot @ 2026-09-09 10:51 UTC (permalink / raw)
  To: Kartik Rajput; +Cc: devicetree, robh, linux-scsi, conor+dt

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] Missing dependency on header file in DT binding example causes dt_binding_check to fail.
--

commit 3569ef54ab3548dc631c5780b8e85a8fb366de60
Author: Kartik Rajput <kkartik@nvidia.com>

dt-bindings: ufs: Add nvidia,tegra264-ufs

This commit adds the device tree binding for the UFS host controller on
NVIDIA Tegra264 SoCs. The controller supports UFS 3.1 up to HS-G4B on two
data lanes.

> diff --git a/Documentation/devicetree/bindings/ufs/nvidia,tegra264-ufs.yaml b/Documentation/devicetree/bindings/ufs/nvidia,tegra264-ufs.yaml
> new file mode 100644
> index 0000000000000..5a9837cb43dd3
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/ufs/nvidia,tegra264-ufs.yaml

[ ... ]

> +examples:
> +  - |
> +    #include <dt-bindings/clock/nvidia,tegra264.h>
> +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> +    #include <dt-bindings/phy/nvidia,tegra264-mphy.h>

[Severity: Low]
Does this missing header dependency cause a build failure?

The YAML example includes <dt-bindings/phy/nvidia,tegra264-mphy.h> here in
Documentation/devicetree/bindings/ufs/nvidia,tegra264-ufs.yaml, which does
not exist in the source tree and is not added by this patch series.

When running make dt_binding_check, this will cause the tool to fail
with a preprocessor error due to the missing header.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260909-tegra264-ufs-v1-0-e4a9831702a0@nvidia.com?part=1

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 4/4] scsi: ufs: tegra: Add Tegra264 UFS host controller driver
  2026-09-09 10:41 ` [PATCH 4/4] scsi: ufs: tegra: Add Tegra264 UFS host controller driver Kartik Rajput
@ 2026-09-09 11:02   ` sashiko-bot
  2026-09-09 14:20   ` Uwe Kleine-König
  1 sibling, 0 replies; 13+ messages in thread
From: sashiko-bot @ 2026-09-09 11:02 UTC (permalink / raw)
  To: Kartik Rajput; +Cc: robh, linux-scsi, conor+dt, devicetree

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [Medium] Referencing a non-existent Kconfig symbol `PHY_TEGRA_MPHY` in `select`.
- [Medium] Unmet dependency risk due to unconditionally selecting a potentially architecture-specific symbol in a driver that supports `COMPILE_TEST`.
- [Medium] Integer truncation of the 5.84 GHz clock rate on 32-bit architectures during `COMPILE_TEST`.
- [Medium] Hardware PHY teardown sequence incorrectly uses forward setup order instead of reverse.
--

commit ba95657952b3e5dc9efe191a253d2fb49a5a1f66
Author: Kartik Rajput <kkartik@nvidia.com>
Subject: scsi: ufs: tegra: Add Tegra264 UFS host controller driver

This commit adds a new UFS host controller driver for NVIDIA Tegra264 SoCs.
It implements Tegra-specific auxiliary registers, clocks, and resets, and
drives four M-PHY lane directions.

> diff --git a/drivers/ufs/host/Kconfig b/drivers/ufs/host/Kconfig
> index ff170c0b6da0c..e4c565fce53cc 100644
> --- a/drivers/ufs/host/Kconfig
> +++ b/drivers/ufs/host/Kconfig
> @@ -168,3 +168,16 @@ config SCSI_UFS_AMD_VERSAL2
[ ... ]
> +config SCSI_UFS_TEGRA
> +	tristate "NVIDIA Tegra264 UFS controller platform driver"
> +	depends on SCSI_UFSHCD_PLATFORM && (ARCH_TEGRA_264_SOC || COMPILE_TEST)
> +	select PHY_TEGRA_MPHY

[Severity: Medium]
Does the PHY_TEGRA_MPHY symbol exist in the kernel tree? If not, selecting it
here will cause silent build failures or leave features disabled.

[Severity: Medium]
Additionally, since this driver supports COMPILE_TEST, does unconditionally
selecting an architecture-specific PHY risk triggering unmet dependency
warnings on unsupported architectures during cross-compilation?

> diff --git a/drivers/ufs/host/ufs-tegra.c b/drivers/ufs/host/ufs-tegra.c
> new file mode 100644
> index 0000000000000..859fe0af66e51
> --- /dev/null
> +++ b/drivers/ufs/host/ufs-tegra.c
[ ... ]
> +#define UFSHC_AUX_DEV_CTRL			0x14
> +#define DEV_CTRL_CLK_EN				BIT(0)
> +#define DEV_CTRL_RESET				BIT(1)
> +
> +#define UFS_TEGRA_PHY_CLK_HS_RATE_HZ		5840000000UL

[Severity: Medium]
Is this literal too large for a 32-bit unsigned long? The literal requires
33 bits, but when COMPILE_TEST is enabled on 32-bit architectures, this
value will be truncated.

[ ... ]
> +static void ufs_tegra_mphy_exit(struct ufs_hba *hba)
> +{
> +	struct ufs_tegra *ufs = ufshcd_get_variant(hba);
> +
> +	phy_exit(ufs->mphy_l0_rx);
> +	phy_exit(ufs->mphy_l0_tx);
> +	phy_exit(ufs->mphy_l1_rx);
> +	phy_exit(ufs->mphy_l1_tx);
> +}

[Severity: Medium]
Does this exit sequence incorrectly mirror the forward initialization order?
Standard resource teardown typically reverses the initialization sequence to
prevent state corruption or lockups upon driver unbind or runtime suspend.

[ ... ]
> +static void ufs_tegra_mphy_power_off(struct ufs_hba *hba)
> +{
> +	struct ufs_tegra *ufs = ufshcd_get_variant(hba);
> +
> +	phy_power_off(ufs->mphy_l0_rx);
> +	phy_power_off(ufs->mphy_l0_tx);
> +	phy_power_off(ufs->mphy_l1_rx);
> +	phy_power_off(ufs->mphy_l1_tx);
> +}

[Severity: Medium]
Similarly, does this power off sequence execute in exact forward
initialization order instead of reverse?

[ ... ]
> +static int ufs_tegra_pwr_change_notify(struct ufs_hba *hba,
> +				       enum ufs_notify_change_status status,
> +				       struct ufs_pa_layer_attr *dev_req_params)
> +{
[ ... ]
> +	if (dev_req_params->hs_rate == PA_HS_MODE_A ||
> +	    dev_req_params->hs_rate == PA_HS_MODE_B) {
> +		err = clk_set_rate(ufs->phy_clk, UFS_TEGRA_PHY_CLK_HS_RATE_HZ);

[Severity: Medium]
The clk_set_rate() API takes an unsigned long for the rate. Does passing
the 33-bit UFS_TEGRA_PHY_CLK_HS_RATE_HZ literal cause an implicit narrowing
conversion and incorrect clock rate configuration on 32-bit systems?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260909-tegra264-ufs-v1-0-e4a9831702a0@nvidia.com?part=4

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 4/4] scsi: ufs: tegra: Add Tegra264 UFS host controller driver
  2026-09-09 10:41 ` [PATCH 4/4] scsi: ufs: tegra: Add Tegra264 UFS host controller driver Kartik Rajput
  2026-09-09 11:02   ` sashiko-bot
@ 2026-09-09 14:20   ` Uwe Kleine-König
  2026-09-09 16:10     ` Bart Van Assche
  1 sibling, 1 reply; 13+ messages in thread
From: Uwe Kleine-König @ 2026-09-09 14:20 UTC (permalink / raw)
  To: Kartik Rajput
  Cc: Alim Akhtar, Avri Altman, Bart Van Assche, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Thierry Reding,
	Jonathan Hunter, James E.J. Bottomley, Martin K. Petersen,
	Philipp Zabel, Thierry Reding, linux-scsi, devicetree,
	linux-tegra, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 843 bytes --]

Hello,

On Wed, Sep 09, 2026 at 04:11:22PM +0530, Kartik Rajput wrote:
> +#include <linux/bitfield.h>
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/mod_devicetable.h>

Please don't add new instances of includes for
<linux/mod_devicetable.h>.  Either rely on <linux/platform_device.h> to
provide of_device_id (my preferred way), or use <linux/device-id/of.h>
if you want full iwyu.

> +#include <linux/of.h>
> +#include <linux/phy/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/reset.h>
> [...]
> +static const struct of_device_id ufs_tegra_of_match[] = {
> +	{ .compatible = "nvidia,tegra264-ufs", },

No trailing comma before a } please

> +	{}

{ } please (i.e. a space between the braces)

> +};
> +MODULE_DEVICE_TABLE(of, ufs_tegra_of_match);

Best regards
Uwe

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 4/4] scsi: ufs: tegra: Add Tegra264 UFS host controller driver
  2026-09-09 14:20   ` Uwe Kleine-König
@ 2026-09-09 16:10     ` Bart Van Assche
  2026-09-10 11:21       ` Uwe Kleine-König
  0 siblings, 1 reply; 13+ messages in thread
From: Bart Van Assche @ 2026-09-09 16:10 UTC (permalink / raw)
  To: Uwe Kleine-König, Kartik Rajput
  Cc: Alim Akhtar, Avri Altman, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Thierry Reding, Jonathan Hunter,
	James E.J. Bottomley, Martin K. Petersen, Philipp Zabel,
	Thierry Reding, linux-scsi, devicetree, linux-tegra, linux-kernel

On 9/9/26 7:20 AM, Uwe Kleine-König wrote:
>> +	{}
> 
> { } please (i.e. a space between the braces)

The preferred style for Linux kernel code is {} (no space).

Bart.


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 4/4] scsi: ufs: tegra: Add Tegra264 UFS host controller driver
  2026-09-09 16:10     ` Bart Van Assche
@ 2026-09-10 11:21       ` Uwe Kleine-König
  2026-09-10 13:09         ` Bart Van Assche
  0 siblings, 1 reply; 13+ messages in thread
From: Uwe Kleine-König @ 2026-09-10 11:21 UTC (permalink / raw)
  To: Bart Van Assche
  Cc: Kartik Rajput, Alim Akhtar, Avri Altman, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Thierry Reding,
	Jonathan Hunter, James E.J. Bottomley, Martin K. Petersen,
	Philipp Zabel, Thierry Reding, linux-scsi, devicetree,
	linux-tegra, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 1024 bytes --]

On Wed, Sep 09, 2026 at 09:10:26AM -0700, Bart Van Assche wrote:
> On 9/9/26 7:20 AM, Uwe Kleine-König wrote:
> > > +	{}
> > 
> > { } please (i.e. a space between the braces)
> 
> The preferred style for Linux kernel code is {} (no space).

Looking at the style in of_device_id arrays in next-20260909:

$ git grep -l of_device_id | xargs -n 1 perl -g -n -e 'print "$1\n" if m/of_device_id\s*[a-zA-Z_0-9]*\[\]\s*=\s*{(?:\s*{[^}]*},\s*({\s*}))/' | sort | uniq -c
      1 	}
      1 {
      3 {  }
   1410 { }
   1098 {}

and extending to *_device_id:

$ git grep -l device_id | xargs -n 1 perl -g -n -e 'print "$1\n" if m/device_id\s*[a-zA-Z_0-9]*\[\]\s*=\s*{(?:\s*{[^}]*},\s*({\s*}))/' | sort | uniq -c
      2 	}
      2 {
      7 {  }
   2492 { }
   1304 {}

So { } is slightly more usual and also better matches the spaces used in

	{ .compatible = "nvidia,tegra264-ufs", },

(but I agree, the latter might be subjective).

What makes you claim that {} is preferred?

Best regards
Uwe

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 4/4] scsi: ufs: tegra: Add Tegra264 UFS host controller driver
  2026-09-10 11:21       ` Uwe Kleine-König
@ 2026-09-10 13:09         ` Bart Van Assche
  2026-09-10 13:52           ` Uwe Kleine-König
  0 siblings, 1 reply; 13+ messages in thread
From: Bart Van Assche @ 2026-09-10 13:09 UTC (permalink / raw)
  To: Uwe Kleine-König
  Cc: Kartik Rajput, Alim Akhtar, Avri Altman, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Thierry Reding,
	Jonathan Hunter, James E.J. Bottomley, Martin K. Petersen,
	Philipp Zabel, Thierry Reding, linux-scsi, devicetree,
	linux-tegra, linux-kernel

On 9/10/26 4:21 AM, Uwe Kleine-König wrote:
> What makes you claim that {} is preferred?

There are many more occurrences of " = {};" (about 7000) in the Linux
kernel than of " = { };" (about 1500). Additionally, clang-format
changes any occurrence of " = { };" into " = {};".

Thanks,

Bart.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 4/4] scsi: ufs: tegra: Add Tegra264 UFS host controller driver
  2026-09-10 13:09         ` Bart Van Assche
@ 2026-09-10 13:52           ` Uwe Kleine-König
  0 siblings, 0 replies; 13+ messages in thread
From: Uwe Kleine-König @ 2026-09-10 13:52 UTC (permalink / raw)
  To: Bart Van Assche
  Cc: Kartik Rajput, Alim Akhtar, Avri Altman, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Thierry Reding,
	Jonathan Hunter, James E.J. Bottomley, Martin K. Petersen,
	Philipp Zabel, Thierry Reding, linux-scsi, devicetree,
	linux-tegra, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 951 bytes --]

Hello Bart,

On Thu, Sep 10, 2026 at 06:09:30AM -0700, Bart Van Assche wrote:
> On 9/10/26 4:21 AM, Uwe Kleine-König wrote:
> > What makes you claim that {} is preferred?
> 
> There are many more occurrences of " = {};" (about 7000) in the Linux
> kernel than of " = { };" (about 1500). Additionally, clang-format
> changes any occurrence of " = { };" into " = {};".

clang-format does this due to

	SpaceInEmptyParentheses: false

in .clang-format which I claim we have due to prefering no space between
() for function calls. It seems only newer clang-format (starting with
version 22) can configure that individually using SpaceInEmptyBraces.

And IMHO my statistic is more relevant because we're not talking about
`= {};` or `= { };`.

But I guess this is all subjective. Having said that I feel offended
when seeing "= {};" and would ask to add a space there, too, when
spotting that during a review.

Best regards
Uwe

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 1/4] dt-bindings: ufs: Add nvidia,tegra264-ufs
  2026-09-09 10:41 ` [PATCH 1/4] dt-bindings: ufs: Add nvidia,tegra264-ufs Kartik Rajput
  2026-09-09 10:51   ` sashiko-bot
@ 2026-09-13  8:40   ` Krzysztof Kozlowski
  1 sibling, 0 replies; 13+ messages in thread
From: Krzysztof Kozlowski @ 2026-09-13  8:40 UTC (permalink / raw)
  To: Kartik Rajput
  Cc: Alim Akhtar, Avri Altman, Bart Van Assche, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Thierry Reding,
	Jonathan Hunter, James E.J. Bottomley, Martin K. Petersen,
	Philipp Zabel, Thierry Reding, linux-scsi, devicetree,
	linux-tegra, linux-kernel

On Wed, Sep 09, 2026 at 04:11:19PM +0530, Kartik Rajput wrote:
> +  clocks:
> +    items:
> +      - description: UFS host controller functional clock
> +      - description: UFS host controller divider clock
> +      - description: UFS reference clock (PLLREFUFS output)
> +      - description: UFS device-side reference clock
> +      - description: M-PHY reference clock (UPHY0 PLL4 digital output)
> +
> +  clock-names:
> +    items:
> +      - const: ufs

core? Names equal to block name are not really useful

> +      - const: div
> +      - const: ref
> +      - const: ref-dev
> +      - const: phy

Shouldn't the phy take its reference clock?

> +
> +  resets:
> +    items:
> +      - description: UFS host controller reset
> +      - description: UFS host controller AXI-master reset
> +      - description: UFS host controller low-power sequencer reset
> +
> +  reset-names:
> +    items:
> +      - const: ufs
> +      - const: axi
> +      - const: lp
> +
> +  phys:
> +    items:
> +      - description: M-PHY lane 0 transmit
> +      - description: M-PHY lane 0 receive
> +      - description: M-PHY lane 1 transmit
> +      - description: M-PHY lane 1 receive
> +
> +  phy-names:
> +    items:
> +      - const: mphy-l0-tx
> +      - const: mphy-l0-rx
> +      - const: mphy-l1-tx
> +      - const: mphy-l1-rx
> +
> +  iommus:
> +    maxItems: 1
> +
> +  dma-coherent: true
> +
> +required:
> +  - compatible
> +  - reg
> +  - reg-names
> +  - clocks
> +  - clock-names
> +  - resets
> +  - reset-names
> +  - phys
> +  - phy-names
> +  - iommus
> +  - dma-coherent
> +
> +allOf:
> +  - $ref: ufs-common.yaml
> +
> +unevaluatedProperties: false
> +
> +examples:
> +  - |
> +    #include <dt-bindings/clock/nvidia,tegra264.h>
> +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> +    #include <dt-bindings/phy/nvidia,tegra264-mphy.h>

You need to decouple dependencies. Otherwise how is this supposed to be
checked with tools? If applied, you just broke maintainer's tree.


> +    #include <dt-bindings/reset/nvidia,tegra264.h>

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2026-09-13  8:40 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-09 10:41 [PATCH 0/4] Add UFS host controller support for NVIDIA Tegra264 Kartik Rajput
2026-09-09 10:41 ` [PATCH 1/4] dt-bindings: ufs: Add nvidia,tegra264-ufs Kartik Rajput
2026-09-09 10:51   ` sashiko-bot
2026-09-13  8:40   ` Krzysztof Kozlowski
2026-09-09 10:41 ` [PATCH 2/4] scsi: ufs: Add UIC DEBUGSAVECONFIGTIME attribute and its field masks Kartik Rajput
2026-09-09 10:41 ` [PATCH 3/4] scsi: ufs: hisi: Use VS_DEBUGSAVECONFIGTIME instead of a literal address Kartik Rajput
2026-09-09 10:41 ` [PATCH 4/4] scsi: ufs: tegra: Add Tegra264 UFS host controller driver Kartik Rajput
2026-09-09 11:02   ` sashiko-bot
2026-09-09 14:20   ` Uwe Kleine-König
2026-09-09 16:10     ` Bart Van Assche
2026-09-10 11:21       ` Uwe Kleine-König
2026-09-10 13:09         ` Bart Van Assche
2026-09-10 13:52           ` Uwe Kleine-König

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox