• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/drivers/gpu/drm/i915/
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
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/* OpRegion mailbox #1: public ACPI methods */
63struct 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 */
85struct 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 */
93struct 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
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_FAILED;
155
156	bclp &= ASLE_BCLP_MSK;
157	if (bclp < 0 || bclp > 255)
158		return ASLE_BACKLIGHT_FAILED;
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_PINEVIEW(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	/* alsi is the current ALS reading in lux. 0 indicates below sensor
188	   range, 0xffff indicates above sensor range. 1-0xfffe are valid */
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	return 0;
202}
203
204static u32 asle_set_pfit(struct drm_device *dev, u32 pfit)
205{
206	/* Panel fitting is currently controlled by the X code, so this is a
207	   noop until modesetting support works fully */
208	if (!(pfit & ASLE_PFIT_VALID))
209		return ASLE_PFIT_FAILED;
210	return 0;
211}
212
213void opregion_asle_intr(struct drm_device *dev)
214{
215	struct drm_i915_private *dev_priv = dev->dev_private;
216	struct opregion_asle *asle = dev_priv->opregion.asle;
217	u32 asle_stat = 0;
218	u32 asle_req;
219
220	if (!asle)
221		return;
222
223	asle_req = asle->aslc & ASLE_REQ_MSK;
224
225	if (!asle_req) {
226		DRM_DEBUG_DRIVER("non asle set request??\n");
227		return;
228	}
229
230	if (asle_req & ASLE_SET_ALS_ILLUM)
231		asle_stat |= asle_set_als_illum(dev, asle->alsi);
232
233	if (asle_req & ASLE_SET_BACKLIGHT)
234		asle_stat |= asle_set_backlight(dev, asle->bclp);
235
236	if (asle_req & ASLE_SET_PFIT)
237		asle_stat |= asle_set_pfit(dev, asle->pfit);
238
239	if (asle_req & ASLE_SET_PWM_FREQ)
240		asle_stat |= asle_set_pwm_freq(dev, asle->pfmb);
241
242	asle->aslc = asle_stat;
243}
244
245static u32 asle_set_backlight_ironlake(struct drm_device *dev, u32 bclp)
246{
247	struct drm_i915_private *dev_priv = dev->dev_private;
248	struct opregion_asle *asle = dev_priv->opregion.asle;
249	u32 cpu_pwm_ctl, pch_pwm_ctl2;
250	u32 max_backlight, level;
251
252	if (!(bclp & ASLE_BCLP_VALID))
253		return ASLE_BACKLIGHT_FAILED;
254
255	bclp &= ASLE_BCLP_MSK;
256	if (bclp < 0 || bclp > 255)
257		return ASLE_BACKLIGHT_FAILED;
258
259	cpu_pwm_ctl = I915_READ(BLC_PWM_CPU_CTL);
260	pch_pwm_ctl2 = I915_READ(BLC_PWM_PCH_CTL2);
261	/* get the max PWM frequency */
262	max_backlight = (pch_pwm_ctl2 >> 16) & BACKLIGHT_DUTY_CYCLE_MASK;
263	/* calculate the expected PMW frequency */
264	level = (bclp * max_backlight) / 255;
265	/* reserve the high 16 bits */
266	cpu_pwm_ctl &= ~(BACKLIGHT_DUTY_CYCLE_MASK);
267	/* write the updated PWM frequency */
268	I915_WRITE(BLC_PWM_CPU_CTL, cpu_pwm_ctl | level);
269
270	asle->cblv = (bclp*0x64)/0xff | ASLE_CBLV_VALID;
271
272	return 0;
273}
274
275void ironlake_opregion_gse_intr(struct drm_device *dev)
276{
277	struct drm_i915_private *dev_priv = dev->dev_private;
278	struct opregion_asle *asle = dev_priv->opregion.asle;
279	u32 asle_stat = 0;
280	u32 asle_req;
281
282	if (!asle)
283		return;
284
285	asle_req = asle->aslc & ASLE_REQ_MSK;
286
287	if (!asle_req) {
288		DRM_DEBUG_DRIVER("non asle set request??\n");
289		return;
290	}
291
292	if (asle_req & ASLE_SET_ALS_ILLUM) {
293		DRM_DEBUG_DRIVER("Illum is not supported\n");
294		asle_stat |= ASLE_ALS_ILLUM_FAILED;
295	}
296
297	if (asle_req & ASLE_SET_BACKLIGHT)
298		asle_stat |= asle_set_backlight_ironlake(dev, asle->bclp);
299
300	if (asle_req & ASLE_SET_PFIT) {
301		DRM_DEBUG_DRIVER("Pfit is not supported\n");
302		asle_stat |= ASLE_PFIT_FAILED;
303	}
304
305	if (asle_req & ASLE_SET_PWM_FREQ) {
306		DRM_DEBUG_DRIVER("PWM freq is not supported\n");
307		asle_stat |= ASLE_PWM_FREQ_FAILED;
308	}
309
310	asle->aslc = asle_stat;
311}
312#define ASLE_ALS_EN    (1<<0)
313#define ASLE_BLC_EN    (1<<1)
314#define ASLE_PFIT_EN   (1<<2)
315#define ASLE_PFMB_EN   (1<<3)
316
317void opregion_enable_asle(struct drm_device *dev)
318{
319	struct drm_i915_private *dev_priv = dev->dev_private;
320	struct opregion_asle *asle = dev_priv->opregion.asle;
321
322	if (asle) {
323		if (IS_MOBILE(dev)) {
324			unsigned long irqflags;
325
326			spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
327			intel_enable_asle(dev);
328			spin_unlock_irqrestore(&dev_priv->user_irq_lock,
329					       irqflags);
330		}
331
332		asle->tche = ASLE_ALS_EN | ASLE_BLC_EN | ASLE_PFIT_EN |
333			ASLE_PFMB_EN;
334		asle->ardy = 1;
335	}
336}
337
338#define ACPI_EV_DISPLAY_SWITCH (1<<0)
339#define ACPI_EV_LID            (1<<1)
340#define ACPI_EV_DOCK           (1<<2)
341
342static struct intel_opregion *system_opregion;
343
344static int intel_opregion_video_event(struct notifier_block *nb,
345				      unsigned long val, void *data)
346{
347	/* The only video events relevant to opregion are 0x80. These indicate
348	   either a docking event, lid switch or display switch request. In
349	   Linux, these are handled by the dock, button and video drivers.
350	   We might want to fix the video driver to be opregion-aware in
351	   future, but right now we just indicate to the firmware that the
352	   request has been handled */
353
354	struct opregion_acpi *acpi;
355
356	if (!system_opregion)
357		return NOTIFY_DONE;
358
359	acpi = system_opregion->acpi;
360	acpi->csts = 0;
361
362	return NOTIFY_OK;
363}
364
365static struct notifier_block intel_opregion_notifier = {
366	.notifier_call = intel_opregion_video_event,
367};
368
369/*
370 * Initialise the DIDL field in opregion. This passes a list of devices to
371 * the firmware. Values are defined by section B.4.2 of the ACPI specification
372 * (version 3)
373 */
374
375static void intel_didl_outputs(struct drm_device *dev)
376{
377	struct drm_i915_private *dev_priv = dev->dev_private;
378	struct intel_opregion *opregion = &dev_priv->opregion;
379	struct drm_connector *connector;
380	acpi_handle handle;
381	struct acpi_device *acpi_dev, *acpi_cdev, *acpi_video_bus = NULL;
382	unsigned long long device_id;
383	acpi_status status;
384	int i = 0;
385
386	handle = DEVICE_ACPI_HANDLE(&dev->pdev->dev);
387	if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev)))
388		return;
389
390	if (acpi_is_video_device(acpi_dev))
391		acpi_video_bus = acpi_dev;
392	else {
393		list_for_each_entry(acpi_cdev, &acpi_dev->children, node) {
394			if (acpi_is_video_device(acpi_cdev)) {
395				acpi_video_bus = acpi_cdev;
396				break;
397			}
398		}
399	}
400
401	if (!acpi_video_bus) {
402		printk(KERN_WARNING "No ACPI video bus found\n");
403		return;
404	}
405
406	list_for_each_entry(acpi_cdev, &acpi_video_bus->children, node) {
407		if (i >= 8) {
408			dev_printk (KERN_ERR, &dev->pdev->dev,
409				    "More than 8 outputs detected\n");
410			return;
411		}
412		status =
413			acpi_evaluate_integer(acpi_cdev->handle, "_ADR",
414						NULL, &device_id);
415		if (ACPI_SUCCESS(status)) {
416			if (!device_id)
417				goto blind_set;
418			opregion->acpi->didl[i] = (u32)(device_id & 0x0f0f);
419			i++;
420		}
421	}
422
423end:
424	/* If fewer than 8 outputs, the list must be null terminated */
425	if (i < 8)
426		opregion->acpi->didl[i] = 0;
427	return;
428
429blind_set:
430	i = 0;
431	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
432		int output_type = ACPI_OTHER_OUTPUT;
433		if (i >= 8) {
434			dev_printk (KERN_ERR, &dev->pdev->dev,
435				    "More than 8 outputs detected\n");
436			return;
437		}
438		switch (connector->connector_type) {
439		case DRM_MODE_CONNECTOR_VGA:
440		case DRM_MODE_CONNECTOR_DVIA:
441			output_type = ACPI_VGA_OUTPUT;
442			break;
443		case DRM_MODE_CONNECTOR_Composite:
444		case DRM_MODE_CONNECTOR_SVIDEO:
445		case DRM_MODE_CONNECTOR_Component:
446		case DRM_MODE_CONNECTOR_9PinDIN:
447			output_type = ACPI_TV_OUTPUT;
448			break;
449		case DRM_MODE_CONNECTOR_DVII:
450		case DRM_MODE_CONNECTOR_DVID:
451		case DRM_MODE_CONNECTOR_DisplayPort:
452		case DRM_MODE_CONNECTOR_HDMIA:
453		case DRM_MODE_CONNECTOR_HDMIB:
454			output_type = ACPI_DIGITAL_OUTPUT;
455			break;
456		case DRM_MODE_CONNECTOR_LVDS:
457			output_type = ACPI_LVDS_OUTPUT;
458			break;
459		}
460		opregion->acpi->didl[i] |= (1<<31) | output_type | i;
461		i++;
462	}
463	goto end;
464}
465
466int intel_opregion_init(struct drm_device *dev, int resume)
467{
468	struct drm_i915_private *dev_priv = dev->dev_private;
469	struct intel_opregion *opregion = &dev_priv->opregion;
470	void *base;
471	u32 asls, mboxes;
472	int err = 0;
473
474	pci_read_config_dword(dev->pdev, PCI_ASLS, &asls);
475	DRM_DEBUG_DRIVER("graphic opregion physical addr: 0x%x\n", asls);
476	if (asls == 0) {
477		DRM_DEBUG_DRIVER("ACPI OpRegion not supported!\n");
478		return -ENOTSUPP;
479	}
480
481	base = ioremap(asls, OPREGION_SZ);
482	if (!base)
483		return -ENOMEM;
484
485	opregion->header = base;
486	if (memcmp(opregion->header->signature, OPREGION_SIGNATURE, 16)) {
487		DRM_DEBUG_DRIVER("opregion signature mismatch\n");
488		err = -EINVAL;
489		goto err_out;
490	}
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		if (drm_core_check_feature(dev, DRIVER_MODESET))
497			intel_didl_outputs(dev);
498	} else {
499		DRM_DEBUG_DRIVER("Public ACPI methods not supported\n");
500		err = -ENOTSUPP;
501		goto err_out;
502	}
503	opregion->enabled = 1;
504
505	if (mboxes & MBOX_SWSCI) {
506		DRM_DEBUG_DRIVER("SWSCI supported\n");
507		opregion->swsci = base + OPREGION_SWSCI_OFFSET;
508	}
509	if (mboxes & MBOX_ASLE) {
510		DRM_DEBUG_DRIVER("ASLE supported\n");
511		opregion->asle = base + OPREGION_ASLE_OFFSET;
512		opregion_enable_asle(dev);
513	}
514
515	if (!resume)
516		acpi_video_register();
517
518
519	/* Notify BIOS we are ready to handle ACPI video ext notifs.
520	 * Right now, all the events are handled by the ACPI video module.
521	 * We don't actually need to do anything with them. */
522	opregion->acpi->csts = 0;
523	opregion->acpi->drdy = 1;
524
525	system_opregion = opregion;
526	register_acpi_notifier(&intel_opregion_notifier);
527
528	return 0;
529
530err_out:
531	iounmap(opregion->header);
532	opregion->header = NULL;
533	acpi_video_register();
534	return err;
535}
536
537void intel_opregion_free(struct drm_device *dev, int suspend)
538{
539	struct drm_i915_private *dev_priv = dev->dev_private;
540	struct intel_opregion *opregion = &dev_priv->opregion;
541
542	if (!opregion->enabled)
543		return;
544
545	if (!suspend)
546		acpi_video_unregister();
547
548	opregion->acpi->drdy = 0;
549
550	system_opregion = NULL;
551	unregister_acpi_notifier(&intel_opregion_notifier);
552
553	/* just clear all opregion memory pointers now */
554	iounmap(opregion->header);
555	opregion->header = NULL;
556	opregion->acpi = NULL;
557	opregion->swsci = NULL;
558	opregion->asle = NULL;
559
560	opregion->enabled = 0;
561}
562