diff options
Diffstat (limited to 'drivers/gpu/drm/i915/display/intel_hdcp.c')
| -rw-r--r-- | drivers/gpu/drm/i915/display/intel_hdcp.c | 214 |
1 files changed, 194 insertions, 20 deletions
diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.c b/drivers/gpu/drm/i915/display/intel_hdcp.c index 7464b44c8bb3..7063e3f5c538 100644 --- a/drivers/gpu/drm/i915/display/intel_hdcp.c +++ b/drivers/gpu/drm/i915/display/intel_hdcp.c @@ -9,6 +9,7 @@ */ #include <linux/component.h> +#include <linux/debugfs.h> #include <linux/i2c.h> #include <linux/random.h> @@ -41,7 +42,7 @@ intel_hdcp_adjust_hdcp_line_rekeying(struct intel_encoder *encoder, u32 rekey_bit = 0; /* Here we assume HDMI is in TMDS mode of operation */ - if (encoder->type != INTEL_OUTPUT_HDMI) + if (!intel_encoder_is_hdmi(encoder)) return; if (DISPLAY_VER(display) >= 30) { @@ -208,7 +209,7 @@ int intel_hdcp_read_valid_bksv(struct intel_digital_port *dig_port, } /* Is HDCP1.4 capable on Platform and Sink */ -bool intel_hdcp_get_capability(struct intel_connector *connector) +static bool intel_hdcp_get_capability(struct intel_connector *connector) { struct intel_digital_port *dig_port; const struct intel_hdcp_shim *shim = connector->hdcp.shim; @@ -264,7 +265,7 @@ static bool intel_hdcp2_prerequisite(struct intel_connector *connector) } /* Is HDCP2.2 capable on Platform and Sink */ -bool intel_hdcp2_get_capability(struct intel_connector *connector) +static bool intel_hdcp2_get_capability(struct intel_connector *connector) { struct intel_hdcp *hdcp = &connector->hdcp; bool capable = false; @@ -278,9 +279,9 @@ bool intel_hdcp2_get_capability(struct intel_connector *connector) return capable; } -void intel_hdcp_get_remote_capability(struct intel_connector *connector, - bool *hdcp_capable, - bool *hdcp2_capable) +static void intel_hdcp_get_remote_capability(struct intel_connector *connector, + bool *hdcp_capable, + bool *hdcp2_capable) { struct intel_hdcp *hdcp = &connector->hdcp; @@ -342,7 +343,7 @@ static bool hdcp_key_loadable(struct intel_display *display) * On HSW and BDW, Display HW loads the Key as soon as Display resumes. * On all BXT+, SW can load the keys only when the PW#1 is turned on. */ - if (IS_HASWELL(i915) || IS_BROADWELL(i915)) + if (display->platform.haswell || display->platform.broadwell) id = HSW_DISP_PW_GLOBAL; else id = SKL_DISP_PW_1; @@ -353,7 +354,7 @@ static bool hdcp_key_loadable(struct intel_display *display) /* * Another req for hdcp key loadability is enabled state of pll for - * cdclk. Without active crtc we wont land here. So we are assuming that + * cdclk. Without active crtc we won't land here. So we are assuming that * cdclk is already on. */ @@ -381,7 +382,7 @@ static int intel_hdcp_load_keys(struct intel_display *display) * On HSW and BDW HW loads the HDCP1.4 Key when Display comes * out of reset. So if Key is not already loaded, its an error state. */ - if (IS_HASWELL(i915) || IS_BROADWELL(i915)) + if (display->platform.haswell || display->platform.broadwell) if (!(intel_de_read(display, HDCP_KEY_STATUS) & HDCP_KEY_LOAD_DONE)) return -ENXIO; @@ -393,7 +394,7 @@ static int intel_hdcp_load_keys(struct intel_display *display) * process from other platforms. These platforms use the GT Driver * Mailbox interface. */ - if (DISPLAY_VER(display) == 9 && !IS_BROXTON(i915)) { + if (DISPLAY_VER(display) == 9 && !display->platform.broxton) { ret = snb_pcode_write(&i915->uncore, SKL_PCODE_LOAD_HDCP_KEYS, 1); if (ret) { drm_err(display->drm, @@ -1550,9 +1551,9 @@ static int hdcp2_authentication_key_exchange(struct intel_connector *connector) * with a 50ms delay if not hdcp2 capable for DP/DPMST encoders * (dock decides to stop advertising hdcp2 capability for some reason). * The reason being that during suspend resume dock usually keeps the - * HDCP2 registers inaccesible causing AUX error. This wouldn't be a + * HDCP2 registers inaccessible causing AUX error. This wouldn't be a * big problem if the userspace just kept retrying with some delay while - * it continues to play low value content but most userpace applications + * it continues to play low value content but most userspace applications * end up throwing an error when it receives one from KMD. This makes * sure we give the dock and the sink devices to complete its power cycle * and then try HDCP authentication. The values of 10 and delay of 50ms @@ -2188,6 +2189,19 @@ static int intel_hdcp2_check_link(struct intel_connector *connector) drm_dbg_kms(display->drm, "HDCP2.2 Downstream topology change\n"); + + ret = hdcp2_authenticate_repeater_topology(connector); + if (!ret) { + intel_hdcp_update_value(connector, + DRM_MODE_CONTENT_PROTECTION_ENABLED, + true); + goto out; + } + + drm_dbg_kms(display->drm, + "[CONNECTOR:%d:%s] Repeater topology auth failed.(%d)\n", + connector->base.base.id, connector->base.name, + ret); } else { drm_dbg_kms(display->drm, "[CONNECTOR:%d:%s] HDCP2.2 link failed, retrying auth\n", @@ -2325,18 +2339,16 @@ static int initialize_hdcp_port_data(struct intel_connector *connector, static bool is_hdcp2_supported(struct intel_display *display) { - struct drm_i915_private *i915 = to_i915(display->drm); - if (intel_hdcp_gsc_cs_required(display)) return true; if (!IS_ENABLED(CONFIG_INTEL_MEI_HDCP)) return false; - return (DISPLAY_VER(display) >= 10 || - IS_KABYLAKE(i915) || - IS_COFFEELAKE(i915) || - IS_COMETLAKE(i915)); + return DISPLAY_VER(display) >= 10 || + display->platform.kabylake || + display->platform.coffeelake || + display->platform.cometlake; } void intel_hdcp_component_init(struct intel_display *display) @@ -2460,13 +2472,16 @@ static int _intel_hdcp_enable(struct intel_atomic_state *state, * Considering that HDCP2.2 is more secure than HDCP1.4, If the setup * is capable of HDCP2.2, it is preferred to use HDCP2.2. */ - if (intel_hdcp2_get_capability(connector)) { + if (!hdcp->force_hdcp14 && intel_hdcp2_get_capability(connector)) { ret = _intel_hdcp2_enable(state, connector); if (!ret) check_link_interval = DRM_HDCP2_CHECK_PERIOD_MS; } + if (hdcp->force_hdcp14) + drm_dbg_kms(display->drm, "Forcing HDCP 1.4\n"); + /* * When HDCP2.2 fails and Content Type is not Type1, HDCP1.4 will * be attempted. @@ -2560,7 +2575,7 @@ void intel_hdcp_update_pipe(struct intel_atomic_state *state, /* * During the HDCP encryption session if Type change is requested, - * disable the HDCP and reenable it with new TYPE value. + * disable the HDCP and re-enable it with new TYPE value. */ if (conn_state->content_protection == DRM_MODE_CONTENT_PROTECTION_UNDESIRED || @@ -2603,6 +2618,15 @@ void intel_hdcp_update_pipe(struct intel_atomic_state *state, _intel_hdcp_enable(state, encoder, crtc_state, conn_state); } +void intel_hdcp_cancel_works(struct intel_connector *connector) +{ + if (!connector->hdcp.shim) + return; + + cancel_delayed_work_sync(&connector->hdcp.check_work); + cancel_work_sync(&connector->hdcp.prop_work); +} + void intel_hdcp_component_fini(struct intel_display *display) { mutex_lock(&display->hdcp.hdcp_mutex); @@ -2718,3 +2742,153 @@ void intel_hdcp_handle_cp_irq(struct intel_connector *connector) queue_delayed_work(i915->unordered_wq, &hdcp->check_work, 0); } + +static void __intel_hdcp_info(struct seq_file *m, struct intel_connector *connector, + bool remote_req) +{ + bool hdcp_cap = false, hdcp2_cap = false; + + if (!connector->hdcp.shim) { + seq_puts(m, "No Connector Support"); + goto out; + } + + if (remote_req) { + intel_hdcp_get_remote_capability(connector, &hdcp_cap, &hdcp2_cap); + } else { + hdcp_cap = intel_hdcp_get_capability(connector); + hdcp2_cap = intel_hdcp2_get_capability(connector); + } + + if (hdcp_cap) + seq_puts(m, "HDCP1.4 "); + if (hdcp2_cap) + seq_puts(m, "HDCP2.2 "); + + if (!hdcp_cap && !hdcp2_cap) + seq_puts(m, "None"); + +out: + seq_puts(m, "\n"); +} + +void intel_hdcp_info(struct seq_file *m, struct intel_connector *connector) +{ + seq_puts(m, "\tHDCP version: "); + if (connector->mst_port) { + __intel_hdcp_info(m, connector, true); + seq_puts(m, "\tMST Hub HDCP version: "); + } + __intel_hdcp_info(m, connector, false); +} + +static int intel_hdcp_sink_capability_show(struct seq_file *m, void *data) +{ + struct intel_connector *connector = m->private; + struct intel_display *display = to_intel_display(connector); + int ret; + + ret = drm_modeset_lock_single_interruptible(&display->drm->mode_config.connection_mutex); + if (ret) + return ret; + + if (!connector->base.encoder || + connector->base.status != connector_status_connected) { + ret = -ENODEV; + goto out; + } + + seq_printf(m, "%s:%d HDCP version: ", connector->base.name, + connector->base.base.id); + __intel_hdcp_info(m, connector, false); + +out: + drm_modeset_unlock(&display->drm->mode_config.connection_mutex); + + return ret; +} +DEFINE_SHOW_ATTRIBUTE(intel_hdcp_sink_capability); + +static ssize_t intel_hdcp_force_14_write(struct file *file, + const char __user *ubuf, + size_t len, loff_t *offp) +{ + struct seq_file *m = file->private_data; + struct intel_connector *connector = m->private; + struct intel_hdcp *hdcp = &connector->hdcp; + bool force_hdcp14 = false; + int ret; + + if (len == 0) + return 0; + + ret = kstrtobool_from_user(ubuf, len, &force_hdcp14); + if (ret < 0) + return ret; + + hdcp->force_hdcp14 = force_hdcp14; + *offp += len; + + return len; +} + +static int intel_hdcp_force_14_show(struct seq_file *m, void *data) +{ + struct intel_connector *connector = m->private; + struct intel_display *display = to_intel_display(connector); + struct intel_encoder *encoder = intel_attached_encoder(connector); + struct intel_hdcp *hdcp = &connector->hdcp; + struct drm_crtc *crtc; + int ret; + + if (!encoder) + return -ENODEV; + + ret = drm_modeset_lock_single_interruptible(&display->drm->mode_config.connection_mutex); + if (ret) + return ret; + + crtc = connector->base.state->crtc; + if (connector->base.status != connector_status_connected || !crtc) { + ret = -ENODEV; + goto out; + } + + seq_printf(m, "%s\n", + str_yes_no(hdcp->force_hdcp14)); +out: + drm_modeset_unlock(&display->drm->mode_config.connection_mutex); + + return ret; +} + +static int intel_hdcp_force_14_open(struct inode *inode, + struct file *file) +{ + return single_open(file, intel_hdcp_force_14_show, + inode->i_private); +} + +static const struct file_operations intel_hdcp_force_14_fops = { + .owner = THIS_MODULE, + .open = intel_hdcp_force_14_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = intel_hdcp_force_14_write +}; + +void intel_hdcp_connector_debugfs_add(struct intel_connector *connector) +{ + struct dentry *root = connector->base.debugfs_entry; + int connector_type = connector->base.connector_type; + + if (connector_type == DRM_MODE_CONNECTOR_DisplayPort || + connector_type == DRM_MODE_CONNECTOR_HDMIA || + connector_type == DRM_MODE_CONNECTOR_HDMIB) { + debugfs_create_file("i915_hdcp_sink_capability", 0444, root, + connector, &intel_hdcp_sink_capability_fops); + debugfs_create_file("i915_force_hdcp14", 0644, root, + connector, &intel_hdcp_force_14_fops); + } +} |