Merge pull request #4250 from jernejsk/colours

Allwinner: Linux: Improve colour management
This commit is contained in:
MilhouseVH
2020-03-09 18:31:31 +00:00
committed by GitHub
3 changed files with 647 additions and 48 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -555,22 +555,33 @@ index dff27934287c..c922639e25eb 100644
ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
From 59c0e09a4133d36772397e59224fd32f1410cc26 Mon Sep 17 00:00:00 2001
From cb6130315f4ae856051725b2de4e208ed90eb740 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Sun, 8 Dec 2019 23:41:44 +0000
Subject: [PATCH] WIP: drm: dw-hdmi: do not force none scan mode
Subject: [PATCH v2 2/4] drm/bridge: dw-hdmi: do not force "none" scan mode
Setting scan mode to "none" confuses some TVs like LG B8, which randomly
change overscan percentage over time. Digital outputs like HDMI and DVI,
handled by this controller, don't really need overscan, so we can always
set scan mode to underscan. Actually, this is exactly what
drm_hdmi_avi_infoframe_from_display_mode() already does, so we can just
remove offending line.
Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
[updated commit message]
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index c922639e25eb..ea4f940406fc 100644
index 24965e53d351..de2c7ec887c8 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -1658,8 +1658,6 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
break;
@@ -1654,8 +1654,6 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
HDMI_EXTENDED_COLORIMETRY_XV_YCC_601;
}
- frame.scan_mode = HDMI_SCAN_MODE_NONE;
@@ -578,4 +589,138 @@ index c922639e25eb..ea4f940406fc 100644
/*
* The Designware IP uses a different byte format from standard
* AVI info frames, though generally the bits are in the correct
--
2.25.1
From 3043a1caa3f6d26128c746b991d086bbb85d50c2 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Sat, 29 Feb 2020 16:23:38 +0100
Subject: [PATCH v2 3/4] drm/bridge: dw-hdmi: Add support for RGB limited range
CEA 861 standard requestis that RGB quantization range is "limited" for
CEA modes. Support that by adding CSC matrix which downscales values.
This allows proper color reproduction on TV and PC monitor at the same
time. In future, override property can be added, like "Broadcast RGB"
in i915 driver.
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 63 +++++++++++++++++------
1 file changed, 46 insertions(+), 17 deletions(-)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index de2c7ec887c8..c8a02e5b5e1b 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -92,6 +92,12 @@ static const u16 csc_coeff_rgb_in_eitu709[3][4] = {
{ 0x6756, 0x78ab, 0x2000, 0x0200 }
};
+static const u16 csc_coeff_rgb_full_to_rgb_limited[3][4] = {
+ { 0x1b7c, 0x0000, 0x0000, 0x0020 },
+ { 0x0000, 0x1b7c, 0x0000, 0x0020 },
+ { 0x0000, 0x0000, 0x1b7c, 0x0020 }
+};
+
struct hdmi_vmode {
bool mdataenablepolarity;
@@ -109,6 +115,7 @@ struct hdmi_data_info {
unsigned int pix_repet_factor;
unsigned int hdcp_enable;
struct hdmi_vmode video_mode;
+ bool rgb_limited_range;
};
struct dw_hdmi_i2c {
@@ -956,7 +963,11 @@ static void hdmi_video_sample(struct dw_hdmi *hdmi)
static int is_color_space_conversion(struct dw_hdmi *hdmi)
{
- return hdmi->hdmi_data.enc_in_bus_format != hdmi->hdmi_data.enc_out_bus_format;
+ return (hdmi->hdmi_data.enc_in_bus_format !=
+ hdmi->hdmi_data.enc_out_bus_format) ||
+ (hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_in_bus_format) &&
+ hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_out_bus_format) &&
+ hdmi->hdmi_data.rgb_limited_range);
}
static int is_color_space_decimation(struct dw_hdmi *hdmi)
@@ -986,25 +997,27 @@ static int is_color_space_interpolation(struct dw_hdmi *hdmi)
static void dw_hdmi_update_csc_coeffs(struct dw_hdmi *hdmi)
{
const u16 (*csc_coeff)[3][4] = &csc_coeff_default;
+ bool is_input_rgb, is_output_rgb;
unsigned i;
u32 csc_scale = 1;
- if (is_color_space_conversion(hdmi)) {
- if (hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_out_bus_format)) {
- if (hdmi->hdmi_data.enc_out_encoding ==
- V4L2_YCBCR_ENC_601)
- csc_coeff = &csc_coeff_rgb_out_eitu601;
- else
- csc_coeff = &csc_coeff_rgb_out_eitu709;
- } else if (hdmi_bus_fmt_is_rgb(
- hdmi->hdmi_data.enc_in_bus_format)) {
- if (hdmi->hdmi_data.enc_out_encoding ==
- V4L2_YCBCR_ENC_601)
- csc_coeff = &csc_coeff_rgb_in_eitu601;
- else
- csc_coeff = &csc_coeff_rgb_in_eitu709;
- csc_scale = 0;
- }
+ is_input_rgb = hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_in_bus_format);
+ is_output_rgb = hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_out_bus_format);
+
+ if (!is_input_rgb && is_output_rgb) {
+ if (hdmi->hdmi_data.enc_out_encoding == V4L2_YCBCR_ENC_601)
+ csc_coeff = &csc_coeff_rgb_out_eitu601;
+ else
+ csc_coeff = &csc_coeff_rgb_out_eitu709;
+ } else if (is_input_rgb && !is_output_rgb) {
+ if (hdmi->hdmi_data.enc_out_encoding == V4L2_YCBCR_ENC_601)
+ csc_coeff = &csc_coeff_rgb_in_eitu601;
+ else
+ csc_coeff = &csc_coeff_rgb_in_eitu709;
+ csc_scale = 0;
+ } else if (is_input_rgb && is_output_rgb &&
+ hdmi->hdmi_data.rgb_limited_range) {
+ csc_coeff = &csc_coeff_rgb_full_to_rgb_limited;
}
/* The CSC registers are sequential, alternating MSB then LSB */
@@ -1614,6 +1627,18 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
drm_hdmi_avi_infoframe_from_display_mode(&frame,
&hdmi->connector, mode);
+ if (hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_out_bus_format)) {
+ drm_hdmi_avi_infoframe_quant_range(&frame, &hdmi->connector,
+ mode,
+ hdmi->hdmi_data.rgb_limited_range ?
+ HDMI_QUANTIZATION_RANGE_LIMITED :
+ HDMI_QUANTIZATION_RANGE_FULL);
+ } else {
+ frame.quantization_range = HDMI_QUANTIZATION_RANGE_DEFAULT;
+ frame.ycc_quantization_range =
+ HDMI_YCC_QUANTIZATION_RANGE_LIMITED;
+ }
+
if (hdmi_bus_fmt_is_yuv444(hdmi->hdmi_data.enc_out_bus_format))
frame.colorspace = HDMI_COLORSPACE_YUV444;
else if (hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_out_bus_format))
@@ -2099,6 +2124,10 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
/* TOFIX: Default to RGB888 output format */
hdmi->hdmi_data.enc_out_bus_format = MEDIA_BUS_FMT_RGB888_1X24;
+ hdmi->hdmi_data.rgb_limited_range = hdmi->sink_is_hdmi &&
+ drm_default_rgb_quant_range(mode) ==
+ HDMI_QUANTIZATION_RANGE_LIMITED;
+
hdmi->hdmi_data.pix_repet_factor = 0;
hdmi->hdmi_data.hdcp_enable = 0;
hdmi->hdmi_data.video_mode.mdataenablepolarity = true;
--
2.25.1

