aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorVille Syrjala <syrjala@sci.fi>2006-12-08 05:40:45 -0500
committerLinus Torvalds <torvalds@woody.osdl.org>2006-12-08 11:29:07 -0500
commitefc08a75d3a2d449edab7d1bee312eaa591f7669 (patch)
treea22c27c69cb226dd6e1fc9dc4c82f57cd81f289e /drivers
parent4ec3fd71e4f5d1201cb7d2374ffdb4f328091fb4 (diff)
[PATCH] atyfb: Improve power management
Some register were only set in aty_init() which is not called on resume. I added the aty_resume_chip() function to reset those registers on resume. Susped-to-ram now works on a HP Omnibook 6000 with acpi_sleep=s3_bios. Signed-off-by: Ville Syrjala <syrjala@sci.fi> Cc: "Antonino A. Daplas" <adaplas@pol.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/video/aty/atyfb.h2
-rw-r--r--drivers/video/aty/atyfb_base.c61
-rw-r--r--drivers/video/aty/mach64_ct.c39
3 files changed, 68 insertions, 34 deletions
diff --git a/drivers/video/aty/atyfb.h b/drivers/video/aty/atyfb.h
index c9b35c6b0b69..f72faff33c0c 100644
--- a/drivers/video/aty/atyfb.h
+++ b/drivers/video/aty/atyfb.h
@@ -185,6 +185,7 @@ struct atyfb_par {
185 int mtrr_aper; 185 int mtrr_aper;
186 int mtrr_reg; 186 int mtrr_reg;
187#endif 187#endif
188 u32 mem_cntl;
188}; 189};
189 190
190 /* 191 /*
@@ -314,6 +315,7 @@ struct aty_pll_ops {
314 void (*set_pll) (const struct fb_info * info, const union aty_pll * pll); 315 void (*set_pll) (const struct fb_info * info, const union aty_pll * pll);
315 void (*get_pll) (const struct fb_info *info, union aty_pll * pll); 316 void (*get_pll) (const struct fb_info *info, union aty_pll * pll);
316 int (*init_pll) (const struct fb_info * info, union aty_pll * pll); 317 int (*init_pll) (const struct fb_info * info, union aty_pll * pll);
318 void (*resume_pll)(const struct fb_info *info, union aty_pll *pll);
317}; 319};
318 320
319extern const struct aty_pll_ops aty_pll_ati18818_1; /* ATI 18818 */ 321extern const struct aty_pll_ops aty_pll_ati18818_1; /* ATI 18818 */
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index a9c73c257f3a..176f9b85cdbe 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -242,6 +242,7 @@ static int atyfb_sync(struct fb_info *info);
242 */ 242 */
243 243
244static int aty_init(struct fb_info *info); 244static int aty_init(struct fb_info *info);
245static void aty_resume_chip(struct fb_info *info);
245#ifdef CONFIG_ATARI 246#ifdef CONFIG_ATARI
246static int store_video_par(char *videopar, unsigned char m64_num); 247static int store_video_par(char *videopar, unsigned char m64_num);
247#endif 248#endif
@@ -1971,6 +1972,7 @@ static void atyfb_palette(int enter)
1971 1972
1972#if defined(CONFIG_PM) && defined(CONFIG_PCI) 1973#if defined(CONFIG_PM) && defined(CONFIG_PCI)
1973 1974
1975#ifdef CONFIG_PPC_PMAC
1974/* Power management routines. Those are used for PowerBook sleep. 1976/* Power management routines. Those are used for PowerBook sleep.
1975 */ 1977 */
1976static int aty_power_mgmt(int sleep, struct atyfb_par *par) 1978static int aty_power_mgmt(int sleep, struct atyfb_par *par)
@@ -2027,21 +2029,13 @@ static int aty_power_mgmt(int sleep, struct atyfb_par *par)
2027 2029
2028 return timeout ? 0 : -EIO; 2030 return timeout ? 0 : -EIO;
2029} 2031}
2032#endif
2030 2033
2031static int atyfb_pci_suspend(struct pci_dev *pdev, pm_message_t state) 2034static int atyfb_pci_suspend(struct pci_dev *pdev, pm_message_t state)
2032{ 2035{
2033 struct fb_info *info = pci_get_drvdata(pdev); 2036 struct fb_info *info = pci_get_drvdata(pdev);
2034 struct atyfb_par *par = (struct atyfb_par *) info->par; 2037 struct atyfb_par *par = (struct atyfb_par *) info->par;
2035 2038
2036#ifndef CONFIG_PPC_PMAC
2037 /* HACK ALERT ! Once I find a proper way to say to each driver
2038 * individually what will happen with it's PCI slot, I'll change
2039 * that. On laptops, the AGP slot is just unclocked, so D2 is
2040 * expected, while on desktops, the card is powered off
2041 */
2042 return 0;
2043#endif /* CONFIG_PPC_PMAC */
2044
2045 if (state.event == pdev->dev.power.power_state.event) 2039 if (state.event == pdev->dev.power.power_state.event)
2046 return 0; 2040 return 0;
2047 2041
@@ -2059,6 +2053,7 @@ static int atyfb_pci_suspend(struct pci_dev *pdev, pm_message_t state)
2059 par->asleep = 1; 2053 par->asleep = 1;
2060 par->lock_blank = 1; 2054 par->lock_blank = 1;
2061 2055
2056#ifdef CONFIG_PPC_PMAC
2062 /* Set chip to "suspend" mode */ 2057 /* Set chip to "suspend" mode */
2063 if (aty_power_mgmt(1, par)) { 2058 if (aty_power_mgmt(1, par)) {
2064 par->asleep = 0; 2059 par->asleep = 0;
@@ -2068,6 +2063,9 @@ static int atyfb_pci_suspend(struct pci_dev *pdev, pm_message_t state)
2068 release_console_sem(); 2063 release_console_sem();
2069 return -EIO; 2064 return -EIO;
2070 } 2065 }
2066#else
2067 pci_set_power_state(pdev, pci_choose_state(pdev, state));
2068#endif
2071 2069
2072 release_console_sem(); 2070 release_console_sem();
2073 2071
@@ -2086,8 +2084,15 @@ static int atyfb_pci_resume(struct pci_dev *pdev)
2086 2084
2087 acquire_console_sem(); 2085 acquire_console_sem();
2088 2086
2087#ifdef CONFIG_PPC_PMAC
2089 if (pdev->dev.power.power_state.event == 2) 2088 if (pdev->dev.power.power_state.event == 2)
2090 aty_power_mgmt(0, par); 2089 aty_power_mgmt(0, par);
2090#else
2091 pci_set_power_state(pdev, PCI_D0);
2092#endif
2093
2094 aty_resume_chip(info);
2095
2091 par->asleep = 0; 2096 par->asleep = 0;
2092 2097
2093 /* Restore display */ 2098 /* Restore display */
@@ -2339,7 +2344,6 @@ static int __devinit aty_init(struct fb_info *info)
2339 const char *ramname = NULL, *xtal; 2344 const char *ramname = NULL, *xtal;
2340 int gtb_memsize, has_var = 0; 2345 int gtb_memsize, has_var = 0;
2341 struct fb_var_screeninfo var; 2346 struct fb_var_screeninfo var;
2342 u32 i;
2343 2347
2344 init_waitqueue_head(&par->vblank.wait); 2348 init_waitqueue_head(&par->vblank.wait);
2345 spin_lock_init(&par->int_lock); 2349 spin_lock_init(&par->int_lock);
@@ -2470,10 +2474,10 @@ static int __devinit aty_init(struct fb_info *info)
2470 if(par->pll_ops->get_pll) 2474 if(par->pll_ops->get_pll)
2471 par->pll_ops->get_pll(info, &saved_pll); 2475 par->pll_ops->get_pll(info, &saved_pll);
2472 2476
2473 i = aty_ld_le32(MEM_CNTL, par); 2477 par->mem_cntl = aty_ld_le32(MEM_CNTL, par);
2474 gtb_memsize = M64_HAS(GTB_DSP); 2478 gtb_memsize = M64_HAS(GTB_DSP);
2475 if (gtb_memsize) 2479 if (gtb_memsize)
2476 switch (i & 0xF) { /* 0xF used instead of MEM_SIZE_ALIAS */ 2480 switch (par->mem_cntl & 0xF) { /* 0xF used instead of MEM_SIZE_ALIAS */
2477 case MEM_SIZE_512K: 2481 case MEM_SIZE_512K:
2478 info->fix.smem_len = 0x80000; 2482 info->fix.smem_len = 0x80000;
2479 break; 2483 break;
@@ -2495,7 +2499,7 @@ static int __devinit aty_init(struct fb_info *info)
2495 default: 2499 default:
2496 info->fix.smem_len = 0x80000; 2500 info->fix.smem_len = 0x80000;
2497 } else 2501 } else
2498 switch (i & MEM_SIZE_ALIAS) { 2502 switch (par->mem_cntl & MEM_SIZE_ALIAS) {
2499 case MEM_SIZE_512K: 2503 case MEM_SIZE_512K:
2500 info->fix.smem_len = 0x80000; 2504 info->fix.smem_len = 0x80000;
2501 break; 2505 break;
@@ -2525,20 +2529,20 @@ static int __devinit aty_init(struct fb_info *info)
2525 2529
2526 if (vram) { 2530 if (vram) {
2527 info->fix.smem_len = vram * 1024; 2531 info->fix.smem_len = vram * 1024;
2528 i = i & ~(gtb_memsize ? 0xF : MEM_SIZE_ALIAS); 2532 par->mem_cntl &= ~(gtb_memsize ? 0xF : MEM_SIZE_ALIAS);
2529 if (info->fix.smem_len <= 0x80000) 2533 if (info->fix.smem_len <= 0x80000)
2530 i |= MEM_SIZE_512K; 2534 par->mem_cntl |= MEM_SIZE_512K;
2531 else if (info->fix.smem_len <= 0x100000) 2535 else if (info->fix.smem_len <= 0x100000)
2532 i |= MEM_SIZE_1M; 2536 par->mem_cntl |= MEM_SIZE_1M;
2533 else if (info->fix.smem_len <= 0x200000) 2537 else if (info->fix.smem_len <= 0x200000)
2534 i |= gtb_memsize ? MEM_SIZE_2M_GTB : MEM_SIZE_2M; 2538 par->mem_cntl |= gtb_memsize ? MEM_SIZE_2M_GTB : MEM_SIZE_2M;
2535 else if (info->fix.smem_len <= 0x400000) 2539 else if (info->fix.smem_len <= 0x400000)
2536 i |= gtb_memsize ? MEM_SIZE_4M_GTB : MEM_SIZE_4M; 2540 par->mem_cntl |= gtb_memsize ? MEM_SIZE_4M_GTB : MEM_SIZE_4M;
2537 else if (info->fix.smem_len <= 0x600000) 2541 else if (info->fix.smem_len <= 0x600000)
2538 i |= gtb_memsize ? MEM_SIZE_6M_GTB : MEM_SIZE_6M; 2542 par->mem_cntl |= gtb_memsize ? MEM_SIZE_6M_GTB : MEM_SIZE_6M;
2539 else 2543 else
2540 i |= gtb_memsize ? MEM_SIZE_8M_GTB : MEM_SIZE_8M; 2544 par->mem_cntl |= gtb_memsize ? MEM_SIZE_8M_GTB : MEM_SIZE_8M;
2541 aty_st_le32(MEM_CNTL, i, par); 2545 aty_st_le32(MEM_CNTL, par->mem_cntl, par);
2542 } 2546 }
2543 2547
2544 /* 2548 /*
@@ -2584,6 +2588,8 @@ static int __devinit aty_init(struct fb_info *info)
2584#endif 2588#endif
2585 if(par->pll_ops->init_pll) 2589 if(par->pll_ops->init_pll)
2586 par->pll_ops->init_pll(info, &par->pll); 2590 par->pll_ops->init_pll(info, &par->pll);
2591 if (par->pll_ops->resume_pll)
2592 par->pll_ops->resume_pll(info, &par->pll);
2587 2593
2588 /* 2594 /*
2589 * Last page of 8 MB (4 MB on ISA) aperture is MMIO, 2595 * Last page of 8 MB (4 MB on ISA) aperture is MMIO,
@@ -2755,6 +2761,19 @@ aty_init_exit:
2755 return -1; 2761 return -1;
2756} 2762}
2757 2763
2764static void aty_resume_chip(struct fb_info *info)
2765{
2766 struct atyfb_par *par = info->par;
2767
2768 aty_st_le32(MEM_CNTL, par->mem_cntl, par);
2769
2770 if (par->pll_ops->resume_pll)
2771 par->pll_ops->resume_pll(info, &par->pll);
2772
2773 if (par->aux_start)
2774 aty_st_le32(BUS_CNTL, aty_ld_le32(BUS_CNTL, par) | BUS_APER_REG_DIS, par);
2775}
2776
2758#ifdef CONFIG_ATARI 2777#ifdef CONFIG_ATARI
2759static int __devinit store_video_par(char *video_str, unsigned char m64_num) 2778static int __devinit store_video_par(char *video_str, unsigned char m64_num)
2760{ 2779{
diff --git a/drivers/video/aty/mach64_ct.c b/drivers/video/aty/mach64_ct.c
index 10232cc2dc76..f3b487b8710b 100644
--- a/drivers/video/aty/mach64_ct.c
+++ b/drivers/video/aty/mach64_ct.c
@@ -398,8 +398,8 @@ static int __devinit aty_init_pll_ct(const struct fb_info *info,
398 union aty_pll *pll) 398 union aty_pll *pll)
399{ 399{
400 struct atyfb_par *par = (struct atyfb_par *) info->par; 400 struct atyfb_par *par = (struct atyfb_par *) info->par;
401 u8 mpost_div, xpost_div, sclk_post_div_real, sclk_fb_div, spll_cntl2; 401 u8 mpost_div, xpost_div, sclk_post_div_real;
402 u32 q, i, memcntl, trp; 402 u32 q, memcntl, trp;
403 u32 dsp_config, dsp_on_off, vga_dsp_config, vga_dsp_on_off; 403 u32 dsp_config, dsp_on_off, vga_dsp_config, vga_dsp_on_off;
404#ifdef DEBUG 404#ifdef DEBUG
405 int pllmclk, pllsclk; 405 int pllmclk, pllsclk;
@@ -575,14 +575,30 @@ static int __devinit aty_init_pll_ct(const struct fb_info *info,
575 mpost_div += (q < 32*8); 575 mpost_div += (q < 32*8);
576 } 576 }
577 sclk_post_div_real = postdividers[mpost_div]; 577 sclk_post_div_real = postdividers[mpost_div];
578 sclk_fb_div = q * sclk_post_div_real / 8; 578 pll->ct.sclk_fb_div = q * sclk_post_div_real / 8;
579 spll_cntl2 = mpost_div << 4; 579 pll->ct.spll_cntl2 = mpost_div << 4;
580#ifdef DEBUG 580#ifdef DEBUG
581 pllsclk = (1000000 * 2 * sclk_fb_div) / 581 pllsclk = (1000000 * 2 * pll->ct.sclk_fb_div) /
582 (par->ref_clk_per * pll->ct.pll_ref_div); 582 (par->ref_clk_per * pll->ct.pll_ref_div);
583 printk("atyfb(%s): use sclk, pllsclk=%d MHz, sclk=mclk=%d MHz\n", 583 printk("atyfb(%s): use sclk, pllsclk=%d MHz, sclk=mclk=%d MHz\n",
584 __FUNCTION__, pllsclk, pllsclk / sclk_post_div_real); 584 __FUNCTION__, pllsclk, pllsclk / sclk_post_div_real);
585#endif 585#endif
586 }
587
588 /* Disable the extra precision pixel clock controls since we do not use them. */
589 pll->ct.ext_vpll_cntl = aty_ld_pll_ct(EXT_VPLL_CNTL, par);
590 pll->ct.ext_vpll_cntl &= ~(EXT_VPLL_EN | EXT_VPLL_VGA_EN | EXT_VPLL_INSYNC);
591
592 return 0;
593}
594
595static void aty_resume_pll_ct(const struct fb_info *info,
596 union aty_pll *pll)
597{
598 struct atyfb_par *par = info->par;
599
600 if (par->mclk_per != par->xclk_per) {
601 int i;
586 /* 602 /*
587 * This disables the sclk, crashes the computer as reported: 603 * This disables the sclk, crashes the computer as reported:
588 * aty_st_pll_ct(SPLL_CNTL2, 3, info); 604 * aty_st_pll_ct(SPLL_CNTL2, 3, info);
@@ -590,8 +606,8 @@ static int __devinit aty_init_pll_ct(const struct fb_info *info,
590 * So it seems the sclk must be enabled before it is used; 606 * So it seems the sclk must be enabled before it is used;
591 * so PLL_GEN_CNTL must be programmed *after* the sclk. 607 * so PLL_GEN_CNTL must be programmed *after* the sclk.
592 */ 608 */
593 aty_st_pll_ct(SCLK_FB_DIV, sclk_fb_div, par); 609 aty_st_pll_ct(SCLK_FB_DIV, pll->ct.sclk_fb_div, par);
594 aty_st_pll_ct(SPLL_CNTL2, spll_cntl2, par); 610 aty_st_pll_ct(SPLL_CNTL2, pll->ct.spll_cntl2, par);
595 /* 611 /*
596 * The sclk has been started. However, I believe the first clock 612 * The sclk has been started. However, I believe the first clock
597 * ticks it generates are not very stable. Hope this primitive loop 613 * ticks it generates are not very stable. Hope this primitive loop
@@ -605,11 +621,7 @@ static int __devinit aty_init_pll_ct(const struct fb_info *info,
605 aty_st_pll_ct(PLL_GEN_CNTL, pll->ct.pll_gen_cntl, par); 621 aty_st_pll_ct(PLL_GEN_CNTL, pll->ct.pll_gen_cntl, par);
606 aty_st_pll_ct(MCLK_FB_DIV, pll->ct.mclk_fb_div, par); 622 aty_st_pll_ct(MCLK_FB_DIV, pll->ct.mclk_fb_div, par);
607 aty_st_pll_ct(PLL_EXT_CNTL, pll->ct.pll_ext_cntl, par); 623 aty_st_pll_ct(PLL_EXT_CNTL, pll->ct.pll_ext_cntl, par);
608 /* Disable the extra precision pixel clock controls since we do not use them. */ 624 aty_st_pll_ct(EXT_VPLL_CNTL, pll->ct.ext_vpll_cntl, par);
609 aty_st_pll_ct(EXT_VPLL_CNTL, aty_ld_pll_ct(EXT_VPLL_CNTL, par) &
610 ~(EXT_VPLL_EN | EXT_VPLL_VGA_EN | EXT_VPLL_INSYNC), par);
611
612 return 0;
613} 625}
614 626
615static int dummy(void) 627static int dummy(void)
@@ -626,5 +638,6 @@ const struct aty_pll_ops aty_pll_ct = {
626 .pll_to_var = aty_pll_to_var_ct, 638 .pll_to_var = aty_pll_to_var_ct,
627 .set_pll = aty_set_pll_ct, 639 .set_pll = aty_set_pll_ct,
628 .get_pll = aty_get_pll_ct, 640 .get_pll = aty_get_pll_ct,
629 .init_pll = aty_init_pll_ct 641 .init_pll = aty_init_pll_ct,
642 .resume_pll = aty_resume_pll_ct,
630}; 643};