[PATCH v6 14/18] video: tegra20: dsi: add T114 support

Svyatoslav Ryhel
2024-01-23T17:19:46Z

Existing Tegra DSI driver mostly fits T114 apart MIPI calibration
which on T114 has dedicated driver. To resolve this MIPI calibration
logic was split for pre-T114 and T114+ devices.

Tested-by: Ion Agorria <ion@agorria.com> # HTC One X
Tested-by: Svyatoslav Ryhel <clamor95@gmail.com> # Nvidia Tegratab T114
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
drivers/video/tegra20/tegra-dsi.c | 78 ++++++++++++++++++-
.../video/tegra20/tegra-dsi.h | 24 +++++-
2 files changed, 96 insertions(+), 6 deletions(-)
rename arch/arm/include/asm/arch-tegra30/dsi.h => drivers/video/tegra20/tegra-dsi.h (90%)

diff --git a/drivers/video/tegra20/tegra-dsi.c b/drivers/video/tegra20/tegra-dsi.c
index de225ed376..25a629535e 100644
--- a/drivers/video/tegra20/tegra-dsi.c
+++ b/drivers/video/tegra20/tegra-dsi.c
@@ -20,17 +20,24 @@
#include <asm/gpio.h>
#include <asm/io.h>
#include <asm/arch/clock.h>
-#include <asm/arch-tegra30/dsi.h>

#include "tegra-dc.h"
+#include "tegra-dsi.h"
#include "mipi-phy.h"

+/* List of supported DSI bridges */
+enum {
+ DSI_V0,
+ DSI_V1,
+};
+
struct tegra_dsi_priv {
struct mipi_dsi_host host;
struct mipi_dsi_device device;
struct mipi_dphy_timing dphy_timing;

struct udevice *panel;
+ struct udevice *mipi;
struct display_timing timing;

struct dsi_ctlr *dsi;
@@ -41,6 +48,8 @@ struct tegra_dsi_priv {
int dsi_clk;
int video_fifo_depth;
int host_fifo_depth;
+
+ u32 version;
};

static void tegra_dc_enable_controller(struct udevice *dev)
@@ -501,6 +510,41 @@ static void tegra_dsi_pad_calibrate(struct dsi_pad_ctrl_reg *pad)
writel(value, TEGRA_VI_BASE + (CSI_CIL_PAD_CONFIG << 2));
}

+static void tegra_dsi_mipi_calibrate(struct tegra_dsi_priv *priv)
+{
+ struct dsi_pad_ctrl_reg *pad = &priv->dsi->pad;
+ u32 value;
+ int ret;
+
+ ret = misc_set_enabled(priv->mipi, true);
+ if (ret)
+ log_debug("%s: failed to enable MIPI calibration: %d\n",
+ __func__, ret);
+
+ writel(0, &pad->pad_ctrl);
+ writel(0, &pad->pad_ctrl_1);
+ writel(0, &pad->pad_ctrl_2);
+ writel(0, &pad->pad_ctrl_3);
+ writel(0, &pad->pad_ctrl_4);
+
+ /* DSI pad enable */
+ value = DSI_PAD_CONTROL_VS1_PULLDN(0) | DSI_PAD_CONTROL_VS1_PDIO(0);
+ writel(value, &pad->pad_ctrl);
+
+ 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);
+ writel(value, &pad->pad_ctrl_2);
+
+ value = DSI_PAD_PREEMP_PD_CLK(0x3) | DSI_PAD_PREEMP_PU_CLK(0x3) |
+ DSI_PAD_PREEMP_PD(0x03) | DSI_PAD_PREEMP_PU(0x3);
+ writel(value, &pad->pad_ctrl_3);
+
+ ret = misc_write(priv->mipi, 0, NULL, 0);
+ if (ret)
+ log_debug("%s: MIPI calibration failed %d\n", __func__, ret);
+}
+
static void tegra_dsi_set_timeout(struct dsi_timeout_reg *rtimeout,
unsigned long bclk,
unsigned int vrefresh)
@@ -664,10 +708,25 @@ static int tegra_dsi_encoder_enable(struct udevice *dev)
u32 value;
int ret;

+ /* If for some reasone DSI is enabled then it needs to
+ * be disabled in order for the panel initialization
+ * commands to be properly sent.
+ */
+ value = readl(&misc->dsi_pwr_ctrl);
+
+ if (value & DSI_POWER_CONTROL_ENABLE) {
+ value = readl(&misc->dsi_pwr_ctrl);
+ value &= ~DSI_POWER_CONTROL_ENABLE;
+ writel(value, &misc->dsi_pwr_ctrl);
+ }
+
/* Disable interrupt */
writel(0, &misc->int_enable);

- tegra_dsi_pad_calibrate(&priv->dsi->pad);
+ if (priv->version)
+ tegra_dsi_mipi_calibrate(priv);
+ else
+ tegra_dsi_pad_calibrate(&priv->dsi->pad);

