Skip to content

Commit a64ced7

Browse files
committed
drm/vc4: hdmi: Support HDMI YUV output
The HDMI controllers in the BCM2711 support YUV444 and YUV420 outputs, let's add support for it. Signed-off-by: Maxime Ripard <[email protected]>
1 parent 510bf67 commit a64ced7

File tree

3 files changed

+119
-11
lines changed

3 files changed

+119
-11
lines changed

drivers/gpu/drm/vc4/vc4_hdmi.c

Lines changed: 97 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,7 @@ static void vc4_hdmi_connector_reset(struct drm_connector *connector)
608608

609609
new_state->base.max_bpc = 8;
610610
new_state->base.max_requested_bpc = 8;
611+
new_state->base.color_format = ilog2(DRM_COLOR_FORMAT_RGB444);
611612
drm_atomic_helper_connector_tv_reset(connector);
612613
}
613614

@@ -672,6 +673,14 @@ static int vc4_hdmi_connector_init(struct drm_device *dev,
672673
return ret;
673674

674675
drm_connector_attach_colorspace_property(connector);
676+
677+
ret = drm_connector_create_hdmi_color_formats_properties(connector,
678+
DRM_COLOR_FORMAT_RGB444 |
679+
DRM_COLOR_FORMAT_YCRCB444 |
680+
DRM_COLOR_FORMAT_YCRCB422);
681+
if (ret)
682+
return ret;
683+
675684
drm_connector_attach_tv_margin_properties(connector);
676685
drm_connector_attach_max_bpc_property(connector, 8, 12);
677686

@@ -787,6 +796,7 @@ static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder)
787796
HDMI_QUANTIZATION_RANGE_LIMITED);
788797
drm_hdmi_avi_infoframe_colorimetry(&frame.avi, cstate);
789798
drm_hdmi_avi_infoframe_bars(&frame.avi, cstate);
799+
drm_hdmi_avi_infoframe_colorspace(&frame.avi, cstate);
790800

791801
vc4_hdmi_write_infoframe(encoder, &frame);
792802
}
@@ -1057,6 +1067,38 @@ static const u16 vc5_hdmi_csc_full_rgb_to_limited_rgb[3][4] = {
10571067
{ 0x0000, 0x0000, 0x1b80, 0x0400 },
10581068
};
10591069

