mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v3 0/2] gpu/drm: tegra: add DSI support for Tegra20/Tegra30
@ 2026-01-25 13:13 Svyatoslav Ryhel
  2026-01-25 13:13 ` [PATCH v3 1/2] gpu/drm: tegra: dsi: add " Svyatoslav Ryhel
                   ` (3 more replies)
  0 siblings, 4 replies; 9+ messages in thread
From: Svyatoslav Ryhel @ 2026-01-25 13:13 UTC (permalink / raw)
  To: Thierry Reding, Mikko Perttunen, David Airlie, Simona Vetter,
	Jonathan Hunter, Diogo Ivo, Svyatoslav Ryhel
  Cc: dri-devel, linux-tegra, linux-kernel

Tegra20/Tegra30 DSI is quite similar to Tegra114+ apart MIPI calibration
logic and clocks. With a few minor tweaks, existing tegra DSI driver
should work on Tegra20/Tegra30 devices just fine. Tested on
Motorola Atrix 4G (T20) and ASUS VivoTab RT TF600T (T30).

This patchset depends on Tegra20/Tegra30 CSI bringup since both share
MIPI calibration logic. Ideally these patches should be picked after
CSI bringup but they will not break anything even if picked before
CSI patches.

---
Changes in v2:
- removed all MIPI calibration, it is handled within CSI bringup
- added per-soc structures into of_match
- added fix for hang caused by register access with uninited hw

Changes in v3:
- switched from version DSI to boolean flags
- added comment regarding Tegra30 clock configuration
- commits were picked:
  "clk: tegra20: reparent dsi clock to pll_d_out0"
  "ARM: tegra: adjust DSI nodes for Tegra20/Tegra30"
- commit adapted to recent DSI changes:
  "gpu/drm: tegra: dsi: move prepare function at the top of encoder
    enable" > "gpu/drm: tegra: dsi: re-add clear enable register if
    DSI was powered by bootloader"
---

Svyatoslav Ryhel (2):
  gpu/drm: tegra: dsi: add support for Tegra20/Tegra30
  gpu/drm: tegra: dsi: re-add clear enable register if DSI was powered
    by bootloader

 drivers/gpu/drm/tegra/drm.c |   2 +
 drivers/gpu/drm/tegra/dsi.c | 116 ++++++++++++++++++++++++++----------
 drivers/gpu/drm/tegra/dsi.h |  10 ++++
 3 files changed, 97 insertions(+), 31 deletions(-)

-- 
2.51.0


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

* [PATCH v3 1/2] gpu/drm: tegra: dsi: add support for Tegra20/Tegra30
  2026-01-25 13:13 [PATCH v3 0/2] gpu/drm: tegra: add DSI support for Tegra20/Tegra30 Svyatoslav Ryhel
@ 2026-01-25 13:13 ` Svyatoslav Ryhel
  2026-03-05 15:21   ` Svyatoslav Ryhel
  2026-01-25 13:13 ` [PATCH v3 2/2] gpu/drm: tegra: dsi: re-add clear enable register if DSI was powered by bootloader Svyatoslav Ryhel
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 9+ messages in thread
From: Svyatoslav Ryhel @ 2026-01-25 13:13 UTC (permalink / raw)
  To: Thierry Reding, Mikko Perttunen, David Airlie, Simona Vetter,
	Jonathan Hunter, Diogo Ivo, Svyatoslav Ryhel
  Cc: dri-devel, linux-tegra, linux-kernel

Tegra20 and Tegra30 are fully compatible with existing Tegra DSI driver
apart from clock configuration and pad calibration which are addressed by
this patch.

Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
 drivers/gpu/drm/tegra/drm.c |   2 +
 drivers/gpu/drm/tegra/dsi.c | 107 +++++++++++++++++++++++++-----------
 drivers/gpu/drm/tegra/dsi.h |  10 ++++
 3 files changed, 88 insertions(+), 31 deletions(-)

diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c
index 4596073fe28f..5d64cd57e764 100644
--- a/drivers/gpu/drm/tegra/drm.c
+++ b/drivers/gpu/drm/tegra/drm.c
@@ -1359,10 +1359,12 @@ static SIMPLE_DEV_PM_OPS(host1x_drm_pm_ops, host1x_drm_suspend,
 
 static const struct of_device_id host1x_drm_subdevs[] = {
 	{ .compatible = "nvidia,tegra20-dc", },
+	{ .compatible = "nvidia,tegra20-dsi", },
 	{ .compatible = "nvidia,tegra20-hdmi", },
 	{ .compatible = "nvidia,tegra20-gr2d", },
 	{ .compatible = "nvidia,tegra20-gr3d", },
 	{ .compatible = "nvidia,tegra30-dc", },
+	{ .compatible = "nvidia,tegra30-dsi", },
 	{ .compatible = "nvidia,tegra30-hdmi", },
 	{ .compatible = "nvidia,tegra30-gr2d", },
 	{ .compatible = "nvidia,tegra30-gr3d", },
diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c
index 02a661d86751..ebc78dceaee6 100644
--- a/drivers/gpu/drm/tegra/dsi.c
+++ b/drivers/gpu/drm/tegra/dsi.c
@@ -53,6 +53,11 @@ to_dsi_state(struct drm_connector_state *state)
 	return container_of(state, struct tegra_dsi_state, base);
 }
 
+struct tegra_dsi_config {
+	bool has_multiple_pad_controls;
+	bool has_mux_parent_clk;
+};
+
 struct tegra_dsi {
 	struct host1x_client client;
 	struct tegra_output output;
@@ -82,6 +87,8 @@ struct tegra_dsi {
 	/* for ganged-mode support */
 	struct tegra_dsi *master;
 	struct tegra_dsi *slave;
+
+	const struct tegra_dsi_config *config;
 };
 
 static inline struct tegra_dsi *
@@ -663,39 +670,46 @@ static int tegra_dsi_pad_enable(struct tegra_dsi *dsi)
 {
 	u32 value;
 
-	value = DSI_PAD_CONTROL_VS1_PULLDN(0) | DSI_PAD_CONTROL_VS1_PDIO(0);
-	tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_0);
+	if (dsi->config->has_multiple_pad_controls) {
+		/*
+		 * XXX Is this still needed? The module reset is deasserted right
+		 * before this function is called.
+		 */
+		tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_0);
+		tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_1);
+		tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_2);
+		tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_3);
+		tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_4);
+
+		value = DSI_PAD_CONTROL_VS1_PULLDN(0) | DSI_PAD_CONTROL_VS1_PDIO(0);
+		tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_0);
+
+		value = DSI_PAD_SLEW_UP(0x7) | DSI_PAD_SLEW_DN(0x7) |
+			DSI_PAD_LP_UP(0x1) | DSI_PAD_LP_DN(0x1) |
+			DSI_PAD_OUT_CLK(0x0);
+		tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_2);
+
+		value = DSI_PAD_PREEMP_PD_CLK(0x3) | DSI_PAD_PREEMP_PU_CLK(0x3) |
+			DSI_PAD_PREEMP_PD(0x03) | DSI_PAD_PREEMP_PU(0x3);
+		tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_3);
+	} else {
+		value = DSI_PAD_CONTROL_LPUPADJ(0x1) | DSI_PAD_CONTROL_LPDNADJ(0x1) |
+			DSI_PAD_CONTROL_PREEMP_EN(0x1) | DSI_PAD_CONTROL_SLEWDNADJ(0x6) |
+			DSI_PAD_CONTROL_SLEWUPADJ(0x6) | DSI_PAD_CONTROL_PDIO(0) |
+			DSI_PAD_CONTROL_PDIO_CLK(0) | DSI_PAD_CONTROL_PULLDN_ENAB(0);
+		tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_0);
+	}
 
 	return 0;
 }
 
 static int tegra_dsi_pad_calibrate(struct tegra_dsi *dsi)
 {
-	u32 value;
 	int err;
 
-	/*
-	 * XXX Is this still needed? The module reset is deasserted right
-	 * before this function is called.
-	 */
-	tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_0);
-	tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_1);
-	tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_2);
-	tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_3);
-	tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_4);
-
 	/* start calibration */
 	tegra_dsi_pad_enable(dsi);
 
-	value = DSI_PAD_SLEW_UP(0x7) | DSI_PAD_SLEW_DN(0x7) |
-		DSI_PAD_LP_UP(0x1) | DSI_PAD_LP_DN(0x1) |
-		DSI_PAD_OUT_CLK(0x0);
-	tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_2);
-
-	value = DSI_PAD_PREEMP_PD_CLK(0x3) | DSI_PAD_PREEMP_PU_CLK(0x3) |
-		DSI_PAD_PREEMP_PD(0x03) | DSI_PAD_PREEMP_PU(0x3);
-	tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_3);
-
 	err = tegra_mipi_start_calibration(dsi->mipi);
 	if (err < 0)
 		return err;
@@ -1568,6 +1582,7 @@ static int tegra_dsi_probe(struct platform_device *pdev)
 	if (!dsi)
 		return -ENOMEM;
 
+	dsi->config = of_device_get_match_data(&pdev->dev);
 	dsi->output.dev = dsi->dev = &pdev->dev;
 	dsi->video_fifo_depth = 1920;
 	dsi->host_fifo_depth = 64;
@@ -1606,7 +1621,7 @@ static int tegra_dsi_probe(struct platform_device *pdev)
 		goto remove;
 	}
 
-	dsi->clk_lp = devm_clk_get(&pdev->dev, "lp");
+	dsi->clk_lp = devm_clk_get_optional(&pdev->dev, "lp");
 	if (IS_ERR(dsi->clk_lp)) {
 		err = dev_err_probe(&pdev->dev, PTR_ERR(dsi->clk_lp),
 				    "cannot get low-power clock\n");
@@ -1627,10 +1642,12 @@ static int tegra_dsi_probe(struct platform_device *pdev)
 		goto remove;
 	}
 
-	err = tegra_dsi_setup_clocks(dsi);
-	if (err < 0) {
-		dev_err(&pdev->dev, "cannot setup clocks\n");
-		goto remove;
+	if (dsi->config->has_mux_parent_clk) {
+		err = tegra_dsi_setup_clocks(dsi);
+		if (err < 0) {
+			dev_err(&pdev->dev, "cannot setup clocks\n");
+			goto remove;
+		}
 	}
 
 	dsi->regs = devm_platform_ioremap_resource(pdev, 0);
@@ -1694,11 +1711,39 @@ static void tegra_dsi_remove(struct platform_device *pdev)
 	tegra_mipi_free(dsi->mipi);
 }
 
+static const struct tegra_dsi_config tegra20_dsi_config = {
+	.has_multiple_pad_controls = false,
+	.has_mux_parent_clk = false,
+};
+
+/*
+ * Tegra30 allows DSIA/DSIB to be muxed to either PLL_D or PLL_D2; this is
+ * simply not modeled in the clock driver yet. If this functionality is
+ * required, the has_mux_parent_clk flag can be set to true once the clock
+ * driver is patched.
+ */
+static const struct tegra_dsi_config tegra30_dsi_config = {
+	.has_multiple_pad_controls = false,
+	.has_mux_parent_clk = false,
+};
+
+static const struct tegra_dsi_config tegra114_dsi_config = {
+	.has_multiple_pad_controls = true,
+	.has_mux_parent_clk = true,
+};
+
+static const struct tegra_dsi_config tegra124_dsi_config = {
+	.has_multiple_pad_controls = true,
+	.has_mux_parent_clk = false,
+};
+
 static const struct of_device_id tegra_dsi_of_match[] = {
-	{ .compatible = "nvidia,tegra210-dsi", },
-	{ .compatible = "nvidia,tegra132-dsi", },
-	{ .compatible = "nvidia,tegra124-dsi", },
-	{ .compatible = "nvidia,tegra114-dsi", },
+	{ .compatible = "nvidia,tegra210-dsi", .data = &tegra124_dsi_config },
+	{ .compatible = "nvidia,tegra132-dsi", .data = &tegra124_dsi_config },
+	{ .compatible = "nvidia,tegra124-dsi", .data = &tegra124_dsi_config },
+	{ .compatible = "nvidia,tegra114-dsi", .data = &tegra114_dsi_config },
+	{ .compatible = "nvidia,tegra30-dsi", .data = &tegra30_dsi_config },
+	{ .compatible = "nvidia,tegra20-dsi", .data = &tegra20_dsi_config },
 	{ },
 };
 MODULE_DEVICE_TABLE(of, tegra_dsi_of_match);
diff --git a/drivers/gpu/drm/tegra/dsi.h b/drivers/gpu/drm/tegra/dsi.h
index f39594e65e97..d834ac0c47ab 100644
--- a/drivers/gpu/drm/tegra/dsi.h
+++ b/drivers/gpu/drm/tegra/dsi.h
@@ -95,6 +95,16 @@
 #define DSI_TALLY_LRX(x)		(((x) & 0xff) <<  8)
 #define DSI_TALLY_HTX(x)		(((x) & 0xff) <<  0)
 #define DSI_PAD_CONTROL_0		0x4b
+/* Tegra20/Tegra30 */
+#define DSI_PAD_CONTROL_PULLDN_ENAB(x)	(((x) & 0x1) << 28)
+#define DSI_PAD_CONTROL_SLEWUPADJ(x)	(((x) & 0x7) << 24)
+#define DSI_PAD_CONTROL_SLEWDNADJ(x)	(((x) & 0x7) << 20)
+#define DSI_PAD_CONTROL_PREEMP_EN(x)	(((x) & 0x1) << 19)
+#define DSI_PAD_CONTROL_PDIO_CLK(x)	(((x) & 0x1) << 18)
+#define DSI_PAD_CONTROL_PDIO(x)		(((x) & 0x3) << 16)
+#define DSI_PAD_CONTROL_LPUPADJ(x)	(((x) & 0x3) << 14)
+#define DSI_PAD_CONTROL_LPDNADJ(x)	(((x) & 0x3) << 12)
+/* Tegra114+ */
 #define DSI_PAD_CONTROL_VS1_PDIO(x)	(((x) & 0xf) <<  0)
 #define DSI_PAD_CONTROL_VS1_PDIO_CLK	(1 <<  8)
 #define DSI_PAD_CONTROL_VS1_PULLDN(x)	(((x) & 0xf) << 16)
-- 
2.51.0


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

* [PATCH v3 2/2] gpu/drm: tegra: dsi: re-add clear enable register if DSI was powered by bootloader
  2026-01-25 13:13 [PATCH v3 0/2] gpu/drm: tegra: add DSI support for Tegra20/Tegra30 Svyatoslav Ryhel
  2026-01-25 13:13 ` [PATCH v3 1/2] gpu/drm: tegra: dsi: add " Svyatoslav Ryhel
