Re: Need help debugging Sony Vaio VPCY2 backlight control problem

Zhang Rui
2011-07-04T08:57:44Z

[-- Attachment #1: Type: text/plain, Size: 888 bytes --]

Hi, Michael,

please check if the two patches attached help.

thanks,
rui

On Mon, 2011-07-04 at 16:48 +0800, Michel Alexandre Salim wrote:
> On 07/04/2011 10:46 AM, Michel Alexandre Salim wrote:
> > Here are the ectool dumps, before setting any brightness (backlight=0),
> > after setting it to 5, and after setting it to 3, plus the typescript
> > log of the commands issued and the sysfs readings.
> >
> > I then set brightness back to 0 (ec-after3.txt) -- didn't log the
> > keyboard interactions because it's the same (value for brightness
> > concurs with what is set, but actual_brightness is still -1)
> >
> > Let me know if you need anything else. Once we can at least pinpoint the
> > problem to the right subsystem, I'll add these attachments to the
> > correct bug report.
> >
> > Thanks,
> >
> And here's the last dump file, forgot to attach it earlier.
>
> Thanks,
>

[-- Attachment #2: 0001-ACPI-Intel-Rework-Opregion-support.patch --]
[-- Type: text/x-patch, Size: 42149 bytes --]

>From b788969e3ee7ba2311e4c7c968895c5a3ca0cf7c Mon Sep 17 00:00:00 2001
From: Matthew Garrett <mjg@redhat.com>
Date: Wed, 18 May 2011 17:12:05 -0400
Subject: [PATCH 1/2] ACPI/Intel: Rework Opregion support

The Integrated Graphics Device opregion specification defines a mechanism
for the OS and system firmware to collaborate on various graphics-related
functionality. This is currently implemented in the i915 driver but isn't
strictly limited to these devices. Move it to a more generic location and
remove the i915 dependency, while simultaneously reworking i915 to make
use of the new driver.

Signed-off-by: Matthew Garrett <mjg@redhat.com>
Acked-by: Jesse Barnes <jbarnes@virtuousgeek.org>
[ickle: rebase onto drm-core-next]
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
drivers/acpi/Kconfig | 8 +
drivers/acpi/Makefile | 1 +
drivers/acpi/acpi_igd_opregion.c | 411 ++++++++++++++++++++++++++
drivers/gpu/drm/Kconfig | 1 +
drivers/gpu/drm/i915/Makefile | 1 -
drivers/gpu/drm/i915/i915_debugfs.c | 2 +-
drivers/gpu/drm/i915/i915_dma.c | 13 +-
drivers/gpu/drm/i915/i915_drv.c | 6 +-
drivers/gpu/drm/i915/i915_drv.h | 34 +--
drivers/gpu/drm/i915/i915_irq.c | 7 +-
drivers/gpu/drm/i915/intel_bios.c | 8 +-
drivers/gpu/drm/i915/intel_lvds.c | 2 +-
drivers/gpu/drm/i915/intel_opregion.c | 516 ---------------------------------
drivers/gpu/drm/i915/intel_panel.c | 4 +-
include/acpi/acpi_igd_opregion.h | 105 +++++++
15 files changed, 552 insertions(+), 567 deletions(-)
create mode 100644 drivers/acpi/acpi_igd_opregion.c
delete mode 100644 drivers/gpu/drm/i915/intel_opregion.c
create mode 100644 include/acpi/acpi_igd_opregion.h

diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index bc2218d..3824361 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -371,4 +371,12 @@ config ACPI_HED

source "drivers/acpi/apei/Kconfig"

+config ACPI_IGD_OPREGION
+ tristate "ACPI Integrated Graphics Device OpRegion support"
+ help
+ This driver adds support for the Intel ACPI Integrated Graphics
+ Device OpRegion specification, allowing communication between
+ the firmware and graphics driver on mobile systems with Intel
+ graphics
+
endif # ACPI
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index b66fbb2..0e641a8 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -61,6 +61,7 @@ obj-$(CONFIG_ACPI_SBS) += sbshc.o
obj-$(CONFIG_ACPI_SBS) += sbs.o
obj-$(CONFIG_ACPI_HED) += hed.o
obj-$(CONFIG_ACPI_EC_DEBUGFS) += ec_sys.o
+obj-$(CONFIG_ACPI_IGD_OPREGION) += acpi_igd_opregion.o

# processor has its own "processor." module_param namespace
processor-y := processor_driver.o processor_throttling.o
diff --git a/drivers/acpi/acpi_igd_opregion.c b/drivers/acpi/acpi_igd_opregion.c
new file mode 100644
index 0000000..0015ca8
--- /dev/null
+++ b/drivers/acpi/acpi_igd_opregion.c
@@ -0,0 +1,411 @@
+/*
+ * Copyright 2008 Intel Corporation <hong.liu@intel.com>
+ * Copyright 2008 Red Hat <mjg@redhat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT. IN NO EVENT SHALL INTEL AND/OR ITS SUPPLIERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#include <linux/acpi.h>
+#include <linux/acpi_io.h>
+#include <acpi/video.h>
+#include <acpi/acpi_igd_opregion.h>
+#include <drm/drmP.h>
+
+#define PCI_ASLE 0xe4
+#define PCI_ASLS 0xfc
+
+#define OPREGION_HEADER_OFFSET 0
+#define OPREGION_ACPI_OFFSET 0x100
+#define ACPI_CLID 0x01ac /* current lid state indicator */
+#define ACPI_CDCK 0x01b0 /* current docking state indicator */
+#define OPREGION_SWSCI_OFFSET 0x200
+#define OPREGION_ASLE_OFFSET 0x300
+#define OPREGION_VBT_OFFSET 0x400
+
+#define OPREGION_SIGNATURE "IntelGraphicsMem"
+#define MBOX_ACPI (1<<0)
+#define MBOX_SWSCI (1<<1)
+#define MBOX_ASLE (1<<2)
+
+/* ASLE irq request bits */
+#define ASLE_SET_ALS_ILLUM (1 << 0)
+#define ASLE_SET_BACKLIGHT (1 << 1)
+#define ASLE_SET_PFIT (1 << 2)
+#define ASLE_SET_PWM_FREQ (1 << 3)
+#define ASLE_REQ_MSK 0xf
+
+/* response bits of ASLE irq request */
+#define ASLE_ALS_ILLUM_FAILED (1<<10)
+#define ASLE_BACKLIGHT_FAILED (1<<12)
+#define ASLE_PFIT_FAILED (1<<14)
+#define ASLE_PWM_FREQ_FAILED (1<<16)
+
+/* ASLE backlight brightness to set */
+#define ASLE_BCLP_VALID (1<<31)
+#define ASLE_BCLP_MSK (~(1<<31))
+
+/* ASLE panel fitting request */
+#define ASLE_PFIT_VALID (1<<31)
+#define ASLE_PFIT_CENTER (1<<0)
+#define ASLE_PFIT_STRETCH_TEXT (1<<1)
+#define ASLE_PFIT_STRETCH_GFX (1<<2)
+
+/* PWM frequency and minimum brightness */
+#define ASLE_PFMB_BRIGHTNESS_MASK (0xff)
+#define ASLE_PFMB_BRIGHTNESS_VALID (1<<8)
+#define ASLE_PFMB_PWM_MASK (0x7ffffe00)
+#define ASLE_PFMB_PWM_VALID (1<<31)
+
+#define ASLE_CBLV_VALID (1<<31)
+
+#define ACPI_OTHER_OUTPUT (0<<8)
+#define ACPI_VGA_OUTPUT (1<<8)
+#define ACPI_TV_OUTPUT (2<<8)
+#define ACPI_DIGITAL_OUTPUT (3<<8)
+#define ACPI_LVDS_OUTPUT (4<<8)
+
+#ifdef CONFIG_ACPI
+static u32 asle_set_backlight(struct opregion_dev *dev, u32 bclp)
+{
+ struct opregion_asle *asle = dev->opregion.asle;
+ u32 max = dev->max_backlight;
+
+ if (!(bclp & ASLE_BCLP_VALID))
+ return ASLE_BACKLIGHT_FAILED;
+
+ bclp &= ASLE_BCLP_MSK;
+ if (bclp > 255)
+ return ASLE_BACKLIGHT_FAILED;
+
+ if (dev->set_backlight)
+ dev->set_backlight(dev->drm_dev, bclp * max / 255);
+
+ asle->cblv = (bclp*0x64)/0xff | ASLE_CBLV_VALID;
+
+ return 0;
+}
+
+static u32 asle_set_als_illum(struct opregion_dev *dev, u32 alsi)
+{
+ if (dev->set_als_illum)
+ dev->set_als_illum(dev->drm_dev, alsi);
+ return 0;
+}
+
+static u32 asle_set_pwm_freq(struct opregion_dev *dev, u32 pfmb)
+{
+ if (pfmb & ASLE_PFMB_PWM_VALID) {
+ if (dev->set_pwm_freq)
+ dev->set_pwm_freq(dev->drm_dev, pfmb);
+ }
+ return 0;
+}
+
+static u32 asle_set_pfit(struct opregion_dev *dev, u32 pfit)
+{
+ if (!(pfit & ASLE_PFIT_VALID))
+ return ASLE_PFIT_FAILED;
+
+ if (dev->set_pfit)
+ dev->set_pfit(dev->drm_dev, pfit);
+
+ return 0;
+}
+
+void igd_opregion_intr(struct opregion_dev *dev)
+{
+ struct opregion_asle *asle = dev->opregion.asle;
+ u32 asle_stat = 0;
+ u32 asle_req;
+
+ if (!asle)
+ return;
+
+ asle_req = asle->aslc & ASLE_REQ_MSK;
+
+ if (!asle_req) {
+ DRM_DEBUG_DRIVER("non asle set request??\n");
+ return;
+ }
+
+ if (asle_req & ASLE_SET_ALS_ILLUM)
+ asle_stat |= asle_set_als_illum(dev, asle->alsi);
+
+ if (asle_req & ASLE_SET_BACKLIGHT)
+ asle_stat |= asle_set_backlight(dev, asle->bclp);
+
+ if (asle_req & ASLE_SET_PFIT)
+ asle_stat |= asle_set_pfit(dev, asle->pfit);
+
+ if (asle_req & ASLE_SET_PWM_FREQ)
+ asle_stat |= asle_set_pwm_freq(dev, asle->pfmb);
+
+ asle->aslc = asle_stat;
+}
+EXPORT_SYMBOL(igd_opregion_intr);
+
+#define ASLE_ALS_EN (1<<0)
+#define ASLE_BLC_EN (1<<1)
+#define ASLE_PFIT_EN (1<<2)
+#define ASLE_PFMB_EN (1<<3)
+
+void igd_opregion_enable_asle(struct opregion_dev *dev)
+{
+ struct opregion_asle *asle = dev->opregion.asle;
+
+ if (asle && dev->enable_asle) {
+ dev->enable_asle(dev->drm_dev);
+
+ asle->tche = ASLE_ALS_EN | ASLE_BLC_EN | ASLE_PFIT_EN |
+ ASLE_PFMB_EN;
+ asle->ardy = 1;
+ }
+}
+EXPORT_SYMBOL(igd_opregion_enable_asle);
+
+#define ACPI_EV_DISPLAY_SWITCH (1<<0)
+#define ACPI_EV_LID (1<<1)
+#define ACPI_EV_DOCK (1<<2)
+
+static struct igd_opregion *system_opregion;
+
+static int igd_opregion_video_event(struct notifier_block *nb,
+ unsigned long val, void *data)
+{
+ /* The only video events relevant to opregion are 0x80. These indicate
+ either a docking event, lid switch or display switch request. In
+ Linux, these are handled by the dock, button and video drivers.
+ We might want to fix the video driver to be opregion-aware in
+ future, but right now we just indicate to the firmware that the
+ request has been handled */
+
+ struct opregion_acpi *acpi;
+
+ if (!system_opregion)
+ return NOTIFY_DONE;
+
+ acpi = system_opregion->acpi;
+ acpi->csts = 0;
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block igd_opregion_notifier = {
+ .notifier_call = igd_opregion_video_event,
+};
+
+/*
+ * Initialise the DIDL field in opregion. This passes a list of devices to
+ * the firmware. Values are defined by section B.4.2 of the ACPI specification
+ * (version 3)
+ */
+
+static void igd_didl_outputs(struct opregion_dev *dev)
+{
+ struct igd_opregion *opregion = &dev->opregion;
+ struct drm_connector *connector;
+ acpi_handle handle;
+ struct acpi_device *acpi_dev, *acpi_cdev, *acpi_video_bus = NULL;
+ unsigned long long device_id;
+ acpi_status status;
+ int i = 0;
+
+ handle = DEVICE_ACPI_HANDLE(&dev->drm_dev->pdev->dev);
+ if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev)))
+ return;
+
+ if (acpi_is_video_device(acpi_dev))
+ acpi_video_bus = acpi_dev;
+ else {
+ list_for_each_entry(acpi_cdev, &acpi_dev->children, node) {
+ if (acpi_is_video_device(acpi_cdev)) {
+ acpi_video_bus = acpi_cdev;
+ break;
+ }
+ }
+ }
+
+ if (!acpi_video_bus) {
+ printk(KERN_WARNING "No ACPI video bus found\n");
+ return;
+ }
+
+ list_for_each_entry(acpi_cdev, &acpi_video_bus->children, node) {
+ if (i >= 8) {
+ dev_printk(KERN_ERR, &dev->drm_dev->pdev->dev,
+ "More than 8 outputs detected\n");
+ return;
+ }
+ status =
+ acpi_evaluate_integer(acpi_cdev->handle, "_ADR",
+ NULL, &device_id);
+ if (ACPI_SUCCESS(status)) {
+ if (!device_id)
+ goto blind_set;
+ opregion->acpi->didl[i] = (u32)(device_id & 0x0f0f);
+ i++;
+ }
+ }
+
+end:
+ /* If fewer than 8 outputs, the list must be null terminated */
+ if (i < 8)
+ opregion->acpi->didl[i] = 0;
+ return;
+
+blind_set:
+ i = 0;
+ list_for_each_entry(connector, &dev->drm_dev->mode_config.connector_list, head) {
+ int output_type = ACPI_OTHER_OUTPUT;
+ if (i >= 8) {
+ dev_printk(KERN_ERR, &dev->drm_dev->pdev->dev,
+ "More than 8 outputs detected\n");
+ return;
+ }
+ switch (connector->connector_type) {
+ case DRM_MODE_CONNECTOR_VGA:
+ case DRM_MODE_CONNECTOR_DVIA:
+ output_type = ACPI_VGA_OUTPUT;
+ break;
+ case DRM_MODE_CONNECTOR_Composite:
+ case DRM_MODE_CONNECTOR_SVIDEO:
+ case DRM_MODE_CONNECTOR_Component:
+ case DRM_MODE_CONNECTOR_9PinDIN:
+ output_type = ACPI_TV_OUTPUT;
+ break;
+ case DRM_MODE_CONNECTOR_DVII:
+ case DRM_MODE_CONNECTOR_DVID:
+ case DRM_MODE_CONNECTOR_DisplayPort:
+ case DRM_MODE_CONNECTOR_HDMIA:
+ case DRM_MODE_CONNECTOR_HDMIB:
+ output_type = ACPI_DIGITAL_OUTPUT;
+ break;
+ case DRM_MODE_CONNECTOR_LVDS:
+ output_type = ACPI_LVDS_OUTPUT;
+ break;
+ }
+ opregion->acpi->didl[i] |= (1<<31) | output_type | i;
+ i++;
+ }
+ goto end;
+}
+
+void igd_opregion_init(struct opregion_dev *dev)
+{
+ struct igd_opregion *opregion = &dev->opregion;
+
+ if (!opregion->header)
+ return;
+
+ if (opregion->acpi) {
+ if (drm_core_check_feature(dev->drm_dev, DRIVER_MODESET))
+ igd_didl_outputs(dev);
+
+ /* Notify BIOS we are ready to handle ACPI video ext notifs.
+ * Right now, all the events are handled by the ACPI video module.
+ * We don't actually need to do anything with them. */
+ opregion->acpi->csts = 0;
+ opregion->acpi->drdy = 1;
+
+ system_opregion = opregion;
+ register_acpi_notifier(&igd_opregion_notifier);
+ }
+
+ if (opregion->asle)
+ dev->enable_asle(dev->drm_dev);
+}
+EXPORT_SYMBOL(igd_opregion_init);
+
+void igd_opregion_fini(struct opregion_dev *dev)
+{
+ struct igd_opregion *opregion = &dev->opregion;
+
+ if (!opregion->header)
+ return;
+
+ if (opregion->acpi) {
+ opregion->acpi->drdy = 0;
+
+ system_opregion = NULL;
+ unregister_acpi_notifier(&igd_opregion_notifier);
+ }
+
+ /* just clear all opregion memory pointers now */
+ iounmap(opregion->header);
+ opregion->header = NULL;
+ opregion->acpi = NULL;
+ opregion->swsci = NULL;
+ opregion->asle = NULL;
+ opregion->vbt = NULL;
+}
+EXPORT_SYMBOL(igd_opregion_fini);
+#endif
+
+int igd_opregion_setup(struct opregion_dev *dev)
+{
+ struct igd_opregion *opregion = &dev->opregion;
+ void *base;
+ u32 asls, mboxes;
+ int err = 0;
+
+ pci_read_config_dword(dev->drm_dev->pdev, PCI_ASLS, &asls);
+ DRM_DEBUG_DRIVER("graphic opregion physical addr: 0x%x\n", asls);
+ if (asls == 0) {
+ DRM_DEBUG_DRIVER("ACPI OpRegion not supported!\n");
+ return -ENOTSUPP;
+ }
+
+ base = acpi_os_ioremap(asls, OPREGION_SIZE);
+ if (!base)
+ return -ENOMEM;
+
+ if (memcmp(base, OPREGION_SIGNATURE, 16)) {
+ DRM_DEBUG_DRIVER("opregion signature mismatch\n");
+ err = -EINVAL;
+ goto err_out;
+ }
+ opregion->header = base;
+ opregion->vbt = base + OPREGION_VBT_OFFSET;
+
+ mboxes = opregion->header->mboxes;
+ if (mboxes & MBOX_ACPI) {
+ DRM_DEBUG_DRIVER("Public ACPI methods supported\n");
+ opregion->acpi = base + OPREGION_ACPI_OFFSET;
+ }
+
+ if (mboxes & MBOX_SWSCI) {
+ DRM_DEBUG_DRIVER("SWSCI supported\n");
+ opregion->swsci = base + OPREGION_SWSCI_OFFSET;
+ }
+ if (mboxes & MBOX_ASLE) {
+ DRM_DEBUG_DRIVER("ASLE supported\n");
+ opregion->asle = base + OPREGION_ASLE_OFFSET;
+ }
+
+ return 0;
+
+err_out:
+ iounmap(base);
+ return err;
+}
+EXPORT_SYMBOL(igd_opregion_setup);
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index b493663..fd6f79e 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -101,6 +101,7 @@ config DRM_I915
select INPUT if ACPI
select ACPI_VIDEO if ACPI
select ACPI_BUTTON if ACPI
+ select ACPI_IGD_OPREGION if ACPI
help
Choose this option if you have a system that has "Intel Graphics
Media Accelerator" or "HD Graphics" integrated graphics,
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 0ae6a7c..776c362 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -28,7 +28,6 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o \
intel_dvo.o \
intel_ringbuffer.o \
intel_overlay.o \
- intel_opregion.o \
dvo_ch7xxx.o \
dvo_ch7017.o \
dvo_ivch.o \
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 183eaac..74e48bb 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -1136,7 +1136,7 @@ static int i915_opregion(struct seq_file *m, void *unused)
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- struct intel_opregion *opregion = &dev_priv->opregion;
+ struct igd_opregion *opregion = &dev_priv->opregion_dev.opregion;
int ret;

