diff options
-rw-r--r-- | drivers/acpi/video.c | 40 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_dma.c | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_opregion.c | 65 | ||||
-rw-r--r-- | include/acpi/video.h | 11 |
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 | ||
2254 | static int __init acpi_video_init(void) | 2256 | static 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 | |||
2276 | int 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 | } |
2293 | EXPORT_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 | |||
2302 | static int __init acpi_video_init(void) | ||
2303 | { | ||
2304 | if (intel_opregion_present()) | ||
2305 | return 0; | ||
2306 | |||
2307 | return acpi_video_register(); | ||
2308 | } | ||
2271 | 2309 | ||
2272 | static void __exit acpi_video_exit(void) | 2310 | static 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 | ||
1169 | out_iomapfree: | 1170 | out_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 */ |
662 | extern int intel_opregion_init(struct drm_device *dev); | 662 | extern int intel_opregion_init(struct drm_device *dev, int resume); |
663 | extern void intel_opregion_free(struct drm_device *dev); | 663 | extern void intel_opregion_free(struct drm_device *dev); |
664 | extern void opregion_asle_intr(struct drm_device *dev); | 664 | extern void opregion_asle_intr(struct drm_device *dev); |
665 | extern void opregion_enable_asle(struct drm_device *dev); | 665 | extern 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 | |||
139 | static u32 asle_set_backlight(struct drm_device *dev, u32 bclp) | 146 | static 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 | ||
285 | int 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 | |||
298 | static 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 | |||
343 | int 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) | ||
5 | extern int acpi_video_register(void); | ||
6 | #else | ||
7 | static inline int acpi_video_register(void) { return 0; } | ||
8 | #endif | ||
9 | |||
10 | #endif | ||
11 | |||