summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAbhinav Kumar <abhinavk@codeaurora.org>2017-07-27 18:31:41 -0700
committerGerrit - the friendly Code Review server <code-review@localhost>2017-08-10 17:40:43 -0700
commit5920f5fe3c882ff942416df34589434251ab8dc6 (patch)
tree7b33d5b0b708753b65ac2acc87239d29f47e25d3
parent5e05fc53d8e968ab298d6290f8083f89a0af8d6b (diff)
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>
-rw-r--r--drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c34
-rw-r--r--drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h15
-rw-r--r--drivers/gpu/drm/msm/sde/sde_connector.c22
-rw-r--r--drivers/gpu/drm/msm/sde/sde_connector.h19
-rw-r--r--drivers/gpu/drm/msm/sde/sde_encoder.c51
-rw-r--r--drivers/gpu/drm/msm/sde/sde_encoder_phys.h2
-rw-r--r--drivers/gpu/drm/msm/sde/sde_kms.c3
7 files changed, 141 insertions, 5 deletions
diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c
index 0949b55a6d87..ab8e7a0ed6a5 100644
--- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c
+++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c
@@ -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;
diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h
index 441bb3a6dfe8..e80fc66a6244 100644
--- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h
+++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h
@@ -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_ */
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c
index d79361bbe265..5fa4c21060f9 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.c
+++ b/drivers/gpu/drm/msm/sde/sde_connector.c
@@ -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;
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.h b/drivers/gpu/drm/msm/sde/sde_connector.h
index 73a20133a944..b76ce0aaf577 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.h
+++ b/drivers/gpu/drm/msm/sde/sde_connector.h
@@ -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_ */
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c
index 44b680d8ddc5..23fb79241d84 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.c
@@ -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) {
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
index 20f125155de3..aec844d640bd 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
@@ -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;
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c
index eaa1eca8fc8e..cdf67c0aa864 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.c
+++ b/drivers/gpu/drm/msm/sde/sde_kms.c
@@ -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;