ret = mutex_lock_interruptible(&dev->struct_mutex);
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 0239e99..8e68a1b 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -2027,7 +2027,14 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
/* Try to make sure MCHBAR is enabled before poking at it */
intel_setup_mchbar(dev);
intel_setup_gmbus(dev);
- intel_opregion_setup(dev);
+
+ if (IS_MOBILE(dev)) {
+ dev_priv->opregion_dev.max_backlight = intel_panel_get_max_backlight(dev);
+ dev_priv->opregion_dev.set_backlight = intel_panel_set_backlight;
+ }
+ dev_priv->opregion_dev.enable_asle = intel_enable_asle;
+ dev_priv->opregion_dev.drm_dev = dev;
+ igd_opregion_setup(&dev_priv->opregion_dev);

/* Make sure the bios did its job and set up vital registers */
intel_setup_bios(dev);
@@ -2087,7 +2094,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
}

/* Must be done after probing outputs */
- intel_opregion_init(dev);
+ igd_opregion_init(&dev_priv->opregion_dev);
acpi_video_register();

setup_timer(&dev_priv->hangcheck_timer, i915_hangcheck_elapsed,
@@ -2176,7 +2183,7 @@ int i915_driver_unload(struct drm_device *dev)
if (dev->pdev->msi_enabled)
pci_disable_msi(dev->pdev);

- intel_opregion_fini(dev);
+ igd_opregion_fini(&dev_priv->opregion_dev);

if (drm_core_check_feature(dev, DRIVER_MODESET)) {
/* Flush any outstanding unpin_work. */
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index c041869..0656106 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -371,7 +371,7 @@ static int i915_drm_freeze(struct drm_device *dev)

i915_save_state(dev);

- intel_opregion_fini(dev);
+ igd_opregion_fini(&dev_priv->opregion_dev);

/* Modeset on resume, not lid events */
dev_priv->modeset_on_lid = 0;
@@ -421,7 +421,7 @@ static int i915_drm_thaw(struct drm_device *dev)
}

i915_restore_state(dev);
- intel_opregion_setup(dev);
+ igd_opregion_setup(&dev_priv->opregion_dev);

/* KMS EnterVT equivalent */
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
@@ -441,7 +441,7 @@ static int i915_drm_thaw(struct drm_device *dev)
ironlake_enable_rc6(dev);
}

