drm: bridge: dw-hdmi: Support BT709 hdr and 8-bit hdr output

Signed-off-by: Algea Cao <algea.cao@rock-chips.com>
Change-Id: If9a90c05f98f39aa2481aec9a4b2fa5378313f45
This commit is contained in:
Algea Cao
2023-02-08 17:29:50 +08:00
committed by Tao Huang
parent 5d81881b45
commit 053a921a19
3 changed files with 72 additions and 17 deletions
+38 -4
View File
@@ -2279,6 +2279,11 @@ static void hdmi_config_drm_infoframe(struct dw_hdmi *hdmi,
hdmi_writeb(hdmi, buffer[4 + i], HDMI_FC_DRM_PB0 + i);
hdmi_writeb(hdmi, 1, HDMI_FC_DRM_UP);
/*
* avi and hdr infoframe cannot be sent at the same time
* for compatibility with Huawei TV
*/
mdelay(50);
hdmi_modb(hdmi, HDMI_FC_PACKET_TX_EN_DRM_ENABLE,
HDMI_FC_PACKET_TX_EN_DRM_MASK, HDMI_FC_PACKET_TX_EN);
@@ -2639,6 +2644,9 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi,
hdmi->hdmi_data.enc_out_bus_format =
MEDIA_BUS_FMT_RGB888_1X24;
if (hdmi->plat_data->set_prev_bus_format)
hdmi->plat_data->set_prev_bus_format(data, hdmi->hdmi_data.enc_out_bus_format);
/* TOFIX: Get input encoding from plat data or fallback to none */
if (hdmi->plat_data->get_enc_in_encoding)
hdmi->hdmi_data.enc_in_encoding =
@@ -3032,9 +3040,31 @@ static bool hdr_metadata_equal(const struct drm_connector_state *old_state,
{
struct drm_property_blob *old_blob = old_state->hdr_output_metadata;
struct drm_property_blob *new_blob = new_state->hdr_output_metadata;
int i;
u8 *data;
if (!old_blob || !new_blob)
return old_blob == new_blob;
if (!old_blob && !new_blob)
return true;
if (!old_blob) {
data = (u8 *)new_blob->data;
for (i = 0; i < new_blob->length; i++)
if (data[i])
return false;
return true;
}
if (!new_blob) {
data = (u8 *)old_blob->data;
for (i = 0; i < old_blob->length; i++)
if (data[i])
return false;
return true;
}
if (old_blob->length != new_blob->length)
return false;
@@ -3048,8 +3078,10 @@ static bool check_hdr_color_change(struct drm_connector_state *old_state,
{
void *data = hdmi->plat_data->phy_data;
if (!hdr_metadata_equal(old_state, new_state))
return hdmi->plat_data->check_hdr_color_change(new_state, data);
if (!hdr_metadata_equal(old_state, new_state)) {
hdmi->plat_data->check_hdr_color_change(new_state, data);
return true;
}
return false;
}
@@ -3083,6 +3115,8 @@ static int dw_hdmi_connector_atomic_check(struct drm_connector *connector,
* drm_display_mode and set phy status to enabled.
*/
if (!vmode->mpixelclock) {
hdmi->curr_conn = connector;
if (hdmi->plat_data->get_enc_in_encoding)
hdmi->hdmi_data.enc_in_encoding =
hdmi->plat_data->get_enc_in_encoding(data);
+33 -12
View File
@@ -201,6 +201,7 @@ struct rockchip_hdmi {
unsigned long bus_format;
unsigned long output_bus_format;
unsigned long enc_out_encoding;
unsigned long prev_bus_format;
int color_changed;
int hpd_irq;
@@ -1870,6 +1871,7 @@ dw_hdmi_rockchip_select_output(struct drm_connector_state *conn_state,
unsigned int color_depth;
bool support_dc = false;
bool sink_is_hdmi = true;
bool yuv422_out = false;
u32 max_tmds_clock = info->max_tmds_clock;
int output_eotf;
@@ -1962,21 +1964,29 @@ dw_hdmi_rockchip_select_output(struct drm_connector_state *conn_state,
hdmi->colorimetry = conn_state->colorspace;
if ((*eotf > HDMI_EOTF_TRADITIONAL_GAMMA_SDR &&
conn_state->connector->hdr_sink_metadata.hdmi_type1.eotf &
BIT(*eotf)) || ((hdmi->colorimetry >= DRM_MODE_COLORIMETRY_BT2020_CYCC) &&
(hdmi->colorimetry <= DRM_MODE_COLORIMETRY_BT2020_YCC)))
/* bt2020 sdr/hdr output */
if ((hdmi->colorimetry >= DRM_MODE_COLORIMETRY_BT2020_CYCC) &&
(hdmi->colorimetry <= DRM_MODE_COLORIMETRY_BT2020_YCC) &&
hdmi->edid_colorimetry & (BIT(6) | BIT(7))) {
*enc_out_encoding = V4L2_YCBCR_ENC_BT2020;
else if ((vic == 6) || (vic == 7) || (vic == 21) || (vic == 22) ||
(vic == 2) || (vic == 3) || (vic == 17) || (vic == 18))
*enc_out_encoding = V4L2_YCBCR_ENC_601;
else
yuv422_out = true;
/* bt709 hdr output */
} else if ((hdmi->colorimetry <= DRM_MODE_COLORIMETRY_BT2020_CYCC) &&
(hdmi->colorimetry >= DRM_MODE_COLORIMETRY_BT2020_YCC) &&
(conn_state->connector->hdr_sink_metadata.hdmi_type1.eotf & BIT(*eotf) &&
*eotf > HDMI_EOTF_TRADITIONAL_GAMMA_SDR)) {
*enc_out_encoding = V4L2_YCBCR_ENC_709;
yuv422_out = true;
} else if ((vic == 6) || (vic == 7) || (vic == 21) || (vic == 22) ||
(vic == 2) || (vic == 3) || (vic == 17) || (vic == 18)) {
*enc_out_encoding = V4L2_YCBCR_ENC_601;
} else {
*enc_out_encoding = V4L2_YCBCR_ENC_709;
}
if (*enc_out_encoding == V4L2_YCBCR_ENC_BT2020 && color_depth == 8) {
/* BT2020 require color depth at lest 10bit */
color_depth = 10;
/* We prefer use YCbCr422 to send 10bit */
if ((yuv422_out || hdmi->hdmi_output == RK_IF_FORMAT_YCBCR_HQ) &&
color_depth == 10 && hdmi_bus_fmt_color_depth(hdmi->prev_bus_format) == 8) {
/* We prefer use YCbCr422 to send hdr 10bit */
if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
*color_format = RK_IF_FORMAT_YCBCR422;
if (hdmi->is_hdmi_qp) {
@@ -2433,6 +2443,13 @@ dw_hdmi_rockchip_check_hdr_color_change(struct drm_connector_state *conn_state,
return false;
}
static void dw_hdmi_rockchip_set_prev_bus_format(void *data, unsigned long bus_format)
{
struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
hdmi->prev_bus_format = bus_format;
}
static const struct drm_prop_enum_list color_depth_enum_list[] = {
{ 0, "Automatic" }, /* Prefer highest color depth */
{ 8, "24bit" },
@@ -2515,6 +2532,7 @@ dw_hdmi_rockchip_attach_properties(struct drm_connector *connector,
}
hdmi->bus_format = color;
hdmi->prev_bus_format = color;
if (hdmi->hdmi_output == RK_IF_FORMAT_YCBCR422) {
if (hdmi->colordepth == 12)
@@ -3211,6 +3229,7 @@ static const struct dw_hdmi_plat_data rk3528_hdmi_drv_data = {
.phy_ops = &rk3528_hdmi_phy_ops,
.phy_name = "inno_dw_hdmi_phy2",
.phy_force_vendor = true,
.use_drm_infoframe = true,
.ycbcr_420_allowed = true,
};
@@ -3343,6 +3362,8 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
dw_hdmi_rockchip_update_color_format;
plat_data->check_hdr_color_change =
dw_hdmi_rockchip_check_hdr_color_change;
plat_data->set_prev_bus_format =
dw_hdmi_rockchip_set_prev_bus_format;
plat_data->property_ops = &dw_hdmi_rockchip_property_ops;
secondary = rockchip_hdmi_find_by_id(dev->driver, !hdmi->id);
+1 -1
View File
@@ -254,8 +254,8 @@ struct dw_hdmi_plat_data {
int (*get_vp_id)(struct drm_crtc_state *crtc_state);
void (*update_color_format)(struct drm_connector_state *conn_state, void *data);
bool (*check_hdr_color_change)(struct drm_connector_state *conn_state, void *data);
int (*get_colorimetry)(void *data, struct edid *edid);
void (*set_prev_bus_format)(void *data, unsigned long bus_format);
int (*get_colorimetry)(void *data, struct edid *edid);
/* Vendor Property support */
const struct dw_hdmi_property_ops *property_ops;