drivers/misc: create new module to handle sysfs and topology events
Create a new module to handle sysfs and topology events that are related to application/userspace layer interactions for HDCP functionality. In turn, this will create a clear separation from the HDCP QSEECOM layer that defines the communication mechanism between the kernel and the TrustZone layers. CRs-Fixed: 2183436 Change-Id: I048aa95b24044646126e80d8af88893af16e72d3 Signed-off-by: Ajay Singh Parmar <aparmar@codeaurora.org> Signed-off-by: Tatenda Chipeperekwa <tatendac@codeaurora.org>
This commit is contained in:
parent
3f0e1c0ee6
commit
8a77c8a11d
14 changed files with 518 additions and 447 deletions
|
|
@ -809,6 +809,10 @@
|
|||
<&apps_smmu 0x716 0x1>;
|
||||
};
|
||||
|
||||
qcom_msmhdcp: qcom,msm_hdcp {
|
||||
compatible = "qcom,msm-hdcp";
|
||||
};
|
||||
|
||||
qcom_crypto: qcrypto@1de0000 {
|
||||
compatible = "qcom,qcrypto";
|
||||
reg = <0x1de0000 0x20000>,
|
||||
|
|
|
|||
|
|
@ -48,11 +48,6 @@ struct dp_hdcp {
|
|||
void *hdcp1;
|
||||
void *hdcp2;
|
||||
|
||||
int enc_lvl;
|
||||
|
||||
bool auth_state;
|
||||
bool hdcp1_present;
|
||||
bool hdcp2_present;
|
||||
bool feature_enabled;
|
||||
};
|
||||
|
||||
|
|
@ -93,7 +88,6 @@ struct dp_display_private {
|
|||
struct work_struct attention_work;
|
||||
struct mutex hdcp_mutex;
|
||||
struct mutex session_lock;
|
||||
int hdcp_status;
|
||||
unsigned long audio_status;
|
||||
};
|
||||
|
||||
|
|
@ -109,9 +103,8 @@ static bool dp_display_framework_ready(struct dp_display_private *dp)
|
|||
|
||||
static inline bool dp_display_is_hdcp_enabled(struct dp_display_private *dp)
|
||||
{
|
||||
return dp->hdcp.feature_enabled &&
|
||||
(dp->hdcp.hdcp1_present || dp->hdcp.hdcp2_present) &&
|
||||
dp->hdcp.ops;
|
||||
return dp->hdcp.feature_enabled && dp->link->hdcp_status.hdcp_version
|
||||
&& dp->hdcp.ops;
|
||||
}
|
||||
|
||||
static irqreturn_t dp_display_irq(int irq, void *dev_id)
|
||||
|
|
@ -156,32 +149,25 @@ static void dp_display_hdcp_cb_work(struct work_struct *work)
|
|||
|
||||
ops = dp->hdcp.ops;
|
||||
|
||||
switch (dp->hdcp_status) {
|
||||
case HDCP_STATE_AUTHENTICATING:
|
||||
pr_debug("start authenticaton\n");
|
||||
pr_debug("%s: %s\n",
|
||||
sde_hdcp_version(dp->link->hdcp_status.hdcp_version),
|
||||
sde_hdcp_state_name(dp->link->hdcp_status.hdcp_state));
|
||||
|
||||
switch (dp->link->hdcp_status.hdcp_state) {
|
||||
case HDCP_STATE_AUTHENTICATING:
|
||||
if (dp->hdcp.ops && dp->hdcp.ops->authenticate)
|
||||
rc = dp->hdcp.ops->authenticate(dp->hdcp.data);
|
||||
|
||||
break;
|
||||
case HDCP_STATE_AUTHENTICATED:
|
||||
pr_debug("hdcp authenticated\n");
|
||||
dp->hdcp.auth_state = true;
|
||||
break;
|
||||
case HDCP_STATE_AUTH_FAIL:
|
||||
dp->hdcp.auth_state = false;
|
||||
|
||||
if (dp->power_on) {
|
||||
pr_debug("Reauthenticating\n");
|
||||
if (ops && ops->reauthenticate) {
|
||||
rc = ops->reauthenticate(dp->hdcp.data);
|
||||
if (rc)
|
||||
pr_err("reauth failed rc=%d\n", rc);
|
||||
pr_err("failed rc=%d\n", rc);
|
||||
}
|
||||
} else {
|
||||
pr_debug("not reauthenticating, cable disconnected\n");
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
@ -189,7 +175,7 @@ static void dp_display_hdcp_cb_work(struct work_struct *work)
|
|||
}
|
||||
|
||||
static void dp_display_notify_hdcp_status_cb(void *ptr,
|
||||
enum sde_hdcp_states status)
|
||||
enum sde_hdcp_state state)
|
||||
{
|
||||
struct dp_display_private *dp = ptr;
|
||||
|
||||
|
|
@ -198,7 +184,7 @@ static void dp_display_notify_hdcp_status_cb(void *ptr,
|
|||
return;
|
||||
}
|
||||
|
||||
dp->hdcp_status = status;
|
||||
dp->link->hdcp_status.hdcp_state = state;
|
||||
|
||||
if (dp->dp_display.is_connected)
|
||||
queue_delayed_work(dp->wq, &dp->hdcp_cb_work, HZ/4);
|
||||
|
|
@ -214,12 +200,16 @@ static void dp_display_update_hdcp_info(struct dp_display_private *dp)
|
|||
{
|
||||
void *fd = NULL;
|
||||
struct sde_hdcp_ops *ops = NULL;
|
||||
bool hdcp2_present = false, hdcp1_present = false;
|
||||
|
||||
if (!dp) {
|
||||
pr_err("invalid input\n");
|
||||
return;
|
||||
}
|
||||
|
||||
dp->link->hdcp_status.hdcp_state = HDCP_STATE_INACTIVE;
|
||||
dp->link->hdcp_status.hdcp_version = HDCP_VERSION_NONE;
|
||||
|
||||
if (!dp->hdcp.feature_enabled) {
|
||||
pr_debug("feature not enabled\n");
|
||||
return;
|
||||
|
|
@ -230,26 +220,29 @@ static void dp_display_update_hdcp_info(struct dp_display_private *dp)
|
|||
ops = sde_dp_hdcp2p2_start(fd);
|
||||
|
||||
if (ops && ops->feature_supported)
|
||||
dp->hdcp.hdcp2_present = ops->feature_supported(fd);
|
||||
hdcp2_present = ops->feature_supported(fd);
|
||||
else
|
||||
dp->hdcp.hdcp2_present = false;
|
||||
hdcp2_present = false;
|
||||
|
||||
pr_debug("hdcp2p2: %s\n",
|
||||
dp->hdcp.hdcp2_present ? "supported" : "not supported");
|
||||
hdcp2_present ? "supported" : "not supported");
|
||||
|
||||
if (!dp->hdcp.hdcp2_present) {
|
||||
dp->hdcp.hdcp1_present = hdcp1_check_if_supported_load_app();
|
||||
if (!hdcp2_present) {
|
||||
hdcp1_present = hdcp1_check_if_supported_load_app();
|
||||
|
||||
if (dp->hdcp.hdcp1_present) {
|
||||
if (hdcp1_present) {
|
||||
fd = dp->hdcp.hdcp1;
|
||||
ops = sde_hdcp_1x_start(fd);
|
||||
dp->link->hdcp_status.hdcp_version = HDCP_VERSION_1X;
|
||||
}
|
||||
} else {
|
||||
dp->link->hdcp_status.hdcp_version = HDCP_VERSION_2P2;
|
||||
}
|
||||
|
||||
pr_debug("hdcp1x: %s\n",
|
||||
dp->hdcp.hdcp1_present ? "supported" : "not supported");
|
||||
hdcp1_present ? "supported" : "not supported");
|
||||
|
||||
if (dp->hdcp.hdcp2_present || dp->hdcp.hdcp1_present) {
|
||||
if (hdcp2_present || hdcp1_present) {
|
||||
dp->hdcp.data = fd;
|
||||
dp->hdcp.ops = ops;
|
||||
} else {
|
||||
|
|
@ -287,7 +280,6 @@ static int dp_display_initialize_hdcp(struct dp_display_private *dp)
|
|||
hdcp_init_data.drm_aux = dp->aux->drm_aux;
|
||||
hdcp_init_data.cb_data = (void *)dp;
|
||||
hdcp_init_data.workq = dp->wq;
|
||||
hdcp_init_data.mutex = &dp->hdcp_mutex;
|
||||
hdcp_init_data.sec_access = true;
|
||||
hdcp_init_data.notify_status = dp_display_notify_hdcp_status_cb;
|
||||
hdcp_init_data.core_io = &dp->parser->io.ctrl_io;
|
||||
|
|
@ -298,6 +290,7 @@ static int dp_display_initialize_hdcp(struct dp_display_private *dp)
|
|||
hdcp_init_data.qfprom_io = &dp->parser->io.qfprom_io;
|
||||
hdcp_init_data.hdcp_io = &dp->parser->io.hdcp_io;
|
||||
hdcp_init_data.revision = &dp->panel->link_info.revision;
|
||||
hdcp_init_data.msm_hdcp_dev = dp->parser->msm_hdcp_dev;
|
||||
|
||||
dp->hdcp.hdcp1 = sde_hdcp_1x_init(&hdcp_init_data);
|
||||
if (IS_ERR_OR_NULL(dp->hdcp.hdcp1)) {
|
||||
|
|
@ -623,7 +616,7 @@ end:
|
|||
static void dp_display_clean(struct dp_display_private *dp)
|
||||
{
|
||||
if (dp_display_is_hdcp_enabled(dp)) {
|
||||
dp->hdcp_status = HDCP_STATE_INACTIVE;
|
||||
dp->link->hdcp_status.hdcp_state = HDCP_STATE_INACTIVE;
|
||||
|
||||
cancel_delayed_work_sync(&dp->hdcp_cb_work);
|
||||
if (dp->hdcp.ops->off)
|
||||
|
|
@ -1103,7 +1096,7 @@ static int dp_display_post_enable(struct dp_display *dp_display)
|
|||
if (dp_display_is_hdcp_enabled(dp)) {
|
||||
cancel_delayed_work_sync(&dp->hdcp_cb_work);
|
||||
|
||||
dp->hdcp_status = HDCP_STATE_AUTHENTICATING;
|
||||
dp->link->hdcp_status.hdcp_state = HDCP_STATE_AUTHENTICATING;
|
||||
queue_delayed_work(dp->wq, &dp->hdcp_cb_work, HZ / 2);
|
||||
}
|
||||
|
||||
|
|
@ -1137,7 +1130,7 @@ static int dp_display_pre_disable(struct dp_display *dp_display)
|
|||
}
|
||||
|
||||
if (dp_display_is_hdcp_enabled(dp)) {
|
||||
dp->hdcp_status = HDCP_STATE_INACTIVE;
|
||||
dp->link->hdcp_status.hdcp_state = HDCP_STATE_INACTIVE;
|
||||
|
||||
cancel_delayed_work_sync(&dp->hdcp_cb_work);
|
||||
if (dp->hdcp.ops->off)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
|
|
@ -19,6 +19,7 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/hdcp_qseecom.h>
|
||||
#include <linux/msm_hdcp.h>
|
||||
#include <drm/drm_dp_helper.h>
|
||||
|
||||
#include "sde_hdcp.h"
|
||||
|
|
@ -320,35 +321,16 @@ static void dp_hdcp2p2_min_level_change(void *client_ctx,
|
|||
struct dp_hdcp2p2_ctrl *ctrl = (struct dp_hdcp2p2_ctrl *)client_ctx;
|
||||
struct hdcp_lib_wakeup_data cdata = {
|
||||
HDCP_LIB_WKUP_CMD_QUERY_STREAM_TYPE};
|
||||
bool enc_notify = true;
|
||||
int enc_lvl;
|
||||
|
||||
if (!ctrl) {
|
||||
pr_err("invalid input\n");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (min_enc_level) {
|
||||
case 0:
|
||||
enc_lvl = HDCP_STATE_AUTH_ENC_NONE;
|
||||
break;
|
||||
case 1:
|
||||
enc_lvl = HDCP_STATE_AUTH_ENC_1X;
|
||||
break;
|
||||
case 2:
|
||||
enc_lvl = HDCP_STATE_AUTH_ENC_2P2;
|
||||
break;
|
||||
default:
|
||||
enc_notify = false;
|
||||
}
|
||||
|
||||
pr_debug("enc level changed %d\n", min_enc_level);
|
||||
|
||||
cdata.context = ctrl->lib_ctx;
|
||||
dp_hdcp2p2_wakeup_lib(ctrl, &cdata);
|
||||
|
||||
if (enc_notify && ctrl->init_data.notify_status)
|
||||
ctrl->init_data.notify_status(ctrl->init_data.cb_data, enc_lvl);
|
||||
}
|
||||
|
||||
static void dp_hdcp2p2_auth_failed(struct dp_hdcp2p2_ctrl *ctrl)
|
||||
|
|
@ -812,7 +794,6 @@ void *sde_dp_hdcp2p2_init(struct sde_hdcp_init_data *init_data)
|
|||
|
||||
static struct hdcp_client_ops client_ops = {
|
||||
.wakeup = dp_hdcp2p2_wakeup,
|
||||
.notify_lvl_change = dp_hdcp2p2_min_level_change,
|
||||
};
|
||||
static struct dp_hdcp2p2_int_set int_set1[] = {
|
||||
{BIT(17), "authentication successful", NULL},
|
||||
|
|
@ -867,6 +848,9 @@ void *sde_dp_hdcp2p2_init(struct sde_hdcp_init_data *init_data)
|
|||
goto error;
|
||||
}
|
||||
|
||||
msm_hdcp_register_cb(init_data->msm_hdcp_dev, ctrl,
|
||||
dp_hdcp2p2_min_level_change);
|
||||
|
||||
kthread_init_worker(&ctrl->worker);
|
||||
|
||||
kthread_init_work(&ctrl->auth, dp_hdcp2p2_auth_work);
|
||||
|
|
|
|||
|
|
@ -72,6 +72,11 @@ struct dp_link_test_audio {
|
|||
u32 test_audio_period_ch_8;
|
||||
};
|
||||
|
||||
struct dp_link_hdcp_status {
|
||||
int hdcp_state;
|
||||
int hdcp_version;
|
||||
};
|
||||
|
||||
struct dp_link_phy_params {
|
||||
u32 phy_test_pattern_sel;
|
||||
u8 v_level;
|
||||
|
|
@ -110,6 +115,7 @@ struct dp_link {
|
|||
struct dp_link_test_audio test_audio;
|
||||
struct dp_link_phy_params phy_params;
|
||||
struct dp_link_params link_params;
|
||||
struct dp_link_hdcp_status hdcp_status;
|
||||
|
||||
u32 (*get_test_bits_depth)(struct dp_link *dp_link, u32 bpp);
|
||||
int (*process_request)(struct dp_link *dp_link);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
|
|
@ -15,6 +15,7 @@
|
|||
#define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__
|
||||
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/of_platform.h>
|
||||
|
||||
#include "dp_parser.h"
|
||||
|
||||
|
|
@ -215,6 +216,30 @@ static int dp_parser_misc(struct dp_parser *parser)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int dp_parser_msm_hdcp_dev(struct dp_parser *parser)
|
||||
{
|
||||
struct device_node *node;
|
||||
struct platform_device *pdev;
|
||||
|
||||
node = of_find_compatible_node(NULL, NULL, "qcom,msm-hdcp");
|
||||
if (!node) {
|
||||
// This is a non-fatal error, module initialization can proceed
|
||||
pr_warn("couldn't find msm-hdcp node\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
pdev = of_find_device_by_node(node);
|
||||
if (!pdev) {
|
||||
// This is a non-fatal error, module initialization can proceed
|
||||
pr_warn("couldn't find msm-hdcp pdev\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
parser->msm_hdcp_dev = &pdev->dev;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dp_parser_pinctrl(struct dp_parser *parser)
|
||||
{
|
||||
int rc = 0;
|
||||
|
|
@ -643,6 +668,10 @@ static int dp_parser_parse(struct dp_parser *parser)
|
|||
goto err;
|
||||
|
||||
rc = dp_parser_pinctrl(parser);
|
||||
if (rc)
|
||||
goto err;
|
||||
|
||||
rc = dp_parser_msm_hdcp_dev(parser);
|
||||
err:
|
||||
return rc;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
|
|
@ -166,6 +166,7 @@ static inline char *dp_phy_aux_config_type_to_string(u32 cfg_type)
|
|||
* struct dp_parser - DP parser's data exposed to clients
|
||||
*
|
||||
* @pdev: platform data of the client
|
||||
* @msm_hdcp_dev: device pointer for the HDCP driver
|
||||
* @mp: gpio, regulator and clock related data
|
||||
* @pinctrl: pin-control related data
|
||||
* @ctrl_resouce: controller's register address realated data
|
||||
|
|
@ -174,6 +175,7 @@ static inline char *dp_phy_aux_config_type_to_string(u32 cfg_type)
|
|||
*/
|
||||
struct dp_parser {
|
||||
struct platform_device *pdev;
|
||||
struct device *msm_hdcp_dev;
|
||||
struct dss_module_power mp[DP_MAX_PM];
|
||||
struct dp_pinctrl pinctrl;
|
||||
struct dp_io io;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2012, 2014-2017, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2012, 2014-2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
|
|
@ -30,17 +30,21 @@ enum sde_hdcp_client_id {
|
|||
HDCP_CLIENT_DP,
|
||||
};
|
||||
|
||||
enum sde_hdcp_states {
|
||||
enum sde_hdcp_state {
|
||||
HDCP_STATE_INACTIVE,
|
||||
HDCP_STATE_AUTHENTICATING,
|
||||
HDCP_STATE_AUTHENTICATED,
|
||||
HDCP_STATE_AUTH_FAIL,
|
||||
HDCP_STATE_AUTH_ENC_NONE,
|
||||
HDCP_STATE_AUTH_ENC_1X,
|
||||
HDCP_STATE_AUTH_ENC_2P2
|
||||
};
|
||||
|
||||
enum sde_hdcp_version {
|
||||
HDCP_VERSION_NONE,
|
||||
HDCP_VERSION_1X,
|
||||
HDCP_VERSION_2P2
|
||||
};
|
||||
|
||||
struct sde_hdcp_init_data {
|
||||
struct device *msm_hdcp_dev;
|
||||
struct dss_io_data *core_io;
|
||||
struct dss_io_data *dp_ahb;
|
||||
struct dss_io_data *dp_aux;
|
||||
|
|
@ -52,7 +56,7 @@ struct sde_hdcp_init_data {
|
|||
struct mutex *mutex;
|
||||
struct workqueue_struct *workq;
|
||||
void *cb_data;
|
||||
void (*notify_status)(void *cb_data, enum sde_hdcp_states status);
|
||||
void (*notify_status)(void *cb_data, enum sde_hdcp_state state);
|
||||
u8 sink_rx_status;
|
||||
unsigned char *revision;
|
||||
u32 phy_addr;
|
||||
|
|
@ -69,11 +73,32 @@ struct sde_hdcp_ops {
|
|||
void (*off)(void *hdcp_ctrl);
|
||||
};
|
||||
|
||||
static inline const char *sde_hdcp_state_name(enum sde_hdcp_state hdcp_state)
|
||||
{
|
||||
switch (hdcp_state) {
|
||||
case HDCP_STATE_INACTIVE: return "HDCP_STATE_INACTIVE";
|
||||
case HDCP_STATE_AUTHENTICATING: return "HDCP_STATE_AUTHENTICATING";
|
||||
case HDCP_STATE_AUTHENTICATED: return "HDCP_STATE_AUTHENTICATED";
|
||||
case HDCP_STATE_AUTH_FAIL: return "HDCP_STATE_AUTH_FAIL";
|
||||
default: return "???";
|
||||
}
|
||||
}
|
||||
|
||||
static inline const char *sde_hdcp_version(enum sde_hdcp_version hdcp_version)
|
||||
{
|
||||
switch (hdcp_version) {
|
||||
case HDCP_VERSION_NONE: return "HDCP_VERSION_NONE";
|
||||
case HDCP_VERSION_1X: return "HDCP_VERSION_1X";
|
||||
case HDCP_VERSION_2P2: return "HDCP_VERSION_2P2";
|
||||
default: return "???";
|
||||
}
|
||||
}
|
||||
|
||||
void *sde_hdcp_1x_init(struct sde_hdcp_init_data *init_data);
|
||||
void sde_hdcp_1x_deinit(void *input);
|
||||
struct sde_hdcp_ops *sde_hdcp_1x_start(void *input);
|
||||
void *sde_dp_hdcp2p2_init(struct sde_hdcp_init_data *init_data);
|
||||
void sde_dp_hdcp2p2_deinit(void *input);
|
||||
const char *sde_hdcp_state_name(enum sde_hdcp_states hdcp_state);
|
||||
const char *sde_hdcp_state_name(enum sde_hdcp_state hdcp_state);
|
||||
struct sde_hdcp_ops *sde_dp_hdcp2p2_start(void *input);
|
||||
#endif /* __SDE_HDCP_H__ */
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/msm_hdcp.h>
|
||||
#include <linux/hdcp_qseecom.h>
|
||||
#include <drm/drm_dp_helper.h>
|
||||
#include "sde_hdcp.h"
|
||||
|
|
@ -213,8 +214,7 @@ struct sde_hdcp_1x {
|
|||
bool sink_r0_ready;
|
||||
bool reauth;
|
||||
bool ksv_ready;
|
||||
enum sde_hdcp_states hdcp_state;
|
||||
struct HDCP_V2V1_MSG_TOPOLOGY cached_tp;
|
||||
enum sde_hdcp_state hdcp_state;
|
||||
struct HDCP_V2V1_MSG_TOPOLOGY current_tp;
|
||||
struct delayed_work hdcp_auth_work;
|
||||
struct completion r0_checked;
|
||||
|
|
@ -227,17 +227,6 @@ struct sde_hdcp_1x {
|
|||
struct workqueue_struct *workq;
|
||||
};
|
||||
|
||||
const char *sde_hdcp_state_name(enum sde_hdcp_states hdcp_state)
|
||||
{
|
||||
switch (hdcp_state) {
|
||||
case HDCP_STATE_INACTIVE: return "HDCP_STATE_INACTIVE";
|
||||
case HDCP_STATE_AUTHENTICATING: return "HDCP_STATE_AUTHENTICATING";
|
||||
case HDCP_STATE_AUTHENTICATED: return "HDCP_STATE_AUTHENTICATED";
|
||||
case HDCP_STATE_AUTH_FAIL: return "HDCP_STATE_AUTH_FAIL";
|
||||
default: return "???";
|
||||
}
|
||||
}
|
||||
|
||||
static int sde_hdcp_1x_count_one(u8 *array, u8 len)
|
||||
{
|
||||
int i, j, count = 0;
|
||||
|
|
@ -1062,30 +1051,12 @@ error:
|
|||
return rc;
|
||||
}
|
||||
|
||||
static void sde_hdcp_1x_cache_topology(struct sde_hdcp_1x *hdcp)
|
||||
{
|
||||
if (!hdcp || !hdcp->init_data.dp_ahb || !hdcp->init_data.dp_aux ||
|
||||
!hdcp->init_data.dp_link || !hdcp->init_data.dp_p0) {
|
||||
pr_err("invalid input\n");
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy((void *)&hdcp->cached_tp,
|
||||
(void *) &hdcp->current_tp,
|
||||
sizeof(hdcp->cached_tp));
|
||||
hdcp1_cache_repeater_topology((void *)&hdcp->cached_tp);
|
||||
}
|
||||
|
||||
static void sde_hdcp_1x_notify_topology(void)
|
||||
{
|
||||
hdcp1_notify_topology();
|
||||
}
|
||||
|
||||
static void sde_hdcp_1x_update_auth_status(struct sde_hdcp_1x *hdcp)
|
||||
{
|
||||
if (sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATED)) {
|
||||
sde_hdcp_1x_cache_topology(hdcp);
|
||||
sde_hdcp_1x_notify_topology();
|
||||
msm_hdcp_cache_repeater_topology(hdcp->init_data.msm_hdcp_dev,
|
||||
&hdcp->current_tp);
|
||||
msm_hdcp_notify_topology(hdcp->init_data.msm_hdcp_dev);
|
||||
}
|
||||
|
||||
if (hdcp->init_data.notify_status &&
|
||||
|
|
@ -1262,11 +1233,9 @@ static void sde_hdcp_1x_off(void *input)
|
|||
* Also, need to set the state to inactive here so that any ongoing
|
||||
* reauth works will know that the HDCP session has been turned off.
|
||||
*/
|
||||
mutex_lock(hdcp->init_data.mutex);
|
||||
DSS_REG_W(io, isr->int_reg,
|
||||
DSS_REG_R(io, isr->int_reg) & ~HDCP_INT_EN);
|
||||
hdcp->hdcp_state = HDCP_STATE_INACTIVE;
|
||||
mutex_unlock(hdcp->init_data.mutex);
|
||||
|
||||
/* complete any wait pending */
|
||||
complete_all(&hdcp->sink_r0_available);
|
||||
|
|
@ -1510,7 +1479,7 @@ void *sde_hdcp_1x_init(struct sde_hdcp_init_data *init_data)
|
|||
.off = sde_hdcp_1x_off
|
||||
};
|
||||
|
||||
if (!init_data || !init_data->mutex || !init_data->notify_status ||
|
||||
if (!init_data || !init_data->notify_status ||
|
||||
!init_data->workq || !init_data->cb_data) {
|
||||
pr_err("invalid input\n");
|
||||
goto error;
|
||||
|
|
|
|||
|
|
@ -49,7 +49,8 @@ obj-$(CONFIG_LATTICE_ECP3_CONFIG) += lattice-ecp3-config.o
|
|||
obj-$(CONFIG_SRAM) += sram.o
|
||||
obj-y += mic/
|
||||
obj-$(CONFIG_GENWQE) += genwqe/
|
||||
obj-$(CONFIG_HDCP_QSEECOM) += hdcp.o
|
||||
obj-$(CONFIG_HDCP_QSEECOM) += hdcp_qseecom.o
|
||||
obj-$(CONFIG_HDCP_QSEECOM) += msm_hdcp.o
|
||||
obj-$(CONFIG_QSEECOM) += qseecom.o
|
||||
obj-$(CONFIG_ECHO) += echo/
|
||||
obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o
|
||||
|
|
|
|||
2240
drivers/misc/hdcp_qseecom.c
Normal file
2240
drivers/misc/hdcp_qseecom.c
Normal file
File diff suppressed because it is too large
Load diff
356
drivers/misc/msm_hdcp.c
Normal file
356
drivers/misc/msm_hdcp.c
Normal file
|
|
@ -0,0 +1,356 @@
|
|||
/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "[msm-hdcp] %s: " fmt, __func__
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/msm_hdcp.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#define CLASS_NAME "hdcp"
|
||||
#define DRIVER_NAME "msm_hdcp"
|
||||
|
||||
struct msm_hdcp {
|
||||
struct platform_device *pdev;
|
||||
dev_t dev_num;
|
||||
struct cdev cdev;
|
||||
struct class *class;
|
||||
struct device *device;
|
||||
struct HDCP_V2V1_MSG_TOPOLOGY cached_tp;
|
||||
u32 tp_msgid;
|
||||
void *client_ctx;
|
||||
void (*cb)(void *ctx, int data);
|
||||
};
|
||||
|
||||
void msm_hdcp_register_cb(struct device *dev, void *ctx,
|
||||
void (*cb)(void *ctx, int data))
|
||||
{
|
||||
struct msm_hdcp *hdcp = NULL;
|
||||
|
||||
if (!dev) {
|
||||
pr_err("invalid device pointer\n");
|
||||
return;
|
||||
}
|
||||
|
||||
hdcp = dev_get_drvdata(dev);
|
||||
if (!hdcp) {
|
||||
pr_err("invalid driver pointer\n");
|
||||
return;
|
||||
}
|
||||
|
||||
hdcp->cb = cb;
|
||||
hdcp->client_ctx = ctx;
|
||||
}
|
||||
|
||||
void msm_hdcp_notify_topology(struct device *dev)
|
||||
{
|
||||
char *envp[4];
|
||||
char tp[SZ_16];
|
||||
char ver[SZ_16];
|
||||
struct msm_hdcp *hdcp = NULL;
|
||||
|
||||
if (!dev) {
|
||||
pr_err("invalid device pointer\n");
|
||||
return;
|
||||
}
|
||||
|
||||
hdcp = dev_get_drvdata(dev);
|
||||
if (!hdcp) {
|
||||
pr_err("invalid driver pointer\n");
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf(tp, SZ_16, "%d", DOWN_CHECK_TOPOLOGY);
|
||||
snprintf(ver, SZ_16, "%d", HDCP_V1_TX);
|
||||
|
||||
envp[0] = "HDCP_MGR_EVENT=MSG_READY";
|
||||
envp[1] = tp;
|
||||
envp[2] = ver;
|
||||
envp[3] = NULL;
|
||||
|
||||
kobject_uevent_env(&hdcp->device->kobj, KOBJ_CHANGE, envp);
|
||||
}
|
||||
|
||||
void msm_hdcp_cache_repeater_topology(struct device *dev,
|
||||
struct HDCP_V2V1_MSG_TOPOLOGY *tp)
|
||||
{
|
||||
struct msm_hdcp *hdcp = NULL;
|
||||
|
||||
if (!dev || !tp) {
|
||||
pr_err("invalid input\n");
|
||||
return;
|
||||
}
|
||||
|
||||
hdcp = dev_get_drvdata(dev);
|
||||
if (!hdcp) {
|
||||
pr_err("invalid driver pointer\n");
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(&hdcp->cached_tp, tp,
|
||||
sizeof(struct HDCP_V2V1_MSG_TOPOLOGY));
|
||||
}
|
||||
|
||||
static ssize_t msm_hdcp_1x_sysfs_rda_tp(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
ssize_t ret = 0;
|
||||
struct msm_hdcp *hdcp = NULL;
|
||||
|
||||
if (!dev) {
|
||||
pr_err("invalid device pointer\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
hdcp = dev_get_drvdata(dev);
|
||||
if (!hdcp) {
|
||||
pr_err("invalid driver pointer\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
switch (hdcp->tp_msgid) {
|
||||
case DOWN_CHECK_TOPOLOGY:
|
||||
case DOWN_REQUEST_TOPOLOGY:
|
||||
buf[MSG_ID_IDX] = hdcp->tp_msgid;
|
||||
buf[RET_CODE_IDX] = HDCP_AUTHED;
|
||||
ret = HEADER_LEN;
|
||||
|
||||
memcpy(buf + HEADER_LEN, &hdcp->cached_tp,
|
||||
sizeof(struct HDCP_V2V1_MSG_TOPOLOGY));
|
||||
|
||||
ret += sizeof(struct HDCP_V2V1_MSG_TOPOLOGY);
|
||||
|
||||
/* clear the flag once data is read back to user space*/
|
||||
hdcp->tp_msgid = -1;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t msm_hdcp_1x_sysfs_wta_tp(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
int msgid = 0;
|
||||
ssize_t ret = count;
|
||||
struct msm_hdcp *hdcp = NULL;
|
||||
|
||||
if (!dev) {
|
||||
pr_err("invalid device pointer\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
hdcp = dev_get_drvdata(dev);
|
||||
if (!hdcp) {
|
||||
pr_err("invalid driver pointer\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
msgid = buf[0];
|
||||
|
||||
switch (msgid) {
|
||||
case DOWN_CHECK_TOPOLOGY:
|
||||
case DOWN_REQUEST_TOPOLOGY:
|
||||
hdcp->tp_msgid = msgid;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t msm_hdcp_2x_sysfs_wta_min_level_change(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
int rc;
|
||||
int min_enc_lvl;
|
||||
ssize_t ret = count;
|
||||
struct msm_hdcp *hdcp = NULL;
|
||||
|
||||
if (!dev) {
|
||||
pr_err("invalid device pointer\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
hdcp = dev_get_drvdata(dev);
|
||||
if (!hdcp) {
|
||||
pr_err("invalid driver pointer\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
rc = kstrtoint(buf, 10, &min_enc_lvl);
|
||||
if (rc) {
|
||||
pr_err("kstrtoint failed. rc=%d\n", rc);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (hdcp->cb && hdcp->client_ctx)
|
||||
hdcp->cb(hdcp->client_ctx, min_enc_lvl);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(tp, 0644, msm_hdcp_1x_sysfs_rda_tp,
|
||||
msm_hdcp_1x_sysfs_wta_tp);
|
||||
|
||||
static DEVICE_ATTR(min_level_change, 0200, NULL,
|
||||
msm_hdcp_2x_sysfs_wta_min_level_change);
|
||||
|
||||
static struct attribute *msm_hdcp_fs_attrs[] = {
|
||||
&dev_attr_tp.attr,
|
||||
&dev_attr_min_level_change.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group msm_hdcp_fs_attr_group = {
|
||||
.attrs = msm_hdcp_fs_attrs
|
||||
};
|
||||
|
||||
static int msm_hdcp_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_hdcp_close(struct inode *inode, struct file *file)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct file_operations msm_hdcp_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = msm_hdcp_open,
|
||||
.release = msm_hdcp_close,
|
||||
};
|
||||
|
||||
static const struct of_device_id msm_hdcp_dt_match[] = {
|
||||
{ .compatible = "qcom,msm-hdcp",},
|
||||
{}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, msm_hdcp_dt_match);
|
||||
|
||||
static int msm_hdcp_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
struct msm_hdcp *hdcp;
|
||||
|
||||
hdcp = devm_kzalloc(&pdev->dev, sizeof(struct msm_hdcp), GFP_KERNEL);
|
||||
if (!hdcp)
|
||||
return -ENOMEM;
|
||||
|
||||
hdcp->pdev = pdev;
|
||||
|
||||
platform_set_drvdata(pdev, hdcp);
|
||||
|
||||
ret = alloc_chrdev_region(&hdcp->dev_num, 0, 1, DRIVER_NAME);
|
||||
if (ret < 0) {
|
||||
pr_err("alloc_chrdev_region failed ret = %d\n", ret);
|
||||
goto error_get_dev_num;
|
||||
}
|
||||
|
||||
hdcp->class = class_create(THIS_MODULE, CLASS_NAME);
|
||||
if (IS_ERR(hdcp->class)) {
|
||||
ret = PTR_ERR(hdcp->class);
|
||||
pr_err("couldn't create class rc = %d\n", ret);
|
||||
goto error_class_create;
|
||||
}
|
||||
|
||||
hdcp->device = device_create(hdcp->class, NULL,
|
||||
hdcp->dev_num, NULL, DRIVER_NAME);
|
||||
if (IS_ERR(hdcp->device)) {
|
||||
ret = PTR_ERR(hdcp->device);
|
||||
pr_err("device_create failed %d\n", ret);
|
||||
goto error_class_device_create;
|
||||
}
|
||||
|
||||
cdev_init(&hdcp->cdev, &msm_hdcp_fops);
|
||||
ret = cdev_add(&hdcp->cdev, MKDEV(MAJOR(hdcp->dev_num), 0), 1);
|
||||
if (ret < 0) {
|
||||
pr_err("cdev_add failed %d\n", ret);
|
||||
goto error_cdev_add;
|
||||
}
|
||||
|
||||
ret = sysfs_create_group(&hdcp->device->kobj, &msm_hdcp_fs_attr_group);
|
||||
if (ret)
|
||||
pr_err("unable to register msm_hdcp sysfs nodes\n");
|
||||
|
||||
return 0;
|
||||
error_cdev_add:
|
||||
device_destroy(hdcp->class, hdcp->dev_num);
|
||||
error_class_device_create:
|
||||
class_destroy(hdcp->class);
|
||||
error_class_create:
|
||||
unregister_chrdev_region(hdcp->dev_num, 1);
|
||||
error_get_dev_num:
|
||||
devm_kfree(&pdev->dev, hdcp);
|
||||
hdcp = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int msm_hdcp_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct msm_hdcp *hdcp;
|
||||
|
||||
hdcp = platform_get_drvdata(pdev);
|
||||
if (!hdcp)
|
||||
return -ENODEV;
|
||||
|
||||
sysfs_remove_group(&hdcp->device->kobj,
|
||||
&msm_hdcp_fs_attr_group);
|
||||
cdev_del(&hdcp->cdev);
|
||||
device_destroy(hdcp->class, hdcp->dev_num);
|
||||
class_destroy(hdcp->class);
|
||||
unregister_chrdev_region(hdcp->dev_num, 1);
|
||||
|
||||
devm_kfree(&pdev->dev, hdcp);
|
||||
hdcp = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver msm_hdcp_driver = {
|
||||
.probe = msm_hdcp_probe,
|
||||
.remove = msm_hdcp_remove,
|
||||
.driver = {
|
||||
.name = "msm_hdcp",
|
||||
.of_match_table = msm_hdcp_dt_match,
|
||||
.pm = NULL,
|
||||
}
|
||||
};
|
||||
|
||||
static int __init msm_hdcp_init(void)
|
||||
{
|
||||
return platform_driver_register(&msm_hdcp_driver);
|
||||
}
|
||||
|
||||
static void __exit msm_hdcp_exit(void)
|
||||
{
|
||||
return platform_driver_unregister(&msm_hdcp_driver);
|
||||
}
|
||||
|
||||
module_init(msm_hdcp_init);
|
||||
module_exit(msm_hdcp_exit);
|
||||
|
||||
MODULE_DESCRIPTION("MSM HDCP driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
|
|
@ -181,11 +181,9 @@ struct hdcp_txmtr_ops {
|
|||
/**
|
||||
* struct hdcp_client_ops - call back functions to display transport layer
|
||||
* @wakeup: wake up display transport layer with a new command
|
||||
* @notify_lvl_change notify of encryption level changes
|
||||
*/
|
||||
struct hdcp_client_ops {
|
||||
int (*wakeup)(struct hdcp_wakeup_data *data);
|
||||
void (*notify_lvl_change)(void *client_ctx, int min_lvl);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -219,6 +217,4 @@ 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);
|
||||
int hdcp1_set_enc(bool enable);
|
||||
void hdcp1_cache_repeater_topology(void *hdcp1_cached_tp);
|
||||
void hdcp1_notify_topology(void);
|
||||
#endif /* __HDCP_QSEECOM_H */
|
||||
|
|
|
|||
26
include/linux/msm_hdcp.h
Normal file
26
include/linux/msm_hdcp.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef __MSM_HDCP_H
|
||||
#define __MSM_HDCP_H
|
||||
#include <linux/types.h>
|
||||
#include "video/msm_hdmi_hdcp_mgr.h"
|
||||
|
||||
void msm_hdcp_notify_topology(struct device *dev);
|
||||
void msm_hdcp_cache_repeater_topology(struct device *dev,
|
||||
struct HDCP_V2V1_MSG_TOPOLOGY *tp);
|
||||
void msm_hdcp_register_cb(struct device *dev, void *ctx,
|
||||
void (*cb)(void *ctx, int data));
|
||||
|
||||
#endif /* __MSM_HDCP_H */
|
||||
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
#ifndef _UAPI__HDMI_HDCP_MGR_H
|
||||
#ifndef _UAPI__MSM_HDMI_HDCP_MGR_H
|
||||
#define _UAPI__MSM_HDMI_HDCP_MGR_H
|
||||
|
||||
enum DS_TYPE { /* type of downstream device */
|
||||
|
|
|
|||
Loading…
Reference in a new issue