- intel_opregion_init(dev);
+ igd_opregion_init(&dev_priv->opregion_dev);

dev_priv->modeset_on_lid = 0;

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 3a1c277..9b2b94a 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -36,6 +36,7 @@
#include <linux/io-mapping.h>
#include <linux/i2c.h>
#include <drm/intel-gtt.h>
+#include <acpi/acpi_igd_opregion.h>

/* General customization:
*/
@@ -102,21 +103,6 @@ struct mem_block {
struct drm_file *file_priv; /* NULL: free, -1: heap, other: real files */
};

-struct opregion_header;
-struct opregion_acpi;
-struct opregion_swsci;
-struct opregion_asle;
-
-struct intel_opregion {
- struct opregion_header *header;
- struct opregion_acpi *acpi;
- struct opregion_swsci *swsci;
- struct opregion_asle *asle;
- void *vbt;
- u32 __iomem *lid_state;
-};
-#define OPREGION_SIZE (8*1024)
-
struct intel_overlay;
struct intel_overlay_error_state;

@@ -330,7 +316,7 @@ typedef struct drm_i915_private {
int cfb_plane;
int cfb_y;

- struct intel_opregion opregion;
+ struct opregion_dev opregion_dev;

/* overlay */
struct intel_overlay *overlay;
@@ -1281,22 +1267,6 @@ extern inline bool intel_gmbus_is_forced_bit(struct i2c_adapter *adapter)
}
extern void intel_i2c_reset(struct drm_device *dev);