@ 2026-01-25 13:13 ` Svyatoslav Ryhel
  2026-01-26  1:19 ` [PATCH v3 0/2] gpu/drm: tegra: add DSI support for Tegra20/Tegra30 Mikko Perttunen
  2026-03-02  7:57 ` Svyatoslav Ryhel
  3 siblings, 0 replies; 9+ messages in thread
From: Svyatoslav Ryhel @ 2026-01-25 13:13 UTC (permalink / raw)
  To: Thierry Reding, Mikko Perttunen, David Airlie, Simona Vetter,
	Jonathan Hunter, Diogo Ivo, Svyatoslav Ryhel
  Cc: dri-devel, linux-tegra, linux-kernel

Original commit b22fd0b9639e ("drm/tegra: dsi: Clear enable register if
powered by bootloader") was added to address the issue of DSI being in an
unknown state after the bootloader, ensuring correct panel configuration.
This worked fairly well under the assumption that the bootloader had set
up DSI; however, in cases where it did not, the device would hang because
a DSI read was called before the DSI hardware was ready.

Removing this workaround results in the issue described in the original
fix: the panel initialization sequence fails and the panel gets stuck in
an undefined state. This is especially noticeable with command mode panels

In order to properly address this issue, the original workaround is
restored and placed after the DSI hardware is prepared for R/W operations.
This fixes behavior for both cases: where DSI is set by the bootloader and
where DSI is untouched.

I have tested this change on Tegra20 (Motorola Atrix 4G),
Tegra114 (NVIDIA Tegra Note 7 and ASUS Transformer Pad TF701T), and
Tegra124 (Xiaomi Mi Pad) with U-Boot, using both bootloader-initialized
DSI and untouched DSI.

Fixes: b22fd0b9639e ("drm/tegra: dsi: Clear enable register if powered by bootloader")
Fixes: 660b299bed2a ("Revert "drm/tegra: dsi: Clear enable register if powered by bootloader"")

Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
 drivers/gpu/drm/tegra/dsi.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c
index ebc78dceaee6..e499822b6030 100644
--- a/drivers/gpu/drm/tegra/dsi.c
+++ b/drivers/gpu/drm/tegra/dsi.c
@@ -934,6 +934,15 @@ static void tegra_dsi_encoder_enable(struct drm_encoder *encoder)
 		return;
 	}
 
+	/* If the bootloader enabled DSI it needs to be disabled
+	 * in order for the panel initialization commands to be
+	 * properly sent.
+	 */
+	value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
+
+	if (value & DSI_POWER_CONTROL_ENABLE)
+		tegra_dsi_disable(dsi);
+
 	state = tegra_dsi_get_state(dsi);
 
 	tegra_dsi_set_timeout(dsi, state->bclk, state->vrefresh);
-- 
2.51.0


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

* Re: [PATCH v3 0/2] gpu/drm: tegra: add DSI support for Tegra20/Tegra30
  2026-01-25 13:13 [PATCH v3 0/2] gpu/drm: tegra: add DSI support for Tegra20/Tegra30 Svyatoslav Ryhel
  2026-01-25 13:13 ` [PATCH v3 1/2] gpu/drm: tegra: dsi: add " Svyatoslav Ryhel
  2026-01-25 13:13 ` [PATCH v3 2/2] gpu/drm: tegra: dsi: re-add clear enable register if DSI was powered by bootloader Svyatoslav Ryhel
@ 2026-01-26  1:19 ` Mikko Perttunen
  2026-03-02  7:57 ` Svyatoslav Ryhel
  3 siblings, 0 replies; 9+ messages in thread
From: Mikko Perttunen @ 2026-01-26  1:19 UTC (permalink / raw)
  To: Thierry Reding, David Airlie, Simona Vetter, Jonathan Hunter,
	Diogo Ivo, Svyatoslav Ryhel, Svyatoslav Ryhel
  Cc: dri-devel, linux-tegra, linux-kernel

On Sunday, January 25, 2026 10:13 PM Svyatoslav Ryhel wrote:
> Tegra20/Tegra30 DSI is quite similar to Tegra114+ apart MIPI calibration
> logic and clocks. With a few minor tweaks, existing tegra DSI driver
> should work on Tegra20/Tegra30 devices just fine. Tested on
> Motorola Atrix 4G (T20) and ASUS VivoTab RT TF600T (T30).
> 
> This patchset depends on Tegra20/Tegra30 CSI bringup since both share
> MIPI calibration logic. Ideally these patches should be picked after
> CSI bringup but they will not break anything even if picked before
> CSI patches.
> 
> ---
> Changes in v2:
> - removed all MIPI calibration, it is handled within CSI bringup
> - added per-soc structures into of_match
> - added fix for hang caused by register access with uninited hw
> 
> Changes in v3:
> - switched from version DSI to boolean flags
> - added comment regarding Tegra30 clock configuration
> - commits were picked:
>   "clk: tegra20: reparent dsi clock to pll_d_out0"
>   "ARM: tegra: adjust DSI nodes for Tegra20/Tegra30"
> - commit adapted to recent DSI changes:
>   "gpu/drm: tegra: dsi: move prepare function at the top of encoder
>     enable" > "gpu/drm: tegra: dsi: re-add clear enable register if
>     DSI was powered by bootloader"
> ---
> 
> Svyatoslav Ryhel (2):
>   gpu/drm: tegra: dsi: add support for Tegra20/Tegra30
>   gpu/drm: tegra: dsi: re-add clear enable register if DSI was powered
>     by bootloader
> 
>  drivers/gpu/drm/tegra/drm.c |   2 +
>  drivers/gpu/drm/tegra/dsi.c | 116 ++++++++++++++++++++++++++----------
>  drivers/gpu/drm/tegra/dsi.h |  10 ++++
>  3 files changed, 97 insertions(+), 31 deletions(-)
> 
> 

The subject prefix for both patches should be 'drm/tegra: ...', and for patch 2, the Fixes trailers should not have the separating empty line from Signed-off-by. Otherwise

Reviewed-by: Mikko Perttunen <mperttunen@nvidia.com>

Maybe Thierry can fix those while applying?




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

* Re: [PATCH v3 0/2] gpu/drm: tegra: add DSI support for Tegra20/Tegra30
  2026-01-25 13:13 [PATCH v3 0/2] gpu/drm: tegra: add DSI support for Tegra20/Tegra30 Svyatoslav Ryhel
                   ` (2 preceding siblings ...)
  2026-01-26  1:19 ` [PATCH v3 0/2] gpu/drm: tegra: add DSI support for Tegra20/Tegra30 Mikko Perttunen
@ 2026-03-02  7:57 ` Svyatoslav Ryhel
  3 siblings, 0 replies; 9+ messages in thread
