diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/drm/tegra/sor.c | 121 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/sor.h | 4 |
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 | ||
355 | struct tegra_sor_state { | 359 | struct 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 | |||
1489 | tegra_sor_connector_mode_valid(struct drm_connector *connector, | 1495 | tegra_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 | ||
2084 | static 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 | |||
2094 | static 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 | |||
2104 | static 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 | |||
2112 | static 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 | |||
2122 | static 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 | |||
2132 | static 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 | |||
2145 | static 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 | |||
2070 | static void tegra_sor_hdmi_disable(struct drm_encoder *encoder) | 2159 | static 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 | ||
2470 | static const struct drm_encoder_helper_funcs tegra_sor_hdmi_helpers = { | 2577 | static 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 |