drm: start hdcp work when the "Content Protection" was set thought atomic [1/1]

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>
This commit is contained in:
lingjie li
2019-07-05 17:27:04 +08:00
committed by Luke Go
parent ecb536d3db
commit c945cbd1a3
6 changed files with 124 additions and 96 deletions

View 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;
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);

View 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);

View 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;
}

View 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;
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);

View 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);

View 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;
}