Commit 933519a5 authored by Dave Airlie's avatar Dave Airlie

Merge tag 'topic/hdcp-2018-02-13' of git://anongit.freedesktop.org/drm/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
  ...
parents 76ea0f33 2834d9df
...@@ -1224,6 +1224,12 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector, ...@@ -1224,6 +1224,12 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector,
state->picture_aspect_ratio = val; state->picture_aspect_ratio = val;
} else if (property == connector->scaling_mode_property) { } else if (property == connector->scaling_mode_property) {
state->scaling_mode = val; 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) { } else if (connector->funcs->atomic_set_property) {
return connector->funcs->atomic_set_property(connector, return connector->funcs->atomic_set_property(connector,
state, property, val); state, property, val);
...@@ -1303,6 +1309,8 @@ drm_atomic_connector_get_property(struct drm_connector *connector, ...@@ -1303,6 +1309,8 @@ drm_atomic_connector_get_property(struct drm_connector *connector,
*val = state->picture_aspect_ratio; *val = state->picture_aspect_ratio;
} else if (property == connector->scaling_mode_property) { } else if (property == connector->scaling_mode_property) {
*val = state->scaling_mode; *val = state->scaling_mode;
} else if (property == connector->content_protection_property) {
*val = state->content_protection;
} else if (connector->funcs->atomic_get_property) { } else if (connector->funcs->atomic_get_property) {
return connector->funcs->atomic_get_property(connector, return connector->funcs->atomic_get_property(connector,
state, property, val); state, property, val);
......
...@@ -761,6 +761,13 @@ static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = { ...@@ -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_ENUM_NAME_FN(drm_get_tv_subconnector_name,
drm_tv_subconnector_enum_list) 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 * DOC: standard connector properties
* *
...@@ -822,14 +829,50 @@ DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name, ...@@ -822,14 +829,50 @@ DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name,
* should update this value using drm_mode_connector_set_tile_property(). * should update this value using drm_mode_connector_set_tile_property().
* Userspace cannot change this property. * Userspace cannot change this property.
* link-status: * link-status:
* Connector link-status property to indicate the status of link. The default * Connector link-status property to indicate the status of link. The
* value of link-status is "GOOD". If something fails during or after modeset, * default value of link-status is "GOOD". If something fails during or
* the kernel driver may set this to "BAD" and issue a hotplug uevent. Drivers * after modeset, the kernel driver may set this to "BAD" and issue a
* should update this value using drm_mode_connector_set_link_status_property(). * hotplug uevent. Drivers should update this value using
* drm_mode_connector_set_link_status_property().
* non_desktop: * non_desktop:
* Indicates the output should be ignored for purposes of displaying a * Indicates the output should be ignored for purposes of displaying a
* standard desktop environment or console. This is most likely because * standard desktop environment or console. This is most likely because
* the output device is not rectilinear. * 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: * Connectors also have one standardized atomic property:
* *
...@@ -1130,6 +1173,42 @@ int drm_connector_attach_scaling_mode_property(struct drm_connector *connector, ...@@ -1130,6 +1173,42 @@ int drm_connector_attach_scaling_mode_property(struct drm_connector *connector,
} }
EXPORT_SYMBOL(drm_connector_attach_scaling_mode_property); 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 * drm_mode_create_aspect_ratio_property - create aspect ratio property
* @dev: DRM device * @dev: DRM device
......
...@@ -109,6 +109,7 @@ i915-y += intel_audio.o \ ...@@ -109,6 +109,7 @@ i915-y += intel_audio.o \
intel_fbc.o \ intel_fbc.o \
intel_fifo_underrun.o \ intel_fifo_underrun.o \
intel_frontbuffer.o \ intel_frontbuffer.o \
intel_hdcp.o \
intel_hotplug.o \ intel_hotplug.o \
intel_modes.o \ intel_modes.o \
intel_overlay.o \ intel_overlay.o \
......
...@@ -3661,6 +3661,7 @@ extern int intel_setup_gmbus(struct drm_i915_private *dev_priv); ...@@ -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 void intel_teardown_gmbus(struct drm_i915_private *dev_priv);
extern bool intel_gmbus_is_valid_pin(struct drm_i915_private *dev_priv, extern bool intel_gmbus_is_valid_pin(struct drm_i915_private *dev_priv,
unsigned int pin); unsigned int pin);
extern int intel_gmbus_output_aksv(struct i2c_adapter *adapter);
extern struct i2c_adapter * extern struct i2c_adapter *
intel_gmbus_get_adapter(struct drm_i915_private *dev_priv, unsigned int pin); intel_gmbus_get_adapter(struct drm_i915_private *dev_priv, unsigned int pin);
......
...@@ -3074,6 +3074,7 @@ enum i915_power_well_id { ...@@ -3074,6 +3074,7 @@ enum i915_power_well_id {
# define GPIO_DATA_PULLUP_DISABLE (1 << 13) # define GPIO_DATA_PULLUP_DISABLE (1 << 13)
#define GMBUS0 _MMIO(dev_priv->gpio_mmio_base + 0x5100) /* clock/port select */ #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_100KHZ (0<<8)
#define GMBUS_RATE_50KHZ (1<<8) #define GMBUS_RATE_50KHZ (1<<8)
#define GMBUS_RATE_400KHZ (2<<8) /* reserved on Pineview */ #define GMBUS_RATE_400KHZ (2<<8) /* reserved on Pineview */
...@@ -8165,6 +8166,7 @@ enum { ...@@ -8165,6 +8166,7 @@ enum {
#define GEN9_MEM_LATENCY_LEVEL_1_5_SHIFT 8 #define GEN9_MEM_LATENCY_LEVEL_1_5_SHIFT 8
#define GEN9_MEM_LATENCY_LEVEL_2_6_SHIFT 16 #define GEN9_MEM_LATENCY_LEVEL_2_6_SHIFT 16
#define GEN9_MEM_LATENCY_LEVEL_3_7_SHIFT 24 #define GEN9_MEM_LATENCY_LEVEL_3_7_SHIFT 24
#define SKL_PCODE_LOAD_HDCP_KEYS 0x5
#define SKL_PCODE_CDCLK_CONTROL 0x7 #define SKL_PCODE_CDCLK_CONTROL 0x7
#define SKL_CDCLK_PREPARE_FOR_CHANGE 0x3 #define SKL_CDCLK_PREPARE_FOR_CHANGE 0x3
#define SKL_CDCLK_READY_FOR_CHANGE 0x1 #define SKL_CDCLK_READY_FOR_CHANGE 0x1
...@@ -8480,6 +8482,88 @@ enum skl_power_gate { ...@@ -8480,6 +8482,88 @@ enum skl_power_gate {
#define CNL_AUX_ANAOVRD1_ENABLE (1<<16) #define CNL_AUX_ANAOVRD1_ENABLE (1<<16)
#define CNL_AUX_ANAOVRD1_LDO_BYPASS (1<<23) #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 */ /* Per-pipe DDI Function Control */
#define _TRANS_DDI_FUNC_CTL_A 0x60400 #define _TRANS_DDI_FUNC_CTL_A 0x60400
#define _TRANS_DDI_FUNC_CTL_B 0x61400 #define _TRANS_DDI_FUNC_CTL_B 0x61400
...@@ -8511,6 +8595,7 @@ enum skl_power_gate { ...@@ -8511,6 +8595,7 @@ enum skl_power_gate {
#define TRANS_DDI_EDP_INPUT_A_ONOFF (4<<12) #define TRANS_DDI_EDP_INPUT_A_ONOFF (4<<12)
#define TRANS_DDI_EDP_INPUT_B_ONOFF (5<<12) #define TRANS_DDI_EDP_INPUT_B_ONOFF (5<<12)
#define TRANS_DDI_EDP_INPUT_C_ONOFF (6<<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_DP_VC_PAYLOAD_ALLOC (1<<8)
#define TRANS_DDI_HDMI_SCRAMBLER_CTS_ENABLE (1<<7) #define TRANS_DDI_HDMI_SCRAMBLER_CTS_ENABLE (1<<7)
#define TRANS_DDI_HDMI_SCRAMBLER_RESET_FREQ (1<<6) #define TRANS_DDI_HDMI_SCRAMBLER_RESET_FREQ (1<<6)
......
...@@ -110,6 +110,8 @@ int intel_digital_connector_atomic_check(struct drm_connector *conn, ...@@ -110,6 +110,8 @@ int intel_digital_connector_atomic_check(struct drm_connector *conn,
to_intel_digital_connector_state(old_state); to_intel_digital_connector_state(old_state);
struct drm_crtc_state *crtc_state; struct drm_crtc_state *crtc_state;
intel_hdcp_atomic_check(conn, old_state, new_state);
if (!new_state->crtc) if (!new_state->crtc)
return 0; return 0;
......
...@@ -1615,6 +1615,35 @@ void intel_ddi_disable_transcoder_func(struct drm_i915_private *dev_priv, ...@@ -1615,6 +1615,35 @@ void intel_ddi_disable_transcoder_func(struct drm_i915_private *dev_priv,
I915_WRITE(reg, val); 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) bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector)
{ {
struct drm_device *dev = intel_connector->base.dev; struct drm_device *dev = intel_connector->base.dev;
...@@ -2465,6 +2494,11 @@ static void intel_enable_ddi(struct intel_encoder *encoder, ...@@ -2465,6 +2494,11 @@ static void intel_enable_ddi(struct intel_encoder *encoder,
intel_enable_ddi_hdmi(encoder, crtc_state, conn_state); intel_enable_ddi_hdmi(encoder, crtc_state, conn_state);
else else
intel_enable_ddi_dp(encoder, crtc_state, conn_state); 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, static void intel_disable_ddi_dp(struct intel_encoder *encoder,
...@@ -2499,6 +2533,8 @@ static void intel_disable_ddi(struct intel_encoder *encoder, ...@@ -2499,6 +2533,8 @@ static void intel_disable_ddi(struct intel_encoder *encoder,
const struct intel_crtc_state *old_crtc_state, const struct intel_crtc_state *old_crtc_state,
const struct drm_connector_state *old_conn_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)) if (intel_crtc_has_type(old_crtc_state, INTEL_OUTPUT_HDMI))
intel_disable_ddi_hdmi(encoder, old_crtc_state, old_conn_state); intel_disable_ddi_hdmi(encoder, old_crtc_state, old_conn_state);
else else
......
...@@ -15297,6 +15297,10 @@ static void intel_hpd_poll_fini(struct drm_device *dev) ...@@ -15297,6 +15297,10 @@ static void intel_hpd_poll_fini(struct drm_device *dev)
for_each_intel_connector_iter(connector, &conn_iter) { for_each_intel_connector_iter(connector, &conn_iter) {
if (connector->modeset_retry_work.func) if (connector->modeset_retry_work.func)
cancel_work_sync(&connector->modeset_retry_work); 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); drm_connector_list_iter_end(&conn_iter);
} }
......
...@@ -36,7 +36,9 @@ ...@@ -36,7 +36,9 @@
#include <drm/drm_atomic_helper.h> #include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h> #include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h> #include <drm/drm_crtc_helper.h>
#include <drm/drm_dp_helper.h>
#include <drm/drm_edid.h> #include <drm/drm_edid.h>
#include <drm/drm_hdcp.h>
#include "intel_drv.h" #include "intel_drv.h"
#include <drm/i915_drm.h> #include <drm/i915_drm.h>
#include "i915_drv.h" #include "i915_drv.h"
...@@ -1060,10 +1062,29 @@ static uint32_t skl_get_aux_send_ctl(struct intel_dp *intel_dp, ...@@ -1060,10 +1062,29 @@ static uint32_t skl_get_aux_send_ctl(struct intel_dp *intel_dp,
DP_AUX_CH_CTL_SYNC_PULSE_SKL(32); DP_AUX_CH_CTL_SYNC_PULSE_SKL(32);
} }
static uint32_t intel_dp_get_aux_send_ctl(struct intel_dp *intel_dp,
bool has_aux_irq,
int send_bytes,
uint32_t aux_clock_divider,
bool aksv_write)
{
uint32_t val = 0;
if (aksv_write) {
send_bytes += 5;
val |= DP_AUX_CH_CTL_AUX_AKSV_SELECT;
}
return val | intel_dp->get_aux_send_ctl(intel_dp,
has_aux_irq,
send_bytes,
aux_clock_divider);
}
static int static int
intel_dp_aux_ch(struct intel_dp *intel_dp, intel_dp_aux_ch(struct intel_dp *intel_dp,
const uint8_t *send, int send_bytes, const uint8_t *send, int send_bytes,
uint8_t *recv, int recv_size) uint8_t *recv, int recv_size, bool aksv_write)
{ {
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
struct drm_i915_private *dev_priv = struct drm_i915_private *dev_priv =
...@@ -1123,10 +1144,11 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, ...@@ -1123,10 +1144,11 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
} }
while ((aux_clock_divider = intel_dp->get_aux_clock_divider(intel_dp, clock++))) { while ((aux_clock_divider = intel_dp->get_aux_clock_divider(intel_dp, clock++))) {
u32 send_ctl = intel_dp->get_aux_send_ctl(intel_dp, u32 send_ctl = intel_dp_get_aux_send_ctl(intel_dp,
has_aux_irq, has_aux_irq,
send_bytes, send_bytes,
aux_clock_divider); aux_clock_divider,
aksv_write);
/* Must try at least 3 times according to DP spec */ /* Must try at least 3 times according to DP spec */
for (try = 0; try < 5; try++) { for (try = 0; try < 5; try++) {
...@@ -1263,7 +1285,8 @@ intel_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) ...@@ -1263,7 +1285,8 @@ intel_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
if (msg->buffer) if (msg->buffer)
memcpy(txbuf + HEADER_SIZE, msg->buffer, msg->size); memcpy(txbuf + HEADER_SIZE, msg->buffer, msg->size);
ret = intel_dp_aux_ch(intel_dp, txbuf, txsize, rxbuf, rxsize); ret = intel_dp_aux_ch(intel_dp, txbuf, txsize, rxbuf, rxsize,
false);
if (ret > 0) { if (ret > 0) {
msg->reply = rxbuf[0] >> 4; msg->reply = rxbuf[0] >> 4;
...@@ -1285,7 +1308,8 @@ intel_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) ...@@ -1285,7 +1308,8 @@ intel_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
if (WARN_ON(rxsize > 20)) if (WARN_ON(rxsize > 20))
return -E2BIG; return -E2BIG;
ret = intel_dp_aux_ch(intel_dp, txbuf, txsize, rxbuf, rxsize); ret = intel_dp_aux_ch(intel_dp, txbuf, txsize, rxbuf, rxsize,
false);
if (ret > 0) { if (ret > 0) {
msg->reply = rxbuf[0] >> 4; msg->reply = rxbuf[0] >> 4;
/* /*
...@@ -5025,6 +5049,236 @@ void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder) ...@@ -5025,6 +5049,236 @@ void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder)
pps_unlock(intel_dp); pps_unlock(intel_dp);
} }
static
int intel_dp_hdcp_write_an_aksv(struct intel_digital_port *intel_dig_port,
u8 *an)
{
struct intel_dp *intel_dp = enc_to_intel_dp(&intel_dig_port->base.base);
uint8_t txbuf[4], rxbuf[2], reply = 0;
ssize_t dpcd_ret;
int ret;
/* Output An first, that's easy */
dpcd_ret = drm_dp_dpcd_write(&intel_dig_port->dp.aux, DP_AUX_HDCP_AN,
an, DRM_HDCP_AN_LEN);
if (dpcd_ret != DRM_HDCP_AN_LEN) {
DRM_ERROR("Failed to write An over DP/AUX (%zd)\n", dpcd_ret);
return dpcd_ret >= 0 ? -EIO : dpcd_ret;
}
/*
* Since Aksv is Oh-So-Secret, we can't access it in software. So in
* order to get it on the wire, we need to create the AUX header as if
* we were writing the data, and then tickle the hardware to output the
* data once the header is sent out.
*/
txbuf[0] = (DP_AUX_NATIVE_WRITE << 4) |
((DP_AUX_HDCP_AKSV >> 16) & 0xf);
txbuf[1] = (DP_AUX_HDCP_AKSV >> 8) & 0xff;
txbuf[2] = DP_AUX_HDCP_AKSV & 0xff;
txbuf[3] = DRM_HDCP_KSV_LEN - 1;
ret = intel_dp_aux_ch(intel_dp, txbuf, sizeof(txbuf), rxbuf,
sizeof(rxbuf), true);
if (ret < 0) {
DRM_ERROR("Write Aksv over DP/AUX failed (%d)\n", ret);
return ret;
} else if (ret == 0) {
DRM_ERROR("Aksv write over DP/AUX was empty\n");
return -EIO;
}
reply = (rxbuf[0] >> 4) & DP_AUX_NATIVE_REPLY_MASK;
return reply == DP_AUX_NATIVE_REPLY_ACK ? 0 : -EIO;
}
static int intel_dp_hdcp_read_bksv(struct intel_digital_port *intel_dig_port,
u8 *bksv)
{
ssize_t ret;
ret = drm_dp_dpcd_read(&intel_dig_port->dp.aux, DP_AUX_HDCP_BKSV, bksv,
DRM_HDCP_KSV_LEN);
if (ret != DRM_HDCP_KSV_LEN) {
DRM_ERROR("Read Bksv from DP/AUX failed (%zd)\n", ret);
return ret >= 0 ? -EIO : ret;
}
return 0;
}
static int intel_dp_hdcp_read_bstatus(struct intel_digital_port *intel_dig_port,
u8 *bstatus)
{
ssize_t ret;
/*
* For some reason the HDMI and DP HDCP specs call this register
* definition by different names. In the HDMI spec, it's called BSTATUS,
* but in DP it's called BINFO.
*/
ret = drm_dp_dpcd_read(&intel_dig_port->dp.aux, DP_AUX_HDCP_BINFO,
bstatus, DRM_HDCP_BSTATUS_LEN);
if (ret != DRM_HDCP_BSTATUS_LEN) {
DRM_ERROR("Read bstatus from DP/AUX failed (%zd)\n", ret);
return ret >= 0 ? -EIO : ret;
}
return 0;
}
static
int intel_dp_hdcp_read_bcaps(struct intel_digital_port *intel_dig_port,
u8 *bcaps)
{
ssize_t ret;
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;
}
return 0;
}
static
int intel_dp_hdcp_repeater_present(struct intel_digital_port *intel_dig_port,
bool *repeater_present)
{
ssize_t ret;
u8 bcaps;
ret = intel_dp_hdcp_read_bcaps(intel_dig_port, &bcaps);
if (ret)
return ret;
*repeater_present = bcaps & DP_BCAPS_REPEATER_PRESENT;
return 0;
}
static
int intel_dp_hdcp_read_ri_prime(struct intel_digital_port *intel_dig_port,
u8 *ri_prime)
{
ssize_t ret;
ret = drm_dp_dpcd_read(&intel_dig_port->dp.aux, DP_AUX_HDCP_RI_PRIME,
ri_prime, DRM_HDCP_RI_LEN);
if (ret != DRM_HDCP_RI_LEN) {
DRM_ERROR("Read Ri' from DP/AUX failed (%zd)\n", ret);
return ret >= 0 ? -EIO : ret;
}
return 0;
}
static
int intel_dp_hdcp_read_ksv_ready(struct intel_digital_port *intel_dig_port,
bool *ksv_ready)
{
ssize_t ret;
u8 bstatus;
ret = drm_dp_dpcd_read(&intel_dig_port->dp.aux, DP_AUX_HDCP_BSTATUS,
&bstatus, 1);
if (ret != 1) {
DRM_ERROR("Read bstatus from DP/AUX failed (%zd)\n", ret);
return ret >= 0 ? -EIO : ret;
}
*ksv_ready = bstatus & DP_BSTATUS_READY;
return 0;
}
static
int intel_dp_hdcp_read_ksv_fifo(struct intel_digital_port *intel_dig_port,
int num_downstream, u8 *ksv_fifo)
{
ssize_t ret;
int i;
/* KSV list is read via 15 byte window (3 entries @ 5 bytes each) */
for (i = 0; i < num_downstream; i += 3) {
size_t len = min(num_downstream - i, 3) * DRM_HDCP_KSV_LEN;
ret = drm_dp_dpcd_read(&intel_dig_port->dp.aux,
DP_AUX_HDCP_KSV_FIFO,
ksv_fifo + i * DRM_HDCP_KSV_LEN,
len);
if (ret != len) {
DRM_ERROR("Read ksv[%d] from DP/AUX failed (%zd)\n", i,
ret);
return ret >= 0 ? -EIO : ret;
}
}
return 0;
}
static
int intel_dp_hdcp_read_v_prime_part(struct intel_digital_port *intel_dig_port,
int i, u32 *part)
{
ssize_t ret;
if (i >= DRM_HDCP_V_PRIME_NUM_PARTS)
return -EINVAL;
ret = drm_dp_dpcd_read(&intel_dig_port->dp.aux,
DP_AUX_HDCP_V_PRIME(i), part,
DRM_HDCP_V_PRIME_PART_LEN);
if (ret != DRM_HDCP_V_PRIME_PART_LEN) {
DRM_ERROR("Read v'[%d] from DP/AUX failed (%zd)\n", i, ret);
return ret >= 0 ? -EIO : ret;
}
return 0;
}
static
int intel_dp_hdcp_toggle_signalling(struct intel_digital_port *intel_dig_port,
bool enable)
{
/* Not used for single stream DisplayPort setups */
return 0;
}
static
bool intel_dp_hdcp_check_link(struct intel_digital_port *intel_dig_port)
{
ssize_t ret;
u8 bstatus;
ret = drm_dp_dpcd_read(&intel_dig_port->dp.aux, DP_AUX_HDCP_BSTATUS,
&bstatus, 1);
if (ret != 1) {
DRM_ERROR("Read bstatus from DP/AUX failed (%zd)\n", ret);
return false;
}
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 = intel_dp_hdcp_read_bcaps(intel_dig_port, &bcaps);
if (ret)
return 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,
.read_bstatus = intel_dp_hdcp_read_bstatus,
.repeater_present = intel_dp_hdcp_repeater_present,
.read_ri_prime = intel_dp_hdcp_read_ri_prime,
.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_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) static void intel_edp_panel_vdd_sanitize(struct intel_dp *intel_dp)
{ {
struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp));
...@@ -5190,6 +5444,9 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd) ...@@ -5190,6 +5444,9 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
drm_modeset_acquire_fini(&ctx); drm_modeset_acquire_fini(&ctx);
WARN(iret, "Acquiring modeset locks failed with %i\n", iret); WARN(iret, "Acquiring modeset locks failed with %i\n", iret);
/* Short pulse can signify loss of hdcp authentication */
intel_hdcp_check_link(intel_dp->attached_connector);
if (!handled) { if (!handled) {
intel_dp->detect_done = false; intel_dp->detect_done = false;
goto put_power; goto put_power;
...@@ -6179,6 +6436,12 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, ...@@ -6179,6 +6436,12 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
intel_dp_add_properties(intel_dp, connector); intel_dp_add_properties(intel_dp, connector);
if (is_hdcp_supported(dev_priv, port) && !intel_dp_is_edp(intel_dp)) {
int ret = intel_hdcp_init(intel_connector, &intel_dp_hdcp_shim);
if (ret)
DRM_DEBUG_KMS("HDCP init failed, skipping.\n");
}
/* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written /* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written
* 0xd. Failure to do so will result in spurious interrupts being * 0xd. Failure to do so will result in spurious interrupts being
* generated on the port when a cable is not attached. * generated on the port when a cable is not attached.
......
...@@ -41,20 +41,21 @@ ...@@ -41,20 +41,21 @@
#include <drm/drm_atomic.h> #include <drm/drm_atomic.h>
/** /**
* _wait_for - magic (register) wait macro * __wait_for - magic wait macro
* *
* Does the right thing for modeset paths when run under kdgb or similar atomic * Macro to help avoid open coding check/wait/timeout patterns. Note that it's
* contexts. Note that it's important that we check the condition again after * important that we check the condition again after having timed out, since the
* having timed out, since the timeout could be due to preemption or similar and * timeout could be due to preemption or similar and we've never had a chance to
* we've never had a chance to check the condition before the timeout. * check the condition before the timeout.
*/ */
#define _wait_for(COND, US, Wmin, Wmax) ({ \ #define __wait_for(OP, COND, US, Wmin, Wmax) ({ \
unsigned long timeout__ = jiffies + usecs_to_jiffies(US) + 1; \ unsigned long timeout__ = jiffies + usecs_to_jiffies(US) + 1; \
long wait__ = (Wmin); /* recommended min for usleep is 10 us */ \ long wait__ = (Wmin); /* recommended min for usleep is 10 us */ \
int ret__; \ int ret__; \
might_sleep(); \ might_sleep(); \
for (;;) { \ for (;;) { \
bool expired__ = time_after(jiffies, timeout__); \ bool expired__ = time_after(jiffies, timeout__); \
OP; \
if (COND) { \ if (COND) { \
ret__ = 0; \ ret__ = 0; \
break; \ break; \
...@@ -70,6 +71,8 @@ ...@@ -70,6 +71,8 @@
ret__; \ ret__; \
}) })
#define _wait_for(COND, US, Wmin, Wmax) __wait_for(, (COND), (US), (Wmin), \
(Wmax))
#define wait_for(COND, MS) _wait_for((COND), (MS) * 1000, 10, 1000) #define wait_for(COND, MS) _wait_for((COND), (MS) * 1000, 10, 1000)
/* If CONFIG_PREEMPT_COUNT is disabled, in_atomic() always reports false. */ /* If CONFIG_PREEMPT_COUNT is disabled, in_atomic() always reports false. */
...@@ -298,6 +301,80 @@ struct intel_panel { ...@@ -298,6 +301,80 @@ struct intel_panel {
} backlight; } backlight;
}; };
/*
* This structure serves as a translation layer between the generic HDCP code
* and the bus-specific code. What that means is that HDCP over HDMI differs
* from HDCP over DP, so to account for these differences, we need to
* communicate with the receiver through this shim.
*
* For completeness, the 2 buses differ in the following ways:
* - DP AUX vs. DDC
* HDCP registers on the receiver are set via DP AUX for DP, and
* they are set via DDC for HDMI.
* - Receiver register offsets
* The offsets of the registers are different for DP vs. HDMI
* - Receiver register masks/offsets
* For instance, the ready bit for the KSV fifo is in a different
* place on DP vs HDMI
* - Receiver register names
* Seriously. In the DP spec, the 16-bit register containing
* downstream information is called BINFO, on HDMI it's called
* BSTATUS. To confuse matters further, DP has a BSTATUS register
* with a completely different definition.
* - KSV FIFO
* On HDMI, the ksv fifo is read all at once, whereas on DP it must
* be read 3 keys at a time
* - Aksv output
* Since Aksv is hidden in hardware, there's different procedures
* to send it over DP AUX vs DDC
*/
struct intel_hdcp_shim {
/* Outputs the transmitter's An and Aksv values to the receiver. */
int (*write_an_aksv)(struct intel_digital_port *intel_dig_port, u8 *an);
/* Reads the receiver's key selection vector */
int (*read_bksv)(struct intel_digital_port *intel_dig_port, u8 *bksv);
/*
* Reads BINFO from DP receivers and BSTATUS from HDMI receivers. The
* definitions are the same in the respective specs, but the names are
* different. Call it BSTATUS since that's the name the HDMI spec
* uses and it was there first.
*/
int (*read_bstatus)(struct intel_digital_port *intel_dig_port,
u8 *bstatus);
/* Determines whether a repeater is present downstream */
int (*repeater_present)(struct intel_digital_port *intel_dig_port,
bool *repeater_present);
/* Reads the receiver's Ri' value */
int (*read_ri_prime)(struct intel_digital_port *intel_dig_port, u8 *ri);
/* Determines if the receiver's KSV FIFO is ready for consumption */
int (*read_ksv_ready)(struct intel_digital_port *intel_dig_port,
bool *ksv_ready);
/* Reads the ksv fifo for num_downstream devices */
int (*read_ksv_fifo)(struct intel_digital_port *intel_dig_port,
int num_downstream, u8 *ksv_fifo);
/* Reads a 32-bit part of V' from the receiver */
int (*read_v_prime_part)(struct intel_digital_port *intel_dig_port,
int i, u32 *part);
/* Enables HDCP signalling on the port */
int (*toggle_signalling)(struct intel_digital_port *intel_dig_port,
bool enable);
/* Ensures the link is still protected */
bool (*check_link)(struct intel_digital_port *intel_dig_port);
/* Detects panel's hdcp capability. This is optional for HDMI. */
int (*hdcp_capable)(struct intel_digital_port *intel_dig_port,
bool *hdcp_capable);
};
struct intel_connector { struct intel_connector {
struct drm_connector base; struct drm_connector base;
/* /*
...@@ -329,6 +406,12 @@ struct intel_connector { ...@@ -329,6 +406,12 @@ struct intel_connector {
/* Work struct to schedule a uevent on link train failure */ /* Work struct to schedule a uevent on link train failure */
struct work_struct modeset_retry_work; struct work_struct modeset_retry_work;
const struct intel_hdcp_shim *hdcp_shim;
struct mutex hdcp_mutex;
uint64_t hdcp_value; /* protected by hdcp_mutex */
struct delayed_work hdcp_check_work;
struct work_struct hdcp_prop_work;
}; };
struct intel_digital_connector_state { struct intel_digital_connector_state {
...@@ -1297,6 +1380,8 @@ void intel_ddi_compute_min_voltage_level(struct drm_i915_private *dev_priv, ...@@ -1297,6 +1380,8 @@ void intel_ddi_compute_min_voltage_level(struct drm_i915_private *dev_priv,
u32 bxt_signal_levels(struct intel_dp *intel_dp); u32 bxt_signal_levels(struct intel_dp *intel_dp);
uint32_t ddi_signal_levels(struct intel_dp *intel_dp); uint32_t ddi_signal_levels(struct intel_dp *intel_dp);
u8 intel_ddi_dp_voltage_max(struct intel_encoder *encoder); u8 intel_ddi_dp_voltage_max(struct intel_encoder *encoder);
int intel_ddi_toggle_hdcp_signalling(struct intel_encoder *intel_encoder,
bool enable);
unsigned int intel_fb_align_height(const struct drm_framebuffer *fb, unsigned int intel_fb_align_height(const struct drm_framebuffer *fb,
int plane, unsigned int height); int plane, unsigned int height);
...@@ -1757,6 +1842,16 @@ static inline void intel_backlight_device_unregister(struct intel_connector *con ...@@ -1757,6 +1842,16 @@ static inline void intel_backlight_device_unregister(struct intel_connector *con
} }
#endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */ #endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */
/* intel_hdcp.c */
void intel_hdcp_atomic_check(struct drm_connector *connector,
struct drm_connector_state *old_state,
struct drm_connector_state *new_state);
int intel_hdcp_init(struct intel_connector *connector,
const struct intel_hdcp_shim *hdcp_shim);
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);
/* intel_psr.c */ /* intel_psr.c */
#define CAN_PSR(dev_priv) (HAS_PSR(dev_priv) && dev_priv->psr.sink_support) #define CAN_PSR(dev_priv) (HAS_PSR(dev_priv) && dev_priv->psr.sink_support)
......
This diff is collapsed.
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include <drm/drm_atomic_helper.h> #include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h> #include <drm/drm_crtc.h>
#include <drm/drm_edid.h> #include <drm/drm_edid.h>
#include <drm/drm_hdcp.h>
#include <drm/drm_scdc_helper.h> #include <drm/drm_scdc_helper.h>
#include "intel_drv.h" #include "intel_drv.h"
#include <drm/i915_drm.h> #include <drm/i915_drm.h>
...@@ -876,6 +877,248 @@ void intel_dp_dual_mode_set_tmds_output(struct intel_hdmi *hdmi, bool enable) ...@@ -876,6 +877,248 @@ void intel_dp_dual_mode_set_tmds_output(struct intel_hdmi *hdmi, bool enable)
adapter, enable); adapter, enable);
} }
static int intel_hdmi_hdcp_read(struct intel_digital_port *intel_dig_port,
unsigned int offset, void *buffer, size_t size)
{
struct intel_hdmi *hdmi = &intel_dig_port->hdmi;
struct drm_i915_private *dev_priv =
intel_dig_port->base.base.dev->dev_private;
struct i2c_adapter *adapter = intel_gmbus_get_adapter(dev_priv,
hdmi->ddc_bus);
int ret;
u8 start = offset & 0xff;
struct i2c_msg msgs[] = {
{
.addr = DRM_HDCP_DDC_ADDR,
.flags = 0,
.len = 1,
.buf = &start,
},
{
.addr = DRM_HDCP_DDC_ADDR,
.flags = I2C_M_RD,
.len = size,
.buf = buffer
}
};
ret = i2c_transfer(adapter, msgs, ARRAY_SIZE(msgs));
if (ret == ARRAY_SIZE(msgs))
return 0;
return ret >= 0 ? -EIO : ret;
}
static int intel_hdmi_hdcp_write(struct intel_digital_port *intel_dig_port,
unsigned int offset, void *buffer, size_t size)
{
struct intel_hdmi *hdmi = &intel_dig_port->hdmi;
struct drm_i915_private *dev_priv =
intel_dig_port->base.base.dev->dev_private;
struct i2c_adapter *adapter = intel_gmbus_get_adapter(dev_priv,
hdmi->ddc_bus);
int ret;
u8 *write_buf;
struct i2c_msg msg;
write_buf = kzalloc(size + 1, GFP_KERNEL);
if (!write_buf)
return -ENOMEM;
write_buf[0] = offset & 0xff;
memcpy(&write_buf[1], buffer, size);
msg.addr = DRM_HDCP_DDC_ADDR;
msg.flags = 0,
msg.len = size + 1,
msg.buf = write_buf;
ret = i2c_transfer(adapter, &msg, 1);
if (ret == 1)
return 0;
return ret >= 0 ? -EIO : ret;
}
static
int intel_hdmi_hdcp_write_an_aksv(struct intel_digital_port *intel_dig_port,
u8 *an)
{
struct intel_hdmi *hdmi = &intel_dig_port->hdmi;
struct drm_i915_private *dev_priv =
intel_dig_port->base.base.dev->dev_private;
struct i2c_adapter *adapter = intel_gmbus_get_adapter(dev_priv,
hdmi->ddc_bus);
int ret;
ret = intel_hdmi_hdcp_write(intel_dig_port, DRM_HDCP_DDC_AN, an,
DRM_HDCP_AN_LEN);
if (ret) {
DRM_ERROR("Write An over DDC failed (%d)\n", ret);
return ret;
}
ret = intel_gmbus_output_aksv(adapter);
if (ret < 0) {
DRM_ERROR("Failed to output aksv (%d)\n", ret);
return ret;
}
return 0;
}
static int intel_hdmi_hdcp_read_bksv(struct intel_digital_port *intel_dig_port,
u8 *bksv)
{
int ret;
ret = intel_hdmi_hdcp_read(intel_dig_port, DRM_HDCP_DDC_BKSV, bksv,
DRM_HDCP_KSV_LEN);
if (ret)
DRM_ERROR("Read Bksv over DDC failed (%d)\n", ret);
return ret;
}
static
int intel_hdmi_hdcp_read_bstatus(struct intel_digital_port *intel_dig_port,
u8 *bstatus)
{
int ret;
ret = intel_hdmi_hdcp_read(intel_dig_port, DRM_HDCP_DDC_BSTATUS,
bstatus, DRM_HDCP_BSTATUS_LEN);
if (ret)
DRM_ERROR("Read bstatus over DDC failed (%d)\n", ret);
return ret;
}
static
int intel_hdmi_hdcp_repeater_present(struct intel_digital_port *intel_dig_port,
bool *repeater_present)
{
int ret;
u8 val;
ret = intel_hdmi_hdcp_read(intel_dig_port, DRM_HDCP_DDC_BCAPS, &val, 1);
if (ret) {
DRM_ERROR("Read bcaps over DDC failed (%d)\n", ret);
return ret;
}
*repeater_present = val & DRM_HDCP_DDC_BCAPS_REPEATER_PRESENT;
return 0;
}
static
int intel_hdmi_hdcp_read_ri_prime(struct intel_digital_port *intel_dig_port,
u8 *ri_prime)
{
int ret;
ret = intel_hdmi_hdcp_read(intel_dig_port, DRM_HDCP_DDC_RI_PRIME,
ri_prime, DRM_HDCP_RI_LEN);
if (ret)
DRM_ERROR("Read Ri' over DDC failed (%d)\n", ret);
return ret;
}
static
int intel_hdmi_hdcp_read_ksv_ready(struct intel_digital_port *intel_dig_port,
bool *ksv_ready)
{
int ret;
u8 val;
ret = intel_hdmi_hdcp_read(intel_dig_port, DRM_HDCP_DDC_BCAPS, &val, 1);
if (ret) {
DRM_ERROR("Read bcaps over DDC failed (%d)\n", ret);
return ret;
}
*ksv_ready = val & DRM_HDCP_DDC_BCAPS_KSV_FIFO_READY;
return 0;
}
static
int intel_hdmi_hdcp_read_ksv_fifo(struct intel_digital_port *intel_dig_port,
int num_downstream, u8 *ksv_fifo)
{
int ret;
ret = intel_hdmi_hdcp_read(intel_dig_port, DRM_HDCP_DDC_KSV_FIFO,
ksv_fifo, num_downstream * DRM_HDCP_KSV_LEN);
if (ret) {
DRM_ERROR("Read ksv fifo over DDC failed (%d)\n", ret);
return ret;
}
return 0;
}
static
int intel_hdmi_hdcp_read_v_prime_part(struct intel_digital_port *intel_dig_port,
int i, u32 *part)
{
int ret;
if (i >= DRM_HDCP_V_PRIME_NUM_PARTS)
return -EINVAL;
ret = intel_hdmi_hdcp_read(intel_dig_port, DRM_HDCP_DDC_V_PRIME(i),
part, DRM_HDCP_V_PRIME_PART_LEN);
if (ret)
DRM_ERROR("Read V'[%d] over DDC failed (%d)\n", i, ret);
return ret;
}
static
int intel_hdmi_hdcp_toggle_signalling(struct intel_digital_port *intel_dig_port,
bool enable)
{
int ret;
if (!enable)
usleep_range(6, 60); /* Bspec says >= 6us */
ret = intel_ddi_toggle_hdcp_signalling(&intel_dig_port->base, enable);
if (ret) {
DRM_ERROR("%s HDCP signalling failed (%d)\n",
enable ? "Enable" : "Disable", ret);
return ret;
}
return 0;
}
static
bool intel_hdmi_hdcp_check_link(struct intel_digital_port *intel_dig_port)
{
struct drm_i915_private *dev_priv =
intel_dig_port->base.base.dev->dev_private;
enum port port = intel_dig_port->base.port;
int ret;
union {
u32 reg;
u8 shim[DRM_HDCP_RI_LEN];
} ri;
ret = intel_hdmi_hdcp_read_ri_prime(intel_dig_port, ri.shim);
if (ret)
return false;
I915_WRITE(PORT_HDCP_RPRIME(port), ri.reg);
/* Wait for Ri prime match */
if (wait_for(I915_READ(PORT_HDCP_STATUS(port)) &
(HDCP_STATUS_RI_MATCH | HDCP_STATUS_ENC), 1)) {
DRM_ERROR("Ri' mismatch detected, link check failed (%x)\n",
I915_READ(PORT_HDCP_STATUS(port)));
return false;
}
return true;
}
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,
.read_bstatus = intel_hdmi_hdcp_read_bstatus,
.repeater_present = intel_hdmi_hdcp_repeater_present,
.read_ri_prime = intel_hdmi_hdcp_read_ri_prime,
.read_ksv_ready = intel_hdmi_hdcp_read_ksv_ready,
.read_ksv_fifo = intel_hdmi_hdcp_read_ksv_fifo,
.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,
};
static void intel_hdmi_prepare(struct intel_encoder *encoder, static void intel_hdmi_prepare(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state) const struct intel_crtc_state *crtc_state)
{ {
...@@ -2097,6 +2340,13 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, ...@@ -2097,6 +2340,13 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
intel_hdmi_add_properties(intel_hdmi, connector); intel_hdmi_add_properties(intel_hdmi, connector);
if (is_hdcp_supported(dev_priv, port)) {
int ret = intel_hdcp_init(intel_connector,
&intel_hdmi_hdcp_shim);
if (ret)
DRM_DEBUG_KMS("HDCP init failed, skipping.\n");
}
intel_connector_attach_encoder(intel_connector, intel_encoder); intel_connector_attach_encoder(intel_connector, intel_encoder);
intel_hdmi->attached_connector = intel_connector; intel_hdmi->attached_connector = intel_connector;
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <linux/i2c-algo-bit.h> #include <linux/i2c-algo-bit.h>
#include <linux/export.h> #include <linux/export.h>
#include <drm/drmP.h> #include <drm/drmP.h>
#include <drm/drm_hdcp.h>
#include "intel_drv.h" #include "intel_drv.h"
#include <drm/i915_drm.h> #include <drm/i915_drm.h>
#include "i915_drv.h" #include "i915_drv.h"
...@@ -415,7 +416,8 @@ gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg, ...@@ -415,7 +416,8 @@ gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg,
static int static int
gmbus_xfer_write_chunk(struct drm_i915_private *dev_priv, gmbus_xfer_write_chunk(struct drm_i915_private *dev_priv,
unsigned short addr, u8 *buf, unsigned int len) unsigned short addr, u8 *buf, unsigned int len,
u32 gmbus1_index)
{ {
unsigned int chunk_size = len; unsigned int chunk_size = len;
u32 val, loop; u32 val, loop;
...@@ -428,7 +430,7 @@ gmbus_xfer_write_chunk(struct drm_i915_private *dev_priv, ...@@ -428,7 +430,7 @@ gmbus_xfer_write_chunk(struct drm_i915_private *dev_priv,
I915_WRITE_FW(GMBUS3, val); I915_WRITE_FW(GMBUS3, val);
I915_WRITE_FW(GMBUS1, I915_WRITE_FW(GMBUS1,
GMBUS_CYCLE_WAIT | gmbus1_index | GMBUS_CYCLE_WAIT |
(chunk_size << GMBUS_BYTE_COUNT_SHIFT) | (chunk_size << GMBUS_BYTE_COUNT_SHIFT) |
(addr << GMBUS_SLAVE_ADDR_SHIFT) | (addr << GMBUS_SLAVE_ADDR_SHIFT) |
GMBUS_SLAVE_WRITE | GMBUS_SW_RDY); GMBUS_SLAVE_WRITE | GMBUS_SW_RDY);
...@@ -451,7 +453,8 @@ gmbus_xfer_write_chunk(struct drm_i915_private *dev_priv, ...@@ -451,7 +453,8 @@ gmbus_xfer_write_chunk(struct drm_i915_private *dev_priv,
} }
static int static int
gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg) gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg,
u32 gmbus1_index)
{ {
u8 *buf = msg->buf; u8 *buf = msg->buf;
unsigned int tx_size = msg->len; unsigned int tx_size = msg->len;
...@@ -461,7 +464,8 @@ gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg) ...@@ -461,7 +464,8 @@ gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg)
do { do {
len = min(tx_size, GMBUS_BYTE_COUNT_MAX); len = min(tx_size, GMBUS_BYTE_COUNT_MAX);
ret = gmbus_xfer_write_chunk(dev_priv, msg->addr, buf, len); ret = gmbus_xfer_write_chunk(dev_priv, msg->addr, buf, len,
gmbus1_index);
if (ret) if (ret)
return ret; return ret;
...@@ -473,21 +477,21 @@ gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg) ...@@ -473,21 +477,21 @@ gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg)
} }
/* /*
* The gmbus controller can combine a 1 or 2 byte write with a read that * The gmbus controller can combine a 1 or 2 byte write with another read/write
* immediately follows it by using an "INDEX" cycle. * that immediately follows it by using an "INDEX" cycle.
*/ */
static bool static bool
gmbus_is_index_read(struct i2c_msg *msgs, int i, int num) gmbus_is_index_xfer(struct i2c_msg *msgs, int i, int num)
{ {
return (i + 1 < num && return (i + 1 < num &&
msgs[i].addr == msgs[i + 1].addr && msgs[i].addr == msgs[i + 1].addr &&
!(msgs[i].flags & I2C_M_RD) && !(msgs[i].flags & I2C_M_RD) &&
(msgs[i].len == 1 || msgs[i].len == 2) && (msgs[i].len == 1 || msgs[i].len == 2) &&
(msgs[i + 1].flags & I2C_M_RD)); msgs[i + 1].len > 0);
} }
static int static int
gmbus_xfer_index_read(struct drm_i915_private *dev_priv, struct i2c_msg *msgs) gmbus_index_xfer(struct drm_i915_private *dev_priv, struct i2c_msg *msgs)
{ {
u32 gmbus1_index = 0; u32 gmbus1_index = 0;
u32 gmbus5 = 0; u32 gmbus5 = 0;
...@@ -504,7 +508,10 @@ gmbus_xfer_index_read(struct drm_i915_private *dev_priv, struct i2c_msg *msgs) ...@@ -504,7 +508,10 @@ gmbus_xfer_index_read(struct drm_i915_private *dev_priv, struct i2c_msg *msgs)
if (gmbus5) if (gmbus5)
I915_WRITE_FW(GMBUS5, gmbus5); I915_WRITE_FW(GMBUS5, gmbus5);
if (msgs[1].flags & I2C_M_RD)
ret = gmbus_xfer_read(dev_priv, &msgs[1], gmbus1_index); ret = gmbus_xfer_read(dev_priv, &msgs[1], gmbus1_index);
else
ret = gmbus_xfer_write(dev_priv, &msgs[1], gmbus1_index);
/* Clear GMBUS5 after each index transfer */ /* Clear GMBUS5 after each index transfer */
if (gmbus5) if (gmbus5)
...@@ -514,7 +521,8 @@ gmbus_xfer_index_read(struct drm_i915_private *dev_priv, struct i2c_msg *msgs) ...@@ -514,7 +521,8 @@ gmbus_xfer_index_read(struct drm_i915_private *dev_priv, struct i2c_msg *msgs)
} }
static int static int
do_gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num) do_gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num,
u32 gmbus0_source)
{ {
struct intel_gmbus *bus = container_of(adapter, struct intel_gmbus *bus = container_of(adapter,
struct intel_gmbus, struct intel_gmbus,
...@@ -531,17 +539,17 @@ do_gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num) ...@@ -531,17 +539,17 @@ do_gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
pch_gmbus_clock_gating(dev_priv, false); pch_gmbus_clock_gating(dev_priv, false);
retry: retry:
I915_WRITE_FW(GMBUS0, bus->reg0); I915_WRITE_FW(GMBUS0, gmbus0_source | bus->reg0);
for (; i < num; i += inc) { for (; i < num; i += inc) {
inc = 1; inc = 1;
if (gmbus_is_index_read(msgs, i, num)) { if (gmbus_is_index_xfer(msgs, i, num)) {
ret = gmbus_xfer_index_read(dev_priv, &msgs[i]); ret = gmbus_index_xfer(dev_priv, &msgs[i]);
inc = 2; /* an index read is two msgs */ inc = 2; /* an index transmission is two msgs */
} else if (msgs[i].flags & I2C_M_RD) { } else if (msgs[i].flags & I2C_M_RD) {
ret = gmbus_xfer_read(dev_priv, &msgs[i], 0); ret = gmbus_xfer_read(dev_priv, &msgs[i], 0);
} else { } else {
ret = gmbus_xfer_write(dev_priv, &msgs[i]); ret = gmbus_xfer_write(dev_priv, &msgs[i], 0);
} }
if (!ret) if (!ret)
...@@ -656,7 +664,7 @@ gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num) ...@@ -656,7 +664,7 @@ gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
if (ret < 0) if (ret < 0)
bus->force_bit &= ~GMBUS_FORCE_BIT_RETRY; bus->force_bit &= ~GMBUS_FORCE_BIT_RETRY;
} else { } else {
ret = do_gmbus_xfer(adapter, msgs, num); ret = do_gmbus_xfer(adapter, msgs, num, 0);
if (ret == -EAGAIN) if (ret == -EAGAIN)
bus->force_bit |= GMBUS_FORCE_BIT_RETRY; bus->force_bit |= GMBUS_FORCE_BIT_RETRY;
} }
...@@ -666,6 +674,45 @@ gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num) ...@@ -666,6 +674,45 @@ gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
return ret; return ret;
} }
int intel_gmbus_output_aksv(struct i2c_adapter *adapter)
{
struct intel_gmbus *bus = container_of(adapter, struct intel_gmbus,
adapter);
struct drm_i915_private *dev_priv = bus->dev_priv;
int ret;
u8 cmd = DRM_HDCP_DDC_AKSV;
u8 buf[DRM_HDCP_KSV_LEN] = { 0 };
struct i2c_msg msgs[] = {
{
.addr = DRM_HDCP_DDC_ADDR,
.flags = 0,
.len = sizeof(cmd),
.buf = &cmd,
},
{
.addr = DRM_HDCP_DDC_ADDR,
.flags = 0,
.len = sizeof(buf),
.buf = buf,
}
};
intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
mutex_lock(&dev_priv->gmbus_mutex);
/*
* In order to output Aksv to the receiver, use an indexed write to
* pass the i2c command, and tell GMBUS to use the HW-provided value
* instead of sourcing GMBUS3 for the data.
*/
ret = do_gmbus_xfer(adapter, msgs, ARRAY_SIZE(msgs), GMBUS_AKSV_SELECT);
mutex_unlock(&dev_priv->gmbus_mutex);
intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS);
return ret;
}
static u32 gmbus_func(struct i2c_adapter *adapter) static u32 gmbus_func(struct i2c_adapter *adapter)
{ {
return i2c_bit_algo.functionality(adapter) & return i2c_bit_algo.functionality(adapter) &
......
...@@ -1767,12 +1767,14 @@ int __intel_wait_for_register_fw(struct drm_i915_private *dev_priv, ...@@ -1767,12 +1767,14 @@ int __intel_wait_for_register_fw(struct drm_i915_private *dev_priv,
} }
/** /**
* intel_wait_for_register - wait until register matches expected state * __intel_wait_for_register - wait until register matches expected state
* @dev_priv: the i915 device * @dev_priv: the i915 device
* @reg: the register to read * @reg: the register to read
* @mask: mask to apply to register value * @mask: mask to apply to register value
* @value: expected value * @value: expected value
* @timeout_ms: timeout in millisecond * @fast_timeout_us: fast timeout in microsecond for atomic/tight wait
* @slow_timeout_ms: slow timeout in millisecond
* @out_value: optional placeholder to hold registry value
* *
* This routine waits until the target register @reg contains the expected * This routine waits until the target register @reg contains the expected
* @value after applying the @mask, i.e. it waits until :: * @value after applying the @mask, i.e. it waits until ::
...@@ -1783,14 +1785,17 @@ int __intel_wait_for_register_fw(struct drm_i915_private *dev_priv, ...@@ -1783,14 +1785,17 @@ int __intel_wait_for_register_fw(struct drm_i915_private *dev_priv,
* *
* Returns 0 if the register matches the desired condition, or -ETIMEOUT. * Returns 0 if the register matches the desired condition, or -ETIMEOUT.
*/ */
int intel_wait_for_register(struct drm_i915_private *dev_priv, int __intel_wait_for_register(struct drm_i915_private *dev_priv,
i915_reg_t reg, i915_reg_t reg,
u32 mask, u32 mask,
u32 value, u32 value,
unsigned int timeout_ms) unsigned int fast_timeout_us,
unsigned int slow_timeout_ms,
u32 *out_value)
{ {
unsigned fw = unsigned fw =
intel_uncore_forcewake_for_reg(dev_priv, reg, FW_REG_READ); intel_uncore_forcewake_for_reg(dev_priv, reg, FW_REG_READ);
u32 reg_value;
int ret; int ret;
might_sleep(); might_sleep();
...@@ -1800,14 +1805,18 @@ int intel_wait_for_register(struct drm_i915_private *dev_priv, ...@@ -1800,14 +1805,18 @@ int intel_wait_for_register(struct drm_i915_private *dev_priv,
ret = __intel_wait_for_register_fw(dev_priv, ret = __intel_wait_for_register_fw(dev_priv,
reg, mask, value, reg, mask, value,
2, 0, NULL); fast_timeout_us, 0, &reg_value);
intel_uncore_forcewake_put__locked(dev_priv, fw); intel_uncore_forcewake_put__locked(dev_priv, fw);
spin_unlock_irq(&dev_priv->uncore.lock); spin_unlock_irq(&dev_priv->uncore.lock);
if (ret) if (ret)
ret = wait_for((I915_READ_NOTRACE(reg) & mask) == value, ret = __wait_for(reg_value = I915_READ_NOTRACE(reg),
timeout_ms); (reg_value & mask) == value,
slow_timeout_ms * 1000, 10, 1000);
if (out_value)
*out_value = reg_value;
return ret; return ret;
} }
......
...@@ -163,11 +163,23 @@ void intel_uncore_forcewake_put__locked(struct drm_i915_private *dev_priv, ...@@ -163,11 +163,23 @@ void intel_uncore_forcewake_put__locked(struct drm_i915_private *dev_priv,
void intel_uncore_forcewake_user_get(struct drm_i915_private *dev_priv); void intel_uncore_forcewake_user_get(struct drm_i915_private *dev_priv);
void intel_uncore_forcewake_user_put(struct drm_i915_private *dev_priv); void intel_uncore_forcewake_user_put(struct drm_i915_private *dev_priv);
int __intel_wait_for_register(struct drm_i915_private *dev_priv,
i915_reg_t reg,
u32 mask,
u32 value,
unsigned int fast_timeout_us,
unsigned int slow_timeout_ms,
u32 *out_value);
static inline
int intel_wait_for_register(struct drm_i915_private *dev_priv, int intel_wait_for_register(struct drm_i915_private *dev_priv,
i915_reg_t reg, i915_reg_t reg,
u32 mask, u32 mask,
u32 value, u32 value,
unsigned int timeout_ms); unsigned int timeout_ms)
{
return __intel_wait_for_register(dev_priv, reg, mask, value, 2,
timeout_ms, NULL);
}
int __intel_wait_for_register_fw(struct drm_i915_private *dev_priv, int __intel_wait_for_register_fw(struct drm_i915_private *dev_priv,
i915_reg_t reg, i915_reg_t reg,
u32 mask, u32 mask,
......
...@@ -419,6 +419,12 @@ struct drm_connector_state { ...@@ -419,6 +419,12 @@ struct drm_connector_state {
* upscaling, mostly used for built-in panels. * upscaling, mostly used for built-in panels.
*/ */
unsigned int scaling_mode; unsigned int scaling_mode;
/**
* @content_protection: Connector property to request content
* protection. This is most commonly used for HDCP.
*/
unsigned int content_protection;
}; };
/** /**
...@@ -766,6 +772,7 @@ struct drm_cmdline_mode { ...@@ -766,6 +772,7 @@ struct drm_cmdline_mode {
* @tile_h_size: horizontal size of this tile. * @tile_h_size: horizontal size of this tile.
* @tile_v_size: vertical size of this tile. * @tile_v_size: vertical size of this tile.
* @scaling_mode_property: Optional atomic property to control the upscaling. * @scaling_mode_property: Optional atomic property to control the upscaling.
* @content_protection_property: Optional property to control content protection
* *
* Each connector may be connected to one or more CRTCs, or may be clonable by * Each connector may be connected to one or more CRTCs, or may be clonable by
* another connector if they can share a CRTC. Each connector also has a specific * another connector if they can share a CRTC. Each connector also has a specific
...@@ -856,6 +863,12 @@ struct drm_connector { ...@@ -856,6 +863,12 @@ struct drm_connector {
struct drm_property *scaling_mode_property; struct drm_property *scaling_mode_property;
/**
* @content_protection_property: DRM ENUM property for content
* protection
*/
struct drm_property *content_protection_property;
/** /**
* @path_blob_ptr: * @path_blob_ptr:
* *
...@@ -1065,6 +1078,7 @@ const char *drm_get_dvi_i_subconnector_name(int val); ...@@ -1065,6 +1078,7 @@ const char *drm_get_dvi_i_subconnector_name(int val);
const char *drm_get_dvi_i_select_name(int val); const char *drm_get_dvi_i_select_name(int val);
const char *drm_get_tv_subconnector_name(int val); const char *drm_get_tv_subconnector_name(int val);
const char *drm_get_tv_select_name(int val); const char *drm_get_tv_select_name(int val);
const char *drm_get_content_protection_name(int val);
int drm_mode_create_dvi_i_properties(struct drm_device *dev); int drm_mode_create_dvi_i_properties(struct drm_device *dev);
int drm_mode_create_tv_properties(struct drm_device *dev, int drm_mode_create_tv_properties(struct drm_device *dev,
...@@ -1073,6 +1087,8 @@ int drm_mode_create_tv_properties(struct drm_device *dev, ...@@ -1073,6 +1087,8 @@ int drm_mode_create_tv_properties(struct drm_device *dev,
int drm_mode_create_scaling_mode_property(struct drm_device *dev); int drm_mode_create_scaling_mode_property(struct drm_device *dev);
int drm_connector_attach_scaling_mode_property(struct drm_connector *connector, int drm_connector_attach_scaling_mode_property(struct drm_connector *connector,
u32 scaling_mode_mask); u32 scaling_mode_mask);
int drm_connector_attach_content_protection_property(
struct drm_connector *connector);
int drm_mode_create_aspect_ratio_property(struct drm_device *dev); int drm_mode_create_aspect_ratio_property(struct drm_device *dev);
int drm_mode_create_suggested_offset_properties(struct drm_device *dev); int drm_mode_create_suggested_offset_properties(struct drm_device *dev);
......
...@@ -840,6 +840,23 @@ ...@@ -840,6 +840,23 @@
#define DP_CEC_TX_MESSAGE_BUFFER 0x3020 #define DP_CEC_TX_MESSAGE_BUFFER 0x3020
#define DP_CEC_MESSAGE_BUFFER_LENGTH 0x10 #define DP_CEC_MESSAGE_BUFFER_LENGTH 0x10
#define DP_AUX_HDCP_BKSV 0x68000
#define DP_AUX_HDCP_RI_PRIME 0x68005
#define DP_AUX_HDCP_AKSV 0x68007
#define DP_AUX_HDCP_AN 0x6800C
#define DP_AUX_HDCP_V_PRIME(h) (0x68014 + h * 4)
#define DP_AUX_HDCP_BCAPS 0x68028
# define DP_BCAPS_REPEATER_PRESENT BIT(1)
# define DP_BCAPS_HDCP_CAPABLE BIT(0)
#define DP_AUX_HDCP_BSTATUS 0x68029
# define DP_BSTATUS_REAUTH_REQ BIT(3)
# define DP_BSTATUS_LINK_FAILURE BIT(2)
# define DP_BSTATUS_R0_PRIME_READY BIT(1)
# define DP_BSTATUS_READY BIT(0)
#define DP_AUX_HDCP_BINFO 0x6802A
#define DP_AUX_HDCP_KSV_FIFO 0x6802C
#define DP_AUX_HDCP_AINFO 0x6803B
/* DP 1.2 Sideband message defines */ /* DP 1.2 Sideband message defines */
/* peer device type - DP 1.2a Table 2-92 */ /* peer device type - DP 1.2a Table 2-92 */
#define DP_PEER_DEVICE_NONE 0x0 #define DP_PEER_DEVICE_NONE 0x0
......
/* SPDX-License-Identifier: MIT */
/*
* Copyright (C) 2017 Google, Inc.
*
* Authors:
* Sean Paul <seanpaul@chromium.org>
*/
#ifndef _DRM_HDCP_H_INCLUDED_
#define _DRM_HDCP_H_INCLUDED_
/* Period of hdcp checks (to ensure we're still authenticated) */
#define DRM_HDCP_CHECK_PERIOD_MS (128 * 16)
/* Shared lengths/masks between HDMI/DVI/DisplayPort */
#define DRM_HDCP_AN_LEN 8
#define DRM_HDCP_BSTATUS_LEN 2
#define DRM_HDCP_KSV_LEN 5
#define DRM_HDCP_RI_LEN 2
#define DRM_HDCP_V_PRIME_PART_LEN 4
#define DRM_HDCP_V_PRIME_NUM_PARTS 5
#define DRM_HDCP_NUM_DOWNSTREAM(x) (x & 0x3f)
#define DRM_HDCP_MAX_CASCADE_EXCEEDED(x) (x & BIT(3))
#define DRM_HDCP_MAX_DEVICE_EXCEEDED(x) (x & BIT(7))
/* Slave address for the HDCP registers in the receiver */
#define DRM_HDCP_DDC_ADDR 0x3A
/* HDCP register offsets for HDMI/DVI devices */
#define DRM_HDCP_DDC_BKSV 0x00
#define DRM_HDCP_DDC_RI_PRIME 0x08
#define DRM_HDCP_DDC_AKSV 0x10
#define DRM_HDCP_DDC_AN 0x18
#define DRM_HDCP_DDC_V_PRIME(h) (0x20 + h * 4)
#define DRM_HDCP_DDC_BCAPS 0x40
#define DRM_HDCP_DDC_BCAPS_REPEATER_PRESENT BIT(6)
#define DRM_HDCP_DDC_BCAPS_KSV_FIFO_READY BIT(5)
#define DRM_HDCP_DDC_BSTATUS 0x41
#define DRM_HDCP_DDC_KSV_FIFO 0x43
#endif
...@@ -191,6 +191,10 @@ extern "C" { ...@@ -191,6 +191,10 @@ extern "C" {
DRM_MODE_REFLECT_X | \ DRM_MODE_REFLECT_X | \
DRM_MODE_REFLECT_Y) DRM_MODE_REFLECT_Y)
/* Content Protection Flags */
#define DRM_MODE_CONTENT_PROTECTION_UNDESIRED 0
#define DRM_MODE_CONTENT_PROTECTION_DESIRED 1
#define DRM_MODE_CONTENT_PROTECTION_ENABLED 2
struct drm_mode_modeinfo { struct drm_mode_modeinfo {
__u32 clock; __u32 clock;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment