mach64_ct.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:7k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  *  ATI Mach64 CT/VT/GT/LT Support
  3.  */
  4. #include <linux/fb.h>
  5. #include <asm/io.h>
  6. #include <video/fbcon.h>
  7. #include "mach64.h"
  8. #include "atyfb.h"
  9. /* FIXME: remove the FAIL definition */
  10. #define FAIL(x) do { printk(x "n"); return -EINVAL; } while (0)
  11. static void aty_st_pll(int offset, u8 val, const struct fb_info_aty *info);
  12. static int aty_valid_pll_ct(const struct fb_info_aty *info, u32 vclk_per,
  13.     struct pll_ct *pll);
  14. static int aty_dsp_gt(const struct fb_info_aty *info, u8 bpp,
  15.       struct pll_ct *pll);
  16. static int aty_var_to_pll_ct(const struct fb_info_aty *info, u32 vclk_per,
  17.      u8 bpp, union aty_pll *pll);
  18. static u32 aty_pll_ct_to_var(const struct fb_info_aty *info,
  19.      const union aty_pll *pll);
  20. static void aty_st_pll(int offset, u8 val, const struct fb_info_aty *info)
  21. {
  22.     /* write addr byte */
  23.     aty_st_8(CLOCK_CNTL + 1, (offset << 2) | PLL_WR_EN, info);
  24.     /* write the register value */
  25.     aty_st_8(CLOCK_CNTL + 2, val, info);
  26.     aty_st_8(CLOCK_CNTL + 1, (offset << 2) & ~PLL_WR_EN, info);
  27. }
  28. /* ------------------------------------------------------------------------- */
  29.     /*
  30.      *  PLL programming (Mach64 CT family)
  31.      */
  32. static int aty_dsp_gt(const struct fb_info_aty *info, u8 bpp,
  33.       struct pll_ct *pll)
  34. {
  35.     u32 dsp_xclks_per_row, dsp_loop_latency, dsp_precision, dsp_off, dsp_on;
  36.     u32 xclks_per_row, fifo_off, fifo_on, y, fifo_size, page_size;
  37.     /* xclocks_per_row<<11 */
  38.     xclks_per_row = (pll->mclk_fb_div*pll->vclk_post_div_real*64<<11)/
  39.     (pll->vclk_fb_div*pll->mclk_post_div_real*bpp);
  40.     if (xclks_per_row < (1<<11))
  41. FAIL("Dotclock to high");
  42.     if (M64_HAS(FIFO_24)) {
  43. fifo_size = 24;
  44. dsp_loop_latency = 0;
  45.     } else {
  46. fifo_size = 32;
  47. dsp_loop_latency = 2;
  48.     }
  49.     dsp_precision = 0;
  50.     y = (xclks_per_row*fifo_size)>>11;
  51.     while (y) {
  52. y >>= 1;
  53. dsp_precision++;
  54.     }
  55.     dsp_precision -= 5;
  56.     /* fifo_off<<6 */
  57.     fifo_off = ((xclks_per_row*(fifo_size-1))>>5)+(3<<6);
  58.     if (info->total_vram > 1*1024*1024) {
  59. if (info->ram_type >= SDRAM) {
  60.     /* >1 MB SDRAM */
  61.     dsp_loop_latency += 8;
  62.     page_size = 8;
  63. } else {
  64.     /* >1 MB DRAM */
  65.     dsp_loop_latency += 6;
  66.     page_size = 9;
  67. }
  68.     } else {
  69. if (info->ram_type >= SDRAM) {
  70.     /* <2 MB SDRAM */
  71.     dsp_loop_latency += 9;
  72.     page_size = 10;
  73. } else {
  74.     /* <2 MB DRAM */
  75.     dsp_loop_latency += 8;
  76.     page_size = 10;
  77. }
  78.     }
  79.     /* fifo_on<<6 */
  80.     if (xclks_per_row >= (page_size<<11))
  81. fifo_on = ((2*page_size+1)<<6)+(xclks_per_row>>5);
  82.     else
  83. fifo_on = (3*page_size+2)<<6;
  84.     dsp_xclks_per_row = xclks_per_row>>dsp_precision;
  85.     dsp_on = fifo_on>>dsp_precision;
  86.     dsp_off = fifo_off>>dsp_precision;
  87.     pll->dsp_config = (dsp_xclks_per_row & 0x3fff) |
  88.       ((dsp_loop_latency & 0xf)<<16) |
  89.       ((dsp_precision & 7)<<20);
  90.     pll->dsp_on_off = (dsp_on & 0x7ff) | ((dsp_off & 0x7ff)<<16);
  91.     return 0;
  92. }
  93. static int aty_valid_pll_ct(const struct fb_info_aty *info, u32 vclk_per,
  94.     struct pll_ct *pll)
  95. {
  96.     u32 q, x; /* x is a workaround for sparc64-linux-gcc */
  97.     x = x; /* x is a workaround for sparc64-linux-gcc */
  98.     pll->pll_ref_div = info->pll_per*2*255/info->ref_clk_per;
  99.     /* FIXME: use the VTB/GTB /3 post divider if it's better suited */
  100.     q = info->ref_clk_per*pll->pll_ref_div*4/info->mclk_per; /* actually 8*q */
  101.     if (q < 16*8 || q > 255*8)
  102. FAIL("mclk out of range");
  103.     else if (q < 32*8)
  104. pll->mclk_post_div_real = 8;
  105.     else if (q < 64*8)
  106. pll->mclk_post_div_real = 4;
  107.     else if (q < 128*8)
  108. pll->mclk_post_div_real = 2;
  109.     else
  110. pll->mclk_post_div_real = 1;
  111.     pll->mclk_fb_div = q*pll->mclk_post_div_real/8;
  112.     /* FIXME: use the VTB/GTB /{3,6,12} post dividers if they're better suited */
  113.     q = info->ref_clk_per*pll->pll_ref_div*4/vclk_per; /* actually 8*q */
  114.     if (q < 16*8 || q > 255*8)
  115. FAIL("vclk out of range");
  116.     else if (q < 32*8)
  117. pll->vclk_post_div_real = 8;
  118.     else if (q < 64*8)
  119. pll->vclk_post_div_real = 4;
  120.     else if (q < 128*8)
  121. pll->vclk_post_div_real = 2;
  122.     else
  123. pll->vclk_post_div_real = 1;
  124.     pll->vclk_fb_div = q*pll->vclk_post_div_real/8;
  125.     return 0;
  126. }
  127. void aty_calc_pll_ct(const struct fb_info_aty *info, struct pll_ct *pll)
  128. {
  129.     u8 mpostdiv = 0;
  130.     u8 vpostdiv = 0;
  131.     if (M64_HAS(SDRAM_MAGIC_PLL) && (info->ram_type >= SDRAM))
  132. pll->pll_gen_cntl = 0x04;
  133.     else
  134. pll->pll_gen_cntl = 0x84;
  135.     switch (pll->mclk_post_div_real) {
  136. case 1:
  137.     mpostdiv = 0;
  138.     break;
  139. case 2:
  140.     mpostdiv = 1;
  141.     break;
  142. case 3:
  143.     mpostdiv = 4;
  144.     break;
  145. case 4:
  146.     mpostdiv = 2;
  147.     break;
  148. case 8:
  149.     mpostdiv = 3;
  150.     break;
  151.     }
  152.     pll->pll_gen_cntl |= mpostdiv<<4; /* mclk */
  153.     if (M64_HAS(MAGIC_POSTDIV))
  154. pll->pll_ext_cntl = 0;
  155.     else
  156.      pll->pll_ext_cntl = mpostdiv; /* xclk == mclk */
  157.     switch (pll->vclk_post_div_real) {
  158. case 2:
  159.     vpostdiv = 1;
  160.     break;
  161. case 3:
  162.     pll->pll_ext_cntl |= 0x10;
  163. case 1:
  164.     vpostdiv = 0;
  165.     break;
  166. case 6:
  167.     pll->pll_ext_cntl |= 0x10;
  168. case 4:
  169.     vpostdiv = 2;
  170.     break;
  171. case 12:
  172.     pll->pll_ext_cntl |= 0x10;
  173. case 8:
  174.     vpostdiv = 3;
  175.     break;
  176.     }
  177.     pll->pll_vclk_cntl = 0x03; /* VCLK = PLL_VCLK/VCLKx_POST */
  178.     pll->vclk_post_div = vpostdiv;
  179. }
  180. static int aty_var_to_pll_ct(const struct fb_info_aty *info, u32 vclk_per,
  181.      u8 bpp, union aty_pll *pll)
  182. {
  183.     int err;
  184.     if ((err = aty_valid_pll_ct(info, vclk_per, &pll->ct)))
  185. return err;
  186.     if (M64_HAS(GTB_DSP) && (err = aty_dsp_gt(info, bpp, &pll->ct)))
  187. return err;
  188.     aty_calc_pll_ct(info, &pll->ct);
  189.     return 0;
  190. }
  191. static u32 aty_pll_ct_to_var(const struct fb_info_aty *info,
  192.      const union aty_pll *pll)
  193. {
  194.     u32 ref_clk_per = info->ref_clk_per;
  195.     u8 pll_ref_div = pll->ct.pll_ref_div;
  196.     u8 vclk_fb_div = pll->ct.vclk_fb_div;
  197.     u8 vclk_post_div = pll->ct.vclk_post_div_real;
  198.     return ref_clk_per*pll_ref_div*vclk_post_div/vclk_fb_div/2;
  199. }
  200. void aty_set_pll_ct(const struct fb_info_aty *info, const union aty_pll *pll)
  201. {
  202.     aty_st_pll(PLL_REF_DIV, pll->ct.pll_ref_div, info);
  203.     aty_st_pll(PLL_GEN_CNTL, pll->ct.pll_gen_cntl, info);
  204.     aty_st_pll(MCLK_FB_DIV, pll->ct.mclk_fb_div, info);
  205.     aty_st_pll(PLL_VCLK_CNTL, pll->ct.pll_vclk_cntl, info);
  206.     aty_st_pll(VCLK_POST_DIV, pll->ct.vclk_post_div, info);
  207.     aty_st_pll(VCLK0_FB_DIV, pll->ct.vclk_fb_div, info);
  208.     aty_st_pll(PLL_EXT_CNTL, pll->ct.pll_ext_cntl, info);
  209.     if (M64_HAS(GTB_DSP)) {
  210. if (M64_HAS(XL_DLL))
  211.     aty_st_pll(DLL_CNTL, 0x80, info);
  212. else if (info->ram_type >= SDRAM)
  213.     aty_st_pll(DLL_CNTL, 0xa6, info);
  214. else
  215.     aty_st_pll(DLL_CNTL, 0xa0, info);
  216. aty_st_pll(VFC_CNTL, 0x1b, info);
  217. aty_st_le32(DSP_CONFIG, pll->ct.dsp_config, info);
  218. aty_st_le32(DSP_ON_OFF, pll->ct.dsp_on_off, info);
  219.     }
  220. }
  221. static int dummy(void)
  222. {
  223.     return 0;
  224. }
  225. const struct aty_dac_ops aty_dac_ct = {
  226.     set_dac: (void *)dummy,
  227. };
  228. const struct aty_pll_ops aty_pll_ct = {
  229.     var_to_pll: aty_var_to_pll_ct,
  230.     pll_to_var: aty_pll_ct_to_var,
  231.     set_pll: aty_set_pll_ct,
  232. };