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

Commit 5f9446af authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: mdss: hdmi: enable hdmi before ddc transaction"

parents a2afa385 5d52b6fd
Loading
Loading
Loading
Loading
+22 −12
Original line number Diff line number Diff line
@@ -365,6 +365,9 @@ struct hdcp_lib_message_map {
	const char *msg_name;
};

static struct qseecom_handle *hdcp1_handle;
static bool hdcp1_supported = true;

static const char *hdcp_lib_message_name(int msg_id)
{
	/*
@@ -1151,16 +1154,12 @@ static void hdcp_lib_topology_work(struct kthread_work *work)
	u32 timeout;
	struct hdcp_lib_handle *handle = container_of(work,
		struct hdcp_lib_handle, topology);
	struct hdmi_hdcp_wakeup_data cdata = {HDMI_HDCP_WKUP_CMD_INVALID};

	if (!handle) {
		pr_err("invalid input\n");
		return;
	}

	cdata.context = handle->client_ctx;
	cdata.cmd = HDMI_HDCP_WKUP_CMD_RECV_MESSAGE;
	hdcp_lib_wakeup_client(handle, &cdata);

	reinit_completion(&handle->topo_wait);
	timeout = wait_for_completion_timeout(&handle->topo_wait, HZ * 3);
@@ -1172,24 +1171,35 @@ static void hdcp_lib_topology_work(struct kthread_work *work)
	}
}

bool hdcp1_check_if_supported_load_app(void)
{
	int rc = 0;

	/* start hdcp1 app */
	if (hdcp1_supported && !hdcp1_handle) {
		rc = qseecom_start_app(&hdcp1_handle, HDCP1_APP_NAME,
			QSEECOM_SBUFF_SIZE);
		if (rc) {
			pr_err("qseecom_start_app failed %d\n", rc);
			hdcp1_supported = false;
		}
	}

	return hdcp1_supported;
}

