linux/drivers/gpu/drm/mgag200/mgag200_pll.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2
   3#include <linux/delay.h>
   4
   5#include "mgag200_drv.h"
   6
   7/*
   8 * G200
   9 */
  10
  11static int mgag200_pixpll_compute_g200(struct mgag200_pll *pixpll, long clock,
  12                                       struct mgag200_pll_values *pixpllc)
  13{
  14        struct mga_device *mdev = pixpll->mdev;
  15        struct drm_device *dev = &mdev->base;
  16        const int post_div_max = 7;
  17        const int in_div_min = 1;
  18        const int in_div_max = 6;
  19        const int feed_div_min = 7;
  20        const int feed_div_max = 127;
  21        u8 testp, testm, testn;
  22        u8 n = 0, m = 0, p, s;
  23        long f_vco;
  24        long computed;
  25        long delta, tmp_delta;
  26        long ref_clk = mdev->model.g200.ref_clk;
  27        long p_clk_min = mdev->model.g200.pclk_min;
  28        long p_clk_max =  mdev->model.g200.pclk_max;
  29
  30        if (clock > p_clk_max) {
  31                drm_err(dev, "Pixel Clock %ld too high\n", clock);
  32                return -EINVAL;
  33        }
  34
  35        if (clock < p_clk_min >> 3)
  36                clock = p_clk_min >> 3;
  37
  38        f_vco = clock;
  39        for (testp = 0;
  40             testp <= post_div_max && f_vco < p_clk_min;
  41             testp = (testp << 1) + 1, f_vco <<= 1)
  42                ;
  43        p = testp + 1;
  44
  45        delta = clock;
  46
  47        for (testm = in_div_min; testm <= in_div_max; testm++) {
  48                for (testn = feed_div_min; testn <= feed_div_max; testn++) {
  49                        computed = ref_clk * (testn + 1) / (testm + 1);
  50                        if (computed < f_vco)
  51                                tmp_delta = f_vco - computed;
  52                        else
  53                                tmp_delta = computed - f_vco;
  54                        if (tmp_delta < delta) {
  55                                delta = tmp_delta;
  56                                m = testm + 1;
  57                                n = testn + 1;
  58                        }
  59                }
  60        }
  61        f_vco = ref_clk * n / m;
  62        if (f_vco < 100000)
  63                s = 0;
  64        else if (f_vco < 140000)
  65                s = 1;
  66        else if (f_vco < 180000)
  67                s = 2;
  68        else
  69                s = 3;
  70
  71        drm_dbg_kms(dev, "clock: %ld vco: %ld m: %d n: %d p: %d s: %d\n",
  72                    clock, f_vco, m, n, p, s);
  73
  74        pixpllc->m = m;
  75        pixpllc->n = n;
  76        pixpllc->p = p;
  77        pixpllc->s = s;
  78
  79        return 0;
  80}
  81
  82static void
  83mgag200_pixpll_update_g200(struct mgag200_pll *pixpll, const struct mgag200_pll_values *pixpllc)
  84{
  85        struct mga_device *mdev = pixpll->mdev;
  86        unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
  87        u8 xpixpllcm, xpixpllcn, xpixpllcp;
  88
  89        pixpllcm = pixpllc->m - 1;
  90        pixpllcn = pixpllc->n - 1;
  91        pixpllcp = pixpllc->p - 1;
  92        pixpllcs = pixpllc->s;
  93
  94        xpixpllcm = pixpllcm;
  95        xpixpllcn = pixpllcn;
  96        xpixpllcp = (pixpllcs << 3) | pixpllcp;
  97
  98        WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
  99
 100        WREG_DAC(MGA1064_PIX_PLLC_M, xpixpllcm);
 101        WREG_DAC(MGA1064_PIX_PLLC_N, xpixpllcn);
 102        WREG_DAC(MGA1064_PIX_PLLC_P, xpixpllcp);
 103}
 104
 105static const struct mgag200_pll_funcs mgag200_pixpll_funcs_g200 = {
 106        .compute = mgag200_pixpll_compute_g200,
 107        .update = mgag200_pixpll_update_g200,
 108};
 109
 110/*
 111 * G200SE
 112 */
 113
 114static int mgag200_pixpll_compute_g200se_00(struct mgag200_pll *pixpll, long clock,
 115                                            struct mgag200_pll_values *pixpllc)
 116{
 117        static const unsigned int vcomax = 320000;
 118        static const unsigned int vcomin = 160000;
 119        static const unsigned int pllreffreq = 25000;
 120
 121        unsigned int delta, tmpdelta, permitteddelta;
 122        unsigned int testp, testm, testn;
 123        unsigned int p, m, n, s;
 124        unsigned int computed;
 125
 126        m = n = p = s = 0;
 127        delta = 0xffffffff;
 128        permitteddelta = clock * 5 / 1000;
 129
 130        for (testp = 8; testp > 0; testp /= 2) {
 131                if (clock * testp > vcomax)
 132                        continue;
 133                if (clock * testp < vcomin)
 134                        continue;
 135
 136                for (testn = 17; testn < 256; testn++) {
 137                        for (testm = 1; testm < 32; testm++) {
 138                                computed = (pllreffreq * testn) / (testm * testp);
 139                                if (computed > clock)
 140                                        tmpdelta = computed - clock;
 141                                else
 142                                        tmpdelta = clock - computed;
 143                                if (tmpdelta < delta) {
 144                                        delta = tmpdelta;
 145                                        m = testm;
 146                                        n = testn;
 147                                        p = testp;
 148                                }
 149                        }
 150                }
 151        }
 152
 153        if (delta > permitteddelta) {
 154                pr_warn("PLL delta too large\n");
 155                return -EINVAL;
 156        }
 157
 158        pixpllc->m = m;
 159        pixpllc->n = n;
 160        pixpllc->p = p;
 161        pixpllc->s = s;
 162
 163        return 0;
 164}
 165
 166static void mgag200_pixpll_update_g200se_00(struct mgag200_pll *pixpll,
 167                                            const struct mgag200_pll_values *pixpllc)
 168{
 169        unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
 170        u8 xpixpllcm, xpixpllcn, xpixpllcp;
 171        struct mga_device *mdev = pixpll->mdev;
 172
 173        pixpllcm = pixpllc->m - 1;
 174        pixpllcn = pixpllc->n - 1;
 175        pixpllcp = pixpllc->p - 1;
 176        pixpllcs = pixpllc->s;
 177
 178        xpixpllcm = pixpllcm | ((pixpllcn & BIT(8)) >> 1);
 179        xpixpllcn = pixpllcn;
 180        xpixpllcp = (pixpllcs << 3) | pixpllcp;
 181
 182        WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
 183
 184        WREG_DAC(MGA1064_PIX_PLLC_M, xpixpllcm);
 185        WREG_DAC(MGA1064_PIX_PLLC_N, xpixpllcn);
 186        WREG_DAC(MGA1064_PIX_PLLC_P, xpixpllcp);
 187}
 188
 189static int mgag200_pixpll_compute_g200se_04(struct mgag200_pll *pixpll, long clock,
 190                                            struct mgag200_pll_values *pixpllc)
 191{
 192        static const unsigned int vcomax = 1600000;
 193        static const unsigned int vcomin = 800000;
 194        static const unsigned int pllreffreq = 25000;
 195        static const unsigned int pvalues_e4[] = {16, 14, 12, 10, 8, 6, 4, 2, 1};
 196
 197        unsigned int delta, tmpdelta, permitteddelta;
 198        unsigned int testp, testm, testn;
 199        unsigned int p, m, n, s;
 200        unsigned int computed;
 201        unsigned int fvv;
 202        unsigned int i;
 203
 204        m = n = p = s = 0;
 205        delta = 0xffffffff;
 206
 207        if (clock < 25000)
 208                clock = 25000;
 209        clock = clock * 2;
 210
 211        /* Permited delta is 0.5% as VESA Specification */
 212        permitteddelta = clock * 5 / 1000;
 213
 214        for (i = 0 ; i < ARRAY_SIZE(pvalues_e4); i++) {
 215                testp = pvalues_e4[i];
 216
 217                if ((clock * testp) > vcomax)
 218                        continue;
 219                if ((clock * testp) < vcomin)
 220                        continue;
 221
 222                for (testn = 50; testn <= 256; testn++) {
 223                        for (testm = 1; testm <= 32; testm++) {
 224                                computed = (pllreffreq * testn) / (testm * testp);
 225                                if (computed > clock)
 226                                        tmpdelta = computed - clock;
 227                                else
 228                                        tmpdelta = clock - computed;
 229
 230                                if (tmpdelta < delta) {
 231                                        delta = tmpdelta;
 232                                        m = testm;
 233                                        n = testn;
 234                                        p = testp;
 235                                }
 236                        }
 237                }
 238        }
 239
 240        fvv = pllreffreq * n / m;
 241        fvv = (fvv - 800000) / 50000;
 242        if (fvv > 15)
 243                fvv = 15;
 244        s = fvv << 1;
 245
 246        if (delta > permitteddelta) {
 247                pr_warn("PLL delta too large\n");
 248                return -EINVAL;
 249        }
 250
 251        pixpllc->m = m;
 252        pixpllc->n = n;
 253        pixpllc->p = p;
 254        pixpllc->s = s;
 255
 256        return 0;
 257}
 258
 259static void mgag200_pixpll_update_g200se_04(struct mgag200_pll *pixpll,
 260                                            const struct mgag200_pll_values *pixpllc)
 261{
 262        unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
 263        u8 xpixpllcm, xpixpllcn, xpixpllcp;
 264        struct mga_device *mdev = pixpll->mdev;
 265
 266        pixpllcm = pixpllc->m - 1;
 267        pixpllcn = pixpllc->n - 1;
 268        pixpllcp = pixpllc->p - 1;
 269        pixpllcs = pixpllc->s;
 270
 271        xpixpllcm = pixpllcm | ((pixpllcn & BIT(8)) >> 1);
 272        xpixpllcn = pixpllcn;
 273        xpixpllcp = (pixpllcs << 3) | pixpllcp;
 274
 275        WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
 276
 277        WREG_DAC(MGA1064_PIX_PLLC_M, xpixpllcm);
 278        WREG_DAC(MGA1064_PIX_PLLC_N, xpixpllcn);
 279        WREG_DAC(MGA1064_PIX_PLLC_P, xpixpllcp);
 280
 281        WREG_DAC(0x1a, 0x09);
 282        msleep(20);
 283        WREG_DAC(0x1a, 0x01);
 284}
 285
 286static const struct mgag200_pll_funcs mgag200_pixpll_funcs_g200se_00 = {
 287        .compute = mgag200_pixpll_compute_g200se_00,
 288        .update = mgag200_pixpll_update_g200se_00,
 289};
 290
 291static const struct mgag200_pll_funcs mgag200_pixpll_funcs_g200se_04 = {
 292        .compute = mgag200_pixpll_compute_g200se_04,
 293        .update = mgag200_pixpll_update_g200se_04,
 294};
 295
 296/*
 297 * G200WB
 298 */
 299
 300static int mgag200_pixpll_compute_g200wb(struct mgag200_pll *pixpll, long clock,
 301                                         struct mgag200_pll_values *pixpllc)
 302{
 303        static const unsigned int vcomax = 550000;
 304        static const unsigned int vcomin = 150000;
 305        static const unsigned int pllreffreq = 48000;
 306
 307        unsigned int delta, tmpdelta;
 308        unsigned int testp, testm, testn;
 309        unsigned int p, m, n, s;
 310        unsigned int computed;
 311
 312        m = n = p = s = 0;
 313        delta = 0xffffffff;
 314
 315        for (testp = 1; testp < 9; testp++) {
 316                if (clock * testp > vcomax)
 317                        continue;
 318                if (clock * testp < vcomin)
 319                        continue;
 320
 321                for (testm = 1; testm < 17; testm++) {
 322                        for (testn = 1; testn < 151; testn++) {
 323                                computed = (pllreffreq * testn) / (testm * testp);
 324                                if (computed > clock)
 325                                        tmpdelta = computed - clock;
 326                                else
 327                                        tmpdelta = clock - computed;
 328                                if (tmpdelta < delta) {
 329                                        delta = tmpdelta;
 330                                        n = testn;
 331                                        m = testm;
 332                                        p = testp;
 333                                        s = 0;
 334                                }
 335                        }
 336                }
 337        }
 338
 339        pixpllc->m = m;
 340        pixpllc->n = n;
 341        pixpllc->p = p;
 342        pixpllc->s = s;
 343
 344        return 0;
 345}
 346
 347static void
 348mgag200_pixpll_update_g200wb(struct mgag200_pll *pixpll, const struct mgag200_pll_values *pixpllc)
 349{
 350        unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
 351        u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp;
 352        int i, j, tmpcount, vcount;
 353        struct mga_device *mdev = pixpll->mdev;
 354        bool pll_locked = false;
 355
 356        pixpllcm = pixpllc->m - 1;
 357        pixpllcn = pixpllc->n - 1;
 358        pixpllcp = pixpllc->p - 1;
 359        pixpllcs = pixpllc->s;
 360
 361        xpixpllcm = ((pixpllcn & BIT(8)) >> 1) | pixpllcm;
 362        xpixpllcn = pixpllcn;
 363        xpixpllcp = ((pixpllcn & GENMASK(10, 9)) >> 3) | (pixpllcs << 3) | pixpllcp;
 364
 365        WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
 366
 367        for (i = 0; i <= 32 && pll_locked == false; i++) {
 368                if (i > 0) {
 369                        WREG8(MGAREG_CRTC_INDEX, 0x1e);
 370                        tmp = RREG8(MGAREG_CRTC_DATA);
 371                        if (tmp < 0xff)
 372                                WREG8(MGAREG_CRTC_DATA, tmp+1);
 373                }
 374
 375                /* set pixclkdis to 1 */
 376                WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
 377                tmp = RREG8(DAC_DATA);
 378                tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS;
 379                WREG8(DAC_DATA, tmp);
 380
 381                WREG8(DAC_INDEX, MGA1064_REMHEADCTL);
 382                tmp = RREG8(DAC_DATA);
 383                tmp |= MGA1064_REMHEADCTL_CLKDIS;
 384                WREG8(DAC_DATA, tmp);
 385
 386                /* select PLL Set C */
 387                tmp = RREG8(MGAREG_MEM_MISC_READ);
 388                tmp |= 0x3 << 2;
 389                WREG8(MGAREG_MEM_MISC_WRITE, tmp);
 390
 391                WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
 392                tmp = RREG8(DAC_DATA);
 393                tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN | 0x80;
 394                WREG8(DAC_DATA, tmp);
 395
 396                udelay(500);
 397
 398                /* reset the PLL */
 399                WREG8(DAC_INDEX, MGA1064_VREF_CTL);
 400                tmp = RREG8(DAC_DATA);
 401                tmp &= ~0x04;
 402                WREG8(DAC_DATA, tmp);
 403
 404                udelay(50);
 405
 406                /* program pixel pll register */
 407                WREG_DAC(MGA1064_WB_PIX_PLLC_N, xpixpllcn);
 408                WREG_DAC(MGA1064_WB_PIX_PLLC_M, xpixpllcm);
 409                WREG_DAC(MGA1064_WB_PIX_PLLC_P, xpixpllcp);
 410
 411                udelay(50);
 412
 413                /* turn pll on */
 414                WREG8(DAC_INDEX, MGA1064_VREF_CTL);
 415                tmp = RREG8(DAC_DATA);
 416                tmp |= 0x04;
 417                WREG_DAC(MGA1064_VREF_CTL, tmp);
 418
 419                udelay(500);
 420
 421                /* select the pixel pll */
 422                WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
 423                tmp = RREG8(DAC_DATA);
 424                tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK;
 425                tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL;
 426                WREG8(DAC_DATA, tmp);
 427
 428                WREG8(DAC_INDEX, MGA1064_REMHEADCTL);
 429                tmp = RREG8(DAC_DATA);
 430                tmp &= ~MGA1064_REMHEADCTL_CLKSL_MSK;
 431                tmp |= MGA1064_REMHEADCTL_CLKSL_PLL;
 432                WREG8(DAC_DATA, tmp);
 433
 434                /* reset dotclock rate bit */
 435                WREG8(MGAREG_SEQ_INDEX, 1);
 436                tmp = RREG8(MGAREG_SEQ_DATA);
 437                tmp &= ~0x8;
 438                WREG8(MGAREG_SEQ_DATA, tmp);
 439
 440                WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
 441                tmp = RREG8(DAC_DATA);
 442                tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS;
 443                WREG8(DAC_DATA, tmp);
 444
 445                vcount = RREG8(MGAREG_VCOUNT);
 446
 447                for (j = 0; j < 30 && pll_locked == false; j++) {
 448                        tmpcount = RREG8(MGAREG_VCOUNT);
 449                        if (tmpcount < vcount)
 450                                vcount = 0;
 451                        if ((tmpcount - vcount) > 2)
 452                                pll_locked = true;
 453                        else
 454                                udelay(5);
 455                }
 456        }
 457
 458        WREG8(DAC_INDEX, MGA1064_REMHEADCTL);
 459        tmp = RREG8(DAC_DATA);
 460        tmp &= ~MGA1064_REMHEADCTL_CLKDIS;
 461        WREG_DAC(MGA1064_REMHEADCTL, tmp);
 462}
 463
 464static const struct mgag200_pll_funcs mgag200_pixpll_funcs_g200wb = {
 465        .compute = mgag200_pixpll_compute_g200wb,
 466        .update = mgag200_pixpll_update_g200wb,
 467};
 468
 469/*
 470 * G200EV
 471 */
 472
 473static int mgag200_pixpll_compute_g200ev(struct mgag200_pll *pixpll, long clock,
 474                                         struct mgag200_pll_values *pixpllc)
 475{
 476        static const unsigned int vcomax = 550000;
 477        static const unsigned int vcomin = 150000;
 478        static const unsigned int pllreffreq = 50000;
 479
 480        unsigned int delta, tmpdelta;
 481        unsigned int testp, testm, testn;
 482        unsigned int p, m, n, s;
 483        unsigned int computed;
 484
 485        m = n = p = s = 0;
 486        delta = 0xffffffff;
 487
 488        for (testp = 16; testp > 0; testp--) {
 489                if (clock * testp > vcomax)
 490                        continue;
 491                if (clock * testp < vcomin)
 492                        continue;
 493
 494                for (testn = 1; testn < 257; testn++) {
 495                        for (testm = 1; testm < 17; testm++) {
 496                                computed = (pllreffreq * testn) /
 497                                        (testm * testp);
 498                                if (computed > clock)
 499                                        tmpdelta = computed - clock;
 500                                else
 501                                        tmpdelta = clock - computed;
 502                                if (tmpdelta < delta) {
 503                                        delta = tmpdelta;
 504                                        n = testn;
 505                                        m = testm;
 506                                        p = testp;
 507                                }
 508                        }
 509                }
 510        }
 511
 512        pixpllc->m = m;
 513        pixpllc->n = n;
 514        pixpllc->p = p;
 515        pixpllc->s = s;
 516
 517        return 0;
 518}
 519
 520static void
 521mgag200_pixpll_update_g200ev(struct mgag200_pll *pixpll, const struct mgag200_pll_values *pixpllc)
 522{
 523        unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
 524        u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp;
 525        struct mga_device *mdev = pixpll->mdev;
 526
 527        pixpllcm = pixpllc->m - 1;
 528        pixpllcn = pixpllc->n - 1;
 529        pixpllcp = pixpllc->p - 1;
 530        pixpllcs = pixpllc->s;
 531
 532        xpixpllcm = pixpllcm;
 533        xpixpllcn = pixpllcn;
 534        xpixpllcp = (pixpllcs << 3) | pixpllcp;
 535
 536        WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
 537
 538        WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
 539        tmp = RREG8(DAC_DATA);
 540        tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS;
 541        WREG8(DAC_DATA, tmp);
 542
 543        tmp = RREG8(MGAREG_MEM_MISC_READ);
 544        tmp |= 0x3 << 2;
 545        WREG8(MGAREG_MEM_MISC_WRITE, tmp);
 546
 547        WREG8(DAC_INDEX, MGA1064_PIX_PLL_STAT);
 548        tmp = RREG8(DAC_DATA);
 549        WREG8(DAC_DATA, tmp & ~0x40);
 550
 551        WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
 552        tmp = RREG8(DAC_DATA);
 553        tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;
 554        WREG8(DAC_DATA, tmp);
 555
 556        WREG_DAC(MGA1064_EV_PIX_PLLC_M, xpixpllcm);
 557        WREG_DAC(MGA1064_EV_PIX_PLLC_N, xpixpllcn);
 558        WREG_DAC(MGA1064_EV_PIX_PLLC_P, xpixpllcp);
 559
 560        udelay(50);
 561
 562        WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
 563        tmp = RREG8(DAC_DATA);
 564        tmp &= ~MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;
 565        WREG8(DAC_DATA, tmp);
 566
 567        udelay(500);
 568
 569        WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
 570        tmp = RREG8(DAC_DATA);
 571        tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK;
 572        tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL;
 573        WREG8(DAC_DATA, tmp);
 574
 575        WREG8(DAC_INDEX, MGA1064_PIX_PLL_STAT);
 576        tmp = RREG8(DAC_DATA);
 577        WREG8(DAC_DATA, tmp | 0x40);
 578
 579        tmp = RREG8(MGAREG_MEM_MISC_READ);
 580        tmp |= (0x3 << 2);
 581        WREG8(MGAREG_MEM_MISC_WRITE, tmp);
 582
 583        WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
 584        tmp = RREG8(DAC_DATA);
 585        tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS;
 586        WREG8(DAC_DATA, tmp);
 587}
 588
 589static const struct mgag200_pll_funcs mgag200_pixpll_funcs_g200ev = {
 590        .compute = mgag200_pixpll_compute_g200ev,
 591        .update = mgag200_pixpll_update_g200ev,
 592};
 593
 594/*
 595 * G200EH
 596 */
 597
 598static int mgag200_pixpll_compute_g200eh(struct mgag200_pll *pixpll, long clock,
 599                                         struct mgag200_pll_values *pixpllc)
 600{
 601        static const unsigned int vcomax = 800000;
 602        static const unsigned int vcomin = 400000;
 603        static const unsigned int pllreffreq = 33333;
 604
 605        unsigned int delta, tmpdelta;
 606        unsigned int testp, testm, testn;
 607        unsigned int p, m, n, s;
 608        unsigned int computed;
 609
 610        m = n = p = s = 0;
 611        delta = 0xffffffff;
 612
 613        for (testp = 16; testp > 0; testp >>= 1) {
 614                if (clock * testp > vcomax)
 615                        continue;
 616                if (clock * testp < vcomin)
 617                        continue;
 618
 619                for (testm = 1; testm < 33; testm++) {
 620                        for (testn = 17; testn < 257; testn++) {
 621                                computed = (pllreffreq * testn) / (testm * testp);
 622                                if (computed > clock)
 623                                        tmpdelta = computed - clock;
 624                                else
 625                                        tmpdelta = clock - computed;
 626                                if (tmpdelta < delta) {
 627                                        delta = tmpdelta;
 628                                        n = testn;
 629                                        m = testm;
 630                                        p = testp;
 631                                }
 632                        }
 633                }
 634        }
 635
 636        pixpllc->m = m;
 637        pixpllc->n = n;
 638        pixpllc->p = p;
 639        pixpllc->s = s;
 640
 641        return 0;
 642}
 643
 644static void
 645mgag200_pixpll_update_g200eh(struct mgag200_pll *pixpll, const struct mgag200_pll_values *pixpllc)
 646{
 647        unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
 648        u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp;
 649        int i, j, tmpcount, vcount;
 650        struct mga_device *mdev = pixpll->mdev;
 651        bool pll_locked = false;
 652
 653        pixpllcm = pixpllc->m - 1;
 654        pixpllcn = pixpllc->n - 1;
 655        pixpllcp = pixpllc->p - 1;
 656        pixpllcs = pixpllc->s;
 657
 658        xpixpllcm = ((pixpllcn & BIT(8)) >> 1) | pixpllcm;
 659        xpixpllcn = pixpllcn;
 660        xpixpllcp = (pixpllcs << 3) | pixpllcp;
 661
 662        WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
 663
 664        for (i = 0; i <= 32 && pll_locked == false; i++) {
 665                WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
 666                tmp = RREG8(DAC_DATA);
 667                tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS;
 668                WREG8(DAC_DATA, tmp);
 669
 670                tmp = RREG8(MGAREG_MEM_MISC_READ);
 671                tmp |= 0x3 << 2;
 672                WREG8(MGAREG_MEM_MISC_WRITE, tmp);
 673
 674                WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
 675                tmp = RREG8(DAC_DATA);
 676                tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;
 677                WREG8(DAC_DATA, tmp);
 678
 679                udelay(500);
 680
 681                WREG_DAC(MGA1064_EH_PIX_PLLC_M, xpixpllcm);
 682                WREG_DAC(MGA1064_EH_PIX_PLLC_N, xpixpllcn);
 683                WREG_DAC(MGA1064_EH_PIX_PLLC_P, xpixpllcp);
 684
 685                udelay(500);
 686
 687                WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
 688                tmp = RREG8(DAC_DATA);
 689                tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK;
 690                tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL;
 691                WREG8(DAC_DATA, tmp);
 692
 693                WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
 694                tmp = RREG8(DAC_DATA);
 695                tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS;
 696                tmp &= ~MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;
 697                WREG8(DAC_DATA, tmp);
 698
 699                vcount = RREG8(MGAREG_VCOUNT);
 700
 701                for (j = 0; j < 30 && pll_locked == false; j++) {
 702                        tmpcount = RREG8(MGAREG_VCOUNT);
 703                        if (tmpcount < vcount)
 704                                vcount = 0;
 705                        if ((tmpcount - vcount) > 2)
 706                                pll_locked = true;
 707                        else
 708                                udelay(5);
 709                }
 710        }
 711}
 712
 713static const struct mgag200_pll_funcs mgag200_pixpll_funcs_g200eh = {
 714        .compute = mgag200_pixpll_compute_g200eh,
 715        .update = mgag200_pixpll_update_g200eh,
 716};
 717
 718/*
 719 * G200EH3
 720 */
 721
 722static int mgag200_pixpll_compute_g200eh3(struct mgag200_pll *pixpll, long clock,
 723                                          struct mgag200_pll_values *pixpllc)
 724{
 725        static const unsigned int vcomax = 3000000;
 726        static const unsigned int vcomin = 1500000;
 727        static const unsigned int pllreffreq = 25000;
 728
 729        unsigned int delta, tmpdelta;
 730        unsigned int testp, testm, testn;
 731        unsigned int p, m, n, s;
 732        unsigned int computed;
 733
 734        m = n = p = s = 0;
 735        delta = 0xffffffff;
 736        testp = 0;
 737
 738        for (testm = 150; testm >= 6; testm--) {
 739                if (clock * testm > vcomax)
 740                        continue;
 741                if (clock * testm < vcomin)
 742                        continue;
 743                for (testn = 120; testn >= 60; testn--) {
 744                        computed = (pllreffreq * testn) / testm;
 745                        if (computed > clock)
 746                                tmpdelta = computed - clock;
 747                        else
 748                                tmpdelta = clock - computed;
 749                        if (tmpdelta < delta) {
 750                                delta = tmpdelta;
 751                                n = testn + 1;
 752                                m = testm + 1;
 753                                p = testp + 1;
 754                        }
 755                        if (delta == 0)
 756                                break;
 757                }
 758                if (delta == 0)
 759                        break;
 760        }
 761
 762        pixpllc->m = m;
 763        pixpllc->n = n;
 764        pixpllc->p = p;
 765        pixpllc->s = s;
 766
 767        return 0;
 768}
 769
 770static const struct mgag200_pll_funcs mgag200_pixpll_funcs_g200eh3 = {
 771        .compute = mgag200_pixpll_compute_g200eh3,
 772        .update = mgag200_pixpll_update_g200eh, // same as G200EH
 773};
 774
 775/*
 776 * G200ER
 777 */
 778
 779static int mgag200_pixpll_compute_g200er(struct mgag200_pll *pixpll, long clock,
 780                                         struct mgag200_pll_values *pixpllc)
 781{
 782        static const unsigned int vcomax = 1488000;
 783        static const unsigned int vcomin = 1056000;
 784        static const unsigned int pllreffreq = 48000;
 785        static const unsigned int m_div_val[] = { 1, 2, 4, 8 };
 786
 787        unsigned int delta, tmpdelta;
 788        int testr, testn, testm, testo;
 789        unsigned int p, m, n, s;
 790        unsigned int computed, vco;
 791
 792        m = n = p = s = 0;
 793        delta = 0xffffffff;
 794
 795        for (testr = 0; testr < 4; testr++) {
 796                if (delta == 0)
 797                        break;
 798                for (testn = 5; testn < 129; testn++) {
 799                        if (delta == 0)
 800                                break;
 801                        for (testm = 3; testm >= 0; testm--) {
 802                                if (delta == 0)
 803                                        break;
 804                                for (testo = 5; testo < 33; testo++) {
 805                                        vco = pllreffreq * (testn + 1) /
 806                                                (testr + 1);
 807                                        if (vco < vcomin)
 808                                                continue;
 809                                        if (vco > vcomax)
 810                                                continue;
 811                                        computed = vco / (m_div_val[testm] * (testo + 1));
 812                                        if (computed > clock)
 813                                                tmpdelta = computed - clock;
 814                                        else
 815                                                tmpdelta = clock - computed;
 816                                        if (tmpdelta < delta) {
 817                                                delta = tmpdelta;
 818                                                m = (testm | (testo << 3)) + 1;
 819                                                n = testn + 1;
 820                                                p = testr + 1;
 821                                                s = testr;
 822                                        }
 823                                }
 824                        }
 825                }
 826        }
 827
 828        pixpllc->m = m;
 829        pixpllc->n = n;
 830        pixpllc->p = p;
 831        pixpllc->s = s;
 832
 833        return 0;
 834}
 835
 836static void
 837mgag200_pixpll_update_g200er(struct mgag200_pll *pixpll, const struct mgag200_pll_values *pixpllc)
 838{
 839        unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
 840        u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp;
 841        struct mga_device *mdev = pixpll->mdev;
 842
 843        pixpllcm = pixpllc->m - 1;
 844        pixpllcn = pixpllc->n - 1;
 845        pixpllcp = pixpllc->p - 1;
 846        pixpllcs = pixpllc->s;
 847
 848        xpixpllcm = pixpllcm;
 849        xpixpllcn = pixpllcn;
 850        xpixpllcp = (pixpllcs << 3) | pixpllcp;
 851
 852        WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
 853
 854        WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
 855        tmp = RREG8(DAC_DATA);
 856        tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS;
 857        WREG8(DAC_DATA, tmp);
 858
 859        WREG8(DAC_INDEX, MGA1064_REMHEADCTL);
 860        tmp = RREG8(DAC_DATA);
 861        tmp |= MGA1064_REMHEADCTL_CLKDIS;
 862        WREG8(DAC_DATA, tmp);
 863
 864        tmp = RREG8(MGAREG_MEM_MISC_READ);
 865        tmp |= (0x3<<2) | 0xc0;
 866        WREG8(MGAREG_MEM_MISC_WRITE, tmp);
 867
 868        WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
 869        tmp = RREG8(DAC_DATA);
 870        tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS;
 871        tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;
 872        WREG8(DAC_DATA, tmp);
 873
 874        udelay(500);
 875
 876        WREG_DAC(MGA1064_ER_PIX_PLLC_N, xpixpllcn);
 877        WREG_DAC(MGA1064_ER_PIX_PLLC_M, xpixpllcm);
 878        WREG_DAC(MGA1064_ER_PIX_PLLC_P, xpixpllcp);
 879
 880        udelay(50);
 881}
 882
 883static const struct mgag200_pll_funcs mgag200_pixpll_funcs_g200er = {
 884        .compute = mgag200_pixpll_compute_g200er,
 885        .update = mgag200_pixpll_update_g200er,
 886};
 887
 888/*
 889 * G200EW3
 890 */
 891
 892static int mgag200_pixpll_compute_g200ew3(struct mgag200_pll *pixpll, long clock,
 893                                          struct mgag200_pll_values *pixpllc)
 894{
 895        static const unsigned int vcomax = 800000;
 896        static const unsigned int vcomin = 400000;
 897        static const unsigned int pllreffreq = 25000;
 898
 899        unsigned int delta, tmpdelta;
 900        unsigned int testp, testm, testn, testp2;
 901        unsigned int p, m, n, s;
 902        unsigned int computed;
 903
 904        m = n = p = s = 0;
 905        delta = 0xffffffff;
 906
 907        for (testp = 1; testp < 8; testp++) {
 908                for (testp2 = 1; testp2 < 8; testp2++) {
 909                        if (testp < testp2)
 910                                continue;
 911                        if ((clock * testp * testp2) > vcomax)
 912                                continue;
 913                        if ((clock * testp * testp2) < vcomin)
 914                                continue;
 915                        for (testm = 1; testm < 26; testm++) {
 916                                for (testn = 32; testn < 2048 ; testn++) {
 917                                        computed = (pllreffreq * testn) / (testm * testp * testp2);
 918                                        if (computed > clock)
 919                                                tmpdelta = computed - clock;
 920                                        else
 921                                                tmpdelta = clock - computed;
 922                                        if (tmpdelta < delta) {
 923                                                delta = tmpdelta;
 924                                                m = testm + 1;
 925                                                n = testn + 1;
 926                                                p = testp + 1;
 927                                                s = testp2;
 928                                        }
 929                                }
 930                        }
 931                }
 932        }
 933
 934        pixpllc->m = m;
 935        pixpllc->n = n;
 936        pixpllc->p = p;
 937        pixpllc->s = s;
 938
 939        return 0;
 940}
 941
 942static const struct mgag200_pll_funcs mgag200_pixpll_funcs_g200ew3 = {
 943        .compute = mgag200_pixpll_compute_g200ew3,
 944        .update = mgag200_pixpll_update_g200wb, // same as G200WB
 945};
 946
 947/*
 948 * PLL initialization
 949 */
 950
 951int mgag200_pixpll_init(struct mgag200_pll *pixpll, struct mga_device *mdev)
 952{
 953        struct drm_device *dev = &mdev->base;
 954
 955        pixpll->mdev = mdev;
 956
 957        switch (mdev->type) {
 958        case G200_PCI:
 959        case G200_AGP:
 960                pixpll->funcs = &mgag200_pixpll_funcs_g200;
 961                break;
 962        case G200_SE_A:
 963        case G200_SE_B:
 964                if (mdev->model.g200se.unique_rev_id >= 0x04)
 965                        pixpll->funcs = &mgag200_pixpll_funcs_g200se_04;
 966                else
 967                        pixpll->funcs = &mgag200_pixpll_funcs_g200se_00;
 968                break;
 969        case G200_WB:
 970                pixpll->funcs = &mgag200_pixpll_funcs_g200wb;
 971                break;
 972        case G200_EV:
 973                pixpll->funcs = &mgag200_pixpll_funcs_g200ev;
 974                break;
 975        case G200_EH:
 976                pixpll->funcs = &mgag200_pixpll_funcs_g200eh;
 977                break;
 978        case G200_EH3:
 979                pixpll->funcs = &mgag200_pixpll_funcs_g200eh3;
 980                break;
 981        case G200_ER:
 982                pixpll->funcs = &mgag200_pixpll_funcs_g200er;
 983                break;
 984        case G200_EW3:
 985                pixpll->funcs = &mgag200_pixpll_funcs_g200ew3;
 986                break;
 987        default:
 988                drm_err(dev, "unknown device type %d\n", mdev->type);
 989                return -ENODEV;
 990        }
 991
 992        return 0;
 993}
 994