brintos

brintos / linux-shallow public Read only

0
0
Text · 20.3 KiB · d06d248 Raw
909 lines · c
1// SPDX-License-Identifier: GPL-2.02 3/*4 *  ATI Mach64 GX Support5 */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           25725 26#define STOP_BITS_2595     0x180027 28 29#define MIN_N_408		230 31#define MIN_N_1703		632 33#define MIN_M		234#define MAX_M		3035#define MIN_N		3536#define MAX_N		255-837 38 39    /*40     *  Support Functions41     */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 Chip67     */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 old128	 *         driver129	 */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 DAC203     */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	else260		mask = 0x0C;261 262	/* The following assumes that the BIOS has correctly set R7 of the263	 * Device Setup Register A at boot time.264	 */265#define A860_DELAY_L	0x80266 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 DAC286     */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		} else305			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 Chip339     */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 Chip493     */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) <= 127540			    && (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 Chip609     */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				else661					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 Chip732     */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 Chip879     */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};909