-/* intel_opregion.c */
-extern int intel_opregion_setup(struct drm_device *dev);
-#ifdef CONFIG_ACPI
-extern void intel_opregion_init(struct drm_device *dev);
-extern void intel_opregion_fini(struct drm_device *dev);
-extern void intel_opregion_asle_intr(struct drm_device *dev);
-extern void intel_opregion_gse_intr(struct drm_device *dev);
-extern void intel_opregion_enable_asle(struct drm_device *dev);
-#else
-static inline void intel_opregion_init(struct drm_device *dev) { return; }
-static inline void intel_opregion_fini(struct drm_device *dev) { return; }
-static inline void intel_opregion_asle_intr(struct drm_device *dev) { return; }
-static inline void intel_opregion_gse_intr(struct drm_device *dev) { return; }
-static inline void intel_opregion_enable_asle(struct drm_device *dev) { return; }
-#endif
-
/* intel_acpi.c */
#ifdef CONFIG_ACPI
extern void intel_register_dsm_handler(void);
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 349a03e..f6eeeac 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -601,7 +601,7 @@ irqreturn_t ironlake_irq_handler(DRM_IRQ_ARGS)
notify_ring(dev, &dev_priv->ring[BCS]);

if (de_iir & DE_GSE)
- intel_opregion_gse_intr(dev);
+ igd_opregion_intr(&dev_priv->opregion_dev);

if (de_iir & DE_PLANEA_FLIP_DONE) {
intel_prepare_page_flip(dev, 0);
@@ -1322,9 +1322,8 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
blc_event = true;
}

-
if (blc_event || (iir & I915_ASLE_INTERRUPT))
- intel_opregion_asle_intr(dev);
+ igd_opregion_intr(&dev_priv->opregion_dev);

