Skip to content

Commit

Permalink
drm/msm: Implement HDCP 1.x using the new drm HDCP helpers
Browse files Browse the repository at this point in the history
This patch adds HDCP 1.x support to msm DP connectors using the new HDCP
helpers.

Cc: Stephen Boyd <swboyd@chromium.org>
Cc: Abhinav Kumar <abhinavk@codeaurora.org>
Reviewed-by: Stephen Boyd <swboyd@chromium.org>
Signed-off-by: Sean Paul <seanpaul@chromium.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20210913175747.47456-15-sean@poorly.run #v1
Link: https://patchwork.freedesktop.org/patch/msgid/20210915203834.1439-14-sean@poorly.run #v2
Link: https://patchwork.freedesktop.org/patch/msgid/20211001151145.55916-15-sean@poorly.run #v3
Link: https://patchwork.freedesktop.org/patch/msgid/20211105030434.2828845-15-sean@poorly.run #v4

Changes in v2:
-Squash [1] into this patch with the following changes (Stephen)
  -Update the sc7180 dtsi file
  -Remove resource names and just use index (Stephen)
Changes in v3:
-Split out the dtsi change from v2 (Stephen)
-Fix set-but-unused warning identified by 0-day
-Fix up a couple of style nits (Stephen)
-Store HDCP key directly in dp_hdcp struct (Stephen)
-Remove wmb in HDCP key initialization, move an_seed (Stephen)
-Use FIELD_PREP for bstatus/bcaps (Stephen)
-#define read_poll_timeout values (Stephen)
-Remove unnecessary parentheses in dp_hdcp_store_ksv_fifo (Stephen)
-Add compatible string for hdcp (Stephen)
-Rename dp_hdcp_write_* functions (Abhinav)
-Add 1us delay between An reads (Abhinav)
-Delete unused dp_hdcp_read_* functions
Changes in v4:
-Rebase on Bjorn's multi-dp patchset
Changes in v5:
-Change return check of drm_hdcp_helper_initialize_dp() (Stephen)

[1] https://patchwork.freedesktop.org/patch/msgid/20210913175747.47456-14-sean@poorly.run
  • Loading branch information
atseanpaul authored and intel-lab-lkp committed Apr 11, 2022
1 parent 339f05c commit ba0d772
Show file tree
Hide file tree
Showing 13 changed files with 720 additions and 8 deletions.
1 change: 1 addition & 0 deletions drivers/gpu/drm/msm/Makefile
Expand Up @@ -106,6 +106,7 @@ msm-$(CONFIG_DRM_MSM_DP)+= dp/dp_aux.o \
dp/dp_ctrl.o \
dp/dp_display.o \
dp/dp_drm.o \
dp/dp_hdcp.o \
dp/dp_hpd.o \
dp/dp_link.o \
dp/dp_panel.o \
Expand Down
46 changes: 45 additions & 1 deletion drivers/gpu/drm/msm/dp/dp_debug.c
Expand Up @@ -8,13 +8,15 @@
#include <linux/debugfs.h>
#include <drm/drm_connector.h>
#include <drm/drm_file.h>
#include <drm/drm_hdcp.h>

#include "dp_parser.h"
#include "dp_catalog.h"
#include "dp_aux.h"
#include "dp_ctrl.h"
#include "dp_debug.h"
#include "dp_display.h"
#include "dp_hdcp.h"

#define DEBUG_NAME "msm_dp"

Expand All @@ -25,6 +27,7 @@ struct dp_debug_private {
struct dp_link *link;
struct dp_panel *panel;
struct drm_connector *connector;
struct dp_hdcp *hdcp;
struct device *dev;
struct drm_device *drm_dev;

Expand Down Expand Up @@ -198,6 +201,35 @@ static int dp_test_active_open(struct inode *inode,
inode->i_private);
}