/* APIs exposed to all clients */
int hdcp1_set_keys(uint32_t *aksv_msb, uint32_t *aksv_lsb)
{
	int rc = 0;
	struct hdcp1_key_set_req *key_set_req;
	struct hdcp1_key_set_rsp *key_set_rsp;
	struct qseecom_handle *hdcp1_handle = NULL;

	if (aksv_msb == NULL || aksv_lsb == NULL)
		return -EINVAL;

	/* start hdcp1 app */
	rc = qseecom_start_app(&hdcp1_handle, HDCP1_APP_NAME,
						QSEECOM_SBUFF_SIZE);
	if (rc) {
		pr_err("qseecom_start_app failed %d\n", rc);
		return -ENOSYS;
	}
	if (!hdcp1_supported || !hdcp1_handle)
		return -EINVAL;

	/* set keys and request aksv */
	key_set_req = (struct hdcp1_key_set_req *)hdcp1_handle->sbuf;
+34 −9
Original line number Diff line number Diff line
@@ -56,7 +56,6 @@ struct hdmi_hdcp2p2_ctrl {
	struct hdmi_hdcp_ops *ops;
	void *lib_ctx; /* Handle to HDCP 2.2 Trustzone library */
	struct hdcp_txmtr_ops *lib; /* Ops for driver to call into TZ */
	struct completion rxstatus_completion; /* Rx status interrupt */

	enum hdmi_hdcp_wakeup_cmd wakeup_cmd;
	char *send_msg_buf;
@@ -356,7 +355,7 @@ static int hdmi_hdcp2p2_ddc_write_message(struct hdmi_hdcp2p2_ctrl *ctrl,

	rc = hdmi_ddc_write(ctrl->init_data.ddc_ctrl);
	if (rc)
		pr_err("Cannot write HDCP message register");
		pr_err("Cannot write HDCP message register\n");
	return rc;
}

@@ -625,11 +624,12 @@ static void hdmi_hdcp2p2_link_work(struct kthread_work *work)
	int rc = 0;
	struct hdmi_hdcp2p2_ctrl *ctrl = container_of(work,
		struct hdmi_hdcp2p2_ctrl, link);
	struct hdcp_lib_wakeup_data cdata = {HDCP_LIB_WKUP_CMD_STOP};
	struct hdcp_lib_wakeup_data cdata = {HDCP_LIB_WKUP_CMD_INVALID};
	struct hdmi_tx_ddc_ctrl *ddc_ctrl;
	struct hdmi_tx_hdcp2p2_ddc_data *ddc_data;
	u64 mult;
	struct msm_hdmi_mode_timing_info *timing;
	char *recvd_msg_buf = NULL;

	if (!ctrl) {
		pr_err("invalid input\n");
@@ -643,6 +643,7 @@ static void hdmi_hdcp2p2_link_work(struct kthread_work *work)
	ddc_ctrl = ctrl->init_data.ddc_ctrl;
	if (!ddc_ctrl) {
		rc = -EINVAL;
		cdata.cmd = HDCP_LIB_WKUP_CMD_STOP;
		goto exit;
	}

@@ -654,27 +655,53 @@ static void hdmi_hdcp2p2_link_work(struct kthread_work *work)

	timing = ctrl->init_data.timing;
	mult = hdmi_tx_get_v_total(timing) / 20;
	ddc_data->intr_mask = RXSTATUS_REAUTH_REQ;
	ddc_data->intr_mask = RXSTATUS_READY | RXSTATUS_MESSAGE_SIZE |
		RXSTATUS_REAUTH_REQ;
	ddc_data->timer_delay_lines = (u32)mult;
	ddc_data->read_method = HDCP2P2_RXSTATUS_HW_DDC_SW_TRIGGER;

	rc = hdmi_hdcp2p2_ddc_read_rxstatus(ddc_ctrl);
	if (rc) {
		pr_err("error reading rxstatus %d\n", rc);
		cdata.cmd = HDCP_LIB_WKUP_CMD_STOP;
		goto exit;
	}

	if (ddc_data->reauth_req) {
		pr_debug("sync reported loss of synchronization, reauth\n");
		rc = -ENOLINK;
		cdata.cmd = HDCP_LIB_WKUP_CMD_STOP;
		goto exit;
	}

	if (ddc_data->ready && ddc_data->message_size) {
		pr_debug("topology changed. rxstatus msg size %d\n",
			ddc_data->message_size);

		recvd_msg_buf = kzalloc(ddc_data->message_size, GFP_KERNEL);
		if (!recvd_msg_buf) {
			cdata.cmd = HDCP_LIB_WKUP_CMD_STOP;
			goto exit;
		}

		rc = hdmi_hdcp2p2_ddc_read_message(ctrl, recvd_msg_buf,
			ddc_data->message_size, ctrl->timeout);
		if (rc) {
			cdata.cmd = HDCP_LIB_WKUP_CMD_STOP;
			pr_err("error reading message %d\n", rc);
		} else {
			cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_RECV_SUCCESS;
			cdata.recvd_msg_buf = recvd_msg_buf;
			cdata.recvd_msg_len = ddc_data->message_size;
		}
	}
exit:
	mutex_unlock(&ctrl->mutex);

	if (rc) {
		/* notify hdcp lib to stop auth */
	hdmi_hdcp2p2_wakeup_lib(ctrl, &cdata);
	kfree(recvd_msg_buf);

	if (rc) {
		/* notify hdmi tx about auth failure */
		hdmi_hdcp2p2_auth_failed(ctrl);

@@ -779,8 +806,6 @@ void *hdmi_hdcp2p2_init(struct hdmi_hdcp_init_data *init_data)
		goto error;
	}

	init_completion(&ctrl->rxstatus_completion);

	ctrl->sink_status = SINK_DISCONNECTED;

	atomic_set(&ctrl->auth_state, HDCP_STATE_INACTIVE);
+66 −92
Original line number Diff line number Diff line
@@ -397,24 +397,9 @@ static bool hdmi_tx_is_cea_format(int mode)

static inline bool hdmi_tx_is_hdcp_enabled(struct hdmi_tx_ctrl *hdmi_ctrl)
{
	bool ret = false;

	if (hdmi_ctrl->hdcp_feature_on) {
		if (hdmi_ctrl->hdcp14_present) {
			/* Check to see if sw keys are available */
			if (hdmi_ctrl->hdcp14_sw_keys) {
				u32 m_aksv, l_aksv;

				ret = !hdcp1_set_keys(&m_aksv, &l_aksv);
			} else {
				ret = true;
			}
		}
		if (hdmi_ctrl->hdcp22_present)
			ret = true;
	}

	return ret;
	return hdmi_ctrl->hdcp_feature_on &&
		(hdmi_ctrl->hdcp14_present || hdmi_ctrl->hdcp22_present) &&
		hdmi_ctrl->hdcp_ops;
}

static const char *hdmi_tx_pm_name(enum hdmi_tx_power_module_type module)
@@ -1245,7 +1230,7 @@ static void hdmi_tx_hdcp_cb_work(struct work_struct *work)
		if (hdmi_ctrl->hpd_state && hdmi_ctrl->panel_power_on) {
			DEV_DBG("%s: Reauthenticating\n", __func__);
			rc = hdmi_ctrl->hdcp_ops->hdmi_hdcp_reauthenticate(
				hdmi_ctrl->hdcp_feature_data);
				hdmi_ctrl->hdcp_data);
			if (rc)
				DEV_ERR("%s: HDCP reauth failed. rc=%d\n",
					__func__, rc);
@@ -1421,6 +1406,7 @@ static int hdmi_tx_init_features(struct hdmi_tx_ctrl *hdmi_ctrl,
	struct hdmi_hdcp_init_data hdcp_init_data;
	struct hdmi_cec_init_data cec_init_data;
	struct resource *res = NULL;
	void *fd = NULL;

	if (!hdmi_ctrl || !fbi) {
		DEV_ERR("%s: invalid input\n", __func__);
@@ -1432,23 +1418,21 @@ static int hdmi_tx_init_features(struct hdmi_tx_ctrl *hdmi_ctrl,
	edid_init_data.ds_data = &hdmi_ctrl->ds_data;
	edid_init_data.max_pclk_khz = hdmi_ctrl->max_pclk_khz;

	hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID] =
		hdmi_edid_init(&edid_init_data);
	if (!hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID]) {
	fd = hdmi_edid_init(&edid_init_data);
	if (!fd) {
		DEV_ERR("%s: hdmi_edid_init failed\n", __func__);
		return -EPERM;
	}

	hdmi_ctrl->panel_data.panel_info.edid_data =
		hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID];
	hdmi_ctrl->panel_data.panel_info.edid_data = fd;

	/* get edid buffer from edid parser */
	hdmi_ctrl->edid_buf = edid_init_data.buf;
	hdmi_ctrl->edid_buf_size = edid_init_data.buf_size;

	hdmi_edid_set_video_resolution(
		hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID],
		hdmi_ctrl->vid_cfg.vic, true);
	hdmi_edid_set_video_resolution(fd, hdmi_ctrl->vid_cfg.vic, true);

	hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID] = fd;

	/* Initialize HDCP features */
	res = platform_get_resource_byname(hdmi_ctrl->pdev,
@@ -1461,10 +1445,8 @@ static int hdmi_tx_init_features(struct hdmi_tx_ctrl *hdmi_ctrl,

	hdcp_init_data.phy_addr      = res->start;
	hdcp_init_data.core_io       = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
	hdcp_init_data.qfprom_io =
		&hdmi_ctrl->pdata.io[HDMI_TX_QFPROM_IO];
	hdcp_init_data.hdcp_io =
		&hdmi_ctrl->pdata.io[HDMI_TX_HDCP_IO];
	hdcp_init_data.qfprom_io     = &hdmi_ctrl->pdata.io[HDMI_TX_QFPROM_IO];
	hdcp_init_data.hdcp_io       = &hdmi_ctrl->pdata.io[HDMI_TX_HDCP_IO];
	hdcp_init_data.mutex         = &hdmi_ctrl->mutex;
	hdcp_init_data.sysfs_kobj    = hdmi_ctrl->kobj;
	hdcp_init_data.ddc_ctrl      = &hdmi_ctrl->ddc_ctrl;
@@ -1474,47 +1456,36 @@ static int hdmi_tx_init_features(struct hdmi_tx_ctrl *hdmi_ctrl,
	hdcp_init_data.hdmi_tx_ver   = hdmi_ctrl->hdmi_tx_ver;
	hdcp_init_data.timing        = &hdmi_ctrl->vid_cfg.timing;

	/*
	 * Try to initialize both HDCP 1.4 and 2.2 features, decide which one
	 * to use at HPD time
	 */
	if (hdmi_ctrl->hdcp14_present) {
		fd = hdmi_hdcp_init(&hdcp_init_data);

		hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP] =
			hdmi_hdcp_init(&hdcp_init_data);

		if (IS_ERR_OR_NULL(
				  hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP])) {
			DEV_ERR("%s: hdmi_hdcp_init failed\n", __func__);
			hdmi_edid_deinit(hdmi_ctrl->feature_data[
				HDMI_TX_FEAT_EDID]);
			hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID] = NULL;
			return -EPERM;
		if (IS_ERR_OR_NULL(fd)) {
			DEV_WARN("%s: hdmi_hdcp_init failed\n", __func__);
		} else {
			hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP] = fd;
			DEV_DBG("%s: HDCP 1.4 configured\n", __func__);
		}
		DEV_DBG("%s: HDCP 1.4 feature initialized\n", __func__);
	}

	hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP2P2] =
		hdmi_hdcp2p2_init(&hdcp_init_data);
	fd = hdmi_hdcp2p2_init(&hdcp_init_data);

	if (IS_ERR_OR_NULL(
			hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP2P2])) {
	if (IS_ERR_OR_NULL(fd)) {
		DEV_WARN("%s: hdmi_hdcp2p2_init failed\n", __func__);
		hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP2P2] = NULL;
	} else {
		DEV_DBG("%s: HDCP 2.2 feature initialized\n", __func__);
		hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP2P2] = fd;
		DEV_DBG("%s: HDCP 2.2 configured\n", __func__);
	}


	/* Initialize CEC feature */
	cec_init_data.io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
	cec_init_data.sysfs_kobj = hdmi_ctrl->kobj;
	cec_init_data.workq = hdmi_ctrl->workq;

	hdmi_ctrl->feature_data[HDMI_TX_FEAT_CEC] =
		hdmi_cec_init(&cec_init_data);
	if (!hdmi_ctrl->feature_data[HDMI_TX_FEAT_CEC])
	fd = hdmi_cec_init(&cec_init_data);
	if (!fd)
		DEV_WARN("%s: hdmi_cec_init failed\n", __func__);
	else
		hdmi_ctrl->feature_data[HDMI_TX_FEAT_CEC] = fd;

	return 0;
} /* hdmi_tx_init_features */
@@ -1622,13 +1593,19 @@ static void hdmi_tx_update_hdcp_info(struct hdmi_tx_ctrl *hdmi_ctrl)
	else
		hdmi_ctrl->hdcp22_present = false;

	if (!hdmi_ctrl->hdcp22_present && hdmi_ctrl->hdcp14_present) {
	if (!hdmi_ctrl->hdcp22_present) {
		if (hdmi_ctrl->hdcp1_use_sw_keys)
			hdmi_ctrl->hdcp14_present =
				hdcp1_check_if_supported_load_app();

		if (hdmi_ctrl->hdcp14_present) {
			fd = hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP];
			ops = hdmi_hdcp_start(fd);
		}
	}

	/* update internal data about hdcp */
	hdmi_ctrl->hdcp_feature_data = fd;
	hdmi_ctrl->hdcp_data = fd;
	hdmi_ctrl->hdcp_ops = ops;
}

