]> git.hungrycats.org Git - linux/commitdiff
[PATCH] radeonfb update
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>
Fri, 11 Feb 2005 00:03:30 +0000 (16:03 -0800)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Fri, 11 Feb 2005 00:03:30 +0000 (16:03 -0800)
It adds the sleep support for newer powermacs, improve power saving on some
laptops, makes use of the new fbdev modelist management routines, and fixes
a few backlight related issues.

I tested it on a thinkpad T30 and a few PPC boxes with success.  It should
be less invasive than the previous one (I don't try to restore the mode on
exit, that is what breaks the thinkpad and possibly other stuffs that boot
in VGA text mode), plus fixed a couple of bugs in the mode detection code.
I also reverted the memory map fix on ppc since it doesn't work properly on
some recent laptops where the firmware sets a tiled display.  I'll rework
that completely to update the memory map as part of the mode setting later.
That should fix various issues when switching with X/DRI on x86.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
drivers/video/aty/ati_ids.h
drivers/video/aty/radeon_base.c
drivers/video/aty/radeon_monitor.c
drivers/video/aty/radeon_pm.c
drivers/video/aty/radeonfb.h
drivers/video/radeonfb.c
include/video/radeon.h

index e4171869f3443561704f87c50b76c413e4b865ad..13321c689cf68a8937ee766e9e776f5dc0ed4581 100644 (file)
@@ -4,6 +4,18 @@
  * radeonfb
  */
 
+#define PCI_CHIP_RV380_3150             0x3150
+#define PCI_CHIP_RV380_3151             0x3151
+#define PCI_CHIP_RV380_3152             0x3152
+#define PCI_CHIP_RV380_3153             0x3153
+#define PCI_CHIP_RV380_3154             0x3154
+#define PCI_CHIP_RV380_3156             0x3156
+#define PCI_CHIP_RV380_3E50             0x3E50
+#define PCI_CHIP_RV380_3E51             0x3E51
+#define PCI_CHIP_RV380_3E52             0x3E52
+#define PCI_CHIP_RV380_3E53             0x3E53
+#define PCI_CHIP_RV380_3E54             0x3E54
+#define PCI_CHIP_RV380_3E56             0x3E56
 #define PCI_CHIP_RS100_4136            0x4136
 #define PCI_CHIP_RS200_4137            0x4137
 #define PCI_CHIP_R300_AD               0x4144
 #define PCI_CHIP_RV250_Ie              0x4965
 #define PCI_CHIP_RV250_If              0x4966
 #define PCI_CHIP_RV250_Ig              0x4967
+#define PCI_CHIP_R420_JH                0x4A48
+#define PCI_CHIP_R420_JI                0x4A49
+#define PCI_CHIP_R420_JJ                0x4A4A
+#define PCI_CHIP_R420_JK                0x4A4B
+#define PCI_CHIP_R420_JL                0x4A4C
+#define PCI_CHIP_R420_JM                0x4A4D
+#define PCI_CHIP_R420_JN                0x4A4E
+#define PCI_CHIP_R420_JP                0x4A50
 #define PCI_CHIP_MACH64LB              0x4C42
 #define PCI_CHIP_MACH64LD              0x4C44
 #define PCI_CHIP_RAGE128LE             0x4C45
@@ -73,6 +93,7 @@
 #define PCI_CHIP_RV250_Le              0x4C65
 #define PCI_CHIP_RV250_Lf              0x4C66
 #define PCI_CHIP_RV250_Lg              0x4C67
+#define PCI_CHIP_RV250_Ln              0x4C6E
 #define PCI_CHIP_RAGE128MF             0x4D46
 #define PCI_CHIP_RAGE128ML             0x4D4C
 #define PCI_CHIP_R300_ND               0x4E44
 #define PCI_CHIP_RAGE128TS             0x5453
 #define PCI_CHIP_RAGE128TT             0x5454
 #define PCI_CHIP_RAGE128TU             0x5455
+#define PCI_CHIP_RV370_5460             0x5460
+#define PCI_CHIP_RV370_5461             0x5461
+#define PCI_CHIP_RV370_5462             0x5462
+#define PCI_CHIP_RV370_5463             0x5463
+#define PCI_CHIP_RV370_5464             0x5464
+#define PCI_CHIP_RV370_5465             0x5465
+#define PCI_CHIP_RV370_5466             0x5466
+#define PCI_CHIP_RV370_5467             0x5467
+#define PCI_CHIP_R423_UH                0x5548
+#define PCI_CHIP_R423_UI                0x5549
+#define PCI_CHIP_R423_UJ                0x554A
+#define PCI_CHIP_R423_UK                0x554B
+#define PCI_CHIP_R423_UQ                0x5551
+#define PCI_CHIP_R423_UR                0x5552
+#define PCI_CHIP_R423_UT                0x5554
 #define PCI_CHIP_MACH64VT              0x5654
 #define PCI_CHIP_MACH64VU              0x5655
 #define PCI_CHIP_MACH64VV              0x5656
 #define PCI_CHIP_RS300_5835            0x5835
 #define PCI_CHIP_RS300_5836            0x5836
 #define PCI_CHIP_RS300_5837            0x5837
+#define PCI_CHIP_RV370_5B60             0x5B60
+#define PCI_CHIP_RV370_5B61             0x5B61
+#define PCI_CHIP_RV370_5B62             0x5B62
+#define PCI_CHIP_RV370_5B63             0x5B63
+#define PCI_CHIP_RV370_5B64             0x5B64
+#define PCI_CHIP_RV370_5B65             0x5B65
+#define PCI_CHIP_RV370_5B66             0x5B66
+#define PCI_CHIP_RV370_5B67             0x5B67
 #define PCI_CHIP_RV280_5960            0x5960
 #define PCI_CHIP_RV280_5961            0x5961
 #define PCI_CHIP_RV280_5962            0x5962
-#define PCI_CHIP_RV280_5963            0x5963
 #define PCI_CHIP_RV280_5964            0x5964
-#define PCI_CHIP_RV280_5968            0x5968
-#define PCI_CHIP_RV280_5969            0x5969
-#define PCI_CHIP_RV280_596A            0x596A
-#define PCI_CHIP_RV280_596B            0x596B
 #define PCI_CHIP_RV280_5C61            0x5C61
 #define PCI_CHIP_RV280_5C63            0x5C63
+#define PCI_CHIP_R423_5D57              0x5D57
+#define PCI_CHIP_RS350_7834             0x7834
+#define PCI_CHIP_RS350_7835             0x7835
+
index e9f12f4f6477738757458d2c7a3b55151eca2687..60917ba049bc700de471af2e85b15afa7da59913 100644 (file)
@@ -1,5 +1,7 @@
+
 /*
- *     drivers/video/radeonfb.c
+ *     drivers/video/aty/radeon_base.c
+ *
  *     framebuffer driver for ATI Radeon chipset video boards
  *
  *     Copyright 2003  Ben. Herrenschmidt <benh@kernel.crashing.org>
@@ -75,7 +77,6 @@
 
 #ifdef CONFIG_PPC_OF
 
-#include <asm/prom.h>
 #include <asm/pci-bridge.h>
 #include "../macmodes.h"
 
@@ -150,8 +151,10 @@ static struct pci_device_id radeonfb_pci_table[] = {
        CHIP_DEF(PCI_CHIP_RV250_Ig,     RV250,  CHIP_HAS_CRTC2),
        /* Mobility 9100 IGP (U3) */
        CHIP_DEF(PCI_CHIP_RS300_5835,   RS300,  CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY),
+       CHIP_DEF(PCI_CHIP_RS350_7835,   RS300,  CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY),
        /* 9100 IGP (A5) */
        CHIP_DEF(PCI_CHIP_RS300_5834,   RS300,  CHIP_HAS_CRTC2 | CHIP_IS_IGP),
