vserver 1.9.5.x5
[linux-2.6.git] / drivers / video / aty / radeon_pm.c
index c26f43c..498dc4e 100644 (file)
+/*
+ *     drivers/video/aty/radeon_pm.c
+ *
+ *     Copyright 2003,2004 Ben. Herrenschmidt <benh@kernel.crashing.org>
+ *     Copyright 2004 Paul Mackerras <paulus@samba.org>
+ *
+ *     This is the power management code for ATI radeon chipsets. It contains
+ *     some dynamic clock PM enable/disable code similar to what X.org does,
+ *     some D2-state (APM-style) sleep/wakeup code for use on some PowerMacs,
+ *     and the necessary bits to re-initialize from scratch a few chips found
+ *     on PowerMacs as well. The later could be extended to more platforms
+ *     provided the memory controller configuration code be made more generic,
+ *     and you can get the proper mode register commands for your RAMs.
+ *     Those things may be found in the BIOS image...
+ */
+
 #include "radeonfb.h"
 
 #include <linux/console.h>
 #include <linux/agp_backend.h>
 
-/*
- * Currently, only PowerMac do D2 state
- */
-#define CONFIG_RADEON_HAS_D2   CONFIG_PPC_PMAC
-
-#ifdef CONFIG_RADEON_HAS_D2
-/*
- * On PowerMac, we assume any mobility chip based machine does D2
- */
 #ifdef CONFIG_PPC_PMAC
-static inline int radeon_suspend_to_d2(struct radeonfb_info *rinfo, u32 state)
-{
-       return rinfo->is_mobility;
-}
-#else
-static inline int radeon_suspend_to_d2(struct radeonfb_info *rinfo, u32 state)
-{
-       return 0;
-}
+#include <asm/processor.h>
+#include <asm/prom.h>
+#include <asm/pmac_feature.h>
 #endif
 
-#endif /* CONFIG_RADEON_HAS_D2 */
-
-/*
- * Radeon M6, M7 and M9 Power Management code. This code currently
- * only supports the mobile chips in D2 mode, that is typically what
- * is used on Apple laptops, it's based from some informations provided
- * by ATI along with hours of tracing of MacOS drivers.
- * 
- * New version of this code almost totally rewritten by ATI, many thanks
- * for their support.
- */
+#include "ati_ids.h"
 
 void radeon_pm_disable_dynamic_mode(struct radeonfb_info *rinfo)
 {
+       u32 tmp;
 
-       u32 sclk_cntl;
-       u32 mclk_cntl;
-       u32 sclk_more_cntl;
-       
-       u32 vclk_ecp_cntl;
-       u32 pixclks_cntl;
-
-       /* Mobility chips only, untested on M9+/M10/11 */
-       if (!rinfo->is_mobility)
+       /* RV100 */
+       if ((rinfo->family == CHIP_FAMILY_RV100) && (!rinfo->is_mobility)) {
+               if (rinfo->has_CRTC2) {
+                       tmp = INPLL(pllSCLK_CNTL);
+                       tmp &= ~SCLK_CNTL__DYN_STOP_LAT_MASK;
+                       tmp |= SCLK_CNTL__CP_MAX_DYN_STOP_LAT | SCLK_CNTL__FORCEON_MASK;
+                       OUTPLL(pllSCLK_CNTL, tmp);
+               }
+               tmp = INPLL(pllMCLK_CNTL);
+               tmp |= (MCLK_CNTL__FORCE_MCLKA |
+                       MCLK_CNTL__FORCE_MCLKB |
+                       MCLK_CNTL__FORCE_YCLKA |
+                       MCLK_CNTL__FORCE_YCLKB |
+                       MCLK_CNTL__FORCE_AIC |
+                       MCLK_CNTL__FORCE_MC);
+                OUTPLL(pllMCLK_CNTL, tmp);
+               return;
+       }
+       /* R100 */
+       if (!rinfo->has_CRTC2) {
+                tmp = INPLL(pllSCLK_CNTL);
+                tmp |= (SCLK_CNTL__FORCE_CP    | SCLK_CNTL__FORCE_HDP  |
+                       SCLK_CNTL__FORCE_DISP1  | SCLK_CNTL__FORCE_TOP  |
+                        SCLK_CNTL__FORCE_E2    | SCLK_CNTL__FORCE_SE   |
+                       SCLK_CNTL__FORCE_IDCT   | SCLK_CNTL__FORCE_VIP  |
+                       SCLK_CNTL__FORCE_RE     | SCLK_CNTL__FORCE_PB   |
+                       SCLK_CNTL__FORCE_TAM    | SCLK_CNTL__FORCE_TDM  |
+                        SCLK_CNTL__FORCE_RB);
+                OUTPLL(pllSCLK_CNTL, tmp);
                return;
-       if (rinfo->family > CHIP_FAMILY_RV250)
+       }
+       /* RV350 (M10) */
+       if (rinfo->family == CHIP_FAMILY_RV350) {
+                /* for RV350/M10, no delays are required. */
+                tmp = INPLL(pllSCLK_CNTL2);
+                tmp |= (SCLK_CNTL2__R300_FORCE_TCL |
+                        SCLK_CNTL2__R300_FORCE_GA  |
+                       SCLK_CNTL2__R300_FORCE_CBA);
+                OUTPLL(pllSCLK_CNTL2, tmp);
+
+                tmp = INPLL(pllSCLK_CNTL);
+                tmp |= (SCLK_CNTL__FORCE_DISP2         | SCLK_CNTL__FORCE_CP           |
+                        SCLK_CNTL__FORCE_HDP           | SCLK_CNTL__FORCE_DISP1        |
+                        SCLK_CNTL__FORCE_TOP           | SCLK_CNTL__FORCE_E2           |
+                        SCLK_CNTL__R300_FORCE_VAP      | SCLK_CNTL__FORCE_IDCT         |
+                       SCLK_CNTL__FORCE_VIP            | SCLK_CNTL__R300_FORCE_SR      |
+                       SCLK_CNTL__R300_FORCE_PX        | SCLK_CNTL__R300_FORCE_TX      |
+                       SCLK_CNTL__R300_FORCE_US        | SCLK_CNTL__FORCE_TV_SCLK      |
+                        SCLK_CNTL__R300_FORCE_SU       | SCLK_CNTL__FORCE_OV0);
+                OUTPLL(pllSCLK_CNTL, tmp);
+
+                tmp = INPLL(pllSCLK_MORE_CNTL);
+               tmp |= (SCLK_MORE_CNTL__FORCE_DISPREGS  | SCLK_MORE_CNTL__FORCE_MC_GUI  |
+                       SCLK_MORE_CNTL__FORCE_MC_HOST);
+                OUTPLL(pllSCLK_MORE_CNTL, tmp);
+
+               tmp = INPLL(pllMCLK_CNTL);
+               tmp |= (MCLK_CNTL__FORCE_MCLKA |
+                       MCLK_CNTL__FORCE_MCLKB |
+                       MCLK_CNTL__FORCE_YCLKA |
+                       MCLK_CNTL__FORCE_YCLKB |
+                       MCLK_CNTL__FORCE_MC);
+                OUTPLL(pllMCLK_CNTL, tmp);
+
+                tmp = INPLL(pllVCLK_ECP_CNTL);
+                tmp &= ~(VCLK_ECP_CNTL__PIXCLK_ALWAYS_ONb  |
+                         VCLK_ECP_CNTL__PIXCLK_DAC_ALWAYS_ONb |
+                        VCLK_ECP_CNTL__R300_DISP_DAC_PIXCLK_DAC_BLANK_OFF);
+                OUTPLL(pllVCLK_ECP_CNTL, tmp);
+
+                tmp = INPLL(pllPIXCLKS_CNTL);
+                tmp &= ~(PIXCLKS_CNTL__PIX2CLK_ALWAYS_ONb              |
+                        PIXCLKS_CNTL__PIX2CLK_DAC_ALWAYS_ONb           |
+                        PIXCLKS_CNTL__DISP_TVOUT_PIXCLK_TV_ALWAYS_ONb  |
+                        PIXCLKS_CNTL__R300_DVOCLK_ALWAYS_ONb           |
+                        PIXCLKS_CNTL__PIXCLK_BLEND_ALWAYS_ONb          |
+                        PIXCLKS_CNTL__PIXCLK_GV_ALWAYS_ONb             |
+                        PIXCLKS_CNTL__R300_PIXCLK_DVO_ALWAYS_ONb       |
+                        PIXCLKS_CNTL__PIXCLK_LVDS_ALWAYS_ONb           |
+                        PIXCLKS_CNTL__PIXCLK_TMDS_ALWAYS_ONb           |
+                        PIXCLKS_CNTL__R300_PIXCLK_TRANS_ALWAYS_ONb     |
+                        PIXCLKS_CNTL__R300_PIXCLK_TVO_ALWAYS_ONb       |
+                        PIXCLKS_CNTL__R300_P2G2CLK_ALWAYS_ONb          |
+                        PIXCLKS_CNTL__R300_P2G2CLK_ALWAYS_ONb          |
+                        PIXCLKS_CNTL__R300_DISP_DAC_PIXCLK_DAC2_BLANK_OFF);
+                OUTPLL(pllPIXCLKS_CNTL, tmp);
+
                return;
+       }
        
+       /* Default */
+
        /* Force Core Clocks */
-       sclk_cntl = INPLL( pllSCLK_CNTL_M6);
-       sclk_cntl |=    SCLK_CNTL_M6__FORCE_CP|
-                       SCLK_CNTL_M6__FORCE_HDP|
-                       SCLK_CNTL_M6__FORCE_DISP1|
-                       SCLK_CNTL_M6__FORCE_DISP2|
-                       SCLK_CNTL_M6__FORCE_TOP|
-                       SCLK_CNTL_M6__FORCE_E2|
-                       SCLK_CNTL_M6__FORCE_SE|
-                       SCLK_CNTL_M6__FORCE_IDCT|
-                       SCLK_CNTL_M6__FORCE_VIP|
-                       SCLK_CNTL_M6__FORCE_RE|
-                       SCLK_CNTL_M6__FORCE_PB|
-                       SCLK_CNTL_M6__FORCE_TAM|
-                       SCLK_CNTL_M6__FORCE_TDM|
-                       SCLK_CNTL_M6__FORCE_RB|
-                       SCLK_CNTL_M6__FORCE_TV_SCLK|
-                       SCLK_CNTL_M6__FORCE_SUBPIC|
-                       SCLK_CNTL_M6__FORCE_OV0;
-       OUTPLL( pllSCLK_CNTL_M6, sclk_cntl);
-       
-       
-       
-       sclk_more_cntl = INPLL(pllSCLK_MORE_CNTL);
-       sclk_more_cntl |=       SCLK_MORE_CNTL__FORCE_DISPREGS|
-                               SCLK_MORE_CNTL__FORCE_MC_GUI|
-                               SCLK_MORE_CNTL__FORCE_MC_HOST;  
-       OUTPLL(pllSCLK_MORE_CNTL, sclk_more_cntl);
-       
-       /* Force Display clocks */
-       vclk_ecp_cntl = INPLL( pllVCLK_ECP_CNTL);
-       vclk_ecp_cntl &= ~(     VCLK_ECP_CNTL__PIXCLK_ALWAYS_ONb |
-                               VCLK_ECP_CNTL__PIXCLK_DAC_ALWAYS_ONb);
+       tmp = INPLL(pllSCLK_CNTL);
+       tmp |= (SCLK_CNTL__FORCE_CP | SCLK_CNTL__FORCE_E2);
 
-       OUTPLL( pllVCLK_ECP_CNTL, vclk_ecp_cntl);
-       
-       pixclks_cntl = INPLL( pllPIXCLKS_CNTL);
-       pixclks_cntl &= ~(      PIXCLKS_CNTL__PIXCLK_GV_ALWAYS_ONb |
-                               PIXCLKS_CNTL__PIXCLK_BLEND_ALWAYS_ONb|
-                               PIXCLKS_CNTL__PIXCLK_DIG_TMDS_ALWAYS_ONb |
-                               PIXCLKS_CNTL__PIXCLK_LVDS_ALWAYS_ONb|
-                               PIXCLKS_CNTL__PIXCLK_TMDS_ALWAYS_ONb|
-                               PIXCLKS_CNTL__PIX2CLK_ALWAYS_ONb|
-                               PIXCLKS_CNTL__PIX2CLK_DAC_ALWAYS_ONb);
-                                               
-       OUTPLL( pllPIXCLKS_CNTL, pixclks_cntl);
+       /* XFree doesn't do that case, but we had this code from Apple and it
+        * seem necessary for proper suspend/resume operations
+        */
+       if (rinfo->is_mobility) {
+               tmp |=  SCLK_CNTL__FORCE_HDP|
+                       SCLK_CNTL__FORCE_DISP1|
+                       SCLK_CNTL__FORCE_DISP2|
+                       SCLK_CNTL__FORCE_TOP|
+                       SCLK_CNTL__FORCE_SE|
+                       SCLK_CNTL__FORCE_IDCT|
+                       SCLK_CNTL__FORCE_VIP|
+                       SCLK_CNTL__FORCE_PB|
+                       SCLK_CNTL__FORCE_RE|
+                       SCLK_CNTL__FORCE_TAM|
+                       SCLK_CNTL__FORCE_TDM|
+                       SCLK_CNTL__FORCE_RB|
+                       SCLK_CNTL__FORCE_TV_SCLK|
+                       SCLK_CNTL__FORCE_SUBPIC|
+                       SCLK_CNTL__FORCE_OV0;
+       }
+       else if (rinfo->family == CHIP_FAMILY_R300 ||
+                  rinfo->family == CHIP_FAMILY_R350) {
+               tmp |=  SCLK_CNTL__FORCE_HDP   |
+                       SCLK_CNTL__FORCE_DISP1 |
+                       SCLK_CNTL__FORCE_DISP2 |
+                       SCLK_CNTL__FORCE_TOP   |
+                       SCLK_CNTL__FORCE_IDCT  |
+                       SCLK_CNTL__FORCE_VIP;
+       }
+       OUTPLL(pllSCLK_CNTL, tmp);
+       radeon_msleep(16);
+
+       if (rinfo->family == CHIP_FAMILY_R300 || rinfo->family == CHIP_FAMILY_R350) {
+               tmp = INPLL(pllSCLK_CNTL2);
+               tmp |=  SCLK_CNTL2__R300_FORCE_TCL |
+                       SCLK_CNTL2__R300_FORCE_GA  |
+                       SCLK_CNTL2__R300_FORCE_CBA;
+               OUTPLL(pllSCLK_CNTL2, tmp);
+               radeon_msleep(16);
+       }
+
+       tmp = INPLL(pllCLK_PIN_CNTL);
+       tmp &= ~CLK_PIN_CNTL__SCLK_DYN_START_CNTL;
+       OUTPLL(pllCLK_PIN_CNTL, tmp);
+       radeon_msleep(15);
+
+       if (rinfo->is_IGP) {
+               /* Weird  ... X is _un_ forcing clocks here, I think it's
+                * doing backward. Imitate it for now...
+                */
+               tmp = INPLL(pllMCLK_CNTL);
+               tmp &= ~(MCLK_CNTL__FORCE_MCLKA |
+                        MCLK_CNTL__FORCE_YCLKA);
+               OUTPLL(pllMCLK_CNTL, tmp);
+               radeon_msleep(16);
+       }
+       /* Hrm... same shit, X doesn't do that but I have to */
+       else if (rinfo->is_mobility) {
+               tmp = INPLL(pllMCLK_CNTL);
+               tmp |= (MCLK_CNTL__FORCE_MCLKA |
+                       MCLK_CNTL__FORCE_MCLKB |
+                       MCLK_CNTL__FORCE_YCLKA |
+                       MCLK_CNTL__FORCE_YCLKB);
+               OUTPLL(pllMCLK_CNTL, tmp);
+               radeon_msleep(16);
+
+               tmp = INPLL(pllMCLK_MISC);
+               tmp &=  ~(MCLK_MISC__MC_MCLK_MAX_DYN_STOP_LAT|
+                         MCLK_MISC__IO_MCLK_MAX_DYN_STOP_LAT|
+                         MCLK_MISC__MC_MCLK_DYN_ENABLE|
+                         MCLK_MISC__IO_MCLK_DYN_ENABLE);
+               OUTPLL(pllMCLK_MISC, tmp);
+               radeon_msleep(15);
+       }
 
-       /* Force Memory Clocks */
-       mclk_cntl = INPLL( pllMCLK_CNTL_M6);
-       mclk_cntl &= ~( MCLK_CNTL_M6__FORCE_MCLKA |  
-                       MCLK_CNTL_M6__FORCE_MCLKB |
-                       MCLK_CNTL_M6__FORCE_YCLKA |
-                       MCLK_CNTL_M6__FORCE_YCLKB );
-       OUTPLL( pllMCLK_CNTL_M6, mclk_cntl);
+       if (rinfo->is_mobility) {
+               tmp = INPLL(pllSCLK_MORE_CNTL);
+               tmp |=  SCLK_MORE_CNTL__FORCE_DISPREGS|
+                       SCLK_MORE_CNTL__FORCE_MC_GUI|
+                       SCLK_MORE_CNTL__FORCE_MC_HOST;
+               OUTPLL(pllSCLK_MORE_CNTL, tmp);
+               radeon_msleep(16);
+       }
+
+       tmp = INPLL(pllPIXCLKS_CNTL);
+       tmp &= ~(PIXCLKS_CNTL__PIXCLK_GV_ALWAYS_ONb |
+                PIXCLKS_CNTL__PIXCLK_BLEND_ALWAYS_ONb|
+                PIXCLKS_CNTL__PIXCLK_DIG_TMDS_ALWAYS_ONb |
+                PIXCLKS_CNTL__PIXCLK_LVDS_ALWAYS_ONb|
+                PIXCLKS_CNTL__PIXCLK_TMDS_ALWAYS_ONb|
+                PIXCLKS_CNTL__PIX2CLK_ALWAYS_ONb|
+                PIXCLKS_CNTL__PIX2CLK_DAC_ALWAYS_ONb);
+       OUTPLL(pllPIXCLKS_CNTL, tmp);
+       radeon_msleep(16);
+
+       tmp = INPLL( pllVCLK_ECP_CNTL);
+       tmp &= ~(VCLK_ECP_CNTL__PIXCLK_ALWAYS_ONb |
+                VCLK_ECP_CNTL__PIXCLK_DAC_ALWAYS_ONb);
+       OUTPLL( pllVCLK_ECP_CNTL, tmp);
+       radeon_msleep(16);
 }
 
 void radeon_pm_enable_dynamic_mode(struct radeonfb_info *rinfo)
 {
-       u32 clk_pwrmgt_cntl;
-       u32 sclk_cntl;
-       u32 sclk_more_cntl;
-       u32 clk_pin_cntl;
-       u32 pixclks_cntl;
-       u32 vclk_ecp_cntl;
-       u32 mclk_cntl;
-       u32 mclk_misc;
+       u32 tmp;
 
-       /* Mobility chips only, untested on M9+/M10/11 */
-       if (!rinfo->is_mobility)
+       /* R100 */
+       if (!rinfo->has_CRTC2) {
+                tmp = INPLL(pllSCLK_CNTL);
+
+               if ((INREG(CONFIG_CNTL) & CFG_ATI_REV_ID_MASK) > CFG_ATI_REV_A13)
+                    tmp &= ~(SCLK_CNTL__FORCE_CP       | SCLK_CNTL__FORCE_RB);
+                tmp &= ~(SCLK_CNTL__FORCE_HDP          | SCLK_CNTL__FORCE_DISP1 |
+                        SCLK_CNTL__FORCE_TOP           | SCLK_CNTL__FORCE_SE   |
+                        SCLK_CNTL__FORCE_IDCT          | SCLK_CNTL__FORCE_RE   |
+                        SCLK_CNTL__FORCE_PB            | SCLK_CNTL__FORCE_TAM  |
+                        SCLK_CNTL__FORCE_TDM);
+                OUTPLL(pllSCLK_CNTL, tmp);
                return;
-       if (rinfo->family > CHIP_FAMILY_RV250)
-               return;
-       
-       /* Set Latencies */
-       clk_pwrmgt_cntl = INPLL( pllCLK_PWRMGT_CNTL_M6);
-       
-       clk_pwrmgt_cntl &= ~(    CLK_PWRMGT_CNTL_M6__ENGINE_DYNCLK_MODE_MASK|
-                                CLK_PWRMGT_CNTL_M6__ACTIVE_HILO_LAT_MASK|
-                                CLK_PWRMGT_CNTL_M6__DISP_DYN_STOP_LAT_MASK|
-                                CLK_PWRMGT_CNTL_M6__DYN_STOP_MODE_MASK);
-       /* Mode 1 */
-       clk_pwrmgt_cntl =       CLK_PWRMGT_CNTL_M6__MC_CH_MODE|
-                               CLK_PWRMGT_CNTL_M6__ENGINE_DYNCLK_MODE | 
-                               (1<<CLK_PWRMGT_CNTL_M6__ACTIVE_HILO_LAT__SHIFT) |
-                               (0<<CLK_PWRMGT_CNTL_M6__DISP_DYN_STOP_LAT__SHIFT)|
-                               (0<<CLK_PWRMGT_CNTL_M6__DYN_STOP_MODE__SHIFT);
-
-       OUTPLL( pllCLK_PWRMGT_CNTL_M6, clk_pwrmgt_cntl);
-                                               
-
-       clk_pin_cntl = INPLL( pllCLK_PIN_CNTL);
-       clk_pin_cntl |= CLK_PIN_CNTL__SCLK_DYN_START_CNTL;
-        
-       OUTPLL( pllCLK_PIN_CNTL, clk_pin_cntl);
-
-       /* Enable Dyanmic mode for SCLK */
+       }
 
-       sclk_cntl = INPLL( pllSCLK_CNTL_M6);    
-       sclk_cntl &= SCLK_CNTL_M6__SCLK_SRC_SEL_MASK;
-       sclk_cntl |= SCLK_CNTL_M6__FORCE_VIP;           
+       /* M10 */
+       if (rinfo->family == CHIP_FAMILY_RV350) {
+               tmp = INPLL(pllSCLK_CNTL2);
+               tmp &= ~(SCLK_CNTL2__R300_FORCE_TCL |
+                        SCLK_CNTL2__R300_FORCE_GA  |
+                        SCLK_CNTL2__R300_FORCE_CBA);
+               tmp |=  (SCLK_CNTL2__R300_TCL_MAX_DYN_STOP_LAT |
+                        SCLK_CNTL2__R300_GA_MAX_DYN_STOP_LAT  |
+                        SCLK_CNTL2__R300_CBA_MAX_DYN_STOP_LAT);
+               OUTPLL(pllSCLK_CNTL2, tmp);
+
+               tmp = INPLL(pllSCLK_CNTL);
+               tmp &= ~(SCLK_CNTL__FORCE_DISP2 | SCLK_CNTL__FORCE_CP      |
+                        SCLK_CNTL__FORCE_HDP   | SCLK_CNTL__FORCE_DISP1   |
+                        SCLK_CNTL__FORCE_TOP   | SCLK_CNTL__FORCE_E2      |
+                        SCLK_CNTL__R300_FORCE_VAP | SCLK_CNTL__FORCE_IDCT |
+                        SCLK_CNTL__FORCE_VIP   | SCLK_CNTL__R300_FORCE_SR |
+                        SCLK_CNTL__R300_FORCE_PX | SCLK_CNTL__R300_FORCE_TX |
+                        SCLK_CNTL__R300_FORCE_US | SCLK_CNTL__FORCE_TV_SCLK |
+                        SCLK_CNTL__R300_FORCE_SU | SCLK_CNTL__FORCE_OV0);
+               tmp |= SCLK_CNTL__DYN_STOP_LAT_MASK;
+               OUTPLL(pllSCLK_CNTL, tmp);
+
+               tmp = INPLL(pllSCLK_MORE_CNTL);
+               tmp &= ~SCLK_MORE_CNTL__FORCEON;
+               tmp |=  SCLK_MORE_CNTL__DISPREGS_MAX_DYN_STOP_LAT |
+                       SCLK_MORE_CNTL__MC_GUI_MAX_DYN_STOP_LAT |
+                       SCLK_MORE_CNTL__MC_HOST_MAX_DYN_STOP_LAT;
+               OUTPLL(pllSCLK_MORE_CNTL, tmp);
+
+               tmp = INPLL(pllVCLK_ECP_CNTL);
+               tmp |= (VCLK_ECP_CNTL__PIXCLK_ALWAYS_ONb |
+                       VCLK_ECP_CNTL__PIXCLK_DAC_ALWAYS_ONb);
+               OUTPLL(pllVCLK_ECP_CNTL, tmp);
+
+               tmp = INPLL(pllPIXCLKS_CNTL);
+               tmp |= (PIXCLKS_CNTL__PIX2CLK_ALWAYS_ONb         |
+                       PIXCLKS_CNTL__PIX2CLK_DAC_ALWAYS_ONb     |
+                       PIXCLKS_CNTL__DISP_TVOUT_PIXCLK_TV_ALWAYS_ONb |
+                       PIXCLKS_CNTL__R300_DVOCLK_ALWAYS_ONb            |
+                       PIXCLKS_CNTL__PIXCLK_BLEND_ALWAYS_ONb    |
+                       PIXCLKS_CNTL__PIXCLK_GV_ALWAYS_ONb       |
+                       PIXCLKS_CNTL__R300_PIXCLK_DVO_ALWAYS_ONb        |
+                       PIXCLKS_CNTL__PIXCLK_LVDS_ALWAYS_ONb     |
+                       PIXCLKS_CNTL__PIXCLK_TMDS_ALWAYS_ONb     |
+                       PIXCLKS_CNTL__R300_PIXCLK_TRANS_ALWAYS_ONb      |
+                       PIXCLKS_CNTL__R300_PIXCLK_TVO_ALWAYS_ONb        |
+                       PIXCLKS_CNTL__R300_P2G2CLK_ALWAYS_ONb           |
+                       PIXCLKS_CNTL__R300_P2G2CLK_ALWAYS_ONb);
+               OUTPLL(pllPIXCLKS_CNTL, tmp);
+
+               tmp = INPLL(pllMCLK_MISC);
+               tmp |= (MCLK_MISC__MC_MCLK_DYN_ENABLE |
+                       MCLK_MISC__IO_MCLK_DYN_ENABLE);
+               OUTPLL(pllMCLK_MISC, tmp);
+
+               tmp = INPLL(pllMCLK_CNTL);
+               tmp |= (MCLK_CNTL__FORCE_MCLKA | MCLK_CNTL__FORCE_MCLKB);
+               tmp &= ~(MCLK_CNTL__FORCE_YCLKA  |
+                        MCLK_CNTL__FORCE_YCLKB  |
+                        MCLK_CNTL__FORCE_MC);
+
+               /* Some releases of vbios have set DISABLE_MC_MCLKA
+                * and DISABLE_MC_MCLKB bits in the vbios table.  Setting these
+                * bits will cause H/W hang when reading video memory with dynamic
+                * clocking enabled.
+                */
+               if ((tmp & MCLK_CNTL__R300_DISABLE_MC_MCLKA) &&
+                   (tmp & MCLK_CNTL__R300_DISABLE_MC_MCLKB)) {
+                       /* If both bits are set, then check the active channels */
+                       tmp = INPLL(pllMCLK_CNTL);
+                       if (rinfo->vram_width == 64) {
+                           if (INREG(MEM_CNTL) & R300_MEM_USE_CD_CH_ONLY)
+                               tmp &= ~MCLK_CNTL__R300_DISABLE_MC_MCLKB;
+                           else
+                               tmp &= ~MCLK_CNTL__R300_DISABLE_MC_MCLKA;
+                       } else {
+                           tmp &= ~(MCLK_CNTL__R300_DISABLE_MC_MCLKA |
+                                    MCLK_CNTL__R300_DISABLE_MC_MCLKB);
+                       }
+               }
+               OUTPLL(pllMCLK_CNTL, tmp);
+               return;
+       }
 
-       OUTPLL( pllSCLK_CNTL_M6, sclk_cntl);
+       /* R300 */
+       if (rinfo->family == CHIP_FAMILY_R300 || rinfo->family == CHIP_FAMILY_R350) {
+               tmp = INPLL(pllSCLK_CNTL);
+               tmp &= ~(SCLK_CNTL__R300_FORCE_VAP);
+               tmp |= SCLK_CNTL__FORCE_CP;
+               OUTPLL(pllSCLK_CNTL, tmp);
+               radeon_msleep(15);
+
+               tmp = INPLL(pllSCLK_CNTL2);
+               tmp &= ~(SCLK_CNTL2__R300_FORCE_TCL |
+                        SCLK_CNTL2__R300_FORCE_GA  |
+                        SCLK_CNTL2__R300_FORCE_CBA);
+               OUTPLL(pllSCLK_CNTL2, tmp);
+       }
 
+       /* Others */
 
-       sclk_more_cntl = INPLL(pllSCLK_MORE_CNTL);
-       sclk_more_cntl &= ~(SCLK_MORE_CNTL__FORCE_DISPREGS);
-                                                   
-       OUTPLL(pllSCLK_MORE_CNTL, sclk_more_cntl);
+       tmp = INPLL( pllCLK_PWRMGT_CNTL);
+       tmp &= ~(CLK_PWRMGT_CNTL__ACTIVE_HILO_LAT_MASK|
+                CLK_PWRMGT_CNTL__DISP_DYN_STOP_LAT_MASK|
+                CLK_PWRMGT_CNTL__DYN_STOP_MODE_MASK);
+       tmp |= CLK_PWRMGT_CNTL__ENGINE_DYNCLK_MODE_MASK |
+              (0x01 << CLK_PWRMGT_CNTL__ACTIVE_HILO_LAT__SHIFT);
+       OUTPLL( pllCLK_PWRMGT_CNTL, tmp);
+       radeon_msleep(15);
 
-       
-       /* Enable Dynamic mode for PIXCLK & PIX2CLK */
+       tmp = INPLL(pllCLK_PIN_CNTL);
+       tmp |= CLK_PIN_CNTL__SCLK_DYN_START_CNTL;
+       OUTPLL(pllCLK_PIN_CNTL, tmp);
+       radeon_msleep(15);
 
-       pixclks_cntl = INPLL( pllPIXCLKS_CNTL);
-       
-       pixclks_cntl|=  PIXCLKS_CNTL__PIX2CLK_ALWAYS_ONb | 
-                       PIXCLKS_CNTL__PIX2CLK_DAC_ALWAYS_ONb|
-                       PIXCLKS_CNTL__PIXCLK_BLEND_ALWAYS_ONb|
-                       PIXCLKS_CNTL__PIXCLK_GV_ALWAYS_ONb|
-                       PIXCLKS_CNTL__PIXCLK_DIG_TMDS_ALWAYS_ONb|
-                       PIXCLKS_CNTL__PIXCLK_LVDS_ALWAYS_ONb|
-                       PIXCLKS_CNTL__PIXCLK_TMDS_ALWAYS_ONb;
-
-       OUTPLL( pllPIXCLKS_CNTL, pixclks_cntl);
-               
-               
-       vclk_ecp_cntl = INPLL( pllVCLK_ECP_CNTL);
+       /* When DRI is enabled, setting DYN_STOP_LAT to zero can cause some R200
+        * to lockup randomly, leave them as set by BIOS.
+        */
+       tmp = INPLL(pllSCLK_CNTL);
+       tmp &= ~SCLK_CNTL__FORCEON_MASK;
+
+       /*RAGE_6::A11 A12 A12N1 A13, RV250::A11 A12, R300*/
+       if ((rinfo->family == CHIP_FAMILY_RV250 &&
+            ((INREG(CONFIG_CNTL) & CFG_ATI_REV_ID_MASK) < CFG_ATI_REV_A13)) ||
+           ((rinfo->family == CHIP_FAMILY_RV100) &&
+            ((INREG(CONFIG_CNTL) & CFG_ATI_REV_ID_MASK) <= CFG_ATI_REV_A13))) {
+               tmp |= SCLK_CNTL__FORCE_CP;
+               tmp |= SCLK_CNTL__FORCE_VIP;
+       }
+       OUTPLL(pllSCLK_CNTL, tmp);
+       radeon_msleep(15);
+
+       if ((rinfo->family == CHIP_FAMILY_RV200) ||
+           (rinfo->family == CHIP_FAMILY_RV250) ||
+           (rinfo->family == CHIP_FAMILY_RV280)) {
+               tmp = INPLL(pllSCLK_MORE_CNTL);
+               tmp &= ~SCLK_MORE_CNTL__FORCEON;
+
+               /* RV200::A11 A12 RV250::A11 A12 */
+               if (((rinfo->family == CHIP_FAMILY_RV200) ||
+                    (rinfo->family == CHIP_FAMILY_RV250)) &&
+                   ((INREG(CONFIG_CNTL) & CFG_ATI_REV_ID_MASK) < CFG_ATI_REV_A13))
+                       tmp |= SCLK_MORE_CNTL__FORCEON;
+
+               OUTPLL(pllSCLK_MORE_CNTL, tmp);
+               radeon_msleep(15);
+       }
        
-       vclk_ecp_cntl|=  VCLK_ECP_CNTL__PIXCLK_ALWAYS_ONb | 
-                        VCLK_ECP_CNTL__PIXCLK_DAC_ALWAYS_ONb;
-
-       OUTPLL( pllVCLK_ECP_CNTL, vclk_ecp_cntl);
 
+       /* RV200::A11 A12, RV250::A11 A12 */
+       if (((rinfo->family == CHIP_FAMILY_RV200) ||
+            (rinfo->family == CHIP_FAMILY_RV250)) &&
+           ((INREG(CONFIG_CNTL) & CFG_ATI_REV_ID_MASK) < CFG_ATI_REV_A13)) {
+               tmp = INPLL(pllPLL_PWRMGT_CNTL);
+               tmp |= PLL_PWRMGT_CNTL__TCL_BYPASS_DISABLE;
+               OUTPLL(pllPLL_PWRMGT_CNTL, tmp);
+               radeon_msleep(15);
+       }
 
-       /* Enable Dynamic mode for MCLK */
-
-       mclk_cntl  = INPLL( pllMCLK_CNTL_M6);
-       mclk_cntl |=    MCLK_CNTL_M6__FORCE_MCLKA|  
-                       MCLK_CNTL_M6__FORCE_MCLKB|      
-                       MCLK_CNTL_M6__FORCE_YCLKA|
-                       MCLK_CNTL_M6__FORCE_YCLKB;
-                       
-       OUTPLL( pllMCLK_CNTL_M6, mclk_cntl);
-
-       mclk_misc = INPLL(pllMCLK_MISC);
-       mclk_misc |=    MCLK_MISC__MC_MCLK_MAX_DYN_STOP_LAT|
+       tmp = INPLL(pllPIXCLKS_CNTL);
+       tmp |=  PIXCLKS_CNTL__PIX2CLK_ALWAYS_ONb |
+               PIXCLKS_CNTL__PIX2CLK_DAC_ALWAYS_ONb|
+               PIXCLKS_CNTL__PIXCLK_BLEND_ALWAYS_ONb|
+               PIXCLKS_CNTL__PIXCLK_GV_ALWAYS_ONb|
+               PIXCLKS_CNTL__PIXCLK_DIG_TMDS_ALWAYS_ONb|
+               PIXCLKS_CNTL__PIXCLK_LVDS_ALWAYS_ONb|
+               PIXCLKS_CNTL__PIXCLK_TMDS_ALWAYS_ONb;
+       OUTPLL(pllPIXCLKS_CNTL, tmp);
+       radeon_msleep(15);
+               
+       tmp = INPLL(pllVCLK_ECP_CNTL);
+       tmp |=  VCLK_ECP_CNTL__PIXCLK_ALWAYS_ONb |
+               VCLK_ECP_CNTL__PIXCLK_DAC_ALWAYS_ONb;
+       OUTPLL(pllVCLK_ECP_CNTL, tmp);
+
+       /* X doesn't do that ... hrm, we do on mobility && Macs */
+#ifdef CONFIG_PPC_OF
+       if (rinfo->is_mobility) {
+               tmp  = INPLL(pllMCLK_CNTL);
+               tmp &= ~(MCLK_CNTL__FORCE_MCLKA |
+                        MCLK_CNTL__FORCE_MCLKB |
+                        MCLK_CNTL__FORCE_YCLKA |
+                        MCLK_CNTL__FORCE_YCLKB);
+               OUTPLL(pllMCLK_CNTL, tmp);
+               radeon_msleep(15);
+
+               tmp = INPLL(pllMCLK_MISC);
+               tmp |=  MCLK_MISC__MC_MCLK_MAX_DYN_STOP_LAT|
                        MCLK_MISC__IO_MCLK_MAX_DYN_STOP_LAT|
                        MCLK_MISC__MC_MCLK_DYN_ENABLE|
-                       MCLK_MISC__IO_MCLK_DYN_ENABLE;  
-       
-       OUTPLL(pllMCLK_MISC, mclk_misc);
+                       MCLK_MISC__IO_MCLK_DYN_ENABLE;
+               OUTPLL(pllMCLK_MISC, tmp);
+               radeon_msleep(15);
+       }
+#endif /* CONFIG_PPC_OF */
 }
 
 #ifdef CONFIG_PM
