[PATCH v1 0/3] Add T114 video support

T114 is not that different from T30 and all T30 drivers will work on T114 as well with some minor adjustments.
Commits pass buildman for tegra and U-Boot tests.
Svyatoslav Ryhel (3): video: tegra20: dc: add T114 support video: tegra20: add MIPI calibration driver video: tegra20: dsi: add T114 support
arch/arm/dts/tegra114-u-boot.dtsi | 9 + arch/arm/include/asm/arch-tegra/dsi.h | 235 +++++++++++++++++++ arch/arm/include/asm/arch-tegra114/display.h | 28 +++ arch/arm/include/asm/arch-tegra114/pwm.h | 13 + arch/arm/include/asm/arch-tegra30/dsi.h | 211 +---------------- drivers/video/tegra20/Makefile | 2 +- drivers/video/tegra20/tegra-dc.c | 1 + drivers/video/tegra20/tegra-dsi.c | 78 +++++- drivers/video/tegra20/tegra-mipi.c | 185 +++++++++++++++ 9 files changed, 550 insertions(+), 212 deletions(-) create mode 100644 arch/arm/include/asm/arch-tegra/dsi.h create mode 100644 arch/arm/include/asm/arch-tegra114/display.h create mode 100644 arch/arm/include/asm/arch-tegra114/pwm.h create mode 100644 drivers/video/tegra20/tegra-mipi.c

Existing Tegra DC driver fits perfectly well for Tegra 4 so let's add a compatible to state this.
Signed-off-by: Svyatoslav Ryhel clamor95@gmail.com --- arch/arm/dts/tegra114-u-boot.dtsi | 9 +++++++ arch/arm/include/asm/arch-tegra114/display.h | 28 ++++++++++++++++++++ arch/arm/include/asm/arch-tegra114/pwm.h | 13 +++++++++ drivers/video/tegra20/tegra-dc.c | 1 + 4 files changed, 51 insertions(+) create mode 100644 arch/arm/include/asm/arch-tegra114/display.h create mode 100644 arch/arm/include/asm/arch-tegra114/pwm.h
diff --git a/arch/arm/dts/tegra114-u-boot.dtsi b/arch/arm/dts/tegra114-u-boot.dtsi index 7c11972552..3038227dbe 100644 --- a/arch/arm/dts/tegra114-u-boot.dtsi +++ b/arch/arm/dts/tegra114-u-boot.dtsi @@ -1,3 +1,12 @@ #include <config.h>
#include "tegra-u-boot.dtsi" + +/ { + host1x@50000000 { + bootph-all; + dc@54200000 { + bootph-all; + }; + }; +}; diff --git a/arch/arm/include/asm/arch-tegra114/display.h b/arch/arm/include/asm/arch-tegra114/display.h new file mode 100644 index 0000000000..9411525799 --- /dev/null +++ b/arch/arm/include/asm/arch-tegra114/display.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2010 + * NVIDIA Corporation <www.nvidia.com> + */ + +#ifndef __ASM_ARCH_TEGRA_DISPLAY_H +#define __ASM_ARCH_TEGRA_DISPLAY_H + +#include <asm/arch-tegra/dc.h> + +/* This holds information about a window which can be displayed */ +struct disp_ctl_win { + enum win_color_depth_id fmt; /* Color depth/format */ + unsigned int bpp; /* Bits per pixel */ + phys_addr_t phys_addr; /* Physical address in memory */ + unsigned int x; /* Horizontal address offset (bytes) */ + unsigned int y; /* Veritical address offset (bytes) */ + unsigned int w; /* Width of source window */ + unsigned int h; /* Height of source window */ + unsigned int stride; /* Number of bytes per line */ + unsigned int out_x; /* Left edge of output window (col) */ + unsigned int out_y; /* Top edge of output window (row) */ + unsigned int out_w; /* Width of output window in pixels */ + unsigned int out_h; /* Height of output window in pixels */ +}; + +#endif /*__ASM_ARCH_TEGRA_DISPLAY_H*/ diff --git a/arch/arm/include/asm/arch-tegra114/pwm.h b/arch/arm/include/asm/arch-tegra114/pwm.h new file mode 100644 index 0000000000..af39151803 --- /dev/null +++ b/arch/arm/include/asm/arch-tegra114/pwm.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Tegra pulse width frequency modulator definitions + * + * Copyright (c) 2011 The Chromium OS Authors. + */ + +#ifndef __ASM_ARCH_TEGRA114_PWM_H +#define __ASM_ARCH_TEGRA114_PWM_H + +#include <asm/arch-tegra/pwm.h> + +#endif /* __ASM_ARCH_TEGRA114_PWM_H */ diff --git a/drivers/video/tegra20/tegra-dc.c b/drivers/video/tegra20/tegra-dc.c index f53ad46397..20fa4bb27c 100644 --- a/drivers/video/tegra20/tegra-dc.c +++ b/drivers/video/tegra20/tegra-dc.c @@ -467,6 +467,7 @@ static const struct video_ops tegra_lcd_ops = { static const struct udevice_id tegra_lcd_ids[] = { { .compatible = "nvidia,tegra20-dc" }, { .compatible = "nvidia,tegra30-dc" }, + { .compatible = "nvidia,tegra114-dc" }, { } };

