Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ee5e5e7a authored by Sean Paul's avatar Sean Paul
Browse files

drm/i915: Add HDCP framework + base implementation



This patch adds the framework required to add HDCP support to intel
connectors. It implements Aksv loading from fuse, and parts 1/2/3
of the HDCP authentication scheme.

Note that without shim implementations, this does not actually implement
HDCP. That will come in subsequent patches.

Changes in v2:
- Don't open code wait_fors (Chris)
- drm_hdcp.c under MIT license (Daniel)
- Move intel_hdcp_disable() call above ddi_disable (Ram)
- Fix // comments (I wore a cone of shame for 12 hours to atone) (Daniel)
- Justify intel_hdcp_shim with comments (Daniel)
- Fixed async locking issues by adding hdcp_mutex (Daniel)
- Don't alter connector_state in enable/disable (Daniel)
Changes in v3:
- Added hdcp_mutex/hdcp_value to make async reasonable
- Added hdcp_prop_work to separate link checking & property setting
- Added new helper for atomic_check state tracking (Daniel)
- Moved enable/disable into atomic_commit with matching helpers
- Moved intel_hdcp_check_link out of all locks when called from dp
- Bumped up ksv_fifo timeout (noticed failure on one of my dongles)
Changes in v4:
- Remove SKL_ prefix from most register names (Daniel)
- Move enable/disable back to modeset path (Daniel)
- s/get_random_long/get_random_u32/ (Daniel)
- Remove mode_config.mutex lock in prop_work (Daniel)
- Add intel_hdcp_init to handle init of conn components (Daniel)
- Actually check return value of attach_property
- Check Bksv is valid before trying to authenticate (Ram)
Changes in v5:
- checkpatch whitespace changes
- s/DRM_MODE_CONTENT_PROTECTION_OFF/DRM_MODE_CONTENT_PROTECTION_UNDESIRED/
- Fix ksv list wait timeout (actually wait 5s)
- Increase the R0 timeout to 300ms (Ram)
Changes in v6:
- SPDX license

Cc: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: default avatarRamalingam C <ramalingm.c@intel.com>
Reviewed-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: default avatarSean Paul <seanpaul@chromium.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20180108195545.218615-6-seanpaul@chromium.org
parent 495eb7f8
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -108,6 +108,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 \
+83 −0
Original line number Original line Diff line number Diff line
@@ -8043,6 +8043,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
@@ -8345,6 +8346,88 @@ enum skl_power_gate {
#define  SKL_PW_TO_PG(pw)			((pw) - SKL_DISP_PW_1 + SKL_PG1)
#define  SKL_PW_TO_PG(pw)			((pw) - SKL_DISP_PW_1 + SKL_PG1)
#define  SKL_FUSE_PG_DIST_STATUS(pg)		(1 << (27 - (pg)))
#define  SKL_FUSE_PG_DIST_STATUS(pg)		(1 << (27 - (pg)))



/* 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_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
+2 −0
Original line number Original line Diff line number Diff line
@@ -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;


+7 −0
Original line number Original line Diff line number Diff line
@@ -2423,6 +2423,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,
@@ -2457,6 +2462,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
+4 −0
Original line number Original line Diff line number Diff line
@@ -15217,6 +15217,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);
}
}
Loading