Loading drivers/gpu/drm/msm/sde_hdcp_1x.c +28 −35 Original line number Diff line number Diff line Loading @@ -210,6 +210,7 @@ struct sde_hdcp_1x { u8 bcaps; u32 tp_msgid; u32 an_0, an_1, aksv_0, aksv_1; u32 aksv_msb, aksv_lsb; bool sink_r0_ready; bool reauth; bool ksv_ready; Loading Loading @@ -237,11 +238,9 @@ static int sde_hdcp_1x_count_one(u8 *array, u8 len) return count; } static int sde_hdcp_1x_load_keys(void *input) static int sde_hdcp_1x_enable_hdcp_engine(void *input) { int rc = 0; u32 aksv_lsb, aksv_msb; u8 aksv[5]; struct dss_io_data *dp_ahb; struct dss_io_data *dp_aux; struct dss_io_data *dp_link; Loading Loading @@ -269,30 +268,8 @@ static int sde_hdcp_1x_load_keys(void *input) dp_link = hdcp->init_data.dp_link; reg_set = &hdcp->reg_set; if (hdcp1_set_keys(hdcp->hdcp1_handle, &aksv_msb, &aksv_lsb)) { pr_err("setting hdcp SW keys failed\n"); rc = -EINVAL; goto end; } pr_debug("%s: AKSV=%02x%08x\n", SDE_HDCP_STATE_NAME, aksv_msb, aksv_lsb); aksv[0] = aksv_lsb & 0xFF; aksv[1] = (aksv_lsb >> 8) & 0xFF; aksv[2] = (aksv_lsb >> 16) & 0xFF; aksv[3] = (aksv_lsb >> 24) & 0xFF; aksv[4] = aksv_msb & 0xFF; /* check there are 20 ones in AKSV */ if (sde_hdcp_1x_count_one(aksv, 5) != 20) { pr_err("AKSV bit count failed\n"); rc = -EINVAL; goto end; } DSS_REG_W(dp_aux, reg_set->aksv_lsb, aksv_lsb); DSS_REG_W(dp_aux, reg_set->aksv_msb, aksv_msb); DSS_REG_W(dp_aux, reg_set->aksv_lsb, hdcp->aksv_lsb); DSS_REG_W(dp_aux, reg_set->aksv_msb, hdcp->aksv_msb); /* Setup seed values for random number An */ DSS_REG_W(dp_link, reg_set->entropy_ctrl0, 0xB1FFB0FF); Loading Loading @@ -1142,20 +1119,29 @@ static void sde_hdcp_1x_auth_work(struct work_struct *work) static int sde_hdcp_1x_authenticate(void *input) { struct sde_hdcp_1x *hdcp = (struct sde_hdcp_1x *)input; int rc = 0; if (!hdcp) { pr_err("invalid input\n"); return -EINVAL; rc = -EINVAL; goto error; } flush_delayed_work(&hdcp->hdcp_auth_work); if (!sde_hdcp_1x_state(HDCP_STATE_INACTIVE)) { pr_err("invalid state\n"); return -EINVAL; rc = -EINVAL; goto error; } rc = hdcp1_start(hdcp->hdcp1_handle, &hdcp->aksv_msb, &hdcp->aksv_lsb); if (rc) { pr_err("hdcp1_start failed (%d)\n", rc); goto error; } if (!sde_hdcp_1x_load_keys(input)) { if (!sde_hdcp_1x_enable_hdcp_engine(input)) { queue_delayed_work(hdcp->workq, &hdcp->hdcp_auth_work, HZ/2); Loading @@ -1164,7 +1150,8 @@ static int sde_hdcp_1x_authenticate(void *input) sde_hdcp_1x_update_auth_status(hdcp); } return 0; error: return rc; } /* hdcp_1x_authenticate */ static int sde_hdcp_1x_reauthenticate(void *input) Loading @@ -1173,7 +1160,7 @@ static int sde_hdcp_1x_reauthenticate(void *input) struct dss_io_data *io; struct sde_hdcp_reg_set *reg_set; struct sde_hdcp_int_set *isr; u32 ret = 0, reg; u32 reg; if (!hdcp || !hdcp->init_data.dp_ahb) { pr_err("invalid input\n"); Loading Loading @@ -1201,9 +1188,8 @@ static int sde_hdcp_1x_reauthenticate(void *input) DSS_REG_W(io, reg_set->reset, reg & ~reg_set->reset_bit); hdcp->hdcp_state = HDCP_STATE_INACTIVE; sde_hdcp_1x_authenticate(hdcp); return ret; return sde_hdcp_1x_authenticate(hdcp); } /* hdcp_1x_reauthenticate */ static void sde_hdcp_1x_off(void *input) Loading Loading @@ -1264,6 +1250,8 @@ static void sde_hdcp_1x_off(void *input) hdcp->sink_r0_ready = false; hdcp1_stop(hdcp->hdcp1_handle); pr_debug("%s: HDCP: Off\n", SDE_HDCP_STATE_NAME); } /* hdcp_1x_off */ Loading Loading @@ -1365,13 +1353,18 @@ static int sde_hdcp_1x_isr(void *input) static bool sde_hdcp_1x_feature_supported(void *input) { struct sde_hdcp_1x *hdcp = (struct sde_hdcp_1x *)input; bool feature_supported = false; if (!hdcp) { pr_err("invalid input\n"); return -EINVAL; } return hdcp1_feature_supported(hdcp->hdcp1_handle); feature_supported = hdcp1_feature_supported(hdcp->hdcp1_handle); pr_debug("feature_supported = %d\n", feature_supported); return feature_supported; } void sde_hdcp_1x_deinit(void *input) Loading drivers/misc/hdcp_qseecom.c +285 −39 Original line number Diff line number Diff line Loading @@ -10,7 +10,7 @@ * GNU General Public License for more details. */ #define pr_fmt(fmt) "%s: " fmt, __func__ #define pr_fmt(fmt) "[hdcp-qseecom] %s: " fmt, __func__ #include <linux/kernel.h> #include <linux/slab.h> Loading Loading @@ -44,6 +44,7 @@ #define HDCP1_AKSV_SIZE 8 #define HDCP1_SET_KEY 202 #define HDCP1_KEY_VERIFY 204 #define HDCP1_SET_ENC 205 #define BITS_8_IN_BYTES 1 Loading Loading @@ -213,6 +214,7 @@ enum { hdcp_cmd_init = SERVICE_CREATE_CMD(11), hdcp_cmd_deinit = SERVICE_CREATE_CMD(12), hdcp_cmd_version = SERVICE_CREATE_CMD(14), hdcp_cmd_verify_key = SERVICE_CREATE_CMD(15), hdcp_cmd_session_init = SERVICE_CREATE_CMD(16), hdcp_cmd_session_deinit = SERVICE_CREATE_CMD(17), hdcp_cmd_start_auth = SERVICE_CREATE_CMD(18), Loading Loading @@ -271,6 +273,25 @@ struct __attribute__ ((__packed__)) hdcp_version_rsp { uint32_t appversion; }; struct __attribute__ ((__packed__)) hdcp_verify_key_req { uint32_t commandid; }; struct __attribute__ ((__packed__)) hdcp_verify_key_rsp { uint32_t status; uint32_t commandId; }; struct __attribute__ ((__packed__)) hdcp1_key_verify_req { uint32_t commandid; uint32_t key_type; }; struct __attribute__ ((__packed__)) hdcp1_key_verify_rsp { uint32_t commandId; uint32_t ret; }; struct __attribute__ ((__packed__)) hdcp_init_v1_req { uint32_t commandid; }; Loading Loading @@ -509,6 +530,7 @@ struct hdcp2_handle { uint32_t session_id; bool legacy_app; uint32_t device_type; char *app_name; int (*app_init)(struct hdcp2_handle *handle); int (*tx_init)(struct hdcp2_handle *handle); Loading @@ -524,6 +546,8 @@ struct hdcp1_handle { struct qseecom_handle *qseecom_handle; bool feature_supported; uint32_t device_type; enum hdcp_state hdcp_state; char *app_name; }; #define HDCP_CMD_STATUS_TO_STR(x) #x Loading Loading @@ -715,12 +739,12 @@ static int hdcp2_app_load(struct hdcp2_handle *handle) } if (handle->hdcp_state & HDCP_STATE_APP_LOADED) { pr_err("library already loaded\n"); pr_err("%s app already loaded\n", handle->app_name); goto error; } rc = qseecom_start_app(&handle->qseecom_handle, HDCP2P2_APP_NAME, QSEECOM_SBUFF_SIZE); handle->app_name, QSEECOM_SBUFF_SIZE); if (rc) { pr_err("qseecom_start_app failed for HDCP2P2 (%d)\n", rc); goto error; Loading Loading @@ -787,7 +811,7 @@ static int hdcp2_app_unload(struct hdcp2_handle *handle) } handle->hdcp_state &= ~HDCP_STATE_APP_LOADED; pr_debug("success\n"); pr_debug("%s app unloaded\n", handle->app_name); return rc; error: Loading @@ -795,6 +819,25 @@ static int hdcp2_app_unload(struct hdcp2_handle *handle) return rc; } static int hdcp2_verify_key(struct hdcp2_handle *handle) { int rc = 0; hdcp2_app_init_var(verify_key); if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) { pr_err("%s app not loaded\n", handle->app_name); rc = -EINVAL; goto error; } rc = hdcp2_app_process_cmd(verify_key); pr_debug("verify_key = %d\n", rc); error: return rc; } bool hdcp2_feature_supported(void *data) { int rc = 0; Loading @@ -814,13 +857,13 @@ bool hdcp2_feature_supported(void *data) rc = hdcp2_app_load(handle); if (!rc) { if (!hdcp2_verify_key(handle)) { pr_debug("HDCP 2.2 supported\n"); handle->feature_supported = true; hdcp2_app_unload(handle); supported = true; } hdcp2_app_unload(handle); } error: return supported; } Loading @@ -838,7 +881,7 @@ static int hdcp2_app_session_init(struct hdcp2_handle *handle) } if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) { pr_err("app not loaded\n"); pr_err("%s app not loaded\n", handle->app_name); rc = -EINVAL; goto error; } Loading Loading @@ -871,7 +914,7 @@ static int hdcp2_app_session_deinit(struct hdcp2_handle *handle) hdcp2_app_init_var(session_deinit); if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) { pr_err("app not loaded\n"); pr_err("%s app not loaded\n", handle->app_name); rc = -EINVAL; goto error; } Loading Loading @@ -901,7 +944,7 @@ static int hdcp2_app_tx_deinit(struct hdcp2_handle *handle) hdcp2_app_init_var(tx_deinit); if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) { pr_err("app not loaded\n"); pr_err("%s app not loaded\n", handle->app_name); rc = -EINVAL; goto error; } Loading Loading @@ -1214,6 +1257,7 @@ void *hdcp2_init(u32 device_type) goto error; handle->device_type = device_type; handle->app_name = HDCP2P2_APP_NAME; error: return handle; } Loading @@ -1229,6 +1273,11 @@ void *hdcp1_init(void) struct hdcp1_handle *handle = kzalloc(sizeof(struct hdcp1_handle), GFP_KERNEL); if (!handle) goto error; handle->app_name = HDCP1_APP_NAME; error: return handle; } Loading @@ -1237,43 +1286,45 @@ void hdcp1_deinit(void *data) kfree(data); } bool hdcp1_feature_supported(void *data) static int hdcp1_count_ones(u8 *array, u8 len) { int rc = 0; bool supported = false; struct hdcp1_handle *handle = data; int i, j, count = 0; if (!handle) { pr_err("invalid input\n"); goto error; for (i = 0; i < len; i++) for (j = 0; j < 8; j++) count += (((array[i] >> j) & 0x1) ? 1 : 0); return count; } if (handle->feature_supported) { supported = true; goto error; } static int hdcp1_validate_aksv(u32 aksv_msb, u32 aksv_lsb) { int const number_of_ones = 20; u8 aksv[5]; rc = qseecom_start_app(&handle->qseecom_handle, HDCP1_APP_NAME, QSEECOM_SBUFF_SIZE); if (rc) { pr_err("qseecom_start_app failed %d\n", rc); goto error; pr_debug("AKSV=%02x%08x\n", aksv_msb, aksv_lsb); aksv[0] = aksv_lsb & 0xFF; aksv[1] = (aksv_lsb >> 8) & 0xFF; aksv[2] = (aksv_lsb >> 16) & 0xFF; aksv[3] = (aksv_lsb >> 24) & 0xFF; aksv[4] = aksv_msb & 0xFF; /* check there are 20 ones in AKSV */ if (hdcp1_count_ones(aksv, 5) != number_of_ones) { pr_err("AKSV bit count failed\n"); return -EINVAL; } pr_debug("HDCP 1.x supported\n"); handle->feature_supported = true; supported = true; error: return supported; return 0; } /* APIs exposed to all clients */ int hdcp1_set_keys(void *data, uint32_t *aksv_msb, uint32_t *aksv_lsb) static int hdcp1_set_key(struct hdcp1_handle *hdcp1_handle, u32 *aksv_msb, u32 *aksv_lsb) { int rc = 0; struct hdcp1_key_set_req *key_set_req; struct hdcp1_key_set_rsp *key_set_rsp; struct hdcp1_handle *hdcp1_handle = data; struct qseecom_handle *handle = NULL; if (aksv_msb == NULL || aksv_lsb == NULL) { Loading @@ -1286,8 +1337,8 @@ int hdcp1_set_keys(void *data, uint32_t *aksv_msb, uint32_t *aksv_lsb) return -EINVAL; } if (!hdcp1_handle->feature_supported) { pr_err("HDCP 1.x not supported\n"); if (!(hdcp1_handle->hdcp_state & HDCP_STATE_APP_LOADED)) { pr_err("%s app not loaded\n", hdcp1_handle->app_name); return -EINVAL; } Loading Loading @@ -1322,9 +1373,138 @@ int hdcp1_set_keys(void *data, uint32_t *aksv_msb, uint32_t *aksv_lsb) *aksv_lsb = key_set_rsp->ksv[4] << 24 | key_set_rsp->ksv[5] << 16 | key_set_rsp->ksv[6] << 8 | key_set_rsp->ksv[7]; rc = hdcp1_validate_aksv(*aksv_msb, *aksv_lsb); if (rc) { pr_err("aksv validation failed (%d)\n", rc); return rc; } return 0; } static int hdcp1_app_load(struct hdcp1_handle *handle) { int rc = 0; if (!handle) { pr_err("invalid handle\n"); goto error; } rc = qseecom_start_app(&handle->qseecom_handle, handle->app_name, QSEECOM_SBUFF_SIZE); if (rc) { pr_err("%s app load failed (%d)\n", handle->app_name, rc); goto error; } handle->hdcp_state |= HDCP_STATE_APP_LOADED; pr_debug("%s app loaded\n", handle->app_name); error: return rc; } static void hdcp1_app_unload(struct hdcp1_handle *handle) { int rc = 0; if (!handle || !handle->qseecom_handle) { pr_err("invalid handle\n"); return; } if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) { pr_warn("%s app not loaded\n", handle->app_name); return; } /* deallocate the resources for qseecom HDCP 1.x handle */ rc = qseecom_shutdown_app(&handle->qseecom_handle); if (rc) { pr_err("%s app unload failed (%d)\n", handle->app_name, rc); return; } handle->hdcp_state &= ~HDCP_STATE_APP_LOADED; pr_debug("%s app unloaded\n", handle->app_name); } static int hdcp1_verify_key(struct hdcp1_handle *hdcp1_handle) { int rc = 0; struct hdcp1_key_verify_req *key_verify_req; struct hdcp1_key_verify_rsp *key_verify_rsp; struct qseecom_handle *handle = NULL; if (!hdcp1_handle || !hdcp1_handle->qseecom_handle) { pr_err("invalid HDCP 1.x handle\n"); return -EINVAL; } if (!(hdcp1_handle->hdcp_state & HDCP_STATE_APP_LOADED)) { pr_err("%s app not loaded\n", hdcp1_handle->app_name); return -EINVAL; } handle = hdcp1_handle->qseecom_handle; key_verify_req = (struct hdcp1_key_verify_req *)handle->sbuf; key_verify_req->commandid = HDCP1_KEY_VERIFY; key_verify_rsp = (struct hdcp1_key_verify_rsp *)(handle->sbuf + QSEECOM_ALIGN(sizeof(struct hdcp1_key_verify_req))); rc = qseecom_send_command(handle, key_verify_req, QSEECOM_ALIGN(sizeof (struct hdcp1_key_verify_req)), key_verify_rsp, QSEECOM_ALIGN(sizeof (struct hdcp1_key_set_rsp))); if (rc < 0) { pr_err("command HDCP1_KEY_VERIFY failed (%d)\n", rc); return -EINVAL; } rc = key_verify_rsp->ret; if (rc) { pr_err("key_verify failed, rsp=%d\n", key_verify_rsp->ret); return -EINVAL; } pr_debug("success\n"); return 0; } bool hdcp1_feature_supported(void *data) { bool supported = false; struct hdcp1_handle *handle = data; int rc = 0; if (!handle) { pr_err("invalid handle\n"); goto error; } if (handle->feature_supported) { supported = true; goto error; } rc = hdcp1_app_load(handle); if (!rc && (handle->hdcp_state & HDCP_STATE_APP_LOADED)) { if (!hdcp1_verify_key(handle)) { pr_debug("HDCP 1.x supported\n"); handle->feature_supported = true; supported = true; } hdcp1_app_unload(handle); } error: return supported; } int hdcp1_set_enc(void *data, bool enable) { int rc = 0; Loading @@ -1343,6 +1523,11 @@ int hdcp1_set_enc(void *data, bool enable) return -EINVAL; } if (!(hdcp1_handle->hdcp_state & HDCP_STATE_APP_LOADED)) { pr_err("%s app not loaded\n", hdcp1_handle->app_name); return -EINVAL; } handle = hdcp1_handle->qseecom_handle; /* set keys and request aksv */ Loading Loading @@ -1373,3 +1558,64 @@ int hdcp1_set_enc(void *data, bool enable) return 0; } int hdcp1_start(void *data, u32 *aksv_msb, u32 *aksv_lsb) { int rc = 0; struct hdcp1_handle *hdcp1_handle = data; if (!aksv_msb || !aksv_lsb) { pr_err("invalid aksv output buffer\n"); rc = -EINVAL; goto error; } if (!hdcp1_handle) { pr_err("invalid handle\n"); rc = -EINVAL; goto error; } if (!hdcp1_handle->feature_supported) { pr_err("feature not supported\n"); rc = -EINVAL; goto error; } if (hdcp1_handle->hdcp_state & HDCP_STATE_APP_LOADED) { pr_debug("%s app already loaded\n", hdcp1_handle->app_name); goto error; } rc = hdcp1_app_load(hdcp1_handle); if (rc) goto error; rc = hdcp1_set_key(hdcp1_handle, aksv_msb, aksv_lsb); if (rc) goto key_error; pr_debug("success\n"); return rc; key_error: hdcp1_app_unload(hdcp1_handle); error: return rc; } void hdcp1_stop(void *data) { struct hdcp1_handle *hdcp1_handle = data; if (!hdcp1_handle || !hdcp1_handle->qseecom_handle) { pr_err("invalid handle\n"); return; } if (!(hdcp1_handle->hdcp_state & HDCP_STATE_APP_LOADED)) { pr_debug("%s app not loaded\n", hdcp1_handle->app_name); return; } hdcp1_app_unload(hdcp1_handle); } include/linux/hdcp_qseecom.h +7 −3 Original line number Diff line number Diff line Loading @@ -60,8 +60,9 @@ static inline const char *hdcp2_app_cmd_str(enum hdcp2_app_cmd cmd) void *hdcp1_init(void); void hdcp1_deinit(void *data); bool hdcp1_feature_supported(void *data); int hdcp1_set_keys(void *data, uint32_t *aksv_msb, uint32_t *aksv_lsb); int hdcp1_start(void *data, u32 *aksv_msb, u32 *aksv_lsb); int hdcp1_set_enc(void *data, bool enable); void hdcp1_stop(void *data); void *hdcp2_init(u32 device_type); void hdcp2_deinit(void *ctx); Loading @@ -84,8 +85,7 @@ static inline bool hdcp1_feature_supported(void *data) return false; } static inline int hdcp1_set_keys(void *data, uint32_t *aksv_msb, uint32_t *aksv_lsb) static inline int hdcp1_start(void *data, u32 *aksv_msb, u32 *aksv_lsb) { return 0; } Loading @@ -95,6 +95,10 @@ static inline int hdcp1_set_enc(void *data, bool enable) return 0; } static inline void hdcp1_stop(void *data) { } static inline void *hdcp2_init(u32 device_type) { return NULL; Loading Loading
drivers/gpu/drm/msm/sde_hdcp_1x.c +28 −35 Original line number Diff line number Diff line Loading @@ -210,6 +210,7 @@ struct sde_hdcp_1x { u8 bcaps; u32 tp_msgid; u32 an_0, an_1, aksv_0, aksv_1; u32 aksv_msb, aksv_lsb; bool sink_r0_ready; bool reauth; bool ksv_ready; Loading Loading @@ -237,11 +238,9 @@ static int sde_hdcp_1x_count_one(u8 *array, u8 len) return count; } static int sde_hdcp_1x_load_keys(void *input) static int sde_hdcp_1x_enable_hdcp_engine(void *input) { int rc = 0; u32 aksv_lsb, aksv_msb; u8 aksv[5]; struct dss_io_data *dp_ahb; struct dss_io_data *dp_aux; struct dss_io_data *dp_link; Loading Loading @@ -269,30 +268,8 @@ static int sde_hdcp_1x_load_keys(void *input) dp_link = hdcp->init_data.dp_link; reg_set = &hdcp->reg_set; if (hdcp1_set_keys(hdcp->hdcp1_handle, &aksv_msb, &aksv_lsb)) { pr_err("setting hdcp SW keys failed\n"); rc = -EINVAL; goto end; } pr_debug("%s: AKSV=%02x%08x\n", SDE_HDCP_STATE_NAME, aksv_msb, aksv_lsb); aksv[0] = aksv_lsb & 0xFF; aksv[1] = (aksv_lsb >> 8) & 0xFF; aksv[2] = (aksv_lsb >> 16) & 0xFF; aksv[3] = (aksv_lsb >> 24) & 0xFF; aksv[4] = aksv_msb & 0xFF; /* check there are 20 ones in AKSV */ if (sde_hdcp_1x_count_one(aksv, 5) != 20) { pr_err("AKSV bit count failed\n"); rc = -EINVAL; goto end; } DSS_REG_W(dp_aux, reg_set->aksv_lsb, aksv_lsb); DSS_REG_W(dp_aux, reg_set->aksv_msb, aksv_msb); DSS_REG_W(dp_aux, reg_set->aksv_lsb, hdcp->aksv_lsb); DSS_REG_W(dp_aux, reg_set->aksv_msb, hdcp->aksv_msb); /* Setup seed values for random number An */ DSS_REG_W(dp_link, reg_set->entropy_ctrl0, 0xB1FFB0FF); Loading Loading @@ -1142,20 +1119,29 @@ static void sde_hdcp_1x_auth_work(struct work_struct *work) static int sde_hdcp_1x_authenticate(void *input) { struct sde_hdcp_1x *hdcp = (struct sde_hdcp_1x *)input; int rc = 0; if (!hdcp) { pr_err("invalid input\n"); return -EINVAL; rc = -EINVAL; goto error; } flush_delayed_work(&hdcp->hdcp_auth_work); if (!sde_hdcp_1x_state(HDCP_STATE_INACTIVE)) { pr_err("invalid state\n"); return -EINVAL; rc = -EINVAL; goto error; } rc = hdcp1_start(hdcp->hdcp1_handle, &hdcp->aksv_msb, &hdcp->aksv_lsb); if (rc) { pr_err("hdcp1_start failed (%d)\n", rc); goto error; } if (!sde_hdcp_1x_load_keys(input)) { if (!sde_hdcp_1x_enable_hdcp_engine(input)) { queue_delayed_work(hdcp->workq, &hdcp->hdcp_auth_work, HZ/2); Loading @@ -1164,7 +1150,8 @@ static int sde_hdcp_1x_authenticate(void *input) sde_hdcp_1x_update_auth_status(hdcp); } return 0; error: return rc; } /* hdcp_1x_authenticate */ static int sde_hdcp_1x_reauthenticate(void *input) Loading @@ -1173,7 +1160,7 @@ static int sde_hdcp_1x_reauthenticate(void *input) struct dss_io_data *io; struct sde_hdcp_reg_set *reg_set; struct sde_hdcp_int_set *isr; u32 ret = 0, reg; u32 reg; if (!hdcp || !hdcp->init_data.dp_ahb) { pr_err("invalid input\n"); Loading Loading @@ -1201,9 +1188,8 @@ static int sde_hdcp_1x_reauthenticate(void *input) DSS_REG_W(io, reg_set->reset, reg & ~reg_set->reset_bit); hdcp->hdcp_state = HDCP_STATE_INACTIVE; sde_hdcp_1x_authenticate(hdcp); return ret; return sde_hdcp_1x_authenticate(hdcp); } /* hdcp_1x_reauthenticate */ static void sde_hdcp_1x_off(void *input) Loading Loading @@ -1264,6 +1250,8 @@ static void sde_hdcp_1x_off(void *input) hdcp->sink_r0_ready = false; hdcp1_stop(hdcp->hdcp1_handle); pr_debug("%s: HDCP: Off\n", SDE_HDCP_STATE_NAME); } /* hdcp_1x_off */ Loading Loading @@ -1365,13 +1353,18 @@ static int sde_hdcp_1x_isr(void *input) static bool sde_hdcp_1x_feature_supported(void *input) { struct sde_hdcp_1x *hdcp = (struct sde_hdcp_1x *)input; bool feature_supported = false; if (!hdcp) { pr_err("invalid input\n"); return -EINVAL; } return hdcp1_feature_supported(hdcp->hdcp1_handle); feature_supported = hdcp1_feature_supported(hdcp->hdcp1_handle); pr_debug("feature_supported = %d\n", feature_supported); return feature_supported; } void sde_hdcp_1x_deinit(void *input) Loading
drivers/misc/hdcp_qseecom.c +285 −39 Original line number Diff line number Diff line Loading @@ -10,7 +10,7 @@ * GNU General Public License for more details. */ #define pr_fmt(fmt) "%s: " fmt, __func__ #define pr_fmt(fmt) "[hdcp-qseecom] %s: " fmt, __func__ #include <linux/kernel.h> #include <linux/slab.h> Loading Loading @@ -44,6 +44,7 @@ #define HDCP1_AKSV_SIZE 8 #define HDCP1_SET_KEY 202 #define HDCP1_KEY_VERIFY 204 #define HDCP1_SET_ENC 205 #define BITS_8_IN_BYTES 1 Loading Loading @@ -213,6 +214,7 @@ enum { hdcp_cmd_init = SERVICE_CREATE_CMD(11), hdcp_cmd_deinit = SERVICE_CREATE_CMD(12), hdcp_cmd_version = SERVICE_CREATE_CMD(14), hdcp_cmd_verify_key = SERVICE_CREATE_CMD(15), hdcp_cmd_session_init = SERVICE_CREATE_CMD(16), hdcp_cmd_session_deinit = SERVICE_CREATE_CMD(17), hdcp_cmd_start_auth = SERVICE_CREATE_CMD(18), Loading Loading @@ -271,6 +273,25 @@ struct __attribute__ ((__packed__)) hdcp_version_rsp { uint32_t appversion; }; struct __attribute__ ((__packed__)) hdcp_verify_key_req { uint32_t commandid; }; struct __attribute__ ((__packed__)) hdcp_verify_key_rsp { uint32_t status; uint32_t commandId; }; struct __attribute__ ((__packed__)) hdcp1_key_verify_req { uint32_t commandid; uint32_t key_type; }; struct __attribute__ ((__packed__)) hdcp1_key_verify_rsp { uint32_t commandId; uint32_t ret; }; struct __attribute__ ((__packed__)) hdcp_init_v1_req { uint32_t commandid; }; Loading Loading @@ -509,6 +530,7 @@ struct hdcp2_handle { uint32_t session_id; bool legacy_app; uint32_t device_type; char *app_name; int (*app_init)(struct hdcp2_handle *handle); int (*tx_init)(struct hdcp2_handle *handle); Loading @@ -524,6 +546,8 @@ struct hdcp1_handle { struct qseecom_handle *qseecom_handle; bool feature_supported; uint32_t device_type; enum hdcp_state hdcp_state; char *app_name; }; #define HDCP_CMD_STATUS_TO_STR(x) #x Loading Loading @@ -715,12 +739,12 @@ static int hdcp2_app_load(struct hdcp2_handle *handle) } if (handle->hdcp_state & HDCP_STATE_APP_LOADED) { pr_err("library already loaded\n"); pr_err("%s app already loaded\n", handle->app_name); goto error; } rc = qseecom_start_app(&handle->qseecom_handle, HDCP2P2_APP_NAME, QSEECOM_SBUFF_SIZE); handle->app_name, QSEECOM_SBUFF_SIZE); if (rc) { pr_err("qseecom_start_app failed for HDCP2P2 (%d)\n", rc); goto error; Loading Loading @@ -787,7 +811,7 @@ static int hdcp2_app_unload(struct hdcp2_handle *handle) } handle->hdcp_state &= ~HDCP_STATE_APP_LOADED; pr_debug("success\n"); pr_debug("%s app unloaded\n", handle->app_name); return rc; error: Loading @@ -795,6 +819,25 @@ static int hdcp2_app_unload(struct hdcp2_handle *handle) return rc; } static int hdcp2_verify_key(struct hdcp2_handle *handle) { int rc = 0; hdcp2_app_init_var(verify_key); if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) { pr_err("%s app not loaded\n", handle->app_name); rc = -EINVAL; goto error; } rc = hdcp2_app_process_cmd(verify_key); pr_debug("verify_key = %d\n", rc); error: return rc; } bool hdcp2_feature_supported(void *data) { int rc = 0; Loading @@ -814,13 +857,13 @@ bool hdcp2_feature_supported(void *data) rc = hdcp2_app_load(handle); if (!rc) { if (!hdcp2_verify_key(handle)) { pr_debug("HDCP 2.2 supported\n"); handle->feature_supported = true; hdcp2_app_unload(handle); supported = true; } hdcp2_app_unload(handle); } error: return supported; } Loading @@ -838,7 +881,7 @@ static int hdcp2_app_session_init(struct hdcp2_handle *handle) } if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) { pr_err("app not loaded\n"); pr_err("%s app not loaded\n", handle->app_name); rc = -EINVAL; goto error; } Loading Loading @@ -871,7 +914,7 @@ static int hdcp2_app_session_deinit(struct hdcp2_handle *handle) hdcp2_app_init_var(session_deinit); if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) { pr_err("app not loaded\n"); pr_err("%s app not loaded\n", handle->app_name); rc = -EINVAL; goto error; } Loading Loading @@ -901,7 +944,7 @@ static int hdcp2_app_tx_deinit(struct hdcp2_handle *handle) hdcp2_app_init_var(tx_deinit); if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) { pr_err("app not loaded\n"); pr_err("%s app not loaded\n", handle->app_name); rc = -EINVAL; goto error; } Loading Loading @@ -1214,6 +1257,7 @@ void *hdcp2_init(u32 device_type) goto error; handle->device_type = device_type; handle->app_name = HDCP2P2_APP_NAME; error: return handle; } Loading @@ -1229,6 +1273,11 @@ void *hdcp1_init(void) struct hdcp1_handle *handle = kzalloc(sizeof(struct hdcp1_handle), GFP_KERNEL); if (!handle) goto error; handle->app_name = HDCP1_APP_NAME; error: return handle; } Loading @@ -1237,43 +1286,45 @@ void hdcp1_deinit(void *data) kfree(data); } bool hdcp1_feature_supported(void *data) static int hdcp1_count_ones(u8 *array, u8 len) { int rc = 0; bool supported = false; struct hdcp1_handle *handle = data; int i, j, count = 0; if (!handle) { pr_err("invalid input\n"); goto error; for (i = 0; i < len; i++) for (j = 0; j < 8; j++) count += (((array[i] >> j) & 0x1) ? 1 : 0); return count; } if (handle->feature_supported) { supported = true; goto error; } static int hdcp1_validate_aksv(u32 aksv_msb, u32 aksv_lsb) { int const number_of_ones = 20; u8 aksv[5]; rc = qseecom_start_app(&handle->qseecom_handle, HDCP1_APP_NAME, QSEECOM_SBUFF_SIZE); if (rc) { pr_err("qseecom_start_app failed %d\n", rc); goto error; pr_debug("AKSV=%02x%08x\n", aksv_msb, aksv_lsb); aksv[0] = aksv_lsb & 0xFF; aksv[1] = (aksv_lsb >> 8) & 0xFF; aksv[2] = (aksv_lsb >> 16) & 0xFF; aksv[3] = (aksv_lsb >> 24) & 0xFF; aksv[4] = aksv_msb & 0xFF; /* check there are 20 ones in AKSV */ if (hdcp1_count_ones(aksv, 5) != number_of_ones) { pr_err("AKSV bit count failed\n"); return -EINVAL; } pr_debug("HDCP 1.x supported\n"); handle->feature_supported = true; supported = true; error: return supported; return 0; } /* APIs exposed to all clients */ int hdcp1_set_keys(void *data, uint32_t *aksv_msb, uint32_t *aksv_lsb) static int hdcp1_set_key(struct hdcp1_handle *hdcp1_handle, u32 *aksv_msb, u32 *aksv_lsb) { int rc = 0; struct hdcp1_key_set_req *key_set_req; struct hdcp1_key_set_rsp *key_set_rsp; struct hdcp1_handle *hdcp1_handle = data; struct qseecom_handle *handle = NULL; if (aksv_msb == NULL || aksv_lsb == NULL) { Loading @@ -1286,8 +1337,8 @@ int hdcp1_set_keys(void *data, uint32_t *aksv_msb, uint32_t *aksv_lsb) return -EINVAL; } if (!hdcp1_handle->feature_supported) { pr_err("HDCP 1.x not supported\n"); if (!(hdcp1_handle->hdcp_state & HDCP_STATE_APP_LOADED)) { pr_err("%s app not loaded\n", hdcp1_handle->app_name); return -EINVAL; } Loading Loading @@ -1322,9 +1373,138 @@ int hdcp1_set_keys(void *data, uint32_t *aksv_msb, uint32_t *aksv_lsb) *aksv_lsb = key_set_rsp->ksv[4] << 24 | key_set_rsp->ksv[5] << 16 | key_set_rsp->ksv[6] << 8 | key_set_rsp->ksv[7]; rc = hdcp1_validate_aksv(*aksv_msb, *aksv_lsb); if (rc) { pr_err("aksv validation failed (%d)\n", rc); return rc; } return 0; } static int hdcp1_app_load(struct hdcp1_handle *handle) { int rc = 0; if (!handle) { pr_err("invalid handle\n"); goto error; } rc = qseecom_start_app(&handle->qseecom_handle, handle->app_name, QSEECOM_SBUFF_SIZE); if (rc) { pr_err("%s app load failed (%d)\n", handle->app_name, rc); goto error; } handle->hdcp_state |= HDCP_STATE_APP_LOADED; pr_debug("%s app loaded\n", handle->app_name); error: return rc; } static void hdcp1_app_unload(struct hdcp1_handle *handle) { int rc = 0; if (!handle || !handle->qseecom_handle) { pr_err("invalid handle\n"); return; } if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) { pr_warn("%s app not loaded\n", handle->app_name); return; } /* deallocate the resources for qseecom HDCP 1.x handle */ rc = qseecom_shutdown_app(&handle->qseecom_handle); if (rc) { pr_err("%s app unload failed (%d)\n", handle->app_name, rc); return; } handle->hdcp_state &= ~HDCP_STATE_APP_LOADED; pr_debug("%s app unloaded\n", handle->app_name); } static int hdcp1_verify_key(struct hdcp1_handle *hdcp1_handle) { int rc = 0; struct hdcp1_key_verify_req *key_verify_req; struct hdcp1_key_verify_rsp *key_verify_rsp; struct qseecom_handle *handle = NULL; if (!hdcp1_handle || !hdcp1_handle->qseecom_handle) { pr_err("invalid HDCP 1.x handle\n"); return -EINVAL; } if (!(hdcp1_handle->hdcp_state & HDCP_STATE_APP_LOADED)) { pr_err("%s app not loaded\n", hdcp1_handle->app_name); return -EINVAL; } handle = hdcp1_handle->qseecom_handle; key_verify_req = (struct hdcp1_key_verify_req *)handle->sbuf; key_verify_req->commandid = HDCP1_KEY_VERIFY; key_verify_rsp = (struct hdcp1_key_verify_rsp *)(handle->sbuf + QSEECOM_ALIGN(sizeof(struct hdcp1_key_verify_req))); rc = qseecom_send_command(handle, key_verify_req, QSEECOM_ALIGN(sizeof (struct hdcp1_key_verify_req)), key_verify_rsp, QSEECOM_ALIGN(sizeof (struct hdcp1_key_set_rsp))); if (rc < 0) { pr_err("command HDCP1_KEY_VERIFY failed (%d)\n", rc); return -EINVAL; } rc = key_verify_rsp->ret; if (rc) { pr_err("key_verify failed, rsp=%d\n", key_verify_rsp->ret); return -EINVAL; } pr_debug("success\n"); return 0; } bool hdcp1_feature_supported(void *data) { bool supported = false; struct hdcp1_handle *handle = data; int rc = 0; if (!handle) { pr_err("invalid handle\n"); goto error; } if (handle->feature_supported) { supported = true; goto error; } rc = hdcp1_app_load(handle); if (!rc && (handle->hdcp_state & HDCP_STATE_APP_LOADED)) { if (!hdcp1_verify_key(handle)) { pr_debug("HDCP 1.x supported\n"); handle->feature_supported = true; supported = true; } hdcp1_app_unload(handle); } error: return supported; } int hdcp1_set_enc(void *data, bool enable) { int rc = 0; Loading @@ -1343,6 +1523,11 @@ int hdcp1_set_enc(void *data, bool enable) return -EINVAL; } if (!(hdcp1_handle->hdcp_state & HDCP_STATE_APP_LOADED)) { pr_err("%s app not loaded\n", hdcp1_handle->app_name); return -EINVAL; } handle = hdcp1_handle->qseecom_handle; /* set keys and request aksv */ Loading Loading @@ -1373,3 +1558,64 @@ int hdcp1_set_enc(void *data, bool enable) return 0; } int hdcp1_start(void *data, u32 *aksv_msb, u32 *aksv_lsb) { int rc = 0; struct hdcp1_handle *hdcp1_handle = data; if (!aksv_msb || !aksv_lsb) { pr_err("invalid aksv output buffer\n"); rc = -EINVAL; goto error; } if (!hdcp1_handle) { pr_err("invalid handle\n"); rc = -EINVAL; goto error; } if (!hdcp1_handle->feature_supported) { pr_err("feature not supported\n"); rc = -EINVAL; goto error; } if (hdcp1_handle->hdcp_state & HDCP_STATE_APP_LOADED) { pr_debug("%s app already loaded\n", hdcp1_handle->app_name); goto error; } rc = hdcp1_app_load(hdcp1_handle); if (rc) goto error; rc = hdcp1_set_key(hdcp1_handle, aksv_msb, aksv_lsb); if (rc) goto key_error; pr_debug("success\n"); return rc; key_error: hdcp1_app_unload(hdcp1_handle); error: return rc; } void hdcp1_stop(void *data) { struct hdcp1_handle *hdcp1_handle = data; if (!hdcp1_handle || !hdcp1_handle->qseecom_handle) { pr_err("invalid handle\n"); return; } if (!(hdcp1_handle->hdcp_state & HDCP_STATE_APP_LOADED)) { pr_debug("%s app not loaded\n", hdcp1_handle->app_name); return; } hdcp1_app_unload(hdcp1_handle); }
include/linux/hdcp_qseecom.h +7 −3 Original line number Diff line number Diff line Loading @@ -60,8 +60,9 @@ static inline const char *hdcp2_app_cmd_str(enum hdcp2_app_cmd cmd) void *hdcp1_init(void); void hdcp1_deinit(void *data); bool hdcp1_feature_supported(void *data); int hdcp1_set_keys(void *data, uint32_t *aksv_msb, uint32_t *aksv_lsb); int hdcp1_start(void *data, u32 *aksv_msb, u32 *aksv_lsb); int hdcp1_set_enc(void *data, bool enable); void hdcp1_stop(void *data); void *hdcp2_init(u32 device_type); void hdcp2_deinit(void *ctx); Loading @@ -84,8 +85,7 @@ static inline bool hdcp1_feature_supported(void *data) return false; } static inline int hdcp1_set_keys(void *data, uint32_t *aksv_msb, uint32_t *aksv_lsb) static inline int hdcp1_start(void *data, u32 *aksv_msb, u32 *aksv_lsb) { return 0; } Loading @@ -95,6 +95,10 @@ static inline int hdcp1_set_enc(void *data, bool enable) return 0; } static inline void hdcp1_stop(void *data) { } static inline void *hdcp2_init(u32 device_type) { return NULL; Loading