ft232: support the ASYNC_LOW_LATENCY flag
[safe/jmp/linux-2.6] / drivers / video / aty / mach64_ct.c
index 9bdb2aa..2745b85 100644 (file)
@@ -8,6 +8,9 @@
 #include <asm/io.h>
 #include <video/mach64.h>
 #include "atyfb.h"
+#ifdef CONFIG_PPC
+#include <asm/machdep.h>
+#endif
 
 #undef DEBUG
 
@@ -27,7 +30,7 @@ u8 aty_ld_pll_ct(int offset, const struct atyfb_par *par)
        return res;
 }
 
-void aty_st_pll_ct(int offset, u8 val, const struct atyfb_par *par)
+static void aty_st_pll_ct(int offset, u8 val, const struct atyfb_par *par)
 {
        /* write addr byte */
        aty_st_8(CLOCK_CNTL_ADDR, ((offset << 2) & PLL_ADDR) | PLL_WR_EN, par);
@@ -197,7 +200,7 @@ static int aty_dsp_gt(const struct fb_info *info, u32 bpp, struct pll_ct *pll)
        pll->dsp_config = (dsp_precision << 20) | (pll->dsp_loop_latency << 16) | dsp_xclks;
 #ifdef DEBUG
        printk("atyfb(%s): dsp_config 0x%08x, dsp_on_off 0x%08x\n",
-               __FUNCTION__, pll->dsp_config, pll->dsp_on_off);
+               __func__, pll->dsp_config, pll->dsp_on_off);
 #endif
        return 0;
 }
@@ -206,9 +209,7 @@ static int aty_valid_pll_ct(const struct fb_info *info, u32 vclk_per, struct pll
 {
        u32 q;
        struct atyfb_par *par = (struct atyfb_par *) info->par;
-#ifdef DEBUG
        int pllvclk;
-#endif
 
        /* FIXME: use the VTB/GTB /{3,6,12} post dividers if they're better suited */
        q = par->ref_clk_per * pll->pll_ref_div * 4 / vclk_per;
@@ -223,13 +224,26 @@ static int aty_valid_pll_ct(const struct fb_info *info, u32 vclk_per, struct pll
        pll->vclk_post_div_real = postdividers[pll->vclk_post_div];
        //    pll->vclk_post_div <<= 6;
        pll->vclk_fb_div = q * pll->vclk_post_div_real / 8;
-#ifdef DEBUG
        pllvclk = (1000000 * 2 * pll->vclk_fb_div) /
                (par->ref_clk_per * pll->pll_ref_div);
+#ifdef DEBUG
        printk("atyfb(%s): pllvclk=%d MHz, vclk=%d MHz\n",
-               __FUNCTION__, pllvclk, pllvclk / pll->vclk_post_div_real);
+               __func__, pllvclk, pllvclk / pll->vclk_post_div_real);
 #endif
        pll->pll_vclk_cntl = 0x03; /* VCLK = PLL_VCLK/VCLKx_POST */
+
+       /* Set ECP (scaler/overlay clock) divider */
+       if (par->pll_limits.ecp_max) {
+               int ecp = pllvclk / pll->vclk_post_div_real;
+               int ecp_div = 0;
+
+               while (ecp > par->pll_limits.ecp_max && ecp_div < 2) {
+                       ecp >>= 1;
+                       ecp_div++;
+               }
+               pll->pll_vclk_cntl |= ecp_div << 4;
+       }
+
        return 0;
 }
 
@@ -258,7 +272,7 @@ static u32 aty_pll_to_var_ct(const struct fb_info *info, const union aty_pll *pl
        }
 #endif
 #ifdef DEBUG
-       printk("atyfb(%s): calculated 0x%08X(%i)\n", __FUNCTION__, ret, ret);
+       printk("atyfb(%s): calculated 0x%08X(%i)\n", __func__, ret, ret);
 #endif
        return ret;
 }
