--- ../../mergedfb/cvs/cvs-2003-7-31/ati.orig/radeon_driver.c	Wed Jul 30 23:55:18 2003
+++ radeon_driver.c	Tue Aug 12 15:25:20 2003
@@ -103,6 +103,9 @@
 static void RADEONDisplayPowerManagementSet(ScrnInfoPtr pScrn,
 					    int PowerManagementMode,
 					    int flags);
+/* power management functions */
+static void RADEONPMDisableDynamicMode(ScrnInfoPtr pScrn);
+static void RADEONPMEnableDynamicMode(ScrnInfoPtr pScrn);
 
 typedef enum {
     OPTION_NOACCEL,
@@ -131,7 +134,8 @@
     OPTION_CLONE_HSYNC,
     OPTION_CLONE_VREFRESH,
     OPTION_FBDEV,
-    OPTION_VIDEO_KEY
+    OPTION_VIDEO_KEY,
+    OPTION_DYN_PM
 } RADEONOpts;
 
 const OptionInfoRec RADEONOptions[] = {
@@ -162,6 +166,7 @@
     { OPTION_CLONE_VREFRESH, "CloneVRefresh",    OPTV_ANYSTR,  {0}, FALSE },
     { OPTION_FBDEV,          "UseFBDev",         OPTV_BOOLEAN, {0}, FALSE },
     { OPTION_VIDEO_KEY,      "VideoKey",         OPTV_INTEGER, {0}, FALSE },
+    { OPTION_DYN_PM,	     "DynamicPM",	 OPTV_ANYSTR,  {0}, FALSE },
     { -1,                    NULL,               OPTV_NONE,    {0}, FALSE }
 };
 
@@ -4021,6 +4026,7 @@
     RADEONInfoPtr  info  = RADEONPTR(pScrn);
     BoxRec         MemBox;
     int            y2;
+    char           *strptr;
 
     RADEONTRACE(("RADEONScreenInit %x %d\n",
 		 pScrn->memPhysBase, pScrn->fbOffset));
@@ -4423,6 +4429,32 @@
 	}
     }
 
+    /* power management stuff */
+    info->PowerManAlways = FALSE;
+    info->PowerManDPMS = FALSE;
+    info->PMActive = FALSE;
+    strptr = (char *)xf86GetOptValString(info->Options, OPTION_DYN_PM);
+    if(strptr) {
+    	if((!strcmp(strptr,"Always")) || (!strcmp(strptr,"always"))) {
+		if (!info->PMActive) {
+		    info->PowerManAlways = TRUE;
+		    RADEONPMEnableDynamicMode(pScrn);
+                    info->PMActive = TRUE;
+		}
+	}
+        else if((!strcmp(strptr,"DPMS")) || (!strcmp(strptr,"dpms"))) {
+		if (!info->PMActive) {
+                    info->PowerManDPMS = TRUE;
+		}
+        }
+        else {
+	        xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+	            "\"%s\" is not a valid parameter for Option \"DynamicPM\"\n", strptr);
+	    	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+	            "Valid parameters are \"Always\", or \"DPMS\"\n");
+	}
+    }
+
 				/* Acceleration setup */
     if (!xf86ReturnOptValBool(info->Options, OPTION_NOACCEL, FALSE)) {
 	if (RADEONAccelInit(pScreen)) {
@@ -6443,6 +6475,12 @@
 
     xf86ClearPrimInitDone(info->pEnt->index);
 
+    /* turn off power management */
+    if (info->PMActive) {
+	RADEONPMDisableDynamicMode(pScrn);
+	info->PMActive = FALSE;
+    }
+
     pScreen->BlockHandler = info->BlockHandler;
     pScreen->CloseScreen = info->CloseScreen;
     return (*pScreen->CloseScreen)(scrnIndex, pScreen);
@@ -6570,6 +6608,11 @@
 		    OUTREGP (RADEON_LVDS_GEN_CNTL, RADEON_LVDS_ON, ~RADEON_LVDS_ON);
 		}
 	    }