From: Svyatoslav Ryhel @ 2026-03-02  7:57 UTC (permalink / raw)
  To: Thierry Reding, Mikko Perttunen, David Airlie, Simona Vetter,
	Jonathan Hunter, Diogo Ivo, Svyatoslav Ryhel, Thierry Reding
  Cc: dri-devel, linux-tegra, linux-kernel

нд, 25 січ. 2026 р. о 15:13 Svyatoslav Ryhel <clamor95@gmail.com> пише:
>
> Tegra20/Tegra30 DSI is quite similar to Tegra114+ apart MIPI calibration
> logic and clocks. With a few minor tweaks, existing tegra DSI driver
> should work on Tegra20/Tegra30 devices just fine. Tested on
> Motorola Atrix 4G (T20) and ASUS VivoTab RT TF600T (T30).
>
> This patchset depends on Tegra20/Tegra30 CSI bringup since both share
> MIPI calibration logic. Ideally these patches should be picked after
> CSI bringup but they will not break anything even if picked before
> CSI patches.
>
> ---
> Changes in v2:
> - removed all MIPI calibration, it is handled within CSI bringup
> - added per-soc structures into of_match
> - added fix for hang caused by register access with uninited hw
>
> Changes in v3:
> - switched from version DSI to boolean flags
> - added comment regarding Tegra30 clock configuration
> - commits were picked:
>   "clk: tegra20: reparent dsi clock to pll_d_out0"
>   "ARM: tegra: adjust DSI nodes for Tegra20/Tegra30"
> - commit adapted to recent DSI changes:
>   "gpu/drm: tegra: dsi: move prepare function at the top of encoder
>     enable" > "gpu/drm: tegra: dsi: re-add clear enable register if
>     DSI was powered by bootloader"
> ---
>
> Svyatoslav Ryhel (2):
>   gpu/drm: tegra: dsi: add support for Tegra20/Tegra30
>   gpu/drm: tegra: dsi: re-add clear enable register if DSI was powered
>     by bootloader
>
>  drivers/gpu/drm/tegra/drm.c |   2 +
>  drivers/gpu/drm/tegra/dsi.c | 116 ++++++++++++++++++++++++++----------
>  drivers/gpu/drm/tegra/dsi.h |  10 ++++
>  3 files changed, 97 insertions(+), 31 deletions(-)
>

Hello Thierry!

May these patches be picked if everyone is fine with them? If you like
I can amend and resend them with Mikko's suggestions applied.

Best regards,
Svyatoslav R.

> --
> 2.51.0
>

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

* Re: [PATCH v3 1/2] gpu/drm: tegra: dsi: add support for Tegra20/Tegra30
  2026-01-25 13:13 ` [PATCH v3 1/2] gpu/drm: tegra: dsi: add " Svyatoslav Ryhel
@ 2026-03-05 15:21   ` Svyatoslav Ryhel
  2026-03-05 15:50     ` Svyatoslav Ryhel
  0 siblings, 1 reply; 9+ messages in thread
From: Svyatoslav Ryhel @ 2026-03-05 15:21 UTC (permalink / raw)
  To: Thierry Reding, Mikko Perttunen, David Airlie, Simona Vetter,
	Jonathan Hunter, Diogo Ivo, Svyatoslav Ryhel
  Cc: dri-devel, linux-tegra, linux-kernel

нд, 25 січ. 2026 р. о 15:13 Svyatoslav Ryhel <clamor95@gmail.com> пише:
>
> Tegra20 and Tegra30 are fully compatible with existing Tegra DSI driver
> apart from clock configuration and pad calibration which are addressed by
> this patch.
>
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> ---
>  drivers/gpu/drm/tegra/drm.c |   2 +
>  drivers/gpu/drm/tegra/dsi.c | 107 +++++++++++++++++++++++++-----------
>  drivers/gpu/drm/tegra/dsi.h |  10 ++++
>  3 files changed, 88 insertions(+), 31 deletions(-)
>
> diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c
> index 4596073fe28f..5d64cd57e764 100644
> --- a/drivers/gpu/drm/tegra/drm.c
> +++ b/drivers/gpu/drm/tegra/drm.c
> @@ -1359,10 +1359,12 @@ static SIMPLE_DEV_PM_OPS(host1x_drm_pm_ops, host1x_drm_suspend,
>
>  static const struct of_device_id host1x_drm_subdevs[] = {
>         { .compatible = "nvidia,tegra20-dc", },
> +       { .compatible = "nvidia,tegra20-dsi", },
>         { .compatible = "nvidia,tegra20-hdmi", },
>         { .compatible = "nvidia,tegra20-gr2d", },
>         { .compatible = "nvidia,tegra20-gr3d", },
>         { .compatible = "nvidia,tegra30-dc", },
> +       { .compatible = "nvidia,tegra30-dsi", },
>         { .compatible = "nvidia,tegra30-hdmi", },
>         { .compatible = "nvidia,tegra30-gr2d", },
>         { .compatible = "nvidia,tegra30-gr3d", },
> diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c
> index 02a661d86751..ebc78dceaee6 100644
> --- a/drivers/gpu/drm/tegra/dsi.c
> +++ b/drivers/gpu/drm/tegra/dsi.c
> @@ -53,6 +53,11 @@ to_dsi_state(struct drm_connector_state *state)
>         return container_of(state, struct tegra_dsi_state, base);
>  }
>
> +struct tegra_dsi_config {
> +       bool has_multiple_pad_controls;
> +       bool has_mux_parent_clk;
> +};
> +
>  struct tegra_dsi {
>         struct host1x_client client;
>         struct tegra_output output;
> @@ -82,6 +87,8 @@ struct tegra_dsi {
>         /* for ganged-mode support */
>         struct tegra_dsi *master;
>         struct tegra_dsi *slave;
> +
> +       const struct tegra_dsi_config *config;
>  };
>
>  static inline struct tegra_dsi *
> @@ -663,39 +670,46 @@ static int tegra_dsi_pad_enable(struct tegra_dsi *dsi)
>  {
>         u32 value;
>
> -       value = DSI_PAD_CONTROL_VS1_PULLDN(0) | DSI_PAD_CONTROL_VS1_PDIO(0);
> -       tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_0);
> +       if (dsi->config->has_multiple_pad_controls) {
> +               /*
> +                * XXX Is this still needed? The module reset is deasserted right
> +                * before this function is called.
> +                */
> +               tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_0);
> +               tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_1);
> +               tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_2);
> +               tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_3);
> +               tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_4);
> +
> +               value = DSI_PAD_CONTROL_VS1_PULLDN(0) | DSI_PAD_CONTROL_VS1_PDIO(0);
> +               tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_0);
> +
> +               value = DSI_PAD_SLEW_UP(0x7) | DSI_PAD_SLEW_DN(0x7) |
> +                       DSI_PAD_LP_UP(0x1) | DSI_PAD_LP_DN(0x1) |
> +                       DSI_PAD_OUT_CLK(0x0);
> +               tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_2);
> +
> +               value = DSI_PAD_PREEMP_PD_CLK(0x3) | DSI_PAD_PREEMP_PU_CLK(0x3) |
> +                       DSI_PAD_PREEMP_PD(0x03) | DSI_PAD_PREEMP_PU(0x3);
> +               tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_3);
> +       } else {
> +               value = DSI_PAD_CONTROL_LPUPADJ(0x1) | DSI_PAD_CONTROL_LPDNADJ(0x1) |
> +                       DSI_PAD_CONTROL_PREEMP_EN(0x1) | DSI_PAD_CONTROL_SLEWDNADJ(0x6) |
> +                       DSI_PAD_CONTROL_SLEWUPADJ(0x6) | DSI_PAD_CONTROL_PDIO(0) |
> +                       DSI_PAD_CONTROL_PDIO_CLK(0) | DSI_PAD_CONTROL_PULLDN_ENAB(0);
> +               tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_0);
> +       }
>
>         return 0;
>  }
>
>  static int tegra_dsi_pad_calibrate(struct tegra_dsi *dsi)
>  {
> -       u32 value;
>         int err;
>
> -       /*
> -        * XXX Is this still needed? The module reset is deasserted right
> -        * before this function is called.
> -        */
> -       tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_0);
> -       tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_1);
> -       tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_2);
> -       tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_3);
> -       tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_4);
> -
>         /* start calibration */
>         tegra_dsi_pad_enable(dsi);
>
> -       value = DSI_PAD_SLEW_UP(0x7) | DSI_PAD_SLEW_DN(0x7) |
> -               DSI_PAD_LP_UP(0x1) | DSI_PAD_LP_DN(0x1) |
> -               DSI_PAD_OUT_CLK(0x0);
> -       tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_2);
> -
> -       value = DSI_PAD_PREEMP_PD_CLK(0x3) | DSI_PAD_PREEMP_PU_CLK(0x3) |
> -               DSI_PAD_PREEMP_PD(0x03) | DSI_PAD_PREEMP_PU(0x3);
> -       tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_3);
> -
>         err = tegra_mipi_start_calibration(dsi->mipi);
>         if (err < 0)
>                 return err;
> @@ -1568,6 +1582,7 @@ static int tegra_dsi_probe(struct platform_device *pdev)
>         if (!dsi)
>                 return -ENOMEM;
>
> +       dsi->config = of_device_get_match_data(&pdev->dev);
>         dsi->output.dev = dsi->dev = &pdev->dev;
>         dsi->video_fifo_depth = 1920;
>         dsi->host_fifo_depth = 64;
> @@ -1606,7 +1621,7 @@ static int tegra_dsi_probe(struct platform_device *pdev)
>                 goto remove;
>         }
>
> -       dsi->clk_lp = devm_clk_get(&pdev->dev, "lp");
> +       dsi->clk_lp = devm_clk_get_optional(&pdev->dev, "lp");
>         if (IS_ERR(dsi->clk_lp)) {
>                 err = dev_err_probe(&pdev->dev, PTR_ERR(dsi->clk_lp),
>                                     "cannot get low-power clock\n");
> @@ -1627,10 +1642,12 @@ static int tegra_dsi_probe(struct platform_device *pdev)
>                 goto remove;
>         }
>
> -       err = tegra_dsi_setup_clocks(dsi);
> -       if (err < 0) {
> -               dev_err(&pdev->dev, "cannot setup clocks\n");
> -               goto remove;
> +       if (dsi->config->has_mux_parent_clk) {
> +               err = tegra_dsi_setup_clocks(dsi);
> +               if (err < 0) {
> +                       dev_err(&pdev->dev, "cannot setup clocks\n");
> +                       goto remove;
> +               }
>         }
>
>         dsi->regs = devm_platform_ioremap_resource(pdev, 0);
> @@ -1694,11 +1711,39 @@ static void tegra_dsi_remove(struct platform_device *pdev)
>         tegra_mipi_free(dsi->mipi);
>  }
>
> +static const struct tegra_dsi_config tegra20_dsi_config = {
> +       .has_multiple_pad_controls = false,
> +       .has_mux_parent_clk = false,
> +};
> +
> +/*
> + * Tegra30 allows DSIA/DSIB to be muxed to either PLL_D or PLL_D2; this is
> + * simply not modeled in the clock driver yet. If this functionality is
> + * required, the has_mux_parent_clk flag can be set to true once the clock
> + * driver is patched.
> + */
> +static const struct tegra_dsi_config tegra30_dsi_config = {
> +       .has_multiple_pad_controls = false,
> +       .has_mux_parent_clk = false,
> +};
> +
> +static const struct tegra_dsi_config tegra114_dsi_config = {
> +       .has_multiple_pad_controls = true,
> +       .has_mux_parent_clk = true,
> +};
> +
> +static const struct tegra_dsi_config tegra124_dsi_config = {
> +       .has_multiple_pad_controls = true,
> +       .has_mux_parent_clk = false,
> +};

Mikko, I have an update regarding Tegra124 config. If
tegra_dsi_setup_clocks is not called for Tegra124 (has_mux_parent_clk
= false) DSI will not work. I cannot say for sure what is going on
with clocks since my tegra124 device has broken usb in mainline Linux
and without panel is no go. I would like to address this before this
series is picked.

> +
>  static const struct of_device_id tegra_dsi_of_match[] = {
> -       { .compatible = "nvidia,tegra210-dsi", },
> -       { .compatible = "nvidia,tegra132-dsi", },
> -       { .compatible = "nvidia,tegra124-dsi", },
> -       { .compatible = "nvidia,tegra114-dsi", },
> +       { .compatible = "nvidia,tegra210-dsi", .data = &tegra124_dsi_config },
> +       { .compatible = "nvidia,tegra132-dsi", .data = &tegra124_dsi_config },
> +       { .compatible = "nvidia,tegra124-dsi", .data = &tegra124_dsi_config },
> +       { .compatible = "nvidia,tegra114-dsi", .data = &tegra114_dsi_config },
> +       { .compatible = "nvidia,tegra30-dsi", .data = &tegra30_dsi_config },
> +       { .compatible = "nvidia,tegra20-dsi", .data = &tegra20_dsi_config },
>         { },
>  };
>  MODULE_DEVICE_TABLE(of, tegra_dsi_of_match);
> diff --git a/drivers/gpu/drm/tegra/dsi.h b/drivers/gpu/drm/tegra/dsi.h
> index f39594e65e97..d834ac0c47ab 100644
> --- a/drivers/gpu/drm/tegra/dsi.h
> +++ b/drivers/gpu/drm/tegra/dsi.h
> @@ -95,6 +95,16 @@
>  #define DSI_TALLY_LRX(x)               (((x) & 0xff) <<  8)
>  #define DSI_TALLY_HTX(x)               (((x) & 0xff) <<  0)
>  #define DSI_PAD_CONTROL_0              0x4b
> +/* Tegra20/Tegra30 */
> +#define DSI_PAD_CONTROL_PULLDN_ENAB(x) (((x) & 0x1) << 28)
> +#define DSI_PAD_CONTROL_SLEWUPADJ(x)   (((x) & 0x7) << 24)
> +#define DSI_PAD_CONTROL_SLEWDNADJ(x)   (((x) & 0x7) << 20)
> +#define DSI_PAD_CONTROL_PREEMP_EN(x)   (((x) & 0x1) << 19)
> +#define DSI_PAD_CONTROL_PDIO_CLK(x)    (((x) & 0x1) << 18)
> +#define DSI_PAD_CONTROL_PDIO(x)                (((x) & 0x3) << 16)
> +#define DSI_PAD_CONTROL_LPUPADJ(x)     (((x) & 0x3) << 14)
> +#define DSI_PAD_CONTROL_LPDNADJ(x)     (((x) & 0x3) << 12)
> +/* Tegra114+ */
>  #define DSI_PAD_CONTROL_VS1_PDIO(x)    (((x) & 0xf) <<  0)
>  #define DSI_PAD_CONTROL_VS1_PDIO_CLK   (1 <<  8)
>  #define DSI_PAD_CONTROL_VS1_PULLDN(x)  (((x) & 0xf) << 16)
> --
> 2.51.0
>

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

* Re: [PATCH v3 1/2] gpu/drm: tegra: dsi: add support for Tegra20/Tegra30
  2026-03-05 15:21   ` Svyatoslav Ryhel