@@ -218,7 +460,7 @@ static u32 INMC(struct radeonfb_info *rinfo, u8 indx)
        return INREG( MC_IND_DATA);
 }
 
-static void radeon_pm_save_regs(struct radeonfb_info *rinfo)
+static void radeon_pm_save_regs(struct radeonfb_info *rinfo, int saving_for_d3)
 {
        rinfo->save_regs[0] = INPLL(PLL_PWRMGT_CNTL);
        rinfo->save_regs[1] = INPLL(CLK_PWRMGT_CNTL);
@@ -233,7 +475,6 @@ static void radeon_pm_save_regs(struct radeonfb_info *rinfo)
        rinfo->save_regs[9] = INREG(DISP_MISC_CNTL);
        rinfo->save_regs[10] = INREG(DISP_PWR_MAN);
        rinfo->save_regs[11] = INREG(LVDS_GEN_CNTL);
-       rinfo->save_regs[12] = INREG(LVDS_PLL_CNTL);
        rinfo->save_regs[13] = INREG(TV_DAC_CNTL);
        rinfo->save_regs[14] = INREG(BUS_CNTL1);
        rinfo->save_regs[15] = INREG(CRTC_OFFSET_CNTL);
@@ -256,6 +497,93 @@ static void radeon_pm_save_regs(struct radeonfb_info *rinfo)
        rinfo->save_regs[31] = INREG(DISPLAY_BASE_ADDR);
        rinfo->save_regs[32] = INREG(MC_AGP_LOCATION);
        rinfo->save_regs[33] = INREG(CRTC2_DISPLAY_BASE_ADDR);
+
+       rinfo->save_regs[34] = INPLL(SCLK_MORE_CNTL);
+       rinfo->save_regs[35] = INREG(MEM_SDRAM_MODE_REG);
+       rinfo->save_regs[36] = INREG(BUS_CNTL);
+       rinfo->save_regs[39] = INREG(RBBM_CNTL);
+       rinfo->save_regs[40] = INREG(DAC_CNTL);
+       rinfo->save_regs[41] = INREG(HOST_PATH_CNTL);
+       rinfo->save_regs[37] = INREG(MPP_TB_CONFIG);
+       rinfo->save_regs[38] = INREG(FCP_CNTL);
+
+       if (rinfo->is_mobility) {
+               rinfo->save_regs[12] = INREG(LVDS_PLL_CNTL);
+               rinfo->save_regs[43] = INPLL(pllSSPLL_CNTL);
+               rinfo->save_regs[44] = INPLL(pllSSPLL_REF_DIV);
+               rinfo->save_regs[45] = INPLL(pllSSPLL_DIV_0);
+               rinfo->save_regs[90] = INPLL(pllSS_INT_CNTL);
+               rinfo->save_regs[91] = INPLL(pllSS_TST_CNTL);
+               rinfo->save_regs[81] = INREG(LVDS_GEN_CNTL);
+       }
+
+       if (rinfo->family >= CHIP_FAMILY_RV200) {
+               rinfo->save_regs[42] = INREG(MEM_REFRESH_CNTL);
+               rinfo->save_regs[46] = INREG(MC_CNTL);
+               rinfo->save_regs[47] = INREG(MC_INIT_GFX_LAT_TIMER);
+               rinfo->save_regs[48] = INREG(MC_INIT_MISC_LAT_TIMER);
+               rinfo->save_regs[49] = INREG(MC_TIMING_CNTL);
+               rinfo->save_regs[50] = INREG(MC_READ_CNTL_AB);
+               rinfo->save_regs[51] = INREG(MC_IOPAD_CNTL);
+               rinfo->save_regs[52] = INREG(MC_CHIP_IO_OE_CNTL_AB);
+               rinfo->save_regs[53] = INREG(MC_DEBUG);
+       }
+       rinfo->save_regs[54] = INREG(PAMAC0_DLY_CNTL);
+       rinfo->save_regs[55] = INREG(PAMAC1_DLY_CNTL);
+       rinfo->save_regs[56] = INREG(PAD_CTLR_MISC);
+       rinfo->save_regs[57] = INREG(FW_CNTL);
+
+       if (rinfo->family >= CHIP_FAMILY_R300) {
+               rinfo->save_regs[58] = INMC(rinfo, ixR300_MC_MC_INIT_WR_LAT_TIMER);
+               rinfo->save_regs[59] = INMC(rinfo, ixR300_MC_IMP_CNTL);
+               rinfo->save_regs[60] = INMC(rinfo, ixR300_MC_CHP_IO_CNTL_C0);
+               rinfo->save_regs[61] = INMC(rinfo, ixR300_MC_CHP_IO_CNTL_C1);
+               rinfo->save_regs[62] = INMC(rinfo, ixR300_MC_CHP_IO_CNTL_D0);
+               rinfo->save_regs[63] = INMC(rinfo, ixR300_MC_CHP_IO_CNTL_D1);
+               rinfo->save_regs[64] = INMC(rinfo, ixR300_MC_BIST_CNTL_3);
+               rinfo->save_regs[65] = INMC(rinfo, ixR300_MC_CHP_IO_CNTL_A0);
+               rinfo->save_regs[66] = INMC(rinfo, ixR300_MC_CHP_IO_CNTL_A1);
+               rinfo->save_regs[67] = INMC(rinfo, ixR300_MC_CHP_IO_CNTL_B0);
+               rinfo->save_regs[68] = INMC(rinfo, ixR300_MC_CHP_IO_CNTL_B1);
+               rinfo->save_regs[69] = INMC(rinfo, ixR300_MC_DEBUG_CNTL);
+               rinfo->save_regs[70] = INMC(rinfo, ixR300_MC_DLL_CNTL);
+               rinfo->save_regs[71] = INMC(rinfo, ixR300_MC_IMP_CNTL_0);
+               rinfo->save_regs[72] = INMC(rinfo, ixR300_MC_ELPIDA_CNTL);
+               rinfo->save_regs[96] = INMC(rinfo, ixR300_MC_READ_CNTL_CD);
+       } else {
+               rinfo->save_regs[59] = INMC(rinfo, ixMC_IMP_CNTL);
+               rinfo->save_regs[65] = INMC(rinfo, ixMC_CHP_IO_CNTL_A0);
+               rinfo->save_regs[66] = INMC(rinfo, ixMC_CHP_IO_CNTL_A1);
+               rinfo->save_regs[67] = INMC(rinfo, ixMC_CHP_IO_CNTL_B0);
+               rinfo->save_regs[68] = INMC(rinfo, ixMC_CHP_IO_CNTL_B1);
+               rinfo->save_regs[71] = INMC(rinfo, ixMC_IMP_CNTL_0);
+       }
+
+       rinfo->save_regs[73] = INPLL(pllMPLL_CNTL);
+       rinfo->save_regs[74] = INPLL(pllSPLL_CNTL);
+       rinfo->save_regs[75] = INPLL(pllMPLL_AUX_CNTL);
+       rinfo->save_regs[76] = INPLL(pllSPLL_AUX_CNTL);
+       rinfo->save_regs[77] = INPLL(pllM_SPLL_REF_FB_DIV);
+       rinfo->save_regs[78] = INPLL(pllAGP_PLL_CNTL);
+       rinfo->save_regs[79] = INREG(PAMAC2_DLY_CNTL);
+
+       rinfo->save_regs[80] = INREG(OV0_BASE_ADDR);
+       rinfo->save_regs[82] = INREG(FP_GEN_CNTL);
+       rinfo->save_regs[83] = INREG(FP2_GEN_CNTL);
+       rinfo->save_regs[84] = INREG(TMDS_CNTL);
+       rinfo->save_regs[85] = INREG(TMDS_TRANSMITTER_CNTL);
+       rinfo->save_regs[86] = INREG(DISP_OUTPUT_CNTL);
+       rinfo->save_regs[87] = INREG(DISP_HW_DEBUG);
+       rinfo->save_regs[88] = INREG(TV_MASTER_CNTL);
+       rinfo->save_regs[89] = INPLL(pllP2PLL_REF_DIV);
+       rinfo->save_regs[92] = INPLL(pllPPLL_DIV_0);
+       rinfo->save_regs[93] = INPLL(pllPPLL_CNTL);
+       rinfo->save_regs[94] = INREG(GRPH_BUFFER_CNTL);
+       rinfo->save_regs[95] = INREG(GRPH2_BUFFER_CNTL);
+       rinfo->save_regs[96] = INREG(HDP_DEBUG);
+       rinfo->save_regs[97] = INPLL(pllMDLL_CKO);
+       rinfo->save_regs[98] = INPLL(pllMDLL_RDCKA);
+       rinfo->save_regs[99] = INPLL(pllMDLL_RDCKB);
 }
 
 static void radeon_pm_restore_regs(struct radeonfb_info *rinfo)
