From a98c30fdc00e146daed013598f10708d6b0ef11e Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 19 Apr 2022 12:33:09 -0700 Subject: mei: add support for graphics system controller (gsc) devices GSC is a graphics system controller, based on CSE, it provides a chassis controller for graphics discrete cards, as well as it supports media protection on selected devices. mei_gsc binds to a auxiliary devices exposed by Intel discrete driver i915. v2: fix error check in mei_gsc_probe v3: update MODULE_LICENSE ("GPL" is preferred over "GPL v2" and they both map to GPL version 2) Signed-off-by: Alexander Usyskin Signed-off-by: Tomas Winkler Reviewed-by: Daniele Ceraolo Spurio Signed-off-by: Daniele Ceraolo Spurio Acked-by: Rodrigo Vivi #v3 Link: https://patchwork.freedesktop.org/patch/msgid/20220419193314.526966-3-daniele.ceraolospurio@intel.com --- drivers/misc/mei/Kconfig | 14 ++++ drivers/misc/mei/Makefile | 3 + drivers/misc/mei/gsc-me.c | 194 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/misc/mei/hw-me.c | 27 ++++++- drivers/misc/mei/hw-me.h | 2 + 5 files changed, 238 insertions(+), 2 deletions(-) create mode 100644 drivers/misc/mei/gsc-me.c (limited to 'drivers/misc') diff --git a/drivers/misc/mei/Kconfig b/drivers/misc/mei/Kconfig index 0e0bcd0da852..d21486d69df2 100644 --- a/drivers/misc/mei/Kconfig +++ b/drivers/misc/mei/Kconfig @@ -46,6 +46,20 @@ config INTEL_MEI_TXE Supported SoCs: Intel Bay Trail +config INTEL_MEI_GSC + tristate "Intel MEI GSC embedded device" + depends on INTEL_MEI + depends on INTEL_MEI_ME + depends on X86 && PCI + depends on DRM_I915 + help + Intel auxiliary driver for GSC devices embedded in Intel graphics devices. + + An MEI device here called GSC can be embedded in an + Intel graphics devices, to support a range of chassis + tasks such as graphics card firmware update and security + tasks. + source "drivers/misc/mei/hdcp/Kconfig" source "drivers/misc/mei/pxp/Kconfig" diff --git a/drivers/misc/mei/Makefile b/drivers/misc/mei/Makefile index d8e5165917f2..fb740d754900 100644 --- a/drivers/misc/mei/Makefile +++ b/drivers/misc/mei/Makefile @@ -18,6 +18,9 @@ obj-$(CONFIG_INTEL_MEI_ME) += mei-me.o mei-me-objs := pci-me.o mei-me-objs += hw-me.o +obj-$(CONFIG_INTEL_MEI_GSC) += mei-gsc.o +mei-gsc-objs := gsc-me.o + obj-$(CONFIG_INTEL_MEI_TXE) += mei-txe.o mei-txe-objs := pci-txe.o mei-txe-objs += hw-txe.o diff --git a/drivers/misc/mei/gsc-me.c b/drivers/misc/mei/gsc-me.c new file mode 100644 index 000000000000..c474094645a0 --- /dev/null +++ b/drivers/misc/mei/gsc-me.c @@ -0,0 +1,194 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(c) 2019-2022, Intel Corporation. All rights reserved. + * + * Intel Management Engine Interface (Intel MEI) Linux driver + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mei_dev.h" +#include "hw-me.h" +#include "hw-me-regs.h" + +#include "mei-trace.h" + +#define MEI_GSC_RPM_TIMEOUT 500 + +static int mei_gsc_read_hfs(const struct mei_device *dev, int where, u32 *val) +{ + struct mei_me_hw *hw = to_me_hw(dev); + + *val = ioread32(hw->mem_addr + where + 0xC00); + + return 0; +} + +static int mei_gsc_probe(struct auxiliary_device *aux_dev, + const struct auxiliary_device_id *aux_dev_id) +{ + struct mei_aux_device *adev = auxiliary_dev_to_mei_aux_dev(aux_dev); + struct mei_device *dev; + struct mei_me_hw *hw; + struct device *device; + const struct mei_cfg *cfg; + int ret; + + cfg = mei_me_get_cfg(aux_dev_id->driver_data); + if (!cfg) + return -ENODEV; + + device = &aux_dev->dev; + + dev = mei_me_dev_init(device, cfg); + if (!dev) { + ret = -ENOMEM; + goto err; + } + + hw = to_me_hw(dev); + hw->mem_addr = devm_ioremap_resource(device, &adev->bar); + if (IS_ERR(hw->mem_addr)) { + dev_err(device, "mmio not mapped\n"); + ret = PTR_ERR(hw->mem_addr); + goto err; + } + + hw->irq = adev->irq; + hw->read_fws = mei_gsc_read_hfs; + + dev_set_drvdata(device, dev); + + ret = devm_request_threaded_irq(device, hw->irq, + mei_me_irq_quick_handler, + mei_me_irq_thread_handler, + IRQF_ONESHOT, KBUILD_MODNAME, dev); + if (ret) { + dev_err(device, "irq register failed %d\n", ret); + goto err; + } + + pm_runtime_get_noresume(device); + pm_runtime_set_active(device); + pm_runtime_enable(device); + + if (mei_start(dev)) { + dev_err(device, "init hw failure.\n"); + ret = -ENODEV; + goto irq_err; + } + + pm_runtime_set_autosuspend_delay(device, MEI_GSC_RPM_TIMEOUT); + pm_runtime_use_autosuspend(device); + + ret = mei_register(dev, device); + if (ret) + goto register_err; + + pm_runtime_put_noidle(device); + return 0; + +register_err: + mei_stop(dev); +irq_err: + devm_free_irq(device, hw->irq, dev); + +err: + dev_err(device, "probe failed: %d\n", ret); + dev_set_drvdata(device, NULL); + return ret; +} + +static void mei_gsc_remove(struct auxiliary_device *aux_dev) +{ + struct mei_device *dev; + struct mei_me_hw *hw; + + dev = dev_get_drvdata(&aux_dev->dev); + if (!dev) + return; + + hw = to_me_hw(dev); + + mei_stop(dev); + + mei_deregister(dev); + + pm_runtime_disable(&aux_dev->dev); + + mei_disable_interrupts(dev); + devm_free_irq(&aux_dev->dev, hw->irq, dev); +} + +static int __maybe_unused mei_gsc_pm_suspend(struct device *device) +{ + struct mei_device *dev = dev_get_drvdata(device); + + if (!dev) + return -ENODEV; + + mei_stop(dev); + + mei_disable_interrupts(dev); + + return 0; +} + +static int __maybe_unused mei_gsc_pm_resume(struct device *device) +{ + struct mei_device *dev = dev_get_drvdata(device); + int err; + + if (!dev) + return -ENODEV; + + err = mei_restart(dev); + if (err) + return err; + + /* Start timer if stopped in suspend */ + schedule_delayed_work(&dev->timer_work, HZ); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(mei_gsc_pm_ops, mei_gsc_pm_suspend, mei_gsc_pm_resume); + +static const struct auxiliary_device_id mei_gsc_id_table[] = { + { + .name = "i915.mei-gsc", + .driver_data = MEI_ME_GSC_CFG, + + }, + { + .name = "i915.mei-gscfi", + .driver_data = MEI_ME_GSCFI_CFG, + }, + { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(auxiliary, mei_gsc_id_table); + +static struct auxiliary_driver mei_gsc_driver = { + .probe = mei_gsc_probe, + .remove = mei_gsc_remove, + .driver = { + /* auxiliary_driver_register() sets .name to be the modname */ + .pm = &mei_gsc_pm_ops, + }, + .id_table = mei_gsc_id_table +}; +module_auxiliary_driver(mei_gsc_driver); + +MODULE_AUTHOR("Intel Corporation"); +MODULE_ALIAS("auxiliary:i915.mei-gsc"); +MODULE_ALIAS("auxiliary:i915.mei-gscfi"); +MODULE_LICENSE("GPL"); diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c index 719fee9af156..03945d3b34da 100644 --- a/drivers/misc/mei/hw-me.c +++ b/drivers/misc/mei/hw-me.c @@ -1226,6 +1226,7 @@ irqreturn_t mei_me_irq_quick_handler(int irq, void *dev_id) me_intr_disable(dev, hcsr); return IRQ_WAKE_THREAD; } +EXPORT_SYMBOL_GPL(mei_me_irq_quick_handler); /** * mei_me_irq_thread_handler - function called after ISR to handle the interrupt @@ -1326,6 +1327,7 @@ end: mutex_unlock(&dev->device_lock); return IRQ_HANDLED; } +EXPORT_SYMBOL_GPL(mei_me_irq_thread_handler); static const struct mei_hw_ops mei_me_hw_ops = { @@ -1440,6 +1442,12 @@ static bool mei_me_fw_type_sps_ign(const struct pci_dev *pdev) #define MEI_CFG_KIND_ITOUCH \ .kind = "itouch" +#define MEI_CFG_TYPE_GSC \ + .kind = "gsc" + +#define MEI_CFG_TYPE_GSCFI \ + .kind = "gscfi" + #define MEI_CFG_FW_SPS_IGN \ .quirk_probe = mei_me_fw_type_sps_ign @@ -1572,6 +1580,18 @@ static const struct mei_cfg mei_me_pch15_sps_cfg = { MEI_CFG_FW_SPS_IGN, }; +/* Graphics System Controller */ +static const struct mei_cfg mei_me_gsc_cfg = { + MEI_CFG_TYPE_GSC, + MEI_CFG_PCH8_HFS, +}; + +/* Graphics System Controller Firmware Interface */ +static const struct mei_cfg mei_me_gscfi_cfg = { + MEI_CFG_TYPE_GSCFI, + MEI_CFG_PCH8_HFS, +}; + /* * mei_cfg_list - A list of platform platform specific configurations. * Note: has to be synchronized with enum mei_cfg_idx. @@ -1592,6 +1612,8 @@ static const struct mei_cfg *const mei_cfg_list[] = { [MEI_ME_PCH12_SPS_ITOUCH_CFG] = &mei_me_pch12_itouch_sps_cfg, [MEI_ME_PCH15_CFG] = &mei_me_pch15_cfg, [MEI_ME_PCH15_SPS_CFG] = &mei_me_pch15_sps_cfg, + [MEI_ME_GSC_CFG] = &mei_me_gsc_cfg, + [MEI_ME_GSCFI_CFG] = &mei_me_gscfi_cfg, }; const struct mei_cfg *mei_me_get_cfg(kernel_ulong_t idx) @@ -1602,7 +1624,8 @@ const struct mei_cfg *mei_me_get_cfg(kernel_ulong_t idx) return NULL; return mei_cfg_list[idx]; -}; +} +EXPORT_SYMBOL_GPL(mei_me_get_cfg); /** * mei_me_dev_init - allocates and initializes the mei device structure @@ -1637,4 +1660,4 @@ struct mei_device *mei_me_dev_init(struct device *parent, return dev; } - +EXPORT_SYMBOL_GPL(mei_me_dev_init); diff --git a/drivers/misc/mei/hw-me.h b/drivers/misc/mei/hw-me.h index 00a7132ac7a2..a071c645e905 100644 --- a/drivers/misc/mei/hw-me.h +++ b/drivers/misc/mei/hw-me.h @@ -112,6 +112,8 @@ enum mei_cfg_idx { MEI_ME_PCH12_SPS_ITOUCH_CFG, MEI_ME_PCH15_CFG, MEI_ME_PCH15_SPS_CFG, + MEI_ME_GSC_CFG, + MEI_ME_GSCFI_CFG, MEI_ME_NUM_CFG, }; -- cgit v1.2.3 From ce97126d6c1825fc7b3dd21a66a83458055bcbd7 Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Tue, 19 Apr 2022 12:33:10 -0700 Subject: mei: gsc: setup char driver alive in spite of firmware handshake failure Setup char device in spite of firmware handshake failure. In order to provide host access to the firmware status registers and other information required for the manufacturing process. Signed-off-by: Alexander Usyskin Signed-off-by: Tomas Winkler Reviewed-by: Daniele Ceraolo Spurio Signed-off-by: Daniele Ceraolo Spurio Link: https://patchwork.freedesktop.org/patch/msgid/20220419193314.526966-4-daniele.ceraolospurio@intel.com --- drivers/misc/mei/gsc-me.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/mei/gsc-me.c b/drivers/misc/mei/gsc-me.c index c474094645a0..c91bf440ea26 100644 --- a/drivers/misc/mei/gsc-me.c +++ b/drivers/misc/mei/gsc-me.c @@ -79,11 +79,12 @@ static int mei_gsc_probe(struct auxiliary_device *aux_dev, pm_runtime_set_active(device); pm_runtime_enable(device); - if (mei_start(dev)) { - dev_err(device, "init hw failure.\n"); - ret = -ENODEV; - goto irq_err; - } + /* Continue to char device setup in spite of firmware handshake failure. + * In order to provide access to the firmware status registers to the user + * space via sysfs. + */ + if (mei_start(dev)) + dev_warn(device, "init hw failure.\n"); pm_runtime_set_autosuspend_delay(device, MEI_GSC_RPM_TIMEOUT); pm_runtime_use_autosuspend(device); @@ -97,7 +98,6 @@ static int mei_gsc_probe(struct auxiliary_device *aux_dev, register_err: mei_stop(dev); -irq_err: devm_free_irq(device, hw->irq, dev); err: -- cgit v1.2.3 From ad10a35461a5fc4e4d09a7259ede2508f042c6dd Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 19 Apr 2022 12:33:11 -0700 Subject: mei: gsc: add runtime pm handlers Implement runtime handlers for mei-gsc, to track idle state of the device properly. CC: Rodrigo Vivi Signed-off-by: Tomas Winkler Signed-off-by: Alexander Usyskin Reviewed-by: Rodrigo Vivi Signed-off-by: Daniele Ceraolo Spurio Link: https://patchwork.freedesktop.org/patch/msgid/20220419193314.526966-5-daniele.ceraolospurio@intel.com --- drivers/misc/mei/gsc-me.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) (limited to 'drivers/misc') diff --git a/drivers/misc/mei/gsc-me.c b/drivers/misc/mei/gsc-me.c index c91bf440ea26..c8145e9b62b6 100644 --- a/drivers/misc/mei/gsc-me.c +++ b/drivers/misc/mei/gsc-me.c @@ -159,7 +159,72 @@ static int __maybe_unused mei_gsc_pm_resume(struct device *device) return 0; } -static SIMPLE_DEV_PM_OPS(mei_gsc_pm_ops, mei_gsc_pm_suspend, mei_gsc_pm_resume); +static int __maybe_unused mei_gsc_pm_runtime_idle(struct device *device) +{ + struct mei_device *dev = dev_get_drvdata(device); + + if (!dev) + return -ENODEV; + if (mei_write_is_idle(dev)) + pm_runtime_autosuspend(device); + + return -EBUSY; +} + +static int __maybe_unused mei_gsc_pm_runtime_suspend(struct device *device) +{ + struct mei_device *dev = dev_get_drvdata(device); + struct mei_me_hw *hw; + int ret; + + if (!dev) + return -ENODEV; + + mutex_lock(&dev->device_lock); + + if (mei_write_is_idle(dev)) { + hw = to_me_hw(dev); + hw->pg_state = MEI_PG_ON; + ret = 0; + } else { + ret = -EAGAIN; + } + + mutex_unlock(&dev->device_lock); + + return ret; +} + +static int __maybe_unused mei_gsc_pm_runtime_resume(struct device *device) +{ + struct mei_device *dev = dev_get_drvdata(device); + struct mei_me_hw *hw; + irqreturn_t irq_ret; + + if (!dev) + return -ENODEV; + + mutex_lock(&dev->device_lock); + + hw = to_me_hw(dev); + hw->pg_state = MEI_PG_OFF; + + mutex_unlock(&dev->device_lock); + + irq_ret = mei_me_irq_thread_handler(1, dev); + if (irq_ret != IRQ_HANDLED) + dev_err(dev->dev, "thread handler fail %d\n", irq_ret); + + return 0; +} + +static const struct dev_pm_ops mei_gsc_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(mei_gsc_pm_suspend, + mei_gsc_pm_resume) + SET_RUNTIME_PM_OPS(mei_gsc_pm_runtime_suspend, + mei_gsc_pm_runtime_resume, + mei_gsc_pm_runtime_idle) +}; static const struct auxiliary_device_id mei_gsc_id_table[] = { { -- cgit v1.2.3 From 1bc22fc53a536c051bfbcc377ed50eb217c1fe7e Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Tue, 19 Apr 2022 12:33:12 -0700 Subject: mei: gsc: retrieve the firmware version Add a hook to retrieve the firmware version of the GSC devices to bus-fixup. GSC has a different MKHI clients GUIDs but the same message structure to retrieve the firmware version as MEI so mei_fwver() can be reused. CC: Ashutosh Dixit Signed-off-by: Alexander Usyskin Signed-off-by: Tomas Winkler Reviewed-by: Daniele Ceraolo Spurio Signed-off-by: Daniele Ceraolo Spurio Link: https://patchwork.freedesktop.org/patch/msgid/20220419193314.526966-6-daniele.ceraolospurio@intel.com --- drivers/misc/mei/bus-fixup.c | 25 +++++++++++++++++++++++++ drivers/misc/mei/hw-me.c | 2 ++ 2 files changed, 27 insertions(+) (limited to 'drivers/misc') diff --git a/drivers/misc/mei/bus-fixup.c b/drivers/misc/mei/bus-fixup.c index 67844089db21..59506ba6fc48 100644 --- a/drivers/misc/mei/bus-fixup.c +++ b/drivers/misc/mei/bus-fixup.c @@ -30,6 +30,12 @@ static const uuid_le mei_nfc_info_guid = MEI_UUID_NFC_INFO; #define MEI_UUID_MKHIF_FIX UUID_LE(0x55213584, 0x9a29, 0x4916, \ 0xba, 0xdf, 0xf, 0xb7, 0xed, 0x68, 0x2a, 0xeb) +#define MEI_UUID_IGSC_MKHI UUID_LE(0xE2C2AFA2, 0x3817, 0x4D19, \ + 0x9D, 0x95, 0x06, 0xB1, 0x6B, 0x58, 0x8A, 0x5D) + +#define MEI_UUID_IGSC_MKHI_FIX UUID_LE(0x46E0C1FB, 0xA546, 0x414F, \ + 0x91, 0x70, 0xB7, 0xF4, 0x6D, 0x57, 0xB4, 0xAD) + #define MEI_UUID_HDCP UUID_LE(0xB638AB7E, 0x94E2, 0x4EA2, \ 0xA5, 0x52, 0xD1, 0xC5, 0x4B, 0x62, 0x7F, 0x04) @@ -241,6 +247,23 @@ static void mei_mkhi_fix(struct mei_cl_device *cldev) mei_cldev_disable(cldev); } +static void mei_gsc_mkhi_ver(struct mei_cl_device *cldev) +{ + int ret; + + /* No need to enable the client if nothing is needed from it */ + if (!cldev->bus->fw_f_fw_ver_supported) + return; + + ret = mei_cldev_enable(cldev); + if (ret) + return; + + ret = mei_fwver(cldev); + if (ret < 0) + dev_err(&cldev->dev, "FW version command failed %d\n", ret); + mei_cldev_disable(cldev); +} /** * mei_wd - wd client on the bus, change protocol version * as the API has changed. @@ -492,6 +515,8 @@ static struct mei_fixup { MEI_FIXUP(MEI_UUID_NFC_HCI, mei_nfc), MEI_FIXUP(MEI_UUID_WD, mei_wd), MEI_FIXUP(MEI_UUID_MKHIF_FIX, mei_mkhi_fix), + MEI_FIXUP(MEI_UUID_IGSC_MKHI, mei_gsc_mkhi_ver), + MEI_FIXUP(MEI_UUID_IGSC_MKHI_FIX, mei_gsc_mkhi_ver), MEI_FIXUP(MEI_UUID_HDCP, whitelist), MEI_FIXUP(MEI_UUID_ANY, vt_support), MEI_FIXUP(MEI_UUID_PAVP, whitelist), diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c index 03945d3b34da..9870bf717979 100644 --- a/drivers/misc/mei/hw-me.c +++ b/drivers/misc/mei/hw-me.c @@ -1584,12 +1584,14 @@ static const struct mei_cfg mei_me_pch15_sps_cfg = { static const struct mei_cfg mei_me_gsc_cfg = { MEI_CFG_TYPE_GSC, MEI_CFG_PCH8_HFS, + MEI_CFG_FW_VER_SUPP, }; /* Graphics System Controller Firmware Interface */ static const struct mei_cfg mei_me_gscfi_cfg = { MEI_CFG_TYPE_GSCFI, MEI_CFG_PCH8_HFS, + MEI_CFG_FW_VER_SUPP, }; /* -- cgit v1.2.3 From 6a99099fe1d6c46cbcd74298eeb386c4b9048f77 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 21 Apr 2022 09:31:06 +0200 Subject: drm/display: Move HDCP helpers into display-helper module Move DRM's HDCP helper library into the display/ subdirectory and add it to DRM's display helpers. Split the header file into core and helpers. Update all affected drivers. No functional changes. v3: * fix Kconfig dependencies v2: * fix include statements (Jani, Javier) * update Kconfig symbols Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20220421073108.19226-7-tzimmermann@suse.de --- Documentation/gpu/drm-kms-helpers.rst | 2 +- drivers/gpu/drm/Makefile | 2 +- drivers/gpu/drm/amd/display/Kconfig | 1 + drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2 +- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c | 2 +- drivers/gpu/drm/amd/display/modules/hdcp/hdcp.h | 2 +- drivers/gpu/drm/bridge/Kconfig | 1 + drivers/gpu/drm/bridge/analogix/Kconfig | 1 + drivers/gpu/drm/bridge/analogix/anx7625.c | 2 +- drivers/gpu/drm/bridge/cadence/Kconfig | 1 + .../gpu/drm/bridge/cadence/cdns-mhdp8546-core.c | 2 +- .../gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.c | 2 +- drivers/gpu/drm/bridge/ite-it6505.c | 2 +- drivers/gpu/drm/display/Kconfig | 6 + drivers/gpu/drm/display/Makefile | 1 + drivers/gpu/drm/display/drm_hdcp_helper.c | 421 ++++++++++++++++++++ drivers/gpu/drm/drm_hdcp.c | 423 --------------------- drivers/gpu/drm/i915/Kconfig | 1 + drivers/gpu/drm/i915/display/intel_dp_hdcp.c | 2 +- drivers/gpu/drm/i915/display/intel_gmbus.c | 2 +- drivers/gpu/drm/i915/display/intel_hdcp.c | 2 +- drivers/gpu/drm/i915/display/intel_hdmi.c | 2 +- drivers/misc/mei/hdcp/mei_hdcp.h | 2 +- include/drm/display/drm_hdcp.h | 298 +++++++++++++++ include/drm/display/drm_hdcp_helper.h | 22 ++ include/drm/drm_hdcp.h | 308 --------------- include/drm/i915_mei_hdcp_interface.h | 2 +- 27 files changed, 768 insertions(+), 746 deletions(-) create mode 100644 drivers/gpu/drm/display/drm_hdcp_helper.c delete mode 100644 drivers/gpu/drm/drm_hdcp.c create mode 100644 include/drm/display/drm_hdcp.h create mode 100644 include/drm/display/drm_hdcp_helper.h delete mode 100644 include/drm/drm_hdcp.h (limited to 'drivers/misc') diff --git a/Documentation/gpu/drm-kms-helpers.rst b/Documentation/gpu/drm-kms-helpers.rst index 7af55fb4072c..cfda5a092a48 100644 --- a/Documentation/gpu/drm-kms-helpers.rst +++ b/Documentation/gpu/drm-kms-helpers.rst @@ -226,7 +226,7 @@ Panel Self Refresh Helper Reference HDCP Helper Functions Reference =============================== -.. kernel-doc:: drivers/gpu/drm/drm_hdcp.c +.. kernel-doc:: drivers/gpu/drm/display/drm_hdcp_helper.c :export: Display Port Helper Functions Reference diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index b8353af70152..746a3a4953f3 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -58,7 +58,7 @@ obj-$(CONFIG_DRM_TTM_HELPER) += drm_ttm_helper.o # drm_kms_helper-y := drm_bridge_connector.o drm_crtc_helper.o \ - drm_encoder_slave.o drm_flip_work.o drm_hdcp.o \ + drm_encoder_slave.o drm_flip_work.o \ drm_probe_helper.o \ drm_plane_helper.o drm_atomic_helper.o \ drm_kms_helper_common.o \ diff --git a/drivers/gpu/drm/amd/display/Kconfig b/drivers/gpu/drm/amd/display/Kconfig index 127667e549c1..b4029c0d5d8c 100644 --- a/drivers/gpu/drm/amd/display/Kconfig +++ b/drivers/gpu/drm/amd/display/Kconfig @@ -20,6 +20,7 @@ config DRM_AMD_DC_DCN config DRM_AMD_DC_HDCP bool "Enable HDCP support in DC" depends on DRM_AMD_DC + select DRM_DISPLAY_HDCP_HELPER help Choose this option if you want to support HDCP authentication. diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 7ef20da6c18f..e3130b4af540 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -48,7 +48,7 @@ #include "amdgpu_dm.h" #ifdef CONFIG_DRM_AMD_DC_HDCP #include "amdgpu_dm_hdcp.h" -#include +#include #endif #include "amdgpu_pm.h" #include "amdgpu_atombios.h" diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c index bf0d50277f8f..15c0e3f2a9c3 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c @@ -27,7 +27,7 @@ #include "amdgpu.h" #include "amdgpu_dm.h" #include "dm_helpers.h" -#include +#include #include "hdcp_psp.h" /* diff --git a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp.h b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp.h index 6e88705e22f7..392c0c03365a 100644 --- a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp.h +++ b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp.h @@ -30,7 +30,7 @@ #include "hdcp_log.h" #include -#include +#include enum mod_hdcp_trans_input_result { UNKNOWN = 0, diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index 73ea668babbf..ef9f1b0d91bf 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -79,6 +79,7 @@ config DRM_ITE_IT6505 tristate "ITE IT6505 DisplayPort bridge" depends on OF select DRM_DISPLAY_DP_HELPER + select DRM_DISPLAY_HDCP_HELPER select DRM_DISPLAY_HELPER select DRM_DP_AUX_BUS select DRM_KMS_HELPER diff --git a/drivers/gpu/drm/bridge/analogix/Kconfig b/drivers/gpu/drm/bridge/analogix/Kconfig index 5570322dc528..173dada218ec 100644 --- a/drivers/gpu/drm/bridge/analogix/Kconfig +++ b/drivers/gpu/drm/bridge/analogix/Kconfig @@ -35,6 +35,7 @@ config DRM_ANALOGIX_ANX7625 depends on DRM depends on OF select DRM_DISPLAY_DP_HELPER + select DRM_DISPLAY_HDCP_HELPER select DRM_DISPLAY_HELPER select DRM_DP_AUX_BUS select DRM_MIPI_DSI diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c index be2c096374aa..53a5da6c49dd 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.c +++ b/drivers/gpu/drm/bridge/analogix/anx7625.c @@ -23,11 +23,11 @@ #include #include +#include #include #include #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/bridge/cadence/Kconfig b/drivers/gpu/drm/bridge/cadence/Kconfig index 0f9e46c6de9b..1d06182bea71 100644 --- a/drivers/gpu/drm/bridge/cadence/Kconfig +++ b/drivers/gpu/drm/bridge/cadence/Kconfig @@ -2,6 +2,7 @@ config DRM_CDNS_MHDP8546 tristate "Cadence DPI/DP bridge" select DRM_DISPLAY_DP_HELPER + select DRM_DISPLAY_HDCP_HELPER select DRM_DISPLAY_HELPER select DRM_KMS_HELPER select DRM_PANEL_BRIDGE diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c index dec93a6d14c7..67f0f444b4e8 100644 --- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c +++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c @@ -36,13 +36,13 @@ #include #include +#include #include #include #include #include #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.c index fccd6fbcc257..946212a95598 100644 --- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.c +++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.c @@ -11,7 +11,7 @@ #include -#include +#include #include "cdns-mhdp8546-hdcp.h" diff --git a/drivers/gpu/drm/bridge/ite-it6505.c b/drivers/gpu/drm/bridge/ite-it6505.c index 85cffc108278..8fed30df08b0 100644 --- a/drivers/gpu/drm/bridge/ite-it6505.c +++ b/drivers/gpu/drm/bridge/ite-it6505.c @@ -22,12 +22,12 @@ #include #include +#include #include #include #include #include #include -#include #include #include diff --git a/drivers/gpu/drm/display/Kconfig b/drivers/gpu/drm/display/Kconfig index fcd9ffd39f26..4406af5cc8bb 100644 --- a/drivers/gpu/drm/display/Kconfig +++ b/drivers/gpu/drm/display/Kconfig @@ -17,6 +17,12 @@ config DRM_DISPLAY_DP_HELPER help DRM display helpers for DisplayPort. +config DRM_DISPLAY_HDCP_HELPER + bool + depends on DRM_DISPLAY_HELPER + help + DRM display helpers for HDCP. + config DRM_DP_AUX_CHARDEV bool "DRM DP AUX Interface" depends on DRM diff --git a/drivers/gpu/drm/display/Makefile b/drivers/gpu/drm/display/Makefile index 4f4e35034960..abeb5ad8c351 100644 --- a/drivers/gpu/drm/display/Makefile +++ b/drivers/gpu/drm/display/Makefile @@ -7,6 +7,7 @@ drm_display_helper-$(CONFIG_DRM_DISPLAY_DP_HELPER) += drm_dp_dual_mode_helper.o drm_dp_helper.o \ drm_dp_mst_topology.o \ drm_dsc_helper.o +drm_display_helper-$(CONFIG_DRM_DISPLAY_HDCP_HELPER) += drm_hdcp_helper.o drm_display_helper-$(CONFIG_DRM_DP_AUX_CHARDEV) += drm_dp_aux_dev.o drm_display_helper-$(CONFIG_DRM_DP_CEC) += drm_dp_cec.o diff --git a/drivers/gpu/drm/display/drm_hdcp_helper.c b/drivers/gpu/drm/display/drm_hdcp_helper.c new file mode 100644 index 000000000000..e78999c72bd7 --- /dev/null +++ b/drivers/gpu/drm/display/drm_hdcp_helper.c @@ -0,0 +1,421 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019 Intel Corporation. + * + * Authors: + * Ramalingam C + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +static inline void drm_hdcp_print_ksv(const u8 *ksv) +{ + DRM_DEBUG("\t%#02x, %#02x, %#02x, %#02x, %#02x\n", + ksv[0], ksv[1], ksv[2], ksv[3], ksv[4]); +} + +static u32 drm_hdcp_get_revoked_ksv_count(const u8 *buf, u32 vrls_length) +{ + u32 parsed_bytes = 0, ksv_count = 0, vrl_ksv_cnt, vrl_sz; + + while (parsed_bytes < vrls_length) { + vrl_ksv_cnt = *buf; + ksv_count += vrl_ksv_cnt; + + vrl_sz = (vrl_ksv_cnt * DRM_HDCP_KSV_LEN) + 1; + buf += vrl_sz; + parsed_bytes += vrl_sz; + } + + /* + * When vrls are not valid, ksvs are not considered. + * Hence SRM will be discarded. + */ + if (parsed_bytes != vrls_length) + ksv_count = 0; + + return ksv_count; +} + +static u32 drm_hdcp_get_revoked_ksvs(const u8 *buf, u8 **revoked_ksv_list, + u32 vrls_length) +{ + u32 vrl_ksv_cnt, vrl_ksv_sz, vrl_idx = 0; + u32 parsed_bytes = 0, ksv_count = 0; + + do { + vrl_ksv_cnt = *buf; + vrl_ksv_sz = vrl_ksv_cnt * DRM_HDCP_KSV_LEN; + + buf++; + + DRM_DEBUG("vrl: %d, Revoked KSVs: %d\n", vrl_idx++, + vrl_ksv_cnt); + memcpy((*revoked_ksv_list) + (ksv_count * DRM_HDCP_KSV_LEN), + buf, vrl_ksv_sz); + + ksv_count += vrl_ksv_cnt; + buf += vrl_ksv_sz; + + parsed_bytes += (vrl_ksv_sz + 1); + } while (parsed_bytes < vrls_length); + + return ksv_count; +} + +static inline u32 get_vrl_length(const u8 *buf) +{ + return drm_hdcp_be24_to_cpu(buf); +} + +static int drm_hdcp_parse_hdcp1_srm(const u8 *buf, size_t count, + u8 **revoked_ksv_list, u32 *revoked_ksv_cnt) +{ + struct hdcp_srm_header *header; + u32 vrl_length, ksv_count; + + if (count < (sizeof(struct hdcp_srm_header) + + DRM_HDCP_1_4_VRL_LENGTH_SIZE + DRM_HDCP_1_4_DCP_SIG_SIZE)) { + DRM_ERROR("Invalid blob length\n"); + return -EINVAL; + } + + header = (struct hdcp_srm_header *)buf; + DRM_DEBUG("SRM ID: 0x%x, SRM Ver: 0x%x, SRM Gen No: 0x%x\n", + header->srm_id, + be16_to_cpu(header->srm_version), header->srm_gen_no); + + WARN_ON(header->reserved); + + buf = buf + sizeof(*header); + vrl_length = get_vrl_length(buf); + if (count < (sizeof(struct hdcp_srm_header) + vrl_length) || + vrl_length < (DRM_HDCP_1_4_VRL_LENGTH_SIZE + + DRM_HDCP_1_4_DCP_SIG_SIZE)) { + DRM_ERROR("Invalid blob length or vrl length\n"); + return -EINVAL; + } + + /* Length of the all vrls combined */ + vrl_length -= (DRM_HDCP_1_4_VRL_LENGTH_SIZE + + DRM_HDCP_1_4_DCP_SIG_SIZE); + + if (!vrl_length) { + DRM_ERROR("No vrl found\n"); + return -EINVAL; + } + + buf += DRM_HDCP_1_4_VRL_LENGTH_SIZE; + ksv_count = drm_hdcp_get_revoked_ksv_count(buf, vrl_length); + if (!ksv_count) { + DRM_DEBUG("Revoked KSV count is 0\n"); + return 0; + } + + *revoked_ksv_list = kcalloc(ksv_count, DRM_HDCP_KSV_LEN, GFP_KERNEL); + if (!*revoked_ksv_list) { + DRM_ERROR("Out of Memory\n"); + return -ENOMEM; + } + + if (drm_hdcp_get_revoked_ksvs(buf, revoked_ksv_list, + vrl_length) != ksv_count) { + *revoked_ksv_cnt = 0; + kfree(*revoked_ksv_list); + return -EINVAL; + } + + *revoked_ksv_cnt = ksv_count; + return 0; +} + +static int drm_hdcp_parse_hdcp2_srm(const u8 *buf, size_t count, + u8 **revoked_ksv_list, u32 *revoked_ksv_cnt) +{ + struct hdcp_srm_header *header; + u32 vrl_length, ksv_count, ksv_sz; + + if (count < (sizeof(struct hdcp_srm_header) + + DRM_HDCP_2_VRL_LENGTH_SIZE + DRM_HDCP_2_DCP_SIG_SIZE)) { + DRM_ERROR("Invalid blob length\n"); + return -EINVAL; + } + + header = (struct hdcp_srm_header *)buf; + DRM_DEBUG("SRM ID: 0x%x, SRM Ver: 0x%x, SRM Gen No: 0x%x\n", + header->srm_id & DRM_HDCP_SRM_ID_MASK, + be16_to_cpu(header->srm_version), header->srm_gen_no); + + if (header->reserved) + return -EINVAL; + + buf = buf + sizeof(*header); + vrl_length = get_vrl_length(buf); + + if (count < (sizeof(struct hdcp_srm_header) + vrl_length) || + vrl_length < (DRM_HDCP_2_VRL_LENGTH_SIZE + + DRM_HDCP_2_DCP_SIG_SIZE)) { + DRM_ERROR("Invalid blob length or vrl length\n"); + return -EINVAL; + } + + /* Length of the all vrls combined */ + vrl_length -= (DRM_HDCP_2_VRL_LENGTH_SIZE + + DRM_HDCP_2_DCP_SIG_SIZE); + + if (!vrl_length) { + DRM_ERROR("No vrl found\n"); + return -EINVAL; + } + + buf += DRM_HDCP_2_VRL_LENGTH_SIZE; + ksv_count = (*buf << 2) | DRM_HDCP_2_KSV_COUNT_2_LSBITS(*(buf + 1)); + if (!ksv_count) { + DRM_DEBUG("Revoked KSV count is 0\n"); + return 0; + } + + *revoked_ksv_list = kcalloc(ksv_count, DRM_HDCP_KSV_LEN, GFP_KERNEL); + if (!*revoked_ksv_list) { + DRM_ERROR("Out of Memory\n"); + return -ENOMEM; + } + + ksv_sz = ksv_count * DRM_HDCP_KSV_LEN; + buf += DRM_HDCP_2_NO_OF_DEV_PLUS_RESERVED_SZ; + + DRM_DEBUG("Revoked KSVs: %d\n", ksv_count); + memcpy(*revoked_ksv_list, buf, ksv_sz); + + *revoked_ksv_cnt = ksv_count; + return 0; +} + +static inline bool is_srm_version_hdcp1(const u8 *buf) +{ + return *buf == (u8)(DRM_HDCP_1_4_SRM_ID << 4); +} + +static inline bool is_srm_version_hdcp2(const u8 *buf) +{ + return *buf == (u8)(DRM_HDCP_2_SRM_ID << 4 | DRM_HDCP_2_INDICATOR); +} + +static int drm_hdcp_srm_update(const u8 *buf, size_t count, + u8 **revoked_ksv_list, u32 *revoked_ksv_cnt) +{ + if (count < sizeof(struct hdcp_srm_header)) + return -EINVAL; + + if (is_srm_version_hdcp1(buf)) + return drm_hdcp_parse_hdcp1_srm(buf, count, revoked_ksv_list, + revoked_ksv_cnt); + else if (is_srm_version_hdcp2(buf)) + return drm_hdcp_parse_hdcp2_srm(buf, count, revoked_ksv_list, + revoked_ksv_cnt); + else + return -EINVAL; +} + +static int drm_hdcp_request_srm(struct drm_device *drm_dev, + u8 **revoked_ksv_list, u32 *revoked_ksv_cnt) +{ + char fw_name[36] = "display_hdcp_srm.bin"; + const struct firmware *fw; + int ret; + + ret = request_firmware_direct(&fw, (const char *)fw_name, + drm_dev->dev); + if (ret < 0) { + *revoked_ksv_cnt = 0; + *revoked_ksv_list = NULL; + ret = 0; + goto exit; + } + + if (fw->size && fw->data) + ret = drm_hdcp_srm_update(fw->data, fw->size, revoked_ksv_list, + revoked_ksv_cnt); + +exit: + release_firmware(fw); + return ret; +} + +/** + * drm_hdcp_check_ksvs_revoked - Check the revoked status of the IDs + * + * @drm_dev: drm_device for which HDCP revocation check is requested + * @ksvs: List of KSVs (HDCP receiver IDs) + * @ksv_count: KSV count passed in through @ksvs + * + * This function reads the HDCP System renewability Message(SRM Table) + * from userspace as a firmware and parses it for the revoked HDCP + * KSVs(Receiver IDs) detected by DCP LLC. Once the revoked KSVs are known, + * revoked state of the KSVs in the list passed in by display drivers are + * decided and response is sent. + * + * SRM should be presented in the name of "display_hdcp_srm.bin". + * + * Format of the SRM table, that userspace needs to write into the binary file, + * is defined at: + * 1. Renewability chapter on 55th page of HDCP 1.4 specification + * https://www.digital-cp.com/sites/default/files/specifications/HDCP%20Specification%20Rev1_4_Secure.pdf + * 2. Renewability chapter on 63rd page of HDCP 2.2 specification + * https://www.digital-cp.com/sites/default/files/specifications/HDCP%20on%20HDMI%20Specification%20Rev2_2_Final1.pdf + * + * Returns: + * Count of the revoked KSVs or -ve error number in case of the failure. + */ +int drm_hdcp_check_ksvs_revoked(struct drm_device *drm_dev, u8 *ksvs, + u32 ksv_count) +{ + u32 revoked_ksv_cnt = 0, i, j; + u8 *revoked_ksv_list = NULL; + int ret = 0; + + ret = drm_hdcp_request_srm(drm_dev, &revoked_ksv_list, + &revoked_ksv_cnt); + if (ret) + return ret; + + /* revoked_ksv_cnt will be zero when above function failed */ + for (i = 0; i < revoked_ksv_cnt; i++) + for (j = 0; j < ksv_count; j++) + if (!memcmp(&ksvs[j * DRM_HDCP_KSV_LEN], + &revoked_ksv_list[i * DRM_HDCP_KSV_LEN], + DRM_HDCP_KSV_LEN)) { + DRM_DEBUG("Revoked KSV is "); + drm_hdcp_print_ksv(&ksvs[j * DRM_HDCP_KSV_LEN]); + ret++; + } + + kfree(revoked_ksv_list); + return ret; +} +EXPORT_SYMBOL_GPL(drm_hdcp_check_ksvs_revoked); + +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) + +static struct drm_prop_enum_list drm_hdcp_content_type_enum_list[] = { + { DRM_MODE_HDCP_CONTENT_TYPE0, "HDCP Type0" }, + { DRM_MODE_HDCP_CONTENT_TYPE1, "HDCP Type1" }, +}; +DRM_ENUM_NAME_FN(drm_get_hdcp_content_type_name, + drm_hdcp_content_type_enum_list) + +/** + * drm_connector_attach_content_protection_property - attach content protection + * property + * + * @connector: connector to attach CP property on. + * @hdcp_content_type: is HDCP Content Type property needed for connector + * + * 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. + * + * When hdcp_content_type is true enum property called HDCP Content Type is + * created (if it is not already) and attached to the connector. + * + * This property is used for sending the protected content's stream type + * from userspace to kernel on selected connectors. Protected content provider + * will decide their type of their content and declare the same to kernel. + * + * Content type will be used during the HDCP 2.2 authentication. + * Content type will be set to &drm_connector_state.hdcp_content_type. + * + * The content protection will be set to &drm_connector_state.content_protection + * + * When kernel triggered content protection state change like DESIRED->ENABLED + * and ENABLED->DESIRED, will use drm_hdcp_update_content_protection() to update + * the content protection state of a connector. + * + * Returns: + * Zero on success, negative errno on failure. + */ +int drm_connector_attach_content_protection_property( + struct drm_connector *connector, bool hdcp_content_type) +{ + struct drm_device *dev = connector->dev; + struct drm_property *prop = + dev->mode_config.content_protection_property; + + if (!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); + dev->mode_config.content_protection_property = prop; + + if (!hdcp_content_type) + return 0; + + prop = dev->mode_config.hdcp_content_type_property; + if (!prop) + prop = drm_property_create_enum(dev, 0, "HDCP Content Type", + drm_hdcp_content_type_enum_list, + ARRAY_SIZE( + drm_hdcp_content_type_enum_list)); + if (!prop) + return -ENOMEM; + + drm_object_attach_property(&connector->base, prop, + DRM_MODE_HDCP_CONTENT_TYPE0); + dev->mode_config.hdcp_content_type_property = prop; + + return 0; +} +EXPORT_SYMBOL(drm_connector_attach_content_protection_property); + +/** + * drm_hdcp_update_content_protection - Updates the content protection state + * of a connector + * + * @connector: drm_connector on which content protection state needs an update + * @val: New state of the content protection property + * + * This function can be used by display drivers, to update the kernel triggered + * content protection state changes of a drm_connector such as DESIRED->ENABLED + * and ENABLED->DESIRED. No uevent for DESIRED->UNDESIRED or ENABLED->UNDESIRED, + * as userspace is triggering such state change and kernel performs it without + * fail.This function update the new state of the property into the connector's + * state and generate an uevent to notify the userspace. + */ +void drm_hdcp_update_content_protection(struct drm_connector *connector, + u64 val) +{ + struct drm_device *dev = connector->dev; + struct drm_connector_state *state = connector->state; + + WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex)); + if (state->content_protection == val) + return; + + state->content_protection = val; + drm_sysfs_connector_status_event(connector, + dev->mode_config.content_protection_property); +} +EXPORT_SYMBOL(drm_hdcp_update_content_protection); diff --git a/drivers/gpu/drm/drm_hdcp.c b/drivers/gpu/drm/drm_hdcp.c deleted file mode 100644 index ca9b8f697202..000000000000 --- a/drivers/gpu/drm/drm_hdcp.c +++ /dev/null @@ -1,423 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2019 Intel Corporation. - * - * Authors: - * Ramalingam C - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "drm_internal.h" - -static inline void drm_hdcp_print_ksv(const u8 *ksv) -{ - DRM_DEBUG("\t%#02x, %#02x, %#02x, %#02x, %#02x\n", - ksv[0], ksv[1], ksv[2], ksv[3], ksv[4]); -} - -static u32 drm_hdcp_get_revoked_ksv_count(const u8 *buf, u32 vrls_length) -{ - u32 parsed_bytes = 0, ksv_count = 0, vrl_ksv_cnt, vrl_sz; - - while (parsed_bytes < vrls_length) { - vrl_ksv_cnt = *buf; - ksv_count += vrl_ksv_cnt; - - vrl_sz = (vrl_ksv_cnt * DRM_HDCP_KSV_LEN) + 1; - buf += vrl_sz; - parsed_bytes += vrl_sz; - } - - /* - * When vrls are not valid, ksvs are not considered. - * Hence SRM will be discarded. - */ - if (parsed_bytes != vrls_length) - ksv_count = 0; - - return ksv_count; -} - -static u32 drm_hdcp_get_revoked_ksvs(const u8 *buf, u8 **revoked_ksv_list, - u32 vrls_length) -{ - u32 vrl_ksv_cnt, vrl_ksv_sz, vrl_idx = 0; - u32 parsed_bytes = 0, ksv_count = 0; - - do { - vrl_ksv_cnt = *buf; - vrl_ksv_sz = vrl_ksv_cnt * DRM_HDCP_KSV_LEN; - - buf++; - - DRM_DEBUG("vrl: %d, Revoked KSVs: %d\n", vrl_idx++, - vrl_ksv_cnt); - memcpy((*revoked_ksv_list) + (ksv_count * DRM_HDCP_KSV_LEN), - buf, vrl_ksv_sz); - - ksv_count += vrl_ksv_cnt; - buf += vrl_ksv_sz; - - parsed_bytes += (vrl_ksv_sz + 1); - } while (parsed_bytes < vrls_length); - - return ksv_count; -} - -static inline u32 get_vrl_length(const u8 *buf) -{ - return drm_hdcp_be24_to_cpu(buf); -} - -static int drm_hdcp_parse_hdcp1_srm(const u8 *buf, size_t count, - u8 **revoked_ksv_list, u32 *revoked_ksv_cnt) -{ - struct hdcp_srm_header *header; - u32 vrl_length, ksv_count; - - if (count < (sizeof(struct hdcp_srm_header) + - DRM_HDCP_1_4_VRL_LENGTH_SIZE + DRM_HDCP_1_4_DCP_SIG_SIZE)) { - DRM_ERROR("Invalid blob length\n"); - return -EINVAL; - } - - header = (struct hdcp_srm_header *)buf; - DRM_DEBUG("SRM ID: 0x%x, SRM Ver: 0x%x, SRM Gen No: 0x%x\n", - header->srm_id, - be16_to_cpu(header->srm_version), header->srm_gen_no); - - WARN_ON(header->reserved); - - buf = buf + sizeof(*header); - vrl_length = get_vrl_length(buf); - if (count < (sizeof(struct hdcp_srm_header) + vrl_length) || - vrl_length < (DRM_HDCP_1_4_VRL_LENGTH_SIZE + - DRM_HDCP_1_4_DCP_SIG_SIZE)) { - DRM_ERROR("Invalid blob length or vrl length\n"); - return -EINVAL; - } - - /* Length of the all vrls combined */ - vrl_length -= (DRM_HDCP_1_4_VRL_LENGTH_SIZE + - DRM_HDCP_1_4_DCP_SIG_SIZE); - - if (!vrl_length) { - DRM_ERROR("No vrl found\n"); - return -EINVAL; - } - - buf += DRM_HDCP_1_4_VRL_LENGTH_SIZE; - ksv_count = drm_hdcp_get_revoked_ksv_count(buf, vrl_length); - if (!ksv_count) { - DRM_DEBUG("Revoked KSV count is 0\n"); - return 0; - } - - *revoked_ksv_list = kcalloc(ksv_count, DRM_HDCP_KSV_LEN, GFP_KERNEL); - if (!*revoked_ksv_list) { - DRM_ERROR("Out of Memory\n"); - return -ENOMEM; - } - - if (drm_hdcp_get_revoked_ksvs(buf, revoked_ksv_list, - vrl_length) != ksv_count) { - *revoked_ksv_cnt = 0; - kfree(*revoked_ksv_list); - return -EINVAL; - } - - *revoked_ksv_cnt = ksv_count; - return 0; -} - -static int drm_hdcp_parse_hdcp2_srm(const u8 *buf, size_t count, - u8 **revoked_ksv_list, u32 *revoked_ksv_cnt) -{ - struct hdcp_srm_header *header; - u32 vrl_length, ksv_count, ksv_sz; - - if (count < (sizeof(struct hdcp_srm_header) + - DRM_HDCP_2_VRL_LENGTH_SIZE + DRM_HDCP_2_DCP_SIG_SIZE)) { - DRM_ERROR("Invalid blob length\n"); - return -EINVAL; - } - - header = (struct hdcp_srm_header *)buf; - DRM_DEBUG("SRM ID: 0x%x, SRM Ver: 0x%x, SRM Gen No: 0x%x\n", - header->srm_id & DRM_HDCP_SRM_ID_MASK, - be16_to_cpu(header->srm_version), header->srm_gen_no); - - if (header->reserved) - return -EINVAL; - - buf = buf + sizeof(*header); - vrl_length = get_vrl_length(buf); - - if (count < (sizeof(struct hdcp_srm_header) + vrl_length) || - vrl_length < (DRM_HDCP_2_VRL_LENGTH_SIZE + - DRM_HDCP_2_DCP_SIG_SIZE)) { - DRM_ERROR("Invalid blob length or vrl length\n"); - return -EINVAL; - } - - /* Length of the all vrls combined */ - vrl_length -= (DRM_HDCP_2_VRL_LENGTH_SIZE + - DRM_HDCP_2_DCP_SIG_SIZE); - - if (!vrl_length) { - DRM_ERROR("No vrl found\n"); - return -EINVAL; - } - - buf += DRM_HDCP_2_VRL_LENGTH_SIZE; - ksv_count = (*buf << 2) | DRM_HDCP_2_KSV_COUNT_2_LSBITS(*(buf + 1)); - if (!ksv_count) { - DRM_DEBUG("Revoked KSV count is 0\n"); - return 0; - } - - *revoked_ksv_list = kcalloc(ksv_count, DRM_HDCP_KSV_LEN, GFP_KERNEL); - if (!*revoked_ksv_list) { - DRM_ERROR("Out of Memory\n"); - return -ENOMEM; - } - - ksv_sz = ksv_count * DRM_HDCP_KSV_LEN; - buf += DRM_HDCP_2_NO_OF_DEV_PLUS_RESERVED_SZ; - - DRM_DEBUG("Revoked KSVs: %d\n", ksv_count); - memcpy(*revoked_ksv_list, buf, ksv_sz); - - *revoked_ksv_cnt = ksv_count; - return 0; -} - -static inline bool is_srm_version_hdcp1(const u8 *buf) -{ - return *buf == (u8)(DRM_HDCP_1_4_SRM_ID << 4); -} - -static inline bool is_srm_version_hdcp2(const u8 *buf) -{ - return *buf == (u8)(DRM_HDCP_2_SRM_ID << 4 | DRM_HDCP_2_INDICATOR); -} - -static int drm_hdcp_srm_update(const u8 *buf, size_t count, - u8 **revoked_ksv_list, u32 *revoked_ksv_cnt) -{ - if (count < sizeof(struct hdcp_srm_header)) - return -EINVAL; - - if (is_srm_version_hdcp1(buf)) - return drm_hdcp_parse_hdcp1_srm(buf, count, revoked_ksv_list, - revoked_ksv_cnt); - else if (is_srm_version_hdcp2(buf)) - return drm_hdcp_parse_hdcp2_srm(buf, count, revoked_ksv_list, - revoked_ksv_cnt); - else - return -EINVAL; -} - -static int drm_hdcp_request_srm(struct drm_device *drm_dev, - u8 **revoked_ksv_list, u32 *revoked_ksv_cnt) -{ - char fw_name[36] = "display_hdcp_srm.bin"; - const struct firmware *fw; - int ret; - - ret = request_firmware_direct(&fw, (const char *)fw_name, - drm_dev->dev); - if (ret < 0) { - *revoked_ksv_cnt = 0; - *revoked_ksv_list = NULL; - ret = 0; - goto exit; - } - - if (fw->size && fw->data) - ret = drm_hdcp_srm_update(fw->data, fw->size, revoked_ksv_list, - revoked_ksv_cnt); - -exit: - release_firmware(fw); - return ret; -} - -/** - * drm_hdcp_check_ksvs_revoked - Check the revoked status of the IDs - * - * @drm_dev: drm_device for which HDCP revocation check is requested - * @ksvs: List of KSVs (HDCP receiver IDs) - * @ksv_count: KSV count passed in through @ksvs - * - * This function reads the HDCP System renewability Message(SRM Table) - * from userspace as a firmware and parses it for the revoked HDCP - * KSVs(Receiver IDs) detected by DCP LLC. Once the revoked KSVs are known, - * revoked state of the KSVs in the list passed in by display drivers are - * decided and response is sent. - * - * SRM should be presented in the name of "display_hdcp_srm.bin". - * - * Format of the SRM table, that userspace needs to write into the binary file, - * is defined at: - * 1. Renewability chapter on 55th page of HDCP 1.4 specification - * https://www.digital-cp.com/sites/default/files/specifications/HDCP%20Specification%20Rev1_4_Secure.pdf - * 2. Renewability chapter on 63rd page of HDCP 2.2 specification - * https://www.digital-cp.com/sites/default/files/specifications/HDCP%20on%20HDMI%20Specification%20Rev2_2_Final1.pdf - * - * Returns: - * Count of the revoked KSVs or -ve error number in case of the failure. - */ -int drm_hdcp_check_ksvs_revoked(struct drm_device *drm_dev, u8 *ksvs, - u32 ksv_count) -{ - u32 revoked_ksv_cnt = 0, i, j; - u8 *revoked_ksv_list = NULL; - int ret = 0; - - ret = drm_hdcp_request_srm(drm_dev, &revoked_ksv_list, - &revoked_ksv_cnt); - if (ret) - return ret; - - /* revoked_ksv_cnt will be zero when above function failed */ - for (i = 0; i < revoked_ksv_cnt; i++) - for (j = 0; j < ksv_count; j++) - if (!memcmp(&ksvs[j * DRM_HDCP_KSV_LEN], - &revoked_ksv_list[i * DRM_HDCP_KSV_LEN], - DRM_HDCP_KSV_LEN)) { - DRM_DEBUG("Revoked KSV is "); - drm_hdcp_print_ksv(&ksvs[j * DRM_HDCP_KSV_LEN]); - ret++; - } - - kfree(revoked_ksv_list); - return ret; -} -EXPORT_SYMBOL_GPL(drm_hdcp_check_ksvs_revoked); - -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) - -static struct drm_prop_enum_list drm_hdcp_content_type_enum_list[] = { - { DRM_MODE_HDCP_CONTENT_TYPE0, "HDCP Type0" }, - { DRM_MODE_HDCP_CONTENT_TYPE1, "HDCP Type1" }, -}; -DRM_ENUM_NAME_FN(drm_get_hdcp_content_type_name, - drm_hdcp_content_type_enum_list) - -/** - * drm_connector_attach_content_protection_property - attach content protection - * property - * - * @connector: connector to attach CP property on. - * @hdcp_content_type: is HDCP Content Type property needed for connector - * - * 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. - * - * When hdcp_content_type is true enum property called HDCP Content Type is - * created (if it is not already) and attached to the connector. - * - * This property is used for sending the protected content's stream type - * from userspace to kernel on selected connectors. Protected content provider - * will decide their type of their content and declare the same to kernel. - * - * Content type will be used during the HDCP 2.2 authentication. - * Content type will be set to &drm_connector_state.hdcp_content_type. - * - * The content protection will be set to &drm_connector_state.content_protection - * - * When kernel triggered content protection state change like DESIRED->ENABLED - * and ENABLED->DESIRED, will use drm_hdcp_update_content_protection() to update - * the content protection state of a connector. - * - * Returns: - * Zero on success, negative errno on failure. - */ -int drm_connector_attach_content_protection_property( - struct drm_connector *connector, bool hdcp_content_type) -{ - struct drm_device *dev = connector->dev; - struct drm_property *prop = - dev->mode_config.content_protection_property; - - if (!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); - dev->mode_config.content_protection_property = prop; - - if (!hdcp_content_type) - return 0; - - prop = dev->mode_config.hdcp_content_type_property; - if (!prop) - prop = drm_property_create_enum(dev, 0, "HDCP Content Type", - drm_hdcp_content_type_enum_list, - ARRAY_SIZE( - drm_hdcp_content_type_enum_list)); - if (!prop) - return -ENOMEM; - - drm_object_attach_property(&connector->base, prop, - DRM_MODE_HDCP_CONTENT_TYPE0); - dev->mode_config.hdcp_content_type_property = prop; - - return 0; -} -EXPORT_SYMBOL(drm_connector_attach_content_protection_property); - -/** - * drm_hdcp_update_content_protection - Updates the content protection state - * of a connector - * - * @connector: drm_connector on which content protection state needs an update - * @val: New state of the content protection property - * - * This function can be used by display drivers, to update the kernel triggered - * content protection state changes of a drm_connector such as DESIRED->ENABLED - * and ENABLED->DESIRED. No uevent for DESIRED->UNDESIRED or ENABLED->UNDESIRED, - * as userspace is triggering such state change and kernel performs it without - * fail.This function update the new state of the property into the connector's - * state and generate an uevent to notify the userspace. - */ -void drm_hdcp_update_content_protection(struct drm_connector *connector, - u64 val) -{ - struct drm_device *dev = connector->dev; - struct drm_connector_state *state = connector->state; - - WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex)); - if (state->content_protection == val) - return; - - state->content_protection = val; - drm_sysfs_connector_status_event(connector, - dev->mode_config.content_protection_property); -} -EXPORT_SYMBOL(drm_hdcp_update_content_protection); diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig index 883284ca0a29..a78d82cccbff 100644 --- a/drivers/gpu/drm/i915/Kconfig +++ b/drivers/gpu/drm/i915/Kconfig @@ -11,6 +11,7 @@ config DRM_I915 select SHMEM select TMPFS select DRM_DISPLAY_DP_HELPER + select DRM_DISPLAY_HDCP_HELPER select DRM_DISPLAY_HELPER select DRM_KMS_HELPER select DRM_PANEL diff --git a/drivers/gpu/drm/i915/display/intel_dp_hdcp.c b/drivers/gpu/drm/i915/display/intel_dp_hdcp.c index 598cad09d499..a7640dbcf00e 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_hdcp.c +++ b/drivers/gpu/drm/i915/display/intel_dp_hdcp.c @@ -8,7 +8,7 @@ #include #include -#include +#include #include #include "intel_ddi.h" diff --git a/drivers/gpu/drm/i915/display/intel_gmbus.c b/drivers/gpu/drm/i915/display/intel_gmbus.c index 21281a7bdc17..a6ba7fb72339 100644 --- a/drivers/gpu/drm/i915/display/intel_gmbus.c +++ b/drivers/gpu/drm/i915/display/intel_gmbus.c @@ -31,7 +31,7 @@ #include #include -#include +#include #include "i915_drv.h" #include "intel_de.h" diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.c b/drivers/gpu/drm/i915/display/intel_hdcp.c index 4de4c174a987..44ac0cee8b77 100644 --- a/drivers/gpu/drm/i915/display/intel_hdcp.c +++ b/drivers/gpu/drm/i915/display/intel_hdcp.c @@ -12,7 +12,7 @@ #include #include -#include +#include #include #include "i915_drv.h" diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c index a4a6f8bd2841..c713cebc63fe 100644 --- a/drivers/gpu/drm/i915/display/intel_hdmi.c +++ b/drivers/gpu/drm/i915/display/intel_hdmi.c @@ -32,10 +32,10 @@ #include #include +#include #include #include #include -#include #include #include diff --git a/drivers/misc/mei/hdcp/mei_hdcp.h b/drivers/misc/mei/hdcp/mei_hdcp.h index 834757f5e072..ca09c8f83d6b 100644 --- a/drivers/misc/mei/hdcp/mei_hdcp.h +++ b/drivers/misc/mei/hdcp/mei_hdcp.h @@ -9,7 +9,7 @@ #ifndef __MEI_HDCP_H__ #define __MEI_HDCP_H__ -#include +#include /* me_hdcp_status: Enumeration of all HDCP Status Codes */ enum me_hdcp_status { diff --git a/include/drm/display/drm_hdcp.h b/include/drm/display/drm_hdcp.h new file mode 100644 index 000000000000..96a99b1377c0 --- /dev/null +++ b/include/drm/display/drm_hdcp.h @@ -0,0 +1,298 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright (C) 2017 Google, Inc. + * + * Authors: + * Sean Paul + */ + +#ifndef _DRM_HDCP_H_ +#define _DRM_HDCP_H_ + +#include + +/* Period of hdcp checks (to ensure we're still authenticated) */ +#define DRM_HDCP_CHECK_PERIOD_MS (128 * 16) +#define DRM_HDCP2_CHECK_PERIOD_MS 500 + +/* 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 & 0x7f) +#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 + +/* Value to use at the end of the SHA-1 bytestream used for repeaters */ +#define DRM_HDCP_SHA1_TERMINATOR 0x80 + +/* 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 + +#define DRM_HDCP_1_4_SRM_ID 0x8 +#define DRM_HDCP_1_4_VRL_LENGTH_SIZE 3 +#define DRM_HDCP_1_4_DCP_SIG_SIZE 40 + +/* Protocol message definition for HDCP2.2 specification */ +/* + * Protected content streams are classified into 2 types: + * - Type0: Can be transmitted with HDCP 1.4+ + * - Type1: Can be transmitted with HDCP 2.2+ + */ +#define HDCP_STREAM_TYPE0 0x00 +#define HDCP_STREAM_TYPE1 0x01 + +/* HDCP2.2 Msg IDs */ +#define HDCP_2_2_NULL_MSG 1 +#define HDCP_2_2_AKE_INIT 2 +#define HDCP_2_2_AKE_SEND_CERT 3 +#define HDCP_2_2_AKE_NO_STORED_KM 4 +#define HDCP_2_2_AKE_STORED_KM 5 +#define HDCP_2_2_AKE_SEND_HPRIME 7 +#define HDCP_2_2_AKE_SEND_PAIRING_INFO 8 +#define HDCP_2_2_LC_INIT 9 +#define HDCP_2_2_LC_SEND_LPRIME 10 +#define HDCP_2_2_SKE_SEND_EKS 11 +#define HDCP_2_2_REP_SEND_RECVID_LIST 12 +#define HDCP_2_2_REP_SEND_ACK 15 +#define HDCP_2_2_REP_STREAM_MANAGE 16 +#define HDCP_2_2_REP_STREAM_READY 17 + +#define HDCP_2_2_RTX_LEN 8 +#define HDCP_2_2_RRX_LEN 8 + +#define HDCP_2_2_K_PUB_RX_MOD_N_LEN 128 +#define HDCP_2_2_K_PUB_RX_EXP_E_LEN 3 +#define HDCP_2_2_K_PUB_RX_LEN (HDCP_2_2_K_PUB_RX_MOD_N_LEN + \ + HDCP_2_2_K_PUB_RX_EXP_E_LEN) + +#define HDCP_2_2_DCP_LLC_SIG_LEN 384 + +#define HDCP_2_2_E_KPUB_KM_LEN 128 +#define HDCP_2_2_E_KH_KM_M_LEN (16 + 16) +#define HDCP_2_2_H_PRIME_LEN 32 +#define HDCP_2_2_E_KH_KM_LEN 16 +#define HDCP_2_2_RN_LEN 8 +#define HDCP_2_2_L_PRIME_LEN 32 +#define HDCP_2_2_E_DKEY_KS_LEN 16 +#define HDCP_2_2_RIV_LEN 8 +#define HDCP_2_2_SEQ_NUM_LEN 3 +#define HDCP_2_2_V_PRIME_HALF_LEN (HDCP_2_2_L_PRIME_LEN / 2) +#define HDCP_2_2_RECEIVER_ID_LEN DRM_HDCP_KSV_LEN +#define HDCP_2_2_MAX_DEVICE_COUNT 31 +#define HDCP_2_2_RECEIVER_IDS_MAX_LEN (HDCP_2_2_RECEIVER_ID_LEN * \ + HDCP_2_2_MAX_DEVICE_COUNT) +#define HDCP_2_2_MPRIME_LEN 32 + +/* Following Macros take a byte at a time for bit(s) masking */ +/* + * TODO: HDCP_2_2_MAX_CONTENT_STREAMS_CNT is based upon actual + * H/W MST streams capacity. + * This required to be moved out to platform specific header. + */ +#define HDCP_2_2_MAX_CONTENT_STREAMS_CNT 4 +#define HDCP_2_2_TXCAP_MASK_LEN 2 +#define HDCP_2_2_RXCAPS_LEN 3 +#define HDCP_2_2_RX_REPEATER(x) ((x) & BIT(0)) +#define HDCP_2_2_DP_HDCP_CAPABLE(x) ((x) & BIT(1)) +#define HDCP_2_2_RXINFO_LEN 2 + +/* HDCP1.x compliant device in downstream */ +#define HDCP_2_2_HDCP1_DEVICE_CONNECTED(x) ((x) & BIT(0)) + +/* HDCP2.0 Compliant repeater in downstream */ +#define HDCP_2_2_HDCP_2_0_REP_CONNECTED(x) ((x) & BIT(1)) +#define HDCP_2_2_MAX_CASCADE_EXCEEDED(x) ((x) & BIT(2)) +#define HDCP_2_2_MAX_DEVS_EXCEEDED(x) ((x) & BIT(3)) +#define HDCP_2_2_DEV_COUNT_LO(x) (((x) & (0xF << 4)) >> 4) +#define HDCP_2_2_DEV_COUNT_HI(x) ((x) & BIT(0)) +#define HDCP_2_2_DEPTH(x) (((x) & (0x7 << 1)) >> 1) + +struct hdcp2_cert_rx { + u8 receiver_id[HDCP_2_2_RECEIVER_ID_LEN]; + u8 kpub_rx[HDCP_2_2_K_PUB_RX_LEN]; + u8 reserved[2]; + u8 dcp_signature[HDCP_2_2_DCP_LLC_SIG_LEN]; +} __packed; + +struct hdcp2_streamid_type { + u8 stream_id; + u8 stream_type; +} __packed; + +/* + * The TxCaps field specified in the HDCP HDMI, DP specs + * This field is big endian as specified in the errata. + */ +struct hdcp2_tx_caps { + /* Transmitter must set this to 0x2 */ + u8 version; + + /* Reserved for HDCP and DP Spec. Read as Zero */ + u8 tx_cap_mask[HDCP_2_2_TXCAP_MASK_LEN]; +} __packed; + +/* Main structures for HDCP2.2 protocol communication */ +struct hdcp2_ake_init { + u8 msg_id; + u8 r_tx[HDCP_2_2_RTX_LEN]; + struct hdcp2_tx_caps tx_caps; +} __packed; + +struct hdcp2_ake_send_cert { + u8 msg_id; + struct hdcp2_cert_rx cert_rx; + u8 r_rx[HDCP_2_2_RRX_LEN]; + u8 rx_caps[HDCP_2_2_RXCAPS_LEN]; +} __packed; + +struct hdcp2_ake_no_stored_km { + u8 msg_id; + u8 e_kpub_km[HDCP_2_2_E_KPUB_KM_LEN]; +} __packed; + +struct hdcp2_ake_stored_km { + u8 msg_id; + u8 e_kh_km_m[HDCP_2_2_E_KH_KM_M_LEN]; +} __packed; + +struct hdcp2_ake_send_hprime { + u8 msg_id; + u8 h_prime[HDCP_2_2_H_PRIME_LEN]; +} __packed; + +struct hdcp2_ake_send_pairing_info { + u8 msg_id; + u8 e_kh_km[HDCP_2_2_E_KH_KM_LEN]; +} __packed; + +struct hdcp2_lc_init { + u8 msg_id; + u8 r_n[HDCP_2_2_RN_LEN]; +} __packed; + +struct hdcp2_lc_send_lprime { + u8 msg_id; + u8 l_prime[HDCP_2_2_L_PRIME_LEN]; +} __packed; + +struct hdcp2_ske_send_eks { + u8 msg_id; + u8 e_dkey_ks[HDCP_2_2_E_DKEY_KS_LEN]; + u8 riv[HDCP_2_2_RIV_LEN]; +} __packed; + +struct hdcp2_rep_send_receiverid_list { + u8 msg_id; + u8 rx_info[HDCP_2_2_RXINFO_LEN]; + u8 seq_num_v[HDCP_2_2_SEQ_NUM_LEN]; + u8 v_prime[HDCP_2_2_V_PRIME_HALF_LEN]; + u8 receiver_ids[HDCP_2_2_RECEIVER_IDS_MAX_LEN]; +} __packed; + +struct hdcp2_rep_send_ack { + u8 msg_id; + u8 v[HDCP_2_2_V_PRIME_HALF_LEN]; +} __packed; + +struct hdcp2_rep_stream_manage { + u8 msg_id; + u8 seq_num_m[HDCP_2_2_SEQ_NUM_LEN]; + __be16 k; + struct hdcp2_streamid_type streams[HDCP_2_2_MAX_CONTENT_STREAMS_CNT]; +} __packed; + +struct hdcp2_rep_stream_ready { + u8 msg_id; + u8 m_prime[HDCP_2_2_MPRIME_LEN]; +} __packed; + +/* HDCP2.2 TIMEOUTs in mSec */ +#define HDCP_2_2_CERT_TIMEOUT_MS 100 +#define HDCP_2_2_DP_CERT_READ_TIMEOUT_MS 110 +#define HDCP_2_2_HPRIME_NO_PAIRED_TIMEOUT_MS 1000 +#define HDCP_2_2_HPRIME_PAIRED_TIMEOUT_MS 200 +#define HDCP_2_2_DP_HPRIME_READ_TIMEOUT_MS 7 +#define HDCP_2_2_PAIRING_TIMEOUT_MS 200 +#define HDCP_2_2_DP_PAIRING_READ_TIMEOUT_MS 5 +#define HDCP_2_2_HDMI_LPRIME_TIMEOUT_MS 20 +#define HDCP_2_2_DP_LPRIME_TIMEOUT_MS 16 +#define HDCP_2_2_RECVID_LIST_TIMEOUT_MS 3000 +#define HDCP_2_2_STREAM_READY_TIMEOUT_MS 100 + +/* HDMI HDCP2.2 Register Offsets */ +#define HDCP_2_2_HDMI_REG_VER_OFFSET 0x50 +#define HDCP_2_2_HDMI_REG_WR_MSG_OFFSET 0x60 +#define HDCP_2_2_HDMI_REG_RXSTATUS_OFFSET 0x70 +#define HDCP_2_2_HDMI_REG_RD_MSG_OFFSET 0x80 +#define HDCP_2_2_HDMI_REG_DBG_OFFSET 0xC0 + +#define HDCP_2_2_HDMI_SUPPORT_MASK BIT(2) +#define HDCP_2_2_RX_CAPS_VERSION_VAL 0x02 +#define HDCP_2_2_SEQ_NUM_MAX 0xFFFFFF +#define HDCP_2_2_DELAY_BEFORE_ENCRYPTION_EN 200 + +/* Below macros take a byte at a time and mask the bit(s) */ +#define HDCP_2_2_HDMI_RXSTATUS_LEN 2 +#define HDCP_2_2_HDMI_RXSTATUS_MSG_SZ_HI(x) ((x) & 0x3) +#define HDCP_2_2_HDMI_RXSTATUS_READY(x) ((x) & BIT(2)) +#define HDCP_2_2_HDMI_RXSTATUS_REAUTH_REQ(x) ((x) & BIT(3)) + +/* + * Helper functions to convert 24bit big endian hdcp sequence number to + * host format and back + */ +static inline +u32 drm_hdcp_be24_to_cpu(const u8 seq_num[HDCP_2_2_SEQ_NUM_LEN]) +{ + return (u32)(seq_num[2] | seq_num[1] << 8 | seq_num[0] << 16); +} + +static inline +void drm_hdcp_cpu_to_be24(u8 seq_num[HDCP_2_2_SEQ_NUM_LEN], u32 val) +{ + seq_num[0] = val >> 16; + seq_num[1] = val >> 8; + seq_num[2] = val; +} + +#define DRM_HDCP_SRM_GEN1_MAX_BYTES (5 * 1024) +#define DRM_HDCP_1_4_SRM_ID 0x8 +#define DRM_HDCP_SRM_ID_MASK (0xF << 4) +#define DRM_HDCP_1_4_VRL_LENGTH_SIZE 3 +#define DRM_HDCP_1_4_DCP_SIG_SIZE 40 +#define DRM_HDCP_2_SRM_ID 0x9 +#define DRM_HDCP_2_INDICATOR 0x1 +#define DRM_HDCP_2_INDICATOR_MASK 0xF +#define DRM_HDCP_2_VRL_LENGTH_SIZE 3 +#define DRM_HDCP_2_DCP_SIG_SIZE 384 +#define DRM_HDCP_2_NO_OF_DEV_PLUS_RESERVED_SZ 4 +#define DRM_HDCP_2_KSV_COUNT_2_LSBITS(byte) (((byte) & 0xC0) >> 6) + +struct hdcp_srm_header { + u8 srm_id; + u8 reserved; + __be16 srm_version; + u8 srm_gen_no; +} __packed; + +/* Content Type classification for HDCP2.2 vs others */ +#define DRM_MODE_HDCP_CONTENT_TYPE0 0 +#define DRM_MODE_HDCP_CONTENT_TYPE1 1 + +#endif diff --git a/include/drm/display/drm_hdcp_helper.h b/include/drm/display/drm_hdcp_helper.h new file mode 100644 index 000000000000..8aaf87bf2735 --- /dev/null +++ b/include/drm/display/drm_hdcp_helper.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright (C) 2017 Google, Inc. + * + * Authors: + * Sean Paul + */ + +#ifndef _DRM_HDCP_HELPER_H_INCLUDED_ +#define _DRM_HDCP_HELPER_H_INCLUDED_ + +#include + +struct drm_device; +struct drm_connector; + +int drm_hdcp_check_ksvs_revoked(struct drm_device *dev, u8 *ksvs, u32 ksv_count); +int drm_connector_attach_content_protection_property(struct drm_connector *connector, + bool hdcp_content_type); +void drm_hdcp_update_content_protection(struct drm_connector *connector, u64 val); + +#endif diff --git a/include/drm/drm_hdcp.h b/include/drm/drm_hdcp.h deleted file mode 100644 index 0b1111e3228e..000000000000 --- a/include/drm/drm_hdcp.h +++ /dev/null @@ -1,308 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* - * Copyright (C) 2017 Google, Inc. - * - * Authors: - * Sean Paul - */ - -#ifndef _DRM_HDCP_H_INCLUDED_ -#define _DRM_HDCP_H_INCLUDED_ - -#include - -/* Period of hdcp checks (to ensure we're still authenticated) */ -#define DRM_HDCP_CHECK_PERIOD_MS (128 * 16) -#define DRM_HDCP2_CHECK_PERIOD_MS 500 - -/* 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 & 0x7f) -#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 - -/* Value to use at the end of the SHA-1 bytestream used for repeaters */ -#define DRM_HDCP_SHA1_TERMINATOR 0x80 - -/* 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 - -#define DRM_HDCP_1_4_SRM_ID 0x8 -#define DRM_HDCP_1_4_VRL_LENGTH_SIZE 3 -#define DRM_HDCP_1_4_DCP_SIG_SIZE 40 - -/* Protocol message definition for HDCP2.2 specification */ -/* - * Protected content streams are classified into 2 types: - * - Type0: Can be transmitted with HDCP 1.4+ - * - Type1: Can be transmitted with HDCP 2.2+ - */ -#define HDCP_STREAM_TYPE0 0x00 -#define HDCP_STREAM_TYPE1 0x01 - -/* HDCP2.2 Msg IDs */ -#define HDCP_2_2_NULL_MSG 1 -#define HDCP_2_2_AKE_INIT 2 -#define HDCP_2_2_AKE_SEND_CERT 3 -#define HDCP_2_2_AKE_NO_STORED_KM 4 -#define HDCP_2_2_AKE_STORED_KM 5 -#define HDCP_2_2_AKE_SEND_HPRIME 7 -#define HDCP_2_2_AKE_SEND_PAIRING_INFO 8 -#define HDCP_2_2_LC_INIT 9 -#define HDCP_2_2_LC_SEND_LPRIME 10 -#define HDCP_2_2_SKE_SEND_EKS 11 -#define HDCP_2_2_REP_SEND_RECVID_LIST 12 -#define HDCP_2_2_REP_SEND_ACK 15 -#define HDCP_2_2_REP_STREAM_MANAGE 16 -#define HDCP_2_2_REP_STREAM_READY 17 - -#define HDCP_2_2_RTX_LEN 8 -#define HDCP_2_2_RRX_LEN 8 - -#define HDCP_2_2_K_PUB_RX_MOD_N_LEN 128 -#define HDCP_2_2_K_PUB_RX_EXP_E_LEN 3 -#define HDCP_2_2_K_PUB_RX_LEN (HDCP_2_2_K_PUB_RX_MOD_N_LEN + \ - HDCP_2_2_K_PUB_RX_EXP_E_LEN) - -#define HDCP_2_2_DCP_LLC_SIG_LEN 384 - -#define HDCP_2_2_E_KPUB_KM_LEN 128 -#define HDCP_2_2_E_KH_KM_M_LEN (16 + 16) -#define HDCP_2_2_H_PRIME_LEN 32 -#define HDCP_2_2_E_KH_KM_LEN 16 -#define HDCP_2_2_RN_LEN 8 -#define HDCP_2_2_L_PRIME_LEN 32 -#define HDCP_2_2_E_DKEY_KS_LEN 16 -#define HDCP_2_2_RIV_LEN 8 -#define HDCP_2_2_SEQ_NUM_LEN 3 -#define HDCP_2_2_V_PRIME_HALF_LEN (HDCP_2_2_L_PRIME_LEN / 2) -#define HDCP_2_2_RECEIVER_ID_LEN DRM_HDCP_KSV_LEN -#define HDCP_2_2_MAX_DEVICE_COUNT 31 -#define HDCP_2_2_RECEIVER_IDS_MAX_LEN (HDCP_2_2_RECEIVER_ID_LEN * \ - HDCP_2_2_MAX_DEVICE_COUNT) -#define HDCP_2_2_MPRIME_LEN 32 - -/* Following Macros take a byte at a time for bit(s) masking */ -/* - * TODO: HDCP_2_2_MAX_CONTENT_STREAMS_CNT is based upon actual - * H/W MST streams capacity. - * This required to be moved out to platform specific header. - */ -#define HDCP_2_2_MAX_CONTENT_STREAMS_CNT 4 -#define HDCP_2_2_TXCAP_MASK_LEN 2 -#define HDCP_2_2_RXCAPS_LEN 3 -#define HDCP_2_2_RX_REPEATER(x) ((x) & BIT(0)) -#define HDCP_2_2_DP_HDCP_CAPABLE(x) ((x) & BIT(1)) -#define HDCP_2_2_RXINFO_LEN 2 - -/* HDCP1.x compliant device in downstream */ -#define HDCP_2_2_HDCP1_DEVICE_CONNECTED(x) ((x) & BIT(0)) - -/* HDCP2.0 Compliant repeater in downstream */ -#define HDCP_2_2_HDCP_2_0_REP_CONNECTED(x) ((x) & BIT(1)) -#define HDCP_2_2_MAX_CASCADE_EXCEEDED(x) ((x) & BIT(2)) -#define HDCP_2_2_MAX_DEVS_EXCEEDED(x) ((x) & BIT(3)) -#define HDCP_2_2_DEV_COUNT_LO(x) (((x) & (0xF << 4)) >> 4) -#define HDCP_2_2_DEV_COUNT_HI(x) ((x) & BIT(0)) -#define HDCP_2_2_DEPTH(x) (((x) & (0x7 << 1)) >> 1) - -struct hdcp2_cert_rx { - u8 receiver_id[HDCP_2_2_RECEIVER_ID_LEN]; - u8 kpub_rx[HDCP_2_2_K_PUB_RX_LEN]; - u8 reserved[2]; - u8 dcp_signature[HDCP_2_2_DCP_LLC_SIG_LEN]; -} __packed; - -struct hdcp2_streamid_type { - u8 stream_id; - u8 stream_type; -} __packed; - -/* - * The TxCaps field specified in the HDCP HDMI, DP specs - * This field is big endian as specified in the errata. - */ -struct hdcp2_tx_caps { - /* Transmitter must set this to 0x2 */ - u8 version; - - /* Reserved for HDCP and DP Spec. Read as Zero */ - u8 tx_cap_mask[HDCP_2_2_TXCAP_MASK_LEN]; -} __packed; - -/* Main structures for HDCP2.2 protocol communication */ -struct hdcp2_ake_init { - u8 msg_id; - u8 r_tx[HDCP_2_2_RTX_LEN]; - struct hdcp2_tx_caps tx_caps; -} __packed; - -struct hdcp2_ake_send_cert { - u8 msg_id; - struct hdcp2_cert_rx cert_rx; - u8 r_rx[HDCP_2_2_RRX_LEN]; - u8 rx_caps[HDCP_2_2_RXCAPS_LEN]; -} __packed; - -struct hdcp2_ake_no_stored_km { - u8 msg_id; - u8 e_kpub_km[HDCP_2_2_E_KPUB_KM_LEN]; -} __packed; - -struct hdcp2_ake_stored_km { - u8 msg_id; - u8 e_kh_km_m[HDCP_2_2_E_KH_KM_M_LEN]; -} __packed; - -struct hdcp2_ake_send_hprime { - u8 msg_id; - u8 h_prime[HDCP_2_2_H_PRIME_LEN]; -} __packed; - -struct hdcp2_ake_send_pairing_info { - u8 msg_id; - u8 e_kh_km[HDCP_2_2_E_KH_KM_LEN]; -} __packed; - -struct hdcp2_lc_init { - u8 msg_id; - u8 r_n[HDCP_2_2_RN_LEN]; -} __packed; - -struct hdcp2_lc_send_lprime { - u8 msg_id; - u8 l_prime[HDCP_2_2_L_PRIME_LEN]; -} __packed; - -struct hdcp2_ske_send_eks { - u8 msg_id; - u8 e_dkey_ks[HDCP_2_2_E_DKEY_KS_LEN]; - u8 riv[HDCP_2_2_RIV_LEN]; -} __packed; - -struct hdcp2_rep_send_receiverid_list { - u8 msg_id; - u8 rx_info[HDCP_2_2_RXINFO_LEN]; - u8 seq_num_v[HDCP_2_2_SEQ_NUM_LEN]; - u8 v_prime[HDCP_2_2_V_PRIME_HALF_LEN]; - u8 receiver_ids[HDCP_2_2_RECEIVER_IDS_MAX_LEN]; -} __packed; - -struct hdcp2_rep_send_ack { - u8 msg_id; - u8 v[HDCP_2_2_V_PRIME_HALF_LEN]; -} __packed; - -struct hdcp2_rep_stream_manage { - u8 msg_id; - u8 seq_num_m[HDCP_2_2_SEQ_NUM_LEN]; - __be16 k; - struct hdcp2_streamid_type streams[HDCP_2_2_MAX_CONTENT_STREAMS_CNT]; -} __packed; - -struct hdcp2_rep_stream_ready { - u8 msg_id; - u8 m_prime[HDCP_2_2_MPRIME_LEN]; -} __packed; - -/* HDCP2.2 TIMEOUTs in mSec */ -#define HDCP_2_2_CERT_TIMEOUT_MS 100 -#define HDCP_2_2_DP_CERT_READ_TIMEOUT_MS 110 -#define HDCP_2_2_HPRIME_NO_PAIRED_TIMEOUT_MS 1000 -#define HDCP_2_2_HPRIME_PAIRED_TIMEOUT_MS 200 -#define HDCP_2_2_DP_HPRIME_READ_TIMEOUT_MS 7 -#define HDCP_2_2_PAIRING_TIMEOUT_MS 200 -#define HDCP_2_2_DP_PAIRING_READ_TIMEOUT_MS 5 -#define HDCP_2_2_HDMI_LPRIME_TIMEOUT_MS 20 -#define HDCP_2_2_DP_LPRIME_TIMEOUT_MS 16 -#define HDCP_2_2_RECVID_LIST_TIMEOUT_MS 3000 -#define HDCP_2_2_STREAM_READY_TIMEOUT_MS 100 - -/* HDMI HDCP2.2 Register Offsets */ -#define HDCP_2_2_HDMI_REG_VER_OFFSET 0x50 -#define HDCP_2_2_HDMI_REG_WR_MSG_OFFSET 0x60 -#define HDCP_2_2_HDMI_REG_RXSTATUS_OFFSET 0x70 -#define HDCP_2_2_HDMI_REG_RD_MSG_OFFSET 0x80 -#define HDCP_2_2_HDMI_REG_DBG_OFFSET 0xC0 - -#define HDCP_2_2_HDMI_SUPPORT_MASK BIT(2) -#define HDCP_2_2_RX_CAPS_VERSION_VAL 0x02 -#define HDCP_2_2_SEQ_NUM_MAX 0xFFFFFF -#define HDCP_2_2_DELAY_BEFORE_ENCRYPTION_EN 200 - -/* Below macros take a byte at a time and mask the bit(s) */ -#define HDCP_2_2_HDMI_RXSTATUS_LEN 2 -#define HDCP_2_2_HDMI_RXSTATUS_MSG_SZ_HI(x) ((x) & 0x3) -#define HDCP_2_2_HDMI_RXSTATUS_READY(x) ((x) & BIT(2)) -#define HDCP_2_2_HDMI_RXSTATUS_REAUTH_REQ(x) ((x) & BIT(3)) - -/* - * Helper functions to convert 24bit big endian hdcp sequence number to - * host format and back - */ -static inline -u32 drm_hdcp_be24_to_cpu(const u8 seq_num[HDCP_2_2_SEQ_NUM_LEN]) -{ - return (u32)(seq_num[2] | seq_num[1] << 8 | seq_num[0] << 16); -} - -static inline -void drm_hdcp_cpu_to_be24(u8 seq_num[HDCP_2_2_SEQ_NUM_LEN], u32 val) -{ - seq_num[0] = val >> 16; - seq_num[1] = val >> 8; - seq_num[2] = val; -} - -#define DRM_HDCP_SRM_GEN1_MAX_BYTES (5 * 1024) -#define DRM_HDCP_1_4_SRM_ID 0x8 -#define DRM_HDCP_SRM_ID_MASK (0xF << 4) -#define DRM_HDCP_1_4_VRL_LENGTH_SIZE 3 -#define DRM_HDCP_1_4_DCP_SIG_SIZE 40 -#define DRM_HDCP_2_SRM_ID 0x9 -#define DRM_HDCP_2_INDICATOR 0x1 -#define DRM_HDCP_2_INDICATOR_MASK 0xF -#define DRM_HDCP_2_VRL_LENGTH_SIZE 3 -#define DRM_HDCP_2_DCP_SIG_SIZE 384 -#define DRM_HDCP_2_NO_OF_DEV_PLUS_RESERVED_SZ 4 -#define DRM_HDCP_2_KSV_COUNT_2_LSBITS(byte) (((byte) & 0xC0) >> 6) - -struct hdcp_srm_header { - u8 srm_id; - u8 reserved; - __be16 srm_version; - u8 srm_gen_no; -} __packed; - -struct drm_device; -struct drm_connector; - -int drm_hdcp_check_ksvs_revoked(struct drm_device *dev, - u8 *ksvs, u32 ksv_count); -int drm_connector_attach_content_protection_property( - struct drm_connector *connector, bool hdcp_content_type); -void drm_hdcp_update_content_protection(struct drm_connector *connector, - u64 val); - -/* Content Type classification for HDCP2.2 vs others */ -#define DRM_MODE_HDCP_CONTENT_TYPE0 0 -#define DRM_MODE_HDCP_CONTENT_TYPE1 1 - -#endif diff --git a/include/drm/i915_mei_hdcp_interface.h b/include/drm/i915_mei_hdcp_interface.h index 702f613243bb..f441cbcd95a4 100644 --- a/include/drm/i915_mei_hdcp_interface.h +++ b/include/drm/i915_mei_hdcp_interface.h @@ -11,7 +11,7 @@ #include #include -#include +#include /** * enum hdcp_port_type - HDCP port implementation type defined by ME FW -- cgit v1.2.3