DORMANTno replies

[PATCH 8/8] atyfb: Resume chip

From: syrjala@sci.fi
Date: 2005-03-17 03:07:55

This patch makes suspend-to-ram work on my HP OmniBook 6000 laptop when 
used with the acpi_sleep=s3_bios kernel option.

Some register were only set in aty_init() so I added the aty_resume_chip() 
function to reset those registers on resume.

Calling aty_power_mgmt() makes the suspend fail so I moved those calls 
under CONFIG_PMAC_PPC.

Signed-off-by: Ville Syrjala <syrjala@sci.fi>
---

 atyfb.h      |    2 ++
 atyfb_base.c |   56 +++++++++++++++++++++++++++++++++++++++++++-------------
 mach64_ct.c  |   49 ++++++++++++++++++++++++++++++++-----------------
 3 files changed, 77 insertions(+), 30 deletions(-)

diff -urN linux/drivers/video/aty/atyfb_base.c linux/drivers/video/aty/atyfb_base.c
--- linux/drivers/video/aty/atyfb_base.c	2005-03-16 19:37:14.000000000 +0200
+++ linux/drivers/video/aty/atyfb_base.c	2005-03-16 20:02:44.000000000 +0200
@@ -253,6 +253,7 @@
      */
 
 static int aty_init(struct fb_info *info, const char *name);
+static int aty_resume_chip(struct fb_info *info);
 #ifdef CONFIG_ATARI
 static int store_video_par(char *videopar, unsigned char m64_num);
 #endif
@@ -1992,6 +1993,7 @@
 
 #if defined(CONFIG_PM) && defined(CONFIG_PCI)
 
+#ifdef CONFIG_PPC_PMAC
 /* Power management routines. Those are used for PowerBook sleep.
  */
 static int aty_power_mgmt(int sleep, struct atyfb_par *par)
@@ -2048,6 +2050,7 @@
 
 	return timeout ? 0 : -EIO;
 }
