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

Commit 8ee1c3db authored by Matthew Garrett's avatar Matthew Garrett Committed by Dave Airlie
Browse files

Add Intel ACPI IGD OpRegion support



This adds the support necessary for allowing ACPI backlight control to
work on some newer Intel-based graphics systems. Tested on Thinkpad T61
and HP 2510p hardware.

Signed-off-by: default avatarMatthew Garrett <mjg@redhat.com>
Signed-off-by: default avatarDave Airlie <airlied@linux.ie>
parent 398c9cb2
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -3,7 +3,7 @@
# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.

ccflags-y := -Iinclude/drm
i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o
i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o i915_opregion.o

i915-$(CONFIG_COMPAT)   += i915_ioc32.o

+4 −0
Original line number Diff line number Diff line
@@ -810,6 +810,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
	if (!IS_I945G(dev) && !IS_I945GM(dev))
		pci_enable_msi(dev->pdev);

	intel_opregion_init(dev);

	spin_lock_init(&dev_priv->user_irq_lock);

	return ret;
@@ -827,6 +829,8 @@ int i915_driver_unload(struct drm_device *dev)
	if (dev_priv->mmio_map)
		drm_rmmap(dev, dev_priv->mmio_map);

	intel_opregion_free(dev);

	drm_free(dev->dev_private, sizeof(drm_i915_private_t),
		 DRM_MEM_DRIVER);

+4 −0
Original line number Diff line number Diff line
@@ -371,6 +371,8 @@ static int i915_suspend(struct drm_device *dev, pm_message_t state)

	i915_save_vga(dev);

	intel_opregion_free(dev);

	if (state.event == PM_EVENT_SUSPEND) {
		/* Shut down the device */
		pci_disable_device(dev->pdev);
@@ -532,6 +534,8 @@ static int i915_resume(struct drm_device *dev)

	i915_restore_vga(dev);

	intel_opregion_init(dev);

	return 0;
}

+17 −0
Original line number Diff line number Diff line
@@ -82,6 +82,14 @@ typedef struct _drm_i915_vbl_swap {
	unsigned int sequence;
} drm_i915_vbl_swap_t;

struct intel_opregion {
	struct opregion_header *header;
	struct opregion_acpi *acpi;
	struct opregion_swsci *swsci;
	struct opregion_asle *asle;
	int enabled;
};

typedef struct drm_i915_private {
	drm_local_map_t *sarea;
	drm_local_map_t *mmio_map;
@@ -122,6 +130,8 @@ typedef struct drm_i915_private {
	drm_i915_vbl_swap_t vbl_swaps;
	unsigned int swaps_pending;

	struct intel_opregion opregion;

	/* Register state */
	u8 saveLBB;
	u32 saveDSPACNTR;
@@ -244,6 +254,7 @@ extern int i915_vblank_pipe_get(struct drm_device *dev, void *data,
				struct drm_file *file_priv);
extern int i915_vblank_swap(struct drm_device *dev, void *data,
			    struct drm_file *file_priv);
extern void i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask);

/* i915_mem.c */
extern int i915_mem_alloc(struct drm_device *dev, void *data,
@@ -258,6 +269,12 @@ extern void i915_mem_takedown(struct mem_block **heap);
extern void i915_mem_release(struct drm_device * dev,
			     struct drm_file *file_priv, struct mem_block *heap);

/* i915_opregion.c */
extern int intel_opregion_init(struct drm_device *dev);
extern void intel_opregion_free(struct drm_device *dev);
extern void opregion_asle_intr(struct drm_device *dev);
extern void opregion_enable_asle(struct drm_device *dev);

#define I915_READ(reg)          DRM_READ32(dev_priv->mmio_map, (reg))
#define I915_WRITE(reg,val)     DRM_WRITE32(dev_priv->mmio_map, (reg), (val))
#define I915_READ16(reg)	DRM_READ16(dev_priv->mmio_map, (reg))
+17 −8
Original line number Diff line number Diff line
@@ -36,9 +36,11 @@
/** These are the interrupts used by the driver */
#define I915_INTERRUPT_ENABLE_MASK (I915_USER_INTERRUPT |		\
				    I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT | \
				    I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT)
				    I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT | \
				    I915_ASLE_INTERRUPT |		\
				    I915_DISPLAY_PIPE_B_EVENT_INTERRUPT)

static inline void
void
i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask)
{
	if ((dev_priv->irq_mask_reg & mask) != 0) {
@@ -274,6 +276,9 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
		return IRQ_NONE;
	}

	I915_WRITE(PIPEASTAT, pipea_stats);
	I915_WRITE(PIPEBSTAT, pipeb_stats);

	I915_WRITE(IIR, iir);
	if (dev->pdev->msi_enabled)
		I915_WRITE(IMR, dev_priv->irq_mask_reg);
@@ -306,14 +311,14 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)

		if (dev_priv->swaps_pending > 0)
			drm_locked_tasklet(dev, i915_vblank_tasklet);
		I915_WRITE(PIPEASTAT,
			pipea_stats|I915_VBLANK_INTERRUPT_ENABLE|
			PIPE_VBLANK_INTERRUPT_STATUS);
		I915_WRITE(PIPEBSTAT,
			pipeb_stats|I915_VBLANK_INTERRUPT_ENABLE|
			PIPE_VBLANK_INTERRUPT_STATUS);
	}

	if (iir & I915_ASLE_INTERRUPT)
		opregion_asle_intr(dev);

	if (iir & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT)
		opregion_asle_intr(dev);

	return IRQ_HANDLED;
}

@@ -661,10 +666,14 @@ void i915_driver_irq_postinstall(struct drm_device * dev)
	if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B)
		dev_priv->irq_mask_reg &= ~I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;

	dev_priv->irq_mask_reg &= I915_INTERRUPT_ENABLE_MASK;

	I915_WRITE(IMR, dev_priv->irq_mask_reg);
	I915_WRITE(IER, I915_INTERRUPT_ENABLE_MASK);
	(void) I915_READ(IER);

	opregion_enable_asle(dev);

	DRM_INIT_WAITQUEUE(&dev_priv->irq_queue);
}

Loading