[PATCH 6/8] drm/i915: Detect panel's hdcp capability

Ramalingam C
2018-02-02T10:51:15Z

As a first step of HDCP authentication detects the panel's HDCP
capability. This is mandated for DP HDCP1.4.

For DP 0th Bit of Bcaps register indicates the panel's hdcp capability
For HDMI valid BKSV indicates the panel's hdcp capability.

Signed-off-by: Ramalingam C <ramalingam.c@intel.com>
---
drivers/gpu/drm/i915/intel_dp.c | 19 +++++++++++++++++++
drivers/gpu/drm/i915/intel_drv.h | 5 +++++
drivers/gpu/drm/i915/intel_hdcp.c | 10 ++++++++--
drivers/gpu/drm/i915/intel_hdmi.c | 17 +++++++++++++++++
4 files changed, 49 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 03d86ff9b805..2623b2beda1a 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -5218,6 +5218,24 @@ bool intel_dp_hdcp_check_link(struct intel_digital_port *intel_dig_port)
return !(bstatus & (DP_BSTATUS_LINK_FAILURE | DP_BSTATUS_REAUTH_REQ));
}

+static
+int intel_dp_hdcp_capable(struct intel_digital_port *intel_dig_port,
+ bool *hdcp_capable)
+{
+ ssize_t ret;
+ u8 bcaps;
+
+ ret = drm_dp_dpcd_read(&intel_dig_port->dp.aux, DP_AUX_HDCP_BCAPS,
+ &bcaps, 1);
+ if (ret != 1) {
+ DRM_ERROR("Read bcaps from DP/AUX failed (%zd)\n", ret);
+ return ret >= 0 ? -EIO : ret;
+ }
+
+ *hdcp_capable = bcaps & DP_BCAPS_HDCP_CAPABLE;
+ return 0;
+}
+
static const struct intel_hdcp_shim intel_dp_hdcp_shim = {
.write_an_aksv = intel_dp_hdcp_write_an_aksv,
.read_bksv = intel_dp_hdcp_read_bksv,
@@ -5229,6 +5247,7 @@ static const struct intel_hdcp_shim intel_dp_hdcp_shim = {
.read_v_prime_part = intel_dp_hdcp_read_v_prime_part,
.toggle_signalling = intel_dp_hdcp_toggle_signalling,
.check_link = intel_dp_hdcp_check_link,
+ .hdcp_capable = intel_dp_hdcp_capable,
};

static void intel_edp_panel_vdd_sanitize(struct intel_dp *intel_dp)
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index d6a808374dfb..409aee9010ba 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -369,6 +369,10 @@ struct intel_hdcp_shim {

/* Ensures the link is still protected */
bool (*check_link)(struct intel_digital_port *intel_dig_port);
+
+ /* Detects panel's hdcp capablility */
+ int (*hdcp_capable)(struct intel_digital_port *intel_dig_port,
+ bool *hdcp_capable);
};

struct intel_connector {
@@ -1848,6 +1852,7 @@ int intel_hdcp_enable(struct intel_connector *connector);
int intel_hdcp_disable(struct intel_connector *connector);
int intel_hdcp_check_link(struct intel_connector *connector);
bool is_hdcp_supported(struct drm_i915_private *dev_priv, enum port port);
+bool intel_hdcp_is_ksv_valid(u8 *ksv);

/* intel_psr.c */
#define CAN_PSR(dev_priv) (HAS_PSR(dev_priv) && dev_priv->psr.sink_support)
diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c
index 5de9afd275b2..a3463557f0f6 100644
--- a/drivers/gpu/drm/i915/intel_hdcp.c
+++ b/drivers/gpu/drm/i915/intel_hdcp.c
@@ -132,7 +132,6 @@ u32 intel_hdcp_get_repeater_ctl(struct intel_digital_port *intel_dig_port)
return -EINVAL;
}

-static
bool intel_hdcp_is_ksv_valid(u8 *ksv)
{
int i, ones = 0;
@@ -418,13 +417,20 @@ static int intel_hdcp_auth(struct intel_connector *connector)
u32 reg;
u8 shim[DRM_HDCP_RI_LEN];
} ri;
- bool repeater_present;
+ bool repeater_present, hdcp_capable;
const struct intel_hdcp_shim *shim = connector->hdcp_shim;
struct intel_digital_port *intel_dig_port = conn_to_dig_port(connector);

dev_priv = to_i915(connector->base.dev);
port = intel_dig_port->base.port;

+ /* Detect whether panel is HDCP capable or not */
+ ret = shim->hdcp_capable(intel_dig_port, &hdcp_capable);
+ if (ret)
+ return ret;
+ if (!hdcp_capable)
+ return -EINVAL;
+
/* Initialize An with 2 random values and acquire it */
for (i = 0; i < 2; i++)
I915_WRITE(PORT_HDCP_ANINIT(port), get_random_u32());
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index f5d7bfb43006..dfca361ebb24 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -1106,6 +1106,22 @@ bool intel_hdmi_hdcp_check_link(struct intel_digital_port *intel_dig_port)
return true;
}

+static
+int intel_hdmi_hdcp_capable(struct intel_digital_port *intel_dig_port,
+ bool *hdcp_capable)
+{
+ u8 bksv[5];
+ int ret, retry = 1;
+
+ do {
+ ret = intel_hdmi_hdcp_read_bksv(intel_dig_port, bksv);
+ if (!ret)
+ *hdcp_capable = intel_hdcp_is_ksv_valid(bksv);
+ } while (!(*hdcp_capable) && retry--);
+
+ return ret;
+}
+
static const struct intel_hdcp_shim intel_hdmi_hdcp_shim = {
.write_an_aksv = intel_hdmi_hdcp_write_an_aksv,
.read_bksv = intel_hdmi_hdcp_read_bksv,
@@ -1117,6 +1133,7 @@ static const struct intel_hdcp_shim intel_hdmi_hdcp_shim = {
.read_v_prime_part = intel_hdmi_hdcp_read_v_prime_part,
.toggle_signalling = intel_hdmi_hdcp_toggle_signalling,
.check_link = intel_hdmi_hdcp_check_link,
+ .hdcp_capable = intel_hdmi_hdcp_capable,
};

static void intel_hdmi_prepare(struct intel_encoder *encoder,
--
2.7.4