@@ -1678,20 +1655,23 @@ static void hdmi_tx_hpd_int_work(struct work_struct *work)
static int hdmi_tx_check_capability(struct hdmi_tx_ctrl *hdmi_ctrl)
{
	u32 hdmi_disabled, hdcp_disabled, reg_val;
	bool sw_keys = false;
	struct dss_io_data *io = NULL;
	int ret = 0;

	if (!hdmi_ctrl) {
		DEV_ERR("%s: invalid input\n", __func__);
		return -EINVAL;
		ret = -EINVAL;
		goto end;
	}

	io = &hdmi_ctrl->pdata.io[HDMI_TX_QFPROM_IO];
	if (!io->base) {
		DEV_ERR("%s: QFPROM io is not initialized\n", __func__);
		return -EINVAL;
		ret = -EINVAL;
		goto end;
	}

	/* check if hdmi and hdcp are disabled */
	if (hdmi_ctrl->hdmi_tx_ver < HDMI_TX_VERSION_4) {
		hdcp_disabled = DSS_REG_R_ND(io,
			QFPROM_RAW_FEAT_CONFIG_ROW0_LSB) & BIT(31);
@@ -1703,6 +1683,7 @@ static int hdmi_tx_check_capability(struct hdmi_tx_ctrl *hdmi_ctrl)
			QFPROM_RAW_FEAT_CONFIG_ROW0_LSB + QFPROM_RAW_VERSION_4);
		hdcp_disabled = reg_val & BIT(12);
		hdmi_disabled = reg_val & BIT(13);

		reg_val = DSS_REG_R_ND(io, SEC_CTRL_HW_VERSION);
		/*
		 * With HDCP enabled on capable hardware, check if HW
@@ -1713,7 +1694,7 @@ static int hdmi_tx_check_capability(struct hdmi_tx_ctrl *hdmi_ctrl)
				QFPROM_RAW_FEAT_CONFIG_ROW0_MSB +
				QFPROM_RAW_VERSION_4);
			if (!(reg_val & BIT(23)))
				sw_keys = true;
				hdmi_ctrl->hdcp1_use_sw_keys = true;
		}
	}

@@ -1722,19 +1703,13 @@ static int hdmi_tx_check_capability(struct hdmi_tx_ctrl *hdmi_ctrl)

	if (hdmi_disabled) {
		DEV_ERR("%s: HDMI disabled\n", __func__);
		return -ENODEV;
	}

	if (hdcp_disabled) {
		hdmi_ctrl->hdcp14_present = 0;
		DEV_WARN("%s: HDCP disabled\n", __func__);
	} else {
		hdmi_ctrl->hdcp14_present = 1;
		hdmi_ctrl->hdcp14_sw_keys = sw_keys;
		DEV_DBG("%s: Device is HDCP enabled\n", __func__);
		ret = -ENODEV;
		goto end;
	}

	return 0;
	hdmi_ctrl->hdcp14_present = !hdcp_disabled;
end:
	return ret;
} /* hdmi_tx_check_capability */

static int hdmi_tx_set_video_fmt(struct hdmi_tx_ctrl *hdmi_ctrl,
@@ -3329,11 +3304,11 @@ static int hdmi_tx_start(struct hdmi_tx_ctrl *hdmi_ctrl)
		hdmi_tx_set_spd_infoframe(hdmi_ctrl);
	}

	hdmi_tx_set_mode(hdmi_ctrl, true);

	if (hdmi_tx_setup_scrambler(hdmi_ctrl))
		DEV_WARN("%s: Scrambler setup failed\n", __func__);

	hdmi_tx_set_mode(hdmi_ctrl, true);

	DEV_INFO("%s: HDMI Core: Initialized\n", __func__);

	return rc;
@@ -3779,10 +3754,10 @@ static irqreturn_t hdmi_tx_isr(int irq, void *data)
		if (hdmi_cec_isr(hdmi_ctrl->feature_data[HDMI_TX_FEAT_CEC]))
			DEV_ERR("%s: hdmi_cec_isr failed\n", __func__);

	if (hdmi_ctrl->hdcp_ops && hdmi_ctrl->hdcp_feature_data) {
	if (hdmi_ctrl->hdcp_ops && hdmi_ctrl->hdcp_data) {
		if (hdmi_ctrl->hdcp_ops->hdmi_hdcp_isr) {
			if (hdmi_ctrl->hdcp_ops->hdmi_hdcp_isr(
				hdmi_ctrl->hdcp_feature_data))
				hdmi_ctrl->hdcp_data))
				DEV_ERR("%s: hdmi_hdcp_isr failed\n",
					 __func__);
		}
@@ -3815,7 +3790,7 @@ static void hdmi_tx_dev_deinit(struct hdmi_tx_ctrl *hdmi_ctrl)
	}

	hdmi_ctrl->hdcp_ops = NULL;
	hdmi_ctrl->hdcp_feature_data = NULL;
	hdmi_ctrl->hdcp_data = NULL;

	if (hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID]) {
		hdmi_edid_deinit(hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID]);
