From c75a9cccbf89ae38daccf5392fccd135e84af9d0 Mon Sep 17 00:00:00 2001
From: Markus Pfeiffer <profmakx@dragonflybsd.org>
Date: Mon, 8 Sep 2014 21:48:03 +0100
Subject: [PATCH] sys/dev/drm/i915: Activate ACPI

---
 sys/dev/drm/i915/Makefile         |  4 ++-
 sys/dev/drm/i915/i915_drv.h       |  2 ++
 sys/dev/drm/i915/intel_opregion.c | 69 +++++++++++++++++++++++++++++++++------
 3 files changed, 64 insertions(+), 11 deletions(-)

diff --git a/sys/dev/drm/i915/Makefile b/sys/dev/drm/i915/Makefile
index d5fcc7c..8e7a210 100644
--- a/sys/dev/drm/i915/Makefile
+++ b/sys/dev/drm/i915/Makefile
@@ -30,9 +30,11 @@ SRCS	= \
 	intel_sprite.c \
 	intel_tv.c
 
-SRCS   += device_if.h bus_if.h pci_if.h iicbus_if.h iicbb_if.h opt_drm.h \
+
+SRCS   += acpi_if.h device_if.h bus_if.h pci_if.h iicbus_if.h iicbb_if.h opt_drm.h \
 	  opt_ktr.h
 
 CFLAGS+= -I${SYSDIR}/dev/drm/include
+CFLAGS+= -I${.CURDIR}/../../../contrib/dev/acpica/source/include
 
 .include <bsd.kmod.mk>
diff --git a/sys/dev/drm/i915/i915_drv.h b/sys/dev/drm/i915/i915_drv.h
index 33dba21..91f8e44 100644
--- a/sys/dev/drm/i915/i915_drv.h
+++ b/sys/dev/drm/i915/i915_drv.h
@@ -39,6 +39,8 @@
 #include <linux/kref.h>
 #include <linux/workqueue.h>
 
+#define CONFIG_ACPI 1
+
 /* General customization:
  */
 
diff --git a/sys/dev/drm/i915/intel_opregion.c b/sys/dev/drm/i915/intel_opregion.c
index 5a1e799..c98659c 100644
--- a/sys/dev/drm/i915/intel_opregion.c
+++ b/sys/dev/drm/i915/intel_opregion.c
@@ -29,6 +29,9 @@
 #include <drm/i915_drm.h>
 #include "i915_drv.h"
 #include "intel_drv.h"
+#include <contrib/dev/acpica/source/include/acpi.h>
+#include <contrib/dev/acpica/source/include/accommon.h>
+#include <dev/acpica/acpivar.h>
 
 #include <linux/io.h>
 
@@ -291,6 +294,7 @@ void intel_opregion_enable_asle(struct drm_device *dev)
 
 static struct intel_opregion *system_opregion;
 
+#if 0
 static int intel_opregion_video_event(struct notifier_block *nb,
 				      unsigned long val, void *data)
 {
@@ -323,6 +327,17 @@ static int intel_opregion_video_event(struct notifier_block *nb,
 static struct notifier_block intel_opregion_notifier = {
 	.notifier_call = intel_opregion_video_event,
 };
+#endif
+
+
+static int acpi_is_video_device(ACPI_HANDLE devh) {
+	ACPI_HANDLE h;
+	if (ACPI_FAILURE(AcpiGetHandle(devh, "_DOD", &h)) ||
+	    ACPI_FAILURE(AcpiGetHandle(devh, "_DOS", &h))) {
+		return 0;
+	}
+	return 1;
+}
 
 /*
  * Initialise the DIDL field in opregion. This passes a list of devices to
@@ -335,26 +350,40 @@ static void intel_didl_outputs(struct drm_device *dev)
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_opregion *opregion = &dev_priv->opregion;
 	struct drm_connector *connector;
-	acpi_handle handle;
+	u32 device_id;
+	ACPI_HANDLE handle, acpi_video_bus, acpi_cdev;
+	ACPI_STATUS status;
+/*	acpi_handle handle;
 	struct acpi_device *acpi_dev, *acpi_cdev, *acpi_video_bus = NULL;
 	unsigned long long device_id;
-	acpi_status status;
+	acpi_status status; */
 	u32 temp;
 	int i = 0;
 
-	handle = DEVICE_ACPI_HANDLE(&dev->pdev->dev);
-	if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev)))
+	handle = acpi_get_handle(dev->dev);
+	if (!handle)
 		return;
 
