2022-05-16 21:40:32 +00:00
|
|
|
From a2e09555e32742320fdaa511e1ccf6aafbf29485 Mon Sep 17 00:00:00 2001
|
|
|
|
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
|
|
|
Date: Mon, 7 Mar 2022 15:19:38 +0000
|
|
|
|
Subject: [PATCH] drm/vc4: hdmi: Add CSC for BT601/709/2020 limited and
|
|
|
|
full range output
|
|
|
|
|
|
|
|
The HVS always composes in the RGB domain, but there is a colourspace
|
|
|
|
conversion block on the output to allow for sending YCbCr over the
|
|
|
|
HDMI interface.
|
|
|
|
The colourspace on that link is configurable via the "Colorspace"
|
|
|
|
property on the connector, and that updates the infoframes. There
|
|
|
|
is also selection of limited or full range based on the mode selected
|
|
|
|
or an override.
|
|
|
|
|
|
|
|
Add code to update the CSC as well so that the metadata matches the
|
|
|
|
image data.
|
|
|
|
|
|
|
|
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
|
|
|
---
|
|
|
|
drivers/gpu/drm/vc4/vc4_hdmi.c | 198 ++++++++++++++++++++++++---------
|
|
|
|
1 file changed, 146 insertions(+), 52 deletions(-)
|
|
|
|
|
|
|
|
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
|
|
|
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
2022-05-18 14:32:03 +00:00
|
|
|
@@ -139,8 +139,8 @@ static bool vc4_hdmi_mode_needs_scrambli
|
2022-05-16 21:40:32 +00:00
|
|
|
return clock > HDMI_14_MAX_TMDS_CLK;
|
|
|
|
}
|
|
|
|
|
|
|
|
-static bool vc4_hdmi_is_full_range_rgb(struct vc4_hdmi *vc4_hdmi,
|
|
|
|
- const struct drm_display_mode *mode)
|
|
|
|
+static bool vc4_hdmi_is_full_range(struct vc4_hdmi *vc4_hdmi,
|
|
|
|
+ const struct drm_display_mode *mode)
|
|
|
|
{
|
|
|
|
struct vc4_hdmi_encoder *vc4_encoder = &vc4_hdmi->encoder;
|
|
|
|
|
2022-05-18 14:32:03 +00:00
|
|
|
@@ -680,7 +680,7 @@ static void vc4_hdmi_set_avi_infoframe(s
|
2022-05-16 21:40:32 +00:00
|
|
|
|
|
|
|
drm_hdmi_avi_infoframe_quant_range(&frame.avi,
|
|
|
|
connector, mode,
|
|
|
|
- vc4_hdmi_is_full_range_rgb(vc4_hdmi, mode) ?
|
|
|
|
+ vc4_hdmi_is_full_range(vc4_hdmi, mode) ?
|
|
|
|
HDMI_QUANTIZATION_RANGE_FULL :
|
|
|
|
HDMI_QUANTIZATION_RANGE_LIMITED);
|
|
|
|
drm_hdmi_avi_infoframe_colorimetry(&frame.avi, cstate);
|
2022-05-18 14:32:03 +00:00
|
|
|
@@ -914,7 +914,7 @@ static void vc4_hdmi_csc_setup(struct vc
|
2022-05-16 21:40:32 +00:00
|
|
|
csc_ctl = VC4_SET_FIELD(VC4_HD_CSC_CTL_ORDER_BGR,
|
|
|
|
VC4_HD_CSC_CTL_ORDER);
|
|
|
|
|
|
|
|
- if (!vc4_hdmi_is_full_range_rgb(vc4_hdmi, mode)) {
|
|
|
|
+ if (!vc4_hdmi_is_full_range(vc4_hdmi, mode)) {
|
|
|
|
/* CEA VICs other than #1 requre limited range RGB
|
|
|
|
* output unless overridden by an AVI infoframe.
|
|
|
|
* Apply a colorspace conversion to squash 0-255 down
|
2022-05-18 14:32:03 +00:00
|
|
|
@@ -944,7 +944,6 @@ static void vc4_hdmi_csc_setup(struct vc
|
2022-05-16 21:40:32 +00:00
|
|
|
spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
-
|
|
|
|
/*
|
|
|
|
* If we need to output Full Range RGB, then use the unity matrix
|
|
|
|
*
|
2022-05-18 14:32:03 +00:00
|
|
|
@@ -952,15 +951,6 @@ static void vc4_hdmi_csc_setup(struct vc
|
2022-05-16 21:40:32 +00:00
|
|
|
* [ 0 1 0 0]
|
|
|
|
* [ 0 0 1 0]
|
|
|
|
*
|
|
|
|
- * Matrix is signed 2p13 fixed point, with signed 9p6 offsets
|
|
|
|
- */
|
|
|
|
-static const u16 vc5_hdmi_csc_full_rgb_unity[3][4] = {
|
|
|
|
- { 0x2000, 0x0000, 0x0000, 0x0000 },
|
|
|
|
- { 0x0000, 0x2000, 0x0000, 0x0000 },
|
|
|
|
- { 0x0000, 0x0000, 0x2000, 0x0000 },
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-/*
|
|
|
|
* CEA VICs other than #1 require limited range RGB output unless
|
|
|
|
* overridden by an AVI infoframe. Apply a colorspace conversion to
|
|
|
|
* squash 0-255 down to 16-235. The matrix here is:
|
2022-05-18 14:32:03 +00:00
|
|
|
@@ -971,42 +961,105 @@ static const u16 vc5_hdmi_csc_full_rgb_u
|
2022-05-16 21:40:32 +00:00
|
|
|
*
|
|
|
|
* Matrix is signed 2p13 fixed point, with signed 9p6 offsets
|
|
|
|
*/
|
|
|
|
-static const u16 vc5_hdmi_csc_full_rgb_to_limited_rgb[3][4] = {
|
|
|
|
- { 0x1b80, 0x0000, 0x0000, 0x0400 },
|
|
|
|
- { 0x0000, 0x1b80, 0x0000, 0x0400 },
|
|
|
|
- { 0x0000, 0x0000, 0x1b80, 0x0400 },
|
|
|
|
+static const u16 vc5_hdmi_csc_full_rgb_to_rgb[2][3][4] = {
|
|
|
|
+ {
|
|
|
|
+ /* Full range - unity */
|
|
|
|
+ { 0x2000, 0x0000, 0x0000, 0x0000 },
|
|
|
|
+ { 0x0000, 0x2000, 0x0000, 0x0000 },
|
|
|
|
+ { 0x0000, 0x0000, 0x2000, 0x0000 },
|
|
|
|
+ }, {
|
|
|
|
+ /* Limited range */
|
|
|
|
+ { 0x1b80, 0x0000, 0x0000, 0x0400 },
|
|
|
|
+ { 0x0000, 0x1b80, 0x0000, 0x0400 },
|
|
|
|
+ { 0x0000, 0x0000, 0x1b80, 0x0400 },
|
|
|
|
+ }
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * Conversion between Full Range RGB and YUV using the BT.601 Colorspace
|
|
|
|
+ *
|
|
|
|
+ * Full range
|
|
|
|
+ * [ 0.299000 0.587000 0.114000 0.000000 ]
|
|
|
|
+ * [ -0.168736 -0.331264 0.500000 128.000000 ]
|
|
|
|
+ * [ 0.500000 -0.418688 -0.081312 128.000000 ]
|
|
|
|
+ *
|
|
|
|
+ * Limited range
|
|
|
|
+ * [ 0.255785 0.502160 0.097523 16.000000 ]
|
|
|
|
+ * [ -0.147644 -0.289856 0.437500 128.000000 ]
|
|
|
|
+ * [ 0.437500 -0.366352 -0.071148 128.000000 ]
|
|
|
|
+ *
|
|
|
|
+ * Matrix is signed 2p13 fixed point, with signed 9p6 offsets
|
|
|
|
+ */
|
|
|
|
+static const u16 vc5_hdmi_csc_full_rgb_to_yuv_bt601[2][3][4] = {
|
|
|
|
+ {
|
|
|
|
+ /* Full range */
|
|
|
|
+ { 0x0991, 0x12c9, 0x03a6, 0x0000 },
|
|
|
|
+ { 0xfa9b, 0xf567, 0x1000, 0x2000 },
|
|
|
|
+ { 0x1000, 0xf29b, 0xfd67, 0x2000 },
|
|
|
|
+ }, {
|
|
|
|
+ /* Limited range */
|
|
|
|
+ { 0x082f, 0x1012, 0x031f, 0x0400 },
|
|
|
|
+ { 0xfb48, 0xf6ba, 0x0e00, 0x2000 },
|
|
|
|
+ { 0x0e00, 0xf448, 0xfdba, 0x2000 },
|
|
|
|
+ }
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
- * Conversion between Full Range RGB and Full Range YUV422 using the
|
|
|
|
- * BT.709 Colorspace
|
|
|
|
+ * Conversion between Full Range RGB and YUV using the BT.709 Colorspace
|
|
|
|
+ *
|
|
|
|
+ * Full range
|
|
|
|
+ * [ 0.212600 0.715200 0.072200 0.000000 ]
|
|
|
|
+ * [ -0.114572 -0.385428 0.500000 128.000000 ]
|
|
|
|
+ * [ 0.500000 -0.454153 -0.045847 128.000000 ]
|
|
|
|
*
|
|
|
|
- * [ 0.212639 0.715169 0.072192 0 ]
|
|
|
|
- * [ -0.117208 -0.394207 0.511416 128 ]
|
|
|
|
- * [ 0.511416 -0.464524 -0.046891 128 ]
|
|
|
|
+ * Limited range
|
|
|
|
+ * [ 0.181873 0.611831 0.061765 16.000000 ]
|
|
|
|
+ * [ -0.100251 -0.337249 0.437500 128.000000 ]
|
|
|
|
+ * [ 0.437500 -0.397384 -0.040116 128.000000 ]
|
|
|
|
*
|
|
|
|
* Matrix is signed 2p13 fixed point, with signed 9p6 offsets
|
|
|
|
*/
|
|
|
|
-static const u16 vc5_hdmi_csc_full_rgb_to_full_yuv422_bt709[3][4] = {
|
|
|
|
- { 0x06ce, 0x16e3, 0x024f, 0x0000 },
|
|
|
|
- { 0xfc41, 0xf364, 0x105e, 0x2000 },
|
|
|
|
- { 0x105e, 0xf124, 0xfe81, 0x2000 },
|
|
|
|
+static const u16 vc5_hdmi_csc_full_rgb_to_yuv_bt709[2][3][4] = {
|
|
|
|
+ {
|
|
|
|
+ /* Full range */
|
|
|
|
+ { 0x06ce, 0x16e3, 0x024f, 0x0000 },
|
|
|
|
+ { 0xfc56, 0xf3ac, 0x1000, 0x2000 },
|
|
|
|
+ { 0x1000, 0xf179, 0xfe89, 0x2000 },
|
|
|
|
+ }, {
|
|
|
|
+ /* Limited range */
|
|
|
|
+ { 0x05d2, 0x1394, 0x01fa, 0x0400 },
|
|
|
|
+ { 0xfccc, 0xf536, 0x0e00, 0x2000 },
|
|
|
|
+ { 0x0e00, 0xf34a, 0xfeb8, 0x2000 },
|
|
|
|
+ }
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
- * Conversion between Full Range RGB and Full Range YUV444 using the
|
|
|
|
- * BT.709 Colorspace
|
|
|
|
+ * Conversion between Full Range RGB and YUV using the BT.2020 Colorspace
|
|
|
|
+ *
|
|
|
|
+ * Full range
|
|
|
|
+ * [ 0.262700 0.678000 0.059300 0.000000 ]
|
|
|
|
+ * [ -0.139630 -0.360370 0.500000 128.000000 ]
|
|
|
|
+ * [ 0.500000 -0.459786 -0.040214 128.000000 ]
|
|
|
|
*
|
|
|
|
- * [ -0.117208 -0.394207 0.511416 128 ]
|
|
|
|
- * [ 0.511416 -0.464524 -0.046891 128 ]
|
|
|
|
- * [ 0.212639 0.715169 0.072192 0 ]
|
|
|
|
+ * Limited range
|
|
|
|
+ * [ 0.224732 0.580008 0.050729 16.000000 ]
|
|
|
|
+ * [ -0.122176 -0.315324 0.437500 128.000000 ]
|
|
|
|
+ * [ 0.437500 -0.402312 -0.035188 128.000000 ]
|
|
|
|
*
|
|
|
|
* Matrix is signed 2p13 fixed point, with signed 9p6 offsets
|
|
|
|
*/
|
|
|
|
-static const u16 vc5_hdmi_csc_full_rgb_to_full_yuv444_bt709[3][4] = {
|
|
|
|
- { 0xfc41, 0xf364, 0x105e, 0x2000 },
|
|
|
|
- { 0x105e, 0xf124, 0xfe81, 0x2000 },
|
|
|
|
- { 0x06ce, 0x16e3, 0x024f, 0x0000 },
|
|
|
|
+static const u16 vc5_hdmi_csc_full_rgb_to_yuv_bt2020[2][3][4] = {
|
|
|
|
+ {
|
|
|
|
+ /* Full range */
|
|
|
|
+ { 0x0868, 0x15b2, 0x01e6, 0x0000 },
|
|
|
|
+ { 0xfb89, 0xf479, 0x1000, 0x2000 },
|
|
|
|
+ { 0x1000, 0xf14a, 0xfeb8, 0x2000 },
|
|
|
|
+ }, {
|
|
|
|
+ /* Limited range */
|
|
|
|
+ { 0x0731, 0x128f, 0x01a0, 0x0400 },
|
|
|
|
+ { 0xfc18, 0xf5ea, 0x0e00, 0x2000 },
|
|
|
|
+ { 0x0e00, 0xf321, 0xfee1, 0x2000 },
|
|
|
|
+ }
|
|
|
|
};
|
|
|
|
|
|
|
|
static void vc5_hdmi_set_csc_coeffs(struct vc4_hdmi *vc4_hdmi,
|
2022-05-18 14:32:03 +00:00
|
|
|
@@ -1022,12 +1075,28 @@ static void vc5_hdmi_set_csc_coeffs(stru
|
2022-05-16 21:40:32 +00:00
|
|
|
HDMI_WRITE(HDMI_CSC_34_33, (coeffs[2][3] << 16) | coeffs[2][2]);
|
|
|
|
}
|
|
|
|
|
|
|
|
+static void vc5_hdmi_set_csc_coeffs_swap(struct vc4_hdmi *vc4_hdmi,
|
|
|
|
+ const u16 coeffs[3][4])
|
|
|
|
+{
|
|
|
|
+ lockdep_assert_held(&vc4_hdmi->hw_lock);
|
|
|
|
+
|
|
|
|
+ /* YUV444 needs the CSC matrices using the channels in a different order */
|
|
|
|
+ HDMI_WRITE(HDMI_CSC_12_11, (coeffs[2][1] << 16) | coeffs[2][0]);
|
|
|
|
+ HDMI_WRITE(HDMI_CSC_14_13, (coeffs[2][3] << 16) | coeffs[2][2]);
|
|
|
|
+ HDMI_WRITE(HDMI_CSC_22_21, (coeffs[0][1] << 16) | coeffs[0][0]);
|
|
|
|
+ HDMI_WRITE(HDMI_CSC_24_23, (coeffs[0][3] << 16) | coeffs[0][2]);
|
|
|
|
+ HDMI_WRITE(HDMI_CSC_32_31, (coeffs[1][1] << 16) | coeffs[1][0]);
|
|
|
|
+ HDMI_WRITE(HDMI_CSC_34_33, (coeffs[1][3] << 16) | coeffs[1][2]);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi,
|
|
|
|
struct drm_connector_state *state,
|
|
|
|
const struct drm_display_mode *mode)
|
|
|
|
{
|
|
|
|
struct vc4_hdmi_connector_state *vc4_state =
|
|
|
|
conn_state_to_vc4_hdmi_conn_state(state);
|
|
|
|
+ unsigned int lim_range = vc4_hdmi_is_full_range(vc4_hdmi, mode) ? 0 : 1;
|
|
|
|
+ const u16 (*csc)[4];
|
|
|
|
unsigned long flags;
|
|
|
|
u32 if_cfg = 0;
|
|
|
|
u32 if_xbar = 0x543210;
|
2022-05-18 14:32:03 +00:00
|
|
|
@@ -1039,31 +1108,56 @@ static void vc5_hdmi_csc_setup(struct vc
|
2022-05-16 21:40:32 +00:00
|
|
|
|
|
|
|
switch (vc4_state->output_format) {
|
|
|
|
case VC4_HDMI_OUTPUT_YUV444:
|
|
|
|
- vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_to_full_yuv444_bt709);
|
|
|
|
- break;
|
|
|
|
-
|
|
|
|
case VC4_HDMI_OUTPUT_YUV422:
|
|
|
|
- csc_ctl |= VC4_SET_FIELD(VC5_MT_CP_CSC_CTL_FILTER_MODE_444_TO_422_STANDARD,
|
|
|
|
- VC5_MT_CP_CSC_CTL_FILTER_MODE_444_TO_422) |
|
|
|
|
- VC5_MT_CP_CSC_CTL_USE_444_TO_422 |
|
|
|
|
- VC5_MT_CP_CSC_CTL_USE_RNG_SUPPRESSION;
|
|
|
|
-
|
|
|
|
- csc_chan_ctl |= VC4_SET_FIELD(VC5_MT_CP_CHANNEL_CTL_OUTPUT_REMAP_LEGACY_STYLE,
|
|
|
|
- VC5_MT_CP_CHANNEL_CTL_OUTPUT_REMAP);
|
|
|
|
+ switch (state->colorspace) {
|
|
|
|
+ default:
|
|
|
|
+ case DRM_MODE_COLORIMETRY_NO_DATA:
|
|
|
|
+ case DRM_MODE_COLORIMETRY_BT709_YCC:
|
|
|
|
+ case DRM_MODE_COLORIMETRY_XVYCC_709:
|
|
|
|
+ case DRM_MODE_COLORIMETRY_RGB_WIDE_FIXED:
|
|
|
|
+ case DRM_MODE_COLORIMETRY_RGB_WIDE_FLOAT:
|
|
|
|
+ csc = vc5_hdmi_csc_full_rgb_to_yuv_bt709[lim_range];
|
|
|
|
+ break;
|
|
|
|
+ case DRM_MODE_COLORIMETRY_SMPTE_170M_YCC:
|
|
|
|
+ case DRM_MODE_COLORIMETRY_XVYCC_601:
|
|
|
|
+ case DRM_MODE_COLORIMETRY_SYCC_601:
|
|
|
|
+ case DRM_MODE_COLORIMETRY_OPYCC_601:
|
|
|
|
+ case DRM_MODE_COLORIMETRY_BT601_YCC:
|
|
|
|
+ csc = vc5_hdmi_csc_full_rgb_to_yuv_bt601[lim_range];
|
|
|
|
+ break;
|
|
|
|
+ case DRM_MODE_COLORIMETRY_BT2020_CYCC:
|
|
|
|
+ case DRM_MODE_COLORIMETRY_BT2020_YCC:
|
|
|
|
+ case DRM_MODE_COLORIMETRY_BT2020_RGB:
|
|
|
|
+ case DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65:
|
|
|
|
+ case DRM_MODE_COLORIMETRY_DCI_P3_RGB_THEATER:
|
|
|
|
+ csc = vc5_hdmi_csc_full_rgb_to_yuv_bt2020[lim_range];
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- if_cfg |= VC4_SET_FIELD(VC5_DVP_HT_VEC_INTERFACE_CFG_SEL_422_FORMAT_422_LEGACY,
|
|
|
|
- VC5_DVP_HT_VEC_INTERFACE_CFG_SEL_422);
|
|
|
|
+ if (vc4_state->output_format == VC4_HDMI_OUTPUT_YUV422) {
|
|
|
|
+ csc_ctl |= VC4_SET_FIELD(VC5_MT_CP_CSC_CTL_FILTER_MODE_444_TO_422_STANDARD,
|
|
|
|
+ VC5_MT_CP_CSC_CTL_FILTER_MODE_444_TO_422) |
|
|
|
|
+ VC5_MT_CP_CSC_CTL_USE_444_TO_422 |
|
|
|
|
+ VC5_MT_CP_CSC_CTL_USE_RNG_SUPPRESSION;
|
|
|
|
+
|
|
|
|
+ csc_chan_ctl |= VC4_SET_FIELD(VC5_MT_CP_CHANNEL_CTL_OUTPUT_REMAP_LEGACY_STYLE,
|
|
|
|
+ VC5_MT_CP_CHANNEL_CTL_OUTPUT_REMAP);
|
|
|
|
+
|
|
|
|
+ if_cfg |= VC4_SET_FIELD(VC5_DVP_HT_VEC_INTERFACE_CFG_SEL_422_FORMAT_422_LEGACY,
|
|
|
|
+ VC5_DVP_HT_VEC_INTERFACE_CFG_SEL_422);
|
|
|
|
+
|
|
|
|
+ vc5_hdmi_set_csc_coeffs(vc4_hdmi, csc);
|
|
|
|
+ } else {
|
|
|
|
+ vc5_hdmi_set_csc_coeffs_swap(vc4_hdmi, csc);
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_to_full_yuv422_bt709);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VC4_HDMI_OUTPUT_RGB:
|
|
|
|
if_xbar = 0x354021;
|
|
|
|
|
|
|
|
- if (!vc4_hdmi_is_full_range_rgb(vc4_hdmi, mode))
|
|
|
|
- vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_to_limited_rgb);
|
|
|
|
- else
|
|
|
|
- vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_unity);
|
|
|
|
+ vc5_hdmi_set_csc_coeffs(vc4_hdmi,
|
|
|
|
+ vc5_hdmi_csc_full_rgb_to_rgb[lim_range]);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|