@ 2026-03-05 15:50     ` Svyatoslav Ryhel
  2026-03-09  5:21       ` Mikko Perttunen
  0 siblings, 1 reply; 9+ messages in thread
From: Svyatoslav Ryhel @ 2026-03-05 15:50 UTC (permalink / raw)
  To: Thierry Reding, Mikko Perttunen, David Airlie, Simona Vetter,
	Jonathan Hunter, Diogo Ivo, Svyatoslav Ryhel
  Cc: dri-devel, linux-tegra, linux-kernel

чт, 5 бер. 2026 р. о 17:21 Svyatoslav Ryhel <clamor95@gmail.com> пише:
>
> нд, 25 січ. 2026 р. о 15:13 Svyatoslav Ryhel <clamor95@gmail.com> пише:
> >
> > Tegra20 and Tegra30 are fully compatible with existing Tegra DSI driver
> > apart from clock configuration and pad calibration which are addressed by
> > this patch.
> >
> > Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > ---
> >  drivers/gpu/drm/tegra/drm.c |   2 +
> >  drivers/gpu/drm/tegra/dsi.c | 107 +++++++++++++++++++++++++-----------
> >  drivers/gpu/drm/tegra/dsi.h |  10 ++++
> >  3 files changed, 88 insertions(+), 31 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c
> > index 4596073fe28f..5d64cd57e764 100644
> > --- a/drivers/gpu/drm/tegra/drm.c
> > +++ b/drivers/gpu/drm/tegra/drm.c
> > @@ -1359,10 +1359,12 @@ static SIMPLE_DEV_PM_OPS(host1x_drm_pm_ops, host1x_drm_suspend,
> >
> >  static const struct of_device_id host1x_drm_subdevs[] = {
> >         { .compatible = "nvidia,tegra20-dc", },
> > +       { .compatible = "nvidia,tegra20-dsi", },
> >         { .compatible = "nvidia,tegra20-hdmi", },
> >         { .compatible = "nvidia,tegra20-gr2d", },
> >         { .compatible = "nvidia,tegra20-gr3d", },
> >         { .compatible = "nvidia,tegra30-dc", },
> > +       { .compatible = "nvidia,tegra30-dsi", },
> >         { .compatible = "nvidia,tegra30-hdmi", },
> >         { .compatible = "nvidia,tegra30-gr2d", },
> >         { .compatible = "nvidia,tegra30-gr3d", },
> > diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c
> > index 02a661d86751..ebc78dceaee6 100644
> > --- a/drivers/gpu/drm/tegra/dsi.c
> > +++ b/drivers/gpu/drm/tegra/dsi.c
> > @@ -53,6 +53,11 @@ to_dsi_state(struct drm_connector_state *state)
> >         return container_of(state, struct tegra_dsi_state, base);
> >  }
> >
> > +struct tegra_dsi_config {
> > +       bool has_multiple_pad_controls;
> > +       bool has_mux_parent_clk;
> > +};
> > +
> >  struct tegra_dsi {
> >         struct host1x_client client;
> >         struct tegra_output output;
> > @@ -82,6 +87,8 @@ struct tegra_dsi {
> >         /* for ganged-mode support */
> >         struct tegra_dsi *master;
> >         struct tegra_dsi *slave;
> > +
> > +       const struct tegra_dsi_config *config;
> >  };
> >
> >  static inline struct tegra_dsi *
> > @@ -663,39 +670,46 @@ static int tegra_dsi_pad_enable(struct tegra_dsi *dsi)
> >  {
> >         u32 value;
> >
> > -       value = DSI_PAD_CONTROL_VS1_PULLDN(0) | DSI_PAD_CONTROL_VS1_PDIO(0);
> > -       tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_0);
> > +       if (dsi->config->has_multiple_pad_controls) {
> > +               /*
> > +                * XXX Is this still needed? The module reset is deasserted right
> > +                * before this function is called.
> > +                */
> > +               tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_0);
> > +               tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_1);
> > +               tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_2);
> > +               tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_3);
> > +               tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_4);
> > +
> > +               value = DSI_PAD_CONTROL_VS1_PULLDN(0) | DSI_PAD_CONTROL_VS1_PDIO(0);
> > +               tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_0);
> > +
> > +               value = DSI_PAD_SLEW_UP(0x7) | DSI_PAD_SLEW_DN(0x7) |
> > +                       DSI_PAD_LP_UP(0x1) | DSI_PAD_LP_DN(0x1) |
> > +                       DSI_PAD_OUT_CLK(0x0);
> > +               tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_2);
> > +
> > +               value = DSI_PAD_PREEMP_PD_CLK(0x3) | DSI_PAD_PREEMP_PU_CLK(0x3) |
> > +                       DSI_PAD_PREEMP_PD(0x03) | DSI_PAD_PREEMP_PU(0x3);
> > +               tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_3);
> > +       } else {
> > +               value = DSI_PAD_CONTROL_LPUPADJ(0x1) | DSI_PAD_CONTROL_LPDNADJ(0x1) |
> > +                       DSI_PAD_CONTROL_PREEMP_EN(0x1) | DSI_PAD_CONTROL_SLEWDNADJ(0x6) |
> > +                       DSI_PAD_CONTROL_SLEWUPADJ(0x6) | DSI_PAD_CONTROL_PDIO(0) |
> > +                       DSI_PAD_CONTROL_PDIO_CLK(0) | DSI_PAD_CONTROL_PULLDN_ENAB(0);
> > +               tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_0);
> > +       }
> >
> >         return 0;
> >  }
> >
> >  static int tegra_dsi_pad_calibrate(struct tegra_dsi *dsi)
> >  {
> > -       u32 value;
> >         int err;
> >
> > -       /*
> > -        * XXX Is this still needed? The module reset is deasserted right
> > -        * before this function is called.
> > -        */
> > -       tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_0);
> > -       tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_1);
> > -       tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_2);
> > -       tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_3);
> > -       tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_4);
> > -
> >         /* start calibration */
> >         tegra_dsi_pad_enable(dsi);
> >
> > -       value = DSI_PAD_SLEW_UP(0x7) | DSI_PAD_SLEW_DN(0x7) |
> > -               DSI_PAD_LP_UP(0x1) | DSI_PAD_LP_DN(0x1) |
> > -               DSI_PAD_OUT_CLK(0x0);
> > -       tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_2);
> > -
> > -       value = DSI_PAD_PREEMP_PD_CLK(0x3) | DSI_PAD_PREEMP_PU_CLK(0x3) |
> > -               DSI_PAD_PREEMP_PD(0x03) | DSI_PAD_PREEMP_PU(0x3);
> > -       tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_3);
> > -
> >         err = tegra_mipi_start_calibration(dsi->mipi);
> >         if (err < 0)
> >                 return err;
> > @@ -1568,6 +1582,7 @@ static int tegra_dsi_probe(struct platform_device *pdev)
> >         if (!dsi)
> >                 return -ENOMEM;
> >
> > +       dsi->config = of_device_get_match_data(&pdev->dev);
> >         dsi->output.dev = dsi->dev = &pdev->dev;
> >         dsi->video_fifo_depth = 1920;
> >         dsi->host_fifo_depth = 64;
> > @@ -1606,7 +1621,7 @@ static int tegra_dsi_probe(struct platform_device *pdev)
> >                 goto remove;
> >         }
> >
> > -       dsi->clk_lp = devm_clk_get(&pdev->dev, "lp");
> > +       dsi->clk_lp = devm_clk_get_optional(&pdev->dev, "lp");
> >         if (IS_ERR(dsi->clk_lp)) {
> >                 err = dev_err_probe(&pdev->dev, PTR_ERR(dsi->clk_lp),
> >                                     "cannot get low-power clock\n");
> > @@ -1627,10 +1642,12 @@ static int tegra_dsi_probe(struct platform_device *pdev)
> >                 goto remove;
> >         }
> >
> > -       err = tegra_dsi_setup_clocks(dsi);
> > -       if (err < 0) {
> > -               dev_err(&pdev->dev, "cannot setup clocks\n");
> > -               goto remove;
> > +       if (dsi->config->has_mux_parent_clk) {
> > +               err = tegra_dsi_setup_clocks(dsi);
> > +               if (err < 0) {
> > +                       dev_err(&pdev->dev, "cannot setup clocks\n");
> > +                       goto remove;
> > +               }
> >         }
> >
> >         dsi->regs = devm_platform_ioremap_resource(pdev, 0);
> > @@ -1694,11 +1711,39 @@ static void tegra_dsi_remove(struct platform_device *pdev)
> >         tegra_mipi_free(dsi->mipi);
> >  }
> >
> > +static const struct tegra_dsi_config tegra20_dsi_config = {
> > +       .has_multiple_pad_controls = false,
> > +       .has_mux_parent_clk = false,
> > +};
> > +
> > +/*
> > + * Tegra30 allows DSIA/DSIB to be muxed to either PLL_D or PLL_D2; this is
> > + * simply not modeled in the clock driver yet. If this functionality is
> > + * required, the has_mux_parent_clk flag can be set to true once the clock
> > + * driver is patched.
> > + */
> > +static const struct tegra_dsi_config tegra30_dsi_config = {
> > +       .has_multiple_pad_controls = false,
> > +       .has_mux_parent_clk = false,
> > +};
> > +
> > +static const struct tegra_dsi_config tegra114_dsi_config = {
> > +       .has_multiple_pad_controls = true,
> > +       .has_mux_parent_clk = true,
> > +};
> > +
> > +static const struct tegra_dsi_config tegra124_dsi_config = {
> > +       .has_multiple_pad_controls = true,
> > +       .has_mux_parent_clk = false,
> > +};
>
> Mikko, I have an update regarding Tegra124 config. If
> tegra_dsi_setup_clocks is not called for Tegra124 (has_mux_parent_clk
> = false) DSI will not work. I cannot say for sure what is going on
> with clocks since my tegra124 device has broken usb in mainline Linux
> and without panel is no go. I would like to address this before this
> series is picked.
>