-	if (acpi_is_video_device(acpi_dev))
-		acpi_video_bus = acpi_dev;
+	if (acpi_is_video_device(handle))
+		acpi_video_bus = handle;
 	else {
+#if 0 /* linux */
 		list_for_each_entry(acpi_cdev, &acpi_dev->children, node) {
 			if (acpi_is_video_device(acpi_cdev)) {
 				acpi_video_bus = acpi_cdev;
 				break;
 			}
 		}
+#endif
+		acpi_cdev = NULL;
+		acpi_video_bus = NULL;
+		while (AcpiGetNextObject(ACPI_TYPE_DEVICE, handle, acpi_cdev,
+					 &acpi_cdev) != AE_NOT_FOUND) {
+			if (acpi_is_video_device(acpi_cdev)) {
+				acpi_video_bus = acpi_cdev;
+				break;
+			}
+		}
 	}
 
 	if (!acpi_video_bus) {
@@ -362,6 +391,22 @@ static void intel_didl_outputs(struct drm_device *dev)
 		return;
 	}
 
+	acpi_cdev = NULL;
+	while (AcpiGetNextObject(ACPI_TYPE_DEVICE, acpi_video_bus, acpi_cdev,
+				 &acpi_cdev) != AE_NOT_FOUND) {
+		if (i >= 8) {
+			device_printf(dev->dev, "More than 8 outputs detected\n");
+			return;
+		}
+		status = acpi_GetInteger(acpi_cdev, "_ADR", &device_id);
+		if (ACPI_SUCCESS(status)) {
+			if (!device_id)
+				goto blind_set;
+			opregion->acpi->didl[i] = (u32)(device_id & 0x0f0f);
+			i++;
+		}
+	}
+#if 0 /* linux */
 	list_for_each_entry(acpi_cdev, &acpi_video_bus->children, node) {
 		if (i >= 8) {
 			dev_printk(KERN_ERR, &dev->pdev->dev,
@@ -379,7 +424,7 @@ static void intel_didl_outputs(struct drm_device *dev)
 			i++;
 		}
 	}
-
+#endif
 end:
 	/* If fewer than 8 outputs, the list must be null terminated */
 	if (i < 8)
@@ -391,7 +436,7 @@ blind_set:
 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
 		int output_type = ACPI_OTHER_OUTPUT;
 		if (i >= 8) {
-			dev_printk(KERN_ERR, &dev->pdev->dev,
+			device_printf(dev->dev,
 				    "More than 8 outputs detected\n");
 			return;
 		}
@@ -420,7 +465,7 @@ blind_set:
 		temp = ioread32(&opregion->acpi->didl[i]);
 		iowrite32(temp | (1<<31) | output_type | i,
 			  &opregion->acpi->didl[i]);
-		i++;
+	i++;
 	}
 	goto end;
 }
@@ -465,7 +510,9 @@ void intel_opregion_init(struct drm_device *dev)
 		iowrite32(1, &opregion->acpi->drdy);
 
 		system_opregion = opregion;
+#if 0 /* linux */
 		register_acpi_notifier(&intel_opregion_notifier);
+#endif
 	}
 
 	if (opregion->asle)
@@ -484,11 +531,13 @@ void intel_opregion_fini(struct drm_device *dev)
 		iowrite32(0, &opregion->acpi->drdy);
 
 		system_opregion = NULL;
+#if 0 /* linux */
 		unregister_acpi_notifier(&intel_opregion_notifier);
+#endif
 	}
 
 	/* just clear all opregion memory pointers now */
-	iounmap(opregion->header);
+	pmap_unmapdev((vm_offset_t)opregion->header, OPREGION_SIZE);
 	opregion->header = NULL;
 	opregion->acpi = NULL;
 	opregion->swsci = NULL;
-- 
2.0.2

