mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-09 12:17:12 +09:00
drm: bridge: dw-hdmi: Implement connector atomic_begin
To avoid screen flash when updating CSC, we introduce connector atomic_begin. Before flush crtc and connector, it's need to send AVMUTE flag to make screen black, and clear flag after CSC updated. AVMUTE -> Update CRTC -> Update HDMI -> Clear AVMUTE Change-Id: Id47caac1e25fcce5a5aa7b879da4a6b9a9bab8a1 Signed-off-by: Zheng Yang <zhengyang@rock-chips.com>
This commit is contained in:
@@ -170,6 +170,7 @@ struct hdmi_data_info {
|
||||
unsigned int pix_repet_factor;
|
||||
unsigned int hdcp_enable;
|
||||
struct hdmi_vmode video_mode;
|
||||
bool update;
|
||||
};
|
||||
|
||||
struct dw_hdmi_i2c {
|
||||
@@ -2015,6 +2016,7 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
|
||||
{
|
||||
int ret;
|
||||
void *data = hdmi->plat_data->phy_data;
|
||||
bool need_delay = false;
|
||||
|
||||
hdmi_disable_overflow_interrupts(hdmi);
|
||||
|
||||
@@ -2098,6 +2100,8 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
|
||||
if (ret)
|
||||
return ret;
|
||||
hdmi->phy.enabled = true;
|
||||
} else {
|
||||
need_delay = true;
|
||||
}
|
||||
/* HDMI Initialization Step B.3 */
|
||||
dw_hdmi_enable_video_path(hdmi);
|
||||
@@ -2128,6 +2132,9 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
|
||||
|
||||
dw_hdmi_clear_overflow(hdmi);
|
||||
|
||||
/* XXX: Add delay to make csc work before unmute video. */
|
||||
if (need_delay)
|
||||
msleep(50);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2294,13 +2301,12 @@ static int dw_hdmi_connector_get_modes(struct drm_connector *connector)
|
||||
}
|
||||
|
||||
static void
|
||||
dw_hdmi_connector_atomic_flush(struct drm_connector *connector,
|
||||
dw_hdmi_connector_atomic_begin(struct drm_connector *connector,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi,
|
||||
connector);
|
||||
connector);
|
||||
void *data = hdmi->plat_data->phy_data;
|
||||
struct drm_display_mode *mode = NULL;
|
||||
unsigned int enc_in_bus_format;
|
||||
unsigned int enc_out_bus_format;
|
||||
unsigned int enc_in_encoding;
|
||||
@@ -2309,21 +2315,8 @@ dw_hdmi_connector_atomic_flush(struct drm_connector *connector,
|
||||
if (!hdmi->hpd_state || !conn_state->crtc)
|
||||
return;
|
||||
|
||||
DRM_DEBUG("%s\n", __func__);
|
||||
|
||||
/*
|
||||
* If HDMI is enabled in uboot, it's need to record
|
||||
* drm_display_mode and set phy status to enabled.
|
||||
*/
|
||||
if (!hdmi->hdmi_data.video_mode.mpixelclock) {
|
||||
mode = &conn_state->crtc->mode;
|
||||
memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode));
|
||||
hdmi->hdmi_data.video_mode.mpixelclock = mode->clock;
|
||||
hdmi->hdmi_data.video_mode.previous_pixelclock = mode->clock;
|
||||
hdmi->hdmi_data.video_mode.previous_tmdsclock = mode->clock;
|
||||
hdmi->phy.enabled = true;
|
||||
if (!hdmi->hdmi_data.video_mode.mpixelclock)
|
||||
return;
|
||||
}
|
||||
|
||||
if (hdmi->plat_data->get_enc_in_encoding)
|
||||
enc_in_encoding = hdmi->plat_data->get_enc_in_encoding(data);
|
||||
@@ -2347,8 +2340,48 @@ dw_hdmi_connector_atomic_flush(struct drm_connector *connector,
|
||||
if (enc_in_encoding != hdmi->hdmi_data.enc_in_encoding ||
|
||||
enc_out_encoding != hdmi->hdmi_data.enc_out_encoding ||
|
||||
enc_in_bus_format != hdmi->hdmi_data.enc_in_bus_format ||
|
||||
enc_out_bus_format != hdmi->hdmi_data.enc_out_bus_format)
|
||||
enc_out_bus_format != hdmi->hdmi_data.enc_out_bus_format) {
|
||||
hdmi->hdmi_data.update = true;
|
||||
hdmi_writeb(hdmi, HDMI_FC_GCP_SET_AVMUTE, HDMI_FC_GCP);
|
||||
/* XXX: Add delay to make av mute work on sink*/
|
||||
msleep(50);
|
||||
} else {
|
||||
hdmi->hdmi_data.update = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dw_hdmi_connector_atomic_flush(struct drm_connector *connector,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi,
|
||||
connector);
|
||||
struct drm_display_mode *mode = NULL;
|
||||
|
||||
if (!hdmi->hpd_state || !conn_state->crtc)
|
||||
return;
|
||||
|
||||
DRM_DEBUG("%s\n", __func__);
|
||||
|
||||
/*
|
||||
* If HDMI is enabled in uboot, it's need to record
|
||||
* drm_display_mode and set phy status to enabled.
|
||||
*/
|
||||
if (!hdmi->hdmi_data.video_mode.mpixelclock) {
|
||||
mode = &conn_state->crtc->mode;
|
||||
memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode));
|
||||
hdmi->hdmi_data.video_mode.mpixelclock = mode->clock;
|
||||
hdmi->hdmi_data.video_mode.previous_pixelclock = mode->clock;
|
||||
hdmi->hdmi_data.video_mode.previous_tmdsclock = mode->clock;
|
||||
hdmi->phy.enabled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (hdmi->hdmi_data.update) {
|
||||
dw_hdmi_setup(hdmi, &hdmi->previous_mode);
|
||||
hdmi_writeb(hdmi, HDMI_FC_GCP_CLEAR_AVMUTE, HDMI_FC_GCP);
|
||||
hdmi->hdmi_data.update = false;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -2423,6 +2456,7 @@ static const struct drm_connector_funcs dw_hdmi_connector_funcs = {
|
||||
static const struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = {
|
||||
.get_modes = dw_hdmi_connector_get_modes,
|
||||
.best_encoder = drm_atomic_helper_best_encoder,
|
||||
.atomic_begin = dw_hdmi_connector_atomic_begin,
|
||||
.atomic_flush = dw_hdmi_connector_atomic_flush,
|
||||
};
|
||||
|
||||
|
||||
@@ -853,6 +853,10 @@ enum {
|
||||
HDMI_FC_AVICONF3_QUANT_RANGE_LIMITED = 0x00,
|
||||
HDMI_FC_AVICONF3_QUANT_RANGE_FULL = 0x04,
|
||||
|
||||
/* HDMI_FC_GCP */
|
||||
HDMI_FC_GCP_SET_AVMUTE = 0x2,
|
||||
HDMI_FC_GCP_CLEAR_AVMUTE = 0x1,
|
||||
|
||||
/* FC_DBGFORCE field values */
|
||||
HDMI_FC_DBGFORCE_FORCEAUDIO = 0x10,
|
||||
HDMI_FC_DBGFORCE_FORCEVIDEO = 0x1,
|
||||
|
||||
Reference in New Issue
Block a user