diff --git a/drivers/misc/hdcp.c b/drivers/misc/hdcp.c index b6675fcbaaaa..66b1135fe855 100644 --- a/drivers/misc/hdcp.c +++ b/drivers/misc/hdcp.c @@ -126,11 +126,12 @@ /*This API calls the library deinit function */ #define HDCP_LIB_DEINIT SERVICE_TXMTR_CREATE_CMD(12) -enum hdcp_app_status { - LOADED, - UNLOADED, - FAILED = -1, -}; +#define HDCP_LIB_EXECUTE(x) {\ + if (handle->tethered)\ + hdcp_lib_##x(handle);\ + else\ + queue_kthread_work(&handle->worker, &handle->wk_##x);\ +} enum hdcp_state { HDCP_STATE_INIT = 0x00, @@ -337,12 +338,12 @@ struct hdcp_lib_handle { bool feature_supported; void *client_ctx; struct hdcp_client_ops *client_ops; - struct mutex hdcp_lock; struct mutex msg_lock; struct mutex wakeup_mutex; enum hdcp_state hdcp_state; enum hdcp_lib_wakeup_cmd wakeup_cmd; bool repeater_flag; + bool tethered; struct qseecom_handle *qseecom_handle; int last_msg_sent; char *last_msg_recvd_buf; @@ -353,13 +354,13 @@ struct hdcp_lib_handle { struct completion topo_wait; struct kthread_worker worker; - struct kthread_work init; - struct kthread_work msg_sent; - struct kthread_work msg_recvd; - struct kthread_work timeout; - struct kthread_work clean; - struct kthread_work topology; - struct kthread_work stream; + struct kthread_work wk_init; + struct kthread_work wk_msg_sent; + struct kthread_work wk_msg_recvd; + struct kthread_work wk_timeout; + struct kthread_work wk_clean; + struct kthread_work wk_topology; + struct kthread_work wk_stream; }; struct hdcp_lib_message_map { @@ -367,6 +368,13 @@ struct hdcp_lib_message_map { const char *msg_name; }; +static void hdcp_lib_clean(struct hdcp_lib_handle *handle); +static void hdcp_lib_init(struct hdcp_lib_handle *handle); +static void hdcp_lib_msg_sent(struct hdcp_lib_handle *handle); +static void hdcp_lib_msg_recvd(struct hdcp_lib_handle *handle); +static void hdcp_lib_timeout(struct hdcp_lib_handle *handle); +static void hdcp_lib_stream(struct hdcp_lib_handle *handle); + static struct qseecom_handle *hdcp1_handle; static bool hdcp1_supported = true; @@ -467,7 +475,7 @@ static int hdcp_lib_enable_encryption(struct hdcp_lib_handle *handle) return 0; error: if (!atomic_read(&handle->hdcp_off)) - queue_kthread_work(&handle->worker, &handle->clean); + HDCP_LIB_EXECUTE(clean); return rc; } @@ -678,21 +686,17 @@ exit: return rc; } -static void hdcp_lib_query_stream_type_work(struct kthread_work *work) +static void hdcp_lib_stream(struct hdcp_lib_handle *handle) { int rc = 0; struct hdcp_query_stream_type_req *req_buf; struct hdcp_query_stream_type_rsp *rsp_buf; - struct hdcp_lib_handle *handle = container_of(work, - struct hdcp_lib_handle, stream); if (!handle) { pr_err("invalid handle\n"); return; } - mutex_lock(&handle->hdcp_lock); - /* send command to TZ */ req_buf = (struct hdcp_query_stream_type_req *)handle-> qseecom_handle->sbuf; @@ -724,12 +728,18 @@ static void hdcp_lib_query_stream_type_work(struct kthread_work *work) handle->hdcp_timeout = rsp_buf->timeout; handle->msglen = rsp_buf->msglen; exit: - mutex_unlock(&handle->hdcp_lock); - if (!rc && !atomic_read(&handle->hdcp_off)) hdcp_lib_send_message(handle); } +static void hdcp_lib_query_stream_work(struct kthread_work *work) +{ + struct hdcp_lib_handle *handle = container_of(work, + struct hdcp_lib_handle, wk_stream); + + hdcp_lib_stream(handle); +} + static bool hdcp_lib_client_feature_supported(void *phdcpcontext) { int rc = 0; @@ -759,46 +769,46 @@ exit: static void hdcp_lib_check_worker_status(struct hdcp_lib_handle *handle) { - if (!list_empty(&handle->init.node)) + if (!list_empty(&handle->wk_init.node)) pr_debug("init work queued\n"); - if (handle->worker.current_work == &handle->init) + if (handle->worker.current_work == &handle->wk_init) pr_debug("init work executing\n"); - if (!list_empty(&handle->msg_sent.node)) + if (!list_empty(&handle->wk_msg_sent.node)) pr_debug("msg_sent work queued\n"); - if (handle->worker.current_work == &handle->msg_sent) + if (handle->worker.current_work == &handle->wk_msg_sent) pr_debug("msg_sent work executing\n"); - if (!list_empty(&handle->msg_recvd.node)) + if (!list_empty(&handle->wk_msg_recvd.node)) pr_debug("msg_recvd work queued\n"); - if (handle->worker.current_work == &handle->msg_recvd) + if (handle->worker.current_work == &handle->wk_msg_recvd) pr_debug("msg_recvd work executing\n"); - if (!list_empty(&handle->timeout.node)) + if (!list_empty(&handle->wk_timeout.node)) pr_debug("timeout work queued\n"); - if (handle->worker.current_work == &handle->timeout) + if (handle->worker.current_work == &handle->wk_timeout) pr_debug("timeout work executing\n"); - if (!list_empty(&handle->clean.node)) + if (!list_empty(&handle->wk_clean.node)) pr_debug("clean work queued\n"); - if (handle->worker.current_work == &handle->clean) + if (handle->worker.current_work == &handle->wk_clean) pr_debug("clean work executing\n"); - if (!list_empty(&handle->topology.node)) + if (!list_empty(&handle->wk_topology.node)) pr_debug("topology work queued\n"); - if (handle->worker.current_work == &handle->topology) + if (handle->worker.current_work == &handle->wk_topology) pr_debug("topology work executing\n"); - if (!list_empty(&handle->stream.node)) + if (!list_empty(&handle->wk_stream.node)) pr_debug("stream work queued\n"); - if (handle->worker.current_work == &handle->stream) + if (handle->worker.current_work == &handle->wk_stream) pr_debug("stream work executing\n"); } @@ -829,6 +839,28 @@ exit: return rc; } +static void hdcp_lib_update_exec_type(void *ctx, bool tethered) +{ + struct hdcp_lib_handle *handle = ctx; + + if (!handle) + return; + + mutex_lock(&handle->wakeup_mutex); + + if (handle->tethered == tethered) { + pr_debug("exec mode same as %s\n", + tethered ? "tethered" : "threaded"); + } else { + handle->tethered = tethered; + + pr_debug("exec mode changed to %s\n", + tethered ? "tethered" : "threaded"); + } + + mutex_unlock(&handle->wakeup_mutex); +} + static int hdcp_lib_wakeup(struct hdcp_lib_wakeup_data *data) { struct hdcp_lib_handle *handle; @@ -846,9 +878,9 @@ static int hdcp_lib_wakeup(struct hdcp_lib_wakeup_data *data) handle->wakeup_cmd = data->cmd; handle->timeout_left = data->timeout; - pr_debug("%s, timeout left: %dms\n", + pr_debug("%s, timeout left: %dms, tethered %d\n", hdcp_lib_cmd_to_str(handle->wakeup_cmd), - handle->timeout_left); + handle->timeout_left, handle->tethered); rc = hdcp_lib_check_valid_state(handle); if (rc) @@ -885,42 +917,42 @@ static int hdcp_lib_wakeup(struct hdcp_lib_wakeup_data *data) atomic_set(&handle->hdcp_off, 0); handle->hdcp_state = HDCP_STATE_INIT; - queue_kthread_work(&handle->worker, &handle->init); + HDCP_LIB_EXECUTE(init); break; case HDCP_LIB_WKUP_CMD_STOP: atomic_set(&handle->hdcp_off, 1); - queue_kthread_work(&handle->worker, &handle->clean); + + HDCP_LIB_EXECUTE(clean); break; case HDCP_LIB_WKUP_CMD_MSG_SEND_SUCCESS: handle->last_msg_sent = handle->listener_buf[0]; - queue_kthread_work(&handle->worker, &handle->msg_sent); + HDCP_LIB_EXECUTE(msg_sent); break; case HDCP_LIB_WKUP_CMD_MSG_SEND_FAILED: case HDCP_LIB_WKUP_CMD_MSG_RECV_FAILED: - queue_kthread_work(&handle->worker, &handle->clean); + HDCP_LIB_EXECUTE(clean); break; case HDCP_LIB_WKUP_CMD_MSG_RECV_SUCCESS: - queue_kthread_work(&handle->worker, &handle->msg_recvd); + HDCP_LIB_EXECUTE(msg_recvd); break; case HDCP_LIB_WKUP_CMD_MSG_RECV_TIMEOUT: - queue_kthread_work(&handle->worker, &handle->timeout); + HDCP_LIB_EXECUTE(timeout); break; case HDCP_LIB_WKUP_CMD_QUERY_STREAM_TYPE: - queue_kthread_work(&handle->worker, &handle->stream); + HDCP_LIB_EXECUTE(stream); break; default: pr_err("invalid wakeup command %d\n", handle->wakeup_cmd); } exit: mutex_unlock(&handle->wakeup_mutex); + return rc; } -static void hdcp_lib_msg_sent_work(struct kthread_work *work) +static void hdcp_lib_msg_sent(struct hdcp_lib_handle *handle) { - struct hdcp_lib_handle *handle = container_of(work, - struct hdcp_lib_handle, msg_sent); struct hdmi_hdcp_wakeup_data cdata = {HDMI_HDCP_WKUP_CMD_INVALID}; if (!handle) { @@ -928,13 +960,6 @@ static void hdcp_lib_msg_sent_work(struct kthread_work *work) return; } - if (handle->wakeup_cmd != HDCP_LIB_WKUP_CMD_MSG_SEND_SUCCESS) { - pr_err("invalid wakeup command %d\n", handle->wakeup_cmd); - return; - } - - mutex_lock(&handle->hdcp_lock); - cdata.context = handle->client_ctx; switch (handle->last_msg_sent) { @@ -942,15 +967,15 @@ static void hdcp_lib_msg_sent_work(struct kthread_work *work) if (handle->repeater_flag) { if (!atomic_read(&handle->hdcp_off)) queue_kthread_work(&handle->worker, - &handle->topology); + &handle->wk_topology); } - if (!hdcp_lib_enable_encryption(handle)) + if (!hdcp_lib_enable_encryption(handle)) { cdata.cmd = HDMI_HDCP_WKUP_CMD_STATUS_SUCCESS; - else + } else { if (!atomic_read(&handle->hdcp_off)) - queue_kthread_work(&handle->worker, - &handle->clean); + HDCP_LIB_EXECUTE(clean); + } break; case REPEATER_AUTH_SEND_ACK_MESSAGE_ID: pr_debug("Repeater authentication successful\n"); @@ -960,72 +985,70 @@ static void hdcp_lib_msg_sent_work(struct kthread_work *work) cdata.timeout = handle->timeout_left; } - mutex_unlock(&handle->hdcp_lock); - hdcp_lib_wakeup_client(handle, &cdata); } +static void hdcp_lib_msg_sent_work(struct kthread_work *work) +{ + struct hdcp_lib_handle *handle = container_of(work, + struct hdcp_lib_handle, wk_msg_sent); + + if (handle->wakeup_cmd != HDCP_LIB_WKUP_CMD_MSG_SEND_SUCCESS) { + pr_err("invalid wakeup command %d\n", handle->wakeup_cmd); + return; + } + + hdcp_lib_msg_sent(handle); +} + +static void hdcp_lib_init(struct hdcp_lib_handle *handle) +{ + int rc = 0; + + if (!handle) { + pr_err("invalid handle\n"); + return; + } + + if (handle->wakeup_cmd != HDCP_LIB_WKUP_CMD_START) { + pr_err("invalid wakeup command %d\n", handle->wakeup_cmd); + return; + } + + rc = hdcp_lib_library_load(handle); + if (rc) + goto exit; + + rc = hdcp_lib_txmtr_init(handle); + if (rc) + goto exit; + + hdcp_lib_send_message(handle); + + return; +exit: + HDCP_LIB_EXECUTE(clean); +} + static void hdcp_lib_init_work(struct kthread_work *work) { - int rc = 0; - bool send_msg = false; struct hdcp_lib_handle *handle = container_of(work, - struct hdcp_lib_handle, init); + struct hdcp_lib_handle, wk_init); - if (!handle) { - pr_err("invalid handle\n"); - return; - } - - mutex_lock(&handle->hdcp_lock); - - if (handle->wakeup_cmd == HDCP_LIB_WKUP_CMD_START) { - rc = hdcp_lib_library_load(handle); - if (rc) - goto exit; - - rc = hdcp_lib_txmtr_init(handle); - if (rc) - goto exit; - - send_msg = true; - } else if (handle->wakeup_cmd == HDCP_LIB_WKUP_CMD_STOP) { - rc = hdcp_lib_txmtr_deinit(handle); - if (rc) - goto exit; - - rc = hdcp_lib_library_unload(handle); - if (rc) - goto exit; - } else { - pr_err("invalid wakeup cmd: %d\n", handle->wakeup_cmd); - } -exit: - mutex_unlock(&handle->hdcp_lock); - - if (send_msg) - hdcp_lib_send_message(handle); - - if (rc && !atomic_read(&handle->hdcp_off)) - queue_kthread_work(&handle->worker, &handle->clean); + hdcp_lib_init(handle); } -static void hdcp_lib_manage_timeout_work(struct kthread_work *work) +static void hdcp_lib_timeout(struct hdcp_lib_handle *handle) { int rc = 0; - bool send_msg = false; struct hdcp_send_timeout_req *req_buf; struct hdcp_send_timeout_rsp *rsp_buf; - struct hdcp_lib_handle *handle = container_of(work, - struct hdcp_lib_handle, timeout); if (!handle) { pr_err("invalid handle\n"); return; } - mutex_lock(&handle->hdcp_lock); - req_buf = (struct hdcp_send_timeout_req *) (handle->qseecom_handle->sbuf); req_buf->commandid = HDCP_TXMTR_SEND_MESSAGE_TIMEOUT; @@ -1068,23 +1091,24 @@ static void hdcp_lib_manage_timeout_work(struct kthread_work *work) handle->hdcp_timeout = rsp_buf->timeout; handle->msglen = rsp_buf->msglen; - send_msg = true; + hdcp_lib_send_message(handle); } } error: - mutex_unlock(&handle->hdcp_lock); - - if (send_msg) - hdcp_lib_send_message(handle); - - if (rc && !atomic_read(&handle->hdcp_off)) - queue_kthread_work(&handle->worker, &handle->clean); + if (!atomic_read(&handle->hdcp_off)) + HDCP_LIB_EXECUTE(clean); } -static void hdcp_lib_cleanup_work(struct kthread_work *work) +static void hdcp_lib_manage_timeout_work(struct kthread_work *work) { struct hdcp_lib_handle *handle = container_of(work, - struct hdcp_lib_handle, clean); + struct hdcp_lib_handle, wk_timeout); + + hdcp_lib_timeout(handle); +} + +static void hdcp_lib_clean(struct hdcp_lib_handle *handle) +{ struct hdmi_hdcp_wakeup_data cdata = {HDMI_HDCP_WKUP_CMD_INVALID}; if (!handle) { @@ -1092,15 +1116,11 @@ static void hdcp_lib_cleanup_work(struct kthread_work *work) return; }; - mutex_lock(&handle->hdcp_lock); - - cdata.context = handle->client_ctx; - cdata.cmd = HDMI_HDCP_WKUP_CMD_STATUS_FAILED; - hdcp_lib_txmtr_deinit(handle); hdcp_lib_library_unload(handle); - mutex_unlock(&handle->hdcp_lock); + cdata.context = handle->client_ctx; + cdata.cmd = HDMI_HDCP_WKUP_CMD_STATUS_FAILED; if (!atomic_read(&handle->hdcp_off)) hdcp_lib_wakeup_client(handle, &cdata); @@ -1108,23 +1128,29 @@ static void hdcp_lib_cleanup_work(struct kthread_work *work) atomic_set(&handle->hdcp_off, 1); } -static void hdcp_lib_msg_recvd_work(struct kthread_work *work) + +static void hdcp_lib_cleanup_work(struct kthread_work *work) +{ + struct hdcp_lib_handle *handle = container_of(work, + struct hdcp_lib_handle, wk_clean); + + hdcp_lib_clean(handle); +} + +static void hdcp_lib_msg_recvd(struct hdcp_lib_handle *handle) { int rc = 0; + struct hdmi_hdcp_wakeup_data cdata = {HDMI_HDCP_WKUP_CMD_INVALID}; struct hdcp_rcvd_msg_req *req_buf; struct hdcp_rcvd_msg_rsp *rsp_buf; uint32_t msglen; - char *msg = NULL; - struct hdcp_lib_handle *handle = container_of(work, - struct hdcp_lib_handle, msg_recvd); - struct hdmi_hdcp_wakeup_data cdata = {HDMI_HDCP_WKUP_CMD_INVALID}; + char *msg; if (!handle) { pr_err("invalid handle\n"); return; } - mutex_lock(&handle->hdcp_lock); cdata.context = handle->client_ctx; mutex_lock(&handle->msg_lock); @@ -1233,19 +1259,26 @@ static void hdcp_lib_msg_recvd_work(struct kthread_work *work) exit: kzfree(msg); - mutex_unlock(&handle->hdcp_lock); hdcp_lib_wakeup_client(handle, &cdata); if (rc && !atomic_read(&handle->hdcp_off)) - queue_kthread_work(&handle->worker, &handle->clean); + HDCP_LIB_EXECUTE(clean); +} + +static void hdcp_lib_msg_recvd_work(struct kthread_work *work) +{ + struct hdcp_lib_handle *handle = container_of(work, + struct hdcp_lib_handle, wk_msg_recvd); + + hdcp_lib_msg_recvd(handle); } 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 hdcp_lib_handle, wk_topology); if (!handle) { pr_err("invalid input\n"); @@ -1258,7 +1291,7 @@ static void hdcp_lib_topology_work(struct kthread_work *work) pr_err("topology receiver id list timeout\n"); if (!atomic_read(&handle->hdcp_off)) - queue_kthread_work(&handle->worker, &handle->clean); + HDCP_LIB_EXECUTE(clean); } } @@ -1329,32 +1362,35 @@ int hdcp1_set_keys(uint32_t *aksv_msb, uint32_t *aksv_lsb) return 0; } -int hdcp_library_register(void **pphdcpcontext, - struct hdcp_client_ops *client_ops, - struct hdcp_txmtr_ops *txmtr_ops, - void *client_ctx) +int hdcp_library_register(struct hdcp_register_data *data) { int rc = 0; struct hdcp_lib_handle *handle = NULL; - if (!pphdcpcontext) { - pr_err("invalid input: context passed\n"); + if (!data) { + pr_err("invalid input\n"); return -EINVAL; } - if (!txmtr_ops) { + if (!data->txmtr_ops) { pr_err("invalid input: txmtr context\n"); return -EINVAL; } - if (!client_ops) { + if (!data->client_ops) { pr_err("invalid input: client_ops\n"); return -EINVAL; } + if (!data->hdcp_ctx) { + pr_err("invalid input: hdcp_ctx\n"); + return -EINVAL; + } + /* populate ops to be called by client */ - txmtr_ops->feature_supported = hdcp_lib_client_feature_supported; - txmtr_ops->wakeup = hdcp_lib_wakeup; + data->txmtr_ops->feature_supported = hdcp_lib_client_feature_supported; + data->txmtr_ops->wakeup = hdcp_lib_wakeup; + data->txmtr_ops->update_exec_type = hdcp_lib_update_exec_type; handle = kzalloc(sizeof(*handle), GFP_KERNEL); if (!handle) { @@ -1362,24 +1398,26 @@ int hdcp_library_register(void **pphdcpcontext, goto unlock; } - handle->client_ctx = client_ctx; - handle->client_ops = client_ops; + handle->client_ctx = data->client_ctx; + handle->client_ops = data->client_ops; + handle->tethered = data->tethered; + + pr_debug("tethered %d\n", handle->tethered); atomic_set(&handle->hdcp_off, 0); - mutex_init(&handle->hdcp_lock); mutex_init(&handle->msg_lock); mutex_init(&handle->wakeup_mutex); init_kthread_worker(&handle->worker); - init_kthread_work(&handle->init, hdcp_lib_init_work); - init_kthread_work(&handle->msg_sent, hdcp_lib_msg_sent_work); - init_kthread_work(&handle->msg_recvd, hdcp_lib_msg_recvd_work); - init_kthread_work(&handle->timeout, hdcp_lib_manage_timeout_work); - init_kthread_work(&handle->clean, hdcp_lib_cleanup_work); - init_kthread_work(&handle->topology, hdcp_lib_topology_work); - init_kthread_work(&handle->stream, hdcp_lib_query_stream_type_work); + init_kthread_work(&handle->wk_init, hdcp_lib_init_work); + init_kthread_work(&handle->wk_msg_sent, hdcp_lib_msg_sent_work); + init_kthread_work(&handle->wk_msg_recvd, hdcp_lib_msg_recvd_work); + init_kthread_work(&handle->wk_timeout, hdcp_lib_manage_timeout_work); + init_kthread_work(&handle->wk_clean, hdcp_lib_cleanup_work); + init_kthread_work(&handle->wk_topology, hdcp_lib_topology_work); + init_kthread_work(&handle->wk_stream, hdcp_lib_query_stream_work); init_completion(&handle->topo_wait); @@ -1389,7 +1427,7 @@ int hdcp_library_register(void **pphdcpcontext, goto error; } - *((struct hdcp_lib_handle **)pphdcpcontext) = handle; + *data->hdcp_ctx = handle; handle->thread = kthread_run(kthread_worker_fn, &handle->worker, "hdcp_tz_lib"); @@ -1423,7 +1461,6 @@ void hdcp_library_deregister(void *phdcpcontext) kzfree(handle->qseecom_handle); kzfree(handle->last_msg_recvd_buf); - mutex_destroy(&handle->hdcp_lock); mutex_destroy(&handle->wakeup_mutex); kzfree(handle->listener_buf); diff --git a/drivers/video/fbdev/msm/mdss_hdmi_hdcp.h b/drivers/video/fbdev/msm/mdss_hdmi_hdcp.h index 2e8a5126d6fd..7dda3ff5c67d 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_hdcp.h +++ b/drivers/video/fbdev/msm/mdss_hdmi_hdcp.h @@ -40,6 +40,7 @@ struct hdmi_hdcp_init_data { u32 phy_addr; u32 hdmi_tx_ver; struct msm_hdmi_mode_timing_info *timing; + bool tethered; }; struct hdmi_hdcp_ops { diff --git a/drivers/video/fbdev/msm/mdss_hdmi_hdcp2p2.c b/drivers/video/fbdev/msm/mdss_hdmi_hdcp2p2.c index 8607d95c2fa6..78936832ab30 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_hdcp2p2.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_hdcp2p2.c @@ -51,6 +51,7 @@ enum hdmi_hdcp2p2_sink_status { struct hdmi_hdcp2p2_ctrl { atomic_t auth_state; + bool tethered; enum hdmi_hdcp2p2_sink_status sink_status; /* Is sink connected */ struct hdmi_hdcp_init_data init_data; /* Feature data from HDMI drv */ struct mutex mutex; /* mutex to protect access to ctrl */ @@ -77,6 +78,11 @@ struct hdmi_hdcp2p2_ctrl { struct delayed_work link_check_work; }; +static int hdmi_hdcp2p2_auth(struct hdmi_hdcp2p2_ctrl *ctrl); +static void hdmi_hdcp2p2_send_msg(struct hdmi_hdcp2p2_ctrl *ctrl); +static void hdmi_hdcp2p2_recv_msg(struct hdmi_hdcp2p2_ctrl *ctrl); +static void hdmi_hdcp2p2_auth_status(struct hdmi_hdcp2p2_ctrl *ctrl); + static inline bool hdmi_hdcp2p2_is_valid_state(struct hdmi_hdcp2p2_ctrl *ctrl) { if (ctrl->wakeup_cmd == HDMI_HDCP_WKUP_CMD_AUTHENTICATE) @@ -133,9 +139,9 @@ static int hdmi_hdcp2p2_wakeup(struct hdmi_hdcp_wakeup_data *data) mutex_lock(&ctrl->wakeup_mutex); - pr_debug("cmd: %s, timeout %dms\n", + pr_debug("cmd: %s, timeout %dms, tethered %d\n", hdmi_hdcp_cmd_to_str(data->cmd), - data->timeout); + data->timeout, ctrl->tethered); ctrl->wakeup_cmd = data->cmd; @@ -152,6 +158,9 @@ static int hdmi_hdcp2p2_wakeup(struct hdmi_hdcp_wakeup_data *data) if (hdmi_hdcp2p2_copy_buf(ctrl, data)) goto exit; + if (ctrl->tethered) + goto exit; + switch (ctrl->wakeup_cmd) { case HDMI_HDCP_WKUP_CMD_SEND_MESSAGE: queue_kthread_work(&ctrl->worker, &ctrl->send_msg); @@ -179,6 +188,9 @@ static inline int hdmi_hdcp2p2_wakeup_lib(struct hdmi_hdcp2p2_ctrl *ctrl, { int rc = 0; + if (ctrl) + ctrl->wakeup_cmd = HDMI_HDCP_WKUP_CMD_INVALID; + if (ctrl && ctrl->lib && ctrl->lib->wakeup && data && (data->cmd != HDCP_LIB_WKUP_CMD_INVALID)) { rc = ctrl->lib->wakeup(data); @@ -190,6 +202,55 @@ static inline int hdmi_hdcp2p2_wakeup_lib(struct hdmi_hdcp2p2_ctrl *ctrl, return rc; } +static void hdmi_hdcp2p2_run(struct hdmi_hdcp2p2_ctrl *ctrl) +{ + if (!ctrl) { + pr_err("invalid input\n"); + return; + } + + while (1) { + switch (ctrl->wakeup_cmd) { + case HDMI_HDCP_WKUP_CMD_SEND_MESSAGE: + hdmi_hdcp2p2_send_msg(ctrl); + break; + + case HDMI_HDCP_WKUP_CMD_RECV_MESSAGE: + hdmi_hdcp2p2_recv_msg(ctrl); + break; + + case HDMI_HDCP_WKUP_CMD_STATUS_SUCCESS: + case HDMI_HDCP_WKUP_CMD_STATUS_FAILED: + hdmi_hdcp2p2_auth_status(ctrl); + default: + goto exit; + } + } +exit: + ctrl->wakeup_cmd = HDMI_HDCP_WKUP_CMD_INVALID; +} + +int hdmi_hdcp2p2_authenticate_tethered(struct hdmi_hdcp2p2_ctrl *ctrl) +{ + int rc = 0; + + if (!ctrl) { + pr_err("invalid input\n"); + rc = -EINVAL; + goto exit; + } + + rc = hdmi_hdcp2p2_auth(ctrl); + if (rc) { + pr_err("auth failed %d\n", rc); + goto exit; + } + + hdmi_hdcp2p2_run(ctrl); +exit: + return rc; +} + static void hdmi_hdcp2p2_reset(struct hdmi_hdcp2p2_ctrl *ctrl) { if (!ctrl) { @@ -217,17 +278,27 @@ static void hdmi_hdcp2p2_off(void *input) hdmi_hdcp2p2_ddc_disable(ctrl->init_data.ddc_ctrl); - cdata.context = input; - - hdmi_hdcp2p2_wakeup(&cdata); + if (ctrl->tethered) { + hdmi_hdcp2p2_auth(ctrl); + } else { + cdata.context = input; + hdmi_hdcp2p2_wakeup(&cdata); + } } static int hdmi_hdcp2p2_authenticate(void *input) { struct hdmi_hdcp2p2_ctrl *ctrl = input; struct hdmi_hdcp_wakeup_data cdata = {HDMI_HDCP_WKUP_CMD_AUTHENTICATE}; + u32 regval; int rc = 0; + /* Enable authentication success interrupt */ + regval = DSS_REG_R(ctrl->init_data.core_io, HDMI_HDCP_INT_CTRL2); + regval |= BIT(1) | BIT(2); + + DSS_REG_W(ctrl->init_data.core_io, HDMI_HDCP_INT_CTRL2, regval); + flush_kthread_worker(&ctrl->worker); ctrl->sink_status = SINK_CONNECTED; @@ -237,15 +308,18 @@ static int hdmi_hdcp2p2_authenticate(void *input) hdmi_scrambler_ddc_disable(ctrl->init_data.ddc_ctrl); hdmi_hdcp2p2_ddc_disable(ctrl->init_data.ddc_ctrl); - cdata.context = input; - hdmi_hdcp2p2_wakeup(&cdata); + if (ctrl->tethered) { + hdmi_hdcp2p2_authenticate_tethered(ctrl); + } else { + cdata.context = input; + hdmi_hdcp2p2_wakeup(&cdata); + } return rc; } static int hdmi_hdcp2p2_reauthenticate(void *input) { - int rc = 0; struct hdmi_hdcp2p2_ctrl *ctrl = (struct hdmi_hdcp2p2_ctrl *)input; if (!ctrl) { @@ -255,11 +329,8 @@ static int hdmi_hdcp2p2_reauthenticate(void *input) hdmi_hdcp2p2_reset((struct hdmi_hdcp2p2_ctrl *)input); - rc = hdmi_hdcp2p2_authenticate(input); - - return rc; + return hdmi_hdcp2p2_authenticate(input); } - static ssize_t hdmi_hdcp2p2_sysfs_rda_sink_status(struct device *dev, struct device_attribute *attr, char *buf) { @@ -281,6 +352,54 @@ static ssize_t hdmi_hdcp2p2_sysfs_rda_sink_status(struct device *dev, return ret; } +static ssize_t hdmi_hdcp2p2_sysfs_rda_tethered(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + struct hdmi_hdcp2p2_ctrl *ctrl = + hdmi_get_featuredata_from_sysfs_dev(dev, HDMI_TX_FEAT_HDCP2P2); + + if (!ctrl) { + pr_err("invalid input\n"); + return -EINVAL; + } + + mutex_lock(&ctrl->mutex); + ret = snprintf(buf, PAGE_SIZE, "%d\n", ctrl->tethered); + mutex_unlock(&ctrl->mutex); + + return ret; +} + +static ssize_t hdmi_hdcp2p2_sysfs_wta_tethered(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct hdmi_hdcp2p2_ctrl *ctrl = + hdmi_get_featuredata_from_sysfs_dev(dev, HDMI_TX_FEAT_HDCP2P2); + int rc, tethered; + + if (!ctrl) { + pr_err("invalid input\n"); + return -EINVAL; + } + + mutex_lock(&ctrl->mutex); + rc = kstrtoint(buf, 10, &tethered); + if (rc) { + pr_err("kstrtoint failed. rc=%d\n", rc); + goto exit; + } + + ctrl->tethered = !!tethered; + + if (ctrl->lib && ctrl->lib->update_exec_type && ctrl->lib_ctx) + ctrl->lib->update_exec_type(ctrl->lib_ctx, ctrl->tethered); +exit: + mutex_unlock(&ctrl->mutex); + + return count; +} + static ssize_t hdmi_hdcp2p2_sysfs_rda_trigger(struct device *dev, struct device_attribute *attr, char *buf) { @@ -366,6 +485,9 @@ static ssize_t hdmi_hdcp2p2_sysfs_wta_min_level_change(struct device *dev, cdata.context = ctrl->lib_ctx; hdmi_hdcp2p2_wakeup_lib(ctrl, &cdata); + if (ctrl->tethered) + hdmi_hdcp2p2_run(ctrl); + if (enc_notify && ctrl->init_data.notify_status) ctrl->init_data.notify_status(ctrl->init_data.cb_data, enc_lvl); @@ -424,7 +546,7 @@ static int hdmi_hdcp2p2_ddc_read_message(struct hdmi_hdcp2p2_ctrl *ctrl, return rc; } -static int hdmi_hdcp2p2_ddc_write_message(struct hdmi_hdcp2p2_ctrl *ctrl, +int hdmi_hdcp2p2_ddc_write_message(struct hdmi_hdcp2p2_ctrl *ctrl, u8 *buf, size_t size) { struct hdmi_tx_ddc_data ddc_data; @@ -503,12 +625,15 @@ static DEVICE_ATTR(sink_status, S_IRUGO, hdmi_hdcp2p2_sysfs_rda_sink_status, NULL); static DEVICE_ATTR(hdcp2_version, S_IRUGO, hdmi_hdcp2p2_sysfs_rda_hdcp2_version, NULL); +static DEVICE_ATTR(tethered, S_IRUGO | S_IWUSR, hdmi_hdcp2p2_sysfs_rda_tethered, + hdmi_hdcp2p2_sysfs_wta_tethered); static struct attribute *hdmi_hdcp2p2_fs_attrs[] = { &dev_attr_trigger.attr, &dev_attr_min_level_change.attr, &dev_attr_sink_status.attr, &dev_attr_hdcp2_version.attr, + &dev_attr_tethered.attr, NULL, }; @@ -541,22 +666,19 @@ end: return supported; } -static void hdmi_hdcp2p2_send_msg_work(struct kthread_work *work) +static void hdmi_hdcp2p2_send_msg(struct hdmi_hdcp2p2_ctrl *ctrl) { int rc = 0; - struct hdmi_hdcp2p2_ctrl *ctrl = container_of(work, - struct hdmi_hdcp2p2_ctrl, send_msg); struct hdcp_lib_wakeup_data cdata = {HDCP_LIB_WKUP_CMD_INVALID}; - char *msg; uint32_t msglen; + char *msg = NULL; if (!ctrl) { pr_err("invalid input\n"); - return; + rc = -EINVAL; + goto exit; } - mutex_lock(&ctrl->mutex); - cdata.context = ctrl->lib_ctx; if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) { @@ -569,12 +691,14 @@ static void hdmi_hdcp2p2_send_msg_work(struct kthread_work *work) if (!msglen) { mutex_unlock(&ctrl->msg_lock); + rc = -EINVAL; goto exit; } msg = kzalloc(msglen, GFP_KERNEL); if (!msg) { mutex_unlock(&ctrl->msg_lock); + rc = -ENOMEM; goto exit; } @@ -591,41 +715,46 @@ static void hdmi_hdcp2p2_send_msg_work(struct kthread_work *work) cdata.timeout = ctrl->timeout_left; } exit: - kzfree(msg); - mutex_unlock(&ctrl->mutex); + kfree(msg); hdmi_hdcp2p2_wakeup_lib(ctrl, &cdata); } -static void hdmi_hdcp2p2_recv_msg_work(struct kthread_work *work) +static void hdmi_hdcp2p2_send_msg_work(struct kthread_work *work) { - int rc = 0; - int timeout_hsync; - char *recvd_msg_buf = NULL; struct hdmi_hdcp2p2_ctrl *ctrl = container_of(work, - struct hdmi_hdcp2p2_ctrl, recv_msg); + struct hdmi_hdcp2p2_ctrl, send_msg); + + hdmi_hdcp2p2_send_msg(ctrl); +} + +static void hdmi_hdcp2p2_recv_msg(struct hdmi_hdcp2p2_ctrl *ctrl) +{ + int rc, timeout_hsync; + char *recvd_msg_buf = NULL; struct hdmi_tx_hdcp2p2_ddc_data *ddc_data; struct hdmi_tx_ddc_ctrl *ddc_ctrl; struct hdcp_lib_wakeup_data cdata = {HDCP_LIB_WKUP_CMD_INVALID}; if (!ctrl) { pr_err("invalid input\n"); - return; + rc = -EINVAL; + goto exit; } - mutex_lock(&ctrl->mutex); - cdata.context = ctrl->lib_ctx; + ddc_ctrl = ctrl->init_data.ddc_ctrl; + if (!ddc_ctrl) { + pr_err("invalid ddc ctrl\n"); + rc = -EINVAL; + goto exit; + } + if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) { pr_err("hdcp is off\n"); goto exit; } - - ddc_ctrl = ctrl->init_data.ddc_ctrl; - if (!ddc_ctrl) - goto exit; - hdmi_ddc_config(ddc_ctrl); ddc_data = &ddc_ctrl->hdcp2p2_ddc_data; @@ -667,13 +796,17 @@ static void hdmi_hdcp2p2_recv_msg_work(struct kthread_work *work) } recvd_msg_buf = kzalloc(ddc_data->message_size, GFP_KERNEL); - if (!recvd_msg_buf) + if (!recvd_msg_buf) { + rc = -ENOMEM; goto exit; + } rc = hdmi_hdcp2p2_ddc_read_message(ctrl, recvd_msg_buf, ddc_data->message_size, ctrl->timeout_left); - if (rc) + if (rc) { pr_err("error reading message %d\n", rc); + goto exit; + } cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_RECV_SUCCESS; cdata.recvd_msg_buf = recvd_msg_buf; @@ -685,12 +818,19 @@ exit: else if (rc) cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_RECV_FAILED; - mutex_unlock(&ctrl->mutex); hdmi_hdcp2p2_wakeup_lib(ctrl, &cdata); kfree(recvd_msg_buf); } +static void hdmi_hdcp2p2_recv_msg_work(struct kthread_work *work) +{ + struct hdmi_hdcp2p2_ctrl *ctrl = container_of(work, + struct hdmi_hdcp2p2_ctrl, recv_msg); + + hdmi_hdcp2p2_recv_msg(ctrl); +} + static int hdmi_hdcp2p2_link_check(struct hdmi_hdcp2p2_ctrl *ctrl) { struct hdmi_tx_ddc_ctrl *ddc_ctrl; @@ -726,48 +866,38 @@ static int hdmi_hdcp2p2_link_check(struct hdmi_hdcp2p2_ctrl *ctrl) return hdmi_hdcp2p2_ddc_read_rxstatus(ddc_ctrl, false); } -static void hdmi_hdcp2p2_auth_status_work(struct kthread_work *work) +static void hdmi_hdcp2p2_auth_status(struct hdmi_hdcp2p2_ctrl *ctrl) { - struct hdmi_hdcp2p2_ctrl *ctrl = container_of(work, - struct hdmi_hdcp2p2_ctrl, status); - if (!ctrl) { pr_err("invalid input\n"); return; } - mutex_lock(&ctrl->mutex); - if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) { pr_err("hdcp is off\n"); - goto exit; + return; } if (ctrl->wakeup_cmd == HDMI_HDCP_WKUP_CMD_STATUS_FAILED) { hdmi_hdcp2p2_auth_failed(ctrl); } else if (ctrl->wakeup_cmd == HDMI_HDCP_WKUP_CMD_STATUS_SUCCESS) { - /* Enable interrupts */ - u32 regval = DSS_REG_R(ctrl->init_data.core_io, - HDMI_HDCP_INT_CTRL2); - pr_debug("Now authenticated. Enabling interrupts\n"); - regval |= BIT(1); - regval |= BIT(2); - regval |= BIT(5); - - DSS_REG_W(ctrl->init_data.core_io, - HDMI_HDCP_INT_CTRL2, regval); - ctrl->init_data.notify_status(ctrl->init_data.cb_data, HDCP_STATE_AUTHENTICATED); if (!hdmi_hdcp2p2_link_check(ctrl)) - schedule_delayed_work(&ctrl->link_check_work, - msecs_to_jiffies(HDCP2P2_LINK_CHECK_TIME_MS)); + queue_kthread_work(&ctrl->worker, &ctrl->link); } -exit: - mutex_unlock(&ctrl->mutex); } +static void hdmi_hdcp2p2_auth_status_work(struct kthread_work *work) +{ + struct hdmi_hdcp2p2_ctrl *ctrl = container_of(work, + struct hdmi_hdcp2p2_ctrl, status); + + hdmi_hdcp2p2_auth_status(ctrl); +} + + static void hdmi_hdcp2p2_link_schedule_work(struct work_struct *work) { struct hdmi_hdcp2p2_ctrl *ctrl = container_of(to_delayed_work(work), @@ -792,8 +922,6 @@ static void hdmi_hdcp2p2_link_work(struct kthread_work *work) return; } - mutex_lock(&ctrl->mutex); - cdata.context = ctrl->lib_ctx; ddc_ctrl = ctrl->init_data.ddc_ctrl; @@ -842,15 +970,14 @@ static void hdmi_hdcp2p2_link_work(struct kthread_work *work) } } exit: - mutex_unlock(&ctrl->mutex); - hdmi_hdcp2p2_wakeup_lib(ctrl, &cdata); kfree(recvd_msg_buf); - if (rc) { - /* notify hdmi tx about auth failure */ - hdmi_hdcp2p2_auth_failed(ctrl); + if (ctrl->tethered) + hdmi_hdcp2p2_run(ctrl); + if (rc) { + hdmi_hdcp2p2_auth_failed(ctrl); return; } @@ -859,19 +986,16 @@ exit: msecs_to_jiffies(HDCP2P2_LINK_CHECK_TIME_MS)); } -static void hdmi_hdcp2p2_auth_work(struct kthread_work *work) +static int hdmi_hdcp2p2_auth(struct hdmi_hdcp2p2_ctrl *ctrl) { - struct hdmi_hdcp2p2_ctrl *ctrl = container_of(work, - struct hdmi_hdcp2p2_ctrl, auth); struct hdcp_lib_wakeup_data cdata = {HDCP_LIB_WKUP_CMD_INVALID}; + int rc = 0; if (!ctrl) { pr_err("invalid input\n"); - return; + return -EINVAL; } - mutex_lock(&ctrl->mutex); - cdata.context = ctrl->lib_ctx; if (atomic_read(&ctrl->auth_state) == HDCP_STATE_AUTHENTICATING) @@ -879,10 +1003,19 @@ static void hdmi_hdcp2p2_auth_work(struct kthread_work *work) else cdata.cmd = HDCP_LIB_WKUP_CMD_STOP; - mutex_unlock(&ctrl->mutex); - - if (hdmi_hdcp2p2_wakeup_lib(ctrl, &cdata)) + rc = hdmi_hdcp2p2_wakeup_lib(ctrl, &cdata); + if (rc) hdmi_hdcp2p2_auth_failed(ctrl); + + return rc; +} + +static void hdmi_hdcp2p2_auth_work(struct kthread_work *work) +{ + struct hdmi_hdcp2p2_ctrl *ctrl = container_of(work, + struct hdmi_hdcp2p2_ctrl, auth); + + hdmi_hdcp2p2_auth(ctrl); } void hdmi_hdcp2p2_deinit(void *input) @@ -912,8 +1045,8 @@ void hdmi_hdcp2p2_deinit(void *input) void *hdmi_hdcp2p2_init(struct hdmi_hdcp_init_data *init_data) { - struct hdmi_hdcp2p2_ctrl *ctrl; int rc; + struct hdmi_hdcp2p2_ctrl *ctrl; static struct hdmi_hdcp_ops ops = { .hdmi_hdcp_reauthenticate = hdmi_hdcp2p2_reauthenticate, .hdmi_hdcp_authenticate = hdmi_hdcp2p2_authenticate, @@ -926,6 +1059,7 @@ void *hdmi_hdcp2p2_init(struct hdmi_hdcp_init_data *init_data) }; static struct hdcp_txmtr_ops txmtr_ops; + struct hdcp_register_data register_data; pr_debug("HDCP2P2 feature initialization\n"); @@ -947,6 +1081,7 @@ void *hdmi_hdcp2p2_init(struct hdmi_hdcp_init_data *init_data) ctrl->init_data = *init_data; ctrl->lib = &txmtr_ops; + ctrl->tethered = init_data->tethered; rc = sysfs_create_group(init_data->sysfs_kobj, &hdmi_hdcp2p2_fs_attr_group); @@ -964,8 +1099,13 @@ void *hdmi_hdcp2p2_init(struct hdmi_hdcp_init_data *init_data) mutex_init(&ctrl->msg_lock); mutex_init(&ctrl->wakeup_mutex); - rc = hdcp_library_register(&ctrl->lib_ctx, - &client_ops, ctrl->lib, ctrl); + register_data.hdcp_ctx = &ctrl->lib_ctx; + register_data.client_ops = &client_ops; + register_data.txmtr_ops = &txmtr_ops; + register_data.client_ctx = ctrl; + register_data.tethered = ctrl->tethered; + + rc = hdcp_library_register(®ister_data); if (rc) { pr_err("Unable to register with HDCP 2.2 library\n"); goto error; diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.c b/drivers/video/fbdev/msm/mdss_hdmi_tx.c index a88648bad161..ed66718c5e5c 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_tx.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.c @@ -1563,9 +1563,9 @@ end: static int hdmi_tx_init_features(struct hdmi_tx_ctrl *hdmi_ctrl, struct fb_info *fbi) { - struct hdmi_edid_init_data edid_init_data; - struct hdmi_hdcp_init_data hdcp_init_data; - struct hdmi_cec_init_data cec_init_data; + struct hdmi_edid_init_data edid_init_data = {0}; + struct hdmi_hdcp_init_data hdcp_init_data = {0}; + struct hdmi_cec_init_data cec_init_data = {0}; struct resource *res = NULL; void *fd = NULL; @@ -4332,6 +4332,8 @@ static int hdmi_tx_panel_event_handler(struct mdss_panel_data *panel_data, case MDSS_EVENT_BLANK: if (hdmi_tx_is_hdcp_enabled(hdmi_ctrl)) { + flush_delayed_work(&hdmi_ctrl->hdcp_cb_work); + DEV_DBG("%s: Turning off HDCP\n", __func__); hdmi_ctrl->hdcp_ops->hdmi_hdcp_off( hdmi_ctrl->hdcp_data); diff --git a/include/linux/hdcp_qseecom.h b/include/linux/hdcp_qseecom.h index 94caf29cba9f..ab39126b41ef 100644 --- a/include/linux/hdcp_qseecom.h +++ b/include/linux/hdcp_qseecom.h @@ -96,7 +96,7 @@ static inline char *hdcp_lib_cmd_to_str(uint32_t cmd) struct hdcp_txmtr_ops { int (*wakeup)(struct hdcp_lib_wakeup_data *data); bool (*feature_supported)(void *phdcpcontext); - + void (*update_exec_type)(void *ctx, bool tethered); int (*hdcp_txmtr_get_state)(void *phdcpcontext, uint32_t *state); }; @@ -105,9 +105,15 @@ struct hdcp_client_ops { int (*wakeup)(struct hdmi_hdcp_wakeup_data *data); }; -int hdcp_library_register(void **pphdcpcontext, - struct hdcp_client_ops *client_ops, - struct hdcp_txmtr_ops *txmtr_ops, void *client_ctx); +struct hdcp_register_data { + struct hdcp_client_ops *client_ops; + struct hdcp_txmtr_ops *txmtr_ops; + void *client_ctx; + void **hdcp_ctx; + bool tethered; +}; + +int hdcp_library_register(struct hdcp_register_data *data); void hdcp_library_deregister(void *phdcpcontext); bool hdcp1_check_if_supported_load_app(void); int hdcp1_set_keys(uint32_t *aksv_msb, uint32_t *aksv_lsb);