Browse Source

Merge "disp: msm: sde: add xin client clock status for wb2" into display-kernel.lnx.5.4

Linux Build Service Account 5 years ago
parent
commit
8fb0e26527

+ 22 - 1
msm/sde/sde_encoder_phys_wb.c

@@ -1200,6 +1200,25 @@ static int sde_encoder_phys_wb_frame_timeout(struct sde_encoder_phys *phys_enc)
 	return event;
 }
 
+static bool _sde_encoder_phys_wb_is_idle(
+		struct sde_encoder_phys *phys_enc)
+{
+	bool ret = false;
+	struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
+	struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
+	struct sde_vbif_get_xin_status_params xin_status = {0};
+
+	xin_status.vbif_idx = hw_wb->caps->vbif_idx;
+	xin_status.xin_id = hw_wb->caps->xin_id;
+	xin_status.clk_ctrl = hw_wb->caps->clk_ctrl;
+	if (sde_vbif_get_xin_status(phys_enc->sde_kms, &xin_status)) {
+		_sde_encoder_phys_wb_frame_done_helper(wb_enc, false);
+		ret = true;
+	}
+
+	return ret;
+}
+
 static int _sde_encoder_phys_wb_wait_for_commit_done(
 		struct sde_encoder_phys *phys_enc, bool is_disable)
 {
@@ -1235,7 +1254,9 @@ static int _sde_encoder_phys_wb_wait_for_commit_done(
 		KICKOFF_TIMEOUT_MS);
 	rc = sde_encoder_helper_wait_for_irq(phys_enc, INTR_IDX_WB_DONE,
 		&wait_info);
-	if (rc == -ETIMEDOUT) {
+	if (rc == -ETIMEDOUT && _sde_encoder_phys_wb_is_idle(phys_enc)) {
+		rc = 0;
+	} else if (rc == -ETIMEDOUT) {
 		SDE_EVT32(DRMID(phys_enc->parent), WBID(wb_enc),
 			wb_enc->frame_count, SDE_EVTLOG_ERROR);
 		SDE_ERROR("wb:%d kickoff timed out\n", WBID(wb_enc));

+ 16 - 1
msm/sde/sde_hw_catalog.c

@@ -441,6 +441,7 @@ enum {
 	WB_ID,
 	WB_XIN_ID,
 	WB_CLK_CTRL,
+	WB_CLK_STATUS,
 	WB_PROP_MAX,
 };
 
@@ -832,6 +833,8 @@ static struct sde_prop_type wb_prop[] = {
 	{WB_XIN_ID, "qcom,sde-wb-xin-id", false, PROP_TYPE_U32_ARRAY},
 	{WB_CLK_CTRL, "qcom,sde-wb-clk-ctrl", false,
 		PROP_TYPE_BIT_OFFSET_ARRAY},
+	{WB_CLK_STATUS, "qcom,sde-wb-clk-status", false,
+		PROP_TYPE_BIT_OFFSET_ARRAY},
 };
 
 static struct sde_prop_type vbif_prop[] = {
@@ -881,7 +884,7 @@ static struct sde_prop_type reg_dma_prop[REG_DMA_PROP_MAX] = {
 		"qcom,sde-reg-dma-broadcast-disabled", false, PROP_TYPE_BOOL},
 	[REG_DMA_XIN_ID] = {REG_DMA_XIN_ID,
 		"qcom,sde-reg-dma-xin-id", false, PROP_TYPE_U32},
-	[REG_DMA_CLK_CTRL] = {REG_DMA_XIN_ID,
+	[REG_DMA_CLK_CTRL] = {REG_DMA_CLK_CTRL,
 		"qcom,sde-reg-dma-clk-ctrl", false, PROP_TYPE_BIT_OFFSET_ARRAY},
 };
 
@@ -1842,6 +1845,12 @@ static int _sde_sspp_setup_cmn(struct device_node *np,
 			sde_cfg->mdp[j].clk_ctrls[sspp->clk_ctrl].bit_off =
 					PROP_BITVALUE_ACCESS(props->values,
 					SSPP_CLK_CTRL, i, 1);
+			sde_cfg->mdp[j].clk_status[sspp->clk_ctrl].reg_off =
+					PROP_BITVALUE_ACCESS(props->values,
+					SSPP_CLK_STATUS, i, 0);
+			sde_cfg->mdp[j].clk_status[sspp->clk_ctrl].bit_off =
+					PROP_BITVALUE_ACCESS(props->values,
+					SSPP_CLK_STATUS, i, 1);
 		}
 
 		SDE_DEBUG("xin:%d ram:%d clk%d:%x/%d\n",
@@ -2354,6 +2363,12 @@ static int sde_wb_parse_dt(struct device_node *np, struct sde_mdss_cfg *sde_cfg)
 			sde_cfg->mdp[j].clk_ctrls[wb->clk_ctrl].bit_off =
 				PROP_BITVALUE_ACCESS(prop_value,
 						WB_CLK_CTRL, i, 1);
+			sde_cfg->mdp[j].clk_status[wb->clk_ctrl].reg_off =
+				PROP_BITVALUE_ACCESS(prop_value,
+						WB_CLK_STATUS, i, 0);
+			sde_cfg->mdp[j].clk_status[wb->clk_ctrl].bit_off =
+				PROP_BITVALUE_ACCESS(prop_value,
+						WB_CLK_STATUS, i, 1);
 		}
 
 		wb->format_list = sde_cfg->wb_formats;

+ 2 - 0
msm/sde/sde_hw_catalog.h

@@ -868,6 +868,7 @@ struct sde_clk_ctrl_reg {
  * @has_dest_scaler:   indicates support of destination scaler
  * @smart_panel_align_mode: split display smart panel align modes
  * @clk_ctrls          clock control register definition
+ * @clk_status         clock status register definition
  */
 struct sde_mdp_cfg {
 	SDE_HW_BLK_INFO;
@@ -877,6 +878,7 @@ struct sde_mdp_cfg {
 	bool has_dest_scaler;
 	u32 smart_panel_align_mode;
 	struct sde_clk_ctrl_reg clk_ctrls[SDE_CLK_CTRL_MAX];
+	struct sde_clk_ctrl_reg clk_status[SDE_CLK_CTRL_MAX];
 };
 
 /* struct sde_uidle_cfg : MDP TOP-BLK instance info

+ 22 - 0
msm/sde/sde_hw_top.c

@@ -219,6 +219,27 @@ static bool sde_hw_setup_clk_force_ctrl(struct sde_hw_mdp *mdp,
 	return clk_forced_on;
 }
 
+static int sde_hw_get_clk_ctrl_status(struct sde_hw_mdp *mdp,
+		enum sde_clk_ctrl_type clk_ctrl, bool *status)
+{
+	struct sde_hw_blk_reg_map *c;
+	u32 reg_off, bit_off;
+
+	if (!mdp)
+		return -EINVAL;
+
+	c = &mdp->hw;
+
+	if (clk_ctrl <= SDE_CLK_CTRL_NONE || clk_ctrl >= SDE_CLK_CTRL_MAX ||
+			!mdp->caps->clk_status[clk_ctrl].reg_off)
+		return -EINVAL;
+
+	reg_off = mdp->caps->clk_status[clk_ctrl].reg_off;
+	bit_off = mdp->caps->clk_status[clk_ctrl].bit_off;
+
+	*status = SDE_REG_READ(c, reg_off) & BIT(bit_off);
+	return 0;
+}
 
 static void sde_hw_get_danger_status(struct sde_hw_mdp *mdp,
 		struct sde_danger_safe_status *status)
@@ -600,6 +621,7 @@ static void _setup_mdp_ops(struct sde_hw_mdp_ops *ops,
 	ops->setup_pp_split = sde_hw_setup_pp_split;
 	ops->setup_cdm_output = sde_hw_setup_cdm_output;
 	ops->setup_clk_force_ctrl = sde_hw_setup_clk_force_ctrl;
+	ops->get_clk_ctrl_status = sde_hw_get_clk_ctrl_status;
 	ops->get_danger_status = sde_hw_get_danger_status;
 	ops->setup_vsync_source = sde_hw_setup_vsync_source;
 	ops->set_cwb_ppb_cntl = sde_hw_program_cwb_ppb_ctrl;

+ 10 - 0
msm/sde/sde_hw_top.h

@@ -140,6 +140,16 @@ struct sde_hw_mdp_ops {
 	bool (*setup_clk_force_ctrl)(struct sde_hw_mdp *mdp,
 			enum sde_clk_ctrl_type clk_ctrl, bool enable);
 
+	/**
+	 * get_clk_ctrl_status - get clock control status
+	 * @mdp: mdp top context driver
+	 * @clk_ctrl: clock to be controlled
+	 * @status: returns true if clock is on
+	 * @return: 0 if success, otherwise return code
+	 */
+	int (*get_clk_ctrl_status)(struct sde_hw_mdp *mdp,
+			enum sde_clk_ctrl_type clk_ctrl, bool *status);
+
 	/**
 	 * setup_dce - set DCE mux for DSC ctrl path
 	 * @mdp: mdp top context driver

+ 52 - 0
msm/sde/sde_vbif.c

@@ -406,6 +406,58 @@ bool sde_vbif_set_xin_halt(struct sde_kms *sde_kms,
 	return forced_on;
 }
 
+bool sde_vbif_get_xin_status(struct sde_kms *sde_kms,
+		struct sde_vbif_get_xin_status_params *params)
+{
+	struct sde_hw_vbif *vbif = NULL;
+	struct sde_hw_mdp *mdp;
+	int i, rc;
+	bool status;
+
+	if (!sde_kms || !params) {
+		SDE_ERROR("invalid arguments\n");
+		return false;
+	}
+
+	if (!sde_kms_is_vbif_operation_allowed(sde_kms)) {
+		SDE_DEBUG("vbif operations not permitted\n");
+		return true;
+	}
+
+	mdp = sde_kms->hw_mdp;
+
+	for (i = 0; i < ARRAY_SIZE(sde_kms->hw_vbif); i++) {
+		if (sde_kms->hw_vbif[i] &&
+				sde_kms->hw_vbif[i]->idx == params->vbif_idx) {
+			vbif = sde_kms->hw_vbif[i];
+			break;
+		}
+	}
+
+	if (!vbif || !mdp) {
+		SDE_DEBUG("invalid arguments vbif:%d mdp:%d vbif idx:%d\n",
+				vbif != NULL, mdp != NULL, params->vbif_idx);
+		return false;
+	}
+
+	if (!mdp->ops.get_clk_ctrl_status ||
+			!vbif->ops.get_xin_halt_status)
+		return false;
+
+	mutex_lock(&vbif->mutex);
+	SDE_EVT32_VERBOSE(vbif->idx, params->xin_id);
+	status = vbif->ops.get_xin_halt_status(vbif, params->xin_id);
+	if (status) {
+		rc = !mdp->ops.get_clk_ctrl_status(mdp, params->clk_ctrl,
+				&status);
+		if (rc)
+			status = false;
+	}
+	mutex_unlock(&vbif->mutex);
+
+	return status;
+}
+
 void sde_vbif_set_qos_remap(struct sde_kms *sde_kms,
 		struct sde_vbif_set_qos_params *params)
 {

+ 22 - 0
msm/sde/sde_vbif.h

@@ -44,6 +44,18 @@ struct sde_vbif_set_xin_halt_params {
 	bool enable;
 };
 
+/**
+ * struct sde_vbif_get_xin_status_params - xin halt parameters
+ * @vbif_idx: vbif identifier
+ * @xin_id: client interface identifier
+ * @clk_ctrl: clock control identifier of the xin
+ */
+struct sde_vbif_get_xin_status_params {
+	u32 vbif_idx;
+	u32 xin_id;
+	u32 clk_ctrl;
+};
+
 /**
  * struct sde_vbif_set_qos_params - QoS remapper parameter
  * @vbif_idx: vbif identifier
@@ -78,6 +90,16 @@ void sde_vbif_set_ot_limit(struct sde_kms *sde_kms,
 bool sde_vbif_set_xin_halt(struct sde_kms *sde_kms,
 		struct sde_vbif_set_xin_halt_params *params);
 
+/**
+ * sde_vbif_get_xin_status - halt one of the xin ports
+ *	This function isn't thread safe.
+ * @sde_kms:	SDE handler
+ * @params:	Pointer to xin status parameters
+ * Returns:	true if xin client is idle, false otherwise
+ */
+bool sde_vbif_get_xin_status(struct sde_kms *sde_kms,
+		struct sde_vbif_get_xin_status_params *params);
+
 /**
  * sde_vbif_set_qos_remap - set QoS priority level remap
  * @sde_kms:	SDE handler