Skip to content

Commit

Permalink
drm: bridge: cdns-mhdp8546: Enable HDCP
Browse files Browse the repository at this point in the history
This patch enable HDCP in MHDP driver.

Signed-off-by: Parshuram Thombare <pthombar@cadence.com>
Reviewed-by: Robert Foss <robert.foss@linaro.org>
  • Loading branch information
pthombarcdns authored and intel-lab-lkp committed Mar 17, 2021
1 parent 4f973e3 commit 9c8eb15
Show file tree
Hide file tree
Showing 5 changed files with 782 additions and 13 deletions.
2 changes: 1 addition & 1 deletion drivers/gpu/drm/bridge/cadence/Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_DRM_CDNS_MHDP8546) += cdns-mhdp8546.o
cdns-mhdp8546-y := cdns-mhdp8546-core.o
cdns-mhdp8546-y := cdns-mhdp8546-core.o cdns-mhdp8546-hdcp.o
cdns-mhdp8546-$(CONFIG_DRM_CDNS_MHDP8546_J721E) += cdns-mhdp8546-j721e.o
113 changes: 101 additions & 12 deletions drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,15 @@
#include <drm/drm_connector.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_dp_helper.h>
#include <drm/drm_hdcp.h>
#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>

#include <asm/unaligned.h>

#include "cdns-mhdp8546-core.h"

#include "cdns-mhdp8546-hdcp.h"
#include "cdns-mhdp8546-j721e.h"

static int cdns_mhdp_mailbox_read(struct cdns_mhdp_device *mhdp)
Expand Down Expand Up @@ -1614,10 +1615,47 @@ enum drm_mode_status cdns_mhdp_mode_valid(struct drm_connector *conn,
return MODE_OK;
}

static int cdns_mhdp_connector_atomic_check(struct drm_connector *conn,
struct drm_atomic_state *state)
{
struct drm_connector_state *old_state, *new_state;
struct drm_crtc_state *crtc_state;
u64 old_cp, new_cp;

old_state = drm_atomic_get_old_connector_state(state, conn);
new_state = drm_atomic_get_new_connector_state(state, conn);
old_cp = old_state->content_protection;
new_cp = new_state->content_protection;

if (old_state->hdcp_content_type != new_state->hdcp_content_type &&
new_cp != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
new_state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
goto mode_changed;
}

if (!new_state->crtc) {
if (old_cp == DRM_MODE_CONTENT_PROTECTION_ENABLED)
new_state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
return 0;
}

if (old_cp == new_cp ||
(old_cp == DRM_MODE_CONTENT_PROTECTION_DESIRED &&
new_cp == DRM_MODE_CONTENT_PROTECTION_ENABLED))
return 0;

mode_changed:
crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc);
crtc_state->mode_changed = true;

return 0;
}

static const struct drm_connector_helper_funcs cdns_mhdp_conn_helper_funcs = {
.detect_ctx = cdns_mhdp_connector_detect,
.get_modes = cdns_mhdp_get_modes,
.mode_valid = cdns_mhdp_mode_valid,
.atomic_check = cdns_mhdp_connector_atomic_check,
};

static const struct drm_connector_funcs cdns_mhdp_conn_funcs = {
Expand Down Expand Up @@ -1662,7 +1700,7 @@ static int cdns_mhdp_connector_init(struct cdns_mhdp_device *mhdp)
return ret;
}

return 0;
return drm_connector_attach_content_protection_property(conn, true);
}

