2019-10-23 00:31:12

by Rajat Jain

[permalink] [raw]
Subject: [PATCH] drm: Add support for integrated privacy screens

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 <[email protected]>
---
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 <drm/drm_atomic.h>
#include <drm/drm_print.h>
#include <drm/drm_drv.h>
+#include <drm/drm_privacy_screen.h>
#include <drm/drm_writeback.h>
#include <drm/drm_vblank.h>

@@ -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 <linux/acpi.h>
+#include <linux/pci.h>
+
+#include <drm/drm_connector.h>
+#include <drm/drm_device.h>
+#include <drm/drm_print.h>
+
+#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 <drm/drm_dp_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_hdcp.h>
+#include <drm/drm_privacy_screen.h>
#include <drm/drm_probe_helper.h>
#include <drm/i915_drm.h>

@@ -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__ */
--
2.23.0.866.gb869b98d4c-goog


2019-10-23 12:38:13

by Daniel Vetter

[permalink] [raw]
Subject: Re: [PATCH] drm: Add support for integrated privacy screens

On Tue, Oct 22, 2019 at 05:12:06PM -0700, Rajat Jain wrote:
> 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 <[email protected]>

New properties need property docs in the relevant section:

https://dri.freedesktop.org/docs/drm/gpu/drm-kms.html#kms-properties

$ make htmldocs

for building them locally.

Cheers, Daniel

> ---
> 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 <drm/drm_atomic.h>
> #include <drm/drm_print.h>
> #include <drm/drm_drv.h>
> +#include <drm/drm_privacy_screen.h>
> #include <drm/drm_writeback.h>
> #include <drm/drm_vblank.h>
>
> @@ -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 <linux/acpi.h>
> +#include <linux/pci.h>
> +
> +#include <drm/drm_connector.h>
> +#include <drm/drm_device.h>
> +#include <drm/drm_print.h>
> +
> +#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 <drm/drm_dp_helper.h>
> #include <drm/drm_edid.h>
> #include <drm/drm_hdcp.h>
> +#include <drm/drm_privacy_screen.h>
> #include <drm/drm_probe_helper.h>
> #include <drm/i915_drm.h>
>
> @@ -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__ */
> --
> 2.23.0.866.gb869b98d4c-goog
>

--
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

2019-10-25 09:50:04

by Pavel Machek

[permalink] [raw]
Subject: Re: [PATCH] drm: Add support for integrated privacy screens

On Tue 2019-10-22 17:12:06, Rajat Jain wrote:
> 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:

Much better than separate /sys interface, thanks!
Pavel

--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany


Attachments:
(No filename) (576.00 B)
signature.asc (188.00 B)
Digital signature
Download all attachments

2019-10-25 09:51:23

by Thierry Reding

[permalink] [raw]
Subject: Re: [PATCH] drm: Add support for integrated privacy screens

On Tue, Oct 22, 2019 at 05:12:06PM -0700, Rajat Jain wrote:
> 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 <[email protected]>
> ---
> 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

I like this much better than the prior proposal to use sysfs. However
the support currently looks a bit tangled. I realize that we only have a
single implementation for this in hardware right now, so there's no use
in over-engineering things, but I think we can do a better job from the
start without getting into too many abstractions. See below.

> 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 <drm/drm_atomic.h>
> #include <drm/drm_print.h>
> #include <drm/drm_drv.h>
> +#include <drm/drm_privacy_screen.h>
> #include <drm/drm_writeback.h>
> #include <drm/drm_vblank.h>
>
> @@ -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);

This doesn't look right. Shouldn't you store the value in the connector
state and then leave it up to the connector driver to set it
appropriately? I think that also has the advantage of untangling this
support a little.

> } 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);

Similarly, I think this can just return the atomic state's value for
this.

> } 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,

Seems to me like the -screen suffix here is somewhat redundant. Yes, the
thing that we enable/disable may be called a "privacy screen", but the
property that we enable/disable on the connector is the "privacy" of the
user. I'd reflect that in all the related variable names and so on as
well.

> + 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 <linux/acpi.h>
> +#include <linux/pci.h>
> +
> +#include <drm/drm_connector.h>
> +#include <drm/drm_device.h>
> +#include <drm/drm_print.h>
> +
> +#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)

This is the main part that I think is a little tangled. This is a very
specific implementation that hides in a generic API.

I we store the privacy setting in the atomic state, there isn't really a
reason to store the privacy handle in the connector. Instead it could be
simply stored in the driver that supports this.

Ideally I think we'd have a very small drm_privacy_screen object type
that would just wrap this, but perhaps we don't need that right away,
given that we only have a single implementation so far.

However, I think if we just pushed this specific implementation into the
drivers that'd help pave the way for something more generic later on
without a lot of extra work up front.

For example you could turn the drm_connector_attach_acpi_node() into a
helper that simply returns the ACPI handle, something like this perhaps:

struct acpi_handle *drm_acpi_find_privacy_screen(struct drm_connector *connector,
unsigned int port)
{
...
}

That the i915 driver would then call and store the returned value
internally. When it commits the atomic state for the connector it can
then call the drm_acpi_set_privacy() (I think that'd be a better name
for your drm_privacy_screen_set_val()) by passing that handle and the
value from the atomic state.

The above has the advantage that we don't clutter the generic core with
something that's not at all generic. If eventually we see that these
types of privacy screens are implemented in more device we can always
refactor this into something really generic and maybe even decide to put
it into the drm_connector directly.

> +{
> + 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 <drm/drm_dp_helper.h>
> #include <drm/drm_edid.h>
> #include <drm/drm_hdcp.h>
> +#include <drm/drm_privacy_screen.h>
> #include <drm/drm_probe_helper.h>
> #include <drm/i915_drm.h>
>
> @@ -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,
> +};
> +

Shouldn't this go into include/uapi/drm/drm_mode.h? That would have the
advantage of giving userspace symbolic names to use when setting the
property.

Maybe also rename these to something like:

#define DRM_MODE_PRIVACY_DISABLED 0
#define DRM_MODE_PRIVACY_ENABLED 1

for consistency with other properties.

Thierry

> /**
> * 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__ */
> --
> 2.23.0.866.gb869b98d4c-goog
>


Attachments:
(No filename) (19.57 kB)
signature.asc (849.00 B)
Download all attachments

2019-10-25 18:53:54

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH] drm: Add support for integrated privacy screens

Hi Rajat,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on linus/master]
[cannot apply to v5.4-rc4 next-20191024]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]

url: https://github.com/0day-ci/linux/commits/Rajat-Jain/drm-Add-support-for-integrated-privacy-screens/20191025-020550
base: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git f116b96685a046a89c25d4a6ba2da489145c8888
config: i386-defconfig (attached as .config)
compiler: gcc-7 (Debian 7.4.0-14) 7.4.0
reproduce:
# save the attached .config to linux build tree
make ARCH=i386

If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <[email protected]>

All warnings (new ones prefixed by >>):