@@ -270,12 +598,15 @@ static void radeon_pm_restore_regs(struct radeonfb_info *rinfo)
        OUTPLL(VCLK_ECP_CNTL, rinfo->save_regs[5]);
        OUTPLL(PIXCLKS_CNTL, rinfo->save_regs[6]);
        OUTPLL(MCLK_MISC, rinfo->save_regs[7]);
-       
+       if (rinfo->family == CHIP_FAMILY_RV350)
+               OUTPLL(SCLK_MORE_CNTL, rinfo->save_regs[34]);
+
        OUTREG(SURFACE_CNTL, rinfo->save_regs[29]);
        OUTREG(MC_FB_LOCATION, rinfo->save_regs[30]);
        OUTREG(DISPLAY_BASE_ADDR, rinfo->save_regs[31]);
        OUTREG(MC_AGP_LOCATION, rinfo->save_regs[32]);
        OUTREG(CRTC2_DISPLAY_BASE_ADDR, rinfo->save_regs[33]);
+       OUTREG(CONFIG_MEMSIZE, rinfo->video_ram);
 
        OUTREG(DISP_MISC_CNTL, rinfo->save_regs[9]);
        OUTREG(DISP_PWR_MAN, rinfo->save_regs[10]);
@@ -287,10 +618,8 @@ static void radeon_pm_restore_regs(struct radeonfb_info *rinfo)
        OUTREG(AGP_CNTL, rinfo->save_regs[16]);
        OUTREG(CRTC_GEN_CNTL, rinfo->save_regs[17]);
        OUTREG(CRTC2_GEN_CNTL, rinfo->save_regs[18]);
-
-       // wait VBL before that one  ?
        OUTPLL(P2PLL_CNTL, rinfo->save_regs[8]);
-       
+
        OUTREG(GPIOPAD_A, rinfo->save_regs[19]);
        OUTREG(GPIOPAD_EN, rinfo->save_regs[20]);
        OUTREG(GPIOPAD_MASK, rinfo->save_regs[21]);
