Add helper functions that can allow i915 to detect and control
an integrated privacy screen via ACPI methods. These shall be used
in the next patch.

Signed-off-by: Rajat Jain <raja...@google.com>
---
v8: Initial version. formed by refactoring the previous patch 4.
    print the connector name in the debug messages.

 drivers/gpu/drm/i915/Makefile                 |   3 +-
 .../drm/i915/display/intel_privacy_screen.c   | 184 ++++++++++++++++++
 .../drm/i915/display/intel_privacy_screen.h   |  27 +++
 3 files changed, 213 insertions(+), 1 deletion(-)
 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 9f887a86e555d..da42389107f9c 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -209,7 +209,8 @@ i915-y += \
        display/intel_vga.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_privacy_screen.c 
b/drivers/gpu/drm/i915/display/intel_privacy_screen.c
new file mode 100644
index 0000000000000..66039103c821b
--- /dev/null
+++ b/drivers/gpu/drm/i915/display/intel_privacy_screen.c
@@ -0,0 +1,184 @@
+// SPDX-License-Identifier: GPL-2.0 OR MIT
+/*
+ * Intel ACPI privacy screen code
+ *
+ * Copyright © 2020 Google Inc.
+ *
+ * This code can help detect and control an integrated EPS (electronic
+ * privacy screen) via ACPI functions. It expects an ACPI node for the
+ * drm connector device with the following elements:
+ *
+ * UUID should be "c7033113-8720-4ceb-9090-9d52b3e52d73"
+ *
+ * _ADR = ACPI address per Spec (also see intel_acpi_device_id_update())
+ * https://uefi.org/sites/default/files/resources/ACPI_6_3_final_Jan30.pdf
+ * Pages 1119 - 1123.
+ *
+ * _DSM method that will perform the following functions according to
+ * Local1 argument passed to it:
+ *  - Local1 = 0 (EPS capabilities): Report EPS presence and capabilities.
+ *  - Local1 = 1 (EPS State)  :  _DSM returns 1 if EPS is enabled, 0 otherwise.
+ *  - Local1 = 2 (EPS Enable) :  _DSM enables EPS
+ *  - Local1 = 3 (EPS Disable):  _DSM disables EPS
+ *
+ * Here is a sample ACPI node:
+ *
+ *  Scope (\_SB.PCI0.GFX0) // Intel graphics device (PCI device)
+ *  {
+ *      Method (_DOD, 0, NotSerialized)  // _DOD: Display Output Devices
+ *      {
+ *          Return (Package (0x01)
+ *          {
+ *              0x80010400
+ *          })
+ *      }
+ *
+ *      Device (LCD)
+ *      {
+ *          Name (_ADR, 0x80010400)  // _ADR: Address
+ *          Name (_STA, 0x0F)  // _STA: Status
+ *
+ *          Method (EPSP, 0, NotSerialized) // EPS Present
+ *          {
+ *              Return (0x01)
+ *          }
+ *
+ *          Method (EPSS, 0, NotSerialized) // EPS State
+ *          {
+ *              Local0 = \_SB.PCI0.GRXS (0xCD)
+ *              Return (Local0)
+ *          }
+ *
+ *          Method (EPSE, 0, NotSerialized) // EPS Enable
+ *          {
+ *              \_SB.PCI0.STXS (0xCD)
+ *          }
+ *
+ *          Method (EPSD, 0, NotSerialized) // EPS Disable
+ *          {
+ *              \_SB.PCI0.CTXS (0xCD)
+ *          }
+ *
+ *          Method (_DSM, 4, Serialized)  // _DSM: Device-Specific Method
+ *          {
+ *              ToBuffer (Arg0, Local0)
+ *              If ((Local0 == ToUUID 
("c7033113-8720-4ceb-9090-9d52b3e52d73")))
+ *              {
+ *                  ToInteger (Arg2, Local1)
+ *                  If ((Local1 == Zero))
+ *                  {
+ *                      Local2 = EPSP ()
+ *                      If ((Local2 == One))
+ *                      {
+ *                          Return (Buffer (One)
+ *                          {
+ *                               0x0F
+ *                          })
+ *                      }
+ *                  }
+ *
+ *                  If ((Local1 == One))
+ *                  {
+ *                      Return (EPSS ())
+ *                  }
+ *
+ *                  If ((Local1 == 0x02))
+ *                  {
+ *                      EPSE ()
+ *                  }
+ *
+ *                  If ((Local1 == 0x03))
+ *                  {
+ *                      EPSD ()
+ *                  }
+ *
+ *                  Return (Buffer (One)
+ *                  {
+ *                       0x00
+ *                  })
+ *              }
+ *
+ *              Return (Buffer (One)
+ *              {
+ *                   0x00
+ *              })
+ *          }
+ *      }
+ *  }
+ */
+
+#include <linux/acpi.h>
+
+#include "intel_privacy_screen.h"
+
+#define CONN_NAME(conn)                                                \
+       (conn->base.kdev ? dev_name(conn->base.kdev) : "NONAME")
+
+#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(struct intel_connector *connector,
+                                        u64 func)
+{
+       union acpi_object *obj;
+       acpi_handle acpi_handle = connector->acpi_handle;
+       struct drm_device *drm = connector->base.dev;
+
+       if (!acpi_handle)
+               return;
+
+       obj = acpi_evaluate_dsm(acpi_handle, &drm_conn_dsm_guid,
+                               CONNECTOR_DSM_REVID, func, NULL);
+       if (!obj) {
+               drm_err(drm, "%s: failed to evaluate _DSM for fn %llx\n",
+                       CONN_NAME(connector), func);
+               return;
+       }
+
+       ACPI_FREE(obj);
+}
+
+void intel_privacy_screen_set_val(struct intel_connector *connector,
+                                 enum drm_privacy_screen_status val)
+{
+       struct drm_device *drm = connector->base.dev;
+
+       if (val == PRIVACY_SCREEN_DISABLED) {
+               drm_dbg_kms(drm, "%s: disabling privacy-screen\n",
+                           CONN_NAME(connector));
+               acpi_privacy_screen_call_dsm(connector,
+                                            CONNECTOR_DSM_FN_PRIVACY_DISABLE);
+       } else {
+               drm_dbg_kms(drm, "%s: enabling privacy-screen\n",
+                           CONN_NAME(connector));
+               acpi_privacy_screen_call_dsm(connector,
+                                            CONNECTOR_DSM_FN_PRIVACY_ENABLE);
+       }
+}
+
+bool intel_privacy_screen_present(struct intel_connector *connector)
+{
+       acpi_handle handle = connector->acpi_handle;
+       struct drm_device *drm = connector->base.dev;
+
+       if (handle &&
+           acpi_check_dsm(handle, &drm_conn_dsm_guid,
+                          CONNECTOR_DSM_REVID,
+                          1 << CONNECTOR_DSM_FN_PRIVACY_ENABLE |
+                          1 << CONNECTOR_DSM_FN_PRIVACY_DISABLE)) {
+               drm_info(drm, "%s: supports ACPI privacy-screen\n",
+                        CONN_NAME(connector));
+               return true;
+       }
+
+       drm_dbg_kms(drm, "%s: doesn't support ACPI privacy-screen\n",
+                   CONN_NAME(connector));
+       return false;
+}
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 0000000000000..8655745ff9085
--- /dev/null
+++ b/drivers/gpu/drm/i915/display/intel_privacy_screen.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0 OR MIT */
+/*
+ * Copyright © 2020 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 *connector);
+void intel_privacy_screen_set_val(struct intel_connector *connector,
+                                 enum drm_privacy_screen_status val);
+#else
+static bool intel_privacy_screen_present(struct intel_connector *connector)
+{
+       return false;
+}
+
+static void
+intel_privacy_screen_set_val(struct intel_connector *connector,
+                            enum drm_privacy_screen_status val)
+{ }
+#endif /* CONFIG_ACPI */
+
+#endif /* __DRM_PRIVACY_SCREEN_H__ */
-- 
2.25.1.481.gfbce0eb801-goog

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to