Received: by 10.223.164.202 with SMTP id h10csp158255wrb; Wed, 29 Nov 2017 19:11:04 -0800 (PST) X-Google-Smtp-Source: AGs4zMZ2MjAAcAWqtk9xMOF5knCbo+mJgOCAvrzRToUXjGx+QgZCioMUbR8IqbcY+0A8AmEN6i7V X-Received: by 10.98.137.14 with SMTP id v14mr5208133pfd.10.1512011463971; Wed, 29 Nov 2017 19:11:03 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1512011463; cv=none; d=google.com; s=arc-20160816; b=VNLsPPKk67G0l4pkgfXCPFlg5iG3azptm2uObnldVp+4VPQt+dXzn+525UTYRIYoBN I/p0HbV/NUnwzMaySUKi31muKwXOyQbvGZQEDjf2LEYpRPR5C3pDL9BWkQgE1JGP6RxF qIRJfiyamqLFCWc/WhU9G110nRs1FC+HDMcz/28/CI62Eu1ettPyJkLeTnqqTyOPD8A9 91xzjkQJW6yKvmn9lwT1Z8NwY/cxJpGcKF5rx3MCIUidrRb9U64UY4R+y+e41nh5EY1s k0IwPdsG/g2VSeCDe1UvdaovdWPg5ksa96+ThAbrWzo+osfH9rUQHypSa0+v7C7/4nzQ HqUg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=xeHljpXMMMG0IYnAhdVMBSK2mB5Kg74AsEU8YdPmUMQ=; b=AiGDlfPkGDExBhMU/KbpihmYtR/D4uC7bwZQphceD9kBjwTnD1pAgSQA6cG+nMYmaO 9buFP42zYCyc/+S6MMC/u2OQh4D2dKqJX+QenbxTeAcUKToNtCyyG9xfXC1R8QfN+Fgj pFyjANwNVlvaB6sJJj6NjoCTneMAlP1iwgRLsDVgnvcM6CqR8JMqCOcC4yKl+XgWTSWh 2x9szPS42UFItKFda4Kct0zEcTMwZhlXLuByexRzw7HMJ2NG8+EeflTb9jPQfYIkWn7i asWKKWS9svGSRv3v1KmF5yxPrJRLV8efcKJcu/shfADQMDgADuKl8CSNmB4XkRP15+Py 1SLg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b=ceDZsotL; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id bg3si2259355plb.668.2017.11.29.19.10.47; Wed, 29 Nov 2017 19:11:03 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b=ceDZsotL; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753654AbdK3DKX (ORCPT + 99 others); Wed, 29 Nov 2017 22:10:23 -0500 Received: from mail-yb0-f196.google.com ([209.85.213.196]:36746 "EHLO mail-yb0-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753628AbdK3DKV (ORCPT ); Wed, 29 Nov 2017 22:10:21 -0500 Received: by mail-yb0-f196.google.com with SMTP id c69so2198154ybf.3 for ; Wed, 29 Nov 2017 19:10:21 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=xeHljpXMMMG0IYnAhdVMBSK2mB5Kg74AsEU8YdPmUMQ=; b=ceDZsotLDaSJjKvqepgONx3RFa1VjMT8eDlJ0GRqRvbe7y/u/06N8q6mEJqL2DZhHT d0k4d1nRWgYqeC0JRjbrzhb1Z+jbpIuZpXZN86KUz/4ccaBvnS1lMbIuvb5bXeRhyr1S e9qVA78/uTs6IybE9Eq9eSt5kfa5DwxUwd9f0= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=xeHljpXMMMG0IYnAhdVMBSK2mB5Kg74AsEU8YdPmUMQ=; b=GZZpVoFvQU8EZn8yFmVb46EHBghS/pknnzzpN3zEnsvpAD5Q/B8aRBK7sGk3r5k026 yYvBLzRsbrrfC9l6eX6PpfTKV5/bNCQ2pXH71uKbUg/kENQotvnzfsnMITLD3Nzpy7qL h1eqtO6sR+d5SEMupx9M6XRMwNNfe02ej0/mzPV7xK91JtTQBqY6y3XOqA1iKq+fjTS/ aja/l4REcDFo0vYDrJZFEYu095hgF0mS+RbMZgGp+sqKXxKNb4XhJqWAki5oji7MLi2O fhGTE53oTSMBGVBkvjfcCtbZX0QLBGiaGJCldwWT9pzz3qY0aKcpiqgC7+L8WGkeAGm+ VILQ== X-Gm-Message-State: AJaThX5m/tSgOsdEIn8Nywh9rAL3rm956aIT+s+Kjf6h4ttgdawmz/HC R06Ab4gJY+1ocjIOrzHKCSuH9g== X-Received: by 10.37.161.131 with SMTP id a3mr631298ybi.19.1512011420870; Wed, 29 Nov 2017 19:10:20 -0800 (PST) Received: from rosewood.cam.corp.google.com ([2620:0:1013:11:d3af:69ac:1964:28e8]) by smtp.gmail.com with ESMTPSA id u24sm1460752ywh.84.2017.11.29.19.10.20 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 29 Nov 2017 19:10:20 -0800 (PST) From: Sean Paul To: dri-devel@lists.freedesktop.org, intel-gfx@lists.freedesktop.org Cc: Sean Paul , Jani Nikula , Joonas Lahtinen , Rodrigo Vivi , David Airlie , linux-kernel@vger.kernel.org Subject: [RFC PATCH 6/6] drm/i915: Implement HDCP for DisplayPort Date: Wed, 29 Nov 2017 22:09:01 -0500 Message-Id: <20171130030907.26848-7-seanpaul@chromium.org> X-Mailer: git-send-email 2.15.0.531.g2ccb3012c9-goog In-Reply-To: <20171130030907.26848-1-seanpaul@chromium.org> References: <20171130030907.26848-1-seanpaul@chromium.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This patch adds HDCP support for DisplayPort connectors by implementing the intel_hdcp_shim. Most of this is straightforward read/write from/to DPCD registers. One thing worth pointing out is the Aksv output bit. It wasn't easily separable like it's HDMI counterpart, so it's crammed in with the rest of it. Signed-off-by: Sean Paul --- drivers/gpu/drm/i915/intel_dp.c | 243 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 236 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index d11281004109..091c8bcc4645 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -36,7 +36,9 @@ #include #include #include +#include #include +#include #include "intel_drv.h" #include #include "i915_drv.h" @@ -1039,10 +1041,29 @@ static uint32_t skl_get_aux_send_ctl(struct intel_dp *intel_dp, 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 intel_dp_aux_ch(struct intel_dp *intel_dp, 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 drm_i915_private *dev_priv = @@ -1102,10 +1123,11 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, } while ((aux_clock_divider = intel_dp->get_aux_clock_divider(intel_dp, clock++))) { - u32 send_ctl = intel_dp->get_aux_send_ctl(intel_dp, - has_aux_irq, - send_bytes, - aux_clock_divider); + u32 send_ctl = intel_dp_get_aux_send_ctl(intel_dp, + has_aux_irq, + send_bytes, + aux_clock_divider, + aksv_write); /* Must try at least 3 times according to DP spec */ for (try = 0; try < 5; try++) { @@ -1242,7 +1264,8 @@ intel_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) if (msg->buffer) 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) { msg->reply = rxbuf[0] >> 4; @@ -1264,7 +1287,8 @@ intel_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) if (WARN_ON(rxsize > 20)) 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) { msg->reply = rxbuf[0] >> 4; /* @@ -4310,6 +4334,8 @@ intel_dp_check_link_status(struct intel_dp *intel_dp) intel_dp_retrain_link(intel_dp); } + + intel_hdcp_check_link(intel_dp->attached_connector); } /* @@ -4977,6 +5003,203 @@ void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder) 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 (%ld)\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 (%ld)\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 (%ld)\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 = 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 (%ld)\n", ret); + return ret >= 0 ? -EIO : 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 (%ld)\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 (%ld)\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 (%ld)\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 (%ld)\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 (%ld)\n", ret); + return ret >= 0 ? -EIO : ret; + } + return !(bstatus & DP_BSTATUS_LINK_FAILURE); +} + +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, +}; + static void intel_edp_panel_vdd_sanitize(struct intel_dp *intel_dp) { struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); @@ -6097,6 +6320,12 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, intel_dp_add_properties(intel_dp, connector); + if (INTEL_GEN(dev_priv) >= 9 && !intel_dp_is_edp(intel_dp)) { + drm_connector_attach_content_protection_property(connector); + intel_connector->hdcp_shim = &intel_dp_hdcp_shim; + INIT_DELAYED_WORK(&intel_connector->hdcp_work, intel_hdcp_work); + } + /* 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 * generated on the port when a cable is not attached. -- 2.15.0.531.g2ccb3012c9-goog From 1585573138958356206@xxx Fri Dec 01 09:26:19 +0000 2017 X-GM-THRID: 1585543613313960349 X-Gmail-Labels: Inbox,Category Forums,HistoricalUnread