diff drivers/radeon/radeonfb.c @ 2132:94617874ed1c

Imported some XFree86-CVS stuff
author nick
date Mon, 08 Oct 2001 08:22:32 +0000
parents db1880f741d4
children 96d1926373a1
line wrap: on
line diff
--- a/drivers/radeon/radeonfb.c	Sun Oct 07 23:19:34 2001 +0000
+++ b/drivers/radeon/radeonfb.c	Mon Oct 08 08:22:32 2001 +0000
@@ -88,7 +88,7 @@
 #if DEBUG
 #define RTRACE		printk
 #else
-#define RTRACE		if(0) printk
+#define RTRACE(...)	((void)0)
 #endif
 
 
@@ -158,21 +158,6 @@
 } reg_val;
 
 
-/* these common regs are cleared before mode setting so they do not
- * interfere with anything
- */
-reg_val common_regs[] = {
-	{ OVR_CLR, 0 },	
-	{ OVR_WID_LEFT_RIGHT, 0 },
-	{ OVR_WID_TOP_BOTTOM, 0 },
-	{ OV0_SCALE_CNTL, 0 },
-	{ SUBPIC_CNTL, 0 },
-	{ VIPH_CONTROL, 0 },
-	{ I2C_CNTL_1, 0 },
-	{ GEN_INT_CNTL, 0 },
-	{ CAP0_TRIG_CNTL, 0 },
-};
-
 #define COMMON_REGS_SIZE = (sizeof(common_regs)/sizeof(common_regs[0]))
 
 typedef struct {
@@ -224,25 +209,94 @@
 
 
 struct radeon_regs {
+			/* Common registers */
+	u32 ovr_clr;
+	u32 ovr_wid_left_right;
+	u32 ovr_wid_top_bottom;
+	u32 ov0_scale_cntl;
+	u32 mpp_tb_config;
+	u32 mpp_gp_config;
+	u32 subpic_cntl;
+	u32 viph_control;
+	u32 i2c_cntl_1;
+	u32 gen_int_cntl;
+	u32 cap0_trig_cntl;
+	u32 cap1_trig_cntl;
+	u32 bus_cntl;
+			/* Other registers to save for VT switches */
+	u32 dp_datatype;
+	u32 rbbm_soft_reset;
+	u32 clock_cntl_index;
+	u32 amcgpio_en_reg;
+	u32 amcgpio_mask;
+			/* CRTC registers */
+	u32 crtc_gen_cntl;
+	u32 crtc_ext_cntl;
+	u32 dac_cntl;
 	u32 crtc_h_total_disp;
 	u32 crtc_h_sync_strt_wid;
 	u32 crtc_v_total_disp;
 	u32 crtc_v_sync_strt_wid;
+	u32 crtc_offset;
+	u32 crtc_offset_cntl;
 	u32 crtc_pitch;
+			/* CRTC2 registers */
+	u32 crtc2_gen_cntl;
+	u32 dac2_cntl;
+	u32 disp_output_cntl;
+	u32 crtc2_h_total_disp;
+	u32 crtc2_h_sync_strt_wid;
+	u32 crtc2_v_total_disp;
+	u32 crtc2_v_sync_strt_wid;
+	u32 crtc2_offset;
+	u32 crtc2_offset_cntl;
+	u32 crtc2_pitch;
+			/* Flat panel registers */
+	u32 fp_crtc_h_total_disp;
+	u32 fp_crtc_v_total_disp;
+	u32 fp_gen_cntl;
+	u32 fp_h_sync_strt_wid;
+	u32 fp_horz_stretch;
+	u32 fp_panel_cntl;
+	u32 fp_v_sync_strt_wid;
+	u32 fp_vert_stretch;
+	u32 lvds_gen_cntl;
+	u32 lvds_pll_cntl;
+	u32 tmds_crc;
+			/* DDA registers */
+	u32 dda_config;
+	u32 dda_on_off;
+
+			/* Computed values for PLL */
+	u32 dot_clock_freq;
+	u32 pll_output_freq;
+	int feedback_div;
+	int post_div;
+			/* PLL registers */
+	u32 ppll_ref_div;
+	u32 ppll_div_3;
+	u32 htotal_cntl;
+			/* Computed values for PLL2 */
+	u32 dot_clock_freq_2;
+	u32 pll_output_freq_2;
+	int feedback_div_2;
+	int post_div_2;
+			/* PLL2 registers */
+	u32 p2pll_ref_div;
+	u32 p2pll_div_0;
+	u32 htotal_cntl2;
+			/* Pallet */
+	int palette_valid;
+	u32 palette[256];
+	u32 palette2[256];
+
 	u32 flags;
 	u32 pix_clock;
 	int xres, yres;
 	int bpp;
-	u32 crtc_gen_cntl;
-	u32 crtc_ext_cntl;
 #if defined(__BIG_ENDIAN)
 	u32 surface_cntl;
 #endif
-	u32 dac_cntl;
-	u32 dda_config;
-	u32 dda_on_off;
-	u32 ppll_div_3;
-	u32 ppll_ref_div;
 };
 
 
@@ -260,8 +314,19 @@
 	int dviDispType;
 	int hasTVout;
 	int isM7;
+	int isM6;
 	int isR200;
 	int theatre_num;
+				/* Computed values for FPs */
+	int PanelXRes;
+	int PanelYRes;
+	int HOverPlus;
+	int HSyncWidth;
+	int HBlank;
+	int VOverPlus;
+	int VSyncWidth;
+	int VBlank;
+	int PanelPwrDly;
 
 	u32 mmio_base_phys;
 	u32 fb_base_phys;
@@ -269,6 +334,9 @@
 	u32 mmio_base;
 	u32 fb_base;
 
+	u32 MemCntl;
+	u32 BusCntl;
+
 	struct pci_dev *pdev;
 
 	struct display disp;
@@ -290,8 +358,6 @@
 
 	struct ram_info ram;
 
-	u32 hack_crtc_ext_cntl;
-	u32 hack_crtc_v_sync_strt_wid;
 #ifdef CONFIG_MTRR
 	struct { int vram; int vram_valid; } mtrr;
 #endif
@@ -310,6 +376,11 @@
 #endif  
 };
 