+#endif
 
 static int atyfb_pci_suspend(struct pci_dev *pdev, pm_message_t state)
 {
@@ -2062,9 +2065,12 @@
 	 */
 	if (state >= 3)
 		state = 2;
+
+	if (state != 2)
+		return 0;
 #endif /* CONFIG_PPC_PMAC */
 
-	if (state != 2 || state == pdev->dev.power.power_state)
+	if (state == pdev->dev.power.power_state)
 		return 0;
 
 	acquire_console_sem();
@@ -2081,6 +2087,7 @@
 	par->asleep = 1;
 	par->lock_blank = 1;
 
+#ifdef CONFIG_PPC_PMAC
 	/* Set chip to "suspend" mode */
 	if (aty_power_mgmt(1, par)) {
 		par->asleep = 0;
@@ -2090,6 +2097,7 @@
 		release_console_sem();
 		return -EIO;
 	}
+#endif
 
 	release_console_sem();
 
@@ -2108,8 +2116,12 @@
 
 	acquire_console_sem();
 
+#ifdef CONFIG_PPC_PMAC
 	if (pdev->dev.power.power_state == 2)
 		aty_power_mgmt(0, par);
+#else
+	aty_resume_chip(info);
+#endif
 	par->asleep = 0;
 
 	/* Restore display */
@@ -2211,7 +2223,6 @@
 	int gtb_memsize;
 	struct fb_var_screeninfo var;
 	u8 pll_ref_div;
-	u32 i;
 #if defined(CONFIG_PPC)
 	int sense;
 #endif
@@ -2344,10 +2355,10 @@
 	if(par->pll_ops->get_pll)
 		par->pll_ops->get_pll(info, &saved_pll);
 
-	i = aty_ld_le32(MEM_CNTL, par);
+	par->mem_cntl = aty_ld_le32(MEM_CNTL, par);
 	gtb_memsize = M64_HAS(GTB_DSP);
 	if (gtb_memsize)
-		switch (i & 0xF) {	/* 0xF used instead of MEM_SIZE_ALIAS */
+		switch (par->mem_cntl & 0xF) {	/* 0xF used instead of MEM_SIZE_ALIAS */
 		case MEM_SIZE_512K:
 			info->fix.smem_len = 0x80000;
 			break;
@@ -2369,7 +2380,7 @@
 		default:
 			info->fix.smem_len = 0x80000;
 	} else
-		switch (i & MEM_SIZE_ALIAS) {
+		switch (par->mem_cntl & MEM_SIZE_ALIAS) {
 		case MEM_SIZE_512K:
 			info->fix.smem_len = 0x80000;
 			break;
@@ -2399,20 +2410,20 @@
 
 	if (vram) {
 		info->fix.smem_len = vram * 1024;
-		i = i & ~(gtb_memsize ? 0xF : MEM_SIZE_ALIAS);
+		par->mem_cntl = par->mem_cntl & ~(gtb_memsize ? 0xF : MEM_SIZE_ALIAS);
 		if (info->fix.smem_len <= 0x80000)
-			i |= MEM_SIZE_512K;
+			par->mem_cntl |= MEM_SIZE_512K;
 		else if (info->fix.smem_len <= 0x100000)
-			i |= MEM_SIZE_1M;
+			par->mem_cntl |= MEM_SIZE_1M;
 		else if (info->fix.smem_len <= 0x200000)
-			i |= gtb_memsize ? MEM_SIZE_2M_GTB : MEM_SIZE_2M;
+			par->mem_cntl |= gtb_memsize ? MEM_SIZE_2M_GTB : MEM_SIZE_2M;
 		else if (info->fix.smem_len <= 0x400000)
-			i |= gtb_memsize ? MEM_SIZE_4M_GTB : MEM_SIZE_4M;
+			par->mem_cntl |= gtb_memsize ? MEM_SIZE_4M_GTB : MEM_SIZE_4M;
 		else if (info->fix.smem_len <= 0x600000)
-			i |= gtb_memsize ? MEM_SIZE_6M_GTB : MEM_SIZE_6M;
+			par->mem_cntl |= gtb_memsize ? MEM_SIZE_6M_GTB : MEM_SIZE_6M;
 		else
-			i |= gtb_memsize ? MEM_SIZE_8M_GTB : MEM_SIZE_8M;
-		aty_st_le32(MEM_CNTL, i, par);
+			par->mem_cntl |= gtb_memsize ? MEM_SIZE_8M_GTB : MEM_SIZE_8M;
+		aty_st_le32(MEM_CNTL, par->mem_cntl, par);
 	}
 
 	/*
@@ -2458,6 +2469,8 @@
 #endif
 	if(par->pll_ops->init_pll)
 		par->pll_ops->init_pll(info, &par->pll);
+	if(par->pll_ops->resume_pll)
+		par->pll_ops->resume_pll(info, &par->pll);
 
 	/*
 	 *  Last page of 8 MB (4 MB on ISA) aperture is MMIO
@@ -2611,6 +2624,23 @@
 	return -1;
 }
 
+static int aty_resume_chip(struct fb_info *info)
+{
+	struct atyfb_par *par = (struct atyfb_par *) info->par;
+	int gtb_memsize;
+	u32 i;
+
+	aty_st_le32(MEM_CNTL, par->mem_cntl, par);
+
+	if(par->pll_ops->resume_pll)
+		par->pll_ops->resume_pll(info, &par->pll);
+
+	if (par->aux_start)
+		aty_st_le32(BUS_CNTL, aty_ld_le32(BUS_CNTL, par) | BUS_APER_REG_DIS, par);
+
+	return 0;
+}
+
 #ifdef CONFIG_ATARI
 static int __init store_video_par(char *video_str, unsigned char m64_num)
 {
diff -urN linux/drivers/video/aty/atyfb.h linux/drivers/video/aty/atyfb.h
--- linux/drivers/video/aty/atyfb.h	2005-03-16 19:27:41.000000000 +0200
+++ linux/drivers/video/aty/atyfb.h	2005-03-16 19:51:24.000000000 +0200
@@ -186,6 +186,7 @@
 	int mtrr_aper;
 	int mtrr_reg;
 #endif
+	u32 mem_cntl;
 };
 
     /*
@@ -315,6 +316,7 @@
 	void (*set_pll)   (const struct fb_info * info, const union aty_pll * pll);
 	void (*get_pll)   (const struct fb_info *info, union aty_pll * pll);
 	int (*init_pll)   (const struct fb_info * info, union aty_pll * pll);
+	int (*resume_pll) (const struct fb_info * info, union aty_pll * pll);
 };
 
 extern const struct aty_pll_ops aty_pll_ati18818_1; /* ATI 18818 */
diff -urN linux/drivers/video/aty/mach64_ct.c linux/drivers/video/aty/mach64_ct.c
--- linux/drivers/video/aty/mach64_ct.c	2005-03-16 19:42:53.000000000 +0200
+++ linux/drivers/video/aty/mach64_ct.c	2005-03-16 19:56:49.000000000 +0200
@@ -398,8 +398,8 @@
 				 union aty_pll *pll)
 {
 	struct atyfb_par *par = (struct atyfb_par *) info->par;
-	u8 mpost_div, xpost_div, sclk_post_div_real, sclk_fb_div, spll_cntl2;
-	u32 q, i, memcntl, trp;
+	u8 mpost_div, xpost_div, sclk_post_div_real;
+	u32 q, memcntl, trp;
 	u32 dsp_config, dsp_on_off, vga_dsp_config, vga_dsp_on_off;
 #ifdef DEBUG
 	int pllmclk, pllsclk;
@@ -575,23 +575,39 @@
 			mpost_div += (q <  32*8);
 		}
 		sclk_post_div_real = postdividers[mpost_div];
-		sclk_fb_div = q * sclk_post_div_real / 8;
-		spll_cntl2 = mpost_div << 4;
+		pll->ct.sclk_fb_div = q * sclk_post_div_real / 8;
+		pll->ct.spll_cntl2 = mpost_div << 4;
 #ifdef DEBUG
-		pllsclk = (1000000 * 2 * sclk_fb_div) /
+		pllsclk = (1000000 * 2 * pll->ct.sclk_fb_div) /
 			(par->ref_clk_per * pll->ct.pll_ref_div);
 		printk("atyfb(%s): use sclk, pllsclk=%d MHz, sclk=mclk=%d MHz\n",
 			__FUNCTION__, pllsclk, pllsclk / sclk_post_div_real);
 #endif
+	}
+
+	/* Disable the extra precision pixel clock controls since we do not use them. */
+	pll->ct.ext_vpll_cntl = aty_ld_pll_ct(EXT_VPLL_CNTL, par);
+	pll->ct.ext_vpll_cntl &= ~(EXT_VPLL_EN | EXT_VPLL_VGA_EN | EXT_VPLL_INSYNC);
+
+	return 0;
+}
+
+static int __init aty_resume_pll_ct(const struct fb_info *info,
+				    union aty_pll *pll)
+{
+	struct atyfb_par *par = (struct atyfb_par *) info->par;
+
+	if (par->mclk_per != par->xclk_per) {
+		int i;
 		/*
-		* This disables the sclk, crashes the computer as reported:
-		* aty_st_pll_ct(SPLL_CNTL2, 3, info);
-		*
-		* So it seems the sclk must be enabled before it is used;
-		* so PLL_GEN_CNTL must be programmed *after* the sclk.
-		*/
-		aty_st_pll_ct(SCLK_FB_DIV, sclk_fb_div, par);
-		aty_st_pll_ct(SPLL_CNTL2, spll_cntl2, par);
+		 * This disables the sclk, crashes the computer as reported:
+		 * aty_st_pll_ct(SPLL_CNTL2, 3, info);
+		 *
+		 * So it seems the sclk must be enabled before it is used;
+		 * so PLL_GEN_CNTL must be programmed *after* the sclk.
+		 */
+		aty_st_pll_ct(SCLK_FB_DIV, pll->ct.sclk_fb_div, par);
+		aty_st_pll_ct(SPLL_CNTL2, pll->ct.spll_cntl2, par);
 		/*
 		 * The sclk has been started. However, I believe the first clock
 		 * ticks it generates are not very stable. Hope this primitive loop
@@ -605,9 +621,7 @@
 	aty_st_pll_ct(PLL_GEN_CNTL, pll->ct.pll_gen_cntl, par);
 	aty_st_pll_ct(MCLK_FB_DIV, pll->ct.mclk_fb_div, par);
 	aty_st_pll_ct(PLL_EXT_CNTL, pll->ct.pll_ext_cntl, par);
-	/* Disable the extra precision pixel clock controls since we do not use them. */
-	aty_st_pll_ct(EXT_VPLL_CNTL, aty_ld_pll_ct(EXT_VPLL_CNTL, par) &
-		~(EXT_VPLL_EN | EXT_VPLL_VGA_EN | EXT_VPLL_INSYNC), par);
+	aty_st_pll_ct(EXT_VPLL_CNTL, pll->ct.ext_vpll_cntl, par);
 
 	return 0;
 }
@@ -626,5 +640,6 @@
 	.pll_to_var	= aty_pll_to_var_ct,
 	.set_pll	= aty_set_pll_ct,
 	.get_pll	= aty_get_pll_ct,
-	.init_pll       = aty_init_pll_ct
+	.init_pll	= aty_init_pll_ct,
+	.resume_pll	= aty_resume_pll_ct,
 };



-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help