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>
35279961Sjhb#include <contrib/dev/acpica/include/acpi.h>
36279961Sjhb#include <contrib/dev/acpica/include/accommon.h>
37279961Sjhb#include <dev/acpica/acpivar.h>
38235783Skib
39235783Skib#define PCI_ASLE 0xe4
40235783Skib#define PCI_ASLS 0xfc
41235783Skib
42235783Skib#define OPREGION_HEADER_OFFSET 0
43235783Skib#define OPREGION_ACPI_OFFSET   0x100
44235783Skib#define   ACPI_CLID 0x01ac /* current lid state indicator */
45235783Skib#define   ACPI_CDCK 0x01b0 /* current docking state indicator */
46235783Skib#define OPREGION_SWSCI_OFFSET  0x200
47235783Skib#define OPREGION_ASLE_OFFSET   0x300
48235783Skib#define OPREGION_VBT_OFFSET    0x400
49235783Skib
50235783Skib#define OPREGION_SIGNATURE "IntelGraphicsMem"
51235783Skib#define MBOX_ACPI      (1<<0)
52235783Skib#define MBOX_SWSCI     (1<<1)
53235783Skib#define MBOX_ASLE      (1<<2)
54235783Skib
55235783Skibstruct opregion_header {
56235783Skib	u8 signature[16];
57235783Skib	u32 size;
58235783Skib	u32 opregion_ver;
59235783Skib	u8 bios_ver[32];
60235783Skib	u8 vbios_ver[16];
61235783Skib	u8 driver_ver[16];
62235783Skib	u32 mboxes;
63235783Skib	u8 reserved[164];
64235783Skib} __attribute__((packed));
65235783Skib
66235783Skib/* OpRegion mailbox #1: public ACPI methods */
67235783Skibstruct opregion_acpi {
68235783Skib	u32 drdy;       /* driver readiness */
69235783Skib	u32 csts;       /* notification status */
70235783Skib	u32 cevt;       /* current event */
71235783Skib	u8 rsvd1[20];
72235783Skib	u32 didl[8];    /* supported display devices ID list */
73235783Skib	u32 cpdl[8];    /* currently presented display list */
74235783Skib	u32 cadl[8];    /* currently active display list */
75235783Skib	u32 nadl[8];    /* next active devices list */
76235783Skib	u32 aslp;       /* ASL sleep time-out */
77235783Skib	u32 tidx;       /* toggle table index */
78235783Skib	u32 chpd;       /* current hotplug enable indicator */
79235783Skib	u32 clid;       /* current lid state*/
80235783Skib	u32 cdck;       /* current docking state */
81235783Skib	u32 sxsw;       /* Sx state resume */
82235783Skib	u32 evts;       /* ASL supported events */
83235783Skib	u32 cnot;       /* current OS notification */
84235783Skib	u32 nrdy;       /* driver status */
85235783Skib	u8 rsvd2[60];
86235783Skib} __attribute__((packed));
87235783Skib
88235783Skib/* OpRegion mailbox #2: SWSCI */
89235783Skibstruct opregion_swsci {
90235783Skib	u32 scic;       /* SWSCI command|status|data */
91235783Skib	u32 parm;       /* command parameters */
92235783Skib	u32 dslp;       /* driver sleep time-out */
93235783Skib	u8 rsvd[244];
94235783Skib} __attribute__((packed));
95235783Skib
96235783Skib/* OpRegion mailbox #3: ASLE */
97235783Skibstruct opregion_asle {
98235783Skib	u32 ardy;       /* driver readiness */
99235783Skib	u32 aslc;       /* ASLE interrupt command */
100235783Skib	u32 tche;       /* technology enabled indicator */
101235783Skib	u32 alsi;       /* current ALS illuminance reading */
102235783Skib	u32 bclp;       /* backlight brightness to set */
103235783Skib	u32 pfit;       /* panel fitting state */
104235783Skib	u32 cblv;       /* current brightness level */
105235783Skib	u16 bclm[20];   /* backlight level duty cycle mapping table */
106235783Skib	u32 cpfm;       /* current panel fitting mode */
107235783Skib	u32 epfm;       /* enabled panel fitting modes */
108235783Skib	u8 plut[74];    /* panel LUT and identifier */
109235783Skib	u32 pfmb;       /* PWM freq and min brightness */
110235783Skib	u8 rsvd[102];
111235783Skib} __attribute__((packed));
112235783Skib
113235783Skib/* ASLE irq request bits */
114235783Skib#define ASLE_SET_ALS_ILLUM     (1 << 0)
115235783Skib#define ASLE_SET_BACKLIGHT     (1 << 1)
116235783Skib#define ASLE_SET_PFIT          (1 << 2)
117235783Skib#define ASLE_SET_PWM_FREQ      (1 << 3)
118235783Skib#define ASLE_REQ_MSK           0xf
119235783Skib
120235783Skib/* response bits of ASLE irq request */
121235783Skib#define ASLE_ALS_ILLUM_FAILED	(1<<10)
122235783Skib#define ASLE_BACKLIGHT_FAILED	(1<<12)
123235783Skib#define ASLE_PFIT_FAILED	(1<<14)
124235783Skib#define ASLE_PWM_FREQ_FAILED	(1<<16)
125235783Skib
126235783Skib/* ASLE backlight brightness to set */
127235783Skib#define ASLE_BCLP_VALID                (1<<31)
128235783Skib#define ASLE_BCLP_MSK          (~(1<<31))
129235783Skib
130235783Skib/* ASLE panel fitting request */
131235783Skib#define ASLE_PFIT_VALID         (1<<31)
132235783Skib#define ASLE_PFIT_CENTER (1<<0)
133235783Skib#define ASLE_PFIT_STRETCH_TEXT (1<<1)
134235783Skib#define ASLE_PFIT_STRETCH_GFX (1<<2)
135235783Skib
136235783Skib/* PWM frequency and minimum brightness */
137235783Skib#define ASLE_PFMB_BRIGHTNESS_MASK (0xff)
138235783Skib#define ASLE_PFMB_BRIGHTNESS_VALID (1<<8)
139235783Skib#define ASLE_PFMB_PWM_MASK (0x7ffffe00)
140235783Skib#define ASLE_PFMB_PWM_VALID (1<<31)
141235783Skib
142235783Skib#define ASLE_CBLV_VALID         (1<<31)
143235783Skib
144235783Skib#define ACPI_OTHER_OUTPUT (0<<8)
145235783Skib#define ACPI_VGA_OUTPUT (1<<8)
146235783Skib#define ACPI_TV_OUTPUT (2<<8)
147235783Skib#define ACPI_DIGITAL_OUTPUT (3<<8)
148235783Skib#define ACPI_LVDS_OUTPUT (4<<8)
149235783Skib
150282199Sdumbbell#if defined(CONFIG_ACPI)
151235783Skibstatic u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
152235783Skib{
153235783Skib	struct drm_i915_private *dev_priv = dev->dev_private;
154235783Skib	struct opregion_asle *asle = dev_priv->opregion.asle;
155235783Skib	u32 max;
156235783Skib
157235783Skib	if (!(bclp & ASLE_BCLP_VALID))
158235783Skib		return ASLE_BACKLIGHT_FAILED;
159235783Skib
160235783Skib	bclp &= ASLE_BCLP_MSK;
161235783Skib	if (bclp > 255)
162235783Skib		return ASLE_BACKLIGHT_FAILED;
163235783Skib
164235783Skib	max = intel_panel_get_max_backlight(dev);
165235783Skib	intel_panel_set_backlight(dev, bclp * max / 255);
166235783Skib	asle->cblv = (bclp*0x64)/0xff | ASLE_CBLV_VALID;
167235783Skib
168235783Skib	return 0;
169235783Skib}
170235783Skib
171235783Skibstatic u32 asle_set_als_illum(struct drm_device *dev, u32 alsi)
172235783Skib{
173235783Skib	/* alsi is the current ALS reading in lux. 0 indicates below sensor
174235783Skib	   range, 0xffff indicates above sensor range. 1-0xfffe are valid */
175235783Skib	return 0;
176235783Skib}
177235783Skib
178235783Skibstatic u32 asle_set_pwm_freq(struct drm_device *dev, u32 pfmb)
179235783Skib{
180235783Skib	struct drm_i915_private *dev_priv = dev->dev_private;
181235783Skib	if (pfmb & ASLE_PFMB_PWM_VALID) {
182235783Skib		u32 blc_pwm_ctl = I915_READ(BLC_PWM_CTL);
183235783Skib		u32 pwm = pfmb & ASLE_PFMB_PWM_MASK;
184235783Skib		blc_pwm_ctl &= BACKLIGHT_DUTY_CYCLE_MASK;
185235783Skib		pwm = pwm >> 9;
186235783Skib		/* FIXME - what do we do with the PWM? */
187235783Skib	}
188235783Skib	return 0;
189235783Skib}
190235783Skib
191235783Skibstatic u32 asle_set_pfit(struct drm_device *dev, u32 pfit)
192235783Skib{
193235783Skib	/* Panel fitting is currently controlled by the X code, so this is a
194235783Skib	   noop until modesetting support works fully */
195235783Skib	if (!(pfit & ASLE_PFIT_VALID))
196235783Skib		return ASLE_PFIT_FAILED;
197235783Skib	return 0;
198235783Skib}
199235783Skib
200235783Skibvoid intel_opregion_asle_intr(struct drm_device *dev)
201235783Skib{
202235783Skib	struct drm_i915_private *dev_priv = dev->dev_private;
203235783Skib	struct opregion_asle *asle = dev_priv->opregion.asle;
204235783Skib	u32 asle_stat = 0;
205235783Skib	u32 asle_req;
206235783Skib
207235783Skib	if (!asle)
208235783Skib		return;
209235783Skib
210235783Skib	asle_req = asle->aslc & ASLE_REQ_MSK;
211235783Skib
212235783Skib	if (!asle_req) {
213235783Skib		DRM_DEBUG("non asle set request??\n");
214235783Skib		return;
215235783Skib	}
216235783Skib
217235783Skib	if (asle_req & ASLE_SET_ALS_ILLUM)
218235783Skib		asle_stat |= asle_set_als_illum(dev, asle->alsi);
219235783Skib
220235783Skib	if (asle_req & ASLE_SET_BACKLIGHT)
221235783Skib		asle_stat |= asle_set_backlight(dev, asle->bclp);
222235783Skib
223235783Skib	if (asle_req & ASLE_SET_PFIT)
224235783Skib		asle_stat |= asle_set_pfit(dev, asle->pfit);
225235783Skib
226235783Skib	if (asle_req & ASLE_SET_PWM_FREQ)
227235783Skib		asle_stat |= asle_set_pwm_freq(dev, asle->pfmb);
228235783Skib
229235783Skib	asle->aslc = asle_stat;
230235783Skib}
231235783Skib
232235783Skibvoid intel_opregion_gse_intr(struct drm_device *dev)
233235783Skib{
234235783Skib	struct drm_i915_private *dev_priv = dev->dev_private;
235235783Skib	struct opregion_asle *asle = dev_priv->opregion.asle;
236235783Skib	u32 asle_stat = 0;
237235783Skib	u32 asle_req;
238235783Skib
239235783Skib	if (!asle)
240235783Skib		return;
241235783Skib
242235783Skib	asle_req = asle->aslc & ASLE_REQ_MSK;
243235783Skib
244235783Skib	if (!asle_req) {
245235783Skib		DRM_DEBUG("non asle set request??\n");
246235783Skib		return;
247235783Skib	}
248235783Skib
249235783Skib	if (asle_req & ASLE_SET_ALS_ILLUM) {
250235783Skib		DRM_DEBUG("Illum is not supported\n");
251235783Skib		asle_stat |= ASLE_ALS_ILLUM_FAILED;
252235783Skib	}
253235783Skib
254235783Skib	if (asle_req & ASLE_SET_BACKLIGHT)
255235783Skib		asle_stat |= asle_set_backlight(dev, asle->bclp);
256235783Skib
257235783Skib	if (asle_req & ASLE_SET_PFIT) {
258235783Skib		DRM_DEBUG("Pfit is not supported\n");
259235783Skib		asle_stat |= ASLE_PFIT_FAILED;
260235783Skib	}
261235783Skib
262235783Skib	if (asle_req & ASLE_SET_PWM_FREQ) {
263235783Skib		DRM_DEBUG("PWM freq is not supported\n");
264235783Skib		asle_stat |= ASLE_PWM_FREQ_FAILED;
265235783Skib	}
266235783Skib
267235783Skib	asle->aslc = asle_stat;
268235783Skib}
269235783Skib#define ASLE_ALS_EN    (1<<0)
270235783Skib#define ASLE_BLC_EN    (1<<1)
271235783Skib#define ASLE_PFIT_EN   (1<<2)
272235783Skib#define ASLE_PFMB_EN   (1<<3)
273235783Skib
274235783Skibvoid intel_opregion_enable_asle(struct drm_device *dev)
275235783Skib{
276235783Skib	struct drm_i915_private *dev_priv = dev->dev_private;
277235783Skib	struct opregion_asle *asle = dev_priv->opregion.asle;
278235783Skib
279235783Skib	if (asle) {
280235783Skib		if (IS_MOBILE(dev))
281235783Skib			intel_enable_asle(dev);
282235783Skib
283235783Skib		asle->tche = ASLE_ALS_EN | ASLE_BLC_EN | ASLE_PFIT_EN |
284235783Skib			ASLE_PFMB_EN;
285235783Skib		asle->ardy = 1;
286235783Skib	}
287235783Skib}
288235783Skib
289235783Skib#define ACPI_EV_DISPLAY_SWITCH (1<<0)
290235783Skib#define ACPI_EV_LID            (1<<1)
291235783Skib#define ACPI_EV_DOCK           (1<<2)
292235783Skib
293235783Skibstatic struct intel_opregion *system_opregion;
294235783Skib
295279961Sjhb#if 0
296235783Skibstatic int intel_opregion_video_event(struct notifier_block *nb,
297235783Skib				      unsigned long val, void *data)
298235783Skib{
299235783Skib	/* The only video events relevant to opregion are 0x80. These indicate
300235783Skib	   either a docking event, lid switch or display switch request. In
301235783Skib	   Linux, these are handled by the dock, button and video drivers.
302235783Skib	*/
303235783Skib	struct opregion_acpi *acpi;
304235783Skib	struct acpi_bus_event *event = data;
305235783Skib	int ret = NOTIFY_OK;
306235783Skib
307235783Skib	if (strcmp(event->device_class, ACPI_VIDEO_CLASS) != 0)
308235783Skib		return NOTIFY_DONE;
309235783Skib
310235783Skib	if (!system_opregion)
311235783Skib		return NOTIFY_DONE;
312235783Skib
313235783Skib	acpi = system_opregion->acpi;
314235783Skib
315235783Skib	if (event->type == 0x80 && !(acpi->cevt & 0x1))
316235783Skib		ret = NOTIFY_BAD;
317235783Skib
318235783Skib	acpi->csts = 0;
319235783Skib
320235783Skib	return ret;
321235783Skib}
322235783Skib
323235783Skibstatic struct notifier_block intel_opregion_notifier = {
324235783Skib	.notifier_call = intel_opregion_video_event,
325235783Skib};
326279961Sjhb#endif
327235783Skib
328235783Skib/*
329235783Skib * Initialise the DIDL field in opregion. This passes a list of devices to
330235783Skib * the firmware. Values are defined by section B.4.2 of the ACPI specification
331235783Skib * (version 3)
332235783Skib */
333235783Skib
334279961Sjhbstatic int acpi_is_video_device(ACPI_HANDLE devh) {
335279961Sjhb	ACPI_HANDLE h;
336279961Sjhb	if (ACPI_FAILURE(AcpiGetHandle(devh, "_DOD", &h)) ||
337279961Sjhb		ACPI_FAILURE(AcpiGetHandle(devh, "_DOS", &h))) {
338279961Sjhb		return 0;
339279961Sjhb	}
340279961Sjhb	return 1;
341279961Sjhb}
342279961Sjhb
343235783Skibstatic void intel_didl_outputs(struct drm_device *dev)
344235783Skib{
345235783Skib	struct drm_i915_private *dev_priv = dev->dev_private;
346235783Skib	struct intel_opregion *opregion = &dev_priv->opregion;
347235783Skib	struct drm_connector *connector;
348279961Sjhb	u32 device_id;
349279961Sjhb	ACPI_HANDLE handle, acpi_video_bus, acpi_cdev;
350279961Sjhb	ACPI_STATUS status;
351235783Skib	int i = 0;
352235783Skib
353282199Sdumbbell	handle = acpi_get_handle(dev->dev);
354279961Sjhb	if (!handle)
355235783Skib		return;
356235783Skib
357279961Sjhb	if (acpi_is_video_device(handle))
358279961Sjhb		acpi_video_bus = handle;
359235783Skib	else {
360279961Sjhb		acpi_cdev = NULL;
361279961Sjhb		acpi_video_bus = NULL;
362279961Sjhb		while (AcpiGetNextObject(ACPI_TYPE_DEVICE, handle, acpi_cdev,
363279961Sjhb					&acpi_cdev) != AE_NOT_FOUND) {
364279961Sjhb			if (acpi_is_video_device(acpi_cdev)) {
365279961Sjhb				acpi_video_bus = acpi_cdev;
366279961Sjhb				break;
367279961Sjhb			}
368279961Sjhb		}
369279961Sjhb#if 0
370235783Skib		list_for_each_entry(acpi_cdev, &acpi_dev->children, node) {
371235783Skib			if (acpi_is_video_device(acpi_cdev)) {
372235783Skib				acpi_video_bus = acpi_cdev;
373235783Skib				break;
374235783Skib			}
375235783Skib		}
376279961Sjhb#endif
377235783Skib	}
378235783Skib
379235783Skib	if (!acpi_video_bus) {
380282199Sdumbbell		device_printf(dev->dev, "No ACPI video bus found\n");
381235783Skib		return;
382235783Skib	}
383235783Skib
384279961Sjhb	acpi_cdev = NULL;
385279961Sjhb	while (AcpiGetNextObject(ACPI_TYPE_DEVICE, acpi_video_bus, acpi_cdev,
386279961Sjhb				&acpi_cdev) != AE_NOT_FOUND) {
387279961Sjhb		if (i >= 8) {
388282199Sdumbbell			device_printf(dev->dev, "More than 8 outputs detected\n");
389279961Sjhb			return;
390279961Sjhb		}
391279961Sjhb		status = acpi_GetInteger(acpi_cdev, "_ADR", &device_id);
392279961Sjhb		if (ACPI_SUCCESS(status)) {
393279961Sjhb			if (!device_id)
394279961Sjhb				goto blind_set;
395279961Sjhb			opregion->acpi->didl[i] = (u32)(device_id & 0x0f0f);
396279961Sjhb			i++;
397279961Sjhb		}
398279961Sjhb	}
399279961Sjhb#if 0
400235783Skib	list_for_each_entry(acpi_cdev, &acpi_video_bus->children, node) {
401235783Skib		if (i >= 8) {
402235783Skib			dev_printk(KERN_ERR, &dev->pdev->dev,
403235783Skib				    "More than 8 outputs detected\n");
404235783Skib			return;
405235783Skib		}
406235783Skib		status =
407235783Skib			acpi_evaluate_integer(acpi_cdev->handle, "_ADR",
408235783Skib						NULL, &device_id);
409235783Skib		if (ACPI_SUCCESS(status)) {
410235783Skib			if (!device_id)
411235783Skib				goto blind_set;
412235783Skib			opregion->acpi->didl[i] = (u32)(device_id & 0x0f0f);
413235783Skib			i++;
414235783Skib		}
415235783Skib	}
416279961Sjhb#endif
417235783Skib
418235783Skibend:
419235783Skib	/* If fewer than 8 outputs, the list must be null terminated */
420235783Skib	if (i < 8)
421235783Skib		opregion->acpi->didl[i] = 0;
422235783Skib	return;
423235783Skib
424235783Skibblind_set:
425235783Skib	i = 0;
426235783Skib	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
427235783Skib		int output_type = ACPI_OTHER_OUTPUT;
428235783Skib		if (i >= 8) {
429282199Sdumbbell			device_printf(dev->dev,
430235783Skib				    "More than 8 outputs detected\n");
431235783Skib			return;
432235783Skib		}
433235783Skib		switch (connector->connector_type) {
434235783Skib		case DRM_MODE_CONNECTOR_VGA:
435235783Skib		case DRM_MODE_CONNECTOR_DVIA:
436235783Skib			output_type = ACPI_VGA_OUTPUT;
437235783Skib			break;
438235783Skib		case DRM_MODE_CONNECTOR_Composite:
439235783Skib		case DRM_MODE_CONNECTOR_SVIDEO:
440235783Skib		case DRM_MODE_CONNECTOR_Component:
441235783Skib		case DRM_MODE_CONNECTOR_9PinDIN:
442235783Skib			output_type = ACPI_TV_OUTPUT;
443235783Skib			break;
444235783Skib		case DRM_MODE_CONNECTOR_DVII:
445235783Skib		case DRM_MODE_CONNECTOR_DVID:
446235783Skib		case DRM_MODE_CONNECTOR_DisplayPort:
447235783Skib		case DRM_MODE_CONNECTOR_HDMIA:
448235783Skib		case DRM_MODE_CONNECTOR_HDMIB:
449235783Skib			output_type = ACPI_DIGITAL_OUTPUT;
450235783Skib			break;
451235783Skib		case DRM_MODE_CONNECTOR_LVDS:
452235783Skib			output_type = ACPI_LVDS_OUTPUT;
453235783Skib			break;
454235783Skib		}
455235783Skib		opregion->acpi->didl[i] |= (1<<31) | output_type | i;
456235783Skib		i++;
457235783Skib	}
458235783Skib	goto end;
459235783Skib}
460235783Skib
461279961Sjhbstatic void intel_setup_cadls(struct drm_device *dev)
462279961Sjhb{
463279961Sjhb	struct drm_i915_private *dev_priv = dev->dev_private;
464279961Sjhb	struct intel_opregion *opregion = &dev_priv->opregion;
465279961Sjhb	int i = 0;
466279961Sjhb	u32 disp_id;
467279961Sjhb
468279961Sjhb	/* Initialize the CADL field by duplicating the DIDL values.
469279961Sjhb	 * Technically, this is not always correct as display outputs may exist,
470279961Sjhb	 * but not active. This initialization is necessary for some Clevo
471279961Sjhb	 * laptops that check this field before processing the brightness and
472279961Sjhb	 * display switching hotkeys. Just like DIDL, CADL is NULL-terminated if
473279961Sjhb	 * there are less than eight devices. */
474279961Sjhb	do {
475279961Sjhb		disp_id = opregion->acpi->didl[i];
476279961Sjhb		opregion->acpi->cadl[i] = disp_id;
477279961Sjhb	} while (++i < 8 && disp_id != 0);
478279961Sjhb}
479279961Sjhb
480235783Skibvoid intel_opregion_init(struct drm_device *dev)
481235783Skib{
482235783Skib	struct drm_i915_private *dev_priv = dev->dev_private;
483235783Skib	struct intel_opregion *opregion = &dev_priv->opregion;
484235783Skib
485235783Skib	if (!opregion->header)
486235783Skib		return;
487235783Skib
488235783Skib	if (opregion->acpi) {
489279961Sjhb		if (drm_core_check_feature(dev, DRIVER_MODESET)) {
490235783Skib			intel_didl_outputs(dev);
491279961Sjhb			intel_setup_cadls(dev);
492279961Sjhb		}
493235783Skib
494235783Skib		/* Notify BIOS we are ready to handle ACPI video ext notifs.
495235783Skib		 * Right now, all the events are handled by the ACPI video module.
496235783Skib		 * We don't actually need to do anything with them. */
497235783Skib		opregion->acpi->csts = 0;
498235783Skib		opregion->acpi->drdy = 1;
499235783Skib
500235783Skib		system_opregion = opregion;
501279961Sjhb#if 0
502235783Skib		register_acpi_notifier(&intel_opregion_notifier);
503279961Sjhb#endif
504235783Skib	}
505235783Skib
506235783Skib	if (opregion->asle)
507235783Skib		intel_opregion_enable_asle(dev);
508235783Skib}
509235783Skib
510235783Skibvoid intel_opregion_fini(struct drm_device *dev)
511235783Skib{
512235783Skib	struct drm_i915_private *dev_priv = dev->dev_private;
513235783Skib	struct intel_opregion *opregion = &dev_priv->opregion;
514235783Skib
515235783Skib	if (!opregion->header)
516235783Skib		return;
517235783Skib
518235783Skib	if (opregion->acpi) {
519235783Skib		opregion->acpi->drdy = 0;
520235783Skib
521235783Skib		system_opregion = NULL;
522279961Sjhb#if 0
523235783Skib		unregister_acpi_notifier(&intel_opregion_notifier);
524279961Sjhb#endif
525235783Skib	}
526235783Skib
527235783Skib	/* just clear all opregion memory pointers now */
528279961Sjhb	pmap_unmapdev((vm_offset_t)opregion->header, OPREGION_SIZE);
529235783Skib	opregion->header = NULL;
530235783Skib	opregion->acpi = NULL;
531235783Skib	opregion->swsci = NULL;
532235783Skib	opregion->asle = NULL;
533235783Skib	opregion->vbt = NULL;
534235783Skib}
535235783Skib#else
536295623Sdumbbellvoid
537235783Skibintel_opregion_init(struct drm_device *dev)
538235783Skib{
539235783Skib}
540235783Skib
541235783Skibvoid
542235783Skibintel_opregion_fini(struct drm_device *dev)
543235783Skib{
544235783Skib	struct drm_i915_private *dev_priv;
545235783Skib	struct intel_opregion *opregion;
546235783Skib
547235783Skib	dev_priv = dev->dev_private;
548235783Skib	opregion = &dev_priv->opregion;
549235783Skib
550235783Skib	if (opregion->header == NULL)
551235783Skib		return;
552235783Skib
553235783Skib	pmap_unmapdev((vm_offset_t)opregion->header, OPREGION_SIZE);
554235783Skib	opregion->header = NULL;
555235783Skib	opregion->acpi = NULL;
556235783Skib	opregion->swsci = NULL;
557235783Skib	opregion->asle = NULL;
558235783Skib	opregion->vbt = NULL;
559235783Skib}
560235783Skib#endif
561235783Skib
562235783Skibint intel_opregion_setup(struct drm_device *dev)
563235783Skib{
564235783Skib	struct drm_i915_private *dev_priv = dev->dev_private;
565235783Skib	struct intel_opregion *opregion = &dev_priv->opregion;
566235783Skib	char *base;
567235783Skib	u32 asls, mboxes;
568235783Skib	int err = 0;
569235783Skib
570282199Sdumbbell	asls = pci_read_config(dev->dev, PCI_ASLS, 4);
571235783Skib	DRM_DEBUG("graphic opregion physical addr: 0x%x\n", asls);
572235783Skib	if (asls == 0) {
573235783Skib		DRM_DEBUG("ACPI OpRegion not supported!\n");
574235783Skib		return -ENOTSUP;
575235783Skib	}
576235783Skib
577235783Skib	base = (void *)pmap_mapbios(asls, OPREGION_SIZE);
578235783Skib	if (!base)
579235783Skib		return -ENOMEM;
580235783Skib
581235783Skib	if (memcmp(base, OPREGION_SIGNATURE, 16)) {
582235783Skib		DRM_DEBUG("opregion signature mismatch\n");
583235783Skib		err = -EINVAL;
584235783Skib		goto err_out;
585235783Skib	}
586235783Skib	opregion->header = (struct opregion_header *)base;
587235783Skib	opregion->vbt = base + OPREGION_VBT_OFFSET;
588235783Skib
589235783Skib	opregion->lid_state = (u32 *)(base + ACPI_CLID);
590235783Skib
591235783Skib	mboxes = opregion->header->mboxes;
592235783Skib	if (mboxes & MBOX_ACPI) {
593235783Skib		DRM_DEBUG("Public ACPI methods supported\n");
594235783Skib		opregion->acpi = (struct opregion_acpi *)(base +
595235783Skib		    OPREGION_ACPI_OFFSET);
596235783Skib	}
597235783Skib
598235783Skib	if (mboxes & MBOX_SWSCI) {
599235783Skib		DRM_DEBUG("SWSCI supported\n");
600235783Skib		opregion->swsci = (struct opregion_swsci *)(base +
601235783Skib		    OPREGION_SWSCI_OFFSET);
602235783Skib	}
603235783Skib	if (mboxes & MBOX_ASLE) {
604235783Skib		DRM_DEBUG("ASLE supported\n");
605235783Skib		opregion->asle = (struct opregion_asle *)(base +
606235783Skib		    OPREGION_ASLE_OFFSET);
607235783Skib	}
608235783Skib
609235783Skib	return 0;
610235783Skib
611235783Skiberr_out:
612235783Skib	pmap_unmapdev((vm_offset_t)base, OPREGION_SIZE);
613235783Skib	return err;
614235783Skib}
615