@@ -3940,8 +3915,7 @@ static int hdmi_tx_start_hdcp(struct hdmi_tx_ctrl *hdmi_ctrl)
		return -ENODEV;
	}

	rc = hdmi_ctrl->hdcp_ops->hdmi_hdcp_authenticate(
			hdmi_ctrl->hdcp_feature_data);
	rc = hdmi_ctrl->hdcp_ops->hdmi_hdcp_authenticate(hdmi_ctrl->hdcp_data);
	if (rc)
		DEV_ERR("%s: hdcp auth failed. rc=%d\n", __func__, rc);

@@ -4085,7 +4059,7 @@ static int hdmi_tx_panel_event_handler(struct mdss_panel_data *panel_data,
		if (hdmi_tx_is_hdcp_enabled(hdmi_ctrl)) {
			DEV_DBG("%s: Turning off HDCP\n", __func__);
			hdmi_ctrl->hdcp_ops->hdmi_hdcp_off(
				hdmi_ctrl->hdcp_feature_data);
				hdmi_ctrl->hdcp_data);

			hdmi_ctrl->hdcp_ops = NULL;

+2 −1
Original line number Diff line number Diff line
@@ -174,6 +174,7 @@ struct hdmi_tx_ctrl {
	bool ds_registered;
	bool scrambler_enabled;
	u32 hdcp14_present;
	bool hdcp1_use_sw_keys;
	bool audio_ack_enabled;
	atomic_t audio_ack_pending;
	bool hdcp14_sw_keys;
@@ -188,7 +189,7 @@ struct hdmi_tx_ctrl {

	void *feature_data[HDMI_TX_FEAT_MAX];
	struct hdmi_hdcp_ops *hdcp_ops;
	void *hdcp_feature_data;
	void *hdcp_data;
	bool hdcp22_present;

	u8 *edid_buf;
+0 −2
Original line number Diff line number Diff line
@@ -1672,8 +1672,6 @@ int hdmi_hdcp2p2_ddc_read_rxstatus(struct hdmi_tx_ddc_ctrl *ctrl)

	/* check for errors and clear status */
	reg_val = DSS_REG_R(ctrl->io, HDMI_HDCP2P2_DDC_STATUS);
	if (reg_val & BIT(0))
		pr_debug("ddc busy\n");

	if (reg_val & BIT(4)) {
		pr_err("ddc aborted\n");
Loading