static int cdns_mhdp_attach(struct drm_bridge *bridge,
Expand Down Expand Up @@ -1957,6 +1995,14 @@ static void cdns_mhdp_atomic_enable(struct drm_bridge *bridge,
if (WARN_ON(!conn_state))
goto out;

if (mhdp->hw_state == MHDP_HW_READY &&
conn_state->content_protection ==
DRM_MODE_CONTENT_PROTECTION_DESIRED) {
mutex_unlock(&mhdp->link_mutex);
cdns_mhdp_hdcp_enable(mhdp, conn_state->hdcp_content_type);
mutex_lock(&mhdp->link_mutex);
}

crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
if (WARN_ON(!crtc_state))
goto out;
Expand Down Expand Up @@ -2000,6 +2046,7 @@ static void cdns_mhdp_atomic_disable(struct drm_bridge *bridge,

mutex_lock(&mhdp->link_mutex);

cdns_mhdp_hdcp_disable(mhdp);
mhdp->bridge_enabled = false;
cdns_mhdp_reg_read(mhdp, CDNS_DP_FRAMER_GLOBAL_CONFIG, &resp);
resp &= ~CDNS_DP_FRAMER_EN;
Expand Down Expand Up @@ -2288,7 +2335,6 @@ static irqreturn_t cdns_mhdp_irq_handler(int irq, void *data)
struct cdns_mhdp_device *mhdp = data;
u32 apb_stat, sw_ev0;
bool bridge_attached;
int ret;

apb_stat = readl(mhdp->regs + CDNS_APB_INT_STATUS);
if (!(apb_stat & CDNS_APB_INT_MASK_SW_EVENT_INT))
Expand All @@ -2307,20 +2353,54 @@ static irqreturn_t cdns_mhdp_irq_handler(int irq, void *data)
spin_unlock(&mhdp->start_lock);

if (bridge_attached && (sw_ev0 & CDNS_DPTX_HPD)) {
ret = cdns_mhdp_update_link_status(mhdp);
if (mhdp->connector.dev) {
if (ret < 0)
schedule_work(&mhdp->modeset_retry_work);
else
drm_kms_helper_hotplug_event(mhdp->bridge.dev);
} else {
drm_bridge_hpd_notify(&mhdp->bridge, cdns_mhdp_detect(mhdp));
}
schedule_work(&mhdp->hpd_work);
}

if (sw_ev0 & ~CDNS_DPTX_HPD) {
mhdp->sw_events |= (sw_ev0 & ~CDNS_DPTX_HPD);
wake_up(&mhdp->sw_events_wq);
}

return IRQ_HANDLED;
}

u32 cdns_mhdp_wait_for_sw_event(struct cdns_mhdp_device *mhdp, u32 event)
{
u32 ret;

ret = wait_event_timeout(mhdp->sw_events_wq,
mhdp->sw_events & event,
msecs_to_jiffies(500));
if (!ret) {
dev_dbg(mhdp->dev, "SW event 0x%x timeout\n", event);
goto sw_event_out;
}

ret = mhdp->sw_events;
mhdp->sw_events &= ~event;

sw_event_out:
return ret;
}

static void cdns_mhdp_hpd_work(struct work_struct *work)
{
struct cdns_mhdp_device *mhdp = container_of(work,
struct cdns_mhdp_device,
hpd_work);
int ret;

ret = cdns_mhdp_update_link_status(mhdp);
if (mhdp->connector.dev) {
if (ret < 0)
schedule_work(&mhdp->modeset_retry_work);
else
drm_kms_helper_hotplug_event(mhdp->bridge.dev);
} else {
drm_bridge_hpd_notify(&mhdp->bridge, cdns_mhdp_detect(mhdp));
}
}

static int cdns_mhdp_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
Expand Down Expand Up @@ -2356,6 +2436,12 @@ static int cdns_mhdp_probe(struct platform_device *pdev)
return PTR_ERR(mhdp->regs);
}

mhdp->sapb_regs = devm_platform_ioremap_resource_byname(pdev, "mhdptx-sapb");
if (IS_ERR(mhdp->sapb_regs)) {
dev_err(dev, "Failed to get SAPB memory resource\n");
return PTR_ERR(mhdp->sapb_regs);
}

mhdp->phy = devm_of_phy_get_by_index(dev, pdev->dev.of_node, 0);
if (IS_ERR(mhdp->phy)) {
dev_err(dev, "no PHY configured\n");
Expand Down Expand Up @@ -2430,13 +2516,16 @@ static int cdns_mhdp_probe(struct platform_device *pdev)

/* Initialize the work for modeset in case of link train failure */
INIT_WORK(&mhdp->modeset_retry_work, cdns_mhdp_modeset_retry_fn);
INIT_WORK(&mhdp->hpd_work, cdns_mhdp_hpd_work);

init_waitqueue_head(&mhdp->fw_load_wq);
init_waitqueue_head(&mhdp->sw_events_wq);

ret = cdns_mhdp_load_firmware(mhdp);
if (ret)
goto phy_exit;

cdns_mhdp_hdcp_init(mhdp);
drm_bridge_add(&mhdp->bridge);

return 0;
Expand Down
21 changes: 21 additions & 0 deletions drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ struct phy;

#define CDNS_SW_EVENT0 0x00044
#define CDNS_DPTX_HPD BIT(0)
#define CDNS_HDCP_TX_STATUS BIT(4)
#define CDNS_HDCP2_TX_IS_KM_STORED BIT(5)
#define CDNS_HDCP2_TX_STORE_KM BIT(6)
#define CDNS_HDCP_TX_IS_RCVR_ID_VALID BIT(7)

#define CDNS_SW_EVENT1 0x00048
#define CDNS_SW_EVENT2 0x0004c
Expand Down Expand Up @@ -339,8 +343,17 @@ struct cdns_mhdp_platform_info {
#define to_cdns_mhdp_bridge_state(s) \
container_of(s, struct cdns_mhdp_bridge_state, base)

struct cdns_mhdp_hdcp {
struct delayed_work check_work;
struct work_struct prop_work;
struct mutex mutex; /* mutex to protect hdcp.value */
u32 value;
u8 hdcp_content_type;
};

struct cdns_mhdp_device {
void __iomem *regs;
void __iomem *sapb_regs;
void __iomem *j721e_regs;

struct device *dev;
Expand Down Expand Up @@ -392,9 +405,17 @@ struct cdns_mhdp_device {

/* Work struct to schedule a uevent on link train failure */
struct work_struct modeset_retry_work;
struct work_struct hpd_work;

wait_queue_head_t sw_events_wq;
u32 sw_events;

struct cdns_mhdp_hdcp hdcp;
};

#define connector_to_mhdp(x) container_of(x, struct cdns_mhdp_device, connector)
#define bridge_to_mhdp(x) container_of(x, struct cdns_mhdp_device, bridge)

u32 cdns_mhdp_wait_for_sw_event(struct cdns_mhdp_device *mhdp, uint32_t event);

#endif
Loading

0 comments on commit 9c8eb15

Please sign in to comment.