+       CHIP_DEF(PCI_CHIP_RS350_7834,   RS300,  CHIP_HAS_CRTC2 | CHIP_IS_IGP),
        /* Mobility 9200 (M9+) */
        CHIP_DEF(PCI_CHIP_RV280_5C61,   RV280,  CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
        CHIP_DEF(PCI_CHIP_RV280_5C63,   RV280,  CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
@@ -194,6 +197,33 @@ static struct pci_device_id radeonfb_pci_table[] = {
        CHIP_DEF(PCI_CHIP_R350_NI,      R350,   CHIP_HAS_CRTC2),
        CHIP_DEF(PCI_CHIP_R360_NJ,      R350,   CHIP_HAS_CRTC2),
        CHIP_DEF(PCI_CHIP_R350_NK,      R350,   CHIP_HAS_CRTC2),
+       /* Newer stuff */
+       CHIP_DEF(PCI_CHIP_RV380_3E50,   RV380,  CHIP_HAS_CRTC2),
+       CHIP_DEF(PCI_CHIP_RV380_3E54,   RV380,  CHIP_HAS_CRTC2),
+       CHIP_DEF(PCI_CHIP_RV380_3150,   RV380,  CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
+       CHIP_DEF(PCI_CHIP_RV380_3154,   RV380,  CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
+       CHIP_DEF(PCI_CHIP_RV370_5B60,   RV380,  CHIP_HAS_CRTC2),
+       CHIP_DEF(PCI_CHIP_RV370_5B62,   RV380,  CHIP_HAS_CRTC2),
+       CHIP_DEF(PCI_CHIP_RV370_5B64,   RV380,  CHIP_HAS_CRTC2),
+       CHIP_DEF(PCI_CHIP_RV370_5B65,   RV380,  CHIP_HAS_CRTC2),
+       CHIP_DEF(PCI_CHIP_RV370_5460,   RV380,  CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
+       CHIP_DEF(PCI_CHIP_RV370_5464,   RV380,  CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
+       CHIP_DEF(PCI_CHIP_R420_JH,      R420,   CHIP_HAS_CRTC2),
+       CHIP_DEF(PCI_CHIP_R420_JI,      R420,   CHIP_HAS_CRTC2),
+       CHIP_DEF(PCI_CHIP_R420_JJ,      R420,   CHIP_HAS_CRTC2),
+       CHIP_DEF(PCI_CHIP_R420_JK,      R420,   CHIP_HAS_CRTC2),
+       CHIP_DEF(PCI_CHIP_R420_JL,      R420,   CHIP_HAS_CRTC2),
+       CHIP_DEF(PCI_CHIP_R420_JM,      R420,   CHIP_HAS_CRTC2),
+       CHIP_DEF(PCI_CHIP_R420_JN,      R420,   CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
+       CHIP_DEF(PCI_CHIP_R420_JP,      R420,   CHIP_HAS_CRTC2),
+       CHIP_DEF(PCI_CHIP_R423_UH,      R420,   CHIP_HAS_CRTC2),
+       CHIP_DEF(PCI_CHIP_R423_UI,      R420,   CHIP_HAS_CRTC2),
+       CHIP_DEF(PCI_CHIP_R423_UJ,      R420,   CHIP_HAS_CRTC2),
+       CHIP_DEF(PCI_CHIP_R423_UK,      R420,   CHIP_HAS_CRTC2),
+       CHIP_DEF(PCI_CHIP_R423_UQ,      R420,   CHIP_HAS_CRTC2),
+       CHIP_DEF(PCI_CHIP_R423_UR,      R420,   CHIP_HAS_CRTC2),
+       CHIP_DEF(PCI_CHIP_R423_UT,      R420,   CHIP_HAS_CRTC2),
+       CHIP_DEF(PCI_CHIP_R423_5D57,    R420,   CHIP_HAS_CRTC2),
        /* Original Radeon/7200 */
        CHIP_DEF(PCI_CHIP_RADEON_QD,    RADEON, 0),
        CHIP_DEF(PCI_CHIP_RADEON_QE,    RADEON, 0),
@@ -233,6 +263,7 @@ static reg_val common_regs[] = {
 static char *mode_option;
 static char *monitor_layout;
 static int noaccel = 0;
+static int default_dynclk = -2;
 static int nomodeset = 0;
 static int ignore_edid = 0;
 static int mirror = 0;
@@ -290,7 +321,8 @@ static int __devinit radeon_map_ROM(struct radeonfb_info *rinfo, struct pci_dev
                                                                                                           
        rom = pci_map_rom(dev, &rom_size);
        if (!rom) {
-               printk(KERN_ERR "radeonfb: ROM failed to map\n");
+               printk(KERN_ERR "radeonfb (%s): ROM failed to map\n",
+                      pci_name(rinfo->pdev));
                return -ENOMEM;
        }
        
@@ -298,8 +330,8 @@ static int __devinit radeon_map_ROM(struct radeonfb_info *rinfo, struct pci_dev
 
        /* Very simple test to make sure it appeared */
        if (BIOS_IN16(0) != 0xaa55) {
-               printk(KERN_ERR "radeonfb: Invalid ROM signature %x should be 0xaa55\n",
-                      BIOS_IN16(0));
+               printk(KERN_ERR "radeonfb (%s): Invalid ROM signature %x should be"
+                      "0xaa55\n", pci_name(rinfo->pdev), BIOS_IN16(0));
                goto failed;
        }
        /* Look for the PCI data to check the ROM type */
@@ -330,8 +362,8 @@ static int __devinit radeon_map_ROM(struct radeonfb_info *rinfo, struct pci_dev
         * } pci_data_t;
         */
        if (BIOS_IN32(dptr) !=  (('R' << 24) | ('I' << 16) | ('C' << 8) | 'P')) {
-               printk(KERN_WARNING "radeonfb: PCI DATA signature in ROM incorrect: %08x\n",
-                      BIOS_IN32(dptr));
+               printk(KERN_WARNING "radeonfb (%s): PCI DATA signature in ROM"
+                      "incorrect: %08x\n", pci_name(rinfo->pdev), BIOS_IN32(dptr));
                goto anyway;
        }
        rom_type = BIOS_IN8(dptr + 0x14);
@@ -398,14 +430,11 @@ static int  __devinit radeon_find_mem_vbios(struct radeonfb_info *rinfo)
  */
 static int __devinit radeon_read_xtal_OF (struct radeonfb_info *rinfo)
 {
-       struct device_node *dp;
+       struct device_node *dp = rinfo->of_node;
        u32 *val;
 
-       dp = pci_device_to_OF_node(rinfo->pdev);
-       if (dp == NULL) {
-               printk(KERN_WARNING "radeonfb: Cannot match card to OF node !\n");
+       if (dp == NULL)
                return -ENODEV;
-       }
        val = (u32 *) get_property(dp, "ATY,RefCLK", NULL);
        if (!val || !*val) {
                printk(KERN_WARNING "radeonfb: No ATY,RefCLK property !\n");
@@ -488,20 +517,20 @@ static int __devinit radeon_probe_pll_params(struct radeonfb_info *rinfo)
                denom = 1;
                break;
        case 1:
-               n = ((INPLL(X_MPLL_REF_FB_DIV) >> 16) & 0xff);
-               m = (INPLL(X_MPLL_REF_FB_DIV) & 0xff);
+               n = ((INPLL(M_SPLL_REF_FB_DIV) >> 16) & 0xff);
+               m = (INPLL(M_SPLL_REF_FB_DIV) & 0xff);
                num = 2*n;
                denom = 2*m;
                break;
        case 2:
-               n = ((INPLL(X_MPLL_REF_FB_DIV) >> 8) & 0xff);
-               m = (INPLL(X_MPLL_REF_FB_DIV) & 0xff);
+               n = ((INPLL(M_SPLL_REF_FB_DIV) >> 8) & 0xff);
+               m = (INPLL(M_SPLL_REF_FB_DIV) & 0xff);
                num = 2*n;
                denom = 2*m;
         break;
        }
 
-       ppll_div_sel = INREG(CLOCK_CNTL_INDEX + 1) & 0x3;
+       ppll_div_sel = INREG8(CLOCK_CNTL_INDEX + 1) & 0x3;
 
        n = (INPLL(PPLL_DIV_0 + ppll_div_sel) & 0x7ff);
        m = (INPLL(PPLL_REF_DIV) & 0x3ff);
@@ -545,7 +574,7 @@ static int __devinit radeon_probe_pll_params(struct radeonfb_info *rinfo)
                return -1;
        }
 
-       tmp = INPLL(X_MPLL_REF_FB_DIV);
+       tmp = INPLL(M_SPLL_REF_FB_DIV);
        ref_div = INPLL(PPLL_REF_DIV) & 0x3ff;
 
        Ns = (tmp & 0xff0000) >> 16;
@@ -625,7 +654,7 @@ static void __devinit radeon_get_pllinfo(struct radeonfb_info *rinfo)
                rinfo->pll.ref_clk = 2700;
                break;
        }
-       rinfo->pll.ref_div = INPLL(PPLL_REF_DIV) & 0x3ff;
+       rinfo->pll.ref_div = INPLL(PPLL_REF_DIV) & PPLL_REF_DIV_MASK;
 
 
 #ifdef CONFIG_PPC_OF
@@ -906,10 +935,11 @@ static int radeonfb_ioctl (struct inode *inode, struct file *file, unsigned int
 }
 
 
-static int radeon_screen_blank (struct radeonfb_info *rinfo, int blank, int mode_switch)
+int radeon_screen_blank(struct radeonfb_info *rinfo, int blank, int mode_switch)
 {
         u32 val;
        u32 tmp_pix_clks;
+       int unblank = 0;
 
        if (rinfo->lock_blank)
                return 0;
@@ -920,9 +950,6 @@ static int radeon_screen_blank (struct radeonfb_info *rinfo, int blank, int mode
         val &= ~(CRTC_DISPLAY_DIS | CRTC_HSYNC_DIS |
                  CRTC_VSYNC_DIS);
         switch (blank) {
-       case FB_BLANK_UNBLANK:
-       case FB_BLANK_NORMAL:
-               break;
        case FB_BLANK_VSYNC_SUSPEND:
                val |= (CRTC_DISPLAY_DIS | CRTC_VSYNC_DIS);
                break;
@@ -933,42 +960,51 @@ static int radeon_screen_blank (struct radeonfb_info *rinfo, int blank, int mode
                val |= (CRTC_DISPLAY_DIS | CRTC_VSYNC_DIS |
                        CRTC_HSYNC_DIS);
                break;
+       case FB_BLANK_NORMAL:
+               val |= CRTC_DISPLAY_DIS;
+               break;
+       case FB_BLANK_UNBLANK:
+       default:
+               unblank = 1;
         }
        OUTREG(CRTC_EXT_CNTL, val);
 
 
        switch (rinfo->mon1_type) {
        case MT_DFP:
-               if (mode_switch)
-                       break;
-               if (blank == FB_BLANK_UNBLANK ||
-                   blank == FB_BLANK_NORMAL)
+               if (unblank)
                        OUTREGP(FP_GEN_CNTL, (FP_FPON | FP_TMDS_EN),
                                ~(FP_FPON | FP_TMDS_EN));
-               else
+               else {
+                       if (mode_switch || blank == FB_BLANK_NORMAL)
+                               break;
                        OUTREGP(FP_GEN_CNTL, 0, ~(FP_FPON | FP_TMDS_EN));
+               }
                break;
        case MT_LCD:
+               del_timer_sync(&rinfo->lvds_timer);
                val = INREG(LVDS_GEN_CNTL);
-               if (blank == FB_BLANK_UNBLANK ||
-                   blank == FB_BLANK_NORMAL) {
+               if (unblank) {
                        u32 target_val = (val & ~LVDS_DISPLAY_DIS) | LVDS_BLON | LVDS_ON
-                               | LVDS_ON | (rinfo->init_state.lvds_gen_cntl & LVDS_DIGON);
+                               | LVDS_EN | (rinfo->init_state.lvds_gen_cntl
+                                            & (LVDS_DIGON | LVDS_BL_MOD_EN));
                        if ((val ^ target_val) == LVDS_DISPLAY_DIS)
                                OUTREG(LVDS_GEN_CNTL, target_val);
                        else if ((val ^ target_val) != 0) {
-                               del_timer_sync(&rinfo->lvds_timer);
-                               OUTREG(LVDS_GEN_CNTL, target_val & ~LVDS_ON);
+                               OUTREG(LVDS_GEN_CNTL, target_val
+                                      & ~(LVDS_ON | LVDS_BL_MOD_EN));
                                rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
-                               rinfo->init_state.lvds_gen_cntl |= target_val & LVDS_STATE_MASK;
+                               rinfo->init_state.lvds_gen_cntl |=
+                                       target_val & LVDS_STATE_MASK;
                                if (mode_switch) {
-                                       msleep(rinfo->panel_info.pwr_delay);
+                                       radeon_msleep(rinfo->panel_info.pwr_delay);
                                        OUTREG(LVDS_GEN_CNTL, target_val);
                                }
                                else {
                                        rinfo->pending_lvds_gen_cntl = target_val;
                                        mod_timer(&rinfo->lvds_timer,
-                                               jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay));
+                                          jiffies +
+                                          msecs_to_jiffies(rinfo->panel_info.pwr_delay));
                                }
                        }
                } else {
@@ -976,7 +1012,7 @@ static int radeon_screen_blank (struct radeonfb_info *rinfo, int blank, int mode
                        OUTREG(LVDS_GEN_CNTL, val);
 
                        /* We don't do a full switch-off on a simple mode switch */
-                       if (mode_switch)
+                       if (mode_switch || blank == FB_BLANK_NORMAL)
                                break;
 
                        /* Asic bug, when turning off LVDS_ON, we have to make sure
@@ -985,8 +1021,16 @@ static int radeon_screen_blank (struct radeonfb_info *rinfo, int blank, int mode
                        tmp_pix_clks = INPLL(PIXCLKS_CNTL);
                        if (rinfo->is_mobility || rinfo->is_IGP)
                                OUTPLLP(PIXCLKS_CNTL, 0, ~PIXCLK_LVDS_ALWAYS_ONb);
-                       val &= ~(LVDS_BLON | LVDS_ON);
+                       val &= ~(LVDS_BL_MOD_EN);
                        OUTREG(LVDS_GEN_CNTL, val);
+                       udelay(100);
+                       val &= ~(LVDS_ON | LVDS_EN);
+                       OUTREG(LVDS_GEN_CNTL, val);
+                       val &= ~LVDS_DIGON;
+                       rinfo->pending_lvds_gen_cntl = val;
+                       mod_timer(&rinfo->lvds_timer,
+                                 jiffies +
+                                 msecs_to_jiffies(rinfo->panel_info.pwr_delay));
                        rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
                        rinfo->init_state.lvds_gen_cntl |= val & LVDS_STATE_MASK;
                        if (rinfo->is_mobility || rinfo->is_IGP)
@@ -1003,16 +1047,14 @@ static int radeon_screen_blank (struct radeonfb_info *rinfo, int blank, int mode
        return (blank == FB_BLANK_NORMAL) ? -EINVAL : 0;
 }
 
-int radeonfb_blank (int blank, struct fb_info *info)
+static int radeonfb_blank (int blank, struct fb_info *info)
 {
         struct radeonfb_info *rinfo = info->par;
 
        if (rinfo->asleep)
                return 0;
                
-       radeon_screen_blank(rinfo, blank, 0);
-
-       return 0;
+       return radeon_screen_blank(rinfo, blank, 0);
 }
 
 static int radeonfb_setcolreg (unsigned regno, unsigned red, unsigned green,
@@ -1097,7 +1139,7 @@ static int radeonfb_setcolreg (unsigned regno, unsigned red, unsigned green,
 }
 
 
-static void radeon_save_state (struct radeonfb_info *rinfo, struct radeon_regs *save)
+void radeon_save_state (struct radeonfb_info *rinfo, struct radeon_regs *save)
 {
        /* CRTC regs */
        save->crtc_gen_cntl = INREG(CRTC_GEN_CNTL);
@@ -1121,8 +1163,14 @@ static void radeon_save_state (struct radeonfb_info *rinfo, struct radeon_regs *
        save->fp_vert_stretch = INREG(FP_VERT_STRETCH);
        save->lvds_gen_cntl = INREG(LVDS_GEN_CNTL);
        save->lvds_pll_cntl = INREG(LVDS_PLL_CNTL);
-       save->tmds_crc = INREG(TMDS_CRC);       save->tmds_transmitter_cntl = INREG(TMDS_TRANSMITTER_CNTL);
+       save->tmds_crc = INREG(TMDS_CRC);
+       save->tmds_transmitter_cntl = INREG(TMDS_TRANSMITTER_CNTL);
        save->vclk_ecp_cntl = INPLL(VCLK_ECP_CNTL);
+
+       /* PLL regs */
+       save->clk_cntl_index = INREG(CLOCK_CNTL_INDEX) & ~0x3f;
+       save->ppll_div_3 = INPLL(PPLL_DIV_3);
+       save->ppll_ref_div = INPLL(PPLL_REF_DIV);
 }
 
 
@@ -1134,19 +1182,22 @@ static void radeon_write_pll_regs(struct radeonfb_info *rinfo, struct radeon_reg
 
        /* Workaround from XFree */
        if (rinfo->is_mobility) {
-               /* A temporal workaround for the occational blanking on certain laptop panels. 
-                  This appears to related to the PLL divider registers (fail to lock?).  
-                  It occurs even when all dividers are the same with their old settings.  
-                  In this case we really don't need to fiddle with PLL registers. 
-                  By doing this we can avoid the blanking problem with some panels.
-               */
+               /* A temporal workaround for the occational blanking on certain laptop
+                * panels. This appears to related to the PLL divider registers
+                * (fail to lock?). It occurs even when all dividers are the same
+                * with their old settings. In this case we really don't need to
+                * fiddle with PLL registers. By doing this we can avoid the blanking
+                * problem with some panels.
+                */
                if ((mode->ppll_ref_div == (INPLL(PPLL_REF_DIV) & PPLL_REF_DIV_MASK)) &&
                    (mode->ppll_div_3 == (INPLL(PPLL_DIV_3) &
                                          (PPLL_POST3_DIV_MASK | PPLL_FB3_DIV_MASK)))) {
-                       /* We still have to force a switch to PPLL div 3 thanks to
+                       /* We still have to force a switch to selected PPLL div thanks to
                         * an XFree86 driver bug which will switch it away in some cases
                         * even when using UseFDev */
-                       OUTREGP(CLOCK_CNTL_INDEX, PPLL_DIV_SEL_MASK, ~PPLL_DIV_SEL_MASK);
+                       OUTREGP(CLOCK_CNTL_INDEX,
+                               mode->clk_cntl_index & PPLL_DIV_SEL_MASK,
+                               ~PPLL_DIV_SEL_MASK);
                        return;
                }
        }
@@ -1159,8 +1210,10 @@ static void radeon_write_pll_regs(struct radeonfb_info *rinfo, struct radeon_reg
                PPLL_RESET | PPLL_ATOMIC_UPDATE_EN | PPLL_VGA_ATOMIC_UPDATE_EN,
                ~(PPLL_RESET | PPLL_ATOMIC_UPDATE_EN | PPLL_VGA_ATOMIC_UPDATE_EN));
 
-       /* Switch to PPLL div 3 */
-       OUTREGP(CLOCK_CNTL_INDEX, PPLL_DIV_SEL_MASK, ~PPLL_DIV_SEL_MASK);
+       /* Switch to selected PPLL divider */
+       OUTREGP(CLOCK_CNTL_INDEX,
+               mode->clk_cntl_index & PPLL_DIV_SEL_MASK,
+               ~PPLL_DIV_SEL_MASK);
 
        /* Set PPLL ref. div */
        if (rinfo->family == CHIP_FAMILY_R300 ||
@@ -1205,7 +1258,7 @@ static void radeon_write_pll_regs(struct radeonfb_info *rinfo, struct radeon_reg
                ~(PPLL_RESET | PPLL_SLEEP | PPLL_ATOMIC_UPDATE_EN | PPLL_VGA_ATOMIC_UPDATE_EN));
 
        /* We may want some locking ... oh well */
-               msleep(5);
+               radeon_msleep(5);
 
        /* Switch back VCLK source to PPLL */
        OUTPLLP(VCLK_ECP_CNTL, VCLK_SRC_SEL_PPLLCLK, ~VCLK_SRC_SEL_MASK);
@@ -1218,21 +1271,17 @@ static void radeon_lvds_timer_func(unsigned long data)
 {
        struct radeonfb_info *rinfo = (struct radeonfb_info *)data;
 
-       radeon_fifo_wait(3);
+       radeon_engine_idle();
 
        OUTREG(LVDS_GEN_CNTL, rinfo->pending_lvds_gen_cntl);
-       if (rinfo->pending_pixclks_cntl) {
-               OUTPLL(PIXCLKS_CNTL, rinfo->pending_pixclks_cntl);
-               rinfo->pending_pixclks_cntl = 0;
-       }
 }
 
 /*
  * Apply a video mode. This will apply the whole register set, including
  * the PLL registers, to the card
  */
-static void radeon_write_mode (struct radeonfb_info *rinfo,
-                               struct radeon_regs *mode)
+void radeon_write_mode (struct radeonfb_info *rinfo, struct radeon_regs *mode,
+                       int regs_only)
 {
        int i;
        int primary_mon = PRIMARY_MONITOR(rinfo);
@@ -1240,10 +1289,8 @@ static void radeon_write_mode (struct radeonfb_info *rinfo,
        if (nomodeset)
                return;
 
-       del_timer_sync(&rinfo->lvds_timer);
-
-       radeon_screen_blank(rinfo, FB_BLANK_POWERDOWN, 1);
-       msleep(100);
+       if (!regs_only)
+               radeon_screen_blank(rinfo, FB_BLANK_NORMAL, 0);
 
        radeon_fifo_wait(31);
        for (i=0; i<10; i++)
@@ -1285,7 +1332,8 @@ static void radeon_write_mode (struct radeonfb_info *rinfo,
                OUTREG(TMDS_TRANSMITTER_CNTL, mode->tmds_transmitter_cntl);
        }
 
-       radeon_screen_blank(rinfo, FB_BLANK_UNBLANK, 1);
+       if (!regs_only)
+               radeon_screen_blank(rinfo, FB_BLANK_UNBLANK, 0);
 
        radeon_fifo_wait(2);
        OUTPLL(VCLK_ECP_CNTL, mode->vclk_ecp_cntl);
@@ -1386,6 +1434,16 @@ static void radeon_calc_pll_regs(struct radeonfb_info *rinfo, struct radeon_regs
                        break;
        }
 
+       /* If we fall through the bottom, try the "default value"
+          given by the terminal post_div->bitvalue */
+       if ( !post_div->divider ) {
+               post_div = &post_divs[post_div->bitvalue];
+               pll_output_freq = post_div->divider * freq;
+       }
+       RTRACE("ref_div = %d, ref_clk = %d, output_freq = %d\n",
+              rinfo->pll.ref_div, rinfo->pll.ref_clk,
+              pll_output_freq);
+
        /* If we fall through the bottom, try the "default value"
           given by the terminal post_div->bitvalue */
        if ( !post_div->divider ) {
@@ -1406,22 +1464,27 @@ static void radeon_calc_pll_regs(struct radeonfb_info *rinfo, struct radeon_regs
        RTRACE("ppll_div_3 = 0x%x\n", regs->ppll_div_3);
 }
 
-int radeonfb_set_par(struct fb_info *info)
+static int radeonfb_set_par(struct fb_info *info)
 {
        struct radeonfb_info *rinfo = info->par;
        struct fb_var_screeninfo *mode = &info->var;
-       struct radeon_regs newmode;
+       struct radeon_regs *newmode;
        int hTotal, vTotal, hSyncStart, hSyncEnd,
            hSyncPol, vSyncStart, vSyncEnd, vSyncPol, cSync;
        u8 hsync_adj_tab[] = {0, 0x12, 9, 9, 6, 5};
        u8 hsync_fudge_fp[] = {2, 2, 0, 0, 5, 5};
        u32 sync, h_sync_pol, v_sync_pol, dotClock, pixClock;
        int i, freq;
-        int format = 0;
+       int format = 0;
        int nopllcalc = 0;
        int hsync_start, hsync_fudge, bytpp, hsync_wid, vsync_wid;
        int primary_mon = PRIMARY_MONITOR(rinfo);
        int depth = var_to_depth(mode);
+       int use_rmx = 0;
+
+       newmode = kmalloc(sizeof(struct radeon_regs), GFP_KERNEL);
+       if (!newmode)
+               return -ENOMEM;
 
        /* We always want engine to be idle on a mode switch, even
         * if we won't actually change the mode
@@ -1462,9 +1525,9 @@ int radeonfb_set_par(struct fb_info *info)
 
                if (rinfo->panel_info.use_bios_dividers) {
                        nopllcalc = 1;
-                       newmode.ppll_div_3 = rinfo->panel_info.fbk_divider |
+                       newmode->ppll_div_3 = rinfo->panel_info.fbk_divider |
                                (rinfo->panel_info.post_divider << 16);
-                       newmode.ppll_ref_div = rinfo->panel_info.ref_divider;
+                       newmode->ppll_ref_div = rinfo->panel_info.ref_divider;
                }
        }
        dotClock = 1000000000 / pixClock;
@@ -1502,38 +1565,38 @@ int radeonfb_set_par(struct fb_info *info)
 
        hsync_start = hSyncStart - 8 + hsync_fudge;
 
-       newmode.crtc_gen_cntl = CRTC_EXT_DISP_EN | CRTC_EN |
+       newmode->crtc_gen_cntl = CRTC_EXT_DISP_EN | CRTC_EN |
                                (format << 8);
 
        /* Clear auto-center etc... */
-       newmode.crtc_more_cntl = rinfo->init_state.crtc_more_cntl;
-       newmode.crtc_more_cntl &= 0xfffffff0;
+       newmode->crtc_more_cntl = rinfo->init_state.crtc_more_cntl;
+       newmode->crtc_more_cntl &= 0xfffffff0;
        
        if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) {
-               newmode.crtc_ext_cntl = VGA_ATI_LINEAR | XCRT_CNT_EN;
+               newmode->crtc_ext_cntl = VGA_ATI_LINEAR | XCRT_CNT_EN;
                if (mirror)
-                       newmode.crtc_ext_cntl |= CRTC_CRT_ON;
+                       newmode->crtc_ext_cntl |= CRTC_CRT_ON;
 
-               newmode.crtc_gen_cntl &= ~(CRTC_DBL_SCAN_EN |
+               newmode->crtc_gen_cntl &= ~(CRTC_DBL_SCAN_EN |
                                           CRTC_INTERLACE_EN);
        } else {
-               newmode.crtc_ext_cntl = VGA_ATI_LINEAR | XCRT_CNT_EN |
+               newmode->crtc_ext_cntl = VGA_ATI_LINEAR | XCRT_CNT_EN |
                                        CRTC_CRT_ON;
        }
 
-       newmode.dac_cntl = /* INREG(DAC_CNTL) | */ DAC_MASK_ALL | DAC_VGA_ADR_EN |
+       newmode->dac_cntl = /* INREG(DAC_CNTL) | */ DAC_MASK_ALL | DAC_VGA_ADR_EN |
                           DAC_8BIT_EN;
 
-       newmode.crtc_h_total_disp = ((((hTotal / 8) - 1) & 0x3ff) |
+       newmode->crtc_h_total_disp = ((((hTotal / 8) - 1) & 0x3ff) |
                                     (((mode->xres / 8) - 1) << 16));
 
-       newmode.crtc_h_sync_strt_wid = ((hsync_start & 0x1fff) |
+       newmode->crtc_h_sync_strt_wid = ((hsync_start & 0x1fff) |
                                        (hsync_wid << 16) | (h_sync_pol << 23));
 
-       newmode.crtc_v_total_disp = ((vTotal - 1) & 0xffff) |
+       newmode->crtc_v_total_disp = ((vTotal - 1) & 0xffff) |
                                    ((mode->yres - 1) << 16);
 
-       newmode.crtc_v_sync_strt_wid = (((vSyncStart - 1) & 0xfff) |
+       newmode->crtc_v_sync_strt_wid = (((vSyncStart - 1) & 0xfff) |
                                         (vsync_wid << 16) | (v_sync_pol  << 23));
 
        if (!(info->flags & FBINFO_HWACCEL_DISABLED)) {
@@ -1542,18 +1605,18 @@ int radeonfb_set_par(struct fb_info *info)
                                & ~(0x3f)) >> 6;
 
                /* Then, re-multiply it to get the CRTC pitch */
-               newmode.crtc_pitch = (rinfo->pitch << 3) / ((mode->bits_per_pixel + 1) / 8);
+               newmode->crtc_pitch = (rinfo->pitch << 3) / ((mode->bits_per_pixel + 1) / 8);
        } else
-               newmode.crtc_pitch = (mode->xres_virtual >> 3);
+               newmode->crtc_pitch = (mode->xres_virtual >> 3);
 
-       newmode.crtc_pitch |= (newmode.crtc_pitch << 16);
+       newmode->crtc_pitch |= (newmode->crtc_pitch << 16);
 
        /*
         * It looks like recent chips have a problem with SURFACE_CNTL,
         * setting SURF_TRANSLATION_DIS completely disables the
         * swapper as well, so we leave it unset now.
         */
-       newmode.surface_cntl = 0;
+       newmode->surface_cntl = 0;
 
 #if defined(__BIG_ENDIAN)
 
@@ -1563,28 +1626,28 @@ int radeonfb_set_par(struct fb_info *info)
         */
        switch (mode->bits_per_pixel) {
                case 16:
-                       newmode.surface_cntl |= NONSURF_AP0_SWP_16BPP;
-                       newmode.surface_cntl |= NONSURF_AP1_SWP_16BPP;
+                       newmode->surface_cntl |= NONSURF_AP0_SWP_16BPP;
+                       newmode->surface_cntl |= NONSURF_AP1_SWP_16BPP;
                        break;
                case 24:        
                case 32:
-                       newmode.surface_cntl |= NONSURF_AP0_SWP_32BPP;
-                       newmode.surface_cntl |= NONSURF_AP1_SWP_32BPP;
+                       newmode->surface_cntl |= NONSURF_AP0_SWP_32BPP;
+                       newmode->surface_cntl |= NONSURF_AP1_SWP_32BPP;
                        break;
        }
 #endif
 
        /* Clear surface registers */
        for (i=0; i<8; i++) {
-               newmode.surf_lower_bound[i] = 0;
-               newmode.surf_upper_bound[i] = 0x1f;
-               newmode.surf_info[i] = 0;
+               newmode->surf_lower_bound[i] = 0;
+               newmode->surf_upper_bound[i] = 0x1f;
+               newmode->surf_info[i] = 0;
        }
 
        RTRACE("h_total_disp = 0x%x\t   hsync_strt_wid = 0x%x\n",
-               newmode.crtc_h_total_disp, newmode.crtc_h_sync_strt_wid);
+               newmode->crtc_h_total_disp, newmode->crtc_h_sync_strt_wid);
        RTRACE("v_total_disp = 0x%x\t   vsync_strt_wid = 0x%x\n",
-               newmode.crtc_v_total_disp, newmode.crtc_v_sync_strt_wid);
+               newmode->crtc_v_total_disp, newmode->crtc_v_sync_strt_wid);
 
        rinfo->bpp = mode->bits_per_pixel;
        rinfo->depth = depth;
@@ -1592,10 +1655,14 @@ int radeonfb_set_par(struct fb_info *info)
        RTRACE("pixclock = %lu\n", (unsigned long)pixClock);
        RTRACE("freq = %lu\n", (unsigned long)freq);
 
+       /* We use PPLL_DIV_3 */
+       newmode->clk_cntl_index = 0x300;
+
+       /* Calculate PPLL value if necessary */
        if (!nopllcalc)
-               radeon_calc_pll_regs(rinfo, &newmode, freq);
+               radeon_calc_pll_regs(rinfo, newmode, freq);
 
-       newmode.vclk_ecp_cntl = rinfo->init_state.vclk_ecp_cntl;
+       newmode->vclk_ecp_cntl = rinfo->init_state.vclk_ecp_cntl;
 
        if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) {
                unsigned int hRatio, vRatio;
@@ -1605,35 +1672,37 @@ int radeonfb_set_par(struct fb_info *info)
                if (mode->yres > rinfo->panel_info.yres)
                        mode->yres = rinfo->panel_info.yres;
 
-               newmode.fp_horz_stretch = (((rinfo->panel_info.xres / 8) - 1)
+               newmode->fp_horz_stretch = (((rinfo->panel_info.xres / 8) - 1)
                                           << HORZ_PANEL_SHIFT);
-               newmode.fp_vert_stretch = ((rinfo->panel_info.yres - 1)
+               newmode->fp_vert_stretch = ((rinfo->panel_info.yres - 1)
                                           << VERT_PANEL_SHIFT);
 
                if (mode->xres != rinfo->panel_info.xres) {
                        hRatio = round_div(mode->xres * HORZ_STRETCH_RATIO_MAX,
                                           rinfo->panel_info.xres);
-                       newmode.fp_horz_stretch = (((((unsigned long)hRatio) & HORZ_STRETCH_RATIO_MASK)) |
-                                                  (newmode.fp_horz_stretch &
+                       newmode->fp_horz_stretch = (((((unsigned long)hRatio) & HORZ_STRETCH_RATIO_MASK)) |
+                                                  (newmode->fp_horz_stretch &
                                                    (HORZ_PANEL_SIZE | HORZ_FP_LOOP_STRETCH |
                                                     HORZ_AUTO_RATIO_INC)));
-                       newmode.fp_horz_stretch |= (HORZ_STRETCH_BLEND |
+                       newmode->fp_horz_stretch |= (HORZ_STRETCH_BLEND |
                                                    HORZ_STRETCH_ENABLE);
+                       use_rmx = 1;
                }
-               newmode.fp_horz_stretch &= ~HORZ_AUTO_RATIO;
+               newmode->fp_horz_stretch &= ~HORZ_AUTO_RATIO;
 
                if (mode->yres != rinfo->panel_info.yres) {
                        vRatio = round_div(mode->yres * VERT_STRETCH_RATIO_MAX,
                                           rinfo->panel_info.yres);
-                       newmode.fp_vert_stretch = (((((unsigned long)vRatio) & VERT_STRETCH_RATIO_MASK)) |
-                                                  (newmode.fp_vert_stretch &
+                       newmode->fp_vert_stretch = (((((unsigned long)vRatio) & VERT_STRETCH_RATIO_MASK)) |
+                                                  (newmode->fp_vert_stretch &
                                                   (VERT_PANEL_SIZE | VERT_STRETCH_RESERVED)));
-                       newmode.fp_vert_stretch |= (VERT_STRETCH_BLEND |
+                       newmode->fp_vert_stretch |= (VERT_STRETCH_BLEND |
                                                    VERT_STRETCH_ENABLE);
+                       use_rmx = 1;
                }
-               newmode.fp_vert_stretch &= ~VERT_AUTO_RATIO_EN;
+               newmode->fp_vert_stretch &= ~VERT_AUTO_RATIO_EN;
 
-               newmode.fp_gen_cntl = (rinfo->init_state.fp_gen_cntl & (u32)
+               newmode->fp_gen_cntl = (rinfo->init_state.fp_gen_cntl & (u32)
                                       ~(FP_SEL_CRTC2 |
                                         FP_RMX_HVSYNC_CONTROL_EN |
                                         FP_DFP_SYNC_SEL |
@@ -1643,46 +1712,56 @@ int radeonfb_set_par(struct fb_info *info)
                                         FP_CRTC_USE_SHADOW_VEND |
                                         FP_CRT_SYNC_ALT));
 
-               newmode.fp_gen_cntl |= (FP_CRTC_DONT_SHADOW_VPAR |
-                                       FP_CRTC_DONT_SHADOW_HEND);
+               newmode->fp_gen_cntl |= (FP_CRTC_DONT_SHADOW_VPAR |
+                                       FP_CRTC_DONT_SHADOW_HEND |
+                                       FP_PANEL_FORMAT);
 
-               newmode.lvds_gen_cntl = rinfo->init_state.lvds_gen_cntl;
-               newmode.lvds_pll_cntl = rinfo->init_state.lvds_pll_cntl;
-               newmode.tmds_crc = rinfo->init_state.tmds_crc;
-               newmode.tmds_transmitter_cntl = rinfo->init_state.tmds_transmitter_cntl;
+               if (IS_R300_VARIANT(rinfo) ||
+                   (rinfo->family == CHIP_FAMILY_R200)) {
+                       newmode->fp_gen_cntl &= ~R200_FP_SOURCE_SEL_MASK;
+                       if (use_rmx)
+                               newmode->fp_gen_cntl |= R200_FP_SOURCE_SEL_RMX;
+                       else
+                               newmode->fp_gen_cntl |= R200_FP_SOURCE_SEL_CRTC1;
+               } else
+                       newmode->fp_gen_cntl |= FP_SEL_CRTC1;
+
+               newmode->lvds_gen_cntl = rinfo->init_state.lvds_gen_cntl;
+               newmode->lvds_pll_cntl = rinfo->init_state.lvds_pll_cntl;
+               newmode->tmds_crc = rinfo->init_state.tmds_crc;
+               newmode->tmds_transmitter_cntl = rinfo->init_state.tmds_transmitter_cntl;
 
                if (primary_mon == MT_LCD) {
-                       newmode.lvds_gen_cntl |= (LVDS_ON | LVDS_BLON);
-                       newmode.fp_gen_cntl &= ~(FP_FPON | FP_TMDS_EN);
+                       newmode->lvds_gen_cntl |= (LVDS_ON | LVDS_BLON);
+                       newmode->fp_gen_cntl &= ~(FP_FPON | FP_TMDS_EN);
                } else {
                        /* DFP */
-                       newmode.fp_gen_cntl |= (FP_FPON | FP_TMDS_EN);
-                       newmode.tmds_transmitter_cntl = (TMDS_RAN_PAT_RST | TMDS_ICHCSEL) &
+                       newmode->fp_gen_cntl |= (FP_FPON | FP_TMDS_EN);
+                       newmode->tmds_transmitter_cntl = (TMDS_RAN_PAT_RST | TMDS_ICHCSEL) &
                                                         ~(TMDS_PLLRST);
                        /* TMDS_PLL_EN bit is reversed on RV (and mobility) chips */
-                       if ((rinfo->family == CHIP_FAMILY_R300) ||
-                           (rinfo->family == CHIP_FAMILY_R350) ||
-                           (rinfo->family == CHIP_FAMILY_RV350) ||
+                       if (IS_R300_VARIANT(rinfo) ||
                            (rinfo->family == CHIP_FAMILY_R200) || !rinfo->has_CRTC2)
-                               newmode.tmds_transmitter_cntl &= ~TMDS_PLL_EN;
+                               newmode->tmds_transmitter_cntl &= ~TMDS_PLL_EN;
                        else
-                               newmode.tmds_transmitter_cntl |= TMDS_PLL_EN;
-                       newmode.crtc_ext_cntl &= ~CRTC_CRT_ON;
+                               newmode->tmds_transmitter_cntl |= TMDS_PLL_EN;
+                       newmode->crtc_ext_cntl &= ~CRTC_CRT_ON;
                }
 
-               newmode.fp_crtc_h_total_disp = (((rinfo->panel_info.hblank / 8) & 0x3ff) |
+               newmode->fp_crtc_h_total_disp = (((rinfo->panel_info.hblank / 8) & 0x3ff) |
                                (((mode->xres / 8) - 1) << 16));
-               newmode.fp_crtc_v_total_disp = (rinfo->panel_info.vblank & 0xffff) |
+               newmode->fp_crtc_v_total_disp = (rinfo->panel_info.vblank & 0xffff) |
                                ((mode->yres - 1) << 16);
-               newmode.fp_h_sync_strt_wid = ((rinfo->panel_info.hOver_plus & 0x1fff) |
+               newmode->fp_h_sync_strt_wid = ((rinfo->panel_info.hOver_plus & 0x1fff) |
                                (hsync_wid << 16) | (h_sync_pol << 23));
-               newmode.fp_v_sync_strt_wid = ((rinfo->panel_info.vOver_plus & 0xfff) |
+               newmode->fp_v_sync_strt_wid = ((rinfo->panel_info.vOver_plus & 0xfff) |
                                (vsync_wid << 16) | (v_sync_pol  << 23));
        }
 
        /* do it! */
        if (!rinfo->asleep) {
-               radeon_write_mode (rinfo, &newmode);
+               memcpy(&rinfo->state, newmode, sizeof(*newmode));
+               radeon_write_mode (rinfo, newmode, 0);
                /* (re)initialize the engine */
                if (!(info->flags & FBINFO_HWACCEL_DISABLED))
                        radeonfb_engine_init (rinfo);
@@ -1702,6 +1781,7 @@ int radeonfb_set_par(struct fb_info *info)
                             rinfo->depth, info->fix.line_length);
 #endif
 
+       kfree(newmode);
        return 0;
 }
 
@@ -1812,12 +1892,14 @@ static int radeon_set_backlight_enable(int on, int level, void *data)
        if (on && (level > BACKLIGHT_OFF)) {
                lvds_gen_cntl &= ~LVDS_DISPLAY_DIS;
                if (!(lvds_gen_cntl & LVDS_BLON) || !(lvds_gen_cntl & LVDS_ON)) {
-                       lvds_gen_cntl |= LVDS_BLON /* | LVDS_EN | LVDS_DIGON */;
+                       lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_DIGON);
+                       lvds_gen_cntl |= LVDS_BLON | LVDS_EN;
                        OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
                        lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
                        lvds_gen_cntl |= (conv_table[level] <<
                                          LVDS_BL_MOD_LEVEL_SHIFT);
                        lvds_gen_cntl |= LVDS_ON;
+                       lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_BL_MOD_EN);
                        rinfo->pending_lvds_gen_cntl = lvds_gen_cntl;
                        mod_timer(&rinfo->lvds_timer,
                                  jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay));
@@ -1837,13 +1919,18 @@ static int radeon_set_backlight_enable(int on, int level, void *data)
                tmpPixclksCntl = INPLL(PIXCLKS_CNTL);
                if (rinfo->is_mobility || rinfo->is_IGP)
                        OUTPLLP(PIXCLKS_CNTL, 0, ~PIXCLK_LVDS_ALWAYS_ONb);
-               lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
+               lvds_gen_cntl &= ~(LVDS_BL_MOD_LEVEL_MASK | LVDS_BL_MOD_EN);
                lvds_gen_cntl |= (conv_table[0] <<
                                  LVDS_BL_MOD_LEVEL_SHIFT);
                lvds_gen_cntl |= LVDS_DISPLAY_DIS;
                OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
-               lvds_gen_cntl &= ~(LVDS_ON | LVDS_BLON /* | LVDS_EN | LVDS_DIGON */);
+               udelay(100);
+               lvds_gen_cntl &= ~(LVDS_ON | LVDS_EN);
                OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
+               lvds_gen_cntl &= ~(LVDS_DIGON);
+               rinfo->pending_lvds_gen_cntl = lvds_gen_cntl;
+               mod_timer(&rinfo->lvds_timer,
+                         jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay));
                if (rinfo->is_mobility || rinfo->is_IGP)
                        OUTPLL(PIXCLKS_CNTL, tmpPixclksCntl);
        }
@@ -1926,10 +2013,12 @@ static void fixup_memory_mappings(struct radeonfb_info *rinfo)
        OUTREG(DISPLAY_BASE_ADDR, aper_base);
        if (rinfo->has_CRTC2)
                OUTREG(CRTC2_DISPLAY_BASE_ADDR, aper_base);
+       OUTREG(OV0_BASE_ADDR, aper_base);
 #else
        OUTREG(DISPLAY_BASE_ADDR, 0);
        if (rinfo->has_CRTC2)
                OUTREG(CRTC2_DISPLAY_BASE_ADDR, 0);
+       OUTREG(OV0_BASE_ADDR, 0);
 #endif
        mdelay(100);
 
@@ -1947,6 +2036,100 @@ static void fixup_memory_mappings(struct radeonfb_info *rinfo)
 #endif /* CONFIG_PPC_OF */
 
 
+static void radeon_identify_vram(struct radeonfb_info *rinfo)
+{
+       u32 tmp;
+
+       /* framebuffer size */
+        if ((rinfo->family == CHIP_FAMILY_RS100) ||
+            (rinfo->family == CHIP_FAMILY_RS200) ||
+            (rinfo->family == CHIP_FAMILY_RS300)) {
+          u32 tom = INREG(NB_TOM);
+          tmp = ((((tom >> 16) - (tom & 0xffff) + 1) << 6) * 1024);
+
+               radeon_fifo_wait(6);
+          OUTREG(MC_FB_LOCATION, tom);
+          OUTREG(DISPLAY_BASE_ADDR, (tom & 0xffff) << 16);
+          OUTREG(CRTC2_DISPLAY_BASE_ADDR, (tom & 0xffff) << 16);
+          OUTREG(OV0_BASE_ADDR, (tom & 0xffff) << 16);
+
+          /* This is supposed to fix the crtc2 noise problem. */
+          OUTREG(GRPH2_BUFFER_CNTL, INREG(GRPH2_BUFFER_CNTL) & ~0x7f0000);
+
+          if ((rinfo->family == CHIP_FAMILY_RS100) ||
+              (rinfo->family == CHIP_FAMILY_RS200)) {
+             /* This is to workaround the asic bug for RMX, some versions
+                of BIOS dosen't have this register initialized correctly.
+             */
+             OUTREGP(CRTC_MORE_CNTL, CRTC_H_CUTOFF_ACTIVE_EN,
+                     ~CRTC_H_CUTOFF_ACTIVE_EN);
+          }
+        } else {
+          tmp = INREG(CONFIG_MEMSIZE);
+        }
+
+       /* mem size is bits [28:0], mask off the rest */
+       rinfo->video_ram = tmp & CONFIG_MEMSIZE_MASK;
+
+       /*
+        * Hack to get around some busted production M6's
+        * reporting no ram
+        */
+       if (rinfo->video_ram == 0) {
+               switch (rinfo->pdev->device) {
+               case PCI_CHIP_RADEON_LY:
+               case PCI_CHIP_RADEON_LZ:
+                       rinfo->video_ram = 8192 * 1024;
+                       break;
+               default:
+                       break;
+               }
+       }
+
+
+       /*
+        * Now try to identify VRAM type
+        */
+       if (rinfo->is_IGP || (rinfo->family >= CHIP_FAMILY_R300) ||
+           (INREG(MEM_SDRAM_MODE_REG) & (1<<30)))
+               rinfo->vram_ddr = 1;
+       else
+               rinfo->vram_ddr = 0;
+
+       tmp = INREG(MEM_CNTL);
+       if (IS_R300_VARIANT(rinfo)) {
+               tmp &=  R300_MEM_NUM_CHANNELS_MASK;
+               switch (tmp) {
+               case 0:  rinfo->vram_width = 64; break;
+               case 1:  rinfo->vram_width = 128; break;
+               case 2:  rinfo->vram_width = 256; break;
+               default: rinfo->vram_width = 128; break;
+               }
+       } else if ((rinfo->family == CHIP_FAMILY_RV100) ||
+                  (rinfo->family == CHIP_FAMILY_RS100) ||
+                  (rinfo->family == CHIP_FAMILY_RS200)){
+               if (tmp & RV100_MEM_HALF_MODE)
+                       rinfo->vram_width = 32;
+               else
+                       rinfo->vram_width = 64;
+       } else {
+               if (tmp & MEM_NUM_CHANNELS_MASK)
+                       rinfo->vram_width = 128;
+               else
+                       rinfo->vram_width = 64;
+       }
+
+       /* This may not be correct, as some cards can have half of channel disabled
+        * ToDo: identify these cases
+        */
+
+       RTRACE("radeonfb (%s): Found %ldk of %s %d bits wide videoram\n",
+              pci_name(rinfo->pdev),
+              rinfo->video_ram / 1024,
+              rinfo->vram_ddr ? "DDR" : "SDRAM",
+              rinfo->vram_width);
+}
+
 /*
  * Sysfs
  */
@@ -2012,7 +2195,6 @@ static int radeonfb_pci_register (struct pci_dev *pdev,
 {
        struct fb_info *info;
        struct radeonfb_info *rinfo;
-       u32 tmp;
        int ret;
 
        RTRACE("radeonfb_pci_register BEGIN\n");
@@ -2020,13 +2202,15 @@ static int radeonfb_pci_register (struct pci_dev *pdev,
        /* Enable device in PCI config */
        ret = pci_enable_device(pdev);
        if (ret < 0) {
-               printk(KERN_ERR "radeonfb: Cannot enable PCI device\n");
+               printk(KERN_ERR "radeonfb (%s): Cannot enable PCI device\n",
+                      pci_name(pdev));
                goto err_out;
        }
 
        info = framebuffer_alloc(sizeof(struct radeonfb_info), &pdev->dev);
        if (!info) {
-               printk (KERN_ERR "radeonfb: could not allocate memory\n");
+               printk (KERN_ERR "radeonfb (%s): could not allocate memory\n",
+                       pci_name(pdev));
                ret = -ENOMEM;
                goto err_disable;
        }
@@ -2055,121 +2239,39 @@ static int radeonfb_pci_register (struct pci_dev *pdev,
        /* request the mem regions */
        ret = pci_request_regions(pdev, "radeonfb");
        if (ret < 0) {
-               printk( KERN_ERR "radeonfb: cannot reserve PCI regions."
-                       "  Someone already got them?\n");
+               printk( KERN_ERR "radeonfb (%s): cannot reserve PCI regions."
+                       "  Someone already got them?\n", pci_name(rinfo->pdev));
                goto err_release_fb;
        }
 
        /* map the regions */
        rinfo->mmio_base = ioremap(rinfo->mmio_base_phys, RADEON_REGSIZE);
        if (!rinfo->mmio_base) {
-               printk(KERN_ERR "radeonfb: cannot map MMIO\n");
+               printk(KERN_ERR "radeonfb (%s): cannot map MMIO\n", pci_name(rinfo->pdev));
                ret = -EIO;
                goto err_release_pci;
        }
 
+       rinfo->fb_local_base = INREG(MC_FB_LOCATION) << 16;
+
+#ifdef CONFIG_PPC_OF
+       /* On PPC, we obtain the OF device-node pointer to the firmware
+        * data for this chip
+        */
+       rinfo->of_node = pci_device_to_OF_node(pdev);
+       if (rinfo->of_node == NULL)
+               printk(KERN_WARNING "radeonfb (%s): Cannot match card to OF node !\n",
+                      pci_name(rinfo->pdev));
+
        /* On PPC, the firmware sets up a memory mapping that tends
         * to cause lockups when enabling the engine. We reconfigure
         * the card internal memory mappings properly
         */
-#ifdef CONFIG_PPC_OF
        fixup_memory_mappings(rinfo);
-#else  
-       rinfo->fb_local_base = INREG(MC_FB_LOCATION) << 16;
 #endif /* CONFIG_PPC_OF */
 
-       /* framebuffer size */
-        if ((rinfo->family == CHIP_FAMILY_RS100) ||
-            (rinfo->family == CHIP_FAMILY_RS200) ||
-            (rinfo->family == CHIP_FAMILY_RS300)) {
-          u32 tom = INREG(NB_TOM);
-          tmp = ((((tom >> 16) - (tom & 0xffff) + 1) << 6) * 1024);
-               radeon_fifo_wait(6);
-          OUTREG(MC_FB_LOCATION, tom);
-          OUTREG(DISPLAY_BASE_ADDR, (tom & 0xffff) << 16);
-          OUTREG(CRTC2_DISPLAY_BASE_ADDR, (tom & 0xffff) << 16);
-          OUTREG(OV0_BASE_ADDR, (tom & 0xffff) << 16);
-          /* This is supposed to fix the crtc2 noise problem. */
-          OUTREG(GRPH2_BUFFER_CNTL, INREG(GRPH2_BUFFER_CNTL) & ~0x7f0000);
-          if ((rinfo->family == CHIP_FAMILY_RS100) ||
-              (rinfo->family == CHIP_FAMILY_RS200)) {
-             /* This is to workaround the asic bug for RMX, some versions
-                of BIOS dosen't have this register initialized correctly.
-             */
-             OUTREGP(CRTC_MORE_CNTL, CRTC_H_CUTOFF_ACTIVE_EN,
-                     ~CRTC_H_CUTOFF_ACTIVE_EN);
-          }
-        } else {
-          tmp = INREG(CONFIG_MEMSIZE);
-        }
-
-       /* mem size is bits [28:0], mask off the rest */
-       rinfo->video_ram = tmp & CONFIG_MEMSIZE_MASK;
-
-       /* ram type */
-       tmp = INREG(MEM_SDRAM_MODE_REG);
-       switch ((MEM_CFG_TYPE & tmp) >> 30) {
-               case 0:
-                       /* SDR SGRAM (2:1) */
-                       strcpy(rinfo->ram_type, "SDR SGRAM");
-                       rinfo->ram.ml = 4;
-                       rinfo->ram.mb = 4;
-                       rinfo->ram.trcd = 1;
-                       rinfo->ram.trp = 2;
-                       rinfo->ram.twr = 1;
-                       rinfo->ram.cl = 2;
-                       rinfo->ram.loop_latency = 16;
-                       rinfo->ram.rloop = 16;
-                       break;
-               case 1:
-                       /* DDR SGRAM */
-                       strcpy(rinfo->ram_type, "DDR SGRAM");
-                       rinfo->ram.ml = 4;
-                       rinfo->ram.mb = 4;
-                       rinfo->ram.trcd = 3;
-                       rinfo->ram.trp = 3;
-                       rinfo->ram.twr = 2;
-                       rinfo->ram.cl = 3;
-                       rinfo->ram.tr2w = 1;
-                       rinfo->ram.loop_latency = 16;
-                       rinfo->ram.rloop = 16;
-               break;
-               default:
-                       /* 64-bit SDR SGRAM */
-                       strcpy(rinfo->ram_type, "SDR SGRAM 64");
-                       rinfo->ram.ml = 4;
-                       rinfo->ram.mb = 8;
-                       rinfo->ram.trcd = 3;
-                       rinfo->ram.trp = 3;
-                       rinfo->ram.twr = 1;
-                       rinfo->ram.cl = 3;
-                       rinfo->ram.tr2w = 1;
-                       rinfo->ram.loop_latency = 17;
-                       rinfo->ram.rloop = 17;
-               break;
-       }
-
-       /*
-        * Hack to get around some busted production M6's
-        * reporting no ram
-        */
-       if (rinfo->video_ram == 0) {
-               switch (pdev->device) {
-               case PCI_CHIP_RADEON_LY:
-               case PCI_CHIP_RADEON_LZ:
-                       rinfo->video_ram = 8192 * 1024;
-                       break;
-               default:
-                       printk (KERN_ERR "radeonfb: no video RAM reported\n");
-                       ret = -ENXIO;
-                       goto err_unmap_rom;
-               }
-       }
-
-       RTRACE("radeonfb: probed %s %ldk videoram\n", (rinfo->ram_type), (rinfo->video_ram/1024));
+       /* Get VRAM size and type */
+       radeon_identify_vram(rinfo);
 
        rinfo->mapped_vram = min_t(unsigned long, MAX_MAPPED_VRAM, rinfo->video_ram);
 
@@ -2182,12 +2284,13 @@ static int radeonfb_pci_register (struct pci_dev *pdev,
        if (rinfo->fb_base)
                memset_io(rinfo->fb_base, 0, rinfo->mapped_vram);
        else {
-               printk (KERN_ERR "radeonfb: cannot map FB\n");
+               printk (KERN_ERR "radeonfb (%s): cannot map FB\n", pci_name(rinfo->pdev));
                ret = -EIO;
                goto err_unmap_rom;
        }
 
-       RTRACE("radeonfb: mapped %ldk videoram\n", rinfo->mapped_vram/1024);
+       RTRACE("radeonfb (%s): mapped %ldk videoram\n", pci_name(rinfo->pdev),
+              rinfo->mapped_vram/1024);
 
        /*
         * Check for required workaround for PLL accesses
@@ -2254,21 +2357,22 @@ static int radeonfb_pci_register (struct pci_dev *pdev,
         * so we can restore this upon __exit
         */
        radeon_save_state (rinfo, &rinfo->init_state);
+       memcpy(&rinfo->state, &rinfo->init_state, sizeof(struct radeon_regs));
 
        pci_set_drvdata(pdev, info);
 
-       /* Enable PM on mobility chips */
-       if (rinfo->is_mobility) {
-               /* Find PM registers in config space */
-               rinfo->pm_reg = pci_find_capability(pdev, PCI_CAP_ID_PM);
-               /* Enable dynamic PM of chip clocks */
-               radeon_pm_enable_dynamic_mode(rinfo);
-               printk("radeonfb: Power Management enabled for Mobility chipsets\n");
-       }
+       /* Setup Power Management capabilities */
+       if (default_dynclk < -1) {
+               /* -2 is special: means  ON on mobility chips and do not change on others */
+               radeonfb_pm_init(rinfo, rinfo->is_mobility ? 1 : -1);
+       } else
+               radeonfb_pm_init(rinfo, default_dynclk);
 
+       /* Register with fbdev layer */
        ret = register_framebuffer(info);
        if (ret < 0) {
-               printk (KERN_ERR "radeonfb: could not register framebuffer\n");
+               printk (KERN_ERR "radeonfb (%s): could not register framebuffer\n",
+                       pci_name(rinfo->pdev));
                goto err_unmap_fb;
        }
 
@@ -2287,8 +2391,7 @@ static int radeonfb_pci_register (struct pci_dev *pdev,
        }
 #endif
 
-       printk ("radeonfb: %s %s %ld MB\n", rinfo->name, rinfo->ram_type,
-               (rinfo->video_ram/(1024*1024)));
+       printk ("radeonfb (%s): %s\n", pci_name(rinfo->pdev), rinfo->name);
 
        if (rinfo->bios_seg)
                radeon_unmap_ROM(rinfo, pdev);
@@ -2331,13 +2434,18 @@ static void __devexit radeonfb_pci_unregister (struct pci_dev *pdev)
         if (!rinfo)
                 return;
  
+       radeonfb_pm_exit(rinfo);
+
+#if 0
        /* restore original state
         * 
-        * Doesn't quite work yet, possibly because of the PPC hacking
-        * I do on startup, disable for now. --BenH
+        * Doesn't quite work yet, I suspect if we come from a legacy
+        * VGA mode (or worse, text mode), we need to do some VGA black
+        * magic here that I know nothing about. --BenH
         */
-        radeon_write_mode (rinfo, &rinfo->init_state);
+        radeon_write_mode (rinfo, &rinfo->init_state, 1);
+ #endif
+
        del_timer_sync(&rinfo->lvds_timer);
 
 #ifdef CONFIG_MTRR
@@ -2443,6 +2551,8 @@ MODULE_AUTHOR("Ani Joshi");
 MODULE_DESCRIPTION("framebuffer driver for ATI Radeon chipset");
 MODULE_LICENSE("GPL");
 module_param(noaccel, bool, 0);
+module_param(default_dynclk, int, -2);
+MODULE_PARM_DESC(default_dynclk, "int: -2=enable on mobility only,-1=do not change,0=off,1=on");
 MODULE_PARM_DESC(noaccel, "bool: disable acceleration");
 module_param(nomodeset, bool, 0);
 MODULE_PARM_DESC(nomodeset, "bool: disable actual setting of video mode");
index f55f863ba23d864cc2de1017019dbfd2b1e105b2..9094137ccde0a407e7d02492d310e6de82e42ff6 100644 (file)
@@ -1,11 +1,6 @@
 #include "radeonfb.h"
 #include "../edid.h"
 
-#ifdef CONFIG_PPC_OF
-#include <asm/prom.h>
-#include <asm/pci-bridge.h>
-#endif /* CONFIG_PPC_OF */
-
 static struct fb_var_screeninfo radeonfb_default_var = {
        .xres           = 640,
        .yres           = 480,
@@ -64,9 +59,11 @@ static char *radeon_get_mon_name(int type)
  * models with broken OF probing by hard-coding known EDIDs for some Mac
  * laptops internal LVDS panel. (XXX: not done yet)
  */
-static int __devinit radeon_parse_montype_prop(struct device_node *dp, u8 **out_EDID, int hdno)
+static int __devinit radeon_parse_montype_prop(struct device_node *dp, u8 **out_EDID,
+                                              int hdno)
 {
-        static char *propnames[] = { "DFP,EDID", "LCD,EDID", "EDID", "EDID1", "EDID2",  NULL };
+        static char *propnames[] = { "DFP,EDID", "LCD,EDID", "EDID",
+                                    "EDID1", "EDID2",  NULL };
        u8 *pedid = NULL;
        u8 *pmt = NULL;
        u8 *tmp;
@@ -122,7 +119,7 @@ static int __devinit radeon_probe_OF_head(struct radeonfb_info *rinfo, int head_
 
        RTRACE("radeon_probe_OF_head\n");
 
-        dp = pci_device_to_OF_node(rinfo->pdev);
+        dp = rinfo->of_node;
         while (dp == NULL)
                return MT_NONE;
 
@@ -502,8 +499,9 @@ void __devinit radeon_probe_screens(struct radeonfb_info *rinfo,
 #endif /* CONFIG_PPC_OF */
 #ifdef CONFIG_FB_RADEON_I2C
                        if (rinfo->mon1_type == MT_NONE)
-                               rinfo->mon1_type = radeon_probe_i2c_connector(rinfo, ddc_dvi,
-                                                                     &rinfo->mon1_EDID);
+                               rinfo->mon1_type =
+                                       radeon_probe_i2c_connector(rinfo, ddc_dvi,
+                                                                  &rinfo->mon1_EDID);
                        if (rinfo->mon1_type == MT_NONE)
                                rinfo->mon1_type =
                                        radeon_probe_i2c_connector(rinfo, ddc_vga,
@@ -545,7 +543,8 @@ void __devinit radeon_probe_screens(struct radeonfb_info *rinfo,
                 */
 #ifdef CONFIG_PPC_OF
                if (rinfo->mon1_type == MT_NONE)
-                       rinfo->mon1_type = radeon_probe_OF_head(rinfo, 0, &rinfo->mon1_EDID);
+                       rinfo->mon1_type = radeon_probe_OF_head(rinfo, 0,
+                                                               &rinfo->mon1_EDID);
 #endif /* CONFIG_PPC_OF */
 #ifdef CONFIG_FB_RADEON_I2C
                if (rinfo->mon1_type == MT_NONE)
@@ -572,7 +571,8 @@ void __devinit radeon_probe_screens(struct radeonfb_info *rinfo,
                 */
 #ifdef CONFIG_PPC_OF
                if (rinfo->mon2_type == MT_NONE)
-                       rinfo->mon2_type = radeon_probe_OF_head(rinfo, 1, &rinfo->mon2_EDID);
+                       rinfo->mon2_type = radeon_probe_OF_head(rinfo, 1,
+                                                               &rinfo->mon2_EDID);
 #endif /* CONFIG_PPC_OF */
 #ifdef CONFIG_FB_RADEON_I2C
                if (rinfo->mon2_type == MT_NONE)
@@ -648,10 +648,10 @@ void __devinit radeon_probe_screens(struct radeonfb_info *rinfo,
  */
 static void radeon_fixup_panel_info(struct radeonfb_info *rinfo)
 {
- #ifdef CONFIG_PPC_OF
+#ifdef CONFIG_PPC_OF
        /*
         * LCD Flat panels should use fixed dividers, we enfore that on
-        * PowerMac only for now...
+        * PPC only for now...
         */
        if (!rinfo->panel_info.use_bios_dividers && rinfo->mon1_type == MT_LCD
            && rinfo->is_mobility) {
@@ -702,40 +702,24 @@ static void radeon_var_to_panel_info(struct radeonfb_info *rinfo, struct fb_var_
        rinfo->panel_info.pwr_delay = 200;
 }
 
-static void radeon_var_to_videomode(struct fb_videomode *mode,
-                                   const struct fb_var_screeninfo *var)
-{
-    mode->xres = var->xres;
-    mode->yres = var->yres;
-    mode->pixclock = var->pixclock;
-    mode->left_margin = var->left_margin;
-    mode->right_margin = var->right_margin;
-    mode->upper_margin = var->upper_margin;
-    mode->lower_margin = var->lower_margin;
-    mode->hsync_len = var->hsync_len;
-    mode->vsync_len = var->vsync_len;
-    mode->sync = var->sync;
-    mode->vmode = var->vmode;
-}
-
 static void radeon_videomode_to_var(struct fb_var_screeninfo *var,
                                    const struct fb_videomode *mode)
 {
-    var->xres = mode->xres;
-    var->yres = mode->yres;
-    var->xres_virtual = mode->xres;
-    var->yres_virtual = mode->yres;
-    var->xoffset = 0;
-    var->yoffset = 0;
-    var->pixclock = mode->pixclock;
-    var->left_margin = mode->left_margin;
-    var->right_margin = mode->right_margin;
-    var->upper_margin = mode->upper_margin;
-    var->lower_margin = mode->lower_margin;
-    var->hsync_len = mode->hsync_len;
-    var->vsync_len = mode->vsync_len;
-    var->sync = mode->sync;
-    var->vmode = mode->vmode;
+       var->xres = mode->xres;
+       var->yres = mode->yres;
+       var->xres_virtual = mode->xres;
+       var->yres_virtual = mode->yres;
+       var->xoffset = 0;
+       var->yoffset = 0;
+       var->pixclock = mode->pixclock;
+       var->left_margin = mode->left_margin;
+       var->right_margin = mode->right_margin;
+       var->upper_margin = mode->upper_margin;
+       var->lower_margin = mode->lower_margin;
+       var->hsync_len = mode->hsync_len;
+       var->vsync_len = mode->vsync_len;
+       var->sync = mode->sync;
+       var->vmode = mode->vmode;
 }
 
 /*
@@ -744,12 +728,14 @@ static void radeon_videomode_to_var(struct fb_var_screeninfo *var,
  */
 void __devinit radeon_check_modes(struct radeonfb_info *rinfo, const char *mode_option)
 {
+       struct fb_info * info = rinfo->info;
        int has_default_mode = 0;
 
        /*
         * Fill default var first
         */
-       rinfo->info->var = radeonfb_default_var;
+       info->var = radeonfb_default_var;
+       INIT_LIST_HEAD(&info->modelist);
 
        /*
         * First check out what BIOS has to say
@@ -783,7 +769,7 @@ void __devinit radeon_check_modes(struct radeonfb_info *rinfo, const char *mode_
         * those
         */
        if (rinfo->mon1_type != MT_CRT && rinfo->panel_info.valid) {
-               struct fb_var_screeninfo *var = &rinfo->info->var;
+               struct fb_var_screeninfo *var = &info->var;
 
                RTRACE("Setting up default mode based on panel info\n");
                var->xres = rinfo->panel_info.xres;
@@ -814,9 +800,12 @@ void __devinit radeon_check_modes(struct radeonfb_info *rinfo, const char *mode_
         * Now build modedb from EDID
         */
        if (rinfo->mon1_EDID) {
-               rinfo->mon1_modedb = fb_create_modedb(rinfo->mon1_EDID,
-                                                     &rinfo->mon1_dbsize);
-               fb_get_monitor_limits(rinfo->mon1_EDID, &rinfo->info->monspecs);
+               fb_edid_to_monspecs(rinfo->mon1_EDID, &info->monspecs);
+               fb_videomode_to_modelist(info->monspecs.modedb,
+                                        info->monspecs.modedb_len,
+                                        &info->modelist);
+               rinfo->mon1_modedb = info->monspecs.modedb;
+               rinfo->mon1_dbsize = info->monspecs.modedb_len;
        }
 
        
@@ -847,31 +836,62 @@ void __devinit radeon_check_modes(struct radeonfb_info *rinfo, const char *mode_
                modedb = rinfo->mon1_modedb;
                dbsize = rinfo->mon1_dbsize;
                snprintf(modename, 31, "%dx%d", rinfo->panel_info.xres, rinfo->panel_info.yres);
-               if (fb_find_mode(&rinfo->info->var, rinfo->info, modename,
+               if (fb_find_mode(&info->var, info, modename,
                                 modedb, dbsize, NULL, 8) == 0) {
                        printk(KERN_WARNING "radeonfb: Can't find mode for panel size, going back to CRT\n");
                        rinfo->mon1_type = MT_CRT;
                        goto pickup_default;
                }
                has_default_mode = 1;
-               radeon_var_to_panel_info(rinfo, &rinfo->info->var);
+               radeon_var_to_panel_info(rinfo, &info->var);
        }
 
  pickup_default:
        /*
-        * Pick up a random default mode
+        * Apply passed-in mode option if any
         */
-       if (!has_default_mode || mode_option) {
-               struct fb_videomode default_mode;
-               if (has_default_mode)
-                       radeon_var_to_videomode(&default_mode, &rinfo->info->var);
-               else
-                       radeon_var_to_videomode(&default_mode, &radeonfb_default_var);
-               if (fb_find_mode(&rinfo->info->var, rinfo->info, mode_option,
-                                rinfo->mon1_modedb, rinfo->mon1_dbsize, &default_mode, 8) == 0)
-                       rinfo->info->var = radeonfb_default_var;
-       }
+       if (mode_option) {
+               if (fb_find_mode(&info->var, info, mode_option,
+                                info->monspecs.modedb,
+                                info->monspecs.modedb_len, NULL, 8) != 0)
+                       has_default_mode = 1;
+       }
+
+       /*
+        * Still no mode, let's pick up a default from the db
+        */
+       if (!has_default_mode && info->monspecs.modedb != NULL) {
+               struct fb_monspecs *specs = &info->monspecs;
+               struct fb_videomode *modedb = NULL;
+
+               /* get preferred timing */
+               if (specs->misc & FB_MISC_1ST_DETAIL) {
+                       int i;
 
+                       for (i = 0; i < specs->modedb_len; i++) {
+                               if (specs->modedb[i].flag & FB_MODE_IS_FIRST) {
+                                       modedb = &specs->modedb[i];
+                                       break;
+                               }
+                       }
+               } else {
+                       /* otherwise, get first mode in database */
+                       modedb = &specs->modedb[0];
+               }
+               if (modedb != NULL) {
+                       info->var.bits_per_pixel = 8;
+                       radeon_videomode_to_var(&info->var, modedb);
+                       has_default_mode = 1;
+               }
+       }
+       if (1) {
+               struct fb_videomode mode;
+               /* Make sure that whatever mode got selected is actually in the
+                * modelist or the kernel may die
+                */
+               fb_var_to_videomode(&mode, &info->var);
+               fb_add_videomode(&mode, &info->modelist);
+       }
 }
 
 /*
index c033fe4cd887773087c983392970fa6c01d2eaae..4f23594acbeb0dd84ec6037f0b153464a0eb83ab 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);
+               OUTREG(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;
+               OUTREG(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);
        
@@ -480,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);
        
@@ -510,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
+       } else {
+               OUTREG(BUS_CNTL1, INREG(BUS_CNTL1));
+               OUTREG(BUS_CNTL1, (INREG(BUS_CNTL1) & ~0x4000) | 0x8000);
+       }
 
-       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(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;        
@@ -547,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|
@@ -571,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);                                
 
@@ -601,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;
-
-       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));
+       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;
 
-       /* 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);
@@ -619,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;
+       }
 }
 
 
@@ -646,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);
@@ -777,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;
@@ -796,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);
                
@@ -815,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,
@@ -841,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);
 
@@ -883,21 +2539,52 @@ 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
         */
-#ifdef CONFIG_RADEON_HAS_D2
-       if (radeon_suspend_to_d2(rinfo, state))
+       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)
+        */
+       if (rinfo->pm_mode & radeon_pm_d2)
                radeon_set_suspend(rinfo, 1);
-#endif /* CONFIG_RADEON_HAS_D2 */
 
        release_console_sem();
 
+ done:
        pdev->dev.power.power_state = state;
 
        return 0;
@@ -907,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.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);
 
@@ -931,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);
 
-       release_console_sem();
+       /* 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;
 
-       printk(KERN_DEBUG "radeonfb: resumed !\n");
+ bail:
+       release_console_sem();
 
-       return 0;
+       return rc;
+}
+
+#ifdef CONFIG_PPC_OF
+static void radeonfb_early_resume(void *data)
+{
+        struct radeonfb_info *rinfo = data;
+
+       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
+}
index 7377cb7b14b957f8196200259c4ee0f92b1f62e5..a01aa344c99ead41ce51c8fe6c5e4d910831fcc1 100644 (file)
 
 #include <asm/io.h>
 
+#ifdef CONFIG_PPC_OF
+#include <asm/prom.h>
+#endif
+
 #include <video/radeon.h>
 
+/* Some weird black magic use by Apple driver that we don't use for
+ * now --BenH
+ */
+#undef HAS_PLL_M9_GPIO_MAGIC
+
 /***************************************************************
  * Most of the definitions here are adapted right from XFree86 *
  ***************************************************************/
@@ -33,7 +42,8 @@ enum radeon_family {
        CHIP_FAMILY_RV100,
        CHIP_FAMILY_RS100,    /* U1 (IGP320M) or A3 (IGP320)*/
        CHIP_FAMILY_RV200,
-       CHIP_FAMILY_RS200,    /* U2 (IGP330M/340M/350M) or A4 (IGP330/340/345/350), RS250 (IGP 7000) */
+       CHIP_FAMILY_RS200,    /* U2 (IGP330M/340M/350M) or A4 (IGP330/340/345/350),
+                                RS250 (IGP 7000) */
        CHIP_FAMILY_R200,
        CHIP_FAMILY_RV250,
        CHIP_FAMILY_RS300,    /* Radeon 9000 IGP */
@@ -41,9 +51,26 @@ enum radeon_family {
        CHIP_FAMILY_R300,
        CHIP_FAMILY_R350,
        CHIP_FAMILY_RV350,
+       CHIP_FAMILY_RV380,    /* RV370/RV380/M22/M24 */
+       CHIP_FAMILY_R420,     /* R420/R423/M18 */
        CHIP_FAMILY_LAST,
 };
 
+#define IS_RV100_VARIANT(rinfo) (((rinfo)->family == CHIP_FAMILY_RV100)  || \
+                                ((rinfo)->family == CHIP_FAMILY_RV200)  || \
+                                ((rinfo)->family == CHIP_FAMILY_RS100)  || \
+                                ((rinfo)->family == CHIP_FAMILY_RS200)  || \
+                                ((rinfo)->family == CHIP_FAMILY_RV250)  || \
+                                ((rinfo)->family == CHIP_FAMILY_RV280)  || \
+                                ((rinfo)->family == CHIP_FAMILY_RS300))
+
+
+#define IS_R300_VARIANT(rinfo) (((rinfo)->family == CHIP_FAMILY_R300)  || \
+                               ((rinfo)->family == CHIP_FAMILY_RV350) || \
+                               ((rinfo)->family == CHIP_FAMILY_R350)  || \
+                               ((rinfo)->family == CHIP_FAMILY_RV380) || \
+                               ((rinfo)->family == CHIP_FAMILY_R420))
+
 /*
  * Chip flags
  */
@@ -102,21 +129,6 @@ struct pll_info {
        int ref_clk;
 };
 
-/*
- * VRAM infos
- */
-struct ram_info {
-       int ml;
-       int mb;
-       int trcd;
-       int trp;
-       int twr;
-       int cl;
-       int tr2w;
-       int loop_latency;
-       int rloop;
-};
-
 
 /*
  * This structure contains the various registers manipulated by this
@@ -210,6 +222,7 @@ struct radeon_regs {
        u32             ppll_div_3;
        u32             ppll_ref_div;
        u32             vclk_ecp_cntl;
+       u32             clk_cntl_index;
 
        /* Computed values for PLL2 */
        u32             dot_clock_freq_2;
@@ -250,6 +263,12 @@ struct radeon_i2c_chan {
 };
 #endif
 
+enum radeon_pm_mode {
+       radeon_pm_none  = 0,            /* Nothing supported */
+       radeon_pm_d2    = 0x00000001,   /* Can do D2 state */
+       radeon_pm_off   = 0x00000002,   /* Can resume from D3 cold */
+};
+
 struct radeonfb_info {
        struct fb_info          *info;
 
@@ -257,7 +276,6 @@ struct radeonfb_info {
        struct radeon_regs      init_state;
 
        char                    name[DEVICE_NAME_SIZE];
-       char                    ram_type[12];
 
        unsigned long           mmio_base_phys;
        unsigned long           fb_base_phys;
@@ -268,6 +286,9 @@ struct radeonfb_info {
        unsigned long           fb_local_base;
 
        struct pci_dev          *pdev;
+#ifdef CONFIG_PPC_OF
+       struct device_node      *of_node;
+#endif
 
        void __iomem            *bios_seg;
        int                     fp_bios_start;
@@ -281,6 +302,8 @@ struct radeonfb_info {
        u8                      rev;
        unsigned long           video_ram;
        unsigned long           mapped_vram;
+       int                     vram_width;
+       int                     vram_ddr;
 
        int                     pitch, bpp, depth;
 
@@ -288,6 +311,7 @@ struct radeonfb_info {
        int                     is_mobility;
        int                     is_IGP;
        int                     R300_cg_workaround;
+       int                     m9p_workaround;
        int                     reversed_DAC;
        int                     reversed_TMDS;
        struct panel_info       panel_info;
@@ -302,14 +326,16 @@ struct radeonfb_info {
 
        struct pll_info         pll;
 
-       struct ram_info         ram;
-
        int                     mtrr_hdl;
 
        int                     pm_reg;
-       u32                     save_regs[64];
+       u32                     save_regs[100];
        int                     asleep;
        int                     lock_blank;
+       int                     dynclk;
+       int                     no_schedule;
+       enum radeon_pm_mode     pm_mode;
+       void                    (*reinit_func)(struct radeonfb_info *rinfo);
 
        /* Lock on register access */
        spinlock_t              reg_lock;
@@ -317,11 +343,12 @@ struct radeonfb_info {
        /* Timer used for delayed LVDS operations */
        struct timer_list       lvds_timer;
        u32                     pending_lvds_gen_cntl;
-       u32                     pending_pixclks_cntl;
 
 #ifdef CONFIG_FB_RADEON_I2C
        struct radeon_i2c_chan  i2c[4];
 #endif
+
+       u32                     cfg_save[64];
 };
 
 
@@ -353,6 +380,22 @@ struct radeonfb_info {
 #define INREG(addr)            readl((rinfo->mmio_base)+addr)
 #define OUTREG(addr,val)       writel(val, (rinfo->mmio_base)+addr)
 
+static inline void _OUTREGP(struct radeonfb_info *rinfo, u32 addr,
+                      u32 val, u32 mask)
+{
+       unsigned long flags;
+       unsigned int tmp;
+
+       spin_lock_irqsave(&rinfo->reg_lock, flags);
+       tmp = INREG(addr);
+       tmp &= (mask);
+       tmp |= (val);
+       OUTREG(addr, tmp);
+       spin_unlock_irqrestore(&rinfo->reg_lock, flags);
+}
+
+#define OUTREGP(addr,val,mask) _OUTREGP(rinfo, addr, val,mask)
+
 static inline void R300_cg_workardound(struct radeonfb_info *rinfo)
 {
        u32 save, tmp;
@@ -363,18 +406,35 @@ static inline void R300_cg_workardound(struct radeonfb_info *rinfo)
        OUTREG(CLOCK_CNTL_INDEX, save);
 }
 
-#define __OUTPLL(addr,val)     \
-       do {    \
-               OUTREG8(CLOCK_CNTL_INDEX, (addr & 0x0000003f) | 0x00000080); \
-               OUTREG(CLOCK_CNTL_DATA, val); \
-} while(0)
-
 
 static inline u32 __INPLL(struct radeonfb_info *rinfo, u32 addr)
 {
        u32 data;
+#ifdef HAS_PLL_M9_GPIO_MAGIC
+       u32 sv[3];
+
+       if (rinfo->m9p_workaround) {
+               sv[0] = INREG(0x19c);
+               sv[1] = INREG(0x1a0);
+               sv[2] = INREG(0x198);
+               OUTREG(0x198, 0);
+               OUTREG(0x1a0, 0);
+               OUTREG(0x19c, 0);
+       }
+#endif /* HAS_PLL_M9_GPIO_MAGIC */
+
        OUTREG8(CLOCK_CNTL_INDEX, addr & 0x0000003f);
        data = (INREG(CLOCK_CNTL_DATA));
+
+#ifdef HAS_PLL_M9_GPIO_MAGIC
+       if (rinfo->m9p_workaround) {
+               (void)INREG(CRTC_GEN_CNTL);
+               data = INREG(CLOCK_CNTL_DATA);
+               OUTREG(0x19c, sv[0]);
+               OUTREG(0x1a0, sv[1]);
+               OUTREG(0x198, sv[2]);
+       }
+#endif /* HAS_PLL_M9_GPIO_MAGIC */
        if (rinfo->R300_cg_workaround)
                R300_cg_workardound(rinfo);
        return data;
@@ -393,37 +453,61 @@ static inline u32 _INPLL(struct radeonfb_info *rinfo, u32 addr)
 
 #define INPLL(addr)            _INPLL(rinfo, addr)
 
-#define OUTPLL(addr,val)       \
-       do {    \
-               unsigned long flags;\
-               spin_lock_irqsave(&rinfo->reg_lock, flags); \
-               __OUTPLL(addr, val); \
-               spin_unlock_irqrestore(&rinfo->reg_lock, flags); \
-       } while(0)
-
-#define OUTPLLP(addr,val,mask)                                         \
-       do {                                                            \
-               unsigned long flags;                                    \
-               unsigned int _tmp;                                      \
-               spin_lock_irqsave(&rinfo->reg_lock, flags);             \
-               _tmp  = __INPLL(rinfo,addr);                            \
-               _tmp &= (mask);                                         \
-               _tmp |= (val);                                          \
-               __OUTPLL(addr, _tmp);                                   \
-               spin_unlock_irqrestore(&rinfo->reg_lock, flags);        \
-       } while (0)
-
-#define OUTREGP(addr,val,mask)                                         \
-       do {                                                            \
-               unsigned long flags;                                    \
-               unsigned int _tmp;                                      \
-               spin_lock_irqsave(&rinfo->reg_lock, flags);             \
-               _tmp = INREG(addr);                                     \
-               _tmp &= (mask);                                         \
-               _tmp |= (val);                                          \
-               OUTREG(addr, _tmp);                                     \
-               spin_unlock_irqrestore(&rinfo->reg_lock, flags);        \
-       } while (0)
+
+static inline void __OUTPLL(struct radeonfb_info *rinfo, unsigned int index, u32 val)
+{
+#ifdef HAS_PLL_M9_GPIO_MAGIC
+       u32 sv[3];
+
+       if (rinfo->m9p_workaround) {
+               sv[0] = INREG(0x19c);
+               sv[1] = INREG(0x1a0);
+               sv[2] = INREG(0x198);
+               OUTREG(0x198, 0);
+               OUTREG(0x1a0, 0);
+               OUTREG(0x19c, 0);
+               mdelay(1);
+       }
+#endif /* HAS_PLL_M9_GPIO_MAGIC */
+
+       OUTREG8(CLOCK_CNTL_INDEX, (index & 0x0000003f) | 0x00000080);
+       OUTREG(CLOCK_CNTL_DATA, val);
+
+#ifdef HAS_PLL_M9_GPIO_MAGIC
+       if (rinfo->m9p_workaround) {
+               OUTREG(0x19c, sv[0]);
+               OUTREG(0x1a0, sv[1]);
+               OUTREG(0x198, sv[2]);
+       }
+#endif /* HAS_PLL_M9_GPIO_MAGIC */
+}
+
+static inline void _OUTPLL(struct radeonfb_info *rinfo, unsigned int index, u32 val)
+{
+               unsigned long flags;
+       spin_lock_irqsave(&rinfo->reg_lock, flags);
+       __OUTPLL(rinfo, index, val);
+       spin_unlock_irqrestore(&rinfo->reg_lock, flags);
+}
+
+static inline void _OUTPLLP(struct radeonfb_info *rinfo, unsigned int index,
+                           u32 val, u32 mask)
+{
+       unsigned long flags;
+       unsigned int tmp;
+
+       spin_lock_irqsave(&rinfo->reg_lock, flags);
+       tmp  = __INPLL(rinfo, index);
+       tmp &= (mask);
+       tmp |= (val);
+       __OUTPLL(rinfo, index, tmp);
+       spin_unlock_irqrestore(&rinfo->reg_lock, flags);
+}
+
+
+#define OUTPLL(index, val)             _OUTPLL(rinfo, index, val)
+#define OUTPLLP(index, val, mask)      _OUTPLLP(rinfo, index, val, mask)
+
 
 #define BIOS_IN8(v)    (readb(rinfo->bios_seg + (v)))
 #define BIOS_IN16(v)   (readb(rinfo->bios_seg + (v)) | \
@@ -484,7 +568,7 @@ static inline void radeon_engine_flush (struct radeonfb_info *rinfo)
 }
 
 
-static inline void _radeon_fifo_wait (struct radeonfb_info *rinfo, int entries)
+static inline void _radeon_fifo_wait(struct radeonfb_info *rinfo, int entries)
 {
        int i;
 
@@ -497,7 +581,7 @@ static inline void _radeon_fifo_wait (struct radeonfb_info *rinfo, int entries)
 }
 
 
-static inline void _radeon_engine_idle (struct radeonfb_info *rinfo)
+static inline void _radeon_engine_idle(struct radeonfb_info *rinfo)
 {
        int i;
 
@@ -514,8 +598,24 @@ static inline void _radeon_engine_idle (struct radeonfb_info *rinfo)
        printk(KERN_ERR "radeonfb: Idle Timeout !\n");
 }
 
+/* Note about this function: we have some rare cases where we must not schedule,
+ * this typically happen with our special "wake up early" hook which allows us to
+ * wake up the graphic chip (and thus get the console back) before everything else
+ * on some machines that support that mecanism. At this point, interrupts are off
+ * and scheduling is not permitted
+ */
+static inline void _radeon_msleep(struct radeonfb_info *rinfo, unsigned long ms)
+{
+       if (rinfo->no_schedule)
+               mdelay(ms);
+       else
+               msleep(ms);
+}
+
+
 #define radeon_engine_idle()           _radeon_engine_idle(rinfo)
 #define radeon_fifo_wait(entries)      _radeon_fifo_wait(rinfo,entries)
+#define radeon_msleep(ms)              _radeon_msleep(rinfo,ms)
 
 
 /* I2C Functions */
@@ -524,10 +624,10 @@ extern void radeon_delete_i2c_busses(struct radeonfb_info *rinfo);
 extern int radeon_probe_i2c_connector(struct radeonfb_info *rinfo, int conn, u8 **out_edid);
 
 /* PM Functions */
-extern void radeon_pm_disable_dynamic_mode(struct radeonfb_info *rinfo);
-extern void radeon_pm_enable_dynamic_mode(struct radeonfb_info *rinfo);
 extern int radeonfb_pci_suspend(struct pci_dev *pdev, u32 state);
 extern int radeonfb_pci_resume(struct pci_dev *pdev);
+extern void radeonfb_pm_init(struct radeonfb_info *rinfo, int dynclk);
+extern void radeonfb_pm_exit(struct radeonfb_info *rinfo);
 
 /* Monitor probe functions */
 extern void radeon_probe_screens(struct radeonfb_info *rinfo,
@@ -546,7 +646,9 @@ extern void radeonfb_engine_init (struct radeonfb_info *rinfo);
 extern void radeonfb_engine_reset(struct radeonfb_info *rinfo);
 
 /* Other functions */
-extern int radeonfb_blank(int blank, struct fb_info *info);
-extern int radeonfb_set_par(struct fb_info *info);
+extern int radeon_screen_blank(struct radeonfb_info *rinfo, int blank, int mode_switch);
+extern void radeon_save_state (struct radeonfb_info *rinfo, struct radeon_regs *save);
+extern void radeon_write_mode (struct radeonfb_info *rinfo, struct radeon_regs *mode,
+                              int reg_only);
 
 #endif /* __RADEONFB_H__ */
index ccbc4fc7200a9fba85eb361dbbe302515115552a..9a2e3adea0fd50cff12b8a0d8a784a0acbefc619 100644 (file)
@@ -814,7 +814,7 @@ static void radeon_get_pllinfo(struct radeonfb_info *rinfo, void __iomem *bios_s
                if (radeon_read_OF(rinfo)) {
                        unsigned int tmp, Nx, M, ref_div, xclk;
 
-                       tmp = INPLL(X_MPLL_REF_FB_DIV);
+                       tmp = INPLL(M_SPLL_REF_FB_DIV);
                        ref_div = INPLL(PPLL_REF_DIV) & 0x3ff;
 
                        Nx = (tmp & 0xff00) >> 8;
index 91ba041acab6a98f5b8acd60c86746046487b316..83467e18f5e96337ee550f26f35bcd8ac9f0c36b 100644 (file)
@@ -21,6 +21,7 @@
 #define PAD_AGPINPUT_DELAY                     0x0164  
 #define PAD_CTLR_STRENGTH                      0x0168  
 #define PAD_CTLR_UPDATE                        0x016C
+#define PAD_CTLR_MISC                          0x0aa0
 #define AGP_CNTL                               0x0174
 #define BM_STATUS                              0x0160
 #define CAP0_TRIG_CNTL                        0x0950
 #define DAC_CNTL2                              0x007c
 #define CRTC_GEN_CNTL                          0x0050  
 #define MEM_CNTL                               0x0140  
+#define MC_CNTL                                0x0140
 #define EXT_MEM_CNTL                           0x0144  
+#define MC_TIMING_CNTL                         0x0144
 #define MC_AGP_LOCATION                        0x014C  
 #define MEM_IO_CNTL_A0                         0x0178  
+#define MEM_REFRESH_CNTL                       0x0178
 #define MEM_INIT_LATENCY_TIMER                 0x0154  
+#define MC_INIT_GFX_LAT_TIMER                  0x0154
 #define MEM_SDRAM_MODE_REG                     0x0158  
 #define AGP_BASE                               0x0170  
 #define MEM_IO_CNTL_A1                         0x017C  
+#define MC_READ_CNTL_AB                        0x017C
 #define MEM_IO_CNTL_B0                         0x0180
+#define MC_INIT_MISC_LAT_TIMER                 0x0180
 #define MEM_IO_CNTL_B1                         0x0184
+#define MC_IOPAD_CNTL                          0x0184
 #define MC_DEBUG                               0x0188
 #define MC_STATUS                              0x0150  
 #define MEM_IO_OE_CNTL                         0x018C  
+#define MC_CHIP_IO_OE_CNTL_AB                  0x018C
 #define MC_FB_LOCATION                         0x0148  
 #define HOST_PATH_CNTL                         0x0130  
 #define MEM_VGA_WP_SEL                         0x0038  
 #define TMDS_CRC                              0x02a0
 #define TMDS_TRANSMITTER_CNTL                 0x02a4
 #define MPP_TB_CONFIG                         0x01c0
+#define PAMAC0_DLY_CNTL                        0x0a94
+#define PAMAC1_DLY_CNTL                        0x0a98
+#define PAMAC2_DLY_CNTL                        0x0a9c
+#define FW_CNTL                                0x0118
+#define FCP_CNTL                               0x0910
+#define VGA_DDA_ON_OFF                         0x02ec
+#define TV_MASTER_CNTL                         0x0800
 
 //#define BASE_CODE                           0x0f0b
 #define BIOS_0_SCRATCH                        0x0010
 #define PPLL_DIV_3                                 0x0007
 #define VCLK_ECP_CNTL                              0x0008
 #define HTOTAL_CNTL                                0x0009
-#define X_MPLL_REF_FB_DIV                          0x000a
+#define M_SPLL_REF_FB_DIV                          0x000a
 #define AGP_PLL_CNTL                               0x000b
 #define SPLL_CNTL                                  0x000c
 #define SCLK_CNTL                                  0x000d
 #define CFG_VGA_RAM_EN                             0x00000100
 #define CFG_ATI_REV_ID_MASK                       (0xf << 16)
 #define CFG_ATI_REV_A11                                   (0 << 16)
+#define CFG_ATI_REV_A12                                   (1 << 16)
+#define CFG_ATI_REV_A13                                   (2 << 16)
 
 /* CRTC_EXT_CNTL bit constants */
 #define VGA_ATI_LINEAR                             0x00000008
 /* FP_GEN_CNTL bit constants */
 #define FP_FPON                                           (1 << 0)
 #define FP_TMDS_EN                                (1 << 2)
+#define FP_PANEL_FORMAT                            (1 << 3)
 #define FP_EN_TMDS                                (1 << 7)
 #define FP_DETECT_SENSE                                   (1 << 8)
+#define R200_FP_SOURCE_SEL_MASK                    (3 << 10)
+#define R200_FP_SOURCE_SEL_CRTC1                   (0 << 10)
+#define R200_FP_SOURCE_SEL_CRTC2                   (1 << 10)
+#define R200_FP_SOURCE_SEL_RMX                     (2 << 10)
+#define R200_FP_SOURCE_SEL_TRANS                   (3 << 10)
+#define FP_SEL_CRTC1                              (0 << 13)
 #define FP_SEL_CRTC2                              (1 << 13)
+#define FP_USE_VGA_HSYNC                           (1 << 14)
 #define FP_CRTC_DONT_SHADOW_HPAR                  (1 << 15)
 #define FP_CRTC_DONT_SHADOW_VPAR                  (1 << 16)
 #define FP_CRTC_DONT_SHADOW_HEND                  (1 << 17)
 #define DAC_CMP_OUTPUT                             (1 <<  7)
 
 /* DAC_CNTL2 bit constants */   
+#define DAC2_EXPAND_MODE                          (1 << 14)
 #define DAC2_CMP_EN                                (1 << 7)
 #define DAC2_PALETTE_ACCESS_CNTL                   (1 << 5)
 
 #define MEM_ARBITER_STATUS_BUSY                    0x00400000
 #define MEM_REQ_UNLOCK                             0x00000000
 #define MEM_REQ_LOCK                               0x00800000
+#define MEM_NUM_CHANNELS_MASK                     0x00000001
+#define MEM_USE_B_CH_ONLY                          0x00000002
+#define RV100_MEM_HALF_MODE                        0x00000008
+#define R300_MEM_NUM_CHANNELS_MASK                 0x00000003
+#define R300_MEM_USE_CD_CH_ONLY                    0x00000004
 
 
 /* RBBM_SOFT_RESET bit constants */
 
 #define MC_IND_INDEX                           0x01F8
 #define MC_IND_DATA                            0x01FC
-#define MEM_REFRESH_CNTL                       0x0178
 
-// CLK_PIN_CNTL
+/* PAD_CTLR_STRENGTH */
+#define PAD_MANUAL_OVERRIDE            0x80000000
+
+// pllCLK_PIN_CNTL
 #define CLK_PIN_CNTL__OSC_EN_MASK                          0x00000001L
 #define CLK_PIN_CNTL__OSC_EN                               0x00000001L
 #define CLK_PIN_CNTL__XTL_LOW_GAIN_MASK                    0x00000004L
 #define CLK_PIN_CNTL__XTALIN_ALWAYS_ONb                    0x00080000L
 #define CLK_PIN_CNTL__PWRSEQ_DELAY_MASK                    0xff000000L
 
-// CLK_PWRMGT_CNTL_M6
-#define        CLK_PWRMGT_CNTL_M6__MPLL_PWRMGT_OFF__SHIFT         0x00000000
-#define        CLK_PWRMGT_CNTL_M6__SPLL_PWRMGT_OFF__SHIFT         0x00000001
-#define        CLK_PWRMGT_CNTL_M6__PPLL_PWRMGT_OFF__SHIFT         0x00000002
-#define        CLK_PWRMGT_CNTL_M6__P2PLL_PWRMGT_OFF__SHIFT        0x00000003
-#define        CLK_PWRMGT_CNTL_M6__MCLK_TURNOFF__SHIFT            0x00000004
-#define        CLK_PWRMGT_CNTL_M6__SCLK_TURNOFF__SHIFT            0x00000005
-#define        CLK_PWRMGT_CNTL_M6__PCLK_TURNOFF__SHIFT            0x00000006
-#define        CLK_PWRMGT_CNTL_M6__P2CLK_TURNOFF__SHIFT           0x00000007
-#define        CLK_PWRMGT_CNTL_M6__MC_CH_MODE__SHIFT              0x00000008
-#define        CLK_PWRMGT_CNTL_M6__TEST_MODE__SHIFT               0x00000009
-#define        CLK_PWRMGT_CNTL_M6__GLOBAL_PMAN_EN__SHIFT          0x0000000a
-#define        CLK_PWRMGT_CNTL_M6__ENGINE_DYNCLK_MODE__SHIFT      0x0000000c
-#define        CLK_PWRMGT_CNTL_M6__ACTIVE_HILO_LAT__SHIFT         0x0000000d
-#define        CLK_PWRMGT_CNTL_M6__DISP_DYN_STOP_LAT__SHIFT       0x0000000f
-#define        CLK_PWRMGT_CNTL_M6__MC_BUSY__SHIFT                 0x00000010
-#define        CLK_PWRMGT_CNTL_M6__MC_INT_CNTL__SHIFT             0x00000011
-#define        CLK_PWRMGT_CNTL_M6__MC_SWITCH__SHIFT               0x00000012
-#define        CLK_PWRMGT_CNTL_M6__DLL_READY__SHIFT               0x00000013
-#define        CLK_PWRMGT_CNTL_M6__DISP_PM__SHIFT                 0x00000014
-#define        CLK_PWRMGT_CNTL_M6__DYN_STOP_MODE__SHIFT           0x00000015
-#define        CLK_PWRMGT_CNTL_M6__CG_NO1_DEBUG__SHIFT            0x00000018
-#define        CLK_PWRMGT_CNTL_M6__TVPLL_PWRMGT_OFF__SHIFT        0x0000001e
-#define        CLK_PWRMGT_CNTL_M6__TVCLK_TURNOFF__SHIFT           0x0000001f
-
-// P2PLL_CNTL
+// pllCLK_PWRMGT_CNTL
+#define        CLK_PWRMGT_CNTL__MPLL_PWRMGT_OFF__SHIFT         0x00000000
+#define        CLK_PWRMGT_CNTL__SPLL_PWRMGT_OFF__SHIFT         0x00000001
+#define        CLK_PWRMGT_CNTL__PPLL_PWRMGT_OFF__SHIFT         0x00000002
+#define        CLK_PWRMGT_CNTL__P2PLL_PWRMGT_OFF__SHIFT        0x00000003
+#define        CLK_PWRMGT_CNTL__MCLK_TURNOFF__SHIFT            0x00000004
+#define        CLK_PWRMGT_CNTL__SCLK_TURNOFF__SHIFT            0x00000005
+#define        CLK_PWRMGT_CNTL__PCLK_TURNOFF__SHIFT            0x00000006
+#define        CLK_PWRMGT_CNTL__P2CLK_TURNOFF__SHIFT           0x00000007
+#define        CLK_PWRMGT_CNTL__MC_CH_MODE__SHIFT              0x00000008
+#define        CLK_PWRMGT_CNTL__TEST_MODE__SHIFT               0x00000009
+#define        CLK_PWRMGT_CNTL__GLOBAL_PMAN_EN__SHIFT          0x0000000a
+#define        CLK_PWRMGT_CNTL__ENGINE_DYNCLK_MODE__SHIFT      0x0000000c
+#define        CLK_PWRMGT_CNTL__ACTIVE_HILO_LAT__SHIFT         0x0000000d
+#define        CLK_PWRMGT_CNTL__DISP_DYN_STOP_LAT__SHIFT       0x0000000f
+#define        CLK_PWRMGT_CNTL__MC_BUSY__SHIFT                 0x00000010
+#define        CLK_PWRMGT_CNTL__MC_INT_CNTL__SHIFT             0x00000011
+#define        CLK_PWRMGT_CNTL__MC_SWITCH__SHIFT               0x00000012
+#define        CLK_PWRMGT_CNTL__DLL_READY__SHIFT               0x00000013
+#define        CLK_PWRMGT_CNTL__DISP_PM__SHIFT                 0x00000014
+#define        CLK_PWRMGT_CNTL__DYN_STOP_MODE__SHIFT           0x00000015
+#define        CLK_PWRMGT_CNTL__CG_NO1_DEBUG__SHIFT            0x00000018
+#define        CLK_PWRMGT_CNTL__TVPLL_PWRMGT_OFF__SHIFT        0x0000001e
+#define        CLK_PWRMGT_CNTL__TVCLK_TURNOFF__SHIFT           0x0000001f
+
+// pllP2PLL_CNTL
 #define P2PLL_CNTL__P2PLL_RESET_MASK                       0x00000001L
 #define P2PLL_CNTL__P2PLL_RESET                            0x00000001L
 #define P2PLL_CNTL__P2PLL_SLEEP_MASK                       0x00000002L
 #define P2PLL_CNTL__P2PLL_DISABLE_AUTO_RESET_MASK          0x00080000L
 #define P2PLL_CNTL__P2PLL_DISABLE_AUTO_RESET               0x00080000L
 
-// PIXCLKS_CNTL
+// pllPIXCLKS_CNTL
 #define        PIXCLKS_CNTL__PIX2CLK_SRC_SEL__SHIFT               0x00000000
 #define        PIXCLKS_CNTL__PIX2CLK_INVERT__SHIFT                0x00000004
 #define        PIXCLKS_CNTL__PIX2CLK_SRC_INVERT__SHIFT            0x00000005
 #define        PIXCLKS_CNTL__PIXCLK_TMDS_ALWAYS_ONb__SHIFT        0x0000000f
 
 
-// PIXCLKS_CNTL
+// pllPIXCLKS_CNTL
 #define PIXCLKS_CNTL__PIX2CLK_SRC_SEL_MASK                 0x00000003L
-#define PIXCLKS_CNTL__PIX2CLK_INVERT_MASK                  0x00000010L
 #define PIXCLKS_CNTL__PIX2CLK_INVERT                       0x00000010L
-#define PIXCLKS_CNTL__PIX2CLK_SRC_INVERT_MASK              0x00000020L
 #define PIXCLKS_CNTL__PIX2CLK_SRC_INVERT                   0x00000020L
-#define PIXCLKS_CNTL__PIX2CLK_ALWAYS_ONb_MASK              0x00000040L
 #define PIXCLKS_CNTL__PIX2CLK_ALWAYS_ONb                   0x00000040L
-#define PIXCLKS_CNTL__PIX2CLK_DAC_ALWAYS_ONb_MASK          0x00000080L
 #define PIXCLKS_CNTL__PIX2CLK_DAC_ALWAYS_ONb               0x00000080L
-#define PIXCLKS_CNTL__PIXCLK_TV_SRC_SEL_MASK               0x00000100L
 #define PIXCLKS_CNTL__PIXCLK_TV_SRC_SEL                    0x00000100L
-#define PIXCLKS_CNTL__PIXCLK_BLEND_ALWAYS_ONb_MASK         0x00000800L
 #define PIXCLKS_CNTL__PIXCLK_BLEND_ALWAYS_ONb              0x00000800L
-#define PIXCLKS_CNTL__PIXCLK_GV_ALWAYS_ONb_MASK            0x00001000L
 #define PIXCLKS_CNTL__PIXCLK_GV_ALWAYS_ONb                 0x00001000L
-#define PIXCLKS_CNTL__PIXCLK_DIG_TMDS_ALWAYS_ONb_MASK      0x00002000L
 #define PIXCLKS_CNTL__PIXCLK_DIG_TMDS_ALWAYS_ONb           0x00002000L
-#define PIXCLKS_CNTL__PIXCLK_LVDS_ALWAYS_ONb_MASK          0x00004000L
 #define PIXCLKS_CNTL__PIXCLK_LVDS_ALWAYS_ONb               0x00004000L
-#define PIXCLKS_CNTL__PIXCLK_TMDS_ALWAYS_ONb_MASK          0x00008000L
 #define PIXCLKS_CNTL__PIXCLK_TMDS_ALWAYS_ONb               0x00008000L
+#define PIXCLKS_CNTL__DISP_TVOUT_PIXCLK_TV_ALWAYS_ONb      (1 << 9)
+#define PIXCLKS_CNTL__R300_DVOCLK_ALWAYS_ONb               (1 << 10)
+#define PIXCLKS_CNTL__R300_PIXCLK_DVO_ALWAYS_ONb           (1 << 13)
+#define PIXCLKS_CNTL__R300_PIXCLK_TRANS_ALWAYS_ONb         (1 << 16)
+#define PIXCLKS_CNTL__R300_PIXCLK_TVO_ALWAYS_ONb           (1 << 17)
+#define PIXCLKS_CNTL__R300_P2G2CLK_ALWAYS_ONb              (1 << 18)
+#define PIXCLKS_CNTL__R300_P2G2CLK_DAC_ALWAYS_ONb          (1 << 19)
+#define PIXCLKS_CNTL__R300_DISP_DAC_PIXCLK_DAC2_BLANK_OFF  (1 << 23)
 
 
-// P2PLL_DIV_0
+// pllP2PLL_DIV_0
 #define P2PLL_DIV_0__P2PLL_FB_DIV_MASK                     0x000007ffL
 #define P2PLL_DIV_0__P2PLL_ATOMIC_UPDATE_W_MASK            0x00008000L
 #define P2PLL_DIV_0__P2PLL_ATOMIC_UPDATE_W                 0x00008000L
 #define P2PLL_DIV_0__P2PLL_ATOMIC_UPDATE_R                 0x00008000L
 #define P2PLL_DIV_0__P2PLL_POST_DIV_MASK                   0x00070000L
 
-// SCLK_CNTL_M6
-#define SCLK_CNTL_M6__SCLK_SRC_SEL_MASK                    0x00000007L
-#define SCLK_CNTL_M6__CP_MAX_DYN_STOP_LAT_MASK             0x00000008L
-#define SCLK_CNTL_M6__CP_MAX_DYN_STOP_LAT                  0x00000008L
-#define SCLK_CNTL_M6__HDP_MAX_DYN_STOP_LAT_MASK            0x00000010L
-#define SCLK_CNTL_M6__HDP_MAX_DYN_STOP_LAT                 0x00000010L
-#define SCLK_CNTL_M6__TV_MAX_DYN_STOP_LAT_MASK             0x00000020L
-#define SCLK_CNTL_M6__TV_MAX_DYN_STOP_LAT                  0x00000020L
-#define SCLK_CNTL_M6__E2_MAX_DYN_STOP_LAT_MASK             0x00000040L
-#define SCLK_CNTL_M6__E2_MAX_DYN_STOP_LAT                  0x00000040L
-#define SCLK_CNTL_M6__SE_MAX_DYN_STOP_LAT_MASK             0x00000080L
-#define SCLK_CNTL_M6__SE_MAX_DYN_STOP_LAT                  0x00000080L
-#define SCLK_CNTL_M6__IDCT_MAX_DYN_STOP_LAT_MASK           0x00000100L
-#define SCLK_CNTL_M6__IDCT_MAX_DYN_STOP_LAT                0x00000100L
-#define SCLK_CNTL_M6__VIP_MAX_DYN_STOP_LAT_MASK            0x00000200L
-#define SCLK_CNTL_M6__VIP_MAX_DYN_STOP_LAT                 0x00000200L
-#define SCLK_CNTL_M6__RE_MAX_DYN_STOP_LAT_MASK             0x00000400L
-#define SCLK_CNTL_M6__RE_MAX_DYN_STOP_LAT                  0x00000400L
-#define SCLK_CNTL_M6__PB_MAX_DYN_STOP_LAT_MASK             0x00000800L
-#define SCLK_CNTL_M6__PB_MAX_DYN_STOP_LAT                  0x00000800L
-#define SCLK_CNTL_M6__TAM_MAX_DYN_STOP_LAT_MASK            0x00001000L
-#define SCLK_CNTL_M6__TAM_MAX_DYN_STOP_LAT                 0x00001000L
-#define SCLK_CNTL_M6__TDM_MAX_DYN_STOP_LAT_MASK            0x00002000L
-#define SCLK_CNTL_M6__TDM_MAX_DYN_STOP_LAT                 0x00002000L
-#define SCLK_CNTL_M6__RB_MAX_DYN_STOP_LAT_MASK             0x00004000L
-#define SCLK_CNTL_M6__RB_MAX_DYN_STOP_LAT                  0x00004000L
-#define SCLK_CNTL_M6__FORCE_DISP2_MASK                     0x00008000L
-#define SCLK_CNTL_M6__FORCE_DISP2                          0x00008000L
-#define SCLK_CNTL_M6__FORCE_CP_MASK                        0x00010000L
-#define SCLK_CNTL_M6__FORCE_CP                             0x00010000L
-#define SCLK_CNTL_M6__FORCE_HDP_MASK                       0x00020000L
-#define SCLK_CNTL_M6__FORCE_HDP                            0x00020000L
-#define SCLK_CNTL_M6__FORCE_DISP1_MASK                     0x00040000L
-#define SCLK_CNTL_M6__FORCE_DISP1                          0x00040000L
-#define SCLK_CNTL_M6__FORCE_TOP_MASK                       0x00080000L
-#define SCLK_CNTL_M6__FORCE_TOP                            0x00080000L
-#define SCLK_CNTL_M6__FORCE_E2_MASK                        0x00100000L
-#define SCLK_CNTL_M6__FORCE_E2                             0x00100000L
-#define SCLK_CNTL_M6__FORCE_SE_MASK                        0x00200000L
-#define SCLK_CNTL_M6__FORCE_SE                             0x00200000L
-#define SCLK_CNTL_M6__FORCE_IDCT_MASK                      0x00400000L
-#define SCLK_CNTL_M6__FORCE_IDCT                           0x00400000L
-#define SCLK_CNTL_M6__FORCE_VIP_MASK                       0x00800000L
-#define SCLK_CNTL_M6__FORCE_VIP                            0x00800000L
-#define SCLK_CNTL_M6__FORCE_RE_MASK                        0x01000000L
-#define SCLK_CNTL_M6__FORCE_RE                             0x01000000L
-#define SCLK_CNTL_M6__FORCE_PB_MASK                        0x02000000L
-#define SCLK_CNTL_M6__FORCE_PB                             0x02000000L
-#define SCLK_CNTL_M6__FORCE_TAM_MASK                       0x04000000L
-#define SCLK_CNTL_M6__FORCE_TAM                            0x04000000L
-#define SCLK_CNTL_M6__FORCE_TDM_MASK                       0x08000000L
-#define SCLK_CNTL_M6__FORCE_TDM                            0x08000000L
-#define SCLK_CNTL_M6__FORCE_RB_MASK                        0x10000000L
-#define SCLK_CNTL_M6__FORCE_RB                             0x10000000L
-#define SCLK_CNTL_M6__FORCE_TV_SCLK_MASK                   0x20000000L
-#define SCLK_CNTL_M6__FORCE_TV_SCLK                        0x20000000L
-#define SCLK_CNTL_M6__FORCE_SUBPIC_MASK                    0x40000000L
-#define SCLK_CNTL_M6__FORCE_SUBPIC                         0x40000000L
-#define SCLK_CNTL_M6__FORCE_OV0_MASK                       0x80000000L
-#define SCLK_CNTL_M6__FORCE_OV0                            0x80000000L
+// pllSCLK_CNTL
+#define SCLK_CNTL__SCLK_SRC_SEL_MASK                    0x00000007L
+#define SCLK_CNTL__CP_MAX_DYN_STOP_LAT                  0x00000008L
+#define SCLK_CNTL__HDP_MAX_DYN_STOP_LAT                 0x00000010L
+#define SCLK_CNTL__TV_MAX_DYN_STOP_LAT                  0x00000020L
+#define SCLK_CNTL__E2_MAX_DYN_STOP_LAT                  0x00000040L
+#define SCLK_CNTL__SE_MAX_DYN_STOP_LAT                  0x00000080L
+#define SCLK_CNTL__IDCT_MAX_DYN_STOP_LAT                0x00000100L
+#define SCLK_CNTL__VIP_MAX_DYN_STOP_LAT                 0x00000200L
+#define SCLK_CNTL__RE_MAX_DYN_STOP_LAT                  0x00000400L
+#define SCLK_CNTL__PB_MAX_DYN_STOP_LAT                  0x00000800L
+#define SCLK_CNTL__TAM_MAX_DYN_STOP_LAT                 0x00001000L
+#define SCLK_CNTL__TDM_MAX_DYN_STOP_LAT                 0x00002000L
+#define SCLK_CNTL__RB_MAX_DYN_STOP_LAT                  0x00004000L
+#define SCLK_CNTL__DYN_STOP_LAT_MASK                     0x00007ff8
+#define SCLK_CNTL__FORCE_DISP2                          0x00008000L
+#define SCLK_CNTL__FORCE_CP                             0x00010000L
+#define SCLK_CNTL__FORCE_HDP                            0x00020000L
+#define SCLK_CNTL__FORCE_DISP1                          0x00040000L
+#define SCLK_CNTL__FORCE_TOP                            0x00080000L
+#define SCLK_CNTL__FORCE_E2                             0x00100000L
+#define SCLK_CNTL__FORCE_SE                             0x00200000L
+#define SCLK_CNTL__FORCE_IDCT                           0x00400000L
+#define SCLK_CNTL__FORCE_VIP                            0x00800000L
+#define SCLK_CNTL__FORCE_RE                             0x01000000L
+#define SCLK_CNTL__FORCE_PB                             0x02000000L
+#define SCLK_CNTL__FORCE_TAM                            0x04000000L
+#define SCLK_CNTL__FORCE_TDM                            0x08000000L
+#define SCLK_CNTL__FORCE_RB                             0x10000000L
+#define SCLK_CNTL__FORCE_TV_SCLK                        0x20000000L
+#define SCLK_CNTL__FORCE_SUBPIC                         0x40000000L
+#define SCLK_CNTL__FORCE_OV0                            0x80000000L
+#define SCLK_CNTL__R300_FORCE_VAP                       (1<<21)
+#define SCLK_CNTL__R300_FORCE_SR                        (1<<25)
+#define SCLK_CNTL__R300_FORCE_PX                        (1<<26)
+#define SCLK_CNTL__R300_FORCE_TX                        (1<<27)
+#define SCLK_CNTL__R300_FORCE_US                        (1<<28)
+#define SCLK_CNTL__R300_FORCE_SU                        (1<<30)
+#define SCLK_CNTL__FORCEON_MASK                         0xffff8000L
+
+// pllSCLK_CNTL2
+#define SCLK_CNTL2__R300_TCL_MAX_DYN_STOP_LAT           (1<<10)
+#define SCLK_CNTL2__R300_GA_MAX_DYN_STOP_LAT            (1<<11)
+#define SCLK_CNTL2__R300_CBA_MAX_DYN_STOP_LAT           (1<<12)
+#define SCLK_CNTL2__R300_FORCE_TCL                      (1<<13)
+#define SCLK_CNTL2__R300_FORCE_CBA                      (1<<14)
+#define SCLK_CNTL2__R300_FORCE_GA                       (1<<15)
 
 // SCLK_MORE_CNTL
-#define SCLK_MORE_CNTL__DISPREGS_MAX_DYN_STOP_LAT_MASK     0x00000001L
 #define SCLK_MORE_CNTL__DISPREGS_MAX_DYN_STOP_LAT          0x00000001L
-#define SCLK_MORE_CNTL__MC_GUI_MAX_DYN_STOP_LAT_MASK       0x00000002L
 #define SCLK_MORE_CNTL__MC_GUI_MAX_DYN_STOP_LAT            0x00000002L
-#define SCLK_MORE_CNTL__MC_HOST_MAX_DYN_STOP_LAT_MASK      0x00000004L
 #define SCLK_MORE_CNTL__MC_HOST_MAX_DYN_STOP_LAT           0x00000004L
-#define SCLK_MORE_CNTL__FORCE_DISPREGS_MASK                0x00000100L
 #define SCLK_MORE_CNTL__FORCE_DISPREGS                     0x00000100L
-#define SCLK_MORE_CNTL__FORCE_MC_GUI_MASK                  0x00000200L
 #define SCLK_MORE_CNTL__FORCE_MC_GUI                       0x00000200L
-#define SCLK_MORE_CNTL__FORCE_MC_HOST_MASK                 0x00000400L
 #define SCLK_MORE_CNTL__FORCE_MC_HOST                      0x00000400L
-#define SCLK_MORE_CNTL__STOP_SCLK_EN_MASK                  0x00001000L
 #define SCLK_MORE_CNTL__STOP_SCLK_EN                       0x00001000L
-#define SCLK_MORE_CNTL__STOP_SCLK_A_MASK                   0x00002000L
 #define SCLK_MORE_CNTL__STOP_SCLK_A                        0x00002000L
-#define SCLK_MORE_CNTL__STOP_SCLK_B_MASK                   0x00004000L
 #define SCLK_MORE_CNTL__STOP_SCLK_B                        0x00004000L
-#define SCLK_MORE_CNTL__STOP_SCLK_C_MASK                   0x00008000L
 #define SCLK_MORE_CNTL__STOP_SCLK_C                        0x00008000L
-#define SCLK_MORE_CNTL__HALF_SPEED_SCLK_MASK               0x00010000L
 #define SCLK_MORE_CNTL__HALF_SPEED_SCLK                    0x00010000L
-#define SCLK_MORE_CNTL__IO_CG_VOLTAGE_DROP_MASK            0x00020000L
 #define SCLK_MORE_CNTL__IO_CG_VOLTAGE_DROP                 0x00020000L
-#define SCLK_MORE_CNTL__TVFB_SOFT_RESET_MASK               0x00040000L
 #define SCLK_MORE_CNTL__TVFB_SOFT_RESET                    0x00040000L
-#define SCLK_MORE_CNTL__VOLTAGE_DROP_SYNC_MASK             0x00080000L
 #define SCLK_MORE_CNTL__VOLTAGE_DROP_SYNC                  0x00080000L
-#define SCLK_MORE_CNTL__VOLTAGE_DELAY_SEL_MASK             0x00300000L
-#define SCLK_MORE_CNTL__IDLE_DELAY_HALF_SCLK_MASK          0x00400000L
 #define SCLK_MORE_CNTL__IDLE_DELAY_HALF_SCLK               0x00400000L
-#define SCLK_MORE_CNTL__AGP_BUSY_HALF_SCLK_MASK            0x00800000L
 #define SCLK_MORE_CNTL__AGP_BUSY_HALF_SCLK                 0x00800000L
 #define SCLK_MORE_CNTL__CG_SPARE_RD_C_MASK                 0xff000000L
-
-// MCLK_CNTL_M6
-#define MCLK_CNTL_M6__MCLKA_SRC_SEL_MASK                   0x00000007L
-#define MCLK_CNTL_M6__YCLKA_SRC_SEL_MASK                   0x00000070L
-#define MCLK_CNTL_M6__MCLKB_SRC_SEL_MASK                   0x00000700L
-#define MCLK_CNTL_M6__YCLKB_SRC_SEL_MASK                   0x00007000L
-#define MCLK_CNTL_M6__FORCE_MCLKA_MASK                     0x00010000L
-#define MCLK_CNTL_M6__FORCE_MCLKA                          0x00010000L
-#define MCLK_CNTL_M6__FORCE_MCLKB_MASK                     0x00020000L
-#define MCLK_CNTL_M6__FORCE_MCLKB                          0x00020000L
-#define MCLK_CNTL_M6__FORCE_YCLKA_MASK                     0x00040000L
-#define MCLK_CNTL_M6__FORCE_YCLKA                          0x00040000L
-#define MCLK_CNTL_M6__FORCE_YCLKB_MASK                     0x00080000L
-#define MCLK_CNTL_M6__FORCE_YCLKB                          0x00080000L
-#define MCLK_CNTL_M6__FORCE_MC_MASK                        0x00100000L
-#define MCLK_CNTL_M6__FORCE_MC                             0x00100000L
-#define MCLK_CNTL_M6__FORCE_AIC_MASK                       0x00200000L
-#define MCLK_CNTL_M6__FORCE_AIC                            0x00200000L
-#define MCLK_CNTL_M6__MRDCKA0_SOUTSEL_MASK                 0x03000000L
-#define MCLK_CNTL_M6__MRDCKA1_SOUTSEL_MASK                 0x0c000000L
-#define MCLK_CNTL_M6__MRDCKB0_SOUTSEL_MASK                 0x30000000L
-#define MCLK_CNTL_M6__MRDCKB1_SOUTSEL_MASK                 0xc0000000L
+#define SCLK_MORE_CNTL__FORCEON                            0x00000700L
+
+// MCLK_CNTL
+#define MCLK_CNTL__MCLKA_SRC_SEL_MASK                   0x00000007L
+#define MCLK_CNTL__YCLKA_SRC_SEL_MASK                   0x00000070L
+#define MCLK_CNTL__MCLKB_SRC_SEL_MASK                   0x00000700L
+#define MCLK_CNTL__YCLKB_SRC_SEL_MASK                   0x00007000L
+#define MCLK_CNTL__FORCE_MCLKA_MASK                     0x00010000L
+#define MCLK_CNTL__FORCE_MCLKA                          0x00010000L
+#define MCLK_CNTL__FORCE_MCLKB_MASK                     0x00020000L
+#define MCLK_CNTL__FORCE_MCLKB                          0x00020000L
+#define MCLK_CNTL__FORCE_YCLKA_MASK                     0x00040000L
+#define MCLK_CNTL__FORCE_YCLKA                          0x00040000L
+#define MCLK_CNTL__FORCE_YCLKB_MASK                     0x00080000L
+#define MCLK_CNTL__FORCE_YCLKB                          0x00080000L
+#define MCLK_CNTL__FORCE_MC_MASK                        0x00100000L
+#define MCLK_CNTL__FORCE_MC                             0x00100000L
+#define MCLK_CNTL__FORCE_AIC_MASK                       0x00200000L
+#define MCLK_CNTL__FORCE_AIC                            0x00200000L
+#define MCLK_CNTL__MRDCKA0_SOUTSEL_MASK                 0x03000000L
+#define MCLK_CNTL__MRDCKA1_SOUTSEL_MASK                 0x0c000000L
+#define MCLK_CNTL__MRDCKB0_SOUTSEL_MASK                 0x30000000L
+#define MCLK_CNTL__MRDCKB1_SOUTSEL_MASK                 0xc0000000L
+#define MCLK_CNTL__R300_DISABLE_MC_MCLKA                (1 << 21)
+#define MCLK_CNTL__R300_DISABLE_MC_MCLKB                (1 << 21)
 
 // MCLK_MISC
 #define MCLK_MISC__SCLK_SOURCED_FROM_MPLL_SEL_MASK         0x00000003L
 
 // VCLK_ECP_CNTL
 #define VCLK_ECP_CNTL__VCLK_SRC_SEL_MASK                   0x00000003L
-#define VCLK_ECP_CNTL__VCLK_INVERT_MASK                    0x00000010L
 #define VCLK_ECP_CNTL__VCLK_INVERT                         0x00000010L
-#define VCLK_ECP_CNTL__PIXCLK_SRC_INVERT_MASK              0x00000020L
 #define VCLK_ECP_CNTL__PIXCLK_SRC_INVERT                   0x00000020L
-#define VCLK_ECP_CNTL__PIXCLK_ALWAYS_ONb_MASK              0x00000040L
 #define VCLK_ECP_CNTL__PIXCLK_ALWAYS_ONb                   0x00000040L
-#define VCLK_ECP_CNTL__PIXCLK_DAC_ALWAYS_ONb_MASK          0x00000080L
 #define VCLK_ECP_CNTL__PIXCLK_DAC_ALWAYS_ONb               0x00000080L
 #define VCLK_ECP_CNTL__ECP_DIV_MASK                        0x00000300L
-#define VCLK_ECP_CNTL__ECP_FORCE_ON_MASK                   0x00040000L
 #define VCLK_ECP_CNTL__ECP_FORCE_ON                        0x00040000L
-#define VCLK_ECP_CNTL__SUBCLK_FORCE_ON_MASK                0x00080000L
 #define VCLK_ECP_CNTL__SUBCLK_FORCE_ON                     0x00080000L
+#define VCLK_ECP_CNTL__R300_DISP_DAC_PIXCLK_DAC_BLANK_OFF  (1<<23)
 
 // PLL_PWRMGT_CNTL
 #define PLL_PWRMGT_CNTL__MPLL_TURNOFF_MASK                 0x00000001L
 #define PLL_PWRMGT_CNTL__SU_SUSTAIN_DISABLE                0x00080000L
 #define PLL_PWRMGT_CNTL__TCL_BYPASS_DISABLE_MASK           0x00100000L
 #define PLL_PWRMGT_CNTL__TCL_BYPASS_DISABLE                0x00100000L
-#define PLL_PWRMGT_CNTL__TCL_CLOCK_ACTIVE_RD_MASK          0x00200000L
+#define PLL_PWRMGT_CNTL__TCL_CLOCK_CTIVE_RD_MASK          0x00200000L
 #define PLL_PWRMGT_CNTL__TCL_CLOCK_ACTIVE_RD               0x00200000L
 #define PLL_PWRMGT_CNTL__CG_NO2_DEBUG_MASK                 0xff000000L
 
-// CLK_PWRMGT_CNTL_M6
-#define CLK_PWRMGT_CNTL_M6__MPLL_PWRMGT_OFF_MASK           0x00000001L
-#define CLK_PWRMGT_CNTL_M6__MPLL_PWRMGT_OFF                0x00000001L
-#define CLK_PWRMGT_CNTL_M6__SPLL_PWRMGT_OFF_MASK           0x00000002L
-#define CLK_PWRMGT_CNTL_M6__SPLL_PWRMGT_OFF                0x00000002L
-#define CLK_PWRMGT_CNTL_M6__PPLL_PWRMGT_OFF_MASK           0x00000004L
-#define CLK_PWRMGT_CNTL_M6__PPLL_PWRMGT_OFF                0x00000004L
-#define CLK_PWRMGT_CNTL_M6__P2PLL_PWRMGT_OFF_MASK          0x00000008L
-#define CLK_PWRMGT_CNTL_M6__P2PLL_PWRMGT_OFF               0x00000008L
-#define CLK_PWRMGT_CNTL_M6__MCLK_TURNOFF_MASK              0x00000010L
-#define CLK_PWRMGT_CNTL_M6__MCLK_TURNOFF                   0x00000010L
-#define CLK_PWRMGT_CNTL_M6__SCLK_TURNOFF_MASK              0x00000020L
-#define CLK_PWRMGT_CNTL_M6__SCLK_TURNOFF                   0x00000020L
-#define CLK_PWRMGT_CNTL_M6__PCLK_TURNOFF_MASK              0x00000040L
-#define CLK_PWRMGT_CNTL_M6__PCLK_TURNOFF                   0x00000040L
-#define CLK_PWRMGT_CNTL_M6__P2CLK_TURNOFF_MASK             0x00000080L
-#define CLK_PWRMGT_CNTL_M6__P2CLK_TURNOFF                  0x00000080L
-#define CLK_PWRMGT_CNTL_M6__MC_CH_MODE_MASK                0x00000100L
-#define CLK_PWRMGT_CNTL_M6__MC_CH_MODE                     0x00000100L
-#define CLK_PWRMGT_CNTL_M6__TEST_MODE_MASK                 0x00000200L
-#define CLK_PWRMGT_CNTL_M6__TEST_MODE                      0x00000200L
-#define CLK_PWRMGT_CNTL_M6__GLOBAL_PMAN_EN_MASK            0x00000400L
-#define CLK_PWRMGT_CNTL_M6__GLOBAL_PMAN_EN                 0x00000400L
-#define CLK_PWRMGT_CNTL_M6__ENGINE_DYNCLK_MODE_MASK        0x00001000L
-#define CLK_PWRMGT_CNTL_M6__ENGINE_DYNCLK_MODE             0x00001000L
-#define CLK_PWRMGT_CNTL_M6__ACTIVE_HILO_LAT_MASK           0x00006000L
-#define CLK_PWRMGT_CNTL_M6__DISP_DYN_STOP_LAT_MASK         0x00008000L
-#define CLK_PWRMGT_CNTL_M6__DISP_DYN_STOP_LAT              0x00008000L
-#define CLK_PWRMGT_CNTL_M6__MC_BUSY_MASK                   0x00010000L
-#define CLK_PWRMGT_CNTL_M6__MC_BUSY                        0x00010000L
-#define CLK_PWRMGT_CNTL_M6__MC_INT_CNTL_MASK               0x00020000L
-#define CLK_PWRMGT_CNTL_M6__MC_INT_CNTL                    0x00020000L
-#define CLK_PWRMGT_CNTL_M6__MC_SWITCH_MASK                 0x00040000L
-#define CLK_PWRMGT_CNTL_M6__MC_SWITCH                      0x00040000L
-#define CLK_PWRMGT_CNTL_M6__DLL_READY_MASK                 0x00080000L
-#define CLK_PWRMGT_CNTL_M6__DLL_READY                      0x00080000L
-#define CLK_PWRMGT_CNTL_M6__DISP_PM_MASK                   0x00100000L
-#define CLK_PWRMGT_CNTL_M6__DISP_PM                        0x00100000L
-#define CLK_PWRMGT_CNTL_M6__DYN_STOP_MODE_MASK             0x00e00000L
-#define CLK_PWRMGT_CNTL_M6__CG_NO1_DEBUG_MASK              0x3f000000L
-#define CLK_PWRMGT_CNTL_M6__TVPLL_PWRMGT_OFF_MASK          0x40000000L
-#define CLK_PWRMGT_CNTL_M6__TVPLL_PWRMGT_OFF               0x40000000L
-#define CLK_PWRMGT_CNTL_M6__TVCLK_TURNOFF_MASK             0x80000000L
-#define CLK_PWRMGT_CNTL_M6__TVCLK_TURNOFF                  0x80000000L
+// CLK_PWRMGT_CNTL
+#define CLK_PWRMGT_CNTL__MPLL_PWRMGT_OFF_MASK           0x00000001L
+#define CLK_PWRMGT_CNTL__MPLL_PWRMGT_OFF                0x00000001L
+#define CLK_PWRMGT_CNTL__SPLL_PWRMGT_OFF_MASK           0x00000002L
+#define CLK_PWRMGT_CNTL__SPLL_PWRMGT_OFF                0x00000002L
+#define CLK_PWRMGT_CNTL__PPLL_PWRMGT_OFF_MASK           0x00000004L
+#define CLK_PWRMGT_CNTL__PPLL_PWRMGT_OFF                0x00000004L
+#define CLK_PWRMGT_CNTL__P2PLL_PWRMGT_OFF_MASK          0x00000008L
+#define CLK_PWRMGT_CNTL__P2PLL_PWRMGT_OFF               0x00000008L
+#define CLK_PWRMGT_CNTL__MCLK_TURNOFF_MASK              0x00000010L
+#define CLK_PWRMGT_CNTL__MCLK_TURNOFF                   0x00000010L
+#define CLK_PWRMGT_CNTL__SCLK_TURNOFF_MASK              0x00000020L
+#define CLK_PWRMGT_CNTL__SCLK_TURNOFF                   0x00000020L
+#define CLK_PWRMGT_CNTL__PCLK_TURNOFF_MASK              0x00000040L
+#define CLK_PWRMGT_CNTL__PCLK_TURNOFF                   0x00000040L
+#define CLK_PWRMGT_CNTL__P2CLK_TURNOFF_MASK             0x00000080L
+#define CLK_PWRMGT_CNTL__P2CLK_TURNOFF                  0x00000080L
+#define CLK_PWRMGT_CNTL__MC_CH_MODE_MASK                0x00000100L
+#define CLK_PWRMGT_CNTL__MC_CH_MODE                     0x00000100L
+#define CLK_PWRMGT_CNTL__TEST_MODE_MASK                 0x00000200L
+#define CLK_PWRMGT_CNTL__TEST_MODE                      0x00000200L
+#define CLK_PWRMGT_CNTL__GLOBAL_PMAN_EN_MASK            0x00000400L
+#define CLK_PWRMGT_CNTL__GLOBAL_PMAN_EN                 0x00000400L
+#define CLK_PWRMGT_CNTL__ENGINE_DYNCLK_MODE_MASK        0x00001000L
+#define CLK_PWRMGT_CNTL__ENGINE_DYNCLK_MODE             0x00001000L
+#define CLK_PWRMGT_CNTL__ACTIVE_HILO_LAT_MASK           0x00006000L
+#define CLK_PWRMGT_CNTL__DISP_DYN_STOP_LAT_MASK         0x00008000L
+#define CLK_PWRMGT_CNTL__DISP_DYN_STOP_LAT              0x00008000L
+#define CLK_PWRMGT_CNTL__MC_BUSY_MASK                   0x00010000L
+#define CLK_PWRMGT_CNTL__MC_BUSY                        0x00010000L
+#define CLK_PWRMGT_CNTL__MC_INT_CNTL_MASK               0x00020000L
+#define CLK_PWRMGT_CNTL__MC_INT_CNTL                    0x00020000L
+#define CLK_PWRMGT_CNTL__MC_SWITCH_MASK                 0x00040000L
+#define CLK_PWRMGT_CNTL__MC_SWITCH                      0x00040000L
+#define CLK_PWRMGT_CNTL__DLL_READY_MASK                 0x00080000L
+#define CLK_PWRMGT_CNTL__DLL_READY                      0x00080000L
+#define CLK_PWRMGT_CNTL__DISP_PM_MASK                   0x00100000L
+#define CLK_PWRMGT_CNTL__DISP_PM                        0x00100000L
+#define CLK_PWRMGT_CNTL__DYN_STOP_MODE_MASK             0x00e00000L
+#define CLK_PWRMGT_CNTL__CG_NO1_DEBUG_MASK              0x3f000000L
+#define CLK_PWRMGT_CNTL__TVPLL_PWRMGT_OFF_MASK          0x40000000L
+#define CLK_PWRMGT_CNTL__TVPLL_PWRMGT_OFF               0x40000000L
+#define CLK_PWRMGT_CNTL__TVCLK_TURNOFF_MASK             0x80000000L
+#define CLK_PWRMGT_CNTL__TVCLK_TURNOFF                  0x80000000L
 
 // BUS_CNTL1
 #define BUS_CNTL1__PMI_IO_DISABLE_MASK                     0x00000001L
 #define MDLL_RDCKB__MRDCKB1_BP_SEL_MASK                    0x80000000L
 #define MDLL_RDCKB__MRDCKB1_BP_SEL                         0x80000000L
 
-#define pllVCLK_ECP_CNTL                            0x0008
-#define pllDISP_TEST_MACRO_RW_WRITE                 0x001A
-#define pllDISP_TEST_MACRO_RW_READ                  0x001B
-#define pllDISP_TEST_MACRO_RW_DATA                  0x001C
-#define pllDISP_TEST_MACRO_RW_CNTL                  0x001D
-#define pllPIXCLKS_CNTL                             0x002D
+#define MDLL_R300_RDCK__MRDCKA_SLEEP                       0x00000001L
+#define MDLL_R300_RDCK__MRDCKA_RESET                       0x00000002L
+#define MDLL_R300_RDCK__MRDCKB_SLEEP                       0x00000004L
+#define MDLL_R300_RDCK__MRDCKB_RESET                       0x00000008L
+#define MDLL_R300_RDCK__MRDCKC_SLEEP                       0x00000010L
+#define MDLL_R300_RDCK__MRDCKC_RESET                       0x00000020L
+#define MDLL_R300_RDCK__MRDCKD_SLEEP                       0x00000040L
+#define MDLL_R300_RDCK__MRDCKD_RESET                       0x00000080L
+
+#define pllCLK_PIN_CNTL                             0x0001
+#define pllPPLL_CNTL                                0x0002
+#define pllPPLL_REF_DIV                             0x0003
 #define pllPPLL_DIV_0                               0x0004
 #define pllPPLL_DIV_1                               0x0005
 #define pllPPLL_DIV_2                               0x0006
 #define pllPPLL_DIV_3                               0x0007
+#define pllVCLK_ECP_CNTL                            0x0008
 #define pllHTOTAL_CNTL                              0x0009
-#define pllPLL_TEST_CNTL_M6                         0x0013
-#define pllP2PLL_DIV_0                              0x002C
-#define pllHTOTAL2_CNTL                             0x002E
-#define pllCLK_PIN_CNTL                             0x0001
-#define pllPPLL_CNTL                                0x0002
-#define pllPPLL_REF_DIV                             0x0003
-#define pllSPLL_CNTL                                0x000C
-#define pllSPLL_AUX_CNTL                            0x0024
-#define pllSCLK_CNTL_M6                             0x000D
+#define pllM_SPLL_REF_FB_DIV                        0x000A
 #define pllAGP_PLL_CNTL                             0x000B
+#define pllSPLL_CNTL                                0x000C
+#define pllSCLK_CNTL                                0x000D
+#define pllMPLL_CNTL                                0x000E
+#define pllMDLL_CKO                                 0x000F
+#define pllMDLL_RDCKA                               0x0010
+#define pllMDLL_RDCKB                               0x0011
+#define pllMCLK_CNTL                                0x0012
+#define pllPLL_TEST_CNTL                            0x0013
+#define pllCLK_PWRMGT_CNTL                          0x0014
+#define pllPLL_PWRMGT_CNTL                          0x0015
+#define pllCG_TEST_MACRO_RW_WRITE                   0x0016
+#define pllCG_TEST_MACRO_RW_READ                    0x0017
+#define pllCG_TEST_MACRO_RW_DATA                    0x0018
+#define pllCG_TEST_MACRO_RW_CNTL                    0x0019
+#define pllDISP_TEST_MACRO_RW_WRITE                 0x001A
+#define pllDISP_TEST_MACRO_RW_READ                  0x001B
+#define pllDISP_TEST_MACRO_RW_DATA                  0x001C
+#define pllDISP_TEST_MACRO_RW_CNTL                  0x001D
+#define pllSCLK_CNTL2                               0x001E
+#define pllMCLK_MISC                                0x001F
 #define pllTV_PLL_FINE_CNTL                         0x0020
 #define pllTV_PLL_CNTL                              0x0021
 #define pllTV_PLL_CNTL1                             0x0022
 #define pllTV_DTO_INCREMENTS                        0x0023
+#define pllSPLL_AUX_CNTL                            0x0024
+#define pllMPLL_AUX_CNTL                            0x0025
 #define pllP2PLL_CNTL                               0x002A
 #define pllP2PLL_REF_DIV                            0x002B
+#define pllP2PLL_DIV_0                              0x002C
+#define pllPIXCLKS_CNTL                             0x002D
+#define pllHTOTAL2_CNTL                             0x002E
 #define pllSSPLL_CNTL                               0x0030
 #define pllSSPLL_REF_DIV                            0x0031
 #define pllSSPLL_DIV_0                              0x0032
 #define pllSS_INT_CNTL                              0x0033
 #define pllSS_TST_CNTL                              0x0034
 #define pllSCLK_MORE_CNTL                           0x0035
-#define pllCLK_PWRMGT_CNTL_M6                       0x0014
-#define pllPLL_PWRMGT_CNTL                          0x0015
-#define pllM_SPLL_REF_FB_DIV                        0x000A
-#define pllMPLL_CNTL                                0x000E
-#define pllMPLL_AUX_CNTL                            0x0025
-#define pllMDLL_CKO                                 0x000F
-#define pllMDLL_RDCKA                               0x0010
-#define pllMDLL_RDCKB                               0x0011
-#define pllMCLK_CNTL_M6                             0x0012
-#define pllMCLK_MISC                                0x001F
-#define pllCG_TEST_MACRO_RW_WRITE                   0x0016
-#define pllCG_TEST_MACRO_RW_READ                    0x0017
-#define pllCG_TEST_MACRO_RW_DATA                    0x0018
-#define pllCG_TEST_MACRO_RW_CNTL                    0x0019
 
 #define ixMC_PERF_CNTL                             0x0000
 #define ixMC_PERF_SEL                              0x0001
 #define ixMC_BIST_CTRL                             0x0012
 #define ixREG_COLLAR_WRITE                         0x0013
 #define ixREG_COLLAR_READ                          0x0014
-
+#define ixR300_MC_IMP_CNTL                         0x0018
+#define ixR300_MC_CHP_IO_CNTL_A0                   0x0019
+#define ixR300_MC_CHP_IO_CNTL_A1                   0x001a
+#define ixR300_MC_CHP_IO_CNTL_B0                   0x001b
+#define ixR300_MC_CHP_IO_CNTL_B1                   0x001c
+#define ixR300_MC_CHP_IO_CNTL_C0                   0x001d
+#define ixR300_MC_CHP_IO_CNTL_C1                   0x001e
+#define ixR300_MC_CHP_IO_CNTL_D0                   0x001f
+#define ixR300_MC_CHP_IO_CNTL_D1                   0x0020
+#define ixR300_MC_IMP_CNTL_0                       0x0021
+#define ixR300_MC_ELPIDA_CNTL                      0x0022
+#define ixR300_MC_CHP_IO_OE_CNTL_CD                0x0023
+#define ixR300_MC_READ_CNTL_CD                     0x0024
+#define ixR300_MC_MC_INIT_WR_LAT_TIMER             0x0025
+#define ixR300_MC_DEBUG_CNTL                       0x0026
+#define ixR300_MC_BIST_CNTL_0                      0x0028
+#define ixR300_MC_BIST_CNTL_1                      0x0029
+#define ixR300_MC_BIST_CNTL_2                      0x002a
+#define ixR300_MC_BIST_CNTL_3                      0x002b
+#define ixR300_MC_BIST_CNTL_4                      0x002c
+#define ixR300_MC_BIST_CNTL_5                      0x002d
+#define ixR300_MC_IMP_STATUS                       0x002e
+#define ixR300_MC_DLL_CNTL                         0x002f
 #define NB_TOM                                     0x15C