/* With MSI, interrupts are only generated when iir
* transitions from zero to nonzero. If another bit got
@@ -1977,7 +1976,7 @@ int i915_driver_irq_postinstall(struct drm_device *dev)
I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
}

- intel_opregion_enable_asle(dev);
+ igd_opregion_enable_asle(&dev_priv->opregion_dev);

return 0;
}
diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c
index 927442a..f606735 100644
--- a/drivers/gpu/drm/i915/intel_bios.c
+++ b/drivers/gpu/drm/i915/intel_bios.c
@@ -611,15 +611,15 @@ intel_parse_bios(struct drm_device *dev)

init_vbt_defaults(dev_priv);

- /* XXX Should this validation be moved to intel_opregion.c? */
- if (dev_priv->opregion.vbt) {
- struct vbt_header *vbt = dev_priv->opregion.vbt;
+ /* XXX Should this validation be moved to acpi_igd_opregion.c? */
+ if (dev_priv->opregion_dev.opregion.vbt) {
+ struct vbt_header *vbt = dev_priv->opregion_dev.opregion.vbt;
if (memcmp(vbt->signature, "$VBT", 4) == 0) {
DRM_DEBUG_DRIVER("Using VBT from OpRegion: %20s\n",
vbt->signature);
bdb = (struct bdb_header *)((char *)vbt + vbt->bdb_offset);
} else
- dev_priv->opregion.vbt = NULL;
+ dev_priv->opregion_dev.opregion.vbt = NULL;
}

if (bdb == NULL) {
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index 67cb076..3b90e68 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -825,7 +825,7 @@ static bool lvds_is_present_in_vbt(struct drm_device *dev,
* additional data. Trust that if the VBT was written into
* the OpRegion then they have validated the LVDS's existence.
*/
- if (dev_priv->opregion.vbt)
+ if (dev_priv->opregion_dev.opregion.vbt)
return true;
}

diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c
deleted file mode 100644
index d2c7104..0000000
--- a/drivers/gpu/drm/i915/intel_opregion.c
+++ /dev/null
@@ -1,516 +0,0 @@
-/*
- * Copyright 2008 Intel Corporation <hong.liu@intel.com>
- * Copyright 2008 Red Hat <mjg@redhat.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sub license, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NON-INFRINGEMENT. IN NO EVENT SHALL INTEL AND/OR ITS SUPPLIERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- */
-
-#include <linux/acpi.h>
-#include <linux/acpi_io.h>
-#include <acpi/video.h>
-
-#include "drmP.h"
-#include "i915_drm.h"
-#include "i915_drv.h"
-#include "intel_drv.h"
-
-#define PCI_ASLE 0xe4
-#define PCI_ASLS 0xfc
-
-#define OPREGION_HEADER_OFFSET 0
-#define OPREGION_ACPI_OFFSET 0x100
-#define ACPI_CLID 0x01ac /* current lid state indicator */
-#define ACPI_CDCK 0x01b0 /* current docking state indicator */
-#define OPREGION_SWSCI_OFFSET 0x200
-#define OPREGION_ASLE_OFFSET 0x300
-#define OPREGION_VBT_OFFSET 0x400
-
-#define OPREGION_SIGNATURE "IntelGraphicsMem"
-#define MBOX_ACPI (1<<0)
-#define MBOX_SWSCI (1<<1)
-#define MBOX_ASLE (1<<2)
-
-struct opregion_header {
- u8 signature[16];
- u32 size;
- u32 opregion_ver;
- u8 bios_ver[32];
- u8 vbios_ver[16];
- u8 driver_ver[16];
- u32 mboxes;
- u8 reserved[164];
-} __attribute__((packed));
-
-/* OpRegion mailbox #1: public ACPI methods */
-struct opregion_acpi {
- u32 drdy; /* driver readiness */
- u32 csts; /* notification status */
- u32 cevt; /* current event */
- u8 rsvd1[20];
- u32 didl[8]; /* supported display devices ID list */
- u32 cpdl[8]; /* currently presented display list */
- u32 cadl[8]; /* currently active display list */
- u32 nadl[8]; /* next active devices list */
- u32 aslp; /* ASL sleep time-out */
- u32 tidx; /* toggle table index */
- u32 chpd; /* current hotplug enable indicator */
- u32 clid; /* current lid state*/
- u32 cdck; /* current docking state */
- u32 sxsw; /* Sx state resume */
- u32 evts; /* ASL supported events */
- u32 cnot; /* current OS notification */
- u32 nrdy; /* driver status */
- u8 rsvd2[60];
-} __attribute__((packed));
-
-/* OpRegion mailbox #2: SWSCI */
-struct opregion_swsci {
- u32 scic; /* SWSCI command|status|data */
- u32 parm; /* command parameters */
- u32 dslp; /* driver sleep time-out */
- u8 rsvd[244];
-} __attribute__((packed));
-
-/* OpRegion mailbox #3: ASLE */
-struct opregion_asle {
- u32 ardy; /* driver readiness */
- u32 aslc; /* ASLE interrupt command */
- u32 tche; /* technology enabled indicator */
- u32 alsi; /* current ALS illuminance reading */
- u32 bclp; /* backlight brightness to set */
- u32 pfit; /* panel fitting state */
- u32 cblv; /* current brightness level */
- u16 bclm[20]; /* backlight level duty cycle mapping table */
- u32 cpfm; /* current panel fitting mode */
- u32 epfm; /* enabled panel fitting modes */
- u8 plut[74]; /* panel LUT and identifier */
- u32 pfmb; /* PWM freq and min brightness */
- u8 rsvd[102];
-} __attribute__((packed));
-
-/* ASLE irq request bits */
-#define ASLE_SET_ALS_ILLUM (1 << 0)
-#define ASLE_SET_BACKLIGHT (1 << 1)
-#define ASLE_SET_PFIT (1 << 2)
-#define ASLE_SET_PWM_FREQ (1 << 3)
-#define ASLE_REQ_MSK 0xf
-
-/* response bits of ASLE irq request */
-#define ASLE_ALS_ILLUM_FAILED (1<<10)
-#define ASLE_BACKLIGHT_FAILED (1<<12)
-#define ASLE_PFIT_FAILED (1<<14)
-#define ASLE_PWM_FREQ_FAILED (1<<16)
-
-/* ASLE backlight brightness to set */
-#define ASLE_BCLP_VALID (1<<31)
-#define ASLE_BCLP_MSK (~(1<<31))
-
-/* ASLE panel fitting request */
-#define ASLE_PFIT_VALID (1<<31)
-#define ASLE_PFIT_CENTER (1<<0)
-#define ASLE_PFIT_STRETCH_TEXT (1<<1)
-#define ASLE_PFIT_STRETCH_GFX (1<<2)
-
-/* PWM frequency and minimum brightness */
-#define ASLE_PFMB_BRIGHTNESS_MASK (0xff)
-#define ASLE_PFMB_BRIGHTNESS_VALID (1<<8)
-#define ASLE_PFMB_PWM_MASK (0x7ffffe00)
-#define ASLE_PFMB_PWM_VALID (1<<31)
-
-#define ASLE_CBLV_VALID (1<<31)
-
-#define ACPI_OTHER_OUTPUT (0<<8)
-#define ACPI_VGA_OUTPUT (1<<8)
-#define ACPI_TV_OUTPUT (2<<8)
-#define ACPI_DIGITAL_OUTPUT (3<<8)
-#define ACPI_LVDS_OUTPUT (4<<8)
-
-#ifdef CONFIG_ACPI
-static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct opregion_asle *asle = dev_priv->opregion.asle;
- u32 max;
-
- if (!(bclp & ASLE_BCLP_VALID))
- return ASLE_BACKLIGHT_FAILED;
-
- bclp &= ASLE_BCLP_MSK;
- if (bclp > 255)
- return ASLE_BACKLIGHT_FAILED;
-
- max = intel_panel_get_max_backlight(dev);
- intel_panel_set_backlight(dev, bclp * max / 255);
- asle->cblv = (bclp*0x64)/0xff | ASLE_CBLV_VALID;
-
- return 0;
-}
-
-static u32 asle_set_als_illum(struct drm_device *dev, u32 alsi)
-{
- /* alsi is the current ALS reading in lux. 0 indicates below sensor
- range, 0xffff indicates above sensor range. 1-0xfffe are valid */
- return 0;
-}
-
-static u32 asle_set_pwm_freq(struct drm_device *dev, u32 pfmb)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- if (pfmb & ASLE_PFMB_PWM_VALID) {
- u32 blc_pwm_ctl = I915_READ(BLC_PWM_CTL);
- u32 pwm = pfmb & ASLE_PFMB_PWM_MASK;
- blc_pwm_ctl &= BACKLIGHT_DUTY_CYCLE_MASK;
- pwm = pwm >> 9;
- /* FIXME - what do we do with the PWM? */
- }
- return 0;
-}
-
-static u32 asle_set_pfit(struct drm_device *dev, u32 pfit)
-{
- /* Panel fitting is currently controlled by the X code, so this is a
- noop until modesetting support works fully */
- if (!(pfit & ASLE_PFIT_VALID))
- return ASLE_PFIT_FAILED;
- return 0;
-}
-
-void intel_opregion_asle_intr(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct opregion_asle *asle = dev_priv->opregion.asle;
- u32 asle_stat = 0;
- u32 asle_req;
-
- if (!asle)
- return;
-
- asle_req = asle->aslc & ASLE_REQ_MSK;
-
- if (!asle_req) {
- DRM_DEBUG_DRIVER("non asle set request??\n");
- return;
- }
-
- if (asle_req & ASLE_SET_ALS_ILLUM)
- asle_stat |= asle_set_als_illum(dev, asle->alsi);
-
- if (asle_req & ASLE_SET_BACKLIGHT)
- asle_stat |= asle_set_backlight(dev, asle->bclp);
-
- if (asle_req & ASLE_SET_PFIT)
- asle_stat |= asle_set_pfit(dev, asle->pfit);
-
- if (asle_req & ASLE_SET_PWM_FREQ)
- asle_stat |= asle_set_pwm_freq(dev, asle->pfmb);
-
- asle->aslc = asle_stat;
-}
-
-/* Only present on Ironlake+ */
-void intel_opregion_gse_intr(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct opregion_asle *asle = dev_priv->opregion.asle;
- u32 asle_stat = 0;
- u32 asle_req;
-
- if (!asle)
- return;
-
- asle_req = asle->aslc & ASLE_REQ_MSK;
-
- if (!asle_req) {
- DRM_DEBUG_DRIVER("non asle set request??\n");
- return;
- }
-
- if (asle_req & ASLE_SET_ALS_ILLUM) {
- DRM_DEBUG_DRIVER("Illum is not supported\n");
- asle_stat |= ASLE_ALS_ILLUM_FAILED;
- }
-
- if (asle_req & ASLE_SET_BACKLIGHT)
- asle_stat |= asle_set_backlight(dev, asle->bclp);
-
- if (asle_req & ASLE_SET_PFIT) {
- DRM_DEBUG_DRIVER("Pfit is not supported\n");
- asle_stat |= ASLE_PFIT_FAILED;
- }
-
- if (asle_req & ASLE_SET_PWM_FREQ) {
- DRM_DEBUG_DRIVER("PWM freq is not supported\n");
- asle_stat |= ASLE_PWM_FREQ_FAILED;
- }
-
- asle->aslc = asle_stat;
-}
-#define ASLE_ALS_EN (1<<0)
-#define ASLE_BLC_EN (1<<1)
-#define ASLE_PFIT_EN (1<<2)
-#define ASLE_PFMB_EN (1<<3)
-
-void intel_opregion_enable_asle(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct opregion_asle *asle = dev_priv->opregion.asle;
-
- if (asle) {
- if (IS_MOBILE(dev))
- intel_enable_asle(dev);
-
- asle->tche = ASLE_ALS_EN | ASLE_BLC_EN | ASLE_PFIT_EN |
- ASLE_PFMB_EN;
- asle->ardy = 1;
- }
-}
-
-#define ACPI_EV_DISPLAY_SWITCH (1<<0)
-#define ACPI_EV_LID (1<<1)
-#define ACPI_EV_DOCK (1<<2)
-
-static struct intel_opregion *system_opregion;
-
-static int intel_opregion_video_event(struct notifier_block *nb,
- unsigned long val, void *data)
-{
- /* The only video events relevant to opregion are 0x80. These indicate
- either a docking event, lid switch or display switch request. In
- Linux, these are handled by the dock, button and video drivers.
- We might want to fix the video driver to be opregion-aware in
- future, but right now we just indicate to the firmware that the
- request has been handled */
-
- struct opregion_acpi *acpi;
-
- if (!system_opregion)
- return NOTIFY_DONE;
-
- acpi = system_opregion->acpi;
- acpi->csts = 0;
-
- return NOTIFY_OK;
-}
-
-static struct notifier_block intel_opregion_notifier = {
- .notifier_call = intel_opregion_video_event,
-};
-
-/*
- * Initialise the DIDL field in opregion. This passes a list of devices to
- * the firmware. Values are defined by section B.4.2 of the ACPI specification
- * (version 3)
- */
-
-static void intel_didl_outputs(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_opregion *opregion = &dev_priv->opregion;
- struct drm_connector *connector;
- acpi_handle handle;
- struct acpi_device *acpi_dev, *acpi_cdev, *acpi_video_bus = NULL;
- unsigned long long device_id;
- acpi_status status;
- int i = 0;
-
- handle = DEVICE_ACPI_HANDLE(&dev->pdev->dev);
- if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev)))
- return;
-
- if (acpi_is_video_device(acpi_dev))
- acpi_video_bus = acpi_dev;
- else {
- list_for_each_entry(acpi_cdev, &acpi_dev->children, node) {
- if (acpi_is_video_device(acpi_cdev)) {
- acpi_video_bus = acpi_cdev;
- break;
- }
- }
- }
-
- if (!acpi_video_bus) {
- printk(KERN_WARNING "No ACPI video bus found\n");
- return;
- }
-
- list_for_each_entry(acpi_cdev, &acpi_video_bus->children, node) {
- if (i >= 8) {
- dev_printk (KERN_ERR, &dev->pdev->dev,
- "More than 8 outputs detected\n");
- return;
- }
- status =
- acpi_evaluate_integer(acpi_cdev->handle, "_ADR",
- NULL, &device_id);
- if (ACPI_SUCCESS(status)) {
- if (!device_id)
- goto blind_set;
- opregion->acpi->didl[i] = (u32)(device_id & 0x0f0f);
- i++;
- }
- }
-
-end:
- /* If fewer than 8 outputs, the list must be null terminated */
- if (i < 8)
- opregion->acpi->didl[i] = 0;
- return;
-
-blind_set:
- i = 0;
- list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
- int output_type = ACPI_OTHER_OUTPUT;
- if (i >= 8) {
- dev_printk (KERN_ERR, &dev->pdev->dev,
- "More than 8 outputs detected\n");
- return;
- }
- switch (connector->connector_type) {
- case DRM_MODE_CONNECTOR_VGA:
- case DRM_MODE_CONNECTOR_DVIA:
- output_type = ACPI_VGA_OUTPUT;
- break;
- case DRM_MODE_CONNECTOR_Composite:
- case DRM_MODE_CONNECTOR_SVIDEO:
- case DRM_MODE_CONNECTOR_Component:
- case DRM_MODE_CONNECTOR_9PinDIN:
- output_type = ACPI_TV_OUTPUT;
- break;
- case DRM_MODE_CONNECTOR_DVII:
- case DRM_MODE_CONNECTOR_DVID:
- case DRM_MODE_CONNECTOR_DisplayPort:
- case DRM_MODE_CONNECTOR_HDMIA:
- case DRM_MODE_CONNECTOR_HDMIB:
- output_type = ACPI_DIGITAL_OUTPUT;
- break;
- case DRM_MODE_CONNECTOR_LVDS:
- output_type = ACPI_LVDS_OUTPUT;
- break;
- }
- opregion->acpi->didl[i] |= (1<<31) | output_type | i;
- i++;
- }
- goto end;
-}
-
-void intel_opregion_init(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_opregion *opregion = &dev_priv->opregion;
-
- if (!opregion->header)
- return;
-
- if (opregion->acpi) {
- if (drm_core_check_feature(dev, DRIVER_MODESET))
- intel_didl_outputs(dev);
-
- /* Notify BIOS we are ready to handle ACPI video ext notifs.
- * Right now, all the events are handled by the ACPI video module.
- * We don't actually need to do anything with them. */
- opregion->acpi->csts = 0;
- opregion->acpi->drdy = 1;
-
- system_opregion = opregion;
- register_acpi_notifier(&intel_opregion_notifier);
- }
-
- if (opregion->asle)
- intel_opregion_enable_asle(dev);
-}
-
-void intel_opregion_fini(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_opregion *opregion = &dev_priv->opregion;
-
- if (!opregion->header)
- return;
-
- if (opregion->acpi) {
- opregion->acpi->drdy = 0;
-
- system_opregion = NULL;
- unregister_acpi_notifier(&intel_opregion_notifier);
- }
-
- /* just clear all opregion memory pointers now */
- iounmap(opregion->header);
- opregion->header = NULL;
- opregion->acpi = NULL;
- opregion->swsci = NULL;
- opregion->asle = NULL;
- opregion->vbt = NULL;
-}
-#endif
-
-int intel_opregion_setup(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_opregion *opregion = &dev_priv->opregion;
- void *base;
- u32 asls, mboxes;
- int err = 0;
-
- pci_read_config_dword(dev->pdev, PCI_ASLS, &asls);
- DRM_DEBUG_DRIVER("graphic opregion physical addr: 0x%x\n", asls);
- if (asls == 0) {
- DRM_DEBUG_DRIVER("ACPI OpRegion not supported!\n");
- return -ENOTSUPP;
- }
-
- base = acpi_os_ioremap(asls, OPREGION_SIZE);
- if (!base)
- return -ENOMEM;
-
- if (memcmp(base, OPREGION_SIGNATURE, 16)) {
- DRM_DEBUG_DRIVER("opregion signature mismatch\n");
- err = -EINVAL;
- goto err_out;
- }
- opregion->header = base;
- opregion->vbt = base + OPREGION_VBT_OFFSET;
-
- opregion->lid_state = base + ACPI_CLID;
-
- mboxes = opregion->header->mboxes;
- if (mboxes & MBOX_ACPI) {
- DRM_DEBUG_DRIVER("Public ACPI methods supported\n");
- opregion->acpi = base + OPREGION_ACPI_OFFSET;
- }
-
- if (mboxes & MBOX_SWSCI) {
- DRM_DEBUG_DRIVER("SWSCI supported\n");
- opregion->swsci = base + OPREGION_SWSCI_OFFSET;
- }
- if (mboxes & MBOX_ASLE) {
- DRM_DEBUG_DRIVER("ASLE supported\n");
- opregion->asle = base + OPREGION_ASLE_OFFSET;
- }
-
- return 0;
-
-err_out:
- iounmap(base);
- return err;
-}
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
index a06ff07..f893ff0 100644
--- a/drivers/gpu/drm/i915/intel_panel.c
+++ b/drivers/gpu/drm/i915/intel_panel.c
@@ -297,8 +297,8 @@ intel_panel_detect(struct drm_device *dev)
* appears to be either the BIOS or Linux ACPI fault */
#if 0
/* Assume that the BIOS does not lie through the OpRegion... */
- if (dev_priv->opregion.lid_state)
- return ioread32(dev_priv->opregion.lid_state) & 0x1 ?
+ if (dev_priv->opregion_dev.opregion.acpi)
+ return ioread32(&dev_priv->opregion_dev.opregion.acpi->clid) & 0x1 ?
connector_status_connected :
connector_status_disconnected;
#endif
diff --git a/include/acpi/acpi_igd_opregion.h b/include/acpi/acpi_igd_opregion.h
new file mode 100644
index 0000000..36fefd2
--- /dev/null
+++ b/include/acpi/acpi_igd_opregion.h
@@ -0,0 +1,105 @@
+#ifndef __ACPI_IGD_OPREGION_H__
+#define __ACPI_IGD_OPREGION_H__
+
+#include <drm/drmP.h>
+
+#define OPREGION_SIZE (8*1024)
+
+struct opregion_header {
+ u8 signature[16];
+ u32 size;
+ u32 opregion_ver;
+ u8 bios_ver[32];
+ u8 vbios_ver[16];
+ u8 driver_ver[16];
+ u32 mboxes;
+ u8 reserved[164];
+} __packed;
+
+/* OpRegion mailbox #1: public ACPI methods */
+struct opregion_acpi {
+ u32 drdy; /* driver readiness */
+ u32 csts; /* notification status */
+ u32 cevt; /* current event */
+ u8 rsvd1[20];
+ u32 didl[8]; /* supported display devices ID list */
+ u32 cpdl[8]; /* currently presented display list */
+ u32 cadl[8]; /* currently active display list */
+ u32 nadl[8]; /* next active devices list */
+ u32 aslp; /* ASL sleep time-out */
+ u32 tidx; /* toggle table index */
+ u32 chpd; /* current hotplug enable indicator */
+ u32 clid; /* current lid state*/
+ u32 cdck; /* current docking state */
+ u32 sxsw; /* Sx state resume */
+ u32 evts; /* ASL supported events */
+ u32 cnot; /* current OS notification */
+ u32 nrdy; /* driver status */
+ u8 rsvd2[60];
+} __packed;
+
+/* OpRegion mailbox #2: SWSCI */
+struct opregion_swsci {
+ u32 scic; /* SWSCI command|status|data */
+ u32 parm; /* command parameters */
+ u32 dslp; /* driver sleep time-out */
+ u8 rsvd[244];
+} __packed;
+
+/* OpRegion mailbox #3: ASLE */
+struct opregion_asle {
+ u32 ardy; /* driver readiness */
+ u32 aslc; /* ASLE interrupt command */
+ u32 tche; /* technology enabled indicator */
+ u32 alsi; /* current ALS illuminance reading */
+ u32 bclp; /* backlight brightness to set */
+ u32 pfit; /* panel fitting state */
+ u32 cblv; /* current brightness level */
+ u16 bclm[20]; /* backlight level duty cycle mapping table */
+ u32 cpfm; /* current panel fitting mode */
+ u32 epfm; /* enabled panel fitting modes */
+ u8 plut[74]; /* panel LUT and identifier */
+ u32 pfmb; /* PWM freq and min brightness */
+ u8 rsvd[102];
+} __packed;
+
+struct igd_opregion {
+ struct opregion_header *header;
+ struct opregion_acpi *acpi;
+ struct opregion_swsci *swsci;
+ struct opregion_asle *asle;
+ void *vbt;
+};
+
+struct opregion_dev {
+ struct drm_device *drm_dev;
+ u32 max_backlight;
+ void (*set_backlight)(struct drm_device *dev, u32 value);
+ void (*set_als_illum)(struct drm_device *dev, u32 alsi);
+ void (*set_pwm_freq)(struct drm_device *dev, u32 pfmb);
+ void (*set_pfit)(struct drm_device *dev, u32 pfit);
+ void (*enable_asle)(struct drm_device *drm_dev);
+ struct igd_opregion opregion;
+};
+
+#if (defined CONFIG_ACPI_IGD_OPREGION || defined CONFIG_ACPI_IGD_OPREGION_MODULE)
+
+int igd_opregion_setup(struct opregion_dev *dev);
+void igd_opregion_init(struct opregion_dev *dev);
+void igd_opregion_fini(struct opregion_dev *dev);
+void igd_opregion_intr(struct opregion_dev *dev);
+void igd_opregion_enable_asle(struct opregion_dev *dev);
+
+#else
+
+static inline int igd_opregion_setup(struct opregion_dev *dev)
+{
+ return 0;
+}
+
+static inline void igd_opregion_init(struct opregion_dev *dev) {};
+static inline void igd_opregion_fini(struct opregion_dev *dev) {};
+static inline void igd_opregion_intr(struct opregion_dev *dev) {};
+static inline void igd_opregion_enable_asle(struct opregion_dev *dev) {};
+#endif
+#endif
--
1.7.5

