mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-12 21:44:06 +08:00
drm/tegra: sor: Stabilize eDP
Rework eDP code to correspond more closely to what's documented. This also improves the reliability of modesets. Signed-off-by: Thierry Reding <treding@nvidia.com>
This commit is contained in:
parent
6f684de537
commit
38b445bc13
@ -1878,119 +1878,80 @@ static void tegra_sor_edp_enable(struct drm_encoder *encoder)
|
|||||||
|
|
||||||
pm_runtime_get_sync(sor->dev);
|
pm_runtime_get_sync(sor->dev);
|
||||||
|
|
||||||
if (output->panel)
|
|
||||||
drm_panel_prepare(output->panel);
|
|
||||||
|
|
||||||
err = drm_dp_aux_enable(sor->aux);
|
|
||||||
if (err < 0)
|
|
||||||
dev_err(sor->dev, "failed to enable DP: %d\n", err);
|
|
||||||
|
|
||||||
err = drm_dp_link_probe(sor->aux, &sor->link);
|
|
||||||
if (err < 0) {
|
|
||||||
dev_err(sor->dev, "failed to probe eDP link: %d\n", err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* switch to safe parent clock */
|
/* switch to safe parent clock */
|
||||||
err = tegra_sor_set_parent_clock(sor, sor->clk_safe);
|
err = tegra_sor_set_parent_clock(sor, sor->clk_safe);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
dev_err(sor->dev, "failed to set safe parent clock: %d\n", err);
|
dev_err(sor->dev, "failed to set safe parent clock: %d\n", err);
|
||||||
|
|
||||||
value = tegra_sor_readl(sor, SOR_CLK_CNTRL);
|
err = tegra_io_rail_power_on(TEGRA_IO_RAIL_LVDS);
|
||||||
value &= ~SOR_CLK_CNTRL_DP_CLK_SEL_MASK;
|
if (err < 0)
|
||||||
value |= SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_DPCLK;
|
dev_err(sor->dev, "failed to power on LVDS rail: %d\n", err);
|
||||||
tegra_sor_writel(sor, value, SOR_CLK_CNTRL);
|
|
||||||
|
usleep_range(20, 100);
|
||||||
|
|
||||||
|
err = drm_dp_aux_enable(sor->aux);
|
||||||
|
if (err < 0)
|
||||||
|
dev_err(sor->dev, "failed to enable DPAUX: %d\n", err);
|
||||||
|
|
||||||
|
err = drm_dp_link_probe(sor->aux, &sor->link);
|
||||||
|
if (err < 0)
|
||||||
|
dev_err(sor->dev, "failed to probe eDP link: %d\n", err);
|
||||||
|
|
||||||
|
err = drm_dp_link_choose(&sor->link, mode, info);
|
||||||
|
if (err < 0)
|
||||||
|
dev_err(sor->dev, "failed to choose link: %d\n", err);
|
||||||
|
|
||||||
|
if (output->panel)
|
||||||
|
drm_panel_prepare(output->panel);
|
||||||
|
|
||||||
value = tegra_sor_readl(sor, sor->soc->regs->pll2);
|
value = tegra_sor_readl(sor, sor->soc->regs->pll2);
|
||||||
value &= ~SOR_PLL2_BANDGAP_POWERDOWN;
|
value &= ~SOR_PLL2_BANDGAP_POWERDOWN;
|
||||||
tegra_sor_writel(sor, value, sor->soc->regs->pll2);
|
tegra_sor_writel(sor, value, sor->soc->regs->pll2);
|
||||||
usleep_range(20, 100);
|
|
||||||
|
usleep_range(20, 40);
|
||||||
|
|
||||||
value = tegra_sor_readl(sor, sor->soc->regs->pll3);
|
value = tegra_sor_readl(sor, sor->soc->regs->pll3);
|
||||||
value |= SOR_PLL3_PLL_VDD_MODE_3V3;
|
value |= SOR_PLL3_PLL_VDD_MODE_3V3;
|
||||||
tegra_sor_writel(sor, value, sor->soc->regs->pll3);
|
tegra_sor_writel(sor, value, sor->soc->regs->pll3);
|
||||||
|
|
||||||
value = SOR_PLL0_ICHPMP(0xf) | SOR_PLL0_VCOCAP_RST |
|
value = tegra_sor_readl(sor, sor->soc->regs->pll0);
|
||||||
SOR_PLL0_PLLREG_LEVEL_V45 | SOR_PLL0_RESISTOR_EXT;
|
value &= ~(SOR_PLL0_VCOPD | SOR_PLL0_PWR);
|
||||||
tegra_sor_writel(sor, value, sor->soc->regs->pll0);
|
tegra_sor_writel(sor, value, sor->soc->regs->pll0);
|
||||||
|
|
||||||
value = tegra_sor_readl(sor, sor->soc->regs->pll2);
|
value = tegra_sor_readl(sor, sor->soc->regs->pll2);
|
||||||
value |= SOR_PLL2_SEQ_PLLCAPPD;
|
|
||||||
value &= ~SOR_PLL2_SEQ_PLLCAPPD_ENFORCE;
|
value &= ~SOR_PLL2_SEQ_PLLCAPPD_ENFORCE;
|
||||||
value |= SOR_PLL2_LVDS_ENABLE;
|
value |= SOR_PLL2_SEQ_PLLCAPPD;
|
||||||
tegra_sor_writel(sor, value, sor->soc->regs->pll2);
|
tegra_sor_writel(sor, value, sor->soc->regs->pll2);
|
||||||
|
|
||||||
value = SOR_PLL1_TERM_COMPOUT | SOR_PLL1_TMDS_TERM;
|
usleep_range(200, 400);
|
||||||
tegra_sor_writel(sor, value, sor->soc->regs->pll1);
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
value = tegra_sor_readl(sor, sor->soc->regs->pll2);
|
|
||||||
if ((value & SOR_PLL2_SEQ_PLLCAPPD_ENFORCE) == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
usleep_range(250, 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
value = tegra_sor_readl(sor, sor->soc->regs->pll2);
|
value = tegra_sor_readl(sor, sor->soc->regs->pll2);
|
||||||
value &= ~SOR_PLL2_POWERDOWN_OVERRIDE;
|
value &= ~SOR_PLL2_POWERDOWN_OVERRIDE;
|
||||||
value &= ~SOR_PLL2_PORT_POWERDOWN;
|
value &= ~SOR_PLL2_PORT_POWERDOWN;
|
||||||
tegra_sor_writel(sor, value, sor->soc->regs->pll2);
|
tegra_sor_writel(sor, value, sor->soc->regs->pll2);
|
||||||
|
|
||||||
/*
|
|
||||||
* power up
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* set safe link bandwidth (1.62 Gbps) */
|
|
||||||
value = tegra_sor_readl(sor, SOR_CLK_CNTRL);
|
value = tegra_sor_readl(sor, SOR_CLK_CNTRL);
|
||||||
value &= ~SOR_CLK_CNTRL_DP_LINK_SPEED_MASK;
|
value &= ~SOR_CLK_CNTRL_DP_CLK_SEL_MASK;
|
||||||
value |= SOR_CLK_CNTRL_DP_LINK_SPEED_G1_62;
|
value |= SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_DPCLK;
|
||||||
tegra_sor_writel(sor, value, SOR_CLK_CNTRL);
|
tegra_sor_writel(sor, value, SOR_CLK_CNTRL);
|
||||||
|
|
||||||
/* step 1 */
|
value = tegra_sor_readl(sor, SOR_DP_SPARE0);
|
||||||
value = tegra_sor_readl(sor, sor->soc->regs->pll2);
|
/* XXX not in TRM */
|
||||||
value |= SOR_PLL2_SEQ_PLLCAPPD_ENFORCE | SOR_PLL2_PORT_POWERDOWN |
|
value |= SOR_DP_SPARE_PANEL_INTERNAL;
|
||||||
SOR_PLL2_BANDGAP_POWERDOWN;
|
value |= SOR_DP_SPARE_SEQ_ENABLE;
|
||||||
tegra_sor_writel(sor, value, sor->soc->regs->pll2);
|
tegra_sor_writel(sor, value, SOR_DP_SPARE0);
|
||||||
|
|
||||||
|
/* XXX not in TRM */
|
||||||
|
tegra_sor_writel(sor, 0, SOR_LVDS);
|
||||||
|
|
||||||
value = tegra_sor_readl(sor, sor->soc->regs->pll0);
|
value = tegra_sor_readl(sor, sor->soc->regs->pll0);
|
||||||
value |= SOR_PLL0_VCOPD | SOR_PLL0_PWR;
|
value &= ~SOR_PLL0_ICHPMP_MASK;
|
||||||
|
value &= ~SOR_PLL0_VCOCAP_MASK;
|
||||||
|
value |= SOR_PLL0_ICHPMP(0x1);
|
||||||
|
value |= SOR_PLL0_VCOCAP(0x3);
|
||||||
|
value |= SOR_PLL0_RESISTOR_EXT;
|
||||||
tegra_sor_writel(sor, value, sor->soc->regs->pll0);
|
tegra_sor_writel(sor, value, sor->soc->regs->pll0);
|
||||||
|
|
||||||
value = tegra_sor_readl(sor, sor->soc->regs->dp_padctl0);
|
|
||||||
value &= ~SOR_DP_PADCTL_PAD_CAL_PD;
|
|
||||||
tegra_sor_writel(sor, value, sor->soc->regs->dp_padctl0);
|
|
||||||
|
|
||||||
/* step 2 */
|
|
||||||
err = tegra_io_pad_power_enable(sor->pad);
|
|
||||||
if (err < 0)
|
|
||||||
dev_err(sor->dev, "failed to power on I/O pad: %d\n", err);
|
|
||||||
|
|
||||||
usleep_range(5, 100);
|
|
||||||
|
|
||||||
/* step 3 */
|
|
||||||
value = tegra_sor_readl(sor, sor->soc->regs->pll2);
|
|
||||||
value &= ~SOR_PLL2_BANDGAP_POWERDOWN;
|
|
||||||
tegra_sor_writel(sor, value, sor->soc->regs->pll2);
|
|
||||||
|
|
||||||
usleep_range(20, 100);
|
|
||||||
|
|
||||||
/* step 4 */
|
|
||||||
value = tegra_sor_readl(sor, sor->soc->regs->pll0);
|
|
||||||
value &= ~SOR_PLL0_VCOPD;
|
|
||||||
value &= ~SOR_PLL0_PWR;
|
|
||||||
tegra_sor_writel(sor, value, sor->soc->regs->pll0);
|
|
||||||
|
|
||||||
value = tegra_sor_readl(sor, sor->soc->regs->pll2);
|
|
||||||
value &= ~SOR_PLL2_SEQ_PLLCAPPD_ENFORCE;
|
|
||||||
tegra_sor_writel(sor, value, sor->soc->regs->pll2);
|
|
||||||
|
|
||||||
usleep_range(200, 1000);
|
|
||||||
|
|
||||||
/* step 5 */
|
|
||||||
value = tegra_sor_readl(sor, sor->soc->regs->pll2);
|
|
||||||
value &= ~SOR_PLL2_PORT_POWERDOWN;
|
|
||||||
tegra_sor_writel(sor, value, sor->soc->regs->pll2);
|
|
||||||
|
|
||||||
/* XXX not in TRM */
|
/* XXX not in TRM */
|
||||||
for (value = 0, i = 0; i < 5; i++)
|
for (value = 0, i = 0; i < 5; i++)
|
||||||
value |= SOR_XBAR_CTRL_LINK0_XSEL(i, sor->xbar_cfg[i]) |
|
value |= SOR_XBAR_CTRL_LINK0_XSEL(i, sor->xbar_cfg[i]) |
|
||||||
@ -2015,7 +1976,6 @@ static void tegra_sor_edp_enable(struct drm_encoder *encoder)
|
|||||||
value |= SOR_DP_LINKCTL_ENABLE;
|
value |= SOR_DP_LINKCTL_ENABLE;
|
||||||
tegra_sor_writel(sor, value, SOR_DP_LINKCTL0);
|
tegra_sor_writel(sor, value, SOR_DP_LINKCTL0);
|
||||||
|
|
||||||
/* calibrate termination resistance (XXX do this only on HPD) */
|
|
||||||
tegra_sor_dp_term_calibrate(sor);
|
tegra_sor_dp_term_calibrate(sor);
|
||||||
|
|
||||||
err = drm_dp_link_train(&sor->link);
|
err = drm_dp_link_train(&sor->link);
|
||||||
@ -2025,21 +1985,16 @@ static void tegra_sor_edp_enable(struct drm_encoder *encoder)
|
|||||||
dev_dbg(sor->dev, "link training succeeded\n");
|
dev_dbg(sor->dev, "link training succeeded\n");
|
||||||
|
|
||||||
err = drm_dp_link_power_up(sor->aux, &sor->link);
|
err = drm_dp_link_power_up(sor->aux, &sor->link);
|
||||||
if (err < 0) {
|
if (err < 0)
|
||||||
dev_err(sor->dev, "failed to power up eDP link: %d\n",
|
dev_err(sor->dev, "failed to power up eDP link: %d\n", err);
|
||||||
err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* compute configuration */
|
/* compute configuration */
|
||||||
memset(&config, 0, sizeof(config));
|
memset(&config, 0, sizeof(config));
|
||||||
config.bits_per_pixel = state->bpc * 3;
|
config.bits_per_pixel = state->bpc * 3;
|
||||||
|
|
||||||
err = tegra_sor_compute_config(sor, mode, &config, &sor->link);
|
err = tegra_sor_compute_config(sor, mode, &config, &sor->link);
|
||||||
if (err < 0) {
|
if (err < 0)
|
||||||
dev_err(sor->dev, "failed to compute configuration: %d\n", err);
|
dev_err(sor->dev, "failed to compute configuration: %d\n", err);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
tegra_sor_apply_config(sor, &config);
|
tegra_sor_apply_config(sor, &config);
|
||||||
|
|
||||||
@ -2067,19 +2022,24 @@ static void tegra_sor_edp_enable(struct drm_encoder *encoder)
|
|||||||
|
|
||||||
tegra_sor_update(sor);
|
tegra_sor_update(sor);
|
||||||
|
|
||||||
|
err = tegra_sor_power_up(sor, 250);
|
||||||
|
if (err < 0)
|
||||||
|
dev_err(sor->dev, "failed to power up SOR: %d\n", err);
|
||||||
|
|
||||||
|
/* attach and wake up */
|
||||||
|
err = tegra_sor_attach(sor);
|
||||||
|
if (err < 0)
|
||||||
|
dev_err(sor->dev, "failed to attach SOR: %d\n", err);
|
||||||
|
|
||||||
value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
|
value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
|
||||||
value |= SOR_ENABLE(0);
|
value |= SOR_ENABLE(0);
|
||||||
tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
|
tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
|
||||||
|
|
||||||
tegra_dc_commit(dc);
|
tegra_dc_commit(dc);
|
||||||
|
|
||||||
err = tegra_sor_attach(sor);
|
|
||||||
if (err < 0)
|
|
||||||
dev_err(sor->dev, "failed to attach SOR: %d\n", err);
|
|
||||||
|
|
||||||
err = tegra_sor_wakeup(sor);
|
err = tegra_sor_wakeup(sor);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
dev_err(sor->dev, "failed to enable DC: %d\n", err);
|
dev_err(sor->dev, "failed to wakeup SOR: %d\n", err);
|
||||||
|
|
||||||
if (output->panel)
|
if (output->panel)
|
||||||
drm_panel_enable(output->panel);
|
drm_panel_enable(output->panel);
|
||||||
|
Loading…
Reference in New Issue
Block a user