summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c9
-rw-r--r--drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_hdcp2p2.c36
-rw-r--r--drivers/gpu/drm/msm/sde_hdcp.h1
-rw-r--r--drivers/misc/hdcp.c108
-rw-r--r--include/linux/hdcp_qseecom.h1
5 files changed, 153 insertions, 2 deletions
diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c
index fa111d581529..0f77e35ef287 100644
--- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c
+++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c
@@ -666,6 +666,15 @@ static void sde_hdmi_tx_hdcp_cb_work(struct work_struct *work)
}
break;
+ case HDCP_STATE_AUTH_FAIL_NOREAUTH:
+ if (hdmi_ctrl->hdcp1_use_sw_keys && hdmi_ctrl->hdcp14_present) {
+ if (hdmi_ctrl->auth_state && !hdmi_ctrl->hdcp22_present)
+ hdcp1_set_enc(false);
+ }
+
+ hdmi_ctrl->auth_state = false;
+
+ break;
case HDCP_STATE_AUTH_ENC_NONE:
hdmi_ctrl->enc_lvl = HDCP_STATE_AUTH_ENC_NONE;
if (sde_hdmi_tx_is_panel_on(hdmi_ctrl))
diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_hdcp2p2.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_hdcp2p2.c
index 1e673440f399..51f5c8d8dde6 100644
--- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_hdcp2p2.c
+++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_hdcp2p2.c
@@ -338,6 +338,41 @@ static void sde_hdmi_hdcp2p2_auth_failed(struct sde_hdmi_hdcp2p2_ctrl *ctrl)
HDCP_STATE_AUTH_FAIL);
}
+static void sde_hdmi_hdcp2p2_fail_noreauth(struct sde_hdmi_hdcp2p2_ctrl *ctrl)
+{
+ if (!ctrl) {
+ SDE_ERROR("invalid input\n");
+ return;
+ }
+
+ atomic_set(&ctrl->auth_state, HDCP_STATE_AUTH_FAIL);
+
+ sde_hdmi_hdcp2p2_ddc_disable(ctrl->init_data.cb_data);
+
+ /* notify hdmi tx about HDCP failure */
+ ctrl->init_data.notify_status(ctrl->init_data.cb_data,
+ HDCP_STATE_AUTH_FAIL_NOREAUTH);
+}
+
+static void sde_hdmi_hdcp2p2_srm_cb(void *client_ctx)
+{
+ struct sde_hdmi_hdcp2p2_ctrl *ctrl =
+ (struct sde_hdmi_hdcp2p2_ctrl *)client_ctx;
+ struct hdcp_lib_wakeup_data cdata = {
+ HDCP_LIB_WKUP_CMD_INVALID};
+
+ if (!ctrl) {
+ SDE_ERROR("invalid input\n");
+ return;
+ }
+
+ cdata.context = ctrl->lib_ctx;
+ cdata.cmd = HDCP_LIB_WKUP_CMD_STOP;
+ sde_hdmi_hdcp2p2_wakeup_lib(ctrl, &cdata);
+
+ sde_hdmi_hdcp2p2_fail_noreauth(ctrl);
+}
+
static int sde_hdmi_hdcp2p2_ddc_rd_message(struct sde_hdmi_hdcp2p2_ctrl *ctrl,
u8 *buf, int size, u32 timeout)
{
@@ -888,6 +923,7 @@ void *sde_hdmi_hdcp2p2_init(struct sde_hdcp_init_data *init_data)
static struct hdcp_client_ops client_ops = {
.wakeup = sde_hdmi_hdcp2p2_wakeup,
.notify_lvl_change = sde_hdmi_hdcp2p2_min_level_change,
+ .srm_cb = sde_hdmi_hdcp2p2_srm_cb,
};
static struct hdcp_txmtr_ops txmtr_ops;
diff --git a/drivers/gpu/drm/msm/sde_hdcp.h b/drivers/gpu/drm/msm/sde_hdcp.h
index 49cca9399cb0..c414f68a8e0d 100644
--- a/drivers/gpu/drm/msm/sde_hdcp.h
+++ b/drivers/gpu/drm/msm/sde_hdcp.h
@@ -43,6 +43,7 @@ enum sde_hdcp_states {
HDCP_STATE_AUTHENTICATING,
HDCP_STATE_AUTHENTICATED,
HDCP_STATE_AUTH_FAIL,
+ HDCP_STATE_AUTH_FAIL_NOREAUTH,
HDCP_STATE_AUTH_ENC_NONE,
HDCP_STATE_AUTH_ENC_1X,
HDCP_STATE_AUTH_ENC_2P2
diff --git a/drivers/misc/hdcp.c b/drivers/misc/hdcp.c
index 687f55bd5afd..87daee7cf1c6 100644
--- a/drivers/misc/hdcp.c
+++ b/drivers/misc/hdcp.c
@@ -38,6 +38,7 @@
#include "qseecom_kernel.h"
+#define SRMAPP_NAME "hdcpsrm"
#define TZAPP_NAME "hdcp2p2"
#define HDCP1_APP_NAME "hdcp1"
#define QSEECOM_SBUFF_SIZE 0x1000
@@ -138,6 +139,7 @@
#define HDCP_SESSION_INIT SERVICE_CREATE_CMD(16)
#define HDCP_SESSION_DEINIT SERVICE_CREATE_CMD(17)
#define HDCP_TXMTR_START_AUTHENTICATE SERVICE_CREATE_CMD(18)
+#define HDCP_TXMTR_VALIDATE_RECEIVER_ID_LIST SERVICE_CREATE_CMD(19)
#define HCDP_TXMTR_GET_MAJOR_VERSION(v) (((v) >> 16) & 0xFF)
#define HCDP_TXMTR_GET_MINOR_VERSION(v) (((v) >> 8) & 0xFF)
@@ -485,6 +487,15 @@ struct __attribute__ ((__packed__)) hdcp_start_auth_rsp {
uint8_t message[MAX_TX_MESSAGE_SIZE];
};
+struct __attribute__ ((__packed__)) hdcp_rcv_id_list_req {
+ uint32_t commandid;
+ uint32_t ctxHandle;
+};
+struct __attribute__ ((__packed__)) hdcp_rcv_id_list_rsp {
+ uint32_t status;
+ uint32_t commandid;
+};
+
/*
* struct hdcp_lib_handle - handle for hdcp client
* @qseecom_handle - for sending commands to qseecom
@@ -575,6 +586,8 @@ static int hdcp_lib_txmtr_init(struct hdcp_lib_handle *handle);
static int hdcp_lib_txmtr_init_legacy(struct hdcp_lib_handle *handle);
static struct qseecom_handle *hdcp1_handle;
+static struct qseecom_handle *hdcpsrm_handle;
+
static bool hdcp1_supported = true;
static bool hdcp1_enc_enabled;
static struct mutex hdcp1_ta_cmd_lock;
@@ -1044,6 +1057,15 @@ static int hdcp_lib_library_load(struct hdcp_lib_handle *handle)
goto exit;
}
+ if (!hdcpsrm_handle) {
+ rc = qseecom_start_app(&hdcpsrm_handle,
+ SRMAPP_NAME, QSEECOM_SBUFF_SIZE);
+ if (rc) {
+ pr_err("qseecom_start_app failed for SRM TA %d\n", rc);
+ goto exit;
+ }
+ }
+
handle->hdcp_state |= HDCP_STATE_APP_LOADED;
pr_debug("qseecom_start_app success\n");
@@ -1113,10 +1135,17 @@ static int hdcp_lib_library_unload(struct hdcp_lib_handle *handle)
goto exit;
}
- /* deallocate the resources for qseecom handle */
+ /* deallocate the resources for qseecom hdcp2p2 handle */
rc = qseecom_shutdown_app(&handle->qseecom_handle);
if (rc) {
- pr_err("qseecom_shutdown_app failed err: %d\n", rc);
+ pr_err("hdcp2p2 qseecom_shutdown_app failed err: %d\n", rc);
+ goto exit;
+ }
+
+ /* deallocate the resources for qseecom hdcpsrm handle */
+ rc = qseecom_shutdown_app(&hdcpsrm_handle);
+ if (rc) {
+ pr_err("hdcpsrm qseecom_shutdown_app failed err: %d\n", rc);
goto exit;
}
@@ -2322,6 +2351,48 @@ int hdcp1_set_keys(uint32_t *aksv_msb, uint32_t *aksv_lsb)
return 0;
}
+static int hdcp_validate_recv_id(struct hdcp_lib_handle *handle)
+{
+ int rc = 0;
+ struct hdcp_rcv_id_list_req *recv_id_req;
+ struct hdcp_rcv_id_list_rsp *recv_id_rsp;
+
+ if (!handle || !handle->qseecom_handle ||
+ !handle->qseecom_handle->sbuf) {
+ pr_err("invalid handle\n");
+ return -EINVAL;
+ }
+
+ /* validate the receiver ID list against the new SRM blob */
+ recv_id_req = (struct hdcp_rcv_id_list_req *)
+ handle->qseecom_handle->sbuf;
+ recv_id_req->commandid = HDCP_TXMTR_VALIDATE_RECEIVER_ID_LIST;
+ recv_id_req->ctxHandle = handle->tz_ctxhandle;
+
+ recv_id_rsp = (struct hdcp_rcv_id_list_rsp *)
+ (handle->qseecom_handle->sbuf +
+ QSEECOM_ALIGN(sizeof(struct hdcp_rcv_id_list_req)));
+
+ rc = qseecom_send_command(handle->qseecom_handle,
+ recv_id_req,
+ QSEECOM_ALIGN(sizeof(struct hdcp_rcv_id_list_req)),
+ recv_id_rsp,
+ QSEECOM_ALIGN(sizeof(struct hdcp_rcv_id_list_rsp)));
+
+
+ if ((rc < 0) || (recv_id_rsp->status != HDCP_SUCCESS) ||
+ (recv_id_rsp->commandid !=
+ HDCP_TXMTR_VALIDATE_RECEIVER_ID_LIST)) {
+ pr_err("qseecom cmd failed with err = %d status = %d\n",
+ rc, recv_id_rsp->status);
+ rc = -EINVAL;
+ goto exit;
+ }
+
+exit:
+ return rc;
+}
+
int hdcp1_set_enc(bool enable)
{
int rc = 0;
@@ -2601,12 +2672,44 @@ static ssize_t hdmi_hdcp2p2_sysfs_wta_min_level_change(struct device *dev,
return ret;
}
+static ssize_t hdmi_hdcp_srm_updated(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int rc;
+ int srm_updated;
+ struct hdcp_lib_handle *handle;
+ ssize_t ret = count;
+
+ handle = hdcp_drv_mgr->handle;
+
+ rc = kstrtoint(buf, 10, &srm_updated);
+ if (rc) {
+ pr_err("%s: kstrtoint failed. rc=%d\n", __func__, rc);
+ return -EINVAL;
+ }
+
+ if (srm_updated) {
+ if (hdcp_validate_recv_id(handle)) {
+ pr_debug("SRM check FAILED\n");
+ if (handle && handle->client_ops->srm_cb)
+ handle->client_ops->srm_cb(handle->client_ctx);
+ } else {
+ pr_debug("SRM check PASSED\n");
+ }
+ }
+
+ return ret;
+}
+
static DEVICE_ATTR(tp, S_IRUGO | S_IWUSR, msm_hdcp_1x_sysfs_rda_tp,
msm_hdcp_1x_sysfs_wta_tp);
static DEVICE_ATTR(min_level_change, S_IWUSR, NULL,
hdmi_hdcp2p2_sysfs_wta_min_level_change);
+static DEVICE_ATTR(srm_updated, S_IWUSR, NULL,
+hdmi_hdcp_srm_updated);
+
void hdcp1_cache_repeater_topology(void *hdcp1_cached_tp)
{
memcpy((void *)&hdcp_drv_mgr->cached_tp,
@@ -2617,6 +2720,7 @@ void hdcp1_cache_repeater_topology(void *hdcp1_cached_tp)
static struct attribute *msm_hdcp_fs_attrs[] = {
&dev_attr_tp.attr,
&dev_attr_min_level_change.attr,
+ &dev_attr_srm_updated.attr,
NULL
};
diff --git a/include/linux/hdcp_qseecom.h b/include/linux/hdcp_qseecom.h
index dc513fbab580..8e1b853e738e 100644
--- a/include/linux/hdcp_qseecom.h
+++ b/include/linux/hdcp_qseecom.h
@@ -126,6 +126,7 @@ struct hdcp_txmtr_ops {
struct hdcp_client_ops {
int (*wakeup)(struct hdmi_hdcp_wakeup_data *data);
void (*notify_lvl_change)(void *client_ctx, int min_lvl);
+ void (*srm_cb)(void *client_ctx);
};
enum hdcp_device_type {