Chuck Ebbert b5010d0
From 782468d6a9fb865677c166ceffc2271e1f709cc5 Mon Sep 17 00:00:00 2001
Chuck Ebbert b5010d0
From: Ben Skeggs <bskeggs@redhat.com>
Chuck Ebbert b5010d0
Date: Fri, 16 Apr 2010 08:12:34 +1000
Chuck Ebbert b5010d0
Subject: [PATCH 2/3] drm-nouveau-acpi-edid-fallback
Chuck Ebbert b5010d0
Chuck Ebbert b5010d0
---
Chuck Ebbert b5010d0
 drivers/gpu/drm/nouveau/nouveau_acpi.c      |   81 ++++++++++++++++++++++++--
Chuck Ebbert b5010d0
 drivers/gpu/drm/nouveau/nouveau_connector.c |    8 +++
Chuck Ebbert b5010d0
 drivers/gpu/drm/nouveau/nouveau_drv.h       |   20 +++++--
Chuck Ebbert b5010d0
 drivers/gpu/drm/nouveau/nouveau_state.c     |    5 +-
Chuck Ebbert b5010d0
 4 files changed, 98 insertions(+), 16 deletions(-)
Chuck Ebbert b5010d0
Chuck Ebbert b5010d0
diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c
Chuck Ebbert b5010d0
index 48227e7..ac7fd04 100644
Chuck Ebbert b5010d0
--- a/drivers/gpu/drm/nouveau/nouveau_acpi.c
Chuck Ebbert b5010d0
+++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c
Chuck Ebbert b5010d0
@@ -2,11 +2,13 @@
Chuck Ebbert b5010d0
 #include <linux/acpi.h>
Chuck Ebbert b5010d0
 #include <acpi/acpi_drivers.h>
Chuck Ebbert b5010d0
 #include <acpi/acpi_bus.h>
Chuck Ebbert b5010d0
+#include <acpi/video.h>
Chuck Ebbert b5010d0
 
Chuck Ebbert b5010d0
 #include "drmP.h"
Chuck Ebbert b5010d0
 #include "drm.h"
Chuck Ebbert b5010d0
 #include "drm_sarea.h"
Chuck Ebbert b5010d0
 #include "drm_crtc_helper.h"
Chuck Ebbert b5010d0
+#include "nouveau_connector.h"
Chuck Ebbert b5010d0
 #include "nouveau_drv.h"
Chuck Ebbert b5010d0
 #include "nouveau_drm.h"
Chuck Ebbert b5010d0
 #include "nv50_display.h"
Chuck Ebbert b5010d0
@@ -35,7 +37,7 @@ static int nouveau_dsm(struct drm_device *dev, int func, int arg, int *result)
Chuck Ebbert b5010d0
 		0xB3, 0x4D, 0x7E, 0x5F, 0xEA, 0x12, 0x9F, 0xD4,
Chuck Ebbert b5010d0
 	};
Chuck Ebbert b5010d0
 
Chuck Ebbert b5010d0
-	struct pci_dev *pdev = dev->pdev;
Chuck Ebbert b5010d0
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
Chuck Ebbert b5010d0
 	struct acpi_handle *handle;
Chuck Ebbert b5010d0
 	struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
Chuck Ebbert b5010d0
 	struct acpi_object_list input;
Chuck Ebbert b5010d0
@@ -43,11 +45,11 @@ static int nouveau_dsm(struct drm_device *dev, int func, int arg, int *result)
Chuck Ebbert b5010d0
 	union acpi_object *obj;
Chuck Ebbert b5010d0
 	int err;
Chuck Ebbert b5010d0
 
Chuck Ebbert b5010d0
-	handle = DEVICE_ACPI_HANDLE(&pdev->dev);
Chuck Ebbert b5010d0
-
Chuck Ebbert b5010d0
-	if (!handle)
Chuck Ebbert b5010d0
+	if (!dev_priv->acpi_device)
Chuck Ebbert b5010d0
 		return -ENODEV;
Chuck Ebbert b5010d0
 
Chuck Ebbert b5010d0
+	handle = dev_priv->acpi_device->handle;
Chuck Ebbert b5010d0
+
Chuck Ebbert b5010d0
 	input.count = 4;
Chuck Ebbert b5010d0
 	input.pointer = params;
Chuck Ebbert b5010d0
 	params[0].type = ACPI_TYPE_BUFFER;
Chuck Ebbert b5010d0
@@ -62,7 +64,8 @@ static int nouveau_dsm(struct drm_device *dev, int func, int arg, int *result)
Chuck Ebbert b5010d0
 