In file included from include/linux/printk.h:7:0,
from include/linux/kernel.h:15,
from include/linux/list.h:9,
from include/linux/kobject.h:19,
from include/linux/of.h:17,
from include/linux/irqdomain.h:35,
from include/linux/acpi.h:13,
from drivers/gpu//drm/drm_privacy_screen.c:8:
drivers/gpu//drm/drm_privacy_screen.c: In function 'drm_privacy_screen_present':
>> include/linux/kern_levels.h:5:18: warning: format '%s' expects argument of type 'char *', but argument 2 has type 'struct device *' [-Wformat=]
#define KERN_SOH "\001" /* ASCII Start Of Header */
^
include/linux/kern_levels.h:12:22: note: in expansion of macro 'KERN_SOH'
#define KERN_WARNING KERN_SOH "4" /* warning conditions */
^~~~~~~~
>> include/drm/drm_print.h:290:15: note: in expansion of macro 'KERN_WARNING'
printk##once(KERN_##level "[" DRM_NAME "] " fmt, ##__VA_ARGS__)
^~~~~
include/drm/drm_print.h:297:2: note: in expansion of macro '_DRM_PRINTK'
_DRM_PRINTK(, WARNING, fmt, ##__VA_ARGS__)
^~~~~~~~~~~
>> drivers/gpu//drm/drm_privacy_screen.c:170:3: note: in expansion of macro 'DRM_WARN'
DRM_WARN("%s: Odd, connector ACPI node but no privacy scrn?\n",
^~~~~~~~
drivers/gpu//drm/drm_privacy_screen.c:170:14: note: format string is defined here
DRM_WARN("%s: Odd, connector ACPI node but no privacy scrn?\n",
~^
--
In file included from include/linux/printk.h:7:0,
from include/linux/kernel.h:15,
from include/linux/list.h:9,
from include/linux/kobject.h:19,
from include/linux/of.h:17,
from include/linux/irqdomain.h:35,
from include/linux/acpi.h:13,
from drivers/gpu/drm/drm_privacy_screen.c:8:
drivers/gpu/drm/drm_privacy_screen.c: In function 'drm_privacy_screen_present':
>> include/linux/kern_levels.h:5:18: warning: format '%s' expects argument of type 'char *', but argument 2 has type 'struct device *' [-Wformat=]
#define KERN_SOH "\001" /* ASCII Start Of Header */
^
include/linux/kern_levels.h:12:22: note: in expansion of macro 'KERN_SOH'
#define KERN_WARNING KERN_SOH "4" /* warning conditions */
^~~~~~~~
>> include/drm/drm_print.h:290:15: note: in expansion of macro 'KERN_WARNING'
printk##once(KERN_##level "[" DRM_NAME "] " fmt, ##__VA_ARGS__)
^~~~~
include/drm/drm_print.h:297:2: note: in expansion of macro '_DRM_PRINTK'
_DRM_PRINTK(, WARNING, fmt, ##__VA_ARGS__)
^~~~~~~~~~~
drivers/gpu/drm/drm_privacy_screen.c:170:3: note: in expansion of macro 'DRM_WARN'
DRM_WARN("%s: Odd, connector ACPI node but no privacy scrn?\n",
^~~~~~~~
drivers/gpu/drm/drm_privacy_screen.c:170:14: note: format string is defined here
DRM_WARN("%s: Odd, connector ACPI node but no privacy scrn?\n",
~^

vim +/KERN_WARNING +290 include/drm/drm_print.h

02c9656b2f0d69 Haneen Mohammed 2017-10-17 288
02c9656b2f0d69 Haneen Mohammed 2017-10-17 289 #define _DRM_PRINTK(once, level, fmt, ...) \
db87086492581c Joe Perches 2018-03-16 @290 printk##once(KERN_##level "[" DRM_NAME "] " fmt, ##__VA_ARGS__)
02c9656b2f0d69 Haneen Mohammed 2017-10-17 291

:::::: The code at line 290 was first introduced by commit
:::::: db87086492581c87f768b7d17d01308153ecffc1 drm: Reduce object size of DRM_DEV_<LEVEL> uses

:::::: TO: Joe Perches <[email protected]>
:::::: CC: Daniel Vetter <[email protected]>

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation


Attachments:
(No filename) (4.82 kB)
.config.gz (27.49 kB)
Download all attachments

2019-10-25 18:59:50

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH] drm: Add support for integrated privacy screens

Hi Rajat,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on linus/master]
[cannot apply to v5.4-rc4 next-20191024]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]

url: https://github.com/0day-ci/linux/commits/Rajat-Jain/drm-Add-support-for-integrated-privacy-screens/20191025-020550
base: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git f116b96685a046a89c25d4a6ba2da489145c8888
reproduce: make htmldocs

If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <[email protected]>

All warnings (new ones prefixed by >>):

include/linux/input/sparse-keymap.h:43: warning: Function parameter or member 'sw' not described in 'key_entry'
include/linux/skbuff.h:888: warning: Function parameter or member 'dev_scratch' not described in 'sk_buff'
include/linux/skbuff.h:888: warning: Function parameter or member 'list' not described in 'sk_buff'
include/linux/skbuff.h:888: warning: Function parameter or member 'ip_defrag_offset' not described in 'sk_buff'
include/linux/skbuff.h:888: warning: Function parameter or member 'skb_mstamp_ns' not described in 'sk_buff'
include/linux/skbuff.h:888: warning: Function parameter or member '__cloned_offset' not described in 'sk_buff'
include/linux/skbuff.h:888: warning: Function parameter or member 'head_frag' not described in 'sk_buff'
include/linux/skbuff.h:888: warning: Function parameter or member '__pkt_type_offset' not described in 'sk_buff'
include/linux/skbuff.h:888: warning: Function parameter or member 'encapsulation' not described in 'sk_buff'
include/linux/skbuff.h:888: warning: Function parameter or member 'encap_hdr_csum' not described in 'sk_buff'
include/linux/skbuff.h:888: warning: Function parameter or member 'csum_valid' not described in 'sk_buff'
include/linux/skbuff.h:888: warning: Function parameter or member '__pkt_vlan_present_offset' not described in 'sk_buff'
include/linux/skbuff.h:888: warning: Function parameter or member 'vlan_present' not described in 'sk_buff'
include/linux/skbuff.h:888: warning: Function parameter or member 'csum_complete_sw' not described in 'sk_buff'
include/linux/skbuff.h:888: warning: Function parameter or member 'csum_level' not described in 'sk_buff'
include/linux/skbuff.h:888: warning: Function parameter or member 'inner_protocol_type' not described in 'sk_buff'
include/linux/skbuff.h:888: warning: Function parameter or member 'remcsum_offload' not described in 'sk_buff'
include/linux/skbuff.h:888: warning: Function parameter or member 'sender_cpu' not described in 'sk_buff'
include/linux/skbuff.h:888: warning: Function parameter or member 'reserved_tailroom' not described in 'sk_buff'
include/linux/skbuff.h:888: warning: Function parameter or member 'inner_ipproto' not described in 'sk_buff'
include/net/sock.h:233: warning: Function parameter or member 'skc_addrpair' not described in 'sock_common'
include/net/sock.h:233: warning: Function parameter or member 'skc_portpair' not described in 'sock_common'
include/net/sock.h:233: warning: Function parameter or member 'skc_ipv6only' not described in 'sock_common'
include/net/sock.h:233: warning: Function parameter or member 'skc_net_refcnt' not described in 'sock_common'
include/net/sock.h:233: warning: Function parameter or member 'skc_v6_daddr' not described in 'sock_common'
include/net/sock.h:233: warning: Function parameter or member 'skc_v6_rcv_saddr' not described in 'sock_common'
include/net/sock.h:233: warning: Function parameter or member 'skc_cookie' not described in 'sock_common'
include/net/sock.h:233: warning: Function parameter or member 'skc_listener' not described in 'sock_common'
include/net/sock.h:233: warning: Function parameter or member 'skc_tw_dr' not described in 'sock_common'
include/net/sock.h:233: warning: Function parameter or member 'skc_rcv_wnd' not described in 'sock_common'
include/net/sock.h:233: warning: Function parameter or member 'skc_tw_rcv_nxt' not described in 'sock_common'
include/net/sock.h:515: warning: Function parameter or member 'sk_rx_skb_cache' not described in 'sock'
include/net/sock.h:515: warning: Function parameter or member 'sk_wq_raw' not described in 'sock'
include/net/sock.h:515: warning: Function parameter or member 'tcp_rtx_queue' not described in 'sock'
include/net/sock.h:515: warning: Function parameter or member 'sk_tx_skb_cache' not described in 'sock'
include/net/sock.h:515: warning: Function parameter or member 'sk_route_forced_caps' not described in 'sock'
include/net/sock.h:515: warning: Function parameter or member 'sk_txtime_report_errors' not described in 'sock'
include/net/sock.h:515: warning: Function parameter or member 'sk_validate_xmit_skb' not described in 'sock'
include/net/sock.h:515: warning: Function parameter or member 'sk_bpf_storage' not described in 'sock'
include/net/sock.h:2450: warning: Function parameter or member 'tcp_rx_skb_cache_key' not described in 'DECLARE_STATIC_KEY_FALSE'
include/net/sock.h:2450: warning: Excess function parameter 'sk' description in 'DECLARE_STATIC_KEY_FALSE'
include/net/sock.h:2450: warning: Excess function parameter 'skb' description in 'DECLARE_STATIC_KEY_FALSE'
include/linux/netdevice.h:2053: warning: Function parameter or member 'gso_partial_features' not described in 'net_device'
include/linux/netdevice.h:2053: warning: Function parameter or member 'l3mdev_ops' not described in 'net_device'
include/linux/netdevice.h:2053: warning: Function parameter or member 'xfrmdev_ops' not described in 'net_device'
include/linux/netdevice.h:2053: warning: Function parameter or member 'tlsdev_ops' not described in 'net_device'
include/linux/netdevice.h:2053: warning: Function parameter or member 'name_assign_type' not described in 'net_device'
include/linux/netdevice.h:2053: warning: Function parameter or member 'ieee802154_ptr' not described in 'net_device'
include/linux/netdevice.h:2053: warning: Function parameter or member 'mpls_ptr' not described in 'net_device'
include/linux/netdevice.h:2053: warning: Function parameter or member 'xdp_prog' not described in 'net_device'
include/linux/netdevice.h:2053: warning: Function parameter or member 'gro_flush_timeout' not described in 'net_device'
include/linux/netdevice.h:2053: warning: Function parameter or member 'nf_hooks_ingress' not described in 'net_device'
include/linux/netdevice.h:2053: warning: Function parameter or member '____cacheline_aligned_in_smp' not described in 'net_device'
include/linux/netdevice.h:2053: warning: Function parameter or member 'qdisc_hash' not described in 'net_device'
include/linux/netdevice.h:2053: warning: Function parameter or member 'xps_cpus_map' not described in 'net_device'
include/linux/netdevice.h:2053: warning: Function parameter or member 'xps_rxqs_map' not described in 'net_device'
include/linux/phylink.h:56: warning: Function parameter or member '__ETHTOOL_DECLARE_LINK_MODE_MASK(advertising' not described in 'phylink_link_state'
include/linux/phylink.h:56: warning: Function parameter or member '__ETHTOOL_DECLARE_LINK_MODE_MASK(lp_advertising' not described in 'phylink_link_state'
include/linux/rculist.h:374: warning: Excess function parameter 'cond' description in 'list_for_each_entry_rcu'
include/linux/rculist.h:651: warning: Excess function parameter 'cond' description in 'hlist_for_each_entry_rcu'
mm/util.c:1: warning: 'get_user_pages_fast' not found
drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c:335: warning: Excess function parameter 'dev' description in 'amdgpu_gem_prime_export'
drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c:336: warning: Excess function parameter 'dev' description in 'amdgpu_gem_prime_export'
drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c:142: warning: Function parameter or member 'blockable' not described in 'amdgpu_mn_read_lock'
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:347: warning: cannot understand function prototype: 'struct amdgpu_vm_pt_cursor '
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:348: warning: cannot understand function prototype: 'struct amdgpu_vm_pt_cursor '
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:494: warning: Function parameter or member 'start' not described in 'amdgpu_vm_pt_first_dfs'
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:546: warning: Function parameter or member 'adev' not described in 'for_each_amdgpu_vm_pt_dfs_safe'
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:546: warning: Function parameter or member 'vm' not described in 'for_each_amdgpu_vm_pt_dfs_safe'
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:546: warning: Function parameter or member 'start' not described in 'for_each_amdgpu_vm_pt_dfs_safe'
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:546: warning: Function parameter or member 'cursor' not described in 'for_each_amdgpu_vm_pt_dfs_safe'
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:546: warning: Function parameter or member 'entry' not described in 'for_each_amdgpu_vm_pt_dfs_safe'
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:821: warning: Function parameter or member 'level' not described in 'amdgpu_vm_bo_param'
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1283: warning: Function parameter or member 'params' not described in 'amdgpu_vm_update_flags'
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1283: warning: Function parameter or member 'bo' not described in 'amdgpu_vm_update_flags'
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1283: warning: Function parameter or member 'level' not described in 'amdgpu_vm_update_flags'
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1283: warning: Function parameter or member 'pe' not described in 'amdgpu_vm_update_flags'
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1283: warning: Function parameter or member 'addr' not described in 'amdgpu_vm_update_flags'
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1283: warning: Function parameter or member 'count' not described in 'amdgpu_vm_update_flags'
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1283: warning: Function parameter or member 'incr' not described in 'amdgpu_vm_update_flags'
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1283: warning: Function parameter or member 'flags' not described in 'amdgpu_vm_update_flags'
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:2821: warning: Function parameter or member 'pasid' not described in 'amdgpu_vm_make_compute'
drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c:378: warning: Excess function parameter 'entry' description in 'amdgpu_irq_dispatch'
drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c:379: warning: Function parameter or member 'ih' not described in 'amdgpu_irq_dispatch'
drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c:379: warning: Excess function parameter 'entry' description in 'amdgpu_irq_dispatch'
drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c:1: warning: no structured comments found
drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c:1: warning: no structured comments found
drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c:1: warning: 'pp_dpm_sclk pp_dpm_mclk pp_dpm_pcie' not found
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:132: warning: Incorrect use of kernel-doc format: * @atomic_obj
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:238: warning: Incorrect use of kernel-doc format: * gpu_info FW provided soc bounding box struct or 0 if not
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:243: warning: Function parameter or member 'atomic_obj' not described in 'amdgpu_display_manager'
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:243: warning: Function parameter or member 'backlight_link' not described in 'amdgpu_display_manager'
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:243: warning: Function parameter or member 'backlight_caps' not described in 'amdgpu_display_manager'
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:243: warning: Function parameter or member 'freesync_module' not described in 'amdgpu_display_manager'
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:243: warning: Function parameter or member 'fw_dmcu' not described in 'amdgpu_display_manager'
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:243: warning: Function parameter or member 'dmcu_fw_version' not described in 'amdgpu_display_manager'
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:243: warning: Function parameter or member 'soc_bounding_box' not described in 'amdgpu_display_manager'
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c:1: warning: 'dm_crtc_high_irq' not found
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c:1: warning: 'register_hpd_handlers' not found
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c:1: warning: 'dm_pflip_high_irq' not found
>> include/drm/drm_connector.h:1431: warning: Function parameter or member 'privacy_screen_handle' not described in 'drm_connector'
include/drm/drm_modeset_helper_vtables.h:1053: warning: Function parameter or member 'prepare_writeback_job' not described in 'drm_connector_helper_funcs'
include/drm/drm_modeset_helper_vtables.h:1053: warning: Function parameter or member 'cleanup_writeback_job' not described in 'drm_connector_helper_funcs'
include/drm/drm_atomic_state_helper.h:1: warning: no structured comments found
include/drm/drm_gem_shmem_helper.h:87: warning: Function parameter or member 'madv' not described in 'drm_gem_shmem_object'
include/drm/drm_gem_shmem_helper.h:87: warning: Function parameter or member 'madv_list' not described in 'drm_gem_shmem_object'
drivers/gpu/drm/i915/display/intel_dpll_mgr.h:158: warning: Enum value 'DPLL_ID_TGL_MGPLL5' not described in enum 'intel_dpll_id'
drivers/gpu/drm/i915/display/intel_dpll_mgr.h:158: warning: Enum value 'DPLL_ID_TGL_MGPLL6' not described in enum 'intel_dpll_id'
drivers/gpu/drm/i915/display/intel_dpll_mgr.h:158: warning: Excess enum value 'DPLL_ID_TGL_TCPLL6' description in 'intel_dpll_id'
drivers/gpu/drm/i915/display/intel_dpll_mgr.h:158: warning: Excess enum value 'DPLL_ID_TGL_TCPLL5' description in 'intel_dpll_id'
drivers/gpu/drm/i915/display/intel_dpll_mgr.h:342: warning: Function parameter or member 'wakeref' not described in 'intel_shared_dpll'
Error: Cannot open file drivers/gpu/drm/i915/i915_gem_batch_pool.c
Error: Cannot open file drivers/gpu/drm/i915/i915_gem_batch_pool.c
Error: Cannot open file drivers/gpu/drm/i915/i915_gem_batch_pool.c
drivers/gpu/drm/i915/i915_drv.h:1129: warning: Incorrect use of kernel-doc format: * The OA context specific information.
drivers/gpu/drm/i915/i915_drv.h:1143: warning: Incorrect use of kernel-doc format: * State of the OA buffer.
drivers/gpu/drm/i915/i915_drv.h:1154: warning: Incorrect use of kernel-doc format: * Locks reads and writes to all head/tail state
drivers/gpu/drm/i915/i915_drv.h:1176: warning: Incorrect use of kernel-doc format: * One 'aging' tail pointer and one 'aged' tail pointer ready to
drivers/gpu/drm/i915/i915_drv.h:1188: warning: Incorrect use of kernel-doc format: * Index for the aged tail ready to read() data up to.
drivers/gpu/drm/i915/i915_drv.h:1193: warning: Incorrect use of kernel-doc format: * A monotonic timestamp for when the current aging tail pointer
drivers/gpu/drm/i915/i915_drv.h:1199: warning: Incorrect use of kernel-doc format: * Although we can always read back the head pointer register,
drivers/gpu/drm/i915/i915_drv.h:1207: warning: Function parameter or member 'pinned_ctx' not described in 'i915_perf_stream'
drivers/gpu/drm/i915/i915_drv.h:1207: warning: Function parameter or member 'specific_ctx_id' not described in 'i915_perf_stream'
drivers/gpu/drm/i915/i915_drv.h:1207: warning: Function parameter or member 'specific_ctx_id_mask' not described in 'i915_perf_stream'
drivers/gpu/drm/i915/i915_drv.h:1207: warning: Function parameter or member 'poll_check_timer' not described in 'i915_perf_stream'
drivers/gpu/drm/i915/i915_drv.h:1207: warning: Function parameter or member 'poll_wq' not described in 'i915_perf_stream'
drivers/gpu/drm/i915/i915_drv.h:1207: warning: Function parameter or member 'pollin' not described in 'i915_perf_stream'
drivers/gpu/drm/i915/i915_drv.h:1207: warning: Function parameter or member 'periodic' not described in 'i915_perf_stream'
drivers/gpu/drm/i915/i915_drv.h:1207: warning: Function parameter or member 'period_exponent' not described in 'i915_perf_stream'
drivers/gpu/drm/i915/i915_drv.h:1207: warning: Function parameter or member 'oa_buffer' not described in 'i915_perf_stream'
drivers/gpu/drm/i915/i915_drv.h:1129: warning: Incorrect use of kernel-doc format: * The OA context specific information.
drivers/gpu/drm/i915/i915_drv.h:1143: warning: Incorrect use of kernel-doc format: * State of the OA buffer.
drivers/gpu/drm/i915/i915_drv.h:1154: warning: Incorrect use of kernel-doc format: * Locks reads and writes to all head/tail state
drivers/gpu/drm/i915/i915_drv.h:1176: warning: Incorrect use of kernel-doc format: * One 'aging' tail pointer and one 'aged' tail pointer ready to
drivers/gpu/drm/i915/i915_drv.h:1188: warning: Incorrect use of kernel-doc format: * Index for the aged tail ready to read() data up to.
drivers/gpu/drm/i915/i915_drv.h:1193: warning: Incorrect use of kernel-doc format: * A monotonic timestamp for when the current aging tail pointer
drivers/gpu/drm/i915/i915_drv.h:1199: warning: Incorrect use of kernel-doc format: * Although we can always read back the head pointer register,
drivers/gpu/drm/i915/i915_drv.h:1129: warning: Incorrect use of kernel-doc format: * The OA context specific information.
drivers/gpu/drm/i915/i915_drv.h:1143: warning: Incorrect use of kernel-doc format: * State of the OA buffer.
drivers/gpu/drm/i915/i915_drv.h:1154: warning: Incorrect use of kernel-doc format: * Locks reads and writes to all head/tail state
drivers/gpu/drm/i915/i915_drv.h:1176: warning: Incorrect use of kernel-doc format: * One 'aging' tail pointer and one 'aged' tail pointer ready to
drivers/gpu/drm/i915/i915_drv.h:1188: warning: Incorrect use of kernel-doc format: * Index for the aged tail ready to read() data up to.
drivers/gpu/drm/i915/i915_drv.h:1193: warning: Incorrect use of kernel-doc format: * A monotonic timestamp for when the current aging tail pointer
drivers/gpu/drm/i915/i915_drv.h:1199: warning: Incorrect use of kernel-doc format: * Although we can always read back the head pointer register,
drivers/gpu/drm/mcde/mcde_drv.c:1: warning: 'ST-Ericsson MCDE DRM Driver' not found
include/net/cfg80211.h:1185: warning: Function parameter or member 'txpwr' not described in 'station_parameters'
include/net/mac80211.h:4056: warning: Function parameter or member 'sta_set_txpwr' not described in 'ieee80211_ops'
include/net/mac80211.h:2018: warning: Function parameter or member 'txpwr' not described in 'ieee80211_sta'
Documentation/admin-guide/perf/imx-ddr.rst:21: WARNING: Unexpected indentation.
Documentation/admin-guide/perf/imx-ddr.rst:34: WARNING: Unexpected indentation.
Documentation/admin-guide/perf/imx-ddr.rst:40: WARNING: Unexpected indentation.
Documentation/admin-guide/perf/imx-ddr.rst:45: WARNING: Unexpected indentation.
Documentation/admin-guide/perf/imx-ddr.rst:52: WARNING: Unexpected indentation.
Documentation/admin-guide/xfs.rst:257: WARNING: Block quote ends without a blank line; unexpected unindent.
include/uapi/linux/firewire-cdev.h:312: WARNING: Inline literal start-string without end-string.
drivers/firewire/core-transaction.c:606: WARNING: Inline strong start-string without end-string.
Documentation/usb/index.rst:5: WARNING: toctree contains reference to nonexisting document 'usb/rio'
Documentation/usb/index.rst:5: WARNING: toctree contains reference to nonexisting document 'usb/wusb-design-overview'
Documentation/usb/text_files.rst:22: WARNING: Include file 'Documentation/usb/wusb-cbaf' not found or reading it failed
WARNING: kernel-doc 'scripts/kernel-doc -rst -enable-lineno -function Reservation Object Overview drivers/dma-buf/reservation.c' failed with return code 1
WARNING: kernel-doc 'scripts/kernel-doc -rst -enable-lineno -export drivers/dma-buf/reservation.c' failed with return code 2
WARNING: kernel-doc 'scripts/kernel-doc -rst -enable-lineno -internal include/linux/reservation.h' failed with return code 2
include/linux/spi/spi.h:382: WARNING: Unexpected indentation.
drivers/message/fusion/mptbase.c:5057: WARNING: Definition list ends without a blank line; unexpected unindent.
Documentation/translations/it_IT/process/maintainer-pgp-guide.rst:458: WARNING: Unknown target name: "nitrokey pro".
Documentation/trace/kprobetrace.rst:100: WARNING: Explicit markup ends without a blank line; unexpected unindent.
include/linux/regulator/driver.h:284: WARNING: Unknown target name: "regulator_regmap_x_voltage".
Documentation/security/keys/core.rst:1110: WARNING: Inline emphasis start-string without end-string.
Documentation/security/keys/core.rst:1110: WARNING: Inline emphasis start-string without end-string.
Documentation/security/keys/core.rst:1108: WARNING: Inline emphasis start-string without end-string.
Documentation/security/keys/core.rst:1108: WARNING: Inline emphasis start-string without end-string.
Documentation/security/keys/core.rst:1108: WARNING: Inline emphasis start-string without end-string.
Documentation/filesystems/ubifs-authentication.rst:94: WARNING: Inline interpreted text or phrase reference start-string without end-string.
Documentation/driver-api/gpio/driver.rst:420: WARNING: Unexpected indentation.
Documentation/driver-api/gpio/driver.rst:418: WARNING: Inline emphasis start-string without end-string.
Documentation/driver-api/gpio/driver.rst:422: WARNING: Block quote ends without a blank line; unexpected unindent.
Documentation/driver-api/gpio/driver.rst:424: WARNING: Inline emphasis start-string without end-string.
Documentation/driver-api/gpio/driver.rst:424: WARNING: Inline emphasis start-string without end-string.
Documentation/driver-api/gpio/driver.rst:424: WARNING: Inline emphasis start-string without end-string.
Documentation/driver-api/gpio/driver.rst:428: WARNING: Inline emphasis start-string without end-string.
Documentation/driver-api/gpio/driver.rst:441: WARNING: Unexpected indentation.
Documentation/driver-api/gpio/driver.rst:435: WARNING: Inline emphasis start-string without end-string.
Documentation/driver-api/gpio/driver.rst:435: WARNING: Inline emphasis start-string without end-string.
Documentation/driver-api/gpio/driver.rst:442: WARNING: Block quote ends without a blank line; unexpected unindent.
Documentation/driver-api/gpio/driver.rst:444: WARNING: Definition list ends without a blank line; unexpected unindent.
Documentation/driver-api/gpio/driver.rst:455: WARNING: Unexpected indentation.
Documentation/driver-api/gpio/driver.rst:453: WARNING: Inline emphasis start-string without end-string.
Documentation/driver-api/gpio/driver.rst:455: WARNING: Inline emphasis start-string without end-string.
Documentation/driver-api/gpio/driver.rst:458: WARNING: Block quote ends without a blank line; unexpected unindent.
Documentation/driver-api/gpio/driver.rst:460: WARNING: Inline emphasis start-string without end-string.
Documentation/driver-api/gpio/driver.rst:460: WARNING: Inline emphasis start-string without end-string.
Documentation/driver-api/gpio/driver.rst:460: WARNING: Inline emphasis start-string without end-string.
Documentation/driver-api/gpio/driver.rst:464: WARNING: Inline emphasis start-string without end-string.
Documentation/driver-api/gpio/driver.rst:471: WARNING: Inline emphasis start-string without end-string.
include/linux/i2c.h:522: WARNING: Inline strong start-string without end-string.
Documentation/misc-devices/index.rst:14: WARNING: toctree contains reference to nonexisting document 'misc-devices/xilinx_sdfec'
fs/seq_file.c:40: WARNING: Inline strong start-string without end-string.
fs/seq_file.c:40: WARNING: Inline strong start-string without end-string.
fs/seq_file.c:40: WARNING: Inline strong start-string without end-string.
fs/seq_file.c:40: WARNING: Inline strong start-string without end-string.
fs/posix_acl.c:636: WARNING: Inline emphasis start-string without end-string.

vim +1431 include/drm/drm_connector.h

52217195176115 Daniel Vetter 2016-08-12 @1431

:::::: The code at line 1431 was first introduced by commit
:::::: 522171951761153172c75b94ae1f4bc9ab631745 drm: Extract drm_connector.[hc]

:::::: TO: Daniel Vetter <[email protected]>
:::::: CC: Daniel Vetter <[email protected]>

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation


Attachments:
(No filename) (25.01 kB)
.config.gz (7.11 kB)
Download all attachments

2019-10-25 19:07:34

by Rajat Jain

[permalink] [raw]
Subject: Re: [PATCH] drm: Add support for integrated privacy screens

Hi,

Thanks for your review and comments. Please see inline below.

On Thu, Oct 24, 2019 at 4:20 AM Thierry Reding <[email protected]> wrote:
>
> On Tue, Oct 22, 2019 at 05:12:06PM -0700, Rajat Jain wrote:
> > 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 <[email protected]>
> > ---
> > 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
>
> I like this much better than the prior proposal to use sysfs. However
> the support currently looks a bit tangled. I realize that we only have a
> single implementation for this in hardware right now, so there's no use
> in over-engineering things, but I think we can do a better job from the
> start without getting into too many abstractions. See below.
>
> > 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 <drm/drm_atomic.h>
> > #include <drm/drm_print.h>
> > #include <drm/drm_drv.h>
> > +#include <drm/drm_privacy_screen.h>
> > #include <drm/drm_writeback.h>
> > #include <drm/drm_vblank.h>
> >
> > @@ -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);
>
> This doesn't look right. Shouldn't you store the value in the connector
> state and then leave it up to the connector driver to set it
> appropriately? I think that also has the advantage of untangling this
> support a little.

Hopefully this gets answered in my explanations below.

>
> > } 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);
>
> Similarly, I think this can just return the atomic state's value for
> this.

I did think about having a state variable in software to get and set
this. However, I think it is not very far fetched that some platforms
may have "hardware kill" switches that allow hardware to switch
privacy-screen on and off directly, in addition to the software
control that we are implementing. Privacy is a touchy subject in
enterprise, and anything that reduces the possibility of having any
inconsistency between software state and hardware state is desirable.
So in this case, I chose to not have a state in software about this -
we just report the hardware state everytime we are asked for it.

>
> > } 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,
>
> Seems to me like the -screen suffix here is somewhat redundant. Yes, the
> thing that we enable/disable may be called a "privacy screen", but the
> property that we enable/disable on the connector is the "privacy" of the
> user. I'd reflect that in all the related variable names and so on as
> well.

IMHO a property called "privacy" may be a little generic for the users
to understand what it is. For e.g. when I started looking at code, I
found the "Content Protection" property and I got confused thinking
may be it provides something similar to what I'm trying to do. I think
"privacy-screen" conveys the complete context without being long, so
there is no confusion or ambiguity. But I don't mind changing it if a
property "privacy" is what people think is better to convey what it
is, as long as it is clear to user.

>
> > + 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 <linux/acpi.h>
> > +#include <linux/pci.h>
> > +
> > +#include <drm/drm_connector.h>
> > +#include <drm/drm_device.h>
> > +#include <drm/drm_print.h>
> > +
> > +#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)
>
> This is the main part that I think is a little tangled. This is a very
> specific implementation that hides in a generic API.

I agree that this is an ACPI specific implementation, but other than
that, I think it does not have any driver specific details. More
detailed thoughts on this below.

>
> I we store the privacy setting in the atomic state, there isn't really a
> reason to store the privacy handle in the connector. Instead it could be
> simply stored in the driver that supports this.
>
> Ideally I think we'd have a very small drm_privacy_screen object type
> that would just wrap this, but perhaps we don't need that right away,
> given that we only have a single implementation so far.

Yes, agreed.

>
> However, I think if we just pushed this specific implementation into the
> drivers that'd help pave the way for something more generic later on
> without a lot of extra work up front.
>
> For example you could turn the drm_connector_attach_acpi_node() into a
> helper that simply returns the ACPI handle, something like this perhaps:
>
> struct acpi_handle *drm_acpi_find_privacy_screen(struct drm_connector *connector,
> unsigned int port)
> {
> ...
> }

Yes, I like that idea of making it a helper function. In fact, finding
an ACPI node for the connector doesn't have to do anything with
privacy screen (so it can be used for other purposes also, in future).

>
> That the i915 driver would then call and store the returned value
> internally. When it commits the atomic state for the connector it can
> then call the drm_acpi_set_privacy() (I think that'd be a better name
> for your drm_privacy_screen_set_val()) by passing that handle and the
> value from the atomic state.
>
> The above has the advantage that we don't clutter the generic core with
> something that's not at all generic. If eventually we see that these
> types of privacy screens are implemented in more device we can always
> refactor this into something really generic and maybe even decide to put
> it into the drm_connector directly.

This is where I think I'm in slight disagreement. I think the
functionality we're adding is still "generic", just that the only
hardware *I have today* to test is using Intel eDP ports. But I don't
see why AMD CPU laptops can't have it (For E.g. HP's Elitebook 745 G5
seems to use AMD and has integrated privacy screen feature
http://www8.hp.com/h20195/V2/GetPDF.aspx/4aa7-2802eee) .
My worry is that if we don't make it generic today, we might see
duplicate / similar-but-different / different ways of this in other
places (e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=110ea1d833ad)
because unless it is generic to start with, it is difficult for some
one to change later for the fear of breaking hardware that is already
in market given that
* hardware may not be available to new developer to test for
regressions (also there is very little motivation to check any
hardware other than your own).
* specially for a code that relies on firmware ACPI (firmware
upgrades in field are always costly).

My understanding is that we're adding 2 functionalities here:

