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

mach64_gx.c (20792B)


      1// SPDX-License-Identifier: GPL-2.0
      2
      3/*
      4 *  ATI Mach64 GX Support
      5 */
      6
      7#include <linux/delay.h>
      8#include <linux/fb.h>
      9
     10#include <asm/io.h>
     11
     12#include <video/mach64.h>
     13#include "atyfb.h"
     14
     15/* Definitions for the ICS 2595 == ATI 18818_1 Clockchip */
     16
     17#define REF_FREQ_2595       1432	/*  14.33 MHz  (exact   14.31818) */
     18#define REF_DIV_2595          46	/* really 43 on ICS 2595 !!!  */
     19				  /* ohne Prescaler */
     20#define MAX_FREQ_2595      15938	/* 159.38 MHz  (really 170.486) */
     21#define MIN_FREQ_2595       8000	/*  80.00 MHz  (        85.565) */
     22				  /* mit Prescaler 2, 4, 8 */
     23#define ABS_MIN_FREQ_2595   1000	/*  10.00 MHz  (really  10.697) */
     24#define N_ADJ_2595           257
     25
     26#define STOP_BITS_2595     0x1800
     27
     28
     29#define MIN_N_408		2
     30
     31#define MIN_N_1703		6
     32
     33#define MIN_M		2
     34#define MAX_M		30
     35#define MIN_N		35
     36#define MAX_N		255-8
     37
     38
     39    /*
     40     *  Support Functions
     41     */
     42
     43static void aty_dac_waste4(const struct atyfb_par *par)
     44{
     45	(void) aty_ld_8(DAC_REGS, par);
     46
     47	(void) aty_ld_8(DAC_REGS + 2, par);
     48	(void) aty_ld_8(DAC_REGS + 2, par);
     49	(void) aty_ld_8(DAC_REGS + 2, par);
     50	(void) aty_ld_8(DAC_REGS + 2, par);
     51}
     52
     53static void aty_StrobeClock(const struct atyfb_par *par)
     54{
     55	u8 tmp;
     56
     57	udelay(26);
     58
     59	tmp = aty_ld_8(CLOCK_CNTL, par);
     60	aty_st_8(CLOCK_CNTL + par->clk_wr_offset, tmp | CLOCK_STROBE, par);
     61	return;
     62}
     63
     64
     65    /*
     66     *  IBM RGB514 DAC and Clock Chip
     67     */
     68
     69static void aty_st_514(int offset, u8 val, const struct atyfb_par *par)
     70{
     71	aty_st_8(DAC_CNTL, 1, par);
     72	/* right addr byte */
     73	aty_st_8(DAC_W_INDEX, offset & 0xff, par);
     74	/* left addr byte */
     75	aty_st_8(DAC_DATA, (offset >> 8) & 0xff, par);
     76	aty_st_8(DAC_MASK, val, par);
     77	aty_st_8(DAC_CNTL, 0, par);
     78}
     79
     80static int aty_set_dac_514(const struct fb_info *info,
     81			   const union aty_pll *pll, u32 bpp, u32 accel)
     82{
     83	struct atyfb_par *par = (struct atyfb_par *) info->par;
     84	static struct {
     85		u8 pixel_dly;
     86		u8 misc2_cntl;
     87		u8 pixel_rep;
     88		u8 pixel_cntl_index;
     89		u8 pixel_cntl_v1;
     90	} tab[3] = {
     91		{
     92		0, 0x41, 0x03, 0x71, 0x45},	/* 8 bpp */
     93		{
     94		0, 0x45, 0x04, 0x0c, 0x01},	/* 555 */
     95		{
     96		0, 0x45, 0x06, 0x0e, 0x00},	/* XRGB */
     97	};
     98	int i;
     99
    100	switch (bpp) {
    101	case 8:
    102	default:
    103		i = 0;
    104		break;
    105	case 16:
    106		i = 1;
    107		break;
    108	case 32:
    109		i = 2;
    110		break;
    111	}
    112	aty_st_514(0x90, 0x00, par);	/* VRAM Mask Low */
    113	aty_st_514(0x04, tab[i].pixel_dly, par);	/* Horizontal Sync Control */
    114	aty_st_514(0x05, 0x00, par);	/* Power Management */
    115	aty_st_514(0x02, 0x01, par);	/* Misc Clock Control */
    116	aty_st_514(0x71, tab[i].misc2_cntl, par);	/* Misc Control 2 */
    117	aty_st_514(0x0a, tab[i].pixel_rep, par);	/* Pixel Format */
    118	aty_st_514(tab[i].pixel_cntl_index, tab[i].pixel_cntl_v1, par);
    119	/* Misc Control 2 / 16 BPP Control / 32 BPP Control */
    120	return 0;
    121}
    122
    123static int aty_var_to_pll_514(const struct fb_info *info, u32 vclk_per,
    124			      u32 bpp, union aty_pll *pll)
    125{
    126	/*
    127	 *  FIXME: use real calculations instead of using fixed values from the old
    128	 *         driver
    129	 */
    130	static struct {
    131		u32 limit;	/* pixlock rounding limit (arbitrary) */
    132		u8 m;		/* (df<<6) | vco_div_count */
    133		u8 n;		/* ref_div_count */
    134	} RGB514_clocks[7] = {
    135		{
    136		8000, (3 << 6) | 20, 9},	/*  7395 ps / 135.2273 MHz */
    137		{
    138		10000, (1 << 6) | 19, 3},	/*  9977 ps / 100.2273 MHz */
    139		{
    140		13000, (1 << 6) | 2, 3},	/* 12509 ps /  79.9432 MHz */
    141		{
    142		14000, (2 << 6) | 8, 7},	/* 13394 ps /  74.6591 MHz */
    143		{
    144		16000, (1 << 6) | 44, 6},	/* 15378 ps /  65.0284 MHz */
    145		{
    146		25000, (1 << 6) | 15, 5},	/* 17460 ps /  57.2727 MHz */
    147		{
    148		50000, (0 << 6) | 53, 7},	/* 33145 ps /  30.1705 MHz */
    149	};
    150	int i;
    151
    152	for (i = 0; i < ARRAY_SIZE(RGB514_clocks); i++)
    153		if (vclk_per <= RGB514_clocks[i].limit) {
    154			pll->ibm514.m = RGB514_clocks[i].m;
    155			pll->ibm514.n = RGB514_clocks[i].n;
    156			return 0;
    157		}
    158	return -EINVAL;
    159}
    160
    161static u32 aty_pll_514_to_var(const struct fb_info *info,
    162			      const union aty_pll *pll)
    163{
    164	struct atyfb_par *par = (struct atyfb_par *) info->par;
    165	u8 df, vco_div_count, ref_div_count;
    166
    167	df = pll->ibm514.m >> 6;
    168	vco_div_count = pll->ibm514.m & 0x3f;
    169	ref_div_count = pll->ibm514.n;
    170
    171	return ((par->ref_clk_per * ref_div_count) << (3 - df))/
    172	    		(vco_div_count + 65);
    173}
    174
    175static void aty_set_pll_514(const struct fb_info *info,
    176			    const union aty_pll *pll)
    177{
    178	struct atyfb_par *par = (struct atyfb_par *) info->par;
    179
    180	aty_st_514(0x06, 0x02, par);	/* DAC Operation */
    181	aty_st_514(0x10, 0x01, par);	/* PLL Control 1 */
    182	aty_st_514(0x70, 0x01, par);	/* Misc Control 1 */
    183	aty_st_514(0x8f, 0x1f, par);	/* PLL Ref. Divider Input */
    184	aty_st_514(0x03, 0x00, par);	/* Sync Control */
    185	aty_st_514(0x05, 0x00, par);	/* Power Management */
    186	aty_st_514(0x20, pll->ibm514.m, par);	/* F0 / M0 */
    187	aty_st_514(0x21, pll->ibm514.n, par);	/* F1 / N0 */
    188}
    189
    190const struct aty_dac_ops aty_dac_ibm514 = {
    191	.set_dac	= aty_set_dac_514,
    192};
    193
    194const struct aty_pll_ops aty_pll_ibm514 = {
    195	.var_to_pll	= aty_var_to_pll_514,
    196	.pll_to_var	= aty_pll_514_to_var,
    197	.set_pll	= aty_set_pll_514,
    198};
    199
    200
    201    /*
    202     *  ATI 68860-B DAC
    203     */
    204
    205static int aty_set_dac_ATI68860_B(const struct fb_info *info,
    206				  const union aty_pll *pll, u32 bpp,
    207				  u32 accel)
    208{
    209	struct atyfb_par *par = (struct atyfb_par *) info->par;
    210	u32 gModeReg, devSetupRegA, temp, mask;
    211
    212	gModeReg = 0;
    213	devSetupRegA = 0;
    214
    215	switch (bpp) {
    216	case 8:
    217		gModeReg = 0x83;
    218		devSetupRegA =
    219		    0x60 | 0x00 /*(info->mach64DAC8Bit ? 0x00 : 0x01) */ ;
    220		break;
    221	case 15:
    222		gModeReg = 0xA0;
    223		devSetupRegA = 0x60;
    224		break;
    225	case 16:
    226		gModeReg = 0xA1;
    227		devSetupRegA = 0x60;
    228		break;
    229	case 24:
    230		gModeReg = 0xC0;
    231		devSetupRegA = 0x60;
    232		break;
    233	case 32:
    234		gModeReg = 0xE3;
    235		devSetupRegA = 0x60;
    236		break;
    237	}
    238
    239	if (!accel) {
    240		gModeReg = 0x80;
    241		devSetupRegA = 0x61;
    242	}
    243
    244	temp = aty_ld_8(DAC_CNTL, par);
    245	aty_st_8(DAC_CNTL, (temp & ~DAC_EXT_SEL_RS2) | DAC_EXT_SEL_RS3,
    246		 par);
    247
    248	aty_st_8(DAC_REGS + 2, 0x1D, par);
    249	aty_st_8(DAC_REGS + 3, gModeReg, par);
    250	aty_st_8(DAC_REGS, 0x02, par);
    251
    252	temp = aty_ld_8(DAC_CNTL, par);
    253	aty_st_8(DAC_CNTL, temp | DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3, par);
    254
    255	if (info->fix.smem_len < ONE_MB)
    256		mask = 0x04;
    257	else if (info->fix.smem_len == ONE_MB)
    258		mask = 0x08;
    259	else
    260		mask = 0x0C;
    261
    262	/* The following assumes that the BIOS has correctly set R7 of the
    263	 * Device Setup Register A at boot time.
    264	 */
    265#define A860_DELAY_L	0x80
    266
    267	temp = aty_ld_8(DAC_REGS, par);
    268	aty_st_8(DAC_REGS, (devSetupRegA | mask) | (temp & A860_DELAY_L),
    269		 par);
    270	temp = aty_ld_8(DAC_CNTL, par);
    271	aty_st_8(DAC_CNTL, (temp & ~(DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3)),
    272		 par);
    273
    274	aty_st_le32(BUS_CNTL, 0x890e20f1, par);
    275	aty_st_le32(DAC_CNTL, 0x47052100, par);
    276	return 0;
    277}
    278
    279const struct aty_dac_ops aty_dac_ati68860b = {
    280	.set_dac	= aty_set_dac_ATI68860_B,
    281};
    282
    283
    284    /*
    285     *  AT&T 21C498 DAC
    286     */
    287
    288static int aty_set_dac_ATT21C498(const struct fb_info *info,
    289				 const union aty_pll *pll, u32 bpp,
    290				 u32 accel)
    291{
    292	struct atyfb_par *par = (struct atyfb_par *) info->par;
    293	u32 dotClock;
    294	int muxmode = 0;
    295	int DACMask = 0;
    296
    297	dotClock = 100000000 / pll->ics2595.period_in_ps;
    298
    299	switch (bpp) {
    300	case 8:
    301		if (dotClock > 8000) {
    302			DACMask = 0x24;
    303			muxmode = 1;
    304		} else
    305			DACMask = 0x04;
    306		break;
    307	case 15:
    308		DACMask = 0x16;
    309		break;
    310	case 16:
    311		DACMask = 0x36;
    312		break;
    313	case 24:
    314		DACMask = 0xE6;
    315		break;
    316	case 32:
    317		DACMask = 0xE6;
    318		break;
    319	}
    320
    321	if (1 /* info->mach64DAC8Bit */ )
    322		DACMask |= 0x02;
    323
    324	aty_dac_waste4(par);
    325	aty_st_8(DAC_REGS + 2, DACMask, par);
    326
    327	aty_st_le32(BUS_CNTL, 0x890e20f1, par);
    328	aty_st_le32(DAC_CNTL, 0x00072000, par);
    329	return muxmode;
    330}
    331
    332const struct aty_dac_ops aty_dac_att21c498 = {
    333	.set_dac	= aty_set_dac_ATT21C498,
    334};
    335
    336
    337    /*
    338     *  ATI 18818 / ICS 2595 Clock Chip
    339     */
    340
    341static int aty_var_to_pll_18818(const struct fb_info *info, u32 vclk_per,
    342				u32 bpp, union aty_pll *pll)
    343{
    344	u32 MHz100;		/* in 0.01 MHz */
    345	u32 program_bits;
    346	u32 post_divider;
    347
    348	/* Calculate the programming word */
    349	MHz100 = 100000000 / vclk_per;
    350
    351	program_bits = -1;
    352	post_divider = 1;
    353
    354	if (MHz100 > MAX_FREQ_2595) {
    355		return -EINVAL;
    356	} else if (MHz100 < ABS_MIN_FREQ_2595) {
    357		return -EINVAL;
    358	} else {
    359		while (MHz100 < MIN_FREQ_2595) {
    360			MHz100 *= 2;
    361			post_divider *= 2;
    362		}
    363	}
    364	MHz100 *= 1000;
    365	MHz100 = (REF_DIV_2595 * MHz100) / REF_FREQ_2595;
    366 
    367	MHz100 += 500;		/* + 0.5 round */
    368	MHz100 /= 1000;
    369
    370	if (program_bits == -1) {
    371		program_bits = MHz100 - N_ADJ_2595;
    372		switch (post_divider) {
    373		case 1:
    374			program_bits |= 0x0600;
    375			break;
    376		case 2:
    377			program_bits |= 0x0400;
    378			break;
    379		case 4:
    380			program_bits |= 0x0200;
    381			break;
    382		case 8:
    383		default:
    384			break;
    385		}
    386	}
    387
    388	program_bits |= STOP_BITS_2595;
    389
    390	pll->ics2595.program_bits = program_bits;
    391	pll->ics2595.locationAddr = 0;
    392	pll->ics2595.post_divider = post_divider;
    393	pll->ics2595.period_in_ps = vclk_per;
    394
    395	return 0;
    396}
    397
    398static u32 aty_pll_18818_to_var(const struct fb_info *info,
    399				const union aty_pll *pll)
    400{
    401	return (pll->ics2595.period_in_ps);	/* default for now */
    402}
    403
    404static void aty_ICS2595_put1bit(u8 data, const struct atyfb_par *par)
    405{
    406	u8 tmp;
    407
    408	data &= 0x01;
    409	tmp = aty_ld_8(CLOCK_CNTL, par);
    410	aty_st_8(CLOCK_CNTL + par->clk_wr_offset,
    411		 (tmp & ~0x04) | (data << 2), par);
    412
    413	tmp = aty_ld_8(CLOCK_CNTL, par);
    414	aty_st_8(CLOCK_CNTL + par->clk_wr_offset, (tmp & ~0x08) | (0 << 3),
    415		 par);
    416
    417	aty_StrobeClock(par);
    418
    419	tmp = aty_ld_8(CLOCK_CNTL, par);
    420	aty_st_8(CLOCK_CNTL + par->clk_wr_offset, (tmp & ~0x08) | (1 << 3),
    421		 par);
    422
    423	aty_StrobeClock(par);
    424	return;
    425}
    426
    427static void aty_set_pll18818(const struct fb_info *info,
    428			     const union aty_pll *pll)
    429{
    430	struct atyfb_par *par = (struct atyfb_par *) info->par;
    431	u32 program_bits;
    432	u32 locationAddr;
    433
    434	u32 i;
    435
    436	u8 old_clock_cntl;
    437	u8 old_crtc_ext_disp;
    438
    439	old_clock_cntl = aty_ld_8(CLOCK_CNTL, par);
    440	aty_st_8(CLOCK_CNTL + par->clk_wr_offset, 0, par);
    441
    442	old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, par);
    443	aty_st_8(CRTC_GEN_CNTL + 3,
    444		 old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24), par);
    445
    446	mdelay(15);		/* delay for 50 (15) ms */
    447
    448	program_bits = pll->ics2595.program_bits;
    449	locationAddr = pll->ics2595.locationAddr;
    450
    451	/* Program the clock chip */
    452	aty_st_8(CLOCK_CNTL + par->clk_wr_offset, 0, par);	/* Strobe = 0 */
    453	aty_StrobeClock(par);
    454	aty_st_8(CLOCK_CNTL + par->clk_wr_offset, 1, par);	/* Strobe = 0 */
    455	aty_StrobeClock(par);
    456
    457	aty_ICS2595_put1bit(1, par);	/* Send start bits */
    458	aty_ICS2595_put1bit(0, par);	/* Start bit */
    459	aty_ICS2595_put1bit(0, par);	/* Read / ~Write */
    460
    461	for (i = 0; i < 5; i++) {	/* Location 0..4 */
    462		aty_ICS2595_put1bit(locationAddr & 1, par);
    463		locationAddr >>= 1;
    464	}
    465
    466	for (i = 0; i < 8 + 1 + 2 + 2; i++) {
    467		aty_ICS2595_put1bit(program_bits & 1, par);
    468		program_bits >>= 1;
    469	}
    470
    471	mdelay(1);		/* delay for 1 ms */
    472
    473	(void) aty_ld_8(DAC_REGS, par);	/* Clear DAC Counter */
    474	aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, par);
    475	aty_st_8(CLOCK_CNTL + par->clk_wr_offset,
    476		 old_clock_cntl | CLOCK_STROBE, par);
    477
    478	mdelay(50);		/* delay for 50 (15) ms */
    479	aty_st_8(CLOCK_CNTL + par->clk_wr_offset,
    480		 ((pll->ics2595.locationAddr & 0x0F) | CLOCK_STROBE), par);
    481	return;
    482}
    483
    484const struct aty_pll_ops aty_pll_ati18818_1 = {
    485	.var_to_pll	= aty_var_to_pll_18818,
    486	.pll_to_var	= aty_pll_18818_to_var,
    487	.set_pll	= aty_set_pll18818,
    488};
    489
    490
    491    /*
    492     *  STG 1703 Clock Chip
    493     */
    494
    495static int aty_var_to_pll_1703(const struct fb_info *info, u32 vclk_per,
    496			       u32 bpp, union aty_pll *pll)
    497{
    498	u32 mhz100;		/* in 0.01 MHz */
    499	u32 program_bits;
    500	/* u32 post_divider; */
    501	u32 mach64MinFreq, mach64MaxFreq, mach64RefFreq;
    502	u32 temp, tempB;
    503	u16 remainder, preRemainder;
    504	short divider = 0, tempA;
    505
    506	/* Calculate the programming word */
    507	mhz100 = 100000000 / vclk_per;
    508	mach64MinFreq = MIN_FREQ_2595;
    509	mach64MaxFreq = MAX_FREQ_2595;
    510	mach64RefFreq = REF_FREQ_2595;	/* 14.32 MHz */
    511
    512	/* Calculate program word */
    513	if (mhz100 == 0)
    514		program_bits = 0xE0;
    515	else {
    516		if (mhz100 < mach64MinFreq)
    517			mhz100 = mach64MinFreq;
    518		if (mhz100 > mach64MaxFreq)
    519			mhz100 = mach64MaxFreq;
    520
    521		divider = 0;
    522		while (mhz100 < (mach64MinFreq << 3)) {
    523			mhz100 <<= 1;
    524			divider += 0x20;
    525		}
    526
    527		temp = (unsigned int) (mhz100);
    528		temp = (unsigned int) (temp * (MIN_N_1703 + 2));
    529		temp -= (short) (mach64RefFreq << 1);
    530
    531		tempA = MIN_N_1703;
    532		preRemainder = 0xffff;
    533
    534		do {
    535			tempB = temp;
    536			remainder = tempB % mach64RefFreq;
    537			tempB = tempB / mach64RefFreq;
    538
    539			if ((tempB & 0xffff) <= 127
    540			    && (remainder <= preRemainder)) {
    541				preRemainder = remainder;
    542				divider &= ~0x1f;
    543				divider |= tempA;
    544				divider =
    545				    (divider & 0x00ff) +
    546				    ((tempB & 0xff) << 8);
    547			}
    548
    549			temp += mhz100;
    550			tempA++;
    551		} while (tempA <= (MIN_N_1703 << 1));
    552
    553		program_bits = divider;
    554	}
    555
    556	pll->ics2595.program_bits = program_bits;
    557	pll->ics2595.locationAddr = 0;
    558	pll->ics2595.post_divider = divider;	/* fuer nix */
    559	pll->ics2595.period_in_ps = vclk_per;
    560
    561	return 0;
    562}
    563
    564static u32 aty_pll_1703_to_var(const struct fb_info *info,
    565			       const union aty_pll *pll)
    566{
    567	return (pll->ics2595.period_in_ps);	/* default for now */
    568}
    569
    570static void aty_set_pll_1703(const struct fb_info *info,
    571			     const union aty_pll *pll)
    572{
    573	struct atyfb_par *par = (struct atyfb_par *) info->par;
    574	u32 program_bits;
    575	u32 locationAddr;
    576
    577	char old_crtc_ext_disp;
    578
    579	old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, par);
    580	aty_st_8(CRTC_GEN_CNTL + 3,
    581		 old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24), par);
    582
    583	program_bits = pll->ics2595.program_bits;
    584	locationAddr = pll->ics2595.locationAddr;
    585
    586	/* Program clock */
    587	aty_dac_waste4(par);
    588
    589	(void) aty_ld_8(DAC_REGS + 2, par);
    590	aty_st_8(DAC_REGS + 2, (locationAddr << 1) + 0x20, par);
    591	aty_st_8(DAC_REGS + 2, 0, par);
    592	aty_st_8(DAC_REGS + 2, (program_bits & 0xFF00) >> 8, par);
    593	aty_st_8(DAC_REGS + 2, (program_bits & 0xFF), par);
    594
    595	(void) aty_ld_8(DAC_REGS, par);	/* Clear DAC Counter */
    596	aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, par);
    597	return;
    598}
    599
    600const struct aty_pll_ops aty_pll_stg1703 = {
    601	.var_to_pll	= aty_var_to_pll_1703,
    602	.pll_to_var	= aty_pll_1703_to_var,
    603	.set_pll	= aty_set_pll_1703,
    604};
    605
    606
    607    /*
    608     *  Chrontel 8398 Clock Chip
    609     */
    610
    611static int aty_var_to_pll_8398(const struct fb_info *info, u32 vclk_per,
    612			       u32 bpp, union aty_pll *pll)
    613{
    614	u32 tempA, tempB, fOut, longMHz100, diff, preDiff;
    615
    616	u32 mhz100;		/* in 0.01 MHz */
    617	u32 program_bits;
    618	/* u32 post_divider; */
    619	u32 mach64MinFreq, mach64MaxFreq;
    620	u16 m, n, k = 0, save_m, save_n, twoToKth;
    621
    622	/* Calculate the programming word */
    623	mhz100 = 100000000 / vclk_per;
    624	mach64MinFreq = MIN_FREQ_2595;
    625	mach64MaxFreq = MAX_FREQ_2595;
    626
    627	save_m = 0;
    628	save_n = 0;
    629
    630	/* Calculate program word */
    631	if (mhz100 == 0)
    632		program_bits = 0xE0;
    633	else {
    634		if (mhz100 < mach64MinFreq)
    635			mhz100 = mach64MinFreq;
    636		if (mhz100 > mach64MaxFreq)
    637			mhz100 = mach64MaxFreq;
    638
    639		longMHz100 = mhz100 * 256 / 100;	/* 8 bit scale this */
    640
    641		while (mhz100 < (mach64MinFreq << 3)) {
    642			mhz100 <<= 1;
    643			k++;
    644		}
    645
    646		twoToKth = 1 << k;
    647		diff = 0;
    648		preDiff = 0xFFFFFFFF;
    649
    650		for (m = MIN_M; m <= MAX_M; m++) {
    651			for (n = MIN_N; n <= MAX_N; n++) {
    652				tempA = 938356;		/* 14.31818 * 65536 */
    653				tempA *= (n + 8);	/* 43..256 */
    654				tempB = twoToKth * 256;
    655				tempB *= (m + 2);	/* 4..32 */
    656				fOut = tempA / tempB;	/* 8 bit scale */
    657
    658				if (longMHz100 > fOut)
    659					diff = longMHz100 - fOut;
    660				else
    661					diff = fOut - longMHz100;
    662
    663				if (diff < preDiff) {
    664					save_m = m;
    665					save_n = n;
    666					preDiff = diff;
    667				}
    668			}
    669		}
    670
    671		program_bits = (k << 6) + (save_m) + (save_n << 8);
    672	}
    673
    674	pll->ics2595.program_bits = program_bits;
    675	pll->ics2595.locationAddr = 0;
    676	pll->ics2595.post_divider = 0;
    677	pll->ics2595.period_in_ps = vclk_per;
    678
    679	return 0;
    680}
    681
    682static u32 aty_pll_8398_to_var(const struct fb_info *info,
    683			       const union aty_pll *pll)
    684{
    685	return (pll->ics2595.period_in_ps);	/* default for now */
    686}
    687
    688static void aty_set_pll_8398(const struct fb_info *info,
    689			     const union aty_pll *pll)
    690{
    691	struct atyfb_par *par = (struct atyfb_par *) info->par;
    692	u32 program_bits;
    693	u32 locationAddr;
    694
    695	char old_crtc_ext_disp;
    696	char tmp;
    697
    698	old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, par);
    699	aty_st_8(CRTC_GEN_CNTL + 3,
    700		 old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24), par);
    701
    702	program_bits = pll->ics2595.program_bits;
    703	locationAddr = pll->ics2595.locationAddr;
    704
    705	/* Program clock */
    706	tmp = aty_ld_8(DAC_CNTL, par);
    707	aty_st_8(DAC_CNTL, tmp | DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3, par);
    708
    709	aty_st_8(DAC_REGS, locationAddr, par);
    710	aty_st_8(DAC_REGS + 1, (program_bits & 0xff00) >> 8, par);
    711	aty_st_8(DAC_REGS + 1, (program_bits & 0xff), par);
    712
    713	tmp = aty_ld_8(DAC_CNTL, par);
    714	aty_st_8(DAC_CNTL, (tmp & ~DAC_EXT_SEL_RS2) | DAC_EXT_SEL_RS3,
    715		 par);
    716
    717	(void) aty_ld_8(DAC_REGS, par);	/* Clear DAC Counter */
    718	aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, par);
    719
    720	return;
    721}
    722
    723const struct aty_pll_ops aty_pll_ch8398 = {
    724	.var_to_pll	= aty_var_to_pll_8398,
    725	.pll_to_var	= aty_pll_8398_to_var,
    726	.set_pll	= aty_set_pll_8398,
    727};
    728
    729
    730    /*
    731     *  AT&T 20C408 Clock Chip
    732     */
    733
    734static int aty_var_to_pll_408(const struct fb_info *info, u32 vclk_per,
    735			      u32 bpp, union aty_pll *pll)
    736{
    737	u32 mhz100;		/* in 0.01 MHz */
    738	u32 program_bits;
    739	/* u32 post_divider; */
    740	u32 mach64MinFreq, mach64MaxFreq, mach64RefFreq;
    741	u32 temp, tempB;
    742	u16 remainder, preRemainder;
    743	short divider = 0, tempA;
    744
    745	/* Calculate the programming word */
    746	mhz100 = 100000000 / vclk_per;
    747	mach64MinFreq = MIN_FREQ_2595;
    748	mach64MaxFreq = MAX_FREQ_2595;
    749	mach64RefFreq = REF_FREQ_2595;	/* 14.32 MHz */
    750
    751	/* Calculate program word */
    752	if (mhz100 == 0)
    753		program_bits = 0xFF;
    754	else {
    755		if (mhz100 < mach64MinFreq)
    756			mhz100 = mach64MinFreq;
    757		if (mhz100 > mach64MaxFreq)
    758			mhz100 = mach64MaxFreq;
    759
    760		while (mhz100 < (mach64MinFreq << 3)) {
    761			mhz100 <<= 1;
    762			divider += 0x40;
    763		}
    764
    765		temp = (unsigned int) mhz100;
    766		temp = (unsigned int) (temp * (MIN_N_408 + 2));
    767		temp -= ((short) (mach64RefFreq << 1));
    768
    769		tempA = MIN_N_408;
    770		preRemainder = 0xFFFF;
    771
    772		do {
    773			tempB = temp;
    774			remainder = tempB % mach64RefFreq;
    775			tempB = tempB / mach64RefFreq;
    776			if (((tempB & 0xFFFF) <= 255)
    777			    && (remainder <= preRemainder)) {
    778				preRemainder = remainder;
    779				divider &= ~0x3f;
    780				divider |= tempA;
    781				divider =
    782				    (divider & 0x00FF) +
    783				    ((tempB & 0xFF) << 8);
    784			}
    785			temp += mhz100;
    786			tempA++;
    787		} while (tempA <= 32);
    788
    789		program_bits = divider;
    790	}
    791
    792	pll->ics2595.program_bits = program_bits;
    793	pll->ics2595.locationAddr = 0;
    794	pll->ics2595.post_divider = divider;	/* fuer nix */
    795	pll->ics2595.period_in_ps = vclk_per;
    796
    797	return 0;
    798}
    799
    800static u32 aty_pll_408_to_var(const struct fb_info *info,
    801			      const union aty_pll *pll)
    802{
    803	return (pll->ics2595.period_in_ps);	/* default for now */
    804}
    805
    806static void aty_set_pll_408(const struct fb_info *info,
    807			    const union aty_pll *pll)
    808{
    809	struct atyfb_par *par = (struct atyfb_par *) info->par;
    810	u32 program_bits;
    811	u32 locationAddr;
    812
    813	u8 tmpA, tmpB, tmpC;
    814	char old_crtc_ext_disp;
    815
    816	old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, par);
    817	aty_st_8(CRTC_GEN_CNTL + 3,
    818		 old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24), par);
    819
    820	program_bits = pll->ics2595.program_bits;
    821	locationAddr = pll->ics2595.locationAddr;
    822
    823	/* Program clock */
    824	aty_dac_waste4(par);
    825	tmpB = aty_ld_8(DAC_REGS + 2, par) | 1;
    826	aty_dac_waste4(par);
    827	aty_st_8(DAC_REGS + 2, tmpB, par);
    828
    829	tmpA = tmpB;
    830	tmpC = tmpA;
    831	tmpA |= 8;
    832	tmpB = 1;
    833
    834	aty_st_8(DAC_REGS, tmpB, par);
    835	aty_st_8(DAC_REGS + 2, tmpA, par);
    836
    837	udelay(400);		/* delay for 400 us */
    838
    839	locationAddr = (locationAddr << 2) + 0x40;
    840	tmpB = locationAddr;
    841	tmpA = program_bits >> 8;
    842
    843	aty_st_8(DAC_REGS, tmpB, par);
    844	aty_st_8(DAC_REGS + 2, tmpA, par);
    845
    846	tmpB = locationAddr + 1;
    847	tmpA = (u8) program_bits;
    848
    849	aty_st_8(DAC_REGS, tmpB, par);
    850	aty_st_8(DAC_REGS + 2, tmpA, par);
    851
    852	tmpB = locationAddr + 2;
    853	tmpA = 0x77;
    854
    855	aty_st_8(DAC_REGS, tmpB, par);
    856	aty_st_8(DAC_REGS + 2, tmpA, par);
    857
    858	udelay(400);		/* delay for 400 us */
    859	tmpA = tmpC & (~(1 | 8));
    860	tmpB = 1;
    861
    862	aty_st_8(DAC_REGS, tmpB, par);
    863	aty_st_8(DAC_REGS + 2, tmpA, par);
    864
    865	(void) aty_ld_8(DAC_REGS, par);	/* Clear DAC Counter */
    866	aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, par);
    867	return;
    868}
    869
    870const struct aty_pll_ops aty_pll_att20c408 = {
    871	.var_to_pll	= aty_var_to_pll_408,
    872	.pll_to_var	= aty_pll_408_to_var,
    873	.set_pll	= aty_set_pll_408,
    874};
    875
    876
    877    /*
    878     *  Unsupported DAC and Clock Chip
    879     */
    880
    881static int aty_set_dac_unsupported(const struct fb_info *info,
    882				   const union aty_pll *pll, u32 bpp,
    883				   u32 accel)
    884{
    885	struct atyfb_par *par = (struct atyfb_par *) info->par;
    886
    887	aty_st_le32(BUS_CNTL, 0x890e20f1, par);
    888	aty_st_le32(DAC_CNTL, 0x47052100, par);
    889	/* new in 2.2.3p1 from Geert. ???????? */
    890	aty_st_le32(BUS_CNTL, 0x590e10ff, par);
    891	aty_st_le32(DAC_CNTL, 0x47012100, par);
    892	return 0;
    893}
    894
    895static int dummy(void)
    896{
    897	return 0;
    898}
    899
    900const struct aty_dac_ops aty_dac_unsupported = {
    901	.set_dac	= aty_set_dac_unsupported,
    902};
    903
    904const struct aty_pll_ops aty_pll_unsupported = {
    905	.var_to_pll	= (void *) dummy,
    906	.pll_to_var	= (void *) dummy,
    907	.set_pll	= (void *) dummy,
    908};