Merge branch 'fix/asoc' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6
[pandora-kernel.git] / drivers / gpu / drm / i915 / intel_opregion.c
1 /*
2  * Copyright 2008 Intel Corporation <hong.liu@intel.com>
3  * Copyright 2008 Red Hat <mjg@redhat.com>
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining
6  * a copy of this software and associated documentation files (the
7  * "Software"), to deal in the Software without restriction, including
8  * without limitation the rights to use, copy, modify, merge, publish,
9  * distribute, sub license, and/or sell copies of the Software, and to
10  * permit persons to whom the Software is furnished to do so, subject to
11  * the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the
14  * next paragraph) shall be included in all copies or substantial
15  * portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  * NON-INFRINGEMENT.  IN NO EVENT SHALL INTEL AND/OR ITS SUPPLIERS BE
21  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
22  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24  * SOFTWARE.
25  *
26  */
27
28 #include <linux/acpi.h>
29 #include <linux/acpi_io.h>
30 #include <acpi/video.h>
31
32 #include "drmP.h"
33 #include "i915_drm.h"
34 #include "i915_drv.h"
35 #include "intel_drv.h"
36
37 #define PCI_ASLE 0xe4
38 #define PCI_ASLS 0xfc
39
40 #define OPREGION_HEADER_OFFSET 0
41 #define OPREGION_ACPI_OFFSET   0x100
42 #define OPREGION_SWSCI_OFFSET  0x200
43 #define OPREGION_ASLE_OFFSET   0x300
44 #define OPREGION_VBT_OFFSET    0x400
45
46 #define OPREGION_SIGNATURE "IntelGraphicsMem"
47 #define MBOX_ACPI      (1<<0)
48 #define MBOX_SWSCI     (1<<1)
49 #define MBOX_ASLE      (1<<2)
50
51 struct opregion_header {
52        u8 signature[16];
53        u32 size;
54        u32 opregion_ver;
55        u8 bios_ver[32];
56        u8 vbios_ver[16];
57        u8 driver_ver[16];
58        u32 mboxes;
59        u8 reserved[164];
60 } __attribute__((packed));
61
62 /* OpRegion mailbox #1: public ACPI methods */
63 struct opregion_acpi {
64        u32 drdy;       /* driver readiness */
65        u32 csts;       /* notification status */
66        u32 cevt;       /* current event */
67        u8 rsvd1[20];
68        u32 didl[8];    /* supported display devices ID list */
69        u32 cpdl[8];    /* currently presented display list */
70        u32 cadl[8];    /* currently active display list */
71        u32 nadl[8];    /* next active devices list */
72        u32 aslp;       /* ASL sleep time-out */
73        u32 tidx;       /* toggle table index */
74        u32 chpd;       /* current hotplug enable indicator */
75        u32 clid;       /* current lid state*/
76        u32 cdck;       /* current docking state */
77        u32 sxsw;       /* Sx state resume */
78        u32 evts;       /* ASL supported events */
79        u32 cnot;       /* current OS notification */
80        u32 nrdy;       /* driver status */
81        u8 rsvd2[60];
82 } __attribute__((packed));
83
84 /* OpRegion mailbox #2: SWSCI */
85 struct opregion_swsci {
86        u32 scic;       /* SWSCI command|status|data */
87        u32 parm;       /* command parameters */
88        u32 dslp;       /* driver sleep time-out */
89        u8 rsvd[244];
90 } __attribute__((packed));
91
92 /* OpRegion mailbox #3: ASLE */
93 struct opregion_asle {
94        u32 ardy;       /* driver readiness */
95        u32 aslc;       /* ASLE interrupt command */
96        u32 tche;       /* technology enabled indicator */
97        u32 alsi;       /* current ALS illuminance reading */
98        u32 bclp;       /* backlight brightness to set */
99        u32 pfit;       /* panel fitting state */
100        u32 cblv;       /* current brightness level */
101        u16 bclm[20];   /* backlight level duty cycle mapping table */
102        u32 cpfm;       /* current panel fitting mode */
103        u32 epfm;       /* enabled panel fitting modes */
104        u8 plut[74];    /* panel LUT and identifier */
105        u32 pfmb;       /* PWM freq and min brightness */
106        u8 rsvd[102];
107 } __attribute__((packed));
108
109 /* ASLE irq request bits */
110 #define ASLE_SET_ALS_ILLUM     (1 << 0)
111 #define ASLE_SET_BACKLIGHT     (1 << 1)
112 #define ASLE_SET_PFIT          (1 << 2)
113 #define ASLE_SET_PWM_FREQ      (1 << 3)
114 #define ASLE_REQ_MSK           0xf
115
116 /* response bits of ASLE irq request */
117 #define ASLE_ALS_ILLUM_FAILED   (1<<10)
118 #define ASLE_BACKLIGHT_FAILED   (1<<12)
119 #define ASLE_PFIT_FAILED        (1<<14)
120 #define ASLE_PWM_FREQ_FAILED    (1<<16)
121
122 /* ASLE backlight brightness to set */
123 #define ASLE_BCLP_VALID                (1<<31)
124 #define ASLE_BCLP_MSK          (~(1<<31))
125
126 /* ASLE panel fitting request */
127 #define ASLE_PFIT_VALID         (1<<31)
128 #define ASLE_PFIT_CENTER (1<<0)
129 #define ASLE_PFIT_STRETCH_TEXT (1<<1)
130 #define ASLE_PFIT_STRETCH_GFX (1<<2)
131
132 /* PWM frequency and minimum brightness */
133 #define ASLE_PFMB_BRIGHTNESS_MASK (0xff)
134 #define ASLE_PFMB_BRIGHTNESS_VALID (1<<8)
135 #define ASLE_PFMB_PWM_MASK (0x7ffffe00)
136 #define ASLE_PFMB_PWM_VALID (1<<31)
137
138 #define ASLE_CBLV_VALID         (1<<31)
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
146 #ifdef CONFIG_ACPI
147 static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
148 {
149         struct drm_i915_private *dev_priv = dev->dev_private;
150         struct opregion_asle *asle = dev_priv->opregion.asle;
151         u32 max;
152
153         if (!(bclp & ASLE_BCLP_VALID))
154                 return ASLE_BACKLIGHT_FAILED;
155
156         bclp &= ASLE_BCLP_MSK;
157         if (bclp > 255)
158                 return ASLE_BACKLIGHT_FAILED;
159
160         max = intel_panel_get_max_backlight(dev);
161         intel_panel_set_backlight(dev, bclp * max / 255);
162         asle->cblv = (bclp*0x64)/0xff | ASLE_CBLV_VALID;
163
164         return 0;
165 }
166
167 static u32 asle_set_als_illum(struct drm_device *dev, u32 alsi)
168 {
169         /* alsi is the current ALS reading in lux. 0 indicates below sensor
170            range, 0xffff indicates above sensor range. 1-0xfffe are valid */
171         return 0;
172 }
173
174 static u32 asle_set_pwm_freq(struct drm_device *dev, u32 pfmb)
175 {
176         struct drm_i915_private *dev_priv = dev->dev_private;
177         if (pfmb & ASLE_PFMB_PWM_VALID) {
178                 u32 blc_pwm_ctl = I915_READ(BLC_PWM_CTL);
179                 u32 pwm = pfmb & ASLE_PFMB_PWM_MASK;
180                 blc_pwm_ctl &= BACKLIGHT_DUTY_CYCLE_MASK;
181                 pwm = pwm >> 9;
182                 /* FIXME - what do we do with the PWM? */
183         }
184         return 0;
185 }
186
187 static u32 asle_set_pfit(struct drm_device *dev, u32 pfit)
188 {
189         /* Panel fitting is currently controlled by the X code, so this is a
190            noop until modesetting support works fully */
191         if (!(pfit & ASLE_PFIT_VALID))
192                 return ASLE_PFIT_FAILED;
193         return 0;
194 }
195
196 void intel_opregion_asle_intr(struct drm_device *dev)
197 {
198         struct drm_i915_private *dev_priv = dev->dev_private;
199         struct opregion_asle *asle = dev_priv->opregion.asle;
200         u32 asle_stat = 0;
201         u32 asle_req;
202
203         if (!asle)
204                 return;
205
206         asle_req = asle->aslc & ASLE_REQ_MSK;
207
208         if (!asle_req) {
209                 DRM_DEBUG_DRIVER("non asle set request??\n");
210                 return;
211         }
212
213         if (asle_req & ASLE_SET_ALS_ILLUM)
214                 asle_stat |= asle_set_als_illum(dev, asle->alsi);
215
216         if (asle_req & ASLE_SET_BACKLIGHT)
217                 asle_stat |= asle_set_backlight(dev, asle->bclp);
218
219         if (asle_req & ASLE_SET_PFIT)
220                 asle_stat |= asle_set_pfit(dev, asle->pfit);
221
222         if (asle_req & ASLE_SET_PWM_FREQ)
223                 asle_stat |= asle_set_pwm_freq(dev, asle->pfmb);
224
225         asle->aslc = asle_stat;
226 }
227
228 /* Only present on Ironlake+ */
229 void intel_opregion_gse_intr(struct drm_device *dev)
230 {
231         struct drm_i915_private *dev_priv = dev->dev_private;
232         struct opregion_asle *asle = dev_priv->opregion.asle;
233         u32 asle_stat = 0;
234         u32 asle_req;
235
236         if (!asle)
237                 return;
238
239         asle_req = asle->aslc & ASLE_REQ_MSK;
240
241         if (!asle_req) {
242                 DRM_DEBUG_DRIVER("non asle set request??\n");
243                 return;
244         }
245
246         if (asle_req & ASLE_SET_ALS_ILLUM) {
247                 DRM_DEBUG_DRIVER("Illum is not supported\n");
248                 asle_stat |= ASLE_ALS_ILLUM_FAILED;
249         }
250
251         if (asle_req & ASLE_SET_BACKLIGHT)
252                 asle_stat |= asle_set_backlight(dev, asle->bclp);
253
254         if (asle_req & ASLE_SET_PFIT) {
255                 DRM_DEBUG_DRIVER("Pfit is not supported\n");
256                 asle_stat |= ASLE_PFIT_FAILED;
257         }
258
259         if (asle_req & ASLE_SET_PWM_FREQ) {
260                 DRM_DEBUG_DRIVER("PWM freq is not supported\n");
261                 asle_stat |= ASLE_PWM_FREQ_FAILED;
262         }
263
264         asle->aslc = asle_stat;
265 }
266 #define ASLE_ALS_EN    (1<<0)
267 #define ASLE_BLC_EN    (1<<1)
268 #define ASLE_PFIT_EN   (1<<2)
269 #define ASLE_PFMB_EN   (1<<3)
270
271 void intel_opregion_enable_asle(struct drm_device *dev)
272 {
273         struct drm_i915_private *dev_priv = dev->dev_private;
274         struct opregion_asle *asle = dev_priv->opregion.asle;
275
276         if (asle) {
277                 if (IS_MOBILE(dev))
278                         intel_enable_asle(dev);
279
280                 asle->tche = ASLE_ALS_EN | ASLE_BLC_EN | ASLE_PFIT_EN |
281                         ASLE_PFMB_EN;
282                 asle->ardy = 1;
283         }
284 }
285
286 #define ACPI_EV_DISPLAY_SWITCH (1<<0)
287 #define ACPI_EV_LID            (1<<1)
288 #define ACPI_EV_DOCK           (1<<2)
289
290 static struct intel_opregion *system_opregion;
291
292 static int intel_opregion_video_event(struct notifier_block *nb,
293                                       unsigned long val, void *data)
294 {
295         /* The only video events relevant to opregion are 0x80. These indicate
296            either a docking event, lid switch or display switch request. In
297            Linux, these are handled by the dock, button and video drivers.
298            We might want to fix the video driver to be opregion-aware in
299            future, but right now we just indicate to the firmware that the
300            request has been handled */
301
302         struct opregion_acpi *acpi;
303
304         if (!system_opregion)
305                 return NOTIFY_DONE;
306
307         acpi = system_opregion->acpi;
308         acpi->csts = 0;
309
310         return NOTIFY_OK;
311 }
312
313 static struct notifier_block intel_opregion_notifier = {
314         .notifier_call = intel_opregion_video_event,
315 };
316
317 /*
318  * Initialise the DIDL field in opregion. This passes a list of devices to
319  * the firmware. Values are defined by section B.4.2 of the ACPI specification
320  * (version 3)
321  */
322
323 static void intel_didl_outputs(struct drm_device *dev)
324 {
325         struct drm_i915_private *dev_priv = dev->dev_private;
326         struct intel_opregion *opregion = &dev_priv->opregion;
327         struct drm_connector *connector;
328         acpi_handle handle;
329         struct acpi_device *acpi_dev, *acpi_cdev, *acpi_video_bus = NULL;
330         unsigned long long device_id;
331         acpi_status status;
332         int i = 0;
333
334         handle = DEVICE_ACPI_HANDLE(&dev->pdev->dev);
335         if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev)))
336                 return;
337
338         if (acpi_is_video_device(acpi_dev))
339                 acpi_video_bus = acpi_dev;
340         else {
341                 list_for_each_entry(acpi_cdev, &acpi_dev->children, node) {
342                         if (acpi_is_video_device(acpi_cdev)) {
343                                 acpi_video_bus = acpi_cdev;
344                                 break;
345                         }
346                 }
347         }
348
349         if (!acpi_video_bus) {
350                 printk(KERN_WARNING "No ACPI video bus found\n");
351                 return;
352         }
353
354         list_for_each_entry(acpi_cdev, &acpi_video_bus->children, node) {
355                 if (i >= 8) {
356                         dev_printk (KERN_ERR, &dev->pdev->dev,
357                                     "More than 8 outputs detected\n");
358                         return;
359                 }
360                 status =
361                         acpi_evaluate_integer(acpi_cdev->handle, "_ADR",
362                                                 NULL, &device_id);
363                 if (ACPI_SUCCESS(status)) {
364                         if (!device_id)
365                                 goto blind_set;
366                         opregion->acpi->didl[i] = (u32)(device_id & 0x0f0f);
367                         i++;
368                 }
369         }
370
371 end:
372         /* If fewer than 8 outputs, the list must be null terminated */
373         if (i < 8)
374                 opregion->acpi->didl[i] = 0;
375         return;
376
377 blind_set:
378         i = 0;
379         list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
380                 int output_type = ACPI_OTHER_OUTPUT;
381                 if (i >= 8) {
382                         dev_printk (KERN_ERR, &dev->pdev->dev,
383                                     "More than 8 outputs detected\n");
384                         return;
385                 }
386                 switch (connector->connector_type) {
387                 case DRM_MODE_CONNECTOR_VGA:
388                 case DRM_MODE_CONNECTOR_DVIA:
389                         output_type = ACPI_VGA_OUTPUT;
390                         break;
391                 case DRM_MODE_CONNECTOR_Composite:
392                 case DRM_MODE_CONNECTOR_SVIDEO:
393                 case DRM_MODE_CONNECTOR_Component:
394                 case DRM_MODE_CONNECTOR_9PinDIN:
395                         output_type = ACPI_TV_OUTPUT;
396                         break;
397                 case DRM_MODE_CONNECTOR_DVII:
398                 case DRM_MODE_CONNECTOR_DVID:
399                 case DRM_MODE_CONNECTOR_DisplayPort:
400                 case DRM_MODE_CONNECTOR_HDMIA:
401                 case DRM_MODE_CONNECTOR_HDMIB:
402                         output_type = ACPI_DIGITAL_OUTPUT;
403                         break;
404                 case DRM_MODE_CONNECTOR_LVDS:
405                         output_type = ACPI_LVDS_OUTPUT;
406                         break;
407                 }
408                 opregion->acpi->didl[i] |= (1<<31) | output_type | i;
409                 i++;
410         }
411         goto end;
412 }
413
414 void intel_opregion_init(struct drm_device *dev)
415 {
416         struct drm_i915_private *dev_priv = dev->dev_private;
417         struct intel_opregion *opregion = &dev_priv->opregion;
418
419         if (!opregion->header)
420                 return;
421
422         if (opregion->acpi) {
423                 if (drm_core_check_feature(dev, DRIVER_MODESET))
424                         intel_didl_outputs(dev);
425
426                 /* Notify BIOS we are ready to handle ACPI video ext notifs.
427                  * Right now, all the events are handled by the ACPI video module.
428                  * We don't actually need to do anything with them. */
429                 opregion->acpi->csts = 0;
430                 opregion->acpi->drdy = 1;
431
432                 system_opregion = opregion;
433                 register_acpi_notifier(&intel_opregion_notifier);
434         }
435
436         if (opregion->asle)
437                 intel_opregion_enable_asle(dev);
438 }
439
440 void intel_opregion_fini(struct drm_device *dev)
441 {
442         struct drm_i915_private *dev_priv = dev->dev_private;
443         struct intel_opregion *opregion = &dev_priv->opregion;
444
445         if (!opregion->header)
446                 return;
447
448         if (opregion->acpi) {
449                 opregion->acpi->drdy = 0;
450
451                 system_opregion = NULL;
452                 unregister_acpi_notifier(&intel_opregion_notifier);
453         }
454
455         /* just clear all opregion memory pointers now */
456         iounmap(opregion->header);
457         opregion->header = NULL;
458         opregion->acpi = NULL;
459         opregion->swsci = NULL;
460         opregion->asle = NULL;
461         opregion->vbt = NULL;
462 }
463 #endif
464
465 int intel_opregion_setup(struct drm_device *dev)
466 {
467         struct drm_i915_private *dev_priv = dev->dev_private;
468         struct intel_opregion *opregion = &dev_priv->opregion;
469         void *base;
470         u32 asls, mboxes;
471         int err = 0;
472
473         pci_read_config_dword(dev->pdev, PCI_ASLS, &asls);
474         DRM_DEBUG_DRIVER("graphic opregion physical addr: 0x%x\n", asls);
475         if (asls == 0) {
476                 DRM_DEBUG_DRIVER("ACPI OpRegion not supported!\n");
477                 return -ENOTSUPP;
478         }
479
480         base = acpi_os_ioremap(asls, OPREGION_SIZE);
481         if (!base)
482                 return -ENOMEM;
483
484         if (memcmp(base, OPREGION_SIGNATURE, 16)) {
485                 DRM_DEBUG_DRIVER("opregion signature mismatch\n");
486                 err = -EINVAL;
487                 goto err_out;
488         }
489         opregion->header = base;
490         opregion->vbt = base + OPREGION_VBT_OFFSET;
491
492         mboxes = opregion->header->mboxes;
493         if (mboxes & MBOX_ACPI) {
494                 DRM_DEBUG_DRIVER("Public ACPI methods supported\n");
495                 opregion->acpi = base + OPREGION_ACPI_OFFSET;
496         }
497
498         if (mboxes & MBOX_SWSCI) {
499                 DRM_DEBUG_DRIVER("SWSCI supported\n");
500                 opregion->swsci = base + OPREGION_SWSCI_OFFSET;
501         }
502         if (mboxes & MBOX_ASLE) {
503                 DRM_DEBUG_DRIVER("ASLE supported\n");
504                 opregion->asle = base + OPREGION_ASLE_OFFSET;
505         }
506
507         return 0;
508
509 err_out:
510         iounmap(base);
511         return err;
512 }