1) Identify and Attach ACPI node to DRM connector. Since this is
following ACPI spec, I think this is generic enough.

2) Use ACPI _DSM mthods to identify screen, set and get values. This
is where I think we're setting (generic) expectations for the ACPI
methods in how they should behave if ACPI is to be used to control
privacy screen. If we put this in generic code today, future
developers can look at this to understand how their ACPI for new
platforms is to behave if they want to use this generic code. If we
put it in i915 specific code, this will be seen as driver specific
behavior and developers may choose some other behavior in their
driver.

I agree that the functionality we're adding is ACPI specific (today -
but can be extended to gpio in future for non x86 platforms), but not
necessarily driver specific. Actually the only reason, I had to call
the drm_privacy_screen_present() (and the
drm_init_privacy_screen_property()) function from i915 code is because
we need a port_index to lookup ACPI node. If we had that available in
drm code, we wouldn't need to call anything from i915 at all.

So, for the reasons stated above, IMHO it is better to retain this
functionality in drm code instead of i915 driver. But I'm new to the
drm / i915 code, and would be happy to change my code if people have
strong opinions about this. Let me know.

Thanks & Best Regards,

Rajat

>
> > +{
> > + 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 <drm/drm_dp_helper.h>
> > #include <drm/drm_edid.h>
> > #include <drm/drm_hdcp.h>
> > +#include <drm/drm_privacy_screen.h>
> > #include <drm/drm_probe_helper.h>
> > #include <drm/i915_drm.h>
> >
> > @@ -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,
> > +};
> > +
>
> Shouldn't this go into include/uapi/drm/drm_mode.h? That would have the
> advantage of giving userspace symbolic names to use when setting the
> property.
>
> Maybe also rename these to something like:
>
> #define DRM_MODE_PRIVACY_DISABLED 0
> #define DRM_MODE_PRIVACY_ENABLED 1
>
> for consistency with other properties.
>
> Thierry
>
> > /**
> > * 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__ */
> > --
> > 2.23.0.866.gb869b98d4c-goog
> >

2019-10-25 19:54:56

by Thierry Reding

[permalink] [raw]
Subject: Re: [PATCH] drm: Add support for integrated privacy screens

On Thu, Oct 24, 2019 at 01:45:16PM -0700, Rajat Jain wrote:
> Hi,
>
> Thanks for your review and comments. Please see inline below.
>
> On Thu, Oct 24, 2019 at 4:20 AM Thierry Reding <[email protected]> wrote:
> >
> > On Tue, Oct 22, 2019 at 05:12:06PM -0700, Rajat Jain wrote:
> > > 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 <[email protected]>
> > > ---
> > > 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
> >
> > I like this much better than the prior proposal to use sysfs. However
> > the support currently looks a bit tangled. I realize that we only have a
> > single implementation for this in hardware right now, so there's no use
> > in over-engineering things, but I think we can do a better job from the
> > start without getting into too many abstractions. See below.
> >
> > > 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 <drm/drm_atomic.h>
> > > #include <drm/drm_print.h>
> > > #include <drm/drm_drv.h>
> > > +#include <drm/drm_privacy_screen.h>
> > > #include <drm/drm_writeback.h>
> > > #include <drm/drm_vblank.h>
> > >
> > > @@ -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);
> >
> > This doesn't look right. Shouldn't you store the value in the connector
> > state and then leave it up to the connector driver to set it
> > appropriately? I think that also has the advantage of untangling this
> > support a little.
>
> Hopefully this gets answered in my explanations below.
>
> >
> > > } 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);
> >
> > Similarly, I think this can just return the atomic state's value for
> > this.
>
> I did think about having a state variable in software to get and set
> this. However, I think it is not very far fetched that some platforms
> may have "hardware kill" switches that allow hardware to switch
> privacy-screen on and off directly, in addition to the software
> control that we are implementing. Privacy is a touchy subject in
> enterprise, and anything that reduces the possibility of having any
> inconsistency between software state and hardware state is desirable.
> So in this case, I chose to not have a state in software about this -
> we just report the hardware state everytime we are asked for it.

So this doesn't really work with atomic KMS, then. The main idea behind
atomic KMS is that you apply a configuration either completely or not at
all. So at least for setting this property you'd have to go through the
state object.

Now, for reading out the property you might be able to get away with the
above. I'm not sure if that's enough to keep the state up-to-date,
though. Is there some way for a kill switch to trigger an interrupt or
other event of some sort so that the state could be kept up-to-date?

Daniel (or anyone else), do you know of any precedent for state that
might get modified behind the atomic helpers' back? Seems to me like we
need to find some point where we can actually read back the current
"hardware value" of this privacy screen property and store that back
into the state.

>
> >
> > > } 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,
> >
> > Seems to me like the -screen suffix here is somewhat redundant. Yes, the
> > thing that we enable/disable may be called a "privacy screen", but the
> > property that we enable/disable on the connector is the "privacy" of the
> > user. I'd reflect that in all the related variable names and so on as
> > well.
>
> IMHO a property called "privacy" may be a little generic for the users
> to understand what it is. For e.g. when I started looking at code, I
> found the "Content Protection" property and I got confused thinking
> may be it provides something similar to what I'm trying to do. I think
> "privacy-screen" conveys the complete context without being long, so
> there is no confusion or ambiguity. But I don't mind changing it if a
> property "privacy" is what people think is better to convey what it
> is, as long as it is clear to user.

This being a property of a display connector it doesn't seem very
ambiguous to me what this is. How this ends up being presented to the
users is mostly orthogonal anyway. We've got a bunch of properties whose
purpose may not be clear to the average user. The properties, while they
are UABI, don't typically face the user directly. They're still part of
an API, so as long as they are properly documented there shouldn't be
any ambiguities.

> >
> > > + 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 <linux/acpi.h>
> > > +#include <linux/pci.h>
> > > +
> > > +#include <drm/drm_connector.h>
> > > +#include <drm/drm_device.h>
> > > +#include <drm/drm_print.h>
> > > +
> > > +#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)
> >
> > This is the main part that I think is a little tangled. This is a very
> > specific implementation that hides in a generic API.
>
> I agree that this is an ACPI specific implementation, but other than
> that, I think it does not have any driver specific details. More
> detailed thoughts on this below.

Well, the port_index kind of ties this to i915 because that uses this
concept. Other drivers may not.

Also, I'm wondering if you couldn't somehow derive the port_index from
the connector. If all this does is to find an ACPI node corresponding to
a connector, shouldn't the connector really be all that you need?

> > I we store the privacy setting in the atomic state, there isn't really a
> > reason to store the privacy handle in the connector. Instead it could be
> > simply stored in the driver that supports this.
> >
> > Ideally I think we'd have a very small drm_privacy_screen object type
> > that would just wrap this, but perhaps we don't need that right away,
> > given that we only have a single implementation so far.
>
> Yes, agreed.
>
> >
> > However, I think if we just pushed this specific implementation into the
> > drivers that'd help pave the way for something more generic later on
> > without a lot of extra work up front.
> >
> > For example you could turn the drm_connector_attach_acpi_node() into a
> > helper that simply returns the ACPI handle, something like this perhaps:
> >
> > struct acpi_handle *drm_acpi_find_privacy_screen(struct drm_connector *connector,
> > unsigned int port)
> > {
> > ...
> > }
>
> Yes, I like that idea of making it a helper function. In fact, finding
> an ACPI node for the connector doesn't have to do anything with
> privacy screen (so it can be used for other purposes also, in future).

Looks like I misunderstood the purpose of that function. You store the
ACPI handle as connector->privacy_screen_handle, so I was assuming that
it was getting an ACPI handle for some privacy screen subdevice.

> > That the i915 driver would then call and store the returned value
> > internally. When it commits the atomic state for the connector it can
> > then call the drm_acpi_set_privacy() (I think that'd be a better name
> > for your drm_privacy_screen_set_val()) by passing that handle and the
> > value from the atomic state.
> >
> > The above has the advantage that we don't clutter the generic core with
> > something that's not at all generic. If eventually we see that these
> > types of privacy screens are implemented in more device we can always
> > refactor this into something really generic and maybe even decide to put
> > it into the drm_connector directly.
>
> This is where I think I'm in slight disagreement. I think the
> functionality we're adding is still "generic", just that the only
> hardware *I have today* to test is using Intel eDP ports. But I don't
> see why AMD CPU laptops can't have it (For E.g. HP's Elitebook 745 G5
> seems to use AMD and has integrated privacy screen feature
> http://www8.hp.com/h20195/V2/GetPDF.aspx/4aa7-2802eee) .
> My worry is that if we don't make it generic today, we might see
> duplicate / similar-but-different / different ways of this in other
> places (e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=110ea1d833ad)
> because unless it is generic to start with, it is difficult for some
> one to change later for the fear of breaking hardware that is already
> in market given that
> * hardware may not be available to new developer to test for
> regressions (also there is very little motivation to check any
> hardware other than your own).
> * specially for a code that relies on firmware ACPI (firmware
> upgrades in field are always costly).
>
> My understanding is that we're adding 2 functionalities here:
>
> 1) Identify and Attach ACPI node to DRM connector. Since this is
> following ACPI spec, I think this is generic enough.

It's probably worth making this a separate patch in that case. If the
ACPI handle really represents the connector itself, then it seems fine
to store it in the connector. But it shouldn't be called privacy_screen
in that case.

> 2) Use ACPI _DSM mthods to identify screen, set and get values. This
> is where I think we're setting (generic) expectations for the ACPI
> methods in how they should behave if ACPI is to be used to control
> privacy screen. If we put this in generic code today, future
> developers can look at this to understand how their ACPI for new
> platforms is to behave if they want to use this generic code. If we
> put it in i915 specific code, this will be seen as driver specific
> behavior and developers may choose some other behavior in their
> driver.

I think it's fine to put this functionality into generic code. What I
don't think is good to do is to have this code called from generic code.
It's opt-in functionality that drivers should call if they know that the
connector has an associated ACPI handle that can be used for privacy
screen control.

After reading the patch again and realizing that you're not actually
dealing with an ACPI handle to the privacy screen directly but one for
the connector, I think this is okay. You do in fact call into this from
the i915 only. I still don't think the naming is great, and it'd be nice
to see ACPI as part of the function name to make that explicit. We could
always address that at a later point, but may as well do it right from
the start.

> I agree that the functionality we're adding is ACPI specific (today -
> but can be extended to gpio in future for non x86 platforms), but not
> necessarily driver specific. Actually the only reason, I had to call
> the drm_privacy_screen_present() (and the
> drm_init_privacy_screen_property()) function from i915 code is because
> we need a port_index to lookup ACPI node. If we had that available in
> drm code, we wouldn't need to call anything from i915 at all.

You're kind of proving my point about this API being driver-specific, or
at least ACPI specific. Non-ACPI devices (maybe even non-i915 devices?)
may not have a concept of a port index. Encoding this in the API makes
the API non-generic.

As I mentioned above, if we could derive the port index from the
connector, that'd be much better. Could you perhaps use drm_connector's
index field?

Unless there's a way to reliably detect this type of functionality from
generic code, I think it should always be called from the driver.

> So, for the reasons stated above, IMHO it is better to retain this
> functionality in drm code instead of i915 driver. But I'm new to the
> drm / i915 code, and would be happy to change my code if people have
> strong opinions about this. Let me know.

Maybe I was being unclear. I wasn't arguing that all the code should be
moved into the i915 driver. All I was saying that instead of storing the
ACPI handle inside struct drm_connector, we should maybe store it inside
the i915 driver's connector structure. struct drm_connector is a very
generic concept and each and every connector object on every platform
will get that ACPI handle pointer if you add it there. I don't think an
ACPI handle belongs there. For example, on ARM SoCs it's common to have
connectors be backed by a struct device (or struct platform_device more
specifically). But we don't put that information into drm_connector
because PCI graphics adapters don't have a struct device that represents
the connector.

Thierry

>
> Thanks & Best Regards,
>
> Rajat
>
> >
> > > +{
> > > + 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 <drm/drm_dp_helper.h>
> > > #include <drm/drm_edid.h>
> > > #include <drm/drm_hdcp.h>
> > > +#include <drm/drm_privacy_screen.h>
> > > #include <drm/drm_probe_helper.h>
> > > #include <drm/i915_drm.h>
> > >
> > > @@ -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,
> > > +};
> > > +
> >
> > Shouldn't this go into include/uapi/drm/drm_mode.h? That would have the
> > advantage of giving userspace symbolic names to use when setting the
> > property.
> >
> > Maybe also rename these to something like:
> >
> > #define DRM_MODE_PRIVACY_DISABLED 0
> > #define DRM_MODE_PRIVACY_ENABLED 1
> >
> > for consistency with other properties.
> >
> > Thierry
> >
> > > /**
> > > * 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__ */
> > > --
> > > 2.23.0.866.gb869b98d4c-goog
> > >


Attachments:
(No filename) (31.62 kB)
signature.asc (849.00 B)
Download all attachments

2019-10-25 20:54:23

by Rajat Jain

[permalink] [raw]
Subject: Re: [PATCH] drm: Add support for integrated privacy screens

On Fri, Oct 25, 2019 at 4:36 AM Thierry Reding <[email protected]> wrote:
>
> On Thu, Oct 24, 2019 at 01:45:16PM -0700, Rajat Jain wrote:
> > Hi,
> >
> > Thanks for your review and comments. Please see inline below.
> >
> > On Thu, Oct 24, 2019 at 4:20 AM Thierry Reding <[email protected]> wrote:
> > >
> > > On Tue, Oct 22, 2019 at 05:12:06PM -0700, Rajat Jain wrote:
> > > > 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 <[email protected]>
> > > > ---
> > > > 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
> > >
> > > I like this much better than the prior proposal to use sysfs. However
> > > the support currently looks a bit tangled. I realize that we only have a
> > > single implementation for this in hardware right now, so there's no use
> > > in over-engineering things, but I think we can do a better job from the
> > > start without getting into too many abstractions. See below.
> > >
> > > > 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 <drm/drm_atomic.h>
> > > > #include <drm/drm_print.h>
> > > > #include <drm/drm_drv.h>
> > > > +#include <drm/drm_privacy_screen.h>
> > > > #include <drm/drm_writeback.h>
> > > > #include <drm/drm_vblank.h>
> > > >
> > > > @@ -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);
> > >
> > > This doesn't look right. Shouldn't you store the value in the connector
> > > state and then leave it up to the connector driver to set it
> > > appropriately? I think that also has the advantage of untangling this
> > > support a little.
> >
> > Hopefully this gets answered in my explanations below.
> >
> > >
> > > > } 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);
> > >
> > > Similarly, I think this can just return the atomic state's value for
> > > this.
> >
> > I did think about having a state variable in software to get and set
> > this. However, I think it is not very far fetched that some platforms
> > may have "hardware kill" switches that allow hardware to switch
> > privacy-screen on and off directly, in addition to the software
> > control that we are implementing. Privacy is a touchy subject in
> > enterprise, and anything that reduces the possibility of having any
> > inconsistency between software state and hardware state is desirable.
> > So in this case, I chose to not have a state in software about this -
> > we just report the hardware state everytime we are asked for it.
>
> So this doesn't really work with atomic KMS, then. The main idea behind
> atomic KMS is that you apply a configuration either completely or not at
> all. So at least for setting this property you'd have to go through the
> state object.
>
> Now, for reading out the property you might be able to get away with the
> above. I'm not sure if that's enough to keep the state up-to-date,
> though. Is there some way for a kill switch to trigger an interrupt or
> other event of some sort so that the state could be kept up-to-date?

I was basically imagining a hardware that I don't have at the moment.
So I do not know the answer, but I think the answer may be yes.

>
> Daniel (or anyone else), do you know of any precedent for state that
> might get modified behind the atomic helpers' back? Seems to me like we
> need to find some point where we can actually read back the current
> "hardware value" of this privacy screen property and store that back
> into the state.
>

I'll wait for suggestions.

What I did not quite understand about the use of a local state in
software is what does this local software state buy us? Even with
local state, in the "set_property" flow, we'll update it at the same
time when we flush it out to hardware. Is it about avoiding an ACPI
call during the "get_property" flow? Also, is it worth it if i brings
with it complexity of interrupt handling?

> >
> > >
> > > > } 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,
> > >
> > > Seems to me like the -screen suffix here is somewhat redundant. Yes, the
> > > thing that we enable/disable may be called a "privacy screen", but the
> > > property that we enable/disable on the connector is the "privacy" of the
> > > user. I'd reflect that in all the related variable names and so on as
> > > well.
> >
> > IMHO a property called "privacy" may be a little generic for the users
> > to understand what it is. For e.g. when I started looking at code, I
> > found the "Content Protection" property and I got confused thinking
> > may be it provides something similar to what I'm trying to do. I think
> > "privacy-screen" conveys the complete context without being long, so
> > there is no confusion or ambiguity. But I don't mind changing it if a
> > property "privacy" is what people think is better to convey what it
> > is, as long as it is clear to user.
>
> This being a property of a display connector it doesn't seem very
> ambiguous to me what this is. How this ends up being presented to the
> users is mostly orthogonal anyway. We've got a bunch of properties whose
> purpose may not be clear to the average user. The properties, while they
> are UABI, don't typically face the user directly. They're still part of
> an API, so as long as they are properly documented there shouldn't be
> any ambiguities.
>

OK, I do not mind changing to whatever is acceptable. Jani / Daniel,
do you have any recommendation here?

> > >
> > > > + 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 <linux/acpi.h>
> > > > +#include <linux/pci.h>
> > > > +
> > > > +#include <drm/drm_connector.h>
> > > > +#include <drm/drm_device.h>
> > > > +#include <drm/drm_print.h>
> > > > +
> > > > +#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) {
2) > > > > + 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)
> > >
> > > This is the main part that I think is a little tangled. This is a very
> > > specific implementation that hides in a generic API.
> >
> > I agree that this is an ACPI specific implementation, but other than
> > that, I think it does not have any driver specific details. More
> > detailed thoughts on this below.
>
> Well, the port_index kind of ties this to i915 because that uses this
> concept. Other drivers may not.
>
> Also, I'm wondering if you couldn't somehow derive the port_index from
> the connector. If all this does is to find an ACPI node corresponding to
> a connector, shouldn't the connector really be all that you need?
>

Yes, I agree that finding an ACPI node corresponding to a connector,
should require only the info that the connector already has.

> > > I we store the privacy setting in the atomic state, there isn't really a
> > > reason to store the privacy handle in the connector. Instead it could be
> > > simply stored in the driver that supports this.
> > >
> > > Ideally I think we'd have a very small drm_privacy_screen object type
> > > that would just wrap this, but perhaps we don't need that right away,
> > > given that we only have a single implementation so far.
> >
> > Yes, agreed.
> >
> > >
> > > However, I think if we just pushed this specific implementation into the
> > > drivers that'd help pave the way for something more generic later on
> > > without a lot of extra work up front.
> > >
> > > For example you could turn the drm_connector_attach_acpi_node() into a
> > > helper that simply returns the ACPI handle, something like this perhaps:
> > >
> > > struct acpi_handle *drm_acpi_find_privacy_screen(struct drm_connector *connector,
> > > unsigned int port)
> > > {
> > > ...
> > > }
> >
> > Yes, I like that idea of making it a helper function. In fact, finding
> > an ACPI node for the connector doesn't have to do anything with
> > privacy screen (so it can be used for other purposes also, in future).
>
> Looks like I misunderstood the purpose of that function. You store the
> ACPI handle as connector->privacy_screen_handle, so I was assuming that
> it was getting an ACPI handle for some privacy screen subdevice.
>
> > > That the i915 driver would then call and store the returned value
> > > internally. When it commits the atomic state for the connector it can
> > > then call the drm_acpi_set_privacy() (I think that'd be a better name
> > > for your drm_privacy_screen_set_val()) by passing that handle and the
> > > value from the atomic state.
> > >
> > > The above has the advantage that we don't clutter the generic core with
> > > something that's not at all generic. If eventually we see that these
> > > types of privacy screens are implemented in more device we can always
> > > refactor this into something really generic and maybe even decide to put
> > > it into the drm_connector directly.
> >
> > This is where I think I'm in slight disagreement. I think the
> > functionality we're adding is still "generic", just that the only
> > hardware *I have today* to test is using Intel eDP ports. But I don't
> > see why AMD CPU laptops can't have it (For E.g. HP's Elitebook 745 G5
> > seems to use AMD and has integrated privacy screen feature
> > http://www8.hp.com/h20195/V2/GetPDF.aspx/4aa7-2802eee) .
> > My worry is that if we don't make it generic today, we might see
> > duplicate / similar-but-different / different ways of this in other
> > places (e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=110ea1d833ad)
> > because unless it is generic to start with, it is difficult for some
> > one to change later for the fear of breaking hardware that is already
> > in market given that
> > * hardware may not be available to new developer to test for
> > regressions (also there is very little motivation to check any
> > hardware other than your own).
> > * specially for a code that relies on firmware ACPI (firmware
> > upgrades in field are always costly).
> >
> > My understanding is that we're adding 2 functionalities here:
> >
> > 1) Identify and Attach ACPI node to DRM connector. Since this is
> > following ACPI spec, I think this is generic enough.
>
> It's probably worth making this a separate patch in that case. If the
> ACPI handle really represents the connector itself, then it seems fine
> to store it in the connector. But it shouldn't be called privacy_screen
> in that case.