+#define SINGLE_MONITOR(rinfo)  (rinfo->crtDispType == MT_NONE || rinfo->dviDispType == MT_NONE)
+/*#define DUAL_MONITOR(rinfo)    (rinfo->crtDispType != MT_NONE && rinfo->dviDispType != MT_NONE)*/
+/* Disable DUAL monitor support for now */
+#define DUAL_MONITOR(rinfo)    (0)
+#define PRIMARY_MONITOR(rinfo) (rinfo->dviDispType != MT_NONE && rinfo->dviDispType != MT_STV && rinfo->dviDispType != MT_CTV ? rinfo->dviDispType : rinfo->crtDispType)
 
 static struct fb_var_screeninfo radeonfb_default_var = {
         640, 480, 640, 480, 0, 0, 8, 0,
@@ -355,6 +426,61 @@
 
 #define INPLL(addr)		_INPLL(rinfo, addr)
 
+static __inline__ u8 radeon_get_post_div_bitval(int post_div)
+{
+        switch (post_div) {
+                case 1:
+                        return 0x00;
+                case 2: 
+                        return 0x01;
+                case 3: 
+                        return 0x04;
+                case 4:
+                        return 0x02;
+                case 6:
+                        return 0x06;
+                case 8:
+                        return 0x03;
+                case 12:
+                        return 0x07;
+                default:
+                        return 0x02;
+        }
+}
+
+
+
+static __inline__ int round_div(int num, int den)
+{
+        return (num + (den / 2)) / den;
+}
+
+
+
+static __inline__ int min_bits_req(int val)
+{
+        int bits_req = 0;
+                
+        if (val == 0)
+                bits_req = 1;
+                        
+        while (val) {
+                val >>= 1;
+                bits_req++;
+        }       
+
+        return (bits_req);
+}
+
+
+static __inline__ int _max(int val1, int val2)
+{
+        if (val1 >= val2)
+                return val1;
+        else
+                return val2;
+}                       
+
 
 /*
  * 2D engine routines
@@ -478,64 +604,6 @@
 
 #define radeon_engine_reset()		_radeon_engine_reset(rinfo)
 
-
-static __inline__ u8 radeon_get_post_div_bitval(int post_div)
-{
-        switch (post_div) {
-                case 1:
-                        return 0x00;
-                case 2: 
-                        return 0x01;
-                case 3: 
-                        return 0x04;
-                case 4:
-                        return 0x02;
-                case 6:
-                        return 0x06;
-                case 8:
-                        return 0x03;
-                case 12:
-                        return 0x07;
-                default:
-                        return 0x02;
-        }
-}
-
-
-
-static __inline__ int round_div(int num, int den)
-{
-        return (num + (den / 2)) / den;
-}
-
-
-
-static __inline__ int min_bits_req(int val)
-{
-        int bits_req = 0;
-                
-        if (val == 0)
-                bits_req = 1;
-                        
-        while (val) {
-                val >>= 1;
-                bits_req++;
-        }       
-
-        return (bits_req);
-}
-
-
-static __inline__ int _max(int val1, int val2)
-{
-        if (val1 >= val2)
-                return val1;
-        else
-                return val2;
-}                       
-
-
-
 /*
  * globals
  */
@@ -583,13 +651,17 @@
 static int radeon_setcolreg (unsigned regno, unsigned red, unsigned green,
                              unsigned blue, unsigned transp, struct fb_info *info);
 static void radeon_set_dispsw (struct radeonfb_info *rinfo, struct display *disp);
+static void radeon_save_mode (struct radeonfb_info *rinfo,
+                               struct radeon_regs *save);
 static void radeon_save_state (struct radeonfb_info *rinfo,
                                struct radeon_regs *save);
 static void radeon_engine_init (struct radeonfb_info *rinfo);
-static void radeon_load_video_mode (struct radeonfb_info *rinfo,
+static int  radeon_load_video_mode (struct radeonfb_info *rinfo,
                                     struct fb_var_screeninfo *mode);
 static void radeon_write_mode (struct radeonfb_info *rinfo,
                                struct radeon_regs *mode);
+static void radeon_write_state (struct radeonfb_info *rinfo,
+                               struct radeon_regs *mode);
 static int __devinit radeon_set_fbinfo (struct radeonfb_info *rinfo);
 static int __devinit radeon_init_disp (struct radeonfb_info *rinfo);
 static int radeon_init_disp_var (struct radeonfb_info *rinfo);
@@ -957,10 +1029,12 @@
 			break;
 		case PCI_DEVICE_ID_RADEON_LY:
 			rinfo->hasCRTC2 = 1;
+			rinfo->isM6 = 1;
 			strcpy(rinfo->name, "Radeon M6 LY ");
 			break;
 		case PCI_DEVICE_ID_RADEON_LZ:
 			rinfo->hasCRTC2 = 1;
+			rinfo->isM6 = 1;
 			strcpy(rinfo->name, "Radeon M6 LZ ");
 			break;
 		case PCI_DEVICE_ID_RADEON_LW:
@@ -996,8 +1070,8 @@
 	rinfo->video_ram = tmp & CONFIG_MEMSIZE_MASK;
 
 	/* ram type */
-	tmp = INREG(MEM_SDRAM_MODE_REG);
-	switch ((MEM_CFG_TYPE & tmp) >> 30) {
+	rinfo->MemCntl = INREG(MEM_SDRAM_MODE_REG);
+	switch ((MEM_CFG_TYPE & rinfo->MemCntl) >> 30) {
 		case 0:
 			/* SDR SGRAM (2:1) */
 			strcpy(rinfo->ram_type, "SDR SGRAM");
@@ -1040,6 +1114,8 @@
 
 			break;
 	}
+	/* Bus type */
+	rinfo->BusCntl = INREG(BUS_CNTL);
 
 	bios_seg = radeon_find_rom(rinfo);
 	radeon_get_pllinfo(rinfo, bios_seg);
@@ -1202,7 +1278,7 @@
                 return;
  
 	/* restore original state */
-        radeon_write_mode (rinfo, &rinfo->init_state);
+        radeon_write_state (rinfo, &rinfo->init_state);
  
         unregister_framebuffer ((struct fb_info *) rinfo);
 #ifdef CONFIG_MTRR
@@ -1327,6 +1403,665 @@
 	}
 }
 
+static void radeon_init_common_regs(struct radeonfb_info *rinfo,
+                               struct radeon_regs *save)
+{
+RTRACE("radeonfb: radeon_init_common_regs is called\n"); 
+	save->ovr_clr		= 0;
+	save->ovr_wid_left_right= 0;
+	save->ovr_wid_top_bottom= 0;
+	save->ov0_scale_cntl	= 0;
+	save->mpp_tb_config	= 0;
+	save->mpp_gp_config	= 0;
+	save->subpic_cntl	= 0;
+	save->viph_control	= 0;
+	save->i2c_cntl_1	= 0;
+	save->rbbm_soft_reset	= 0;
+	save->cap0_trig_cntl	= 0;
+	save->cap1_trig_cntl	= 0;
+	save->bus_cntl		= rinfo->BusCntl;
+	/*
+	* If bursts are enabled, turn on discards
+	* Radeon doesn't have write bursts
+	
+	* XXX: Disabled by NK since on Radeon VE it causes
+	*      mode corruption.
+	    if (save->bus_cntl & (BUS_READ_BURST))
+	    save->bus_cntl |= BUS_RD_DISCARD_EN;
+	*/
+}
+#if 0
+static int radeon_init_crtc_regs(struct radeonfb_info *rinfo,
+                                 struct radeon_regs *save,
+                                 struct fb_var_screeninfo *mode)
+{
+    int    format;
+    int    hsync_start;
+    int    hsync_wid;
+    int    hsync_fudge;
+    int    vsync_wid;
+    int    bytpp;
+    int    hsync_fudge_default[] = { 0x00, 0x12, 0x09, 0x09, 0x06, 0x05 };
+    int    hsync_fudge_fp[]      = { 0x02, 0x02, 0x00, 0x00, 0x05, 0x05 };
+    int    prim_mon;
+    int    hTotal, vTotal, hSyncStart, hSyncEnd;
+    int    vSyncStart, vSyncEnd;
+RTRACE("radeonfb: radeon_init_crtc_regs is called\n"); 
+
+    switch (mode->bits_per_pixel) {
+    case 8:  format = 2; bytpp = 1; break;
+    case 16: format = 4; bytpp = 2; break;      /*  565 */
+    case 24: format = 5; bytpp = 3; break;      /*  RGB */
+    case 32: format = 6; bytpp = 4; break;      /* xRGB */
+    default:
+	printk("radeonfb: Unsupported pixel depth (%d)\n", mode->bits_per_pixel);
+	return 0;
+    }
+    prim_mon = PRIMARY_MONITOR(rinfo);
+    if ((prim_mon == MT_DFP) || (prim_mon == MT_LCD))
+	hsync_fudge = hsync_fudge_fp[format-1];
+    else
+    hsync_fudge = hsync_fudge_default[format-1];
+
+    save->crtc_gen_cntl = (CRTC_EXT_DISP_EN
+			  | CRTC_EN
+			  | (format << 8)
+			 /* | CRTC_DBL_SCAN_EN*/);
+
+    if((prim_mon == MT_DFP) || (prim_mon == MT_LCD))
+    {
+        save->crtc_ext_cntl = VGA_ATI_LINEAR |
+        			  XCRT_CNT_EN;
+        save->crtc_gen_cntl &= ~(CRTC_DBL_SCAN_EN |
+                                  CRTC_INTERLACE_EN);
+    }
+    else
+    save->crtc_ext_cntl = VGA_ATI_LINEAR |
+			  XCRT_CNT_EN |
+			  CRTC_CRT_ON;
+
+    save->dac_cntl      = (DAC_MASK_ALL
+			   | DAC_VGA_ADR_EN
+			   | DAC_8BIT_EN);
+
+    rinfo->xres = mode->xres;
+    rinfo->yres = mode->yres;
+    rinfo->pixclock = mode->pixclock;
+
+    hSyncStart = mode->xres + mode->right_margin;
+    hSyncEnd = hSyncStart + mode->hsync_len;
+    hTotal = hSyncEnd + mode->left_margin;
+
+    vSyncStart = mode->yres + mode->lower_margin;
+    vSyncEnd = vSyncStart + mode->vsync_len;
+    vTotal = vSyncEnd + mode->upper_margin;
+
+    if(((prim_mon == MT_DFP) || (prim_mon == MT_LCD)))
+    {
+        if(rinfo->PanelXRes < mode->xres)
+            rinfo->xres = mode->xres = rinfo->PanelXRes;
+        if(rinfo->PanelYRes < mode->yres)
+            rinfo->yres = mode->yres = rinfo->PanelYRes;
+        hTotal = mode->xres + rinfo->HBlank + mode->left_margin;
+        hSyncStart = mode->xres + rinfo->HOverPlus + mode->right_margin;
+        hSyncEnd = hSyncStart + rinfo->HSyncWidth + mode->hsync_len;
+        vTotal = mode->yres + rinfo->VBlank + mode->upper_margin;
+        vSyncStart = mode->yres + rinfo->VOverPlus + mode->lower_margin;
+        vSyncEnd = vSyncStart + rinfo->VSyncWidth + mode->vsync_len;
+    }
+
+    save->crtc_h_total_disp = ((((hTotal / 8) - 1) & 0x3ff)
+	   | ((((mode->xres / 8) - 1) & 0x1ff) << 16));
+
+    hsync_wid = (hSyncEnd - hSyncStart) / 8;
+    if (!hsync_wid)       hsync_wid = 1;
+    if (hsync_wid > 0x3f) hsync_wid = 0x3f;
+    hsync_start = hSyncStart - 8 + hsync_fudge;
+
+    save->crtc_h_sync_strt_wid = ((hsync_start & 0x1fff)
+ 				 | (hsync_wid << 16)
+				 | ((mode->sync & FB_SYNC_HOR_HIGH_ACT)
+				    ? 0
+				    : CRTC_H_SYNC_POL));
+
+				/* This works for double scan mode. */
+    save->crtc_v_total_disp = (((vTotal - 1) & 0xffff)
+			      | ((mode->yres - 1) << 16));
+
+    vsync_wid = vSyncEnd - vSyncStart;
+    if (!vsync_wid)       vsync_wid = 1;
+    if (vsync_wid > 0x1f) vsync_wid = 0x1f;
+
+    save->crtc_v_sync_strt_wid = (((vSyncStart - 1) & 0xfff)
+				 | (vsync_wid << 16)
+				 | ((mode->sync & FB_SYNC_VERT_HIGH_ACT)
+				    ? 0
+				    : CRTC_V_SYNC_POL));
+
+    save->crtc_offset      = 0;
+    save->crtc_offset_cntl = 0;
+
+    save->crtc_pitch  = ((mode->xres * bytpp) +
+                        ((mode->bits_per_pixel) - 1)) /
+                        (mode->bits_per_pixel);
+    save->crtc_pitch |= save->crtc_pitch << 16;
+
+    save->xres = mode->xres;
+    save->yres = mode->yres;
+
+RTRACE("radeonfb: radeon_init_crtc_regs returns SUCCESS\n"); 
+    return 1;
+}
+#endif
+static int radeon_init_crtc_regs(struct radeonfb_info *rinfo,
+                                 struct radeon_regs *save,
+                                 struct fb_var_screeninfo *mode)
+{
+	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;
+        int format = 0;
+	int hsync_start, hsync_fudge, bytpp, hsync_wid, vsync_wid;
+	int prim_mon;
+
+	prim_mon = PRIMARY_MONITOR(rinfo);
+
+	rinfo->xres = mode->xres;
+	rinfo->yres = mode->yres;
+	rinfo->pixclock = mode->pixclock;
+
+	hSyncStart = mode->xres + mode->right_margin;
+	hSyncEnd = hSyncStart + mode->hsync_len;
+	hTotal = hSyncEnd + mode->left_margin;
+
+	vSyncStart = mode->yres + mode->lower_margin;
+	vSyncEnd = vSyncStart + mode->vsync_len;
+	vTotal = vSyncEnd + mode->upper_margin;
+
+	sync = mode->sync;
+	h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1;
+	v_sync_pol = sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1;
+
+	RTRACE("hStart = %d, hEnd = %d, hTotal = %d\n",
+		hSyncStart, hSyncEnd, hTotal);
+	RTRACE("vStart = %d, vEnd = %d, vTotal = %d\n",
+		vSyncStart, vSyncEnd, vTotal);
+
+	hsync_wid = (hSyncEnd - hSyncStart) / 8;
+	vsync_wid = vSyncEnd - vSyncStart;
+	if (hsync_wid == 0)
+		hsync_wid = 1;
+	else if (hsync_wid > 0x3f)	/* max */
+		hsync_wid = 0x3f;
+	vsync_wid = mode->vsync_len;
+	if (vsync_wid == 0)
+		vsync_wid = 1;
+	else if (vsync_wid > 0x1f)	/* max */
+		vsync_wid = 0x1f;
+
+	hSyncPol = mode->sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1;
+	vSyncPol = mode->sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1;
+
+	cSync = mode->sync & FB_SYNC_COMP_HIGH_ACT ? (1 << 4) : 0;
+
+	switch (mode->bits_per_pixel) {
+		case 8:
+			format = DST_8BPP;
+			bytpp = 1;
+			break;
+		case 16:
+			format = DST_16BPP;
+			bytpp = 2;
+			break;
+		case 24:
+			format = DST_24BPP;
+			bytpp = 3;
+			break;
+		case 32:
+			format = DST_32BPP;
+			bytpp = 4;
+			break;
+	}
+
+        if ((prim_mon == MT_DFP) || (prim_mon == MT_LCD))
+    	    hsync_fudge = hsync_fudge_fp[format-1];
+        else
+	    hsync_fudge = hsync_adj_tab[format-1];
+
+	hsync_start = hSyncStart - 8 + hsync_fudge;
+	save->crtc_gen_cntl = (CRTC_EXT_DISP_EN
+			      | CRTC_EN
+			      | (format << 8)
+			     /* | CRTC_DBL_SCAN_EN*/);
+
+	if((prim_mon == MT_DFP) || (prim_mon == MT_LCD))
+	{
+    	    save->crtc_ext_cntl = VGA_ATI_LINEAR |
+        			  XCRT_CNT_EN;
+    	    save->crtc_gen_cntl &= ~(CRTC_DBL_SCAN_EN |
+                                  CRTC_INTERLACE_EN);
+	}
+	else
+	    save->crtc_ext_cntl = VGA_ATI_LINEAR |
+				  XCRT_CNT_EN |
+				  CRTC_CRT_ON;
+
+	    save->dac_cntl      = (DAC_MASK_ALL
+				   | DAC_VGA_ADR_EN
+		    		   | DAC_8BIT_EN);
+
+	save->crtc_h_total_disp = ((((hTotal / 8) - 1) & 0x3ff) |
+				     ((((mode->xres / 8) - 1) & 0x1ff) << 16));
+
+	save->crtc_h_sync_strt_wid = ((hsync_start & 0x1fff) |
+					(hsync_wid << 16) | (h_sync_pol << 23));
+
+	save->crtc_v_total_disp = ((vTotal - 1) & 0xffff) |
+				    ((mode->yres - 1) << 16);
+
+	save->crtc_v_sync_strt_wid = (((vSyncStart - 1) & 0xfff) |
+					 (vsync_wid << 16) | (v_sync_pol  << 23));
+
+	save->crtc_pitch = (mode->xres >> 3);
+
+#if defined(__BIG_ENDIAN)
+	save->surface_cntl = SURF_TRANSLATION_DIS;
+	switch (mode->bits_per_pixel) {
+		case 16:
+			save->surface_cntl |= NONSURF_AP0_SWP_16BPP;
+			break;
+		case 24:
+		case 32:
+			save->surface_cntl |= NONSURF_AP0_SWP_32BPP;
+			break;
+	}
+#endif
+
+	rinfo->pitch = ((mode->xres * ((mode->bits_per_pixel + 1) / 8) + 0x3f)
+			& ~(0x3f)) / 64;
+
+	RTRACE("h_total_disp = 0x%x\t   hsync_strt_wid = 0x%x\n",
+		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);
+
+	save->xres = mode->xres;
+	save->yres = mode->yres;
+
+	save->crtc_offset      = 0;
+	save->crtc_offset_cntl = 0;
+
+	rinfo->bpp = mode->bits_per_pixel;
+	return 0;
+}
+
+static int radeon_init_crtc2_regs(struct radeonfb_info *rinfo,
+                                 struct radeon_regs *save,
+                                 struct fb_var_screeninfo *mode)
+{
+    int    format;
+    int    hsync_start;
+    int    hsync_wid;
+    int    hsync_fudge;
+    int    vsync_wid;
+    int    bytpp;
+    int    hsync_fudge_default[] = { 0x00, 0x12, 0x09, 0x09, 0x06, 0x05 };
+    int    hTotal, vTotal, hSyncStart, hSyncEnd;
+    int    vSyncStart, vSyncEnd;
+RTRACE("radeonfb: radeon_init_crtc2_regs is called\n"); 
+
+    switch (mode->bits_per_pixel) {
+    case 8:  format = 2; bytpp = 1; break;
+    case 16: format = 4; bytpp = 2; break;      /*  565 */
+    case 24: format = 5; bytpp = 3; break;      /*  RGB */
+    case 32: format = 6; bytpp = 4; break;      /* xRGB */
+    default:
+	printk("radeonfb: Unsupported pixel depth (%d)\n", mode->bits_per_pixel);
+	return 0;
+    }
+
+    hsync_fudge = hsync_fudge_default[format-1];
+
+    save->crtc2_gen_cntl = (CRTC2_EN
+                          | CRTC2_CRT2_ON
+			  | (format << 8)
+			  /*| CRTC2_DBL_SCAN_EN*/);
+
+    if(!rinfo->isM7)
+        save->dac2_cntl = rinfo->init_state.dac2_cntl 
+                      /*| DAC2_DAC2_CLK_SEL*/
+                      | DAC2_DAC_CLK_SEL;
+    else
+	{
+        save->disp_output_cntl = 
+            ((rinfo->init_state.disp_output_cntl &
+	      (u32)~DISP_DAC_SOURCE_MASK)
+            | DISP_DAC_SOURCE_CRTC2);
+    }
+
+    hSyncStart = mode->xres + mode->right_margin;
+    hSyncEnd = hSyncStart + mode->hsync_len;
+    hTotal = hSyncEnd + mode->left_margin;
+
+    vSyncStart = mode->yres + mode->lower_margin;
+    vSyncEnd = vSyncStart + mode->vsync_len;
+    vTotal = vSyncEnd + mode->upper_margin;
+
+    save->crtc2_h_total_disp = ((((hTotal / 8) - 1) & 0x3ff)
+	   | ((((mode->xres / 8) - 1) & 0x1ff) << 16));
+
+    hsync_wid = (hSyncEnd - hSyncStart) / 8;
+    if (!hsync_wid)       hsync_wid = 1;
+    if (hsync_wid > 0x3f) hsync_wid = 0x3f;
+    hsync_start = hSyncStart - 8 + hsync_fudge;
+
+    save->crtc2_h_sync_strt_wid = ((hsync_start & 0x1fff)
+				 | (hsync_wid << 16)
+				 | ((mode->sync & FB_SYNC_HOR_HIGH_ACT)
+				    ? 0
+				    : CRTC_H_SYNC_POL));
+
+				/* This works for double scan mode. */
+    save->crtc2_v_total_disp = (((vTotal - 1) & 0xffff)
+			      | ((mode->yres - 1) << 16));
+
+    vsync_wid = vSyncEnd - vSyncStart;
+    if (!vsync_wid)       vsync_wid = 1;
+    if (vsync_wid > 0x1f) vsync_wid = 0x1f;
+
+    save->crtc2_v_sync_strt_wid = (((vSyncStart - 1) & 0xfff)
+				 | (vsync_wid << 16)
+				 | ((mode->sync & FB_SYNC_VERT_HIGH_ACT)
+				    ? 0
+				    : CRTC2_V_SYNC_POL));
+
+    save->crtc2_offset      = 0;
+    save->crtc2_offset_cntl = 0;
+
+    save->crtc2_pitch  = ((mode->xres * bytpp) +
+			 ((mode->bits_per_pixel) -1)) /
+			 (mode->bits_per_pixel);
+    save->crtc2_pitch |= save->crtc2_pitch << 16;
+	
+RTRACE("radeonfb: radeon_init_crtc2_regs returns SUCCESS\n"); 
+    return 1;
+}
+
+static void radeon_init_fp_regs(struct radeonfb_info *rinfo,
+                                 struct radeon_regs *save,
+                                 struct fb_var_screeninfo *mode)
+{
+    float Hratio, Vratio;
+    int prim_mon;
+RTRACE("radeonfb: radeon_init_fp_regs is called\n"); 
+    if(rinfo->PanelXRes == 0 || rinfo->PanelYRes == 0)
+    {
+        Hratio = 1;
+        Vratio = 1;
+    }
+    else
+    {
+      if (mode->xres > rinfo->PanelXRes) mode->xres = rinfo->PanelXRes;
+      if (mode->yres > rinfo->PanelYRes) mode->yres = rinfo->PanelYRes;
+
+      Hratio = (float)mode->xres/(float)rinfo->PanelXRes;
+      Vratio = (float)mode->yres/(float)rinfo->PanelYRes;
+    }
+
+    if (Hratio == 1.0)
+    {
+        save->fp_horz_stretch = rinfo->init_state.fp_horz_stretch;
+        save->fp_horz_stretch &= ~(HORZ_STRETCH_BLEND |
+	                           HORZ_STRETCH_ENABLE);
+    }
+    else
+    {               
+      save->fp_horz_stretch =
+            ((((unsigned long)(Hratio * HORZ_STRETCH_RATIO_MAX +
+            0.5)) & HORZ_STRETCH_RATIO_MASK)) |
+	 (rinfo->init_state.fp_horz_stretch & (HORZ_PANEL_SIZE |
+				   HORZ_FP_LOOP_STRETCH |
+                                  HORZ_AUTO_RATIO_INC));
+        save->fp_horz_stretch |=  (HORZ_STRETCH_BLEND |
+						  HORZ_STRETCH_ENABLE);
+    }
+    save->fp_horz_stretch &= ~HORZ_AUTO_RATIO;
+
+    if (Vratio == 1.0) 
+    {
+        save->fp_vert_stretch = rinfo->init_state.fp_vert_stretch;
+        save->fp_vert_stretch &= ~(VERT_STRETCH_ENABLE|
+                                   VERT_STRETCH_BLEND);
+    }   
+    else
+    {               
+      save->fp_vert_stretch =
+	    (((((unsigned long)(Vratio * VERT_STRETCH_RATIO_MAX +
+            0.5)) & VERT_STRETCH_RATIO_MASK)) |
+	 (rinfo->init_state.fp_vert_stretch & (VERT_PANEL_SIZE |
+				   VERT_STRETCH_RESERVED)));
+        save->fp_vert_stretch |=  (VERT_STRETCH_ENABLE |
+						  VERT_STRETCH_BLEND);
+    }
+    save->fp_vert_stretch &= ~VERT_AUTO_RATIO_EN;
+
+    save->fp_gen_cntl = (rinfo->init_state.fp_gen_cntl & (u32)
+					~(FP_SEL_CRTC2 |
+			                  FP_RMX_HVSYNC_CONTROL_EN |
+					  FP_DFP_SYNC_SEL |	
+                                          FP_CRT_SYNC_SEL | 
+					  FP_CRTC_LOCK_8DOT |	
+					  FP_USE_SHADOW_EN |
+					  FP_CRTC_USE_SHADOW_VEND |
+					  FP_CRT_SYNC_ALT));
+    save->fp_gen_cntl |= (FP_CRTC_DONT_SHADOW_VPAR |
+                          FP_CRTC_DONT_SHADOW_HEND );
+
+    save->lvds_gen_cntl        = rinfo->init_state.lvds_gen_cntl;
+    save->lvds_pll_cntl        = rinfo->init_state.lvds_pll_cntl;
+    save->tmds_crc             = rinfo->init_state.tmds_crc;
+
+    /* Disable CRT output by disabling CRT output for DFP*/
+    save->crtc_ext_cntl  &= ~CRTC_CRT_ON;
+    prim_mon = PRIMARY_MONITOR(rinfo);
+    if(prim_mon == MT_LCD)
+    {
+        save->lvds_gen_cntl  |= (LVDS_ON | LVDS_BLON);
+        save->fp_gen_cntl    &= ~(FP_FPON | FP_TMDS_EN);
+    }
+    else if(prim_mon == MT_DFP)
+        save->fp_gen_cntl    |= (FP_FPON | FP_TMDS_EN);
+
+    save->fp_crtc_h_total_disp = rinfo->init_state.fp_crtc_h_total_disp;
+    save->fp_crtc_v_total_disp = rinfo->init_state.fp_crtc_v_total_disp;
+    save->fp_h_sync_strt_wid   = rinfo->init_state.fp_h_sync_strt_wid;
+    save->fp_v_sync_strt_wid   = rinfo->init_state.fp_v_sync_strt_wid;
+}
+
+static void radeon_init_pll_regs(struct radeonfb_info *rinfo,
+                                 struct radeon_regs *save,
+                                 struct fb_var_screeninfo *mode)
+{
+    u32 dot_clock = 1000000000 / mode->pixclock;
+    u32 freq = dot_clock / 10;  /* x 100 */
+    struct {
+	int divider;
+	int bitvalue;
+    } *post_div, post_divs[] = {
+	{ 1,  0 },
+	{ 2,  1 },
+	{ 4,  2 },
+	{ 8,  3 },
+	{ 3,  4 },
+	{ 16, 5 },
+	{ 6,  6 },
+	{ 12, 7 },
+	{ 0,  0 },
+    };
+    if (freq > rinfo->pll.ppll_max)	freq = rinfo->pll.ppll_max;
+    if (freq*12 < rinfo->pll.ppll_min)	freq = rinfo->pll.ppll_min / 12;
+
+    for (post_div = &post_divs[0]; post_div->divider; ++post_div) {
+	    rinfo->pll_output_freq = post_div->divider * freq;
+	    if (rinfo->pll_output_freq >= rinfo->pll.ppll_min  &&
+		rinfo->pll_output_freq <= rinfo->pll.ppll_max) break;
+    }
+
+    rinfo->post_div = post_div->divider;
+    rinfo->fb_div = round_div(rinfo->pll.ref_div*rinfo->pll_output_freq,
+				rinfo->pll.ref_clk);
+    save->ppll_ref_div = rinfo->pll.ref_div;
+    save->ppll_div_3 = rinfo->fb_div | (post_div->bitvalue << 16);
+    save->htotal_cntl    = 0;
+
+RTRACE("post div = 0x%x\n", rinfo->post_div);
+RTRACE("fb_div = 0x%x\n", rinfo->fb_div);
+RTRACE("ppll_div_3 = 0x%x\n", newmode.ppll_div_3);
+}
+
+static void radeon_init_pll2_regs(struct radeonfb_info *rinfo,
+                                 struct radeon_regs *save,
+                                 struct fb_var_screeninfo *mode)
+{
+    u32 dot_clock = 1000000000 / mode->pixclock;
+    u32 freq = dot_clock * 100;
+    struct {
+	int divider;
+	int bitvalue;
+    } *post_div,
+      post_divs[]   = {
+				/* From RAGE 128 VR/RAGE 128 GL Register
+				   Reference Manual (Technical Reference
+				   Manual P/N RRG-G04100-C Rev. 0.04), page
+				   3-17 (PLL_DIV_[3:0]).  */
+	{  1, 0 },              /* VCLK_SRC                 */
+	{  2, 1 },              /* VCLK_SRC/2               */
+	{  4, 2 },              /* VCLK_SRC/4               */
+	{  8, 3 },              /* VCLK_SRC/8               */
+	{  3, 4 },              /* VCLK_SRC/3               */
+	{ 16, 5 },              /* VCLK_SRC/16              */
+	{  6, 6 },              /* VCLK_SRC/6               */
+	{ 12, 7 },              /* VCLK_SRC/12              */
+	{  0, 0 }
+    };
+RTRACE("radeonfb: radeon_init_pll2_regs is called\n"); 
+
+    if (freq > rinfo->pll.ppll_max) freq = rinfo->pll.ppll_max;
+    if (freq*12 < rinfo->pll.ppll_min)    freq = rinfo->pll.ppll_min/12;
+
+    for (post_div = &post_divs[0]; post_div->divider; ++post_div) {
+	save->pll_output_freq_2 = post_div->divider * freq;
+	if (save->pll_output_freq_2 >= rinfo->pll.ppll_min
+	    && save->pll_output_freq_2 <= rinfo->pll.ppll_max) break;
+    }
+
+    save->dot_clock_freq_2 = freq;
+    save->feedback_div_2   = round_div(rinfo->pll.ref_div
+				     * save->pll_output_freq_2,
+				     rinfo->pll.ref_clk);
+    save->post_div_2       = post_div->divider;
+
+    save->p2pll_ref_div   = rinfo->pll.ref_div;
+    save->p2pll_div_0     = (save->feedback_div_2 | (post_div->bitvalue<<16));
+    save->htotal_cntl2    = 0;
+}
+
+static int radeon_init_dda_regs(struct radeonfb_info *rinfo,
+                                 struct radeon_regs *save,
+                                 struct fb_var_screeninfo *mode)
+{
+    int xclk_freq, vclk_freq, xclk_per_trans, xclk_per_trans_precise;
+    int useable_precision, roff, ron;
+    int min_bits;
+    const int DispFifoWidth=128,DispFifoDepth=32;
+	/* DDA */
+	vclk_freq = round_div(rinfo->pll.ref_clk * rinfo->fb_div,
+			      rinfo->pll.ref_div * rinfo->post_div);
+	xclk_freq = rinfo->pll.xclk;
+
+	xclk_per_trans = round_div(xclk_freq * DispFifoWidth, 
+				    vclk_freq * mode->bits_per_pixel);
+
+	min_bits = min_bits_req(xclk_per_trans);
+	useable_precision = min_bits + 1;
+
+	xclk_per_trans_precise = round_div((xclk_freq * DispFifoWidth) 
+					    << (11 - useable_precision),
+					    vclk_freq * mode->bits_per_pixel);
+
+	ron = (4 * rinfo->ram.mb + 
+	       3 * _max(rinfo->ram.trcd - 2, 0) +
+	       2 * rinfo->ram.trp + 
+	       rinfo->ram.twr + 
+	       rinfo->ram.cl + 
+	       rinfo->ram.tr2w +
+	       xclk_per_trans) << (11 - useable_precision);
+	roff = xclk_per_trans_precise * (DispFifoDepth - 4);
+
+	RTRACE("ron = %d, roff = %d\n", ron, roff);
+	RTRACE("vclk_freq = %d, per = %d\n", vclk_freq, xclk_per_trans_precise);
+
+	if ((ron + rinfo->ram.rloop) >= roff) {
+		printk("radeonfb: error ron out of range\n");
+		return -1;
+	}
+
+	save->dda_config = (xclk_per_trans_precise |
+			      (useable_precision << 16) |
+			      (rinfo->ram.rloop << 20));
+	save->dda_on_off = (ron << 16) | roff;
+	return 0;
+}
+
+/*
+static void radeon_init_palette(struct radeon_regs *save)
+{
+    save->palette_valid = 0;
+}
+*/
+
+static int radeon_init_mode(struct radeonfb_info *rinfo,
+                                 struct radeon_regs *save,
+                                 struct fb_var_screeninfo *mode)
+{
+    int prim_mon;
+RTRACE("radeonfb: radeon_init_mode is called\n"); 
+    if(DUAL_MONITOR(rinfo))
+    {
+        if (!radeon_init_crtc2_regs(rinfo, save, mode))
+            return 0;
+        radeon_init_pll2_regs(rinfo, save, mode);
+    }
+    radeon_init_common_regs(rinfo, save);
+    if(!radeon_init_crtc_regs(rinfo, save, mode))
+        return 0;
+    if(mode->pixclock)
+    {
+      radeon_init_pll_regs(rinfo, save, mode);
+      if (!radeon_init_dda_regs(rinfo, save, mode))
+          return 0;
+    }
+    else
+    {
+        save->ppll_ref_div         = rinfo->init_state.ppll_ref_div;
+        save->ppll_div_3           = rinfo->init_state.ppll_div_3;
+        save->htotal_cntl          = rinfo->init_state.htotal_cntl;
+        save->dda_config           = rinfo->init_state.dda_config;
+        save->dda_on_off           = rinfo->init_state.dda_on_off;
+    }
+    /* radeon_init_palete here */
+    prim_mon = PRIMARY_MONITOR(rinfo);
+    if (((prim_mon == MT_DFP) || (prim_mon == MT_LCD)))
+    {
+        radeon_init_fp_regs(rinfo, save, mode);
+    }
+
+RTRACE("radeonfb: radeon_init_mode returns SUCCESS\n"); 
+    return 1;
+}
+
 static void radeon_engine_init (struct radeonfb_info *rinfo)
 {
 	u32 temp;
@@ -1574,7 +2309,7 @@
         struct radeonfb_info *rinfo = (struct radeonfb_info *) info;
         struct display *disp;
         struct fb_var_screeninfo v;
-        int nom, den, accel;
+        int nom, den, accel, err;
         unsigned chgvar = 0;
  
         disp = (con < 0) ? rinfo->info.disp : &fb_display[con];
@@ -1697,8 +2432,8 @@
 			info->changevar(con);
 	}
 
-	radeon_load_video_mode (rinfo, &v);
-
+	err = radeon_load_video_mode (rinfo, &v);
+	if(err) return err;
 	do_install_cmap(con, info);
 
         return 0;
@@ -1892,13 +2627,6 @@
         	radeon_set_dispsw (rinfo, disp);
 		do_install_cmap(con, info);
 	}