Chuck Ebbert b5010d0
 	err = acpi_evaluate_object(handle, "_DSM", &input, &output);
Chuck Ebbert b5010d0
 	if (err) {
Chuck Ebbert b5010d0
-		NV_INFO(dev, "failed to evaluate _DSM: %d\n", err);
Chuck Ebbert b5010d0
+		if (err != AE_NOT_FOUND)
Chuck Ebbert b5010d0
+			NV_INFO(dev, "failed to evaluate _DSM: %d\n", err);
Chuck Ebbert b5010d0
 		return err;
Chuck Ebbert b5010d0
 	}
Chuck Ebbert b5010d0
 
Chuck Ebbert b5010d0
@@ -86,7 +89,7 @@ static int nouveau_dsm(struct drm_device *dev, int func, int arg, int *result)
Chuck Ebbert b5010d0
 	return 0;
Chuck Ebbert b5010d0
 }
Chuck Ebbert b5010d0
 
Chuck Ebbert b5010d0
-int nouveau_hybrid_setup(struct drm_device *dev)
Chuck Ebbert b5010d0
+static int nouveau_hybrid_setup(struct drm_device *dev)
Chuck Ebbert b5010d0
 {
Chuck Ebbert b5010d0
 	int result;
Chuck Ebbert b5010d0
 
Chuck Ebbert b5010d0
@@ -110,7 +113,7 @@ int nouveau_hybrid_setup(struct drm_device *dev)
Chuck Ebbert b5010d0
 	return 0;
Chuck Ebbert b5010d0
 }
Chuck Ebbert b5010d0
 
Chuck Ebbert b5010d0
-bool nouveau_dsm_probe(struct drm_device *dev)
Chuck Ebbert b5010d0
+static bool nouveau_dsm_probe(struct drm_device *dev)
Chuck Ebbert b5010d0
 {
Chuck Ebbert b5010d0
 	int support = 0;
Chuck Ebbert b5010d0
 
Chuck Ebbert b5010d0
@@ -123,3 +126,67 @@ bool nouveau_dsm_probe(struct drm_device *dev)
Chuck Ebbert b5010d0
 
Chuck Ebbert b5010d0
 	return true;
Chuck Ebbert b5010d0
 }
