mirror of
https://github.com/torvalds/linux.git
synced 2026-06-03 20:14:06 +02:00
drm/i915/hdcp: HDCP stream encryption support
Both HDCP_{1.x,2.x} requires to select/deselect Multistream HDCP bit
in TRANS_DDI_FUNC_CTL in order to enable/disable stream HDCP
encryption over DP MST Transport Link.
HDCP 1.4 stream encryption requires to validate the stream encryption
status in HDCP_STATUS_{TRANSCODER,PORT} register driving that link
in order to enable/disable the stream encryption.
Both of above requirement are same for all Gen with respect to
B.Spec Documentation.
v2:
- Cosmetic changes function name, error msg print and
stream typo fixes. [Uma]
v3:
- uniformity for connector detail in DMESG. [Ram]
Cc: Ramalingam C <ramalingam.c@intel.com>
Reviewed-by: Uma Shankar <uma.shankar@intel.com>
Reviewed-by: Ramalingam C <ramalingam.c@intel.com>
Tested-by: Karthik B S <karthik.b.s@intel.com>
Signed-off-by: Anshuman Gupta <anshuman.gupta@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20210111081120.28417-8-anshuman.gupta@intel.com
This commit is contained in:
parent
fbf652bdb4
commit
1a67a168f5
|
|
@ -2099,9 +2099,9 @@ void intel_ddi_disable_transcoder_func(const struct intel_crtc_state *crtc_state
|
|||
}
|
||||
}
|
||||
|
||||
int intel_ddi_toggle_hdcp_signalling(struct intel_encoder *intel_encoder,
|
||||
enum transcoder cpu_transcoder,
|
||||
bool enable)
|
||||
int intel_ddi_toggle_hdcp_bits(struct intel_encoder *intel_encoder,
|
||||
enum transcoder cpu_transcoder,
|
||||
bool enable, u32 hdcp_mask)
|
||||
{
|
||||
struct drm_device *dev = intel_encoder->base.dev;
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
|
|
@ -2116,9 +2116,9 @@ int intel_ddi_toggle_hdcp_signalling(struct intel_encoder *intel_encoder,
|
|||
|
||||
tmp = intel_de_read(dev_priv, TRANS_DDI_FUNC_CTL(cpu_transcoder));
|
||||
if (enable)
|
||||
tmp |= TRANS_DDI_HDCP_SIGNALLING;
|
||||
tmp |= hdcp_mask;
|
||||
else
|
||||
tmp &= ~TRANS_DDI_HDCP_SIGNALLING;
|
||||
tmp &= ~hdcp_mask;
|
||||
intel_de_write(dev_priv, TRANS_DDI_FUNC_CTL(cpu_transcoder), tmp);
|
||||
intel_display_power_put(dev_priv, intel_encoder->power_domain, wakeref);
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -50,9 +50,9 @@ u32 bxt_signal_levels(struct intel_dp *intel_dp,
|
|||
const struct intel_crtc_state *crtc_state);
|
||||
u32 ddi_signal_levels(struct intel_dp *intel_dp,
|
||||
const struct intel_crtc_state *crtc_state);
|
||||
int intel_ddi_toggle_hdcp_signalling(struct intel_encoder *intel_encoder,
|
||||
enum transcoder cpu_transcoder,
|
||||
bool enable);
|
||||
int intel_ddi_toggle_hdcp_bits(struct intel_encoder *intel_encoder,
|
||||
enum transcoder cpu_transcoder,
|
||||
bool enable, u32 hdcp_mask);
|
||||
void icl_sanitize_encoder_pll_mapping(struct intel_encoder *encoder);
|
||||
|
||||
#endif /* __INTEL_DDI_H__ */
|
||||
|
|
|
|||
|
|
@ -343,6 +343,10 @@ struct intel_hdcp_shim {
|
|||
enum transcoder cpu_transcoder,
|
||||
bool enable);
|
||||
|
||||
/* Enable/Disable stream encryption on DP MST Transport Link */
|
||||
int (*stream_encryption)(struct intel_connector *connector,
|
||||
bool enable);
|
||||
|
||||
/* Ensures the link is still protected */
|
||||
bool (*check_link)(struct intel_digital_port *dig_port,
|
||||
struct intel_connector *connector);
|
||||
|
|
|
|||
|
|
@ -16,6 +16,30 @@
|
|||
#include "intel_dp.h"
|
||||
#include "intel_hdcp.h"
|
||||
|
||||
static unsigned int transcoder_to_stream_enc_status(enum transcoder cpu_transcoder)
|
||||
{
|
||||
u32 stream_enc_mask;
|
||||
|
||||
switch (cpu_transcoder) {
|
||||
case TRANSCODER_A:
|
||||
stream_enc_mask = HDCP_STATUS_STREAM_A_ENC;
|
||||
break;
|
||||
case TRANSCODER_B:
|
||||
stream_enc_mask = HDCP_STATUS_STREAM_B_ENC;
|
||||
break;
|
||||
case TRANSCODER_C:
|
||||
stream_enc_mask = HDCP_STATUS_STREAM_C_ENC;
|
||||
break;
|
||||
case TRANSCODER_D:
|
||||
stream_enc_mask = HDCP_STATUS_STREAM_D_ENC;
|
||||
break;
|
||||
default:
|
||||
stream_enc_mask = 0;
|
||||
}
|
||||
|
||||
return stream_enc_mask;
|
||||
}
|
||||
|
||||
static void intel_dp_hdcp_wait_for_cp_irq(struct intel_hdcp *hdcp, int timeout)
|
||||
{
|
||||
long ret;
|
||||
|
|
@ -622,24 +646,57 @@ static const struct intel_hdcp_shim intel_dp_hdcp_shim = {
|
|||
};
|
||||
|
||||
static int
|
||||
intel_dp_mst_hdcp_toggle_signalling(struct intel_digital_port *dig_port,
|
||||
enum transcoder cpu_transcoder,
|
||||
bool enable)
|
||||
intel_dp_mst_toggle_hdcp_stream_select(struct intel_connector *connector,
|
||||
bool enable)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
|
||||
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
|
||||
struct drm_i915_private *i915 = to_i915(connector->base.dev);
|
||||
struct intel_hdcp *hdcp = &connector->hdcp;
|
||||
int ret;
|
||||
|
||||
if (!enable)
|
||||
usleep_range(6, 60); /* Bspec says >= 6us */
|
||||
|
||||
ret = intel_ddi_toggle_hdcp_signalling(&dig_port->base,
|
||||
cpu_transcoder, enable);
|
||||
ret = intel_ddi_toggle_hdcp_bits(&dig_port->base,
|
||||
hdcp->stream_transcoder, enable,
|
||||
TRANS_DDI_HDCP_SELECT);
|
||||
if (ret)
|
||||
drm_dbg_kms(&i915->drm, "%s HDCP signalling failed (%d)\n",
|
||||
enable ? "Enable" : "Disable", ret);
|
||||
drm_err(&i915->drm, "%s HDCP stream select failed (%d)\n",
|
||||
enable ? "Enable" : "Disable", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
intel_dp_mst_hdcp_stream_encryption(struct intel_connector *connector,
|
||||
bool enable)
|
||||
{
|
||||
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
|
||||
struct drm_i915_private *i915 = to_i915(connector->base.dev);
|
||||
struct intel_hdcp *hdcp = &connector->hdcp;
|
||||
enum port port = dig_port->base.port;
|
||||
enum transcoder cpu_transcoder = hdcp->stream_transcoder;
|
||||
u32 stream_enc_status;
|
||||
int ret;
|
||||
|
||||
ret = intel_dp_mst_toggle_hdcp_stream_select(connector, enable);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
stream_enc_status = transcoder_to_stream_enc_status(cpu_transcoder);
|
||||
if (!stream_enc_status)
|
||||
return -EINVAL;
|
||||
|
||||
/* Wait for encryption confirmation */
|
||||
if (intel_de_wait_for_register(i915,
|
||||
HDCP_STATUS(i915, cpu_transcoder, port),
|
||||
stream_enc_status,
|
||||
enable ? stream_enc_status : 0,
|
||||
HDCP_ENCRYPT_STATUS_CHANGE_TIMEOUT_MS)) {
|
||||
drm_err(&i915->drm, "Timed out waiting for transcoder: %s stream encryption %s\n",
|
||||
transcoder_name(cpu_transcoder), enable ? "enabled" : "disabled");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
bool intel_dp_mst_hdcp_check_link(struct intel_digital_port *dig_port,
|
||||
struct intel_connector *connector)
|
||||
|
|
@ -656,11 +713,15 @@ bool intel_dp_mst_hdcp_check_link(struct intel_digital_port *dig_port,
|
|||
connector->port, &reply);
|
||||
if (ret) {
|
||||
drm_dbg_kms(&i915->drm,
|
||||
"[CONNECTOR:%d:%s] failed QSES ret=%d\n",
|
||||
connector->base.base.id, connector->base.name, ret);
|
||||
"[%s:%d] failed QSES ret=%d\n",
|
||||
connector->base.name, connector->base.base.id, ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
drm_dbg_kms(&i915->drm, "[%s:%d] QSES stream auth: %d stream enc: %d\n",
|
||||
connector->base.name, connector->base.base.id,
|
||||
reply.auth_completed, reply.encryption_enabled);
|
||||
|
||||
return reply.auth_completed && reply.encryption_enabled;
|
||||
}
|
||||
|
||||
|
|
@ -673,7 +734,8 @@ static const struct intel_hdcp_shim intel_dp_mst_hdcp_shim = {
|
|||
.read_ksv_ready = intel_dp_hdcp_read_ksv_ready,
|
||||
.read_ksv_fifo = intel_dp_hdcp_read_ksv_fifo,
|
||||
.read_v_prime_part = intel_dp_hdcp_read_v_prime_part,
|
||||
.toggle_signalling = intel_dp_mst_hdcp_toggle_signalling,
|
||||
.toggle_signalling = intel_dp_hdcp_toggle_signalling,
|
||||
.stream_encryption = intel_dp_mst_hdcp_stream_encryption,
|
||||
.check_link = intel_dp_mst_hdcp_check_link,
|
||||
.hdcp_capable = intel_dp_hdcp_capable,
|
||||
|
||||
|
|
|
|||
|
|
@ -1494,15 +1494,16 @@ static int kbl_repositioning_enc_en_signal(struct intel_connector *connector,
|
|||
usleep_range(25, 50);
|
||||
}
|
||||
|
||||
ret = intel_ddi_toggle_hdcp_signalling(&dig_port->base, cpu_transcoder,
|
||||
false);
|
||||
ret = intel_ddi_toggle_hdcp_bits(&dig_port->base, cpu_transcoder,
|
||||
false, TRANS_DDI_HDCP_SIGNALLING);
|
||||
if (ret) {
|
||||
drm_err(&dev_priv->drm,
|
||||
"Disable HDCP signalling failed (%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
ret = intel_ddi_toggle_hdcp_signalling(&dig_port->base, cpu_transcoder,
|
||||
true);
|
||||
|
||||
ret = intel_ddi_toggle_hdcp_bits(&dig_port->base, cpu_transcoder,
|
||||
true, TRANS_DDI_HDCP_SIGNALLING);
|
||||
if (ret) {
|
||||
drm_err(&dev_priv->drm,
|
||||
"Enable HDCP signalling failed (%d)\n", ret);
|
||||
|
|
@ -1525,8 +1526,9 @@ int intel_hdmi_hdcp_toggle_signalling(struct intel_digital_port *dig_port,
|
|||
if (!enable)
|
||||
usleep_range(6, 60); /* Bspec says >= 6us */
|
||||
|
||||
ret = intel_ddi_toggle_hdcp_signalling(&dig_port->base, cpu_transcoder,
|
||||
enable);
|
||||
ret = intel_ddi_toggle_hdcp_bits(&dig_port->base,
|
||||
cpu_transcoder, enable,
|
||||
TRANS_DDI_HDCP_SIGNALLING);
|
||||
if (ret) {
|
||||
drm_err(&dev_priv->drm, "%s HDCP signalling failed (%d)\n",
|
||||
enable ? "Enable" : "Disable", ret);
|
||||
|
|
|
|||
|
|
@ -9960,6 +9960,7 @@ enum skl_power_gate {
|
|||
#define TRANS_DDI_DP_VC_PAYLOAD_ALLOC (1 << 8)
|
||||
#define TRANS_DDI_HDMI_SCRAMBLER_CTS_ENABLE (1 << 7)
|
||||
#define TRANS_DDI_HDMI_SCRAMBLER_RESET_FREQ (1 << 6)
|
||||
#define TRANS_DDI_HDCP_SELECT REG_BIT(5)
|
||||
#define TRANS_DDI_BFI_ENABLE (1 << 4)
|
||||
#define TRANS_DDI_HIGH_TMDS_CHAR_RATE (1 << 4)
|
||||
#define TRANS_DDI_HDMI_SCRAMBLING (1 << 0)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user