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

Commit 02b2b76f authored by Abhinav Kumar's avatar Abhinav Kumar
Browse files

drm/msm: add HDCP 1x module for MSM DRM driver



This change adds the HDCP 1x module for MSM DRM
driver and also hooks it up with SDE HDMI driver.

Change-Id: Iaf53c398254f6838a1d3cae610e069c5dbe18138
Signed-off-by: default avatarAbhinav Kumar <abhinavk@codeaurora.org>
parent e4db249b
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -51,7 +51,8 @@ msm_drm-y := \
	sde_dbg_evtlog.o \
	sde_io_util.o \
	dba_bridge.o \
	sde_edid_parser.o
	sde_edid_parser.o \
	sde_hdcp_1x.o

# use drm gpu driver only if qcom_kgsl driver not available
ifneq ($(CONFIG_QCOM_KGSL),y)
+72 −4
Original line number Diff line number Diff line
@@ -439,6 +439,22 @@ static void sde_hdmi_tx_hdcp_cb(void *ptr, enum sde_hdcp_states status)
	queue_delayed_work(hdmi->workq, &hdmi_ctrl->hdcp_cb_work, HZ/4);
}

void sde_hdmi_hdcp_off(struct sde_hdmi *hdmi_ctrl)
{

	if (!hdmi_ctrl) {
		SDE_ERROR("%s: invalid input\n", __func__);
		return;
	}

	if (hdmi_ctrl->hdcp_ops)
		hdmi_ctrl->hdcp_ops->off(hdmi_ctrl->hdcp_data);

	flush_delayed_work(&hdmi_ctrl->hdcp_cb_work);

	hdmi_ctrl->hdcp_ops = NULL;
}

static void sde_hdmi_tx_hdcp_cb_work(struct work_struct *work)
{
	struct sde_hdmi *hdmi_ctrl = NULL;
@@ -1123,8 +1139,14 @@ static irqreturn_t _sde_hdmi_irq(int irq, void *dev_id)
	hdmi_i2c_irq(hdmi->i2c);

	/* Process HDCP: */
	if (hdmi->hdcp_ctrl && hdmi->is_hdcp_supported)
		hdmi_hdcp_ctrl_irq(hdmi->hdcp_ctrl);
	if (sde_hdmi->hdcp_ops && sde_hdmi->hdcp_data) {
		if (sde_hdmi->hdcp_ops->isr) {
			if (sde_hdmi->hdcp_ops->isr(
				sde_hdmi->hdcp_data))
				DEV_ERR("%s: hdcp_1x_isr failed\n",
						__func__);
		}
	}

	/* Process CEC: */
	_sde_hdmi_cec_irq(sde_hdmi);
@@ -1660,6 +1682,7 @@ static int sde_hdmi_tx_check_capability(struct sde_hdmi *sde_hdmi)
static int _sde_hdmi_init_hdcp(struct sde_hdmi *hdmi_ctrl)
{
	struct sde_hdcp_init_data hdcp_init_data;
	void *hdcp_data;
	int rc = 0;
	struct hdmi *hdmi;

@@ -1682,6 +1705,21 @@ static int _sde_hdmi_init_hdcp(struct sde_hdmi *hdmi_ctrl)
	hdcp_init_data.client_id     = HDCP_CLIENT_HDMI;
	hdcp_init_data.ddc_ctrl      = &hdmi_ctrl->ddc_ctrl;

	if (hdmi_ctrl->hdcp14_present) {
		hdcp_data = sde_hdcp_1x_init(&hdcp_init_data);

		if (IS_ERR_OR_NULL(hdcp_data)) {
			DEV_ERR("%s: hdcp 1.4 init failed\n", __func__);
			rc = -EINVAL;
			kfree(hdcp_data);
			goto end;
		} else {
			hdmi_ctrl->hdcp_feature_data[SDE_HDCP_1x] = hdcp_data;
			SDE_HDMI_DEBUG("%s: HDCP 1.4 initialized\n", __func__);
		}
	}

end:
	return rc;
}

@@ -1718,7 +1756,36 @@ int sde_hdmi_connector_post_init(struct drm_connector *connector,
		SDE_ERROR("failed to enable HPD: %d\n", rc);

	_sde_hdmi_get_tx_version(sde_hdmi);

	sde_hdmi_tx_check_capability(sde_hdmi);

	_sde_hdmi_init_hdcp(sde_hdmi);

	return rc;
}

int sde_hdmi_start_hdcp(struct drm_connector *connector)
{
	int rc;
	struct sde_connector *c_conn = to_sde_connector(connector);
	struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display;
	struct hdmi *hdmi = display->ctrl.ctrl;

	if (!hdmi) {
		SDE_ERROR("%s: invalid input\n", __func__);
		return -EINVAL;
	}

	if (!sde_hdmi_tx_is_hdcp_enabled(display))
		return 0;

	if (sde_hdmi_tx_is_encryption_set(display))
		sde_hdmi_config_avmute(hdmi, true);

	rc = display->hdcp_ops->authenticate(display->hdcp_data);
	if (rc)
		SDE_ERROR("%s: hdcp auth failed. rc=%d\n", __func__, rc);

	return rc;
}

@@ -1835,6 +1902,9 @@ int sde_hdmi_dev_deinit(struct sde_hdmi *display)
		SDE_ERROR("Invalid params\n");
		return -EINVAL;
	}
	if (display->hdcp_feature_data[SDE_HDCP_1x])
		sde_hdcp_1x_deinit(display->hdcp_feature_data[SDE_HDCP_1x]);

	return 0;
}

