From patchwork Wed Oct 23 00:12:06 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Rajat Jain X-Patchwork-Id: 11207159 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id CD26D112B for ; Wed, 23 Oct 2019 16:15:05 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id B55772064A for ; Wed, 23 Oct 2019 16:15:05 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org B55772064A Authentication-Results: mail.kernel.org; dmarc=fail (p=reject dis=none) header.from=google.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=intel-gfx-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 4AC3B6EB3E; Wed, 23 Oct 2019 16:15:04 +0000 (UTC) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mail-pl1-x64a.google.com (mail-pl1-x64a.google.com [IPv6:2607:f8b0:4864:20::64a]) by gabe.freedesktop.org (Postfix) with ESMTPS id 9D8E26E860 for ; Wed, 23 Oct 2019 00:12:12 +0000 (UTC) Received: by mail-pl1-x64a.google.com with SMTP id o9so11533163plk.13 for ; Tue, 22 Oct 2019 17:12:12 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:message-id:mime-version:subject:from:to:cc :content-transfer-encoding; bh=zqN70IYDrp81wg8yHsEcapQPROi/kGtOXEycNw/gKkQ=; b=TYx/vgvST9nzvA36BWoQYM97fWuzVS/8bq23Q3O/x1bkTGZXd3fdOZbM9Jsmg+dAQ0 myQuMmgw9I9I18sFIrFzPq82jzzpEZUv2L0hisfdiDdUjrC53SU5/fh8eLRLcwzVO0PI g0sZSZ3sZHiGzYfuMdDSBvIbA76VlVt+A1+YWuHkpbItg/Rwky+Xizf8fAMgLyH+CBiD pbkYOwm77i6Mks1vWO9VTbMN5YNnhcnBGA16FeRhxBv/Am5oviGE2sQqQ7+a06YGnrHj CT/9dbRPu67gXtJr/GQkVM1srlOBcxK5y1Jwgln9sAjBQ21oFCnGdY0JyrFEAC/pQ62l STqw== X-Gm-Message-State: APjAAAU5rPqiZ2ZM4ZX63IGogFp3s19G68CumkFeRYSUpl8J1uo1lzQl afBbx6/zxLAWl9BjXwpHVpFVTkL22lWn X-Google-Smtp-Source: APXvYqw0RcW/1e3HqLig1fAtZTymKCDkceIZ6JqDsGNrVS5AfGoBiOE2MkD/KI39gMRybb4d8Nd1Z3gbMxO+ X-Received: by 2002:a63:ea45:: with SMTP id l5mr6455839pgk.189.1571789531805; Tue, 22 Oct 2019 17:12:11 -0700 (PDT) Date: Tue, 22 Oct 2019 17:12:06 -0700 Message-Id: <20191023001206.15741-1-rajatja@google.com> Mime-Version: 1.0 X-Mailer: git-send-email 2.23.0.866.gb869b98d4c-goog From: Rajat Jain To: Maarten Lankhorst , Maxime Ripard , Sean Paul , David Airlie , Daniel Vetter , Jani Nikula , Joonas Lahtinen , Rodrigo Vivi , " =?utf-8?b?VmlsbGUgU3lyasOkbMOk?= " , Chris Wilson , Imre Deak , " =?utf-8?q?Jos=C3=A9_Roberto_de_Souza?= " , linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, intel-gfx@lists.freedesktop.org, gregkh@linuxfoundation.org, mathewk@google.com, Daniel Thompson , Jonathan Corbet , Pavel Machek , seanpaul@google.com, Duncan Laurie , jsbarnes@google.com X-Mailman-Approved-At: Wed, 23 Oct 2019 16:15:03 +0000 X-Mailman-Original-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:message-id:mime-version:subject:from:to:cc :content-transfer-encoding; bh=zqN70IYDrp81wg8yHsEcapQPROi/kGtOXEycNw/gKkQ=; b=IPG4E9Jd3M9QM7xqGkEWwl+GQZ0MoJs5TAYppdgWpKNp36i/QO5U4VbZEEIgFvGcUk 4tkSvhFZvSj/+AjhQQaRpQPA+AeW7P4qSAL5BNogVEOoBVdE5Y3sfeecY8YtAYtC0O1O ZRFQaftpImMnjc9w6v0gsUGa7RkLKxaXNy2vEXGMfxjDJtSSyAPCweikFkRN+58BGWHK ssK58sRac8FbE/Wp+63t3C08WlqINZY9sLsSMxCudOXkxJCPhI8R4b7jY6RH5dCCW1K8 6EOBknpX1HH6tRhjvnc8uVMQFGQzLnmiFev1g+VOtReTkDYTUFykpyZvRgnn+BVrF3P5 laVw== Subject: [Intel-gfx] [PATCH] drm: Add support for integrated privacy screens X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Rajat Jain , rajatxjain@gmail.com Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" Certain laptops now come with panels that have integrated privacy screens on them. This patch adds support for such panels by adding a privacy-screen property to the drm_connector for the panel, that the userspace can then use to control and check the status. The idea was discussed here: https://lkml.org/lkml/2019/10/1/786 ACPI methods are used to identify, query and control privacy screen: * Identifying an ACPI object corresponding to the panel: The patch follows ACPI Spec 6.3 (available at https://uefi.org/sites/default/files/resources/ACPI_6_3_final_Jan30.pdf). Pages 1119 - 1123 describe what I believe, is a standard way of identifying / addressing "display panels" in the ACPI tables, thus allowing kernel to attach ACPI nodes to the panel. IMHO, this ability to identify and attach ACPI nodes to drm connectors may be useful for reasons other privacy-screens, in future. * Identifying the presence of privacy screen, and controlling it, is done via ACPI _DSM methods. Currently, this is done only for the Intel display ports. But in future, this can be done for any other ports if the hardware becomes available (e.g. external monitors supporting integrated privacy screens?). Also, this code can be extended in future to support non-ACPI methods (e.g. using a kernel GPIO driver to toggle a gpio that controls the privacy-screen). Signed-off-by: Rajat Jain --- drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/drm_atomic_uapi.c | 5 + drivers/gpu/drm/drm_connector.c | 38 +++++ drivers/gpu/drm/drm_privacy_screen.c | 176 ++++++++++++++++++++++++ drivers/gpu/drm/i915/display/intel_dp.c | 3 + include/drm/drm_connector.h | 18 +++ include/drm/drm_mode_config.h | 7 + include/drm/drm_privacy_screen.h | 33 +++++ 8 files changed, 281 insertions(+) create mode 100644 drivers/gpu/drm/drm_privacy_screen.c create mode 100644 include/drm/drm_privacy_screen.h diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 82ff826b33cc..e1fc33d69bb7 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -19,6 +19,7 @@ drm-y := drm_auth.o drm_cache.o \ drm_syncobj.o drm_lease.o drm_writeback.o drm_client.o \ drm_client_modeset.o drm_atomic_uapi.o drm_hdcp.o +drm-$(CONFIG_ACPI) += drm_privacy_screen.o drm-$(CONFIG_DRM_LEGACY) += drm_legacy_misc.o drm_bufs.o drm_context.o drm_dma.o drm_scatter.o drm_lock.o drm-$(CONFIG_DRM_LIB_RANDOM) += lib/drm_random.o drm-$(CONFIG_DRM_VM) += drm_vm.o diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c index 7a26bfb5329c..44131165e4ea 100644 --- a/drivers/gpu/drm/drm_atomic_uapi.c +++ b/drivers/gpu/drm/drm_atomic_uapi.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -766,6 +767,8 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector, fence_ptr); } else if (property == connector->max_bpc_property) { state->max_requested_bpc = val; + } else if (property == config->privacy_screen_property) { + drm_privacy_screen_set_val(connector, val); } else if (connector->funcs->atomic_set_property) { return connector->funcs->atomic_set_property(connector, state, property, val); @@ -842,6 +845,8 @@ drm_atomic_connector_get_property(struct drm_connector *connector, *val = 0; } else if (property == connector->max_bpc_property) { *val = state->max_requested_bpc; + } else if (property == config->privacy_screen_property) { + *val = drm_privacy_screen_get_val(connector); } else if (connector->funcs->atomic_get_property) { return connector->funcs->atomic_get_property(connector, state, property, val); diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index 4c766624b20d..a31e0382132b 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -821,6 +821,11 @@ static const struct drm_prop_enum_list drm_panel_orientation_enum_list[] = { { DRM_MODE_PANEL_ORIENTATION_RIGHT_UP, "Right Side Up" }, }; +static const struct drm_prop_enum_list drm_privacy_screen_enum_list[] = { + { DRM_PRIVACY_SCREEN_DISABLED, "Disabled" }, + { DRM_PRIVACY_SCREEN_ENABLED, "Enabled" }, +}; + static const struct drm_prop_enum_list drm_dvi_i_select_enum_list[] = { { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */ { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ @@ -2253,6 +2258,39 @@ static void drm_tile_group_free(struct kref *kref) kfree(tg); } +/** + * drm_connector_init_privacy_screen_property - + * create and attach the connecter's privacy-screen property. + * @connector: connector for which to init the privacy-screen property. + * + * This function creates and attaches the "privacy-screen" property to the + * connector. Initial state of privacy-screen is set to disabled. + * + * Returns: + * Zero on success, negative errno on failure. + */ +int drm_connector_init_privacy_screen_property(struct drm_connector *connector) +{ + struct drm_device *dev = connector->dev; + struct drm_property *prop; + + prop = dev->mode_config.privacy_screen_property; + if (!prop) { + prop = drm_property_create_enum(dev, DRM_MODE_PROP_ENUM, + "privacy-screen", drm_privacy_screen_enum_list, + ARRAY_SIZE(drm_privacy_screen_enum_list)); + if (!prop) + return -ENOMEM; + + dev->mode_config.privacy_screen_property = prop; + } + + drm_object_attach_property(&connector->base, prop, + DRM_PRIVACY_SCREEN_DISABLED); + return 0; +} +EXPORT_SYMBOL(drm_connector_init_privacy_screen_property); + /** * drm_mode_put_tile_group - drop a reference to a tile group. * @dev: DRM device diff --git a/drivers/gpu/drm/drm_privacy_screen.c b/drivers/gpu/drm/drm_privacy_screen.c new file mode 100644 index 000000000000..1d68e8aa6c5f --- /dev/null +++ b/drivers/gpu/drm/drm_privacy_screen.c @@ -0,0 +1,176 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * DRM privacy Screen code + * + * Copyright © 2019 Google Inc. + */ + +#include +#include + +#include +#include +#include + +#define DRM_CONN_DSM_REVID 1 + +#define DRM_CONN_DSM_FN_PRIVACY_GET_STATUS 1 +#define DRM_CONN_DSM_FN_PRIVACY_ENABLE 2 +#define DRM_CONN_DSM_FN_PRIVACY_DISABLE 3 + +static const guid_t drm_conn_dsm_guid = + GUID_INIT(0xC7033113, 0x8720, 0x4CEB, + 0x90, 0x90, 0x9D, 0x52, 0xB3, 0xE5, 0x2D, 0x73); + +/* + * Makes _DSM call to set privacy screen status or get privacy screen. Return + * value matters only for PRIVACY_GET_STATUS case. Returns 0 if disabled, 1 if + * enabled. + */ +static int acpi_privacy_screen_call_dsm(acpi_handle conn_handle, u64 func) +{ + union acpi_object *obj; + int ret = 0; + + obj = acpi_evaluate_dsm(conn_handle, &drm_conn_dsm_guid, + DRM_CONN_DSM_REVID, func, NULL); + if (!obj) { + DRM_DEBUG_DRIVER("failed to evaluate _DSM for fn %llx\n", func); + /* Can't do much. For get_val, assume privacy_screen disabled */ + goto done; + } + + if (func == DRM_CONN_DSM_FN_PRIVACY_GET_STATUS && + obj->type == ACPI_TYPE_INTEGER) + ret = !!obj->integer.value; +done: + ACPI_FREE(obj); + return ret; +} + +void drm_privacy_screen_set_val(struct drm_connector *connector, + enum drm_privacy_screen val) +{ + acpi_handle acpi_handle = connector->privacy_screen_handle; + + if (!acpi_handle) + return; + + if (val == DRM_PRIVACY_SCREEN_DISABLED) + acpi_privacy_screen_call_dsm(acpi_handle, + DRM_CONN_DSM_FN_PRIVACY_DISABLE); + else if (val == DRM_PRIVACY_SCREEN_ENABLED) + acpi_privacy_screen_call_dsm(acpi_handle, + DRM_CONN_DSM_FN_PRIVACY_ENABLE); +} + +enum drm_privacy_screen drm_privacy_screen_get_val(struct drm_connector + *connector) +{ + acpi_handle acpi_handle = connector->privacy_screen_handle; + + if (acpi_handle && + acpi_privacy_screen_call_dsm(acpi_handle, + DRM_CONN_DSM_FN_PRIVACY_GET_STATUS)) + return DRM_PRIVACY_SCREEN_ENABLED; + + return DRM_PRIVACY_SCREEN_DISABLED; +} + +/* + * See ACPI Spec v6.3, Table B-2, "Display Type" for details. + * In short, these macros define the base _ADR values for ACPI nodes + */ +#define ACPI_BASE_ADR_FOR_OTHERS (0ULL << 8) +#define ACPI_BASE_ADR_FOR_VGA (1ULL << 8) +#define ACPI_BASE_ADR_FOR_TV (2ULL << 8) +#define ACPI_BASE_ADR_FOR_EXT_MON (3ULL << 8) +#define ACPI_BASE_ADR_FOR_INTEGRATED (4ULL << 8) + +#define ACPI_DEVICE_ID_SCHEME (1ULL << 31) +#define ACPI_FIRMWARE_CAN_DETECT (1ULL << 16) + +/* + * Ref: ACPI Spec 6.3 + * https://uefi.org/sites/default/files/resources/ACPI_6_3_final_Jan30.pdf + * Pages 1119 - 1123 describe, what I believe, a standard way of + * identifying / addressing "display panels" in the ACPI. Thus it provides + * a way for the ACPI to define devices for the display panels attached + * to the system. It thus provides a way for the BIOS to export any panel + * specific properties to the system via ACPI (like device trees). + * + * The following function looks up the ACPI node for a connector and links + * to it. Technically it is independent from the privacy_screen code, and + * ideally may be called for all connectors. It is generally a good idea to + * be able to attach an ACPI node to describe anything if needed. (This can + * help in future for other panel specific features maybe). However, it + * needs a "port index" which I believe is the index within a particular + * type of port (Ref to the pages of spec mentioned above). This port index + * unfortunately is not available in DRM code, so currently its call is + * originated from i915 driver. + */ +static int drm_connector_attach_acpi_node(struct drm_connector *connector, + u8 port_index) +{ + struct device *dev = &connector->dev->pdev->dev; + struct acpi_device *conn_dev; + u64 conn_addr; + + /* + * Determine what _ADR to look for, depending on device type and + * port number. Potentially we only care about the + * eDP / integrated displays? + */ + switch (connector->connector_type) { + case DRM_MODE_CONNECTOR_eDP: + conn_addr = ACPI_BASE_ADR_FOR_INTEGRATED + port_index; + break; + case DRM_MODE_CONNECTOR_VGA: + conn_addr = ACPI_BASE_ADR_FOR_VGA + port_index; + break; + case DRM_MODE_CONNECTOR_TV: + conn_addr = ACPI_BASE_ADR_FOR_TV + port_index; + break; + case DRM_MODE_CONNECTOR_DisplayPort: + conn_addr = ACPI_BASE_ADR_FOR_EXT_MON + port_index; + break; + default: + return -ENOTSUPP; + } + + conn_addr |= ACPI_DEVICE_ID_SCHEME; + conn_addr |= ACPI_FIRMWARE_CAN_DETECT; + + DRM_DEV_DEBUG(dev, "%s: Finding drm_connector ACPI node at _ADR=%llX\n", + __func__, conn_addr); + + /* Look up the connector device, under the PCI device */ + conn_dev = acpi_find_child_device(ACPI_COMPANION(dev), + conn_addr, false); + if (!conn_dev) + return -ENODEV; + + connector->privacy_screen_handle = conn_dev->handle; + return 0; +} + +bool drm_privacy_screen_present(struct drm_connector *connector, u8 port_index) +{ + acpi_handle handle; + + if (drm_connector_attach_acpi_node(connector, port_index)) + return false; + + handle = connector->privacy_screen_handle; + if (!acpi_check_dsm(handle, &drm_conn_dsm_guid, + DRM_CONN_DSM_REVID, + 1 << DRM_CONN_DSM_FN_PRIVACY_GET_STATUS | + 1 << DRM_CONN_DSM_FN_PRIVACY_ENABLE | + 1 << DRM_CONN_DSM_FN_PRIVACY_DISABLE)) { + DRM_WARN("%s: Odd, connector ACPI node but no privacy scrn?\n", + connector->dev->dev); + return false; + } + DRM_DEV_INFO(connector->dev->dev, "supports privacy screen\n"); + return true; +} diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 57e9f0ba331b..3ff3962d27db 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -6354,6 +6355,8 @@ intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connect connector->state->scaling_mode = DRM_MODE_SCALE_ASPECT; + if (drm_privacy_screen_present(connector, port - PORT_A)) + drm_connector_init_privacy_screen_property(connector); } } diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 681cb590f952..63b8318bd68c 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -225,6 +225,20 @@ enum drm_link_status { DRM_LINK_STATUS_BAD = DRM_MODE_LINK_STATUS_BAD, }; +/** + * enum drm_privacy_screen - privacy_screen status + * + * This enum is used to track and control the state of the privacy screen. + * There are no separate #defines for the uapi! + * + * @DRM_PRIVACY_SCREEN_DISABLED: The privacy-screen on the panel is disabled + * @DRM_PRIVACY_SCREEN_ENABLED: The privacy-screen on the panel is enabled + */ +enum drm_privacy_screen { + DRM_PRIVACY_SCREEN_DISABLED = 0, + DRM_PRIVACY_SCREEN_ENABLED = 1, +}; + /** * enum drm_panel_orientation - panel_orientation info for &drm_display_info * @@ -1410,6 +1424,9 @@ struct drm_connector { /** @hdr_sink_metadata: HDR Metadata Information read from sink */ struct hdr_sink_metadata hdr_sink_metadata; + + /* Handle used by privacy screen code */ + void *privacy_screen_handle; }; #define obj_to_connector(x) container_of(x, struct drm_connector, base) @@ -1543,6 +1560,7 @@ int drm_connector_init_panel_orientation_property( struct drm_connector *connector, int width, int height); int drm_connector_attach_max_bpc_property(struct drm_connector *connector, int min, int max); +int drm_connector_init_privacy_screen_property(struct drm_connector *connector); /** * struct drm_tile_group - Tile group metadata diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h index 3bcbe30339f0..6d5d23da90d4 100644 --- a/include/drm/drm_mode_config.h +++ b/include/drm/drm_mode_config.h @@ -813,6 +813,13 @@ struct drm_mode_config { */ struct drm_property *panel_orientation_property; + /** + * @privacy_screen_property: Optional connector property to indicate + * and control the state (enabled / disabled) of privacy-screen on the + * panel, if present. + */ + struct drm_property *privacy_screen_property; + /** * @writeback_fb_id_property: Property for writeback connectors, storing * the ID of the output framebuffer. diff --git a/include/drm/drm_privacy_screen.h b/include/drm/drm_privacy_screen.h new file mode 100644 index 000000000000..c589bbc47656 --- /dev/null +++ b/include/drm/drm_privacy_screen.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright © 2019 Google Inc. + */ + +#ifndef __DRM_PRIVACY_SCREEN_H__ +#define __DRM_PRIVACY_SCREEN_H__ + +#ifdef CONFIG_ACPI +bool drm_privacy_screen_present(struct drm_connector *connector, u8 port); +void drm_privacy_screen_set_val(struct drm_connector *connector, + enum drm_privacy_screen val); +enum drm_privacy_screen drm_privacy_screen_get_val(struct drm_connector + *connector); +#else +static inline bool drm_privacy_screen_present(struct drm_connector *connector, + u8 port) +{ + return false; +} + +void drm_privacy_screen_set_val(struct drm_connector *connector, + enum drm_privacy_screen val) +{ } + +enum drm_privacy_screen drm_privacy_screen_get_val( + struct drm_connector *connector) +{ + return DRM_PRIVACY_SCREEN_DISABLED; +} +#endif /* CONFIG_ACPI */ + +#endif /* __DRM_PRIVACY_SCREEN_H__ */ From patchwork Mon Nov 4 19:41:47 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Rajat Jain X-Patchwork-Id: 11228357 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 608261390 for ; Tue, 5 Nov 2019 17:53:47 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 47D7D21882 for ; Tue, 5 Nov 2019 17:53:47 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 47D7D21882 Authentication-Results: mail.kernel.org; dmarc=fail (p=reject dis=none) header.from=google.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=intel-gfx-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id A17766EA3A; Tue, 5 Nov 2019 17:53:46 +0000 (UTC) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mail-pf1-x44a.google.com (mail-pf1-x44a.google.com [IPv6:2607:f8b0:4864:20::44a]) by gabe.freedesktop.org (Postfix) with ESMTPS id B9AB9896AF for ; Mon, 4 Nov 2019 19:41:58 +0000 (UTC) Received: by mail-pf1-x44a.google.com with SMTP id x3so14225811pfr.2 for ; Mon, 04 Nov 2019 11:41:58 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc:content-transfer-encoding; bh=YdVyYg2TmQWu6y8ro0turwBGFf90uoYSpY3DT2vX64s=; b=ABrIMJNtja9YnlIW34cjh2XnGwRda66XUjH7RrLzew0qTcL+zpZs+x0FI1zIijfait 82GDX4WIHz4P9j3h/oMDZo+sAgvFrHo67bC907bra4a1SMy/tb4Op81AW14CaVIInLOw cJMhWx8Ba2PBSaBDvPb+eQapYI3csNmG3l/6JSMaC9c0uL/W5likmDHgU9HItHAa/Jb6 ayjb3BYikBQ9ggsz69cMwj0TEojhVP9djlgSyLzWLZ/hJ8n96N3eykB4rYqJph1uWB4r e5ucWBw3avjApX4Fap2ds6q67aL5kMW6oGECpADKTc1Vw0kHezrSDASKcT5I2+zVEKTo G+Qg== X-Gm-Message-State: APjAAAUIfRy+02DJZWMYG8TDqlSb8mZGbjCzAHKzCiBBnW1+5C+GdEHk 56aaw0+OktdhhVhdEWoXsXPY/HmHQezY X-Google-Smtp-Source: APXvYqzWIBzt1JHFt6ogpAZ9xhFDdJOaQRMhLHY3DaK6aSnDATwEYqL9Z+ZpYF7w/1SgRgoQeZ4Pv0z/pePe X-Received: by 2002:a63:1a5e:: with SMTP id a30mr27305343pgm.299.1572896517733; Mon, 04 Nov 2019 11:41:57 -0800 (PST) Date: Mon, 4 Nov 2019 11:41:47 -0800 In-Reply-To: <20191104194147.185642-1-rajatja@google.com> Message-Id: <20191104194147.185642-3-rajatja@google.com> Mime-Version: 1.0 References: <20191023001206.15741-1-rajatja@google.com> <20191104194147.185642-1-rajatja@google.com> X-Mailer: git-send-email 2.24.0.rc1.363.gb1bccd3e3d-goog From: Rajat Jain To: Maarten Lankhorst , Maxime Ripard , Sean Paul , David Airlie , Daniel Vetter , Jani Nikula , Joonas Lahtinen , Rodrigo Vivi , " =?utf-8?b?VmlsbGUgU3lyasOkbMOk?= " , Chris Wilson , Imre Deak , " =?utf-8?q?Jos=C3=A9_Roberto_de_Souza?= " , linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, intel-gfx@lists.freedesktop.org, gregkh@linuxfoundation.org, mathewk@google.com, Daniel Thompson , Jonathan Corbet , Pavel Machek , seanpaul@google.com, Duncan Laurie , jsbarnes@google.com, Thierry Reding X-Mailman-Approved-At: Tue, 05 Nov 2019 17:53:45 +0000 X-Mailman-Original-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc:content-transfer-encoding; bh=YdVyYg2TmQWu6y8ro0turwBGFf90uoYSpY3DT2vX64s=; b=Awwva4OYZqsgvr4XB0eagEQnkESDAGDOveuMyxA3WOUz8UuvUMXNsmfJCxw8C+D15U Y/RcQc3ZcVijXTQNWz8uaJkOx28iDKZscO1fFDaC/dcGcUmHyXv57TEAHJq8C/j7JdAN bbR0ylU4f9XtuKy5n5bJttu2tNFrg4HBVhvgX6HHmoyxkJhwlWkJpioZxTnKvp9auQoM +HGUS96U5pkKVyfB4aHsK3hCVeRM3xkjLZOHMI1nhB8Cm9KlDxsB3c3ZeEK/xn1Jckzf Jgjx+gzf+ZnzOmcXUFx2tKvBiA564FXEaZHx+QpG/kPWTNjkxeCBpx1GgIFjW5uNPB1u yKkw== Subject: [Intel-gfx] [PATCH v2 3/3] drm/i915: Add support for integrated privacy screens X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Rajat Jain , rajatxjain@gmail.com Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" Certain laptops now come with panels that have integrated privacy screens on them. This patch adds support for such panels by adding a privacy-screen property to the intel_connector for the panel, that the userspace can then use to control and check the status. Identifying the presence of privacy screen, and controlling it, is done via ACPI _DSM methods. Currently, this is done only for the Intel display ports. But in future, this can be done for any other ports if the hardware becomes available (e.g. external monitors supporting integrated privacy screens?). Signed-off-by: Rajat Jain Change-Id: Ic9ff07fc4a50797d2d0dfb919f11aa0821a4b548 --- v2: Formed by splitting the original patch into multiple patches. - All code has been moved into i915 now. - Privacy screen is a i915 property - Have a local state variable to store the prvacy screen. Don't read it from hardware. drivers/gpu/drm/i915/Makefile | 3 +- drivers/gpu/drm/i915/display/intel_atomic.c | 13 +++- .../gpu/drm/i915/display/intel_connector.c | 35 ++++++++++ .../gpu/drm/i915/display/intel_connector.h | 1 + .../drm/i915/display/intel_display_types.h | 4 ++ drivers/gpu/drm/i915/display/intel_dp.c | 5 ++ .../drm/i915/display/intel_privacy_screen.c | 70 +++++++++++++++++++ .../drm/i915/display/intel_privacy_screen.h | 25 +++++++ include/uapi/drm/i915_drm.h | 14 ++++ 9 files changed, 166 insertions(+), 4 deletions(-) create mode 100644 drivers/gpu/drm/i915/display/intel_privacy_screen.c create mode 100644 drivers/gpu/drm/i915/display/intel_privacy_screen.h diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 2587ea834f06..3589ebcf27bc 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -185,7 +185,8 @@ i915-y += \ display/intel_tc.o i915-$(CONFIG_ACPI) += \ display/intel_acpi.o \ - display/intel_opregion.o + display/intel_opregion.o \ + display/intel_privacy_screen.o i915-$(CONFIG_DRM_FBDEV_EMULATION) += \ display/intel_fbdev.o diff --git a/drivers/gpu/drm/i915/display/intel_atomic.c b/drivers/gpu/drm/i915/display/intel_atomic.c index d3fb75bb9eb1..378772d3449c 100644 --- a/drivers/gpu/drm/i915/display/intel_atomic.c +++ b/drivers/gpu/drm/i915/display/intel_atomic.c @@ -37,6 +37,7 @@ #include "intel_atomic.h" #include "intel_display_types.h" #include "intel_hdcp.h" +#include "intel_privacy_screen.h" #include "intel_sprite.h" /** @@ -57,11 +58,14 @@ int intel_digital_connector_atomic_get_property(struct drm_connector *connector, struct drm_i915_private *dev_priv = to_i915(dev); struct intel_digital_connector_state *intel_conn_state = to_intel_digital_connector_state(state); + struct intel_connector *intel_connector = to_intel_connector(connector); if (property == dev_priv->force_audio_property) *val = intel_conn_state->force_audio; else if (property == dev_priv->broadcast_rgb_property) *val = intel_conn_state->broadcast_rgb; + else if (property == intel_connector->privacy_screen_property) + *val = intel_conn_state->privacy_screen_status; else { DRM_DEBUG_ATOMIC("Unknown property [PROP:%d:%s]\n", property->base.id, property->name); @@ -89,15 +93,18 @@ int intel_digital_connector_atomic_set_property(struct drm_connector *connector, struct drm_i915_private *dev_priv = to_i915(dev); struct intel_digital_connector_state *intel_conn_state = to_intel_digital_connector_state(state); + struct intel_connector *intel_connector = to_intel_connector(connector); if (property == dev_priv->force_audio_property) { intel_conn_state->force_audio = val; return 0; - } - - if (property == dev_priv->broadcast_rgb_property) { + } else if (property == dev_priv->broadcast_rgb_property) { intel_conn_state->broadcast_rgb = val; return 0; + } else if (property == intel_connector->privacy_screen_property) { + intel_privacy_screen_set_val(intel_connector, val); + intel_conn_state->privacy_screen_status = val; + return 0; } DRM_DEBUG_ATOMIC("Unknown property [PROP:%d:%s]\n", diff --git a/drivers/gpu/drm/i915/display/intel_connector.c b/drivers/gpu/drm/i915/display/intel_connector.c index 308ec63207ee..3ccbf52aedf9 100644 --- a/drivers/gpu/drm/i915/display/intel_connector.c +++ b/drivers/gpu/drm/i915/display/intel_connector.c @@ -281,3 +281,38 @@ intel_attach_colorspace_property(struct drm_connector *connector) drm_object_attach_property(&connector->base, connector->colorspace_property, 0); } + +static const struct drm_prop_enum_list privacy_screen_enum[] = { + { PRIVACY_SCREEN_DISABLED, "Disabled" }, + { PRIVACY_SCREEN_ENABLED, "Enabled" }, +}; + +/** + * intel_attach_privacy_screen_property - + * create and attach the connecter's privacy-screen property. * + * @connector: connector for which to init the privacy-screen property + * + * This function creates and attaches the "privacy-screen" property to the + * connector. Initial state of privacy-screen is set to disabled. + */ +void +intel_attach_privacy_screen_property(struct drm_connector *connector) +{ + struct intel_connector *intel_connector = to_intel_connector(connector); + struct drm_property *prop; + + if (!intel_connector->privacy_screen_property) { + prop = drm_property_create_enum(connector->dev, + DRM_MODE_PROP_ENUM, + "privacy-screen", + privacy_screen_enum, + ARRAY_SIZE(privacy_screen_enum)); + if (!prop) + return; + + intel_connector->privacy_screen_property = prop; + } + + drm_object_attach_property(&connector->base, prop, + PRIVACY_SCREEN_DISABLED); +} diff --git a/drivers/gpu/drm/i915/display/intel_connector.h b/drivers/gpu/drm/i915/display/intel_connector.h index 93a7375c8196..61005f37a338 100644 --- a/drivers/gpu/drm/i915/display/intel_connector.h +++ b/drivers/gpu/drm/i915/display/intel_connector.h @@ -31,5 +31,6 @@ void intel_attach_force_audio_property(struct drm_connector *connector); void intel_attach_broadcast_rgb_property(struct drm_connector *connector); void intel_attach_aspect_ratio_property(struct drm_connector *connector); void intel_attach_colorspace_property(struct drm_connector *connector); +void intel_attach_privacy_screen_property(struct drm_connector *connector); #endif /* __INTEL_CONNECTOR_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index c2706afc069b..83b8c98049a7 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -426,6 +426,9 @@ struct intel_connector { struct work_struct modeset_retry_work; struct intel_hdcp hdcp; + + /* Optional "privacy-screen" property for the connector panel */ + struct drm_property *privacy_screen_property; }; struct intel_digital_connector_state { @@ -433,6 +436,7 @@ struct intel_digital_connector_state { enum hdmi_force_audio force_audio; int broadcast_rgb; + enum intel_privacy_screen_status privacy_screen_status; }; #define to_intel_digital_connector_state(x) container_of(x, struct intel_digital_connector_state, base) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 4fac408a4299..1963e92404ba 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -62,6 +62,7 @@ #include "intel_lspcon.h" #include "intel_lvds.h" #include "intel_panel.h" +#include "intel_privacy_screen.h" #include "intel_psr.h" #include "intel_sideband.h" #include "intel_tc.h" @@ -6358,6 +6359,10 @@ intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connect /* Lookup the ACPI node corresponding to the connector */ intel_connector_lookup_acpi_node(intel_connector); + + /* Check for integrated Privacy screen support */ + if (intel_privacy_screen_present(intel_connector)) + intel_attach_privacy_screen_property(connector); } } diff --git a/drivers/gpu/drm/i915/display/intel_privacy_screen.c b/drivers/gpu/drm/i915/display/intel_privacy_screen.c new file mode 100644 index 000000000000..4c422e38c51a --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_privacy_screen.c @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Intel ACPI privacy screen code + * + * Copyright © 2019 Google Inc. + */ + +#include + +#include "intel_privacy_screen.h" + +#define CONNECTOR_DSM_REVID 1 + +#define CONNECTOR_DSM_FN_PRIVACY_ENABLE 2 +#define CONNECTOR_DSM_FN_PRIVACY_DISABLE 3 + +static const guid_t drm_conn_dsm_guid = + GUID_INIT(0xC7033113, 0x8720, 0x4CEB, + 0x90, 0x90, 0x9D, 0x52, 0xB3, 0xE5, 0x2D, 0x73); + +/* Makes _DSM call to set privacy screen status */ +static void acpi_privacy_screen_call_dsm(acpi_handle conn_handle, u64 func) +{ + union acpi_object *obj; + + obj = acpi_evaluate_dsm(conn_handle, &drm_conn_dsm_guid, + CONNECTOR_DSM_REVID, func, NULL); + if (!obj) { + DRM_DEBUG_DRIVER("failed to evaluate _DSM for fn %llx\n", func); + return; + } + + ACPI_FREE(obj); +} + +void intel_privacy_screen_set_val(struct intel_connector *intel_connector, + enum intel_privacy_screen_status val) +{ + acpi_handle acpi_handle = intel_connector->acpi_handle; + + if (!acpi_handle) + return; + + if (val == PRIVACY_SCREEN_DISABLED) + acpi_privacy_screen_call_dsm(acpi_handle, + CONNECTOR_DSM_FN_PRIVACY_DISABLE); + else if (val == PRIVACY_SCREEN_ENABLED) + acpi_privacy_screen_call_dsm(acpi_handle, + CONNECTOR_DSM_FN_PRIVACY_ENABLE); +} + +bool intel_privacy_screen_present(struct intel_connector *intel_connector) +{ + acpi_handle handle = intel_connector->acpi_handle; + + if (!handle) + return false; + + if (!acpi_check_dsm(handle, &drm_conn_dsm_guid, + CONNECTOR_DSM_REVID, + 1 << CONNECTOR_DSM_FN_PRIVACY_ENABLE | + 1 << CONNECTOR_DSM_FN_PRIVACY_DISABLE)) { + DRM_WARN("%s: Odd, connector ACPI node but no privacy scrn?\n", + dev_name(intel_connector->base.dev->dev)); + return false; + } + DRM_DEV_INFO(intel_connector->base.dev->dev, + "supports privacy screen\n"); + return true; +} diff --git a/drivers/gpu/drm/i915/display/intel_privacy_screen.h b/drivers/gpu/drm/i915/display/intel_privacy_screen.h new file mode 100644 index 000000000000..212f73349a00 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_privacy_screen.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright © 2019 Google Inc. + */ + +#ifndef __DRM_PRIVACY_SCREEN_H__ +#define __DRM_PRIVACY_SCREEN_H__ + +#include "intel_display_types.h" + +#ifdef CONFIG_ACPI +bool intel_privacy_screen_present(struct intel_connector *intel_connector); +void intel_privacy_screen_set_val(struct intel_connector *intel_connector, + enum intel_privacy_screen_status val); +#else +bool intel_privacy_screen_present(struct intel_connector *intel_connector); +{ + return false; +} +void intel_privacy_screen_set_val(struct intel_connector *intel_connector, + enum intel_privacy_screen_status val) +{ } +#endif /* CONFIG_ACPI */ + +#endif /* __DRM_PRIVACY_SCREEN_H__ */ diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h index 469dc512cca3..cf08d5636363 100644 --- a/include/uapi/drm/i915_drm.h +++ b/include/uapi/drm/i915_drm.h @@ -2123,6 +2123,20 @@ struct drm_i915_query_engine_info { struct drm_i915_engine_info engines[]; }; +/** + * enum intel_privacy_screen_status - privacy_screen status + * + * This enum is used to track and control the state of the integrated privacy + * screen present on some display panels, via the "privacy-screen" property. + * + * @PRIVACY_SCREEN_DISABLED: The privacy-screen on the panel is disabled + * @PRIVACY_SCREEN_ENABLED: The privacy-screen on the panel is enabled + **/ +enum intel_privacy_screen_status { + PRIVACY_SCREEN_DISABLED = 0, + PRIVACY_SCREEN_ENABLED = 1, +}; + #if defined(__cplusplus) } #endif