root/drivers/video/fbdev/matrox/g450_pll.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. g450_vco2f
  2. g450_f2vco
  3. g450_mnp2vco
  4. g450_mnp2f
  5. pll_freq_delta
  6. g450_nextpll
  7. g450_firstpll
  8. g450_setpll
  9. g450_cmppll
  10. g450_isplllocked
  11. g450_testpll
  12. updatehwstate_clk
  13. matroxfb_g450_setpll_cond
  14. g450_findworkingpll
  15. g450_addcache
  16. g450_checkcache
  17. __g450_setclk
  18. matroxfb_g450_setclk

   1 /*
   2  *
   3  * Hardware accelerated Matrox PCI cards - G450/G550 PLL control.
   4  *
   5  * (c) 2001-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
   6  *
   7  * Portions Copyright (c) 2001 Matrox Graphics Inc.
   8  *
   9  * Version: 1.64 2002/06/10
  10  *
  11  * This file is subject to the terms and conditions of the GNU General Public
  12  * License. See the file COPYING in the main directory of this archive for
  13  * more details.
  14  *
  15  */
  16 
  17 #include "g450_pll.h"
  18 #include "matroxfb_DAC1064.h"
  19 
  20 static inline unsigned int g450_vco2f(unsigned char p, unsigned int fvco) {
  21         return (p & 0x40) ? fvco : fvco >> ((p & 3) + 1);
  22 }
  23 
  24 static inline unsigned int g450_f2vco(unsigned char p, unsigned int fin) {
  25         return (p & 0x40) ? fin : fin << ((p & 3) + 1);
  26 }
  27 
  28 static unsigned int g450_mnp2vco(const struct matrox_fb_info *minfo,
  29                                  unsigned int mnp)
  30 {
  31         unsigned int m, n;
  32 
  33         m = ((mnp >> 16) & 0x0FF) + 1;
  34         n = ((mnp >>  7) & 0x1FE) + 4;
  35         return (minfo->features.pll.ref_freq * n + (m >> 1)) / m;
  36 }
  37 
  38 unsigned int g450_mnp2f(const struct matrox_fb_info *minfo, unsigned int mnp)
  39 {
  40         return g450_vco2f(mnp, g450_mnp2vco(minfo, mnp));
  41 }
  42 
  43 static inline unsigned int pll_freq_delta(unsigned int f1, unsigned int f2) {
  44         if (f2 < f1) {
  45                 f2 = f1 - f2;
  46         } else {
  47                 f2 = f2 - f1;
  48         }
  49         return f2;
  50 }
  51 
  52 #define NO_MORE_MNP     0x01FFFFFF
  53 #define G450_MNP_FREQBITS       (0xFFFFFF43)    /* do not mask high byte so we'll catch NO_MORE_MNP */
  54 
  55 static unsigned int g450_nextpll(const struct matrox_fb_info *minfo,
  56                                  const struct matrox_pll_limits *pi,
  57                                  unsigned int *fvco, unsigned int mnp)
  58 {
  59         unsigned int m, n, p;
  60         unsigned int tvco = *fvco;
  61 
  62         m = (mnp >> 16) & 0xFF;
  63         p = mnp & 0xFF;
  64 
  65         do {
  66                 if (m == 0 || m == 0xFF) {
  67                         if (m == 0) {
  68                                 if (p & 0x40) {
  69                                         return NO_MORE_MNP;
  70                                 }
  71                                 if (p & 3) {
  72                                         p--;
  73                                 } else {
  74                                         p = 0x40;
  75                                 }
  76                                 tvco >>= 1;
  77                                 if (tvco < pi->vcomin) {
  78                                         return NO_MORE_MNP;
  79                                 }
  80                                 *fvco = tvco;
  81                         }
  82 
  83                         p &= 0x43;
  84                         if (tvco < 550000) {
  85 /*                              p |= 0x00; */
  86                         } else if (tvco < 700000) {
  87                                 p |= 0x08;
  88                         } else if (tvco < 1000000) {
  89                                 p |= 0x10;
  90                         } else if (tvco < 1150000) {
  91                                 p |= 0x18;
  92                         } else {
  93                                 p |= 0x20;
  94                         }
  95                         m = 9;
  96                 } else {
  97                         m--;
  98                 }
  99                 n = ((tvco * (m+1) + minfo->features.pll.ref_freq) / (minfo->features.pll.ref_freq * 2)) - 2;
 100         } while (n < 0x03 || n > 0x7A);
 101         return (m << 16) | (n << 8) | p;
 102 }
 103 
 104 static unsigned int g450_firstpll(const struct matrox_fb_info *minfo,
 105                                   const struct matrox_pll_limits *pi,
 106                                   unsigned int *vco, unsigned int fout)
 107 {
 108         unsigned int p;
 109         unsigned int vcomax;
 110 
 111         vcomax = pi->vcomax;
 112         if (fout > (vcomax / 2)) {
 113                 if (fout > vcomax) {
 114                         *vco = vcomax;
 115                 } else {
 116                         *vco = fout;
 117                 }
 118                 p = 0x40;
 119         } else {
 120                 unsigned int tvco;
 121 
 122                 p = 3;
 123                 tvco = g450_f2vco(p, fout);
 124                 while (p && (tvco > vcomax)) {
 125                         p--;
 126                         tvco >>= 1;
 127                 }
 128                 if (tvco < pi->vcomin) {
 129                         tvco = pi->vcomin;
 130                 }
 131                 *vco = tvco;
 132         }
 133         return g450_nextpll(minfo, pi, vco, 0xFF0000 | p);
 134 }
 135 
 136 static inline unsigned int g450_setpll(const struct matrox_fb_info *minfo,
 137                                        unsigned int mnp, unsigned int pll)
 138 {
 139         switch (pll) {
 140                 case M_PIXEL_PLL_A:
 141                         matroxfb_DAC_out(minfo, M1064_XPIXPLLAM, mnp >> 16);
 142                         matroxfb_DAC_out(minfo, M1064_XPIXPLLAN, mnp >> 8);
 143                         matroxfb_DAC_out(minfo, M1064_XPIXPLLAP, mnp);
 144                         return M1064_XPIXPLLSTAT;
 145 
 146                 case M_PIXEL_PLL_B:
 147                         matroxfb_DAC_out(minfo, M1064_XPIXPLLBM, mnp >> 16);
 148                         matroxfb_DAC_out(minfo, M1064_XPIXPLLBN, mnp >> 8);
 149                         matroxfb_DAC_out(minfo, M1064_XPIXPLLBP, mnp);
 150                         return M1064_XPIXPLLSTAT;
 151 
 152                 case M_PIXEL_PLL_C:
 153                         matroxfb_DAC_out(minfo, M1064_XPIXPLLCM, mnp >> 16);
 154                         matroxfb_DAC_out(minfo, M1064_XPIXPLLCN, mnp >> 8);
 155                         matroxfb_DAC_out(minfo, M1064_XPIXPLLCP, mnp);
 156                         return M1064_XPIXPLLSTAT;
 157 
 158                 case M_SYSTEM_PLL:
 159                         matroxfb_DAC_out(minfo, DAC1064_XSYSPLLM, mnp >> 16);
 160                         matroxfb_DAC_out(minfo, DAC1064_XSYSPLLN, mnp >> 8);
 161                         matroxfb_DAC_out(minfo, DAC1064_XSYSPLLP, mnp);
 162                         return DAC1064_XSYSPLLSTAT;
 163 
 164                 case M_VIDEO_PLL:
 165                         matroxfb_DAC_out(minfo, M1064_XVIDPLLM, mnp >> 16);
 166                         matroxfb_DAC_out(minfo, M1064_XVIDPLLN, mnp >> 8);
 167                         matroxfb_DAC_out(minfo, M1064_XVIDPLLP, mnp);
 168                         return M1064_XVIDPLLSTAT;
 169         }
 170         return 0;
 171 }
 172 
 173 static inline unsigned int g450_cmppll(const struct matrox_fb_info *minfo,
 174                                        unsigned int mnp, unsigned int pll)
 175 {
 176         unsigned char m = mnp >> 16;
 177         unsigned char n = mnp >> 8;
 178         unsigned char p = mnp;
 179 
 180         switch (pll) {
 181                 case M_PIXEL_PLL_A:
 182                         return (matroxfb_DAC_in(minfo, M1064_XPIXPLLAM) != m ||
 183                                 matroxfb_DAC_in(minfo, M1064_XPIXPLLAN) != n ||
 184                                 matroxfb_DAC_in(minfo, M1064_XPIXPLLAP) != p);
 185 
 186                 case M_PIXEL_PLL_B:
 187                         return (matroxfb_DAC_in(minfo, M1064_XPIXPLLBM) != m ||
 188                                 matroxfb_DAC_in(minfo, M1064_XPIXPLLBN) != n ||
 189                                 matroxfb_DAC_in(minfo, M1064_XPIXPLLBP) != p);
 190 
 191                 case M_PIXEL_PLL_C:
 192                         return (matroxfb_DAC_in(minfo, M1064_XPIXPLLCM) != m ||
 193                                 matroxfb_DAC_in(minfo, M1064_XPIXPLLCN) != n ||
 194                                 matroxfb_DAC_in(minfo, M1064_XPIXPLLCP) != p);
 195 
 196                 case M_SYSTEM_PLL:
 197                         return (matroxfb_DAC_in(minfo, DAC1064_XSYSPLLM) != m ||
 198                                 matroxfb_DAC_in(minfo, DAC1064_XSYSPLLN) != n ||
 199                                 matroxfb_DAC_in(minfo, DAC1064_XSYSPLLP) != p);
 200 
 201                 case M_VIDEO_PLL:
 202                         return (matroxfb_DAC_in(minfo, M1064_XVIDPLLM) != m ||
 203                                 matroxfb_DAC_in(minfo, M1064_XVIDPLLN) != n ||
 204                                 matroxfb_DAC_in(minfo, M1064_XVIDPLLP) != p);
 205         }
 206         return 1;
 207 }
 208 
 209 static inline int g450_isplllocked(const struct matrox_fb_info *minfo,
 210                                    unsigned int regidx)
 211 {
 212         unsigned int j;
 213 
 214         for (j = 0; j < 1000; j++) {
 215                 if (matroxfb_DAC_in(minfo, regidx) & 0x40) {
 216                         unsigned int r = 0;
 217                         int i;
 218 
 219                         for (i = 0; i < 100; i++) {
 220                                 r += matroxfb_DAC_in(minfo, regidx) & 0x40;
 221                         }
 222                         return r >= (90 * 0x40);
 223                 }
 224                 /* udelay(1)... but DAC_in is much slower... */
 225         }
 226         return 0;
 227 }
 228 
 229 static int g450_testpll(const struct matrox_fb_info *minfo, unsigned int mnp,
 230                         unsigned int pll)
 231 {
 232         return g450_isplllocked(minfo, g450_setpll(minfo, mnp, pll));
 233 }
 234 
 235 static void updatehwstate_clk(struct matrox_hw_state* hw, unsigned int mnp, unsigned int pll) {
 236         switch (pll) {
 237                 case M_SYSTEM_PLL:
 238                         hw->DACclk[3] = mnp >> 16;
 239                         hw->DACclk[4] = mnp >> 8;
 240                         hw->DACclk[5] = mnp;
 241                         break;
 242         }
 243 }
 244 
 245 void matroxfb_g450_setpll_cond(struct matrox_fb_info *minfo, unsigned int mnp,
 246                                unsigned int pll)
 247 {
 248         if (g450_cmppll(minfo, mnp, pll)) {
 249                 g450_setpll(minfo, mnp, pll);
 250         }
 251 }
 252 
 253 static inline unsigned int g450_findworkingpll(struct matrox_fb_info *minfo,
 254                                                unsigned int pll,
 255                                                unsigned int *mnparray,
 256                                                unsigned int mnpcount)
 257 {
 258         unsigned int found = 0;
 259         unsigned int idx;
 260         unsigned int mnpfound = mnparray[0];
 261                 
 262         for (idx = 0; idx < mnpcount; idx++) {
 263                 unsigned int sarray[3];
 264                 unsigned int *sptr;
 265                 {
 266                         unsigned int mnp;
 267                 
 268                         sptr = sarray;
 269                         mnp = mnparray[idx];
 270                         if (mnp & 0x38) {
 271                                 *sptr++ = mnp - 8;
 272                         }
 273                         if ((mnp & 0x38) != 0x38) {
 274                                 *sptr++ = mnp + 8;
 275                         }
 276                         *sptr = mnp;
 277                 }
 278                 while (sptr >= sarray) {
 279                         unsigned int mnp = *sptr--;
 280                 
 281                         if (g450_testpll(minfo, mnp - 0x0300, pll) &&
 282                             g450_testpll(minfo, mnp + 0x0300, pll) &&
 283                             g450_testpll(minfo, mnp - 0x0200, pll) &&
 284                             g450_testpll(minfo, mnp + 0x0200, pll) &&
 285                             g450_testpll(minfo, mnp - 0x0100, pll) &&
 286                             g450_testpll(minfo, mnp + 0x0100, pll)) {
 287                                 if (g450_testpll(minfo, mnp, pll)) {
 288                                         return mnp;
 289                                 }
 290                         } else if (!found && g450_testpll(minfo, mnp, pll)) {
 291                                 mnpfound = mnp;
 292                                 found = 1;
 293                         }
 294                 }
 295         }
 296         g450_setpll(minfo, mnpfound, pll);
 297         return mnpfound;
 298 }
 299 
 300 static void g450_addcache(struct matrox_pll_cache* ci, unsigned int mnp_key, unsigned int mnp_value) {
 301         if (++ci->valid > ARRAY_SIZE(ci->data)) {
 302                 ci->valid = ARRAY_SIZE(ci->data);
 303         }
 304         memmove(ci->data + 1, ci->data, (ci->valid - 1) * sizeof(*ci->data));
 305         ci->data[0].mnp_key = mnp_key & G450_MNP_FREQBITS;
 306         ci->data[0].mnp_value = mnp_value;
 307 }
 308 
 309 static int g450_checkcache(struct matrox_fb_info *minfo,
 310                            struct matrox_pll_cache *ci, unsigned int mnp_key)
 311 {
 312         unsigned int i;
 313         
 314         mnp_key &= G450_MNP_FREQBITS;
 315         for (i = 0; i < ci->valid; i++) {
 316                 if (ci->data[i].mnp_key == mnp_key) {
 317                         unsigned int mnp;
 318                         
 319                         mnp = ci->data[i].mnp_value;
 320                         if (i) {
 321                                 memmove(ci->data + 1, ci->data, i * sizeof(*ci->data));
 322                                 ci->data[0].mnp_key = mnp_key;
 323                                 ci->data[0].mnp_value = mnp;
 324                         }
 325                         return mnp;
 326                 }
 327         }
 328         return NO_MORE_MNP;
 329 }
 330 
 331 static int __g450_setclk(struct matrox_fb_info *minfo, unsigned int fout,
 332                          unsigned int pll, unsigned int *mnparray,
 333                          unsigned int *deltaarray)
 334 {
 335         unsigned int mnpcount;
 336         unsigned int pixel_vco;
 337         const struct matrox_pll_limits* pi;
 338         struct matrox_pll_cache* ci;
 339 
 340         pixel_vco = 0;
 341         switch (pll) {
 342                 case M_PIXEL_PLL_A:
 343                 case M_PIXEL_PLL_B:
 344                 case M_PIXEL_PLL_C:
 345                         {
 346                                 u_int8_t tmp, xpwrctrl;
 347                                 unsigned long flags;
 348                                 
 349                                 matroxfb_DAC_lock_irqsave(flags);
 350 
 351                                 xpwrctrl = matroxfb_DAC_in(minfo, M1064_XPWRCTRL);
 352                                 matroxfb_DAC_out(minfo, M1064_XPWRCTRL, xpwrctrl & ~M1064_XPWRCTRL_PANELPDN);
 353                                 mga_outb(M_SEQ_INDEX, M_SEQ1);
 354                                 mga_outb(M_SEQ_DATA, mga_inb(M_SEQ_DATA) | M_SEQ1_SCROFF);
 355                                 tmp = matroxfb_DAC_in(minfo, M1064_XPIXCLKCTRL);
 356                                 tmp |= M1064_XPIXCLKCTRL_DIS;
 357                                 if (!(tmp & M1064_XPIXCLKCTRL_PLL_UP)) {
 358                                         tmp |= M1064_XPIXCLKCTRL_PLL_UP;
 359                                 }
 360                                 matroxfb_DAC_out(minfo, M1064_XPIXCLKCTRL, tmp);
 361                                 /* DVI PLL preferred for frequencies up to
 362                                    panel link max, standard PLL otherwise */
 363                                 if (fout >= minfo->max_pixel_clock_panellink)
 364                                         tmp = 0;
 365                                 else tmp =
 366                                         M1064_XDVICLKCTRL_DVIDATAPATHSEL |
 367                                         M1064_XDVICLKCTRL_C1DVICLKSEL |
 368                                         M1064_XDVICLKCTRL_C1DVICLKEN |
 369                                         M1064_XDVICLKCTRL_DVILOOPCTL |
 370                                         M1064_XDVICLKCTRL_P1LOOPBWDTCTL;
 371                                 /* Setting this breaks PC systems so don't do it */
 372                                 /* matroxfb_DAC_out(minfo, M1064_XDVICLKCTRL, tmp); */
 373                                 matroxfb_DAC_out(minfo, M1064_XPWRCTRL,
 374                                                  xpwrctrl);
 375 
 376                                 matroxfb_DAC_unlock_irqrestore(flags);
 377                         }
 378                         {
 379                                 u_int8_t misc;
 380                 
 381                                 misc = mga_inb(M_MISC_REG_READ) & ~0x0C;
 382                                 switch (pll) {
 383                                         case M_PIXEL_PLL_A:
 384                                                 break;
 385                                         case M_PIXEL_PLL_B:
 386                                                 misc |=  0x04;
 387                                                 break;
 388                                         default:
 389                                                 misc |=  0x0C;
 390                                                 break;
 391                                 }
 392                                 mga_outb(M_MISC_REG, misc);
 393                         }
 394                         pi = &minfo->limits.pixel;
 395                         ci = &minfo->cache.pixel;
 396                         break;
 397                 case M_SYSTEM_PLL:
 398                         {
 399                                 u_int32_t opt;
 400 
 401                                 pci_read_config_dword(minfo->pcidev, PCI_OPTION_REG, &opt);
 402                                 if (!(opt & 0x20)) {
 403                                         pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, opt | 0x20);
 404                                 }
 405                         }
 406                         pi = &minfo->limits.system;
 407                         ci = &minfo->cache.system;
 408                         break;
 409                 case M_VIDEO_PLL:
 410                         {
 411                                 u_int8_t tmp;
 412                                 unsigned int mnp;
 413                                 unsigned long flags;
 414                                 
 415                                 matroxfb_DAC_lock_irqsave(flags);
 416                                 tmp = matroxfb_DAC_in(minfo, M1064_XPWRCTRL);
 417                                 if (!(tmp & 2)) {
 418                                         matroxfb_DAC_out(minfo, M1064_XPWRCTRL, tmp | 2);
 419                                 }
 420                                 
 421                                 mnp = matroxfb_DAC_in(minfo, M1064_XPIXPLLCM) << 16;
 422                                 mnp |= matroxfb_DAC_in(minfo, M1064_XPIXPLLCN) << 8;
 423                                 pixel_vco = g450_mnp2vco(minfo, mnp);
 424                                 matroxfb_DAC_unlock_irqrestore(flags);
 425                         }
 426                         pi = &minfo->limits.video;
 427                         ci = &minfo->cache.video;
 428                         break;
 429                 default:
 430                         return -EINVAL;
 431         }
 432 
 433         mnpcount = 0;
 434         {
 435                 unsigned int mnp;
 436                 unsigned int xvco;
 437 
 438                 for (mnp = g450_firstpll(minfo, pi, &xvco, fout); mnp != NO_MORE_MNP; mnp = g450_nextpll(minfo, pi, &xvco, mnp)) {
 439                         unsigned int idx;
 440                         unsigned int vco;
 441                         unsigned int delta;
 442 
 443                         vco = g450_mnp2vco(minfo, mnp);
 444 #if 0                   
 445                         if (pll == M_VIDEO_PLL) {
 446                                 unsigned int big, small;
 447 
 448                                 if (vco < pixel_vco) {
 449                                         small = vco;
 450                                         big = pixel_vco;
 451                                 } else {
 452                                         small = pixel_vco;
 453                                         big = vco;
 454                                 }
 455                                 while (big > small) {
 456                                         big >>= 1;
 457                                 }
 458                                 if (big == small) {
 459                                         continue;
 460                                 }
 461                         }
 462 #endif                  
 463                         delta = pll_freq_delta(fout, g450_vco2f(mnp, vco));
 464                         for (idx = mnpcount; idx > 0; idx--) {
 465                                 /* == is important; due to nextpll algorithm we get
 466                                    sorted equally good frequencies from lower VCO 
 467                                    frequency to higher - with <= lowest wins, while
 468                                    with < highest one wins */
 469                                 if (delta <= deltaarray[idx-1]) {
 470                                         /* all else being equal except VCO,
 471                                          * choose VCO not near (within 1/16th or so) VCOmin
 472                                          * (freqs near VCOmin aren't as stable)
 473                                          */
 474                                         if (delta == deltaarray[idx-1]
 475                                             && vco != g450_mnp2vco(minfo, mnparray[idx-1])
 476                                             && vco < (pi->vcomin * 17 / 16)) {
 477                                                 break;
 478                                         }
 479                                         mnparray[idx] = mnparray[idx-1];
 480                                         deltaarray[idx] = deltaarray[idx-1];
 481                                 } else {
 482                                         break;
 483                                 }
 484                         }
 485                         mnparray[idx] = mnp;
 486                         deltaarray[idx] = delta;
 487                         mnpcount++;
 488                 }
 489         }
 490         /* VideoPLL and PixelPLL matched: do nothing... In all other cases we should get at least one frequency */
 491         if (!mnpcount) {
 492                 return -EBUSY;
 493         }
 494         {
 495                 unsigned long flags;
 496                 unsigned int mnp;
 497                 
 498                 matroxfb_DAC_lock_irqsave(flags);
 499                 mnp = g450_checkcache(minfo, ci, mnparray[0]);
 500                 if (mnp != NO_MORE_MNP) {
 501                         matroxfb_g450_setpll_cond(minfo, mnp, pll);
 502                 } else {
 503                         mnp = g450_findworkingpll(minfo, pll, mnparray, mnpcount);
 504                         g450_addcache(ci, mnparray[0], mnp);
 505                 }
 506                 updatehwstate_clk(&minfo->hw, mnp, pll);
 507                 matroxfb_DAC_unlock_irqrestore(flags);
 508                 return mnp;
 509         }
 510 }
 511 
 512 /* It must be greater than number of possible PLL values.
 513  * Currently there is 5(p) * 10(m) = 50 possible values. */
 514 #define MNP_TABLE_SIZE  64
 515 
 516 int matroxfb_g450_setclk(struct matrox_fb_info *minfo, unsigned int fout,
 517                          unsigned int pll)
 518 {
 519         unsigned int* arr;
 520         
 521         arr = kmalloc(sizeof(*arr) * MNP_TABLE_SIZE * 2, GFP_KERNEL);
 522         if (arr) {
 523                 int r;
 524 
 525                 r = __g450_setclk(minfo, fout, pll, arr, arr + MNP_TABLE_SIZE);
 526                 kfree(arr);
 527                 return r;
 528         }
 529         return -ENOMEM;
 530 }
 531 
 532 EXPORT_SYMBOL(matroxfb_g450_setclk);
 533 EXPORT_SYMBOL(g450_mnp2f);
 534 EXPORT_SYMBOL(matroxfb_g450_setpll_cond);
 535 
 536 MODULE_AUTHOR("(c) 2001-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
 537 MODULE_DESCRIPTION("Matrox G450/G550 PLL driver");
 538 
 539 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */