Skip to content

Commit

Permalink
Merge tag 'topic/hdcp-2018-02-13' of git://anongit.freedesktop.org/dr…
Browse files Browse the repository at this point in the history
…m/drm-misc into drm-next

Add HDCP support to i915 drm driver.

* tag 'topic/hdcp-2018-02-13' of git://anongit.freedesktop.org/drm/drm-misc: (26 commits)
  drm/i915: fix misalignment in HDCP register def
  drm/i915: Reauthenticate HDCP on failure
  drm/i915: Detect panel's hdcp capability
  drm/i915: Optimize HDCP key load
  drm/i915: Retry HDCP bksv read
  drm/i915: Connector info in HDCP debug msgs
  drm/i915: Stop encryption for repeater with no sink
  drm/i915: Handle failure from 2nd stage HDCP auth
  drm/i915: Downgrade hdcp logs from INFO to DEBUG_KMS
  drm/i915: Restore HDCP DRM_INFO when with no downstream
  drm/i915: Check for downstream topology errors
  drm/i915: Start repeater auth on READY/CP_IRQ
  drm/i915: II stage HDCP auth for repeater only
  drm/i915: Extending HDCP for HSW, BDW and BXT+
  drm/i915/dp: Fix compilation of intel_dp_hdcp_check_link
  drm/i915: Only disable HDCP when it's active
  drm/i915: Don't allow HDCP on PORT E/F
  drm/i915: Implement HDCP for DisplayPort
  drm/i915: Implement HDCP for HDMI
  drm/i915: Add function to output Aksv over GMBUS
  ...
  • Loading branch information