Yes, I agree.

>
> > 2) Use ACPI _DSM mthods to identify screen, set and get values. This
> > is where I think we're setting (generic) expectations for the ACPI
> > methods in how they should behave if ACPI is to be used to control
> > privacy screen. If we put this in generic code today, future
> > developers can look at this to understand how their ACPI for new
> > platforms is to behave if they want to use this generic code. If we
> > put it in i915 specific code, this will be seen as driver specific
> > behavior and developers may choose some other behavior in their
> > driver.
>
> I think it's fine to put this functionality into generic code. What I
> don't think is good to do is to have this code called from generic code.
> It's opt-in functionality that drivers should call if they know that the
> connector has an associated ACPI handle that can be used for privacy
> screen control.

Ah, OK, I see where the disconnect was. Sure, I think we are converging now.

>
> After reading the patch again and realizing that you're not actually
> dealing with an ACPI handle to the privacy screen directly but one for
> the connector, I think this is okay. You do in fact call into this from
> the i915 only. I still don't think the naming is great, and it'd be nice
> to see ACPI as part of the function name to make that explicit. We could
> always address that at a later point, but may as well do it right from
> the start.

Sure, I agree and will change the naming.

>
> > I agree that the functionality we're adding is ACPI specific (today -
> > but can be extended to gpio in future for non x86 platforms), but not
> > necessarily driver specific. Actually the only reason, I had to call
> > the drm_privacy_screen_present() (and the
> > drm_init_privacy_screen_property()) function from i915 code is because
> > we need a port_index to lookup ACPI node. If we had that available in
> > drm code, we wouldn't need to call anything from i915 at all.
>
> You're kind of proving my point about this API being driver-specific, or
> at least ACPI specific. Non-ACPI devices (maybe even non-i915 devices?)
> may not have a concept of a port index. Encoding this in the API makes
> the API non-generic.
>
> As I mentioned above, if we could derive the port index from the
> connector, that'd be much better. Could you perhaps use drm_connector's
> index field?

That's a good idea. I'll check it out to see if it matches my needs.
If it does, I think we might have found a way to make it totally
separate from i915. I don't have a vast range of test hardware and
monitors etc to test though. So I'll test with what I have available.

I'll keep you updated.

>
> Unless there's a way to reliably detect this type of functionality from
> generic code, I think it should always be called from the driver.
>
> > So, for the reasons stated above, IMHO it is better to retain this
> > functionality in drm code instead of i915 driver. But I'm new to the
> > drm / i915 code, and would be happy to change my code if people have
> > strong opinions about this. Let me know.
>
> Maybe I was being unclear. I wasn't arguing that all the code should be
> moved into the i915 driver. All I was saying that instead of storing the
> ACPI handle inside struct drm_connector, we should maybe store it inside
> the i915 driver's connector structure. struct drm_connector is a very
> generic concept and each and every connector object on every platform
> will get that ACPI handle pointer if you add it there. I don't think an
> ACPI handle belongs there. For example, on ARM SoCs it's common to have
> connectors be backed by a struct device (or struct platform_device more
> specifically). But we don't put that information into drm_connector
> because PCI graphics adapters don't have a struct device that represents
> the connector.

OK, I understand what you are saying. The ACPI handle essentially
denotes the firmware node for that drm_connector device, analogous to
the device tree nodes. Ideally, I wanted to have it stored in the
drm_connector->kdev->fwnode which I think was the best place as it
would also make the ACPI node visible in the sysfs like it is visible
for PCI devices today. Unfortunately I found that the
drm_connector->kdev is not created at the time when I need to lookup
and register privacy screen (kdev is created much later), so that is
not an option. Note that the drm_privacy_screen_set_val() and
drm_privacy_screen_get_val() will need to access this ACPI handle to
do their jobs. So unless I move that code or the property representing
privacy screen also into i915, I can't really put that handle in i915.

Thanks,

Rajat



>
> Thierry
>
> >
> > Thanks & Best Regards,
> >
> > Rajat
> >
> > >
> > > > +{
> > > > + 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 <drm/drm_dp_helper.h>
> > > > #include <drm/drm_edid.h>
> > > > #include <drm/drm_hdcp.h>
> > > > +#include <drm/drm_privacy_screen.h>
> > > > #include <drm/drm_probe_helper.h>
> > > > #include <drm/i915_drm.h>
> > > >
> > > > @@ -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,
> > > > +};
> > > > +
> > >
> > > Shouldn't this go into include/uapi/drm/drm_mode.h? That would have the
> > > advantage of giving userspace symbolic names to use when setting the
> > > property.
> > >
> > > Maybe also rename these to something like:
> > >
> > > #define DRM_MODE_PRIVACY_DISABLED 0
> > > #define DRM_MODE_PRIVACY_ENABLED 1
> > >
> > > for consistency with other properties.
> > >
> > > Thierry
> > >
> > > > /**
> > > > * 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__ */
> > > > --
> > > > 2.23.0.866.gb869b98d4c-goog
> > > >

2019-10-25 20:54:29

by Daniel Vetter

[permalink] [raw]
Subject: Re: [PATCH] drm: Add support for integrated privacy screens

On Fri, Oct 25, 2019 at 1:36 PM Thierry Reding <[email protected]> wrote:
>
> On Thu, Oct 24, 2019 at 01:45:16PM -0700, Rajat Jain wrote:
> > Hi,
> >
> > Thanks for your review and comments. Please see inline below.
> >
> > On Thu, Oct 24, 2019 at 4:20 AM Thierry Reding <[email protected]> wrote:
> > >
> > > On Tue, Oct 22, 2019 at 05:12:06PM -0700, Rajat Jain wrote:
> > > > 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 <[email protected]>
> > > > ---
> > > > 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
> > >
> > > I like this much better than the prior proposal to use sysfs. However
> > > the support currently looks a bit tangled. I realize that we only have a
> > > single implementation for this in hardware right now, so there's no use
> > > in over-engineering things, but I think we can do a better job from the
> > > start without getting into too many abstractions. See below.
> > >
> > > > 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 <drm/drm_atomic.h>
> > > > #include <drm/drm_print.h>
> > > > #include <drm/drm_drv.h>
> > > > +#include <drm/drm_privacy_screen.h>
> > > > #include <drm/drm_writeback.h>
> > > > #include <drm/drm_vblank.h>
> > > >
> > > > @@ -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);
> > >
> > > This doesn't look right. Shouldn't you store the value in the connector
> > > state and then leave it up to the connector driver to set it
> > > appropriately? I think that also has the advantage of untangling this
> > > support a little.
> >
> > Hopefully this gets answered in my explanations below.
> >
> > >
> > > > } 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);
> > >
> > > Similarly, I think this can just return the atomic state's value for
> > > this.
> >
> > I did think about having a state variable in software to get and set
> > this. However, I think it is not very far fetched that some platforms
> > may have "hardware kill" switches that allow hardware to switch
> > privacy-screen on and off directly, in addition to the software
> > control that we are implementing. Privacy is a touchy subject in
> > enterprise, and anything that reduces the possibility of having any
> > inconsistency between software state and hardware state is desirable.
> > So in this case, I chose to not have a state in software about this -
> > we just report the hardware state everytime we are asked for it.
>
> So this doesn't really work with atomic KMS, then. The main idea behind
> atomic KMS is that you apply a configuration either completely or not at
> all. So at least for setting this property you'd have to go through the
> state object.
>
> Now, for reading out the property you might be able to get away with the
> above. I'm not sure if that's enough to keep the state up-to-date,
> though. Is there some way for a kill switch to trigger an interrupt or
> other event of some sort so that the state could be kept up-to-date?
>
> Daniel (or anyone else), do you know of any precedent for state that
> might get modified behind the atomic helpers' back? Seems to me like we
> need to find some point where we can actually read back the current
> "hardware value" of this privacy screen property and store that back
> into the state.

We have atomic properties that the driver also updates, not just userspace:
- link status
- hdcp machinery

But both still use the state structures like anything else, and then
update that state structure through some worker.

And yes I totally didn't catch this here, this breaks atomic, badly :-)

>
> >
> > >
> > > > } 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,
> > >
> > > Seems to me like the -screen suffix here is somewhat redundant. Yes, the
> > > thing that we enable/disable may be called a "privacy screen", but the
> > > property that we enable/disable on the connector is the "privacy" of the
> > > user. I'd reflect that in all the related variable names and so on as
> > > well.
> >
> > IMHO a property called "privacy" may be a little generic for the users
> > to understand what it is. For e.g. when I started looking at code, I
> > found the "Content Protection" property and I got confused thinking
> > may be it provides something similar to what I'm trying to do. I think
> > "privacy-screen" conveys the complete context without being long, so
> > there is no confusion or ambiguity. But I don't mind changing it if a
> > property "privacy" is what people think is better to convey what it
> > is, as long as it is clear to user.
>
> This being a property of a display connector it doesn't seem very
> ambiguous to me what this is. How this ends up being presented to the
> users is mostly orthogonal anyway. We've got a bunch of properties whose
> purpose may not be clear to the average user. The properties, while they
> are UABI, don't typically face the user directly. They're still part of
> an API, so as long as they are properly documented there shouldn't be
> any ambiguities.

Sometimes we go the cheap way with connector properties and say that
those should be set by the user directly, through something like
xrandr (mostly for stuff to hack around broken monitors). But ofc
nicer if the property comes with some proper userspace integration.

> > > > + 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 <linux/acpi.h>
> > > > +#include <linux/pci.h>
> > > > +
> > > > +#include <drm/drm_connector.h>
> > > > +#include <drm/drm_device.h>
> > > > +#include <drm/drm_print.h>
> > > > +
> > > > +#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)
> > >
> > > This is the main part that I think is a little tangled. This is a very
> > > specific implementation that hides in a generic API.
> >
> > I agree that this is an ACPI specific implementation, but other than
> > that, I think it does not have any driver specific details. More
> > detailed thoughts on this below.
>
> Well, the port_index kind of ties this to i915 because that uses this
> concept. Other drivers may not.
>
> Also, I'm wondering if you couldn't somehow derive the port_index from
> the connector. If all this does is to find an ACPI node corresponding to
> a connector, shouldn't the connector really be all that you need?

Yeah port should be stored already plenty of times in i915 connector structs.

> > > I we store the privacy setting in the atomic state, there isn't really a
> > > reason to store the privacy handle in the connector. Instead it could be
> > > simply stored in the driver that supports this.
> > >
> > > Ideally I think we'd have a very small drm_privacy_screen object type
> > > that would just wrap this, but perhaps we don't need that right away,
> > > given that we only have a single implementation so far.
> >
> > Yes, agreed.
> >
> > >
> > > However, I think if we just pushed this specific implementation into the
> > > drivers that'd help pave the way for something more generic later on
> > > without a lot of extra work up front.
> > >
> > > For example you could turn the drm_connector_attach_acpi_node() into a
> > > helper that simply returns the ACPI handle, something like this perhaps:
> > >
> > > struct acpi_handle *drm_acpi_find_privacy_screen(struct drm_connector *connector,
> > > unsigned int port)
> > > {
> > > ...
> > > }
> >
> > Yes, I like that idea of making it a helper function. In fact, finding
> > an ACPI node for the connector doesn't have to do anything with
> > privacy screen (so it can be used for other purposes also, in future).
>
> Looks like I misunderstood the purpose of that function. You store the
> ACPI handle as connector->privacy_screen_handle, so I was assuming that
> it was getting an ACPI handle for some privacy screen subdevice.
>
> > > That the i915 driver would then call and store the returned value
> > > internally. When it commits the atomic state for the connector it can
> > > then call the drm_acpi_set_privacy() (I think that'd be a better name
> > > for your drm_privacy_screen_set_val()) by passing that handle and the
> > > value from the atomic state.
> > >
> > > The above has the advantage that we don't clutter the generic core with
> > > something that's not at all generic. If eventually we see that these
> > > types of privacy screens are implemented in more device we can always
> > > refactor this into something really generic and maybe even decide to put
> > > it into the drm_connector directly.
> >
> > This is where I think I'm in slight disagreement. I think the
> > functionality we're adding is still "generic", just that the only
> > hardware *I have today* to test is using Intel eDP ports. But I don't
> > see why AMD CPU laptops can't have it (For E.g. HP's Elitebook 745 G5
> > seems to use AMD and has integrated privacy screen feature
> > http://www8.hp.com/h20195/V2/GetPDF.aspx/4aa7-2802eee) .
> > My worry is that if we don't make it generic today, we might see
> > duplicate / similar-but-different / different ways of this in other
> > places (e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=110ea1d833ad)
> > because unless it is generic to start with, it is difficult for some
> > one to change later for the fear of breaking hardware that is already
> > in market given that
> > * hardware may not be available to new developer to test for
> > regressions (also there is very little motivation to check any
> > hardware other than your own).
> > * specially for a code that relies on firmware ACPI (firmware
> > upgrades in field are always costly).
> >
> > My understanding is that we're adding 2 functionalities here:
> >
> > 1) Identify and Attach ACPI node to DRM connector. Since this is
> > following ACPI spec, I think this is generic enough.
>
> It's probably worth making this a separate patch in that case. If the
> ACPI handle really represents the connector itself, then it seems fine
> to store it in the connector. But it shouldn't be called privacy_screen
> in that case.

Probably still should be in i915. We have a few firmware handle things
in there already. If other drivers need this, we could make an acpi
helper library that drivers can call to find the right acpi handle for
their connector.

> > 2) Use ACPI _DSM mthods to identify screen, set and get values. This
> > is where I think we're setting (generic) expectations for the ACPI
> > methods in how they should behave if ACPI is to be used to control
> > privacy screen. If we put this in generic code today, future
> > developers can look at this to understand how their ACPI for new
> > platforms is to behave if they want to use this generic code. If we
> > put it in i915 specific code, this will be seen as driver specific
> > behavior and developers may choose some other behavior in their
> > driver.
>
> I think it's fine to put this functionality into generic code. What I
> don't think is good to do is to have this code called from generic code.
> It's opt-in functionality that drivers should call if they know that the
> connector has an associated ACPI handle that can be used for privacy
> screen control.
>
> After reading the patch again and realizing that you're not actually
> dealing with an ACPI handle to the privacy screen directly but one for
> the connector, I think this is okay. You do in fact call into this from
> the i915 only. I still don't think the naming is great, and it'd be nice
> to see ACPI as part of the function name to make that explicit. We could
> always address that at a later point, but may as well do it right from
> the start.
>
> > I agree that the functionality we're adding is ACPI specific (today -
> > but can be extended to gpio in future for non x86 platforms), but not
> > necessarily driver specific. Actually the only reason, I had to call
> > the drm_privacy_screen_present() (and the
> > drm_init_privacy_screen_property()) function from i915 code is because
> > we need a port_index to lookup ACPI node. If we had that available in
> > drm code, we wouldn't need to call anything from i915 at all.
>
> You're kind of proving my point about this API being driver-specific, or
> at least ACPI specific. Non-ACPI devices (maybe even non-i915 devices?)
> may not have a concept of a port index. Encoding this in the API makes
> the API non-generic.
>
> As I mentioned above, if we could derive the port index from the
> connector, that'd be much better. Could you perhaps use drm_connector's
> index field?
>
> Unless there's a way to reliably detect this type of functionality from
> generic code, I think it should always be called from the driver.

Maybe time to pitch the old classic again:

https://blog.ffwll.ch/2016/12/midlayers-once-more-with-feeling.html

Especially all the links in the first part.

> > So, for the reasons stated above, IMHO it is better to retain this
> > functionality in drm code instead of i915 driver. But I'm new to the
> > drm / i915 code, and would be happy to change my code if people have
> > strong opinions about this. Let me know.
>
> Maybe I was being unclear. I wasn't arguing that all the code should be
> moved into the i915 driver. All I was saying that instead of storing the
> ACPI handle inside struct drm_connector, we should maybe store it inside
> the i915 driver's connector structure. struct drm_connector is a very
> generic concept and each and every connector object on every platform
> will get that ACPI handle pointer if you add it there. I don't think an
> ACPI handle belongs there. For example, on ARM SoCs it's common to have
> connectors be backed by a struct device (or struct platform_device more
> specifically). But we don't put that information into drm_connector
> because PCI graphics adapters don't have a struct device that represents
> the connector.

+1 on all the stuff Thierry says here essentially.

Cheers, Daniel

>
> Thierry
>
> >
> > Thanks & Best Regards,
> >
> > Rajat
> >
> > >
> > > > +{
> > > > + 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 <drm/drm_dp_helper.h>
> > > > #include <drm/drm_edid.h>
> > > > #include <drm/drm_hdcp.h>
> > > > +#include <drm/drm_privacy_screen.h>
> > > > #include <drm/drm_probe_helper.h>
> > > > #include <drm/i915_drm.h>
> > > >
> > > > @@ -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,
> > > > +};
> > > > +
> > >
> > > Shouldn't this go into include/uapi/drm/drm_mode.h? That would have the
> > > advantage of giving userspace symbolic names to use when setting the
> > > property.
> > >
> > > Maybe also rename these to something like:
> > >
> > > #define DRM_MODE_PRIVACY_DISABLED 0
> > > #define DRM_MODE_PRIVACY_ENABLED 1
> > >
> > > for consistency with other properties.
> > >
> > > Thierry
> > >
> > > > /**
> > > > * 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__ */
> > > > --
> > > > 2.23.0.866.gb869b98d4c-goog
> > > >



--
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

2019-10-26 11:10:39

by Daniel Stone

[permalink] [raw]
Subject: Re: [Intel-gfx] [PATCH] drm: Add support for integrated privacy screens

Hi Thierry,

On Fri, 25 Oct 2019 at 12:36, Thierry Reding <[email protected]> wrote:
> On Thu, Oct 24, 2019 at 01:45:16PM -0700, Rajat Jain wrote:
> > I did think about having a state variable in software to get and set
> > this. However, I think it is not very far fetched that some platforms
> > may have "hardware kill" switches that allow hardware to switch
> > privacy-screen on and off directly, in addition to the software
> > control that we are implementing. Privacy is a touchy subject in
> > enterprise, and anything that reduces the possibility of having any
> > inconsistency between software state and hardware state is desirable.
> > So in this case, I chose to not have a state in software about this -
> > we just report the hardware state everytime we are asked for it.
>
> So this doesn't really work with atomic KMS, then. The main idea behind
> atomic KMS is that you apply a configuration either completely or not at
> all. So at least for setting this property you'd have to go through the
> state object.
>
> Now, for reading out the property you might be able to get away with the
> above. I'm not sure if that's enough to keep the state up-to-date,
> though. Is there some way for a kill switch to trigger an interrupt or
> other event of some sort so that the state could be kept up-to-date?
>
> Daniel (or anyone else), do you know of any precedent for state that
> might get modified behind the atomic helpers' back? Seems to me like we
> need to find some point where we can actually read back the current
> "hardware value" of this privacy screen property and store that back
> into the state.