-
-	/* XXX absurd hack for X to restore console */
-	{
-		OUTREG(CRTC_EXT_CNTL, rinfo->hack_crtc_ext_cntl);
-		OUTREG(CRTC_V_SYNC_STRT_WID, rinfo->hack_crtc_v_sync_strt_wid);
-	}
-
         return 0;
 }
 
@@ -2080,300 +2808,400 @@
 	return 0;
 }
 
-
-
-static void radeon_save_state (struct radeonfb_info *rinfo,
+static void radeon_save_common_regs(struct radeonfb_info *rinfo,
+                               struct radeon_regs *save)
+{
+RTRACE("radeonfb: radeon_save_common_regs is called\n"); 
+	save->ovr_clr		= INREG(OVR_CLR);
+	save->ovr_wid_left_right= INREG(OVR_WID_LEFT_RIGHT);
+	save->ovr_wid_top_bottom= INREG(OVR_WID_TOP_BOTTOM);
+	save->ov0_scale_cntl	= INREG(OV0_SCALE_CNTL);
+	save->mpp_tb_config	= INREG(MPP_TB_CONFIG);
+	save->mpp_gp_config	= INREG(MPP_GP_CONFIG);
+	save->subpic_cntl	= INREG(SUBPIC_CNTL);
+	save->viph_control	= INREG(VIPH_CONTROL);
+	save->i2c_cntl_1	= INREG(I2C_CNTL_1);
+	save->gen_int_cntl	= INREG(GEN_INT_CNTL);
+	save->cap0_trig_cntl	= INREG(CAP0_TRIG_CNTL);
+	save->cap1_trig_cntl	= INREG(CAP1_TRIG_CNTL);
+	save->bus_cntl		= INREG(BUS_CNTL);
+}
+
+static void radeon_save_crtc_regs(struct radeonfb_info *rinfo,
+                               struct radeon_regs *save)
+{
+RTRACE("radeonfb: radeon_save_crtc_regs is called\n"); 
+	save->crtc_gen_cntl		= INREG(CRTC_GEN_CNTL);
+	save->crtc_ext_cntl		= INREG(CRTC_EXT_CNTL);
+	save->dac_cntl			= INREG(DAC_CNTL);
+        save->crtc_h_total_disp		= INREG(CRTC_H_TOTAL_DISP);
+        save->crtc_h_sync_strt_wid	= INREG(CRTC_H_SYNC_STRT_WID);
+        save->crtc_v_total_disp		= INREG(CRTC_V_TOTAL_DISP);
+        save->crtc_v_sync_strt_wid	= INREG(CRTC_V_SYNC_STRT_WID);
+	save->crtc_offset		= INREG(CRTC_OFFSET);
+	save->crtc_offset_cntl		= INREG(CRTC_OFFSET_CNTL);
+	save->crtc_pitch		= INREG(CRTC_PITCH);
+}
+
+static void radeon_save_crtc2_regs(struct radeonfb_info *rinfo,
+                               struct radeon_regs *save)
+{
+RTRACE("radeonfb: radeon_save_crtc2_regs is called\n"); 
+	save->dac2_cntl			= INREG(DAC_CNTL2);
+	save->disp_output_cntl		= INREG(DISP_OUTPUT_CNTL);
+
+	save->crtc2_gen_cntl		= INREG(CRTC2_GEN_CNTL);
+	save->crtc2_h_total_disp	= INREG(CRTC2_H_TOTAL_DISP);
+	save->crtc2_h_sync_strt_wid	= INREG(CRTC2_H_SYNC_STRT_WID);
+	save->crtc2_v_total_disp	= INREG(CRTC2_V_TOTAL_DISP);
+	save->crtc2_v_sync_strt_wid	= INREG(CRTC2_V_SYNC_STRT_WID);
+	save->crtc2_offset		= INREG(CRTC2_OFFSET);
+	save->crtc2_offset_cntl		= INREG(CRTC2_OFFSET_CNTL);
+	save->crtc2_pitch		= INREG(CRTC2_PITCH);
+}
+
+static void radeon_save_fp_regs(struct radeonfb_info *rinfo,
+                               struct radeon_regs *save)
+{
+RTRACE("radeonfb: radeon_save_fp_regs is called\n"); 
+	save->fp_crtc_h_total_disp	= INREG(FP_CRTC_H_TOTAL_DISP);
+	save->fp_crtc_v_total_disp	= INREG(FP_CRTC_V_TOTAL_DISP);
+	save->fp_gen_cntl		= INREG(FP_GEN_CNTL);
+	save->fp_h_sync_strt_wid	= INREG(FP_H_SYNC_STRT_WID);
+	save->fp_horz_stretch		= INREG(FP_HORZ_STRETCH);
+	save->fp_v_sync_strt_wid	= INREG(FP_V_SYNC_STRT_WID);
+	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);
+}
+
+static void radeon_save_pll_regs(struct radeonfb_info *rinfo,
+                               struct radeon_regs *save)
+{
+RTRACE("radeonfb: radeon_save_pll_regs is called\n"); 
+	save->ppll_ref_div	= INPLL(PPLL_REF_DIV);
+	save->ppll_div_3	= INPLL(PPLL_DIV_3);
+	save->htotal_cntl	= INPLL(HTOTAL_CNTL);
+}
+
+static void radeon_save_pll2_regs(struct radeonfb_info *rinfo,
+                               struct radeon_regs *save)
+{
+RTRACE("radeonfb: radeon_save_pll2_regs is called\n"); 
+	save->p2pll_ref_div	= INPLL(P2PLL_REF_DIV);
+	save->p2pll_div_0	= INPLL(P2PLL_DIV_0);
+	save->htotal_cntl2	= INPLL(HTOTAL2_CNTL);
+}
+
+static void radeon_save_dda_regs(struct radeonfb_info *rinfo,
+                               struct radeon_regs *save)
+{
+RTRACE("radeonfb: radeon_save_dda_regs is called\n"); 
+	save->dda_config	= INREG(DDA_CONFIG);
+	save->dda_on_off	= INREG(DDA_ON_OFF);
+}
+
+#if 0
+static void radeon_save_palette(struct radeonfb_info *rinfo,
                                struct radeon_regs *save)
 {
-	save->crtc_gen_cntl = INREG(CRTC_GEN_CNTL);
-	save->crtc_ext_cntl = INREG(CRTC_EXT_CNTL);
-	save->dac_cntl = INREG(DAC_CNTL);
-        save->crtc_h_total_disp = INREG(CRTC_H_TOTAL_DISP);
-        save->crtc_h_sync_strt_wid = INREG(CRTC_H_SYNC_STRT_WID);
-        save->crtc_v_total_disp = INREG(CRTC_V_TOTAL_DISP);
-        save->crtc_v_sync_strt_wid = INREG(CRTC_V_SYNC_STRT_WID);
-	save->crtc_pitch = INREG(CRTC_PITCH);
+    int i;
+RTRACE("radeonfb: radeon_save_palette is called\n"); 
+    PAL_SELECT(1);
+    INPAL_START(0);
+    for (i = 0; i < 256; i++) save->palette2[i] = INPAL_NEXT();
+    PAL_SELECT(0);
+    INPAL_START(0);
+    for (i = 0; i < 256; i++) save->palette[i] = INPAL_NEXT();
+}
+#endif
+
+static void radeon_write_common_regs(struct radeonfb_info *rinfo,
+                               struct radeon_regs *restore)
+{
+RTRACE("radeonfb: radeon_write_common_regs is called\n"); 
+	OUTREG(OVR_CLR,			restore->ovr_clr);
+	OUTREG(OVR_WID_LEFT_RIGHT,	restore->ovr_wid_left_right);
+	OUTREG(OVR_WID_TOP_BOTTOM,	restore->ovr_wid_top_bottom);
+	OUTREG(OV0_SCALE_CNTL,		restore->ov0_scale_cntl);
+	OUTREG(MPP_TB_CONFIG,		restore->mpp_tb_config );
+	OUTREG(MPP_GP_CONFIG,		restore->mpp_gp_config );
+	OUTREG(SUBPIC_CNTL,		restore->subpic_cntl);
+	OUTREG(VIPH_CONTROL,		restore->viph_control);
+	OUTREG(I2C_CNTL_1,		restore->i2c_cntl_1);
+	OUTREG(GEN_INT_CNTL,		restore->gen_int_cntl);
+	OUTREG(CAP0_TRIG_CNTL,		restore->cap0_trig_cntl);
+	OUTREG(CAP1_TRIG_CNTL,		restore->cap1_trig_cntl);
+	OUTREG(BUS_CNTL,		restore->bus_cntl);
+}
+
+static void radeon_write_crtc_regs(struct radeonfb_info *rinfo,
+                               struct radeon_regs *restore)
+{
+RTRACE("radeonfb: radeon_write_crtc_regs is called\n"); 
+	OUTREG(CRTC_GEN_CNTL,		restore->crtc_gen_cntl);
+
+	OUTREGP(CRTC_EXT_CNTL,		restore->crtc_ext_cntl,
+		CRTC_VSYNC_DIS |
+		CRTC_HSYNC_DIS |
+		CRTC_DISPLAY_DIS);
+
+	OUTREGP(DAC_CNTL,		restore->dac_cntl,
+		DAC_RANGE_CNTL |
+		DAC_BLANKING);
+
+	OUTREG(CRTC_H_TOTAL_DISP,	restore->crtc_h_total_disp);
+	OUTREG(CRTC_H_SYNC_STRT_WID,	restore->crtc_h_sync_strt_wid);
+	OUTREG(CRTC_V_TOTAL_DISP,	restore->crtc_v_total_disp);
+	OUTREG(CRTC_V_SYNC_STRT_WID,	restore->crtc_v_sync_strt_wid);
+	OUTREG(CRTC_OFFSET,		restore->crtc_offset);
+	OUTREG(CRTC_OFFSET_CNTL,	restore->crtc_offset_cntl);
+	OUTREG(CRTC_PITCH,		restore->crtc_pitch);
+}
+
+static void radeon_write_crtc2_regs(struct radeonfb_info *rinfo,
+                               struct radeon_regs *restore)
+{
+RTRACE("radeonfb: radeon_write_crtc2_regs is called\n"); 
+/*	OUTREG(CRTC2_GEN_CNTL,		restore->crtc2_gen_cntl);*/
+	OUTREGP(CRTC2_GEN_CNTL,		restore->crtc2_gen_cntl,
+		CRTC2_VSYNC_DIS |
+		CRTC2_HSYNC_DIS |
+		CRTC2_DISP_DIS);
+
+	OUTREG(DAC_CNTL2,		restore->dac2_cntl);
+	OUTREG(DISP_OUTPUT_CNTL,	restore->disp_output_cntl);
+
+	OUTREG(CRTC2_H_TOTAL_DISP,	restore->crtc2_h_total_disp);
+	OUTREG(CRTC2_H_SYNC_STRT_WID,	restore->crtc2_h_sync_strt_wid);
+	OUTREG(CRTC2_V_TOTAL_DISP,	restore->crtc2_v_total_disp);
+	OUTREG(CRTC2_V_SYNC_STRT_WID,	restore->crtc2_v_sync_strt_wid);
+	OUTREG(CRTC2_OFFSET,		restore->crtc2_offset);
+	OUTREG(CRTC2_OFFSET_CNTL,	restore->crtc2_offset_cntl);
+	OUTREG(CRTC2_PITCH,		restore->crtc2_pitch);
+}
+
+static void radeon_write_fp_regs(struct radeonfb_info *rinfo,
+                               struct radeon_regs *restore)
+{
+  int prim_mon;
+  u32 tmp;
+RTRACE("radeonfb: radeon_write_fp_regs is called\n"); 
+	OUTREG(FP_CRTC_H_TOTAL_DISP,	restore->fp_crtc_h_total_disp);
+	OUTREG(FP_CRTC_V_TOTAL_DISP,	restore->fp_crtc_v_total_disp);
+	OUTREG(FP_H_SYNC_STRT_WID,	restore->fp_h_sync_strt_wid);
+	OUTREG(FP_V_SYNC_STRT_WID,	restore->fp_v_sync_strt_wid);
+	OUTREG(TMDS_CRC,		restore->tmds_crc);
+	OUTREG(FP_HORZ_STRETCH,		restore->fp_horz_stretch);
+	OUTREG(FP_VERT_STRETCH,		restore->fp_vert_stretch);
+	OUTREG(FP_GEN_CNTL,		restore->fp_gen_cntl);
+	prim_mon = PRIMARY_MONITOR(rinfo);
+	if(prim_mon == MT_LCD) {
+		tmp = INREG(LVDS_GEN_CNTL);
+		if((tmp & (LVDS_ON | LVDS_BLON)) ==
+		(restore->lvds_gen_cntl & (LVDS_ON | LVDS_BLON))) {
+			OUTREG(LVDS_GEN_CNTL, restore->lvds_gen_cntl);
+		}
+	}
+	else {
+		if (restore->lvds_gen_cntl & (LVDS_ON | LVDS_BLON)) {
+#if 0
+/* TODO it later */
+			usleep(rinfo->PanelPwrDly * 1000);
+#endif
+			OUTREG(LVDS_GEN_CNTL, restore->lvds_gen_cntl);
+		}
+		else {
+			OUTREG(LVDS_GEN_CNTL,
+			restore->lvds_gen_cntl | LVDS_BLON);
+#if 0
+/* TODO it later */
+			usleep(rinfo->PanelPwrDly * 1000);
+#endif
+			OUTREG(LVDS_GEN_CNTL, restore->lvds_gen_cntl);
+		}
+	}
 }
 
