Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c9a56fba authored by Ajay Singh Parmar's avatar Ajay Singh Parmar
Browse files

msm: mdss: hdmi: proper ddc interrupt handling



Enable both software and hardware interrupts for DDC to
properly check for DDC engine being idle before any new
DDC transaction.

Change-Id: Iaab95483954e76397620a9f708982de060318d8a
Signed-off-by: default avatarAjay Singh Parmar <aparmar@codeaurora.org>
parent 988f227e
Loading
Loading
Loading
Loading
+29 −22
Original line number Diff line number Diff line
@@ -167,8 +167,9 @@ static void hdmi_hdcp_hw_ddc_clean(struct hdmi_hdcp_ctrl *hdcp_ctrl)
{
	struct dss_io_data *io = NULL;
	u32 hdcp_ddc_status, ddc_hw_status;
	u32 ddc_xfer_done, ddc_xfer_req, ddc_hw_done;
	u32 ddc_hw_not_ready;
	u32 ddc_xfer_done, ddc_xfer_req;
	u32 ddc_hw_req, ddc_hw_not_idle;
	bool ddc_hw_not_ready, xfer_not_done, hw_not_done;
	u32 timeout_count;

	if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) {
@@ -182,17 +183,24 @@ static void hdmi_hdcp_hw_ddc_clean(struct hdmi_hdcp_ctrl *hdcp_ctrl)
			return;
	}

	if (DSS_REG_R(io, HDMI_DDC_HW_STATUS) != 0) {
	/* Wait to be clean on DDC HW engine */
	timeout_count = 100;
	do {
		hdcp_ddc_status = DSS_REG_R(io, HDMI_HDCP_DDC_STATUS);
			ddc_hw_status = DSS_REG_R(io, HDMI_DDC_HW_STATUS);
			ddc_xfer_done = hdcp_ddc_status & BIT(10);
		ddc_xfer_req    = hdcp_ddc_status & BIT(4);
			ddc_hw_done = ddc_hw_status & BIT(3);
			ddc_hw_not_ready = !ddc_xfer_done ||
				ddc_xfer_req || !ddc_hw_done;
		ddc_xfer_done   = hdcp_ddc_status & BIT(10);

		ddc_hw_status   = DSS_REG_R(io, HDMI_DDC_HW_STATUS);
		ddc_hw_req      = ddc_hw_status & BIT(16);
		ddc_hw_not_idle = ddc_hw_status & (BIT(0) | BIT(1));

		/* ddc transfer was requested but not completed */
		xfer_not_done = ddc_xfer_req && !ddc_xfer_done;

		/* ddc status is not idle or a hw request pending */
		hw_not_done = ddc_hw_not_idle || ddc_hw_req;

		ddc_hw_not_ready = xfer_not_done || hw_not_done;

		DEV_DBG("%s: %s: timeout count(%d): ddc hw%sready\n",
			__func__, HDCP_STATE_NAME, timeout_count,
@@ -202,7 +210,6 @@ static void hdmi_hdcp_hw_ddc_clean(struct hdmi_hdcp_ctrl *hdcp_ctrl)
		if (ddc_hw_not_ready)
			msleep(20);
		} while (ddc_hw_not_ready && --timeout_count);
	}
} /* hdmi_hdcp_hw_ddc_clean */

static int hdcp_scm_call(struct scm_hdcp_req *req, u32 *resp)
+32 −12
Original line number Diff line number Diff line
@@ -502,24 +502,38 @@ static void hdmi_ddc_print_data(struct hdmi_tx_ddc_data *ddc_data)
static int hdmi_ddc_clear_irq(struct hdmi_tx_ddc_ctrl *ddc_ctrl,
	char *what)
{
	u32 reg_val, time_out_count;
	u32 ddc_int_ctrl, ddc_status, in_use, timeout;
	u32 sw_done_mask = BIT(2);
	u32 sw_done_ack  = BIT(1);
	u32 hw_done_mask = BIT(6);
	u32 hw_done_ack  = BIT(5);
	u32 in_use_by_sw = BIT(0);
	u32 in_use_by_hw = BIT(1);

	if (!ddc_ctrl || !ddc_ctrl->io) {
		pr_err("invalid input\n");
		return -EINVAL;
	}

	/* clear pending and enable interrupt */
	time_out_count = 0xFFFF;
	/* wait until DDC HW is free */
	timeout = 100;
	do {
		--time_out_count;
		/* Clear and Enable DDC interrupt */
		DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_INT_CTRL,
			BIT(2) | BIT(1));
		reg_val = DSS_REG_R_ND(ddc_ctrl->io, HDMI_DDC_INT_CTRL);
	} while ((reg_val & BIT(0)) && time_out_count);
		--timeout;
		ddc_status = DSS_REG_R_ND(ddc_ctrl->io, HDMI_DDC_HW_STATUS);
		in_use = ddc_status & (in_use_by_sw | in_use_by_hw);
		if (in_use) {
			pr_debug("ddc is in use by %s\n",
				ddc_status & in_use_by_sw ? "sw" : "hw");
			msleep(20);
		}
	} while (in_use && timeout);

	if (!time_out_count) {
	/* clear and enable interrutps */
	ddc_int_ctrl = sw_done_mask | sw_done_ack | hw_done_mask | hw_done_ack;

	DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_INT_CTRL, ddc_int_ctrl);

	if (!timeout) {
		pr_err("%s: timedout\n", what);
		return -ETIMEDOUT;
	}
@@ -877,12 +891,18 @@ int hdmi_ddc_isr(struct hdmi_tx_ddc_ctrl *ddc_ctrl, u32 version)

	ddc_int_ctrl = DSS_REG_R_ND(ddc_ctrl->io, HDMI_DDC_INT_CTRL);
	if ((ddc_int_ctrl & BIT(2)) && (ddc_int_ctrl & BIT(0))) {
		/* SW_DONE INT occured, clr it */
		/* SW_DONE INT occurred, clr it */
		DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_INT_CTRL,
			ddc_int_ctrl | BIT(1));
		complete(&ddc_ctrl->ddc_sw_done);
	}

	if ((ddc_int_ctrl & BIT(6)) && (ddc_int_ctrl & BIT(4))) {
		/* HW_DONE INT occurred, clr it */
		DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_INT_CTRL,
			ddc_int_ctrl | BIT(5));
	}

	pr_debug("ddc_int_ctrl=%04x\n", ddc_int_ctrl);
	if (version < HDMI_TX_SCRAMBLER_MIN_TX_VERSION)
		goto end;
@@ -1699,7 +1719,7 @@ int hdmi_hdcp2p2_ddc_read_rxstatus(struct hdmi_tx_ddc_ctrl *ctrl)
		rc = -EIO;
	}

	DSS_REG_W(ctrl->io, HDMI_HW_DDC_CTRL, reg_val);
	DSS_REG_W(ctrl->io, HDMI_HDCP2P2_DDC_STATUS, reg_val);

	/* Disable hardware access to RxStatus register */
	hdmi_hdcp2p2_ddc_disable(ctrl);