From 805856e53a56917852fd10977ef246e510e65ff2 Mon Sep 17 00:00:00 2001 From: warped-rudi Date: Wed, 5 Aug 2015 20:13:22 +0200 Subject: [PATCH 1/3] video: mxc_edid: Parse Video Capability Data Block The information from this block is used to detect if a sink supports overriding of the RGB quantisation range. Signed-off-by: Rudi --- drivers/video/mxc/mxc_edid.c | 16 ++++++++++++++++ include/video/mxc_edid.h | 4 ++++ 2 files changed, 20 insertions(+) diff --git a/drivers/video/mxc/mxc_edid.c b/drivers/video/mxc/mxc_edid.c index d791bfea5609b4..59e157882315d1 100644 --- a/drivers/video/mxc/mxc_edid.c +++ b/drivers/video/mxc/mxc_edid.c @@ -547,6 +547,22 @@ int mxc_edid_parse_ext_blk(unsigned char *edid, break; } case 0x7: /*User extended block*/ + if (blklen >= 2 && edid[index + 1] == 0) { /*Video Capability Data Block*/ + u8 data = edid[index + 2]; + + cfg->cea_scan_mode_ce = (data >> 0) & 3; + cfg->cea_scan_mode_it = (data >> 2) & 3; + cfg->cea_scan_mode_pt = (data >> 4) & 3; + cfg->cea_rgb_range_selectable = (data >> 6) & 1; + + DPRINTK("VCDB over/underscan behavior (CE) %d\n", cfg->cea_scan_mode_ce); + DPRINTK("VCDB over/underscan behavior (IT) %d\n", cfg->cea_scan_mode_it); + DPRINTK("VCDB over/underscan behavior (PT) %d\n", cfg->cea_scan_mode_pt); + DPRINTK("VCDB RGB quant. range selectable %d\n", cfg->cea_rgb_range_selectable); + + index += blklen; + break; + } default: /* skip */ DPRINTK("Not handle block, tagcode = 0x%x\n", tagcode); diff --git a/include/video/mxc_edid.h b/include/video/mxc_edid.h index 34e797cc80b4d8..9d34f22835f8eb 100644 --- a/include/video/mxc_edid.h +++ b/include/video/mxc_edid.h @@ -64,6 +64,10 @@ struct mxc_edid_cfg { bool cea_ycbcr444; bool cea_ycbcr422; bool hdmi_cap; + bool cea_rgb_range_selectable; + u8 cea_scan_mode_ce; + u8 cea_scan_mode_it; + u8 cea_scan_mode_pt; /*VSD*/ bool vsd_support_ai; From 60251e8643f6dc17effbea2630bdcf019b53b910 Mon Sep 17 00:00:00 2001 From: warped-rudi Date: Wed, 5 Aug 2015 20:16:44 +0200 Subject: [PATCH 2/3] video: mxc_hdmi: Add new option 'auto' for RGB Quant Range setting This new option, which is now the default, will automatically use full range, when the sink announces that it supports quantisation overriding. Otherwise, the default range (i.e. limited) is used. Signed-off-by: Rudi --- drivers/video/mxc/mxc_hdmi.c | 41 ++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/drivers/video/mxc/mxc_hdmi.c b/drivers/video/mxc/mxc_hdmi.c index 65c85caee9465b..208c798b1942e6 100644 --- a/drivers/video/mxc/mxc_hdmi.c +++ b/drivers/video/mxc/mxc_hdmi.c @@ -216,10 +216,11 @@ extern int mxcfb_blank(int blank, struct fb_info *info); static void mxc_hdmi_setup(struct mxc_hdmi *hdmi, unsigned long event); static void hdmi_enable_overflow_interrupts(void); static void hdmi_disable_overflow_interrupts(void); +static unsigned int getRGBQuantRange(struct mxc_hdmi *hdmi); -static char *rgb_quant_range = "default"; +static char *rgb_quant_range = "auto"; module_param(rgb_quant_range, charp, S_IRUGO); -MODULE_PARM_DESC(rgb_quant_range, "RGB Quant Range (default, limited, full)"); +MODULE_PARM_DESC(rgb_quant_range, "RGB Quant Range (auto, default, limited, full)"); static struct platform_device_id imx_hdmi_devtype[] = { { @@ -355,8 +356,9 @@ static ssize_t mxc_hdmi_show_rgb_quant_range(struct device *dev, struct device_attribute *attr, char *buf) { struct mxc_hdmi *hdmi = dev_get_drvdata(dev); + int n; - switch (hdmi->hdmi_data.rgb_quant_range) { + switch (getRGBQuantRange(hdmi)) { case HDMI_FC_AVICONF2_RGB_QUANT_LIMITED_RANGE: strcpy(buf, "limited\n"); break; @@ -369,7 +371,14 @@ static ssize_t mxc_hdmi_show_rgb_quant_range(struct device *dev, break; }; - return strlen(buf); + n = strlen(buf); + + if (hdmi->hdmi_data.rgb_quant_range == HDMI_FC_AVICONF2_RGB_QUANT_MASK) { + strcpy(buf + n - 1, " (auto)\n"); + n += 7; + } + + return n; } static ssize_t mxc_hdmi_store_rgb_quant_range(struct device *dev, @@ -384,6 +393,8 @@ static ssize_t mxc_hdmi_store_rgb_quant_range(struct device *dev, hdmi->hdmi_data.rgb_quant_range = HDMI_FC_AVICONF2_RGB_QUANT_FULL_RANGE; } else if (sysfs_streq("default", buf)) { hdmi->hdmi_data.rgb_quant_range = HDMI_FC_AVICONF2_RGB_QUANT_DEFAULT; + } else if (sysfs_streq("auto", buf)) { + hdmi->hdmi_data.rgb_quant_range = HDMI_FC_AVICONF2_RGB_QUANT_MASK; } else { ret = -EINVAL; goto out; @@ -510,12 +521,23 @@ static void hdmi_video_sample(struct mxc_hdmi *hdmi) hdmi_writeb(0x0, HDMI_TX_BCBDATA1); } +static unsigned int getRGBQuantRange(struct mxc_hdmi *hdmi) +{ + if (hdmi->hdmi_data.rgb_quant_range != HDMI_FC_AVICONF2_RGB_QUANT_MASK) + return hdmi->hdmi_data.rgb_quant_range; + + return hdmi->edid_cfg.cea_rgb_range_selectable ? + HDMI_FC_AVICONF2_RGB_QUANT_FULL_RANGE : HDMI_FC_AVICONF2_RGB_QUANT_DEFAULT; +} + static int isColorSpaceConversion(struct mxc_hdmi *hdmi) { + unsigned int rgb_quant_range = getRGBQuantRange(hdmi); + return (hdmi->hdmi_data.enc_in_format != hdmi->hdmi_data.enc_out_format) || (hdmi->hdmi_data.enc_out_format == RGB && - ((hdmi->hdmi_data.rgb_quant_range == HDMI_FC_AVICONF2_RGB_QUANT_LIMITED_RANGE) || - (hdmi->hdmi_data.rgb_quant_range == HDMI_FC_AVICONF2_RGB_QUANT_DEFAULT && hdmi->vic > 1))); + ((rgb_quant_range == HDMI_FC_AVICONF2_RGB_QUANT_LIMITED_RANGE) || + (rgb_quant_range == HDMI_FC_AVICONF2_RGB_QUANT_DEFAULT && hdmi->vic > 1))); } static int isColorSpaceDecimation(struct mxc_hdmi *hdmi) @@ -1475,8 +1497,7 @@ static void hdmi_config_AVI(struct mxc_hdmi *hdmi) ********************************************/ val = HDMI_FC_AVICONF2_IT_CONTENT_NO_DATA | ext_colorimetry | - hdmi->hdmi_data.rgb_quant_range | - HDMI_FC_AVICONF2_SCALING_NONE; + getRGBQuantRange(hdmi) | HDMI_FC_AVICONF2_SCALING_NONE; hdmi_writeb(val, HDMI_FC_AVICONF2); /******************************************** @@ -2798,8 +2819,10 @@ static int mxc_hdmi_disp_init(struct mxc_dispdrv_handle *disp, hdmi->hdmi_data.rgb_quant_range = HDMI_FC_AVICONF2_RGB_QUANT_LIMITED_RANGE; } else if (!strcasecmp(rgb_quant_range, "full")) { hdmi->hdmi_data.rgb_quant_range = HDMI_FC_AVICONF2_RGB_QUANT_FULL_RANGE; - } else { + } else if (!strcasecmp(rgb_quant_range, "default")) { hdmi->hdmi_data.rgb_quant_range = HDMI_FC_AVICONF2_RGB_QUANT_DEFAULT; + } else { + hdmi->hdmi_data.rgb_quant_range = HDMI_FC_AVICONF2_RGB_QUANT_MASK; } ret = devm_request_irq(&hdmi->pdev->dev, irq, mxc_hdmi_hotplug, IRQF_SHARED, From f2c34aa14dfd77ad0bf6d0ccb7224fdf528ca193 Mon Sep 17 00:00:00 2001 From: warped-rudi Date: Thu, 6 Aug 2015 08:33:58 +0200 Subject: [PATCH 3/3] video: mxc_hdmi: Add command line switch to disable EDID processing. Allow the use of the fallback videomode list even in case a valid EDID is obtainable. This is done by adding 'mxc_hdmi.ignore_edid=1' to the kernel command line. Signed-off-by: Rudi --- drivers/video/mxc/mxc_hdmi.c | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/drivers/video/mxc/mxc_hdmi.c b/drivers/video/mxc/mxc_hdmi.c index 208c798b1942e6..87acdb48d59e2d 100644 --- a/drivers/video/mxc/mxc_hdmi.c +++ b/drivers/video/mxc/mxc_hdmi.c @@ -222,6 +222,10 @@ static char *rgb_quant_range = "auto"; module_param(rgb_quant_range, charp, S_IRUGO); MODULE_PARM_DESC(rgb_quant_range, "RGB Quant Range (auto, default, limited, full)"); +static bool ignore_edid = 0; +module_param(ignore_edid, bool, S_IRUGO); +MODULE_PARM_DESC(ignore_edid, "Ignore EDID (default=0)"); + static struct platform_device_id imx_hdmi_devtype[] = { { .name = "hdmi-imx6DL", @@ -2062,19 +2066,23 @@ static void mxc_hdmi_cable_connected(struct mxc_hdmi *hdmi) hdmi->hp_state = HDMI_HOTPLUG_CONNECTED_NO_EDID; /* HDMI Initialization Step C */ - edid_status = mxc_hdmi_read_edid(hdmi); - - /* Read EDID again if first EDID read failed */ - if (edid_status == HDMI_EDID_NO_MODES || - edid_status == HDMI_EDID_FAIL) { - int retry_status; - dev_warn(&hdmi->pdev->dev, "Read EDID again\n"); - msleep(200); - retry_status = mxc_hdmi_read_edid(hdmi); - /* If we get NO_MODES on the 1st and SAME on the 2nd attempt we - * want NO_MODES as final result. */ - if (retry_status != HDMI_EDID_SAME) - edid_status = retry_status; + if (ignore_edid) { + edid_status = HDMI_EDID_FAIL; + } else { + edid_status = mxc_hdmi_read_edid(hdmi); + + /* Read EDID again if first EDID read failed */ + if (edid_status == HDMI_EDID_NO_MODES || + edid_status == HDMI_EDID_FAIL) { + int retry_status; + dev_warn(&hdmi->pdev->dev, "Read EDID again\n"); + msleep(200); + retry_status = mxc_hdmi_read_edid(hdmi); + /* If we get NO_MODES on the 1st and SAME on the 2nd attempt we + * want NO_MODES as final result. */ + if (retry_status != HDMI_EDID_SAME) + edid_status = retry_status; + } } /* HDMI Initialization Steps D, E, F */