@@ -319,30 +648,32 @@ static void radeon_pm_disable_iopad(struct radeonfb_info *rinfo)
 
 static void radeon_pm_program_v2clk(struct radeonfb_info *rinfo)
 {
-       /* we use __INPLL and _OUTPLL and do the locking ourselves... */
-       unsigned long flags;
-       spin_lock_irqsave(&rinfo->reg_lock, flags);
        /* Set v2clk to 65MHz */
-       __OUTPLL(pllPIXCLKS_CNTL,
-               __INPLL(rinfo, pllPIXCLKS_CNTL) & ~PIXCLKS_CNTL__PIX2CLK_SRC_SEL_MASK);
+       if (rinfo->family <= CHIP_FAMILY_RV280) {
+               OUTPLL(pllPIXCLKS_CNTL,
+                        __INPLL(rinfo, pllPIXCLKS_CNTL)
+                        & ~PIXCLKS_CNTL__PIX2CLK_SRC_SEL_MASK);
         
-       __OUTPLL(pllP2PLL_REF_DIV, 0x0000000c);
-       __OUTPLL(pllP2PLL_CNTL, 0x0000bf00);
-       __OUTPLL(pllP2PLL_DIV_0, 0x00020074 | P2PLL_DIV_0__P2PLL_ATOMIC_UPDATE_W);
+               OUTPLL(pllP2PLL_REF_DIV, 0x0000000c);
+               OUTPLL(pllP2PLL_CNTL, 0x0000bf00);
+       } else {
+               OUTPLL(pllP2PLL_REF_DIV, 0x0000000c);
+               INPLL(pllP2PLL_REF_DIV);
+               OUTPLL(pllP2PLL_CNTL, 0x0000a700);
+       }
+
+       OUTPLL(pllP2PLL_DIV_0, 0x00020074 | P2PLL_DIV_0__P2PLL_ATOMIC_UPDATE_W);
        
-       __OUTPLL(pllP2PLL_CNTL,
-               __INPLL(rinfo, pllP2PLL_CNTL) & ~P2PLL_CNTL__P2PLL_SLEEP);
+       OUTPLL(pllP2PLL_CNTL, INPLL(pllP2PLL_CNTL) & ~P2PLL_CNTL__P2PLL_SLEEP);
        mdelay(1);
 
-       __OUTPLL(pllP2PLL_CNTL,
-               __INPLL(rinfo, pllP2PLL_CNTL) & ~P2PLL_CNTL__P2PLL_RESET);
+       OUTPLL(pllP2PLL_CNTL, INPLL(pllP2PLL_CNTL) & ~P2PLL_CNTL__P2PLL_RESET);
        mdelay( 1);
 
-       __OUTPLL(pllPIXCLKS_CNTL,
-               (__INPLL(rinfo, pllPIXCLKS_CNTL) & ~PIXCLKS_CNTL__PIX2CLK_SRC_SEL_MASK)
+       OUTPLL(pllPIXCLKS_CNTL,
+               (INPLL(pllPIXCLKS_CNTL) & ~PIXCLKS_CNTL__PIX2CLK_SRC_SEL_MASK)
                | (0x03 << PIXCLKS_CNTL__PIX2CLK_SRC_SEL__SHIFT));
        mdelay( 1);     
-       spin_unlock_irqrestore(&rinfo->reg_lock, flags);
 }
 
 static void radeon_pm_low_current(struct radeonfb_info *rinfo)
@@ -350,8 +681,12 @@ static void radeon_pm_low_current(struct radeonfb_info *rinfo)
        u32 reg;
 
        reg  = INREG(BUS_CNTL1);
-       reg &= ~BUS_CNTL1_MOBILE_PLATFORM_SEL_MASK;
-       reg |= BUS_CNTL1_AGPCLK_VALID | (1<<BUS_CNTL1_MOBILE_PLATFORM_SEL_SHIFT);
+       if (rinfo->family <= CHIP_FAMILY_RV280) {
+               reg &= ~BUS_CNTL1_MOBILE_PLATFORM_SEL_MASK;
+               reg |= BUS_CNTL1_AGPCLK_VALID | (1<<BUS_CNTL1_MOBILE_PLATFORM_SEL_SHIFT);
+       } else {
+               reg |= 0x4080;
+       }
        OUTREG(BUS_CNTL1, reg);
        
        reg  = INPLL(PLL_PWRMGT_CNTL);
@@ -400,35 +735,42 @@ static void radeon_pm_setup_for_suspend(struct radeonfb_info *rinfo)
        u32 tmp;
        
        /* Force Core Clocks */
-       sclk_cntl = INPLL( pllSCLK_CNTL_M6);
-       sclk_cntl |=    SCLK_CNTL_M6__IDCT_MAX_DYN_STOP_LAT|
-                       SCLK_CNTL_M6__VIP_MAX_DYN_STOP_LAT|
-                       SCLK_CNTL_M6__RE_MAX_DYN_STOP_LAT|
-                       SCLK_CNTL_M6__PB_MAX_DYN_STOP_LAT|
-                       SCLK_CNTL_M6__TAM_MAX_DYN_STOP_LAT|
-                       SCLK_CNTL_M6__TDM_MAX_DYN_STOP_LAT|
-                       SCLK_CNTL_M6__RB_MAX_DYN_STOP_LAT|
+       sclk_cntl = INPLL( pllSCLK_CNTL);
+       sclk_cntl |=    SCLK_CNTL__IDCT_MAX_DYN_STOP_LAT|
+                       SCLK_CNTL__VIP_MAX_DYN_STOP_LAT|
+                       SCLK_CNTL__RE_MAX_DYN_STOP_LAT|
+                       SCLK_CNTL__PB_MAX_DYN_STOP_LAT|
+                       SCLK_CNTL__TAM_MAX_DYN_STOP_LAT|
+                       SCLK_CNTL__TDM_MAX_DYN_STOP_LAT|
+                       SCLK_CNTL__RB_MAX_DYN_STOP_LAT|
                        
-                       SCLK_CNTL_M6__FORCE_DISP2|
-                       SCLK_CNTL_M6__FORCE_CP|
-                       SCLK_CNTL_M6__FORCE_HDP|
-                       SCLK_CNTL_M6__FORCE_DISP1|
-                       SCLK_CNTL_M6__FORCE_TOP|
-                       SCLK_CNTL_M6__FORCE_E2|
-                       SCLK_CNTL_M6__FORCE_SE|
-                       SCLK_CNTL_M6__FORCE_IDCT|
-                       SCLK_CNTL_M6__FORCE_VIP|
+                       SCLK_CNTL__FORCE_DISP2|
+                       SCLK_CNTL__FORCE_CP|
+                       SCLK_CNTL__FORCE_HDP|
+                       SCLK_CNTL__FORCE_DISP1|
+                       SCLK_CNTL__FORCE_TOP|
+                       SCLK_CNTL__FORCE_E2|
+                       SCLK_CNTL__FORCE_SE|
+                       SCLK_CNTL__FORCE_IDCT|
+                       SCLK_CNTL__FORCE_VIP|
                        
-                       SCLK_CNTL_M6__FORCE_RE|
-                       SCLK_CNTL_M6__FORCE_PB|
-                       SCLK_CNTL_M6__FORCE_TAM|
-                       SCLK_CNTL_M6__FORCE_TDM|
-                       SCLK_CNTL_M6__FORCE_RB|
-                       SCLK_CNTL_M6__FORCE_TV_SCLK|
-                       SCLK_CNTL_M6__FORCE_SUBPIC|
-                       SCLK_CNTL_M6__FORCE_OV0;
-
-       OUTPLL( pllSCLK_CNTL_M6, sclk_cntl);
+                       SCLK_CNTL__FORCE_PB|
+                       SCLK_CNTL__FORCE_TAM|
+                       SCLK_CNTL__FORCE_TDM|
+                       SCLK_CNTL__FORCE_RB|
+                       SCLK_CNTL__FORCE_TV_SCLK|
+                       SCLK_CNTL__FORCE_SUBPIC|
+                       SCLK_CNTL__FORCE_OV0;
+       if (rinfo->family <= CHIP_FAMILY_RV280)
+               sclk_cntl |= SCLK_CNTL__FORCE_RE;
+       else
+               sclk_cntl |= SCLK_CNTL__SE_MAX_DYN_STOP_LAT |
+                       SCLK_CNTL__E2_MAX_DYN_STOP_LAT |
+                       SCLK_CNTL__TV_MAX_DYN_STOP_LAT |
+                       SCLK_CNTL__HDP_MAX_DYN_STOP_LAT |
+                       SCLK_CNTL__CP_MAX_DYN_STOP_LAT;
+
+       OUTPLL( pllSCLK_CNTL, sclk_cntl);
 
        sclk_more_cntl = INPLL(pllSCLK_MORE_CNTL);
        sclk_more_cntl |=       SCLK_MORE_CNTL__FORCE_DISPREGS |
@@ -438,18 +780,19 @@ static void radeon_pm_setup_for_suspend(struct radeonfb_info *rinfo)
        OUTPLL(pllSCLK_MORE_CNTL, sclk_more_cntl);              
 
        
-       mclk_cntl = INPLL( pllMCLK_CNTL_M6);
-       mclk_cntl &= ~( MCLK_CNTL_M6__FORCE_MCLKA |  
-                       MCLK_CNTL_M6__FORCE_MCLKB |
-                       MCLK_CNTL_M6__FORCE_YCLKA | 
-                       MCLK_CNTL_M6__FORCE_YCLKB | 
-                       MCLK_CNTL_M6__FORCE_MC
+       mclk_cntl = INPLL( pllMCLK_CNTL);
+       mclk_cntl &= ~( MCLK_CNTL__FORCE_MCLKA |
+                       MCLK_CNTL__FORCE_MCLKB |
+                       MCLK_CNTL__FORCE_YCLKA |
+                       MCLK_CNTL__FORCE_YCLKB |
+                       MCLK_CNTL__FORCE_MC
                      );        
-       OUTPLL( pllMCLK_CNTL_M6, mclk_cntl);
+       OUTPLL( pllMCLK_CNTL, mclk_cntl);
        
        /* Force Display clocks */
        vclk_ecp_cntl = INPLL( pllVCLK_ECP_CNTL);
-       vclk_ecp_cntl &= ~(VCLK_ECP_CNTL__PIXCLK_ALWAYS_ONb |VCLK_ECP_CNTL__PIXCLK_DAC_ALWAYS_ONb);
+       vclk_ecp_cntl &= ~(VCLK_ECP_CNTL__PIXCLK_ALWAYS_ONb
+                          | VCLK_ECP_CNTL__PIXCLK_DAC_ALWAYS_ONb);
        vclk_ecp_cntl |= VCLK_ECP_CNTL__ECP_FORCE_ON;
        OUTPLL( pllVCLK_ECP_CNTL, vclk_ecp_cntl);
        
@@ -465,7 +808,9 @@ static void radeon_pm_setup_for_suspend(struct radeonfb_info *rinfo)
                                                
        OUTPLL( pllPIXCLKS_CNTL, pixclks_cntl);
 
-
+       /* Switch off LVDS interface */
+       OUTREG(LVDS_GEN_CNTL, INREG(LVDS_GEN_CNTL) &
+              ~(LVDS_BLON | LVDS_EN | LVDS_ON | LVDS_DIGON));
 
        /* Enable System power management */
        pll_pwrmgt_cntl = INPLL( pllPLL_PWRMGT_CNTL);
@@ -478,26 +823,27 @@ static void radeon_pm_setup_for_suspend(struct radeonfb_info *rinfo)
                                                
        OUTPLL( pllPLL_PWRMGT_CNTL, pll_pwrmgt_cntl);
        
-       clk_pwrmgt_cntl  = INPLL( pllCLK_PWRMGT_CNTL_M6);
+       clk_pwrmgt_cntl  = INPLL( pllCLK_PWRMGT_CNTL);
        
-       clk_pwrmgt_cntl &= ~(   CLK_PWRMGT_CNTL_M6__MPLL_PWRMGT_OFF|
-                               CLK_PWRMGT_CNTL_M6__SPLL_PWRMGT_OFF|
-                               CLK_PWRMGT_CNTL_M6__PPLL_PWRMGT_OFF|
-                               CLK_PWRMGT_CNTL_M6__P2PLL_PWRMGT_OFF|
-                               CLK_PWRMGT_CNTL_M6__MCLK_TURNOFF|
-                               CLK_PWRMGT_CNTL_M6__SCLK_TURNOFF|
-                               CLK_PWRMGT_CNTL_M6__PCLK_TURNOFF|
-                               CLK_PWRMGT_CNTL_M6__P2CLK_TURNOFF|
-                               CLK_PWRMGT_CNTL_M6__TVPLL_PWRMGT_OFF|
-                               CLK_PWRMGT_CNTL_M6__GLOBAL_PMAN_EN|
-                               CLK_PWRMGT_CNTL_M6__ENGINE_DYNCLK_MODE|
-                               CLK_PWRMGT_CNTL_M6__ACTIVE_HILO_LAT_MASK|
-                               CLK_PWRMGT_CNTL_M6__CG_NO1_DEBUG_MASK                   
+       clk_pwrmgt_cntl &= ~(   CLK_PWRMGT_CNTL__MPLL_PWRMGT_OFF|
+                               CLK_PWRMGT_CNTL__SPLL_PWRMGT_OFF|
+                               CLK_PWRMGT_CNTL__PPLL_PWRMGT_OFF|
+                               CLK_PWRMGT_CNTL__P2PLL_PWRMGT_OFF|
+                               CLK_PWRMGT_CNTL__MCLK_TURNOFF|
+                               CLK_PWRMGT_CNTL__SCLK_TURNOFF|
+                               CLK_PWRMGT_CNTL__PCLK_TURNOFF|
+                               CLK_PWRMGT_CNTL__P2CLK_TURNOFF|
+                               CLK_PWRMGT_CNTL__TVPLL_PWRMGT_OFF|
+                               CLK_PWRMGT_CNTL__GLOBAL_PMAN_EN|
+                               CLK_PWRMGT_CNTL__ENGINE_DYNCLK_MODE|
+                               CLK_PWRMGT_CNTL__ACTIVE_HILO_LAT_MASK|
+                               CLK_PWRMGT_CNTL__CG_NO1_DEBUG_MASK
                        );
                                                
-       clk_pwrmgt_cntl |= CLK_PWRMGT_CNTL_M6__GLOBAL_PMAN_EN | CLK_PWRMGT_CNTL_M6__DISP_PM;
+       clk_pwrmgt_cntl |= CLK_PWRMGT_CNTL__GLOBAL_PMAN_EN
+               | CLK_PWRMGT_CNTL__DISP_PM;
        
-       OUTPLL( pllCLK_PWRMGT_CNTL_M6, clk_pwrmgt_cntl);        
+       OUTPLL( pllCLK_PWRMGT_CNTL, clk_pwrmgt_cntl);
        
        clk_pin_cntl = INPLL( pllCLK_PIN_CNTL);
        
@@ -508,12 +854,19 @@ static void radeon_pm_setup_for_suspend(struct radeonfb_info *rinfo)
        OUTPLL( pllMCLK_MISC, tmp);
        
        /* AGP PLL control */
-       OUTREG(BUS_CNTL1, INREG(BUS_CNTL1) |  BUS_CNTL1__AGPCLK_VALID);
+       if (rinfo->family <= CHIP_FAMILY_RV280) {
+               OUTREG(BUS_CNTL1, INREG(BUS_CNTL1) |  BUS_CNTL1__AGPCLK_VALID);
 
-       OUTREG(BUS_CNTL1,
-               (INREG(BUS_CNTL1) & ~BUS_CNTL1__MOBILE_PLATFORM_SEL_MASK)
-               | (2<<BUS_CNTL1__MOBILE_PLATFORM_SEL__SHIFT));  // 440BX
-       OUTREG(CRTC_OFFSET_CNTL, (INREG(CRTC_OFFSET_CNTL) & ~CRTC_OFFSET_CNTL__CRTC_STEREO_SYNC_OUT_EN));
+               OUTREG(BUS_CNTL1,
+                      (INREG(BUS_CNTL1) & ~BUS_CNTL1__MOBILE_PLATFORM_SEL_MASK)
+                      | (2<<BUS_CNTL1__MOBILE_PLATFORM_SEL__SHIFT));   // 440BX
+       } else {
+               OUTREG(BUS_CNTL1, INREG(BUS_CNTL1));
+               OUTREG(BUS_CNTL1, (INREG(BUS_CNTL1) & ~0x4000) | 0x8000);
+       }
+
+       OUTREG(CRTC_OFFSET_CNTL, (INREG(CRTC_OFFSET_CNTL)
+                                 & ~CRTC_OFFSET_CNTL__CRTC_STEREO_SYNC_OUT_EN));
        
        clk_pin_cntl &= ~CLK_PIN_CNTL__CG_CLK_TO_OUTPIN;
        clk_pin_cntl |= CLK_PIN_CNTL__XTALIN_ALWAYS_ONb;        
@@ -545,16 +898,16 @@ static void radeon_pm_setup_for_suspend(struct radeonfb_info *rinfo)
                                DISP_MISC_CNTL__SOFT_RESET_DIG_TMDS|
                                DISP_MISC_CNTL__SOFT_RESET_TV);
        
-       OUTREG(DISP_MISC_CNTL, disp_mis_cntl);                                  
+       OUTREG(DISP_MISC_CNTL, disp_mis_cntl);
                                                
        disp_pwr_man = INREG(DISP_PWR_MAN);
        
        disp_pwr_man &= ~(      DISP_PWR_MAN__DISP_PWR_MAN_D3_CRTC_EN   | 
-                                               DISP_PWR_MAN__DISP2_PWR_MAN_D3_CRTC2_EN |
-                                               DISP_PWR_MAN__DISP_PWR_MAN_DPMS_MASK|           
-                                               DISP_PWR_MAN__DISP_D3_RST|
-                                               DISP_PWR_MAN__DISP_D3_REG_RST
-                                       );
+                               DISP_PWR_MAN__DISP2_PWR_MAN_D3_CRTC2_EN |
+                               DISP_PWR_MAN__DISP_PWR_MAN_DPMS_MASK|
+                               DISP_PWR_MAN__DISP_D3_RST|
+                               DISP_PWR_MAN__DISP_D3_REG_RST
+                               );
        
        disp_pwr_man |= DISP_PWR_MAN__DISP_D3_GRPH_RST|
                                        DISP_PWR_MAN__DISP_D3_SUBPIC_RST|
@@ -569,27 +922,29 @@ static void radeon_pm_setup_for_suspend(struct radeonfb_info *rinfo)
        
        OUTREG(DISP_PWR_MAN, disp_pwr_man);                                     
                                                        
-       clk_pwrmgt_cntl = INPLL( pllCLK_PWRMGT_CNTL_M6);
+       clk_pwrmgt_cntl = INPLL( pllCLK_PWRMGT_CNTL);
        pll_pwrmgt_cntl = INPLL( pllPLL_PWRMGT_CNTL) ;
        clk_pin_cntl    = INPLL( pllCLK_PIN_CNTL);
        disp_pwr_man    = INREG(DISP_PWR_MAN);
                
        
        /* D2 */
-       clk_pwrmgt_cntl |= CLK_PWRMGT_CNTL_M6__DISP_PM;
+       clk_pwrmgt_cntl |= CLK_PWRMGT_CNTL__DISP_PM;
        pll_pwrmgt_cntl |= PLL_PWRMGT_CNTL__MOBILE_SU | PLL_PWRMGT_CNTL__SU_SCLK_USE_BCLK;
        clk_pin_cntl    |= CLK_PIN_CNTL__XTALIN_ALWAYS_ONb;
-       disp_pwr_man    &= ~(DISP_PWR_MAN__DISP_PWR_MAN_D3_CRTC_EN_MASK | DISP_PWR_MAN__DISP2_PWR_MAN_D3_CRTC2_EN_MASK);                                                        
-                                               
+       disp_pwr_man    &= ~(DISP_PWR_MAN__DISP_PWR_MAN_D3_CRTC_EN_MASK
+                            | DISP_PWR_MAN__DISP2_PWR_MAN_D3_CRTC2_EN_MASK);
 
-       OUTPLL( pllCLK_PWRMGT_CNTL_M6, clk_pwrmgt_cntl);
+       OUTPLL( pllCLK_PWRMGT_CNTL, clk_pwrmgt_cntl);
        OUTPLL( pllPLL_PWRMGT_CNTL, pll_pwrmgt_cntl);
        OUTPLL( pllCLK_PIN_CNTL, clk_pin_cntl);
        OUTREG(DISP_PWR_MAN, disp_pwr_man);
 
        /* disable display request & disable display */
-       OUTREG( CRTC_GEN_CNTL, (INREG( CRTC_GEN_CNTL) & ~CRTC_GEN_CNTL__CRTC_EN) | CRTC_GEN_CNTL__CRTC_DISP_REQ_EN_B);
-       OUTREG( CRTC2_GEN_CNTL, (INREG( CRTC2_GEN_CNTL) & ~CRTC2_GEN_CNTL__CRTC2_EN) | CRTC2_GEN_CNTL__CRTC2_DISP_REQ_EN_B);
+       OUTREG( CRTC_GEN_CNTL, (INREG( CRTC_GEN_CNTL) & ~CRTC_GEN_CNTL__CRTC_EN)
+               | CRTC_GEN_CNTL__CRTC_DISP_REQ_EN_B);
+       OUTREG( CRTC2_GEN_CNTL, (INREG( CRTC2_GEN_CNTL) & ~CRTC2_GEN_CNTL__CRTC2_EN)
+               | CRTC2_GEN_CNTL__CRTC2_DISP_REQ_EN_B);
 
        mdelay(17);                                
 
@@ -599,17 +954,15 @@ static void radeon_pm_yclk_mclk_sync(struct radeonfb_info *rinfo)
 {
        u32 mc_chp_io_cntl_a1, mc_chp_io_cntl_b1;
 
-       mc_chp_io_cntl_a1 = INMC( rinfo, ixMC_CHP_IO_CNTL_A1) & ~MC_CHP_IO_CNTL_A1__MEM_SYNC_ENA_MASK;
-       mc_chp_io_cntl_b1 = INMC( rinfo, ixMC_CHP_IO_CNTL_B1) & ~MC_CHP_IO_CNTL_B1__MEM_SYNC_ENB_MASK;
+       mc_chp_io_cntl_a1 = INMC( rinfo, ixMC_CHP_IO_CNTL_A1)
+               & ~MC_CHP_IO_CNTL_A1__MEM_SYNC_ENA_MASK;
+       mc_chp_io_cntl_b1 = INMC( rinfo, ixMC_CHP_IO_CNTL_B1)
+               & ~MC_CHP_IO_CNTL_B1__MEM_SYNC_ENB_MASK;
 
-       OUTMC( rinfo, ixMC_CHP_IO_CNTL_A1, mc_chp_io_cntl_a1 | (1<<MC_CHP_IO_CNTL_A1__MEM_SYNC_ENA__SHIFT));
-       OUTMC( rinfo, ixMC_CHP_IO_CNTL_B1, mc_chp_io_cntl_b1 | (1<<MC_CHP_IO_CNTL_B1__MEM_SYNC_ENB__SHIFT));
-
-       /* Wassup ? This doesn't seem to be defined, let's hope we are ok this way --BenH */
-#ifdef MCLK_YCLK_SYNC_ENABLE
-       mc_chp_io_cntl_a1 |= (2<<MC_CHP_IO_CNTL_A1__MEM_SYNC_ENA__SHIFT);
-       mc_chp_io_cntl_b1 |= (2<<MC_CHP_IO_CNTL_B1__MEM_SYNC_ENB__SHIFT);
-#endif
+       OUTMC( rinfo, ixMC_CHP_IO_CNTL_A1, mc_chp_io_cntl_a1
+              | (1<<MC_CHP_IO_CNTL_A1__MEM_SYNC_ENA__SHIFT));
+       OUTMC( rinfo, ixMC_CHP_IO_CNTL_B1, mc_chp_io_cntl_b1
+              | (1<<MC_CHP_IO_CNTL_B1__MEM_SYNC_ENB__SHIFT));
 
        OUTMC( rinfo, ixMC_CHP_IO_CNTL_A1, mc_chp_io_cntl_a1);
        OUTMC( rinfo, ixMC_CHP_IO_CNTL_B1, mc_chp_io_cntl_b1);
@@ -617,25 +970,70 @@ static void radeon_pm_yclk_mclk_sync(struct radeonfb_info *rinfo)
        mdelay( 1);
 }
 
-static void radeon_pm_program_mode_reg(struct radeonfb_info *rinfo, u16 value, u8 delay_required)
+static void radeon_pm_yclk_mclk_sync_m10(struct radeonfb_info *rinfo)
+{
+       u32 mc_chp_io_cntl_a1, mc_chp_io_cntl_b1;
+
+       mc_chp_io_cntl_a1 = INMC(rinfo, ixR300_MC_CHP_IO_CNTL_A1)
+               & ~MC_CHP_IO_CNTL_A1__MEM_SYNC_ENA_MASK;
+       mc_chp_io_cntl_b1 = INMC(rinfo, ixR300_MC_CHP_IO_CNTL_B1)
+               & ~MC_CHP_IO_CNTL_B1__MEM_SYNC_ENB_MASK;
+
+       OUTMC( rinfo, ixR300_MC_CHP_IO_CNTL_A1,
+              mc_chp_io_cntl_a1 | (1<<MC_CHP_IO_CNTL_A1__MEM_SYNC_ENA__SHIFT));
+       OUTMC( rinfo, ixR300_MC_CHP_IO_CNTL_B1,
+              mc_chp_io_cntl_b1 | (1<<MC_CHP_IO_CNTL_B1__MEM_SYNC_ENB__SHIFT));
+
+       OUTMC( rinfo, ixR300_MC_CHP_IO_CNTL_A1, mc_chp_io_cntl_a1);
+       OUTMC( rinfo, ixR300_MC_CHP_IO_CNTL_B1, mc_chp_io_cntl_b1);
+
+       mdelay( 1);
+}
+
+static void radeon_pm_program_mode_reg(struct radeonfb_info *rinfo, u16 value,
+                                      u8 delay_required)
 {  
        u32 mem_sdram_mode;
 
        mem_sdram_mode  = INREG( MEM_SDRAM_MODE_REG);
 
        mem_sdram_mode &= ~MEM_SDRAM_MODE_REG__MEM_MODE_REG_MASK;
-       mem_sdram_mode |= (value<<MEM_SDRAM_MODE_REG__MEM_MODE_REG__SHIFT) | MEM_SDRAM_MODE_REG__MEM_CFG_TYPE;
+       mem_sdram_mode |= (value<<MEM_SDRAM_MODE_REG__MEM_MODE_REG__SHIFT)
+               | MEM_SDRAM_MODE_REG__MEM_CFG_TYPE;
        OUTREG( MEM_SDRAM_MODE_REG, mem_sdram_mode);
+       if (delay_required >= 2)
+               mdelay(1);
 
        mem_sdram_mode |=  MEM_SDRAM_MODE_REG__MEM_SDRAM_RESET;
        OUTREG( MEM_SDRAM_MODE_REG, mem_sdram_mode);
+       if (delay_required >= 2)
+               mdelay(1);
 
        mem_sdram_mode &= ~MEM_SDRAM_MODE_REG__MEM_SDRAM_RESET;
        OUTREG( MEM_SDRAM_MODE_REG, mem_sdram_mode);
+       if (delay_required >= 2)
+               mdelay(1);
+
+       if (delay_required) {
+               do {
+                       if (delay_required >= 2)
+                               mdelay(1);
+               } while ((INREG(MC_STATUS)
+                         & (MC_STATUS__MEM_PWRUP_COMPL_A |
+                            MC_STATUS__MEM_PWRUP_COMPL_B)) == 0);
+       }
+}
 
-       if (delay_required == 1)
-               while( (INREG( MC_STATUS) & (MC_STATUS__MEM_PWRUP_COMPL_A | MC_STATUS__MEM_PWRUP_COMPL_B) ) == 0 )
-                       { };    
+static void radeon_pm_m10_program_mode_wait(struct radeonfb_info *rinfo)
+{
+       int cnt;
+
+       for (cnt = 0; cnt < 100; ++cnt) {
+               mdelay(1);
+               if (INREG(MC_STATUS) & (MC_STATUS__MEM_PWRUP_COMPL_A
+                                       | MC_STATUS__MEM_PWRUP_COMPL_B))
+                       break;
+       }
 }
 
 
@@ -644,126 +1042,274 @@ static void radeon_pm_enable_dll(struct radeonfb_info *rinfo)
 #define DLL_RESET_DELAY        5
 #define DLL_SLEEP_DELAY                1
 
-       u32 DLL_CKO_Value = INPLL(pllMDLL_CKO)   | MDLL_CKO__MCKOA_SLEEP |  MDLL_CKO__MCKOA_RESET;
-       u32 DLL_CKA_Value = INPLL(pllMDLL_RDCKA) | MDLL_RDCKA__MRDCKA0_SLEEP | MDLL_RDCKA__MRDCKA1_SLEEP | MDLL_RDCKA__MRDCKA0_RESET | MDLL_RDCKA__MRDCKA1_RESET;
-       u32 DLL_CKB_Value = INPLL(pllMDLL_RDCKB) | MDLL_RDCKB__MRDCKB0_SLEEP | MDLL_RDCKB__MRDCKB1_SLEEP | MDLL_RDCKB__MRDCKB0_RESET | MDLL_RDCKB__MRDCKB1_RESET;
+       u32 cko = INPLL(pllMDLL_CKO)   | MDLL_CKO__MCKOA_SLEEP
+               | MDLL_CKO__MCKOA_RESET;
+       u32 cka = INPLL(pllMDLL_RDCKA) | MDLL_RDCKA__MRDCKA0_SLEEP
+               | MDLL_RDCKA__MRDCKA1_SLEEP | MDLL_RDCKA__MRDCKA0_RESET
+               | MDLL_RDCKA__MRDCKA1_RESET;
+       u32 ckb = INPLL(pllMDLL_RDCKB) | MDLL_RDCKB__MRDCKB0_SLEEP
+               | MDLL_RDCKB__MRDCKB1_SLEEP | MDLL_RDCKB__MRDCKB0_RESET
+               | MDLL_RDCKB__MRDCKB1_RESET;
 
        /* Setting up the DLL range for write */
-       OUTPLL(pllMDLL_CKO,     DLL_CKO_Value);
-       OUTPLL(pllMDLL_RDCKA,   DLL_CKA_Value);
-       OUTPLL(pllMDLL_RDCKB,   DLL_CKB_Value);
-
-       mdelay( DLL_RESET_DELAY);
-
-       /* Channel A */
-
-       /* Power Up */
-       DLL_CKO_Value &= ~(MDLL_CKO__MCKOA_SLEEP );
-       OUTPLL(pllMDLL_CKO,     DLL_CKO_Value);
-       mdelay( DLL_SLEEP_DELAY);               
-   
-       DLL_CKO_Value &= ~(MDLL_CKO__MCKOA_RESET );
-       OUTPLL(pllMDLL_CKO,     DLL_CKO_Value);
-       mdelay( DLL_RESET_DELAY);               
-
-       /* Power Up */
-       DLL_CKA_Value &= ~(MDLL_RDCKA__MRDCKA0_SLEEP );
-       OUTPLL(pllMDLL_RDCKA,   DLL_CKA_Value);
-       mdelay( DLL_SLEEP_DELAY);               
-
-       DLL_CKA_Value &= ~(MDLL_RDCKA__MRDCKA0_RESET );
-       OUTPLL(pllMDLL_RDCKA,   DLL_CKA_Value);
-       mdelay( DLL_RESET_DELAY);               
-
-       /* Power Up */
-       DLL_CKA_Value &= ~(MDLL_RDCKA__MRDCKA1_SLEEP);
-       OUTPLL(pllMDLL_RDCKA,   DLL_CKA_Value);
-       mdelay( DLL_SLEEP_DELAY);               
-
-       DLL_CKA_Value &= ~(MDLL_RDCKA__MRDCKA1_RESET);
-       OUTPLL(pllMDLL_RDCKA,   DLL_CKA_Value);
-       mdelay( DLL_RESET_DELAY);               
-
+       OUTPLL(pllMDLL_CKO,     cko);
+       OUTPLL(pllMDLL_RDCKA,   cka);
+       OUTPLL(pllMDLL_RDCKB,   ckb);
+
+       mdelay(DLL_RESET_DELAY*2);
+
+       cko &= ~(MDLL_CKO__MCKOA_SLEEP | MDLL_CKO__MCKOB_SLEEP);
+       OUTPLL(pllMDLL_CKO, cko);
+       mdelay(DLL_SLEEP_DELAY);
+       cko &= ~(MDLL_CKO__MCKOA_RESET | MDLL_CKO__MCKOB_RESET);
+       OUTPLL(pllMDLL_CKO, cko);
+       mdelay(DLL_RESET_DELAY);
+
+       cka &= ~(MDLL_RDCKA__MRDCKA0_SLEEP | MDLL_RDCKA__MRDCKA1_SLEEP);
+       OUTPLL(pllMDLL_RDCKA, cka);
+       mdelay(DLL_SLEEP_DELAY);
+       cka &= ~(MDLL_RDCKA__MRDCKA0_RESET | MDLL_RDCKA__MRDCKA1_RESET);
+       OUTPLL(pllMDLL_RDCKA, cka);
+       mdelay(DLL_RESET_DELAY);
+
+       ckb &= ~(MDLL_RDCKB__MRDCKB0_SLEEP | MDLL_RDCKB__MRDCKB1_SLEEP);
+       OUTPLL(pllMDLL_RDCKB, ckb);
+       mdelay(DLL_SLEEP_DELAY);
+       ckb &= ~(MDLL_RDCKB__MRDCKB0_RESET | MDLL_RDCKB__MRDCKB1_RESET);
+       OUTPLL(pllMDLL_RDCKB, ckb);
+       mdelay(DLL_RESET_DELAY);
+
+
+#undef DLL_RESET_DELAY
+#undef DLL_SLEEP_DELAY
+}
 
-       /* Channel B */
+static void radeon_pm_enable_dll_m10(struct radeonfb_info *rinfo)
+{
+       u32 dll_value;
+       u32 dll_sleep_mask = 0;
+       u32 dll_reset_mask = 0;
+       u32 mc;
 
-       /* Power Up */
-       DLL_CKO_Value &= ~(MDLL_CKO__MCKOB_SLEEP );
-       OUTPLL(pllMDLL_CKO,     DLL_CKO_Value);
-       mdelay( DLL_SLEEP_DELAY);               
-   
-       DLL_CKO_Value &= ~(MDLL_CKO__MCKOB_RESET );
-       OUTPLL(pllMDLL_CKO,     DLL_CKO_Value);
-       mdelay( DLL_RESET_DELAY);               
+#define DLL_RESET_DELAY        5
+#define DLL_SLEEP_DELAY                1
 
-       /* Power Up */
-       DLL_CKB_Value &= ~(MDLL_RDCKB__MRDCKB0_SLEEP);
-       OUTPLL(pllMDLL_RDCKB,   DLL_CKB_Value);
-       mdelay( DLL_SLEEP_DELAY);               
+       OUTMC(rinfo, ixR300_MC_DLL_CNTL, rinfo->save_regs[70]);
+       mc = INREG(MC_CNTL);
+       /* Check which channels are enabled */
+       switch (mc & 0x3) {
+       case 1:
+               if (mc & 0x4)
+                       break;
+       case 2:
+               dll_sleep_mask |= MDLL_R300_RDCK__MRDCKB_SLEEP;
+               dll_reset_mask |= MDLL_R300_RDCK__MRDCKB_RESET;
+       case 0:
+               dll_sleep_mask |= MDLL_R300_RDCK__MRDCKA_SLEEP;
+               dll_reset_mask |= MDLL_R300_RDCK__MRDCKA_RESET;
+       }
+       switch (mc & 0x3) {
+       case 1:
+               if (!(mc & 0x4))
+                       break;
+       case 2:
+               dll_sleep_mask |= MDLL_R300_RDCK__MRDCKD_SLEEP;
+               dll_reset_mask |= MDLL_R300_RDCK__MRDCKD_RESET;
+               dll_sleep_mask |= MDLL_R300_RDCK__MRDCKC_SLEEP;
+               dll_reset_mask |= MDLL_R300_RDCK__MRDCKC_RESET;
+       }
 
-       DLL_CKB_Value &= ~(MDLL_RDCKB__MRDCKB0_RESET);
-       OUTPLL(pllMDLL_RDCKB,   DLL_CKB_Value);
-       mdelay( DLL_RESET_DELAY);               
+       dll_value = INPLL(pllMDLL_RDCKA);
 
        /* Power Up */
-       DLL_CKB_Value &= ~(MDLL_RDCKB__MRDCKB1_SLEEP);
-       OUTPLL(pllMDLL_RDCKB,   DLL_CKB_Value);
+       dll_value &= ~(dll_sleep_mask);
+       OUTPLL(pllMDLL_RDCKA, dll_value);
        mdelay( DLL_SLEEP_DELAY);               
 
-       DLL_CKB_Value &= ~(MDLL_RDCKB__MRDCKB1_RESET);
-       OUTPLL(pllMDLL_RDCKB,   DLL_CKB_Value);
+       dll_value &= ~(dll_reset_mask);
+       OUTPLL(pllMDLL_RDCKA, dll_value);
        mdelay( DLL_RESET_DELAY);               
 
 #undef DLL_RESET_DELAY 
 #undef DLL_SLEEP_DELAY
 }
 