-
-
-static void radeon_load_video_mode (struct radeonfb_info *rinfo,
+static void radeon_write_pll_regs(struct radeonfb_info *rinfo,
+                               struct radeon_regs *restore)
+{
+RTRACE("radeonfb: radeon_write_pll_regs is called\n"); 
+	OUTPLLP(0x08, 0x00, ~(0x03));
+	while ( (INREG(CLOCK_CNTL_INDEX) & PLL_DIV_SEL) != PLL_DIV_SEL) {
+		OUTREGP(CLOCK_CNTL_INDEX, PLL_DIV_SEL, 0xffff);
+	}
+	OUTPLLP(PPLL_CNTL, PPLL_RESET, 0xffff);
+	while ( (INPLL(PPLL_REF_DIV) & PPLL_REF_DIV_MASK) !=
+			(restore->ppll_ref_div & PPLL_REF_DIV_MASK)) {
+		OUTPLLP(PPLL_REF_DIV,
+			restore->ppll_ref_div, ~PPLL_REF_DIV_MASK);
+	}
+	while ( (INPLL(PPLL_DIV_3) & PPLL_FB3_DIV_MASK) !=
+			(restore->ppll_div_3 & PPLL_FB3_DIV_MASK)) {
+		OUTPLLP(PPLL_DIV_3,restore->ppll_div_3, ~PPLL_FB3_DIV_MASK);
+	}
+	while ( (INPLL(PPLL_DIV_3) & PPLL_POST3_DIV_MASK) !=
+			(restore->ppll_div_3 & PPLL_POST3_DIV_MASK)) {
+		OUTPLLP(PPLL_DIV_3,restore->ppll_div_3, ~PPLL_POST3_DIV_MASK);
+	}
+	OUTPLL(HTOTAL_CNTL, restore->htotal_cntl);
+	OUTPLLP(PPLL_CNTL, 0, ~PPLL_RESET);
+	OUTPLLP(0x08, 0x03, ~(0x03));
+}
+
+
+static void radeon_write_pll2_regs(struct radeonfb_info *rinfo,
+                               struct radeon_regs *restore)
+{
+RTRACE("radeonfb: radeon_write_pll2_regs is called\n"); 
+	OUTPLLP(0x2d, 0x00, ~(0x03));
+	while (INREG(CLOCK_CNTL_INDEX) & ~(PLL2_DIV_SEL_MASK)) {
+		OUTREGP(CLOCK_CNTL_INDEX, 0, PLL2_DIV_SEL_MASK);
+	}
+	OUTPLLP(P2PLL_CNTL,P2PLL_RESET,0xffff);
+	while ( (INPLL(P2PLL_REF_DIV) & P2PLL_REF_DIV_MASK) !=
+			(restore->p2pll_ref_div & P2PLL_REF_DIV_MASK)) {
+		OUTPLLP(P2PLL_REF_DIV, restore->p2pll_ref_div, ~P2PLL_REF_DIV_MASK);
+	}
+	while ( (INPLL(P2PLL_DIV_0) & P2PLL_FB0_DIV_MASK) !=
+			(restore->p2pll_div_0 & P2PLL_FB0_DIV_MASK)) {
+		OUTPLLP(P2PLL_DIV_0, restore->p2pll_div_0, ~P2PLL_FB0_DIV_MASK);
+	}
+	while ( (INPLL(P2PLL_DIV_0) & P2PLL_POST0_DIV_MASK) !=
+			(restore->p2pll_div_0 & P2PLL_POST0_DIV_MASK)) {
+		OUTPLLP(P2PLL_DIV_0,restore->p2pll_div_0, ~P2PLL_POST0_DIV_MASK);
+	}
+	OUTPLL(HTOTAL2_CNTL, restore->htotal_cntl2);
+	OUTPLLP(P2PLL_CNTL, 0, ~(P2PLL_RESET | P2PLL_SLEEP));
+	OUTPLLP(0x2d, 0x03, ~(0x03));
+}
+
+static void radeon_write_dda_regs(struct radeonfb_info *rinfo,
+                               struct radeon_regs *restore)
+{
+RTRACE("radeonfb: radeon_write_dda_regs is called\n"); 
+	OUTREG(DDA_CONFIG,	restore->dda_config);
+	OUTREG(DDA_ON_OFF,	restore->dda_on_off);
+}
+
+#if 0
+static void radeon_write_palette(struct radeonfb_info *rinfo,
+                               struct radeon_regs *restore)
+{
+    int i;
+
+RTRACE("radeonfb: radeon_write_palette is called\n"); 
+    PAL_SELECT(1);
+    OUTPAL_START(0);
+    for (i = 0; i < 256; i++) {
+	RADEONWaitForFifo(32); /* delay */
+	OUTPAL_NEXT_CARD32(restore->palette2[i]);
+    }
+
+    PAL_SELECT(0);
+    OUTPAL_START(0);
+    for (i = 0; i < 256; i++) {
+	RADEONWaitForFifo(32); /* delay */
+	OUTPAL_NEXT_CARD32(restore->palette[i]);
+    }
+}
+#endif
+
+static void radeon_save_mode (struct radeonfb_info *rinfo,
+                               struct radeon_regs *save)
+{
+  int prim_mon;
+RTRACE("radeonfb: radeon_save_mode is called\n"); 
+  if(DUAL_MONITOR(rinfo)) {
+	radeon_save_crtc2_regs(rinfo,save);
+	radeon_save_pll2_regs(rinfo,save);
+  }
+  radeon_save_common_regs(rinfo,save);
+  radeon_save_crtc_regs(rinfo,save);
+  prim_mon = PRIMARY_MONITOR(rinfo);
+  if(prim_mon == MT_LCD || prim_mon == MT_DFP) radeon_save_fp_regs(rinfo,save);
+  radeon_save_pll_regs(rinfo,save);
+  radeon_save_dda_regs(rinfo,save);
+/*radeon_save_palette(rinfo,save);*/
+}
+
+static void radeon_save_state(struct radeonfb_info *rinfo,
+                              struct radeon_regs *save)
+{
+RTRACE("radeonfb: radeon_save_state is called\n"); 
+	save->dp_datatype	= INREG(DP_DATATYPE);
+	save->rbbm_soft_reset	= INREG(RBBM_SOFT_RESET);
+	save->clock_cntl_index	= INREG(CLOCK_CNTL_INDEX);
+	save->amcgpio_en_reg	= INREG(AMCGPIO_EN_REG);
+	save->amcgpio_mask	= INREG(AMCGPIO_MASK);
+	radeon_save_mode(rinfo,save);
+}
+
+static int radeon_load_video_mode (struct radeonfb_info *rinfo,
                                     struct fb_var_screeninfo *mode)
 {
+/*
 	struct radeon_regs newmode;
-	int hTotal, vTotal, hSyncStart, hSyncEnd,
-	    hSyncPol, vSyncStart, vSyncEnd, vSyncPol, cSync;
-	u8 hsync_adj_tab[] = {0, 0x12, 9, 9, 6, 5};
-	u32 dotClock = 1000000000 / mode->pixclock,
-	    sync, h_sync_pol, v_sync_pol;
-	int freq = dotClock / 10;  /* x 100 */
-        int xclk_freq, vclk_freq, xclk_per_trans, xclk_per_trans_precise;
-        int useable_precision, roff, ron;
-        int min_bits, format = 0;
-	int hsync_start, hsync_fudge, bytpp, hsync_wid, vsync_wid;
-
-	rinfo->xres = mode->xres;
-	rinfo->yres = mode->yres;
-	rinfo->pixclock = mode->pixclock;
-
-	hSyncStart = mode->xres + mode->right_margin;
-	hSyncEnd = hSyncStart + mode->hsync_len;
-	hTotal = hSyncEnd + mode->left_margin;
-
-	vSyncStart = mode->yres + mode->lower_margin;
-	vSyncEnd = vSyncStart + mode->vsync_len;
-	vTotal = vSyncEnd + mode->upper_margin;
-
-	sync = mode->sync;
-	h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1;
-	v_sync_pol = sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1;
-
-	RTRACE("hStart = %d, hEnd = %d, hTotal = %d\n",
-		hSyncStart, hSyncEnd, hTotal);
-	RTRACE("vStart = %d, vEnd = %d, vTotal = %d\n",
-		vSyncStart, vSyncEnd, vTotal);
-
-	hsync_wid = (hSyncEnd - hSyncStart) / 8;
-	vsync_wid = vSyncEnd - vSyncStart;
-	if (hsync_wid == 0)
-		hsync_wid = 1;
-	else if (hsync_wid > 0x3f)	/* max */
-		hsync_wid = 0x3f;
-	vsync_wid = mode->vsync_len;
-	if (vsync_wid == 0)
-		vsync_wid = 1;
-	else if (vsync_wid > 0x1f)	/* max */
-		vsync_wid = 0x1f;
-
-	hSyncPol = mode->sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1;
-	vSyncPol = mode->sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1;
-
-	cSync = mode->sync & FB_SYNC_COMP_HIGH_ACT ? (1 << 4) : 0;
-
-	switch (mode->bits_per_pixel) {
-		case 8:
-			format = DST_8BPP;
-			bytpp = 1;
-			break;
-		case 16:
-			format = DST_16BPP;
-			bytpp = 2;
-			break;
-		case 24:
-			format = DST_24BPP;
-			bytpp = 3;
-			break;
-		case 32:
-			format = DST_32BPP;
-			bytpp = 4;
-			break;
-	}
-
-	hsync_fudge = hsync_adj_tab[format-1];
-	hsync_start = hSyncStart - 8 + hsync_fudge;
-
-	newmode.crtc_gen_cntl = CRTC_EXT_DISP_EN | CRTC_EN |
-				(format << 8);
-	if(rinfo->hasCRTC2) 
-        /* HACKED: !!! Enable CRT port here !!! */
-	     newmode.crtc_ext_cntl = VGA_ATI_LINEAR | XCRT_CNT_EN | CRTC_CRT_ON;
-	else newmode.crtc_ext_cntl = VGA_ATI_LINEAR | XCRT_CNT_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) |
-				     ((((mode->xres / 8) - 1) & 0x1ff) << 16));
-
-	newmode.crtc_h_sync_strt_wid = ((hsync_start & 0x1fff) |
-					(hsync_wid << 16) | (h_sync_pol << 23));
-
-	newmode.crtc_v_total_disp = ((vTotal - 1) & 0xffff) |
-				    ((mode->yres - 1) << 16);
-
-	newmode.crtc_v_sync_strt_wid = (((vSyncStart - 1) & 0xfff) |
-					 (vsync_wid << 16) | (v_sync_pol  << 23));
-
-	newmode.crtc_pitch = (mode->xres >> 3);
-
-#if defined(__BIG_ENDIAN)
-	newmode.surface_cntl = SURF_TRANSLATION_DIS;
-	switch (mode->bits_per_pixel) {
-		case 16:
-			newmode.surface_cntl |= NONSURF_AP0_SWP_16BPP;
-			break;
-		case 24:
-		case 32:
-			newmode.surface_cntl |= NONSURF_AP0_SWP_32BPP;
-			break;
-	}
-#endif
-
-	rinfo->pitch = ((mode->xres * ((mode->bits_per_pixel + 1) / 8) + 0x3f)
-			& ~(0x3f)) / 64;
-
-	RTRACE("h_total_disp = 0x%x\t   hsync_strt_wid = 0x%x\n",
-		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.xres = mode->xres;
-	newmode.yres = mode->yres;
-
-	rinfo->bpp = mode->bits_per_pixel;
-	rinfo->hack_crtc_ext_cntl = newmode.crtc_ext_cntl;
-	rinfo->hack_crtc_v_sync_strt_wid = newmode.crtc_v_sync_strt_wid;
-
-	if (freq > rinfo->pll.ppll_max)
-		freq = rinfo->pll.ppll_max;
-	if (freq*12 < rinfo->pll.ppll_min)
-		freq = rinfo->pll.ppll_min / 12;
-
-	{
-		struct {
-			int divider;
-			int bitvalue;
-		} *post_div,
-		  post_divs[] = {
-			{ 1,  0 },
-			{ 2,  1 },
-			{ 4,  2 },
-			{ 8,  3 },
-			{ 3,  4 },
-			{ 16, 5 },
-			{ 6,  6 },
-			{ 12, 7 },
-			{ 0,  0 },
-		};
-
-		for (post_div = &post_divs[0]; post_div->divider; ++post_div) {
-			rinfo->pll_output_freq = post_div->divider * freq;
-			if (rinfo->pll_output_freq >= rinfo->pll.ppll_min  &&
-			    rinfo->pll_output_freq <= rinfo->pll.ppll_max)
-				break;
-		}
-
-		rinfo->post_div = post_div->divider;
-		rinfo->fb_div = round_div(rinfo->pll.ref_div*rinfo->pll_output_freq,
-					  rinfo->pll.ref_clk);
-		newmode.ppll_ref_div = rinfo->pll.ref_div;
-		newmode.ppll_div_3 = rinfo->fb_div | (post_div->bitvalue << 16);
-	}
-
-	RTRACE("post div = 0x%x\n", rinfo->post_div);
-	RTRACE("fb_div = 0x%x\n", rinfo->fb_div);
-	RTRACE("ppll_div_3 = 0x%x\n", newmode.ppll_div_3);
-
-	/* DDA */
-	vclk_freq = round_div(rinfo->pll.ref_clk * rinfo->fb_div,
-			      rinfo->pll.ref_div * rinfo->post_div);
-	xclk_freq = rinfo->pll.xclk;
-
-	xclk_per_trans = round_div(xclk_freq * 128, vclk_freq * mode->bits_per_pixel);
-
-	min_bits = min_bits_req(xclk_per_trans);
-	useable_precision = min_bits + 1;
-
-	xclk_per_trans_precise = round_div((xclk_freq * 128) << (11 - useable_precision),
-					   vclk_freq * mode->bits_per_pixel);
-
-	ron = (4 * rinfo->ram.mb + 3 * _max(rinfo->ram.trcd - 2, 0) +
-	       2 * rinfo->ram.trp + rinfo->ram.twr + rinfo->ram.cl + rinfo->ram.tr2w +
-	       xclk_per_trans) << (11 - useable_precision);
-	roff = xclk_per_trans_precise * (32 - 4);
-
-	RTRACE("ron = %d, roff = %d\n", ron, roff);
-	RTRACE("vclk_freq = %d, per = %d\n", vclk_freq, xclk_per_trans_precise);
-
-	if ((ron + rinfo->ram.rloop) >= roff) {
-		printk("radeonfb: error ron out of range\n");
-		return;
-	}
-
-	newmode.dda_config = (xclk_per_trans_precise |
-			      (useable_precision << 16) |
-			      (rinfo->ram.rloop << 20));
-	newmode.dda_on_off = (ron << 16) | roff;
-
+
+RTRACE("radeonfb: radeon_load_video_mode is called\n"); 
+	if(!radeon_init_mode(rinfo, &newmode, mode)) return -1;
+
+	radeonfb_blank(VESA_POWERDOWN,&rinfo->info);
+	radeon_write_mode(rinfo, &newmode);
+	radeonfb_blank(VESA_NO_BLANKING,&rinfo->info);
+	return 0;
+*/
+	struct radeon_regs newmode;
+
+radeon_init_common_regs(rinfo,&newmode);
+radeon_init_crtc_regs(rinfo,&newmode,mode);
+radeon_init_pll_regs(rinfo,&newmode,mode);
+radeon_init_dda_regs(rinfo,&newmode,mode);
 	/* do it! */
 	radeon_write_mode (rinfo, &newmode);
-	/* XXX absurd hack for X to restore console on VE */
-	if(rinfo->hasCRTC2 && rinfo->crtDispType == MT_CRT &&
-	   (rinfo->dviDispType == MT_NONE || rinfo->dviDispType == MT_STV)) {
-		OUTREG(CRTC_EXT_CNTL, rinfo->hack_crtc_ext_cntl);
-		OUTREG(CRTC_V_SYNC_STRT_WID, rinfo->hack_crtc_v_sync_strt_wid);
-	}
-	return;
+	return 0;
 }
 