Well, apart from connector state, though that isn't really a property
as such, there's the link_state property, which is explicitly designed
to do just that. That has been quite carefully designed for the
back-and-forth though.

Cheers,
Daniel

2019-10-26 17:23:37

by Daniel Vetter

[permalink] [raw]
Subject: Re: [Intel-gfx] [PATCH] drm: Add support for integrated privacy screens

On Sat, Oct 26, 2019 at 1:07 PM Daniel Stone <[email protected]> wrote:
>
> Hi Thierry,
>
> On Fri, 25 Oct 2019 at 12:36, Thierry Reding <[email protected]> wrote:
> > On Thu, Oct 24, 2019 at 01:45:16PM -0700, Rajat Jain wrote:
> > > I did think about having a state variable in software to get and set
> > > this. However, I think it is not very far fetched that some platforms
> > > may have "hardware kill" switches that allow hardware to switch
> > > privacy-screen on and off directly, in addition to the software
> > > control that we are implementing. Privacy is a touchy subject in
> > > enterprise, and anything that reduces the possibility of having any
> > > inconsistency between software state and hardware state is desirable.
> > > So in this case, I chose to not have a state in software about this -
> > > we just report the hardware state everytime we are asked for it.
> >
> > So this doesn't really work with atomic KMS, then. The main idea behind
> > atomic KMS is that you apply a configuration either completely or not at
> > all. So at least for setting this property you'd have to go through the
> > state object.
> >
> > Now, for reading out the property you might be able to get away with the
> > above. I'm not sure if that's enough to keep the state up-to-date,
> > though. Is there some way for a kill switch to trigger an interrupt or
> > other event of some sort so that the state could be kept up-to-date?
> >
> > Daniel (or anyone else), do you know of any precedent for state that
> > might get modified behind the atomic helpers' back? Seems to me like we
> > need to find some point where we can actually read back the current
> > "hardware value" of this privacy screen property and store that back
> > into the state.
>
> Well, apart from connector state, though that isn't really a property
> as such, there's the link_state property, which is explicitly designed
> to do just that. That has been quite carefully designed for the
> back-and-forth though.

connector state is an immutable property, which is a hilarious way to
say that "only the driver can update it, userspace only reads it". So
not a good template here. But yeah link_state is a good example of
what we need here.
-Daniel
--
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

2019-10-28 16:40:53

by Pekka Paalanen

[permalink] [raw]
Subject: Re: [PATCH] drm: Add support for integrated privacy screens

On Fri, 25 Oct 2019 21:03:12 +0200
Daniel Vetter <[email protected]> wrote:

> On Fri, Oct 25, 2019 at 1:36 PM Thierry Reding <[email protected]> wrote:
> >
> > On Thu, Oct 24, 2019 at 01:45:16PM -0700, Rajat Jain wrote:
> > > Hi,
> > >
> > > Thanks for your review and comments. Please see inline below.
> > >
> > > On Thu, Oct 24, 2019 at 4:20 AM Thierry Reding <[email protected]> wrote:
> > > >
> > > > On Tue, Oct 22, 2019 at 05:12:06PM -0700, Rajat Jain wrote:
> > > > > 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 <[email protected]>
> > > > > ---
> > > > > 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
> > > >
> > > > I like this much better than the prior proposal to use sysfs. However
> > > > the support currently looks a bit tangled. I realize that we only have a
> > > > single implementation for this in hardware right now, so there's no use
> > > > in over-engineering things, but I think we can do a better job from the
> > > > start without getting into too many abstractions. See below.
> > > >
> > > > > 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 <drm/drm_atomic.h>
> > > > > #include <drm/drm_print.h>
> > > > > #include <drm/drm_drv.h>
> > > > > +#include <drm/drm_privacy_screen.h>
> > > > > #include <drm/drm_writeback.h>
> > > > > #include <drm/drm_vblank.h>
> > > > >
> > > > > @@ -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);
> > > >
> > > > This doesn't look right. Shouldn't you store the value in the connector
> > > > state and then leave it up to the connector driver to set it
> > > > appropriately? I think that also has the advantage of untangling this
> > > > support a little.
> > >
> > > Hopefully this gets answered in my explanations below.
> > >
> > > >
> > > > > } 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);
> > > >
> > > > Similarly, I think this can just return the atomic state's value for
> > > > this.
> > >
> > > I did think about having a state variable in software to get and set
> > > this. However, I think it is not very far fetched that some platforms
> > > may have "hardware kill" switches that allow hardware to switch
> > > privacy-screen on and off directly, in addition to the software
> > > control that we are implementing. Privacy is a touchy subject in
> > > enterprise, and anything that reduces the possibility of having any
> > > inconsistency between software state and hardware state is desirable.
> > > So in this case, I chose to not have a state in software about this -
> > > we just report the hardware state everytime we are asked for it.
> >
> > So this doesn't really work with atomic KMS, then. The main idea behind
> > atomic KMS is that you apply a configuration either completely or not at
> > all. So at least for setting this property you'd have to go through the
> > state object.
> >
> > Now, for reading out the property you might be able to get away with the
> > above. I'm not sure if that's enough to keep the state up-to-date,
> > though. Is there some way for a kill switch to trigger an interrupt or
> > other event of some sort so that the state could be kept up-to-date?
> >
> > Daniel (or anyone else), do you know of any precedent for state that
> > might get modified behind the atomic helpers' back? Seems to me like we
> > need to find some point where we can actually read back the current
> > "hardware value" of this privacy screen property and store that back
> > into the state.
>
> We have atomic properties that the driver also updates, not just userspace:
> - link status
> - hdcp machinery

Hi,

just a note about properties. Please, do not use the HDCP "Content
Protection" as an example of a good property design. A property that is
writable by both userspace and kernel is a hard one to use right in my
opinion.

For privacy screens, I suggest defining two optional and separate
properties:

Software control on/off: userspace writable, kernel immutable

Hardware kill switch on/off: userspace immutable, kernel writable

The semantics of these should be fairly clear: if hardware kill switch
exists and is on, then the privacy screen is on. (Does this match
hardware and expected behaviour?) Otherwise, if the software control
exists, it can be used to control the privacy screen.

For delivering change events for the hardware kill switch, please
search for the proposal to enhance hotplug uevents with property ids.
This was discussed and implemented(?) for delivering HDCP "Content
Protection" changes to userspace when implementing the "HDCP Content
Type" property.


Thanks,
pq


Attachments:
(No filename) (849.00 B)
OpenPGP digital signature

2019-11-04 19:42:51

by Rajat Jain

[permalink] [raw]
Subject: [PATCH v2 1/3] drm/i915: Move the code to populate ACPI device ID into intel_acpi

Move the code that populates the ACPI device ID for devices, into
more appripriate intel_acpi.c. This is done in preparation for more
users of this code (in next patch).

Signed-off-by: Rajat Jain <[email protected]>
Change-Id: Ifb3bd458734985c2a78ba682e6f0a2e63e0626ca
---
v2: v1 doesn't exist. Found existing code in i915 driver to assign the ACPI ID
which is what I plan to re-use.


drivers/gpu/drm/i915/display/intel_acpi.c | 87 +++++++++++++++++++
drivers/gpu/drm/i915/display/intel_acpi.h | 6 ++
drivers/gpu/drm/i915/display/intel_opregion.c | 80 +----------------
3 files changed, 97 insertions(+), 76 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_acpi.c b/drivers/gpu/drm/i915/display/intel_acpi.c
index 3456d33feb46..748d9b3125dd 100644
--- a/drivers/gpu/drm/i915/display/intel_acpi.c
+++ b/drivers/gpu/drm/i915/display/intel_acpi.c
@@ -156,3 +156,90 @@ void intel_register_dsm_handler(void)
void intel_unregister_dsm_handler(void)
{
}
+
+/*
+ * ACPI Specification, Revision 5.0, Appendix B.3.2 _DOD (Enumerate All Devices
+ * Attached to the Display Adapter).
+ */
+#define ACPI_DISPLAY_INDEX_SHIFT 0
+#define ACPI_DISPLAY_INDEX_MASK (0xf << 0)
+#define ACPI_DISPLAY_PORT_ATTACHMENT_SHIFT 4
+#define ACPI_DISPLAY_PORT_ATTACHMENT_MASK (0xf << 4)
+#define ACPI_DISPLAY_TYPE_SHIFT 8
+#define ACPI_DISPLAY_TYPE_MASK (0xf << 8)
+#define ACPI_DISPLAY_TYPE_OTHER (0 << 8)
+#define ACPI_DISPLAY_TYPE_VGA (1 << 8)
+#define ACPI_DISPLAY_TYPE_TV (2 << 8)
+#define ACPI_DISPLAY_TYPE_EXTERNAL_DIGITAL (3 << 8)
+#define ACPI_DISPLAY_TYPE_INTERNAL_DIGITAL (4 << 8)
+#define ACPI_VENDOR_SPECIFIC_SHIFT 12
+#define ACPI_VENDOR_SPECIFIC_MASK (0xf << 12)
+#define ACPI_BIOS_CAN_DETECT (1 << 16)
+#define ACPI_DEPENDS_ON_VGA (1 << 17)
+#define ACPI_PIPE_ID_SHIFT 18
+#define ACPI_PIPE_ID_MASK (7 << 18)
+#define ACPI_DEVICE_ID_SCHEME (1ULL << 31)
+
+static u32 acpi_display_type(struct intel_connector *connector)
+{
+ u32 display_type;
+
+ switch (connector->base.connector_type) {
+ case DRM_MODE_CONNECTOR_VGA:
+ case DRM_MODE_CONNECTOR_DVIA:
+ display_type = ACPI_DISPLAY_TYPE_VGA;
+ break;
+ case DRM_MODE_CONNECTOR_Composite:
+ case DRM_MODE_CONNECTOR_SVIDEO:
+ case DRM_MODE_CONNECTOR_Component:
+ case DRM_MODE_CONNECTOR_9PinDIN:
+ case DRM_MODE_CONNECTOR_TV:
+ display_type = ACPI_DISPLAY_TYPE_TV;
+ break;
+ case DRM_MODE_CONNECTOR_DVII:
+ case DRM_MODE_CONNECTOR_DVID:
+ case DRM_MODE_CONNECTOR_DisplayPort:
+ case DRM_MODE_CONNECTOR_HDMIA:
+ case DRM_MODE_CONNECTOR_HDMIB:
+ display_type = ACPI_DISPLAY_TYPE_EXTERNAL_DIGITAL;
+ break;
+ case DRM_MODE_CONNECTOR_LVDS:
+ case DRM_MODE_CONNECTOR_eDP:
+ case DRM_MODE_CONNECTOR_DSI:
+ display_type = ACPI_DISPLAY_TYPE_INTERNAL_DIGITAL;
+ break;
+ case DRM_MODE_CONNECTOR_Unknown:
+ case DRM_MODE_CONNECTOR_VIRTUAL:
+ display_type = ACPI_DISPLAY_TYPE_OTHER;
+ break;
+ default:
+ MISSING_CASE(connector->base.connector_type);
+ display_type = ACPI_DISPLAY_TYPE_OTHER;
+ break;
+ }
+
+ return display_type;
+}
+
+void intel_populate_acpi_ids_for_all_connectors(struct drm_device *drm_dev)
+{
+ struct intel_connector *connector;
+ struct drm_connector_list_iter conn_iter;
+ u8 display_index[16] = {};
+ u32 device_id, type;
+
+ /* Populate the ACPI IDs for all connectors for a given drm_device */
+ drm_connector_list_iter_begin(drm_dev, &conn_iter);
+ for_each_intel_connector_iter(connector, &conn_iter) {
+
+ device_id = acpi_display_type(connector);
+
+ /* Use display type specific display index. */
+ type = (device_id & ACPI_DISPLAY_TYPE_MASK)
+ >> ACPI_DISPLAY_TYPE_SHIFT;
+ device_id |= display_index[type]++ << ACPI_DISPLAY_INDEX_SHIFT;
+
+ connector->acpi_device_id = device_id;
+ }
+ drm_connector_list_iter_end(&conn_iter);
+}
diff --git a/drivers/gpu/drm/i915/display/intel_acpi.h b/drivers/gpu/drm/i915/display/intel_acpi.h
index 1c576b3fb712..8f6d850df6fa 100644
--- a/drivers/gpu/drm/i915/display/intel_acpi.h
+++ b/drivers/gpu/drm/i915/display/intel_acpi.h
@@ -6,12 +6,18 @@
#ifndef __INTEL_ACPI_H__
#define __INTEL_ACPI_H__

+#include "intel_display_types.h"
+
#ifdef CONFIG_ACPI
void intel_register_dsm_handler(void);
void intel_unregister_dsm_handler(void);
+void intel_populate_acpi_ids_for_all_connectors(struct drm_device *drm_dev);
#else
static inline void intel_register_dsm_handler(void) { return; }
static inline void intel_unregister_dsm_handler(void) { return; }
+static inline void
+static inline void
+intel_populate_acpi_ids_for_all_connectors(struct drm_device *drm_dev) { }
#endif /* CONFIG_ACPI */

#endif /* __INTEL_ACPI_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_opregion.c b/drivers/gpu/drm/i915/display/intel_opregion.c
index 969ade623691..f5976a6ab3c4 100644
--- a/drivers/gpu/drm/i915/display/intel_opregion.c
+++ b/drivers/gpu/drm/i915/display/intel_opregion.c
@@ -35,6 +35,7 @@
#include "display/intel_panel.h"

#include "i915_drv.h"
+#include "intel_acpi.h"
#include "intel_display_types.h"
#include "intel_opregion.h"

@@ -242,29 +243,6 @@ struct opregion_asle_ext {
#define SWSCI_SBCB_POST_VBE_PM SWSCI_FUNCTION_CODE(SWSCI_SBCB, 19)
#define SWSCI_SBCB_ENABLE_DISABLE_AUDIO SWSCI_FUNCTION_CODE(SWSCI_SBCB, 21)

-/*
- * ACPI Specification, Revision 5.0, Appendix B.3.2 _DOD (Enumerate All Devices
- * Attached to the Display Adapter).
- */
-#define ACPI_DISPLAY_INDEX_SHIFT 0
-#define ACPI_DISPLAY_INDEX_MASK (0xf << 0)
-#define ACPI_DISPLAY_PORT_ATTACHMENT_SHIFT 4
-#define ACPI_DISPLAY_PORT_ATTACHMENT_MASK (0xf << 4)
-#define ACPI_DISPLAY_TYPE_SHIFT 8
-#define ACPI_DISPLAY_TYPE_MASK (0xf << 8)
-#define ACPI_DISPLAY_TYPE_OTHER (0 << 8)
-#define ACPI_DISPLAY_TYPE_VGA (1 << 8)
-#define ACPI_DISPLAY_TYPE_TV (2 << 8)
-#define ACPI_DISPLAY_TYPE_EXTERNAL_DIGITAL (3 << 8)
-#define ACPI_DISPLAY_TYPE_INTERNAL_DIGITAL (4 << 8)
-#define ACPI_VENDOR_SPECIFIC_SHIFT 12
-#define ACPI_VENDOR_SPECIFIC_MASK (0xf << 12)
-#define ACPI_BIOS_CAN_DETECT (1 << 16)
-#define ACPI_DEPENDS_ON_VGA (1 << 17)
-#define ACPI_PIPE_ID_SHIFT 18
-#define ACPI_PIPE_ID_MASK (7 << 18)
-#define ACPI_DEVICE_ID_SCHEME (1 << 31)
-
#define MAX_DSLP 1500

static int swsci(struct drm_i915_private *dev_priv,
@@ -662,54 +640,12 @@ static void set_did(struct intel_opregion *opregion, int i, u32 val)
}
}

-static u32 acpi_display_type(struct intel_connector *connector)
-{
- u32 display_type;
-
- switch (connector->base.connector_type) {
- case DRM_MODE_CONNECTOR_VGA:
- case DRM_MODE_CONNECTOR_DVIA:
- display_type = ACPI_DISPLAY_TYPE_VGA;
- break;
- case DRM_MODE_CONNECTOR_Composite:
- case DRM_MODE_CONNECTOR_SVIDEO:
- case DRM_MODE_CONNECTOR_Component:
- case DRM_MODE_CONNECTOR_9PinDIN:
- case DRM_MODE_CONNECTOR_TV:
- display_type = ACPI_DISPLAY_TYPE_TV;
- break;
- case DRM_MODE_CONNECTOR_DVII:
- case DRM_MODE_CONNECTOR_DVID:
- case DRM_MODE_CONNECTOR_DisplayPort:
- case DRM_MODE_CONNECTOR_HDMIA:
- case DRM_MODE_CONNECTOR_HDMIB:
- display_type = ACPI_DISPLAY_TYPE_EXTERNAL_DIGITAL;
- break;
- case DRM_MODE_CONNECTOR_LVDS:
- case DRM_MODE_CONNECTOR_eDP:
- case DRM_MODE_CONNECTOR_DSI:
- display_type = ACPI_DISPLAY_TYPE_INTERNAL_DIGITAL;
- break;
- case DRM_MODE_CONNECTOR_Unknown:
- case DRM_MODE_CONNECTOR_VIRTUAL:
- display_type = ACPI_DISPLAY_TYPE_OTHER;
- break;
- default:
- MISSING_CASE(connector->base.connector_type);
- display_type = ACPI_DISPLAY_TYPE_OTHER;
- break;
- }
-
- return display_type;
-}
-
static void intel_didl_outputs(struct drm_i915_private *dev_priv)
{
struct intel_opregion *opregion = &dev_priv->opregion;
struct intel_connector *connector;
struct drm_connector_list_iter conn_iter;
int i = 0, max_outputs;
- int display_index[16] = {};

/*
* In theory, did2, the extended didl, gets added at opregion version
@@ -721,20 +657,12 @@ static void intel_didl_outputs(struct drm_i915_private *dev_priv)
max_outputs = ARRAY_SIZE(opregion->acpi->didl) +
ARRAY_SIZE(opregion->acpi->did2);

+ intel_populate_acpi_ids_for_all_connectors(&dev_priv->drm);
+
drm_connector_list_iter_begin(&dev_priv->drm, &conn_iter);
for_each_intel_connector_iter(connector, &conn_iter) {
- u32 device_id, type;
-
- device_id = acpi_display_type(connector);
-
- /* Use display type specific display index. */
- type = (device_id & ACPI_DISPLAY_TYPE_MASK)
- >> ACPI_DISPLAY_TYPE_SHIFT;
- device_id |= display_index[type]++ << ACPI_DISPLAY_INDEX_SHIFT;
-
- connector->acpi_device_id = device_id;
if (i < max_outputs)
- set_did(opregion, i, device_id);
+ set_did(opregion, i, connector->acpi_device_id);
i++;
}
drm_connector_list_iter_end(&conn_iter);
--
2.24.0.rc1.363.gb1bccd3e3d-goog

2019-11-04 19:42:51

by Rajat Jain

[permalink] [raw]
Subject: [PATCH v2 2/3] drm/i915: Lookup and attach ACPI device node for connectors

Lookup and attach ACPI nodes for intel connectors. The lookup is done
in compliance with ACPI Spec 6.3
https://uefi.org/sites/default/files/resources/ACPI_6_3_final_Jan30.pdf
(Ref: Pages 1119 - 1123).

This can be useful for any connector specific platform properties. (This
will be used for privacy screen in next patch).

Signed-off-by: Rajat Jain <[email protected]>
Change-Id: I798e70714a4402554c8cd2a8e58268353f75814f
---
v2: formed by splitting the original patch into ACPI lookup, and privacy
screen property. Also move it into i915 now that I found existing code
in i915 that can be re-used.

