drm/msm: update CSC matrix during HDR playback
The CSC matrix used in the CDM block should be updated to BT2020 format from the default value during HDR video playback. Add support in the SDE driver to enable switching CSC matrix of CDM block to BT2020 during start of HDR playback and restore it at the stop of the playback to the default CSC. Change-Id: Ic589380188ddef8ada2c8bbc0ca945bb1f319c85 Signed-off-by: Abhinav Kumar <abhinavk@codeaurora.org>
This commit is contained in:
parent
5e05fc53d8
commit
5920f5fe3c
7 changed files with 141 additions and 5 deletions
|
@ -2394,6 +2394,40 @@ bool sde_hdmi_mode_needs_full_range(void *display)
|
|||
return true;
|
||||
}
|
||||
|
||||
enum sde_csc_type sde_hdmi_get_csc_type(struct drm_connector *conn,
|
||||
void *display)
|
||||
{
|
||||
struct sde_hdmi *hdmi_display = (struct sde_hdmi *)display;
|
||||
struct sde_connector_state *c_state;
|
||||
struct drm_msm_ext_panel_hdr_ctrl *hdr_ctrl;
|
||||
struct drm_msm_ext_panel_hdr_metadata *hdr_meta;
|
||||
|
||||
if (!hdmi_display || !conn) {
|
||||
SDE_ERROR("invalid input\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
c_state = to_sde_connector_state(conn->state);
|
||||
|
||||
if (!c_state) {
|
||||
SDE_ERROR("invalid input\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
hdr_ctrl = &c_state->hdr_ctrl;
|
||||
hdr_meta = &hdr_ctrl->hdr_meta;
|
||||
|
||||
if ((hdr_ctrl->hdr_state == HDR_ENABLE)
|
||||
&& (hdr_meta->eotf != 0))
|
||||
return SDE_CSC_RGB2YUV_2020L;
|
||||
else if (sde_hdmi_mode_needs_full_range(hdmi_display)
|
||||
|| conn->yuv_qs)
|
||||
return SDE_CSC_RGB2YUV_601FR;
|
||||
|
||||
error:
|
||||
return SDE_CSC_RGB2YUV_601L;
|
||||
}
|
||||
|
||||
int sde_hdmi_connector_get_modes(struct drm_connector *connector, void *display)
|
||||
{
|
||||
struct sde_hdmi *hdmi_display = (struct sde_hdmi *)display;
|
||||
|
|
|
@ -490,6 +490,15 @@ int sde_hdmi_pre_kickoff(struct drm_connector *connector,
|
|||
*/
|
||||
bool sde_hdmi_mode_needs_full_range(void *display);
|
||||
|
||||
/*
|
||||
* sde_hdmi_get_csc_type - returns the CSC type to be
|
||||
* used based on state of HDR playback
|
||||
* @conn: Pointer to DRM connector
|
||||
* @display: Pointer to private display structure
|
||||
* Returns: true or false based on mode
|
||||
*/
|
||||
enum sde_csc_type sde_hdmi_get_csc_type(struct drm_connector *conn,
|
||||
void *display);
|
||||
#else /*#ifdef CONFIG_DRM_SDE_HDMI*/
|
||||
|
||||
static inline u32 sde_hdmi_get_num_of_displays(void)
|
||||
|
@ -609,5 +618,11 @@ static inline bool sde_hdmi_mode_needs_full_range(void *display)
|
|||
return false;
|
||||
}
|
||||
|
||||
enum sde_csc_type sde_hdmi_get_csc_type(struct drm_connector *conn,
|
||||
void *display)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /*#else of CONFIG_DRM_SDE_HDMI*/
|
||||
#endif /* _SDE_HDMI_H_ */
|
||||
|
|
|
@ -90,6 +90,28 @@ int sde_connector_pre_kickoff(struct drm_connector *connector)
|
|||
return rc;
|
||||
}
|
||||
|
||||
enum sde_csc_type sde_connector_get_csc_type(struct drm_connector *conn)
|
||||
{
|
||||
struct sde_connector *c_conn;
|
||||
|
||||
if (!conn) {
|
||||
SDE_ERROR("invalid argument\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
c_conn = to_sde_connector(conn);
|
||||
|
||||
if (!c_conn->display) {
|
||||
SDE_ERROR("invalid argument\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!c_conn->ops.get_csc_type)
|
||||
return SDE_CSC_RGB2YUV_601L;
|
||||
|
||||
return c_conn->ops.get_csc_type(conn, c_conn->display);
|
||||
}
|
||||
|
||||
bool sde_connector_mode_needs_full_range(struct drm_connector *connector)
|
||||
{
|
||||
struct sde_connector *c_conn;
|
||||
|
|
|
@ -143,6 +143,16 @@ struct sde_connector_ops {
|
|||
* Returns: true or false based on whether full range is needed
|
||||
*/
|
||||
bool (*mode_needs_full_range)(void *display);
|
||||
|
||||
/**
|
||||
* get_csc_type - returns the CSC type to be used
|
||||
* by the CDM block based on HDR state
|
||||
* @connector: Pointer to drm connector structure
|
||||
* @display: Pointer to private display structure
|
||||
* Returns: type of CSC matrix to be used
|
||||
*/
|
||||
enum sde_csc_type (*get_csc_type)(struct drm_connector *connector,
|
||||
void *display);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -342,5 +352,14 @@ int sde_connector_pre_kickoff(struct drm_connector *connector);
|
|||
* Returns: true OR false based on connector mode
|
||||
*/
|
||||
bool sde_connector_mode_needs_full_range(struct drm_connector *connector);
|
||||
|
||||
/**
|
||||
* sde_connector_get_csc_type - query csc type
|
||||
* to be used for the connector
|
||||
* @connector: Pointer to drm connector object
|
||||
* Returns: csc type based on connector HDR state
|
||||
*/
|
||||
enum sde_csc_type sde_connector_get_csc_type(struct drm_connector *conn);
|
||||
|
||||
#endif /* _SDE_CONNECTOR_H_ */
|
||||
|
||||
|
|
|
@ -862,7 +862,12 @@ void sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc)
|
|||
{
|
||||
struct sde_encoder_virt *sde_enc;
|
||||
struct sde_encoder_phys *phys;
|
||||
struct drm_connector *conn_mas = NULL;
|
||||
unsigned int i;
|
||||
enum sde_csc_type conn_csc;
|
||||
struct drm_display_mode *mode;
|
||||
struct sde_hw_cdm *hw_cdm;
|
||||
int mode_is_yuv = 0;
|
||||
int rc;
|
||||
|
||||
if (!drm_enc) {
|
||||
|
@ -882,11 +887,46 @@ void sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc)
|
|||
}
|
||||
|
||||
if (sde_enc->cur_master && sde_enc->cur_master->connector) {
|
||||
rc = sde_connector_pre_kickoff(sde_enc->cur_master->connector);
|
||||
conn_mas = sde_enc->cur_master->connector;
|
||||
rc = sde_connector_pre_kickoff(conn_mas);
|
||||
if (rc)
|
||||
SDE_ERROR_ENC(sde_enc, "kickoff conn%d failed rc %d\n",
|
||||
sde_enc->cur_master->connector->base.id,
|
||||
rc);
|
||||
SDE_ERROR_ENC(sde_enc,
|
||||
"kickoff conn%d failed rc %d\n",
|
||||
conn_mas->base.id,
|
||||
rc);
|
||||
|
||||
for (i = 0; i < sde_enc->num_phys_encs; i++) {
|
||||
phys = sde_enc->phys_encs[i];
|
||||
if (phys) {
|
||||
mode = &phys->cached_mode;
|
||||
mode_is_yuv = (mode->private_flags &
|
||||
MSM_MODE_FLAG_COLOR_FORMAT_YCBCR420);
|
||||
}
|
||||
/**
|
||||
* Check the CSC matrix type to which the
|
||||
* CDM CSC matrix should be updated to based
|
||||
* on the connector HDR state
|
||||
*/
|
||||
conn_csc = sde_connector_get_csc_type(conn_mas);
|
||||
if (phys && mode_is_yuv) {
|
||||
if (phys->enc_cdm_csc != conn_csc) {
|
||||
hw_cdm = phys->hw_cdm;
|
||||
rc = hw_cdm->ops.setup_csc_data(hw_cdm,
|
||||
&sde_csc_10bit_convert[conn_csc]);
|
||||
|
||||
if (rc)
|
||||
SDE_ERROR_ENC(sde_enc,
|
||||
"CSC setup failed rc %d\n",
|
||||
rc);
|
||||
SDE_DEBUG_ENC(sde_enc,
|
||||
"updating CSC %d to %d\n",
|
||||
phys->enc_cdm_csc,
|
||||
conn_csc);
|
||||
phys->enc_cdm_csc = conn_csc;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1543,6 +1583,9 @@ void sde_encoder_phys_setup_cdm(struct sde_encoder_phys *phys_enc,
|
|||
}
|
||||
}
|
||||
|
||||
/* Cache the CSC default matrix type */
|
||||
phys_enc->enc_cdm_csc = csc_type;
|
||||
|
||||
if (hw_cdm && hw_cdm->ops.setup_cdwn) {
|
||||
ret = hw_cdm->ops.setup_cdwn(hw_cdm, cdm_cfg);
|
||||
if (ret < 0) {
|
||||
|
|
|
@ -174,6 +174,7 @@ enum sde_intr_idx {
|
|||
* @split_role: Role to play in a split-panel configuration
|
||||
* @intf_mode: Interface mode
|
||||
* @intf_idx: Interface index on sde hardware
|
||||
* @enc_cdm_csc: Cached CSC type of CDM block
|
||||
* @enc_spinlock: Virtual-Encoder-Wide Spin Lock for IRQ purposes
|
||||
* @enable_state: Enable state tracking
|
||||
* @vblank_refcount: Reference count of vblank request
|
||||
|
@ -201,6 +202,7 @@ struct sde_encoder_phys {
|
|||
enum sde_enc_split_role split_role;
|
||||
enum sde_intf_mode intf_mode;
|
||||
enum sde_intf intf_idx;
|
||||
enum sde_csc_type enc_cdm_csc;
|
||||
spinlock_t *enc_spinlock;
|
||||
enum sde_enc_enable_state enable_state;
|
||||
atomic_t vblank_refcount;
|
||||
|
|
|
@ -594,7 +594,8 @@ static int _sde_kms_setup_displays(struct drm_device *dev,
|
|||
.set_property = sde_hdmi_set_property,
|
||||
.get_property = sde_hdmi_get_property,
|
||||
.pre_kickoff = sde_hdmi_pre_kickoff,
|
||||
.mode_needs_full_range = sde_hdmi_mode_needs_full_range
|
||||
.mode_needs_full_range = sde_hdmi_mode_needs_full_range,
|
||||
.get_csc_type = sde_hdmi_get_csc_type
|
||||
};
|
||||
struct msm_display_info info = {0};
|
||||
struct drm_encoder *encoder;
|
||||
|
|
Loading…
Add table
Reference in a new issue