Просмотр исходного кода

disp: msm: sde: add xin client clock status for wb2

CWB may trigger frame missed message if interrupts
are disabled on specific CPU. WB2 will only find single
interrupt status for two posted start triggered frame.
SDE driver will start checking the xin client clock
status for wb2 timeout case to trigger the valid
frame done status.

Change-Id: I16a99667116732002e6dec8a18330f8b45199387
Signed-off-by: Dhaval Patel <[email protected]>
Dhaval Patel 5 лет назад
Родитель
Сommit
31d4bb10a6

+ 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