From 0da3ea12fc2607beb67c2d54d0347807ea615573 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 20 Feb 2008 09:39:58 +1000 Subject: drm/i915: save/restore interrupt state On resume, if the interrupt state isn't restored correctly, we may end up with a flood of unexpected or ill-timed interrupts, which could cause the kernel to disable the interrupt or vblank events to happen at the wrong time. So save/restore them properly. Signed-off-by: Dave Airlie --- drivers/char/drm/i915_drv.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/char/drm/i915_drv.c') diff --git a/drivers/char/drm/i915_drv.c b/drivers/char/drm/i915_drv.c index 52e51033d32..0f525ad536a 100644 --- a/drivers/char/drm/i915_drv.c +++ b/drivers/char/drm/i915_drv.c @@ -276,6 +276,7 @@ static int i915_suspend(struct drm_device *dev) dev_priv->saveDSPATILEOFF = I915_READ(DSPATILEOFF); } i915_save_palette(dev, PIPE_A); + dev_priv->savePIPEASTAT = I915_READ(I915REG_PIPEASTAT); /* Pipe & plane B info */ dev_priv->savePIPEBCONF = I915_READ(PIPEBCONF); @@ -303,6 +304,7 @@ static int i915_suspend(struct drm_device *dev) dev_priv->saveDSPBTILEOFF = I915_READ(DSPBTILEOFF); } i915_save_palette(dev, PIPE_B); + dev_priv->savePIPEBSTAT = I915_READ(I915REG_PIPEBSTAT); /* CRT state */ dev_priv->saveADPA = I915_READ(ADPA); @@ -329,6 +331,11 @@ static int i915_suspend(struct drm_device *dev) dev_priv->saveFBC_CONTROL2 = I915_READ(FBC_CONTROL2); dev_priv->saveFBC_CONTROL = I915_READ(FBC_CONTROL); + /* Interrupt state */ + dev_priv->saveIIR = I915_READ(I915REG_INT_IDENTITY_R); + dev_priv->saveIER = I915_READ(I915REG_INT_ENABLE_R); + dev_priv->saveIMR = I915_READ(I915REG_INT_MASK_R); + /* VGA state */ dev_priv->saveVCLK_DIVISOR_VGA0 = I915_READ(VCLK_DIVISOR_VGA0); dev_priv->saveVCLK_DIVISOR_VGA1 = I915_READ(VCLK_DIVISOR_VGA1); -- cgit v1.2.3-70-g09d2 From c0c4261b6fd80f0fc5546ed67058592469a4f5b7 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 7 Feb 2008 17:33:28 -0800 Subject: drm/i915: restore pipeconf regs unconditionally On many chipsets, the checks for DPLL enable or VGA mode will prevent the pipeconf regs from being restored, which could result in a blank display or X failing to come back after resume. So restore them unconditionally along with actually restoring pipe B's palette correctly. Signed-off-by: Dave Airlie --- drivers/char/drm/i915_drv.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'drivers/char/drm/i915_drv.c') diff --git a/drivers/char/drm/i915_drv.c b/drivers/char/drm/i915_drv.c index 0f525ad536a..248e7b1c46a 100644 --- a/drivers/char/drm/i915_drv.c +++ b/drivers/char/drm/i915_drv.c @@ -407,9 +407,7 @@ static int i915_resume(struct drm_device *dev) I915_WRITE(DSPATILEOFF, dev_priv->saveDSPATILEOFF); } - if ((dev_priv->saveDPLL_A & DPLL_VCO_ENABLE) && - (dev_priv->saveDPLL_A & DPLL_VGA_MODE_DIS)) - I915_WRITE(PIPEACONF, dev_priv->savePIPEACONF); + I915_WRITE(PIPEACONF, dev_priv->savePIPEACONF); i915_restore_palette(dev, PIPE_A); /* Enable the plane */ @@ -451,10 +449,9 @@ static int i915_resume(struct drm_device *dev) I915_WRITE(DSPBTILEOFF, dev_priv->saveDSPBTILEOFF); } - if ((dev_priv->saveDPLL_B & DPLL_VCO_ENABLE) && - (dev_priv->saveDPLL_B & DPLL_VGA_MODE_DIS)) - I915_WRITE(PIPEBCONF, dev_priv->savePIPEBCONF); - i915_restore_palette(dev, PIPE_A); + I915_WRITE(PIPEBCONF, dev_priv->savePIPEBCONF); + + i915_restore_palette(dev, PIPE_B); /* Enable the plane */ I915_WRITE(DSPBCNTR, dev_priv->saveDSPBCNTR); I915_WRITE(DSPBBASE, I915_READ(DSPBBASE)); -- cgit v1.2.3-70-g09d2 From 1f84e550a870bf5f5f399b611db68f3324ea7883 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 16 Feb 2008 19:19:29 -0800 Subject: drm/i915 more registers for S3 (DSPCLK_GATE_D, CACHE_MODE_0, MI_ARB_STATE) Failing to preserve the MI_ARB_STATE register was causing FIFO underruns on the VGA output on my HP 2510p after resume. Signed-off-by: Dave Airlie --- drivers/char/drm/i915_drv.c | 18 ++++++++++++++++++ drivers/char/drm/i915_drv.h | 10 ++++++++++ 2 files changed, 28 insertions(+) (limited to 'drivers/char/drm/i915_drv.c') diff --git a/drivers/char/drm/i915_drv.c b/drivers/char/drm/i915_drv.c index 248e7b1c46a..5025f5b0241 100644 --- a/drivers/char/drm/i915_drv.c +++ b/drivers/char/drm/i915_drv.c @@ -342,6 +342,15 @@ static int i915_suspend(struct drm_device *dev) dev_priv->saveVCLK_POST_DIV = I915_READ(VCLK_POST_DIV); dev_priv->saveVGACNTRL = I915_READ(VGACNTRL); + /* Clock gating state */ + dev_priv->saveDSPCLK_GATE_D = I915_READ(DSPCLK_GATE_D); + + /* Cache mode state */ + dev_priv->saveCACHE_MODE_0 = I915_READ(CACHE_MODE_0); + + /* Memory Arbitration state */ + dev_priv->saveMI_ARB_STATE = I915_READ(MI_ARB_STATE); + /* Scratch space */ for (i = 0; i < 16; i++) { dev_priv->saveSWF0[i] = I915_READ(SWF0 + (i << 2)); @@ -489,6 +498,15 @@ static int i915_resume(struct drm_device *dev) I915_WRITE(VCLK_POST_DIV, dev_priv->saveVCLK_POST_DIV); udelay(150); + /* Clock gating state */ + I915_WRITE (DSPCLK_GATE_D, dev_priv->saveDSPCLK_GATE_D); + + /* Cache mode state */ + I915_WRITE (CACHE_MODE_0, dev_priv->saveCACHE_MODE_0 | 0xffff0000); + + /* Memory arbitration state */ + I915_WRITE (MI_ARB_STATE, dev_priv->saveMI_ARB_STATE | 0xffff0000); + for (i = 0; i < 16; i++) { I915_WRITE(SWF0 + (i << 2), dev_priv->saveSWF0[i]); I915_WRITE(SWF10 + (i << 2), dev_priv->saveSWF1[i+7]); diff --git a/drivers/char/drm/i915_drv.h b/drivers/char/drm/i915_drv.h index 360f6600427..c10d128e34d 100644 --- a/drivers/char/drm/i915_drv.h +++ b/drivers/char/drm/i915_drv.h @@ -187,6 +187,9 @@ typedef struct drm_i915_private { u32 saveIER; u32 saveIIR; u32 saveIMR; + u32 saveCACHE_MODE_0; + u32 saveDSPCLK_GATE_D; + u32 saveMI_ARB_STATE; u32 saveSWF0[16]; u32 saveSWF1[16]; u32 saveSWF2[3]; @@ -455,6 +458,10 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); */ #define DMA_FADD_S 0x20d4 +/* Memory Interface Arbitration State + */ +#define MI_ARB_STATE 0x20e4 + /* Cache mode 0 reg. * - Manipulating render cache behaviour is central * to the concept of zone rendering, tuning this reg can help avoid @@ -465,6 +472,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); * bit of interest either set or cleared. EG: (BIT<<16) | BIT to set. */ #define Cache_Mode_0 0x2120 +#define CACHE_MODE_0 0x2120 #define CM0_MASK_SHIFT 16 #define CM0_IZ_OPT_DISABLE (1<<6) #define CM0_ZR_OPT_DISABLE (1<<5) @@ -660,6 +668,8 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); /** P1 value is 2 greater than this field */ # define VGA0_PD_P1_MASK (0x1f << 0) +#define DSPCLK_GATE_D 0x6200 + /* I830 CRTC registers */ #define HTOTAL_A 0x60000 #define HBLANK_A 0x60004 -- cgit v1.2.3-70-g09d2 From da636ad6a0d72eb5cb99738056af0bcc3db9ef9d Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Mon, 28 Jan 2008 21:05:22 -0800 Subject: drm/i915: Fix hibernate save/restore of VGA attribute regs In hibernate, we may end up calling the VGA save regs function twice, so we need to make sure it's idempotent. That means leaving ARX in index mode after the first save operation. Fixes hibernate on 965. Signed-off-by: Dave Airlie --- drivers/char/drm/i915_drv.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/char/drm/i915_drv.c') diff --git a/drivers/char/drm/i915_drv.c b/drivers/char/drm/i915_drv.c index 5025f5b0241..35758a6c8b0 100644 --- a/drivers/char/drm/i915_drv.c +++ b/drivers/char/drm/i915_drv.c @@ -160,6 +160,7 @@ static void i915_save_vga(struct drm_device *dev) dev_priv->saveAR[i] = i915_read_ar(st01, i, 0); inb(st01); outb(dev_priv->saveAR_INDEX, VGA_AR_INDEX); + inb(st01); /* Graphics controller registers */ for (i = 0; i < 9; i++) @@ -225,6 +226,7 @@ static void i915_restore_vga(struct drm_device *dev) i915_write_ar(st01, i, dev_priv->saveAR[i], 0); inb(st01); /* switch back to index mode */ outb(dev_priv->saveAR_INDEX | 0x20, VGA_AR_INDEX); + inb(st01); /* VGA color palette registers */ outb(dev_priv->saveDACMASK, VGA_DACMASK); -- cgit v1.2.3-70-g09d2 From b932ccb5674eb649133b5c33950405c37d17aab3 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 20 Feb 2008 10:02:20 +1000 Subject: drm: add support for passing state into the suspend hooks. fix i915 driver to use state for hibernate save avoidance. Signed-off-by: Dave Airlie --- drivers/char/drm/drmP.h | 2 +- drivers/char/drm/drm_sysfs.c | 2 +- drivers/char/drm/i915_drv.c | 13 +++++++++---- 3 files changed, 11 insertions(+), 6 deletions(-) (limited to 'drivers/char/drm/i915_drv.c') diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h index 19d3be5c4b2..a6789f25009 100644 --- a/drivers/char/drm/drmP.h +++ b/drivers/char/drm/drmP.h @@ -568,7 +568,7 @@ struct drm_driver { void (*postclose) (struct drm_device *, struct drm_file *); void (*lastclose) (struct drm_device *); int (*unload) (struct drm_device *); - int (*suspend) (struct drm_device *); + int (*suspend) (struct drm_device *, pm_message_t state); int (*resume) (struct drm_device *); int (*dma_ioctl) (struct drm_device *dev, void *data, struct drm_file *file_priv); void (*dma_ready) (struct drm_device *); diff --git a/drivers/char/drm/drm_sysfs.c b/drivers/char/drm/drm_sysfs.c index fa36153619e..05ed5043254 100644 --- a/drivers/char/drm/drm_sysfs.c +++ b/drivers/char/drm/drm_sysfs.c @@ -36,7 +36,7 @@ static int drm_sysfs_suspend(struct device *dev, pm_message_t state) printk(KERN_ERR "%s\n", __FUNCTION__); if (drm_dev->driver->suspend) - return drm_dev->driver->suspend(drm_dev); + return drm_dev->driver->suspend(drm_dev, state); return 0; } diff --git a/drivers/char/drm/i915_drv.c b/drivers/char/drm/i915_drv.c index 35758a6c8b0..4048f39b7ee 100644 --- a/drivers/char/drm/i915_drv.c +++ b/drivers/char/drm/i915_drv.c @@ -238,7 +238,7 @@ static void i915_restore_vga(struct drm_device *dev) } -static int i915_suspend(struct drm_device *dev) +static int i915_suspend(struct drm_device *dev, pm_message_t state) { struct drm_i915_private *dev_priv = dev->dev_private; int i; @@ -249,6 +249,9 @@ static int i915_suspend(struct drm_device *dev) return -ENODEV; } + if (state.event == PM_EVENT_PRETHAW) + return 0; + pci_save_state(dev->pdev); pci_read_config_byte(dev->pdev, LBB, &dev_priv->saveLBB); @@ -363,9 +366,11 @@ static int i915_suspend(struct drm_device *dev) i915_save_vga(dev); - /* Shut down the device */ - pci_disable_device(dev->pdev); - pci_set_power_state(dev->pdev, PCI_D3hot); + if (state.event == PM_EVENT_SUSPEND) { + /* Shut down the device */ + pci_disable_device(dev->pdev); + pci_set_power_state(dev->pdev, PCI_D3hot); + } return 0; } -- cgit v1.2.3-70-g09d2 From 39273b58a409cd6d65c9732bdca00bacd1626672 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 21 Feb 2008 17:44:35 -0800 Subject: i915: fix AR register restore. Make sure the restoration correctly restores the AR registers by flipping the ARX register into index mode before doing anything. Without this, some people have had the text mode restore all green. Signed-off-by: Jesse Barnes Signed-off-by: Linus Torvalds --- drivers/char/drm/i915_drv.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/char/drm/i915_drv.c') diff --git a/drivers/char/drm/i915_drv.c b/drivers/char/drm/i915_drv.c index 4048f39b7ee..b2b451dc446 100644 --- a/drivers/char/drm/i915_drv.c +++ b/drivers/char/drm/i915_drv.c @@ -222,6 +222,7 @@ static void i915_restore_vga(struct drm_device *dev) dev_priv->saveGR[0x18]); /* Attribute controller registers */ + inb(st01); for (i = 0; i < 20; i++) i915_write_ar(st01, i, dev_priv->saveAR[i], 0); inb(st01); /* switch back to index mode */ -- cgit v1.2.3-70-g09d2