aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThierry Reding <treding@nvidia.com>2017-10-12 13:14:21 -0400
committerThierry Reding <treding@nvidia.com>2017-12-13 08:36:37 -0500
commit36e90221acf37dd0eb5dee70cd189cc60f2e501a (patch)
tree48c2fdf1dec0ac4a68357a76bd807e990ca9063d
parentc57997bce423fb71334a1fefa524569e48a1718f (diff)
drm/tegra: sor: Support HDMI 2.0 modes
In addition to using the SCDC helpers to enable support for scrambling for HDMI 2.0 modes, take into account the high pixel clocks when programming some of the registers. Signed-off-by: Thierry Reding <treding@nvidia.com>
-rw-r--r--drivers/gpu/drm/tegra/sor.c121
-rw-r--r--drivers/gpu/drm/tegra/sor.h4
2 files changed, 119 insertions, 6 deletions
diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c
index 1d7f24df0b10..f6313c4d612e 100644
--- a/drivers/gpu/drm/tegra/sor.c
+++ b/drivers/gpu/drm/tegra/sor.c
@@ -22,6 +22,7 @@
22#include <drm/drm_atomic_helper.h> 22#include <drm/drm_atomic_helper.h>
23#include <drm/drm_dp_helper.h> 23#include <drm/drm_dp_helper.h>
24#include <drm/drm_panel.h> 24#include <drm/drm_panel.h>
25#include <drm/drm_scdc_helper.h>
25 26
26#include "dc.h" 27#include "dc.h"
27#include "drm.h" 28#include "drm.h"
@@ -350,11 +351,16 @@ struct tegra_sor {
350 struct regulator *avdd_io_supply; 351 struct regulator *avdd_io_supply;
351 struct regulator *vdd_pll_supply; 352 struct regulator *vdd_pll_supply;
352 struct regulator *hdmi_supply; 353 struct regulator *hdmi_supply;
354
355 struct delayed_work scdc;
356 bool scdc_enabled;
353}; 357};
354 358
355struct tegra_sor_state { 359struct tegra_sor_state {
356 struct drm_connector_state base; 360 struct drm_connector_state base;
357 361
362 unsigned int link_speed;
363 unsigned long pclk;
358 unsigned int bpc; 364 unsigned int bpc;
359}; 365};
360 366
@@ -1489,10 +1495,6 @@ static enum drm_mode_status
1489tegra_sor_connector_mode_valid(struct drm_connector *connector, 1495tegra_sor_connector_mode_valid(struct drm_connector *connector,
1490 struct drm_display_mode *mode) 1496 struct drm_display_mode *mode)
1491{ 1497{
1492 /* HDMI 2.0 modes are not yet supported */
1493 if (mode->clock > 340000)
1494 return MODE_NOCLOCK;
1495
1496 return MODE_OK; 1498 return MODE_OK;
1497} 1499}
1498 1500
@@ -1917,6 +1919,18 @@ tegra_sor_encoder_atomic_check(struct drm_encoder *encoder,
1917 1919
1918 info = &output->connector.display_info; 1920 info = &output->connector.display_info;
1919 1921
1922 /*
1923 * For HBR2 modes, the SOR brick needs to use the x20 multiplier, so
1924 * the pixel clock must be corrected accordingly.
1925 */
1926 if (pclk >= 340000000) {
1927 state->link_speed = 20;
1928 state->pclk = pclk / 2;
1929 } else {
1930 state->link_speed = 10;
1931 state->pclk = pclk;
1932 }
1933
1920 err = tegra_dc_state_setup_clock(dc, crtc_state, sor->clk_parent, 1934 err = tegra_dc_state_setup_clock(dc, crtc_state, sor->clk_parent,
1921 pclk, 0); 1935 pclk, 0);
1922 if (err < 0) { 1936 if (err < 0) {
@@ -2067,6 +2081,81 @@ tegra_sor_hdmi_find_settings(struct tegra_sor *sor, unsigned long frequency)
2067 return NULL; 2081 return NULL;
2068} 2082}
2069 2083
2084static void tegra_sor_hdmi_disable_scrambling(struct tegra_sor *sor)
2085{
2086 u32 value;
2087
2088 value = tegra_sor_readl(sor, SOR_HDMI2_CTRL);
2089 value &= ~SOR_HDMI2_CTRL_CLOCK_MODE_DIV_BY_4;
2090 value &= ~SOR_HDMI2_CTRL_SCRAMBLE;
2091 tegra_sor_writel(sor, value, SOR_HDMI2_CTRL);
2092}
2093
2094static void tegra_sor_hdmi_scdc_disable(struct tegra_sor *sor)
2095{
2096 struct i2c_adapter *ddc = sor->output.ddc;
2097
2098 drm_scdc_set_high_tmds_clock_ratio(ddc, false);
2099 drm_scdc_set_scrambling(ddc, false);
2100
2101 tegra_sor_hdmi_disable_scrambling(sor);
2102}
2103
2104static void tegra_sor_hdmi_scdc_stop(struct tegra_sor *sor)
2105{
2106 if (sor->scdc_enabled) {
2107 cancel_delayed_work_sync(&sor->scdc);
2108 tegra_sor_hdmi_scdc_disable(sor);
2109 }
2110}
2111
2112static void tegra_sor_hdmi_enable_scrambling(struct tegra_sor *sor)
2113{
2114 u32 value;
2115
2116 value = tegra_sor_readl(sor, SOR_HDMI2_CTRL);
2117 value |= SOR_HDMI2_CTRL_CLOCK_MODE_DIV_BY_4;
2118 value |= SOR_HDMI2_CTRL_SCRAMBLE;
2119 tegra_sor_writel(sor, value, SOR_HDMI2_CTRL);
2120}
2121
2122static void tegra_sor_hdmi_scdc_enable(struct tegra_sor *sor)
2123{
2124 struct i2c_adapter *ddc = sor->output.ddc;
2125
2126 drm_scdc_set_high_tmds_clock_ratio(ddc, true);
2127 drm_scdc_set_scrambling(ddc, true);
2128
2129 tegra_sor_hdmi_enable_scrambling(sor);
2130}
2131
2132static void tegra_sor_hdmi_scdc_work(struct work_struct *work)
2133{
2134 struct tegra_sor *sor = container_of(work, struct tegra_sor, scdc.work);
2135 struct i2c_adapter *ddc = sor->output.ddc;
2136
2137 if (!drm_scdc_get_scrambling_status(ddc)) {
2138 DRM_DEBUG_KMS("SCDC not scrambled\n");
2139 tegra_sor_hdmi_scdc_enable(sor);
2140 }
2141
2142 schedule_delayed_work(&sor->scdc, msecs_to_jiffies(5000));
2143}
2144
2145static void tegra_sor_hdmi_scdc_start(struct tegra_sor *sor)
2146{
2147 struct drm_scdc *scdc = &sor->output.connector.display_info.hdmi.scdc;
2148 struct drm_display_mode *mode;
2149
2150 mode = &sor->output.encoder.crtc->state->adjusted_mode;
2151
2152 if (mode->clock >= 340000 && scdc->supported) {
2153 schedule_delayed_work(&sor->scdc, msecs_to_jiffies(5000));
2154 tegra_sor_hdmi_scdc_enable(sor);
2155 sor->scdc_enabled = true;
2156 }
2157}
2158
2070static void tegra_sor_hdmi_disable(struct drm_encoder *encoder) 2159static void tegra_sor_hdmi_disable(struct drm_encoder *encoder)
2071{ 2160{
2072 struct tegra_output *output = encoder_to_output(encoder); 2161 struct tegra_output *output = encoder_to_output(encoder);
@@ -2075,6 +2164,8 @@ static void tegra_sor_hdmi_disable(struct drm_encoder *encoder)
2075 u32 value; 2164 u32 value;
2076 int err; 2165 int err;
2077 2166
2167 tegra_sor_hdmi_scdc_stop(sor);
2168
2078 err = tegra_sor_detach(sor); 2169 err = tegra_sor_detach(sor);
2079 if (err < 0) 2170 if (err < 0)
2080 dev_err(sor->dev, "failed to detach SOR: %d\n", err); 2171 dev_err(sor->dev, "failed to detach SOR: %d\n", err);
@@ -2114,12 +2205,14 @@ static void tegra_sor_hdmi_enable(struct drm_encoder *encoder)
2114 struct tegra_sor *sor = to_sor(output); 2205 struct tegra_sor *sor = to_sor(output);
2115 struct tegra_sor_state *state; 2206 struct tegra_sor_state *state;
2116 struct drm_display_mode *mode; 2207 struct drm_display_mode *mode;
2208 unsigned long rate, pclk;
2117 unsigned int div, i; 2209 unsigned int div, i;
2118 u32 value; 2210 u32 value;
2119 int err; 2211 int err;
2120 2212
2121 state = to_sor_state(output->connector.state); 2213 state = to_sor_state(output->connector.state);
2122 mode = &encoder->crtc->state->adjusted_mode; 2214 mode = &encoder->crtc->state->adjusted_mode;
2215 pclk = mode->clock * 1000;
2123 2216
2124 pm_runtime_get_sync(sor->dev); 2217 pm_runtime_get_sync(sor->dev);
2125 2218
@@ -2195,10 +2288,13 @@ static void tegra_sor_hdmi_enable(struct drm_encoder *encoder)
2195 value &= ~SOR_CLK_CNTRL_DP_LINK_SPEED_MASK; 2288 value &= ~SOR_CLK_CNTRL_DP_LINK_SPEED_MASK;
2196 value &= ~SOR_CLK_CNTRL_DP_CLK_SEL_MASK; 2289 value &= ~SOR_CLK_CNTRL_DP_CLK_SEL_MASK;
2197 2290
2198 if (mode->clock < 340000) 2291 if (mode->clock < 340000) {
2292 DRM_DEBUG_KMS("setting 2.7 GHz link speed\n");
2199 value |= SOR_CLK_CNTRL_DP_LINK_SPEED_G2_70; 2293 value |= SOR_CLK_CNTRL_DP_LINK_SPEED_G2_70;
2200 else 2294 } else {
2295 DRM_DEBUG_KMS("setting 5.4 GHz link speed\n");
2201 value |= SOR_CLK_CNTRL_DP_LINK_SPEED_G5_40; 2296 value |= SOR_CLK_CNTRL_DP_LINK_SPEED_G5_40;
2297 }
2202 2298
2203 value |= SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_PCLK; 2299 value |= SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_PCLK;
2204 tegra_sor_writel(sor, value, SOR_CLK_CNTRL); 2300 tegra_sor_writel(sor, value, SOR_CLK_CNTRL);
@@ -2254,6 +2350,15 @@ static void tegra_sor_hdmi_enable(struct drm_encoder *encoder)
2254 return; 2350 return;
2255 } 2351 }
2256 2352
2353 /* adjust clock rate for HDMI 2.0 modes */
2354 rate = clk_get_rate(sor->clk_parent);
2355
2356 if (mode->clock >= 340000)
2357 rate /= 2;
2358
2359 DRM_DEBUG_KMS("setting clock to %lu Hz, mode: %lu Hz\n", rate, pclk);
2360
2361 clk_set_rate(sor->clk, rate);
2257 2362
2258 if (!sor->soc->has_nvdisplay) { 2363 if (!sor->soc->has_nvdisplay) {
2259 value = SOR_INPUT_CONTROL_HDMI_SRC_SELECT(dc->pipe); 2364 value = SOR_INPUT_CONTROL_HDMI_SRC_SELECT(dc->pipe);
@@ -2465,6 +2570,8 @@ static void tegra_sor_hdmi_enable(struct drm_encoder *encoder)
2465 err = tegra_sor_wakeup(sor); 2570 err = tegra_sor_wakeup(sor);
2466 if (err < 0) 2571 if (err < 0)
2467 dev_err(sor->dev, "failed to wakeup SOR: %d\n", err); 2572 dev_err(sor->dev, "failed to wakeup SOR: %d\n", err);
2573
2574 tegra_sor_hdmi_scdc_start(sor);
2468} 2575}
2469 2576
2470static const struct drm_encoder_helper_funcs tegra_sor_hdmi_helpers = { 2577static const struct drm_encoder_helper_funcs tegra_sor_hdmi_helpers = {
@@ -2652,6 +2759,8 @@ static int tegra_sor_hdmi_probe(struct tegra_sor *sor)
2652 return err; 2759 return err;
2653 } 2760 }
2654 2761
2762 INIT_DELAYED_WORK(&sor->scdc, tegra_sor_hdmi_scdc_work);
2763
2655 return 0; 2764 return 0;
2656} 2765}
2657 2766
diff --git a/drivers/gpu/drm/tegra/sor.h b/drivers/gpu/drm/tegra/sor.h
index e85ffc8d98e4..fb0854d92a27 100644
--- a/drivers/gpu/drm/tegra/sor.h
+++ b/drivers/gpu/drm/tegra/sor.h
@@ -382,4 +382,8 @@
382#define SOR_HDMI_VSI_INFOFRAME_STATUS 0x124 382#define SOR_HDMI_VSI_INFOFRAME_STATUS 0x124
383#define SOR_HDMI_VSI_INFOFRAME_HEADER 0x125 383#define SOR_HDMI_VSI_INFOFRAME_HEADER 0x125
384 384
385#define SOR_HDMI2_CTRL 0x13e
386#define SOR_HDMI2_CTRL_CLOCK_MODE_DIV_BY_4 (1 << 1)
387#define SOR_HDMI2_CTRL_SCRAMBLE (1 << 0)
388
385#endif 389#endif