Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 01c66889 authored by Zhao Yakui's avatar Zhao Yakui Committed by Eric Anholt
Browse files

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: default avatarZhao Yakui <yakui.zhao@intel.com>
Tested-by: default avatarZhao Yakui <yakui.zhao@intel.com>
[zhenyuw: cleanups, fix typo for checking GSE irq and convert to
current irq handling logic.]
Signed-off-by: default avatarZhenyu Wang <zhenyuw@linux.intel.com>
Signed-off-by: default avatarEric Anholt <eric@anholt.net>
parent 1dc7546d
Loading
Loading
Loading
Loading
+2 −5
Original line number Diff line number Diff line
@@ -1492,8 +1492,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
	}

	/* Must be done after probing outputs */
	/* FIXME: verify on IGDNG */
	if (!IS_IGDNG(dev))
	intel_opregion_init(dev, 0);

	setup_timer(&dev_priv->hangcheck_timer, i915_hangcheck_elapsed,
@@ -1538,7 +1536,6 @@ int i915_driver_unload(struct drm_device *dev)
	if (dev_priv->regs != NULL)
		iounmap(dev_priv->regs);

	if (!IS_IGDNG(dev))
	intel_opregion_free(dev, 0);

	if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+4 −0
Original line number Diff line number Diff line
@@ -733,6 +733,8 @@ i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask);
void
i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask);

void intel_enable_asle (struct drm_device *dev);


/* i915_mem.c */
extern int i915_mem_alloc(struct drm_device *dev, void *data,
@@ -861,11 +863,13 @@ extern int i915_restore_state(struct drm_device *dev);
extern int intel_opregion_init(struct drm_device *dev, int resume);
extern void intel_opregion_free(struct drm_device *dev, int suspend);
extern void opregion_asle_intr(struct drm_device *dev);
extern void ironlake_opregion_gse_intr(struct drm_device *dev);
extern void opregion_enable_asle(struct drm_device *dev);
#else
static inline int intel_opregion_init(struct drm_device *dev, int resume) { return 0; }
static inline void intel_opregion_free(struct drm_device *dev, int suspend) { return; }
static inline void opregion_asle_intr(struct drm_device *dev) { return; }
static inline void ironlake_opregion_gse_intr(struct drm_device *dev) { return; }
static inline void opregion_enable_asle(struct drm_device *dev) { return; }
#endif

+18 −1
Original line number Diff line number Diff line
@@ -156,6 +156,20 @@ i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask)
	}
}

/**
 * intel_enable_asle - enable ASLE interrupt for OpRegion
 */
void intel_enable_asle (struct drm_device *dev)
{
	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;

	if (IS_IGDNG(dev))
		igdng_enable_display_irq(dev_priv, DE_GSE);
	else
		i915_enable_pipestat(dev_priv, 1,
				     I915_LEGACY_BLC_EVENT_ENABLE);
}

/**
 * i915_pipe_enabled - check if a pipe is enabled
 * @dev: DRM device
@@ -288,6 +302,9 @@ irqreturn_t igdng_irq_handler(struct drm_device *dev)
			DRM_WAKEUP(&dev_priv->irq_queue);
		}

		if (de_iir & DE_GSE)
			ironlake_opregion_gse_intr(dev);

		de_iir = new_de_iir;
		gt_iir = new_gt_iir;
	}
@@ -992,7 +1009,7 @@ static int igdng_irq_postinstall(struct drm_device *dev)
{
	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
	/* enable kind of interrupts always enabled */
	u32 display_mask = DE_MASTER_IRQ_CONTROL /*| DE_PCH_EVENT */;
	u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE /*| DE_PCH_EVENT */;
	u32 render_mask = GT_USER_INTERRUPT;

	dev_priv->irq_mask_reg = ~display_mask;
+72 −2
Original line number Diff line number Diff line
@@ -118,6 +118,10 @@ struct opregion_asle {
#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 @@ void opregion_asle_intr(struct drm_device *dev)
	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 @@ void opregion_enable_asle(struct drm_device *dev)
			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);
		}