Ok, from what I can tell, tegra_dsi_setup_clocks ensures that the
Tegra124 DSI parent gate clock is properly configured. I propose
setting has_mux_parent_clk to true for Tegra124, and I will add a
comment to explain why.

Smth like this: "Tegra124 and Tegra210 don't have an actual mux parent
for DSI clocks, but the gate parent clock they use requires the same
setup."

Or flag name can be changed to has_mux_gate_parent_clk or any other
name which fits.

> > +
> >  static const struct of_device_id tegra_dsi_of_match[] = {
> > -       { .compatible = "nvidia,tegra210-dsi", },
> > -       { .compatible = "nvidia,tegra132-dsi", },
> > -       { .compatible = "nvidia,tegra124-dsi", },
> > -       { .compatible = "nvidia,tegra114-dsi", },
> > +       { .compatible = "nvidia,tegra210-dsi", .data = &tegra124_dsi_config },
> > +       { .compatible = "nvidia,tegra132-dsi", .data = &tegra124_dsi_config },
> > +       { .compatible = "nvidia,tegra124-dsi", .data = &tegra124_dsi_config },
> > +       { .compatible = "nvidia,tegra114-dsi", .data = &tegra114_dsi_config },
> > +       { .compatible = "nvidia,tegra30-dsi", .data = &tegra30_dsi_config },
> > +       { .compatible = "nvidia,tegra20-dsi", .data = &tegra20_dsi_config },
> >         { },
> >  };
> >  MODULE_DEVICE_TABLE(of, tegra_dsi_of_match);
> > diff --git a/drivers/gpu/drm/tegra/dsi.h b/drivers/gpu/drm/tegra/dsi.h
> > index f39594e65e97..d834ac0c47ab 100644
> > --- a/drivers/gpu/drm/tegra/dsi.h
> > +++ b/drivers/gpu/drm/tegra/dsi.h
> > @@ -95,6 +95,16 @@
> >  #define DSI_TALLY_LRX(x)               (((x) & 0xff) <<  8)
> >  #define DSI_TALLY_HTX(x)               (((x) & 0xff) <<  0)
> >  #define DSI_PAD_CONTROL_0              0x4b
> > +/* Tegra20/Tegra30 */
> > +#define DSI_PAD_CONTROL_PULLDN_ENAB(x) (((x) & 0x1) << 28)
> > +#define DSI_PAD_CONTROL_SLEWUPADJ(x)   (((x) & 0x7) << 24)
> > +#define DSI_PAD_CONTROL_SLEWDNADJ(x)   (((x) & 0x7) << 20)
> > +#define DSI_PAD_CONTROL_PREEMP_EN(x)   (((x) & 0x1) << 19)
> > +#define DSI_PAD_CONTROL_PDIO_CLK(x)    (((x) & 0x1) << 18)
> > +#define DSI_PAD_CONTROL_PDIO(x)                (((x) & 0x3) << 16)
> > +#define DSI_PAD_CONTROL_LPUPADJ(x)     (((x) & 0x3) << 14)
> > +#define DSI_PAD_CONTROL_LPDNADJ(x)     (((x) & 0x3) << 12)
> > +/* Tegra114+ */
> >  #define DSI_PAD_CONTROL_VS1_PDIO(x)    (((x) & 0xf) <<  0)
> >  #define DSI_PAD_CONTROL_VS1_PDIO_CLK   (1 <<  8)
> >  #define DSI_PAD_CONTROL_VS1_PULLDN(x)  (((x) & 0xf) << 16)
> > --
> > 2.51.0
> >

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

