diff options
author | Simon Glass <sjg@chromium.org> | 2015-04-14 21:03:44 -0600 |
---|---|---|
committer | Tom Warren <twarren@nvidia.com> | 2015-05-13 09:24:12 -0700 |
commit | dedc44b466ba24bd4f38840a79067d806d37d709 (patch) | |
tree | f371ffada3e1b602c30433aff3af0baaead170f9 /drivers/video/tegra124/sor.c | |
parent | 531eaedc7a397b34979c6d35e5de7b78d2dddfde (diff) | |
download | u-boot-dedc44b466ba24bd4f38840a79067d806d37d709.tar.gz |
tegra124: video: Add full link training for eDP
Add full link training as a fallback in case the fast link training
fails.
Signed-off-by: Simon Glass <sjg@chromium.org>
Acked-by: Anatolij Gustschin <agust@denx.de>
Signed-off-by: Tom Warren <twarren@nvidia.com>
Diffstat (limited to 'drivers/video/tegra124/sor.c')
-rw-r--r-- | drivers/video/tegra124/sor.c | 160 |
1 files changed, 144 insertions, 16 deletions
diff --git a/drivers/video/tegra124/sor.c b/drivers/video/tegra124/sor.c index faeda4cb7b3..aa3d80c4c0f 100644 --- a/drivers/video/tegra124/sor.c +++ b/drivers/video/tegra124/sor.c @@ -57,6 +57,23 @@ static inline void tegra_sor_write_field(struct tegra_dc_sor_data *sor, tegra_sor_writel(sor, reg, reg_val); } +void tegra_dp_disable_tx_pu(struct tegra_dc_sor_data *sor) +{ + tegra_sor_write_field(sor, DP_PADCTL(sor->portnum), + DP_PADCTL_TX_PU_MASK, DP_PADCTL_TX_PU_DISABLE); +} + +void tegra_dp_set_pe_vs_pc(struct tegra_dc_sor_data *sor, u32 mask, u32 pe_reg, + u32 vs_reg, u32 pc_reg, u8 pc_supported) +{ + tegra_sor_write_field(sor, PR(sor->portnum), mask, pe_reg); + tegra_sor_write_field(sor, DC(sor->portnum), mask, vs_reg); + if (pc_supported) { + tegra_sor_write_field(sor, POSTCURSOR(sor->portnum), mask, + pc_reg); + } +} + static int tegra_dc_sor_poll_register(struct tegra_dc_sor_data *sor, u32 reg, u32 mask, u32 exp_val, int poll_interval_us, int timeout_ms) @@ -808,12 +825,36 @@ void tegra_dc_sor_set_lane_parm(struct tegra_dc_sor_data *sor, tegra_sor_write_field(sor, DP_PADCTL(sor->portnum), 0xf0, 0x0); } +int tegra_dc_sor_set_voltage_swing(struct tegra_dc_sor_data *sor, + const struct tegra_dp_link_config *link_cfg) +{ + u32 drive_current = 0; + u32 pre_emphasis = 0; + + /* Set to a known-good pre-calibrated setting */ + switch (link_cfg->link_bw) { + case SOR_LINK_SPEED_G1_62: + case SOR_LINK_SPEED_G2_7: + drive_current = 0x13131313; + pre_emphasis = 0; + break; + case SOR_LINK_SPEED_G5_4: + debug("T124 does not support 5.4G link clock.\n"); + default: + debug("Invalid sor link bandwidth: %d\n", link_cfg->link_bw); + return -ENOLINK; + } + + tegra_sor_writel(sor, LANE_DRIVE_CURRENT(sor->portnum), drive_current); + tegra_sor_writel(sor, PR(sor->portnum), pre_emphasis); + + return 0; +} + void tegra_dc_sor_power_down_unused_lanes(struct tegra_dc_sor_data *sor, const struct tegra_dp_link_config *link_cfg) { u32 pad_ctrl = 0; - u32 drive_current = 0; - u32 pre_emphasis = 0; int err = 0; switch (link_cfg->lane_count) { @@ -848,25 +889,112 @@ void tegra_dc_sor_power_down_unused_lanes(struct tegra_dc_sor_data *sor, debug("Wait for lane power down failed: %d\n", err); return; } +} - /* Set to a known-good pre-calibrated setting */ - switch (link_cfg->link_bw) { - case SOR_LINK_SPEED_G1_62: - case SOR_LINK_SPEED_G2_7: - drive_current = 0x13131313; - pre_emphasis = 0; +int tegra_sor_precharge_lanes(struct tegra_dc_sor_data *sor, + const struct tegra_dp_link_config *cfg) +{ + u32 val = 0; + + switch (cfg->lane_count) { + case 4: + val |= (DP_PADCTL_PD_TXD_3_NO | + DP_PADCTL_PD_TXD_2_NO); + /* fall through */ + case 2: + val |= DP_PADCTL_PD_TXD_1_NO; + /* fall through */ + case 1: + val |= DP_PADCTL_PD_TXD_0_NO; break; - case SOR_LINK_SPEED_G5_4: - drive_current = 0x19191919; - pre_emphasis = 0x09090909; default: - printf("Invalid sor link bandwidth: %d\n", link_cfg->link_bw); - return; + debug("dp: invalid lane number %d\n", cfg->lane_count); + return -EINVAL; } - tegra_sor_writel(sor, LANE_DRIVE_CURRENT(sor->portnum), - drive_current); - tegra_sor_writel(sor, PR(sor->portnum), pre_emphasis); + tegra_sor_write_field(sor, DP_PADCTL(sor->portnum), + (0xf << DP_PADCTL_COMODE_TXD_0_DP_TXD_2_SHIFT), + (val << DP_PADCTL_COMODE_TXD_0_DP_TXD_2_SHIFT)); + udelay(100); + tegra_sor_write_field(sor, DP_PADCTL(sor->portnum), + (0xf << DP_PADCTL_COMODE_TXD_0_DP_TXD_2_SHIFT), + 0); + + return 0; +} + +static void tegra_dc_sor_enable_sor(struct dc_ctlr *disp_ctrl, bool enable) +{ + u32 reg_val = readl(&disp_ctrl->disp.disp_win_opt); + + reg_val = enable ? reg_val | SOR_ENABLE : reg_val & ~SOR_ENABLE; + writel(reg_val, &disp_ctrl->disp.disp_win_opt); +} + +int tegra_dc_sor_detach(struct tegra_dc_sor_data *sor) +{ + int dc_reg_ctx[DC_REG_SAVE_SPACE]; + const void *blob = gd->fdt_blob; + struct dc_ctlr *disp_ctrl; + unsigned long dc_int_mask; + int node; + int ret; + + debug("%s\n", __func__); + /* Use the first display controller */ + node = fdtdec_next_compatible(blob, 0, COMPAT_NVIDIA_TEGRA124_DC); + if (node < 0) { + ret = -ENOENT; + goto err; + } + disp_ctrl = (struct dc_ctlr *)fdtdec_get_addr(blob, node, "reg"); + + /* Sleep mode */ + tegra_sor_writel(sor, SUPER_STATE1, SUPER_STATE1_ASY_HEAD_OP_SLEEP | + SUPER_STATE1_ASY_ORMODE_SAFE | + SUPER_STATE1_ATTACHED_YES); + tegra_dc_sor_super_update(sor); + + tegra_dc_sor_disable_win_short_raster(disp_ctrl, dc_reg_ctx); + + if (tegra_dc_sor_poll_register(sor, TEST, + TEST_ACT_HEAD_OPMODE_DEFAULT_MASK, + TEST_ACT_HEAD_OPMODE_SLEEP, 100, + TEGRA_SOR_ATTACH_TIMEOUT_MS)) { + debug("dc timeout waiting for OPMOD = SLEEP\n"); + ret = -ETIMEDOUT; + goto err; + } + + tegra_sor_writel(sor, SUPER_STATE1, SUPER_STATE1_ASY_HEAD_OP_SLEEP | + SUPER_STATE1_ASY_ORMODE_SAFE | + SUPER_STATE1_ATTACHED_NO); + + /* Mask DC interrupts during the 2 dummy frames required for detach */ + dc_int_mask = readl(&disp_ctrl->cmd.int_mask); + writel(0, &disp_ctrl->cmd.int_mask); + + /* Stop DC->SOR path */ + tegra_dc_sor_enable_sor(disp_ctrl, false); + ret = tegra_dc_sor_general_act(disp_ctrl); + if (ret) + goto err; + + /* Stop DC */ + writel(CTRL_MODE_STOP << CTRL_MODE_SHIFT, &disp_ctrl->cmd.disp_cmd); + ret = tegra_dc_sor_general_act(disp_ctrl); + if (ret) + goto err; + + tegra_dc_sor_restore_win_and_raster(disp_ctrl, dc_reg_ctx); + + writel(dc_int_mask, &disp_ctrl->cmd.int_mask); + + return 0; +err: + debug("%s: ret=%d\n", __func__, ret); + + return ret; } int tegra_dc_sor_init(struct tegra_dc_sor_data **sorp) |