diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
index 2c4dfc8..593a5b9 100644
--- a/drivers/gpu/drm/bridge/dw_hdmi.c
+++ b/drivers/gpu/drm/bridge/dw_hdmi.c
@@ -53,6 +53,13 @@ enum hdmi_datamap {
YCbCr422_12B = 0x12,
};
+enum dw_hdmi_hdcp_state {
+ DW_HDMI_HDCP_STATE_DISABLED,
+ DW_HDMI_HDCP_STATE_AUTH_START,
+ DW_HDMI_HDCP_STATE_AUTH_DONE,
+ DW_HDMI_HDCP_STATE_ENCRY_EN,
+};
+
static const u16 csc_coeff_default[3][4] = {
{ 0x2000, 0x0000, 0x0000, 0x0000 },
{ 0x0000, 0x2000, 0x0000, 0x0000 },@@ -97,7 +104,6 @@ struct hdmi_data_info {
unsigned int enc_color_depth;
unsigned int colorimetry;
unsigned int pix_repet_factor;
- unsigned int hdcp_enable;
struct hdmi_vmode video_mode;
};
@@ -154,6 +160,14 @@ struct dw_hdmi {
unsigned int audio_n;
bool audio_enable;
+ /* this mutex is used for sync hdcp key content */
+ struct mutex hdcp_key_mutex;
+ struct dw_hdmi_hdcp_key_1x hdcp_key;
+ bool is_hdcp_key_present;
+
+ struct mutex hdcp_state_mutex;
+ enum dw_hdmi_hdcp_state hdcp_state;
+
void (*write)(struct dw_hdmi *hdmi, u8 val, int offset);
u8 (*read)(struct dw_hdmi *hdmi, int offset);
};@@ -1087,23 +1101,195 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi)
return 0;
}
-static void hdmi_tx_hdcp_config(struct dw_hdmi *hdmi)
+static int hdmi_hdcp_wait_rmsts_ok(struct dw_hdmi *hdmi)
{
- u8 de;
+ unsigned long timeout;
- if (hdmi->hdmi_data.video_mode.mdataenablepolarity)
- de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_HIGH;
- else
- de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_LOW;
+ timeout = jiffies + msecs_to_jiffies(100);
+ while ((hdmi_readb(hdmi, HDMI_HDCPREG_RMSTS) & DPK_WR_OK_STS) == 0) {
+ if (time_after(jiffies, timeout))
+ return -EBUSY;
+ usleep_range(10, 15);
+ }
+
+ return 0;
+}
+
+static int _hdmi_write_hdcp_key(struct dw_hdmi *hdmi)
+{
+ struct dw_hdmi_hdcp_key_1x *key = &hdmi->hdcp_key;
+ int i, j;
+ int ret;
+
+ /* Disable decryption logic */
+ hdmi_writeb(hdmi, 0, HDMI_HDCPREG_RMCTL);
+ ret = hdmi_hdcp_wait_rmsts_ok(hdmi);
+ if (ret)
+ return ret;
+
+ /* The useful data in ksv should be 5 byte */
+ for (i = 4; i >= 0; i--)
+ hdmi_writeb(hdmi, key->ksv[i], HDMI_HDCPREG_DPK0 + i);
+
+ ret = hdmi_hdcp_wait_rmsts_ok(hdmi);
+ if (ret)
+ return ret;
+
+ /* Enable decryption logic */
+ hdmi_writeb(hdmi, 1, HDMI_HDCPREG_RMCTL);
+ hdmi_writeb(hdmi, key->seed[1], HDMI_HDCPREG_SEED1);
+ hdmi_writeb(hdmi, key->seed[0], HDMI_HDCPREG_SEED0);
+
+ /* Write encrypt device private key */
+ for (i = 0; i < DW_HDMI_HDCP_DPK_LEN - 6; i += 7) {
+ for (j = 6; j >= 0; j--)
+ hdmi_writeb(hdmi, key->device_key[i + j],
+ HDMI_HDCPREG_DPK0 + j);
+ ret = hdmi_hdcp_wait_rmsts_ok(hdmi);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static void _hdmi_close_hdcp_auth(struct dw_hdmi *hdmi)
+{
+ WARN_ON(!mutex_is_locked(&hdmi->hdcp_state_mutex));
+
+ /* Disable hdcp encryption */
+ hdmi_modb(hdmi, HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_DISABLE,
+ HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK, HDMI_A_HDCPCFG1);
- /* disable rx detect */
+ /* Disable the RX detect */
hdmi_modb(hdmi, HDMI_A_HDCPCFG0_RXDETECT_DISABLE,
HDMI_A_HDCPCFG0_RXDETECT_MASK, HDMI_A_HDCPCFG0);
- hdmi_modb(hdmi, de, HDMI_A_VIDPOLCFG_DATAENPOL_MASK, HDMI_A_VIDPOLCFG);
+ hdmi->hdcp_state = DW_HDMI_HDCP_STATE_DISABLED;
+}
+
+static void _hdmi_start_hdcp_auth(struct dw_hdmi *hdmi)
+{
+ WARN_ON(!mutex_is_locked(&hdmi->hdcp_state_mutex));
+
+ /* Make sure RX detect is off before we start */
+ _hdmi_close_hdcp_auth(hdmi);
+
+ /* Enable the RX detect; expect an interrupt after this */
+ hdmi_modb(hdmi, HDMI_A_HDCPCFG0_RXDETECT_ENABLE,
+ HDMI_A_HDCPCFG0_RXDETECT_MASK, HDMI_A_HDCPCFG0);
+ hdmi->hdcp_state = DW_HDMI_HDCP_STATE_AUTH_START;
+}
+
+static void _hdmi_enable_hdcp_encry(struct dw_hdmi *hdmi)
+{
+ WARN_ON(!mutex_is_locked(&hdmi->hdcp_state_mutex));
+ WARN_ON(hdmi->hdcp_state != DW_HDMI_HDCP_STATE_AUTH_DONE);
+
+ /* Enable hdcp encryption */
+ hdmi_modb(hdmi, HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_ENABLE,
+ HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK, HDMI_A_HDCPCFG1);
+
+ hdmi->hdcp_state = DW_HDMI_HDCP_STATE_ENCRY_EN;
+}
+
+static void hdmi_disable_hdcp_encry(struct dw_hdmi *hdmi)
+{
+ mutex_lock(&hdmi->hdcp_state_mutex);
+
+ /* Disable hdcp encryption */
hdmi_modb(hdmi, HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_DISABLE,
HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK, HDMI_A_HDCPCFG1);
+
+ /*
+ * Leaving things authed, so keep track of state; note that if we turn
+ * off auth here we blink the screen.
+ */
+ if (hdmi->hdcp_state == DW_HDMI_HDCP_STATE_ENCRY_EN)
+ hdmi->hdcp_state = DW_HDMI_HDCP_STATE_AUTH_DONE;
+
+ mutex_unlock(&hdmi->hdcp_state_mutex);
+}
+
+static int _hdmi_set_hdcp_status_drm_property(struct dw_hdmi *hdmi, bool enable)
+{
+ struct drm_connector *connector = &hdmi->connector;
+ struct drm_mode_config *mc = &connector->dev->mode_config;
+ uint64_t ksv = 0;
+ int i;
+
+ WARN_ON(!mutex_is_locked(&mc->mutex));
+
+ for (i = 0; i > DW_HDMI_HDCP_KSV_LEN; i--)
+ ksv |= hdmi->hdcp_key.ksv[i] << 8 * i;
+
+ ksv = enable ? ksv : 0;
+
+ return drm_object_property_set_value(&connector->base,
+ mc->content_protection_ksv_property,
+ ksv);
+}
+
+static void hdmi_tx_hdcp_config(struct dw_hdmi *hdmi,
+ const struct drm_display_mode *mode)
+{
+ struct hdmi_vmode *vmode = &hdmi->hdmi_data.video_mode;
+ u8 vsync_pol, hsync_pol, data_pol, hdmi_dvi;
+
+ /* Reset HDCP Engine */
+ hdmi_modb(hdmi, HDMI_A_HDCPCFG1_SWRESET_ASSERT,
+ HDMI_A_HDCPCFG1_SWRESET_MASK, HDMI_A_HDCPCFG1);
+
+ /* Configure the video polarity */
+ vsync_pol = mode->flags & DRM_MODE_FLAG_PVSYNC ?
+ HDMI_A_VIDPOLCFG_VSYNCPOL_ACTIVE_HIGH :
+ HDMI_A_VIDPOLCFG_VSYNCPOL_ACTIVE_LOW;
+ hsync_pol = mode->flags & DRM_MODE_FLAG_PHSYNC ?
+ HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_HIGH :
+ HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_LOW;
+ data_pol = vmode->mdataenablepolarity ?
+ HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_HIGH :
+ HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_LOW;
+ hdmi_modb(hdmi, vsync_pol | hsync_pol | data_pol,
+ HDMI_A_VIDPOLCFG_VSYNCPOL_MASK |
+ HDMI_A_VIDPOLCFG_HSYNCPOL_MASK |
+ HDMI_A_VIDPOLCFG_DATAENPOL_MASK,
+ HDMI_A_VIDPOLCFG);
+
+ /* Config the display mode */
+ hdmi_dvi = hdmi->sink_is_hdmi ? HDMI_A_HDCPCFG0_HDMIDVI_HDMI :
+ HDMI_A_HDCPCFG0_HDMIDVI_DVI;
+ hdmi_modb(hdmi, hdmi_dvi, HDMI_A_HDCPCFG0_HDMIDVI_MASK,
+ HDMI_A_HDCPCFG0);
+
+ /* vendor suggest that a_oesswcfg should write this magic number */
+ hdmi_writeb(hdmi, 0x40, HDMI_A_OESSWCFG);
+
+ hdmi_modb(hdmi, HDMI_A_HDCPCFG0_BYPENCRYPTION_DISABLE |
+ HDMI_A_HDCPCFG0_EN11FEATURE_DISABLE |
+ HDMI_A_HDCPCFG0_SYNCRICHECK_ENABLE,
+ HDMI_A_HDCPCFG0_BYPENCRYPTION_MASK |
+ HDMI_A_HDCPCFG0_EN11FEATURE_MASK |
+ HDMI_A_HDCPCFG0_SYNCRICHECK_MASK, HDMI_A_HDCPCFG0);
+
+ hdmi_modb(hdmi, HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_DISABLE |
+ HDMI_A_HDCPCFG1_PH2UPSHFTENC_ENABLE,
+ HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK |
+ HDMI_A_HDCPCFG1_PH2UPSHFTENC_MASK, HDMI_A_HDCPCFG1);
+
+ hdmi_modb(hdmi, HDMI_FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE,
+ HDMI_FC_INVIDCONF_HDCP_KEEPOUT_MASK, HDMI_FC_INVIDCONF);
+
+ /* enable hdcp clock */
+ hdmi_modb(hdmi, 0x00, HDMI_MC_CLKDIS_HDCPCLK_DISABLE, HDMI_MC_CLKDIS);
+
+ mutex_lock(&hdmi->hdcp_state_mutex);
+ if (hdmi->hdcp_state == DW_HDMI_HDCP_STATE_DISABLED)
+ _hdmi_close_hdcp_auth(hdmi);
+ else
+ _hdmi_start_hdcp_auth(hdmi);
+ mutex_unlock(&hdmi->hdcp_state_mutex);
}
static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode)@@ -1218,11 +1404,7 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
dev_dbg(hdmi->dev, "final pixclk = %d\n", vmode->mpixelclock);
/* Set up HDMI_FC_INVIDCONF */
- inv_val = (hdmi->hdmi_data.hdcp_enable ?
- HDMI_FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE :
- HDMI_FC_INVIDCONF_HDCP_KEEPOUT_INACTIVE);
-
- inv_val |= mode->flags & DRM_MODE_FLAG_PVSYNC ?
+ inv_val = mode->flags & DRM_MODE_FLAG_PVSYNC ?
HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_HIGH :
HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_LOW;
@@ -1409,7 +1591,6 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
hdmi->hdmi_data.enc_color_depth = 8;
hdmi->hdmi_data.pix_repet_factor = 0;
- hdmi->hdmi_data.hdcp_enable = 0;
hdmi->hdmi_data.video_mode.mdataenablepolarity = true;
/* HDMI Initialization Step B.1 */
@@ -1444,7 +1625,7 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
hdmi_video_packetize(hdmi);
hdmi_video_csc(hdmi);
hdmi_video_sample(hdmi);
- hdmi_tx_hdcp_config(hdmi);
+ hdmi_tx_hdcp_config(hdmi, mode);
dw_hdmi_clear_overflow(hdmi);
if (hdmi->cable_plugin && hdmi->sink_is_hdmi)
@@ -1470,6 +1651,10 @@ static int dw_hdmi_fb_registered(struct dw_hdmi *hdmi)
hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE,
HDMI_IH_PHY_STAT0);
+ /* Unmask HDCP engaged interrupt */
+ hdmi_writeb(hdmi, (u8)~HDMI_A_APIINTSTAT_HDCP_ENGAGED,
+ HDMI_A_APIINTMSK);
+
return 0;
}
@@ -1614,6 +1799,20 @@ static void dw_hdmi_bridge_disable(struct drm_bridge *bridge)
dw_hdmi_update_power(hdmi);
dw_hdmi_update_phy_mask(hdmi);
mutex_unlock(&hdmi->mutex);
+
+ mutex_lock(&hdmi->hdcp_state_mutex);
+ if (hdmi->hdcp_state != DW_HDMI_HDCP_STATE_DISABLED) {
+ /*
+ * We can ensure each time HDMI unplug/suspend, bridge
+ * disable would be called by the drm framework with mode
+ * config locked, so we just need to maintain the HDCP
+ * desiredness here.
+ */
+ if (hdmi->hdcp_state == DW_HDMI_HDCP_STATE_ENCRY_EN)
+ _hdmi_set_hdcp_status_drm_property(hdmi, false);
+ _hdmi_close_hdcp_auth(hdmi);
+ }
+ mutex_unlock(&hdmi->hdcp_state_mutex);
}
static void dw_hdmi_bridge_enable(struct drm_bridge *bridge)@@ -1722,12 +1921,61 @@ static void dw_hdmi_connector_force(struct drm_connector *connector)
mutex_unlock(&hdmi->mutex);
}
+static void dw_hdmi_set_content_protection(struct dw_hdmi *hdmi, uint64_t val)
+{
+ /*
+ * For enable: we start authentication. When that finishes we'll
+ * get an interrupt and turn on encryption.
+ *
+ * For disable: we just turn off encryption. There's no need to
+ * undo the HDCP auth.
+ */
+
+ switch (val) {
+ case DRM_MODE_CONTENT_PROTECTION_UNDESIRED:
+ hdmi_disable_hdcp_encry(hdmi);
+ break;
+
+ case DRM_MODE_CONTENT_PROTECTION_DESIRED:
+ /*
+ * Start auth over even if at DW_HDMI_HDCP_STATE_AUTH_DONE
+ * since we need the interrupt where we'll set
+ * DRM_MODE_CONTENT_PROTECTION_ENABLED. We don't wan to set
+ * it here because we'd need to grab the mode_config mutex and
+ * that could lead to deadlock.
+ */
+ mutex_lock(&hdmi->hdcp_state_mutex);
+ _hdmi_start_hdcp_auth(hdmi);
+ mutex_unlock(&hdmi->hdcp_state_mutex);
+
+ break;
+ default:
+ WARN_ON(1);
+ }
+}
+
+static int dw_hdmi_connector_set_property(struct drm_connector *connector,
+ struct drm_property *property,
+ uint64_t val)
+{
+ struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi,
+ connector);
+
+ DRM_DEBUG_KMS("[PROPERTY:%s] = %llu\n", property->name, val);
+
+ if (strcmp(property->name, "Content Protection") == 0)
+ dw_hdmi_set_content_protection(hdmi, val);
+
+ return 0;
+}
+
static struct drm_connector_funcs dw_hdmi_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
.detect = dw_hdmi_connector_detect,
.destroy = dw_hdmi_connector_destroy,
.force = dw_hdmi_connector_force,
+ .set_property = dw_hdmi_connector_set_property,
};
static struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = {@@ -1766,16 +2014,22 @@ static irqreturn_t dw_hdmi_i2c_irq(struct dw_hdmi *hdmi)
static irqreturn_t dw_hdmi_hardirq(int irq, void *dev_id)
{
struct dw_hdmi *hdmi = dev_id;
- u8 intr_stat;
+ u8 intr_stat, hdcp_stat;
irqreturn_t ret = IRQ_NONE;
if (hdmi->i2c)
ret = dw_hdmi_i2c_irq(hdmi);
+ hdcp_stat = hdmi_readb(hdmi, HDMI_A_APIINTSTAT);
+ if (hdcp_stat & HDMI_A_APIINTSTAT_HDCP_ENGAGED) {
+ hdmi_writeb(hdmi, ~0, HDMI_A_APIINTMSK);
+ ret = IRQ_WAKE_THREAD;
+ }
+
intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0);
if (intr_stat) {
hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
- return IRQ_WAKE_THREAD;
+ ret = IRQ_WAKE_THREAD;
}
return ret;@@ -1784,7 +2038,7 @@ static irqreturn_t dw_hdmi_hardirq(int irq, void *dev_id)
static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
{
struct dw_hdmi *hdmi = dev_id;
- u8 intr_stat, phy_int_pol, phy_pol_mask, phy_stat;
+ u8 intr_stat, phy_int_pol, phy_pol_mask, phy_stat, hdcp_stat;
intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0);
phy_int_pol = hdmi_readb(hdmi, HDMI_PHY_POL0);@@ -1844,9 +2098,33 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
drm_helper_hpd_irq_event(hdmi->bridge->dev);
}
+ hdcp_stat = hdmi_readb(hdmi, HDMI_A_APIINTSTAT);
+ if (hdcp_stat & HDMI_A_APIINTSTAT_HDCP_ENGAGED) {
+ hdmi_writeb(hdmi, HDMI_A_APIINTSTAT_HDCP_ENGAGED,
+ HDMI_A_APIINTCLR);
+ hdcp_stat &= ~HDMI_A_APIINTSTAT_HDCP_ENGAGED;
+
+ /* Always grab mode config mutex before state mutex */
+ mutex_lock(&hdmi->connector.dev->mode_config.mutex);
+ mutex_lock(&hdmi->hdcp_state_mutex);
+ hdmi->hdcp_state = DW_HDMI_HDCP_STATE_AUTH_DONE;
+ _hdmi_enable_hdcp_encry(hdmi);
+ _hdmi_set_hdcp_status_drm_property(hdmi, true);
+ mutex_unlock(&hdmi->hdcp_state_mutex);
+ mutex_unlock(&hdmi->connector.dev->mode_config.mutex);
+ }
+
+ if (hdcp_stat) {
+ dev_dbg(hdmi->dev, "Unexpected HDCP irq %#x\n", hdcp_stat);
+ hdmi_writeb(hdmi, hdcp_stat, HDMI_A_APIINTCLR);
+ }
+
hdmi_writeb(hdmi, intr_stat, HDMI_IH_PHY_STAT0);
hdmi_writeb(hdmi, ~(HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE),
HDMI_IH_MUTE_PHY_STAT0);
+ hdmi_writeb(hdmi, (u8)~HDMI_A_APIINTSTAT_HDCP_ENGAGED,
+ HDMI_A_APIINTMSK);
+
return IRQ_HANDLED;
}@@ -1854,6 +2132,7 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi)
{
struct drm_encoder *encoder = hdmi->encoder;
+ struct drm_mode_config *mode_config;
struct drm_bridge *bridge;
int ret;
@@ -1880,6 +2159,11 @@ static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi)
drm_connector_init(drm, &hdmi->connector, &dw_hdmi_connector_funcs,
DRM_MODE_CONNECTOR_HDMIA);
+ mode_config = &hdmi->connector.dev->mode_config;
+ drm_object_attach_property(&hdmi->connector.base,
+ mode_config->content_protection_property,
+ DRM_MODE_CONTENT_PROTECTION_UNDESIRED);
+
hdmi->connector.encoder = encoder;
drm_mode_connector_attach_encoder(&hdmi->connector, encoder);
@@ -1887,6 +2171,36 @@ static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi)
return 0;
}
+int dw_hdmi_config_hdcp_key(struct device *dev,
+ const struct dw_hdmi_hdcp_key_1x *keys)
+{
+ struct dw_hdmi *hdmi = dev_get_drvdata(dev);
+ int ret;
+
+ if (!keys)
+ return -EINVAL;
+
+ mutex_lock(&hdmi->hdcp_key_mutex);
+
+ if (hdmi->is_hdcp_key_present) {
+ mutex_unlock(&hdmi->hdcp_key_mutex);
+ return -EBUSY;
+ }
+
+ hdmi->is_hdcp_key_present = true;
+ hdmi->hdcp_key = *keys;
+
+ ret = _hdmi_write_hdcp_key(hdmi);
+ mutex_unlock(&hdmi->hdcp_key_mutex);
+ if (ret) {
+ dev_err(dev, "Failed to write HDCP key to HDMI IP\n");
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(dw_hdmi_config_hdcp_key);
+
int dw_hdmi_bind(struct device *dev, struct device *master,
void *data, struct drm_encoder *encoder,
struct resource *iores, int irq,@@ -1920,6 +2234,9 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
mutex_init(&hdmi->audio_mutex);
spin_lock_init(&hdmi->audio_lock);
+ mutex_init(&hdmi->hdcp_key_mutex);
+ mutex_init(&hdmi->hdcp_state_mutex);
+
of_property_read_u32(np, "reg-io-width", &val);
switch (val) {diff --git a/drivers/gpu/drm/bridge/dw_hdmi.h b/drivers/gpu/drm/bridge/dw_hdmi.h
index 6aadc84..6b43599 100644
--- a/drivers/gpu/drm/bridge/dw_hdmi.h
+++ b/drivers/gpu/drm/bridge/dw_hdmi.h
@@ -478,6 +478,19 @@
#define HDMI_A_PRESETUP 0x501A
#define HDMI_A_SRM_BASE 0x5020
+/* HDCP Registers */
+#define HDMI_HDCPREG_RMCTL 0x780e
+#define HDMI_HDCPREG_RMSTS 0x780f
+#define HDMI_HDCPREG_SEED0 0x7810
+#define HDMI_HDCPREG_SEED1 0x7811
+#define HDMI_HDCPREG_DPK0 0x7812
+#define HDMI_HDCPREG_DPK1 0x7813
+#define HDMI_HDCPREG_DPK2 0x7814
+#define HDMI_HDCPREG_DPK3 0x7815
+#define HDMI_HDCPREG_DPK4 0x7816
+#define HDMI_HDCPREG_DPK5 0x7817
+#define HDMI_HDCPREG_DPK6 0x7818
+
/* CEC Engine Registers */
#define HDMI_CEC_CTRL 0x7D00
#define HDMI_CEC_STAT 0x7D01
@@ -1024,6 +1037,13 @@ enum {
HDMI_A_HDCPCFG1_SWRESET_MASK = 0x1,
HDMI_A_HDCPCFG1_SWRESET_ASSERT = 0x0,
+/* HDCPREG_RMSTS field values */
+ DPK_WR_OK_STS = 0x40,
+
+/* A_APIINT_STAT field values */
+ HDMI_A_APIINTSTAT_HDCP_ENGAGED = 0x80,
+ HDMI_A_APIINTSTAT_HDCP_FAILED = 0x40,
+
/* A_VIDPOLCFG field values */
HDMI_A_VIDPOLCFG_UNENCRYPTCONF_MASK = 0x60,
HDMI_A_VIDPOLCFG_UNENCRYPTCONF_OFFSET = 5,diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index bae79f3..355ec42 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -21,6 +21,14 @@ enum {
DW_HDMI_RES_MAX,
};
+enum {
+ DW_HDMI_HDCP_KSV_LEN = 8,
+ DW_HDMI_HDCP_SHA_LEN = 20,
+ DW_HDMI_HDCP_DPK_LEN = 280,
+ DW_HDMI_HDCP_KEY_LEN = 308,
+ DW_HDMI_HDCP_SEED_LEN = 2,
+};
+
enum dw_hdmi_devtype {
IMX6Q_HDMI,
IMX6DL_HDMI,@@ -47,6 +55,13 @@ struct dw_hdmi_phy_config {
u16 vlev_ctr; /* voltage level control */
};
+struct dw_hdmi_hdcp_key_1x {
+ u8 ksv[DW_HDMI_HDCP_KSV_LEN];
+ u8 device_key[DW_HDMI_HDCP_DPK_LEN];
+ u8 sha1[DW_HDMI_HDCP_SHA_LEN];
+ u8 seed[DW_HDMI_HDCP_SEED_LEN];
+};
+
struct dw_hdmi_plat_data {
enum dw_hdmi_devtype dev_type;
const struct dw_hdmi_mpll_config *mpll_cfg;@@ -65,5 +80,7 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate);
void dw_hdmi_audio_enable(struct dw_hdmi *hdmi);
void dw_hdmi_audio_disable(struct dw_hdmi *hdmi);
+int dw_hdmi_config_hdcp_key(struct device *dev,
+ const struct dw_hdmi_hdcp_key_1x *keys);
#endif /* __IMX_HDMI_H__ */
--
1.9.1
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel