1 | /* |
2 | * |
3 | * Copyright 2008 (c) Intel Corporation |
4 | * Jesse Barnes <jbarnes@virtuousgeek.org> |
5 | * |
6 | * Permission is hereby granted, free of charge, to any person obtaining a |
7 | * copy of this software and associated documentation files (the |
8 | * "Software"), to deal in the Software without restriction, including |
9 | * without limitation the rights to use, copy, modify, merge, publish, |
10 | * distribute, sub license, and/or sell copies of the Software, and to |
11 | * permit persons to whom the Software is furnished to do so, subject to |
12 | * the following conditions: |
13 | * |
14 | * The above copyright notice and this permission notice (including the |
15 | * next paragraph) shall be included in all copies or substantial portions |
16 | * of the Software. |
17 | * |
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
19 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
20 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. |
21 | * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR |
22 | * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
23 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
24 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
25 | */ |
26 | |
27 | #include <drm/drmP.h> |
28 | #include <drm/i915_drm.h> |
29 | #include "intel_drv.h" |
30 | #include "i915_reg.h" |
31 | |
32 | static u8 i915_read_indexed(struct drm_device *dev, u16 index_port, u16 data_port, u8 reg) |
33 | { |
34 | struct drm_i915_private *dev_priv = dev->dev_private; |
35 | |
36 | I915_WRITE8(index_port, reg); |
37 | return I915_READ8(data_port); |
38 | } |
39 | |
40 | static u8 i915_read_ar(struct drm_device *dev, u16 st01, u8 reg, u16 palette_enable) |
41 | { |
42 | struct drm_i915_private *dev_priv = dev->dev_private; |
43 | |
44 | I915_READ8(st01); |
45 | I915_WRITE8(VGA_AR_INDEX, palette_enable | reg); |
46 | return I915_READ8(VGA_AR_DATA_READ); |
47 | } |
48 | |
49 | static void i915_write_ar(struct drm_device *dev, u16 st01, u8 reg, u8 val, u16 palette_enable) |
50 | { |
51 | struct drm_i915_private *dev_priv = dev->dev_private; |
52 | |
53 | I915_READ8(st01); |
54 | I915_WRITE8(VGA_AR_INDEX, palette_enable | reg); |
55 | I915_WRITE8(VGA_AR_DATA_WRITE, val); |
56 | } |
57 | |
58 | static void i915_write_indexed(struct drm_device *dev, u16 index_port, u16 data_port, u8 reg, u8 val) |
59 | { |
60 | struct drm_i915_private *dev_priv = dev->dev_private; |
61 | |
62 | I915_WRITE8(index_port, reg); |
63 | I915_WRITE8(data_port, val); |
64 | } |
65 | |
66 | static void i915_save_vga(struct drm_device *dev) |
67 | { |
68 | struct drm_i915_private *dev_priv = dev->dev_private; |
69 | int i; |
70 | u16 cr_index, cr_data, st01; |
71 | |
72 | /* VGA state */ |
73 | dev_priv->regfile.saveVGA0 = I915_READ(VGA0); |
74 | dev_priv->regfile.saveVGA1 = I915_READ(VGA1); |
75 | dev_priv->regfile.saveVGA_PD = I915_READ(VGA_PD); |
76 | dev_priv->regfile.saveVGACNTRL = I915_READ(i915_vgacntrl_reg(dev)); |
77 | |
78 | /* VGA color palette registers */ |
79 | dev_priv->regfile.saveDACMASK = I915_READ8(VGA_DACMASK); |
80 | |
81 | /* MSR bits */ |
82 | dev_priv->regfile.saveMSR = I915_READ8(VGA_MSR_READ); |
83 | if (dev_priv->regfile.saveMSR & VGA_MSR_CGA_MODE) { |
84 | cr_index = VGA_CR_INDEX_CGA; |
85 | cr_data = VGA_CR_DATA_CGA; |
86 | st01 = VGA_ST01_CGA; |
87 | } else { |
88 | cr_index = VGA_CR_INDEX_MDA; |
89 | cr_data = VGA_CR_DATA_MDA; |
90 | st01 = VGA_ST01_MDA; |
91 | } |
92 | |
93 | /* CRT controller regs */ |
94 | i915_write_indexed(dev, cr_index, cr_data, 0x11, |
95 | i915_read_indexed(dev, cr_index, cr_data, 0x11) & |
96 | (~0x80)); |
97 | for (i = 0; i <= 0x24; i++) |
98 | dev_priv->regfile.saveCR[i] = |
99 | i915_read_indexed(dev, cr_index, cr_data, i); |
100 | /* Make sure we don't turn off CR group 0 writes */ |
101 | dev_priv->regfile.saveCR[0x11] &= ~0x80; |
102 | |
103 | /* Attribute controller registers */ |
104 | I915_READ8(st01); |
105 | dev_priv->regfile.saveAR_INDEX = I915_READ8(VGA_AR_INDEX); |
106 | for (i = 0; i <= 0x14; i++) |
107 | dev_priv->regfile.saveAR[i] = i915_read_ar(dev, st01, i, 0); |
108 | I915_READ8(st01); |
109 | I915_WRITE8(VGA_AR_INDEX, dev_priv->regfile.saveAR_INDEX); |
110 | I915_READ8(st01); |
111 | |
112 | /* Graphics controller registers */ |
113 | for (i = 0; i < 9; i++) |
114 | dev_priv->regfile.saveGR[i] = |
115 | i915_read_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, i); |
116 | |
117 | dev_priv->regfile.saveGR[0x10] = |
118 | i915_read_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x10); |
119 | dev_priv->regfile.saveGR[0x11] = |
120 | i915_read_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x11); |
121 | dev_priv->regfile.saveGR[0x18] = |
122 | i915_read_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x18); |
123 | |
124 | /* Sequencer registers */ |
125 | for (i = 0; i < 8; i++) |
126 | dev_priv->regfile.saveSR[i] = |
127 | i915_read_indexed(dev, VGA_SR_INDEX, VGA_SR_DATA, i); |
128 | } |
129 | |
130 | static void i915_restore_vga(struct drm_device *dev) |
131 | { |
132 | struct drm_i915_private *dev_priv = dev->dev_private; |
133 | int i; |
134 | u16 cr_index, cr_data, st01; |
135 | |
136 | /* VGA state */ |
137 | I915_WRITE(i915_vgacntrl_reg(dev), dev_priv->regfile.saveVGACNTRL); |
138 | |
139 | I915_WRITE(VGA0, dev_priv->regfile.saveVGA0); |
140 | I915_WRITE(VGA1, dev_priv->regfile.saveVGA1); |
141 | I915_WRITE(VGA_PD, dev_priv->regfile.saveVGA_PD); |
142 | POSTING_READ(VGA_PD); |
143 | udelay(150); |
144 | |
145 | /* MSR bits */ |
146 | I915_WRITE8(VGA_MSR_WRITE, dev_priv->regfile.saveMSR); |
147 | if (dev_priv->regfile.saveMSR & VGA_MSR_CGA_MODE) { |
148 | cr_index = VGA_CR_INDEX_CGA; |
149 | cr_data = VGA_CR_DATA_CGA; |
150 | st01 = VGA_ST01_CGA; |
151 | } else { |
152 | cr_index = VGA_CR_INDEX_MDA; |
153 | cr_data = VGA_CR_DATA_MDA; |
154 | st01 = VGA_ST01_MDA; |
155 | } |
156 | |
157 | /* Sequencer registers, don't write SR07 */ |
158 | for (i = 0; i < 7; i++) |
159 | i915_write_indexed(dev, VGA_SR_INDEX, VGA_SR_DATA, i, |
160 | dev_priv->regfile.saveSR[i]); |
161 | |
162 | /* CRT controller regs */ |
163 | /* Enable CR group 0 writes */ |
164 | i915_write_indexed(dev, cr_index, cr_data, 0x11, dev_priv->regfile.saveCR[0x11]); |
165 | for (i = 0; i <= 0x24; i++) |
166 | i915_write_indexed(dev, cr_index, cr_data, i, dev_priv->regfile.saveCR[i]); |
167 | |
168 | /* Graphics controller regs */ |
169 | for (i = 0; i < 9; i++) |
170 | i915_write_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, i, |
171 | dev_priv->regfile.saveGR[i]); |
172 | |
173 | i915_write_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x10, |
174 | dev_priv->regfile.saveGR[0x10]); |
175 | i915_write_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x11, |
176 | dev_priv->regfile.saveGR[0x11]); |
177 | i915_write_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x18, |
178 | dev_priv->regfile.saveGR[0x18]); |
179 | |
180 | /* Attribute controller registers */ |
181 | I915_READ8(st01); /* switch back to index mode */ |
182 | for (i = 0; i <= 0x14; i++) |
183 | i915_write_ar(dev, st01, i, dev_priv->regfile.saveAR[i], 0); |
184 | I915_READ8(st01); /* switch back to index mode */ |
185 | I915_WRITE8(VGA_AR_INDEX, dev_priv->regfile.saveAR_INDEX | 0x20); |
186 | I915_READ8(st01); |
187 | |
188 | /* VGA color palette registers */ |
189 | I915_WRITE8(VGA_DACMASK, dev_priv->regfile.saveDACMASK); |
190 | } |
191 | |
192 | static void i915_save_display(struct drm_device *dev) |
193 | { |
194 | struct drm_i915_private *dev_priv = dev->dev_private; |
195 | |
196 | /* Display arbitration control */ |
197 | if (INTEL_INFO(dev)->gen <= 4) |
198 | dev_priv->regfile.saveDSPARB = I915_READ(DSPARB); |
199 | |
200 | /* This is only meaningful in non-KMS mode */ |
201 | /* Don't regfile.save them in KMS mode */ |
202 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
203 | i915_save_display_reg(dev); |
204 | |
205 | /* LVDS state */ |
206 | if (HAS_PCH_SPLIT(dev)) { |
207 | dev_priv->regfile.savePP_CONTROL = I915_READ(PCH_PP_CONTROL); |
208 | if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) |
209 | dev_priv->regfile.saveLVDS = I915_READ(PCH_LVDS); |
210 | } else if (IS_VALLEYVIEW(dev)) { |
211 | dev_priv->regfile.savePP_CONTROL = I915_READ(PP_CONTROL); |
212 | dev_priv->regfile.savePFIT_PGM_RATIOS = I915_READ(PFIT_PGM_RATIOS); |
213 | |
214 | dev_priv->regfile.saveBLC_HIST_CTL = |
215 | I915_READ(VLV_BLC_HIST_CTL(PIPE_A)); |
216 | dev_priv->regfile.saveBLC_HIST_CTL_B = |
217 | I915_READ(VLV_BLC_HIST_CTL(PIPE_B)); |
218 | } else { |
219 | dev_priv->regfile.savePP_CONTROL = I915_READ(PP_CONTROL); |
220 | dev_priv->regfile.savePFIT_PGM_RATIOS = I915_READ(PFIT_PGM_RATIOS); |
221 | dev_priv->regfile.saveBLC_HIST_CTL = I915_READ(BLC_HIST_CTL); |
222 | if (IS_MOBILE(dev) && !IS_I830(dev)) |
223 | dev_priv->regfile.saveLVDS = I915_READ(LVDS); |
224 | } |
225 | |
226 | if (!IS_I830(dev) && !IS_845G(dev) && !HAS_PCH_SPLIT(dev)) |
227 | dev_priv->regfile.savePFIT_CONTROL = I915_READ(PFIT_CONTROL); |
228 | |
229 | if (HAS_PCH_SPLIT(dev)) { |
230 | dev_priv->regfile.savePP_ON_DELAYS = I915_READ(PCH_PP_ON_DELAYS); |
231 | dev_priv->regfile.savePP_OFF_DELAYS = I915_READ(PCH_PP_OFF_DELAYS); |
232 | dev_priv->regfile.savePP_DIVISOR = I915_READ(PCH_PP_DIVISOR); |
233 | } else { |
234 | dev_priv->regfile.savePP_ON_DELAYS = I915_READ(PP_ON_DELAYS); |
235 | dev_priv->regfile.savePP_OFF_DELAYS = I915_READ(PP_OFF_DELAYS); |
236 | dev_priv->regfile.savePP_DIVISOR = I915_READ(PP_DIVISOR); |
237 | } |
238 | |
239 | /* save FBC interval */ |
240 | if (HAS_FBC(dev) && INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev)) |
241 | dev_priv->regfile.saveFBC_CONTROL = I915_READ(FBC_CONTROL); |
242 | |
243 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
244 | i915_save_vga(dev); |
245 | } |
246 | |
247 | static void i915_restore_display(struct drm_device *dev) |
248 | { |
249 | struct drm_i915_private *dev_priv = dev->dev_private; |
250 | u32 mask = 0xffffffff; |
251 | |
252 | /* Display arbitration */ |
253 | if (INTEL_INFO(dev)->gen <= 4) |
254 | I915_WRITE(DSPARB, dev_priv->regfile.saveDSPARB); |
255 | |
256 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
257 | i915_restore_display_reg(dev); |
258 | |
259 | if (drm_core_check_feature(dev, DRIVER_MODESET)) |
260 | mask = ~LVDS_PORT_EN; |
261 | |
262 | if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) |
263 | I915_WRITE(PCH_LVDS, dev_priv->regfile.saveLVDS & mask); |
264 | else if (INTEL_INFO(dev)->gen <= 4 && IS_MOBILE(dev) && !IS_I830(dev)) |
265 | I915_WRITE(LVDS, dev_priv->regfile.saveLVDS & mask); |
266 | |
267 | if (!IS_I830(dev) && !IS_845G(dev) && !HAS_PCH_SPLIT(dev)) |
268 | I915_WRITE(PFIT_CONTROL, dev_priv->regfile.savePFIT_CONTROL); |
269 | |
270 | if (HAS_PCH_SPLIT(dev)) { |
271 | I915_WRITE(PCH_PP_ON_DELAYS, dev_priv->regfile.savePP_ON_DELAYS); |
272 | I915_WRITE(PCH_PP_OFF_DELAYS, dev_priv->regfile.savePP_OFF_DELAYS); |
273 | I915_WRITE(PCH_PP_DIVISOR, dev_priv->regfile.savePP_DIVISOR); |
274 | I915_WRITE(PCH_PP_CONTROL, dev_priv->regfile.savePP_CONTROL); |
275 | I915_WRITE(RSTDBYCTL, |
276 | dev_priv->regfile.saveMCHBAR_RENDER_STANDBY); |
277 | } else if (IS_VALLEYVIEW(dev)) { |
278 | I915_WRITE(VLV_BLC_HIST_CTL(PIPE_A), |
279 | dev_priv->regfile.saveBLC_HIST_CTL); |
280 | I915_WRITE(VLV_BLC_HIST_CTL(PIPE_B), |
281 | dev_priv->regfile.saveBLC_HIST_CTL); |
282 | } else { |
283 | I915_WRITE(PFIT_PGM_RATIOS, dev_priv->regfile.savePFIT_PGM_RATIOS); |
284 | I915_WRITE(BLC_HIST_CTL, dev_priv->regfile.saveBLC_HIST_CTL); |
285 | I915_WRITE(PP_ON_DELAYS, dev_priv->regfile.savePP_ON_DELAYS); |
286 | I915_WRITE(PP_OFF_DELAYS, dev_priv->regfile.savePP_OFF_DELAYS); |
287 | I915_WRITE(PP_DIVISOR, dev_priv->regfile.savePP_DIVISOR); |
288 | I915_WRITE(PP_CONTROL, dev_priv->regfile.savePP_CONTROL); |
289 | } |
290 | |
291 | /* only restore FBC info on the platform that supports FBC*/ |
292 | intel_disable_fbc(dev); |
293 | |
294 | /* restore FBC interval */ |
295 | if (HAS_FBC(dev) && INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev)) |
296 | I915_WRITE(FBC_CONTROL, dev_priv->regfile.saveFBC_CONTROL); |
297 | |
298 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
299 | i915_restore_vga(dev); |
300 | else |
301 | i915_redisable_vga(dev); |
302 | } |
303 | |
304 | int i915_save_state(struct drm_device *dev) |
305 | { |
306 | struct drm_i915_private *dev_priv = dev->dev_private; |
307 | int i; |
308 | |
309 | mutex_lock(&dev->struct_mutex); |
310 | |
311 | i915_save_display(dev); |
312 | |
313 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) { |
314 | /* Interrupt state */ |
315 | if (HAS_PCH_SPLIT(dev)) { |
316 | dev_priv->regfile.saveDEIER = I915_READ(DEIER); |
317 | dev_priv->regfile.saveDEIMR = I915_READ(DEIMR); |
318 | dev_priv->regfile.saveGTIER = I915_READ(GTIER); |
319 | dev_priv->regfile.saveGTIMR = I915_READ(GTIMR); |
320 | dev_priv->regfile.saveFDI_RXA_IMR = I915_READ(_FDI_RXA_IMR); |
321 | dev_priv->regfile.saveFDI_RXB_IMR = I915_READ(_FDI_RXB_IMR); |
322 | dev_priv->regfile.saveMCHBAR_RENDER_STANDBY = |
323 | I915_READ(RSTDBYCTL); |
324 | dev_priv->regfile.savePCH_PORT_HOTPLUG = I915_READ(PCH_PORT_HOTPLUG); |
325 | } else { |
326 | dev_priv->regfile.saveIER = I915_READ(IER); |
327 | dev_priv->regfile.saveIMR = I915_READ(IMR); |
328 | } |
329 | } |
330 | |
331 | intel_disable_gt_powersave(dev); |
332 | |
333 | /* Cache mode state */ |
334 | if (INTEL_INFO(dev)->gen < 7) |
335 | dev_priv->regfile.saveCACHE_MODE_0 = I915_READ(CACHE_MODE_0); |
336 | |
337 | /* Memory Arbitration state */ |
338 | dev_priv->regfile.saveMI_ARB_STATE = I915_READ(MI_ARB_STATE); |
339 | |
340 | /* Scratch space */ |
341 | for (i = 0; i < 16; i++) { |
342 | dev_priv->regfile.saveSWF0[i] = I915_READ(SWF00 + (i << 2)); |
343 | dev_priv->regfile.saveSWF1[i] = I915_READ(SWF10 + (i << 2)); |
344 | } |
345 | for (i = 0; i < 3; i++) |
346 | dev_priv->regfile.saveSWF2[i] = I915_READ(SWF30 + (i << 2)); |
347 | |
348 | mutex_unlock(&dev->struct_mutex); |
349 | |
350 | return 0; |
351 | } |
352 | |
353 | int i915_restore_state(struct drm_device *dev) |
354 | { |
355 | struct drm_i915_private *dev_priv = dev->dev_private; |
356 | int i; |
357 | |
358 | mutex_lock(&dev->struct_mutex); |
359 | |
360 | i915_gem_restore_fences(dev); |
361 | i915_restore_display(dev); |
362 | |
363 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) { |
364 | /* Interrupt state */ |
365 | if (HAS_PCH_SPLIT(dev)) { |
366 | I915_WRITE(DEIER, dev_priv->regfile.saveDEIER); |
367 | I915_WRITE(DEIMR, dev_priv->regfile.saveDEIMR); |
368 | I915_WRITE(GTIER, dev_priv->regfile.saveGTIER); |
369 | I915_WRITE(GTIMR, dev_priv->regfile.saveGTIMR); |
370 | I915_WRITE(_FDI_RXA_IMR, dev_priv->regfile.saveFDI_RXA_IMR); |
371 | I915_WRITE(_FDI_RXB_IMR, dev_priv->regfile.saveFDI_RXB_IMR); |
372 | I915_WRITE(PCH_PORT_HOTPLUG, dev_priv->regfile.savePCH_PORT_HOTPLUG); |
373 | } else { |
374 | I915_WRITE(IER, dev_priv->regfile.saveIER); |
375 | I915_WRITE(IMR, dev_priv->regfile.saveIMR); |
376 | } |
377 | } |
378 | |
379 | /* Cache mode state */ |
380 | if (INTEL_INFO(dev)->gen < 7) |
381 | I915_WRITE(CACHE_MODE_0, dev_priv->regfile.saveCACHE_MODE_0 | |
382 | 0xffff0000); |
383 | |
384 | /* Memory arbitration state */ |
385 | I915_WRITE(MI_ARB_STATE, dev_priv->regfile.saveMI_ARB_STATE | 0xffff0000); |
386 | |
387 | for (i = 0; i < 16; i++) { |
388 | I915_WRITE(SWF00 + (i << 2), dev_priv->regfile.saveSWF0[i]); |
389 | I915_WRITE(SWF10 + (i << 2), dev_priv->regfile.saveSWF1[i]); |
390 | } |
391 | for (i = 0; i < 3; i++) |
392 | I915_WRITE(SWF30 + (i << 2), dev_priv->regfile.saveSWF2[i]); |
393 | |
394 | mutex_unlock(&dev->struct_mutex); |
395 | |
396 | intel_i2c_reset(dev); |
397 | |
398 | return 0; |
399 | } |
400 | |