[-- Attachment #3: 0002-i915-Add-GPU-backlight-interface.patch --]
[-- Type: text/x-patch, Size: 7211 bytes --]

>From d957b0a6ca265797cce4296dfc3cfda625dfd96f Mon Sep 17 00:00:00 2001
From: Matthew Garrett <mjg@redhat.com>
Date: Wed, 18 May 2011 17:15:48 -0400
Subject: [PATCH 2/2] i915: Add GPU backlight interface

Not all systems provide a firmware or platform interface to backlight
control. We should expose a gpu-level backlight interface to handle that
case.

Signed-off-by: Matthew Garrett <mjg@redhat.com>
---
drivers/gpu/drm/i915/i915_drv.h | 2 +
drivers/gpu/drm/i915/intel_display.c | 2 -
drivers/gpu/drm/i915/intel_dp.c | 6 +++
drivers/gpu/drm/i915/intel_drv.h | 3 +-
drivers/gpu/drm/i915/intel_lvds.c | 6 +++
drivers/gpu/drm/i915/intel_panel.c | 78 ++++++++++++++++++++++++++++++----
6 files changed, 86 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 9b2b94a..68e8869 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -33,6 +33,7 @@
#include "i915_reg.h"
#include "intel_bios.h"
#include "intel_ringbuffer.h"
+#include <linux/backlight.h>
#include <linux/io-mapping.h>
#include <linux/i2c.h>
#include <drm/intel-gtt.h>
@@ -667,6 +668,7 @@ typedef struct drm_i915_private {
int child_dev_num;
struct child_device_config *child_dev;
struct drm_connector *int_lvds_connector;
+ struct backlight_device *backlight;

bool mchbar_need_disable;

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 03726a5..7ffb851 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -6752,8 +6752,6 @@ static void intel_setup_outputs(struct drm_device *dev)
intel_encoder_clones(dev, encoder->clone_mask);
}

- intel_panel_setup_backlight(dev);
-
/* disable all the possible outputs/crtcs before entering KMS mode */
drm_helper_disable_unused_functions(dev);
}
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index a4d8031..c262378 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -1747,6 +1747,11 @@ done:
static void
intel_dp_destroy (struct drm_connector *connector)
{
+ struct intel_dp *intel_dp = intel_attached_dp(connector);
+
+ if (is_edp(intel_dp))
+ intel_panel_destroy_backlight(connector);
+
drm_sysfs_connector_remove(connector);
drm_connector_cleanup(connector);
kfree(connector);
@@ -1989,6 +1994,7 @@ intel_dp_init(struct drm_device *dev, int output_reg)
DRM_MODE_TYPE_PREFERRED;
}
}
+ intel_panel_setup_backlight(connector);
}