* Re: [PATCH v3 1/2] gpu/drm: tegra: dsi: add support for Tegra20/Tegra30
  2026-03-05 15:50     ` Svyatoslav Ryhel
@ 2026-03-09  5:21       ` Mikko Perttunen
  2026-03-09  7:11         ` Svyatoslav Ryhel
  0 siblings, 1 reply; 9+ messages in thread
From: Mikko Perttunen @ 2026-03-09  5:21 UTC (permalink / raw)
  To: Thierry Reding, David Airlie, Simona Vetter, Jonathan Hunter,
	Diogo Ivo, Svyatoslav Ryhel, Svyatoslav Ryhel
  Cc: dri-devel, linux-tegra, linux-kernel

On Friday, March 6, 2026 12:50 AM Svyatoslav Ryhel wrote:
> чт, 5 бер. 2026 р. о 17:21 Svyatoslav Ryhel <clamor95@gmail.com> пише:
> > нд, 25 січ. 2026 р. о 15:13 Svyatoslav Ryhel <clamor95@gmail.com> пише:
> > > Tegra20 and Tegra30 are fully compatible with existing Tegra DSI driver
> > > apart from clock configuration and pad calibration which are addressed
> > > by
> > > this patch.
> > > 
> > > Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > > ---
> > > 
> > >  drivers/gpu/drm/tegra/drm.c |   2 +
> > >  drivers/gpu/drm/tegra/dsi.c | 107 +++++++++++++++++++++++++-----------
> > >  drivers/gpu/drm/tegra/dsi.h |  10 ++++
> > >  3 files changed, 88 insertions(+), 31 deletions(-)
> > > 
> > > diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c
> > > index 4596073fe28f..5d64cd57e764 100644
> > > --- a/drivers/gpu/drm/tegra/drm.c
> > > +++ b/drivers/gpu/drm/tegra/drm.c
> > > @@ -1359,10 +1359,12 @@ static SIMPLE_DEV_PM_OPS(host1x_drm_pm_ops,
> > > host1x_drm_suspend,> > 
> > >  static const struct of_device_id host1x_drm_subdevs[] = {
> > >  
> > >         { .compatible = "nvidia,tegra20-dc", },
> > > 
> > > +       { .compatible = "nvidia,tegra20-dsi", },
> > > 
> > >         { .compatible = "nvidia,tegra20-hdmi", },
> > >         { .compatible = "nvidia,tegra20-gr2d", },
> > >         { .compatible = "nvidia,tegra20-gr3d", },
> > >         { .compatible = "nvidia,tegra30-dc", },
> > > 
> > > +       { .compatible = "nvidia,tegra30-dsi", },
> > > 
> > >         { .compatible = "nvidia,tegra30-hdmi", },
> > >         { .compatible = "nvidia,tegra30-gr2d", },
> > >         { .compatible = "nvidia,tegra30-gr3d", },
> > > 
> > > diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c
> > > index 02a661d86751..ebc78dceaee6 100644
> > > --- a/drivers/gpu/drm/tegra/dsi.c
> > > +++ b/drivers/gpu/drm/tegra/dsi.c
> > > @@ -53,6 +53,11 @@ to_dsi_state(struct drm_connector_state *state)
> > > 
> > >         return container_of(state, struct tegra_dsi_state, base);
> > >  
> > >  }
> > > 
> > > +struct tegra_dsi_config {
> > > +       bool has_multiple_pad_controls;
> > > +       bool has_mux_parent_clk;
> > > +};
> > > +
> > > 
> > >  struct tegra_dsi {
> > >  
> > >         struct host1x_client client;
> > >         struct tegra_output output;
> > > 
> > > @@ -82,6 +87,8 @@ struct tegra_dsi {
> > > 
> > >         /* for ganged-mode support */
> > >         struct tegra_dsi *master;
> > >         struct tegra_dsi *slave;
> > > 
> > > +
> > > +       const struct tegra_dsi_config *config;
> > > 
> > >  };
> > >  
> > >  static inline struct tegra_dsi *
> > > 
> > > @@ -663,39 +670,46 @@ static int tegra_dsi_pad_enable(struct tegra_dsi
> > > *dsi)> > 
> > >  {
> > >  
> > >         u32 value;
> > > 
> > > -       value = DSI_PAD_CONTROL_VS1_PULLDN(0) |
> > > DSI_PAD_CONTROL_VS1_PDIO(0); -       tegra_dsi_writel(dsi, value,
> > > DSI_PAD_CONTROL_0);
> > > +       if (dsi->config->has_multiple_pad_controls) {
> > > +               /*
> > > +                * XXX Is this still needed? The module reset is
> > > deasserted right +                * before this function is called.
> > > +                */
> > > +               tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_0);
> > > +               tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_1);
> > > +               tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_2);
> > > +               tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_3);
> > > +               tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_4);
> > > +
> > > +               value = DSI_PAD_CONTROL_VS1_PULLDN(0) |
> > > DSI_PAD_CONTROL_VS1_PDIO(0); +               tegra_dsi_writel(dsi,
> > > value, DSI_PAD_CONTROL_0);
> > > +
> > > +               value = DSI_PAD_SLEW_UP(0x7) | DSI_PAD_SLEW_DN(0x7) |
> > > +                       DSI_PAD_LP_UP(0x1) | DSI_PAD_LP_DN(0x1) |
> > > +                       DSI_PAD_OUT_CLK(0x0);
> > > +               tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_2);
> > > +
> > > +               value = DSI_PAD_PREEMP_PD_CLK(0x3) |
> > > DSI_PAD_PREEMP_PU_CLK(0x3) | +                      
> > > DSI_PAD_PREEMP_PD(0x03) | DSI_PAD_PREEMP_PU(0x3); +              
> > > tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_3);
> > > +       } else {
> > > +               value = DSI_PAD_CONTROL_LPUPADJ(0x1) |
> > > DSI_PAD_CONTROL_LPDNADJ(0x1) | +                      
> > > DSI_PAD_CONTROL_PREEMP_EN(0x1) | DSI_PAD_CONTROL_SLEWDNADJ(0x6) | +    
> > >                   DSI_PAD_CONTROL_SLEWUPADJ(0x6) |
> > > DSI_PAD_CONTROL_PDIO(0) | +                      
> > > DSI_PAD_CONTROL_PDIO_CLK(0) | DSI_PAD_CONTROL_PULLDN_ENAB(0); +        
> > >       tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_0);
> > > +       }
> > > 
> > >         return 0;
> > >  
> > >  }
> > >  
> > >  static int tegra_dsi_pad_calibrate(struct tegra_dsi *dsi)
> > >  {
> > > 
> > > -       u32 value;
> > > 
> > >         int err;
> > > 
> > > -       /*
> > > -        * XXX Is this still needed? The module reset is deasserted
> > > right
> > > -        * before this function is called.
> > > -        */
> > > -       tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_0);
> > > -       tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_1);
> > > -       tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_2);
> > > -       tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_3);
> > > -       tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_4);
> > > -
> > > 
> > >         /* start calibration */
> > >         tegra_dsi_pad_enable(dsi);
> > > 
> > > -       value = DSI_PAD_SLEW_UP(0x7) | DSI_PAD_SLEW_DN(0x7) |
> > > -               DSI_PAD_LP_UP(0x1) | DSI_PAD_LP_DN(0x1) |
> > > -               DSI_PAD_OUT_CLK(0x0);
> > > -       tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_2);
> > > -
> > > -       value = DSI_PAD_PREEMP_PD_CLK(0x3) | DSI_PAD_PREEMP_PU_CLK(0x3)
> > > |
> > > -               DSI_PAD_PREEMP_PD(0x03) | DSI_PAD_PREEMP_PU(0x3);
> > > -       tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_3);
> > > -
> > > 
> > >         err = tegra_mipi_start_calibration(dsi->mipi);
> > >         if (err < 0)
> > >         
> > >                 return err;
> > > 
> > > @@ -1568,6 +1582,7 @@ static int tegra_dsi_probe(struct platform_device
> > > *pdev)> > 
> > >         if (!dsi)
> > >         
> > >                 return -ENOMEM;
> > > 
> > > +       dsi->config = of_device_get_match_data(&pdev->dev);
> > > 
> > >         dsi->output.dev = dsi->dev = &pdev->dev;
> > >         dsi->video_fifo_depth = 1920;
> > >         dsi->host_fifo_depth = 64;
> > > 
> > > @@ -1606,7 +1621,7 @@ static int tegra_dsi_probe(struct platform_device
> > > *pdev)> > 
> > >                 goto remove;
> > >         
> > >         }
> > > 
> > > -       dsi->clk_lp = devm_clk_get(&pdev->dev, "lp");
> > > +       dsi->clk_lp = devm_clk_get_optional(&pdev->dev, "lp");
> > > 
> > >         if (IS_ERR(dsi->clk_lp)) {
> > >         
> > >                 err = dev_err_probe(&pdev->dev, PTR_ERR(dsi->clk_lp),
> > >                 
> > >                                     "cannot get low-power clock\n");
> > > 
> > > @@ -1627,10 +1642,12 @@ static int tegra_dsi_probe(struct
> > > platform_device *pdev)> > 
> > >                 goto remove;
> > >         
> > >         }
> > > 
> > > -       err = tegra_dsi_setup_clocks(dsi);
> > > -       if (err < 0) {
> > > -               dev_err(&pdev->dev, "cannot setup clocks\n");
> > > -               goto remove;
> > > +       if (dsi->config->has_mux_parent_clk) {
> > > +               err = tegra_dsi_setup_clocks(dsi);
> > > +               if (err < 0) {
> > > +                       dev_err(&pdev->dev, "cannot setup clocks\n");
> > > +                       goto remove;
> > > +               }
> > > 
> > >         }
> > >         
> > >         dsi->regs = devm_platform_ioremap_resource(pdev, 0);
> > > 
> > > @@ -1694,11 +1711,39 @@ static void tegra_dsi_remove(struct
> > > platform_device *pdev)> > 
> > >         tegra_mipi_free(dsi->mipi);
> > >  
> > >  }
> > > 
> > > +static const struct tegra_dsi_config tegra20_dsi_config = {
> > > +       .has_multiple_pad_controls = false,
> > > +       .has_mux_parent_clk = false,
> > > +};
> > > +
> > > +/*
> > > + * Tegra30 allows DSIA/DSIB to be muxed to either PLL_D or PLL_D2; this
> > > is
> > > + * simply not modeled in the clock driver yet. If this functionality is
> > > + * required, the has_mux_parent_clk flag can be set to true once the
> > > clock
> > > + * driver is patched.
> > > + */
> > > +static const struct tegra_dsi_config tegra30_dsi_config = {
> > > +       .has_multiple_pad_controls = false,
> > > +       .has_mux_parent_clk = false,
> > > +};
> > > +
> > > +static const struct tegra_dsi_config tegra114_dsi_config = {
> > > +       .has_multiple_pad_controls = true,
> > > +       .has_mux_parent_clk = true,
> > > +};
> > > +
> > > +static const struct tegra_dsi_config tegra124_dsi_config = {
> > > +       .has_multiple_pad_controls = true,
> > > +       .has_mux_parent_clk = false,
> > > +};
> > 
> > Mikko, I have an update regarding Tegra124 config. If
> > tegra_dsi_setup_clocks is not called for Tegra124 (has_mux_parent_clk
> > = false) DSI will not work. I cannot say for sure what is going on
> > with clocks since my tegra124 device has broken usb in mainline Linux
> > and without panel is no go. I would like to address this before this
> > series is picked.
> 
> Ok, from what I can tell, tegra_dsi_setup_clocks ensures that the
> Tegra124 DSI parent gate clock is properly configured. I propose
> setting has_mux_parent_clk to true for Tegra124, and I will add a
> comment to explain why.
> 
> Smth like this: "Tegra124 and Tegra210 don't have an actual mux parent
> for DSI clocks, but the gate parent clock they use requires the same
> setup."

Have you found something that tegra_dsi_setup_clocks is doing that could 
affect it, or is it just because it doesn't work without?

I looked at the code for clk_get_parent and clk_set_parent, and there 
shouldn't be any effect if the requested parent was already the parent.

I don't have a Tegra124 board available to me right now, but if we can't 
figure out why this is necessary, I'd put a /* TODO: figure out why this is 
necessary on Tegra124 */ in the code.

Perhaps you could check (with the clk_set_parent in place so you can boot) 
what the parent is according to the clock framework before we call 
clk_set_parent.

Mikko

> 
> Or flag name can be changed to has_mux_gate_parent_clk or any other
> name which fits.
> 
> > > +
> > > 
> > >  static const struct of_device_id tegra_dsi_of_match[] = {
> > > 
> > > -       { .compatible = "nvidia,tegra210-dsi", },
> > > -       { .compatible = "nvidia,tegra132-dsi", },
> > > -       { .compatible = "nvidia,tegra124-dsi", },
> > > -       { .compatible = "nvidia,tegra114-dsi", },
> > > +       { .compatible = "nvidia,tegra210-dsi", .data =
> > > &tegra124_dsi_config }, +       { .compatible = "nvidia,tegra132-dsi",
> > > .data = &tegra124_dsi_config }, +       { .compatible =
> > > "nvidia,tegra124-dsi", .data = &tegra124_dsi_config }, +       {
> > > .compatible = "nvidia,tegra114-dsi", .data = &tegra114_dsi_config }, + 
> > >      { .compatible = "nvidia,tegra30-dsi", .data = &tegra30_dsi_config
> > > }, +       { .compatible = "nvidia,tegra20-dsi", .data =
> > > &tegra20_dsi_config },> > 
> > >         { },
> > >  
> > >  };
> > >  MODULE_DEVICE_TABLE(of, tegra_dsi_of_match);
> > > 
> > > diff --git a/drivers/gpu/drm/tegra/dsi.h b/drivers/gpu/drm/tegra/dsi.h
> > > index f39594e65e97..d834ac0c47ab 100644
> > > --- a/drivers/gpu/drm/tegra/dsi.h
> > > +++ b/drivers/gpu/drm/tegra/dsi.h
> > > @@ -95,6 +95,16 @@
> > > 
> > >  #define DSI_TALLY_LRX(x)               (((x) & 0xff) <<  8)
> > >  #define DSI_TALLY_HTX(x)               (((x) & 0xff) <<  0)
> > >  #define DSI_PAD_CONTROL_0              0x4b
> > > 
> > > +/* Tegra20/Tegra30 */
> > > +#define DSI_PAD_CONTROL_PULLDN_ENAB(x) (((x) & 0x1) << 28)
> > > +#define DSI_PAD_CONTROL_SLEWUPADJ(x)   (((x) & 0x7) << 24)
> > > +#define DSI_PAD_CONTROL_SLEWDNADJ(x)   (((x) & 0x7) << 20)
> > > +#define DSI_PAD_CONTROL_PREEMP_EN(x)   (((x) & 0x1) << 19)
> > > +#define DSI_PAD_CONTROL_PDIO_CLK(x)    (((x) & 0x1) << 18)
> > > +#define DSI_PAD_CONTROL_PDIO(x)                (((x) & 0x3) << 16)
> > > +#define DSI_PAD_CONTROL_LPUPADJ(x)     (((x) & 0x3) << 14)
> > > +#define DSI_PAD_CONTROL_LPDNADJ(x)     (((x) & 0x3) << 12)
> > > +/* Tegra114+ */
> > > 
> > >  #define DSI_PAD_CONTROL_VS1_PDIO(x)    (((x) & 0xf) <<  0)
> > >  #define DSI_PAD_CONTROL_VS1_PDIO_CLK   (1 <<  8)
> > >  #define DSI_PAD_CONTROL_VS1_PULLDN(x)  (((x) & 0xf) << 16)
> > > 
> > > --
> > > 2.51.0





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

* Re: [PATCH v3 1/2] gpu/drm: tegra: dsi: add support for Tegra20/Tegra30
  2026-03-09  5:21       ` Mikko Perttunen