+		/* power management */
+            if (info->PowerManDPMS && info->PMActive) {
+                RADEONPMDisableDynamicMode(pScrn);
+		info->PMActive = FALSE;
+	    }
 	} else if ((PowerManagementMode == DPMSModeOff) ||
 		   (PowerManagementMode == DPMSModeSuspend) ||
 		   (PowerManagementMode == DPMSModeStandby)) {
@@ -6609,6 +6652,10 @@
 		    }
 		}
 	    }
+            if (info->PowerManDPMS && !info->PMActive) {
+                RADEONPMEnableDynamicMode(pScrn);
+		info->PMActive = TRUE;
+	    }
 	}
     }
 
@@ -6616,3 +6663,174 @@
     if (info->CPStarted) DRIUnlock(pScrn->pScreen);
 #endif
 }
+
+static void RADEONPMDisableDynamicMode(ScrnInfoPtr pScrn)
+{
+    RADEONInfoPtr  info   = RADEONPTR(pScrn); 
+    unsigned char *RADEONMMIO = info->MMIO;
+    unsigned long sclk_cntl;
+    unsigned long mclk_cntl;
+    unsigned long sclk_more_cntl;
+    unsigned long vclk_ecp_cntl;
+    unsigned long pixclks_cntl;
+
+    /* Mobility chips only */
+    if (!info->IsMobility)
+		return;
+	
+    /* Force Core Clocks */
+    sclk_cntl = INPLL(pScrn, RADEON_SCLK_CNTL);
+    sclk_cntl |= 	RADEON_SCLK_CNTL_M6__FORCE_CP|
+			RADEON_SCLK_CNTL_M6__FORCE_HDP|
+			RADEON_SCLK_CNTL_M6__FORCE_DISP1|
+			RADEON_SCLK_CNTL_M6__FORCE_DISP2|
+			RADEON_SCLK_CNTL_M6__FORCE_TOP|
+			RADEON_SCLK_CNTL_M6__FORCE_E2|
+			RADEON_SCLK_CNTL_M6__FORCE_SE|
+			RADEON_SCLK_CNTL_M6__FORCE_IDCT|
+			RADEON_SCLK_CNTL_M6__FORCE_VIP|
+			RADEON_SCLK_CNTL_M6__FORCE_RE|
+			RADEON_SCLK_CNTL_M6__FORCE_PB|
+			RADEON_SCLK_CNTL_M6__FORCE_TAM|
+			RADEON_SCLK_CNTL_M6__FORCE_TDM|
+			RADEON_SCLK_CNTL_M6__FORCE_RB|
+			RADEON_SCLK_CNTL_M6__FORCE_TV_SCLK|
+			RADEON_SCLK_CNTL_M6__FORCE_SUBPIC|
+			RADEON_SCLK_CNTL_M6__FORCE_OV0;
+    OUTPLL(RADEON_SCLK_CNTL, sclk_cntl);
+	
+	
+	
+    sclk_more_cntl = INPLL(pScrn, RADEON_SCLK_MORE_CNTL);
+    sclk_more_cntl |= 	        RADEON_SCLK_MORE_CNTL__FORCE_DISPREGS|
+				RADEON_SCLK_MORE_CNTL__FORCE_MC_GUI|
+				RADEON_SCLK_MORE_CNTL__FORCE_MC_HOST;	
+    OUTPLL(RADEON_SCLK_MORE_CNTL, sclk_more_cntl);
+	
+    /* Force Display clocks	*/
+    vclk_ecp_cntl = INPLL(pScrn, RADEON_VCLK_ECP_CNTL);
+    vclk_ecp_cntl &= ~(	RADEON_VCLK_ECP_CNTL__PIXCLK_ALWAYS_ONb |
+			 	RADEON_VCLK_ECP_CNTL__PIXCLK_DAC_ALWAYS_ONb);
+ 
+    OUTPLL(RADEON_VCLK_ECP_CNTL, vclk_ecp_cntl);
+	
+    pixclks_cntl = INPLL(pScrn, RADEON_PIXCLKS_CNTL);
+    pixclks_cntl &= ~(	        RADEON_PIXCLKS_CNTL__PIXCLK_GV_ALWAYS_ONb |
+			 	RADEON_PIXCLKS_CNTL__PIXCLK_BLEND_ALWAYS_ONb|
+				RADEON_PIXCLKS_CNTL__PIXCLK_DIG_TMDS_ALWAYS_ONb |
+				RADEON_PIXCLKS_CNTL__PIXCLK_LVDS_ALWAYS_ONb|
+				RADEON_PIXCLKS_CNTL__PIXCLK_TMDS_ALWAYS_ONb|
+				RADEON_PIXCLKS_CNTL__PIX2CLK_ALWAYS_ONb|
+				RADEON_PIXCLKS_CNTL__PIX2CLK_DAC_ALWAYS_ONb);
+						
+    OUTPLL(RADEON_PIXCLKS_CNTL, pixclks_cntl);
+
+    /* Force Memory Clocks */
+    mclk_cntl  = INPLL(pScrn, RADEON_MCLK_CNTL);
+    mclk_cntl |= 	RADEON_MCLK_CNTL_M6__FORCE_MCLKA|  
+			RADEON_MCLK_CNTL_M6__FORCE_MCLKB|	
+			RADEON_MCLK_CNTL_M6__FORCE_YCLKA|
+			RADEON_MCLK_CNTL_M6__FORCE_YCLKB;
+			
+    OUTPLL(RADEON_MCLK_CNTL, mclk_cntl);
+
+    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Dynamic Power Management Disabled\n");
+
+}
+
+static void RADEONPMEnableDynamicMode(ScrnInfoPtr pScrn)
+{
+    RADEONInfoPtr  info   = RADEONPTR(pScrn);
+    unsigned char *RADEONMMIO = info->MMIO;
+    unsigned long clk_pwrmgt_cntl;
+    unsigned long sclk_cntl;
+    unsigned long sclk_more_cntl;
+    unsigned long clk_pin_cntl;
+    unsigned long pixclks_cntl;
+    unsigned long vclk_ecp_cntl;
+    unsigned long mclk_cntl;
+    unsigned long mclk_misc;
+
+    /* Mobility chips only */
+    if (!info->IsMobility)
+                return;
+
+    /* Set Latencies */
+    clk_pwrmgt_cntl = INPLL(pScrn, RADEON_CLK_PWRMGT_CNTL_M6);
+	
+    clk_pwrmgt_cntl &= ~(	 RADEON_CLK_PWRMGT_CNTL_M6__ENGINE_DYNCLK_MODE_MASK|
+				 RADEON_CLK_PWRMGT_CNTL_M6__ACTIVE_HILO_LAT_MASK|
+				 RADEON_CLK_PWRMGT_CNTL_M6__DISP_DYN_STOP_LAT_MASK|
+				 RADEON_CLK_PWRMGT_CNTL_M6__DYN_STOP_MODE_MASK);
+    /* Mode 1 */
+    clk_pwrmgt_cntl = 	        RADEON_CLK_PWRMGT_CNTL_M6__MC_CH_MODE|
+				RADEON_CLK_PWRMGT_CNTL_M6__ENGINE_DYNCLK_MODE | 
+				(1<<RADEON_CLK_PWRMGT_CNTL_M6__ACTIVE_HILO_LAT__SHIFT) |
+				(0<<RADEON_CLK_PWRMGT_CNTL_M6__DISP_DYN_STOP_LAT__SHIFT)|
+				(0<<RADEON_CLK_PWRMGT_CNTL_M6__DYN_STOP_MODE__SHIFT);
+
+    OUTPLL(RADEON_CLK_PWRMGT_CNTL_M6, clk_pwrmgt_cntl);
+						
+
+    clk_pin_cntl = INPLL(pScrn, RADEON_CLK_PIN_CNTL);
+    clk_pin_cntl |= RADEON_CLK_PIN_CNTL__SCLK_DYN_START_CNTL;
+	 
+    OUTPLL(RADEON_CLK_PIN_CNTL, clk_pin_cntl);
+
+    /* Enable Dyanmic mode for SCLK */
+
+    sclk_cntl = INPLL(pScrn, RADEON_SCLK_CNTL);	
+    sclk_cntl &= RADEON_SCLK_CNTL_M6__SCLK_SRC_SEL_MASK;
+    sclk_cntl |= RADEON_SCLK_CNTL_M6__FORCE_VIP;		
+
+    OUTPLL(RADEON_SCLK_CNTL, sclk_cntl);
+
+
+    sclk_more_cntl = INPLL(pScrn, RADEON_SCLK_MORE_CNTL);
+    sclk_more_cntl &= ~(RADEON_SCLK_MORE_CNTL__FORCE_DISPREGS);
+				                    
+    OUTPLL(RADEON_SCLK_MORE_CNTL, sclk_more_cntl);
+
+	
+    /* Enable Dynamic mode for PIXCLK & PIX2CLK */
+
+    pixclks_cntl = INPLL(pScrn, RADEON_PIXCLKS_CNTL);
+	
+    pixclks_cntl|=      RADEON_PIXCLKS_CNTL__PIX2CLK_ALWAYS_ONb | 
+			RADEON_PIXCLKS_CNTL__PIX2CLK_DAC_ALWAYS_ONb|
+			RADEON_PIXCLKS_CNTL__PIXCLK_BLEND_ALWAYS_ONb|
+			RADEON_PIXCLKS_CNTL__PIXCLK_GV_ALWAYS_ONb|
+			RADEON_PIXCLKS_CNTL__PIXCLK_DIG_TMDS_ALWAYS_ONb|
+			RADEON_PIXCLKS_CNTL__PIXCLK_LVDS_ALWAYS_ONb|
+			RADEON_PIXCLKS_CNTL__PIXCLK_TMDS_ALWAYS_ONb;
+
+    OUTPLL(RADEON_PIXCLKS_CNTL, pixclks_cntl);
+		
+		
+    vclk_ecp_cntl = INPLL(pScrn, RADEON_VCLK_ECP_CNTL);
+	
+    vclk_ecp_cntl|=  RADEON_VCLK_ECP_CNTL__PIXCLK_ALWAYS_ONb | 
+			 RADEON_VCLK_ECP_CNTL__PIXCLK_DAC_ALWAYS_ONb;
+
+    OUTPLL(RADEON_VCLK_ECP_CNTL, vclk_ecp_cntl);
+
+
+    /* Enable Dynamic mode for MCLK	*/
+    mclk_cntl = INPLL(pScrn, RADEON_MCLK_CNTL);
+    mclk_cntl &= ~(	RADEON_MCLK_CNTL_M6__FORCE_MCLKA |  
+			RADEON_MCLK_CNTL_M6__FORCE_MCLKB |
+			RADEON_MCLK_CNTL_M6__FORCE_YCLKA |
+			RADEON_MCLK_CNTL_M6__FORCE_YCLKB );
+    OUTPLL(RADEON_MCLK_CNTL, mclk_cntl);
+
+    mclk_misc = INPLL(pScrn, RADEON_MCLK_MISC);
+    mclk_misc |= 	RADEON_MCLK_MISC__MC_MCLK_MAX_DYN_STOP_LAT|
+			RADEON_MCLK_MISC__IO_MCLK_MAX_DYN_STOP_LAT|
+			RADEON_MCLK_MISC__MC_MCLK_DYN_ENABLE|
+			RADEON_MCLK_MISC__IO_MCLK_DYN_ENABLE;	
+	
+    OUTPLL(RADEON_MCLK_MISC, mclk_misc);
+
+    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Dynamic Power Management Enabled\n");
+
+}
