1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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
35#define PCI_ASLE 0xe4
36#define PCI_LBPC 0xf4
37#define PCI_ASLS 0xfc
38
39#define OPREGION_SZ (8*1024)
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 0x1000
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
51struct 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
63struct opregion_acpi {
64 u32 drdy;
65 u32 csts;
66 u32 cevt;
67 u8 rsvd1[20];
68 u32 didl[8];
69 u32 cpdl[8];
70 u32 cadl[8];
71 u32 nadl[8];
72 u32 aslp;
73 u32 tidx;
74 u32 chpd;
75 u32 clid;
76 u32 cdck;
77 u32 sxsw;
78 u32 evts;
79 u32 cnot;
80 u32 nrdy;
81 u8 rsvd2[60];
82} __attribute__((packed));
83
84
85struct opregion_swsci {
86 u32 scic;
87 u32 parm;
88 u32 dslp;
89 u8 rsvd[244];
90} __attribute__((packed));
91
92
93struct opregion_asle {
94 u32 ardy;
95 u32 aslc;
96 u32 tche;
97 u32 alsi;
98 u32 bclp;
99 u32 pfit;
100 u32 cblv;
101 u16 bclm[20];
102 u32 cpfm;
103 u32 epfm;
104 u8 plut[74];
105 u32 pfmb;
106 u8 rsvd[102];
107} __attribute__((packed));
108
109
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
117#define ASLE_ALS_ILLUM_FAIL (2<<10)
118#define ASLE_BACKLIGHT_FAIL (2<<12)
119#define ASLE_PFIT_FAIL (2<<14)
120#define ASLE_PWM_FREQ_FAIL (2<<16)
121
122
123#define ASLE_BCLP_VALID (1<<31)
124#define ASLE_BCLP_MSK (~(1<<31))
125
126
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
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
146static 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 blc_pwm_ctl, blc_pwm_ctl2;
151 u32 max_backlight, level, shift;
152
153 if (!(bclp & ASLE_BCLP_VALID))
154 return ASLE_BACKLIGHT_FAIL;
155
156 bclp &= ASLE_BCLP_MSK;
157 if (bclp < 0 || bclp > 255)
158 return ASLE_BACKLIGHT_FAIL;
159
160 blc_pwm_ctl = I915_READ(BLC_PWM_CTL);
161 blc_pwm_ctl2 = I915_READ(BLC_PWM_CTL2);
162
163 if (IS_I965G(dev) && (blc_pwm_ctl2 & BLM_COMBINATION_MODE))
164 pci_write_config_dword(dev->pdev, PCI_LBPC, bclp);
165 else {
166 if (IS_IGD(dev)) {
167 blc_pwm_ctl &= ~(BACKLIGHT_DUTY_CYCLE_MASK - 1);
168 max_backlight = (blc_pwm_ctl & BACKLIGHT_MODULATION_FREQ_MASK) >>
169 BACKLIGHT_MODULATION_FREQ_SHIFT;
170 shift = BACKLIGHT_DUTY_CYCLE_SHIFT + 1;
171 } else {
172 blc_pwm_ctl &= ~BACKLIGHT_DUTY_CYCLE_MASK;
173 max_backlight = ((blc_pwm_ctl & BACKLIGHT_MODULATION_FREQ_MASK) >>
174 BACKLIGHT_MODULATION_FREQ_SHIFT) * 2;
175 shift = BACKLIGHT_DUTY_CYCLE_SHIFT;
176 }
177 level = (bclp * max_backlight) / 255;
178 I915_WRITE(BLC_PWM_CTL, blc_pwm_ctl | (level << shift));
179 }
180 asle->cblv = (bclp*0x64)/0xff | ASLE_CBLV_VALID;
181
182 return 0;
183}
184
185static u32 asle_set_als_illum(struct drm_device *dev, u32 alsi)
186{
187
188
189 return 0;
190}
191
192static u32 asle_set_pwm_freq(struct drm_device *dev, u32 pfmb)
193{
194 struct drm_i915_private *dev_priv = dev->dev_private;
195 if (pfmb & ASLE_PFMB_PWM_VALID) {
196 u32 blc_pwm_ctl = I915_READ(BLC_PWM_CTL);
197 u32 pwm = pfmb & ASLE_PFMB_PWM_MASK;
198 blc_pwm_ctl &= BACKLIGHT_DUTY_CYCLE_MASK;
199 pwm = pwm >> 9;
200
201 }
202 return 0;
203}
204
205static u32 asle_set_pfit(struct drm_device *dev, u32 pfit)
206{
207
208
209 if (!(pfit & ASLE_PFIT_VALID))
210 return ASLE_PFIT_FAIL;
211 return 0;
212}
213
214void opregion_asle_intr(struct drm_device *dev)
215{
216 struct drm_i915_private *dev_priv = dev->dev_private;
217 struct opregion_asle *asle = dev_priv->opregion.asle;
218 u32 asle_stat = 0;
219 u32 asle_req;
220
221 if (!asle)
222 return;
223
224 asle_req = asle->aslc & ASLE_REQ_MSK;
225
226 if (!asle_req) {
227 DRM_DEBUG("non asle set request??\n");
228 return;
229 }
230
231 if (asle_req & ASLE_SET_ALS_ILLUM)
232 asle_stat |= asle_set_als_illum(dev, asle->alsi);
233
234 if (asle_req & ASLE_SET_BACKLIGHT)
235 asle_stat |= asle_set_backlight(dev, asle->bclp);
236
237 if (asle_req & ASLE_SET_PFIT)
238 asle_stat |= asle_set_pfit(dev, asle->pfit);
239
240 if (asle_req & ASLE_SET_PWM_FREQ)
241 asle_stat |= asle_set_pwm_freq(dev, asle->pfmb);
242
243 asle->aslc = asle_stat;
244}
245
246#define ASLE_ALS_EN (1<<0)
247#define ASLE_BLC_EN (1<<1)
248#define ASLE_PFIT_EN (1<<2)
249#define ASLE_PFMB_EN (1<<3)
250
251void opregion_enable_asle(struct drm_device *dev)
252{
253 struct drm_i915_private *dev_priv = dev->dev_private;
254 struct opregion_asle *asle = dev_priv->opregion.asle;
255
256 if (asle) {
257 if (IS_MOBILE(dev)) {
258 unsigned long irqflags;
259
260 spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
261 i915_enable_pipestat(dev_priv, 1,
262 I915_LEGACY_BLC_EVENT_ENABLE);
263 spin_unlock_irqrestore(&dev_priv->user_irq_lock,
264 irqflags);
265 }
266
267 asle->tche = ASLE_ALS_EN | ASLE_BLC_EN | ASLE_PFIT_EN |
268 ASLE_PFMB_EN;
269 asle->ardy = 1;
270 }
271}
272
273#define ACPI_EV_DISPLAY_SWITCH (1<<0)
274#define ACPI_EV_LID (1<<1)
275#define ACPI_EV_DOCK (1<<2)
276
277static struct intel_opregion *system_opregion;
278
279static int intel_opregion_video_event(struct notifier_block *nb,
280 unsigned long val, void *data)
281{
282
283
284
285
286
287
288
289 struct opregion_acpi *acpi;
290
291 if (!system_opregion)
292 return NOTIFY_DONE;
293
294 acpi = system_opregion->acpi;
295 acpi->csts = 0;
296
297 return NOTIFY_OK;
298}
299
300static struct notifier_block intel_opregion_notifier = {
301 .notifier_call = intel_opregion_video_event,
302};
303
304
305
306
307
308
309
310static void intel_didl_outputs(struct drm_device *dev)
311{
312 struct drm_i915_private *dev_priv = dev->dev_private;
313 struct intel_opregion *opregion = &dev_priv->opregion;
314 struct drm_connector *connector;
315 int i = 0;
316
317 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
318 int output_type = ACPI_OTHER_OUTPUT;
319 if (i >= 8) {
320 dev_printk (KERN_ERR, &dev->pdev->dev,
321 "More than 8 outputs detected\n");
322 return;
323 }
324 switch (connector->connector_type) {
325 case DRM_MODE_CONNECTOR_VGA:
326 case DRM_MODE_CONNECTOR_DVIA:
327 output_type = ACPI_VGA_OUTPUT;
328 break;
329 case DRM_MODE_CONNECTOR_Composite:
330 case DRM_MODE_CONNECTOR_SVIDEO:
331 case DRM_MODE_CONNECTOR_Component:
332 case DRM_MODE_CONNECTOR_9PinDIN:
333 output_type = ACPI_TV_OUTPUT;
334 break;
335 case DRM_MODE_CONNECTOR_DVII:
336 case DRM_MODE_CONNECTOR_DVID:
337 case DRM_MODE_CONNECTOR_DisplayPort:
338 case DRM_MODE_CONNECTOR_HDMIA:
339 case DRM_MODE_CONNECTOR_HDMIB:
340 output_type = ACPI_DIGITAL_OUTPUT;
341 break;
342 case DRM_MODE_CONNECTOR_LVDS:
343 output_type = ACPI_LVDS_OUTPUT;
344 break;
345 }
346 opregion->acpi->didl[i] |= (1<<31) | output_type | i;
347 i++;
348 }
349
350
351 if (i < 8)
352 opregion->acpi->didl[i] = 0;
353}
354
355int intel_opregion_init(struct drm_device *dev, int resume)
356{
357 struct drm_i915_private *dev_priv = dev->dev_private;
358 struct intel_opregion *opregion = &dev_priv->opregion;
359 void *base;
360 u32 asls, mboxes;
361 int err = 0;
362
363 pci_read_config_dword(dev->pdev, PCI_ASLS, &asls);
364 DRM_DEBUG("graphic opregion physical addr: 0x%x\n", asls);
365 if (asls == 0) {
366 DRM_DEBUG("ACPI OpRegion not supported!\n");
367 return -ENOTSUPP;
368 }
369
370 base = ioremap(asls, OPREGION_SZ);
371 if (!base)
372 return -ENOMEM;
373
374 opregion->header = base;
375 if (memcmp(opregion->header->signature, OPREGION_SIGNATURE, 16)) {
376 DRM_DEBUG("opregion signature mismatch\n");
377 err = -EINVAL;
378 goto err_out;
379 }
380
381 mboxes = opregion->header->mboxes;
382 if (mboxes & MBOX_ACPI) {
383 DRM_DEBUG("Public ACPI methods supported\n");
384 opregion->acpi = base + OPREGION_ACPI_OFFSET;
385 if (drm_core_check_feature(dev, DRIVER_MODESET))
386 intel_didl_outputs(dev);
387 } else {
388 DRM_DEBUG("Public ACPI methods not supported\n");
389 err = -ENOTSUPP;
390 goto err_out;
391 }
392 opregion->enabled = 1;
393
394 if (mboxes & MBOX_SWSCI) {
395 DRM_DEBUG("SWSCI supported\n");
396 opregion->swsci = base + OPREGION_SWSCI_OFFSET;
397 }
398 if (mboxes & MBOX_ASLE) {
399 DRM_DEBUG("ASLE supported\n");
400 opregion->asle = base + OPREGION_ASLE_OFFSET;
401 opregion_enable_asle(dev);
402 }
403
404 if (!resume)
405 acpi_video_register();
406
407
408
409
410
411 opregion->acpi->csts = 0;
412 opregion->acpi->drdy = 1;
413
414 system_opregion = opregion;
415 register_acpi_notifier(&intel_opregion_notifier);
416
417 return 0;
418
419err_out:
420 iounmap(opregion->header);
421 opregion->header = NULL;
422 return err;
423}
424
425void intel_opregion_free(struct drm_device *dev, int suspend)
426{
427 struct drm_i915_private *dev_priv = dev->dev_private;
428 struct intel_opregion *opregion = &dev_priv->opregion;
429
430 if (!opregion->enabled)
431 return;
432
433 if (!suspend)
434 acpi_video_unregister();
435
436 opregion->acpi->drdy = 0;
437
438 system_opregion = NULL;
439 unregister_acpi_notifier(&intel_opregion_notifier);
440
441
442 iounmap(opregion->header);
443 opregion->header = NULL;
444 opregion->acpi = NULL;
445 opregion->swsci = NULL;
446 opregion->asle = NULL;
447
448 opregion->enabled = 0;
449}
450