Chuck Ebbert b5010d0
+
Chuck Ebbert b5010d0
+int nouveau_acpi_get_edid(struct drm_device *dev,
Chuck Ebbert b5010d0
+			  struct drm_connector *connector,
Chuck Ebbert b5010d0
+			  struct edid **pedid)
Chuck Ebbert b5010d0
+{
Chuck Ebbert b5010d0
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
Chuck Ebbert b5010d0
+	void *edid;
Chuck Ebbert b5010d0
+	int connector_type = 0;
Chuck Ebbert b5010d0
+	int ret;
Chuck Ebbert b5010d0
+
Chuck Ebbert b5010d0
+	switch (connector->connector_type) {
Chuck Ebbert b5010d0
+	case DRM_MODE_CONNECTOR_VGA:
Chuck Ebbert b5010d0
+		connector_type = ACPI_VIDEO_DISPLAY_CRT;
Chuck Ebbert b5010d0
+		break;
Chuck Ebbert b5010d0
+	case DRM_MODE_CONNECTOR_Composite:
Chuck Ebbert b5010d0
+	case DRM_MODE_CONNECTOR_SVIDEO:
Chuck Ebbert b5010d0
+	case DRM_MODE_CONNECTOR_Component:
Chuck Ebbert b5010d0
+	case DRM_MODE_CONNECTOR_9PinDIN:
Chuck Ebbert b5010d0
+		connector_type = ACPI_VIDEO_DISPLAY_TV;
Chuck Ebbert b5010d0
+		break;
Chuck Ebbert b5010d0
+	case DRM_MODE_CONNECTOR_DVII:
Chuck Ebbert b5010d0
+	case DRM_MODE_CONNECTOR_DVID:
Chuck Ebbert b5010d0
+	case DRM_MODE_CONNECTOR_HDMIA:
Chuck Ebbert b5010d0
+	case DRM_MODE_CONNECTOR_HDMIB:
Chuck Ebbert b5010d0
+	case DRM_MODE_CONNECTOR_DisplayPort:
Chuck Ebbert b5010d0
+		connector_type = ACPI_VIDEO_DISPLAY_DVI;
Chuck Ebbert b5010d0
+		break;
Chuck Ebbert b5010d0
+	case DRM_MODE_CONNECTOR_LVDS:
Chuck Ebbert b5010d0
+		connector_type = ACPI_VIDEO_DISPLAY_LCD;
Chuck Ebbert b5010d0
+		break;
Chuck Ebbert b5010d0
+	}
Chuck Ebbert b5010d0
+
Chuck Ebbert b5010d0
+	ret = acpi_video_get_edid(dev_priv->acpi_device, connector_type, -1, &edid);
Chuck Ebbert b5010d0
+
Chuck Ebbert b5010d0
+	if (ret < 0)
Chuck Ebbert b5010d0
+		return ret;
Chuck Ebbert b5010d0
+
Chuck Ebbert b5010d0
+	*pedid = edid;
Chuck Ebbert b5010d0
+	return 0;
Chuck Ebbert b5010d0
+}
Chuck Ebbert b5010d0
+
Chuck Ebbert b5010d0
+int nouveau_acpi_setup(struct drm_device *dev)
Chuck Ebbert b5010d0
+{
Chuck Ebbert b5010d0
+	struct pci_dev *pdev = dev->pdev;
Chuck Ebbert b5010d0
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
Chuck Ebbert b5010d0
+	acpi_handle handle;
Chuck Ebbert b5010d0
+	struct acpi_device *acpi_dev;
Chuck Ebbert b5010d0
+
Chuck Ebbert b5010d0
+	handle = DEVICE_ACPI_HANDLE(&pdev->dev);
Chuck Ebbert b5010d0
+
Chuck Ebbert b5010d0
+	if (!handle)
Chuck Ebbert b5010d0
+		return -ENODEV;
Chuck Ebbert b5010d0
+
Chuck Ebbert b5010d0
+	if (acpi_bus_get_device(handle, &acpi_dev))
Chuck Ebbert b5010d0
+		return -ENODEV;
Chuck Ebbert b5010d0
+
Chuck Ebbert b5010d0
+	dev_priv->acpi_device = acpi_dev;
Chuck Ebbert b5010d0
+	dev_priv->acpi_dsm = nouveau_dsm_probe(dev);
Chuck Ebbert b5010d0
+
Chuck Ebbert b5010d0
+	if (dev_priv->acpi_dsm)
Chuck Ebbert b5010d0
+		nouveau_hybrid_setup(dev);
Chuck Ebbert b5010d0
+
Chuck Ebbert b5010d0
+	return 0;
Chuck Ebbert b5010d0
+}
Chuck Ebbert b5010d0
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
Chuck Ebbert b5010d0
index fb51958..5832b60 100644
Chuck Ebbert b5010d0
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
Chuck Ebbert b5010d0
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
Chuck Ebbert b5010d0
@@ -356,6 +356,14 @@ nouveau_connector_detect_lvds(struct drm_connector *connector)
Chuck Ebbert b5010d0
 		}
Chuck Ebbert b5010d0
 	}
Chuck Ebbert b5010d0
 
Chuck Ebbert b5010d0
+	/* Let's try ACPI */
Chuck Ebbert b5010d0
+	if (status != connector_status_connected &&
Chuck Ebbert b5010d0
+	    !dev_priv->vbios.fp_no_ddc) {
Chuck Ebbert b5010d0
+		nouveau_acpi_get_edid(dev, connector, &nv_connector->edid);
Chuck Ebbert b5010d0
+		if (nv_connector->edid)
Chuck Ebbert b5010d0
+			status = connector_status_connected;
Chuck Ebbert b5010d0
+	}
Chuck Ebbert b5010d0
+
Chuck Ebbert b5010d0
 out:
Chuck Ebbert b5010d0
 #ifdef CONFIG_ACPI
Chuck Ebbert b5010d0
 	if (status == connector_status_connected &&
Chuck Ebbert b5010d0
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
Chuck Ebbert b5010d0
index c31159a..675d7ac 100644
Chuck Ebbert b5010d0
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
Chuck Ebbert b5010d0
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
Chuck Ebbert b5010d0
@@ -39,6 +39,8 @@
Chuck Ebbert b5010d0
 #define NOUVEAU_FAMILY   0x0000FFFF
Chuck Ebbert b5010d0
 #define NOUVEAU_FLAGS    0xFFFF0000
Chuck Ebbert b5010d0
 
Chuck Ebbert b5010d0
+#include <linux/acpi.h>
Chuck Ebbert b5010d0
+
Chuck Ebbert b5010d0
 #include "ttm/ttm_bo_api.h"
Chuck Ebbert b5010d0
 #include "ttm/ttm_bo_driver.h"
Chuck Ebbert b5010d0
 #include "ttm/ttm_placement.h"
Chuck Ebbert b5010d0
@@ -615,7 +617,11 @@ struct drm_nouveau_private {
Chuck Ebbert b5010d0
 	} susres;
Chuck Ebbert b5010d0
 
Chuck Ebbert b5010d0
 	struct backlight_device *backlight;
Chuck Ebbert b5010d0
+
Chuck Ebbert b5010d0
+#ifdef CONFIG_ACPI
Chuck Ebbert b5010d0
 	bool acpi_dsm;
Chuck Ebbert b5010d0
+	struct acpi_device *acpi_device;
Chuck Ebbert b5010d0
+#endif
Chuck Ebbert b5010d0
 
Chuck Ebbert b5010d0
 	struct nouveau_channel *evo;
Chuck Ebbert b5010d0
 
Chuck Ebbert b5010d0
@@ -846,16 +852,20 @@ extern int  nouveau_dma_wait(struct nouveau_channel *, int slots, int size);
Chuck Ebbert b5010d0
 
Chuck Ebbert b5010d0
 /* nouveau_acpi.c */
Chuck Ebbert b5010d0
 #ifdef CONFIG_ACPI
Chuck Ebbert b5010d0
-extern int nouveau_hybrid_setup(struct drm_device *dev);
Chuck Ebbert b5010d0
-extern bool nouveau_dsm_probe(struct drm_device *dev);
Chuck Ebbert b5010d0
+extern int nouveau_acpi_setup(struct drm_device *dev);
Chuck Ebbert b5010d0
+extern int nouveau_acpi_get_edid(struct drm_device *dev,
Chuck Ebbert b5010d0
+				 struct drm_connector *connector,
Chuck Ebbert b5010d0
+				 struct edid **edid);
Chuck Ebbert b5010d0
 #else
Chuck Ebbert b5010d0
-static inline int nouveau_hybrid_setup(struct drm_device *dev)
Chuck Ebbert b5010d0
+static inline int nouveau_acpi_setup(struct drm_device *dev)
Chuck Ebbert b5010d0
 {
Chuck Ebbert b5010d0
 	return 0;
Chuck Ebbert b5010d0
 }
Chuck Ebbert b5010d0
-static inline bool nouveau_dsm_probe(struct drm_device *dev)
Chuck Ebbert b5010d0
+static inline int nouveau_acpi_get_edid(struct drm_device *dev,
Chuck Ebbert b5010d0
+					struct drm_connector *connector,
Chuck Ebbert b5010d0
+					struct edid **edid)
Chuck Ebbert b5010d0
 {
Chuck Ebbert b5010d0
-	return false;
Chuck Ebbert b5010d0
+	return -ENODEV;
Chuck Ebbert b5010d0
 }
Chuck Ebbert b5010d0
 #endif
Chuck Ebbert b5010d0
 
Chuck Ebbert b5010d0
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c
Chuck Ebbert b5010d0
index 7c1d252..7ca9465 100644
Chuck Ebbert b5010d0
--- a/drivers/gpu/drm/nouveau/nouveau_state.c
Chuck Ebbert b5010d0
+++ b/drivers/gpu/drm/nouveau/nouveau_state.c
Chuck Ebbert b5010d0
@@ -627,10 +627,7 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
Chuck Ebbert b5010d0
 	NV_DEBUG(dev, "vendor: 0x%X device: 0x%X class: 0x%X\n",
Chuck Ebbert b5010d0
 		 dev->pci_vendor, dev->pci_device, dev->pdev->class);
Chuck Ebbert b5010d0
 
Chuck Ebbert b5010d0
-	dev_priv->acpi_dsm = nouveau_dsm_probe(dev);
Chuck Ebbert b5010d0
-
Chuck Ebbert b5010d0
-	if (dev_priv->acpi_dsm)
Chuck Ebbert b5010d0
-		nouveau_hybrid_setup(dev);
Chuck Ebbert b5010d0
+	nouveau_acpi_setup(dev);
Chuck Ebbert b5010d0
 
Chuck Ebbert b5010d0
 	dev_priv->wq = create_workqueue("nouveau");
Chuck Ebbert b5010d0
 	if (!dev_priv->wq)
Chuck Ebbert b5010d0
-- 
Chuck Ebbert b5010d0
1.7.1
Chuck Ebbert b5010d0