drm/msm: change CSC matrix selection logic for CDM block

CDM block is always using a limited quantization range
matrix.

This can be overridden to use a full range matrix if
the sink supports override capability or the mode is a
non-CEA mode.

Adjust the matrix selection logic to accommodate full
range quantization as well.

Change-Id: I708412a923fb0d47e798f35ebe14b4c2f1a72fc9
Signed-off-by: Abhinav Kumar <abhinavk@codeaurora.org>
Signed-off-by: Ajay Singh Parmar <aparmar@codeaurora.org>
Signed-off-by: Chirag Khurana <ckhurana@codeaurora.org>
diff --git a/drivers/gpu/drm/msm/dp/dp_display.h b/drivers/gpu/drm/msm/dp/dp_display.h
index 266de5f..4da21d9 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.h
+++ b/drivers/gpu/drm/msm/dp/dp_display.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -50,4 +50,5 @@
 
 int dp_display_get_num_of_displays(void);
 int dp_display_get_displays(void **displays, int count);
+bool dp_connector_mode_needs_full_range(void *display);
 #endif /* _DP_DISPLAY_H_ */
diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c
index 7c817d3..5b78218 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.c
+++ b/drivers/gpu/drm/msm/dp/dp_drm.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -356,6 +356,34 @@
 	return 0;
 }
 
+bool dp_connector_mode_needs_full_range(void *data)
+{
+	struct dp_display *display = data;
+	struct dp_bridge *bridge;
+	struct dp_display_mode *mode;
+	struct dp_panel_info *timing;
+
+	if (!display) {
+		pr_err("invalid input\n");
+		return false;
+	}
+
+	bridge = display->bridge;
+	if (!bridge) {
+		pr_err("invalid bridge data\n");
+		return false;
+	}
+
+	mode = &bridge->dp_mode;
+	timing = &mode->timing;
+
+	if (timing->h_active == 640 &&
+	    timing->v_active == 480)
+		return true;
+
+	return false;
+}
+
 enum drm_connector_status dp_connector_detect(struct drm_connector *conn,
 		bool force,
 		void *display)
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c
index 96df60f..9fba20f 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.c
+++ b/drivers/gpu/drm/msm/sde/sde_connector.c
@@ -724,6 +724,28 @@
 	return rc;
 }
 
+bool sde_connector_mode_needs_full_range(struct drm_connector *connector)
+{
+	struct sde_connector *c_conn;
+
+	if (!connector) {
+		SDE_ERROR("invalid argument\n");
+		return false;
+	}
+
+	c_conn = to_sde_connector(connector);
+
+	if (!c_conn->display) {
+		SDE_ERROR("invalid argument\n");
+		return false;
+	}
+
+	if (!c_conn->ops.mode_needs_full_range)
+		return false;
+
+	return c_conn->ops.mode_needs_full_range(c_conn->display);
+}
+
 static void sde_connector_destroy(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 0ae6a91..87c2ee2 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.h
+++ b/drivers/gpu/drm/msm/sde/sde_connector.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -184,6 +184,14 @@
 			struct msm_display_kickoff_params *params);
 
 	/**
+	 * mode_needs_full_range - does the mode need full range
+	 * quantization
+	 * @display: Pointer to private display structure
+	 * Returns: true or false based on whether full range is needed
+	 */
+	bool (*mode_needs_full_range)(void *display);
+
+	/**
 	 * clk_ctrl - perform clk enable/disable on the connector
 	 * @handle: Pointer to clk handle
 	 * @type: Type of clks
@@ -703,6 +711,14 @@
 }
 
 /**
+ * sde_connector_mode_needs_full_range - query quantization type
+ * for the connector mode
+ * @connector: Pointer to drm connector object
+ * Returns: true OR false based on connector mode
+ */
+bool sde_connector_mode_needs_full_range(struct drm_connector *connector);
+
+/**
  * sde_connector_get_dither_cfg - get dither property data
  * @conn: Pointer to drm_connector struct
  * @state: Pointer to drm_connector_state struct
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c
index 21c883a..8594f54 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.c
@@ -5171,6 +5171,7 @@
 	struct sde_encoder_virt *sde_enc = NULL;
 	struct sde_hw_cdm *hw_cdm = phys_enc->hw_cdm;
 	struct sde_hw_cdm_cfg *cdm_cfg = &phys_enc->cdm_cfg;
+	struct drm_connector *connector = phys_enc->connector;
 	int ret;
 	u32 csc_type = 0;
 
@@ -5230,10 +5231,26 @@
 			cdm_cfg->h_cdwn_type,
 			cdm_cfg->v_cdwn_type);
 
-	if (output_type == CDM_CDWN_OUTPUT_HDMI)
-		csc_type = SDE_CSC_RGB2YUV_601FR;
-	else if (output_type == CDM_CDWN_OUTPUT_WB)
+	/**
+	 * Choose CSC matrix based on following rules:
+	 * 1. If connector supports quantization select,
+	 *	  pick Full-Range for better quality.
+	 * 2. If non-CEA mode, then pick Full-Range as per CEA spec
+	 * 3. Otherwise, pick Limited-Range as all other CEA modes
+	 *    need a limited range
+	 */
+
+	if (output_type == CDM_CDWN_OUTPUT_HDMI) {
+		if (connector && connector->yuv_qs)
+			csc_type = SDE_CSC_RGB2YUV_601FR;
+		else if (connector &&
+			sde_connector_mode_needs_full_range(connector))
+			csc_type = SDE_CSC_RGB2YUV_601FR;
+		else
+			csc_type = SDE_CSC_RGB2YUV_601L;
+	} else if (output_type == CDM_CDWN_OUTPUT_WB) {
 		csc_type = SDE_CSC_RGB2YUV_601L;
+	}
 
 	if (hw_cdm && hw_cdm->ops.setup_csc_data) {
 		ret = hw_cdm->ops.setup_csc_data(hw_cdm,
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c
index 88af0c0..68c3ca0 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.c
+++ b/drivers/gpu/drm/msm/sde/sde_kms.c
@@ -1318,6 +1318,7 @@
 		.cmd_transfer = NULL,
 		.cont_splash_config = NULL,
 		.get_panel_vfp = NULL,
+		.mode_needs_full_range = dp_connector_mode_needs_full_range,
 	};
 	static const struct sde_connector_ops ext_bridge_ops = {
 		.set_info_blob = dsi_conn_set_info_blob,