1317c35d1SJesse Barnes /* 2317c35d1SJesse Barnes * 3317c35d1SJesse Barnes * Copyright 2008 (c) Intel Corporation 4317c35d1SJesse Barnes * Jesse Barnes <jbarnes@virtuousgeek.org> 5317c35d1SJesse Barnes * 6317c35d1SJesse Barnes * Permission is hereby granted, free of charge, to any person obtaining a 7317c35d1SJesse Barnes * copy of this software and associated documentation files (the 8317c35d1SJesse Barnes * "Software"), to deal in the Software without restriction, including 9317c35d1SJesse Barnes * without limitation the rights to use, copy, modify, merge, publish, 10317c35d1SJesse Barnes * distribute, sub license, and/or sell copies of the Software, and to 11317c35d1SJesse Barnes * permit persons to whom the Software is furnished to do so, subject to 12317c35d1SJesse Barnes * the following conditions: 13317c35d1SJesse Barnes * 14317c35d1SJesse Barnes * The above copyright notice and this permission notice (including the 15317c35d1SJesse Barnes * next paragraph) shall be included in all copies or substantial portions 16317c35d1SJesse Barnes * of the Software. 17317c35d1SJesse Barnes * 18317c35d1SJesse Barnes * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19317c35d1SJesse Barnes * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20317c35d1SJesse Barnes * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21317c35d1SJesse Barnes * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR 22317c35d1SJesse Barnes * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23317c35d1SJesse Barnes * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24317c35d1SJesse Barnes * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25317c35d1SJesse Barnes */ 26317c35d1SJesse Barnes 27317c35d1SJesse Barnes #include "drmP.h" 28317c35d1SJesse Barnes #include "drm.h" 29317c35d1SJesse Barnes #include "i915_drm.h" 30317c35d1SJesse Barnes #include "i915_drv.h" 31317c35d1SJesse Barnes 32317c35d1SJesse Barnes static bool i915_pipe_enabled(struct drm_device *dev, enum pipe pipe) 33317c35d1SJesse Barnes { 34317c35d1SJesse Barnes struct drm_i915_private *dev_priv = dev->dev_private; 35317c35d1SJesse Barnes 36317c35d1SJesse Barnes if (pipe == PIPE_A) 37317c35d1SJesse Barnes return (I915_READ(DPLL_A) & DPLL_VCO_ENABLE); 38317c35d1SJesse Barnes else 39317c35d1SJesse Barnes return (I915_READ(DPLL_B) & DPLL_VCO_ENABLE); 40317c35d1SJesse Barnes } 41317c35d1SJesse Barnes 42317c35d1SJesse Barnes static void i915_save_palette(struct drm_device *dev, enum pipe pipe) 43317c35d1SJesse Barnes { 44317c35d1SJesse Barnes struct drm_i915_private *dev_priv = dev->dev_private; 45317c35d1SJesse Barnes unsigned long reg = (pipe == PIPE_A ? PALETTE_A : PALETTE_B); 46317c35d1SJesse Barnes u32 *array; 47317c35d1SJesse Barnes int i; 48317c35d1SJesse Barnes 49317c35d1SJesse Barnes if (!i915_pipe_enabled(dev, pipe)) 50317c35d1SJesse Barnes return; 51317c35d1SJesse Barnes 52317c35d1SJesse Barnes if (pipe == PIPE_A) 53317c35d1SJesse Barnes array = dev_priv->save_palette_a; 54317c35d1SJesse Barnes else 55317c35d1SJesse Barnes array = dev_priv->save_palette_b; 56317c35d1SJesse Barnes 57317c35d1SJesse Barnes for(i = 0; i < 256; i++) 58317c35d1SJesse Barnes array[i] = I915_READ(reg + (i << 2)); 59317c35d1SJesse Barnes } 60317c35d1SJesse Barnes 61317c35d1SJesse Barnes static void i915_restore_palette(struct drm_device *dev, enum pipe pipe) 62317c35d1SJesse Barnes { 63317c35d1SJesse Barnes struct drm_i915_private *dev_priv = dev->dev_private; 64317c35d1SJesse Barnes unsigned long reg = (pipe == PIPE_A ? PALETTE_A : PALETTE_B); 65317c35d1SJesse Barnes u32 *array; 66317c35d1SJesse Barnes int i; 67317c35d1SJesse Barnes 68317c35d1SJesse Barnes if (!i915_pipe_enabled(dev, pipe)) 69317c35d1SJesse Barnes return; 70317c35d1SJesse Barnes 71317c35d1SJesse Barnes if (pipe == PIPE_A) 72317c35d1SJesse Barnes array = dev_priv->save_palette_a; 73317c35d1SJesse Barnes else 74317c35d1SJesse Barnes array = dev_priv->save_palette_b; 75317c35d1SJesse Barnes 76317c35d1SJesse Barnes for(i = 0; i < 256; i++) 77317c35d1SJesse Barnes I915_WRITE(reg + (i << 2), array[i]); 78317c35d1SJesse Barnes } 79317c35d1SJesse Barnes 80317c35d1SJesse Barnes static u8 i915_read_indexed(struct drm_device *dev, u16 index_port, u16 data_port, u8 reg) 81317c35d1SJesse Barnes { 82317c35d1SJesse Barnes struct drm_i915_private *dev_priv = dev->dev_private; 83317c35d1SJesse Barnes 84317c35d1SJesse Barnes I915_WRITE8(index_port, reg); 85317c35d1SJesse Barnes return I915_READ8(data_port); 86317c35d1SJesse Barnes } 87317c35d1SJesse Barnes 88317c35d1SJesse Barnes static u8 i915_read_ar(struct drm_device *dev, u16 st01, u8 reg, u16 palette_enable) 89317c35d1SJesse Barnes { 90317c35d1SJesse Barnes struct drm_i915_private *dev_priv = dev->dev_private; 91317c35d1SJesse Barnes 92317c35d1SJesse Barnes I915_READ8(st01); 93317c35d1SJesse Barnes I915_WRITE8(VGA_AR_INDEX, palette_enable | reg); 94317c35d1SJesse Barnes return I915_READ8(VGA_AR_DATA_READ); 95317c35d1SJesse Barnes } 96317c35d1SJesse Barnes 97317c35d1SJesse Barnes static void i915_write_ar(struct drm_device *dev, u16 st01, u8 reg, u8 val, u16 palette_enable) 98317c35d1SJesse Barnes { 99317c35d1SJesse Barnes struct drm_i915_private *dev_priv = dev->dev_private; 100317c35d1SJesse Barnes 101317c35d1SJesse Barnes I915_READ8(st01); 102317c35d1SJesse Barnes I915_WRITE8(VGA_AR_INDEX, palette_enable | reg); 103317c35d1SJesse Barnes I915_WRITE8(VGA_AR_DATA_WRITE, val); 104317c35d1SJesse Barnes } 105317c35d1SJesse Barnes 106317c35d1SJesse Barnes static void i915_write_indexed(struct drm_device *dev, u16 index_port, u16 data_port, u8 reg, u8 val) 107317c35d1SJesse Barnes { 108317c35d1SJesse Barnes struct drm_i915_private *dev_priv = dev->dev_private; 109317c35d1SJesse Barnes 110317c35d1SJesse Barnes I915_WRITE8(index_port, reg); 111317c35d1SJesse Barnes I915_WRITE8(data_port, val); 112317c35d1SJesse Barnes } 113317c35d1SJesse Barnes 114317c35d1SJesse Barnes static void i915_save_vga(struct drm_device *dev) 115317c35d1SJesse Barnes { 116317c35d1SJesse Barnes struct drm_i915_private *dev_priv = dev->dev_private; 117317c35d1SJesse Barnes int i; 118317c35d1SJesse Barnes u16 cr_index, cr_data, st01; 119317c35d1SJesse Barnes 120317c35d1SJesse Barnes /* VGA color palette registers */ 121317c35d1SJesse Barnes dev_priv->saveDACMASK = I915_READ8(VGA_DACMASK); 122317c35d1SJesse Barnes 123317c35d1SJesse Barnes /* MSR bits */ 124317c35d1SJesse Barnes dev_priv->saveMSR = I915_READ8(VGA_MSR_READ); 125317c35d1SJesse Barnes if (dev_priv->saveMSR & VGA_MSR_CGA_MODE) { 126317c35d1SJesse Barnes cr_index = VGA_CR_INDEX_CGA; 127317c35d1SJesse Barnes cr_data = VGA_CR_DATA_CGA; 128317c35d1SJesse Barnes st01 = VGA_ST01_CGA; 129317c35d1SJesse Barnes } else { 130317c35d1SJesse Barnes cr_index = VGA_CR_INDEX_MDA; 131317c35d1SJesse Barnes cr_data = VGA_CR_DATA_MDA; 132317c35d1SJesse Barnes st01 = VGA_ST01_MDA; 133317c35d1SJesse Barnes } 134317c35d1SJesse Barnes 135317c35d1SJesse Barnes /* CRT controller regs */ 136317c35d1SJesse Barnes i915_write_indexed(dev, cr_index, cr_data, 0x11, 137317c35d1SJesse Barnes i915_read_indexed(dev, cr_index, cr_data, 0x11) & 138317c35d1SJesse Barnes (~0x80)); 139317c35d1SJesse Barnes for (i = 0; i <= 0x24; i++) 140317c35d1SJesse Barnes dev_priv->saveCR[i] = 141317c35d1SJesse Barnes i915_read_indexed(dev, cr_index, cr_data, i); 142317c35d1SJesse Barnes /* Make sure we don't turn off CR group 0 writes */ 143317c35d1SJesse Barnes dev_priv->saveCR[0x11] &= ~0x80; 144317c35d1SJesse Barnes 145317c35d1SJesse Barnes /* Attribute controller registers */ 146317c35d1SJesse Barnes I915_READ8(st01); 147317c35d1SJesse Barnes dev_priv->saveAR_INDEX = I915_READ8(VGA_AR_INDEX); 148317c35d1SJesse Barnes for (i = 0; i <= 0x14; i++) 149317c35d1SJesse Barnes dev_priv->saveAR[i] = i915_read_ar(dev, st01, i, 0); 150317c35d1SJesse Barnes I915_READ8(st01); 151317c35d1SJesse Barnes I915_WRITE8(VGA_AR_INDEX, dev_priv->saveAR_INDEX); 152317c35d1SJesse Barnes I915_READ8(st01); 153317c35d1SJesse Barnes 154317c35d1SJesse Barnes /* Graphics controller registers */ 155317c35d1SJesse Barnes for (i = 0; i < 9; i++) 156317c35d1SJesse Barnes dev_priv->saveGR[i] = 157317c35d1SJesse Barnes i915_read_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, i); 158317c35d1SJesse Barnes 159317c35d1SJesse Barnes dev_priv->saveGR[0x10] = 160317c35d1SJesse Barnes i915_read_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x10); 161317c35d1SJesse Barnes dev_priv->saveGR[0x11] = 162317c35d1SJesse Barnes i915_read_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x11); 163317c35d1SJesse Barnes dev_priv->saveGR[0x18] = 164317c35d1SJesse Barnes i915_read_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x18); 165317c35d1SJesse Barnes 166317c35d1SJesse Barnes /* Sequencer registers */ 167317c35d1SJesse Barnes for (i = 0; i < 8; i++) 168317c35d1SJesse Barnes dev_priv->saveSR[i] = 169317c35d1SJesse Barnes i915_read_indexed(dev, VGA_SR_INDEX, VGA_SR_DATA, i); 170317c35d1SJesse Barnes } 171317c35d1SJesse Barnes 172317c35d1SJesse Barnes static void i915_restore_vga(struct drm_device *dev) 173317c35d1SJesse Barnes { 174317c35d1SJesse Barnes struct drm_i915_private *dev_priv = dev->dev_private; 175317c35d1SJesse Barnes int i; 176317c35d1SJesse Barnes u16 cr_index, cr_data, st01; 177317c35d1SJesse Barnes 178317c35d1SJesse Barnes /* MSR bits */ 179317c35d1SJesse Barnes I915_WRITE8(VGA_MSR_WRITE, dev_priv->saveMSR); 180317c35d1SJesse Barnes if (dev_priv->saveMSR & VGA_MSR_CGA_MODE) { 181317c35d1SJesse Barnes cr_index = VGA_CR_INDEX_CGA; 182317c35d1SJesse Barnes cr_data = VGA_CR_DATA_CGA; 183317c35d1SJesse Barnes st01 = VGA_ST01_CGA; 184317c35d1SJesse Barnes } else { 185317c35d1SJesse Barnes cr_index = VGA_CR_INDEX_MDA; 186317c35d1SJesse Barnes cr_data = VGA_CR_DATA_MDA; 187317c35d1SJesse Barnes st01 = VGA_ST01_MDA; 188317c35d1SJesse Barnes } 189317c35d1SJesse Barnes 190317c35d1SJesse Barnes /* Sequencer registers, don't write SR07 */ 191317c35d1SJesse Barnes for (i = 0; i < 7; i++) 192317c35d1SJesse Barnes i915_write_indexed(dev, VGA_SR_INDEX, VGA_SR_DATA, i, 193317c35d1SJesse Barnes dev_priv->saveSR[i]); 194317c35d1SJesse Barnes 195317c35d1SJesse Barnes /* CRT controller regs */ 196317c35d1SJesse Barnes /* Enable CR group 0 writes */ 197317c35d1SJesse Barnes i915_write_indexed(dev, cr_index, cr_data, 0x11, dev_priv->saveCR[0x11]); 198317c35d1SJesse Barnes for (i = 0; i <= 0x24; i++) 199317c35d1SJesse Barnes i915_write_indexed(dev, cr_index, cr_data, i, dev_priv->saveCR[i]); 200317c35d1SJesse Barnes 201317c35d1SJesse Barnes /* Graphics controller regs */ 202317c35d1SJesse Barnes for (i = 0; i < 9; i++) 203317c35d1SJesse Barnes i915_write_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, i, 204317c35d1SJesse Barnes dev_priv->saveGR[i]); 205317c35d1SJesse Barnes 206317c35d1SJesse Barnes i915_write_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x10, 207317c35d1SJesse Barnes dev_priv->saveGR[0x10]); 208317c35d1SJesse Barnes i915_write_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x11, 209317c35d1SJesse Barnes dev_priv->saveGR[0x11]); 210317c35d1SJesse Barnes i915_write_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x18, 211317c35d1SJesse Barnes dev_priv->saveGR[0x18]); 212317c35d1SJesse Barnes 213317c35d1SJesse Barnes /* Attribute controller registers */ 214317c35d1SJesse Barnes I915_READ8(st01); /* switch back to index mode */ 215317c35d1SJesse Barnes for (i = 0; i <= 0x14; i++) 216317c35d1SJesse Barnes i915_write_ar(dev, st01, i, dev_priv->saveAR[i], 0); 217317c35d1SJesse Barnes I915_READ8(st01); /* switch back to index mode */ 218317c35d1SJesse Barnes I915_WRITE8(VGA_AR_INDEX, dev_priv->saveAR_INDEX | 0x20); 219317c35d1SJesse Barnes I915_READ8(st01); 220317c35d1SJesse Barnes 221317c35d1SJesse Barnes /* VGA color palette registers */ 222317c35d1SJesse Barnes I915_WRITE8(VGA_DACMASK, dev_priv->saveDACMASK); 223317c35d1SJesse Barnes } 224317c35d1SJesse Barnes 225317c35d1SJesse Barnes int i915_save_state(struct drm_device *dev) 226317c35d1SJesse Barnes { 227317c35d1SJesse Barnes struct drm_i915_private *dev_priv = dev->dev_private; 228317c35d1SJesse Barnes int i; 229317c35d1SJesse Barnes 230317c35d1SJesse Barnes pci_read_config_byte(dev->pdev, LBB, &dev_priv->saveLBB); 231317c35d1SJesse Barnes 232881ee988SKeith Packard /* Render Standby */ 233881ee988SKeith Packard if (IS_I965G(dev) && IS_MOBILE(dev)) 234881ee988SKeith Packard dev_priv->saveRENDERSTANDBY = I915_READ(MCHBAR_RENDER_STANDBY); 235881ee988SKeith Packard 236461cba2dSPeng Li /* Hardware status page */ 237461cba2dSPeng Li dev_priv->saveHWS = I915_READ(HWS_PGA); 238461cba2dSPeng Li 239317c35d1SJesse Barnes /* Display arbitration control */ 240317c35d1SJesse Barnes dev_priv->saveDSPARB = I915_READ(DSPARB); 241317c35d1SJesse Barnes 242317c35d1SJesse Barnes /* Pipe & plane A info */ 243317c35d1SJesse Barnes dev_priv->savePIPEACONF = I915_READ(PIPEACONF); 244317c35d1SJesse Barnes dev_priv->savePIPEASRC = I915_READ(PIPEASRC); 245317c35d1SJesse Barnes dev_priv->saveFPA0 = I915_READ(FPA0); 246317c35d1SJesse Barnes dev_priv->saveFPA1 = I915_READ(FPA1); 247317c35d1SJesse Barnes dev_priv->saveDPLL_A = I915_READ(DPLL_A); 248317c35d1SJesse Barnes if (IS_I965G(dev)) 249317c35d1SJesse Barnes dev_priv->saveDPLL_A_MD = I915_READ(DPLL_A_MD); 250317c35d1SJesse Barnes dev_priv->saveHTOTAL_A = I915_READ(HTOTAL_A); 251317c35d1SJesse Barnes dev_priv->saveHBLANK_A = I915_READ(HBLANK_A); 252317c35d1SJesse Barnes dev_priv->saveHSYNC_A = I915_READ(HSYNC_A); 253317c35d1SJesse Barnes dev_priv->saveVTOTAL_A = I915_READ(VTOTAL_A); 254317c35d1SJesse Barnes dev_priv->saveVBLANK_A = I915_READ(VBLANK_A); 255317c35d1SJesse Barnes dev_priv->saveVSYNC_A = I915_READ(VSYNC_A); 256317c35d1SJesse Barnes dev_priv->saveBCLRPAT_A = I915_READ(BCLRPAT_A); 257317c35d1SJesse Barnes 258317c35d1SJesse Barnes dev_priv->saveDSPACNTR = I915_READ(DSPACNTR); 259317c35d1SJesse Barnes dev_priv->saveDSPASTRIDE = I915_READ(DSPASTRIDE); 260317c35d1SJesse Barnes dev_priv->saveDSPASIZE = I915_READ(DSPASIZE); 261317c35d1SJesse Barnes dev_priv->saveDSPAPOS = I915_READ(DSPAPOS); 262317c35d1SJesse Barnes dev_priv->saveDSPAADDR = I915_READ(DSPAADDR); 263317c35d1SJesse Barnes if (IS_I965G(dev)) { 264317c35d1SJesse Barnes dev_priv->saveDSPASURF = I915_READ(DSPASURF); 265317c35d1SJesse Barnes dev_priv->saveDSPATILEOFF = I915_READ(DSPATILEOFF); 266317c35d1SJesse Barnes } 267317c35d1SJesse Barnes i915_save_palette(dev, PIPE_A); 268317c35d1SJesse Barnes dev_priv->savePIPEASTAT = I915_READ(PIPEASTAT); 269317c35d1SJesse Barnes 270317c35d1SJesse Barnes /* Pipe & plane B info */ 271317c35d1SJesse Barnes dev_priv->savePIPEBCONF = I915_READ(PIPEBCONF); 272317c35d1SJesse Barnes dev_priv->savePIPEBSRC = I915_READ(PIPEBSRC); 273317c35d1SJesse Barnes dev_priv->saveFPB0 = I915_READ(FPB0); 274317c35d1SJesse Barnes dev_priv->saveFPB1 = I915_READ(FPB1); 275317c35d1SJesse Barnes dev_priv->saveDPLL_B = I915_READ(DPLL_B); 276317c35d1SJesse Barnes if (IS_I965G(dev)) 277317c35d1SJesse Barnes dev_priv->saveDPLL_B_MD = I915_READ(DPLL_B_MD); 278317c35d1SJesse Barnes dev_priv->saveHTOTAL_B = I915_READ(HTOTAL_B); 279317c35d1SJesse Barnes dev_priv->saveHBLANK_B = I915_READ(HBLANK_B); 280317c35d1SJesse Barnes dev_priv->saveHSYNC_B = I915_READ(HSYNC_B); 281317c35d1SJesse Barnes dev_priv->saveVTOTAL_B = I915_READ(VTOTAL_B); 282317c35d1SJesse Barnes dev_priv->saveVBLANK_B = I915_READ(VBLANK_B); 283317c35d1SJesse Barnes dev_priv->saveVSYNC_B = I915_READ(VSYNC_B); 284317c35d1SJesse Barnes dev_priv->saveBCLRPAT_A = I915_READ(BCLRPAT_A); 285317c35d1SJesse Barnes 286317c35d1SJesse Barnes dev_priv->saveDSPBCNTR = I915_READ(DSPBCNTR); 287317c35d1SJesse Barnes dev_priv->saveDSPBSTRIDE = I915_READ(DSPBSTRIDE); 288317c35d1SJesse Barnes dev_priv->saveDSPBSIZE = I915_READ(DSPBSIZE); 289317c35d1SJesse Barnes dev_priv->saveDSPBPOS = I915_READ(DSPBPOS); 290317c35d1SJesse Barnes dev_priv->saveDSPBADDR = I915_READ(DSPBADDR); 291b9bfdfe6SJesse Barnes if (IS_I965GM(dev) || IS_GM45(dev)) { 292317c35d1SJesse Barnes dev_priv->saveDSPBSURF = I915_READ(DSPBSURF); 293317c35d1SJesse Barnes dev_priv->saveDSPBTILEOFF = I915_READ(DSPBTILEOFF); 294317c35d1SJesse Barnes } 295317c35d1SJesse Barnes i915_save_palette(dev, PIPE_B); 296317c35d1SJesse Barnes dev_priv->savePIPEBSTAT = I915_READ(PIPEBSTAT); 297317c35d1SJesse Barnes 298*1fd1c624SEric Anholt /* Cursor state */ 299*1fd1c624SEric Anholt dev_priv->saveCURACNTR = I915_READ(CURACNTR); 300*1fd1c624SEric Anholt dev_priv->saveCURAPOS = I915_READ(CURAPOS); 301*1fd1c624SEric Anholt dev_priv->saveCURABASE = I915_READ(CURABASE); 302*1fd1c624SEric Anholt dev_priv->saveCURBCNTR = I915_READ(CURBCNTR); 303*1fd1c624SEric Anholt dev_priv->saveCURBPOS = I915_READ(CURBPOS); 304*1fd1c624SEric Anholt dev_priv->saveCURBBASE = I915_READ(CURBBASE); 305*1fd1c624SEric Anholt if (!IS_I9XX(dev)) 306*1fd1c624SEric Anholt dev_priv->saveCURSIZE = I915_READ(CURSIZE); 307*1fd1c624SEric Anholt 308317c35d1SJesse Barnes /* CRT state */ 309317c35d1SJesse Barnes dev_priv->saveADPA = I915_READ(ADPA); 310317c35d1SJesse Barnes 311317c35d1SJesse Barnes /* LVDS state */ 312317c35d1SJesse Barnes dev_priv->savePP_CONTROL = I915_READ(PP_CONTROL); 313317c35d1SJesse Barnes dev_priv->savePFIT_PGM_RATIOS = I915_READ(PFIT_PGM_RATIOS); 314317c35d1SJesse Barnes dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL); 315317c35d1SJesse Barnes if (IS_I965G(dev)) 316317c35d1SJesse Barnes dev_priv->saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_CTL2); 317317c35d1SJesse Barnes if (IS_MOBILE(dev) && !IS_I830(dev)) 318317c35d1SJesse Barnes dev_priv->saveLVDS = I915_READ(LVDS); 319317c35d1SJesse Barnes if (!IS_I830(dev) && !IS_845G(dev)) 320317c35d1SJesse Barnes dev_priv->savePFIT_CONTROL = I915_READ(PFIT_CONTROL); 321317c35d1SJesse Barnes dev_priv->savePP_ON_DELAYS = I915_READ(PP_ON_DELAYS); 322317c35d1SJesse Barnes dev_priv->savePP_OFF_DELAYS = I915_READ(PP_OFF_DELAYS); 323317c35d1SJesse Barnes dev_priv->savePP_DIVISOR = I915_READ(PP_DIVISOR); 324317c35d1SJesse Barnes 325317c35d1SJesse Barnes /* FIXME: save TV & SDVO state */ 326317c35d1SJesse Barnes 327317c35d1SJesse Barnes /* FBC state */ 328317c35d1SJesse Barnes dev_priv->saveFBC_CFB_BASE = I915_READ(FBC_CFB_BASE); 329317c35d1SJesse Barnes dev_priv->saveFBC_LL_BASE = I915_READ(FBC_LL_BASE); 330317c35d1SJesse Barnes dev_priv->saveFBC_CONTROL2 = I915_READ(FBC_CONTROL2); 331317c35d1SJesse Barnes dev_priv->saveFBC_CONTROL = I915_READ(FBC_CONTROL); 332317c35d1SJesse Barnes 333317c35d1SJesse Barnes /* Interrupt state */ 334317c35d1SJesse Barnes dev_priv->saveIIR = I915_READ(IIR); 335317c35d1SJesse Barnes dev_priv->saveIER = I915_READ(IER); 336317c35d1SJesse Barnes dev_priv->saveIMR = I915_READ(IMR); 337317c35d1SJesse Barnes 338317c35d1SJesse Barnes /* VGA state */ 339317c35d1SJesse Barnes dev_priv->saveVGA0 = I915_READ(VGA0); 340317c35d1SJesse Barnes dev_priv->saveVGA1 = I915_READ(VGA1); 341317c35d1SJesse Barnes dev_priv->saveVGA_PD = I915_READ(VGA_PD); 342317c35d1SJesse Barnes dev_priv->saveVGACNTRL = I915_READ(VGACNTRL); 343317c35d1SJesse Barnes 344317c35d1SJesse Barnes /* Clock gating state */ 345317c35d1SJesse Barnes dev_priv->saveD_STATE = I915_READ(D_STATE); 346317c35d1SJesse Barnes dev_priv->saveCG_2D_DIS = I915_READ(CG_2D_DIS); 347317c35d1SJesse Barnes 348317c35d1SJesse Barnes /* Cache mode state */ 349317c35d1SJesse Barnes dev_priv->saveCACHE_MODE_0 = I915_READ(CACHE_MODE_0); 350317c35d1SJesse Barnes 351317c35d1SJesse Barnes /* Memory Arbitration state */ 352317c35d1SJesse Barnes dev_priv->saveMI_ARB_STATE = I915_READ(MI_ARB_STATE); 353317c35d1SJesse Barnes 354317c35d1SJesse Barnes /* Scratch space */ 355317c35d1SJesse Barnes for (i = 0; i < 16; i++) { 356317c35d1SJesse Barnes dev_priv->saveSWF0[i] = I915_READ(SWF00 + (i << 2)); 357317c35d1SJesse Barnes dev_priv->saveSWF1[i] = I915_READ(SWF10 + (i << 2)); 358317c35d1SJesse Barnes } 359317c35d1SJesse Barnes for (i = 0; i < 3; i++) 360317c35d1SJesse Barnes dev_priv->saveSWF2[i] = I915_READ(SWF30 + (i << 2)); 361317c35d1SJesse Barnes 36279f11c19SKeith Packard /* Fences */ 36379f11c19SKeith Packard if (IS_I965G(dev)) { 36479f11c19SKeith Packard for (i = 0; i < 16; i++) 36579f11c19SKeith Packard dev_priv->saveFENCE[i] = I915_READ64(FENCE_REG_965_0 + (i * 8)); 36679f11c19SKeith Packard } else { 36779f11c19SKeith Packard for (i = 0; i < 8; i++) 36879f11c19SKeith Packard dev_priv->saveFENCE[i] = I915_READ(FENCE_REG_830_0 + (i * 4)); 36979f11c19SKeith Packard 37079f11c19SKeith Packard if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) 37179f11c19SKeith Packard for (i = 0; i < 8; i++) 37279f11c19SKeith Packard dev_priv->saveFENCE[i+8] = I915_READ(FENCE_REG_945_8 + (i * 4)); 37379f11c19SKeith Packard } 374317c35d1SJesse Barnes i915_save_vga(dev); 375317c35d1SJesse Barnes 376317c35d1SJesse Barnes return 0; 377317c35d1SJesse Barnes } 378317c35d1SJesse Barnes 379317c35d1SJesse Barnes int i915_restore_state(struct drm_device *dev) 380317c35d1SJesse Barnes { 381317c35d1SJesse Barnes struct drm_i915_private *dev_priv = dev->dev_private; 382317c35d1SJesse Barnes int i; 383317c35d1SJesse Barnes 384317c35d1SJesse Barnes pci_write_config_byte(dev->pdev, LBB, dev_priv->saveLBB); 385317c35d1SJesse Barnes 386881ee988SKeith Packard /* Render Standby */ 387881ee988SKeith Packard if (IS_I965G(dev) && IS_MOBILE(dev)) 388881ee988SKeith Packard I915_WRITE(MCHBAR_RENDER_STANDBY, dev_priv->saveRENDERSTANDBY); 389881ee988SKeith Packard 390461cba2dSPeng Li /* Hardware status page */ 391461cba2dSPeng Li I915_WRITE(HWS_PGA, dev_priv->saveHWS); 392461cba2dSPeng Li 393881ee988SKeith Packard /* Display arbitration */ 394317c35d1SJesse Barnes I915_WRITE(DSPARB, dev_priv->saveDSPARB); 395317c35d1SJesse Barnes 39679f11c19SKeith Packard /* Fences */ 39779f11c19SKeith Packard if (IS_I965G(dev)) { 39879f11c19SKeith Packard for (i = 0; i < 16; i++) 39979f11c19SKeith Packard I915_WRITE64(FENCE_REG_965_0 + (i * 8), dev_priv->saveFENCE[i]); 40079f11c19SKeith Packard } else { 40179f11c19SKeith Packard for (i = 0; i < 8; i++) 40279f11c19SKeith Packard I915_WRITE(FENCE_REG_830_0 + (i * 4), dev_priv->saveFENCE[i]); 40379f11c19SKeith Packard if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) 40479f11c19SKeith Packard for (i = 0; i < 8; i++) 40579f11c19SKeith Packard I915_WRITE(FENCE_REG_945_8 + (i * 4), dev_priv->saveFENCE[i+8]); 40679f11c19SKeith Packard } 40779f11c19SKeith Packard 408317c35d1SJesse Barnes /* Pipe & plane A info */ 409317c35d1SJesse Barnes /* Prime the clock */ 410317c35d1SJesse Barnes if (dev_priv->saveDPLL_A & DPLL_VCO_ENABLE) { 411317c35d1SJesse Barnes I915_WRITE(DPLL_A, dev_priv->saveDPLL_A & 412317c35d1SJesse Barnes ~DPLL_VCO_ENABLE); 413317c35d1SJesse Barnes DRM_UDELAY(150); 414317c35d1SJesse Barnes } 415317c35d1SJesse Barnes I915_WRITE(FPA0, dev_priv->saveFPA0); 416317c35d1SJesse Barnes I915_WRITE(FPA1, dev_priv->saveFPA1); 417317c35d1SJesse Barnes /* Actually enable it */ 418317c35d1SJesse Barnes I915_WRITE(DPLL_A, dev_priv->saveDPLL_A); 419317c35d1SJesse Barnes DRM_UDELAY(150); 420317c35d1SJesse Barnes if (IS_I965G(dev)) 421317c35d1SJesse Barnes I915_WRITE(DPLL_A_MD, dev_priv->saveDPLL_A_MD); 422317c35d1SJesse Barnes DRM_UDELAY(150); 423317c35d1SJesse Barnes 424317c35d1SJesse Barnes /* Restore mode */ 425317c35d1SJesse Barnes I915_WRITE(HTOTAL_A, dev_priv->saveHTOTAL_A); 426317c35d1SJesse Barnes I915_WRITE(HBLANK_A, dev_priv->saveHBLANK_A); 427317c35d1SJesse Barnes I915_WRITE(HSYNC_A, dev_priv->saveHSYNC_A); 428317c35d1SJesse Barnes I915_WRITE(VTOTAL_A, dev_priv->saveVTOTAL_A); 429317c35d1SJesse Barnes I915_WRITE(VBLANK_A, dev_priv->saveVBLANK_A); 430317c35d1SJesse Barnes I915_WRITE(VSYNC_A, dev_priv->saveVSYNC_A); 431317c35d1SJesse Barnes I915_WRITE(BCLRPAT_A, dev_priv->saveBCLRPAT_A); 432317c35d1SJesse Barnes 433317c35d1SJesse Barnes /* Restore plane info */ 434317c35d1SJesse Barnes I915_WRITE(DSPASIZE, dev_priv->saveDSPASIZE); 435317c35d1SJesse Barnes I915_WRITE(DSPAPOS, dev_priv->saveDSPAPOS); 436317c35d1SJesse Barnes I915_WRITE(PIPEASRC, dev_priv->savePIPEASRC); 437317c35d1SJesse Barnes I915_WRITE(DSPAADDR, dev_priv->saveDSPAADDR); 438317c35d1SJesse Barnes I915_WRITE(DSPASTRIDE, dev_priv->saveDSPASTRIDE); 439317c35d1SJesse Barnes if (IS_I965G(dev)) { 440317c35d1SJesse Barnes I915_WRITE(DSPASURF, dev_priv->saveDSPASURF); 441317c35d1SJesse Barnes I915_WRITE(DSPATILEOFF, dev_priv->saveDSPATILEOFF); 442317c35d1SJesse Barnes } 443317c35d1SJesse Barnes 444317c35d1SJesse Barnes I915_WRITE(PIPEACONF, dev_priv->savePIPEACONF); 445317c35d1SJesse Barnes 446317c35d1SJesse Barnes i915_restore_palette(dev, PIPE_A); 447317c35d1SJesse Barnes /* Enable the plane */ 448317c35d1SJesse Barnes I915_WRITE(DSPACNTR, dev_priv->saveDSPACNTR); 449317c35d1SJesse Barnes I915_WRITE(DSPAADDR, I915_READ(DSPAADDR)); 450317c35d1SJesse Barnes 451317c35d1SJesse Barnes /* Pipe & plane B info */ 452317c35d1SJesse Barnes if (dev_priv->saveDPLL_B & DPLL_VCO_ENABLE) { 453317c35d1SJesse Barnes I915_WRITE(DPLL_B, dev_priv->saveDPLL_B & 454317c35d1SJesse Barnes ~DPLL_VCO_ENABLE); 455317c35d1SJesse Barnes DRM_UDELAY(150); 456317c35d1SJesse Barnes } 457317c35d1SJesse Barnes I915_WRITE(FPB0, dev_priv->saveFPB0); 458317c35d1SJesse Barnes I915_WRITE(FPB1, dev_priv->saveFPB1); 459317c35d1SJesse Barnes /* Actually enable it */ 460317c35d1SJesse Barnes I915_WRITE(DPLL_B, dev_priv->saveDPLL_B); 461317c35d1SJesse Barnes DRM_UDELAY(150); 462317c35d1SJesse Barnes if (IS_I965G(dev)) 463317c35d1SJesse Barnes I915_WRITE(DPLL_B_MD, dev_priv->saveDPLL_B_MD); 464317c35d1SJesse Barnes DRM_UDELAY(150); 465317c35d1SJesse Barnes 466317c35d1SJesse Barnes /* Restore mode */ 467317c35d1SJesse Barnes I915_WRITE(HTOTAL_B, dev_priv->saveHTOTAL_B); 468317c35d1SJesse Barnes I915_WRITE(HBLANK_B, dev_priv->saveHBLANK_B); 469317c35d1SJesse Barnes I915_WRITE(HSYNC_B, dev_priv->saveHSYNC_B); 470317c35d1SJesse Barnes I915_WRITE(VTOTAL_B, dev_priv->saveVTOTAL_B); 471317c35d1SJesse Barnes I915_WRITE(VBLANK_B, dev_priv->saveVBLANK_B); 472317c35d1SJesse Barnes I915_WRITE(VSYNC_B, dev_priv->saveVSYNC_B); 473317c35d1SJesse Barnes I915_WRITE(BCLRPAT_B, dev_priv->saveBCLRPAT_B); 474317c35d1SJesse Barnes 475317c35d1SJesse Barnes /* Restore plane info */ 476317c35d1SJesse Barnes I915_WRITE(DSPBSIZE, dev_priv->saveDSPBSIZE); 477317c35d1SJesse Barnes I915_WRITE(DSPBPOS, dev_priv->saveDSPBPOS); 478317c35d1SJesse Barnes I915_WRITE(PIPEBSRC, dev_priv->savePIPEBSRC); 479317c35d1SJesse Barnes I915_WRITE(DSPBADDR, dev_priv->saveDSPBADDR); 480317c35d1SJesse Barnes I915_WRITE(DSPBSTRIDE, dev_priv->saveDSPBSTRIDE); 481317c35d1SJesse Barnes if (IS_I965G(dev)) { 482317c35d1SJesse Barnes I915_WRITE(DSPBSURF, dev_priv->saveDSPBSURF); 483317c35d1SJesse Barnes I915_WRITE(DSPBTILEOFF, dev_priv->saveDSPBTILEOFF); 484317c35d1SJesse Barnes } 485317c35d1SJesse Barnes 486317c35d1SJesse Barnes I915_WRITE(PIPEBCONF, dev_priv->savePIPEBCONF); 487317c35d1SJesse Barnes 488317c35d1SJesse Barnes i915_restore_palette(dev, PIPE_B); 489317c35d1SJesse Barnes /* Enable the plane */ 490317c35d1SJesse Barnes I915_WRITE(DSPBCNTR, dev_priv->saveDSPBCNTR); 491317c35d1SJesse Barnes I915_WRITE(DSPBADDR, I915_READ(DSPBADDR)); 492317c35d1SJesse Barnes 493*1fd1c624SEric Anholt /* Cursor state */ 494*1fd1c624SEric Anholt I915_WRITE(CURAPOS, dev_priv->saveCURAPOS); 495*1fd1c624SEric Anholt I915_WRITE(CURACNTR, dev_priv->saveCURACNTR); 496*1fd1c624SEric Anholt I915_WRITE(CURABASE, dev_priv->saveCURABASE); 497*1fd1c624SEric Anholt I915_WRITE(CURBPOS, dev_priv->saveCURBPOS); 498*1fd1c624SEric Anholt I915_WRITE(CURBCNTR, dev_priv->saveCURBCNTR); 499*1fd1c624SEric Anholt I915_WRITE(CURBBASE, dev_priv->saveCURBBASE); 500*1fd1c624SEric Anholt if (!IS_I9XX(dev)) 501*1fd1c624SEric Anholt I915_WRITE(CURSIZE, dev_priv->saveCURSIZE); 502*1fd1c624SEric Anholt 503317c35d1SJesse Barnes /* CRT state */ 504317c35d1SJesse Barnes I915_WRITE(ADPA, dev_priv->saveADPA); 505317c35d1SJesse Barnes 506317c35d1SJesse Barnes /* LVDS state */ 507317c35d1SJesse Barnes if (IS_I965G(dev)) 508317c35d1SJesse Barnes I915_WRITE(BLC_PWM_CTL2, dev_priv->saveBLC_PWM_CTL2); 509317c35d1SJesse Barnes if (IS_MOBILE(dev) && !IS_I830(dev)) 510317c35d1SJesse Barnes I915_WRITE(LVDS, dev_priv->saveLVDS); 511317c35d1SJesse Barnes if (!IS_I830(dev) && !IS_845G(dev)) 512317c35d1SJesse Barnes I915_WRITE(PFIT_CONTROL, dev_priv->savePFIT_CONTROL); 513317c35d1SJesse Barnes 514317c35d1SJesse Barnes I915_WRITE(PFIT_PGM_RATIOS, dev_priv->savePFIT_PGM_RATIOS); 515317c35d1SJesse Barnes I915_WRITE(BLC_PWM_CTL, dev_priv->saveBLC_PWM_CTL); 516317c35d1SJesse Barnes I915_WRITE(PP_ON_DELAYS, dev_priv->savePP_ON_DELAYS); 517317c35d1SJesse Barnes I915_WRITE(PP_OFF_DELAYS, dev_priv->savePP_OFF_DELAYS); 518317c35d1SJesse Barnes I915_WRITE(PP_DIVISOR, dev_priv->savePP_DIVISOR); 519317c35d1SJesse Barnes I915_WRITE(PP_CONTROL, dev_priv->savePP_CONTROL); 520317c35d1SJesse Barnes 521317c35d1SJesse Barnes /* FIXME: restore TV & SDVO state */ 522317c35d1SJesse Barnes 523317c35d1SJesse Barnes /* FBC info */ 524317c35d1SJesse Barnes I915_WRITE(FBC_CFB_BASE, dev_priv->saveFBC_CFB_BASE); 525317c35d1SJesse Barnes I915_WRITE(FBC_LL_BASE, dev_priv->saveFBC_LL_BASE); 526317c35d1SJesse Barnes I915_WRITE(FBC_CONTROL2, dev_priv->saveFBC_CONTROL2); 527317c35d1SJesse Barnes I915_WRITE(FBC_CONTROL, dev_priv->saveFBC_CONTROL); 528317c35d1SJesse Barnes 529317c35d1SJesse Barnes /* VGA state */ 530317c35d1SJesse Barnes I915_WRITE(VGACNTRL, dev_priv->saveVGACNTRL); 531317c35d1SJesse Barnes I915_WRITE(VGA0, dev_priv->saveVGA0); 532317c35d1SJesse Barnes I915_WRITE(VGA1, dev_priv->saveVGA1); 533317c35d1SJesse Barnes I915_WRITE(VGA_PD, dev_priv->saveVGA_PD); 534317c35d1SJesse Barnes DRM_UDELAY(150); 535317c35d1SJesse Barnes 536317c35d1SJesse Barnes /* Clock gating state */ 537317c35d1SJesse Barnes I915_WRITE (D_STATE, dev_priv->saveD_STATE); 538317c35d1SJesse Barnes I915_WRITE (CG_2D_DIS, dev_priv->saveCG_2D_DIS); 539317c35d1SJesse Barnes 540317c35d1SJesse Barnes /* Cache mode state */ 541317c35d1SJesse Barnes I915_WRITE (CACHE_MODE_0, dev_priv->saveCACHE_MODE_0 | 0xffff0000); 542317c35d1SJesse Barnes 543317c35d1SJesse Barnes /* Memory arbitration state */ 544317c35d1SJesse Barnes I915_WRITE (MI_ARB_STATE, dev_priv->saveMI_ARB_STATE | 0xffff0000); 545317c35d1SJesse Barnes 546317c35d1SJesse Barnes for (i = 0; i < 16; i++) { 547317c35d1SJesse Barnes I915_WRITE(SWF00 + (i << 2), dev_priv->saveSWF0[i]); 548317c35d1SJesse Barnes I915_WRITE(SWF10 + (i << 2), dev_priv->saveSWF1[i+7]); 549317c35d1SJesse Barnes } 550317c35d1SJesse Barnes for (i = 0; i < 3; i++) 551317c35d1SJesse Barnes I915_WRITE(SWF30 + (i << 2), dev_priv->saveSWF2[i]); 552317c35d1SJesse Barnes 553317c35d1SJesse Barnes i915_restore_vga(dev); 554317c35d1SJesse Barnes 555317c35d1SJesse Barnes return 0; 556317c35d1SJesse Barnes } 557317c35d1SJesse Barnes 558