Merge "drm/msm: update CSC matrix during HDR playback"

This commit is contained in:
Linux Build Service Account 2017-08-11 16:23:51 -07:00 committed by Gerrit - the friendly Code Review server
commit 6949010ef3
8 changed files with 180 additions and 5 deletions

View file

@ -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;

View file

@ -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_ */

View file

@ -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;

View file

@ -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_ */

View file

@ -80,6 +80,42 @@ static struct sde_csc_cfg sde_csc_10bit_convert[SDE_MAX_CSC] = {
{ 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
{ 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
},
[SDE_CSC_RGB2YUV_709L] = {
{
TO_S15D16(0x005d), TO_S15D16(0x013a), TO_S15D16(0x0020),
TO_S15D16(0xffcc), TO_S15D16(0xff53), TO_S15D16(0x00e1),
TO_S15D16(0x00e1), TO_S15D16(0xff34), TO_S15D16(0xffeb),
},
{ 0x0, 0x0, 0x0,},
{ 0x0040, 0x0200, 0x0200,},
{ 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
{ 0x0040, 0x03ac, 0x0040, 0x03c0, 0x0040, 0x03c0,},
},
[SDE_CSC_RGB2YUV_2020L] = {
{
TO_S15D16(0x0073), TO_S15D16(0x0129), TO_S15D16(0x001a),
TO_S15D16(0xffc1), TO_S15D16(0xff5e), TO_S15D16(0x00e0),
TO_S15D16(0x00e0), TO_S15D16(0xff32), TO_S15D16(0xffee),
},
{ 0x0, 0x0, 0x0,},
{ 0x0040, 0x0200, 0x0200,},
{ 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
{ 0x0040, 0x03ac, 0x0040, 0x03c0, 0x0040, 0x03c0,},
},
[SDE_CSC_RGB2YUV_2020FR] = {
{
TO_S15D16(0x0086), TO_S15D16(0x015b), TO_S15D16(0x001e),
TO_S15D16(0xffb9), TO_S15D16(0xff47), TO_S15D16(0x0100),
TO_S15D16(0x0100), TO_S15D16(0xff15), TO_S15D16(0xffeb),
},
{ 0x0, 0x0, 0x0,},
{ 0x0, 0x0200, 0x0200,},
{ 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
{ 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
},
};
/**
@ -826,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) {
@ -846,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;
}
}
}
}
}
@ -1507,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) {

View file

@ -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;

View file

@ -344,6 +344,9 @@ enum sde_3d_blend_mode {
enum sde_csc_type {
SDE_CSC_RGB2YUV_601L,
SDE_CSC_RGB2YUV_601FR,
SDE_CSC_RGB2YUV_709L,
SDE_CSC_RGB2YUV_2020L,
SDE_CSC_RGB2YUV_2020FR,
SDE_MAX_CSC
};

View file

@ -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;