drm: start hdcp work when the "Content Protection" was set thought atomic [1/1]
authorlingjie li <lingjie.li@amlogic.com>
Fri, 5 Jul 2019 09:27:04 +0000 (17:27 +0800)
committerTao Zeng <tao.zeng@amlogic.com>
Mon, 29 Jul 2019 12:02:18 +0000 (05:02 -0700)
PD#SWPL-4866

Problem:
1. The old implement not support atomic. (the atomic check on am_meson
hdmi.c will disable CP,The set property function will not reached when
use atomic set CP)
2. The hdcp work kthread start and terminal not match cause coredump.

Problem:
need add hdcp function.

Solution:
Start hdcp work when the encoder enabled.stop when encoder disabled.
modified hdcp work state machine.

Verify:
On u212 drm backend, use drm-helper-client to set CP property.
need enable atomic on wayland.based on below CL
http://scgit.amlogic.com:8080/#/c/78810/1
http://scgit.amlogic.com:8080/#/c/78804/2
http://scgit.amlogic.com:8080/#/c/78811/1

Change-Id: If213b7def89ff1f1ec63b866a21a3323e098786f
Signed-off-by: lingjie li <lingjie.li@amlogic.com>
arch/arm64/boot/dts/amlogic/g12a_s905x2_u212_drm_buildroot.dts
arch/arm64/boot/dts/amlogic/g12b_a311d_w400_drm_buildroot.dts
drivers/amlogic/drm/drm-v0/am_meson_hdcp.c
drivers/amlogic/drm/drm-v0/am_meson_hdcp.h
drivers/amlogic/drm/drm-v0/am_meson_hdmi.c
drivers/amlogic/drm/meson_hdcp.c
drivers/amlogic/drm/meson_hdcp.h
drivers/amlogic/drm/meson_hdmi.c

index bf0654d..2e5a624 100644 (file)
 
 &drm_amhdmitx {
        status = "okay";
-       hdcp = "disabled";
+       hdcp = "okay";
 };
 
 &drm_lcd {
index ac00f86..430d1e5 100644 (file)
 
 &drm_amhdmitx {
        status = "okay";
-       hdcp = "disabled";
+       hdcp = "okay";
 };
 
 &drm_lcd {
index 6e2f176..73b8476 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/jiffies.h>
+#include <linux/kthread.h>
 #include <linux/workqueue.h>
 #include <linux/amlogic/media/vout/vout_notify.h>
 #include <linux/amlogic/media/vout/hdmi_tx/hdmi_tx_module.h>
@@ -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;
-
-       while (hdcp_fsm) {
-               if (am_hdmi->hdcp_stop_flag)
-                       hdcp_fsm = HDCP_QUIT;
+               hdcp_feature = HDCP14_ENABLE;
+
+       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);
index accf846..c3eb9e9 100644 (file)
@@ -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);
index 7e1a3ee..6cf2c31 100644 (file)
@@ -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;
 }
 
index ab098fb..dcff2c2 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/jiffies.h>
+#include <linux/kthread.h>
 #include <linux/workqueue.h>
 #include <linux/amlogic/media/vout/vout_notify.h>
 #include <linux/amlogic/media/vout/hdmi_tx/hdmi_tx_module.h>
@@ -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;
-
-       while (hdcp_fsm) {
-               if (am_hdmi->hdcp_stop_flag)
-                       hdcp_fsm = HDCP_QUIT;
+               hdcp_feature = HDCP14_ENABLE;
+
+       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);
index 9e4ede0..db41124 100644 (file)
@@ -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);
index 896444a..e5f0ce6 100644 (file)
@@ -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;
 }