1070+
/*
1071+
* Conversion between Full Range RGB and Full Range YUV422 using the
1072+
* BT.709 Colorspace
1073+
*
1074+
* [ 0.212639 0.715169 0.072192 0 ]
1075+
* [ -0.117208 -0.394207 0.511416 128 ]
1076+
* [ 0.511416 -0.464524 -0.046891 128 ]
1077+
*
1078+
* Matrix is signed 2p13 fixed point, with signed 9p6 offsets
1079+
*/
1080+
static const u16 vc5_hdmi_csc_full_rgb_to_full_yuv422_bt709[3][4] = {
1081+
{ 0x06ce, 0x16e3, 0x024f, 0x0000 },
1082+
{ 0xfc41, 0xf364, 0x105e, 0x2000 },
1083+
{ 0x105e, 0xf124, 0xfe81, 0x2000 },
1084+
};
1085+
1086+
/*
1087+
* Conversion between Full Range RGB and Full Range YUV444 using the
1088+
* BT.709 Colorspace
1089+
*
1090+
* [ -0.117208 -0.394207 0.511416 128 ]
1091+
* [ 0.511416 -0.464524 -0.046891 128 ]
1092+
* [ 0.212639 0.715169 0.072192 0 ]
1093+
*
1094+
* Matrix is signed 2p13 fixed point, with signed 9p6 offsets
1095+
*/
1096+
static const u16 vc5_hdmi_csc_full_rgb_to_full_yuv444_bt709[3][4] = {
1097+
{ 0xfc41, 0xf364, 0x105e, 0x2000 },
1098+
{ 0x105e, 0xf124, 0xfe81, 0x2000 },
1099+
{ 0x06ce, 0x16e3, 0x024f, 0x0000 },
1100+
};
1101+
10601102
static void vc5_hdmi_set_csc_coeffs(struct vc4_hdmi *vc4_hdmi,
10611103
const u16 coeffs[3][4])
10621104
{
@@ -1072,16 +1114,48 @@ static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi,
10721114
struct drm_connector_state *state,
10731115
const struct drm_display_mode *mode)
10741116
{
1117+
u32 if_cfg = 0;
1118+
u32 if_xbar = 0x543210;
1119+
u32 csc_chan_ctl = 0;
10751120
u32 csc_ctl = VC5_MT_CP_CSC_CTL_ENABLE | VC4_SET_FIELD(VC4_HD_CSC_CTL_MODE_CUSTOM,
10761121
VC5_MT_CP_CSC_CTL_MODE);
10771122

1078-
HDMI_WRITE(HDMI_VEC_INTERFACE_XBAR, 0x354021);
1123+
switch (BIT(state->color_format)) {
1124+
case DRM_COLOR_FORMAT_YCRCB444:
1125+
vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_to_full_yuv444_bt709);
1126+
break;
10791127

1080-
if (!vc4_hdmi_is_full_range_rgb(vc4_hdmi, mode))
1081-
vc5_hdmi_set_csc_coeffs(vc4_hdmi, &vc5_hdmi_csc_full_rgb_to_limited_rgb);
1082-
else
1083-
vc5_hdmi_set_csc_coeffs(vc4_hdmi, &vc5_hdmi_csc_full_rgb_unity);
1128+
case DRM_COLOR_FORMAT_YCRCB422:
1129+
csc_ctl |= VC4_SET_FIELD(VC5_MT_CP_CSC_CTL_FILTER_MODE_444_TO_422_STANDARD,
1130+
VC5_MT_CP_CSC_CTL_FILTER_MODE_444_TO_422) |
1131+
VC5_MT_CP_CSC_CTL_USE_444_TO_422 |
1132+
VC5_MT_CP_CSC_CTL_USE_RNG_SUPPRESSION;
10841133

1134+
csc_chan_ctl |= VC4_SET_FIELD(VC5_MT_CP_CHANNEL_CTL_OUTPUT_REMAP_LEGACY_STYLE,
1135+
VC5_MT_CP_CHANNEL_CTL_OUTPUT_REMAP);
1136+
1137+
if_cfg |= VC4_SET_FIELD(VC5_DVP_HT_VEC_INTERFACE_CFG_SEL_422_FORMAT_422_LEGACY,
1138+
VC5_DVP_HT_VEC_INTERFACE_CFG_SEL_422);
1139+
1140+
vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_to_full_yuv422_bt709);
1141+
break;
1142+
1143+
case DRM_COLOR_FORMAT_RGB444:
1144+
if_xbar = 0x354021;
1145+
1146+
if (!vc4_hdmi_is_full_range_rgb(vc4_hdmi, mode))
1147+
vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_to_limited_rgb);
1148+
else
1149+
vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_unity);
1150+
break;
1151+
1152+
default:
1153+
break;
1154+
}
1155+
1156+
HDMI_WRITE(HDMI_VEC_INTERFACE_CFG, if_cfg);
1157+
HDMI_WRITE(HDMI_VEC_INTERFACE_XBAR, if_xbar);
1158+
HDMI_WRITE(HDMI_CSC_CHANNEL_CTL, csc_chan_ctl);
10851159
HDMI_WRITE(HDMI_CSC_CTL, csc_ctl);
10861160
}
10871161

@@ -1195,6 +1269,15 @@ static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi,
11951269
break;
11961270
}
11971271

1272+
/*
1273+
* YCC422 is always 36-bit and not considered deep colour so
1274+
* doesn't signal in GCP.
1275+
*/
1276+
if (BIT(state->color_format) == DRM_COLOR_FORMAT_YCRCB422) {
1277+
gcp = 4;
1278+
gcp_en = false;
1279+
}
1280+
11981281
reg = HDMI_READ(HDMI_DEEP_COLOR_CONFIG_1);
11991282
reg &= ~(VC5_HDMI_DEEP_COLOR_CONFIG_1_INIT_PACK_PHASE_MASK |
12001283
VC5_HDMI_DEEP_COLOR_CONFIG_1_COLOR_DEPTH_MASK);
@@ -1455,12 +1538,15 @@ static int vc4_hdmi_encoder_atomic_check(struct drm_encoder *encoder,
14551538
pixel_rate = mode->clock * 1000;
14561539
}
14571540