View File

@@ -1,43 +0,0 @@
From c8217462c6c143a9fada595bf3e34af83eb15f87 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Thu, 27 Jun 2019 21:50:16 +0200
Subject: [PATCH 4/4] HACK: Force full range
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
drivers/gpu/drm/sun4i/sun8i_csc.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.c b/drivers/gpu/drm/sun4i/sun8i_csc.c
index 70c792d052fe..7b60fce1a8c6 100644
--- a/drivers/gpu/drm/sun4i/sun8i_csc.c
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.c
@@ -160,10 +160,10 @@ static void sun8i_csc_set_coefficients(struct regmap *map, u32 base,
switch (mode) {
case SUN8I_CSC_MODE_YUV2RGB:
- table = yuv2rgb[range][encoding];
+ table = yuv2rgb[DRM_COLOR_YCBCR_FULL_RANGE][encoding];
break;
case SUN8I_CSC_MODE_YVU2RGB:
- table = yvu2rgb[range][encoding];
+ table = yvu2rgb[DRM_COLOR_YCBCR_FULL_RANGE][encoding];
break;
default:
DRM_WARN("Wrong CSC mode specified.\n");
@@ -184,10 +184,10 @@ static void sun8i_de3_ccsc_set_coefficients(struct regmap *map, int layer,
switch (mode) {
case SUN8I_CSC_MODE_YUV2RGB:
- table = yuv2rgb_de3[range][encoding];
+ table = yuv2rgb_de3[DRM_COLOR_YCBCR_FULL_RANGE][encoding];
break;
case SUN8I_CSC_MODE_YVU2RGB:
- table = yvu2rgb_de3[range][encoding];
+ table = yvu2rgb_de3[DRM_COLOR_YCBCR_FULL_RANGE][encoding];
break;
default:
DRM_WARN("Wrong CSC mode specified.\n");
--
2.22.0