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
This commit is contained in:
Maciej Purski 2018-02-02 11:54:25 +01:00 committed by Andrzej Hajda
parent 8e627a1b1c
commit ecba7cfa3a
1 changed files with 40 additions and 38 deletions

View File

@ -36,8 +36,11 @@
#define SII8620_BURST_BUF_LEN 288
#define VAL_RX_HDMI_CTRL2_DEFVAL VAL_RX_HDMI_CTRL2_IDLE_CNT(3)
#define MHL1_MAX_LCLK 225000
#define MHL3_MAX_LCLK 600000
#define MHL1_MAX_PCLK 75000
#define MHL1_MAX_PCLK_PP_MODE 150000
#define MHL3_MAX_PCLK 200000
#define MHL3_MAX_PCLK_PP_MODE 300000
enum sii8620_mode {
CM_DISCONNECTED,
@ -2274,17 +2277,43 @@ static void sii8620_detach(struct drm_bridge *bridge)
rc_unregister_device(ctx->rc_dev);
}
static int sii8620_is_packing_required(struct sii8620 *ctx,
const struct drm_display_mode *mode)
{
int max_pclk, max_pclk_pp_mode;
if (sii8620_is_mhl3(ctx)) {
max_pclk = MHL3_MAX_PCLK;
max_pclk_pp_mode = MHL3_MAX_PCLK_PP_MODE;
} else {
max_pclk = MHL1_MAX_PCLK;
max_pclk_pp_mode = MHL1_MAX_PCLK_PP_MODE;
}
if (mode->clock < max_pclk)
return 0;
else if (mode->clock < max_pclk_pp_mode)
return 1;
else
return -1;
}
static enum drm_mode_status sii8620_mode_valid(struct drm_bridge *bridge,
const struct drm_display_mode *mode)
{
struct sii8620 *ctx = bridge_to_sii8620(bridge);
int pack_required = sii8620_is_packing_required(ctx, mode);
bool can_pack = ctx->devcap[MHL_DCAP_VID_LINK_MODE] &
MHL_DCAP_VID_LINK_PPIXEL;
unsigned int max_pclk = sii8620_is_mhl3(ctx) ? MHL3_MAX_LCLK :
MHL1_MAX_LCLK;
max_pclk /= can_pack ? 2 : 3;
return (mode->clock > max_pclk) ? MODE_CLOCK_HIGH : MODE_OK;
switch (pack_required) {
case 0:
return MODE_OK;
case 1:
return (can_pack) ? MODE_OK : MODE_CLOCK_HIGH;
default:
return MODE_CLOCK_HIGH;
}
}
static bool sii8620_mode_fixup(struct drm_bridge *bridge,
@ -2292,43 +2321,16 @@ static bool sii8620_mode_fixup(struct drm_bridge *bridge,
struct drm_display_mode *adjusted_mode)
{
struct sii8620 *ctx = bridge_to_sii8620(bridge);
int max_lclk;
bool ret = true;
mutex_lock(&ctx->lock);
max_lclk = sii8620_is_mhl3(ctx) ? MHL3_MAX_LCLK : MHL1_MAX_LCLK;
if (max_lclk > 3 * adjusted_mode->clock) {
ctx->use_packed_pixel = 0;
goto end;
}
if ((ctx->devcap[MHL_DCAP_VID_LINK_MODE] & MHL_DCAP_VID_LINK_PPIXEL) &&
max_lclk > 2 * adjusted_mode->clock) {
ctx->use_packed_pixel = 1;
goto end;
}
ret = false;
end:
if (ret) {
u8 vic = drm_match_cea_mode(adjusted_mode);
ctx->use_packed_pixel = sii8620_is_packing_required(ctx, adjusted_mode);
ctx->video_code = drm_match_cea_mode(adjusted_mode);
ctx->pixel_clock = adjusted_mode->clock;
if (!vic) {
union hdmi_infoframe frm;
u8 mhl_vic[] = { 0, 95, 94, 93, 98 };
/* FIXME: We need the connector here */
drm_hdmi_vendor_infoframe_from_display_mode(
&frm.vendor.hdmi, NULL, adjusted_mode);
vic = frm.vendor.hdmi.vic;
if (vic >= ARRAY_SIZE(mhl_vic))
vic = 0;
vic = mhl_vic[vic];
}
ctx->video_code = vic;
ctx->pixel_clock = adjusted_mode->clock;
}
mutex_unlock(&ctx->lock);
return ret;
return true;
}
static const struct drm_bridge_funcs sii8620_bridge_funcs = {