@ 2026-03-09  7:11         ` Svyatoslav Ryhel
  0 siblings, 0 replies; 9+ messages in thread
From: Svyatoslav Ryhel @ 2026-03-09  7:11 UTC (permalink / raw)
  To: Mikko Perttunen
  Cc: Thierry Reding, David Airlie, Simona Vetter, Jonathan Hunter,
	Diogo Ivo, dri-devel, linux-tegra, linux-kernel

пн, 9 бер. 2026 р. о 07:21 Mikko Perttunen <mperttunen@nvidia.com> пише:
>
> On Friday, March 6, 2026 12:50 AM Svyatoslav Ryhel wrote:
> > чт, 5 бер. 2026 р. о 17:21 Svyatoslav Ryhel <clamor95@gmail.com> пише:
> > > нд, 25 січ. 2026 р. о 15:13 Svyatoslav Ryhel <clamor95@gmail.com> пише:
> > > > Tegra20 and Tegra30 are fully compatible with existing Tegra DSI driver
> > > > apart from clock configuration and pad calibration which are addressed
> > > > by
> > > > this patch.
> > > >
> > > > Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > > > ---
> > > >
> > > >  drivers/gpu/drm/tegra/drm.c |   2 +
> > > >  drivers/gpu/drm/tegra/dsi.c | 107 +++++++++++++++++++++++++-----------
> > > >  drivers/gpu/drm/tegra/dsi.h |  10 ++++
> > > >  3 files changed, 88 insertions(+), 31 deletions(-)
> > > >
> > > > diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c
> > > > index 4596073fe28f..5d64cd57e764 100644
> > > > --- a/drivers/gpu/drm/tegra/drm.c
> > > > +++ b/drivers/gpu/drm/tegra/drm.c
> > > > @@ -1359,10 +1359,12 @@ static SIMPLE_DEV_PM_OPS(host1x_drm_pm_ops,
> > > > host1x_drm_suspend,> >
> > > >  static const struct of_device_id host1x_drm_subdevs[] = {
> > > >
> > > >         { .compatible = "nvidia,tegra20-dc", },
> > > >
> > > > +       { .compatible = "nvidia,tegra20-dsi", },
> > > >
> > > >         { .compatible = "nvidia,tegra20-hdmi", },
> > > >         { .compatible = "nvidia,tegra20-gr2d", },
> > > >         { .compatible = "nvidia,tegra20-gr3d", },
> > > >         { .compatible = "nvidia,tegra30-dc", },
> > > >
> > > > +       { .compatible = "nvidia,tegra30-dsi", },
> > > >
> > > >         { .compatible = "nvidia,tegra30-hdmi", },
> > > >         { .compatible = "nvidia,tegra30-gr2d", },
> > > >         { .compatible = "nvidia,tegra30-gr3d", },
> > > >
> > > > diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c
> > > > index 02a661d86751..ebc78dceaee6 100644
> > > > --- a/drivers/gpu/drm/tegra/dsi.c
> > > > +++ b/drivers/gpu/drm/tegra/dsi.c
> > > > @@ -53,6 +53,11 @@ to_dsi_state(struct drm_connector_state *state)
> > > >
> > > >         return container_of(state, struct tegra_dsi_state, base);
> > > >
> > > >  }
> > > >
> > > > +struct tegra_dsi_config {
> > > > +       bool has_multiple_pad_controls;
> > > > +       bool has_mux_parent_clk;
> > > > +};
> > > > +
> > > >
> > > >  struct tegra_dsi {
> > > >
> > > >         struct host1x_client client;
> > > >         struct tegra_output output;
> > > >
> > > > @@ -82,6 +87,8 @@ struct tegra_dsi {
> > > >
> > > >         /* for ganged-mode support */
> > > >         struct tegra_dsi *master;
> > > >         struct tegra_dsi *slave;
> > > >
> > > > +
> > > > +       const struct tegra_dsi_config *config;
> > > >
> > > >  };
> > > >
> > > >  static inline struct tegra_dsi *
> > > >
> > > > @@ -663,39 +670,46 @@ static int tegra_dsi_pad_enable(struct tegra_dsi
> > > > *dsi)> >
> > > >  {
> > > >
> > > >         u32 value;
> > > >
> > > > -       value = DSI_PAD_CONTROL_VS1_PULLDN(0) |
> > > > DSI_PAD_CONTROL_VS1_PDIO(0); -       tegra_dsi_writel(dsi, value,
> > > > DSI_PAD_CONTROL_0);
> > > > +       if (dsi->config->has_multiple_pad_controls) {
> > > > +               /*
> > > > +                * XXX Is this still needed? The module reset is
> > > > deasserted right +                * before this function is called.
> > > > +                */
> > > > +               tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_0);
> > > > +               tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_1);
> > > > +               tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_2);
> > > > +               tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_3);
> > > > +               tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_4);
> > > > +
> > > > +               value = DSI_PAD_CONTROL_VS1_PULLDN(0) |
> > > > DSI_PAD_CONTROL_VS1_PDIO(0); +               tegra_dsi_writel(dsi,
> > > > value, DSI_PAD_CONTROL_0);
> > > > +
> > > > +               value = DSI_PAD_SLEW_UP(0x7) | DSI_PAD_SLEW_DN(0x7) |
> > > > +                       DSI_PAD_LP_UP(0x1) | DSI_PAD_LP_DN(0x1) |
> > > > +                       DSI_PAD_OUT_CLK(0x0);
> > > > +               tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_2);
> > > > +
> > > > +               value = DSI_PAD_PREEMP_PD_CLK(0x3) |
> > > > DSI_PAD_PREEMP_PU_CLK(0x3) | +
> > > > DSI_PAD_PREEMP_PD(0x03) | DSI_PAD_PREEMP_PU(0x3); +
> > > > tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_3);
> > > > +       } else {
> > > > +               value = DSI_PAD_CONTROL_LPUPADJ(0x1) |
> > > > DSI_PAD_CONTROL_LPDNADJ(0x1) | +
> > > > DSI_PAD_CONTROL_PREEMP_EN(0x1) | DSI_PAD_CONTROL_SLEWDNADJ(0x6) | +
> > > >                   DSI_PAD_CONTROL_SLEWUPADJ(0x6) |
> > > > DSI_PAD_CONTROL_PDIO(0) | +
> > > > DSI_PAD_CONTROL_PDIO_CLK(0) | DSI_PAD_CONTROL_PULLDN_ENAB(0); +
> > > >       tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_0);
> > > > +       }
> > > >
> > > >         return 0;
> > > >
> > > >  }
> > > >
> > > >  static int tegra_dsi_pad_calibrate(struct tegra_dsi *dsi)
> > > >  {
> > > >
> > > > -       u32 value;
> > > >
> > > >         int err;
> > > >
> > > > -       /*
> > > > -        * XXX Is this still needed? The module reset is deasserted
> > > > right
> > > > -        * before this function is called.
> > > > -        */
> > > > -       tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_0);
> > > > -       tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_1);
> > > > -       tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_2);
> > > > -       tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_3);
> > > > -       tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_4);
> > > > -
> > > >
> > > >         /* start calibration */
> > > >         tegra_dsi_pad_enable(dsi);
> > > >
> > > > -       value = DSI_PAD_SLEW_UP(0x7) | DSI_PAD_SLEW_DN(0x7) |
> > > > -               DSI_PAD_LP_UP(0x1) | DSI_PAD_LP_DN(0x1) |
> > > > -               DSI_PAD_OUT_CLK(0x0);
> > > > -       tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_2);
> > > > -
> > > > -       value = DSI_PAD_PREEMP_PD_CLK(0x3) | DSI_PAD_PREEMP_PU_CLK(0x3)
> > > > |
> > > > -               DSI_PAD_PREEMP_PD(0x03) | DSI_PAD_PREEMP_PU(0x3);
> > > > -       tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_3);
> > > > -
> > > >
> > > >         err = tegra_mipi_start_calibration(dsi->mipi);
> > > >         if (err < 0)
> > > >
> > > >                 return err;
> > > >
> > > > @@ -1568,6 +1582,7 @@ static int tegra_dsi_probe(struct platform_device
> > > > *pdev)> >
> > > >         if (!dsi)
> > > >
> > > >                 return -ENOMEM;
> > > >
> > > > +       dsi->config = of_device_get_match_data(&pdev->dev);
> > > >
> > > >         dsi->output.dev = dsi->dev = &pdev->dev;
> > > >         dsi->video_fifo_depth = 1920;
> > > >         dsi->host_fifo_depth = 64;
> > > >
> > > > @@ -1606,7 +1621,7 @@ static int tegra_dsi_probe(struct platform_device
> > > > *pdev)> >
> > > >                 goto remove;
> > > >
> > > >         }
> > > >
> > > > -       dsi->clk_lp = devm_clk_get(&pdev->dev, "lp");
> > > > +       dsi->clk_lp = devm_clk_get_optional(&pdev->dev, "lp");
> > > >
> > > >         if (IS_ERR(dsi->clk_lp)) {
> > > >
> > > >                 err = dev_err_probe(&pdev->dev, PTR_ERR(dsi->clk_lp),
> > > >
> > > >                                     "cannot get low-power clock\n");
> > > >
> > > > @@ -1627,10 +1642,12 @@ static int tegra_dsi_probe(struct
> > > > platform_device *pdev)> >
> > > >                 goto remove;
> > > >
> > > >         }
> > > >
> > > > -       err = tegra_dsi_setup_clocks(dsi);
> > > > -       if (err < 0) {
> > > > -               dev_err(&pdev->dev, "cannot setup clocks\n");
> > > > -               goto remove;
> > > > +       if (dsi->config->has_mux_parent_clk) {
> > > > +               err = tegra_dsi_setup_clocks(dsi);
> > > > +               if (err < 0) {
> > > > +                       dev_err(&pdev->dev, "cannot setup clocks\n");
> > > > +                       goto remove;
> > > > +               }
> > > >
> > > >         }
> > > >
> > > >         dsi->regs = devm_platform_ioremap_resource(pdev, 0);
> > > >
> > > > @@ -1694,11 +1711,39 @@ static void tegra_dsi_remove(struct
> > > > platform_device *pdev)> >
> > > >         tegra_mipi_free(dsi->mipi);
> > > >
> > > >  }
> > > >
> > > > +static const struct tegra_dsi_config tegra20_dsi_config = {
> > > > +       .has_multiple_pad_controls = false,
> > > > +       .has_mux_parent_clk = false,
> > > > +};
> > > > +
> > > > +/*
> > > > + * Tegra30 allows DSIA/DSIB to be muxed to either PLL_D or PLL_D2; this
> > > > is
> > > > + * simply not modeled in the clock driver yet. If this functionality is
> > > > + * required, the has_mux_parent_clk flag can be set to true once the
> > > > clock
> > > > + * driver is patched.
> > > > + */
> > > > +static const struct tegra_dsi_config tegra30_dsi_config = {
> > > > +       .has_multiple_pad_controls = false,
> > > > +       .has_mux_parent_clk = false,
> > > > +};
> > > > +
> > > > +static const struct tegra_dsi_config tegra114_dsi_config = {
> > > > +       .has_multiple_pad_controls = true,
> > > > +       .has_mux_parent_clk = true,
> > > > +};
> > > > +
> > > > +static const struct tegra_dsi_config tegra124_dsi_config = {
> > > > +       .has_multiple_pad_controls = true,
> > > > +       .has_mux_parent_clk = false,
> > > > +};
> > >
> > > Mikko, I have an update regarding Tegra124 config. If
> > > tegra_dsi_setup_clocks is not called for Tegra124 (has_mux_parent_clk
> > > = false) DSI will not work. I cannot say for sure what is going on
> > > with clocks since my tegra124 device has broken usb in mainline Linux
> > > and without panel is no go. I would like to address this before this
> > > series is picked.
> >
> > Ok, from what I can tell, tegra_dsi_setup_clocks ensures that the
> > Tegra124 DSI parent gate clock is properly configured. I propose
> > setting has_mux_parent_clk to true for Tegra124, and I will add a
> > comment to explain why.
> >
> > Smth like this: "Tegra124 and Tegra210 don't have an actual mux parent
> > for DSI clocks, but the gate parent clock they use requires the same
> > setup."
>
> Have you found something that tegra_dsi_setup_clocks is doing that could
> affect it, or is it just because it doesn't work without?
>

I have not found anything that tegra_dsi_setup_clocks that could
affect configuration. It just does not work without.

> I looked at the code for clk_get_parent and clk_set_parent, and there
> shouldn't be any effect if the requested parent was already the parent.
>
> I don't have a Tegra124 board available to me right now, but if we can't
> figure out why this is necessary, I'd put a /* TODO: figure out why this is
> necessary on Tegra124 */ in the code.
>
> Perhaps you could check (with the clk_set_parent in place so you can boot)
> what the parent is according to the clock framework before we call
> clk_set_parent.
>

Yes I can, I have checked clock hierarchy and it seems to be identical
pre and post setup.

tegra_dsi_setup_clocks takes dsi clock parent and sets its parent
according to dt definition.

pre call it is pll_d_out0 > pll_d_dsi_out > dsia/b and after call it
remains the same.


> Mikko
>
> >
> > Or flag name can be changed to has_mux_gate_parent_clk or any other
> > name which fits.
> >
> > > > +
> > > >
> > > >  static const struct of_device_id tegra_dsi_of_match[] = {
> > > >
> > > > -       { .compatible = "nvidia,tegra210-dsi", },
> > > > -       { .compatible = "nvidia,tegra132-dsi", },
> > > > -       { .compatible = "nvidia,tegra124-dsi", },
> > > > -       { .compatible = "nvidia,tegra114-dsi", },
> > > > +       { .compatible = "nvidia,tegra210-dsi", .data =
> > > > &tegra124_dsi_config }, +       { .compatible = "nvidia,tegra132-dsi",
> > > > .data = &tegra124_dsi_config }, +       { .compatible =
> > > > "nvidia,tegra124-dsi", .data = &tegra124_dsi_config }, +       {
> > > > .compatible = "nvidia,tegra114-dsi", .data = &tegra114_dsi_config }, +
> > > >      { .compatible = "nvidia,tegra30-dsi", .data = &tegra30_dsi_config
> > > > }, +       { .compatible = "nvidia,tegra20-dsi", .data =
> > > > &tegra20_dsi_config },> >
> > > >         { },
> > > >
> > > >  };
> > > >  MODULE_DEVICE_TABLE(of, tegra_dsi_of_match);
> > > >
> > > > diff --git a/drivers/gpu/drm/tegra/dsi.h b/drivers/gpu/drm/tegra/dsi.h
> > > > index f39594e65e97..d834ac0c47ab 100644
> > > > --- a/drivers/gpu/drm/tegra/dsi.h
> > > > +++ b/drivers/gpu/drm/tegra/dsi.h
> > > > @@ -95,6 +95,16 @@
> > > >
> > > >  #define DSI_TALLY_LRX(x)               (((x) & 0xff) <<  8)
> > > >  #define DSI_TALLY_HTX(x)               (((x) & 0xff) <<  0)
> > > >  #define DSI_PAD_CONTROL_0              0x4b
> > > >
> > > > +/* Tegra20/Tegra30 */
> > > > +#define DSI_PAD_CONTROL_PULLDN_ENAB(x) (((x) & 0x1) << 28)
> > > > +#define DSI_PAD_CONTROL_SLEWUPADJ(x)   (((x) & 0x7) << 24)
> > > > +#define DSI_PAD_CONTROL_SLEWDNADJ(x)   (((x) & 0x7) << 20)
> > > > +#define DSI_PAD_CONTROL_PREEMP_EN(x)   (((x) & 0x1) << 19)
> > > > +#define DSI_PAD_CONTROL_PDIO_CLK(x)    (((x) & 0x1) << 18)
> > > > +#define DSI_PAD_CONTROL_PDIO(x)                (((x) & 0x3) << 16)
> > > > +#define DSI_PAD_CONTROL_LPUPADJ(x)     (((x) & 0x3) << 14)
> > > > +#define DSI_PAD_CONTROL_LPDNADJ(x)     (((x) & 0x3) << 12)
> > > > +/* Tegra114+ */
> > > >
> > > >  #define DSI_PAD_CONTROL_VS1_PDIO(x)    (((x) & 0xf) <<  0)
> > > >  #define DSI_PAD_CONTROL_VS1_PDIO_CLK   (1 <<  8)
> > > >  #define DSI_PAD_CONTROL_VS1_PULLDN(x)  (((x) & 0xf) << 16)
> > > >
> > > > --
> > > > 2.51.0
>
>
>
>

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

end of thread, other threads:[~2026-03-09  7:12 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-01-25 13:13 [PATCH v3 0/2] gpu/drm: tegra: add DSI support for Tegra20/Tegra30 Svyatoslav Ryhel
2026-01-25 13:13 ` [PATCH v3 1/2] gpu/drm: tegra: dsi: add " Svyatoslav Ryhel
2026-03-05 15:21   ` Svyatoslav Ryhel
2026-03-05 15:50     ` Svyatoslav Ryhel
2026-03-09  5:21       ` Mikko Perttunen
2026-03-09  7:11         ` Svyatoslav Ryhel
2026-01-25 13:13 ` [PATCH v3 2/2] gpu/drm: tegra: dsi: re-add clear enable register if DSI was powered by bootloader Svyatoslav Ryhel
2026-01-26  1:19 ` [PATCH v3 0/2] gpu/drm: tegra: add DSI support for Tegra20/Tegra30 Mikko Perttunen
2026-03-02  7:57 ` Svyatoslav Ryhel

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

all inboxes | Powered by JetHome®