1458-
if (conn_state->max_bpc == 12) {
1459-
pixel_rate = pixel_rate * 150;
1460-
do_div(pixel_rate, 100);
1461-
} else if (conn_state->max_bpc == 10) {
1462-
pixel_rate = pixel_rate * 125;
1463-
do_div(pixel_rate, 100);
1541+
if (BIT(conn_state->color_format) == DRM_COLOR_FORMAT_RGB444 ||
1542+
BIT(conn_state->color_format) == DRM_COLOR_FORMAT_YCRCB444) {
1543+
if (conn_state->max_bpc == 12) {
1544+
pixel_rate = pixel_rate * 150;
1545+
do_div(pixel_rate, 100);
1546+
} else if (conn_state->max_bpc == 10) {
1547+
pixel_rate = pixel_rate * 125;
1548+
do_div(pixel_rate, 100);
1549+
}
14641550
}
14651551

14661552
if (mode->flags & DRM_MODE_FLAG_DBLCLK)

drivers/gpu/drm/vc4/vc4_hdmi_regs.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ enum vc4_hdmi_field {
5252
HDMI_CSC_24_23,
5353
HDMI_CSC_32_31,
5454
HDMI_CSC_34_33,
55+
HDMI_CSC_CHANNEL_CTL,
5556
HDMI_CSC_CTL,
5657

5758
/*
@@ -117,6 +118,7 @@ enum vc4_hdmi_field {
117118
HDMI_TX_PHY_POWERDOWN_CTL,
118119
HDMI_TX_PHY_RESET_CTL,
119120
HDMI_TX_PHY_TMDS_CLK_WORD_SEL,
121+
HDMI_VEC_INTERFACE_CFG,
120122
HDMI_VEC_INTERFACE_XBAR,
121123
HDMI_VERTA0,
122124
HDMI_VERTA1,
@@ -242,6 +244,7 @@ static const struct vc4_hdmi_register vc5_hdmi_hdmi0_fields[] = {
242244
VC4_HDMI_REG(HDMI_SCRAMBLER_CTL, 0x1c4),
243245

244246
VC5_DVP_REG(HDMI_CLOCK_STOP, 0x0bc),
247+
VC5_DVP_REG(HDMI_VEC_INTERFACE_CFG, 0x0ec),
245248
VC5_DVP_REG(HDMI_VEC_INTERFACE_XBAR, 0x0f0),
246249

247250
VC5_PHY_REG(HDMI_TX_PHY_RESET_CTL, 0x000),
@@ -287,6 +290,7 @@ static const struct vc4_hdmi_register vc5_hdmi_hdmi0_fields[] = {
287290
VC5_CSC_REG(HDMI_CSC_24_23, 0x010),
288291
VC5_CSC_REG(HDMI_CSC_32_31, 0x014),
289292
VC5_CSC_REG(HDMI_CSC_34_33, 0x018),
293+
VC5_CSC_REG(HDMI_CSC_CHANNEL_CTL, 0x02c),
290294
};
291295

292296
static const struct vc4_hdmi_register vc5_hdmi_hdmi1_fields[] = {
@@ -322,6 +326,7 @@ static const struct vc4_hdmi_register vc5_hdmi_hdmi1_fields[] = {
322326
VC4_HDMI_REG(HDMI_SCRAMBLER_CTL, 0x1c4),
323327

324328
VC5_DVP_REG(HDMI_CLOCK_STOP, 0x0bc),
329+
VC5_DVP_REG(HDMI_VEC_INTERFACE_CFG, 0x0ec),
325330
VC5_DVP_REG(HDMI_VEC_INTERFACE_XBAR, 0x0f0),
326331

327332
VC5_PHY_REG(HDMI_TX_PHY_RESET_CTL, 0x000),
@@ -367,6 +372,7 @@ static const struct vc4_hdmi_register vc5_hdmi_hdmi1_fields[] = {
367372
VC5_CSC_REG(HDMI_CSC_24_23, 0x010),
368373
VC5_CSC_REG(HDMI_CSC_32_31, 0x014),
369374
VC5_CSC_REG(HDMI_CSC_34_33, 0x018),
375+
VC5_CSC_REG(HDMI_CSC_CHANNEL_CTL, 0x02c),
370376
};
371377

372378
static inline

drivers/gpu/drm/vc4/vc4_regs.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -774,11 +774,27 @@ enum {
774774
# define VC4_HD_CSC_CTL_RGB2YCC BIT(1)
775775
# define VC4_HD_CSC_CTL_ENABLE BIT(0)
776776

777+
# define VC5_MT_CP_CSC_CTL_USE_444_TO_422 BIT(6)
778+
# define VC5_MT_CP_CSC_CTL_FILTER_MODE_444_TO_422_MASK \
779+
VC4_MASK(5, 4)
780+
# define VC5_MT_CP_CSC_CTL_FILTER_MODE_444_TO_422_STANDARD \
781+
3
782+
# define VC5_MT_CP_CSC_CTL_USE_RNG_SUPPRESSION BIT(3)
777783
# define VC5_MT_CP_CSC_CTL_ENABLE BIT(2)
778784
# define VC5_MT_CP_CSC_CTL_MODE_MASK VC4_MASK(1, 0)
779785

786+
# define VC5_MT_CP_CHANNEL_CTL_OUTPUT_REMAP_MASK \
787+
VC4_MASK(7, 6)
788+
# define VC5_MT_CP_CHANNEL_CTL_OUTPUT_REMAP_LEGACY_STYLE \
789+
2
790+
780791
# define VC4_DVP_HT_CLOCK_STOP_PIXEL BIT(1)
781792

793+
# define VC5_DVP_HT_VEC_INTERFACE_CFG_SEL_422_MASK \
794+
VC4_MASK(3, 2)
795+
# define VC5_DVP_HT_VEC_INTERFACE_CFG_SEL_422_FORMAT_422_LEGACY \
796+
2
797+
782798
/* HVS display list information. */
783799
#define HVS_BOOTLOADER_DLIST_END 32
784800

0 commit comments

Comments
 (0)