@@ -1923,8 +1993,6 @@ static int sde_hdmi_bind(struct device *dev, struct device *master, void *data)
	INIT_DELAYED_WORK(&display->hdcp_cb_work,
					  sde_hdmi_tx_hdcp_cb_work);
	mutex_init(&display->hdcp_mutex);
	_sde_hdmi_init_hdcp(display);

	mutex_unlock(&display->display_lock);
	return rc;

+22 −0
Original line number Diff line number Diff line
@@ -85,6 +85,11 @@ enum hdmi_tx_io_type {
	HDMI_TX_MAX_IO
};

enum hdmi_tx_feature_type {
	SDE_HDCP_1x,
	SDE_HDCP_2P2
};

/**
 * struct sde_hdmi - hdmi display information
 * @pdev:             Pointer to platform device.
@@ -137,7 +142,12 @@ struct sde_hdmi {
	u8 hdcp_status;
	u32 enc_lvl;
	bool auth_state;
	/*hold final data
	 *based on hdcp support
	 */
	void *hdcp_data;
	/*hold hdcp init data*/
	void *hdcp_feature_data[2];
	struct sde_hdcp_ops *hdcp_ops;
	struct sde_hdmi_tx_ddc_ctrl ddc_ctrl;
	struct work_struct hpd_work;
@@ -418,6 +428,8 @@ bool sde_hdmi_tx_is_hdcp_enabled(struct sde_hdmi *hdmi_ctrl);
bool sde_hdmi_tx_is_encryption_set(struct sde_hdmi *hdmi_ctrl);
bool sde_hdmi_tx_is_stream_shareable(struct sde_hdmi *hdmi_ctrl);
bool sde_hdmi_tx_is_panel_on(struct sde_hdmi *hdmi_ctrl);
int sde_hdmi_start_hdcp(struct drm_connector *connector);
void sde_hdmi_hdcp_off(struct sde_hdmi *hdmi_ctrl);

#else /*#ifdef CONFIG_DRM_SDE_HDMI*/

@@ -503,6 +515,16 @@ static inline int sde_hdmi_drm_init(struct sde_hdmi *display,
	return 0;
}

int sde_hdmi_start_hdcp(struct drm_connector *connector)
{
	return 0;
}

void sde_hdmi_hdcp_off(struct sde_hdmi *hdmi_ctrl)
{

}

static inline int sde_hdmi_drm_deinit(struct sde_hdmi *display)
{
	return 0;
+39 −2
Original line number Diff line number Diff line
@@ -396,8 +396,45 @@ static void _sde_hdmi_bridge_pre_enable(struct drm_bridge *bridge)
	mutex_unlock(&display->display_lock);
}

static void sde_hdmi_update_hdcp_info(struct drm_connector *connector)
{
	void *fd = NULL;
	struct sde_hdcp_ops *ops = NULL;
	struct sde_connector *c_conn = to_sde_connector(connector);
	struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display;

	if (!display) {
		DEV_ERR("%s: invalid input\n", __func__);
		return;
	}

	if (!display->hdcp22_present) {
		if (display->hdcp1_use_sw_keys) {
			display->hdcp14_present =
				hdcp1_check_if_supported_load_app();
		}
		if (display->hdcp14_present) {
			fd = display->hdcp_feature_data[SDE_HDCP_1x];
			if (fd)
				ops = sde_hdcp_1x_start(fd);
		}
	}

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

static void _sde_hdmi_bridge_enable(struct drm_bridge *bridge)
{
	struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge);
	struct hdmi *hdmi = sde_hdmi_bridge->hdmi;

	/* need to update hdcp info here to ensure right HDCP support*/
	sde_hdmi_update_hdcp_info(hdmi->connector);

	/* start HDCP authentication */
	sde_hdmi_start_hdcp(hdmi->connector);
}

static void _sde_hdmi_bridge_disable(struct drm_bridge *bridge)
@@ -414,8 +451,8 @@ static void _sde_hdmi_bridge_post_disable(struct drm_bridge *bridge)

	sde_hdmi_notify_clients(display, display->connected);

	if (hdmi->hdcp_ctrl && hdmi->is_hdcp_supported)
		hdmi_hdcp_ctrl_off(hdmi->hdcp_ctrl);
	if (sde_hdmi_tx_is_hdcp_enabled(display))
		sde_hdmi_hdcp_off(display);

	sde_hdmi_audio_off(hdmi);

+1 −1
Original line number Diff line number Diff line
@@ -307,7 +307,7 @@ int sde_hdmi_config_avmute(struct hdmi *hdmi, bool set)
		hdmi_write(hdmi, HDMI_VBI_PKT_CTRL,
			hdmi_read(hdmi, HDMI_VBI_PKT_CTRL) | (BIT(4) & BIT(5)));

	SDE_DEBUG("AVMUTE %s\n", set ? "set" : "cleared");
	pr_info("AVMUTE %s\n", set ? "set" : "cleared");

	return 0;
}
Loading