airlied committed Feb 15, 2018
2 parents 76ea0f3 + 2834d9d commit 933519a
Show file tree
Hide file tree
Showing 19 changed files with 1,820 additions and 43 deletions.
8 changes: 8 additions & 0 deletions drivers/gpu/drm/drm_atomic.c
Original file line number Diff line number Diff line change
Expand Up @@ -1224,6 +1224,12 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector,
state->picture_aspect_ratio = val;
} else if (property == connector->scaling_mode_property) {
state->scaling_mode = val;
} else if (property == connector->content_protection_property) {
if (val == DRM_MODE_CONTENT_PROTECTION_ENABLED) {
DRM_DEBUG_KMS("only drivers can set CP Enabled\n");
return -EINVAL;
}
state->content_protection = val;
} else if (connector->funcs->atomic_set_property) {
return connector->funcs->atomic_set_property(connector,
state, property, val);
Expand Down Expand Up @@ -1303,6 +1309,8 @@ drm_atomic_connector_get_property(struct drm_connector *connector,
*val = state->picture_aspect_ratio;
} else if (property == connector->scaling_mode_property) {
*val = state->scaling_mode;
} else if (property == connector->content_protection_property) {
*val = state->content_protection;
} else if (connector->funcs->atomic_get_property) {
return connector->funcs->atomic_get_property(connector,
state, property, val);
Expand Down
87 changes: 83 additions & 4 deletions drivers/gpu/drm/drm_connector.c
Original file line number Diff line number Diff line change
Expand Up @@ -761,6 +761,13 @@ static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = {
DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name,
drm_tv_subconnector_enum_list)

static struct drm_prop_enum_list drm_cp_enum_list[] = {
{ DRM_MODE_CONTENT_PROTECTION_UNDESIRED, "Undesired" },
{ DRM_MODE_CONTENT_PROTECTION_DESIRED, "Desired" },
{ DRM_MODE_CONTENT_PROTECTION_ENABLED, "Enabled" },
};
DRM_ENUM_NAME_FN(drm_get_content_protection_name, drm_cp_enum_list)

/**
* DOC: standard connector properties
*
Expand Down Expand Up @@ -822,14 +829,50 @@ DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name,
* should update this value using drm_mode_connector_set_tile_property().
* Userspace cannot change this property.
* link-status:
* Connector link-status property to indicate the status of link. The default
* value of link-status is "GOOD". If something fails during or after modeset,
* the kernel driver may set this to "BAD" and issue a hotplug uevent. Drivers
* should update this value using drm_mode_connector_set_link_status_property().
* Connector link-status property to indicate the status of link. The
* default value of link-status is "GOOD". If something fails during or
* after modeset, the kernel driver may set this to "BAD" and issue a
* hotplug uevent. Drivers should update this value using
* drm_mode_connector_set_link_status_property().
* non_desktop:
* Indicates the output should be ignored for purposes of displaying a
* standard desktop environment or console. This is most likely because
* the output device is not rectilinear.
* Content Protection:
* This property is used by userspace to request the kernel protect future
* content communicated over the link. When requested, kernel will apply
* the appropriate means of protection (most often HDCP), and use the
* property to tell userspace the protection is active.
*
* Drivers can set this up by calling
* drm_connector_attach_content_protection_property() on initialization.
*
* The value of this property can be one of the following:
*
* - DRM_MODE_CONTENT_PROTECTION_UNDESIRED = 0
* The link is not protected, content is transmitted in the clear.
* - DRM_MODE_CONTENT_PROTECTION_DESIRED = 1
* Userspace has requested content protection, but the link is not
* currently protected. When in this state, kernel should enable
* Content Protection as soon as possible.
* - DRM_MODE_CONTENT_PROTECTION_ENABLED = 2
* Userspace has requested content protection, and the link is
* protected. Only the driver can set the property to this value.
* If userspace attempts to set to ENABLED, kernel will return
* -EINVAL.
*
* A few guidelines:
*
* - DESIRED state should be preserved until userspace de-asserts it by
* setting the property to UNDESIRED. This means ENABLED should only
* transition to UNDESIRED when the user explicitly requests it.
* - If the state is DESIRED, kernel should attempt to re-authenticate the
* link whenever possible. This includes across disable/enable, dpms,
* hotplug, downstream device changes, link status failures, etc..
* - Userspace is responsible for polling the property to determine when
* the value transitions from ENABLED to DESIRED. This signifies the link
* is no longer protected and userspace should take appropriate action
* (whatever that might be).
*
* Connectors also have one standardized atomic property:
*
Expand Down Expand Up @@ -1130,6 +1173,42 @@ int drm_connector_attach_scaling_mode_property(struct drm_connector *connector,
}
EXPORT_SYMBOL(drm_connector_attach_scaling_mode_property);

/**
* drm_connector_attach_content_protection_property - attach content protection
* property
*
* @connector: connector to attach CP property on.
*
* This is used to add support for content protection on select connectors.
* Content Protection is intentionally vague to allow for different underlying
* technologies, however it is most implemented by HDCP.
*
* The content protection will be set to &drm_connector_state.content_protection
*
* Returns:
* Zero on success, negative errno on failure.
*/
int drm_connector_attach_content_protection_property(
struct drm_connector *connector)
{
struct drm_device *dev = connector->dev;
struct drm_property *prop;

prop = drm_property_create_enum(dev, 0, "Content Protection",
drm_cp_enum_list,
ARRAY_SIZE(drm_cp_enum_list));
if (!prop)
return -ENOMEM;

drm_object_attach_property(&connector->base, prop,
DRM_MODE_CONTENT_PROTECTION_UNDESIRED);

connector->content_protection_property = prop;

return 0;
}
EXPORT_SYMBOL(drm_connector_attach_content_protection_property);

/**
* drm_mode_create_aspect_ratio_property - create aspect ratio property
* @dev: DRM device
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/i915/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ i915-y += intel_audio.o \
intel_fbc.o \
intel_fifo_underrun.o \
intel_frontbuffer.o \
intel_hdcp.o \
intel_hotplug.o \
intel_modes.o \
intel_overlay.o \
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/i915/i915_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -3661,6 +3661,7 @@ extern int intel_setup_gmbus(struct drm_i915_private *dev_priv);
extern void intel_teardown_gmbus(struct drm_i915_private *dev_priv);
extern bool intel_gmbus_is_valid_pin(struct drm_i915_private *dev_priv,
unsigned int pin);
extern int intel_gmbus_output_aksv(struct i2c_adapter *adapter);

extern struct i2c_adapter *
intel_gmbus_get_adapter(struct drm_i915_private *dev_priv, unsigned int pin);
Expand Down
85 changes: 85 additions & 0 deletions drivers/gpu/drm/i915/i915_reg.h
Original file line number Diff line number Diff line change
Expand Up @@ -3074,6 +3074,7 @@ enum i915_power_well_id {
# define GPIO_DATA_PULLUP_DISABLE (1 << 13)

#define GMBUS0 _MMIO(dev_priv->gpio_mmio_base + 0x5100) /* clock/port select */
#define GMBUS_AKSV_SELECT (1<<11)
#define GMBUS_RATE_100KHZ (0<<8)
#define GMBUS_RATE_50KHZ (1<<8)
#define GMBUS_RATE_400KHZ (2<<8) /* reserved on Pineview */
Expand Down Expand Up @@ -8165,6 +8166,7 @@ enum {
#define GEN9_MEM_LATENCY_LEVEL_1_5_SHIFT 8
#define GEN9_MEM_LATENCY_LEVEL_2_6_SHIFT 16
#define GEN9_MEM_LATENCY_LEVEL_3_7_SHIFT 24
#define SKL_PCODE_LOAD_HDCP_KEYS 0x5
#define SKL_PCODE_CDCLK_CONTROL 0x7
#define SKL_CDCLK_PREPARE_FOR_CHANGE 0x3
#define SKL_CDCLK_READY_FOR_CHANGE 0x1
Expand Down Expand Up @@ -8480,6 +8482,88 @@ enum skl_power_gate {
#define CNL_AUX_ANAOVRD1_ENABLE (1<<16)
#define CNL_AUX_ANAOVRD1_LDO_BYPASS (1<<23)

/* HDCP Key Registers */
#define HDCP_KEY_CONF _MMIO(0x66c00)
#define HDCP_AKSV_SEND_TRIGGER BIT(31)
#define HDCP_CLEAR_KEYS_TRIGGER BIT(30)
#define HDCP_KEY_LOAD_TRIGGER BIT(8)
#define HDCP_KEY_STATUS _MMIO(0x66c04)
#define HDCP_FUSE_IN_PROGRESS BIT(7)
#define HDCP_FUSE_ERROR BIT(6)
#define HDCP_FUSE_DONE BIT(5)
#define HDCP_KEY_LOAD_STATUS BIT(1)
#define HDCP_KEY_LOAD_DONE BIT(0)
#define HDCP_AKSV_LO _MMIO(0x66c10)
#define HDCP_AKSV_HI _MMIO(0x66c14)

/* HDCP Repeater Registers */
#define HDCP_REP_CTL _MMIO(0x66d00)
#define HDCP_DDIB_REP_PRESENT BIT(30)
#define HDCP_DDIA_REP_PRESENT BIT(29)
#define HDCP_DDIC_REP_PRESENT BIT(28)
#define HDCP_DDID_REP_PRESENT BIT(27)
#define HDCP_DDIF_REP_PRESENT BIT(26)
#define HDCP_DDIE_REP_PRESENT BIT(25)
#define HDCP_DDIB_SHA1_M0 (1 << 20)
#define HDCP_DDIA_SHA1_M0 (2 << 20)
#define HDCP_DDIC_SHA1_M0 (3 << 20)
#define HDCP_DDID_SHA1_M0 (4 << 20)
#define HDCP_DDIF_SHA1_M0 (5 << 20)
#define HDCP_DDIE_SHA1_M0 (6 << 20) /* Bspec says 5? */
#define HDCP_SHA1_BUSY BIT(16)
#define HDCP_SHA1_READY BIT(17)
#define HDCP_SHA1_COMPLETE BIT(18)
#define HDCP_SHA1_V_MATCH BIT(19)
#define HDCP_SHA1_TEXT_32 (1 << 1)
#define HDCP_SHA1_COMPLETE_HASH (2 << 1)
#define HDCP_SHA1_TEXT_24 (4 << 1)
#define HDCP_SHA1_TEXT_16 (5 << 1)
#define HDCP_SHA1_TEXT_8 (6 << 1)
#define HDCP_SHA1_TEXT_0 (7 << 1)
#define HDCP_SHA_V_PRIME_H0 _MMIO(0x66d04)
#define HDCP_SHA_V_PRIME_H1 _MMIO(0x66d08)
#define HDCP_SHA_V_PRIME_H2 _MMIO(0x66d0C)
#define HDCP_SHA_V_PRIME_H3 _MMIO(0x66d10)
#define HDCP_SHA_V_PRIME_H4 _MMIO(0x66d14)
#define HDCP_SHA_V_PRIME(h) _MMIO((0x66d04 + h * 4))
#define HDCP_SHA_TEXT _MMIO(0x66d18)

/* HDCP Auth Registers */
#define _PORTA_HDCP_AUTHENC 0x66800
#define _PORTB_HDCP_AUTHENC 0x66500
#define _PORTC_HDCP_AUTHENC 0x66600
#define _PORTD_HDCP_AUTHENC 0x66700
#define _PORTE_HDCP_AUTHENC 0x66A00
#define _PORTF_HDCP_AUTHENC 0x66900
#define _PORT_HDCP_AUTHENC(port, x) _MMIO(_PICK(port, \
_PORTA_HDCP_AUTHENC, \
_PORTB_HDCP_AUTHENC, \
_PORTC_HDCP_AUTHENC, \
_PORTD_HDCP_AUTHENC, \
_PORTE_HDCP_AUTHENC, \
_PORTF_HDCP_AUTHENC) + x)
#define PORT_HDCP_CONF(port) _PORT_HDCP_AUTHENC(port, 0x0)
#define HDCP_CONF_CAPTURE_AN BIT(0)
#define HDCP_CONF_AUTH_AND_ENC (BIT(1) | BIT(0))
#define PORT_HDCP_ANINIT(port) _PORT_HDCP_AUTHENC(port, 0x4)
#define PORT_HDCP_ANLO(port) _PORT_HDCP_AUTHENC(port, 0x8)
#define PORT_HDCP_ANHI(port) _PORT_HDCP_AUTHENC(port, 0xC)
#define PORT_HDCP_BKSVLO(port) _PORT_HDCP_AUTHENC(port, 0x10)
#define PORT_HDCP_BKSVHI(port) _PORT_HDCP_AUTHENC(port, 0x14)
#define PORT_HDCP_RPRIME(port) _PORT_HDCP_AUTHENC(port, 0x18)
#define PORT_HDCP_STATUS(port) _PORT_HDCP_AUTHENC(port, 0x1C)
#define HDCP_STATUS_STREAM_A_ENC BIT(31)
#define HDCP_STATUS_STREAM_B_ENC BIT(30)
#define HDCP_STATUS_STREAM_C_ENC BIT(29)
#define HDCP_STATUS_STREAM_D_ENC BIT(28)
#define HDCP_STATUS_AUTH BIT(21)
#define HDCP_STATUS_ENC BIT(20)
#define HDCP_STATUS_RI_MATCH BIT(19)
#define HDCP_STATUS_R0_READY BIT(18)
#define HDCP_STATUS_AN_READY BIT(17)
#define HDCP_STATUS_CIPHER BIT(16)
#define HDCP_STATUS_FRAME_CNT(x) ((x >> 8) & 0xff)

/* Per-pipe DDI Function Control */
#define _TRANS_DDI_FUNC_CTL_A 0x60400
#define _TRANS_DDI_FUNC_CTL_B 0x61400
Expand Down Expand Up @@ -8511,6 +8595,7 @@ enum skl_power_gate {
#define TRANS_DDI_EDP_INPUT_A_ONOFF (4<<12)
#define TRANS_DDI_EDP_INPUT_B_ONOFF (5<<12)
#define TRANS_DDI_EDP_INPUT_C_ONOFF (6<<12)
#define TRANS_DDI_HDCP_SIGNALLING (1<<9)
#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)
Expand Down
2 changes: 2 additions & 0 deletions drivers/gpu/drm/i915/intel_atomic.c
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ int intel_digital_connector_atomic_check(struct drm_connector *conn,
to_intel_digital_connector_state(old_state);
struct drm_crtc_state *crtc_state;

intel_hdcp_atomic_check(conn, old_state, new_state);

if (!new_state->crtc)
return 0;

Expand Down
36 changes: 36 additions & 0 deletions drivers/gpu/drm/i915/intel_ddi.c
Original file line number Diff line number Diff line change
Expand Up @@ -1615,6 +1615,35 @@ void intel_ddi_disable_transcoder_func(struct drm_i915_private *dev_priv,
I915_WRITE(reg, val);
}

int intel_ddi_toggle_hdcp_signalling(struct intel_encoder *intel_encoder,
bool enable)
{
struct drm_device *dev = intel_encoder->base.dev;
struct drm_i915_private *dev_priv = to_i915(dev);
enum pipe pipe = 0;
int ret = 0;
uint32_t tmp;

if (WARN_ON(!intel_display_power_get_if_enabled(dev_priv,
intel_encoder->power_domain)))
return -ENXIO;

if (WARN_ON(!intel_encoder->get_hw_state(intel_encoder, &pipe))) {
ret = -EIO;
goto out;
}

tmp = I915_READ(TRANS_DDI_FUNC_CTL(pipe));
if (enable)
tmp |= TRANS_DDI_HDCP_SIGNALLING;
else
tmp &= ~TRANS_DDI_HDCP_SIGNALLING;
I915_WRITE(TRANS_DDI_FUNC_CTL(pipe), tmp);
out:
intel_display_power_put(dev_priv, intel_encoder->power_domain);
return ret;
}

bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector)
{
struct drm_device *dev = intel_connector->base.dev;
Expand Down Expand Up @@ -2465,6 +2494,11 @@ static void intel_enable_ddi(struct intel_encoder *encoder,
intel_enable_ddi_hdmi(encoder, crtc_state, conn_state);
else
intel_enable_ddi_dp(encoder, crtc_state, conn_state);

/* Enable hdcp if it's desired */
if (conn_state->content_protection ==
DRM_MODE_CONTENT_PROTECTION_DESIRED)
intel_hdcp_enable(to_intel_connector(conn_state->connector));
}

static void intel_disable_ddi_dp(struct intel_encoder *encoder,
Expand Down Expand Up @@ -2499,6 +2533,8 @@ static void intel_disable_ddi(struct intel_encoder *encoder,
const struct intel_crtc_state *old_crtc_state,
const struct drm_connector_state *old_conn_state)
{
intel_hdcp_disable(to_intel_connector(old_conn_state->connector));

if (intel_crtc_has_type(old_crtc_state, INTEL_OUTPUT_HDMI))
intel_disable_ddi_hdmi(encoder, old_crtc_state, old_conn_state);
else
Expand Down
4 changes: 4 additions & 0 deletions drivers/gpu/drm/i915/intel_display.c
Original file line number Diff line number Diff line change
Expand Up @@ -15297,6 +15297,10 @@ static void intel_hpd_poll_fini(struct drm_device *dev)
for_each_intel_connector_iter(connector, &conn_iter) {
if (connector->modeset_retry_work.func)
cancel_work_sync(&connector->modeset_retry_work);
if (connector->hdcp_shim) {
cancel_delayed_work_sync(&connector->hdcp_check_work);
cancel_work_sync(&connector->hdcp_prop_work);
}
}
drm_connector_list_iter_end(&conn_iter);
}
Expand Down
Loading

0 comments on commit 933519a

Please sign in to comment.