drivers/gpu/drm/i915/display/intel_acpi.c | 50 +++++++++++++++++++
drivers/gpu/drm/i915/display/intel_acpi.h | 4 +-
.../drm/i915/display/intel_display_types.h | 3 ++
drivers/gpu/drm/i915/display/intel_dp.c | 4 ++
4 files changed, 60 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/display/intel_acpi.c b/drivers/gpu/drm/i915/display/intel_acpi.c
index 748d9b3125dd..0c10516430b1 100644
--- a/drivers/gpu/drm/i915/display/intel_acpi.c
+++ b/drivers/gpu/drm/i915/display/intel_acpi.c
@@ -243,3 +243,53 @@ void intel_populate_acpi_ids_for_all_connectors(struct drm_device *drm_dev)
}
drm_connector_list_iter_end(&conn_iter);
}
+
+/*
+ * 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. 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 functions looks up the ACPI node for a connector and returns
+ * it. Technically it is independent from the i915 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 an acpi device ID which is build using an index within a particular
+ * type of port (Ref to the pages of spec mentioned above, and to code in
+ * intel_populate_acpi_ids_for_all_connectors()). This device index
+ * unfortunately is not available in DRM code, so currently its call is
+ * originated from i915 driver. If in future this is useful for other drivers
+ * and we can find a generic way of getting a device index, we should move this
+ * function to drm code, maybe.
+ */
+void intel_connector_lookup_acpi_node(struct intel_connector *intel_connector)
+{
+ struct drm_device *drm_dev = intel_connector->base.dev;
+ struct device *dev = &drm_dev->pdev->dev;
+ struct acpi_device *conn_dev;
+ u64 conn_addr;
+
+ /*
+ * Repopulate ACPI IDs for all connectors is needed because the display
+ * index may have changed as a result of hotplugging and unplugging
+ * connectors
+ */
+ intel_populate_acpi_ids_for_all_connectors(drm_dev);
+
+ /* Build the _ADR to look for */
+ conn_addr = intel_connector->acpi_device_id;
+ conn_addr |= ACPI_DEVICE_ID_SCHEME;
+ conn_addr |= ACPI_BIOS_CAN_DETECT;
+
+ DRM_DEV_INFO(dev, "Looking for connector ACPI node at _ADR=%llX\n",
+ conn_addr);
+
+ /* Look up the connector device, under the PCI device */
+ conn_dev = acpi_find_child_device(ACPI_COMPANION(dev), conn_addr,
+ false);
+ intel_connector->acpi_handle = conn_dev ? conn_dev->handle : NULL;
+}
diff --git a/drivers/gpu/drm/i915/display/intel_acpi.h b/drivers/gpu/drm/i915/display/intel_acpi.h
index 8f6d850df6fa..61a4392fac4a 100644
--- a/drivers/gpu/drm/i915/display/intel_acpi.h
+++ b/drivers/gpu/drm/i915/display/intel_acpi.h
@@ -9,14 +9,16 @@
#include "intel_display_types.h"

#ifdef CONFIG_ACPI
+void intel_connector_lookup_acpi_node(struct intel_connector *connector);
void intel_register_dsm_handler(void);
void intel_unregister_dsm_handler(void);
void intel_populate_acpi_ids_for_all_connectors(struct drm_device *drm_dev);
#else
+static inline void
+intel_connector_lookup_acpi_node(struct intel_connector *connector) { return; }
static inline void intel_register_dsm_handler(void) { return; }
static inline void intel_unregister_dsm_handler(void) { return; }
static inline void
-static inline void
intel_populate_acpi_ids_for_all_connectors(struct drm_device *drm_dev) { }
#endif /* CONFIG_ACPI */

diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
index 449abaea619f..c2706afc069b 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -400,6 +400,9 @@ struct intel_connector {
/* ACPI device id for ACPI and driver cooperation */
u32 acpi_device_id;

+ /* ACPI handle corresponding to this connector display, if found */
+ void *acpi_handle;
+
/* Reads out the current hw, returning true if the connector is enabled
* and active (i.e. dpms ON state). */
bool (*get_hw_state)(struct intel_connector *);
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index f865615172a5..4fac408a4299 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -45,6 +45,7 @@
#include "i915_debugfs.h"
#include "i915_drv.h"
#include "i915_trace.h"
+#include "intel_acpi.h"
#include "intel_atomic.h"
#include "intel_audio.h"
#include "intel_connector.h"
@@ -6333,6 +6334,7 @@ intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connect
{
struct drm_i915_private *dev_priv = to_i915(connector->dev);
enum port port = dp_to_dig_port(intel_dp)->base.port;
+ struct intel_connector *intel_connector = to_intel_connector(connector);

if (!IS_G4X(dev_priv) && port != PORT_A)
intel_attach_force_audio_property(connector);
@@ -6354,6 +6356,8 @@ intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connect

connector->state->scaling_mode = DRM_MODE_SCALE_ASPECT;

+ /* Lookup the ACPI node corresponding to the connector */
+ intel_connector_lookup_acpi_node(intel_connector);
}
}

--
2.24.0.rc1.363.gb1bccd3e3d-goog

2019-11-04 19:45:06

by Rajat Jain

[permalink] [raw]
Subject: [PATCH v2 3/3] drm/i915: Add support for integrated privacy screens

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 <[email protected]>
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 <linux/acpi.h>
+
+#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
--
2.24.0.rc1.363.gb1bccd3e3d-goog

2019-11-12 19:15:12

by Rajat Jain

[permalink] [raw]
Subject: Re: [PATCH v2 3/3] drm/i915: Add support for integrated privacy screens

On Mon, Nov 4, 2019 at 11:41 AM Rajat Jain <[email protected]> wrote:
>
> 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 <[email protected]>
> Change-Id: Ic9ff07fc4a50797d2d0dfb919f11aa0821a4b548


Hi Folks,

I posted a v2 taking care of the comments I received (also split it
into 3 patches now, and resused some ACPI code I found in i915
driver). . Wondering if any one got a chance to look at this?

Thanks,

Rajat

> ---
> 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 <linux/acpi.h>
> +
> +#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
> --
> 2.24.0.rc1.363.gb1bccd3e3d-goog
>

2019-11-20 14:52:38

by Jani Nikula

[permalink] [raw]
Subject: Re: [PATCH v2 2/3] drm/i915: Lookup and attach ACPI device node for connectors

On Mon, 04 Nov 2019, Rajat Jain <[email protected]> wrote:
> Lookup and attach ACPI nodes for intel connectors. The lookup is done
> in compliance with ACPI Spec 6.3
> https://uefi.org/sites/default/files/resources/ACPI_6_3_final_Jan30.pdf
> (Ref: Pages 1119 - 1123).
>
> This can be useful for any connector specific platform properties. (This
> will be used for privacy screen in next patch).
>
> Signed-off-by: Rajat Jain <[email protected]>
> Change-Id: I798e70714a4402554c8cd2a8e58268353f75814f
> ---
> v2: formed by splitting the original patch into ACPI lookup, and privacy
> screen property. Also move it into i915 now that I found existing code
> in i915 that can be re-used.
>
> drivers/gpu/drm/i915/display/intel_acpi.c | 50 +++++++++++++++++++
> drivers/gpu/drm/i915/display/intel_acpi.h | 4 +-
> .../drm/i915/display/intel_display_types.h | 3 ++
> drivers/gpu/drm/i915/display/intel_dp.c | 4 ++
> 4 files changed, 60 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/i915/display/intel_acpi.c b/drivers/gpu/drm/i915/display/intel_acpi.c
> index 748d9b3125dd..0c10516430b1 100644
> --- a/drivers/gpu/drm/i915/display/intel_acpi.c
> +++ b/drivers/gpu/drm/i915/display/intel_acpi.c
> @@ -243,3 +243,53 @@ void intel_populate_acpi_ids_for_all_connectors(struct drm_device *drm_dev)
> }
> drm_connector_list_iter_end(&conn_iter);
> }
> +
> +/*
> + * 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. 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 functions looks up the ACPI node for a connector and returns
> + * it. Technically it is independent from the i915 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 an acpi device ID which is build using an index within a particular
> + * type of port (Ref to the pages of spec mentioned above, and to code in
> + * intel_populate_acpi_ids_for_all_connectors()). This device index
> + * unfortunately is not available in DRM code, so currently its call is
> + * originated from i915 driver. If in future this is useful for other drivers
> + * and we can find a generic way of getting a device index, we should move this
> + * function to drm code, maybe.
> + */
> +void intel_connector_lookup_acpi_node(struct intel_connector *intel_connector)

Nitpick, I'd expect a "lookup" function to return whatever it is looking
up, not modify its argument.

> +{
> + struct drm_device *drm_dev = intel_connector->base.dev;
> + struct device *dev = &drm_dev->pdev->dev;
> + struct acpi_device *conn_dev;
> + u64 conn_addr;
> +
> + /*
> + * Repopulate ACPI IDs for all connectors is needed because the display
> + * index may have changed as a result of hotplugging and unplugging
> + * connectors
> + */

I think that can only be true for DP MST. For everything else, I don't
think so. Anyway, why are we doing it here then, depending on whether
someone calls this function or not? If it matters, we should be doing
this whenever there's a chance they've changed, right?

> + intel_populate_acpi_ids_for_all_connectors(drm_dev);
> +
> + /* Build the _ADR to look for */
> + conn_addr = intel_connector->acpi_device_id;
> + conn_addr |= ACPI_DEVICE_ID_SCHEME;
> + conn_addr |= ACPI_BIOS_CAN_DETECT;
> +
> + DRM_DEV_INFO(dev, "Looking for connector ACPI node at _ADR=%llX\n",
> + conn_addr);
> +
> + /* Look up the connector device, under the PCI device */
> + conn_dev = acpi_find_child_device(ACPI_COMPANION(dev), conn_addr,
> + false);
> + intel_connector->acpi_handle = conn_dev ? conn_dev->handle : NULL;

Why don't we do this as part of
intel_populate_acpi_ids_for_all_connectors() or whatever it'll be
called?

> +}
> diff --git a/drivers/gpu/drm/i915/display/intel_acpi.h b/drivers/gpu/drm/i915/display/intel_acpi.h
> index 8f6d850df6fa..61a4392fac4a 100644
> --- a/drivers/gpu/drm/i915/display/intel_acpi.h
> +++ b/drivers/gpu/drm/i915/display/intel_acpi.h
> @@ -9,14 +9,16 @@
> #include "intel_display_types.h"
>
> #ifdef CONFIG_ACPI
> +void intel_connector_lookup_acpi_node(struct intel_connector *connector);
> void intel_register_dsm_handler(void);
> void intel_unregister_dsm_handler(void);
> void intel_populate_acpi_ids_for_all_connectors(struct drm_device *drm_dev);
> #else
> +static inline void
> +intel_connector_lookup_acpi_node(struct intel_connector *connector) { return; }
> static inline void intel_register_dsm_handler(void) { return; }
> static inline void intel_unregister_dsm_handler(void) { return; }
> static inline void
> -static inline void

Whoops.

> intel_populate_acpi_ids_for_all_connectors(struct drm_device *drm_dev) { }
> #endif /* CONFIG_ACPI */
>
> diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
> index 449abaea619f..c2706afc069b 100644
> --- a/drivers/gpu/drm/i915/display/intel_display_types.h
> +++ b/drivers/gpu/drm/i915/display/intel_display_types.h
> @@ -400,6 +400,9 @@ struct intel_connector {
> /* ACPI device id for ACPI and driver cooperation */
> u32 acpi_device_id;
>
> + /* ACPI handle corresponding to this connector display, if found */
> + void *acpi_handle;
> +
> /* Reads out the current hw, returning true if the connector is enabled
> * and active (i.e. dpms ON state). */
> bool (*get_hw_state)(struct intel_connector *);
> diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
> index f865615172a5..4fac408a4299 100644
> --- a/drivers/gpu/drm/i915/display/intel_dp.c
> +++ b/drivers/gpu/drm/i915/display/intel_dp.c
> @@ -45,6 +45,7 @@
> #include "i915_debugfs.h"
> #include "i915_drv.h"
> #include "i915_trace.h"
> +#include "intel_acpi.h"
> #include "intel_atomic.h"
> #include "intel_audio.h"
> #include "intel_connector.h"
> @@ -6333,6 +6334,7 @@ intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connect
> {
> struct drm_i915_private *dev_priv = to_i915(connector->dev);
> enum port port = dp_to_dig_port(intel_dp)->base.port;
> + struct intel_connector *intel_connector = to_intel_connector(connector);
>
> if (!IS_G4X(dev_priv) && port != PORT_A)
> intel_attach_force_audio_property(connector);
> @@ -6354,6 +6356,8 @@ intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connect
>
> connector->state->scaling_mode = DRM_MODE_SCALE_ASPECT;
>
> + /* Lookup the ACPI node corresponding to the connector */
> + intel_connector_lookup_acpi_node(intel_connector);

This is an odd place to do this, isn't it? It's only called once, but
you say the acpi id may change at hotplug.

BR,
Jani.

> }
> }

--
Jani Nikula, Intel Open Source Graphics Center

2019-11-20 15:48:10

by Jani Nikula

[permalink] [raw]
Subject: Re: [PATCH v2 1/3] drm/i915: Move the code to populate ACPI device ID into intel_acpi

On Mon, 04 Nov 2019, Rajat Jain <[email protected]> wrote:
> Move the code that populates the ACPI device ID for devices, into
> more appripriate intel_acpi.c. This is done in preparation for more
> users of this code (in next patch).

I don't think your use of the code makes sense (I'll explain in reply to
the other patches) but I could be persuaded to move the code to
intel_acpi.c.

> Signed-off-by: Rajat Jain <[email protected]>
> Change-Id: Ifb3bd458734985c2a78ba682e6f0a2e63e0626ca

Please drop Change-Ids.

> ---
> v2: v1 doesn't exist. Found existing code in i915 driver to assign the ACPI ID
> which is what I plan to re-use.
>
>
> drivers/gpu/drm/i915/display/intel_acpi.c | 87 +++++++++++++++++++
> drivers/gpu/drm/i915/display/intel_acpi.h | 6 ++
> drivers/gpu/drm/i915/display/intel_opregion.c | 80 +----------------
> 3 files changed, 97 insertions(+), 76 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/display/intel_acpi.c b/drivers/gpu/drm/i915/display/intel_acpi.c
> index 3456d33feb46..748d9b3125dd 100644
> --- a/drivers/gpu/drm/i915/display/intel_acpi.c
> +++ b/drivers/gpu/drm/i915/display/intel_acpi.c
> @@ -156,3 +156,90 @@ void intel_register_dsm_handler(void)
> void intel_unregister_dsm_handler(void)
> {
> }
> +
> +/*
> + * ACPI Specification, Revision 5.0, Appendix B.3.2 _DOD (Enumerate All Devices
> + * Attached to the Display Adapter).
> + */
> +#define ACPI_DISPLAY_INDEX_SHIFT 0
> +#define ACPI_DISPLAY_INDEX_MASK (0xf << 0)
> +#define ACPI_DISPLAY_PORT_ATTACHMENT_SHIFT 4
> +#define ACPI_DISPLAY_PORT_ATTACHMENT_MASK (0xf << 4)
> +#define ACPI_DISPLAY_TYPE_SHIFT 8
> +#define ACPI_DISPLAY_TYPE_MASK (0xf << 8)
> +#define ACPI_DISPLAY_TYPE_OTHER (0 << 8)
> +#define ACPI_DISPLAY_TYPE_VGA (1 << 8)
> +#define ACPI_DISPLAY_TYPE_TV (2 << 8)
> +#define ACPI_DISPLAY_TYPE_EXTERNAL_DIGITAL (3 << 8)
> +#define ACPI_DISPLAY_TYPE_INTERNAL_DIGITAL (4 << 8)
> +#define ACPI_VENDOR_SPECIFIC_SHIFT 12
> +#define ACPI_VENDOR_SPECIFIC_MASK (0xf << 12)
> +#define ACPI_BIOS_CAN_DETECT (1 << 16)
> +#define ACPI_DEPENDS_ON_VGA (1 << 17)
> +#define ACPI_PIPE_ID_SHIFT 18
> +#define ACPI_PIPE_ID_MASK (7 << 18)
> +#define ACPI_DEVICE_ID_SCHEME (1ULL << 31)
> +
> +static u32 acpi_display_type(struct intel_connector *connector)
> +{
> + u32 display_type;
> +
> + switch (connector->base.connector_type) {
> + case DRM_MODE_CONNECTOR_VGA:
> + case DRM_MODE_CONNECTOR_DVIA:
> + display_type = ACPI_DISPLAY_TYPE_VGA;
> + break;
> + case DRM_MODE_CONNECTOR_Composite:
> + case DRM_MODE_CONNECTOR_SVIDEO:
> + case DRM_MODE_CONNECTOR_Component:
> + case DRM_MODE_CONNECTOR_9PinDIN:
> + case DRM_MODE_CONNECTOR_TV:
> + display_type = ACPI_DISPLAY_TYPE_TV;
> + break;
> + case DRM_MODE_CONNECTOR_DVII:
> + case DRM_MODE_CONNECTOR_DVID:
> + case DRM_MODE_CONNECTOR_DisplayPort:
> + case DRM_MODE_CONNECTOR_HDMIA:
> + case DRM_MODE_CONNECTOR_HDMIB:
> + display_type = ACPI_DISPLAY_TYPE_EXTERNAL_DIGITAL;
> + break;
> + case DRM_MODE_CONNECTOR_LVDS:
> + case DRM_MODE_CONNECTOR_eDP:
> + case DRM_MODE_CONNECTOR_DSI:
> + display_type = ACPI_DISPLAY_TYPE_INTERNAL_DIGITAL;
> + break;
> + case DRM_MODE_CONNECTOR_Unknown:
> + case DRM_MODE_CONNECTOR_VIRTUAL:
> + display_type = ACPI_DISPLAY_TYPE_OTHER;
> + break;
> + default:
> + MISSING_CASE(connector->base.connector_type);
> + display_type = ACPI_DISPLAY_TYPE_OTHER;
> + break;
> + }
> +
> + return display_type;
> +}
> +
> +void intel_populate_acpi_ids_for_all_connectors(struct drm_device *drm_dev)

Plase use intel_foo_ prefix for functions in intel_foo.c,
i.e. intel_acpi_ here. Say, intel_acpi_device_id_update() or something.

Please always prefer struct drm_i915_private *i915 over struct
drm_device * pointers in i915 code.

> +{
> + struct intel_connector *connector;
> + struct drm_connector_list_iter conn_iter;
> + u8 display_index[16] = {};
> + u32 device_id, type;
> +
> + /* Populate the ACPI IDs for all connectors for a given drm_device */
> + drm_connector_list_iter_begin(drm_dev, &conn_iter);
> + for_each_intel_connector_iter(connector, &conn_iter) {
> +

Superfluous newline, the device_id and type local vars could be here as
in the original.

> + device_id = acpi_display_type(connector);
> +
> + /* Use display type specific display index. */
> + type = (device_id & ACPI_DISPLAY_TYPE_MASK)
> + >> ACPI_DISPLAY_TYPE_SHIFT;
> + device_id |= display_index[type]++ << ACPI_DISPLAY_INDEX_SHIFT;
> +
> + connector->acpi_device_id = device_id;
> + }
> + drm_connector_list_iter_end(&conn_iter);
> +}
> diff --git a/drivers/gpu/drm/i915/display/intel_acpi.h b/drivers/gpu/drm/i915/display/intel_acpi.h
> index 1c576b3fb712..8f6d850df6fa 100644
> --- a/drivers/gpu/drm/i915/display/intel_acpi.h
> +++ b/drivers/gpu/drm/i915/display/intel_acpi.h
> @@ -6,12 +6,18 @@
> #ifndef __INTEL_ACPI_H__
> #define __INTEL_ACPI_H__
>
> +#include "intel_display_types.h"
> +

Please prefer forward declarations over adding new includes.

struct drm_i915_private;

> #ifdef CONFIG_ACPI
> void intel_register_dsm_handler(void);
> void intel_unregister_dsm_handler(void);
> +void intel_populate_acpi_ids_for_all_connectors(struct drm_device *drm_dev);
> #else
> static inline void intel_register_dsm_handler(void) { return; }
> static inline void intel_unregister_dsm_handler(void) { return; }
> +static inline void
> +static inline void

