drm/i915: make i915 the source of acpi device ids for _DOD
authorJani Nikula <jani.nikula@intel.com>
Wed, 16 Nov 2016 11:29:56 +0000 (13:29 +0200)
committerJani Nikula <jani.nikula@intel.com>
Thu, 17 Nov 2016 10:44:57 +0000 (12:44 +0200)
The graphics driver is supposed to define the DIDL, which are used for
_DOD, not the BIOS. Restore that behaviour.

This is basically a revert of

commit 3143751ff51a163b77f7efd389043e038f3e008e
Author: Zhang Rui <rui.zhang@intel.com>
Date:   Mon Mar 29 15:12:16 2010 +0800

    drm/i915: set DIDL using the ACPI video output device _ADR method return.

which went out of its way to cater to a specific BIOS, setting up DIDL
based on _ADR method. Perhaps that approach worked on that specific
machine, but on the machines I checked the _ADR method invents the
device identifiers out of thin air if DIDL has not been set. The source
for _ADR is also supposed to be the DIDL set by the driver, not the
other way around.

With this, we'll also limit the number of outputs to what the driver
actually has.

A side effect of this change is that the DIDL, and by proxy CADL, will
be initialized in the order of the connector list. That, in turn, has
internal panels in front, ensuring they're included in the DIDL and CADL
lists. Hopefully this ensures the BIOS does not block backlight hotkey
events, thinking the internal panel is off.

v2: do not set ACPI_DEVICE_ID_SCHEME in the device id (Peter Wu)

v3: Rebase

Cc: Peter Wu <peter@lekensteyn.nl>
Cc: Rainer Koenig <Rainer.Koenig@ts.fujitsu.com>
Cc: Jan-Marek Glogowski <glogow@fbihome.de>
Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Cc: Marcos Paulo de Souza <marcos.souza.org@gmail.com>
Cc: Paolo Stivanin <paolostivanin@fastmail.fm>
Tested-by: Rainer Koenig <Rainer.Koenig@ts.fujitsu.com>
Tested-by: Paolo Stivanin <paolostivanin@fastmail.fm>
Tested-by: Marcos Paulo de Souza <marcos.souza.org@gmail.com>
Reviewed-and-tested-by: Peter Wu <peter@lekensteyn.nl>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/9660d29cf310c17bbf4d58c0e09d5b047446e2d5.1479295490.git.jani.nikula@intel.com
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_opregion.c

index 0be407e..5b93455 100644 (file)
@@ -294,6 +294,9 @@ struct intel_connector {
         */
        struct intel_encoder *encoder;
 
+       /* ACPI device id for ACPI and driver cooperation */
+       u32 acpi_device_id;
+
        /* 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 *);
index 7acbbbf..6bac71c 100644 (file)
@@ -674,11 +674,11 @@ static void set_did(struct intel_opregion *opregion, int i, u32 val)
        }
 }
 
-static u32 acpi_display_type(struct drm_connector *connector)
+static u32 acpi_display_type(struct intel_connector *connector)
 {
        u32 display_type;
 
-       switch (connector->connector_type) {
+       switch (connector->base.connector_type) {
        case DRM_MODE_CONNECTOR_VGA:
        case DRM_MODE_CONNECTOR_DVIA:
                display_type = ACPI_DISPLAY_TYPE_VGA;
@@ -707,7 +707,7 @@ static u32 acpi_display_type(struct drm_connector *connector)
                display_type = ACPI_DISPLAY_TYPE_OTHER;
                break;
        default:
-               MISSING_CASE(connector->connector_type);
+               MISSING_CASE(connector->base.connector_type);
                display_type = ACPI_DISPLAY_TYPE_OTHER;
                break;
        }
@@ -718,34 +718,9 @@ static u32 acpi_display_type(struct drm_connector *connector)
 static void intel_didl_outputs(struct drm_i915_private *dev_priv)
 {
        struct intel_opregion *opregion = &dev_priv->opregion;
-       struct pci_dev *pdev = dev_priv->drm.pdev;
-       struct drm_connector *connector;
-       acpi_handle handle;
-       struct acpi_device *acpi_dev, *acpi_cdev, *acpi_video_bus = NULL;
-       unsigned long long device_id;
-       acpi_status status;
-       u32 temp, max_outputs;
-       int i = 0;
-
-       handle = ACPI_HANDLE(&pdev->dev);
-       if (!handle || acpi_bus_get_device(handle, &acpi_dev))
-               return;
-
-       if (acpi_is_video_device(handle))
-               acpi_video_bus = acpi_dev;
-       else {
-               list_for_each_entry(acpi_cdev, &acpi_dev->children, node) {
-                       if (acpi_is_video_device(acpi_cdev->handle)) {
-                               acpi_video_bus = acpi_cdev;
-                               break;
-                       }
-               }
-       }
-
-       if (!acpi_video_bus) {
-               DRM_DEBUG_KMS("No ACPI video bus found\n");
-               return;
-       }
+       struct intel_connector *connector;
+       int i = 0, max_outputs;
+       int display_index[16] = {};
 
        /*
         * In theory, did2, the extended didl, gets added at opregion version
@@ -757,46 +732,31 @@ static void intel_didl_outputs(struct drm_i915_private *dev_priv)
        max_outputs = ARRAY_SIZE(opregion->acpi->didl) +
                ARRAY_SIZE(opregion->acpi->did2);
 
-       list_for_each_entry(acpi_cdev, &acpi_video_bus->children, node) {
-               if (i >= max_outputs) {
-                       DRM_DEBUG_KMS("More than %u outputs detected via ACPI\n",
-                                     max_outputs);
-                       return;
-               }
-               status = acpi_evaluate_integer(acpi_cdev->handle, "_ADR",
-                                              NULL, &device_id);
-               if (ACPI_SUCCESS(status)) {
-                       if (!device_id)
-                               goto blind_set;
-                       set_did(opregion, i++, (u32)(device_id & 0x0f0f));
-               }
+       for_each_intel_connector(&dev_priv->drm, connector) {
+               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);
+               i++;
        }
 
-end:
        DRM_DEBUG_KMS("%d outputs detected\n", i);
 
+       if (i > max_outputs)
+               DRM_ERROR("More than %d outputs in connector list\n",
+                         max_outputs);
+
        /* If fewer than max outputs, the list must be null terminated */
        if (i < max_outputs)
                set_did(opregion, i, 0);
-       return;
-
-blind_set:
-       i = 0;
-       list_for_each_entry(connector,
-                           &dev_priv->drm.mode_config.connector_list, head) {
-               int display_type = acpi_display_type(connector);
-
-               if (i >= max_outputs) {
-                       DRM_DEBUG_KMS("More than %u outputs in connector list\n",
-                                     max_outputs);
-                       return;
-               }
-
-               temp = get_did(opregion, i);
-               set_did(opregion, i, temp | (1 << 31) | display_type | i);
-               i++;
-       }
-       goto end;
 }
 
 static void intel_setup_cadls(struct drm_i915_private *dev_priv)