static ssize_t dp_hdcp_key_write(struct file *file, const char __user *ubuf,
size_t len, loff_t *offp)
{
char *input_buffer;
int ret;
struct dp_debug_private *debug = file->private_data;

if (len != (DRM_HDCP_KSV_LEN + DP_HDCP_NUM_KEYS * DP_HDCP_KEY_LEN))
return -EINVAL;

if (!debug->hdcp)
return -ENOENT;

input_buffer = memdup_user_nul(ubuf, len);
if (IS_ERR(input_buffer))
return PTR_ERR(input_buffer);

ret = dp_hdcp_ingest_key(debug->hdcp, input_buffer, len);

kfree(input_buffer);
if (ret < 0) {
DRM_ERROR("Could not ingest HDCP key, ret=%d\n", ret);
return ret;
}

*offp += len;
return len;
}

static const struct file_operations test_active_fops = {
.owner = THIS_MODULE,
.open = dp_test_active_open,
Expand All @@ -207,6 +239,12 @@ static const struct file_operations test_active_fops = {
.write = dp_test_active_write
};

static const struct file_operations dp_hdcp_key_fops = {
.owner = THIS_MODULE,
.open = simple_open,
.write = dp_hdcp_key_write,
};

static void dp_debug_init(struct dp_debug *dp_debug, struct drm_minor *minor)
{
char path[64];
Expand All @@ -231,11 +269,16 @@ static void dp_debug_init(struct dp_debug *dp_debug, struct drm_minor *minor)
debugfs_create_file("msm_dp_test_type", 0444,
debug->root,
debug, &dp_test_type_fops);

debugfs_create_file("msm_dp_hdcp_key", 0222,
minor->debugfs_root,
debug, &dp_hdcp_key_fops);
}

struct dp_debug *dp_debug_get(struct device *dev, struct dp_panel *panel,
struct dp_usbpd *usbpd, struct dp_link *link,
struct drm_connector *connector, struct drm_minor *minor)
struct dp_hdcp *hdcp, struct drm_connector *connector,
struct drm_minor *minor)
{
struct dp_debug_private *debug;
struct dp_debug *dp_debug;
Expand All @@ -257,6 +300,7 @@ struct dp_debug *dp_debug_get(struct device *dev, struct dp_panel *panel,
debug->usbpd = usbpd;
debug->link = link;
debug->panel = panel;
debug->hdcp = hdcp;
debug->dev = dev;
debug->drm_dev = minor->dev;
debug->connector = connector;
Expand Down
6 changes: 4 additions & 2 deletions drivers/gpu/drm/msm/dp/dp_debug.h
Expand Up @@ -6,6 +6,7 @@
#ifndef _DP_DEBUG_H_
#define _DP_DEBUG_H_

#include "dp_hdcp.h"
#include "dp_panel.h"
#include "dp_link.h"

Expand Down Expand Up @@ -43,7 +44,7 @@ struct dp_debug {
*/
struct dp_debug *dp_debug_get(struct device *dev, struct dp_panel *panel,
struct dp_usbpd *usbpd, struct dp_link *link,
struct drm_connector *connector,
struct dp_hdcp *hdcp, struct drm_connector *connector,
struct drm_minor *minor);

/**
Expand All @@ -60,7 +61,8 @@ void dp_debug_put(struct dp_debug *dp_debug);
static inline
struct dp_debug *dp_debug_get(struct device *dev, struct dp_panel *panel,
struct dp_usbpd *usbpd, struct dp_link *link,
struct drm_connector *connector, struct drm_minor *minor)
struct dp_hdcp *hdcp, struct drm_connector *connector,
struct drm_minor *minor)
{
return ERR_PTR(-EINVAL);
}
Expand Down
46 changes: 44 additions & 2 deletions drivers/gpu/drm/msm/dp/dp_display.c
Expand Up @@ -27,6 +27,7 @@
#include "dp_drm.h"
#include "dp_audio.h"
#include "dp_debug.h"
#include "dp_hdcp.h"

#define HPD_STRING_SIZE 30

Expand Down Expand Up @@ -99,6 +100,7 @@ struct dp_display_private {
struct dp_panel *panel;
struct dp_ctrl *ctrl;
struct dp_debug *debug;
struct dp_hdcp *hdcp;

struct dp_usbpd_cb usbpd_cb;
struct dp_display_mode dp_mode;
Expand Down Expand Up @@ -177,6 +179,15 @@ static struct dp_display_private *dev_get_dp_display_private(struct device *dev)
return container_of(dp, struct dp_display_private, dp_display);
}

struct dp_hdcp *dp_display_connector_to_hdcp(struct drm_connector *connector)
{
struct msm_dp *dp_display = msm_dp_from_connector(connector);
struct dp_display_private *dp;

dp = container_of(dp_display, struct dp_display_private, dp_display);
return dp->hdcp;
}

static int dp_add_event(struct dp_display_private *dp_priv, u32 event,
u32 data, u32 delay)
{
Expand Down Expand Up @@ -749,6 +760,7 @@ static int dp_irq_hpd_handle(struct dp_display_private *dp, u32 data)
static void dp_display_deinit_sub_modules(struct dp_display_private *dp)
{
dp_debug_put(dp->debug);
dp_hdcp_put(dp->hdcp);
dp_audio_put(dp->audio);
dp_panel_put(dp->panel);
dp_aux_put(dp->aux);
Expand Down Expand Up @@ -845,8 +857,18 @@ static int dp_init_sub_modules(struct dp_display_private *dp)
goto error_ctrl;
}

dp->hdcp = dp_hdcp_get(dp->parser, dp->aux);
if (IS_ERR(dp->hdcp)) {
rc = PTR_ERR(dp->hdcp);
DRM_ERROR("failed to initialize hdcp, rc = %d\n", rc);
dp->hdcp = NULL;
goto error_hdcp;
}

return rc;

error_hdcp:
dp_audio_put(dp->audio);
error_ctrl:
dp_panel_put(dp->panel);
error_link:
Expand Down Expand Up @@ -968,6 +990,16 @@ int dp_display_set_plugged_cb(struct msm_dp *dp_display,
return 0;
}

void dp_display_hdcp_commit(struct msm_dp *dp, struct drm_atomic_state *state)
{
struct dp_display_private *dp_display;

dp_display = container_of(dp, struct dp_display_private, dp_display);

if (dp_display->hdcp)
dp_hdcp_commit(dp_display->hdcp, state);
}

int dp_display_validate_mode(struct msm_dp *dp, u32 mode_pclk_khz)
{
const u32 num_components = 3, default_bpp = 24;
Expand Down Expand Up @@ -1498,8 +1530,8 @@ void msm_dp_debugfs_init(struct msm_dp *dp_display, struct drm_minor *minor)
dev = &dp->pdev->dev;

dp->debug = dp_debug_get(dev, dp->panel, dp->usbpd,
dp->link, dp->dp_display.connector,
minor);
dp->link, dp->hdcp,
dp->dp_display.connector, minor);
if (IS_ERR(dp->debug)) {
rc = PTR_ERR(dp->debug);
DRM_ERROR("failed to initialize debug, rc = %d\n", rc);
Expand All @@ -1510,13 +1542,17 @@ void msm_dp_debugfs_init(struct msm_dp *dp_display, struct drm_minor *minor)
int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev,
struct drm_encoder *encoder)
{
struct dp_display_private *dp_display_priv;
struct msm_drm_private *priv;
struct dp_display_private *dp_priv;
int ret;

if (WARN_ON(!encoder) || WARN_ON(!dp_display) || WARN_ON(!dev))
return -EINVAL;

dp_display_priv = container_of(dp_display, struct dp_display_private,
dp_display);

priv = dev->dev_private;
dp_display->drm_dev = dev;

Expand All @@ -1541,6 +1577,12 @@ int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev,

dp_priv->panel->connector = dp_display->connector;

ret = dp_hdcp_attach(dp_display_priv->hdcp, dp_display->connector);
if (ret) {
DRM_ERROR("Failed to attach hdcp, ret=%d\n", ret);
return ret;
}

priv->connectors[priv->num_connectors++] = dp_display->connector;

dp_display->bridge = msm_dp_bridge_init(dp_display, dev, encoder);
Expand Down
5 changes: 5 additions & 0 deletions drivers/gpu/drm/msm/dp/dp_display.h
Expand Up @@ -30,8 +30,13 @@ struct msm_dp {
struct dp_audio *dp_audio;
};

struct drm_atomic_state;

int dp_display_set_plugged_cb(struct msm_dp *dp_display,
hdmi_codec_plugged_cb fn, struct device *codec_dev);
struct dp_hdcp *dp_display_connector_to_hdcp(struct drm_connector *connector);
void dp_display_hdcp_commit(struct msm_dp *dp_display,
struct drm_atomic_state *state);
int dp_display_validate_mode(struct msm_dp *dp_display, u32 mode_pclk_khz);
int dp_display_get_modes(struct msm_dp *dp_display,
struct dp_display_mode *dp_mode);
Expand Down
68 changes: 67 additions & 1 deletion drivers/gpu/drm/msm/dp/dp_drm.c
Expand Up @@ -6,11 +6,20 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_atomic.h>
#include <drm/drm_bridge.h>
#include <drm/drm_connector.h>
#include <drm/drm_crtc.h>
#include <drm/drm_hdcp.h>

#include "msm_drv.h"
#include "msm_kms.h"
#include "dp_drm.h"
#include "dp_hdcp.h"

struct dp_connector_state {
struct drm_connector_state base;
bool hdcp_transition;
};
#define to_dp_connector_state(x) container_of(x, struct dp_connector_state, base)


struct msm_dp_bridge {
Expand All @@ -26,6 +35,11 @@ struct dp_connector {
};
#define to_dp_connector(x) container_of(x, struct dp_connector, base)

struct msm_dp *msm_dp_from_connector(struct drm_connector *connector)
{
return to_dp_connector(connector)->dp_display;
}

/**
* dp_connector_detect - callback to determine if connector is connected
* @conn: Pointer to drm connector structure
Expand Down Expand Up @@ -123,20 +137,72 @@ static enum drm_mode_status dp_connector_mode_valid(
return dp_display_validate_mode(dp_disp, mode->clock);
}

static int dp_connector_atomic_check(struct drm_connector *connector,
struct drm_atomic_state *state)
{
struct drm_connector_state *conn_state;
struct dp_connector_state *dp_state;

conn_state = drm_atomic_get_new_connector_state(state, connector);
dp_state = to_dp_connector_state(conn_state);

dp_state->hdcp_transition = drm_hdcp_atomic_check(connector, state);

return 0;
}

static struct drm_connector_state *
dp_connector_atomic_duplicate_state(struct drm_connector *connector)
{
struct dp_connector_state *state;

state = kzalloc(sizeof(*state), GFP_KERNEL);
if (!state)
return NULL;

state->hdcp_transition = false;

__drm_atomic_helper_connector_duplicate_state(connector, &state->base);
return &state->base;
}

static const struct drm_connector_funcs dp_connector_funcs = {
.detect = dp_connector_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
.destroy = drm_connector_cleanup,
.reset = drm_atomic_helper_connector_reset,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
.atomic_duplicate_state = dp_connector_atomic_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};

static const struct drm_connector_helper_funcs dp_connector_helper_funcs = {
.get_modes = dp_connector_get_modes,
.mode_valid = dp_connector_mode_valid,
.atomic_check = dp_connector_atomic_check,
};

bool dp_drm_is_connector_msm_dp(struct drm_connector *connector)
{
return connector->funcs == &dp_connector_funcs;
}

void dp_drm_atomic_commit(struct drm_connector *connector,
struct drm_connector_state *conn_state,
struct drm_atomic_state *state)
{
struct dp_connector_state *dp_state;
struct msm_dp *dp_disp;

dp_state = to_dp_connector_state(conn_state);

if (!dp_state->hdcp_transition)
return;

dp_disp = msm_dp_from_connector(connector);

dp_display_hdcp_commit(dp_disp, state);
}

/* connector initialization */
struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display)
{
Expand Down
5 changes: 5 additions & 0 deletions drivers/gpu/drm/msm/dp/dp_drm.h
Expand Up @@ -14,5 +14,10 @@
#include "dp_display.h"

struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display);
struct msm_dp *msm_dp_from_connector(struct drm_connector *connector);
bool dp_drm_is_connector_msm_dp(struct drm_connector *connector);
void dp_drm_atomic_commit(struct drm_connector *connector,
struct drm_connector_state *conn_state,
struct drm_atomic_state *state);

#endif /* _DP_DRM_H_ */

0 comments on commit ba0d772

Please sign in to comment.