intel_dp_add_properties(intel_dp, connector);
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 831d7a4..c2b5c11 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -265,7 +265,8 @@ extern void intel_pch_panel_fitting(struct drm_device *dev,
extern u32 intel_panel_get_max_backlight(struct drm_device *dev);
extern u32 intel_panel_get_backlight(struct drm_device *dev);
extern void intel_panel_set_backlight(struct drm_device *dev, u32 level);
-extern void intel_panel_setup_backlight(struct drm_device *dev);
+extern int intel_panel_setup_backlight(struct drm_connector *dev);
+extern void intel_panel_destroy_backlight(struct drm_connector *dev);
extern void intel_panel_enable_backlight(struct drm_device *dev);
extern void intel_panel_disable_backlight(struct drm_device *dev);
extern enum drm_connector_status intel_panel_detect(struct drm_device *dev);
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index 3b90e68..38047b6 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -584,6 +584,9 @@ static void intel_lvds_destroy(struct drm_connector *connector)

if (dev_priv->lid_notifier.notifier_call)
acpi_lid_notifier_unregister(&dev_priv->lid_notifier);
+
+ intel_panel_destroy_backlight(connector);
+
drm_sysfs_connector_remove(connector);
drm_connector_cleanup(connector);
kfree(connector);
@@ -1033,6 +1036,9 @@ out:
/* keep the LVDS connector */
dev_priv->int_lvds_connector = connector;
drm_sysfs_connector_add(connector);
+
+ intel_panel_setup_backlight(connector);
+
return true;

failed:
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
index f893ff0..1be17b5 100644
--- a/drivers/gpu/drm/i915/intel_panel.c
+++ b/drivers/gpu/drm/i915/intel_panel.c
@@ -250,6 +250,76 @@ void intel_panel_set_backlight(struct drm_device *dev, u32 level)
I915_WRITE(BLC_PWM_CTL, tmp | level);
}