-
-    /*****
-      When changing mode with Dual-head card (VE/M6), care must
-      be taken for the special order in setting registers. CRTC2 has
-      to be set before changing CRTC_EXT register.
-      Otherwise we may get a blank screen.
-    *****/
-
 static void radeon_write_mode (struct radeonfb_info *rinfo,
                                struct radeon_regs *mode)
 {
-	int i;
-
-	/* blank screen */
-	OUTREG8(CRTC_EXT_CNTL + 1, 4);
-
-	for (i=0; i<9; i++)
-		OUTREG(common_regs[i].reg, common_regs[i].val);
-
-	OUTREG(CRTC_GEN_CNTL, mode->crtc_gen_cntl);
-	OUTREGP(CRTC_EXT_CNTL, mode->crtc_ext_cntl,
-		CRTC_HSYNC_DIS | CRTC_VSYNC_DIS | CRTC_DISPLAY_DIS);
-	OUTREGP(DAC_CNTL, mode->dac_cntl, DAC_RANGE_CNTL | DAC_BLANKING);
-	OUTREG(CRTC_H_TOTAL_DISP, mode->crtc_h_total_disp);
-	OUTREG(CRTC_H_SYNC_STRT_WID, mode->crtc_h_sync_strt_wid);
-	OUTREG(CRTC_V_TOTAL_DISP, mode->crtc_v_total_disp);
-	OUTREG(CRTC_V_SYNC_STRT_WID, mode->crtc_v_sync_strt_wid);
-	OUTREG(CRTC_OFFSET, 0);
-	OUTREG(CRTC_OFFSET_CNTL, 0);
-	OUTREG(CRTC_PITCH, mode->crtc_pitch);
-#if defined(__BIG_ENDIAN)
-	/* XXX this code makes degradation of mplayer quality on Radeon VE */
-	OUTREG(SURFACE_CNTL, mode->surface_cntl);
-#endif
-/* Here we should restore FP registers for LCD & DFP monitors */
-
-	while ((INREG(CLOCK_CNTL_INDEX) & PPLL_DIV_SEL_MASK) !=
-	       PPLL_DIV_SEL_MASK) {
-		OUTREGP(CLOCK_CNTL_INDEX, PPLL_DIV_SEL_MASK, 0xffff);
+	/*****
+	When changing mode with Dual-head card (VE/M6), care must
+	be taken for the special order in setting registers. CRTC2 has
+	to be set before changing CRTC_EXT register.
+	Otherwise we may get a blank screen.
+	*****/
+RTRACE("radeonfb: radeon_write_mode is called\n"); 
+	if(DUAL_MONITOR(rinfo))	{
+		radeon_write_crtc2_regs(rinfo,mode);
+		radeon_write_pll2_regs(rinfo,mode);
+	}
+	radeon_write_common_regs(rinfo,mode);
+	radeon_write_dda_regs(rinfo,mode);
+	radeon_write_crtc_regs(rinfo,mode);
+	if(rinfo->crtDispType == MT_DFP || rinfo->crtDispType == MT_LCD) {
+		radeon_write_fp_regs(rinfo,mode);
 	}
-
-	OUTPLLP(PPLL_CNTL, PPLL_RESET, 0xffff);
-
-	while ((INPLL(PPLL_REF_DIV) & PPLL_REF_DIV_MASK) !=
-	       (mode->ppll_ref_div & PPLL_REF_DIV_MASK)) {
-		OUTPLLP(PPLL_REF_DIV, mode->ppll_ref_div, ~PPLL_REF_DIV_MASK);
-	}
-
-	while ((INPLL(PPLL_DIV_3) & PPLL_FB3_DIV_MASK) !=
-	       (mode->ppll_div_3 & PPLL_FB3_DIV_MASK)) {
-		OUTPLLP(PPLL_DIV_3, mode->ppll_div_3, ~PPLL_FB3_DIV_MASK);
-	}
-
-	while ((INPLL(PPLL_DIV_3) & PPLL_POST3_DIV_MASK) !=
-	       (mode->ppll_div_3 & PPLL_POST3_DIV_MASK)) {
-		OUTPLLP(PPLL_DIV_3, mode->ppll_div_3, ~PPLL_POST3_DIV_MASK);
-	}
-
-	OUTPLL(HTOTAL_CNTL, 0);
-
-	OUTPLLP(PPLL_CNTL, 0, ~PPLL_RESET);
-
-	OUTREG(DDA_CONFIG, mode->dda_config);
-	OUTREG(DDA_ON_OFF, mode->dda_on_off);
-
-	/* unblank screen */
-	OUTREG8(CRTC_EXT_CNTL + 1, 0);
-
-	return;
+	radeon_write_pll_regs(rinfo,mode);
+}
+
+static void radeon_write_state (struct radeonfb_info *rinfo,
+                               struct radeon_regs *restore)
+{
+RTRACE("radeonfb: radeon_write_state is called\n"); 
+	radeonfb_blank(VESA_POWERDOWN,&rinfo->info);
+	OUTREG(AMCGPIO_MASK,	restore->amcgpio_mask);
+	OUTREG(AMCGPIO_EN_REG,	restore->amcgpio_en_reg);
+	OUTREG(CLOCK_CNTL_INDEX,restore->clock_cntl_index);
+	OUTREG(RBBM_SOFT_RESET,	restore->rbbm_soft_reset);
+	OUTREG(DP_DATATYPE,	restore->dp_datatype);
+	/* M6 card has trouble restoring text mode for its CRT.
+	Needs this workaround.*/
+	if(rinfo->isM6) OUTREG(DAC_CNTL2, restore->dac2_cntl);
+	radeon_write_mode(rinfo,restore);
+	radeonfb_blank(VESA_NO_BLANKING,&rinfo->info);
 }
 
 #if 0