diff --git a/drivers/amlogic/drm/drm-v0/am_meson_hdcp.c b/drivers/amlogic/drm/drm-v0/am_meson_hdcp.c index 6e2f17691386..73b8476b6a38 100644 --- a/drivers/amlogic/drm/drm-v0/am_meson_hdcp.c +++ b/drivers/amlogic/drm/drm-v0/am_meson_hdcp.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -300,21 +301,38 @@ int am_hdcp22_auth(struct am_hdmi_tx *am_hdmi) int am_hdcp_work(void *data) { struct am_hdmi_tx *am_hdmi = data; - struct drm_connector_state *state = am_hdmi->connector.state; - int hdcp_fsm = 0; + struct drm_connector *conn = &(am_hdmi->connector); + int hdcp_fsm = HDCP_READY; + int hdcp_feature = 0; + DRM_INFO("start hdcp work CP=%u\n", conn->state->content_protection); is_hdcp_hdmirx_supported(am_hdmi); if ((am_hdmi->hdcp_tx_type & 0x2) && (am_hdmi->hdcp_rx_type & 0x2)) - hdcp_fsm = HDCP22_ENABLE; + hdcp_feature = HDCP22_ENABLE; else - hdcp_fsm = HDCP14_ENABLE; + hdcp_feature = HDCP14_ENABLE; - while (hdcp_fsm) { - if (am_hdmi->hdcp_stop_flag) - hdcp_fsm = HDCP_QUIT; + do { + /* The state ptr will update pre atomic commit */ + if (conn->state->content_protection == + DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { + if (hdcp_fsm != HDCP_READY) { + hdcp_fsm = HDCP_READY; + DRM_INFO("HDCP status reset!\n"); + } + } else if (hdcp_fsm == HDCP_READY) { + hdcp_fsm = hdcp_feature; + } + if (hdcp_fsm == HDCP_QUIT) + conn->state->content_protection = + DRM_MODE_CONTENT_PROTECTION_UNDESIRED; switch (hdcp_fsm) { + case HDCP_READY: + /* wait for content_protection change */ + msleep_interruptible(5000); + break; case HDCP22_ENABLE: am_hdcp22_enable(am_hdmi); DRM_INFO("hdcp22 work after 10s\n"); @@ -329,16 +347,13 @@ int am_hdcp_work(void *data) hdcp_fsm = HDCP22_FAIL; break; case HDCP22_SUCCESS: - state->content_protection = + conn->state->content_protection = DRM_MODE_CONTENT_PROTECTION_ENABLED; - DRM_DEBUG("hdcp22 is authenticated successfully\n"); hdcp_fsm = HDCP22_AUTH; msleep_interruptible(200); break; case HDCP22_FAIL: am_hdcp22_disable(am_hdmi); - state->content_protection = - DRM_MODE_CONTENT_PROTECTION_UNDESIRED; DRM_INFO("hdcp22 failure and start hdcp14\n"); hdcp_fsm = HDCP14_ENABLE; msleep_interruptible(2000); @@ -348,6 +363,7 @@ int am_hdcp_work(void *data) hdcp_fsm = HDCP_QUIT; break; } + DRM_INFO("hdcp14 work start"); am_hdcp14_enable(am_hdmi); msleep_interruptible(500); hdcp_fsm = HDCP14_AUTH; @@ -359,24 +375,22 @@ int am_hdcp_work(void *data) hdcp_fsm = HDCP14_FAIL; break; case HDCP14_SUCCESS: - state->content_protection = + conn->state->content_protection = DRM_MODE_CONTENT_PROTECTION_ENABLED; - DRM_DEBUG("hdcp14 is authenticated successfully\n"); hdcp_fsm = HDCP14_AUTH; msleep_interruptible(200); break; case HDCP14_FAIL: am_hdcp14_disable(am_hdmi); - state->content_protection = - DRM_MODE_CONTENT_PROTECTION_UNDESIRED; - DRM_DEBUG("hdcp14 failure\n"); + DRM_INFO("hdcp14 failure\n"); hdcp_fsm = HDCP_QUIT; break; case HDCP_QUIT: default: break; } - } + } while (!kthread_should_stop()); + DRM_INFO("hdcp worker stopped\n"); return 0; } EXPORT_SYMBOL(am_hdcp_work); diff --git a/drivers/amlogic/drm/drm-v0/am_meson_hdcp.h b/drivers/amlogic/drm/drm-v0/am_meson_hdcp.h index accf846c6355..c3eb9e9fd0f8 100644 --- a/drivers/amlogic/drm/drm-v0/am_meson_hdcp.h +++ b/drivers/amlogic/drm/drm-v0/am_meson_hdcp.h @@ -32,6 +32,7 @@ #define HDCP22_AUTH 6 #define HDCP22_SUCCESS 7 #define HDCP22_FAIL 8 +#define HDCP_READY 9 int am_hdcp_init(struct am_hdmi_tx *am_hdmi); int is_hdcp_hdmitx_supported(struct am_hdmi_tx *am_hdmi); diff --git a/drivers/amlogic/drm/drm-v0/am_meson_hdmi.c b/drivers/amlogic/drm/drm-v0/am_meson_hdmi.c index 7e1a3eeacfef..6cf2c31c8aeb 100644 --- a/drivers/amlogic/drm/drm-v0/am_meson_hdmi.c +++ b/drivers/amlogic/drm/drm-v0/am_meson_hdmi.c @@ -179,6 +179,29 @@ static enum drm_connector_status am_hdmi_connector_detect return connector_status_unknown; } +void am_hdmi_hdcp_work_state_change(struct am_hdmi_tx *am_hdmi, int stop) +{ + if (am_hdmi->hdcp_tx_type == 0) { + DRM_INFO("hdcp not support\n"); + return; + } + if (am_hdmi->hdcp_work == NULL && stop != 1) { + am_hdmi->hdcp_work = kthread_run(am_hdcp_work, + (void *)am_hdmi, "kthread_hdcp_task"); + if (IS_ERR(am_hdmi->hdcp_work)) { + DRM_INFO("hdcp work create failed\n"); + am_hdmi->hdcp_work = NULL; + } + return; + } + if (am_hdmi->hdcp_work != NULL && stop == 1) { + DRM_INFO("stop hdcp work\n"); + kthread_stop(am_hdmi->hdcp_work); + am_hdmi->hdcp_work = NULL; + am_hdcp_disable(am_hdmi); + } +} + static int am_hdmi_connector_set_property(struct drm_connector *connector, struct drm_property *property, uint64_t val) { @@ -187,6 +210,8 @@ static int am_hdmi_connector_set_property(struct drm_connector *connector, if (property == connector->content_protection_property) { DRM_INFO("property:%s val: %lld\n", property->name, val); + /* For none atomic commit */ + /* atomic will be filter on drm_moder_object.c */ if (val == DRM_MODE_CONTENT_PROTECTION_ENABLED) { DRM_DEBUG_KMS("only drivers can set CP Enabled\n"); return -EINVAL; @@ -266,7 +291,6 @@ void am_hdmi_encoder_enable(struct drm_encoder *encoder) { enum vmode_e vmode = get_current_vmode(); struct am_hdmi_tx *am_hdmi = to_am_hdmi(encoder); - struct drm_connector_state *state = am_hdmi->connector.state; if (vmode == VMODE_HDMI) DRM_INFO("am_hdmi_encoder_enable\n"); @@ -276,16 +300,9 @@ void am_hdmi_encoder_enable(struct drm_encoder *encoder) vout_notifier_call_chain(VOUT_EVENT_MODE_CHANGE_PRE, &vmode); set_vout_vmode(vmode); vout_notifier_call_chain(VOUT_EVENT_MODE_CHANGE, &vmode); + am_hdmi->hdcp_work = NULL; mdelay(1000); - if (state->content_protection == - DRM_MODE_CONTENT_PROTECTION_DESIRED) { - if (am_hdmi->hdcp_tx_type) { - am_hdmi->hdcp_stop_flag = 0; - am_hdmi->hdcp_work = kthread_run(am_hdcp_work, - (void *)am_hdmi, "kthread_hdcp_task"); - } else - DRM_INFO("hdmitx doesn't has hdcp key\n"); - } + am_hdmi_hdcp_work_state_change(am_hdmi, 0); } void am_hdmi_encoder_disable(struct drm_encoder *encoder) @@ -293,32 +310,15 @@ void am_hdmi_encoder_disable(struct drm_encoder *encoder) struct am_hdmi_tx *am_hdmi = to_am_hdmi(encoder); struct drm_connector_state *state = am_hdmi->connector.state; - /*need to add hdmitx disable function ..todo*/ - if (state->content_protection != - DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { - state->content_protection = - DRM_MODE_CONTENT_PROTECTION_UNDESIRED; - am_hdmi->hdcp_stop_flag = 1; - kthread_stop(am_hdmi->hdcp_work); - am_hdcp_disable(am_hdmi); - } + state->content_protection = DRM_MODE_CONTENT_PROTECTION_UNDESIRED; + am_hdmi_hdcp_work_state_change(am_hdmi, 1); + } static int am_hdmi_encoder_atomic_check(struct drm_encoder *encoder, struct drm_crtc_state *crtc_state, struct drm_connector_state *conn_state) { - struct am_hdmi_tx *am_hdmi = to_am_hdmi(encoder); - - DRM_INFO("content_protection:%d\n", conn_state->content_protection); - - if (conn_state->content_protection == - DRM_MODE_CONTENT_PROTECTION_ENABLED) { - kthread_stop(am_hdmi->hdcp_work); - am_hdcp_disable(am_hdmi); - conn_state->content_protection = - DRM_MODE_CONTENT_PROTECTION_DESIRED; - } return 0; } diff --git a/drivers/amlogic/drm/meson_hdcp.c b/drivers/amlogic/drm/meson_hdcp.c index ab098fb9cffb..dcff2c25e5a8 100644 --- a/drivers/amlogic/drm/meson_hdcp.c +++ b/drivers/amlogic/drm/meson_hdcp.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -300,21 +301,38 @@ int am_hdcp22_auth(struct am_hdmi_tx *am_hdmi) int am_hdcp_work(void *data) { struct am_hdmi_tx *am_hdmi = data; - struct drm_connector_state *state = am_hdmi->connector.state; - int hdcp_fsm = 0; + struct drm_connector *conn = &(am_hdmi->connector); + int hdcp_fsm = HDCP_READY; + int hdcp_feature = 0; + DRM_INFO("start hdcp work CP=%u\n", conn->state->content_protection); is_hdcp_hdmirx_supported(am_hdmi); if ((am_hdmi->hdcp_tx_type & 0x2) && (am_hdmi->hdcp_rx_type & 0x2)) - hdcp_fsm = HDCP22_ENABLE; + hdcp_feature = HDCP22_ENABLE; else - hdcp_fsm = HDCP14_ENABLE; + hdcp_feature = HDCP14_ENABLE; - while (hdcp_fsm) { - if (am_hdmi->hdcp_stop_flag) - hdcp_fsm = HDCP_QUIT; + do { + /* The state ptr will update pre atomic commit */ + if (conn->state->content_protection == + DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { + if (hdcp_fsm != HDCP_READY) { + hdcp_fsm = HDCP_READY; + DRM_INFO("HDCP status reset!\n"); + } + } else if (hdcp_fsm == HDCP_READY) { + hdcp_fsm = hdcp_feature; + } + if (hdcp_fsm == HDCP_QUIT) + conn->state->content_protection = + DRM_MODE_CONTENT_PROTECTION_UNDESIRED; switch (hdcp_fsm) { + case HDCP_READY: + /* wait for content_protection change. */ + msleep_interruptible(5000); + break; case HDCP22_ENABLE: am_hdcp22_enable(am_hdmi); DRM_INFO("hdcp22 work after 10s\n"); @@ -329,16 +347,13 @@ int am_hdcp_work(void *data) hdcp_fsm = HDCP22_FAIL; break; case HDCP22_SUCCESS: - state->content_protection = + conn->state->content_protection = DRM_MODE_CONTENT_PROTECTION_ENABLED; - DRM_DEBUG("hdcp22 is authenticated successfully\n"); hdcp_fsm = HDCP22_AUTH; msleep_interruptible(200); break; case HDCP22_FAIL: am_hdcp22_disable(am_hdmi); - state->content_protection = - DRM_MODE_CONTENT_PROTECTION_UNDESIRED; DRM_INFO("hdcp22 failure and start hdcp14\n"); hdcp_fsm = HDCP14_ENABLE; msleep_interruptible(2000); @@ -348,6 +363,7 @@ int am_hdcp_work(void *data) hdcp_fsm = HDCP_QUIT; break; } + DRM_INFO("hdcp14 work start"); am_hdcp14_enable(am_hdmi); msleep_interruptible(500); hdcp_fsm = HDCP14_AUTH; @@ -359,24 +375,22 @@ int am_hdcp_work(void *data) hdcp_fsm = HDCP14_FAIL; break; case HDCP14_SUCCESS: - state->content_protection = + conn->state->content_protection = DRM_MODE_CONTENT_PROTECTION_ENABLED; - DRM_DEBUG("hdcp14 is authenticated successfully\n"); hdcp_fsm = HDCP14_AUTH; msleep_interruptible(200); break; case HDCP14_FAIL: am_hdcp14_disable(am_hdmi); - state->content_protection = - DRM_MODE_CONTENT_PROTECTION_UNDESIRED; - DRM_DEBUG("hdcp14 failure\n"); + DRM_INFO("hdcp14 failure\n"); hdcp_fsm = HDCP_QUIT; break; case HDCP_QUIT: default: break; } - } + } while (!kthread_should_stop()); + DRM_INFO("hdcp worker stopped\n"); return 0; } EXPORT_SYMBOL(am_hdcp_work); diff --git a/drivers/amlogic/drm/meson_hdcp.h b/drivers/amlogic/drm/meson_hdcp.h index 9e4ede0d12df..db41124b21d3 100644 --- a/drivers/amlogic/drm/meson_hdcp.h +++ b/drivers/amlogic/drm/meson_hdcp.h @@ -32,6 +32,7 @@ #define HDCP22_AUTH 6 #define HDCP22_SUCCESS 7 #define HDCP22_FAIL 8 +#define HDCP_READY 9 int am_hdcp_init(struct am_hdmi_tx *am_hdmi); int is_hdcp_hdmitx_supported(struct am_hdmi_tx *am_hdmi); diff --git a/drivers/amlogic/drm/meson_hdmi.c b/drivers/amlogic/drm/meson_hdmi.c index 896444af9019..e5f0ce60eae3 100644 --- a/drivers/amlogic/drm/meson_hdmi.c +++ b/drivers/amlogic/drm/meson_hdmi.c @@ -179,6 +179,29 @@ static enum drm_connector_status am_hdmi_connector_detect return connector_status_unknown; } +void am_hdmi_hdcp_work_state_change(struct am_hdmi_tx *am_hdmi, int stop) +{ + if (am_hdmi->hdcp_tx_type == 0) { + DRM_INFO("hdcp not support\n"); + return; + } + if (am_hdmi->hdcp_work == NULL && stop != 1) { + am_hdmi->hdcp_work = kthread_run(am_hdcp_work, + (void *)am_hdmi, "kthread_hdcp_task"); + if (IS_ERR(am_hdmi->hdcp_work)) { + DRM_INFO("hdcp work create failed\n"); + am_hdmi->hdcp_work = NULL; + } + return; + } + if (am_hdmi->hdcp_work != NULL && stop == 1) { + DRM_INFO("stop hdcp work\n"); + kthread_stop(am_hdmi->hdcp_work); + am_hdmi->hdcp_work = NULL; + am_hdcp_disable(am_hdmi); + } +} + static int am_hdmi_connector_set_property(struct drm_connector *connector, struct drm_property *property, uint64_t val) { @@ -187,6 +210,8 @@ static int am_hdmi_connector_set_property(struct drm_connector *connector, if (property == connector->content_protection_property) { DRM_INFO("property:%s val: %lld\n", property->name, val); + /* For none atomic commit */ + /* atomic will be filter on drm_moder_object.c */ if (val == DRM_MODE_CONTENT_PROTECTION_ENABLED) { DRM_DEBUG_KMS("only drivers can set CP Enabled\n"); return -EINVAL; @@ -266,7 +291,6 @@ void am_hdmi_encoder_enable(struct drm_encoder *encoder) { enum vmode_e vmode = get_current_vmode(); struct am_hdmi_tx *am_hdmi = to_am_hdmi(encoder); - struct drm_connector_state *state = am_hdmi->connector.state; if (vmode == VMODE_HDMI) DRM_INFO("enable\n"); @@ -276,18 +300,9 @@ void am_hdmi_encoder_enable(struct drm_encoder *encoder) vout_notifier_call_chain(VOUT_EVENT_MODE_CHANGE_PRE, &vmode); set_vout_vmode(vmode); vout_notifier_call_chain(VOUT_EVENT_MODE_CHANGE, &vmode); + am_hdmi->hdcp_work = NULL; mdelay(1000); - if (state->content_protection == - DRM_MODE_CONTENT_PROTECTION_DESIRED) { - if (am_hdmi->hdcp_tx_type) { - am_hdmi->hdcp_stop_flag = 0; - am_hdmi->hdcp_work = kthread_run(am_hdcp_work, - (void *)am_hdmi, - "kthread_hdcp_task"); - } else { - DRM_INFO("hdmitx doesn't has hdcp key\n"); - } - } + am_hdmi_hdcp_work_state_change(am_hdmi, 0); } void am_hdmi_encoder_disable(struct drm_encoder *encoder) @@ -295,32 +310,15 @@ void am_hdmi_encoder_disable(struct drm_encoder *encoder) struct am_hdmi_tx *am_hdmi = to_am_hdmi(encoder); struct drm_connector_state *state = am_hdmi->connector.state; - /*need to add hdmitx disable function ..todo*/ - if (state->content_protection != - DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { - state->content_protection = - DRM_MODE_CONTENT_PROTECTION_UNDESIRED; - am_hdmi->hdcp_stop_flag = 1; - kthread_stop(am_hdmi->hdcp_work); - am_hdcp_disable(am_hdmi); - } + state->content_protection = DRM_MODE_CONTENT_PROTECTION_UNDESIRED; + am_hdmi_hdcp_work_state_change(am_hdmi, 1); + } static int am_hdmi_encoder_atomic_check(struct drm_encoder *encoder, struct drm_crtc_state *crtc_state, struct drm_connector_state *conn_state) { - struct am_hdmi_tx *am_hdmi = to_am_hdmi(encoder); - - DRM_INFO("content_protection:%d\n", conn_state->content_protection); - - if (conn_state->content_protection == - DRM_MODE_CONTENT_PROTECTION_ENABLED) { - kthread_stop(am_hdmi->hdcp_work); - am_hdcp_disable(am_hdmi); - conn_state->content_protection = - DRM_MODE_CONTENT_PROTECTION_DESIRED; - } return 0; }