+#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
+static int intel_panel_update_brightness(struct backlight_device *bd)
+{
+ struct drm_device *dev = bl_get_data(bd);
+
+ intel_panel_set_backlight(dev, bd->props.brightness);
+ return 0;
+}
+
+static int intel_panel_get_brightness(struct backlight_device *bd)
+{
+ struct drm_device *dev = bl_get_data(bd);
+
+ return intel_panel_get_backlight(dev);
+}
+
+static const struct backlight_ops intel_panel_bl_ops = {
+ .update_status = intel_panel_update_brightness,
+ .get_brightness = intel_panel_get_brightness,
+};
+
+int intel_panel_setup_backlight(struct drm_connector *connector)
+{
+ struct drm_device *dev = connector->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct backlight_properties props;
+
+ dev_priv->backlight_level = intel_panel_get_backlight(dev);
+ dev_priv->backlight_enabled = dev_priv->backlight_level != 0;
+
+ props.max_brightness = intel_panel_get_max_backlight(dev);
+ props.type = BACKLIGHT_RAW;
+ dev_priv->backlight = backlight_device_register("intel_backlight",
+ &connector->kdev, dev, &intel_panel_bl_ops, &props);
+
+ if (IS_ERR(dev_priv->backlight)) {
+ DRM_ERROR("Failed to register backlight: %ld\n",
+ PTR_ERR(dev_priv->backlight));
+ dev_priv->backlight = NULL;
+ return -ENODEV;
+ }
+
+ dev_priv->backlight->props.brightness = intel_panel_get_backlight(dev);
+ return 0;
+}
+
+void intel_panel_destroy_backlight(struct drm_connector *connector)
+{
+ struct drm_device *dev = connector->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (dev_priv->backlight)
+ backlight_device_unregister(dev_priv->backlight);
+}
+#else
+int intel_panel_setup_backlight(struct drm_connector *connector)
+{
+ struct drm_device *dev = connector->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ dev_priv->backlight_level = intel_panel_get_backlight(dev);
+ dev_priv->backlight_enabled = dev_priv->backlight_level != 0;
+}
+
+void intel_panel_destroy_backlight(struct drm_connector *connector)
+{
+ return;
+}
+#endif
+
void intel_panel_disable_backlight(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -273,14 +343,6 @@ void intel_panel_enable_backlight(struct drm_device *dev)
dev_priv->backlight_enabled = true;
}

-void intel_panel_setup_backlight(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- dev_priv->backlight_level = intel_panel_get_backlight(dev);
- dev_priv->backlight_enabled = dev_priv->backlight_level != 0;
-}
-
enum drm_connector_status
intel_panel_detect(struct drm_device *dev)
{
--
1.7.5