Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  *
0003  * Hardware accelerated Matrox PCI cards - G450/G550 PLL control.
0004  *
0005  * (c) 2001-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
0006  *
0007  * Portions Copyright (c) 2001 Matrox Graphics Inc.
0008  *
0009  * Version: 1.64 2002/06/10
0010  *
0011  * This file is subject to the terms and conditions of the GNU General Public
0012  * License. See the file COPYING in the main directory of this archive for
0013  * more details.
0014  *
0015  */
0016 
0017 #include "g450_pll.h"
0018 #include "matroxfb_DAC1064.h"
0019 
0020 static inline unsigned int g450_vco2f(unsigned char p, unsigned int fvco) {
0021     return (p & 0x40) ? fvco : fvco >> ((p & 3) + 1);
0022 }
0023 
0024 static inline unsigned int g450_f2vco(unsigned char p, unsigned int fin) {
0025     return (p & 0x40) ? fin : fin << ((p & 3) + 1);
0026 }
0027 
0028 static unsigned int g450_mnp2vco(const struct matrox_fb_info *minfo,
0029                  unsigned int mnp)
0030 {
0031     unsigned int m, n;
0032 
0033     m = ((mnp >> 16) & 0x0FF) + 1;
0034     n = ((mnp >>  7) & 0x1FE) + 4;
0035     return (minfo->features.pll.ref_freq * n + (m >> 1)) / m;
0036 }
0037 
0038 unsigned int g450_mnp2f(const struct matrox_fb_info *minfo, unsigned int mnp)
0039 {
0040     return g450_vco2f(mnp, g450_mnp2vco(minfo, mnp));
0041 }
0042 
0043 static inline unsigned int pll_freq_delta(unsigned int f1, unsigned int f2) {
0044     if (f2 < f1) {
0045             f2 = f1 - f2;
0046     } else {
0047         f2 = f2 - f1;
0048     }
0049     return f2;
0050 }
0051 
0052 #define NO_MORE_MNP 0x01FFFFFF
0053 #define G450_MNP_FREQBITS   (0xFFFFFF43)    /* do not mask high byte so we'll catch NO_MORE_MNP */
0054 
0055 static unsigned int g450_nextpll(const struct matrox_fb_info *minfo,
0056                  const struct matrox_pll_limits *pi,
0057                  unsigned int *fvco, unsigned int mnp)
0058 {
0059     unsigned int m, n, p;
0060     unsigned int tvco = *fvco;
0061 
0062     m = (mnp >> 16) & 0xFF;
0063     p = mnp & 0xFF;
0064 
0065     do {
0066         if (m == 0 || m == 0xFF) {
0067             if (m == 0) {
0068                 if (p & 0x40) {
0069                     return NO_MORE_MNP;
0070                 }
0071                     if (p & 3) {
0072                     p--;
0073                 } else {
0074                     p = 0x40;
0075                 }
0076                 tvco >>= 1;
0077                 if (tvco < pi->vcomin) {
0078                     return NO_MORE_MNP;
0079                 }
0080                 *fvco = tvco;
0081             }
0082 
0083             p &= 0x43;
0084             if (tvco < 550000) {
0085 /*              p |= 0x00; */
0086             } else if (tvco < 700000) {
0087                 p |= 0x08;
0088             } else if (tvco < 1000000) {
0089                 p |= 0x10;
0090             } else if (tvco < 1150000) {
0091                 p |= 0x18;
0092             } else {
0093                 p |= 0x20;
0094             }
0095             m = 9;
0096         } else {
0097             m--;
0098         }
0099         n = ((tvco * (m+1) + minfo->features.pll.ref_freq) / (minfo->features.pll.ref_freq * 2)) - 2;
0100     } while (n < 0x03 || n > 0x7A);
0101     return (m << 16) | (n << 8) | p;
0102 }
0103 
0104 static unsigned int g450_firstpll(const struct matrox_fb_info *minfo,
0105                   const struct matrox_pll_limits *pi,
0106                   unsigned int *vco, unsigned int fout)
0107 {
0108     unsigned int p;
0109     unsigned int vcomax;
0110 
0111     vcomax = pi->vcomax;
0112     if (fout > (vcomax / 2)) {
0113         if (fout > vcomax) {
0114             *vco = vcomax;
0115         } else {
0116             *vco = fout;
0117         }
0118         p = 0x40;
0119     } else {
0120         unsigned int tvco;
0121 
0122         p = 3;
0123         tvco = g450_f2vco(p, fout);
0124         while (p && (tvco > vcomax)) {
0125             p--;
0126             tvco >>= 1;
0127         }
0128         if (tvco < pi->vcomin) {
0129             tvco = pi->vcomin;
0130         }
0131         *vco = tvco;
0132     }
0133     return g450_nextpll(minfo, pi, vco, 0xFF0000 | p);
0134 }
0135 
0136 static inline unsigned int g450_setpll(const struct matrox_fb_info *minfo,
0137                        unsigned int mnp, unsigned int pll)
0138 {
0139     switch (pll) {
0140         case M_PIXEL_PLL_A:
0141             matroxfb_DAC_out(minfo, M1064_XPIXPLLAM, mnp >> 16);
0142             matroxfb_DAC_out(minfo, M1064_XPIXPLLAN, mnp >> 8);
0143             matroxfb_DAC_out(minfo, M1064_XPIXPLLAP, mnp);
0144             return M1064_XPIXPLLSTAT;
0145 
0146         case M_PIXEL_PLL_B:
0147             matroxfb_DAC_out(minfo, M1064_XPIXPLLBM, mnp >> 16);
0148             matroxfb_DAC_out(minfo, M1064_XPIXPLLBN, mnp >> 8);
0149             matroxfb_DAC_out(minfo, M1064_XPIXPLLBP, mnp);
0150             return M1064_XPIXPLLSTAT;
0151 
0152         case M_PIXEL_PLL_C:
0153             matroxfb_DAC_out(minfo, M1064_XPIXPLLCM, mnp >> 16);
0154             matroxfb_DAC_out(minfo, M1064_XPIXPLLCN, mnp >> 8);
0155             matroxfb_DAC_out(minfo, M1064_XPIXPLLCP, mnp);
0156             return M1064_XPIXPLLSTAT;
0157 
0158         case M_SYSTEM_PLL:
0159             matroxfb_DAC_out(minfo, DAC1064_XSYSPLLM, mnp >> 16);
0160             matroxfb_DAC_out(minfo, DAC1064_XSYSPLLN, mnp >> 8);
0161             matroxfb_DAC_out(minfo, DAC1064_XSYSPLLP, mnp);
0162             return DAC1064_XSYSPLLSTAT;
0163 
0164         case M_VIDEO_PLL:
0165             matroxfb_DAC_out(minfo, M1064_XVIDPLLM, mnp >> 16);
0166             matroxfb_DAC_out(minfo, M1064_XVIDPLLN, mnp >> 8);
0167             matroxfb_DAC_out(minfo, M1064_XVIDPLLP, mnp);
0168             return M1064_XVIDPLLSTAT;
0169     }
0170     return 0;
0171 }
0172 
0173 static inline unsigned int g450_cmppll(const struct matrox_fb_info *minfo,
0174                        unsigned int mnp, unsigned int pll)
0175 {
0176     unsigned char m = mnp >> 16;
0177     unsigned char n = mnp >> 8;
0178     unsigned char p = mnp;
0179 
0180     switch (pll) {
0181         case M_PIXEL_PLL_A:
0182             return (matroxfb_DAC_in(minfo, M1064_XPIXPLLAM) != m ||
0183                 matroxfb_DAC_in(minfo, M1064_XPIXPLLAN) != n ||
0184                 matroxfb_DAC_in(minfo, M1064_XPIXPLLAP) != p);
0185 
0186         case M_PIXEL_PLL_B:
0187             return (matroxfb_DAC_in(minfo, M1064_XPIXPLLBM) != m ||
0188                 matroxfb_DAC_in(minfo, M1064_XPIXPLLBN) != n ||
0189                 matroxfb_DAC_in(minfo, M1064_XPIXPLLBP) != p);
0190 
0191         case M_PIXEL_PLL_C:
0192             return (matroxfb_DAC_in(minfo, M1064_XPIXPLLCM) != m ||
0193                 matroxfb_DAC_in(minfo, M1064_XPIXPLLCN) != n ||
0194                 matroxfb_DAC_in(minfo, M1064_XPIXPLLCP) != p);
0195 
0196         case M_SYSTEM_PLL:
0197             return (matroxfb_DAC_in(minfo, DAC1064_XSYSPLLM) != m ||
0198                 matroxfb_DAC_in(minfo, DAC1064_XSYSPLLN) != n ||
0199                 matroxfb_DAC_in(minfo, DAC1064_XSYSPLLP) != p);
0200 
0201         case M_VIDEO_PLL:
0202             return (matroxfb_DAC_in(minfo, M1064_XVIDPLLM) != m ||
0203                 matroxfb_DAC_in(minfo, M1064_XVIDPLLN) != n ||
0204                 matroxfb_DAC_in(minfo, M1064_XVIDPLLP) != p);
0205     }
0206     return 1;
0207 }
0208 
0209 static inline int g450_isplllocked(const struct matrox_fb_info *minfo,
0210                    unsigned int regidx)
0211 {
0212     unsigned int j;
0213 
0214     for (j = 0; j < 1000; j++) {
0215         if (matroxfb_DAC_in(minfo, regidx) & 0x40) {
0216             unsigned int r = 0;
0217             int i;
0218 
0219             for (i = 0; i < 100; i++) {
0220                 r += matroxfb_DAC_in(minfo, regidx) & 0x40;
0221             }
0222             return r >= (90 * 0x40);
0223         }
0224         /* udelay(1)... but DAC_in is much slower... */
0225     }
0226     return 0;
0227 }
0228 
0229 static int g450_testpll(const struct matrox_fb_info *minfo, unsigned int mnp,
0230             unsigned int pll)
0231 {
0232     return g450_isplllocked(minfo, g450_setpll(minfo, mnp, pll));
0233 }
0234 
0235 static void updatehwstate_clk(struct matrox_hw_state* hw, unsigned int mnp, unsigned int pll) {
0236     switch (pll) {
0237         case M_SYSTEM_PLL:
0238             hw->DACclk[3] = mnp >> 16;
0239             hw->DACclk[4] = mnp >> 8;
0240             hw->DACclk[5] = mnp;
0241             break;
0242     }
0243 }
0244 
0245 void matroxfb_g450_setpll_cond(struct matrox_fb_info *minfo, unsigned int mnp,
0246                    unsigned int pll)
0247 {
0248     if (g450_cmppll(minfo, mnp, pll)) {
0249         g450_setpll(minfo, mnp, pll);
0250     }
0251 }
0252 
0253 static inline unsigned int g450_findworkingpll(struct matrox_fb_info *minfo,
0254                            unsigned int pll,
0255                            unsigned int *mnparray,
0256                            unsigned int mnpcount)
0257 {
0258     unsigned int found = 0;
0259     unsigned int idx;
0260     unsigned int mnpfound = mnparray[0];
0261         
0262     for (idx = 0; idx < mnpcount; idx++) {
0263         unsigned int sarray[3];
0264         unsigned int *sptr;
0265         {
0266             unsigned int mnp;
0267         
0268             sptr = sarray;
0269             mnp = mnparray[idx];
0270             if (mnp & 0x38) {
0271                 *sptr++ = mnp - 8;
0272             }
0273             if ((mnp & 0x38) != 0x38) {
0274                 *sptr++ = mnp + 8;
0275             }
0276             *sptr = mnp;
0277         }
0278         while (sptr >= sarray) {
0279             unsigned int mnp = *sptr--;
0280         
0281             if (g450_testpll(minfo, mnp - 0x0300, pll) &&
0282                 g450_testpll(minfo, mnp + 0x0300, pll) &&
0283                 g450_testpll(minfo, mnp - 0x0200, pll) &&
0284                 g450_testpll(minfo, mnp + 0x0200, pll) &&
0285                 g450_testpll(minfo, mnp - 0x0100, pll) &&
0286                 g450_testpll(minfo, mnp + 0x0100, pll)) {
0287                 if (g450_testpll(minfo, mnp, pll)) {
0288                     return mnp;
0289                 }
0290             } else if (!found && g450_testpll(minfo, mnp, pll)) {
0291                 mnpfound = mnp;
0292                 found = 1;
0293             }
0294         }
0295     }
0296     g450_setpll(minfo, mnpfound, pll);
0297     return mnpfound;
0298 }
0299 
0300 static void g450_addcache(struct matrox_pll_cache* ci, unsigned int mnp_key, unsigned int mnp_value) {
0301     if (++ci->valid > ARRAY_SIZE(ci->data)) {
0302         ci->valid = ARRAY_SIZE(ci->data);
0303     }
0304     memmove(ci->data + 1, ci->data, (ci->valid - 1) * sizeof(*ci->data));
0305     ci->data[0].mnp_key = mnp_key & G450_MNP_FREQBITS;
0306     ci->data[0].mnp_value = mnp_value;
0307 }
0308 
0309 static int g450_checkcache(struct matrox_fb_info *minfo,
0310                struct matrox_pll_cache *ci, unsigned int mnp_key)
0311 {
0312     unsigned int i;
0313     
0314     mnp_key &= G450_MNP_FREQBITS;
0315     for (i = 0; i < ci->valid; i++) {
0316         if (ci->data[i].mnp_key == mnp_key) {
0317             unsigned int mnp;
0318             
0319             mnp = ci->data[i].mnp_value;
0320             if (i) {
0321                 memmove(ci->data + 1, ci->data, i * sizeof(*ci->data));
0322                 ci->data[0].mnp_key = mnp_key;
0323                 ci->data[0].mnp_value = mnp;
0324             }
0325             return mnp;
0326         }
0327     }
0328     return NO_MORE_MNP;
0329 }
0330 
0331 static int __g450_setclk(struct matrox_fb_info *minfo, unsigned int fout,
0332              unsigned int pll, unsigned int *mnparray,
0333              unsigned int *deltaarray)
0334 {
0335     unsigned int mnpcount;
0336     const struct matrox_pll_limits* pi;
0337     struct matrox_pll_cache* ci;
0338 
0339     switch (pll) {
0340         case M_PIXEL_PLL_A:
0341         case M_PIXEL_PLL_B:
0342         case M_PIXEL_PLL_C:
0343             {
0344                 u_int8_t tmp, xpwrctrl;
0345                 unsigned long flags;
0346                 
0347                 matroxfb_DAC_lock_irqsave(flags);
0348 
0349                 xpwrctrl = matroxfb_DAC_in(minfo, M1064_XPWRCTRL);
0350                 matroxfb_DAC_out(minfo, M1064_XPWRCTRL, xpwrctrl & ~M1064_XPWRCTRL_PANELPDN);
0351                 mga_outb(M_SEQ_INDEX, M_SEQ1);
0352                 mga_outb(M_SEQ_DATA, mga_inb(M_SEQ_DATA) | M_SEQ1_SCROFF);
0353                 tmp = matroxfb_DAC_in(minfo, M1064_XPIXCLKCTRL);
0354                 tmp |= M1064_XPIXCLKCTRL_DIS;
0355                 if (!(tmp & M1064_XPIXCLKCTRL_PLL_UP)) {
0356                     tmp |= M1064_XPIXCLKCTRL_PLL_UP;
0357                 }
0358                 matroxfb_DAC_out(minfo, M1064_XPIXCLKCTRL, tmp);
0359                 /* DVI PLL preferred for frequencies up to
0360                    panel link max, standard PLL otherwise */
0361                 if (fout >= minfo->max_pixel_clock_panellink)
0362                     tmp = 0;
0363                 else tmp =
0364                     M1064_XDVICLKCTRL_DVIDATAPATHSEL |
0365                     M1064_XDVICLKCTRL_C1DVICLKSEL |
0366                     M1064_XDVICLKCTRL_C1DVICLKEN |
0367                     M1064_XDVICLKCTRL_DVILOOPCTL |
0368                     M1064_XDVICLKCTRL_P1LOOPBWDTCTL;
0369                                 /* Setting this breaks PC systems so don't do it */
0370                 /* matroxfb_DAC_out(minfo, M1064_XDVICLKCTRL, tmp); */
0371                 matroxfb_DAC_out(minfo, M1064_XPWRCTRL,
0372                          xpwrctrl);
0373 
0374                 matroxfb_DAC_unlock_irqrestore(flags);
0375             }
0376             {
0377                 u_int8_t misc;
0378         
0379                 misc = mga_inb(M_MISC_REG_READ) & ~0x0C;
0380                 switch (pll) {
0381                     case M_PIXEL_PLL_A:
0382                         break;
0383                     case M_PIXEL_PLL_B:
0384                         misc |=  0x04;
0385                         break;
0386                     default:
0387                         misc |=  0x0C;
0388                         break;
0389                 }
0390                 mga_outb(M_MISC_REG, misc);
0391             }
0392             pi = &minfo->limits.pixel;
0393             ci = &minfo->cache.pixel;
0394             break;
0395         case M_SYSTEM_PLL:
0396             {
0397                 u_int32_t opt;
0398 
0399                 pci_read_config_dword(minfo->pcidev, PCI_OPTION_REG, &opt);
0400                 if (!(opt & 0x20)) {
0401                     pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, opt | 0x20);
0402                 }
0403             }
0404             pi = &minfo->limits.system;
0405             ci = &minfo->cache.system;
0406             break;
0407         case M_VIDEO_PLL:
0408             {
0409                 u_int8_t tmp;
0410                 unsigned int mnp;
0411                 unsigned long flags;
0412                 
0413                 matroxfb_DAC_lock_irqsave(flags);
0414                 tmp = matroxfb_DAC_in(minfo, M1064_XPWRCTRL);
0415                 if (!(tmp & 2)) {
0416                     matroxfb_DAC_out(minfo, M1064_XPWRCTRL, tmp | 2);
0417                 }
0418                 
0419                 mnp = matroxfb_DAC_in(minfo, M1064_XPIXPLLCM) << 16;
0420                 mnp |= matroxfb_DAC_in(minfo, M1064_XPIXPLLCN) << 8;
0421                 matroxfb_DAC_unlock_irqrestore(flags);
0422             }
0423             pi = &minfo->limits.video;
0424             ci = &minfo->cache.video;
0425             break;
0426         default:
0427             return -EINVAL;
0428     }
0429 
0430     mnpcount = 0;
0431     {
0432         unsigned int mnp;
0433         unsigned int xvco;
0434 
0435         for (mnp = g450_firstpll(minfo, pi, &xvco, fout); mnp != NO_MORE_MNP; mnp = g450_nextpll(minfo, pi, &xvco, mnp)) {
0436             unsigned int idx;
0437             unsigned int vco;
0438             unsigned int delta;
0439 
0440             vco = g450_mnp2vco(minfo, mnp);
0441             delta = pll_freq_delta(fout, g450_vco2f(mnp, vco));
0442             for (idx = mnpcount; idx > 0; idx--) {
0443                 /* == is important; due to nextpll algorithm we get
0444                    sorted equally good frequencies from lower VCO 
0445                    frequency to higher - with <= lowest wins, while
0446                    with < highest one wins */
0447                 if (delta <= deltaarray[idx-1]) {
0448                     /* all else being equal except VCO,
0449                      * choose VCO not near (within 1/16th or so) VCOmin
0450                      * (freqs near VCOmin aren't as stable)
0451                      */
0452                     if (delta == deltaarray[idx-1]
0453                         && vco != g450_mnp2vco(minfo, mnparray[idx-1])
0454                         && vco < (pi->vcomin * 17 / 16)) {
0455                         break;
0456                     }
0457                     mnparray[idx] = mnparray[idx-1];
0458                     deltaarray[idx] = deltaarray[idx-1];
0459                 } else {
0460                     break;
0461                 }
0462             }
0463             mnparray[idx] = mnp;
0464             deltaarray[idx] = delta;
0465             mnpcount++;
0466         }
0467     }
0468     /* VideoPLL and PixelPLL matched: do nothing... In all other cases we should get at least one frequency */
0469     if (!mnpcount) {
0470         return -EBUSY;
0471     }
0472     {
0473         unsigned long flags;
0474         unsigned int mnp;
0475         
0476         matroxfb_DAC_lock_irqsave(flags);
0477         mnp = g450_checkcache(minfo, ci, mnparray[0]);
0478         if (mnp != NO_MORE_MNP) {
0479             matroxfb_g450_setpll_cond(minfo, mnp, pll);
0480         } else {
0481             mnp = g450_findworkingpll(minfo, pll, mnparray, mnpcount);
0482             g450_addcache(ci, mnparray[0], mnp);
0483         }
0484         updatehwstate_clk(&minfo->hw, mnp, pll);
0485         matroxfb_DAC_unlock_irqrestore(flags);
0486         return mnp;
0487     }
0488 }
0489 
0490 /* It must be greater than number of possible PLL values.
0491  * Currently there is 5(p) * 10(m) = 50 possible values. */
0492 #define MNP_TABLE_SIZE  64
0493 
0494 int matroxfb_g450_setclk(struct matrox_fb_info *minfo, unsigned int fout,
0495              unsigned int pll)
0496 {
0497     unsigned int* arr;
0498     
0499     arr = kmalloc(sizeof(*arr) * MNP_TABLE_SIZE * 2, GFP_KERNEL);
0500     if (arr) {
0501         int r;
0502 
0503         r = __g450_setclk(minfo, fout, pll, arr, arr + MNP_TABLE_SIZE);
0504         kfree(arr);
0505         return r;
0506     }
0507     return -ENOMEM;
0508 }
0509 
0510 EXPORT_SYMBOL(matroxfb_g450_setclk);
0511 EXPORT_SYMBOL(g450_mnp2f);
0512 EXPORT_SYMBOL(matroxfb_g450_setpll_cond);
0513 
0514 MODULE_AUTHOR("(c) 2001-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
0515 MODULE_DESCRIPTION("Matrox G450/G550 PLL driver");
0516 
0517 MODULE_LICENSE("GPL");