aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/acpi/video.c40
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c5
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c2
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h2
-rw-r--r--drivers/gpu/drm/i915/i915_opregion.c65
-rw-r--r--include/acpi/video.h11
6 files changed, 119 insertions, 6 deletions
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index 9730ec167590..ae427100a1ef 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -37,6 +37,8 @@
37#include <linux/thermal.h> 37#include <linux/thermal.h>
38#include <linux/video_output.h> 38#include <linux/video_output.h>
39#include <linux/sort.h> 39#include <linux/sort.h>
40#include <linux/pci.h>
41#include <linux/pci_ids.h>
40#include <asm/uaccess.h> 42#include <asm/uaccess.h>
41 43
42#include <acpi/acpi_bus.h> 44#include <acpi/acpi_bus.h>
@@ -2251,7 +2253,27 @@ static int acpi_video_bus_remove(struct acpi_device *device, int type)
2251 return 0; 2253 return 0;
2252} 2254}
2253 2255
2254static int __init acpi_video_init(void) 2256static int __init intel_opregion_present(void)
2257{
2258#if defined(CONFIG_DRM_I915) || defined(CONFIG_DRM_I915_MODULE)
2259 struct pci_dev *dev = NULL;
2260 u32 address;
2261
2262 for_each_pci_dev(dev) {
2263 if ((dev->class >> 8) != PCI_CLASS_DISPLAY_VGA)
2264 continue;
2265 if (dev->vendor != PCI_VENDOR_ID_INTEL)
2266 continue;
2267 pci_read_config_dword(dev, 0xfc, &address);
2268 if (!address)
2269 continue;
2270 return 1;
2271 }
2272#endif
2273 return 0;
2274}
2275
2276int acpi_video_register(void)
2255{ 2277{
2256 int result = 0; 2278 int result = 0;
2257 2279
@@ -2268,6 +2290,22 @@ static int __init acpi_video_init(void)
2268 2290
2269 return 0; 2291 return 0;
2270} 2292}
2293EXPORT_SYMBOL(acpi_video_register);
2294
2295/*
2296 * This is kind of nasty. Hardware using Intel chipsets may require
2297 * the video opregion code to be run first in order to initialise
2298 * state before any ACPI video calls are made. To handle this we defer
2299 * registration of the video class until the opregion code has run.
2300 */
2301
2302static int __init acpi_video_init(void)
2303{
2304 if (intel_opregion_present())
2305 return 0;
2306
2307 return acpi_video_register();
2308}
2271 2309
2272static void __exit acpi_video_exit(void) 2310static void __exit acpi_video_exit(void)
2273{ 2311{
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 6d21b9e48b89..638686904e06 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1144,8 +1144,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
1144 if (!IS_I945G(dev) && !IS_I945GM(dev)) 1144 if (!IS_I945G(dev) && !IS_I945GM(dev))
1145 pci_enable_msi(dev->pdev); 1145 pci_enable_msi(dev->pdev);
1146 1146
1147 intel_opregion_init(dev);
1148
1149 spin_lock_init(&dev_priv->user_irq_lock); 1147 spin_lock_init(&dev_priv->user_irq_lock);
1150 dev_priv->user_irq_refcount = 0; 1148 dev_priv->user_irq_refcount = 0;
1151 1149
@@ -1164,6 +1162,9 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
1164 } 1162 }
1165 } 1163 }
1166 1164
1165 /* Must be done after probing outputs */
1166 intel_opregion_init(dev, 0);
1167
1167 return 0; 1168 return 0;
1168 1169
1169out_iomapfree: 1170out_iomapfree:
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index b293ef0bae71..209592fdb7e7 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -99,7 +99,7 @@ static int i915_resume(struct drm_device *dev)
99 99
100 i915_restore_state(dev); 100 i915_restore_state(dev);
101 101
102 intel_opregion_init(dev); 102 intel_opregion_init(dev, 1);
103 103
104 /* KMS EnterVT equivalent */ 104 /* KMS EnterVT equivalent */
105 if (drm_core_check_feature(dev, DRIVER_MODESET)) { 105 if (drm_core_check_feature(dev, DRIVER_MODESET)) {
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index d6cc9861e0a1..1679a951aa7e 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -659,7 +659,7 @@ extern int i915_restore_state(struct drm_device *dev);
659 659
660#ifdef CONFIG_ACPI 660#ifdef CONFIG_ACPI
661/* i915_opregion.c */ 661/* i915_opregion.c */
662extern int intel_opregion_init(struct drm_device *dev); 662extern int intel_opregion_init(struct drm_device *dev, int resume);
663extern void intel_opregion_free(struct drm_device *dev); 663extern void intel_opregion_free(struct drm_device *dev);
664extern void opregion_asle_intr(struct drm_device *dev); 664extern void opregion_asle_intr(struct drm_device *dev);
665extern void opregion_enable_asle(struct drm_device *dev); 665extern void opregion_enable_asle(struct drm_device *dev);
diff --git a/drivers/gpu/drm/i915/i915_opregion.c b/drivers/gpu/drm/i915/i915_opregion.c
index ff012835a386..69427722d20e 100644
--- a/drivers/gpu/drm/i915/i915_opregion.c
+++ b/drivers/gpu/drm/i915/i915_opregion.c
@@ -26,6 +26,7 @@
26 */ 26 */
27 27
28#include <linux/acpi.h> 28#include <linux/acpi.h>
29#include <acpi/video.h>
29 30
30#include "drmP.h" 31#include "drmP.h"
31#include "i915_drm.h" 32#include "i915_drm.h"
@@ -136,6 +137,12 @@ struct opregion_asle {
136 137
137#define ASLE_CBLV_VALID (1<<31) 138#define ASLE_CBLV_VALID (1<<31)
138 139
140#define ACPI_OTHER_OUTPUT (0<<8)
141#define ACPI_VGA_OUTPUT (1<<8)
142#define ACPI_TV_OUTPUT (2<<8)
143#define ACPI_DIGITAL_OUTPUT (3<<8)
144#define ACPI_LVDS_OUTPUT (4<<8)
145
139static u32 asle_set_backlight(struct drm_device *dev, u32 bclp) 146static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
140{ 147{
141 struct drm_i915_private *dev_priv = dev->dev_private; 148 struct drm_i915_private *dev_priv = dev->dev_private;
@@ -282,7 +289,58 @@ static struct notifier_block intel_opregion_notifier = {
282 .notifier_call = intel_opregion_video_event, 289 .notifier_call = intel_opregion_video_event,
283}; 290};
284 291
285int intel_opregion_init(struct drm_device *dev) 292/*
293 * Initialise the DIDL field in opregion. This passes a list of devices to
294 * the firmware. Values are defined by section B.4.2 of the ACPI specification
295 * (version 3)
296 */
297
298static void intel_didl_outputs(struct drm_device *dev)
299{
300 struct drm_i915_private *dev_priv = dev->dev_private;
301 struct intel_opregion *opregion = &dev_priv->opregion;
302 struct drm_connector *connector;
303 int i = 0;
304
305 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
306 int output_type = ACPI_OTHER_OUTPUT;
307 if (i >= 8) {
308 dev_printk (KERN_ERR, &dev->pdev->dev,
309 "More than 8 outputs detected\n");
310 return;
311 }
312 switch (connector->connector_type) {
313 case DRM_MODE_CONNECTOR_VGA:
314 case DRM_MODE_CONNECTOR_DVIA:
315 output_type = ACPI_VGA_OUTPUT;
316 break;
317 case DRM_MODE_CONNECTOR_Composite:
318 case DRM_MODE_CONNECTOR_SVIDEO:
319 case DRM_MODE_CONNECTOR_Component:
320 case DRM_MODE_CONNECTOR_9PinDIN:
321 output_type = ACPI_TV_OUTPUT;
322 break;
323 case DRM_MODE_CONNECTOR_DVII:
324 case DRM_MODE_CONNECTOR_DVID:
325 case DRM_MODE_CONNECTOR_DisplayPort:
326 case DRM_MODE_CONNECTOR_HDMIA:
327 case DRM_MODE_CONNECTOR_HDMIB:
328 output_type = ACPI_DIGITAL_OUTPUT;
329 break;
330 case DRM_MODE_CONNECTOR_LVDS:
331 output_type = ACPI_LVDS_OUTPUT;
332 break;
333 }
334 opregion->acpi->didl[i] |= (1<<31) | output_type | i;
335 i++;
336 }
337
338 /* If fewer than 8 outputs, the list must be null terminated */
339 if (i < 8)
340 opregion->acpi->didl[i] = 0;
341}
342
343int intel_opregion_init(struct drm_device *dev, int resume)
286{ 344{
287 struct drm_i915_private *dev_priv = dev->dev_private; 345 struct drm_i915_private *dev_priv = dev->dev_private;
288 struct intel_opregion *opregion = &dev_priv->opregion; 346 struct intel_opregion *opregion = &dev_priv->opregion;
@@ -312,6 +370,11 @@ int intel_opregion_init(struct drm_device *dev)
312 if (mboxes & MBOX_ACPI) { 370 if (mboxes & MBOX_ACPI) {
313 DRM_DEBUG("Public ACPI methods supported\n"); 371 DRM_DEBUG("Public ACPI methods supported\n");
314 opregion->acpi = base + OPREGION_ACPI_OFFSET; 372 opregion->acpi = base + OPREGION_ACPI_OFFSET;
373 if (drm_core_check_feature(dev, DRIVER_MODESET)) {
374 intel_didl_outputs(dev);
375 if (!resume)
376 acpi_video_register();
377 }
315 } else { 378 } else {
316 DRM_DEBUG("Public ACPI methods not supported\n"); 379 DRM_DEBUG("Public ACPI methods not supported\n");
317 err = -ENOTSUPP; 380 err = -ENOTSUPP;
diff --git a/include/acpi/video.h b/include/acpi/video.h
new file mode 100644
index 000000000000..f0275bb79ce4
--- /dev/null
+++ b/include/acpi/video.h
@@ -0,0 +1,11 @@
1#ifndef __ACPI_VIDEO_H
2#define __ACPI_VIDEO_H
3
4#if (defined CONFIG_ACPI_VIDEO || defined CONFIG_ACPI_VIDEO_MODULE)
5extern int acpi_video_register(void);
6#else
7static inline int acpi_video_register(void) { return 0; }
8#endif
9
10#endif
11