upgrade to linux 2.6.10-1.12_FC2
[linux-2.6.git] / drivers / video / aty / radeon_pm.c
1 #include "radeonfb.h"
2
3 #include <linux/console.h>
4 #include <linux/agp_backend.h>
5
6 /*
7  * Currently, only PowerMac do D2 state
8  */
9 #define CONFIG_RADEON_HAS_D2    CONFIG_PPC_PMAC
10
11 #ifdef CONFIG_RADEON_HAS_D2
12 /*
13  * On PowerMac, we assume any mobility chip based machine does D2
14  */
15 #ifdef CONFIG_PPC_PMAC
16 static inline int radeon_suspend_to_d2(struct radeonfb_info *rinfo, u32 state)
17 {
18         return rinfo->is_mobility;
19 }
20 #else
21 static inline int radeon_suspend_to_d2(struct radeonfb_info *rinfo, u32 state)
22 {
23         return 0;
24 }
25 #endif
26
27 #endif /* CONFIG_RADEON_HAS_D2 */
28
29 /*
30  * Radeon M6, M7 and M9 Power Management code. This code currently
31  * only supports the mobile chips in D2 mode, that is typically what
32  * is used on Apple laptops, it's based from some informations provided
33  * by ATI along with hours of tracing of MacOS drivers.
34  * 
35  * New version of this code almost totally rewritten by ATI, many thanks
36  * for their support.
37  */
38
39 void radeon_pm_disable_dynamic_mode(struct radeonfb_info *rinfo)
40 {
41
42         u32 sclk_cntl;
43         u32 mclk_cntl;
44         u32 sclk_more_cntl;
45         
46         u32 vclk_ecp_cntl;
47         u32 pixclks_cntl;
48
49         /* Mobility chips only, untested on M9+/M10/11 */
50         if (!rinfo->is_mobility)
51                 return;
52         if (rinfo->family > CHIP_FAMILY_RV250)
53                 return;
54         
55         /* Force Core Clocks */
56         sclk_cntl = INPLL( pllSCLK_CNTL_M6);
57         sclk_cntl |=    SCLK_CNTL_M6__FORCE_CP|
58                         SCLK_CNTL_M6__FORCE_HDP|
59                         SCLK_CNTL_M6__FORCE_DISP1|
60                         SCLK_CNTL_M6__FORCE_DISP2|
61                         SCLK_CNTL_M6__FORCE_TOP|
62                         SCLK_CNTL_M6__FORCE_E2|
63                         SCLK_CNTL_M6__FORCE_SE|
64                         SCLK_CNTL_M6__FORCE_IDCT|
65                         SCLK_CNTL_M6__FORCE_VIP|
66                         SCLK_CNTL_M6__FORCE_RE|
67                         SCLK_CNTL_M6__FORCE_PB|
68                         SCLK_CNTL_M6__FORCE_TAM|
69                         SCLK_CNTL_M6__FORCE_TDM|
70                         SCLK_CNTL_M6__FORCE_RB|
71                         SCLK_CNTL_M6__FORCE_TV_SCLK|
72                         SCLK_CNTL_M6__FORCE_SUBPIC|
73                         SCLK_CNTL_M6__FORCE_OV0;
74         OUTPLL( pllSCLK_CNTL_M6, sclk_cntl);
75         
76         
77         
78         sclk_more_cntl = INPLL(pllSCLK_MORE_CNTL);
79         sclk_more_cntl |=       SCLK_MORE_CNTL__FORCE_DISPREGS|
80                                 SCLK_MORE_CNTL__FORCE_MC_GUI|
81                                 SCLK_MORE_CNTL__FORCE_MC_HOST;  
82         OUTPLL(pllSCLK_MORE_CNTL, sclk_more_cntl);
83         
84         /* Force Display clocks */
85         vclk_ecp_cntl = INPLL( pllVCLK_ECP_CNTL);
86         vclk_ecp_cntl &= ~(     VCLK_ECP_CNTL__PIXCLK_ALWAYS_ONb |
87                                 VCLK_ECP_CNTL__PIXCLK_DAC_ALWAYS_ONb);
88
89         OUTPLL( pllVCLK_ECP_CNTL, vclk_ecp_cntl);
90         
91         pixclks_cntl = INPLL( pllPIXCLKS_CNTL);
92         pixclks_cntl &= ~(      PIXCLKS_CNTL__PIXCLK_GV_ALWAYS_ONb |
93                                 PIXCLKS_CNTL__PIXCLK_BLEND_ALWAYS_ONb|
94                                 PIXCLKS_CNTL__PIXCLK_DIG_TMDS_ALWAYS_ONb |
95                                 PIXCLKS_CNTL__PIXCLK_LVDS_ALWAYS_ONb|
96                                 PIXCLKS_CNTL__PIXCLK_TMDS_ALWAYS_ONb|
97                                 PIXCLKS_CNTL__PIX2CLK_ALWAYS_ONb|
98                                 PIXCLKS_CNTL__PIX2CLK_DAC_ALWAYS_ONb);
99                                                 
100         OUTPLL( pllPIXCLKS_CNTL, pixclks_cntl);
101
102         /* Force Memory Clocks */
103         mclk_cntl = INPLL( pllMCLK_CNTL_M6);
104         mclk_cntl &= ~( MCLK_CNTL_M6__FORCE_MCLKA |  
105                         MCLK_CNTL_M6__FORCE_MCLKB |
106                         MCLK_CNTL_M6__FORCE_YCLKA |
107                         MCLK_CNTL_M6__FORCE_YCLKB );
108         OUTPLL( pllMCLK_CNTL_M6, mclk_cntl);
109 }
110
111 void radeon_pm_enable_dynamic_mode(struct radeonfb_info *rinfo)
112 {
113         u32 clk_pwrmgt_cntl;
114         u32 sclk_cntl;
115         u32 sclk_more_cntl;
116         u32 clk_pin_cntl;
117         u32 pixclks_cntl;
118         u32 vclk_ecp_cntl;
119         u32 mclk_cntl;
120         u32 mclk_misc;
121
122         /* Mobility chips only, untested on M9+/M10/11 */
123         if (!rinfo->is_mobility)
124                 return;
125         if (rinfo->family > CHIP_FAMILY_RV250)
126                 return;
127         
128         /* Set Latencies */
129         clk_pwrmgt_cntl = INPLL( pllCLK_PWRMGT_CNTL_M6);
130         
131         clk_pwrmgt_cntl &= ~(    CLK_PWRMGT_CNTL_M6__ENGINE_DYNCLK_MODE_MASK|
132                                  CLK_PWRMGT_CNTL_M6__ACTIVE_HILO_LAT_MASK|
133                                  CLK_PWRMGT_CNTL_M6__DISP_DYN_STOP_LAT_MASK|
134                                  CLK_PWRMGT_CNTL_M6__DYN_STOP_MODE_MASK);
135         /* Mode 1 */
136         clk_pwrmgt_cntl =       CLK_PWRMGT_CNTL_M6__MC_CH_MODE|
137                                 CLK_PWRMGT_CNTL_M6__ENGINE_DYNCLK_MODE | 
138                                 (1<<CLK_PWRMGT_CNTL_M6__ACTIVE_HILO_LAT__SHIFT) |
139                                 (0<<CLK_PWRMGT_CNTL_M6__DISP_DYN_STOP_LAT__SHIFT)|
140                                 (0<<CLK_PWRMGT_CNTL_M6__DYN_STOP_MODE__SHIFT);
141
142         OUTPLL( pllCLK_PWRMGT_CNTL_M6, clk_pwrmgt_cntl);
143                                                 
144
145         clk_pin_cntl = INPLL( pllCLK_PIN_CNTL);
146         clk_pin_cntl |= CLK_PIN_CNTL__SCLK_DYN_START_CNTL;
147          
148         OUTPLL( pllCLK_PIN_CNTL, clk_pin_cntl);
149
150         /* Enable Dyanmic mode for SCLK */
151
152         sclk_cntl = INPLL( pllSCLK_CNTL_M6);    
153         sclk_cntl &= SCLK_CNTL_M6__SCLK_SRC_SEL_MASK;
154         sclk_cntl |= SCLK_CNTL_M6__FORCE_VIP;           
155
156         OUTPLL( pllSCLK_CNTL_M6, sclk_cntl);
157
158
159         sclk_more_cntl = INPLL(pllSCLK_MORE_CNTL);
160         sclk_more_cntl &= ~(SCLK_MORE_CNTL__FORCE_DISPREGS);
161                                                     
162         OUTPLL(pllSCLK_MORE_CNTL, sclk_more_cntl);
163
164         
165         /* Enable Dynamic mode for PIXCLK & PIX2CLK */
166
167         pixclks_cntl = INPLL( pllPIXCLKS_CNTL);
168         
169         pixclks_cntl|=  PIXCLKS_CNTL__PIX2CLK_ALWAYS_ONb | 
170                         PIXCLKS_CNTL__PIX2CLK_DAC_ALWAYS_ONb|
171                         PIXCLKS_CNTL__PIXCLK_BLEND_ALWAYS_ONb|
172                         PIXCLKS_CNTL__PIXCLK_GV_ALWAYS_ONb|
173                         PIXCLKS_CNTL__PIXCLK_DIG_TMDS_ALWAYS_ONb|
174                         PIXCLKS_CNTL__PIXCLK_LVDS_ALWAYS_ONb|
175                         PIXCLKS_CNTL__PIXCLK_TMDS_ALWAYS_ONb;
176
177         OUTPLL( pllPIXCLKS_CNTL, pixclks_cntl);
178                 
179                 
180         vclk_ecp_cntl = INPLL( pllVCLK_ECP_CNTL);
181         
182         vclk_ecp_cntl|=  VCLK_ECP_CNTL__PIXCLK_ALWAYS_ONb | 
183                          VCLK_ECP_CNTL__PIXCLK_DAC_ALWAYS_ONb;
184
185         OUTPLL( pllVCLK_ECP_CNTL, vclk_ecp_cntl);
186
187
188         /* Enable Dynamic mode for MCLK */
189
190         mclk_cntl  = INPLL( pllMCLK_CNTL_M6);
191         mclk_cntl |=    MCLK_CNTL_M6__FORCE_MCLKA|  
192                         MCLK_CNTL_M6__FORCE_MCLKB|      
193                         MCLK_CNTL_M6__FORCE_YCLKA|
194                         MCLK_CNTL_M6__FORCE_YCLKB;
195                         
196         OUTPLL( pllMCLK_CNTL_M6, mclk_cntl);
197
198         mclk_misc = INPLL(pllMCLK_MISC);
199         mclk_misc |=    MCLK_MISC__MC_MCLK_MAX_DYN_STOP_LAT|
200                         MCLK_MISC__IO_MCLK_MAX_DYN_STOP_LAT|
201                         MCLK_MISC__MC_MCLK_DYN_ENABLE|
202                         MCLK_MISC__IO_MCLK_DYN_ENABLE;  
203         
204         OUTPLL(pllMCLK_MISC, mclk_misc);
205 }
206
207 #ifdef CONFIG_PM
208
209 static void OUTMC( struct radeonfb_info *rinfo, u8 indx, u32 value)
210 {
211         OUTREG( MC_IND_INDEX, indx | MC_IND_INDEX__MC_IND_WR_EN);       
212         OUTREG( MC_IND_DATA, value);            
213 }
214
215 static u32 INMC(struct radeonfb_info *rinfo, u8 indx)
216 {
217         OUTREG( MC_IND_INDEX, indx);                                    
218         return INREG( MC_IND_DATA);
219 }
220
221 static void radeon_pm_save_regs(struct radeonfb_info *rinfo)
222 {
223         rinfo->save_regs[0] = INPLL(PLL_PWRMGT_CNTL);
224         rinfo->save_regs[1] = INPLL(CLK_PWRMGT_CNTL);
225         rinfo->save_regs[2] = INPLL(MCLK_CNTL);
226         rinfo->save_regs[3] = INPLL(SCLK_CNTL);
227         rinfo->save_regs[4] = INPLL(CLK_PIN_CNTL);
228         rinfo->save_regs[5] = INPLL(VCLK_ECP_CNTL);
229         rinfo->save_regs[6] = INPLL(PIXCLKS_CNTL);
230         rinfo->save_regs[7] = INPLL(MCLK_MISC);
231         rinfo->save_regs[8] = INPLL(P2PLL_CNTL);
232         
233         rinfo->save_regs[9] = INREG(DISP_MISC_CNTL);
234         rinfo->save_regs[10] = INREG(DISP_PWR_MAN);
235         rinfo->save_regs[11] = INREG(LVDS_GEN_CNTL);
236         rinfo->save_regs[12] = INREG(LVDS_PLL_CNTL);
237         rinfo->save_regs[13] = INREG(TV_DAC_CNTL);
238         rinfo->save_regs[14] = INREG(BUS_CNTL1);
239         rinfo->save_regs[15] = INREG(CRTC_OFFSET_CNTL);
240         rinfo->save_regs[16] = INREG(AGP_CNTL);
241         rinfo->save_regs[17] = (INREG(CRTC_GEN_CNTL) & 0xfdffffff) | 0x04000000;
242         rinfo->save_regs[18] = (INREG(CRTC2_GEN_CNTL) & 0xfdffffff) | 0x04000000;
243         rinfo->save_regs[19] = INREG(GPIOPAD_A);
244         rinfo->save_regs[20] = INREG(GPIOPAD_EN);
245         rinfo->save_regs[21] = INREG(GPIOPAD_MASK);
246         rinfo->save_regs[22] = INREG(ZV_LCDPAD_A);
247         rinfo->save_regs[23] = INREG(ZV_LCDPAD_EN);
248         rinfo->save_regs[24] = INREG(ZV_LCDPAD_MASK);
249         rinfo->save_regs[25] = INREG(GPIO_VGA_DDC);
250         rinfo->save_regs[26] = INREG(GPIO_DVI_DDC);
251         rinfo->save_regs[27] = INREG(GPIO_MONID);
252         rinfo->save_regs[28] = INREG(GPIO_CRT2_DDC);
253
254         rinfo->save_regs[29] = INREG(SURFACE_CNTL);
255         rinfo->save_regs[30] = INREG(MC_FB_LOCATION);
256         rinfo->save_regs[31] = INREG(DISPLAY_BASE_ADDR);
257         rinfo->save_regs[32] = INREG(MC_AGP_LOCATION);
258         rinfo->save_regs[33] = INREG(CRTC2_DISPLAY_BASE_ADDR);
259 }
260
261 static void radeon_pm_restore_regs(struct radeonfb_info *rinfo)
262 {
263         OUTPLL(P2PLL_CNTL, rinfo->save_regs[8] & 0xFFFFFFFE); /* First */
264         
265         OUTPLL(PLL_PWRMGT_CNTL, rinfo->save_regs[0]);
266         OUTPLL(CLK_PWRMGT_CNTL, rinfo->save_regs[1]);
267         OUTPLL(MCLK_CNTL, rinfo->save_regs[2]);
268         OUTPLL(SCLK_CNTL, rinfo->save_regs[3]);
269         OUTPLL(CLK_PIN_CNTL, rinfo->save_regs[4]);
270         OUTPLL(VCLK_ECP_CNTL, rinfo->save_regs[5]);
271         OUTPLL(PIXCLKS_CNTL, rinfo->save_regs[6]);
272         OUTPLL(MCLK_MISC, rinfo->save_regs[7]);
273         
274         OUTREG(SURFACE_CNTL, rinfo->save_regs[29]);
275         OUTREG(MC_FB_LOCATION, rinfo->save_regs[30]);
276         OUTREG(DISPLAY_BASE_ADDR, rinfo->save_regs[31]);
277         OUTREG(MC_AGP_LOCATION, rinfo->save_regs[32]);
278         OUTREG(CRTC2_DISPLAY_BASE_ADDR, rinfo->save_regs[33]);
279
280         OUTREG(DISP_MISC_CNTL, rinfo->save_regs[9]);
281         OUTREG(DISP_PWR_MAN, rinfo->save_regs[10]);
282         OUTREG(LVDS_GEN_CNTL, rinfo->save_regs[11]);
283         OUTREG(LVDS_PLL_CNTL,rinfo->save_regs[12]);
284         OUTREG(TV_DAC_CNTL, rinfo->save_regs[13]);
285         OUTREG(BUS_CNTL1, rinfo->save_regs[14]);
286         OUTREG(CRTC_OFFSET_CNTL, rinfo->save_regs[15]);
287         OUTREG(AGP_CNTL, rinfo->save_regs[16]);
288         OUTREG(CRTC_GEN_CNTL, rinfo->save_regs[17]);
289         OUTREG(CRTC2_GEN_CNTL, rinfo->save_regs[18]);
290
291         // wait VBL before that one  ?
292         OUTPLL(P2PLL_CNTL, rinfo->save_regs[8]);
293         
294         OUTREG(GPIOPAD_A, rinfo->save_regs[19]);
295         OUTREG(GPIOPAD_EN, rinfo->save_regs[20]);
296         OUTREG(GPIOPAD_MASK, rinfo->save_regs[21]);
297         OUTREG(ZV_LCDPAD_A, rinfo->save_regs[22]);
298         OUTREG(ZV_LCDPAD_EN, rinfo->save_regs[23]);
299         OUTREG(ZV_LCDPAD_MASK, rinfo->save_regs[24]);
300         OUTREG(GPIO_VGA_DDC, rinfo->save_regs[25]);
301         OUTREG(GPIO_DVI_DDC, rinfo->save_regs[26]);
302         OUTREG(GPIO_MONID, rinfo->save_regs[27]);
303         OUTREG(GPIO_CRT2_DDC, rinfo->save_regs[28]);
304 }
305
306 static void radeon_pm_disable_iopad(struct radeonfb_info *rinfo)
307 {               
308         OUTREG(GPIOPAD_MASK, 0x0001ffff);
309         OUTREG(GPIOPAD_EN, 0x00000400);
310         OUTREG(GPIOPAD_A, 0x00000000);          
311         OUTREG(ZV_LCDPAD_MASK, 0x00000000);
312         OUTREG(ZV_LCDPAD_EN, 0x00000000);
313         OUTREG(ZV_LCDPAD_A, 0x00000000);        
314         OUTREG(GPIO_VGA_DDC, 0x00030000);
315         OUTREG(GPIO_DVI_DDC, 0x00000000);
316         OUTREG(GPIO_MONID, 0x00030000);
317         OUTREG(GPIO_CRT2_DDC, 0x00000000);
318 }
319
320 static void radeon_pm_program_v2clk(struct radeonfb_info *rinfo)
321 {
322         /* we use __INPLL and _OUTPLL and do the locking ourselves... */
323         unsigned long flags;
324         spin_lock_irqsave(&rinfo->reg_lock, flags);
325         /* Set v2clk to 65MHz */
326         __OUTPLL(pllPIXCLKS_CNTL,
327                 __INPLL(rinfo, pllPIXCLKS_CNTL) & ~PIXCLKS_CNTL__PIX2CLK_SRC_SEL_MASK);
328          
329         __OUTPLL(pllP2PLL_REF_DIV, 0x0000000c);
330         __OUTPLL(pllP2PLL_CNTL, 0x0000bf00);
331         __OUTPLL(pllP2PLL_DIV_0, 0x00020074 | P2PLL_DIV_0__P2PLL_ATOMIC_UPDATE_W);
332         
333         __OUTPLL(pllP2PLL_CNTL,
334                 __INPLL(rinfo, pllP2PLL_CNTL) & ~P2PLL_CNTL__P2PLL_SLEEP);
335         mdelay(1);
336
337         __OUTPLL(pllP2PLL_CNTL,
338                 __INPLL(rinfo, pllP2PLL_CNTL) & ~P2PLL_CNTL__P2PLL_RESET);
339         mdelay( 1);
340
341         __OUTPLL(pllPIXCLKS_CNTL,
342                 (__INPLL(rinfo, pllPIXCLKS_CNTL) & ~PIXCLKS_CNTL__PIX2CLK_SRC_SEL_MASK)
343                 | (0x03 << PIXCLKS_CNTL__PIX2CLK_SRC_SEL__SHIFT));
344         mdelay( 1);     
345         spin_unlock_irqrestore(&rinfo->reg_lock, flags);
346 }
347
348 static void radeon_pm_low_current(struct radeonfb_info *rinfo)
349 {
350         u32 reg;
351
352         reg  = INREG(BUS_CNTL1);
353         reg &= ~BUS_CNTL1_MOBILE_PLATFORM_SEL_MASK;
354         reg |= BUS_CNTL1_AGPCLK_VALID | (1<<BUS_CNTL1_MOBILE_PLATFORM_SEL_SHIFT);
355         OUTREG(BUS_CNTL1, reg);
356         
357         reg  = INPLL(PLL_PWRMGT_CNTL);
358         reg |= PLL_PWRMGT_CNTL_SPLL_TURNOFF | PLL_PWRMGT_CNTL_PPLL_TURNOFF |
359                 PLL_PWRMGT_CNTL_P2PLL_TURNOFF | PLL_PWRMGT_CNTL_TVPLL_TURNOFF;
360         reg &= ~PLL_PWRMGT_CNTL_SU_MCLK_USE_BCLK;
361         reg &= ~PLL_PWRMGT_CNTL_MOBILE_SU;
362         OUTPLL(PLL_PWRMGT_CNTL, reg);
363         
364         reg  = INREG(TV_DAC_CNTL);
365         reg &= ~(TV_DAC_CNTL_BGADJ_MASK |TV_DAC_CNTL_DACADJ_MASK);
366         reg |=TV_DAC_CNTL_BGSLEEP | TV_DAC_CNTL_RDACPD | TV_DAC_CNTL_GDACPD |
367                 TV_DAC_CNTL_BDACPD |
368                 (8<<TV_DAC_CNTL_BGADJ__SHIFT) | (8<<TV_DAC_CNTL_DACADJ__SHIFT);
369         OUTREG(TV_DAC_CNTL, reg);
370         
371         reg  = INREG(TMDS_TRANSMITTER_CNTL);
372         reg &= ~(TMDS_PLL_EN | TMDS_PLLRST);
373         OUTREG(TMDS_TRANSMITTER_CNTL, reg);
374
375         reg = INREG(DAC_CNTL);
376         reg &= ~DAC_CMP_EN;
377         OUTREG(DAC_CNTL, reg);
378
379         reg = INREG(DAC_CNTL2);
380         reg &= ~DAC2_CMP_EN;
381         OUTREG(DAC_CNTL2, reg);
382         
383         reg  = INREG(TV_DAC_CNTL);
384         reg &= ~TV_DAC_CNTL_DETECT;
385         OUTREG(TV_DAC_CNTL, reg);
386 }
387
388 static void radeon_pm_setup_for_suspend(struct radeonfb_info *rinfo)
389 {
390
391         u32 sclk_cntl, mclk_cntl, sclk_more_cntl;
392
393         u32 pll_pwrmgt_cntl;
394         u32 clk_pwrmgt_cntl;
395         u32 clk_pin_cntl;
396         u32 vclk_ecp_cntl; 
397         u32 pixclks_cntl;
398         u32 disp_mis_cntl;
399         u32 disp_pwr_man;
400         u32 tmp;
401         
402         /* Force Core Clocks */
403         sclk_cntl = INPLL( pllSCLK_CNTL_M6);
404         sclk_cntl |=    SCLK_CNTL_M6__IDCT_MAX_DYN_STOP_LAT|
405                         SCLK_CNTL_M6__VIP_MAX_DYN_STOP_LAT|
406                         SCLK_CNTL_M6__RE_MAX_DYN_STOP_LAT|
407                         SCLK_CNTL_M6__PB_MAX_DYN_STOP_LAT|
408                         SCLK_CNTL_M6__TAM_MAX_DYN_STOP_LAT|
409                         SCLK_CNTL_M6__TDM_MAX_DYN_STOP_LAT|
410                         SCLK_CNTL_M6__RB_MAX_DYN_STOP_LAT|
411                         
412                         SCLK_CNTL_M6__FORCE_DISP2|
413                         SCLK_CNTL_M6__FORCE_CP|
414                         SCLK_CNTL_M6__FORCE_HDP|
415                         SCLK_CNTL_M6__FORCE_DISP1|
416                         SCLK_CNTL_M6__FORCE_TOP|
417                         SCLK_CNTL_M6__FORCE_E2|
418                         SCLK_CNTL_M6__FORCE_SE|
419                         SCLK_CNTL_M6__FORCE_IDCT|
420                         SCLK_CNTL_M6__FORCE_VIP|
421                         
422                         SCLK_CNTL_M6__FORCE_RE|
423                         SCLK_CNTL_M6__FORCE_PB|
424                         SCLK_CNTL_M6__FORCE_TAM|
425                         SCLK_CNTL_M6__FORCE_TDM|
426                         SCLK_CNTL_M6__FORCE_RB|
427                         SCLK_CNTL_M6__FORCE_TV_SCLK|
428                         SCLK_CNTL_M6__FORCE_SUBPIC|
429                         SCLK_CNTL_M6__FORCE_OV0;
430
431         OUTPLL( pllSCLK_CNTL_M6, sclk_cntl);
432
433         sclk_more_cntl = INPLL(pllSCLK_MORE_CNTL);
434         sclk_more_cntl |=       SCLK_MORE_CNTL__FORCE_DISPREGS |
435                                 SCLK_MORE_CNTL__FORCE_MC_GUI |
436                                 SCLK_MORE_CNTL__FORCE_MC_HOST;
437
438         OUTPLL(pllSCLK_MORE_CNTL, sclk_more_cntl);              
439
440         
441         mclk_cntl = INPLL( pllMCLK_CNTL_M6);
442         mclk_cntl &= ~( MCLK_CNTL_M6__FORCE_MCLKA |  
443                         MCLK_CNTL_M6__FORCE_MCLKB |
444                         MCLK_CNTL_M6__FORCE_YCLKA | 
445                         MCLK_CNTL_M6__FORCE_YCLKB | 
446                         MCLK_CNTL_M6__FORCE_MC
447                       );        
448         OUTPLL( pllMCLK_CNTL_M6, mclk_cntl);
449         
450         /* Force Display clocks */
451         vclk_ecp_cntl = INPLL( pllVCLK_ECP_CNTL);
452         vclk_ecp_cntl &= ~(VCLK_ECP_CNTL__PIXCLK_ALWAYS_ONb |VCLK_ECP_CNTL__PIXCLK_DAC_ALWAYS_ONb);
453         vclk_ecp_cntl |= VCLK_ECP_CNTL__ECP_FORCE_ON;
454         OUTPLL( pllVCLK_ECP_CNTL, vclk_ecp_cntl);
455         
456         
457         pixclks_cntl = INPLL( pllPIXCLKS_CNTL);
458         pixclks_cntl &= ~(      PIXCLKS_CNTL__PIXCLK_GV_ALWAYS_ONb | 
459                                 PIXCLKS_CNTL__PIXCLK_BLEND_ALWAYS_ONb|
460                                 PIXCLKS_CNTL__PIXCLK_DIG_TMDS_ALWAYS_ONb |
461                                 PIXCLKS_CNTL__PIXCLK_LVDS_ALWAYS_ONb|
462                                 PIXCLKS_CNTL__PIXCLK_TMDS_ALWAYS_ONb|
463                                 PIXCLKS_CNTL__PIX2CLK_ALWAYS_ONb|
464                                 PIXCLKS_CNTL__PIX2CLK_DAC_ALWAYS_ONb);
465                                                 
466         OUTPLL( pllPIXCLKS_CNTL, pixclks_cntl);
467
468         /* Switch off LVDS interface */
469         OUTREG(LVDS_GEN_CNTL, INREG(LVDS_GEN_CNTL) &
470                ~(LVDS_BLON | LVDS_EN | LVDS_ON | LVDS_DIGON));
471
472         /* Enable System power management */
473         pll_pwrmgt_cntl = INPLL( pllPLL_PWRMGT_CNTL);
474         
475         pll_pwrmgt_cntl |=      PLL_PWRMGT_CNTL__SPLL_TURNOFF |
476                                 PLL_PWRMGT_CNTL__MPLL_TURNOFF|
477                                 PLL_PWRMGT_CNTL__PPLL_TURNOFF|
478                                 PLL_PWRMGT_CNTL__P2PLL_TURNOFF|
479                                 PLL_PWRMGT_CNTL__TVPLL_TURNOFF;
480                                                 
481         OUTPLL( pllPLL_PWRMGT_CNTL, pll_pwrmgt_cntl);
482         
483         clk_pwrmgt_cntl  = INPLL( pllCLK_PWRMGT_CNTL_M6);
484         
485         clk_pwrmgt_cntl &= ~(   CLK_PWRMGT_CNTL_M6__MPLL_PWRMGT_OFF|
486                                 CLK_PWRMGT_CNTL_M6__SPLL_PWRMGT_OFF|
487                                 CLK_PWRMGT_CNTL_M6__PPLL_PWRMGT_OFF|
488                                 CLK_PWRMGT_CNTL_M6__P2PLL_PWRMGT_OFF|
489                                 CLK_PWRMGT_CNTL_M6__MCLK_TURNOFF|
490                                 CLK_PWRMGT_CNTL_M6__SCLK_TURNOFF|
491                                 CLK_PWRMGT_CNTL_M6__PCLK_TURNOFF|
492                                 CLK_PWRMGT_CNTL_M6__P2CLK_TURNOFF|
493                                 CLK_PWRMGT_CNTL_M6__TVPLL_PWRMGT_OFF|
494                                 CLK_PWRMGT_CNTL_M6__GLOBAL_PMAN_EN|
495                                 CLK_PWRMGT_CNTL_M6__ENGINE_DYNCLK_MODE|
496                                 CLK_PWRMGT_CNTL_M6__ACTIVE_HILO_LAT_MASK|
497                                 CLK_PWRMGT_CNTL_M6__CG_NO1_DEBUG_MASK                   
498                         );
499                                                 
500         clk_pwrmgt_cntl |= CLK_PWRMGT_CNTL_M6__GLOBAL_PMAN_EN | CLK_PWRMGT_CNTL_M6__DISP_PM;
501         
502         OUTPLL( pllCLK_PWRMGT_CNTL_M6, clk_pwrmgt_cntl);        
503         
504         clk_pin_cntl = INPLL( pllCLK_PIN_CNTL);
505         
506         clk_pin_cntl &= ~CLK_PIN_CNTL__ACCESS_REGS_IN_SUSPEND;
507
508         /* because both INPLL and OUTPLL take the same lock, that's why. */
509         tmp = INPLL( pllMCLK_MISC) | MCLK_MISC__EN_MCLK_TRISTATE_IN_SUSPEND;
510         OUTPLL( pllMCLK_MISC, tmp);
511         
512         /* AGP PLL control */
513         OUTREG(BUS_CNTL1, INREG(BUS_CNTL1) |  BUS_CNTL1__AGPCLK_VALID);
514
515         OUTREG(BUS_CNTL1,
516                 (INREG(BUS_CNTL1) & ~BUS_CNTL1__MOBILE_PLATFORM_SEL_MASK)
517                 | (2<<BUS_CNTL1__MOBILE_PLATFORM_SEL__SHIFT));  // 440BX
518         OUTREG(CRTC_OFFSET_CNTL, (INREG(CRTC_OFFSET_CNTL) & ~CRTC_OFFSET_CNTL__CRTC_STEREO_SYNC_OUT_EN));
519         
520         clk_pin_cntl &= ~CLK_PIN_CNTL__CG_CLK_TO_OUTPIN;
521         clk_pin_cntl |= CLK_PIN_CNTL__XTALIN_ALWAYS_ONb;        
522         OUTPLL( pllCLK_PIN_CNTL, clk_pin_cntl);
523
524         /* Solano2M */
525         OUTREG(AGP_CNTL,
526                 (INREG(AGP_CNTL) & ~(AGP_CNTL__MAX_IDLE_CLK_MASK))
527                 | (0x20<<AGP_CNTL__MAX_IDLE_CLK__SHIFT));
528
529         /* ACPI mode */
530         /* because both INPLL and OUTPLL take the same lock, that's why. */
531         tmp = INPLL( pllPLL_PWRMGT_CNTL) & ~PLL_PWRMGT_CNTL__PM_MODE_SEL;
532         OUTPLL( pllPLL_PWRMGT_CNTL, tmp);
533
534
535         disp_mis_cntl = INREG(DISP_MISC_CNTL);
536         
537         disp_mis_cntl &= ~(     DISP_MISC_CNTL__SOFT_RESET_GRPH_PP | 
538                                 DISP_MISC_CNTL__SOFT_RESET_SUBPIC_PP | 
539                                 DISP_MISC_CNTL__SOFT_RESET_OV0_PP |
540                                 DISP_MISC_CNTL__SOFT_RESET_GRPH_SCLK|
541                                 DISP_MISC_CNTL__SOFT_RESET_SUBPIC_SCLK|
542                                 DISP_MISC_CNTL__SOFT_RESET_OV0_SCLK|
543                                 DISP_MISC_CNTL__SOFT_RESET_GRPH2_PP|
544                                 DISP_MISC_CNTL__SOFT_RESET_GRPH2_SCLK|
545                                 DISP_MISC_CNTL__SOFT_RESET_LVDS|
546                                 DISP_MISC_CNTL__SOFT_RESET_TMDS|
547                                 DISP_MISC_CNTL__SOFT_RESET_DIG_TMDS|
548                                 DISP_MISC_CNTL__SOFT_RESET_TV);
549         
550         OUTREG(DISP_MISC_CNTL, disp_mis_cntl);                                  
551                                                 
552         disp_pwr_man = INREG(DISP_PWR_MAN);
553         
554         disp_pwr_man &= ~(      DISP_PWR_MAN__DISP_PWR_MAN_D3_CRTC_EN   | 
555                                                 DISP_PWR_MAN__DISP2_PWR_MAN_D3_CRTC2_EN |
556                                                 DISP_PWR_MAN__DISP_PWR_MAN_DPMS_MASK|           
557                                                 DISP_PWR_MAN__DISP_D3_RST|
558                                                 DISP_PWR_MAN__DISP_D3_REG_RST
559                                         );
560         
561         disp_pwr_man |= DISP_PWR_MAN__DISP_D3_GRPH_RST|
562                                         DISP_PWR_MAN__DISP_D3_SUBPIC_RST|
563                                         DISP_PWR_MAN__DISP_D3_OV0_RST|
564                                         DISP_PWR_MAN__DISP_D1D2_GRPH_RST|
565                                         DISP_PWR_MAN__DISP_D1D2_SUBPIC_RST|
566                                         DISP_PWR_MAN__DISP_D1D2_OV0_RST|
567                                         DISP_PWR_MAN__DIG_TMDS_ENABLE_RST|
568                                         DISP_PWR_MAN__TV_ENABLE_RST| 
569 //                                      DISP_PWR_MAN__AUTO_PWRUP_EN|
570                                         0;
571         
572         OUTREG(DISP_PWR_MAN, disp_pwr_man);                                     
573                                                         
574         clk_pwrmgt_cntl = INPLL( pllCLK_PWRMGT_CNTL_M6);
575         pll_pwrmgt_cntl = INPLL( pllPLL_PWRMGT_CNTL) ;
576         clk_pin_cntl    = INPLL( pllCLK_PIN_CNTL);
577         disp_pwr_man    = INREG(DISP_PWR_MAN);
578                 
579         
580         /* D2 */
581         clk_pwrmgt_cntl |= CLK_PWRMGT_CNTL_M6__DISP_PM;
582         pll_pwrmgt_cntl |= PLL_PWRMGT_CNTL__MOBILE_SU | PLL_PWRMGT_CNTL__SU_SCLK_USE_BCLK;
583         clk_pin_cntl    |= CLK_PIN_CNTL__XTALIN_ALWAYS_ONb;
584         disp_pwr_man    &= ~(DISP_PWR_MAN__DISP_PWR_MAN_D3_CRTC_EN_MASK | DISP_PWR_MAN__DISP2_PWR_MAN_D3_CRTC2_EN_MASK);                                                        
585                                                 
586
587         OUTPLL( pllCLK_PWRMGT_CNTL_M6, clk_pwrmgt_cntl);
588         OUTPLL( pllPLL_PWRMGT_CNTL, pll_pwrmgt_cntl);
589         OUTPLL( pllCLK_PIN_CNTL, clk_pin_cntl);
590         OUTREG(DISP_PWR_MAN, disp_pwr_man);
591
592         /* disable display request & disable display */
593         OUTREG( CRTC_GEN_CNTL, (INREG( CRTC_GEN_CNTL) & ~CRTC_GEN_CNTL__CRTC_EN) | CRTC_GEN_CNTL__CRTC_DISP_REQ_EN_B);
594         OUTREG( CRTC2_GEN_CNTL, (INREG( CRTC2_GEN_CNTL) & ~CRTC2_GEN_CNTL__CRTC2_EN) | CRTC2_GEN_CNTL__CRTC2_DISP_REQ_EN_B);
595
596         mdelay(17);                                
597
598 }
599
600 static void radeon_pm_yclk_mclk_sync(struct radeonfb_info *rinfo)
601 {
602         u32 mc_chp_io_cntl_a1, mc_chp_io_cntl_b1;
603
604         mc_chp_io_cntl_a1 = INMC( rinfo, ixMC_CHP_IO_CNTL_A1) & ~MC_CHP_IO_CNTL_A1__MEM_SYNC_ENA_MASK;
605         mc_chp_io_cntl_b1 = INMC( rinfo, ixMC_CHP_IO_CNTL_B1) & ~MC_CHP_IO_CNTL_B1__MEM_SYNC_ENB_MASK;
606
607         OUTMC( rinfo, ixMC_CHP_IO_CNTL_A1, mc_chp_io_cntl_a1 | (1<<MC_CHP_IO_CNTL_A1__MEM_SYNC_ENA__SHIFT));
608         OUTMC( rinfo, ixMC_CHP_IO_CNTL_B1, mc_chp_io_cntl_b1 | (1<<MC_CHP_IO_CNTL_B1__MEM_SYNC_ENB__SHIFT));
609
610         /* Wassup ? This doesn't seem to be defined, let's hope we are ok this way --BenH */
611 #ifdef MCLK_YCLK_SYNC_ENABLE
612         mc_chp_io_cntl_a1 |= (2<<MC_CHP_IO_CNTL_A1__MEM_SYNC_ENA__SHIFT);
613         mc_chp_io_cntl_b1 |= (2<<MC_CHP_IO_CNTL_B1__MEM_SYNC_ENB__SHIFT);
614 #endif
615
616         OUTMC( rinfo, ixMC_CHP_IO_CNTL_A1, mc_chp_io_cntl_a1);
617         OUTMC( rinfo, ixMC_CHP_IO_CNTL_B1, mc_chp_io_cntl_b1);
618
619         mdelay( 1);
620 }
621
622 static void radeon_pm_program_mode_reg(struct radeonfb_info *rinfo, u16 value, u8 delay_required)
623 {  
624         u32 mem_sdram_mode;
625
626         mem_sdram_mode  = INREG( MEM_SDRAM_MODE_REG);
627
628         mem_sdram_mode &= ~MEM_SDRAM_MODE_REG__MEM_MODE_REG_MASK;
629         mem_sdram_mode |= (value<<MEM_SDRAM_MODE_REG__MEM_MODE_REG__SHIFT) | MEM_SDRAM_MODE_REG__MEM_CFG_TYPE;
630         OUTREG( MEM_SDRAM_MODE_REG, mem_sdram_mode);
631
632         mem_sdram_mode |=  MEM_SDRAM_MODE_REG__MEM_SDRAM_RESET;
633         OUTREG( MEM_SDRAM_MODE_REG, mem_sdram_mode);
634
635         mem_sdram_mode &= ~MEM_SDRAM_MODE_REG__MEM_SDRAM_RESET;
636         OUTREG( MEM_SDRAM_MODE_REG, mem_sdram_mode);
637
638         if (delay_required == 1)
639                 while( (INREG( MC_STATUS) & (MC_STATUS__MEM_PWRUP_COMPL_A | MC_STATUS__MEM_PWRUP_COMPL_B) ) == 0 )
640                         { };    
641 }
642
643
644 static void radeon_pm_enable_dll(struct radeonfb_info *rinfo)
645 {  
646 #define DLL_RESET_DELAY         5
647 #define DLL_SLEEP_DELAY         1
648
649         u32 DLL_CKO_Value = INPLL(pllMDLL_CKO)   | MDLL_CKO__MCKOA_SLEEP |  MDLL_CKO__MCKOA_RESET;
650         u32 DLL_CKA_Value = INPLL(pllMDLL_RDCKA) | MDLL_RDCKA__MRDCKA0_SLEEP | MDLL_RDCKA__MRDCKA1_SLEEP | MDLL_RDCKA__MRDCKA0_RESET | MDLL_RDCKA__MRDCKA1_RESET;
651         u32 DLL_CKB_Value = INPLL(pllMDLL_RDCKB) | MDLL_RDCKB__MRDCKB0_SLEEP | MDLL_RDCKB__MRDCKB1_SLEEP | MDLL_RDCKB__MRDCKB0_RESET | MDLL_RDCKB__MRDCKB1_RESET;
652
653         /* Setting up the DLL range for write */
654         OUTPLL(pllMDLL_CKO,     DLL_CKO_Value);
655         OUTPLL(pllMDLL_RDCKA,   DLL_CKA_Value);
656         OUTPLL(pllMDLL_RDCKB,   DLL_CKB_Value);
657
658         mdelay( DLL_RESET_DELAY);
659
660         /* Channel A */
661
662         /* Power Up */
663         DLL_CKO_Value &= ~(MDLL_CKO__MCKOA_SLEEP );
664         OUTPLL(pllMDLL_CKO,     DLL_CKO_Value);
665         mdelay( DLL_SLEEP_DELAY);               
666    
667         DLL_CKO_Value &= ~(MDLL_CKO__MCKOA_RESET );
668         OUTPLL(pllMDLL_CKO,     DLL_CKO_Value);
669         mdelay( DLL_RESET_DELAY);               
670
671         /* Power Up */
672         DLL_CKA_Value &= ~(MDLL_RDCKA__MRDCKA0_SLEEP );
673         OUTPLL(pllMDLL_RDCKA,   DLL_CKA_Value);
674         mdelay( DLL_SLEEP_DELAY);               
675
676         DLL_CKA_Value &= ~(MDLL_RDCKA__MRDCKA0_RESET );
677         OUTPLL(pllMDLL_RDCKA,   DLL_CKA_Value);
678         mdelay( DLL_RESET_DELAY);               
679
680         /* Power Up */
681         DLL_CKA_Value &= ~(MDLL_RDCKA__MRDCKA1_SLEEP);
682         OUTPLL(pllMDLL_RDCKA,   DLL_CKA_Value);
683         mdelay( DLL_SLEEP_DELAY);               
684
685         DLL_CKA_Value &= ~(MDLL_RDCKA__MRDCKA1_RESET);
686         OUTPLL(pllMDLL_RDCKA,   DLL_CKA_Value);
687         mdelay( DLL_RESET_DELAY);               
688
689
690         /* Channel B */
691
692         /* Power Up */
693         DLL_CKO_Value &= ~(MDLL_CKO__MCKOB_SLEEP );
694         OUTPLL(pllMDLL_CKO,     DLL_CKO_Value);
695         mdelay( DLL_SLEEP_DELAY);               
696    
697         DLL_CKO_Value &= ~(MDLL_CKO__MCKOB_RESET );
698         OUTPLL(pllMDLL_CKO,     DLL_CKO_Value);
699         mdelay( DLL_RESET_DELAY);               
700
701         /* Power Up */
702         DLL_CKB_Value &= ~(MDLL_RDCKB__MRDCKB0_SLEEP);
703         OUTPLL(pllMDLL_RDCKB,   DLL_CKB_Value);
704         mdelay( DLL_SLEEP_DELAY);               
705
706         DLL_CKB_Value &= ~(MDLL_RDCKB__MRDCKB0_RESET);
707         OUTPLL(pllMDLL_RDCKB,   DLL_CKB_Value);
708         mdelay( DLL_RESET_DELAY);               
709
710         /* Power Up */
711         DLL_CKB_Value &= ~(MDLL_RDCKB__MRDCKB1_SLEEP);
712         OUTPLL(pllMDLL_RDCKB,   DLL_CKB_Value);
713         mdelay( DLL_SLEEP_DELAY);               
714
715         DLL_CKB_Value &= ~(MDLL_RDCKB__MRDCKB1_RESET);
716         OUTPLL(pllMDLL_RDCKB,   DLL_CKB_Value);
717         mdelay( DLL_RESET_DELAY);               
718
719 #undef DLL_RESET_DELAY 
720 #undef DLL_SLEEP_DELAY
721 }
722
723 static void radeon_pm_full_reset_sdram(struct radeonfb_info *rinfo)
724 {
725         u32 crtcGenCntl, crtcGenCntl2, memRefreshCntl, crtc_more_cntl, fp_gen_cntl, fp2_gen_cntl;
726  
727         crtcGenCntl  = INREG( CRTC_GEN_CNTL);
728         crtcGenCntl2 = INREG( CRTC2_GEN_CNTL);
729
730         memRefreshCntl  = INREG( MEM_REFRESH_CNTL);
731         crtc_more_cntl  = INREG( CRTC_MORE_CNTL);
732         fp_gen_cntl     = INREG( FP_GEN_CNTL);
733         fp2_gen_cntl    = INREG( FP2_GEN_CNTL);
734  
735
736         OUTREG( CRTC_MORE_CNTL,         0);
737         OUTREG( FP_GEN_CNTL,    0);
738         OUTREG( FP2_GEN_CNTL,   0);
739  
740         OUTREG( CRTC_GEN_CNTL,  (crtcGenCntl | CRTC_GEN_CNTL__CRTC_DISP_REQ_EN_B) );
741         OUTREG( CRTC2_GEN_CNTL, (crtcGenCntl2 | CRTC2_GEN_CNTL__CRTC2_DISP_REQ_EN_B) );
742   
743         /* Disable refresh */
744         OUTREG( MEM_REFRESH_CNTL, memRefreshCntl | MEM_REFRESH_CNTL__MEM_REFRESH_DIS);
745  
746         /* Reset memory */
747         OUTREG( MEM_SDRAM_MODE_REG,
748                 INREG( MEM_SDRAM_MODE_REG) & ~MEM_SDRAM_MODE_REG__MC_INIT_COMPLETE); // Init  Not Complete
749
750         /* DLL */
751         radeon_pm_enable_dll(rinfo);
752
753         // MLCK /YCLK sync 
754         radeon_pm_yclk_mclk_sync(rinfo);
755
756         /* M6, M7 and M9 so far ... */
757         if (rinfo->is_mobility && rinfo->family <= CHIP_FAMILY_RV250) {
758                 radeon_pm_program_mode_reg(rinfo, 0x2000, 1);   
759                 radeon_pm_program_mode_reg(rinfo, 0x2001, 1);   
760                 radeon_pm_program_mode_reg(rinfo, 0x2002, 1);   
761                 radeon_pm_program_mode_reg(rinfo, 0x0132, 1);   
762                 radeon_pm_program_mode_reg(rinfo, 0x0032, 1); 
763         }       
764
765         OUTREG( MEM_SDRAM_MODE_REG,
766                 INREG( MEM_SDRAM_MODE_REG) |  MEM_SDRAM_MODE_REG__MC_INIT_COMPLETE); // Init Complete
767
768         OUTREG( MEM_REFRESH_CNTL,       memRefreshCntl);
769
770         OUTREG( CRTC_GEN_CNTL,          crtcGenCntl);
771         OUTREG( CRTC2_GEN_CNTL,         crtcGenCntl2);
772         OUTREG( FP_GEN_CNTL,            fp_gen_cntl);
773         OUTREG( FP2_GEN_CNTL,           fp2_gen_cntl);
774
775         OUTREG( CRTC_MORE_CNTL,         crtc_more_cntl);
776
777         mdelay( 15);
778 }
779
780 static void radeon_set_suspend(struct radeonfb_info *rinfo, int suspend)
781 {
782         u16 pwr_cmd;
783         u32 tmp;
784
785         if (!rinfo->pm_reg)
786                 return;
787
788         /* Set the chip into appropriate suspend mode (we use D2,
789          * D3 would require a compete re-initialization of the chip,
790          * including PCI config registers, clocks, AGP conf, ...)
791          */
792         if (suspend) {
793                 printk(KERN_DEBUG "radeonfb: switching to D2 state...\n");
794
795                 /* Disable dynamic power management of clocks for the
796                  * duration of the suspend/resume process
797                  */
798                 radeon_pm_disable_dynamic_mode(rinfo);
799                 /* Save some registers */
800                 radeon_pm_save_regs(rinfo);
801
802                 /* Prepare mobility chips for suspend. Only do that on <= RV250 chips that
803                  * have been tested
804                  */
805                 if (rinfo->is_mobility && rinfo->family <= CHIP_FAMILY_RV250) {
806                         /* Program V2CLK */
807                         radeon_pm_program_v2clk(rinfo);
808                 
809                         /* Disable IO PADs */
810                         radeon_pm_disable_iopad(rinfo);
811
812                         /* Set low current */
813                         radeon_pm_low_current(rinfo);
814
815                         /* Prepare chip for power management */
816                         radeon_pm_setup_for_suspend(rinfo);
817
818                         /* Reset the MDLL */
819                         /* because both INPLL and OUTPLL take the same lock, that's why. */
820                         tmp = INPLL( pllMDLL_CKO) | MDLL_CKO__MCKOA_RESET | MDLL_CKO__MCKOB_RESET;
821                         OUTPLL( pllMDLL_CKO, tmp );
822                 }
823
824                 /* Switch PCI power managment to D2. */
825                 for (;;) {
826                         pci_read_config_word(
827                                 rinfo->pdev, rinfo->pm_reg+PCI_PM_CTRL,
828                                 &pwr_cmd);
829                         if (pwr_cmd & 2)
830                                 break;                  
831                         pci_write_config_word(
832                                 rinfo->pdev, rinfo->pm_reg+PCI_PM_CTRL,
833                                 (pwr_cmd & ~PCI_PM_CTRL_STATE_MASK) | 2);
834                         mdelay(500);
835                 }
836         } else {
837                 printk(KERN_DEBUG "radeonfb: switching to D0 state...\n");
838
839                 /* Switch back PCI powermanagment to D0 */
840                 mdelay(200);
841                 pci_write_config_word(rinfo->pdev, rinfo->pm_reg+PCI_PM_CTRL, 0);
842                 mdelay(500);
843
844                 /* Reset the SDRAM controller  */
845                 radeon_pm_full_reset_sdram(rinfo);
846                 
847                 /* Restore some registers */
848                 radeon_pm_restore_regs(rinfo);
849                 radeon_pm_enable_dynamic_mode(rinfo);
850         }
851 }
852
853 int radeonfb_pci_suspend(struct pci_dev *pdev, u32 state)
854 {
855         struct fb_info *info = pci_get_drvdata(pdev);
856         struct radeonfb_info *rinfo = info->par;
857
858         /* We don't do anything but D2, for now we return 0, but
859          * we may want to change that. How do we know if the BIOS
860          * can properly take care of D3 ? Also, with swsusp, we
861          * know we'll be rebooted, ...
862          */
863
864         printk(KERN_DEBUG "radeonfb: suspending to state: %d...\n", state);
865         
866         acquire_console_sem();
867
868         /* Userland should do this but doesn't... bridge gets suspended
869          * too late. Unfortunately, that works only when AGP is built-in,
870          * not for a module.
871          */
872 #ifdef CONFIG_AGP
873         agp_enable(0);
874 #endif
875
876         fb_set_suspend(info, 1);
877
878         if (!(info->flags & FBINFO_HWACCEL_DISABLED)) {
879                 /* Make sure engine is reset */
880                 radeon_engine_idle();
881                 radeonfb_engine_reset(rinfo);
882                 radeon_engine_idle();
883         }
884
885         /* Blank display and LCD */
886         radeonfb_blank(VESA_POWERDOWN, info);
887
888         /* Sleep */
889         rinfo->asleep = 1;
890         rinfo->lock_blank = 1;
891
892         /* Suspend the chip to D2 state when supported
893          */
894 #ifdef CONFIG_RADEON_HAS_D2
895         if (radeon_suspend_to_d2(rinfo, state))
896                 radeon_set_suspend(rinfo, 1);
897 #endif /* CONFIG_RADEON_HAS_D2 */
898
899         release_console_sem();
900
901         pdev->dev.power.power_state = state;
902
903         return 0;
904 }
905
906 int radeonfb_pci_resume(struct pci_dev *pdev)
907 {
908         struct fb_info *info = pci_get_drvdata(pdev);
909         struct radeonfb_info *rinfo = info->par;
910
911         if (pdev->dev.power.power_state == 0)
912                 return 0;
913
914         acquire_console_sem();
915
916         /* Wakeup chip */
917 #ifdef CONFIG_RADEON_HAS_D2
918         if (radeon_suspend_to_d2(rinfo, 0))
919                 radeon_set_suspend(rinfo, 0);
920 #endif /* CONFIG_RADEON_HAS_D2 */
921
922         rinfo->asleep = 0;
923
924         /* Restore display & engine */
925         radeonfb_set_par(info);
926         fb_pan_display(info, &info->var);
927         fb_set_cmap(&info->cmap, info);
928
929         /* Refresh */
930         fb_set_suspend(info, 0);
931
932         /* Unblank */
933         rinfo->lock_blank = 0;
934         radeonfb_blank(0, info);
935
936         release_console_sem();
937
938         pdev->dev.power.power_state = 0;
939
940         printk(KERN_DEBUG "radeonfb: resumed !\n");
941
942         return 0;
943 }
944
945 #endif /* CONFIG_PM */