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

Commit 5068a5df authored by Ajay Singh Parmar's avatar Ajay Singh Parmar
Browse files

mdss: display-port: add support for hdcp 2.2



Add support for HDCP (High-Bandwidth Digital Content Protect)
version 2.2 for DisplayPort. Define interfaces to interact with
Trust Zone and DisplayPort drivers. Hookup with TZ's kernel
module and send-receive HDCP 2.2 messages to-from sink using
DP's aux channel.

Change-Id: Id77e77ee628667dacc7a714c553b5ce5beafa9bb
Signed-off-by: default avatarAjay Singh Parmar <aparmar@codeaurora.org>
parent 7d2ad0bd
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ obj-$(CONFIG_FB_MSM_MDSS) += mdss_dba_utils.o
obj-$(CONFIG_FB_MSM_MDSS) += mdss_hdcp_1x.o
obj-$(CONFIG_FB_MSM_MDSS_DP_PANEL) += mdss_dp.o mdss_dp_util.o
obj-$(CONFIG_FB_MSM_MDSS_DP_PANEL) += mdss_dp_aux.o
obj-$(CONFIG_FB_MSM_MDSS_DP_PANEL) += mdss_dp_hdcp2p2.o

obj-$(CONFIG_FB_MSM_MDSS) += mdss_io_util.o
obj-$(CONFIG_FB_MSM_MDSS) += msm_ext_display.o
+108 −24
Original line number Diff line number Diff line
@@ -36,7 +36,7 @@
#include "mdss_dp_util.h"
#include "mdss_hdmi_panel.h"
#include <linux/hdcp_qseecom.h>
#include "mdss_hdcp_1x.h"
#include "mdss_hdcp.h"
#include "mdss_debug.h"