+
 static void radeon_pm_full_reset_sdram(struct radeonfb_info *rinfo)
 {
-       u32 crtcGenCntl, crtcGenCntl2, memRefreshCntl, crtc_more_cntl, fp_gen_cntl, fp2_gen_cntl;
+       u32 crtcGenCntl, crtcGenCntl2, memRefreshCntl, crtc_more_cntl,
+               fp_gen_cntl, fp2_gen_cntl;
  
        crtcGenCntl  = INREG( CRTC_GEN_CNTL);
        crtcGenCntl2 = INREG( CRTC2_GEN_CNTL);
 
-       memRefreshCntl  = INREG( MEM_REFRESH_CNTL);
        crtc_more_cntl  = INREG( CRTC_MORE_CNTL);
        fp_gen_cntl     = INREG( FP_GEN_CNTL);
        fp2_gen_cntl    = INREG( FP2_GEN_CNTL);
  
 
-       OUTREG( CRTC_MORE_CNTL,         0);
-       OUTREG( FP_GEN_CNTL,    0);
-       OUTREG( FP2_GEN_CNTL,   0);
+       OUTREG( CRTC_MORE_CNTL, 0);
+       OUTREG( FP_GEN_CNTL, 0);
+       OUTREG( FP2_GEN_CNTL,0);
  
        OUTREG( CRTC_GEN_CNTL,  (crtcGenCntl | CRTC_GEN_CNTL__CRTC_DISP_REQ_EN_B) );
        OUTREG( CRTC2_GEN_CNTL, (crtcGenCntl2 | CRTC2_GEN_CNTL__CRTC2_DISP_REQ_EN_B) );
   
-       /* Disable refresh */
-       OUTREG( MEM_REFRESH_CNTL, memRefreshCntl | MEM_REFRESH_CNTL__MEM_REFRESH_DIS);
+       /* This is the code for the Aluminium PowerBooks M10 */
+       if (rinfo->family == CHIP_FAMILY_RV350) {
+               u32 sdram_mode_reg = rinfo->save_regs[35];
+               static u32 default_mrtable[] =
+                       { 0x21320032,
+                         0x21321000, 0xa1321000, 0x21321000, 0xffffffff,
+                         0x21320032, 0xa1320032, 0x21320032, 0xffffffff,
+                         0x21321002, 0xa1321002, 0x21321002, 0xffffffff,
+                         0x21320132, 0xa1320132, 0x21320132, 0xffffffff,
+                         0x21320032, 0xa1320032, 0x21320032, 0xffffffff,
+                         0x31320032 };
+
+               u32 *mrtable = default_mrtable;
+               int i, mrtable_size = ARRAY_SIZE(default_mrtable);
+
+               mdelay(30);
+
+               /* Disable refresh */
+               memRefreshCntl  = INREG( MEM_REFRESH_CNTL)
+                       & ~MEM_REFRESH_CNTL__MEM_REFRESH_DIS;
+               OUTREG( MEM_REFRESH_CNTL, memRefreshCntl
+                       | MEM_REFRESH_CNTL__MEM_REFRESH_DIS);
+
+               /* Configure and enable M & SPLLs */
+                       radeon_pm_enable_dll_m10(rinfo);
+               radeon_pm_yclk_mclk_sync_m10(rinfo);
+
+#ifdef CONFIG_PPC_OF
+               if (rinfo->of_node != NULL) {
+                       int size;
+
+                       mrtable = (u32 *)get_property(rinfo->of_node, "ATY,MRT", &size);
+                       if (mrtable)
+                               mrtable_size = size >> 2;
+                       else
+                               mrtable = default_mrtable;
+               }
+#endif /* CONFIG_PPC_OF */
+
+               /* Program the SDRAM */
+               sdram_mode_reg = mrtable[0];
+               OUTREG(MEM_SDRAM_MODE_REG, sdram_mode_reg);
+               for (i = 0; i < mrtable_size; i++) {
+                       if (mrtable[i] == 0xffffffffu)
+                               radeon_pm_m10_program_mode_wait(rinfo);
+                       else {
+                               sdram_mode_reg &= ~(MEM_SDRAM_MODE_REG__MEM_MODE_REG_MASK
+                                                   | MEM_SDRAM_MODE_REG__MC_INIT_COMPLETE
+                                                   | MEM_SDRAM_MODE_REG__MEM_SDRAM_RESET);
+                               sdram_mode_reg |= mrtable[i];
+
+                               OUTREG(MEM_SDRAM_MODE_REG, sdram_mode_reg);
+                               mdelay(1);
+                       }
+               }
+
+               /* Restore memory refresh */
+               OUTREG(MEM_REFRESH_CNTL, memRefreshCntl);
+               mdelay(30);
+
+       }
+       /* Here come the desktop RV200 "QW" card */
+       else if (!rinfo->is_mobility && rinfo->family == CHIP_FAMILY_RV200) {
+               /* Disable refresh */
+               memRefreshCntl  = INREG( MEM_REFRESH_CNTL)
+                       & ~MEM_REFRESH_CNTL__MEM_REFRESH_DIS;
+               OUTREG(MEM_REFRESH_CNTL, memRefreshCntl
+                      | MEM_REFRESH_CNTL__MEM_REFRESH_DIS);
+               mdelay(30);
+
+               /* Reset memory */
+               OUTREG(MEM_SDRAM_MODE_REG,
+                      INREG( MEM_SDRAM_MODE_REG) & ~MEM_SDRAM_MODE_REG__MC_INIT_COMPLETE);
+
+               radeon_pm_program_mode_reg(rinfo, 0x2002, 2);
+               radeon_pm_program_mode_reg(rinfo, 0x0132, 2);
+               radeon_pm_program_mode_reg(rinfo, 0x0032, 2);
+
+               OUTREG(MEM_SDRAM_MODE_REG,
+                      INREG(MEM_SDRAM_MODE_REG) | MEM_SDRAM_MODE_REG__MC_INIT_COMPLETE);
+
+               OUTREG( MEM_REFRESH_CNTL,       memRefreshCntl);
+
+       }
+       /* The M6 */
+       else if (rinfo->is_mobility && rinfo->family == CHIP_FAMILY_RV100) {
+               /* Disable refresh */
+               memRefreshCntl = INREG(EXT_MEM_CNTL) & ~(1 << 20);
+               OUTREG( EXT_MEM_CNTL, memRefreshCntl | (1 << 20));
  
-       /* Reset memory */
-       OUTREG( MEM_SDRAM_MODE_REG,
-               INREG( MEM_SDRAM_MODE_REG) & ~MEM_SDRAM_MODE_REG__MC_INIT_COMPLETE); // Init  Not Complete
+               /* Reset memory */
+               OUTREG( MEM_SDRAM_MODE_REG,
+                       INREG( MEM_SDRAM_MODE_REG)
+                       & ~MEM_SDRAM_MODE_REG__MC_INIT_COMPLETE);
 
-       /* DLL */
-       radeon_pm_enable_dll(rinfo);
+               /* DLL */
+               radeon_pm_enable_dll(rinfo);
 
-       // MLCK /YCLK sync 
-       radeon_pm_yclk_mclk_sync(rinfo);
+               /* MLCK / YCLK sync */
+               radeon_pm_yclk_mclk_sync(rinfo);
 
-               /* M6, M7 and M9 so far ... */
-       if (rinfo->is_mobility && rinfo->family <= CHIP_FAMILY_RV250) {
+               /* Program Mode Register */
                radeon_pm_program_mode_reg(rinfo, 0x2000, 1);   
                radeon_pm_program_mode_reg(rinfo, 0x2001, 1);   
                radeon_pm_program_mode_reg(rinfo, 0x2002, 1);   
                radeon_pm_program_mode_reg(rinfo, 0x0132, 1);   
                radeon_pm_program_mode_reg(rinfo, 0x0032, 1); 
-       }       
 
-       OUTREG( MEM_SDRAM_MODE_REG,
-               INREG( MEM_SDRAM_MODE_REG) |  MEM_SDRAM_MODE_REG__MC_INIT_COMPLETE); // Init Complete
+               /* Complete & re-enable refresh */
+               OUTREG( MEM_SDRAM_MODE_REG,
+                       INREG( MEM_SDRAM_MODE_REG) | MEM_SDRAM_MODE_REG__MC_INIT_COMPLETE);
+
+               OUTREG(EXT_MEM_CNTL, memRefreshCntl);
+       }
+       /* And finally, the M7..M9 models, including M9+ (RV280) */
+       else if (rinfo->is_mobility) {
+
+               /* Disable refresh */
+               memRefreshCntl  = INREG( MEM_REFRESH_CNTL)
+                       & ~MEM_REFRESH_CNTL__MEM_REFRESH_DIS;
+               OUTREG( MEM_REFRESH_CNTL, memRefreshCntl
+                       | MEM_REFRESH_CNTL__MEM_REFRESH_DIS);
+
+               /* Reset memory */
+               OUTREG( MEM_SDRAM_MODE_REG,
+                       INREG( MEM_SDRAM_MODE_REG)
+                       & ~MEM_SDRAM_MODE_REG__MC_INIT_COMPLETE);
+
+               /* DLL */
+               radeon_pm_enable_dll(rinfo);
+
+               /* MLCK / YCLK sync */
+               radeon_pm_yclk_mclk_sync(rinfo);
+
+               /* M6, M7 and M9 so far ... */
+               if (rinfo->family <= CHIP_FAMILY_RV250) {
+                       radeon_pm_program_mode_reg(rinfo, 0x2000, 1);
+                       radeon_pm_program_mode_reg(rinfo, 0x2001, 1);
+                       radeon_pm_program_mode_reg(rinfo, 0x2002, 1);
+                       radeon_pm_program_mode_reg(rinfo, 0x0132, 1);
+                       radeon_pm_program_mode_reg(rinfo, 0x0032, 1);
+               }
+               /* M9+ (iBook G4) */
+               else if (rinfo->family == CHIP_FAMILY_RV280) {
+                       radeon_pm_program_mode_reg(rinfo, 0x2000, 1);
+                       radeon_pm_program_mode_reg(rinfo, 0x0132, 1);
+                       radeon_pm_program_mode_reg(rinfo, 0x0032, 1);
+               }
+
+               /* Complete & re-enable refresh */
+               OUTREG( MEM_SDRAM_MODE_REG,
+                       INREG( MEM_SDRAM_MODE_REG) | MEM_SDRAM_MODE_REG__MC_INIT_COMPLETE);
 
-       OUTREG( MEM_REFRESH_CNTL,       memRefreshCntl);
+               OUTREG( MEM_REFRESH_CNTL,       memRefreshCntl);
+       }
 
        OUTREG( CRTC_GEN_CNTL,          crtcGenCntl);
        OUTREG( CRTC2_GEN_CNTL,         crtcGenCntl2);
@@ -775,10 +1321,1076 @@ static void radeon_pm_full_reset_sdram(struct radeonfb_info *rinfo)
        mdelay( 15);
 }
 