tegra_dsi_get_muldiv(device->format, &mul, &div);

@@ -806,6 +865,8 @@ static int tegra_dsi_bridge_probe(struct udevice *dev)
struct mipi_dsi_panel_plat *mipi_plat;
int ret;

+ priv->version = dev_get_driver_data(dev);
+
priv->dsi = (struct dsi_ctlr *)dev_read_addr_ptr(dev);
if (!priv->dsi) {
printf("%s: No display controller address\n", __func__);
@@ -828,6 +889,16 @@ static int tegra_dsi_bridge_probe(struct udevice *dev)
return log_ret(ret);
}

+ if (priv->version) {
+ ret = uclass_get_device_by_phandle(UCLASS_MISC, dev,
+ "nvidia,mipi-calibrate",
+ &priv->mipi);
+ if (ret) {
+ log_debug("%s: cannot get MIPI: error %d\n", __func__, ret);
+ return ret;
+ }
+ }
+
panel_get_display_timing(priv->panel, &priv->timing);

mipi_plat = dev_get_plat(priv->panel);
@@ -859,7 +930,8 @@ static const struct panel_ops tegra_dsi_bridge_ops = {
};

static const struct udevice_id tegra_dsi_bridge_ids[] = {
- { .compatible = "nvidia,tegra30-dsi" },
+ { .compatible = "nvidia,tegra30-dsi", .data = DSI_V0 },
+ { .compatible = "nvidia,tegra114-dsi", .data = DSI_V1 },
{ }
};

diff --git a/arch/arm/include/asm/arch-tegra30/dsi.h b/drivers/video/tegra20/tegra-dsi.h
similarity index 90%
rename from arch/arm/include/asm/arch-tegra30/dsi.h
rename to drivers/video/tegra20/tegra-dsi.h
index 7ade132613..69dac4bd1b 100644
--- a/arch/arm/include/asm/arch-tegra30/dsi.h
+++ b/drivers/video/tegra20/tegra-dsi.h
@@ -4,8 +4,8 @@
* NVIDIA Corporation <www.nvidia.com>
*/

-#ifndef __ASM_ARCH_TEGRA_DSI_H
-#define __ASM_ARCH_TEGRA_DSI_H
+#ifndef _TEGRA_DSI_H
+#define _TEGRA_DSI_H

#ifndef __ASSEMBLY__
#include <linux/bitops.h>
@@ -105,6 +105,10 @@ struct dsi_pad_ctrl_reg {
uint pad_ctrl_cd; /* _PAD_CONTROL_CD_0 */
uint pad_cd_status; /* _PAD_CD_STATUS_0 */
uint dsi_vid_mode_control; /* _DSI_VID_MODE_CONTROL_0 */
+ uint pad_ctrl_1; /* _PAD_CONTROL_1 */
+ uint pad_ctrl_2; /* _PAD_CONTROL_2 */
+ uint pad_ctrl_3; /* _PAD_CONTROL_3 */
+ uint pad_ctrl_4; /* _PAD_CONTROL_4 */
};

/* Display Serial Interface (DSI_) regs */
@@ -184,6 +188,20 @@ struct dsi_ctlr {
#define DSI_PAD_CONTROL_PAD_LPUPADJ(x) (((x) & 0x3) << 14)
#define DSI_PAD_CONTROL_PAD_LPDNADJ(x) (((x) & 0x3) << 12)

+#define DSI_PAD_CONTROL_VS1_PDIO(x) (((x) & 0xf) << 0)
+#define DSI_PAD_CONTROL_VS1_PULLDN(x) (((x) & 0xf) << 16)
+
+#define DSI_PAD_OUT_CLK(x) (((x) & 0x7) << 0)
+#define DSI_PAD_LP_DN(x) (((x) & 0x7) << 4)
+#define DSI_PAD_LP_UP(x) (((x) & 0x7) << 8)
+#define DSI_PAD_SLEW_DN(x) (((x) & 0x7) << 12)
+#define DSI_PAD_SLEW_UP(x) (((x) & 0x7) << 16)
+
+#define DSI_PAD_PREEMP_PD_CLK(x) (((x) & 0x3) << 12)
+#define DSI_PAD_PREEMP_PU_CLK(x) (((x) & 0x3) << 8)
+#define DSI_PAD_PREEMP_PD(x) (((x) & 0x3) << 4)
+#define DSI_PAD_PREEMP_PU(x) (((x) & 0x3) << 0)
+
/*
* pixel format as used in the DSI_CONTROL_FORMAT field
*/
@@ -214,4 +232,4 @@ enum tegra_dsi_format {
#define PAD_DRIV_DN_REF(x) (((x) & 0x7) << 16)
#define PAD_DRIV_UP_REF(x) (((x) & 0x7) << 8)

-#endif /* __ASM_ARCH_TEGRA_DSI_H */
+#endif /* _TEGRA_DSI_H */
--
2.40.1