#define RGB_COMPONENTS		3
@@ -1621,22 +1621,24 @@ static void mdss_dp_hdcp_cb(void *ptr, enum hdcp_states status)
		return;
	}

	ops = dp->hdcp_ops;
	ops = dp->hdcp.ops;

	mutex_lock(&dp->train_mutex);

	switch (status) {
	case HDCP_STATE_AUTHENTICATED:
		pr_debug("hdcp 1.3 authenticated\n");
		pr_debug("hdcp authenticated\n");
		dp->hdcp.auth_state = true;
		break;
	case HDCP_STATE_AUTH_FAIL:
		dp->hdcp.auth_state = false;

		if (dp->power_on) {
			pr_debug("Reauthenticating\n");
			if (ops && ops->reauthenticate) {
				rc = ops->reauthenticate(dp->hdcp_data);
				rc = ops->reauthenticate(dp->hdcp.data);
				if (rc)
					pr_err("HDCP reauth failed. rc=%d\n",
						rc);
					pr_err("reauth failed rc=%d\n", rc);
			}
		} else {
			pr_debug("not reauthenticating, cable disconnected\n");
@@ -1685,19 +1687,22 @@ static int mdss_dp_hdcp_init(struct mdss_panel_data *pdata)
	hdcp_init_data.sec_access    = true;
	hdcp_init_data.client_id     = HDCP_CLIENT_DP;

	dp_drv->hdcp_data = hdcp_1x_init(&hdcp_init_data);
	if (IS_ERR_OR_NULL(dp_drv->hdcp_data)) {
	dp_drv->hdcp.data = hdcp_1x_init(&hdcp_init_data);
	if (IS_ERR_OR_NULL(dp_drv->hdcp.data)) {
		pr_err("Error hdcp init\n");
		rc = -EINVAL;
		goto error;
	}

	dp_drv->panel_data.panel_info.hdcp_1x_data = dp_drv->hdcp_data;
	dp_drv->panel_data.panel_info.hdcp_1x_data = dp_drv->hdcp.data;

	pr_debug("HDCP 1.3 initialized\n");

	dp_drv->hdcp_ops = hdcp_1x_start(dp_drv->hdcp_data);
	dp_drv->hdcp.hdcp2 = dp_hdcp2p2_init(&hdcp_init_data);
	if (!IS_ERR_OR_NULL(dp_drv->hdcp.data))
		pr_debug("HDCP 2.2 initialized\n");

	dp_drv->hdcp.feature_enabled = true;
	return 0;
error:
	return rc;
@@ -1839,13 +1844,46 @@ static void mdss_dp_mainlink_push_idle(struct mdss_panel_data *pdata)
	pr_debug("mainlink off done\n");
}

static void mdss_dp_update_hdcp_info(struct mdss_dp_drv_pdata *dp)
{
	void *fd = NULL;
	struct hdcp_ops *ops = NULL;

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

	/* check first if hdcp2p2 is supported */
	fd = dp->hdcp.hdcp2;
	if (fd)
		ops = dp_hdcp2p2_start(fd);

	if (ops && ops->feature_supported)
		dp->hdcp.hdcp2_present = ops->feature_supported(fd);
	else
		dp->hdcp.hdcp2_present = false;

	if (!dp->hdcp.hdcp2_present) {
		dp->hdcp.hdcp1_present = hdcp1_check_if_supported_load_app();

		if (dp->hdcp.hdcp1_present) {
			fd = dp->hdcp.hdcp1;
			ops = hdcp_1x_start(fd);
		}
	}

	/* update internal data about hdcp */
	dp->hdcp.data = fd;
	dp->hdcp.ops = ops;
}

static int mdss_dp_event_handler(struct mdss_panel_data *pdata,
				  int event, void *arg)
{
	int rc = 0;
	struct fb_info *fbi;
	struct mdss_dp_drv_pdata *dp = NULL;
	struct hdcp_ops *ops;

	if (!pdata) {
		pr_err("%s: Invalid input data\n", __func__);
@@ -1857,24 +1895,23 @@ static int mdss_dp_event_handler(struct mdss_panel_data *pdata,
	dp = container_of(pdata, struct mdss_dp_drv_pdata,
				panel_data);

	ops = dp->hdcp_ops;

	switch (event) {
	case MDSS_EVENT_UNBLANK:
		rc = mdss_dp_on(pdata);
		break;
	case MDSS_EVENT_PANEL_ON:
		if (hdcp1_check_if_supported_load_app()) {
			if (ops && ops->authenticate)
				rc = ops->authenticate(dp->hdcp_data);
		}
		mdss_dp_update_hdcp_info(dp);

		if (dp->hdcp.ops && dp->hdcp.ops->authenticate)
			rc = dp->hdcp.ops->authenticate(dp->hdcp.data);
		break;
	case MDSS_EVENT_PANEL_OFF:
		rc = mdss_dp_off(pdata);
		break;
	case MDSS_EVENT_BLANK:
		if (ops && ops->off)
			ops->off(dp->hdcp_data);
		if (dp->hdcp.ops && dp->hdcp.ops->off)
			dp->hdcp.ops->off(dp->hdcp.data);

		mdss_dp_mainlink_push_idle(pdata);
		break;
	case MDSS_EVENT_FB_REGISTERED:
@@ -1909,6 +1946,7 @@ static int mdss_dp_remove(struct platform_device *pdev)
	struct mdss_dp_drv_pdata *dp_drv = NULL;

	dp_drv = platform_get_drvdata(pdev);
	dp_hdcp2p2_deinit(dp_drv->hdcp.data);

	iounmap(dp_drv->ctrl_io.base);
	dp_drv->ctrl_io.base = NULL;
@@ -2149,11 +2187,6 @@ irqreturn_t dp_isr(int irq, void *ptr)
			dp_aux_native_handler(dp, isr1);
	}

	if (dp->hdcp_ops && dp->hdcp_ops->isr) {
		if (dp->hdcp_ops->isr(dp->hdcp_data))
			pr_err("dp_hdcp_isr failed\n");
	}

	return IRQ_HANDLED;
}

@@ -2410,6 +2443,10 @@ static void usbpd_response_callback(struct usbpd_svid_handler *hdlr, u8 cmd,
			mdss_dp_host_init(&dp_drv->panel_data);
		else
			dp_send_events(dp_drv, EV_USBPD_DP_CONFIGURE);

		if (dp_drv->alt_mode.dp_status.hpd_irq && dp_drv->power_on &&
		    dp_drv->hdcp.ops && dp_drv->hdcp.ops->isr)
			dp_drv->hdcp.ops->isr(dp_drv->hdcp.data);
		break;
	case DP_VDM_STATUS:
		dp_drv->alt_mode.dp_status.response = *vdos;
@@ -2609,6 +2646,53 @@ probe_err:

}

void *mdss_dp_get_hdcp_data(struct device *dev)
{
	struct mdss_dp_drv_pdata *dp_drv = NULL;

	if (!dev) {
		pr_err("%s:Invalid input\n", __func__);
		return NULL;
	}
	dp_drv = dev_get_drvdata(dev);
	if (!dp_drv) {
		pr_err("%s:Invalid dp driver\n", __func__);
		return NULL;
	}
	return dp_drv->hdcp.data;
}

static inline bool dp_is_hdcp_enabled(struct mdss_dp_drv_pdata *dp_drv)
{
	return dp_drv->hdcp.feature_enabled &&
		(dp_drv->hdcp.hdcp1_present || dp_drv->hdcp.hdcp2_present) &&
		dp_drv->hdcp.ops;
}

static inline bool dp_is_stream_shareable(struct mdss_dp_drv_pdata *dp_drv)
{
	bool ret = 0;

	switch (dp_drv->hdcp.enc_lvl) {
	case HDCP_STATE_AUTH_ENC_NONE:
		ret = true;
		break;
	case HDCP_STATE_AUTH_ENC_1X:
		ret = dp_is_hdcp_enabled(dp_drv) &&
			dp_drv->hdcp.auth_state;
		break;
	case HDCP_STATE_AUTH_ENC_2P2:
		ret = dp_drv->hdcp.feature_enabled &&
			dp_drv->hdcp.hdcp2_present &&
			dp_drv->hdcp.auth_state;
		break;
	default:
		ret = false;
	}

	return ret;
}

static const struct of_device_id msm_mdss_dp_dt_match[] = {
	{.compatible = "qcom,mdss-dp"},
	{}
+18 −2
Original line number Diff line number Diff line
@@ -350,6 +350,21 @@ struct dp_pinctrl_res {

irqreturn_t dp_isr(int irq, void *ptr);

struct dp_hdcp {
	void *data;
	struct hdcp_ops *ops;

	void *hdcp1;
	void *hdcp2;

	int enc_lvl;

	bool auth_state;
	bool hdcp1_present;
	bool hdcp2_present;
	bool feature_enabled;
};

struct mdss_dp_drv_pdata {
	/* device driver */
	int (*on) (struct mdss_panel_data *pdata);
@@ -358,6 +373,7 @@ struct mdss_dp_drv_pdata {
	struct platform_device *ext_pdev;

	struct usbpd *pd;
	struct dp_hdcp hdcp;
	struct usbpd_svid_handler svid_handler;
	struct dp_alt_mode alt_mode;
	bool dp_initialized;
@@ -465,8 +481,6 @@ struct mdss_dp_drv_pdata {
	u32 new_vic;
	int fb_node;

	void *hdcp_data;
	struct hdcp_ops *hdcp_ops;
	struct dpcd_test_request test_data;
	struct dpcd_sink_count sink_count;
};
@@ -569,5 +583,7 @@ void mdss_dp_config_ctrl(struct mdss_dp_drv_pdata *ep);
char mdss_dp_gen_link_clk(struct mdss_panel_info *pinfo, char lane_cnt);
int mdss_dp_aux_set_sink_power_state(struct mdss_dp_drv_pdata *ep, char state);
void mdss_dp_aux_send_test_response(struct mdss_dp_drv_pdata *ep);
void *mdss_dp_get_hdcp_data(struct device *dev);
int mdss_dp_hdcp2p2_init(struct mdss_dp_drv_pdata *dp_drv);

#endif /* MDSS_DP_H */
+40 −5
Original line number Diff line number Diff line
@@ -277,14 +277,16 @@ static int dp_aux_read_cmds(struct mdss_dp_drv_pdata *ep,

	wait_for_completion(&ep->aux_comp);

	if (ep->aux_error_num == EDP_AUX_ERR_NONE)
	if (ep->aux_error_num == EDP_AUX_ERR_NONE) {
		ret = dp_cmd_fifo_rx(rp, len, ep->base);
	else
		ret = ep->aux_error_num;

		if (cmds->out_buf)
			memcpy(cmds->out_buf, rp->data, cmds->len);

	} else {
		ret = ep->aux_error_num;
	}

	ep->aux_cmd_busy = 0;
	mutex_unlock(&ep->aux_mutex);

@@ -1694,3 +1696,36 @@ void mdss_dp_aux_init(struct mdss_dp_drv_pdata *ep)
	dp_buf_init(&ep->txp, ep->txbuf, sizeof(ep->txbuf));
	dp_buf_init(&ep->rxp, ep->rxbuf, sizeof(ep->rxbuf));
}

int mdss_dp_aux_read_rx_status(struct mdss_dp_drv_pdata *dp, u8 *rx_status)
{
	bool cp_irq;
	int rc = 0;

	if (!dp) {
		pr_err("%s Invalid input\n", __func__);
		return -EINVAL;
	}

	*rx_status = 0;

	rc = dp_aux_read_buf(dp, DP_DPCD_CP_IRQ, 1, 0);
	if (!rc) {
		pr_err("Error reading CP_IRQ\n");
		return -EINVAL;
	}

	cp_irq = *dp->rxp.data & BIT(2);

	if (cp_irq) {
		rc = dp_aux_read_buf(dp, DP_DPCD_RXSTATUS, 1, 0);
		if (!rc) {
			pr_err("Error reading RxStatus\n");
			return -EINVAL;
		}

		*rx_status = *dp->rxp.data;
	}

	return 0;
}
Loading