cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

mgag200_pll.c (23117B)


      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}