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