Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+119 -6
+115 -6
drivers/gpu/drm/tegra/sor.c
··· 22 22 #include <drm/drm_atomic_helper.h> 23 23 #include <drm/drm_dp_helper.h> 24 24 #include <drm/drm_panel.h> 25 + #include <drm/drm_scdc_helper.h> 25 26 26 27 #include "dc.h" 27 28 #include "drm.h" ··· 351 350 struct regulator *avdd_io_supply; 352 351 struct regulator *vdd_pll_supply; 353 352 struct regulator *hdmi_supply; 353 + 354 + struct delayed_work scdc; 355 + bool scdc_enabled; 354 356 }; 355 357 356 358 struct tegra_sor_state { 357 359 struct drm_connector_state base; 358 360 361 + unsigned int link_speed; 362 + unsigned long pclk; 359 363 unsigned int bpc; 360 364 }; 361 365 ··· 1495 1489 tegra_sor_connector_mode_valid(struct drm_connector *connector, 1496 1490 struct drm_display_mode *mode) 1497 1491 { 1498 - /* HDMI 2.0 modes are not yet supported */ 1499 - if (mode->clock > 340000) 1500 - return MODE_NOCLOCK; 1501 - 1502 1492 return MODE_OK; 1503 1493 } 1504 1494 ··· 1919 1917 1920 1918 info = &output->connector.display_info; 1921 1919 1920 + /* 1921 + * For HBR2 modes, the SOR brick needs to use the x20 multiplier, so 1922 + * the pixel clock must be corrected accordingly. 1923 + */ 1924 + if (pclk >= 340000000) { 1925 + state->link_speed = 20; 1926 + state->pclk = pclk / 2; 1927 + } else { 1928 + state->link_speed = 10; 1929 + state->pclk = pclk; 1930 + } 1931 + 1922 1932 err = tegra_dc_state_setup_clock(dc, crtc_state, sor->clk_parent, 1923 1933 pclk, 0); 1924 1934 if (err < 0) { ··· 2081 2067 return NULL; 2082 2068 } 2083 2069 2070 + static void tegra_sor_hdmi_disable_scrambling(struct tegra_sor *sor) 2071 + { 2072 + u32 value; 2073 + 2074 + value = tegra_sor_readl(sor, SOR_HDMI2_CTRL); 2075 + value &= ~SOR_HDMI2_CTRL_CLOCK_MODE_DIV_BY_4; 2076 + value &= ~SOR_HDMI2_CTRL_SCRAMBLE; 2077 + tegra_sor_writel(sor, value, SOR_HDMI2_CTRL); 2078 + } 2079 + 2080 + static void tegra_sor_hdmi_scdc_disable(struct tegra_sor *sor) 2081 + { 2082 + struct i2c_adapter *ddc = sor->output.ddc; 2083 + 2084 + drm_scdc_set_high_tmds_clock_ratio(ddc, false); 2085 + drm_scdc_set_scrambling(ddc, false); 2086 + 2087 + tegra_sor_hdmi_disable_scrambling(sor); 2088 + } 2089 + 2090 + static void tegra_sor_hdmi_scdc_stop(struct tegra_sor *sor) 2091 + { 2092 + if (sor->scdc_enabled) { 2093 + cancel_delayed_work_sync(&sor->scdc); 2094 + tegra_sor_hdmi_scdc_disable(sor); 2095 + } 2096 + } 2097 + 2098 + static void tegra_sor_hdmi_enable_scrambling(struct tegra_sor *sor) 2099 + { 2100 + u32 value; 2101 + 2102 + value = tegra_sor_readl(sor, SOR_HDMI2_CTRL); 2103 + value |= SOR_HDMI2_CTRL_CLOCK_MODE_DIV_BY_4; 2104 + value |= SOR_HDMI2_CTRL_SCRAMBLE; 2105 + tegra_sor_writel(sor, value, SOR_HDMI2_CTRL); 2106 + } 2107 + 2108 + static void tegra_sor_hdmi_scdc_enable(struct tegra_sor *sor) 2109 + { 2110 + struct i2c_adapter *ddc = sor->output.ddc; 2111 + 2112 + drm_scdc_set_high_tmds_clock_ratio(ddc, true); 2113 + drm_scdc_set_scrambling(ddc, true); 2114 + 2115 + tegra_sor_hdmi_enable_scrambling(sor); 2116 + } 2117 + 2118 + static void tegra_sor_hdmi_scdc_work(struct work_struct *work) 2119 + { 2120 + struct tegra_sor *sor = container_of(work, struct tegra_sor, scdc.work); 2121 + struct i2c_adapter *ddc = sor->output.ddc; 2122 + 2123 + if (!drm_scdc_get_scrambling_status(ddc)) { 2124 + DRM_DEBUG_KMS("SCDC not scrambled\n"); 2125 + tegra_sor_hdmi_scdc_enable(sor); 2126 + } 2127 + 2128 + schedule_delayed_work(&sor->scdc, msecs_to_jiffies(5000)); 2129 + } 2130 + 2131 + static void tegra_sor_hdmi_scdc_start(struct tegra_sor *sor) 2132 + { 2133 + struct drm_scdc *scdc = &sor->output.connector.display_info.hdmi.scdc; 2134 + struct drm_display_mode *mode; 2135 + 2136 + mode = &sor->output.encoder.crtc->state->adjusted_mode; 2137 + 2138 + if (mode->clock >= 340000 && scdc->supported) { 2139 + schedule_delayed_work(&sor->scdc, msecs_to_jiffies(5000)); 2140 + tegra_sor_hdmi_scdc_enable(sor); 2141 + sor->scdc_enabled = true; 2142 + } 2143 + } 2144 + 2084 2145 static void tegra_sor_hdmi_disable(struct drm_encoder *encoder) 2085 2146 { 2086 2147 struct tegra_output *output = encoder_to_output(encoder); ··· 2163 2074 struct tegra_sor *sor = to_sor(output); 2164 2075 u32 value; 2165 2076 int err; 2077 + 2078 + tegra_sor_hdmi_scdc_stop(sor); 2166 2079 2167 2080 err = tegra_sor_detach(sor); 2168 2081 if (err < 0) ··· 2205 2114 struct tegra_sor *sor = to_sor(output); 2206 2115 struct tegra_sor_state *state; 2207 2116 struct drm_display_mode *mode; 2117 + unsigned long rate, pclk; 2208 2118 unsigned int div, i; 2209 2119 u32 value; 2210 2120 int err; 2211 2121 2212 2122 state = to_sor_state(output->connector.state); 2213 2123 mode = &encoder->crtc->state->adjusted_mode; 2124 + pclk = mode->clock * 1000; 2214 2125 2215 2126 pm_runtime_get_sync(sor->dev); 2216 2127 ··· 2288 2195 value &= ~SOR_CLK_CNTRL_DP_LINK_SPEED_MASK; 2289 2196 value &= ~SOR_CLK_CNTRL_DP_CLK_SEL_MASK; 2290 2197 2291 - if (mode->clock < 340000) 2198 + if (mode->clock < 340000) { 2199 + DRM_DEBUG_KMS("setting 2.7 GHz link speed\n"); 2292 2200 value |= SOR_CLK_CNTRL_DP_LINK_SPEED_G2_70; 2293 - else 2201 + } else { 2202 + DRM_DEBUG_KMS("setting 5.4 GHz link speed\n"); 2294 2203 value |= SOR_CLK_CNTRL_DP_LINK_SPEED_G5_40; 2204 + } 2295 2205 2296 2206 value |= SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_PCLK; 2297 2207 tegra_sor_writel(sor, value, SOR_CLK_CNTRL); ··· 2350 2254 return; 2351 2255 } 2352 2256 2257 + /* adjust clock rate for HDMI 2.0 modes */ 2258 + rate = clk_get_rate(sor->clk_parent); 2259 + 2260 + if (mode->clock >= 340000) 2261 + rate /= 2; 2262 + 2263 + DRM_DEBUG_KMS("setting clock to %lu Hz, mode: %lu Hz\n", rate, pclk); 2264 + 2265 + clk_set_rate(sor->clk, rate); 2353 2266 2354 2267 if (!sor->soc->has_nvdisplay) { 2355 2268 value = SOR_INPUT_CONTROL_HDMI_SRC_SELECT(dc->pipe); ··· 2570 2465 err = tegra_sor_wakeup(sor); 2571 2466 if (err < 0) 2572 2467 dev_err(sor->dev, "failed to wakeup SOR: %d\n", err); 2468 + 2469 + tegra_sor_hdmi_scdc_start(sor); 2573 2470 } 2574 2471 2575 2472 static const struct drm_encoder_helper_funcs tegra_sor_hdmi_helpers = { ··· 2758 2651 dev_err(sor->dev, "failed to enable HDMI supply: %d\n", err); 2759 2652 return err; 2760 2653 } 2654 + 2655 + INIT_DELAYED_WORK(&sor->scdc, tegra_sor_hdmi_scdc_work); 2761 2656 2762 2657 return 0; 2763 2658 }
+4
drivers/gpu/drm/tegra/sor.h
··· 382 382 #define SOR_HDMI_VSI_INFOFRAME_STATUS 0x124 383 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 389 #endif