drm/i915: Add ACPI OpRegion support for Ironlake

Add the support of ACPI opregion on Ironlake so that the backlight
brightness can be adjusted by using ACPI interface
   >/sys/class/backlight/acpi_video0/brightness

Signed-off-by: Zhao Yakui <yakui.zhao@intel.com>
Tested-by: Zhao Yakui <yakui.zhao@intel.com>
[zhenyuw: cleanups, fix typo for checking GSE irq and convert to
current irq handling logic.]
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
Signed-off-by: Eric Anholt <eric@anholt.net>
diff --git a/drivers/gpu/drm/i915/i915_opregion.c b/drivers/gpu/drm/i915/i915_opregion.c
index 9032bda..313a1a1 100644
--- a/drivers/gpu/drm/i915/i915_opregion.c
+++ b/drivers/gpu/drm/i915/i915_opregion.c
@@ -118,6 +118,10 @@
 #define ASLE_BACKLIGHT_FAIL    (2<<12)
 #define ASLE_PFIT_FAIL         (2<<14)
 #define ASLE_PWM_FREQ_FAIL     (2<<16)
+#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)
@@ -243,6 +247,73 @@
 	asle->aslc = asle_stat;
 }
 
+static u32 asle_set_backlight_ironlake(struct drm_device *dev, u32 bclp)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct opregion_asle *asle = dev_priv->opregion.asle;
+	u32 cpu_pwm_ctl, pch_pwm_ctl2;
+	u32 max_backlight, level;
+
+	if (!(bclp & ASLE_BCLP_VALID))
+		return ASLE_BACKLIGHT_FAILED;
+
+	bclp &= ASLE_BCLP_MSK;
+	if (bclp < 0 || bclp > 255)
+		return ASLE_BACKLIGHT_FAILED;
+
+	cpu_pwm_ctl = I915_READ(BLC_PWM_CPU_CTL);
+	pch_pwm_ctl2 = I915_READ(BLC_PWM_PCH_CTL2);
+	/* get the max PWM frequency */
+	max_backlight = (pch_pwm_ctl2 >> 16) & BACKLIGHT_DUTY_CYCLE_MASK;
+	/* calculate the expected PMW frequency */
+	level = (bclp * max_backlight) / 255;
+	/* reserve the high 16 bits */
+	cpu_pwm_ctl &= ~(BACKLIGHT_DUTY_CYCLE_MASK);
+	/* write the updated PWM frequency */
+	I915_WRITE(BLC_PWM_CPU_CTL, cpu_pwm_ctl | level);
+
+	asle->cblv = (bclp*0x64)/0xff | ASLE_CBLV_VALID;
+
+	return 0;
+}
+
+void ironlake_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_ironlake(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)
@@ -258,8 +329,7 @@
 			unsigned long irqflags;
 
 			spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
-			i915_enable_pipestat(dev_priv, 1,
-					     I915_LEGACY_BLC_EVENT_ENABLE);
+			intel_enable_asle(dev);
 			spin_unlock_irqrestore(&dev_priv->user_irq_lock,
 					       irqflags);
 		}