@@ -273,11 +287,11 @@ void aty_set_pll_ct(const struct fb_info *info, const union aty_pll *pll)
 #ifdef DEBUG
        printk("atyfb(%s): about to program:\n"
                "pll_ext_cntl=0x%02x pll_gen_cntl=0x%02x pll_vclk_cntl=0x%02x\n",
-               __FUNCTION__,
+               __func__,
                pll->ct.pll_ext_cntl, pll->ct.pll_gen_cntl, pll->ct.pll_vclk_cntl);
 
        printk("atyfb(%s): setting clock %lu for FeedBackDivider %i, ReferenceDivider %i, PostDivider %i(%i)\n",
-               __FUNCTION__,
+               __func__,
                par->clk_wr_offset, pll->ct.vclk_fb_div,
                pll->ct.pll_ref_div, pll->ct.vclk_post_div, pll->ct.vclk_post_div_real);
 #endif
@@ -359,8 +373,8 @@ void aty_set_pll_ct(const struct fb_info *info, const union aty_pll *pll)
 #endif
 }
 
-static void __init aty_get_pll_ct(const struct fb_info *info,
-                                 union aty_pll *pll)
+static void __devinit aty_get_pll_ct(const struct fb_info *info,
+                                    union aty_pll *pll)
 {
        struct atyfb_par *par = (struct atyfb_par *) info->par;
        u8 tmp, clock;
@@ -383,12 +397,12 @@ static void __init aty_get_pll_ct(const struct fb_info *info,
        }
 }
 
-static int __init aty_init_pll_ct(const struct fb_info *info,
-                                union aty_pll *pll)
+static int __devinit aty_init_pll_ct(const struct fb_info *info,
+                                    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;
@@ -417,7 +431,7 @@ static int __init aty_init_pll_ct(const struct fb_info *info,
 
 #ifdef DEBUG
        printk("atyfb(%s): mclk_fb_mult=%d, xclk_post_div=%d\n",
-               __FUNCTION__, pll->ct.mclk_fb_mult, pll->ct.xclk_post_div);
+               __func__, pll->ct.mclk_fb_mult, pll->ct.xclk_post_div);
 #endif
 
        memcntl = aty_ld_le32(MEM_CNTL, par);
@@ -525,11 +539,19 @@ static int __init aty_init_pll_ct(const struct fb_info *info,
        pll->ct.xclk_post_div_real = postdividers[xpost_div];
        pll->ct.mclk_fb_div = q * pll->ct.xclk_post_div_real / 8;
 
+#ifdef CONFIG_PPC
+       if (machine_is(powermac)) {
+               /* Override PLL_EXT_CNTL & 0x07. */
+               pll->ct.xclk_post_div = xpost_div;
+               pll->ct.xclk_ref_div = 1;
+       }
+#endif
+
 #ifdef DEBUG
        pllmclk = (1000000 * pll->ct.mclk_fb_mult * pll->ct.mclk_fb_div) /
                        (par->ref_clk_per * pll->ct.pll_ref_div);
        printk("atyfb(%s): pllmclk=%d MHz, xclk=%d MHz\n",
-               __FUNCTION__, pllmclk, pllmclk / pll->ct.xclk_post_div_real);
+               __func__, pllmclk, pllmclk / pll->ct.xclk_post_div_real);
 #endif
 
        if (M64_HAS(SDRAM_MAGIC_PLL) && (par->ram_type >= SDRAM))
@@ -564,14 +586,29 @@ static int __init aty_init_pll_ct(const struct fb_info *info,
                        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);
+                       __func__, 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 void aty_resume_pll_ct(const struct fb_info *info,
+                             union aty_pll *pll)
+{
+       struct atyfb_par *par = info->par;
+
+       if (par->mclk_per != par->xclk_per) {
                /*
                * This disables the sclk, crashes the computer as reported:
                * aty_st_pll_ct(SPLL_CNTL2, 3, info);
@@ -579,26 +616,20 @@ static int __init aty_init_pll_ct(const struct fb_info *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);
+               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
-                * helps for Rage Mobilities that sometimes crash when
-                * we switch to sclk. (Daniel Mantione, 13-05-2003)
+                * SCLK has been started. Wait for the PLL to lock. 5 ms
+                * should be enough according to mach64 programmer's guide.
                 */
-               for (i=0;i<=0x1ffff;i++);
+               mdelay(5);
        }
 
        aty_st_pll_ct(PLL_REF_DIV, pll->ct.pll_ref_div, par);
        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);
-
-       return 0;
+       aty_st_pll_ct(EXT_VPLL_CNTL, pll->ct.ext_vpll_cntl, par);
 }
 
 static int dummy(void)
@@ -615,5 +646,6 @@ const struct aty_pll_ops aty_pll_ct = {
        .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,
 };