Whoops.

> +intel_populate_acpi_ids_for_all_connectors(struct drm_device *drm_dev) { }
> #endif /* CONFIG_ACPI */
>
> #endif /* __INTEL_ACPI_H__ */
> diff --git a/drivers/gpu/drm/i915/display/intel_opregion.c b/drivers/gpu/drm/i915/display/intel_opregion.c
> index 969ade623691..f5976a6ab3c4 100644
> --- a/drivers/gpu/drm/i915/display/intel_opregion.c
> +++ b/drivers/gpu/drm/i915/display/intel_opregion.c
> @@ -35,6 +35,7 @@
> #include "display/intel_panel.h"
>
> #include "i915_drv.h"
> +#include "intel_acpi.h"
> #include "intel_display_types.h"
> #include "intel_opregion.h"
>
> @@ -242,29 +243,6 @@ struct opregion_asle_ext {
> #define SWSCI_SBCB_POST_VBE_PM SWSCI_FUNCTION_CODE(SWSCI_SBCB, 19)
> #define SWSCI_SBCB_ENABLE_DISABLE_AUDIO SWSCI_FUNCTION_CODE(SWSCI_SBCB, 21)
>
> -/*
> - * ACPI Specification, Revision 5.0, Appendix B.3.2 _DOD (Enumerate All Devices
> - * Attached to the Display Adapter).
> - */
> -#define ACPI_DISPLAY_INDEX_SHIFT 0
> -#define ACPI_DISPLAY_INDEX_MASK (0xf << 0)
> -#define ACPI_DISPLAY_PORT_ATTACHMENT_SHIFT 4
> -#define ACPI_DISPLAY_PORT_ATTACHMENT_MASK (0xf << 4)
> -#define ACPI_DISPLAY_TYPE_SHIFT 8
> -#define ACPI_DISPLAY_TYPE_MASK (0xf << 8)
> -#define ACPI_DISPLAY_TYPE_OTHER (0 << 8)
> -#define ACPI_DISPLAY_TYPE_VGA (1 << 8)
> -#define ACPI_DISPLAY_TYPE_TV (2 << 8)
> -#define ACPI_DISPLAY_TYPE_EXTERNAL_DIGITAL (3 << 8)
> -#define ACPI_DISPLAY_TYPE_INTERNAL_DIGITAL (4 << 8)
> -#define ACPI_VENDOR_SPECIFIC_SHIFT 12
> -#define ACPI_VENDOR_SPECIFIC_MASK (0xf << 12)
> -#define ACPI_BIOS_CAN_DETECT (1 << 16)
> -#define ACPI_DEPENDS_ON_VGA (1 << 17)
> -#define ACPI_PIPE_ID_SHIFT 18
> -#define ACPI_PIPE_ID_MASK (7 << 18)
> -#define ACPI_DEVICE_ID_SCHEME (1 << 31)
> -
> #define MAX_DSLP 1500
>
> static int swsci(struct drm_i915_private *dev_priv,
> @@ -662,54 +640,12 @@ static void set_did(struct intel_opregion *opregion, int i, u32 val)
> }
> }
>
> -static u32 acpi_display_type(struct intel_connector *connector)
> -{
> - u32 display_type;
> -
> - switch (connector->base.connector_type) {
> - case DRM_MODE_CONNECTOR_VGA:
> - case DRM_MODE_CONNECTOR_DVIA:
> - display_type = ACPI_DISPLAY_TYPE_VGA;
> - break;
> - case DRM_MODE_CONNECTOR_Composite:
> - case DRM_MODE_CONNECTOR_SVIDEO:
> - case DRM_MODE_CONNECTOR_Component:
> - case DRM_MODE_CONNECTOR_9PinDIN:
> - case DRM_MODE_CONNECTOR_TV:
> - display_type = ACPI_DISPLAY_TYPE_TV;
> - break;
> - case DRM_MODE_CONNECTOR_DVII:
> - case DRM_MODE_CONNECTOR_DVID:
> - case DRM_MODE_CONNECTOR_DisplayPort:
> - case DRM_MODE_CONNECTOR_HDMIA:
> - case DRM_MODE_CONNECTOR_HDMIB:
> - display_type = ACPI_DISPLAY_TYPE_EXTERNAL_DIGITAL;
> - break;
> - case DRM_MODE_CONNECTOR_LVDS:
> - case DRM_MODE_CONNECTOR_eDP:
> - case DRM_MODE_CONNECTOR_DSI:
> - display_type = ACPI_DISPLAY_TYPE_INTERNAL_DIGITAL;
> - break;
> - case DRM_MODE_CONNECTOR_Unknown:
> - case DRM_MODE_CONNECTOR_VIRTUAL:
> - display_type = ACPI_DISPLAY_TYPE_OTHER;
> - break;
> - default:
> - MISSING_CASE(connector->base.connector_type);
> - display_type = ACPI_DISPLAY_TYPE_OTHER;
> - break;
> - }
> -
> - return display_type;
> -}
> -
> static void intel_didl_outputs(struct drm_i915_private *dev_priv)
> {
> struct intel_opregion *opregion = &dev_priv->opregion;
> struct intel_connector *connector;
> struct drm_connector_list_iter conn_iter;
> int i = 0, max_outputs;
> - int display_index[16] = {};
>
> /*
> * In theory, did2, the extended didl, gets added at opregion version
> @@ -721,20 +657,12 @@ static void intel_didl_outputs(struct drm_i915_private *dev_priv)
> max_outputs = ARRAY_SIZE(opregion->acpi->didl) +
> ARRAY_SIZE(opregion->acpi->did2);
>
> + intel_populate_acpi_ids_for_all_connectors(&dev_priv->drm);
> +

As the acpi_device_ids will be used elsewhere too, maybe this call needs
to be moved to a higher level and called on the resume path. *shrug*

BR,
Jani.

> drm_connector_list_iter_begin(&dev_priv->drm, &conn_iter);
> for_each_intel_connector_iter(connector, &conn_iter) {
> - u32 device_id, type;
> -
> - device_id = acpi_display_type(connector);
> -
> - /* Use display type specific display index. */
> - type = (device_id & ACPI_DISPLAY_TYPE_MASK)
> - >> ACPI_DISPLAY_TYPE_SHIFT;
> - device_id |= display_index[type]++ << ACPI_DISPLAY_INDEX_SHIFT;
> -
> - connector->acpi_device_id = device_id;
> if (i < max_outputs)
> - set_did(opregion, i, device_id);
> + set_did(opregion, i, connector->acpi_device_id);
> i++;
> }
> drm_connector_list_iter_end(&conn_iter);

--
Jani Nikula, Intel Open Source Graphics Center

2019-11-20 15:57:34

by Jani Nikula

[permalink] [raw]
Subject: Re: [PATCH v2 3/3] drm/i915: Add support for integrated privacy screens

On Tue, 12 Nov 2019, Rajat Jain <[email protected]> wrote:
> On Mon, Nov 4, 2019 at 11:41 AM Rajat Jain <[email protected]> wrote:
>>
>> 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 <[email protected]>
>> Change-Id: Ic9ff07fc4a50797d2d0dfb919f11aa0821a4b548
>
>
> Hi Folks,
>
> I posted a v2 taking care of the comments I received (also split it
> into 3 patches now, and resused some ACPI code I found in i915
> driver). . Wondering if any one got a chance to look at this?

For future reference, please post the updated series standalone, *not*
in reply to long, old threads. Besides myself, it'll also help our CI
find your patches and crunch a bunch of tests on them.

Also, do you have an open userspace for this? See [1]. I think this
looks like good stuff to me, but then I'm not responsible for any
userspace component that would actually use this.

BR,
Jani.


[1] https://www.kernel.org/doc/html/latest/gpu/drm-uapi.html#open-source-userspace-requirements



>
> Thanks,
>
> Rajat
>
>> ---
>> 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 <linux/acpi.h>
>> +
>> +#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
>> --
>> 2.24.0.rc1.363.gb1bccd3e3d-goog
>>

--
Jani Nikula, Intel Open Source Graphics Center

2019-11-20 17:18:08

by Jani Nikula

[permalink] [raw]
Subject: Re: [PATCH v2 3/3] drm/i915: Add support for integrated privacy screens

On Mon, 04 Nov 2019, Rajat Jain <[email protected]> wrote:
> 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 <[email protected]>
> 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

Mmmh, wonder if there'll be non-ACPI based privacy screens. I guess we
can sort this out then. *shrug*

> 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);
> +}

I think this should be a drm core level property in drm_connector.[ch]
so that *all* drivers would use the same thing for privacy screens. Not
i915 specific.

I think this is the biggest issue in the patch series.

> 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

Please read http://mid.mail-archive.com/CAKMK7uH-8+tbKsAoiChsxELEc_77RVVxP2wapHWhqB+0Viifog@mail.gmail.com

> +/*
> + * Intel ACPI privacy screen code
> + *
> + * Copyright © 2019 Google Inc.
> + */
> +
> +#include <linux/acpi.h>
> +
> +#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)

Just name the parameter connector, not intel_connector. This throughout.

> +{
> + 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);

else complain?

> +}
> +
> +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,
> +};
> +

The drm_property interface UAPI is based on the strings, *not* on the
values. Please move the enum out of uapi into the drm code.

BR,
jani.

> #if defined(__cplusplus)
> }
> #endif

--
Jani Nikula, Intel Open Source Graphics Center

2019-11-20 21:38:07

by Rajat Jain

[permalink] [raw]
Subject: Re: [PATCH v2 3/3] drm/i915: Add support for integrated privacy screens

Hi Jani,

On Wed, Nov 20, 2019 at 7:11 AM Jani Nikula <[email protected]> wrote:
>
> On Tue, 12 Nov 2019, Rajat Jain <[email protected]> wrote:
> > On Mon, Nov 4, 2019 at 11:41 AM Rajat Jain <[email protected]> wrote:
> >>
> >> 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 <[email protected]>
> >> Change-Id: Ic9ff07fc4a50797d2d0dfb919f11aa0821a4b548
> >
> >
> > Hi Folks,
> >
> > I posted a v2 taking care of the comments I received (also split it
> > into 3 patches now, and resused some ACPI code I found in i915
> > driver). . Wondering if any one got a chance to look at this?
>
> For future reference, please post the updated series standalone, *not*
> in reply to long, old threads. Besides myself, it'll also help our CI
> find your patches and crunch a bunch of tests on them.

Will do.

>
> Also, do you have an open userspace for this? See [1]. I think this
> looks like good stuff to me, but then I'm not responsible for any
> userspace component that would actually use this.

Not sure what you meant but the user for this on Chromebooks (what I
work on) would be the Chrome browser most likely.

Thanks & Best Regards,

Rajat

>
> BR,
> Jani.
>
>
> [1] https://www.kernel.org/doc/html/latest/gpu/drm-uapi.html#open-source-userspace-requirements
>
>
>
> >
> > Thanks,
> >
> > Rajat
> >
> >> ---
> >> 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 <linux/acpi.h>
> >> +
> >> +#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
> >> --
> >> 2.24.0.rc1.363.gb1bccd3e3d-goog
> >>
>
> --
> Jani Nikula, Intel Open Source Graphics Center

2019-12-05 09:36:00

by Rajat Jain

[permalink] [raw]
Subject: Re: [PATCH v2 1/3] drm/i915: Move the code to populate ACPI device ID into intel_acpi

Hi Jani,

Thanks for the review.

On Wed, Nov 20, 2019 at 6:41 AM Jani Nikula <[email protected]> wrote:
>
> On Mon, 04 Nov 2019, Rajat Jain <[email protected]> wrote:
> > Move the code that populates the ACPI device ID for devices, into
> > more appripriate intel_acpi.c. This is done in preparation for more
> > users of this code (in next patch).
>
> I don't think your use of the code makes sense (I'll explain in reply to
> the other patches)

OK, I'll discuss this there.

> but I could be persuaded to move the code to
> intel_acpi.c.
>
> > Signed-off-by: Rajat Jain <[email protected]>
> > Change-Id: Ifb3bd458734985c2a78ba682e6f0a2e63e0626ca
>
> Please drop Change-Ids.

Done.

>
> > ---
> > v2: v1 doesn't exist. Found existing code in i915 driver to assign the ACPI ID
> > which is what I plan to re-use.
> >
> >
> > drivers/gpu/drm/i915/display/intel_acpi.c | 87 +++++++++++++++++++
> > drivers/gpu/drm/i915/display/intel_acpi.h | 6 ++
> > drivers/gpu/drm/i915/display/intel_opregion.c | 80 +----------------
> > 3 files changed, 97 insertions(+), 76 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/i915/display/intel_acpi.c b/drivers/gpu/drm/i915/display/intel_acpi.c
> > index 3456d33feb46..748d9b3125dd 100644
> > --- a/drivers/gpu/drm/i915/display/intel_acpi.c
> > +++ b/drivers/gpu/drm/i915/display/intel_acpi.c
> > @@ -156,3 +156,90 @@ void intel_register_dsm_handler(void)
> > void intel_unregister_dsm_handler(void)
> > {
> > }
> > +
> > +/*
> > + * ACPI Specification, Revision 5.0, Appendix B.3.2 _DOD (Enumerate All Devices
> > + * Attached to the Display Adapter).
> > + */
> > +#define ACPI_DISPLAY_INDEX_SHIFT 0
> > +#define ACPI_DISPLAY_INDEX_MASK (0xf << 0)
> > +#define ACPI_DISPLAY_PORT_ATTACHMENT_SHIFT 4
> > +#define ACPI_DISPLAY_PORT_ATTACHMENT_MASK (0xf << 4)
> > +#define ACPI_DISPLAY_TYPE_SHIFT 8
> > +#define ACPI_DISPLAY_TYPE_MASK (0xf << 8)
> > +#define ACPI_DISPLAY_TYPE_OTHER (0 << 8)
> > +#define ACPI_DISPLAY_TYPE_VGA (1 << 8)
> > +#define ACPI_DISPLAY_TYPE_TV (2 << 8)
> > +#define ACPI_DISPLAY_TYPE_EXTERNAL_DIGITAL (3 << 8)
> > +#define ACPI_DISPLAY_TYPE_INTERNAL_DIGITAL (4 << 8)
> > +#define ACPI_VENDOR_SPECIFIC_SHIFT 12
> > +#define ACPI_VENDOR_SPECIFIC_MASK (0xf << 12)
> > +#define ACPI_BIOS_CAN_DETECT (1 << 16)
> > +#define ACPI_DEPENDS_ON_VGA (1 << 17)
> > +#define ACPI_PIPE_ID_SHIFT 18
> > +#define ACPI_PIPE_ID_MASK (7 << 18)
> > +#define ACPI_DEVICE_ID_SCHEME (1ULL << 31)
> > +
> > +static u32 acpi_display_type(struct intel_connector *connector)
> > +{
> > + u32 display_type;
> > +
> > + switch (connector->base.connector_type) {
> > + case DRM_MODE_CONNECTOR_VGA:
> > + case DRM_MODE_CONNECTOR_DVIA:
> > + display_type = ACPI_DISPLAY_TYPE_VGA;
> > + break;
> > + case DRM_MODE_CONNECTOR_Composite:
> > + case DRM_MODE_CONNECTOR_SVIDEO:
> > + case DRM_MODE_CONNECTOR_Component:
> > + case DRM_MODE_CONNECTOR_9PinDIN:
> > + case DRM_MODE_CONNECTOR_TV:
> > + display_type = ACPI_DISPLAY_TYPE_TV;
> > + break;
> > + case DRM_MODE_CONNECTOR_DVII:
> > + case DRM_MODE_CONNECTOR_DVID:
> > + case DRM_MODE_CONNECTOR_DisplayPort:
> > + case DRM_MODE_CONNECTOR_HDMIA:
> > + case DRM_MODE_CONNECTOR_HDMIB:
> > + display_type = ACPI_DISPLAY_TYPE_EXTERNAL_DIGITAL;
> > + break;
> > + case DRM_MODE_CONNECTOR_LVDS:
> > + case DRM_MODE_CONNECTOR_eDP:
> > + case DRM_MODE_CONNECTOR_DSI:
> > + display_type = ACPI_DISPLAY_TYPE_INTERNAL_DIGITAL;
> > + break;
> > + case DRM_MODE_CONNECTOR_Unknown:
> > + case DRM_MODE_CONNECTOR_VIRTUAL:
> > + display_type = ACPI_DISPLAY_TYPE_OTHER;
> > + break;
> > + default:
> > + MISSING_CASE(connector->base.connector_type);
> > + display_type = ACPI_DISPLAY_TYPE_OTHER;
> > + break;
> > + }
> > +
> > + return display_type;
> > +}
> > +
> > +void intel_populate_acpi_ids_for_all_connectors(struct drm_device *drm_dev)
>
> Plase use intel_foo_ prefix for functions in intel_foo.c,
> i.e. intel_acpi_ here. Say, intel_acpi_device_id_update() or something.

Done.

>
> Please always prefer struct drm_i915_private *i915 over struct
> drm_device * pointers in i915 code.

Done

>
> > +{
> > + struct intel_connector *connector;
> > + struct drm_connector_list_iter conn_iter;
> > + u8 display_index[16] = {};
> > + u32 device_id, type;
> > +
> > + /* Populate the ACPI IDs for all connectors for a given drm_device */
> > + drm_connector_list_iter_begin(drm_dev, &conn_iter);
> > + for_each_intel_connector_iter(connector, &conn_iter) {
> > +
>
> Superfluous newline, the device_id and type local vars could be here as
> in the original.

Done.

>
> > + device_id = acpi_display_type(connector);
> > +
> > + /* Use display type specific display index. */
> > + type = (device_id & ACPI_DISPLAY_TYPE_MASK)
> > + >> ACPI_DISPLAY_TYPE_SHIFT;
> > + device_id |= display_index[type]++ << ACPI_DISPLAY_INDEX_SHIFT;
> > +
> > + connector->acpi_device_id = device_id;
> > + }
> > + drm_connector_list_iter_end(&conn_iter);
> > +}
> > diff --git a/drivers/gpu/drm/i915/display/intel_acpi.h b/drivers/gpu/drm/i915/display/intel_acpi.h
> > index 1c576b3fb712..8f6d850df6fa 100644
> > --- a/drivers/gpu/drm/i915/display/intel_acpi.h
> > +++ b/drivers/gpu/drm/i915/display/intel_acpi.h
> > @@ -6,12 +6,18 @@
> > #ifndef __INTEL_ACPI_H__
> > #define __INTEL_ACPI_H__
> >
> > +#include "intel_display_types.h"
> > +
>
> Please prefer forward declarations over adding new includes.
>
> struct drm_i915_private;
>

Done.

> > #ifdef CONFIG_ACPI
> > void intel_register_dsm_handler(void);
> > void intel_unregister_dsm_handler(void);
> > +void intel_populate_acpi_ids_for_all_connectors(struct drm_device *drm_dev);
> > #else
> > static inline void intel_register_dsm_handler(void) { return; }
> > static inline void intel_unregister_dsm_handler(void) { return; }
> > +static inline void
> > +static inline void
>
> Whoops.

Done.