+#ifdef CONFIG_PPC_OF
+
+static void radeon_pm_reset_pad_ctlr_strength(struct radeonfb_info *rinfo)
+{
+       u32 tmp, tmp2;
+       int i,j;
+
+       /* Reset the PAD_CTLR_STRENGTH & wait for it to be stable */
+       INREG(PAD_CTLR_STRENGTH);
+       OUTREG(PAD_CTLR_STRENGTH, INREG(PAD_CTLR_STRENGTH) & ~PAD_MANUAL_OVERRIDE);
+       tmp = INREG(PAD_CTLR_STRENGTH);
+       for (i = j = 0; i < 65; ++i) {
+               mdelay(1);
+               tmp2 = INREG(PAD_CTLR_STRENGTH);
+               if (tmp != tmp2) {
+                       tmp = tmp2;
+                       i = 0;
+                       j++;
+                       if (j > 10) {
+                               printk(KERN_WARNING "radeon: PAD_CTLR_STRENGTH doesn't "
+                                      "stabilize !\n");
+                               break;
+                       }
+               }
+       }
+}
+
+static void radeon_pm_all_ppls_off(struct radeonfb_info *rinfo)
+{
+       u32 tmp;
+
+       tmp = INPLL(pllPPLL_CNTL);
+       OUTPLL(pllPPLL_CNTL, tmp | 0x3);
+       tmp = INPLL(pllP2PLL_CNTL);
+       OUTPLL(pllP2PLL_CNTL, tmp | 0x3);
+       tmp = INPLL(pllSPLL_CNTL);
+       OUTPLL(pllSPLL_CNTL, tmp | 0x3);
+       tmp = INPLL(pllMPLL_CNTL);
+       OUTPLL(pllMPLL_CNTL, tmp | 0x3);
+}
+
+static void radeon_pm_start_mclk_sclk(struct radeonfb_info *rinfo)
+{
+       u32 tmp;
+
+       /* Switch SPLL to PCI source */
+       tmp = INPLL(pllSCLK_CNTL);
+       OUTPLL(pllSCLK_CNTL, tmp & ~SCLK_CNTL__SCLK_SRC_SEL_MASK);
+
+       /* Reconfigure SPLL charge pump, VCO gain, duty cycle */
+       tmp = INPLL(pllSPLL_CNTL);
+       OUTREG8(CLOCK_CNTL_INDEX, pllSPLL_CNTL + PLL_WR_EN);
+       OUTREG8(CLOCK_CNTL_DATA + 1, (tmp >> 8) & 0xff);
+
+       /* Set SPLL feedback divider */
+       tmp = INPLL(pllM_SPLL_REF_FB_DIV);
+       tmp = (tmp & 0xff00fffful) | (rinfo->save_regs[77] & 0x00ff0000ul);
+       OUTPLL(pllM_SPLL_REF_FB_DIV, tmp);
+
+       /* Power up SPLL */
+       tmp = INPLL(pllSPLL_CNTL);
+       OUTPLL(pllSPLL_CNTL, tmp & ~1);
+       (void)INPLL(pllSPLL_CNTL);
+
+       mdelay(10);
+
+       /* Release SPLL reset */
+       tmp = INPLL(pllSPLL_CNTL);
+       OUTPLL(pllSPLL_CNTL, tmp & ~0x2);
+       (void)INPLL(pllSPLL_CNTL);
+
+       mdelay(10);
+
+       /* Select SCLK source  */
+       tmp = INPLL(pllSCLK_CNTL);
+       tmp &= ~SCLK_CNTL__SCLK_SRC_SEL_MASK;
+       tmp |= rinfo->save_regs[3] & SCLK_CNTL__SCLK_SRC_SEL_MASK;
+       OUTPLL(pllSCLK_CNTL, tmp);
+       (void)INPLL(pllSCLK_CNTL);
+
+       mdelay(10);
+
+       /* Reconfigure MPLL charge pump, VCO gain, duty cycle */
+       tmp = INPLL(pllMPLL_CNTL);
+       OUTREG8(CLOCK_CNTL_INDEX, pllMPLL_CNTL + PLL_WR_EN);
+       OUTREG8(CLOCK_CNTL_DATA + 1, (tmp >> 8) & 0xff);
+
+       /* Set MPLL feedback divider */
+       tmp = INPLL(pllM_SPLL_REF_FB_DIV);
+       tmp = (tmp & 0xffff00fful) | (rinfo->save_regs[77] & 0x0000ff00ul);
+
+       OUTPLL(pllM_SPLL_REF_FB_DIV, tmp);
+       /* Power up MPLL */
+       tmp = INPLL(pllMPLL_CNTL);
+       OUTPLL(pllMPLL_CNTL, tmp & ~0x2);
+       (void)INPLL(pllMPLL_CNTL);
+
+       mdelay(10);
+
+       /* Un-reset MPLL */
+       tmp = INPLL(pllMPLL_CNTL);
+       OUTPLL(pllMPLL_CNTL, tmp & ~0x1);
+       (void)INPLL(pllMPLL_CNTL);
+
+       mdelay(10);
+
+       /* Select source for MCLK */
+       tmp = INPLL(pllMCLK_CNTL);
+       tmp |= rinfo->save_regs[2] & 0xffff;
+       OUTPLL(pllMCLK_CNTL, tmp);
+       (void)INPLL(pllMCLK_CNTL);
+
+       mdelay(10);
+}
+
+static void radeon_pm_m10_disable_spread_spectrum(struct radeonfb_info *rinfo)
+{
+       u32 r2ec;
+
+       /* GACK ! I though we didn't have a DDA on Radeon's anymore
+        * here we rewrite with the same value, ... I suppose we clear
+        * some bits that are already clear ? Or maybe this 0x2ec
+        * register is something new ?
+        */
+       mdelay(20);
+       r2ec = INREG(VGA_DDA_ON_OFF);
+       OUTREG(VGA_DDA_ON_OFF, r2ec);
+       mdelay(1);
+
+       /* Spread spectrum PLLL off */
+       OUTPLL(pllSSPLL_CNTL, 0xbf03);
+
+       /* Spread spectrum disabled */
+       OUTPLL(pllSS_INT_CNTL, rinfo->save_regs[90] & ~3);
+
+       /* The trace shows read & rewrite of LVDS_PLL_CNTL here with same
+        * value, not sure what for...
+        */
+
+       r2ec |= 0x3f0;
+       OUTREG(VGA_DDA_ON_OFF, r2ec);
+       mdelay(1);
+}
+
+static void radeon_pm_m10_enable_lvds_spread_spectrum(struct radeonfb_info *rinfo)
+{
+       u32 r2ec, tmp;
+
+       /* GACK (bis) ! I though we didn't have a DDA on Radeon's anymore
+        * here we rewrite with the same value, ... I suppose we clear/set
+        * some bits that are already clear/set ?
+        */
+       r2ec = INREG(VGA_DDA_ON_OFF);
+       OUTREG(VGA_DDA_ON_OFF, r2ec);
+       mdelay(1);
+
+       /* Enable spread spectrum */
+       OUTPLL(pllSSPLL_CNTL, rinfo->save_regs[43] | 3);
+       mdelay(3);
+
+       OUTPLL(pllSSPLL_REF_DIV, rinfo->save_regs[44]);
+       OUTPLL(pllSSPLL_DIV_0, rinfo->save_regs[45]);
+       tmp = INPLL(pllSSPLL_CNTL);
+       OUTPLL(pllSSPLL_CNTL, tmp & ~0x2);
+       mdelay(6);
+       tmp = INPLL(pllSSPLL_CNTL);
+       OUTPLL(pllSSPLL_CNTL, tmp & ~0x1);
+       mdelay(5);
+
+               OUTPLL(pllSS_INT_CNTL, rinfo->save_regs[90]);
+
+       r2ec |= 8;
+       OUTREG(VGA_DDA_ON_OFF, r2ec);
+       mdelay(20);
+
+       /* Enable LVDS interface */
+       tmp = INREG(LVDS_GEN_CNTL);
+       OUTREG(LVDS_GEN_CNTL, tmp | LVDS_EN);
+
+       /* Enable LVDS_PLL */
+       tmp = INREG(LVDS_PLL_CNTL);
+       tmp &= ~0x30000;
+       tmp |= 0x10000;
+       OUTREG(LVDS_PLL_CNTL, tmp);
+
+       OUTPLL(pllSCLK_MORE_CNTL, rinfo->save_regs[34]);
+       OUTPLL(pllSS_TST_CNTL, rinfo->save_regs[91]);
+
+       /* The trace reads that one here, waiting for something to settle down ? */
+       INREG(RBBM_STATUS);
+
+       /* Ugh ? SS_TST_DEC is supposed to be a read register in the
+        * R300 register spec at least...
+        */
+       tmp = INPLL(pllSS_TST_CNTL);
+       tmp |= 0x00400000;
+       OUTPLL(pllSS_TST_CNTL, tmp);
+}
+
+static void radeon_pm_restore_pixel_pll(struct radeonfb_info *rinfo)
+{
+       u32 tmp;
+
+       OUTREG8(CLOCK_CNTL_INDEX, pllHTOTAL_CNTL + PLL_WR_EN);
+       OUTREG8(CLOCK_CNTL_DATA, 0);
+
+       tmp = INPLL(pllVCLK_ECP_CNTL);
+       OUTPLL(pllVCLK_ECP_CNTL, tmp | 0x80);
+       mdelay(5);
+
+       tmp = INPLL(pllPPLL_REF_DIV);
+       tmp = (tmp & ~PPLL_REF_DIV_MASK) | rinfo->pll.ref_div;
+       OUTPLL(pllPPLL_REF_DIV, tmp);
+       INPLL(pllPPLL_REF_DIV);
+
+       /* Reconfigure SPLL charge pump, VCO gain, duty cycle,
+        * probably useless since we already did it ...
+        */
+       tmp = INPLL(pllPPLL_CNTL);
+       OUTREG8(CLOCK_CNTL_INDEX, pllSPLL_CNTL + PLL_WR_EN);
+       OUTREG8(CLOCK_CNTL_DATA + 1, (tmp >> 8) & 0xff);
+
+       /* Not sure what was intended here ... */
+       tmp = INREG(CLOCK_CNTL_INDEX);
+       OUTREG(CLOCK_CNTL_INDEX, tmp);
+
+       /* Restore our "reference" PPLL divider set by firmware
+        * according to proper spread spectrum calculations
+        */
+       OUTPLL(pllPPLL_DIV_0, rinfo->save_regs[92]);
+
+       tmp = INPLL(pllPPLL_CNTL);
+       OUTPLL(pllPPLL_CNTL, tmp & ~0x2);
+       mdelay(5);
+
+       tmp = INPLL(pllPPLL_CNTL);
+       OUTPLL(pllPPLL_CNTL, tmp & ~0x1);
+       mdelay(5);
+
+       tmp = INPLL(pllVCLK_ECP_CNTL);
+       OUTPLL(pllVCLK_ECP_CNTL, tmp | 3);
+       mdelay(5);
+
+       tmp = INPLL(pllVCLK_ECP_CNTL);
+       OUTPLL(pllVCLK_ECP_CNTL, tmp | 3);
+       mdelay(5);
+
+       /* Switch pixel clock to firmware default div 0 */
+       OUTREG8(CLOCK_CNTL_INDEX+1, 0);
+}
+
+static void radeon_pm_m10_reconfigure_mc(struct radeonfb_info *rinfo)
+{
+       OUTREG(MC_CNTL, rinfo->save_regs[46]);
+       OUTREG(MC_INIT_GFX_LAT_TIMER, rinfo->save_regs[47]);
+       OUTREG(MC_INIT_MISC_LAT_TIMER, rinfo->save_regs[48]);
+       OUTREG(MEM_SDRAM_MODE_REG,
+              rinfo->save_regs[35] & ~MEM_SDRAM_MODE_REG__MC_INIT_COMPLETE);
+       OUTREG(MC_TIMING_CNTL, rinfo->save_regs[49]);
+       OUTREG(MEM_REFRESH_CNTL, rinfo->save_regs[42]);
+       OUTREG(MC_READ_CNTL_AB, rinfo->save_regs[50]);
+       OUTREG(MC_CHIP_IO_OE_CNTL_AB, rinfo->save_regs[52]);
+       OUTREG(MC_IOPAD_CNTL, rinfo->save_regs[51]);
+       OUTREG(MC_DEBUG, rinfo->save_regs[53]);
+
+       OUTMC(rinfo, ixR300_MC_MC_INIT_WR_LAT_TIMER, rinfo->save_regs[58]);
+       OUTMC(rinfo, ixR300_MC_IMP_CNTL, rinfo->save_regs[59]);
+       OUTMC(rinfo, ixR300_MC_CHP_IO_CNTL_C0, rinfo->save_regs[60]);
+       OUTMC(rinfo, ixR300_MC_CHP_IO_CNTL_C1, rinfo->save_regs[61]);
+       OUTMC(rinfo, ixR300_MC_CHP_IO_CNTL_D0, rinfo->save_regs[62]);
+       OUTMC(rinfo, ixR300_MC_CHP_IO_CNTL_D1, rinfo->save_regs[63]);
+       OUTMC(rinfo, ixR300_MC_BIST_CNTL_3, rinfo->save_regs[64]);
+       OUTMC(rinfo, ixR300_MC_CHP_IO_CNTL_A0, rinfo->save_regs[65]);
+       OUTMC(rinfo, ixR300_MC_CHP_IO_CNTL_A1, rinfo->save_regs[66]);
+       OUTMC(rinfo, ixR300_MC_CHP_IO_CNTL_B0, rinfo->save_regs[67]);
+       OUTMC(rinfo, ixR300_MC_CHP_IO_CNTL_B1, rinfo->save_regs[68]);
+       OUTMC(rinfo, ixR300_MC_DEBUG_CNTL, rinfo->save_regs[69]);
+       OUTMC(rinfo, ixR300_MC_DLL_CNTL, rinfo->save_regs[70]);
+       OUTMC(rinfo, ixR300_MC_IMP_CNTL_0, rinfo->save_regs[71]);
+       OUTMC(rinfo, ixR300_MC_ELPIDA_CNTL, rinfo->save_regs[72]);
+       OUTMC(rinfo, ixR300_MC_READ_CNTL_CD, rinfo->save_regs[96]);
+       OUTREG(MC_IND_INDEX, 0);
+}
+
+static void radeon_reinitialize_M10(struct radeonfb_info *rinfo)
+{
+       u32 tmp, i;
+
+       /* Restore a bunch of registers first */
+       OUTREG(MC_AGP_LOCATION, rinfo->save_regs[32]);
+       OUTREG(DISPLAY_BASE_ADDR, rinfo->save_regs[31]);
+       OUTREG(CRTC2_DISPLAY_BASE_ADDR, rinfo->save_regs[33]);
+       OUTREG(MC_FB_LOCATION, rinfo->save_regs[30]);
+       OUTREG(OV0_BASE_ADDR, rinfo->save_regs[80]);
+       OUTREG(CONFIG_MEMSIZE, rinfo->video_ram);
+       OUTREG(BUS_CNTL, rinfo->save_regs[36]);
+       OUTREG(BUS_CNTL1, rinfo->save_regs[14]);
+       OUTREG(MPP_TB_CONFIG, rinfo->save_regs[37]);
+       OUTREG(FCP_CNTL, rinfo->save_regs[38]);
+       OUTREG(RBBM_CNTL, rinfo->save_regs[39]);
+       OUTREG(DAC_CNTL, rinfo->save_regs[40]);
+       OUTREG(DAC_MACRO_CNTL, (INREG(DAC_MACRO_CNTL) & ~0x6) | 8);
+       OUTREG(DAC_MACRO_CNTL, (INREG(DAC_MACRO_CNTL) & ~0x6) | 8);
+
+       /* Hrm... */
+       OUTREG(DAC_CNTL2, INREG(DAC_CNTL2) | DAC2_EXPAND_MODE);
+
+       /* Reset the PAD CTLR */
+       radeon_pm_reset_pad_ctlr_strength(rinfo);
+
+       /* Some PLLs are Read & written identically in the trace here...
+        * I suppose it's actually to switch them all off & reset,
+        * let's assume off is what we want. I'm just doing that for all major PLLs now.
+        */
+       radeon_pm_all_ppls_off(rinfo);
+
+       /* Clear tiling, reset swappers */
+       INREG(SURFACE_CNTL);
+       OUTREG(SURFACE_CNTL, 0);
+
+       /* Some black magic with TV_DAC_CNTL, we should restore those from backups
+        * rather than hard coding...
+        */
+       tmp = INREG(TV_DAC_CNTL) & ~TV_DAC_CNTL_BGADJ_MASK;
+       tmp |= 8 << TV_DAC_CNTL_BGADJ__SHIFT;
+       OUTREG(TV_DAC_CNTL, tmp);
+
+       tmp = INREG(TV_DAC_CNTL) & ~TV_DAC_CNTL_DACADJ_MASK;
+       tmp |= 7 << TV_DAC_CNTL_DACADJ__SHIFT;
+       OUTREG(TV_DAC_CNTL, tmp);
+
+       /* More registers restored */
+       OUTREG(AGP_CNTL, rinfo->save_regs[16]);
+       OUTREG(HOST_PATH_CNTL, rinfo->save_regs[41]);
+       OUTREG(DISP_MISC_CNTL, rinfo->save_regs[9]);
+
+       /* Hrmmm ... What is that ? */
+       tmp = rinfo->save_regs[1]
+               & ~(CLK_PWRMGT_CNTL__ACTIVE_HILO_LAT_MASK |
+                   CLK_PWRMGT_CNTL__MC_BUSY);
+       OUTPLL(pllCLK_PWRMGT_CNTL, tmp);
+
+       OUTREG(PAD_CTLR_MISC, rinfo->save_regs[56]);
+       OUTREG(FW_CNTL, rinfo->save_regs[57]);
+       OUTREG(HDP_DEBUG, rinfo->save_regs[96]);
+       OUTREG(PAMAC0_DLY_CNTL, rinfo->save_regs[54]);
+       OUTREG(PAMAC1_DLY_CNTL, rinfo->save_regs[55]);
+       OUTREG(PAMAC2_DLY_CNTL, rinfo->save_regs[79]);
+
+       /* Restore Memory Controller configuration */
+       radeon_pm_m10_reconfigure_mc(rinfo);
+
+       /* Make sure CRTC's dont touch memory */
+       OUTREG(CRTC_GEN_CNTL, INREG(CRTC_GEN_CNTL)
+              | CRTC_GEN_CNTL__CRTC_DISP_REQ_EN_B);
+       OUTREG(CRTC2_GEN_CNTL, INREG(CRTC2_GEN_CNTL)
+              | CRTC2_GEN_CNTL__CRTC2_DISP_REQ_EN_B);
+       mdelay(30);
+
+       /* Disable SDRAM refresh */
+       OUTREG(MEM_REFRESH_CNTL, INREG(MEM_REFRESH_CNTL)
+              | MEM_REFRESH_CNTL__MEM_REFRESH_DIS);
+
+       /* Restore XTALIN routing (CLK_PIN_CNTL) */
+       OUTPLL(pllCLK_PIN_CNTL, rinfo->save_regs[4]);
+
+       /* Switch MCLK, YCLK and SCLK PLLs to PCI source & force them ON */
+       tmp = rinfo->save_regs[2] & 0xff000000;
+       tmp |=  MCLK_CNTL__FORCE_MCLKA |
+               MCLK_CNTL__FORCE_MCLKB |
+               MCLK_CNTL__FORCE_YCLKA |
+               MCLK_CNTL__FORCE_YCLKB |
+               MCLK_CNTL__FORCE_MC;
+       OUTPLL(pllMCLK_CNTL, tmp);
+
+       /* Force all clocks on in SCLK */
+       tmp = INPLL(pllSCLK_CNTL);
+       tmp |=  SCLK_CNTL__FORCE_DISP2|
+               SCLK_CNTL__FORCE_CP|
+               SCLK_CNTL__FORCE_HDP|
+               SCLK_CNTL__FORCE_DISP1|
+               SCLK_CNTL__FORCE_TOP|
+               SCLK_CNTL__FORCE_E2|
+               SCLK_CNTL__FORCE_SE|
+               SCLK_CNTL__FORCE_IDCT|
+               SCLK_CNTL__FORCE_VIP|
+               SCLK_CNTL__FORCE_PB|
+               SCLK_CNTL__FORCE_TAM|
+               SCLK_CNTL__FORCE_TDM|
+               SCLK_CNTL__FORCE_RB|
+               SCLK_CNTL__FORCE_TV_SCLK|
+               SCLK_CNTL__FORCE_SUBPIC|
+               SCLK_CNTL__FORCE_OV0;
+       tmp |=  SCLK_CNTL__CP_MAX_DYN_STOP_LAT  |
+               SCLK_CNTL__HDP_MAX_DYN_STOP_LAT |
+               SCLK_CNTL__TV_MAX_DYN_STOP_LAT  |
+               SCLK_CNTL__E2_MAX_DYN_STOP_LAT  |
+               SCLK_CNTL__SE_MAX_DYN_STOP_LAT  |
+               SCLK_CNTL__IDCT_MAX_DYN_STOP_LAT|
+               SCLK_CNTL__VIP_MAX_DYN_STOP_LAT |
+               SCLK_CNTL__RE_MAX_DYN_STOP_LAT  |
+               SCLK_CNTL__PB_MAX_DYN_STOP_LAT  |
+               SCLK_CNTL__TAM_MAX_DYN_STOP_LAT |
+               SCLK_CNTL__TDM_MAX_DYN_STOP_LAT |
+               SCLK_CNTL__RB_MAX_DYN_STOP_LAT;
+       OUTPLL(pllSCLK_CNTL, tmp);
+
+       OUTPLL(pllVCLK_ECP_CNTL, 0);
+       OUTPLL(pllPIXCLKS_CNTL, 0);
+       OUTPLL(pllMCLK_MISC,
+              MCLK_MISC__MC_MCLK_MAX_DYN_STOP_LAT |
+              MCLK_MISC__IO_MCLK_MAX_DYN_STOP_LAT);
+
+       mdelay(5);
+
+       /* Restore the M_SPLL_REF_FB_DIV, MPLL_AUX_CNTL and SPLL_AUX_CNTL values */
+       OUTPLL(pllM_SPLL_REF_FB_DIV, rinfo->save_regs[77]);
+       OUTPLL(pllMPLL_AUX_CNTL, rinfo->save_regs[75]);
+       OUTPLL(pllSPLL_AUX_CNTL, rinfo->save_regs[76]);
+
+       /* Now restore the major PLLs settings, keeping them off & reset though */
+       OUTPLL(pllPPLL_CNTL, rinfo->save_regs[93] | 0x3);
+       OUTPLL(pllP2PLL_CNTL, rinfo->save_regs[8] | 0x3);
+       OUTPLL(pllMPLL_CNTL, rinfo->save_regs[73] | 0x03);
+       OUTPLL(pllSPLL_CNTL, rinfo->save_regs[74] | 0x03);
+
+       /* Restore MC DLL state and switch it off/reset too  */
+       OUTMC(rinfo, ixR300_MC_DLL_CNTL, rinfo->save_regs[70]);
+
+       /* Switch MDLL off & reset */
+       OUTPLL(pllMDLL_RDCKA, rinfo->save_regs[98] | 0xff);
+       mdelay(5);
+
+       /* Setup some black magic bits in PLL_PWRMGT_CNTL. Hrm... we saved
+        * 0xa1100007... and MacOS writes 0xa1000007 ..
+        */
+       OUTPLL(pllPLL_PWRMGT_CNTL, rinfo->save_regs[0]);
+
+       /* Restore more stuffs */
+       OUTPLL(pllHTOTAL_CNTL, 0);
+       OUTPLL(pllHTOTAL2_CNTL, 0);
+
+       /* More PLL initial configuration */
+       tmp = INPLL(pllSCLK_CNTL2); /* What for ? */
+       OUTPLL(pllSCLK_CNTL2, tmp);
+
+       tmp = INPLL(pllSCLK_MORE_CNTL);
+       tmp |=  SCLK_MORE_CNTL__FORCE_DISPREGS |        /* a guess */
+               SCLK_MORE_CNTL__FORCE_MC_GUI |
+               SCLK_MORE_CNTL__FORCE_MC_HOST;
+       OUTPLL(pllSCLK_MORE_CNTL, tmp);
+
+       /* Now we actually start MCLK and SCLK */
+       radeon_pm_start_mclk_sclk(rinfo);
+
+       /* Full reset sdrams, this also re-inits the MDLL */
+       radeon_pm_full_reset_sdram(rinfo);
+
+       /* Fill palettes */
+       OUTREG(DAC_CNTL2, INREG(DAC_CNTL2) | 0x20);
+       for (i=0; i<256; i++)
+               OUTREG(PALETTE_30_DATA, 0x15555555);
+       OUTREG(DAC_CNTL2, INREG(DAC_CNTL2) & ~20);
+       udelay(20);
+       for (i=0; i<256; i++)
+               OUTREG(PALETTE_30_DATA, 0x15555555);
+
+       OUTREG(DAC_CNTL2, INREG(DAC_CNTL2) & ~0x20);
+       mdelay(3);
+
+       /* Restore TMDS */
+       OUTREG(FP_GEN_CNTL, rinfo->save_regs[82]);
+       OUTREG(FP2_GEN_CNTL, rinfo->save_regs[83]);
+
+       /* Set LVDS registers but keep interface & pll down */
+       OUTREG(LVDS_GEN_CNTL, rinfo->save_regs[11] &
+              ~(LVDS_EN | LVDS_ON | LVDS_DIGON | LVDS_BLON | LVDS_BL_MOD_EN));
+       OUTREG(LVDS_PLL_CNTL, (rinfo->save_regs[12] & ~0xf0000) | 0x20000);
+
+       OUTREG(DISP_OUTPUT_CNTL, rinfo->save_regs[86]);
+
+       /* Restore GPIOPAD state */
+       OUTREG(GPIOPAD_A, rinfo->save_regs[19]);
+       OUTREG(GPIOPAD_EN, rinfo->save_regs[20]);
+       OUTREG(GPIOPAD_MASK, rinfo->save_regs[21]);
+
+       /* write some stuff to the framebuffer... */
+       for (i = 0; i < 0x8000; ++i)
+               writeb(0, rinfo->fb_base + i);
+
+       mdelay(40);
+       OUTREG(LVDS_GEN_CNTL, INREG(LVDS_GEN_CNTL) | LVDS_DIGON | LVDS_ON);
+       mdelay(40);
+
+       /* Restore a few more things */
+       OUTREG(GRPH_BUFFER_CNTL, rinfo->save_regs[94]);
+       OUTREG(GRPH2_BUFFER_CNTL, rinfo->save_regs[95]);
+
+       /* Take care of spread spectrum & PPLLs now */
+       radeon_pm_m10_disable_spread_spectrum(rinfo);
+       radeon_pm_restore_pixel_pll(rinfo);
+
+       /* GRRRR... I can't figure out the proper LVDS power sequence, and the
+        * code I have for blank/unblank doesn't quite work on some laptop models
+        * it seems ... Hrm. What I have here works most of the time ...
+        */
+       radeon_pm_m10_enable_lvds_spread_spectrum(rinfo);
+}
+
+static void radeon_pm_m9p_reconfigure_mc(struct radeonfb_info *rinfo)
+{
+       OUTREG(MC_CNTL, rinfo->save_regs[46]);
+       OUTREG(MC_INIT_GFX_LAT_TIMER, rinfo->save_regs[47]);
+       OUTREG(MC_INIT_MISC_LAT_TIMER, rinfo->save_regs[48]);
+       OUTREG(MEM_SDRAM_MODE_REG,
+              rinfo->save_regs[35] & ~MEM_SDRAM_MODE_REG__MC_INIT_COMPLETE);
+       OUTREG(MC_TIMING_CNTL, rinfo->save_regs[49]);
+       OUTREG(MC_READ_CNTL_AB, rinfo->save_regs[50]);
+       OUTREG(MEM_REFRESH_CNTL, rinfo->save_regs[42]);
+       OUTREG(MC_IOPAD_CNTL, rinfo->save_regs[51]);
+       OUTREG(MC_DEBUG, rinfo->save_regs[53]);
+       OUTREG(MC_CHIP_IO_OE_CNTL_AB, rinfo->save_regs[52]);
+
+       OUTMC(rinfo, ixMC_IMP_CNTL, rinfo->save_regs[59] /*0x00f460d6*/);
+       OUTMC(rinfo, ixMC_CHP_IO_CNTL_A0, rinfo->save_regs[65] /*0xfecfa666*/);
+       OUTMC(rinfo, ixMC_CHP_IO_CNTL_A1, rinfo->save_regs[66] /*0x141555ff*/);
+       OUTMC(rinfo, ixMC_CHP_IO_CNTL_B0, rinfo->save_regs[67] /*0xfecfa666*/);
+       OUTMC(rinfo, ixMC_CHP_IO_CNTL_B1, rinfo->save_regs[68] /*0x141555ff*/);
+       OUTMC(rinfo, ixMC_IMP_CNTL_0, rinfo->save_regs[71] /*0x00009249*/);
+       OUTREG(MC_IND_INDEX, 0);
+       OUTREG(CONFIG_MEMSIZE, rinfo->video_ram);
+
+       mdelay(20);
+}
+
+static void radeon_reinitialize_M9P(struct radeonfb_info *rinfo)
+{
+       u32 tmp, i;
+
+       /* Restore a bunch of registers first */
+       OUTREG(SURFACE_CNTL, rinfo->save_regs[29]);
+       OUTREG(MC_AGP_LOCATION, rinfo->save_regs[32]);
+       OUTREG(DISPLAY_BASE_ADDR, rinfo->save_regs[31]);
+       OUTREG(CRTC2_DISPLAY_BASE_ADDR, rinfo->save_regs[33]);
+       OUTREG(MC_FB_LOCATION, rinfo->save_regs[30]);
+       OUTREG(OV0_BASE_ADDR, rinfo->save_regs[80]);
+       OUTREG(BUS_CNTL, rinfo->save_regs[36]);
+       OUTREG(BUS_CNTL1, rinfo->save_regs[14]);
+       OUTREG(MPP_TB_CONFIG, rinfo->save_regs[37]);
+       OUTREG(FCP_CNTL, rinfo->save_regs[38]);
+       OUTREG(RBBM_CNTL, rinfo->save_regs[39]);
+
+       OUTREG(DAC_CNTL, rinfo->save_regs[40]);
+       OUTREG(DAC_CNTL2, INREG(DAC_CNTL2) | DAC2_EXPAND_MODE);
+
+       /* Reset the PAD CTLR */
+       radeon_pm_reset_pad_ctlr_strength(rinfo);
+
+       /* Some PLLs are Read & written identically in the trace here...
+        * I suppose it's actually to switch them all off & reset,
+        * let's assume off is what we want. I'm just doing that for all major PLLs now.
+        */
+       radeon_pm_all_ppls_off(rinfo);
+
+       /* Clear tiling, reset swappers */
+       INREG(SURFACE_CNTL);
+       OUTREG(SURFACE_CNTL, 0);
+
+       /* Some black magic with TV_DAC_CNTL, we should restore those from backups
+        * rather than hard coding...
+        */
+       tmp = INREG(TV_DAC_CNTL) & ~TV_DAC_CNTL_BGADJ_MASK;
+       tmp |= 6 << TV_DAC_CNTL_BGADJ__SHIFT;
+       OUTREG(TV_DAC_CNTL, tmp);
+
+       tmp = INREG(TV_DAC_CNTL) & ~TV_DAC_CNTL_DACADJ_MASK;
+       tmp |= 6 << TV_DAC_CNTL_DACADJ__SHIFT;
+       OUTREG(TV_DAC_CNTL, tmp);
+
+       OUTPLL(pllAGP_PLL_CNTL, rinfo->save_regs[78]);
+
+       OUTREG(PAMAC0_DLY_CNTL, rinfo->save_regs[54]);
+       OUTREG(PAMAC1_DLY_CNTL, rinfo->save_regs[55]);
+       OUTREG(PAMAC2_DLY_CNTL, rinfo->save_regs[79]);
+
+       OUTREG(AGP_CNTL, rinfo->save_regs[16]);
+       OUTREG(HOST_PATH_CNTL, rinfo->save_regs[41]); /* MacOS sets that to 0 !!! */
+       OUTREG(DISP_MISC_CNTL, rinfo->save_regs[9]);
+
+       tmp  = rinfo->save_regs[1]
+               & ~(CLK_PWRMGT_CNTL__ACTIVE_HILO_LAT_MASK |
+                   CLK_PWRMGT_CNTL__MC_BUSY);
+       OUTPLL(pllCLK_PWRMGT_CNTL, tmp);
+
+       OUTREG(FW_CNTL, rinfo->save_regs[57]);
+
+       /* Disable SDRAM refresh */
+       OUTREG(MEM_REFRESH_CNTL, INREG(MEM_REFRESH_CNTL)
+              | MEM_REFRESH_CNTL__MEM_REFRESH_DIS);
+
+       /* Restore XTALIN routing (CLK_PIN_CNTL) */
+               OUTPLL(pllCLK_PIN_CNTL, rinfo->save_regs[4]);
+
+       /* Force MCLK to be PCI sourced and forced ON */
+       tmp = rinfo->save_regs[2] & 0xff000000;
+       tmp |=  MCLK_CNTL__FORCE_MCLKA |
+               MCLK_CNTL__FORCE_MCLKB |
+               MCLK_CNTL__FORCE_YCLKA |
+               MCLK_CNTL__FORCE_YCLKB |
+               MCLK_CNTL__FORCE_MC    |
+               MCLK_CNTL__FORCE_AIC;
+       OUTPLL(pllMCLK_CNTL, tmp);
+
+       /* Force SCLK to be PCI sourced with a bunch forced */
+       tmp =   0 |
+               SCLK_CNTL__FORCE_DISP2|
+               SCLK_CNTL__FORCE_CP|
+               SCLK_CNTL__FORCE_HDP|
+               SCLK_CNTL__FORCE_DISP1|
+               SCLK_CNTL__FORCE_TOP|
+               SCLK_CNTL__FORCE_E2|
+               SCLK_CNTL__FORCE_SE|
+               SCLK_CNTL__FORCE_IDCT|
+               SCLK_CNTL__FORCE_VIP|
+               SCLK_CNTL__FORCE_RE|
+               SCLK_CNTL__FORCE_PB|
+               SCLK_CNTL__FORCE_TAM|
+               SCLK_CNTL__FORCE_TDM|
+               SCLK_CNTL__FORCE_RB;
+       OUTPLL(pllSCLK_CNTL, tmp);
+
+       /* Clear VCLK_ECP_CNTL & PIXCLKS_CNTL  */
+       OUTPLL(pllVCLK_ECP_CNTL, 0);
+       OUTPLL(pllPIXCLKS_CNTL, 0);
+
+       /* Setup MCLK_MISC, non dynamic mode */
+       OUTPLL(pllMCLK_MISC,
+              MCLK_MISC__MC_MCLK_MAX_DYN_STOP_LAT |
+              MCLK_MISC__IO_MCLK_MAX_DYN_STOP_LAT);
+
+       mdelay(5);
+
+       /* Set back the default clock dividers */
+       OUTPLL(pllM_SPLL_REF_FB_DIV, rinfo->save_regs[77]);
+       OUTPLL(pllMPLL_AUX_CNTL, rinfo->save_regs[75]);
+       OUTPLL(pllSPLL_AUX_CNTL, rinfo->save_regs[76]);
+
+       /* PPLL and P2PLL default values & off */
+       OUTPLL(pllPPLL_CNTL, rinfo->save_regs[93] | 0x3);
+       OUTPLL(pllP2PLL_CNTL, rinfo->save_regs[8] | 0x3);
+
+       /* S and M PLLs are reset & off, configure them */
+       OUTPLL(pllMPLL_CNTL, rinfo->save_regs[73] | 0x03);
+       OUTPLL(pllSPLL_CNTL, rinfo->save_regs[74] | 0x03);
+
+       /* Default values for MDLL ... fixme */
+       OUTPLL(pllMDLL_CKO, 0x9c009c);
+       OUTPLL(pllMDLL_RDCKA, 0x08830883);
+       OUTPLL(pllMDLL_RDCKB, 0x08830883);
+       mdelay(5);
+
+       /* Restore PLL_PWRMGT_CNTL */ // XXXX
+       tmp = rinfo->save_regs[0];
+       tmp &= ~PLL_PWRMGT_CNTL_SU_SCLK_USE_BCLK;
+       tmp |= PLL_PWRMGT_CNTL_SU_MCLK_USE_BCLK;
+       OUTPLL(PLL_PWRMGT_CNTL,  tmp);
+
+       /* Clear HTOTAL_CNTL & HTOTAL2_CNTL */
+       OUTPLL(pllHTOTAL_CNTL, 0);
+       OUTPLL(pllHTOTAL2_CNTL, 0);
+
+       /* All outputs off */
+       OUTREG(CRTC_GEN_CNTL, 0x04000000);
+       OUTREG(CRTC2_GEN_CNTL, 0x04000000);
+       OUTREG(FP_GEN_CNTL, 0x00004008);
+       OUTREG(FP2_GEN_CNTL, 0x00000008);
+       OUTREG(LVDS_GEN_CNTL, 0x08000008);
+
+       /* Restore Memory Controller configuration */
+       radeon_pm_m9p_reconfigure_mc(rinfo);
+
+       /* Now we actually start MCLK and SCLK */
+       radeon_pm_start_mclk_sclk(rinfo);
+
+       /* Full reset sdrams, this also re-inits the MDLL */
+       radeon_pm_full_reset_sdram(rinfo);
+
+       /* Fill palettes */
+       OUTREG(DAC_CNTL2, INREG(DAC_CNTL2) | 0x20);
+       for (i=0; i<256; i++)
+               OUTREG(PALETTE_30_DATA, 0x15555555);
+       OUTREG(DAC_CNTL2, INREG(DAC_CNTL2) & ~20);
+       udelay(20);
+       for (i=0; i<256; i++)
+               OUTREG(PALETTE_30_DATA, 0x15555555);
+
+       OUTREG(DAC_CNTL2, INREG(DAC_CNTL2) & ~0x20);
+       mdelay(3);
+
+       /* Restore TV stuff, make sure TV DAC is down */
+       OUTREG(TV_MASTER_CNTL, rinfo->save_regs[88]);
+       OUTREG(TV_DAC_CNTL, rinfo->save_regs[13] | 0x07000000);
+
+       /* Restore GPIOS. MacOS does some magic here with one of the GPIO bits,
+        * possibly related to the weird PLL related workarounds and to the
+        * fact that CLK_PIN_CNTL is tweaked in ways I don't fully understand,
+        * but we keep things the simple way here
+        */
+       OUTREG(GPIOPAD_A, rinfo->save_regs[19]);
+       OUTREG(GPIOPAD_EN, rinfo->save_regs[20]);
+       OUTREG(GPIOPAD_MASK, rinfo->save_regs[21]);
+
+       /* Now do things with SCLK_MORE_CNTL. Force bits are already set, copy
+        * high bits from backup
+        */
+       tmp = INPLL(pllSCLK_MORE_CNTL) & 0x0000ffff;
+       tmp |= rinfo->save_regs[34] & 0xffff0000;
+       tmp |= SCLK_MORE_CNTL__FORCE_DISPREGS;
+       OUTPLL(pllSCLK_MORE_CNTL, tmp);
+
+       tmp = INPLL(pllSCLK_MORE_CNTL) & 0x0000ffff;
+       tmp |= rinfo->save_regs[34] & 0xffff0000;
+       tmp |= SCLK_MORE_CNTL__FORCE_DISPREGS;
+       OUTPLL(pllSCLK_MORE_CNTL, tmp);
+
+       OUTREG(LVDS_GEN_CNTL, rinfo->save_regs[11] &
+              ~(LVDS_EN | LVDS_ON | LVDS_DIGON | LVDS_BLON | LVDS_BL_MOD_EN));
+       OUTREG(LVDS_GEN_CNTL, INREG(LVDS_GEN_CNTL) | LVDS_BLON);
+       OUTREG(LVDS_PLL_CNTL, (rinfo->save_regs[12] & ~0xf0000) | 0x20000);
+       mdelay(20);
+
+       /* write some stuff to the framebuffer... */
+       for (i = 0; i < 0x8000; ++i)
+               writeb(0, rinfo->fb_base + i);
+
+       OUTREG(0x2ec, 0x6332a020);
+       OUTPLL(pllSSPLL_REF_DIV, rinfo->save_regs[44] /*0x3f */);
+       OUTPLL(pllSSPLL_DIV_0, rinfo->save_regs[45] /*0x000081bb */);
+       tmp = INPLL(pllSSPLL_CNTL);
+       tmp &= ~2;
+       OUTPLL(pllSSPLL_CNTL, tmp);
+       mdelay(6);
+       tmp &= ~1;
+       OUTPLL(pllSSPLL_CNTL, tmp);
+       mdelay(5);
+       tmp |= 3;
+       OUTPLL(pllSSPLL_CNTL, tmp);
+       mdelay(5);
+
+       OUTPLL(pllSS_INT_CNTL, rinfo->save_regs[90] & ~3);/*0x0020300c*/
+       OUTREG(0x2ec, 0x6332a3f0);
+       mdelay(17);
+
+       OUTPLL(pllPPLL_REF_DIV, rinfo->pll.ref_div);;
+       OUTPLL(pllPPLL_DIV_0, rinfo->save_regs[92]);
+
+       mdelay(40);
+       OUTREG(LVDS_GEN_CNTL, INREG(LVDS_GEN_CNTL) | LVDS_DIGON | LVDS_ON);
+       mdelay(40);
+
+       /* Restore a few more things */
+       OUTREG(GRPH_BUFFER_CNTL, rinfo->save_regs[94]);
+       OUTREG(GRPH2_BUFFER_CNTL, rinfo->save_regs[95]);
+
+       /* Restore PPLL, spread spectrum & LVDS */
+       radeon_pm_m10_disable_spread_spectrum(rinfo);
+       radeon_pm_restore_pixel_pll(rinfo);
+       radeon_pm_m10_enable_lvds_spread_spectrum(rinfo);
+}
+
+#if 0 /* Not ready yet */
+static void radeon_reinitialize_QW(struct radeonfb_info *rinfo)
+{
+       int i;
+       u32 tmp, tmp2;
+       u32 cko, cka, ckb;
+       u32 cgc, cec, c2gc;
+
+       OUTREG(MC_AGP_LOCATION, rinfo->save_regs[32]);
+       OUTREG(DISPLAY_BASE_ADDR, rinfo->save_regs[31]);
+       OUTREG(CRTC2_DISPLAY_BASE_ADDR, rinfo->save_regs[33]);
+       OUTREG(MC_FB_LOCATION, rinfo->save_regs[30]);
+       OUTREG(BUS_CNTL, rinfo->save_regs[36]);
+       OUTREG(RBBM_CNTL, rinfo->save_regs[39]);
+
+       INREG(PAD_CTLR_STRENGTH);
+       OUTREG(PAD_CTLR_STRENGTH, INREG(PAD_CTLR_STRENGTH) & ~0x10000);
+       for (i = 0; i < 65; ++i) {
+               mdelay(1);
+               INREG(PAD_CTLR_STRENGTH);
+       }
+
+       OUTREG(DISP_TEST_DEBUG_CNTL, INREG(DISP_TEST_DEBUG_CNTL) | 0x10000000);
+       OUTREG(OV0_FLAG_CNTRL, INREG(OV0_FLAG_CNTRL) | 0x100);
+       OUTREG(CRTC_GEN_CNTL, INREG(CRTC_GEN_CNTL));
+       OUTREG(DAC_CNTL, 0xff00410a);
+       OUTREG(CRTC2_GEN_CNTL, INREG(CRTC2_GEN_CNTL));
+       OUTREG(DAC_CNTL2, INREG(DAC_CNTL2) | 0x4000);
+
+       OUTREG(SURFACE_CNTL, rinfo->save_regs[29]);
+       OUTREG(AGP_CNTL, rinfo->save_regs[16]);
+       OUTREG(HOST_PATH_CNTL, rinfo->save_regs[41]);
+       OUTREG(DISP_MISC_CNTL, rinfo->save_regs[9]);
+
+       OUTMC(rinfo, ixMC_CHP_IO_CNTL_A0, 0xf7bb4433);
+       OUTREG(MC_IND_INDEX, 0);
+       OUTMC(rinfo, ixMC_CHP_IO_CNTL_B0, 0xf7bb4433);
+       OUTREG(MC_IND_INDEX, 0);
+
+       OUTREG(CRTC_MORE_CNTL, INREG(CRTC_MORE_CNTL));
+
+       tmp = INPLL(pllVCLK_ECP_CNTL);
+       OUTPLL(pllVCLK_ECP_CNTL, tmp);
+       tmp = INPLL(pllPIXCLKS_CNTL);
+       OUTPLL(pllPIXCLKS_CNTL, tmp);
+
+       OUTPLL(MCLK_CNTL, 0xaa3f0000);
+       OUTPLL(SCLK_CNTL, 0xffff0000);
+       OUTPLL(pllMPLL_AUX_CNTL, 6);
+       OUTPLL(pllSPLL_AUX_CNTL, 1);
+       OUTPLL(MDLL_CKO, 0x9f009f);
+       OUTPLL(MDLL_RDCKA, 0x830083);
+       OUTPLL(pllMDLL_RDCKB, 0x830083);
+       OUTPLL(PPLL_CNTL, 0xa433);
+       OUTPLL(P2PLL_CNTL, 0xa433);
+       OUTPLL(MPLL_CNTL, 0x0400a403);
+       OUTPLL(SPLL_CNTL, 0x0400a433);
+
+       tmp = INPLL(M_SPLL_REF_FB_DIV);
+       OUTPLL(M_SPLL_REF_FB_DIV, tmp);
+       tmp = INPLL(M_SPLL_REF_FB_DIV);
+       OUTPLL(M_SPLL_REF_FB_DIV, tmp | 0xc);
+       INPLL(M_SPLL_REF_FB_DIV);
+
+       tmp = INPLL(MPLL_CNTL);
+       OUTREG8(CLOCK_CNTL_INDEX, MPLL_CNTL + PLL_WR_EN);
+       OUTREG8(CLOCK_CNTL_DATA + 1, (tmp >> 8) & 0xff);
+
+       tmp = INPLL(M_SPLL_REF_FB_DIV);
+       OUTPLL(M_SPLL_REF_FB_DIV, tmp | 0x5900);
+
+       tmp = INPLL(MPLL_CNTL);
+       OUTPLL(MPLL_CNTL, tmp & ~0x2);
+       mdelay(1);
+       tmp = INPLL(MPLL_CNTL);
+       OUTPLL(MPLL_CNTL, tmp & ~0x1);
+       mdelay(10);
+
+       OUTPLL(MCLK_CNTL, 0xaa3f1212);
+       mdelay(1);
+
+       INPLL(M_SPLL_REF_FB_DIV);
+       INPLL(MCLK_CNTL);
+       INPLL(M_SPLL_REF_FB_DIV);
+
+       tmp = INPLL(SPLL_CNTL);
+       OUTREG8(CLOCK_CNTL_INDEX, SPLL_CNTL + PLL_WR_EN);
+       OUTREG8(CLOCK_CNTL_DATA + 1, (tmp >> 8) & 0xff);
+
+       tmp = INPLL(M_SPLL_REF_FB_DIV);
+       OUTPLL(M_SPLL_REF_FB_DIV, tmp | 0x780000);
+
+       tmp = INPLL(SPLL_CNTL);
+       OUTPLL(SPLL_CNTL, tmp & ~0x1);
+       mdelay(1);
+       tmp = INPLL(SPLL_CNTL);
+       OUTPLL(SPLL_CNTL, tmp & ~0x2);
+       mdelay(10);
+
+       tmp = INPLL(SCLK_CNTL);
+       OUTPLL(SCLK_CNTL, tmp | 2);
+       mdelay(1);
+
+       cko = INPLL(pllMDLL_CKO);
+       cka = INPLL(pllMDLL_RDCKA);
+       ckb = INPLL(pllMDLL_RDCKB);
+
+       cko &= ~(MDLL_CKO__MCKOA_SLEEP | MDLL_CKO__MCKOB_SLEEP);
+       OUTPLL(pllMDLL_CKO, cko);
+       mdelay(1);
+       cko &= ~(MDLL_CKO__MCKOA_RESET | MDLL_CKO__MCKOB_RESET);
+       OUTPLL(pllMDLL_CKO, cko);
+       mdelay(5);
+
+       cka &= ~(MDLL_RDCKA__MRDCKA0_SLEEP | MDLL_RDCKA__MRDCKA1_SLEEP);
+       OUTPLL(pllMDLL_RDCKA, cka);
+       mdelay(1);
+       cka &= ~(MDLL_RDCKA__MRDCKA0_RESET | MDLL_RDCKA__MRDCKA1_RESET);
+       OUTPLL(pllMDLL_RDCKA, cka);
+       mdelay(5);
+
+       ckb &= ~(MDLL_RDCKB__MRDCKB0_SLEEP | MDLL_RDCKB__MRDCKB1_SLEEP);
+       OUTPLL(pllMDLL_RDCKB, ckb);
+       mdelay(1);
+       ckb &= ~(MDLL_RDCKB__MRDCKB0_RESET | MDLL_RDCKB__MRDCKB1_RESET);
+       OUTPLL(pllMDLL_RDCKB, ckb);
+       mdelay(5);
+
+       OUTMC(rinfo, ixMC_CHP_IO_CNTL_A1, 0x151550ff);
+       OUTREG(MC_IND_INDEX, 0);
+       OUTMC(rinfo, ixMC_CHP_IO_CNTL_B1, 0x151550ff);
+       OUTREG(MC_IND_INDEX, 0);
+       mdelay(1);
+       OUTMC(rinfo, ixMC_CHP_IO_CNTL_A1, 0x141550ff);
+       OUTREG(MC_IND_INDEX, 0);
+       OUTMC(rinfo, ixMC_CHP_IO_CNTL_B1, 0x141550ff);
+       OUTREG(MC_IND_INDEX, 0);
+       mdelay(1);
+
+       OUTPLL(pllHTOTAL_CNTL, 0);
+       OUTPLL(pllHTOTAL2_CNTL, 0);
+
+       OUTREG(MEM_CNTL, 0x29002901);
+       OUTREG(MEM_SDRAM_MODE_REG, 0x45320032); /* XXX use save_regs[35]? */
+       OUTREG(EXT_MEM_CNTL, 0x1a394333);
+       OUTREG(MEM_IO_CNTL_A1, 0x0aac0aac);
+       OUTREG(MEM_INIT_LATENCY_TIMER, 0x34444444);
+       OUTREG(MEM_REFRESH_CNTL, 0x1f1f7218);   /* XXX or save_regs[42]? */
+       OUTREG(MC_DEBUG, 0);
+       OUTREG(MEM_IO_OE_CNTL, 0x04300430);
+
+       OUTMC(rinfo, ixMC_IMP_CNTL, 0x00f460d6);
+       OUTREG(MC_IND_INDEX, 0);
+       OUTMC(rinfo, ixMC_IMP_CNTL_0, 0x00009249);
+       OUTREG(MC_IND_INDEX, 0);
+
+       OUTREG(CONFIG_MEMSIZE, rinfo->video_ram);
+
+       radeon_pm_full_reset_sdram(rinfo);
+
+       INREG(FP_GEN_CNTL);
+       OUTREG(TMDS_CNTL, 0x01000000);  /* XXX ? */
+       tmp = INREG(FP_GEN_CNTL);
+       tmp |= FP_CRTC_DONT_SHADOW_HEND | FP_CRTC_DONT_SHADOW_VPAR | 0x200;
+       OUTREG(FP_GEN_CNTL, tmp);
+
+       tmp = INREG(DISP_OUTPUT_CNTL);
+       tmp &= ~0x400;
+       OUTREG(DISP_OUTPUT_CNTL, tmp);
+
+       OUTPLL(CLK_PIN_CNTL, rinfo->save_regs[4]);
+       OUTPLL(CLK_PWRMGT_CNTL, rinfo->save_regs[1]);
+       OUTPLL(PLL_PWRMGT_CNTL, rinfo->save_regs[0]);
+
+       tmp = INPLL(MCLK_MISC);
+       tmp |= MCLK_MISC__MC_MCLK_DYN_ENABLE | MCLK_MISC__IO_MCLK_DYN_ENABLE;
+       OUTPLL(MCLK_MISC, tmp);
+
+       tmp = INPLL(SCLK_CNTL);
+       OUTPLL(SCLK_CNTL, tmp);
+
+       OUTREG(CRTC_MORE_CNTL, 0);
+       OUTREG8(CRTC_GEN_CNTL+1, 6);
+       OUTREG8(CRTC_GEN_CNTL+3, 1);
+       OUTREG(CRTC_PITCH, 32);
+
+       tmp = INPLL(VCLK_ECP_CNTL);
+       OUTPLL(VCLK_ECP_CNTL, tmp);
+
+       tmp = INPLL(PPLL_CNTL);
+       OUTPLL(PPLL_CNTL, tmp);
+
+       /* palette stuff and BIOS_1_SCRATCH... */
+
+       tmp = INREG(FP_GEN_CNTL);
+       tmp2 = INREG(TMDS_TRANSMITTER_CNTL);
+       tmp |= 2;
+       OUTREG(FP_GEN_CNTL, tmp);
+       mdelay(5);
+       OUTREG(FP_GEN_CNTL, tmp);
+       mdelay(5);
+       OUTREG(TMDS_TRANSMITTER_CNTL, tmp2);
+       OUTREG(CRTC_MORE_CNTL, 0);
+       mdelay(20);
+
+       tmp = INREG(CRTC_MORE_CNTL);
+       OUTREG(CRTC_MORE_CNTL, tmp);
+
+       cgc = INREG(CRTC_GEN_CNTL);
+       cec = INREG(CRTC_EXT_CNTL);
+       c2gc = INREG(CRTC2_GEN_CNTL);
+
+       OUTREG(CRTC_H_SYNC_STRT_WID, 0x008e0580);
+       OUTREG(CRTC_H_TOTAL_DISP, 0x009f00d2);
+       OUTREG8(CLOCK_CNTL_INDEX, HTOTAL_CNTL + PLL_WR_EN);
+       OUTREG8(CLOCK_CNTL_DATA, 0);
+       OUTREG(CRTC_V_SYNC_STRT_WID, 0x00830403);
+       OUTREG(CRTC_V_TOTAL_DISP, 0x03ff0429);
+       OUTREG(FP_CRTC_H_TOTAL_DISP, 0x009f0033);
+       OUTREG(FP_H_SYNC_STRT_WID, 0x008e0080);
+       OUTREG(CRT_CRTC_H_SYNC_STRT_WID, 0x008e0080);
+       OUTREG(FP_CRTC_V_TOTAL_DISP, 0x03ff002a);
+       OUTREG(FP_V_SYNC_STRT_WID, 0x00830004);
+       OUTREG(CRT_CRTC_V_SYNC_STRT_WID, 0x00830004);
+       OUTREG(FP_HORZ_VERT_ACTIVE, 0x009f03ff);
+       OUTREG(FP_HORZ_STRETCH, 0);
+       OUTREG(FP_VERT_STRETCH, 0);
+       OUTREG(OVR_CLR, 0);
+       OUTREG(OVR_WID_LEFT_RIGHT, 0);
+       OUTREG(OVR_WID_TOP_BOTTOM, 0);
+
+       tmp = INPLL(PPLL_REF_DIV);
+       tmp = (tmp & ~PPLL_REF_DIV_MASK) | rinfo->pll.ref_div;
+       OUTPLL(PPLL_REF_DIV, tmp);
+       INPLL(PPLL_REF_DIV);
+
+       OUTREG8(CLOCK_CNTL_INDEX, PPLL_CNTL + PLL_WR_EN);
+       OUTREG8(CLOCK_CNTL_DATA + 1, 0xbc);
+
+       tmp = INREG(CLOCK_CNTL_INDEX);
+       OUTREG(CLOCK_CNTL_INDEX, tmp & 0xff);
+
+       OUTPLL(PPLL_DIV_0, 0x48090);
+
+       tmp = INPLL(PPLL_CNTL);
+       OUTPLL(PPLL_CNTL, tmp & ~0x2);
+       mdelay(1);
+       tmp = INPLL(PPLL_CNTL);
+       OUTPLL(PPLL_CNTL, tmp & ~0x1);
+       mdelay(10);
+
+       tmp = INPLL(VCLK_ECP_CNTL);
+       OUTPLL(VCLK_ECP_CNTL, tmp | 3);
+       mdelay(1);
+
+       tmp = INPLL(VCLK_ECP_CNTL);
+       OUTPLL(VCLK_ECP_CNTL, tmp);
+
+       c2gc |= CRTC2_DISP_REQ_EN_B;
+       OUTREG(CRTC2_GEN_CNTL, c2gc);
+       cgc |= CRTC_EN;
+       OUTREG(CRTC_GEN_CNTL, cgc);
+       OUTREG(CRTC_EXT_CNTL, cec);
+       OUTREG(CRTC_PITCH, 0xa0);
+       OUTREG(CRTC_OFFSET, 0);
+       OUTREG(CRTC_OFFSET_CNTL, 0);
+
+       OUTREG(GRPH_BUFFER_CNTL, 0x20117c7c);
+       OUTREG(GRPH2_BUFFER_CNTL, 0x00205c5c);
+
+       tmp2 = INREG(FP_GEN_CNTL);
+       tmp = INREG(TMDS_TRANSMITTER_CNTL);
+       OUTREG(0x2a8, 0x0000061b);
+       tmp |= TMDS_PLL_EN;
+       OUTREG(TMDS_TRANSMITTER_CNTL, tmp);
+       mdelay(1);
+       tmp &= ~TMDS_PLLRST;
+       OUTREG(TMDS_TRANSMITTER_CNTL, tmp);
+       tmp2 &= ~2;
+       tmp2 |= FP_TMDS_EN;
+       OUTREG(FP_GEN_CNTL, tmp2);
+       mdelay(5);
+       tmp2 |= FP_FPON;
+       OUTREG(FP_GEN_CNTL, tmp2);
+
+       OUTREG(CUR_HORZ_VERT_OFF, CUR_LOCK | 1);
+       cgc = INREG(CRTC_GEN_CNTL);
+       OUTREG(CUR_HORZ_VERT_POSN, 0xbfff0fff);
+       cgc |= 0x10000;
+       OUTREG(CUR_OFFSET, 0);
+}
+#endif /* 0 */
+
+#endif /* CONFIG_PPC_OF */
+
 static void radeon_set_suspend(struct radeonfb_info *rinfo, int suspend)
 {
        u16 pwr_cmd;
        u32 tmp;
+       int i;
 
        if (!rinfo->pm_reg)
                return;
@@ -794,13 +2406,13 @@ static void radeon_set_suspend(struct radeonfb_info *rinfo, int suspend)
                 * duration of the suspend/resume process
                 */
                radeon_pm_disable_dynamic_mode(rinfo);
+
                /* Save some registers */
-               radeon_pm_save_regs(rinfo);
+               radeon_pm_save_regs(rinfo, 0);
 
-               /* Prepare mobility chips for suspend. Only do that on <= RV250 chips that
-                * have been tested
+               /* Prepare mobility chips for suspend.
                 */
-               if (rinfo->is_mobility && rinfo->family <= CHIP_FAMILY_RV250) {
+               if (rinfo->is_mobility) {
                        /* Program V2CLK */
                        radeon_pm_program_v2clk(rinfo);
                
@@ -813,13 +2425,22 @@ static void radeon_set_suspend(struct radeonfb_info *rinfo, int suspend)
                        /* Prepare chip for power management */
                        radeon_pm_setup_for_suspend(rinfo);
 
-                       /* Reset the MDLL */
-                       /* because both INPLL and OUTPLL take the same lock, that's why. */
-                       tmp = INPLL( pllMDLL_CKO) | MDLL_CKO__MCKOA_RESET | MDLL_CKO__MCKOB_RESET;
-                       OUTPLL( pllMDLL_CKO, tmp );
+                       if (rinfo->family <= CHIP_FAMILY_RV280) {
+                               /* Reset the MDLL */
+                               /* because both INPLL and OUTPLL take the same
+                                * lock, that's why. */
+                               tmp = INPLL( pllMDLL_CKO) | MDLL_CKO__MCKOA_RESET
+                                       | MDLL_CKO__MCKOB_RESET;
+                               OUTPLL( pllMDLL_CKO, tmp );
+                       }
                }
 
+               for (i = 0; i < 64; ++i)
+                       pci_read_config_dword(rinfo->pdev, i * 4,
+                                             &rinfo->cfg_save[i]);
+
                /* Switch PCI power managment to D2. */
+               pci_disable_device(rinfo->pdev);
                for (;;) {
                        pci_read_config_word(
                                rinfo->pdev, rinfo->pm_reg+PCI_PM_CTRL,
@@ -839,37 +2460,74 @@ static void radeon_set_suspend(struct radeonfb_info *rinfo, int suspend)
                pci_write_config_word(rinfo->pdev, rinfo->pm_reg+PCI_PM_CTRL, 0);
                mdelay(500);
 
-               /* Reset the SDRAM controller  */
-                       radeon_pm_full_reset_sdram(rinfo);
-               
-               /* Restore some registers */
-               radeon_pm_restore_regs(rinfo);
-               radeon_pm_enable_dynamic_mode(rinfo);
+               if (rinfo->family <= CHIP_FAMILY_RV250) {
+                       /* Reset the SDRAM controller  */
+                       radeon_pm_full_reset_sdram(rinfo);
+
+                       /* Restore some registers */
+                       radeon_pm_restore_regs(rinfo);
+               } else {
+                       /* Restore registers first */
+                       radeon_pm_restore_regs(rinfo);
+                       /* init sdram controller */
+                       radeon_pm_full_reset_sdram(rinfo);
+               }
+       }
+}
+
+static int radeon_restore_pci_cfg(struct radeonfb_info *rinfo)
+{
+       int i;
+       static u32 radeon_cfg_after_resume[64];
+
+       for (i = 0; i < 64; ++i)
+               pci_read_config_dword(rinfo->pdev, i * 4,
+                                     &radeon_cfg_after_resume[i]);
+
+       if (radeon_cfg_after_resume[PCI_BASE_ADDRESS_0/4]
+           == rinfo->cfg_save[PCI_BASE_ADDRESS_0/4])
+               return 0;       /* assume everything is ok */
+
+       for (i = PCI_BASE_ADDRESS_0/4; i < 64; ++i) {
+               if (radeon_cfg_after_resume[i] != rinfo->cfg_save[i])
+                       pci_write_config_dword(rinfo->pdev, i * 4,
+                                              rinfo->cfg_save[i]);
        }
+       pci_write_config_word(rinfo->pdev, PCI_CACHE_LINE_SIZE,
+                             rinfo->cfg_save[PCI_CACHE_LINE_SIZE/4]);
+       pci_write_config_word(rinfo->pdev, PCI_COMMAND,
+                             rinfo->cfg_save[PCI_COMMAND/4]);
+       return 1;
 }
 
+
+static/*extern*/ int susdisking = 0;
+
 int radeonfb_pci_suspend(struct pci_dev *pdev, u32 state)
 {
         struct fb_info *info = pci_get_drvdata(pdev);
         struct radeonfb_info *rinfo = info->par;
+       int i;
 
-       /* We don't do anything but D2, for now we return 0, but
-        * we may want to change that. How do we know if the BIOS
-        * can properly take care of D3 ? Also, with swsusp, we
-        * know we'll be rebooted, ...
-        */
+       if (state == pdev->dev.power.power_state)
+               return 0;
 
-       printk(KERN_DEBUG "radeonfb: suspending to state: %d...\n", state);
-       
-       acquire_console_sem();
+       printk(KERN_DEBUG "radeonfb (%s): suspending to state: %d...\n",
+              pci_name(pdev), state);
 
-       /* Userland should do this but doesn't... bridge gets suspended
-        * too late. Unfortunately, that works only when AGP is built-in,
-        * not for a module.
+       /* For suspend-to-disk, we cheat here. We don't suspend anything and
+        * let fbcon continue drawing until we are all set. That shouldn't
+        * really cause any problem at this point, provided that the wakeup
+        * code knows that any state in memory may not match the HW
         */
-#ifdef CONFIG_AGP
-       agp_enable(0);
-#endif
+       if (state != PM_SUSPEND_MEM)
+               goto done;
+       if (susdisking) {
+               printk("suspending to disk but state = %d\n", state);
+               goto done;
+       }
+
+       acquire_console_sem();
 
        fb_set_suspend(info, 1);
 
@@ -881,22 +2539,53 @@ int radeonfb_pci_suspend(struct pci_dev *pdev, u32 state)
        }
 
        /* Blank display and LCD */
-       radeonfb_blank(VESA_POWERDOWN, info);
+       radeon_screen_blank(rinfo, FB_BLANK_POWERDOWN, 1);
 
        /* Sleep */
        rinfo->asleep = 1;
        rinfo->lock_blank = 1;
+       del_timer_sync(&rinfo->lvds_timer);
 
-       /* Suspend the chip to D2 state when supported
+       /* If we support wakeup from poweroff, we save all regs we can including cfg
+        * space
+        */
+       if (rinfo->pm_mode & radeon_pm_off) {
+               /* Always disable dynamic clocks or weird things are happening when
+                * the chip goes off (basically the panel doesn't shut down properly
+                * and we crash on wakeup),
+                * also, we want the saved regs context to have no dynamic clocks in
+                * it, we'll restore the dynamic clocks state on wakeup
+                */
+               radeon_pm_disable_dynamic_mode(rinfo);
+               mdelay(50);
+               radeon_pm_save_regs(rinfo, 1);
+
+               if (rinfo->is_mobility && !(rinfo->pm_mode & radeon_pm_d2)) {
+                       /* Switch off LVDS interface */
+                       mdelay(1);
+                       OUTREG(LVDS_GEN_CNTL, INREG(LVDS_GEN_CNTL) & ~(LVDS_BL_MOD_EN));
+                       mdelay(1);
+                       OUTREG(LVDS_GEN_CNTL, INREG(LVDS_GEN_CNTL) & ~(LVDS_EN | LVDS_ON));
+                       OUTREG(LVDS_PLL_CNTL, (INREG(LVDS_PLL_CNTL) & ~30000) | 0x20000);
+                       mdelay(20);
+                       OUTREG(LVDS_GEN_CNTL, INREG(LVDS_GEN_CNTL) & ~(LVDS_DIGON));
+
+                       // FIXME: Use PCI layer
+                       for (i = 0; i < 64; ++i)
+                               pci_read_config_dword(rinfo->pdev, i * 4,
+                                                     &rinfo->cfg_save[i]);
+               }
+       }
+       /* If we support D2, we go to it (should be fixed later with a flag forcing
+        * D3 only for some laptops)
         */
-#ifdef CONFIG_RADEON_HAS_D2
-       if (radeon_suspend_to_d2(rinfo, state))
+       if (rinfo->pm_mode & radeon_pm_d2)
                radeon_set_suspend(rinfo, 1);
-#endif /* CONFIG_RADEON_HAS_D2 */
 
        release_console_sem();
 
-       pdev->dev.power_state = state;
+ done:
+       pdev->dev.power.power_state = state;
 
        return 0;
 }
@@ -905,22 +2594,59 @@ int radeonfb_pci_resume(struct pci_dev *pdev)
 {
         struct fb_info *info = pci_get_drvdata(pdev);
         struct radeonfb_info *rinfo = info->par;
+       int rc = 0;
 
-       if (pdev->dev.power_state == 0)
+       if (pdev->dev.power.power_state == 0)
                return 0;
 
-       acquire_console_sem();
+       if (rinfo->no_schedule) {
+               if (try_acquire_console_sem())
+                       return 0;
+       } else
+               acquire_console_sem();
+
+       printk(KERN_DEBUG "radeonfb (%s): resuming from state: %d...\n",
+              pci_name(pdev), pdev->dev.power.power_state);
 
-       /* Wakeup chip */
-#ifdef CONFIG_RADEON_HAS_D2
-       if (radeon_suspend_to_d2(rinfo, 0))
-               radeon_set_suspend(rinfo, 0);
-#endif /* CONFIG_RADEON_HAS_D2 */
 
-       rinfo->asleep = 0;
+       if (pci_enable_device(pdev)) {
+               rc = -ENODEV;
+               printk(KERN_ERR "radeonfb (%s): can't enable PCI device !\n",
+                      pci_name(pdev));
+               goto bail;
+       }
+       pci_set_master(pdev);
+
+       if (pdev->dev.power.power_state == PM_SUSPEND_MEM) {
+               /* Wakeup chip. Check from config space if we were powered off
+                * (todo: additionally, check CLK_PIN_CNTL too)
+                */
+               if ((rinfo->pm_mode & radeon_pm_off) && radeon_restore_pci_cfg(rinfo)) {
+                       if (rinfo->reinit_func != NULL)
+                               rinfo->reinit_func(rinfo);
+                       else {
+                               printk(KERN_ERR "radeonfb (%s): can't resume radeon from"
+                                      " D3 cold, need softboot !", pci_name(pdev));
+                               rc = -EIO;
+                               goto bail;
+                       }
+               }
+               /* If we support D2, try to resume... we should check what was our
+                * state though... (were we really in D2 state ?). Right now, this code
+                * is only enable on Macs so it's fine.
+                */
+               else if (rinfo->pm_mode & radeon_pm_d2)
+                       radeon_set_suspend(rinfo, 0);
+
+               rinfo->asleep = 0;
+       } else
+               radeon_engine_idle();
 
        /* Restore display & engine */
-       radeonfb_set_par(info);
+       radeon_write_mode (rinfo, &rinfo->state, 1);
+       if (!(info->flags & FBINFO_HWACCEL_DISABLED))
+               radeonfb_engine_init (rinfo);
+
        fb_pan_display(info, &info->var);
        fb_set_cmap(&info->cmap, info);
 
@@ -929,15 +2655,107 @@ int radeonfb_pci_resume(struct pci_dev *pdev)
 
        /* Unblank */
        rinfo->lock_blank = 0;
-       radeonfb_blank(0, info);
+       radeon_screen_blank(rinfo, FB_BLANK_UNBLANK, 1);
+
+       /* Check status of dynclk */
+       if (rinfo->dynclk == 1)
+               radeon_pm_enable_dynamic_mode(rinfo);
+       else if (rinfo->dynclk == 0)
+               radeon_pm_disable_dynamic_mode(rinfo);
+
+       pdev->dev.power.power_state = 0;
 
+ bail:
        release_console_sem();
 
-       pdev->dev.power_state = 0;
+       return rc;
+}
 
-       printk(KERN_DEBUG "radeonfb: resumed !\n");
+#ifdef CONFIG_PPC_OF
+static void radeonfb_early_resume(void *data)
+{
+        struct radeonfb_info *rinfo = data;
 
-       return 0;
+       rinfo->no_schedule = 1;
+       radeonfb_pci_resume(rinfo->pdev);
+       rinfo->no_schedule = 0;
 }
+#endif /* CONFIG_PPC_OF */
 
 #endif /* CONFIG_PM */
+
+void radeonfb_pm_init(struct radeonfb_info *rinfo, int dynclk)
+{
+       /* Find PM registers in config space if any*/
+       rinfo->pm_reg = pci_find_capability(rinfo->pdev, PCI_CAP_ID_PM);
+
+       /* Enable/Disable dynamic clocks: TODO add sysfs access */
+       rinfo->dynclk = dynclk;
+       if (dynclk == 1) {
+               radeon_pm_enable_dynamic_mode(rinfo);
+               printk("radeonfb: Dynamic Clock Power Management enabled\n");
+       } else if (dynclk == 0) {
+               radeon_pm_disable_dynamic_mode(rinfo);
+               printk("radeonfb: Dynamic Clock Power Management disabled\n");
+       }
+
+       /* Check if we can power manage on suspend/resume. We can do
+        * D2 on M6, M7 and M9, and we can resume from D3 cold a few other
+        * "Mac" cards, but that's all. We need more infos about what the
+        * BIOS does tho. Right now, all this PM stuff is pmac-only for that
+        * reason. --BenH
+        */
+#if defined(CONFIG_PM) && defined(CONFIG_PPC_OF)
+       if (_machine == _MACH_Pmac && rinfo->of_node) {
+               if (rinfo->is_mobility && rinfo->pm_reg &&
+                   rinfo->family <= CHIP_FAMILY_RV250)
+                       rinfo->pm_mode |= radeon_pm_d2;
+
+               /* We can restart Jasper (M10 chip in albooks), BlueStone (7500 chip
+                * in some desktop G4s), and Via (M9+ chip on iBook G4)
+                */
+               if (!strcmp(rinfo->of_node->name, "ATY,JasperParent")) {
+                       rinfo->reinit_func = radeon_reinitialize_M10;
+                       rinfo->pm_mode |= radeon_pm_off;
+               }
+#if 0 /* Not ready yet */
+               if (!strcmp(rinfo->of_node->name, "ATY,BlueStoneParent")) {
+                       rinfo->reinit_func = radeon_reinitialize_QW;
+                       rinfo->pm_mode |= radeon_pm_off;
+               }
+#endif
+               if (!strcmp(rinfo->of_node->name, "ATY,ViaParent")) {
+                       rinfo->reinit_func = radeon_reinitialize_M9P;
+                       rinfo->pm_mode |= radeon_pm_off;
+                       /* Workaround not used for now */
+                       rinfo->m9p_workaround = 1;
+               }
+
+               /* If any of the above is set, we assume the machine can sleep/resume.
+                * It's a bit of a "shortcut" but will work fine. Ideally, we need infos
+                * from the platform about what happens to the chip...
+                * Now we tell the platform about our capability
+                */
+               if (rinfo->pm_mode != radeon_pm_none) {
+                       pmac_call_feature(PMAC_FTR_DEVICE_CAN_WAKE, rinfo->of_node, 0, 1);
+                       pmac_set_early_video_resume(radeonfb_early_resume, rinfo);
+               }
+
+#if 0
+               /* Power down TV DAC, taht saves a significant amount of power,
+                * we'll have something better once we actually have some TVOut
+                * support
+                */
+               OUTREG(TV_DAC_CNTL, INREG(TV_DAC_CNTL) | 0x07000000);
+#endif
+       }
+#endif /* defined(CONFIG_PM) && defined(CONFIG_PPC_OF) */
+}
+
+void radeonfb_pm_exit(struct radeonfb_info *rinfo)
+{
+#if defined(CONFIG_PM) && defined(CONFIG_PPC_OF)
+       if (rinfo->pm_mode != radeon_pm_none)
+               pmac_set_early_video_resume(NULL, NULL);
+#endif
+}