Dedicated MIPI calibration driver is used on T114 and newer. Before T114 MIPI calibration registers were part of VI and CSI.
Signed-off-by: Svyatoslav Ryhel clamor95@gmail.com --- drivers/video/tegra20/Makefile | 2 +- drivers/video/tegra20/tegra-mipi.c | 185 +++++++++++++++++++++++++++++ 2 files changed, 186 insertions(+), 1 deletion(-) create mode 100644 drivers/video/tegra20/tegra-mipi.c
diff --git a/drivers/video/tegra20/Makefile b/drivers/video/tegra20/Makefile index f0b534c579..a75aea2a87 100644 --- a/drivers/video/tegra20/Makefile +++ b/drivers/video/tegra20/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0+
obj-$(CONFIG_VIDEO_TEGRA20) += tegra-dc.o -obj-$(CONFIG_VIDEO_DSI_TEGRA30) += tegra-dsi.o mipi-phy.o +obj-$(CONFIG_VIDEO_DSI_TEGRA30) += tegra-dsi.o tegra-mipi.o mipi-phy.o obj-$(CONFIG_TEGRA_BACKLIGHT_PWM) += tegra-pwm-backlight.o diff --git a/drivers/video/tegra20/tegra-mipi.c b/drivers/video/tegra20/tegra-mipi.c new file mode 100644 index 0000000000..52e5ea0ff6 --- /dev/null +++ b/drivers/video/tegra20/tegra-mipi.c @@ -0,0 +1,185 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2013 NVIDIA Corporation + * Copyright (c) 2023 Svyatoslav Ryhel clamor95@gmail.com + */ + +#include <dm.h> +#include <misc.h> +#include <linux/delay.h> +#include <linux/iopoll.h> + +#include <asm/io.h> +#include <asm/arch/clock.h> + +/* MIPI control registers 0x00 ~ 0x60 */ +struct mipi_ctlr { + uint mipi_cal_ctrl; + uint mipi_cal_autocal_ctrl; + uint mipi_cal_status; + + uint unused1[2]; + + uint mipi_cal_config_csia; + uint mipi_cal_config_csib; + uint mipi_cal_config_csic; + uint mipi_cal_config_csid; + uint mipi_cal_config_csie; + + uint unused2[4]; + + uint mipi_cal_config_dsia; + uint mipi_cal_config_dsib; + uint mipi_cal_config_dsic; + uint mipi_cal_config_dsid; + + uint unused3[4]; + + uint mipi_cal_bias_pad_cfg0; + uint mipi_cal_bias_pad_cfg1; + uint mipi_cal_bias_pad_cfg2; +}; + +#define MIPI_CAL_CTRL_NOISE_FILTER(x) (((x) & 0xf) << 26) +#define MIPI_CAL_CTRL_PRESCALE(x) (((x) & 0x3) << 24) +#define MIPI_CAL_CTRL_CLKEN_OVR BIT(4) +#define MIPI_CAL_CTRL_START BIT(0) + +#define MIPI_CAL_STATUS_DONE BIT(16) +#define MIPI_CAL_STATUS_ACTIVE BIT(0) + +#define MIPI_CAL_OVERIDE(x) (((x) & 0x1) << 30) +#define MIPI_CAL_SEL(x) (((x) & 0x1) << 21) +#define MIPI_CAL_HSPDOS(x) (((x) & 0x1f) << 16) +#define MIPI_CAL_HSPUOS(x) (((x) & 0x1f) << 8) +#define MIPI_CAL_TERMOS(x) (((x) & 0x1f) << 0) + +#define MIPI_CAL_BIAS_PAD_PDVCLAMP BIT(1) +#define MIPI_CAL_BIAS_PAD_E_VCLAMP_REF BIT(0) + +#define MIPI_CAL_BIAS_PAD_DRV_DN_REF(x) (((x) & 0x7) << 16) +#define MIPI_CAL_BIAS_PAD_DRV_UP_REF(x) (((x) & 0x7) << 8) + +#define MIPI_CAL_BIAS_PAD_VCLAMP(x) (((x) & 0x7) << 16) +#define MIPI_CAL_BIAS_PAD_VAUXP(x) (((x) & 0x7) << 4) +#define MIPI_CAL_BIAS_PAD_PDVREG BIT(1) + +struct tegra_mipi_priv { + struct mipi_ctlr *mipi; + int mipi_clk; +}; + +static int tegra_mipi_calibrate(struct udevice *dev, int offset, const void *buf, + int size) +{ + struct tegra_mipi_priv *priv = dev_get_priv(dev); + u32 value; + + value = MIPI_CAL_BIAS_PAD_DRV_DN_REF(0x2) | + MIPI_CAL_BIAS_PAD_DRV_UP_REF(0x0); + writel(value, &priv->mipi->mipi_cal_bias_pad_cfg1); + + value = readl(&priv->mipi->mipi_cal_bias_pad_cfg2); + value &= ~MIPI_CAL_BIAS_PAD_VCLAMP(0x7); + value &= ~MIPI_CAL_BIAS_PAD_VAUXP(0x7); + writel(value, &priv->mipi->mipi_cal_bias_pad_cfg2); + + value = MIPI_CAL_OVERIDE(0x0) | MIPI_CAL_SEL(0x1) | + MIPI_CAL_HSPDOS(0x0) | MIPI_CAL_HSPUOS(0x4) | + MIPI_CAL_TERMOS(0x5); + writel(value, &priv->mipi->mipi_cal_config_dsia); + writel(value, &priv->mipi->mipi_cal_config_dsib); + + /* Deselect PAD C */ + value = readl(&priv->mipi->mipi_cal_config_dsic); + value &= ~(MIPI_CAL_SEL(0x1)); + writel(value, &priv->mipi->mipi_cal_config_dsic); + + /* Deselect PAD D */ + value = readl(&priv->mipi->mipi_cal_config_dsid); + value &= ~(MIPI_CAL_SEL(0x1)); + writel(value, &priv->mipi->mipi_cal_config_dsid); + + value = readl(&priv->mipi->mipi_cal_ctrl); + value &= ~MIPI_CAL_CTRL_NOISE_FILTER(0xf); + value &= ~MIPI_CAL_CTRL_PRESCALE(0x3); + value |= MIPI_CAL_CTRL_NOISE_FILTER(0xa) | + MIPI_CAL_CTRL_PRESCALE(0x2) | + MIPI_CAL_CTRL_CLKEN_OVR; + writel(value, &priv->mipi->mipi_cal_ctrl); + + /* clear any pending status bits */ + value = readl(&priv->mipi->mipi_cal_status); + writel(value, &priv->mipi->mipi_cal_status); + + value = readl(&priv->mipi->mipi_cal_ctrl); + value |= MIPI_CAL_CTRL_START; + writel(value, &priv->mipi->mipi_cal_ctrl); + + /* + * Wait for min 72uS to let calibration logic finish calibration + * sequence codes before waiting for pads idle state to apply the + * results. + */ + udelay(80); + + return readl_poll_sleep_timeout(&priv->mipi->mipi_cal_status, value, + !(value & MIPI_CAL_STATUS_ACTIVE) && + (value & MIPI_CAL_STATUS_DONE), 100, + 250000); +} + +static int tegra_mipi_enable(struct udevice *dev, bool val) +{ + struct tegra_mipi_priv *priv = dev_get_priv(dev); + u32 value; + + clock_enable(priv->mipi_clk); + udelay(2); + reset_set_enable(priv->mipi_clk, 0); + + value = readl(&priv->mipi->mipi_cal_bias_pad_cfg0); + value &= ~MIPI_CAL_BIAS_PAD_PDVCLAMP; + value |= MIPI_CAL_BIAS_PAD_E_VCLAMP_REF; + writel(value, &priv->mipi->mipi_cal_bias_pad_cfg0); + + value = readl(&priv->mipi->mipi_cal_bias_pad_cfg2); + value &= ~MIPI_CAL_BIAS_PAD_PDVREG; + writel(value, &priv->mipi->mipi_cal_bias_pad_cfg2); + + return 0; +} + +static const struct misc_ops tegra_mipi_ops = { + .write = tegra_mipi_calibrate, + .set_enabled = tegra_mipi_enable, +}; + +static int tegra_mipi_probe(struct udevice *dev) +{ + struct tegra_mipi_priv *priv = dev_get_priv(dev); + + priv->mipi = (struct mipi_ctlr *)dev_read_addr_ptr(dev); + if (!priv->mipi) { + log_err("no MIPI controller address\n"); + return -EINVAL; + } + + priv->mipi_clk = clock_decode_periph_id(dev); + + return 0; +} + +static const struct udevice_id tegra_mipi_ids[] = { + { .compatible = "nvidia,tegra114-mipi" }, + { } +}; + +U_BOOT_DRIVER(tegra_mipi) = { + .name = "tegra_mipi", + .id = UCLASS_MISC, + .ops = &tegra_mipi_ops, + .of_match = tegra_mipi_ids, + .probe = tegra_mipi_probe, + .priv_auto = sizeof(struct tegra_mipi_priv), +};

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.
Signed-off-by: Svyatoslav Ryhel clamor95@gmail.com --- arch/arm/include/asm/arch-tegra/dsi.h | 235 ++++++++++++++++++++++++ arch/arm/include/asm/arch-tegra30/dsi.h | 211 +-------------------- drivers/video/tegra20/tegra-dsi.c | 78 +++++++- 3 files changed, 313 insertions(+), 211 deletions(-) create mode 100644 arch/arm/include/asm/arch-tegra/dsi.h
diff --git a/arch/arm/include/asm/arch-tegra/dsi.h b/arch/arm/include/asm/arch-tegra/dsi.h new file mode 100644 index 0000000000..0a399d8d51 --- /dev/null +++ b/arch/arm/include/asm/arch-tegra/dsi.h @@ -0,0 +1,235 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2010 + * NVIDIA Corporation <www.nvidia.com> + */ + +#ifndef __ASM_ARCH_TEGRA_DSI_H +#define __ASM_ARCH_TEGRA_DSI_H + +#ifndef __ASSEMBLY__ +#include <linux/bitops.h> +#endif + +/* Register definitions for the Tegra display serial interface */ + +/* DSI syncpoint register 0x000 ~ 0x002 */ +struct dsi_syncpt_reg { + /* Address 0x000 ~ 0x002 */ + uint incr_syncpt; /* _INCR_SYNCPT_0 */ + uint incr_syncpt_ctrl; /* _INCR_SYNCPT_CNTRL_0 */ + uint incr_syncpt_err; /* _INCR_SYNCPT_ERROR_0 */ +}; + +/* DSI misc register 0x008 ~ 0x015 */ +struct dsi_misc_reg { + /* Address 0x008 ~ 0x015 */ + uint ctxsw; /* _CTXSW_0 */ + uint dsi_rd_data; /* _DSI_RD_DATA_0 */ + uint dsi_wr_data; /* _DSI_WR_DATA_0 */ + uint dsi_pwr_ctrl; /* _DSI_POWER_CONTROL_0 */ + uint int_enable; /* _INT_ENABLE_0 */ + uint int_status; /* _INT_STATUS_0 */ + uint int_mask; /* _INT_MASK_0 */ + uint host_dsi_ctrl; /* _HOST_DSI_CONTROL_0 */ + uint dsi_ctrl; /* _DSI_CONTROL_0 */ + uint dsi_sol_delay; /* _DSI_SOL_DELAY_0 */ + uint dsi_max_threshold; /* _DSI_MAX_THRESHOLD_0 */ + uint dsi_trigger; /* _DSI_TRIGGER_0 */ + uint dsi_tx_crc; /* _DSI_TX_CRC_0 */ + uint dsi_status; /* _DSI_STATUS_0 */ +}; + +/* DSI init sequence register 0x01a ~ 0x022 */ +struct dsi_init_seq_reg { + /* Address 0x01a ~ 0x022 */ + uint dsi_init_seq_ctrl; /* _DSI_INIT_SEQ_CONTROL_0 */ + uint dsi_init_seq_data_0; /* _DSI_INIT_SEQ_DATA_0_0 */ + uint dsi_init_seq_data_1; /* _DSI_INIT_SEQ_DATA_1_0 */ + uint dsi_init_seq_data_2; /* _DSI_INIT_SEQ_DATA_2_0 */ + uint dsi_init_seq_data_3; /* _DSI_INIT_SEQ_DATA_3_0 */ + uint dsi_init_seq_data_4; /* _DSI_INIT_SEQ_DATA_4_0 */ + uint dsi_init_seq_data_5; /* _DSI_INIT_SEQ_DATA_5_0 */ + uint dsi_init_seq_data_6; /* _DSI_INIT_SEQ_DATA_6_0 */ + uint dsi_init_seq_data_7; /* _DSI_INIT_SEQ_DATA_7_0 */ +}; + +/* DSI packet sequence register 0x023 ~ 0x02e */ +struct dsi_pkt_seq_reg { + /* Address 0x023 ~ 0x02e */ + uint dsi_pkt_seq_0_lo; /* _DSI_PKT_SEQ_0_LO_0 */ + uint dsi_pkt_seq_0_hi; /* _DSI_PKT_SEQ_0_HI_0 */ + uint dsi_pkt_seq_1_lo; /* _DSI_PKT_SEQ_1_LO_0 */ + uint dsi_pkt_seq_1_hi; /* _DSI_PKT_SEQ_1_HI_0 */ + uint dsi_pkt_seq_2_lo; /* _DSI_PKT_SEQ_2_LO_0 */ + uint dsi_pkt_seq_2_hi; /* _DSI_PKT_SEQ_2_HI_0 */ + uint dsi_pkt_seq_3_lo; /* _DSI_PKT_SEQ_3_LO_0 */ + uint dsi_pkt_seq_3_hi; /* _DSI_PKT_SEQ_3_HI_0 */ + uint dsi_pkt_seq_4_lo; /* _DSI_PKT_SEQ_4_LO_0 */ + uint dsi_pkt_seq_4_hi; /* _DSI_PKT_SEQ_4_HI_0 */ + uint dsi_pkt_seq_5_lo; /* _DSI_PKT_SEQ_5_LO_0 */ + uint dsi_pkt_seq_5_hi; /* _DSI_PKT_SEQ_5_HI_0 */ +}; + +/* DSI packet length register 0x033 ~ 0x037 */ +struct dsi_pkt_len_reg { + /* Address 0x033 ~ 0x037 */ + uint dsi_dcs_cmds; /* _DSI_DCS_CMDS_0 */ + uint dsi_pkt_len_0_1; /* _DSI_PKT_LEN_0_1_0 */ + uint dsi_pkt_len_2_3; /* _DSI_PKT_LEN_2_3_0 */ + uint dsi_pkt_len_4_5; /* _DSI_PKT_LEN_4_5_0 */ + uint dsi_pkt_len_6_7; /* _DSI_PKT_LEN_6_7_0 */ +}; + +/* DSI PHY timing register 0x03c ~ 0x03f */ +struct dsi_timing_reg { + /* Address 0x03c ~ 0x03f */ + uint dsi_phy_timing_0; /* _DSI_PHY_TIMING_0_0 */ + uint dsi_phy_timing_1; /* _DSI_PHY_TIMING_1_0 */ + uint dsi_phy_timing_2; /* _DSI_PHY_TIMING_2_0 */ + uint dsi_bta_timing; /* _DSI_BTA_TIMING_0 */ +}; + +/* DSI timeout register 0x044 ~ 0x046 */ +struct dsi_timeout_reg { + /* Address 0x044 ~ 0x046 */ + uint dsi_timeout_0; /* _DSI_TIMEOUT_0_0 */ + uint dsi_timeout_1; /* _DSI_TIMEOUT_1_0 */ + uint dsi_to_tally; /* _DSI_TO_TALLY_0 */ +}; + +/* DSI PAD control register 0x04b ~ 0x04e */ +struct dsi_pad_ctrl_reg { + /* Address 0x04b ~ 0x04e */ + uint pad_ctrl; /* _PAD_CONTROL_0 */ + 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 */ +struct dsi_ctlr { + struct dsi_syncpt_reg syncpt; /* SYNCPT register 0x000 ~ 0x002 */ + uint reserved0[5]; /* reserved_0[5] */ + + struct dsi_misc_reg misc; /* MISC register 0x008 ~ 0x015 */ + uint reserved1[4]; /* reserved_1[4] */ + + struct dsi_init_seq_reg init; /* INIT register 0x01a ~ 0x022 */ + struct dsi_pkt_seq_reg pkt; /* PKT register 0x023 ~ 0x02e */ + uint reserved2[4]; /* reserved_2[4] */ + + struct dsi_pkt_len_reg len; /* LEN registers 0x033 ~ 0x037 */ + uint reserved3[4]; /* reserved_3[4] */ + + struct dsi_timing_reg ptiming; /* TIMING registers 0x03c ~ 0x03f */ + uint reserved4[4]; /* reserved_4[4] */ + + struct dsi_timeout_reg timeout; /* TIMEOUT registers 0x044 ~ 0x046 */ + uint reserved5[4]; /* reserved_5[4] */ + + struct dsi_pad_ctrl_reg pad; /* PAD registers 0x04b ~ 0x04e */ +}; + +#define DSI_POWER_CONTROL_ENABLE BIT(0) + +#define DSI_HOST_CONTROL_FIFO_RESET BIT(21) +#define DSI_HOST_CONTROL_CRC_RESET BIT(20) +#define DSI_HOST_CONTROL_TX_TRIG_SOL (0 << 12) +#define DSI_HOST_CONTROL_TX_TRIG_FIFO (1 << 12) +#define DSI_HOST_CONTROL_TX_TRIG_HOST (2 << 12) +#define DSI_HOST_CONTROL_RAW BIT(6) +#define DSI_HOST_CONTROL_HS BIT(5) +#define DSI_HOST_CONTROL_FIFO_SEL BIT(4) +#define DSI_HOST_CONTROL_IMM_BTA BIT(3) +#define DSI_HOST_CONTROL_PKT_BTA BIT(2) +#define DSI_HOST_CONTROL_CS BIT(1) +#define DSI_HOST_CONTROL_ECC BIT(0) + +#define DSI_CONTROL_HS_CLK_CTRL BIT(20) +#define DSI_CONTROL_CHANNEL(c) (((c) & 0x3) << 16) +#define DSI_CONTROL_FORMAT(f) (((f) & 0x3) << 12) +#define DSI_CONTROL_TX_TRIG(x) (((x) & 0x3) << 8) +#define DSI_CONTROL_LANES(n) (((n) & 0x3) << 4) +#define DSI_CONTROL_DCS_ENABLE BIT(3) +#define DSI_CONTROL_SOURCE(s) (((s) & 0x1) << 2) +#define DSI_CONTROL_VIDEO_ENABLE BIT(1) +#define DSI_CONTROL_HOST_ENABLE BIT(0) + +#define DSI_TRIGGER_HOST BIT(1) +#define DSI_TRIGGER_VIDEO BIT(0) + +#define DSI_STATUS_IDLE BIT(10) +#define DSI_STATUS_UNDERFLOW BIT(9) +#define DSI_STATUS_OVERFLOW BIT(8) + +#define DSI_TIMING_FIELD(value, period, hwinc) \ + ((DIV_ROUND_CLOSEST(value, period) - (hwinc)) & 0xff) + +#define DSI_TIMEOUT_LRX(x) (((x) & 0xffff) << 16) +#define DSI_TIMEOUT_HTX(x) (((x) & 0xffff) << 0) +#define DSI_TIMEOUT_PR(x) (((x) & 0xffff) << 16) +#define DSI_TIMEOUT_TA(x) (((x) & 0xffff) << 0) + +#define DSI_TALLY_TA(x) (((x) & 0xff) << 16) +#define DSI_TALLY_LRX(x) (((x) & 0xff) << 8) +#define DSI_TALLY_HTX(x) (((x) & 0xff) << 0) + +#define DSI_PAD_CONTROL_PAD_PULLDN_ENAB(x) (((x) & 0x1) << 28) +#define DSI_PAD_CONTROL_PAD_SLEWUPADJ(x) (((x) & 0x7) << 24) +#define DSI_PAD_CONTROL_PAD_SLEWDNADJ(x) (((x) & 0x7) << 20) +#define DSI_PAD_CONTROL_PAD_PREEMP_EN(x) (((x) & 0x1) << 19) +#define DSI_PAD_CONTROL_PAD_PDIO_CLK(x) (((x) & 0x1) << 18) +#define DSI_PAD_CONTROL_PAD_PDIO(x) (((x) & 0x3) << 16) +#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 + */ +enum tegra_dsi_format { + TEGRA_DSI_FORMAT_16P, + TEGRA_DSI_FORMAT_18NP, + TEGRA_DSI_FORMAT_18P, + TEGRA_DSI_FORMAT_24P, +}; + +/* DSI calibration in VI region */ +#define TEGRA_VI_BASE 0x54080000 + +#define CSI_CILA_MIPI_CAL_CONFIG_0 0x22a +#define MIPI_CAL_TERMOSA(x) (((x) & 0x1f) << 0) + +#define CSI_CILB_MIPI_CAL_CONFIG_0 0x22b +#define MIPI_CAL_TERMOSB(x) (((x) & 0x1f) << 0) + +#define CSI_CIL_PAD_CONFIG 0x229 +#define PAD_CIL_PDVREG(x) (((x) & 0x01) << 1) + +#define CSI_DSI_MIPI_CAL_CONFIG 0x234 +#define MIPI_CAL_HSPDOSD(x) (((x) & 0x1f) << 16) +#define MIPI_CAL_HSPUOSD(x) (((x) & 0x1f) << 8) + +#define CSI_MIPIBIAS_PAD_CONFIG 0x235 +#define PAD_DRIV_DN_REF(x) (((x) & 0x7) << 16) +#define PAD_DRIV_UP_REF(x) (((x) & 0x7) << 8) + +#endif /* __ASM_ARCH_TEGRA_DSI_H */ diff --git a/arch/arm/include/asm/arch-tegra30/dsi.h b/arch/arm/include/asm/arch-tegra30/dsi.h index 7ade132613..811617cd49 100644 --- a/arch/arm/include/asm/arch-tegra30/dsi.h +++ b/arch/arm/include/asm/arch-tegra30/dsi.h @@ -4,214 +4,9 @@ * NVIDIA Corporation <www.nvidia.com> */
-#ifndef __ASM_ARCH_TEGRA_DSI_H -#define __ASM_ARCH_TEGRA_DSI_H +#ifndef __ASM_ARCH_TEGRA30_DSI_H +#define __ASM_ARCH_TEGRA30_DSI_H
-#ifndef __ASSEMBLY__ -#include <linux/bitops.h> -#endif - -/* Register definitions for the Tegra display serial interface */ - -/* DSI syncpoint register 0x000 ~ 0x002 */ -struct dsi_syncpt_reg { - /* Address 0x000 ~ 0x002 */ - uint incr_syncpt; /* _INCR_SYNCPT_0 */ - uint incr_syncpt_ctrl; /* _INCR_SYNCPT_CNTRL_0 */ - uint incr_syncpt_err; /* _INCR_SYNCPT_ERROR_0 */ -}; - -/* DSI misc register 0x008 ~ 0x015 */ -struct dsi_misc_reg { - /* Address 0x008 ~ 0x015 */ - uint ctxsw; /* _CTXSW_0 */ - uint dsi_rd_data; /* _DSI_RD_DATA_0 */ - uint dsi_wr_data; /* _DSI_WR_DATA_0 */ - uint dsi_pwr_ctrl; /* _DSI_POWER_CONTROL_0 */ - uint int_enable; /* _INT_ENABLE_0 */ - uint int_status; /* _INT_STATUS_0 */ - uint int_mask; /* _INT_MASK_0 */ - uint host_dsi_ctrl; /* _HOST_DSI_CONTROL_0 */ - uint dsi_ctrl; /* _DSI_CONTROL_0 */ - uint dsi_sol_delay; /* _DSI_SOL_DELAY_0 */ - uint dsi_max_threshold; /* _DSI_MAX_THRESHOLD_0 */ - uint dsi_trigger; /* _DSI_TRIGGER_0 */ - uint dsi_tx_crc; /* _DSI_TX_CRC_0 */ - uint dsi_status; /* _DSI_STATUS_0 */ -}; - -/* DSI init sequence register 0x01a ~ 0x022 */ -struct dsi_init_seq_reg { - /* Address 0x01a ~ 0x022 */ - uint dsi_init_seq_ctrl; /* _DSI_INIT_SEQ_CONTROL_0 */ - uint dsi_init_seq_data_0; /* _DSI_INIT_SEQ_DATA_0_0 */ - uint dsi_init_seq_data_1; /* _DSI_INIT_SEQ_DATA_1_0 */ - uint dsi_init_seq_data_2; /* _DSI_INIT_SEQ_DATA_2_0 */ - uint dsi_init_seq_data_3; /* _DSI_INIT_SEQ_DATA_3_0 */ - uint dsi_init_seq_data_4; /* _DSI_INIT_SEQ_DATA_4_0 */ - uint dsi_init_seq_data_5; /* _DSI_INIT_SEQ_DATA_5_0 */ - uint dsi_init_seq_data_6; /* _DSI_INIT_SEQ_DATA_6_0 */ - uint dsi_init_seq_data_7; /* _DSI_INIT_SEQ_DATA_7_0 */ -}; - -/* DSI packet sequence register 0x023 ~ 0x02e */ -struct dsi_pkt_seq_reg { - /* Address 0x023 ~ 0x02e */ - uint dsi_pkt_seq_0_lo; /* _DSI_PKT_SEQ_0_LO_0 */ - uint dsi_pkt_seq_0_hi; /* _DSI_PKT_SEQ_0_HI_0 */ - uint dsi_pkt_seq_1_lo; /* _DSI_PKT_SEQ_1_LO_0 */ - uint dsi_pkt_seq_1_hi; /* _DSI_PKT_SEQ_1_HI_0 */ - uint dsi_pkt_seq_2_lo; /* _DSI_PKT_SEQ_2_LO_0 */ - uint dsi_pkt_seq_2_hi; /* _DSI_PKT_SEQ_2_HI_0 */ - uint dsi_pkt_seq_3_lo; /* _DSI_PKT_SEQ_3_LO_0 */ - uint dsi_pkt_seq_3_hi; /* _DSI_PKT_SEQ_3_HI_0 */ - uint dsi_pkt_seq_4_lo; /* _DSI_PKT_SEQ_4_LO_0 */ - uint dsi_pkt_seq_4_hi; /* _DSI_PKT_SEQ_4_HI_0 */ - uint dsi_pkt_seq_5_lo; /* _DSI_PKT_SEQ_5_LO_0 */ - uint dsi_pkt_seq_5_hi; /* _DSI_PKT_SEQ_5_HI_0 */ -}; - -/* DSI packet length register 0x033 ~ 0x037 */ -struct dsi_pkt_len_reg { - /* Address 0x033 ~ 0x037 */ - uint dsi_dcs_cmds; /* _DSI_DCS_CMDS_0 */ - uint dsi_pkt_len_0_1; /* _DSI_PKT_LEN_0_1_0 */ - uint dsi_pkt_len_2_3; /* _DSI_PKT_LEN_2_3_0 */ - uint dsi_pkt_len_4_5; /* _DSI_PKT_LEN_4_5_0 */ - uint dsi_pkt_len_6_7; /* _DSI_PKT_LEN_6_7_0 */ -}; - -/* DSI PHY timing register 0x03c ~ 0x03f */ -struct dsi_timing_reg { - /* Address 0x03c ~ 0x03f */ - uint dsi_phy_timing_0; /* _DSI_PHY_TIMING_0_0 */ - uint dsi_phy_timing_1; /* _DSI_PHY_TIMING_1_0 */ - uint dsi_phy_timing_2; /* _DSI_PHY_TIMING_2_0 */ - uint dsi_bta_timing; /* _DSI_BTA_TIMING_0 */ -}; - -/* DSI timeout register 0x044 ~ 0x046 */ -struct dsi_timeout_reg { - /* Address 0x044 ~ 0x046 */ - uint dsi_timeout_0; /* _DSI_TIMEOUT_0_0 */ - uint dsi_timeout_1; /* _DSI_TIMEOUT_1_0 */ - uint dsi_to_tally; /* _DSI_TO_TALLY_0 */ -}; - -/* DSI PAD control register 0x04b ~ 0x04e */ -struct dsi_pad_ctrl_reg { - /* Address 0x04b ~ 0x04e */ - uint pad_ctrl; /* _PAD_CONTROL_0 */ - 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 */ -}; - -/* Display Serial Interface (DSI_) regs */ -struct dsi_ctlr { - struct dsi_syncpt_reg syncpt; /* SYNCPT register 0x000 ~ 0x002 */ - uint reserved0[5]; /* reserved_0[5] */ - - struct dsi_misc_reg misc; /* MISC register 0x008 ~ 0x015 */ - uint reserved1[4]; /* reserved_1[4] */ - - struct dsi_init_seq_reg init; /* INIT register 0x01a ~ 0x022 */ - struct dsi_pkt_seq_reg pkt; /* PKT register 0x023 ~ 0x02e */ - uint reserved2[4]; /* reserved_2[4] */ - - struct dsi_pkt_len_reg len; /* LEN registers 0x033 ~ 0x037 */ - uint reserved3[4]; /* reserved_3[4] */ - - struct dsi_timing_reg ptiming; /* TIMING registers 0x03c ~ 0x03f */ - uint reserved4[4]; /* reserved_4[4] */ - - struct dsi_timeout_reg timeout; /* TIMEOUT registers 0x044 ~ 0x046 */ - uint reserved5[4]; /* reserved_5[4] */ - - struct dsi_pad_ctrl_reg pad; /* PAD registers 0x04b ~ 0x04e */ -}; - -#define DSI_POWER_CONTROL_ENABLE BIT(0) - -#define DSI_HOST_CONTROL_FIFO_RESET BIT(21) -#define DSI_HOST_CONTROL_CRC_RESET BIT(20) -#define DSI_HOST_CONTROL_TX_TRIG_SOL (0 << 12) -#define DSI_HOST_CONTROL_TX_TRIG_FIFO (1 << 12) -#define DSI_HOST_CONTROL_TX_TRIG_HOST (2 << 12) -#define DSI_HOST_CONTROL_RAW BIT(6) -#define DSI_HOST_CONTROL_HS BIT(5) -#define DSI_HOST_CONTROL_FIFO_SEL BIT(4) -#define DSI_HOST_CONTROL_IMM_BTA BIT(3) -#define DSI_HOST_CONTROL_PKT_BTA BIT(2) -#define DSI_HOST_CONTROL_CS BIT(1) -#define DSI_HOST_CONTROL_ECC BIT(0) - -#define DSI_CONTROL_HS_CLK_CTRL BIT(20) -#define DSI_CONTROL_CHANNEL(c) (((c) & 0x3) << 16) -#define DSI_CONTROL_FORMAT(f) (((f) & 0x3) << 12) -#define DSI_CONTROL_TX_TRIG(x) (((x) & 0x3) << 8) -#define DSI_CONTROL_LANES(n) (((n) & 0x3) << 4) -#define DSI_CONTROL_DCS_ENABLE BIT(3) -#define DSI_CONTROL_SOURCE(s) (((s) & 0x1) << 2) -#define DSI_CONTROL_VIDEO_ENABLE BIT(1) -#define DSI_CONTROL_HOST_ENABLE BIT(0) - -#define DSI_TRIGGER_HOST BIT(1) -#define DSI_TRIGGER_VIDEO BIT(0) - -#define DSI_STATUS_IDLE BIT(10) -#define DSI_STATUS_UNDERFLOW BIT(9) -#define DSI_STATUS_OVERFLOW BIT(8) - -#define DSI_TIMING_FIELD(value, period, hwinc) \ - ((DIV_ROUND_CLOSEST(value, period) - (hwinc)) & 0xff) - -#define DSI_TIMEOUT_LRX(x) (((x) & 0xffff) << 16) -#define DSI_TIMEOUT_HTX(x) (((x) & 0xffff) << 0) -#define DSI_TIMEOUT_PR(x) (((x) & 0xffff) << 16) -#define DSI_TIMEOUT_TA(x) (((x) & 0xffff) << 0) - -#define DSI_TALLY_TA(x) (((x) & 0xff) << 16) -#define DSI_TALLY_LRX(x) (((x) & 0xff) << 8) -#define DSI_TALLY_HTX(x) (((x) & 0xff) << 0) - -#define DSI_PAD_CONTROL_PAD_PULLDN_ENAB(x) (((x) & 0x1) << 28) -#define DSI_PAD_CONTROL_PAD_SLEWUPADJ(x) (((x) & 0x7) << 24) -#define DSI_PAD_CONTROL_PAD_SLEWDNADJ(x) (((x) & 0x7) << 20) -#define DSI_PAD_CONTROL_PAD_PREEMP_EN(x) (((x) & 0x1) << 19) -#define DSI_PAD_CONTROL_PAD_PDIO_CLK(x) (((x) & 0x1) << 18) -#define DSI_PAD_CONTROL_PAD_PDIO(x) (((x) & 0x3) << 16) -#define DSI_PAD_CONTROL_PAD_LPUPADJ(x) (((x) & 0x3) << 14) -#define DSI_PAD_CONTROL_PAD_LPDNADJ(x) (((x) & 0x3) << 12) - -/* - * pixel format as used in the DSI_CONTROL_FORMAT field - */ -enum tegra_dsi_format { - TEGRA_DSI_FORMAT_16P, - TEGRA_DSI_FORMAT_18NP, - TEGRA_DSI_FORMAT_18P, - TEGRA_DSI_FORMAT_24P, -}; - -/* DSI calibration in VI region */ -#define TEGRA_VI_BASE 0x54080000 - -#define CSI_CILA_MIPI_CAL_CONFIG_0 0x22a -#define MIPI_CAL_TERMOSA(x) (((x) & 0x1f) << 0) - -#define CSI_CILB_MIPI_CAL_CONFIG_0 0x22b -#define MIPI_CAL_TERMOSB(x) (((x) & 0x1f) << 0) - -#define CSI_CIL_PAD_CONFIG 0x229 -#define PAD_CIL_PDVREG(x) (((x) & 0x01) << 1) - -#define CSI_DSI_MIPI_CAL_CONFIG 0x234 -#define MIPI_CAL_HSPDOSD(x) (((x) & 0x1f) << 16) -#define MIPI_CAL_HSPUOSD(x) (((x) & 0x1f) << 8) - -#define CSI_MIPIBIAS_PAD_CONFIG 0x235 -#define PAD_DRIV_DN_REF(x) (((x) & 0x7) << 16) -#define PAD_DRIV_UP_REF(x) (((x) & 0x7) << 8) +#include <asm/arch-tegra/dsi.h>
#endif /* __ASM_ARCH_TEGRA_DSI_H */ diff --git a/drivers/video/tegra20/tegra-dsi.c b/drivers/video/tegra20/tegra-dsi.c index a48f9c85d0..b9cd63903a 100644 --- a/drivers/video/tegra20/tegra-dsi.c +++ b/drivers/video/tegra20/tegra-dsi.c @@ -21,16 +21,23 @@ #include <asm/io.h> #include <asm/arch/clock.h> #include <asm/arch/display.h> -#include <asm/arch-tegra30/dsi.h> +#include <asm/arch-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_err("%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) + 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);
@@ -792,6 +851,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__); @@ -814,6 +875,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_err("cannot get MIPI: error %d\n", ret); + return log_ret(ret); + } + } + panel_get_display_timing(priv->panel, &priv->timing);
mipi_plat = dev_get_plat(priv->panel); @@ -845,7 +916,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 }, { } };
participants (1)
-
Svyatoslav Ryhel