>
> > +intel_populate_acpi_ids_for_all_connectors(struct drm_device *drm_dev) { }
> > #endif /* CONFIG_ACPI */
> >
> > #endif /* __INTEL_ACPI_H__ */
> > diff --git a/drivers/gpu/drm/i915/display/intel_opregion.c b/drivers/gpu/drm/i915/display/intel_opregion.c
> > index 969ade623691..f5976a6ab3c4 100644
> > --- a/drivers/gpu/drm/i915/display/intel_opregion.c
> > +++ b/drivers/gpu/drm/i915/display/intel_opregion.c
> > @@ -35,6 +35,7 @@
> > #include "display/intel_panel.h"
> >
> > #include "i915_drv.h"
> > +#include "intel_acpi.h"
> > #include "intel_display_types.h"
> > #include "intel_opregion.h"
> >
> > @@ -242,29 +243,6 @@ struct opregion_asle_ext {
> > #define SWSCI_SBCB_POST_VBE_PM SWSCI_FUNCTION_CODE(SWSCI_SBCB, 19)
> > #define SWSCI_SBCB_ENABLE_DISABLE_AUDIO SWSCI_FUNCTION_CODE(SWSCI_SBCB, 21)
> >
> > -/*
> > - * ACPI Specification, Revision 5.0, Appendix B.3.2 _DOD (Enumerate All Devices
> > - * Attached to the Display Adapter).
> > - */
> > -#define ACPI_DISPLAY_INDEX_SHIFT 0
> > -#define ACPI_DISPLAY_INDEX_MASK (0xf << 0)
> > -#define ACPI_DISPLAY_PORT_ATTACHMENT_SHIFT 4
> > -#define ACPI_DISPLAY_PORT_ATTACHMENT_MASK (0xf << 4)
> > -#define ACPI_DISPLAY_TYPE_SHIFT 8
> > -#define ACPI_DISPLAY_TYPE_MASK (0xf << 8)
> > -#define ACPI_DISPLAY_TYPE_OTHER (0 << 8)
> > -#define ACPI_DISPLAY_TYPE_VGA (1 << 8)
> > -#define ACPI_DISPLAY_TYPE_TV (2 << 8)
> > -#define ACPI_DISPLAY_TYPE_EXTERNAL_DIGITAL (3 << 8)
> > -#define ACPI_DISPLAY_TYPE_INTERNAL_DIGITAL (4 << 8)
> > -#define ACPI_VENDOR_SPECIFIC_SHIFT 12
> > -#define ACPI_VENDOR_SPECIFIC_MASK (0xf << 12)
> > -#define ACPI_BIOS_CAN_DETECT (1 << 16)
> > -#define ACPI_DEPENDS_ON_VGA (1 << 17)
> > -#define ACPI_PIPE_ID_SHIFT 18
> > -#define ACPI_PIPE_ID_MASK (7 << 18)
> > -#define ACPI_DEVICE_ID_SCHEME (1 << 31)
> > -
> > #define MAX_DSLP 1500
> >
> > static int swsci(struct drm_i915_private *dev_priv,
> > @@ -662,54 +640,12 @@ static void set_did(struct intel_opregion *opregion, int i, u32 val)
> > }
> > }
> >
> > -static u32 acpi_display_type(struct intel_connector *connector)
> > -{
> > - u32 display_type;
> > -
> > - switch (connector->base.connector_type) {
> > - case DRM_MODE_CONNECTOR_VGA:
> > - case DRM_MODE_CONNECTOR_DVIA:
> > - display_type = ACPI_DISPLAY_TYPE_VGA;
> > - break;
> > - case DRM_MODE_CONNECTOR_Composite:
> > - case DRM_MODE_CONNECTOR_SVIDEO:
> > - case DRM_MODE_CONNECTOR_Component:
> > - case DRM_MODE_CONNECTOR_9PinDIN:
> > - case DRM_MODE_CONNECTOR_TV:
> > - display_type = ACPI_DISPLAY_TYPE_TV;
> > - break;
> > - case DRM_MODE_CONNECTOR_DVII:
> > - case DRM_MODE_CONNECTOR_DVID:
> > - case DRM_MODE_CONNECTOR_DisplayPort:
> > - case DRM_MODE_CONNECTOR_HDMIA:
> > - case DRM_MODE_CONNECTOR_HDMIB:
> > - display_type = ACPI_DISPLAY_TYPE_EXTERNAL_DIGITAL;
> > - break;
> > - case DRM_MODE_CONNECTOR_LVDS:
> > - case DRM_MODE_CONNECTOR_eDP:
> > - case DRM_MODE_CONNECTOR_DSI:
> > - display_type = ACPI_DISPLAY_TYPE_INTERNAL_DIGITAL;
> > - break;
> > - case DRM_MODE_CONNECTOR_Unknown:
> > - case DRM_MODE_CONNECTOR_VIRTUAL:
> > - display_type = ACPI_DISPLAY_TYPE_OTHER;
> > - break;
> > - default:
> > - MISSING_CASE(connector->base.connector_type);
> > - display_type = ACPI_DISPLAY_TYPE_OTHER;
> > - break;
> > - }
> > -
> > - return display_type;
> > -}
> > -
> > static void intel_didl_outputs(struct drm_i915_private *dev_priv)
> > {
> > struct intel_opregion *opregion = &dev_priv->opregion;
> > struct intel_connector *connector;
> > struct drm_connector_list_iter conn_iter;
> > int i = 0, max_outputs;
> > - int display_index[16] = {};
> >
> > /*
> > * In theory, did2, the extended didl, gets added at opregion version
> > @@ -721,20 +657,12 @@ static void intel_didl_outputs(struct drm_i915_private *dev_priv)
> > max_outputs = ARRAY_SIZE(opregion->acpi->didl) +
> > ARRAY_SIZE(opregion->acpi->did2);
> >
> > + intel_populate_acpi_ids_for_all_connectors(&dev_priv->drm);
> > +
>
> As the acpi_device_ids will be used elsewhere too, maybe this call needs
> to be moved to a higher level and called on the resume path. *shrug*

I don't understand this code well, happy to do whatever you or others
see fit. I kept it here so as to not to disturb any code that I do not
understand and cause unintended regressions (this code had it here, so
decided to leave it as-is). For the privacy screen purposes, we just
need to know the ACPI ID before we probe for the privacy screen to add
the property.

Thanks,

Rajat




>
> BR,
> Jani.
>
> > drm_connector_list_iter_begin(&dev_priv->drm, &conn_iter);
> > for_each_intel_connector_iter(connector, &conn_iter) {
> > - u32 device_id, type;
> > -
> > - device_id = acpi_display_type(connector);
> > -
> > - /* Use display type specific display index. */
> > - type = (device_id & ACPI_DISPLAY_TYPE_MASK)
> > - >> ACPI_DISPLAY_TYPE_SHIFT;
> > - device_id |= display_index[type]++ << ACPI_DISPLAY_INDEX_SHIFT;
> > -
> > - connector->acpi_device_id = device_id;
> > if (i < max_outputs)
> > - set_did(opregion, i, device_id);
> > + set_did(opregion, i, connector->acpi_device_id);
> > i++;
> > }
> > drm_connector_list_iter_end(&conn_iter);
>
> --
> Jani Nikula, Intel Open Source Graphics Center

2019-12-05 09:36:40

by Rajat Jain

[permalink] [raw]
Subject: Re: [PATCH v2 2/3] drm/i915: Lookup and attach ACPI device node for connectors

On Wed, Nov 20, 2019 at 6:51 AM Jani Nikula <[email protected]> wrote:
>
> On Mon, 04 Nov 2019, Rajat Jain <[email protected]> wrote:
> > Lookup and attach ACPI nodes for intel connectors. The lookup is done
> > in compliance with ACPI Spec 6.3
> > https://uefi.org/sites/default/files/resources/ACPI_6_3_final_Jan30.pdf
> > (Ref: Pages 1119 - 1123).
> >
> > This can be useful for any connector specific platform properties. (This
> > will be used for privacy screen in next patch).
> >
> > Signed-off-by: Rajat Jain <[email protected]>
> > Change-Id: I798e70714a4402554c8cd2a8e58268353f75814f
> > ---
> > v2: formed by splitting the original patch into ACPI lookup, and privacy
> > screen property. Also move it into i915 now that I found existing code
> > in i915 that can be re-used.
> >
> > drivers/gpu/drm/i915/display/intel_acpi.c | 50 +++++++++++++++++++
> > drivers/gpu/drm/i915/display/intel_acpi.h | 4 +-
> > .../drm/i915/display/intel_display_types.h | 3 ++
> > drivers/gpu/drm/i915/display/intel_dp.c | 4 ++
> > 4 files changed, 60 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/gpu/drm/i915/display/intel_acpi.c b/drivers/gpu/drm/i915/display/intel_acpi.c
> > index 748d9b3125dd..0c10516430b1 100644
> > --- a/drivers/gpu/drm/i915/display/intel_acpi.c
> > +++ b/drivers/gpu/drm/i915/display/intel_acpi.c
> > @@ -243,3 +243,53 @@ void intel_populate_acpi_ids_for_all_connectors(struct drm_device *drm_dev)
> > }
> > drm_connector_list_iter_end(&conn_iter);
> > }
> > +
> > +/*
> > + * 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. 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 functions looks up the ACPI node for a connector and returns
> > + * it. Technically it is independent from the i915 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 an acpi device ID which is build using an index within a particular
> > + * type of port (Ref to the pages of spec mentioned above, and to code in
> > + * intel_populate_acpi_ids_for_all_connectors()). This device index
> > + * unfortunately is not available in DRM code, so currently its call is
> > + * originated from i915 driver. If in future this is useful for other drivers
> > + * and we can find a generic way of getting a device index, we should move this
> > + * function to drm code, maybe.
> > + */
> > +void intel_connector_lookup_acpi_node(struct intel_connector *intel_connector)
>
> Nitpick, I'd expect a "lookup" function to return whatever it is looking
> up, not modify its argument.

I folded this function into the other function as you suggested below.

>
> > +{
> > + struct drm_device *drm_dev = intel_connector->base.dev;
> > + struct device *dev = &drm_dev->pdev->dev;
> > + struct acpi_device *conn_dev;
> > + u64 conn_addr;
> > +
> > + /*
> > + * Repopulate ACPI IDs for all connectors is needed because the display
> > + * index may have changed as a result of hotplugging and unplugging
> > + * connectors
> > + */
>
> I think that can only be true for DP MST. For everything else, I don't
> think so. Anyway, why are we doing it here then, depending on whether
> someone calls this function or not? If it matters, we should be doing
> this whenever there's a chance they've changed, right?
>

Actually I removed that comment now. To be really honest, my
understanding about the need to do this on every resume was only based
on the observation that this was being done on every call to
intel_opregion_resume() in addition to intel_opregion_register(). I'm
not sure if my understanding is correct, so unless the original author
of said code intel_opregion_* chimes in, I'm hesitant to change that
code. For privacy screen purposes, this works fine.

> > + intel_populate_acpi_ids_for_all_connectors(drm_dev);
> > +
> > + /* Build the _ADR to look for */
> > + conn_addr = intel_connector->acpi_device_id;
> > + conn_addr |= ACPI_DEVICE_ID_SCHEME;
> > + conn_addr |= ACPI_BIOS_CAN_DETECT;
> > +
> > + DRM_DEV_INFO(dev, "Looking for connector ACPI node at _ADR=%llX\n",
> > + conn_addr);
> > +
> > + /* Look up the connector device, under the PCI device */
> > + conn_dev = acpi_find_child_device(ACPI_COMPANION(dev), conn_addr,
> > + false);
> > + intel_connector->acpi_handle = conn_dev ? conn_dev->handle : NULL;
>
> Why don't we do this as part of
> intel_populate_acpi_ids_for_all_connectors() or whatever it'll be
> called?

Done, I folded this code in there.

>
> > +}
> > diff --git a/drivers/gpu/drm/i915/display/intel_acpi.h b/drivers/gpu/drm/i915/display/intel_acpi.h
> > index 8f6d850df6fa..61a4392fac4a 100644
> > --- a/drivers/gpu/drm/i915/display/intel_acpi.h
> > +++ b/drivers/gpu/drm/i915/display/intel_acpi.h
> > @@ -9,14 +9,16 @@
> > #include "intel_display_types.h"
> >
> > #ifdef CONFIG_ACPI
> > +void intel_connector_lookup_acpi_node(struct intel_connector *connector);
> > void intel_register_dsm_handler(void);
> > void intel_unregister_dsm_handler(void);
> > void intel_populate_acpi_ids_for_all_connectors(struct drm_device *drm_dev);
> > #else
> > +static inline void
> > +intel_connector_lookup_acpi_node(struct intel_connector *connector) { return; }
> > static inline void intel_register_dsm_handler(void) { return; }
> > static inline void intel_unregister_dsm_handler(void) { return; }
> > static inline void
> > -static inline void
>
> Whoops.

Fixed.

> > intel_populate_acpi_ids_for_all_connectors(struct drm_device *drm_dev) { }
> > #endif /* CONFIG_ACPI */
> >
> > diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
> > index 449abaea619f..c2706afc069b 100644
> > --- a/drivers/gpu/drm/i915/display/intel_display_types.h
> > +++ b/drivers/gpu/drm/i915/display/intel_display_types.h
> > @@ -400,6 +400,9 @@ struct intel_connector {
> > /* ACPI device id for ACPI and driver cooperation */
> > u32 acpi_device_id;
> >
> > + /* ACPI handle corresponding to this connector display, if found */
> > + void *acpi_handle;
> > +
> > /* Reads out the current hw, returning true if the connector is enabled
> > * and active (i.e. dpms ON state). */
> > bool (*get_hw_state)(struct intel_connector *);
> > diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
> > index f865615172a5..4fac408a4299 100644
> > --- a/drivers/gpu/drm/i915/display/intel_dp.c
> > +++ b/drivers/gpu/drm/i915/display/intel_dp.c
> > @@ -45,6 +45,7 @@
> > #include "i915_debugfs.h"
> > #include "i915_drv.h"
> > #include "i915_trace.h"
> > +#include "intel_acpi.h"
> > #include "intel_atomic.h"
> > #include "intel_audio.h"
> > #include "intel_connector.h"
> > @@ -6333,6 +6334,7 @@ intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connect
> > {
> > struct drm_i915_private *dev_priv = to_i915(connector->dev);
> > enum port port = dp_to_dig_port(intel_dp)->base.port;
> > + struct intel_connector *intel_connector = to_intel_connector(connector);
> >
> > if (!IS_G4X(dev_priv) && port != PORT_A)
> > intel_attach_force_audio_property(connector);
> > @@ -6354,6 +6356,8 @@ intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connect
> >
> > connector->state->scaling_mode = DRM_MODE_SCALE_ASPECT;
> >
> > + /* Lookup the ACPI node corresponding to the connector */
> > + intel_connector_lookup_acpi_node(intel_connector);
>
> This is an odd place to do this, isn't it? It's only called once, but
> you say the acpi id may change at hotplug.

As I mentioned before, my understanding was probably wrong about this
getting changed at resume. Also, my understanding is that on hotplug
of another display, a new connector will get created (so this function
will be called again anyway on hotplug).

Thanks,

Rajat


>
> BR,
> Jani.
>
> > }
> > }
>
> --
> Jani Nikula, Intel Open Source Graphics Center

2019-12-05 09:36:56

by Rajat Jain

[permalink] [raw]
Subject: Re: [PATCH v2 3/3] drm/i915: Add support for integrated privacy screens

On Wed, Nov 20, 2019 at 7:04 AM Jani Nikula <[email protected]> wrote:
>
> On Mon, 04 Nov 2019, Rajat Jain <[email protected]> wrote:
> > 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 <[email protected]>
> > 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
>
> Mmmh, wonder if there'll be non-ACPI based privacy screens. I guess we
> can sort this out then. *shrug*
>
> > 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);
> > +}
>
> I think this should be a drm core level property in drm_connector.[ch]
> so that *all* drivers would use the same thing for privacy screens. Not
> i915 specific.
>
> I think this is the biggest issue in the patch series.

I actually would be happy to make it a drm_connector property, like I
had in my original patch series. I changed it to i915 specific because
it seemed to me based on the comments that the general sentiment is
that anything to do with acpi should be in i915.

Note that the privacy screen property essentially needs an ACPI handle
to work on, so if I were to move the property into drm_connector, I'd
likely rename the intel_privacy_screen* code to dem_privacy_screen*
code, and it'll still operate on an ACPI handle (stored in
drm_connector structure). The i915's job will then be to lookup that
ACPI handle (because lookup requires display index) and populate it in
drm_connector. Does this sound OK?

>
> > 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
>
> Please read http://mid.mail-archive.com/CAKMK7uH-8+tbKsAoiChsxELEc_77RVVxP2wapHWhqB+0Viifog@mail.gmail.com

OK, I changed it to SPDX-License-Identifier: GPL-2.0 OR MIT


>
> > +/*
> > + * Intel ACPI privacy screen code
> > + *
> > + * Copyright © 2019 Google Inc.
> > + */
> > +
> > +#include <linux/acpi.h>
> > +
> > +#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)
>
> Just name the parameter connector, not intel_connector. This throughout.

Done.

>
> > +{
> > + 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);
>
> else complain?
>

Done.

> > +}
> > +
> > +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,
> > +};
> > +
>
> The drm_property interface UAPI is based on the strings, *not* on the
> values. Please move the enum out of uapi into the drm code.

Oh, so we don't have to expose this to userspace? Understand, so I
moved it to intel_display_types.h

Thanks,

Rajat.


>
> BR,
> jani.
>
> > #if defined(__cplusplus)
> > }
> > #endif
>
> --
> Jani Nikula, Intel Open Source Graphics Center

2019-12-20 20:40:59

by Rajat Jain

[permalink] [raw]
Subject: Re: [PATCH v2 3/3] drm/i915: Add support for integrated privacy screens

HI Jani,


On Thu, Dec 5, 2019 at 1:34 AM Rajat Jain <[email protected]> wrote:
>
> On Wed, Nov 20, 2019 at 7:04 AM Jani Nikula <[email protected]> wrote:
> >
> > On Mon, 04 Nov 2019, Rajat Jain <[email protected]> wrote:
> > > 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 <[email protected]>
> > > 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
> >
> > Mmmh, wonder if there'll be non-ACPI based privacy screens. I guess we
> > can sort this out then. *shrug*
> >
> > > 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);
> > > +}
> >
> > I think this should be a drm core level property in drm_connector.[ch]
> > so that *all* drivers would use the same thing for privacy screens. Not
> > i915 specific.
> >
> > I think this is the biggest issue in the patch series.
>
> I actually would be happy to make it a drm_connector property, like I
> had in my original patch series. I changed it to i915 specific because
> it seemed to me based on the comments that the general sentiment is
> that anything to do with acpi should be in i915.
>
> Note that the privacy screen property essentially needs an ACPI handle
> to work on, so if I were to move the property into drm_connector, I'd
> likely rename the intel_privacy_screen* code to drm_privacy_screen*
> code, and it'll still operate on an ACPI handle (stored in
> drm_connector structure). The i915's job will then be to lookup that
> ACPI handle (because lookup requires display index) and populate it in
> drm_connector. Does this sound OK?

Wondering if you ever got my email. I found out this week that I
needed to be a member of intel-gfx mailing list otherwise my patches
won't show up on patchwork.freedesktop.org. I'm now a member, and I
have posted my latest patchset at:

https://patchwork.freedesktop.org/patch/346275/

I'd appreciate if you could please review and comment and provide your
valuable suggestions.

Thanks & Best Regards,

Rajat

>
> >
> > > 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
> >
> > Please read http://mid.mail-archive.com/CAKMK7uH-8+tbKsAoiChsxELEc_77RVVxP2wapHWhqB+0Viifog@mail.gmail.com
>
> OK, I changed it to SPDX-License-Identifier: GPL-2.0 OR MIT
>
>
> >
> > > +/*
> > > + * Intel ACPI privacy screen code
> > > + *
> > > + * Copyright © 2019 Google Inc.
> > > + */
> > > +
> > > +#include <linux/acpi.h>
> > > +
> > > +#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)
> >
> > Just name the parameter connector, not intel_connector. This throughout.
>
> Done.
>
> >
> > > +{
> > > + 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);
> >
> > else complain?
> >
>
> Done.
>
> > > +}
> > > +
> > > +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,
> > > +};
> > > +
> >
> > The drm_property interface UAPI is based on the strings, *not* on the
> > values. Please move the enum out of uapi into the drm code.
>
> Oh, so we don't have to expose this to userspace? Understand, so I
> moved it to intel_display_types.h
>
> Thanks,
>
> Rajat.
>
>
> >
> > BR,
> > jani.
> >
> > > #if defined(__cplusplus)
> > > }
> > > #endif
> >
> > --
> > Jani Nikula, Intel Open Source Graphics Center