diff options
author | Maciej Purski <m.purski@samsung.com> | 2018-02-02 05:54:25 -0500 |
---|---|---|
committer | Andrzej Hajda <a.hajda@samsung.com> | 2018-06-13 10:26:57 -0400 |
commit | ecba7cfa3afbe489288f2c819158b7402afd7ee9 (patch) | |
tree | 328459a5aa04bfa7a63b345b0cbd78faa1f0ac67 | |
parent | 8e627a1b1ce8feb3e1da4428b71b9b4905f04888 (diff) |
drm/bridge/sii8620: fix display modes validation
Current implementation of mode_valid() and mode_fixup() callbacks
handle packed pixel modes improperly.
Fix it by using proper maximum clock values from the documentation.
Signed-off-by: Maciej Purski <m.purski@samsung.com>
Signed-off-by: Andrzej Hajda <a.hajda@samsung.com>
Link: https://patchwork.freedesktop.org/patch/msgid/1517568865-25219-1-git-send-email-m.purski@samsung.com
-rw-r--r-- | drivers/gpu/drm/bridge/sil-sii8620.c | 80 |
1 files changed, 41 insertions, 39 deletions
diff --git a/drivers/gpu/drm/bridge/sil-sii8620.c b/drivers/gpu/drm/bridge/sil-sii8620.c index 720bc7c325e0..5267dc6551af 100644 --- a/drivers/gpu/drm/bridge/sil-sii8620.c +++ b/drivers/gpu/drm/bridge/sil-sii8620.c | |||
@@ -36,8 +36,11 @@ | |||
36 | 36 | ||
37 | #define SII8620_BURST_BUF_LEN 288 | 37 | #define SII8620_BURST_BUF_LEN 288 |
38 | #define VAL_RX_HDMI_CTRL2_DEFVAL VAL_RX_HDMI_CTRL2_IDLE_CNT(3) | 38 | #define VAL_RX_HDMI_CTRL2_DEFVAL VAL_RX_HDMI_CTRL2_IDLE_CNT(3) |
39 | #define MHL1_MAX_LCLK 225000 | 39 | |
40 | #define MHL3_MAX_LCLK 600000 | 40 | #define MHL1_MAX_PCLK 75000 |
41 | #define MHL1_MAX_PCLK_PP_MODE 150000 | ||
42 | #define MHL3_MAX_PCLK 200000 | ||
43 | #define MHL3_MAX_PCLK_PP_MODE 300000 | ||
41 | 44 | ||
42 | enum sii8620_mode { | 45 | enum sii8620_mode { |
43 | CM_DISCONNECTED, | 46 | CM_DISCONNECTED, |
@@ -2274,17 +2277,43 @@ static void sii8620_detach(struct drm_bridge *bridge) | |||
2274 | rc_unregister_device(ctx->rc_dev); | 2277 | rc_unregister_device(ctx->rc_dev); |
2275 | } | 2278 | } |
2276 | 2279 | ||
2280 | static int sii8620_is_packing_required(struct sii8620 *ctx, | ||
2281 | const struct drm_display_mode *mode) | ||
2282 | { | ||
2283 | int max_pclk, max_pclk_pp_mode; | ||
2284 | |||
2285 | if (sii8620_is_mhl3(ctx)) { | ||
2286 | max_pclk = MHL3_MAX_PCLK; | ||
2287 | max_pclk_pp_mode = MHL3_MAX_PCLK_PP_MODE; | ||
2288 | } else { | ||
2289 | max_pclk = MHL1_MAX_PCLK; | ||
2290 | max_pclk_pp_mode = MHL1_MAX_PCLK_PP_MODE; | ||
2291 | } | ||
2292 | |||
2293 | if (mode->clock < max_pclk) | ||
2294 | return 0; | ||
2295 | else if (mode->clock < max_pclk_pp_mode) | ||
2296 | return 1; | ||
2297 | else | ||
2298 | return -1; | ||
2299 | } | ||
2300 | |||
2277 | static enum drm_mode_status sii8620_mode_valid(struct drm_bridge *bridge, | 2301 | static enum drm_mode_status sii8620_mode_valid(struct drm_bridge *bridge, |
2278 | const struct drm_display_mode *mode) | 2302 | const struct drm_display_mode *mode) |
2279 | { | 2303 | { |
2280 | struct sii8620 *ctx = bridge_to_sii8620(bridge); | 2304 | struct sii8620 *ctx = bridge_to_sii8620(bridge); |
2305 | int pack_required = sii8620_is_packing_required(ctx, mode); | ||
2281 | bool can_pack = ctx->devcap[MHL_DCAP_VID_LINK_MODE] & | 2306 | bool can_pack = ctx->devcap[MHL_DCAP_VID_LINK_MODE] & |
2282 | MHL_DCAP_VID_LINK_PPIXEL; | 2307 | MHL_DCAP_VID_LINK_PPIXEL; |
2283 | unsigned int max_pclk = sii8620_is_mhl3(ctx) ? MHL3_MAX_LCLK : | ||
2284 | MHL1_MAX_LCLK; | ||
2285 | max_pclk /= can_pack ? 2 : 3; | ||
2286 | 2308 | ||
2287 | return (mode->clock > max_pclk) ? MODE_CLOCK_HIGH : MODE_OK; | 2309 | switch (pack_required) { |
2310 | case 0: | ||
2311 | return MODE_OK; | ||
2312 | case 1: | ||
2313 | return (can_pack) ? MODE_OK : MODE_CLOCK_HIGH; | ||
2314 | default: | ||
2315 | return MODE_CLOCK_HIGH; | ||
2316 | } | ||
2288 | } | 2317 | } |
2289 | 2318 | ||
2290 | static bool sii8620_mode_fixup(struct drm_bridge *bridge, | 2319 | static bool sii8620_mode_fixup(struct drm_bridge *bridge, |
@@ -2292,43 +2321,16 @@ static bool sii8620_mode_fixup(struct drm_bridge *bridge, | |||
2292 | struct drm_display_mode *adjusted_mode) | 2321 | struct drm_display_mode *adjusted_mode) |
2293 | { | 2322 | { |
2294 | struct sii8620 *ctx = bridge_to_sii8620(bridge); | 2323 | struct sii8620 *ctx = bridge_to_sii8620(bridge); |
2295 | int max_lclk; | ||
2296 | bool ret = true; | ||
2297 | 2324 | ||
2298 | mutex_lock(&ctx->lock); | 2325 | mutex_lock(&ctx->lock); |
2299 | 2326 | ||
2300 | max_lclk = sii8620_is_mhl3(ctx) ? MHL3_MAX_LCLK : MHL1_MAX_LCLK; | 2327 | ctx->use_packed_pixel = sii8620_is_packing_required(ctx, adjusted_mode); |
2301 | if (max_lclk > 3 * adjusted_mode->clock) { | 2328 | ctx->video_code = drm_match_cea_mode(adjusted_mode); |
2302 | ctx->use_packed_pixel = 0; | 2329 | ctx->pixel_clock = adjusted_mode->clock; |
2303 | goto end; | 2330 | |
2304 | } | ||
2305 | if ((ctx->devcap[MHL_DCAP_VID_LINK_MODE] & MHL_DCAP_VID_LINK_PPIXEL) && | ||
2306 | max_lclk > 2 * adjusted_mode->clock) { | ||
2307 | ctx->use_packed_pixel = 1; | ||
2308 | goto end; | ||
2309 | } | ||
2310 | ret = false; | ||
2311 | end: | ||
2312 | if (ret) { | ||
2313 | u8 vic = drm_match_cea_mode(adjusted_mode); | ||
2314 | |||
2315 | if (!vic) { | ||
2316 | union hdmi_infoframe frm; | ||
2317 | u8 mhl_vic[] = { 0, 95, 94, 93, 98 }; | ||
2318 | |||
2319 | /* FIXME: We need the connector here */ | ||
2320 | drm_hdmi_vendor_infoframe_from_display_mode( | ||
2321 | &frm.vendor.hdmi, NULL, adjusted_mode); | ||
2322 | vic = frm.vendor.hdmi.vic; | ||
2323 | if (vic >= ARRAY_SIZE(mhl_vic)) | ||
2324 | vic = 0; | ||
2325 | vic = mhl_vic[vic]; | ||
2326 | } | ||
2327 | ctx->video_code = vic; | ||
2328 | ctx->pixel_clock = adjusted_mode->clock; | ||
2329 | } | ||
2330 | mutex_unlock(&ctx->lock); | 2331 | mutex_unlock(&ctx->lock); |
2331 | return ret; | 2332 | |
2333 | return true; | ||
2332 | } | 2334 | } |
2333 | 2335 | ||
2334 | static const struct drm_bridge_funcs sii8620_bridge_funcs = { | 2336 | static const struct drm_bridge_funcs sii8620_bridge_funcs = { |