@@ -608,6 +608,7 @@ static void vc4_hdmi_connector_reset(struct drm_connector *connector)
608
608
609
609
new_state -> base .max_bpc = 8 ;
610
610
new_state -> base .max_requested_bpc = 8 ;
611
+ new_state -> base .color_format = ilog2 (DRM_COLOR_FORMAT_RGB444 );
611
612
drm_atomic_helper_connector_tv_reset (connector );
612
613
}
613
614
@@ -672,6 +673,14 @@ static int vc4_hdmi_connector_init(struct drm_device *dev,
672
673
return ret ;
673
674
674
675
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
+
675
684
drm_connector_attach_tv_margin_properties (connector );
676
685
drm_connector_attach_max_bpc_property (connector , 8 , 12 );
677
686
@@ -787,6 +796,7 @@ static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder)
787
796
HDMI_QUANTIZATION_RANGE_LIMITED );
788
797
drm_hdmi_avi_infoframe_colorimetry (& frame .avi , cstate );
789
798
drm_hdmi_avi_infoframe_bars (& frame .avi , cstate );
799
+ drm_hdmi_avi_infoframe_colorspace (& frame .avi , cstate );
790
800
791
801
vc4_hdmi_write_infoframe (encoder , & frame );
792
802
}
@@ -1057,6 +1067,38 @@ static const u16 vc5_hdmi_csc_full_rgb_to_limited_rgb[3][4] = {
1057
1067
{ 0x0000 , 0x0000 , 0x1b80 , 0x0400 },
1058
1068
};
1059
1069
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
+
1060
1102
static void vc5_hdmi_set_csc_coeffs (struct vc4_hdmi * vc4_hdmi ,
1061
1103
const u16 coeffs [3 ][4 ])
1062
1104
{
@@ -1072,16 +1114,48 @@ static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi,
1072
1114
struct drm_connector_state * state ,
1073
1115
const struct drm_display_mode * mode )
1074
1116
{
1117
+ u32 if_cfg = 0 ;
1118
+ u32 if_xbar = 0x543210 ;
1119
+ u32 csc_chan_ctl = 0 ;
1075
1120
u32 csc_ctl = VC5_MT_CP_CSC_CTL_ENABLE | VC4_SET_FIELD (VC4_HD_CSC_CTL_MODE_CUSTOM ,
1076
1121
VC5_MT_CP_CSC_CTL_MODE );
1077
1122
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 ;
1079
1127
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 ;
1084
1133
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 );
1085
1159
HDMI_WRITE (HDMI_CSC_CTL , csc_ctl );
1086
1160
}
1087
1161
@@ -1195,6 +1269,15 @@ static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi,
1195
1269
break ;
1196
1270
}
1197
1271
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
+
1198
1281
reg = HDMI_READ (HDMI_DEEP_COLOR_CONFIG_1 );
1199
1282
reg &= ~(VC5_HDMI_DEEP_COLOR_CONFIG_1_INIT_PACK_PHASE_MASK |
1200
1283
VC5_HDMI_DEEP_COLOR_CONFIG_1_COLOR_DEPTH_MASK );
@@ -1455,12 +1538,15 @@ static int vc4_hdmi_encoder_atomic_check(struct drm_encoder *encoder,
1455
1538
pixel_rate = mode -> clock * 1000 ;
1456
1539
}
1457
1540
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
+ }
1464
1550
}
1465
1551
1466
1552
if (mode -> flags & DRM_MODE_FLAG_DBLCLK )
0 commit comments