1235783Skib/*
2235783Skib * Copyright 2008 Intel Corporation <hong.liu@intel.com>
3235783Skib * Copyright 2008 Red Hat <mjg@redhat.com>
4235783Skib *
5235783Skib * Permission is hereby granted, free of charge, to any person obtaining
6235783Skib * a copy of this software and associated documentation files (the
7235783Skib * "Software"), to deal in the Software without restriction, including
8235783Skib * without limitation the rights to use, copy, modify, merge, publish,
9235783Skib * distribute, sub license, and/or sell copies of the Software, and to
10235783Skib * permit persons to whom the Software is furnished to do so, subject to
11235783Skib * the following conditions:
12235783Skib *
13235783Skib * The above copyright notice and this permission notice (including the
14235783Skib * next paragraph) shall be included in all copies or substantial
15235783Skib * portions of the Software.
16235783Skib *
17235783Skib * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18235783Skib * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19235783Skib * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20235783Skib * NON-INFRINGEMENT.  IN NO EVENT SHALL INTEL AND/OR ITS SUPPLIERS BE
21235783Skib * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
22235783Skib * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23235783Skib * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24235783Skib * SOFTWARE.
25235783Skib *
26235783Skib */
27235783Skib
28235783Skib#include <sys/cdefs.h>
29235783Skib__FBSDID("$FreeBSD$");
30235783Skib
31235783Skib#include <dev/drm2/drmP.h>
32235783Skib#include <dev/drm2/i915/i915_drm.h>
33235783Skib#include <dev/drm2/i915/i915_drv.h>
34235783Skib#include <dev/drm2/i915/intel_drv.h>
35235783Skib
36235783Skib#define PCI_ASLE 0xe4
37235783Skib#define PCI_ASLS 0xfc
38235783Skib
39235783Skib#define OPREGION_HEADER_OFFSET 0
40235783Skib#define OPREGION_ACPI_OFFSET   0x100
41235783Skib#define   ACPI_CLID 0x01ac /* current lid state indicator */
42235783Skib#define   ACPI_CDCK 0x01b0 /* current docking state indicator */
43235783Skib#define OPREGION_SWSCI_OFFSET  0x200
44235783Skib#define OPREGION_ASLE_OFFSET   0x300
45235783Skib#define OPREGION_VBT_OFFSET    0x400
46235783Skib
47235783Skib#define OPREGION_SIGNATURE "IntelGraphicsMem"
48235783Skib#define MBOX_ACPI      (1<<0)
49235783Skib#define MBOX_SWSCI     (1<<1)
50235783Skib#define MBOX_ASLE      (1<<2)
51235783Skib
52235783Skibstruct opregion_header {
53235783Skib	u8 signature[16];
54235783Skib	u32 size;
55235783Skib	u32 opregion_ver;
56235783Skib	u8 bios_ver[32];
57235783Skib	u8 vbios_ver[16];
58235783Skib	u8 driver_ver[16];
59235783Skib	u32 mboxes;
60235783Skib	u8 reserved[164];
61235783Skib} __attribute__((packed));
62235783Skib
63235783Skib/* OpRegion mailbox #1: public ACPI methods */
64235783Skibstruct opregion_acpi {
65235783Skib	u32 drdy;       /* driver readiness */
66235783Skib	u32 csts;       /* notification status */
67235783Skib	u32 cevt;       /* current event */
68235783Skib	u8 rsvd1[20];
69235783Skib	u32 didl[8];    /* supported display devices ID list */
70235783Skib	u32 cpdl[8];    /* currently presented display list */
71235783Skib	u32 cadl[8];    /* currently active display list */
72235783Skib	u32 nadl[8];    /* next active devices list */
73235783Skib	u32 aslp;       /* ASL sleep time-out */
74235783Skib	u32 tidx;       /* toggle table index */
75235783Skib	u32 chpd;       /* current hotplug enable indicator */
76235783Skib	u32 clid;       /* current lid state*/
77235783Skib	u32 cdck;       /* current docking state */
78235783Skib	u32 sxsw;       /* Sx state resume */
79235783Skib	u32 evts;       /* ASL supported events */
80235783Skib	u32 cnot;       /* current OS notification */
81235783Skib	u32 nrdy;       /* driver status */
82235783Skib	u8 rsvd2[60];
83235783Skib} __attribute__((packed));
84235783Skib
85235783Skib/* OpRegion mailbox #2: SWSCI */
86235783Skibstruct opregion_swsci {
87235783Skib	u32 scic;       /* SWSCI command|status|data */
88235783Skib	u32 parm;       /* command parameters */
89235783Skib	u32 dslp;       /* driver sleep time-out */
90235783Skib	u8 rsvd[244];
91235783Skib} __attribute__((packed));
92235783Skib
93235783Skib/* OpRegion mailbox #3: ASLE */
94235783Skibstruct opregion_asle {
95235783Skib	u32 ardy;       /* driver readiness */
96235783Skib	u32 aslc;       /* ASLE interrupt command */
97235783Skib	u32 tche;       /* technology enabled indicator */
98235783Skib	u32 alsi;       /* current ALS illuminance reading */
99235783Skib	u32 bclp;       /* backlight brightness to set */
100235783Skib	u32 pfit;       /* panel fitting state */
101235783Skib	u32 cblv;       /* current brightness level */
102235783Skib	u16 bclm[20];   /* backlight level duty cycle mapping table */
103235783Skib	u32 cpfm;       /* current panel fitting mode */
104235783Skib	u32 epfm;       /* enabled panel fitting modes */
105235783Skib	u8 plut[74];    /* panel LUT and identifier */
106235783Skib	u32 pfmb;       /* PWM freq and min brightness */
107235783Skib	u8 rsvd[102];
108235783Skib} __attribute__((packed));
109235783Skib
110235783Skib/* ASLE irq request bits */
111235783Skib#define ASLE_SET_ALS_ILLUM     (1 << 0)
112235783Skib#define ASLE_SET_BACKLIGHT     (1 << 1)
113235783Skib#define ASLE_SET_PFIT          (1 << 2)
114235783Skib#define ASLE_SET_PWM_FREQ      (1 << 3)
115235783Skib#define ASLE_REQ_MSK           0xf
116235783Skib
117235783Skib/* response bits of ASLE irq request */
118235783Skib#define ASLE_ALS_ILLUM_FAILED	(1<<10)
119235783Skib#define ASLE_BACKLIGHT_FAILED	(1<<12)
120235783Skib#define ASLE_PFIT_FAILED	(1<<14)
121235783Skib#define ASLE_PWM_FREQ_FAILED	(1<<16)
122235783Skib
123235783Skib/* ASLE backlight brightness to set */
124235783Skib#define ASLE_BCLP_VALID                (1<<31)
125235783Skib#define ASLE_BCLP_MSK          (~(1<<31))
126235783Skib
127235783Skib/* ASLE panel fitting request */
128235783Skib#define ASLE_PFIT_VALID         (1<<31)
129235783Skib#define ASLE_PFIT_CENTER (1<<0)
130235783Skib#define ASLE_PFIT_STRETCH_TEXT (1<<1)
131235783Skib#define ASLE_PFIT_STRETCH_GFX (1<<2)
132235783Skib
133235783Skib/* PWM frequency and minimum brightness */
134235783Skib#define ASLE_PFMB_BRIGHTNESS_MASK (0xff)
135235783Skib#define ASLE_PFMB_BRIGHTNESS_VALID (1<<8)
136235783Skib#define ASLE_PFMB_PWM_MASK (0x7ffffe00)
137235783Skib#define ASLE_PFMB_PWM_VALID (1<<31)
138235783Skib
139235783Skib#define ASLE_CBLV_VALID         (1<<31)
140235783Skib
141235783Skib#define ACPI_OTHER_OUTPUT (0<<8)
142235783Skib#define ACPI_VGA_OUTPUT (1<<8)
143235783Skib#define ACPI_TV_OUTPUT (2<<8)
144235783Skib#define ACPI_DIGITAL_OUTPUT (3<<8)
145235783Skib#define ACPI_LVDS_OUTPUT (4<<8)
146235783Skib
147235783Skib#ifdef CONFIG_ACPI
148235783Skibstatic u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
149235783Skib{
150235783Skib	struct drm_i915_private *dev_priv = dev->dev_private;
151235783Skib	struct opregion_asle *asle = dev_priv->opregion.asle;
152235783Skib	u32 max;
153235783Skib
154235783Skib	if (!(bclp & ASLE_BCLP_VALID))
155235783Skib		return ASLE_BACKLIGHT_FAILED;
156235783Skib
157235783Skib	bclp &= ASLE_BCLP_MSK;
158235783Skib	if (bclp > 255)
159235783Skib		return ASLE_BACKLIGHT_FAILED;
160235783Skib
161235783Skib	max = intel_panel_get_max_backlight(dev);
162235783Skib	intel_panel_set_backlight(dev, bclp * max / 255);
163235783Skib	asle->cblv = (bclp*0x64)/0xff | ASLE_CBLV_VALID;
164235783Skib
165235783Skib	return 0;
166235783Skib}
167235783Skib
168235783Skibstatic u32 asle_set_als_illum(struct drm_device *dev, u32 alsi)
169235783Skib{
170235783Skib	/* alsi is the current ALS reading in lux. 0 indicates below sensor
171235783Skib	   range, 0xffff indicates above sensor range. 1-0xfffe are valid */
172235783Skib	return 0;
173235783Skib}
174235783Skib
175235783Skibstatic u32 asle_set_pwm_freq(struct drm_device *dev, u32 pfmb)
176235783Skib{
177235783Skib	struct drm_i915_private *dev_priv = dev->dev_private;
178235783Skib	if (pfmb & ASLE_PFMB_PWM_VALID) {
179235783Skib		u32 blc_pwm_ctl = I915_READ(BLC_PWM_CTL);
180235783Skib		u32 pwm = pfmb & ASLE_PFMB_PWM_MASK;
181235783Skib		blc_pwm_ctl &= BACKLIGHT_DUTY_CYCLE_MASK;
182235783Skib		pwm = pwm >> 9;
183235783Skib		/* FIXME - what do we do with the PWM? */
184235783Skib	}
185235783Skib	return 0;
186235783Skib}
187235783Skib
188235783Skibstatic u32 asle_set_pfit(struct drm_device *dev, u32 pfit)
189235783Skib{
190235783Skib	/* Panel fitting is currently controlled by the X code, so this is a
191235783Skib	   noop until modesetting support works fully */
192235783Skib	if (!(pfit & ASLE_PFIT_VALID))
193235783Skib		return ASLE_PFIT_FAILED;
194235783Skib	return 0;
195235783Skib}
196235783Skib
197235783Skibvoid intel_opregion_asle_intr(struct drm_device *dev)
198235783Skib{
199235783Skib	struct drm_i915_private *dev_priv = dev->dev_private;
200235783Skib	struct opregion_asle *asle = dev_priv->opregion.asle;
201235783Skib	u32 asle_stat = 0;
202235783Skib	u32 asle_req;
203235783Skib
204235783Skib	if (!asle)
205235783Skib		return;
206235783Skib
207235783Skib	asle_req = asle->aslc & ASLE_REQ_MSK;
208235783Skib
209235783Skib	if (!asle_req) {
210235783Skib		DRM_DEBUG("non asle set request??\n");
211235783Skib		return;
212235783Skib	}
213235783Skib
214235783Skib	if (asle_req & ASLE_SET_ALS_ILLUM)
215235783Skib		asle_stat |= asle_set_als_illum(dev, asle->alsi);
216235783Skib
217235783Skib	if (asle_req & ASLE_SET_BACKLIGHT)
218235783Skib		asle_stat |= asle_set_backlight(dev, asle->bclp);
219235783Skib
220235783Skib	if (asle_req & ASLE_SET_PFIT)
221235783Skib		asle_stat |= asle_set_pfit(dev, asle->pfit);
222235783Skib
223235783Skib	if (asle_req & ASLE_SET_PWM_FREQ)
224235783Skib		asle_stat |= asle_set_pwm_freq(dev, asle->pfmb);
225235783Skib
226235783Skib	asle->aslc = asle_stat;
227235783Skib}
228235783Skib
229235783Skibvoid intel_opregion_gse_intr(struct drm_device *dev)
230235783Skib{
231235783Skib	struct drm_i915_private *dev_priv = dev->dev_private;
232235783Skib	struct opregion_asle *asle = dev_priv->opregion.asle;
233235783Skib	u32 asle_stat = 0;
234235783Skib	u32 asle_req;
235235783Skib
236235783Skib	if (!asle)
237235783Skib		return;
238235783Skib
239235783Skib	asle_req = asle->aslc & ASLE_REQ_MSK;
240235783Skib
241235783Skib	if (!asle_req) {
242235783Skib		DRM_DEBUG("non asle set request??\n");
243235783Skib		return;
244235783Skib	}
245235783Skib
246235783Skib	if (asle_req & ASLE_SET_ALS_ILLUM) {
247235783Skib		DRM_DEBUG("Illum is not supported\n");
248235783Skib		asle_stat |= ASLE_ALS_ILLUM_FAILED;
249235783Skib	}
250235783Skib
251235783Skib	if (asle_req & ASLE_SET_BACKLIGHT)
252235783Skib		asle_stat |= asle_set_backlight(dev, asle->bclp);
253235783Skib
254235783Skib	if (asle_req & ASLE_SET_PFIT) {
255235783Skib		DRM_DEBUG("Pfit is not supported\n");
256235783Skib		asle_stat |= ASLE_PFIT_FAILED;
257235783Skib	}
258235783Skib
259235783Skib	if (asle_req & ASLE_SET_PWM_FREQ) {
260235783Skib		DRM_DEBUG("PWM freq is not supported\n");
261235783Skib		asle_stat |= ASLE_PWM_FREQ_FAILED;
262235783Skib	}
263235783Skib
264235783Skib	asle->aslc = asle_stat;
265235783Skib}
266235783Skib#define ASLE_ALS_EN    (1<<0)
267235783Skib#define ASLE_BLC_EN    (1<<1)
268235783Skib#define ASLE_PFIT_EN   (1<<2)
269235783Skib#define ASLE_PFMB_EN   (1<<3)
270235783Skib
271235783Skibvoid intel_opregion_enable_asle(struct drm_device *dev)
272235783Skib{
273235783Skib	struct drm_i915_private *dev_priv = dev->dev_private;
274235783Skib	struct opregion_asle *asle = dev_priv->opregion.asle;
275235783Skib
276235783Skib	if (asle) {
277235783Skib		if (IS_MOBILE(dev))
278235783Skib			intel_enable_asle(dev);
279235783Skib
280235783Skib		asle->tche = ASLE_ALS_EN | ASLE_BLC_EN | ASLE_PFIT_EN |
281235783Skib			ASLE_PFMB_EN;
282235783Skib		asle->ardy = 1;
283235783Skib	}
284235783Skib}
285235783Skib
286235783Skib#define ACPI_EV_DISPLAY_SWITCH (1<<0)
287235783Skib#define ACPI_EV_LID            (1<<1)
288235783Skib#define ACPI_EV_DOCK           (1<<2)
289235783Skib
290235783Skibstatic struct intel_opregion *system_opregion;
291235783Skib
292235783Skibstatic int intel_opregion_video_event(struct notifier_block *nb,
293235783Skib				      unsigned long val, void *data)
294235783Skib{
295235783Skib	/* The only video events relevant to opregion are 0x80. These indicate
296235783Skib	   either a docking event, lid switch or display switch request. In
297235783Skib	   Linux, these are handled by the dock, button and video drivers.
298235783Skib	*/
299235783Skib	struct opregion_acpi *acpi;
300235783Skib	struct acpi_bus_event *event = data;
301235783Skib	int ret = NOTIFY_OK;
302235783Skib
303235783Skib	if (strcmp(event->device_class, ACPI_VIDEO_CLASS) != 0)
304235783Skib		return NOTIFY_DONE;
305235783Skib
306235783Skib	if (!system_opregion)
307235783Skib		return NOTIFY_DONE;
308235783Skib
309235783Skib	acpi = system_opregion->acpi;
310235783Skib
311235783Skib	if (event->type == 0x80 && !(acpi->cevt & 0x1))
312235783Skib		ret = NOTIFY_BAD;
313235783Skib
314235783Skib	acpi->csts = 0;
315235783Skib
316235783Skib	return ret;
317235783Skib}
318235783Skib
319235783Skibstatic struct notifier_block intel_opregion_notifier = {
320235783Skib	.notifier_call = intel_opregion_video_event,
321235783Skib};
322235783Skib
323235783Skib/*
324235783Skib * Initialise the DIDL field in opregion. This passes a list of devices to
325235783Skib * the firmware. Values are defined by section B.4.2 of the ACPI specification
326235783Skib * (version 3)
327235783Skib */
328235783Skib
329235783Skibstatic void intel_didl_outputs(struct drm_device *dev)
330235783Skib{
331235783Skib	struct drm_i915_private *dev_priv = dev->dev_private;
332235783Skib	struct intel_opregion *opregion = &dev_priv->opregion;
333235783Skib	struct drm_connector *connector;
334235783Skib	acpi_handle handle;
335235783Skib	struct acpi_device *acpi_dev, *acpi_cdev, *acpi_video_bus = NULL;
336235783Skib	unsigned long long device_id;
337235783Skib	acpi_status status;
338235783Skib	int i = 0;
339235783Skib
340235783Skib	handle = DEVICE_ACPI_HANDLE(&dev->pdev->dev);
341235783Skib	if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev)))
342235783Skib		return;
343235783Skib
344235783Skib	if (acpi_is_video_device(acpi_dev))
345235783Skib		acpi_video_bus = acpi_dev;
346235783Skib	else {
347235783Skib		list_for_each_entry(acpi_cdev, &acpi_dev->children, node) {
348235783Skib			if (acpi_is_video_device(acpi_cdev)) {
349235783Skib				acpi_video_bus = acpi_cdev;
350235783Skib				break;
351235783Skib			}
352235783Skib		}
353235783Skib	}
354235783Skib
355235783Skib	if (!acpi_video_bus) {
356235783Skib		printk(KERN_WARNING "No ACPI video bus found\n");
357235783Skib		return;
358235783Skib	}
359235783Skib
360235783Skib	list_for_each_entry(acpi_cdev, &acpi_video_bus->children, node) {
361235783Skib		if (i >= 8) {
362235783Skib			dev_printk(KERN_ERR, &dev->pdev->dev,
363235783Skib				    "More than 8 outputs detected\n");
364235783Skib			return;
365235783Skib		}
366235783Skib		status =
367235783Skib			acpi_evaluate_integer(acpi_cdev->handle, "_ADR",
368235783Skib						NULL, &device_id);
369235783Skib		if (ACPI_SUCCESS(status)) {
370235783Skib			if (!device_id)
371235783Skib				goto blind_set;
372235783Skib			opregion->acpi->didl[i] = (u32)(device_id & 0x0f0f);
373235783Skib			i++;
374235783Skib		}
375235783Skib	}
376235783Skib
377235783Skibend:
378235783Skib	/* If fewer than 8 outputs, the list must be null terminated */
379235783Skib	if (i < 8)
380235783Skib		opregion->acpi->didl[i] = 0;
381235783Skib	return;
382235783Skib
383235783Skibblind_set:
384235783Skib	i = 0;
385235783Skib	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
386235783Skib		int output_type = ACPI_OTHER_OUTPUT;
387235783Skib		if (i >= 8) {
388235783Skib			device_printf(dev->device,
389235783Skib				    "More than 8 outputs detected\n");
390235783Skib			return;
391235783Skib		}
392235783Skib		switch (connector->connector_type) {
393235783Skib		case DRM_MODE_CONNECTOR_VGA:
394235783Skib		case DRM_MODE_CONNECTOR_DVIA:
395235783Skib			output_type = ACPI_VGA_OUTPUT;
396235783Skib			break;
397235783Skib		case DRM_MODE_CONNECTOR_Composite:
398235783Skib		case DRM_MODE_CONNECTOR_SVIDEO:
399235783Skib		case DRM_MODE_CONNECTOR_Component:
400235783Skib		case DRM_MODE_CONNECTOR_9PinDIN:
401235783Skib			output_type = ACPI_TV_OUTPUT;
402235783Skib			break;
403235783Skib		case DRM_MODE_CONNECTOR_DVII:
404235783Skib		case DRM_MODE_CONNECTOR_DVID:
405235783Skib		case DRM_MODE_CONNECTOR_DisplayPort:
406235783Skib		case DRM_MODE_CONNECTOR_HDMIA:
407235783Skib		case DRM_MODE_CONNECTOR_HDMIB:
408235783Skib			output_type = ACPI_DIGITAL_OUTPUT;
409235783Skib			break;
410235783Skib		case DRM_MODE_CONNECTOR_LVDS:
411235783Skib			output_type = ACPI_LVDS_OUTPUT;
412235783Skib			break;
413235783Skib		}
414235783Skib		opregion->acpi->didl[i] |= (1<<31) | output_type | i;
415235783Skib		i++;
416235783Skib	}
417235783Skib	goto end;
418235783Skib}
419235783Skib
420235783Skibvoid intel_opregion_init(struct drm_device *dev)
421235783Skib{
422235783Skib	struct drm_i915_private *dev_priv = dev->dev_private;
423235783Skib	struct intel_opregion *opregion = &dev_priv->opregion;
424235783Skib
425235783Skib	if (!opregion->header)
426235783Skib		return;
427235783Skib
428235783Skib	if (opregion->acpi) {
429235783Skib		if (drm_core_check_feature(dev, DRIVER_MODESET))
430235783Skib			intel_didl_outputs(dev);
431235783Skib
432235783Skib		/* Notify BIOS we are ready to handle ACPI video ext notifs.
433235783Skib		 * Right now, all the events are handled by the ACPI video module.
434235783Skib		 * We don't actually need to do anything with them. */
435235783Skib		opregion->acpi->csts = 0;
436235783Skib		opregion->acpi->drdy = 1;
437235783Skib
438235783Skib		system_opregion = opregion;
439235783Skib		register_acpi_notifier(&intel_opregion_notifier);
440235783Skib	}
441235783Skib
442235783Skib	if (opregion->asle)
443235783Skib		intel_opregion_enable_asle(dev);
444235783Skib}
445235783Skib
446235783Skibvoid intel_opregion_fini(struct drm_device *dev)
447235783Skib{
448235783Skib	struct drm_i915_private *dev_priv = dev->dev_private;
449235783Skib	struct intel_opregion *opregion = &dev_priv->opregion;
450235783Skib
451235783Skib	if (!opregion->header)
452235783Skib		return;
453235783Skib
454235783Skib	if (opregion->acpi) {
455235783Skib		opregion->acpi->drdy = 0;
456235783Skib
457235783Skib		system_opregion = NULL;
458235783Skib		unregister_acpi_notifier(&intel_opregion_notifier);
459235783Skib	}
460235783Skib
461235783Skib	/* just clear all opregion memory pointers now */
462235783Skib	iounmap(opregion->header);
463235783Skib	opregion->header = NULL;
464235783Skib	opregion->acpi = NULL;
465235783Skib	opregion->swsci = NULL;
466235783Skib	opregion->asle = NULL;
467235783Skib	opregion->vbt = NULL;
468235783Skib}
469235783Skib#else
470235783Skibint
471235783Skibintel_opregion_init(struct drm_device *dev)
472235783Skib{
473235783Skib
474235783Skib	return (0);
475235783Skib}
476235783Skib
477235783Skibvoid
478235783Skibintel_opregion_fini(struct drm_device *dev)
479235783Skib{
480235783Skib	struct drm_i915_private *dev_priv;
481235783Skib	struct intel_opregion *opregion;
482235783Skib
483235783Skib	dev_priv = dev->dev_private;
484235783Skib	opregion = &dev_priv->opregion;
485235783Skib
486235783Skib	if (opregion->header == NULL)
487235783Skib		return;
488235783Skib
489235783Skib	pmap_unmapdev((vm_offset_t)opregion->header, OPREGION_SIZE);
490235783Skib	opregion->header = NULL;
491235783Skib	opregion->acpi = NULL;
492235783Skib	opregion->swsci = NULL;
493235783Skib	opregion->asle = NULL;
494235783Skib	opregion->vbt = NULL;
495235783Skib}
496235783Skib#endif
497235783Skib
498235783Skibint intel_opregion_setup(struct drm_device *dev)
499235783Skib{
500235783Skib	struct drm_i915_private *dev_priv = dev->dev_private;
501235783Skib	struct intel_opregion *opregion = &dev_priv->opregion;
502235783Skib	char *base;
503235783Skib	u32 asls, mboxes;
504235783Skib	int err = 0;
505235783Skib
506235783Skib	asls = pci_read_config(dev->device, PCI_ASLS, 4);
507235783Skib	DRM_DEBUG("graphic opregion physical addr: 0x%x\n", asls);
508235783Skib	if (asls == 0) {
509235783Skib		DRM_DEBUG("ACPI OpRegion not supported!\n");
510235783Skib		return -ENOTSUP;
511235783Skib	}
512235783Skib
513235783Skib	base = (void *)pmap_mapbios(asls, OPREGION_SIZE);
514235783Skib	if (!base)
515235783Skib		return -ENOMEM;
516235783Skib
517235783Skib	if (memcmp(base, OPREGION_SIGNATURE, 16)) {
518235783Skib		DRM_DEBUG("opregion signature mismatch\n");
519235783Skib		err = -EINVAL;
520235783Skib		goto err_out;
521235783Skib	}
522235783Skib	opregion->header = (struct opregion_header *)base;
523235783Skib	opregion->vbt = base + OPREGION_VBT_OFFSET;
524235783Skib
525235783Skib	opregion->lid_state = (u32 *)(base + ACPI_CLID);
526235783Skib
527235783Skib	mboxes = opregion->header->mboxes;
528235783Skib	if (mboxes & MBOX_ACPI) {
529235783Skib		DRM_DEBUG("Public ACPI methods supported\n");
530235783Skib		opregion->acpi = (struct opregion_acpi *)(base +
531235783Skib		    OPREGION_ACPI_OFFSET);
532235783Skib	}
533235783Skib
534235783Skib	if (mboxes & MBOX_SWSCI) {
535235783Skib		DRM_DEBUG("SWSCI supported\n");
536235783Skib		opregion->swsci = (struct opregion_swsci *)(base +
537235783Skib		    OPREGION_SWSCI_OFFSET);
538235783Skib	}
539235783Skib	if (mboxes & MBOX_ASLE) {
540235783Skib		DRM_DEBUG("ASLE supported\n");
541235783Skib		opregion->asle = (struct opregion_asle *)(base +
542235783Skib		    OPREGION_ASLE_OFFSET);
543235783Skib	}
544235783Skib
545235783Skib	return 0;
546235783Skib
547235783Skiberr_out:
548235783Skib	pmap_unmapdev((vm_offset_t)base, OPREGION_SIZE);
549235783Skib	return err;
550235783Skib}
551