18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci
38c2ecf20Sopenharmony_ci/*
48c2ecf20Sopenharmony_ci *  ATI Mach64 GX Support
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <linux/delay.h>
88c2ecf20Sopenharmony_ci#include <linux/fb.h>
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <asm/io.h>
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <video/mach64.h>
138c2ecf20Sopenharmony_ci#include "atyfb.h"
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci/* Definitions for the ICS 2595 == ATI 18818_1 Clockchip */
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#define REF_FREQ_2595       1432	/*  14.33 MHz  (exact   14.31818) */
188c2ecf20Sopenharmony_ci#define REF_DIV_2595          46	/* really 43 on ICS 2595 !!!  */
198c2ecf20Sopenharmony_ci				  /* ohne Prescaler */
208c2ecf20Sopenharmony_ci#define MAX_FREQ_2595      15938	/* 159.38 MHz  (really 170.486) */
218c2ecf20Sopenharmony_ci#define MIN_FREQ_2595       8000	/*  80.00 MHz  (        85.565) */
228c2ecf20Sopenharmony_ci				  /* mit Prescaler 2, 4, 8 */
238c2ecf20Sopenharmony_ci#define ABS_MIN_FREQ_2595   1000	/*  10.00 MHz  (really  10.697) */
248c2ecf20Sopenharmony_ci#define N_ADJ_2595           257
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#define STOP_BITS_2595     0x1800
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#define MIN_N_408		2
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#define MIN_N_1703		6
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#define MIN_M		2
348c2ecf20Sopenharmony_ci#define MAX_M		30
358c2ecf20Sopenharmony_ci#define MIN_N		35
368c2ecf20Sopenharmony_ci#define MAX_N		255-8
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci    /*
408c2ecf20Sopenharmony_ci     *  Support Functions
418c2ecf20Sopenharmony_ci     */
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_cistatic void aty_dac_waste4(const struct atyfb_par *par)
448c2ecf20Sopenharmony_ci{
458c2ecf20Sopenharmony_ci	(void) aty_ld_8(DAC_REGS, par);
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	(void) aty_ld_8(DAC_REGS + 2, par);
488c2ecf20Sopenharmony_ci	(void) aty_ld_8(DAC_REGS + 2, par);
498c2ecf20Sopenharmony_ci	(void) aty_ld_8(DAC_REGS + 2, par);
508c2ecf20Sopenharmony_ci	(void) aty_ld_8(DAC_REGS + 2, par);
518c2ecf20Sopenharmony_ci}
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_cistatic void aty_StrobeClock(const struct atyfb_par *par)
548c2ecf20Sopenharmony_ci{
558c2ecf20Sopenharmony_ci	u8 tmp;
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	udelay(26);
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	tmp = aty_ld_8(CLOCK_CNTL, par);
608c2ecf20Sopenharmony_ci	aty_st_8(CLOCK_CNTL + par->clk_wr_offset, tmp | CLOCK_STROBE, par);
618c2ecf20Sopenharmony_ci	return;
628c2ecf20Sopenharmony_ci}
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci    /*
668c2ecf20Sopenharmony_ci     *  IBM RGB514 DAC and Clock Chip
678c2ecf20Sopenharmony_ci     */
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistatic void aty_st_514(int offset, u8 val, const struct atyfb_par *par)
708c2ecf20Sopenharmony_ci{
718c2ecf20Sopenharmony_ci	aty_st_8(DAC_CNTL, 1, par);
728c2ecf20Sopenharmony_ci	/* right addr byte */
738c2ecf20Sopenharmony_ci	aty_st_8(DAC_W_INDEX, offset & 0xff, par);
748c2ecf20Sopenharmony_ci	/* left addr byte */
758c2ecf20Sopenharmony_ci	aty_st_8(DAC_DATA, (offset >> 8) & 0xff, par);
768c2ecf20Sopenharmony_ci	aty_st_8(DAC_MASK, val, par);
778c2ecf20Sopenharmony_ci	aty_st_8(DAC_CNTL, 0, par);
788c2ecf20Sopenharmony_ci}
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_cistatic int aty_set_dac_514(const struct fb_info *info,
818c2ecf20Sopenharmony_ci			   const union aty_pll *pll, u32 bpp, u32 accel)
828c2ecf20Sopenharmony_ci{
838c2ecf20Sopenharmony_ci	struct atyfb_par *par = (struct atyfb_par *) info->par;
848c2ecf20Sopenharmony_ci	static struct {
858c2ecf20Sopenharmony_ci		u8 pixel_dly;
868c2ecf20Sopenharmony_ci		u8 misc2_cntl;
878c2ecf20Sopenharmony_ci		u8 pixel_rep;
888c2ecf20Sopenharmony_ci		u8 pixel_cntl_index;
898c2ecf20Sopenharmony_ci		u8 pixel_cntl_v1;
908c2ecf20Sopenharmony_ci	} tab[3] = {
918c2ecf20Sopenharmony_ci		{
928c2ecf20Sopenharmony_ci		0, 0x41, 0x03, 0x71, 0x45},	/* 8 bpp */
938c2ecf20Sopenharmony_ci		{
948c2ecf20Sopenharmony_ci		0, 0x45, 0x04, 0x0c, 0x01},	/* 555 */
958c2ecf20Sopenharmony_ci		{
968c2ecf20Sopenharmony_ci		0, 0x45, 0x06, 0x0e, 0x00},	/* XRGB */
978c2ecf20Sopenharmony_ci	};
988c2ecf20Sopenharmony_ci	int i;
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	switch (bpp) {
1018c2ecf20Sopenharmony_ci	case 8:
1028c2ecf20Sopenharmony_ci	default:
1038c2ecf20Sopenharmony_ci		i = 0;
1048c2ecf20Sopenharmony_ci		break;
1058c2ecf20Sopenharmony_ci	case 16:
1068c2ecf20Sopenharmony_ci		i = 1;
1078c2ecf20Sopenharmony_ci		break;
1088c2ecf20Sopenharmony_ci	case 32:
1098c2ecf20Sopenharmony_ci		i = 2;
1108c2ecf20Sopenharmony_ci		break;
1118c2ecf20Sopenharmony_ci	}
1128c2ecf20Sopenharmony_ci	aty_st_514(0x90, 0x00, par);	/* VRAM Mask Low */
1138c2ecf20Sopenharmony_ci	aty_st_514(0x04, tab[i].pixel_dly, par);	/* Horizontal Sync Control */
1148c2ecf20Sopenharmony_ci	aty_st_514(0x05, 0x00, par);	/* Power Management */
1158c2ecf20Sopenharmony_ci	aty_st_514(0x02, 0x01, par);	/* Misc Clock Control */
1168c2ecf20Sopenharmony_ci	aty_st_514(0x71, tab[i].misc2_cntl, par);	/* Misc Control 2 */
1178c2ecf20Sopenharmony_ci	aty_st_514(0x0a, tab[i].pixel_rep, par);	/* Pixel Format */
1188c2ecf20Sopenharmony_ci	aty_st_514(tab[i].pixel_cntl_index, tab[i].pixel_cntl_v1, par);
1198c2ecf20Sopenharmony_ci	/* Misc Control 2 / 16 BPP Control / 32 BPP Control */
1208c2ecf20Sopenharmony_ci	return 0;
1218c2ecf20Sopenharmony_ci}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_cistatic int aty_var_to_pll_514(const struct fb_info *info, u32 vclk_per,
1248c2ecf20Sopenharmony_ci			      u32 bpp, union aty_pll *pll)
1258c2ecf20Sopenharmony_ci{
1268c2ecf20Sopenharmony_ci	/*
1278c2ecf20Sopenharmony_ci	 *  FIXME: use real calculations instead of using fixed values from the old
1288c2ecf20Sopenharmony_ci	 *         driver
1298c2ecf20Sopenharmony_ci	 */
1308c2ecf20Sopenharmony_ci	static struct {
1318c2ecf20Sopenharmony_ci		u32 limit;	/* pixlock rounding limit (arbitrary) */
1328c2ecf20Sopenharmony_ci		u8 m;		/* (df<<6) | vco_div_count */
1338c2ecf20Sopenharmony_ci		u8 n;		/* ref_div_count */
1348c2ecf20Sopenharmony_ci	} RGB514_clocks[7] = {
1358c2ecf20Sopenharmony_ci		{
1368c2ecf20Sopenharmony_ci		8000, (3 << 6) | 20, 9},	/*  7395 ps / 135.2273 MHz */
1378c2ecf20Sopenharmony_ci		{
1388c2ecf20Sopenharmony_ci		10000, (1 << 6) | 19, 3},	/*  9977 ps / 100.2273 MHz */
1398c2ecf20Sopenharmony_ci		{
1408c2ecf20Sopenharmony_ci		13000, (1 << 6) | 2, 3},	/* 12509 ps /  79.9432 MHz */
1418c2ecf20Sopenharmony_ci		{
1428c2ecf20Sopenharmony_ci		14000, (2 << 6) | 8, 7},	/* 13394 ps /  74.6591 MHz */
1438c2ecf20Sopenharmony_ci		{
1448c2ecf20Sopenharmony_ci		16000, (1 << 6) | 44, 6},	/* 15378 ps /  65.0284 MHz */
1458c2ecf20Sopenharmony_ci		{
1468c2ecf20Sopenharmony_ci		25000, (1 << 6) | 15, 5},	/* 17460 ps /  57.2727 MHz */
1478c2ecf20Sopenharmony_ci		{
1488c2ecf20Sopenharmony_ci		50000, (0 << 6) | 53, 7},	/* 33145 ps /  30.1705 MHz */
1498c2ecf20Sopenharmony_ci	};
1508c2ecf20Sopenharmony_ci	int i;
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(RGB514_clocks); i++)
1538c2ecf20Sopenharmony_ci		if (vclk_per <= RGB514_clocks[i].limit) {
1548c2ecf20Sopenharmony_ci			pll->ibm514.m = RGB514_clocks[i].m;
1558c2ecf20Sopenharmony_ci			pll->ibm514.n = RGB514_clocks[i].n;
1568c2ecf20Sopenharmony_ci			return 0;
1578c2ecf20Sopenharmony_ci		}
1588c2ecf20Sopenharmony_ci	return -EINVAL;
1598c2ecf20Sopenharmony_ci}
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_cistatic u32 aty_pll_514_to_var(const struct fb_info *info,
1628c2ecf20Sopenharmony_ci			      const union aty_pll *pll)
1638c2ecf20Sopenharmony_ci{
1648c2ecf20Sopenharmony_ci	struct atyfb_par *par = (struct atyfb_par *) info->par;
1658c2ecf20Sopenharmony_ci	u8 df, vco_div_count, ref_div_count;
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	df = pll->ibm514.m >> 6;
1688c2ecf20Sopenharmony_ci	vco_div_count = pll->ibm514.m & 0x3f;
1698c2ecf20Sopenharmony_ci	ref_div_count = pll->ibm514.n;
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	return ((par->ref_clk_per * ref_div_count) << (3 - df))/
1728c2ecf20Sopenharmony_ci	    		(vco_div_count + 65);
1738c2ecf20Sopenharmony_ci}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_cistatic void aty_set_pll_514(const struct fb_info *info,
1768c2ecf20Sopenharmony_ci			    const union aty_pll *pll)
1778c2ecf20Sopenharmony_ci{
1788c2ecf20Sopenharmony_ci	struct atyfb_par *par = (struct atyfb_par *) info->par;
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	aty_st_514(0x06, 0x02, par);	/* DAC Operation */
1818c2ecf20Sopenharmony_ci	aty_st_514(0x10, 0x01, par);	/* PLL Control 1 */
1828c2ecf20Sopenharmony_ci	aty_st_514(0x70, 0x01, par);	/* Misc Control 1 */
1838c2ecf20Sopenharmony_ci	aty_st_514(0x8f, 0x1f, par);	/* PLL Ref. Divider Input */
1848c2ecf20Sopenharmony_ci	aty_st_514(0x03, 0x00, par);	/* Sync Control */
1858c2ecf20Sopenharmony_ci	aty_st_514(0x05, 0x00, par);	/* Power Management */
1868c2ecf20Sopenharmony_ci	aty_st_514(0x20, pll->ibm514.m, par);	/* F0 / M0 */
1878c2ecf20Sopenharmony_ci	aty_st_514(0x21, pll->ibm514.n, par);	/* F1 / N0 */
1888c2ecf20Sopenharmony_ci}
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ciconst struct aty_dac_ops aty_dac_ibm514 = {
1918c2ecf20Sopenharmony_ci	.set_dac	= aty_set_dac_514,
1928c2ecf20Sopenharmony_ci};
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ciconst struct aty_pll_ops aty_pll_ibm514 = {
1958c2ecf20Sopenharmony_ci	.var_to_pll	= aty_var_to_pll_514,
1968c2ecf20Sopenharmony_ci	.pll_to_var	= aty_pll_514_to_var,
1978c2ecf20Sopenharmony_ci	.set_pll	= aty_set_pll_514,
1988c2ecf20Sopenharmony_ci};
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci    /*
2028c2ecf20Sopenharmony_ci     *  ATI 68860-B DAC
2038c2ecf20Sopenharmony_ci     */
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_cistatic int aty_set_dac_ATI68860_B(const struct fb_info *info,
2068c2ecf20Sopenharmony_ci				  const union aty_pll *pll, u32 bpp,
2078c2ecf20Sopenharmony_ci				  u32 accel)
2088c2ecf20Sopenharmony_ci{
2098c2ecf20Sopenharmony_ci	struct atyfb_par *par = (struct atyfb_par *) info->par;
2108c2ecf20Sopenharmony_ci	u32 gModeReg, devSetupRegA, temp, mask;
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	gModeReg = 0;
2138c2ecf20Sopenharmony_ci	devSetupRegA = 0;
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	switch (bpp) {
2168c2ecf20Sopenharmony_ci	case 8:
2178c2ecf20Sopenharmony_ci		gModeReg = 0x83;
2188c2ecf20Sopenharmony_ci		devSetupRegA =
2198c2ecf20Sopenharmony_ci		    0x60 | 0x00 /*(info->mach64DAC8Bit ? 0x00 : 0x01) */ ;
2208c2ecf20Sopenharmony_ci		break;
2218c2ecf20Sopenharmony_ci	case 15:
2228c2ecf20Sopenharmony_ci		gModeReg = 0xA0;
2238c2ecf20Sopenharmony_ci		devSetupRegA = 0x60;
2248c2ecf20Sopenharmony_ci		break;
2258c2ecf20Sopenharmony_ci	case 16:
2268c2ecf20Sopenharmony_ci		gModeReg = 0xA1;
2278c2ecf20Sopenharmony_ci		devSetupRegA = 0x60;
2288c2ecf20Sopenharmony_ci		break;
2298c2ecf20Sopenharmony_ci	case 24:
2308c2ecf20Sopenharmony_ci		gModeReg = 0xC0;
2318c2ecf20Sopenharmony_ci		devSetupRegA = 0x60;
2328c2ecf20Sopenharmony_ci		break;
2338c2ecf20Sopenharmony_ci	case 32:
2348c2ecf20Sopenharmony_ci		gModeReg = 0xE3;
2358c2ecf20Sopenharmony_ci		devSetupRegA = 0x60;
2368c2ecf20Sopenharmony_ci		break;
2378c2ecf20Sopenharmony_ci	}
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	if (!accel) {
2408c2ecf20Sopenharmony_ci		gModeReg = 0x80;
2418c2ecf20Sopenharmony_ci		devSetupRegA = 0x61;
2428c2ecf20Sopenharmony_ci	}
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	temp = aty_ld_8(DAC_CNTL, par);
2458c2ecf20Sopenharmony_ci	aty_st_8(DAC_CNTL, (temp & ~DAC_EXT_SEL_RS2) | DAC_EXT_SEL_RS3,
2468c2ecf20Sopenharmony_ci		 par);
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	aty_st_8(DAC_REGS + 2, 0x1D, par);
2498c2ecf20Sopenharmony_ci	aty_st_8(DAC_REGS + 3, gModeReg, par);
2508c2ecf20Sopenharmony_ci	aty_st_8(DAC_REGS, 0x02, par);
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	temp = aty_ld_8(DAC_CNTL, par);
2538c2ecf20Sopenharmony_ci	aty_st_8(DAC_CNTL, temp | DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3, par);
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	if (info->fix.smem_len < ONE_MB)
2568c2ecf20Sopenharmony_ci		mask = 0x04;
2578c2ecf20Sopenharmony_ci	else if (info->fix.smem_len == ONE_MB)
2588c2ecf20Sopenharmony_ci		mask = 0x08;
2598c2ecf20Sopenharmony_ci	else
2608c2ecf20Sopenharmony_ci		mask = 0x0C;
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	/* The following assumes that the BIOS has correctly set R7 of the
2638c2ecf20Sopenharmony_ci	 * Device Setup Register A at boot time.
2648c2ecf20Sopenharmony_ci	 */
2658c2ecf20Sopenharmony_ci#define A860_DELAY_L	0x80
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	temp = aty_ld_8(DAC_REGS, par);
2688c2ecf20Sopenharmony_ci	aty_st_8(DAC_REGS, (devSetupRegA | mask) | (temp & A860_DELAY_L),
2698c2ecf20Sopenharmony_ci		 par);
2708c2ecf20Sopenharmony_ci	temp = aty_ld_8(DAC_CNTL, par);
2718c2ecf20Sopenharmony_ci	aty_st_8(DAC_CNTL, (temp & ~(DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3)),
2728c2ecf20Sopenharmony_ci		 par);
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	aty_st_le32(BUS_CNTL, 0x890e20f1, par);
2758c2ecf20Sopenharmony_ci	aty_st_le32(DAC_CNTL, 0x47052100, par);
2768c2ecf20Sopenharmony_ci	return 0;
2778c2ecf20Sopenharmony_ci}
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ciconst struct aty_dac_ops aty_dac_ati68860b = {
2808c2ecf20Sopenharmony_ci	.set_dac	= aty_set_dac_ATI68860_B,
2818c2ecf20Sopenharmony_ci};
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci    /*
2858c2ecf20Sopenharmony_ci     *  AT&T 21C498 DAC
2868c2ecf20Sopenharmony_ci     */
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_cistatic int aty_set_dac_ATT21C498(const struct fb_info *info,
2898c2ecf20Sopenharmony_ci				 const union aty_pll *pll, u32 bpp,
2908c2ecf20Sopenharmony_ci				 u32 accel)
2918c2ecf20Sopenharmony_ci{
2928c2ecf20Sopenharmony_ci	struct atyfb_par *par = (struct atyfb_par *) info->par;
2938c2ecf20Sopenharmony_ci	u32 dotClock;
2948c2ecf20Sopenharmony_ci	int muxmode = 0;
2958c2ecf20Sopenharmony_ci	int DACMask = 0;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	dotClock = 100000000 / pll->ics2595.period_in_ps;
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	switch (bpp) {
3008c2ecf20Sopenharmony_ci	case 8:
3018c2ecf20Sopenharmony_ci		if (dotClock > 8000) {
3028c2ecf20Sopenharmony_ci			DACMask = 0x24;
3038c2ecf20Sopenharmony_ci			muxmode = 1;
3048c2ecf20Sopenharmony_ci		} else
3058c2ecf20Sopenharmony_ci			DACMask = 0x04;
3068c2ecf20Sopenharmony_ci		break;
3078c2ecf20Sopenharmony_ci	case 15:
3088c2ecf20Sopenharmony_ci		DACMask = 0x16;
3098c2ecf20Sopenharmony_ci		break;
3108c2ecf20Sopenharmony_ci	case 16:
3118c2ecf20Sopenharmony_ci		DACMask = 0x36;
3128c2ecf20Sopenharmony_ci		break;
3138c2ecf20Sopenharmony_ci	case 24:
3148c2ecf20Sopenharmony_ci		DACMask = 0xE6;
3158c2ecf20Sopenharmony_ci		break;
3168c2ecf20Sopenharmony_ci	case 32:
3178c2ecf20Sopenharmony_ci		DACMask = 0xE6;
3188c2ecf20Sopenharmony_ci		break;
3198c2ecf20Sopenharmony_ci	}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	if (1 /* info->mach64DAC8Bit */ )
3228c2ecf20Sopenharmony_ci		DACMask |= 0x02;
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	aty_dac_waste4(par);
3258c2ecf20Sopenharmony_ci	aty_st_8(DAC_REGS + 2, DACMask, par);
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	aty_st_le32(BUS_CNTL, 0x890e20f1, par);
3288c2ecf20Sopenharmony_ci	aty_st_le32(DAC_CNTL, 0x00072000, par);
3298c2ecf20Sopenharmony_ci	return muxmode;
3308c2ecf20Sopenharmony_ci}
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ciconst struct aty_dac_ops aty_dac_att21c498 = {
3338c2ecf20Sopenharmony_ci	.set_dac	= aty_set_dac_ATT21C498,
3348c2ecf20Sopenharmony_ci};
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci    /*
3388c2ecf20Sopenharmony_ci     *  ATI 18818 / ICS 2595 Clock Chip
3398c2ecf20Sopenharmony_ci     */
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_cistatic int aty_var_to_pll_18818(const struct fb_info *info, u32 vclk_per,
3428c2ecf20Sopenharmony_ci				u32 bpp, union aty_pll *pll)
3438c2ecf20Sopenharmony_ci{
3448c2ecf20Sopenharmony_ci	u32 MHz100;		/* in 0.01 MHz */
3458c2ecf20Sopenharmony_ci	u32 program_bits;
3468c2ecf20Sopenharmony_ci	u32 post_divider;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	/* Calculate the programming word */
3498c2ecf20Sopenharmony_ci	MHz100 = 100000000 / vclk_per;
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	program_bits = -1;
3528c2ecf20Sopenharmony_ci	post_divider = 1;
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	if (MHz100 > MAX_FREQ_2595) {
3558c2ecf20Sopenharmony_ci		MHz100 = MAX_FREQ_2595;
3568c2ecf20Sopenharmony_ci		return -EINVAL;
3578c2ecf20Sopenharmony_ci	} else if (MHz100 < ABS_MIN_FREQ_2595) {
3588c2ecf20Sopenharmony_ci		program_bits = 0;	/* MHz100 = 257 */
3598c2ecf20Sopenharmony_ci		return -EINVAL;
3608c2ecf20Sopenharmony_ci	} else {
3618c2ecf20Sopenharmony_ci		while (MHz100 < MIN_FREQ_2595) {
3628c2ecf20Sopenharmony_ci			MHz100 *= 2;
3638c2ecf20Sopenharmony_ci			post_divider *= 2;
3648c2ecf20Sopenharmony_ci		}
3658c2ecf20Sopenharmony_ci	}
3668c2ecf20Sopenharmony_ci	MHz100 *= 1000;
3678c2ecf20Sopenharmony_ci	MHz100 = (REF_DIV_2595 * MHz100) / REF_FREQ_2595;
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	MHz100 += 500;		/* + 0.5 round */
3708c2ecf20Sopenharmony_ci	MHz100 /= 1000;
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	if (program_bits == -1) {
3738c2ecf20Sopenharmony_ci		program_bits = MHz100 - N_ADJ_2595;
3748c2ecf20Sopenharmony_ci		switch (post_divider) {
3758c2ecf20Sopenharmony_ci		case 1:
3768c2ecf20Sopenharmony_ci			program_bits |= 0x0600;
3778c2ecf20Sopenharmony_ci			break;
3788c2ecf20Sopenharmony_ci		case 2:
3798c2ecf20Sopenharmony_ci			program_bits |= 0x0400;
3808c2ecf20Sopenharmony_ci			break;
3818c2ecf20Sopenharmony_ci		case 4:
3828c2ecf20Sopenharmony_ci			program_bits |= 0x0200;
3838c2ecf20Sopenharmony_ci			break;
3848c2ecf20Sopenharmony_ci		case 8:
3858c2ecf20Sopenharmony_ci		default:
3868c2ecf20Sopenharmony_ci			break;
3878c2ecf20Sopenharmony_ci		}
3888c2ecf20Sopenharmony_ci	}
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	program_bits |= STOP_BITS_2595;
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	pll->ics2595.program_bits = program_bits;
3938c2ecf20Sopenharmony_ci	pll->ics2595.locationAddr = 0;
3948c2ecf20Sopenharmony_ci	pll->ics2595.post_divider = post_divider;
3958c2ecf20Sopenharmony_ci	pll->ics2595.period_in_ps = vclk_per;
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	return 0;
3988c2ecf20Sopenharmony_ci}
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_cistatic u32 aty_pll_18818_to_var(const struct fb_info *info,
4018c2ecf20Sopenharmony_ci				const union aty_pll *pll)
4028c2ecf20Sopenharmony_ci{
4038c2ecf20Sopenharmony_ci	return (pll->ics2595.period_in_ps);	/* default for now */
4048c2ecf20Sopenharmony_ci}
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_cistatic void aty_ICS2595_put1bit(u8 data, const struct atyfb_par *par)
4078c2ecf20Sopenharmony_ci{
4088c2ecf20Sopenharmony_ci	u8 tmp;
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	data &= 0x01;
4118c2ecf20Sopenharmony_ci	tmp = aty_ld_8(CLOCK_CNTL, par);
4128c2ecf20Sopenharmony_ci	aty_st_8(CLOCK_CNTL + par->clk_wr_offset,
4138c2ecf20Sopenharmony_ci		 (tmp & ~0x04) | (data << 2), par);
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	tmp = aty_ld_8(CLOCK_CNTL, par);
4168c2ecf20Sopenharmony_ci	aty_st_8(CLOCK_CNTL + par->clk_wr_offset, (tmp & ~0x08) | (0 << 3),
4178c2ecf20Sopenharmony_ci		 par);
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	aty_StrobeClock(par);
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	tmp = aty_ld_8(CLOCK_CNTL, par);
4228c2ecf20Sopenharmony_ci	aty_st_8(CLOCK_CNTL + par->clk_wr_offset, (tmp & ~0x08) | (1 << 3),
4238c2ecf20Sopenharmony_ci		 par);
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci	aty_StrobeClock(par);
4268c2ecf20Sopenharmony_ci	return;
4278c2ecf20Sopenharmony_ci}
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_cistatic void aty_set_pll18818(const struct fb_info *info,
4308c2ecf20Sopenharmony_ci			     const union aty_pll *pll)
4318c2ecf20Sopenharmony_ci{
4328c2ecf20Sopenharmony_ci	struct atyfb_par *par = (struct atyfb_par *) info->par;
4338c2ecf20Sopenharmony_ci	u32 program_bits;
4348c2ecf20Sopenharmony_ci	u32 locationAddr;
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	u32 i;
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	u8 old_clock_cntl;
4398c2ecf20Sopenharmony_ci	u8 old_crtc_ext_disp;
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	old_clock_cntl = aty_ld_8(CLOCK_CNTL, par);
4428c2ecf20Sopenharmony_ci	aty_st_8(CLOCK_CNTL + par->clk_wr_offset, 0, par);
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, par);
4458c2ecf20Sopenharmony_ci	aty_st_8(CRTC_GEN_CNTL + 3,
4468c2ecf20Sopenharmony_ci		 old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24), par);
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	mdelay(15);		/* delay for 50 (15) ms */
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	program_bits = pll->ics2595.program_bits;
4518c2ecf20Sopenharmony_ci	locationAddr = pll->ics2595.locationAddr;
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	/* Program the clock chip */
4548c2ecf20Sopenharmony_ci	aty_st_8(CLOCK_CNTL + par->clk_wr_offset, 0, par);	/* Strobe = 0 */
4558c2ecf20Sopenharmony_ci	aty_StrobeClock(par);
4568c2ecf20Sopenharmony_ci	aty_st_8(CLOCK_CNTL + par->clk_wr_offset, 1, par);	/* Strobe = 0 */
4578c2ecf20Sopenharmony_ci	aty_StrobeClock(par);
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	aty_ICS2595_put1bit(1, par);	/* Send start bits */
4608c2ecf20Sopenharmony_ci	aty_ICS2595_put1bit(0, par);	/* Start bit */
4618c2ecf20Sopenharmony_ci	aty_ICS2595_put1bit(0, par);	/* Read / ~Write */
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	for (i = 0; i < 5; i++) {	/* Location 0..4 */
4648c2ecf20Sopenharmony_ci		aty_ICS2595_put1bit(locationAddr & 1, par);
4658c2ecf20Sopenharmony_ci		locationAddr >>= 1;
4668c2ecf20Sopenharmony_ci	}
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	for (i = 0; i < 8 + 1 + 2 + 2; i++) {
4698c2ecf20Sopenharmony_ci		aty_ICS2595_put1bit(program_bits & 1, par);
4708c2ecf20Sopenharmony_ci		program_bits >>= 1;
4718c2ecf20Sopenharmony_ci	}
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	mdelay(1);		/* delay for 1 ms */
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	(void) aty_ld_8(DAC_REGS, par);	/* Clear DAC Counter */
4768c2ecf20Sopenharmony_ci	aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, par);
4778c2ecf20Sopenharmony_ci	aty_st_8(CLOCK_CNTL + par->clk_wr_offset,
4788c2ecf20Sopenharmony_ci		 old_clock_cntl | CLOCK_STROBE, par);
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	mdelay(50);		/* delay for 50 (15) ms */
4818c2ecf20Sopenharmony_ci	aty_st_8(CLOCK_CNTL + par->clk_wr_offset,
4828c2ecf20Sopenharmony_ci		 ((pll->ics2595.locationAddr & 0x0F) | CLOCK_STROBE), par);
4838c2ecf20Sopenharmony_ci	return;
4848c2ecf20Sopenharmony_ci}
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ciconst struct aty_pll_ops aty_pll_ati18818_1 = {
4878c2ecf20Sopenharmony_ci	.var_to_pll	= aty_var_to_pll_18818,
4888c2ecf20Sopenharmony_ci	.pll_to_var	= aty_pll_18818_to_var,
4898c2ecf20Sopenharmony_ci	.set_pll	= aty_set_pll18818,
4908c2ecf20Sopenharmony_ci};
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci    /*
4948c2ecf20Sopenharmony_ci     *  STG 1703 Clock Chip
4958c2ecf20Sopenharmony_ci     */
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_cistatic int aty_var_to_pll_1703(const struct fb_info *info, u32 vclk_per,
4988c2ecf20Sopenharmony_ci			       u32 bpp, union aty_pll *pll)
4998c2ecf20Sopenharmony_ci{
5008c2ecf20Sopenharmony_ci	u32 mhz100;		/* in 0.01 MHz */
5018c2ecf20Sopenharmony_ci	u32 program_bits;
5028c2ecf20Sopenharmony_ci	/* u32 post_divider; */
5038c2ecf20Sopenharmony_ci	u32 mach64MinFreq, mach64MaxFreq, mach64RefFreq;
5048c2ecf20Sopenharmony_ci	u32 temp, tempB;
5058c2ecf20Sopenharmony_ci	u16 remainder, preRemainder;
5068c2ecf20Sopenharmony_ci	short divider = 0, tempA;
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci	/* Calculate the programming word */
5098c2ecf20Sopenharmony_ci	mhz100 = 100000000 / vclk_per;
5108c2ecf20Sopenharmony_ci	mach64MinFreq = MIN_FREQ_2595;
5118c2ecf20Sopenharmony_ci	mach64MaxFreq = MAX_FREQ_2595;
5128c2ecf20Sopenharmony_ci	mach64RefFreq = REF_FREQ_2595;	/* 14.32 MHz */
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	/* Calculate program word */
5158c2ecf20Sopenharmony_ci	if (mhz100 == 0)
5168c2ecf20Sopenharmony_ci		program_bits = 0xE0;
5178c2ecf20Sopenharmony_ci	else {
5188c2ecf20Sopenharmony_ci		if (mhz100 < mach64MinFreq)
5198c2ecf20Sopenharmony_ci			mhz100 = mach64MinFreq;
5208c2ecf20Sopenharmony_ci		if (mhz100 > mach64MaxFreq)
5218c2ecf20Sopenharmony_ci			mhz100 = mach64MaxFreq;
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci		divider = 0;
5248c2ecf20Sopenharmony_ci		while (mhz100 < (mach64MinFreq << 3)) {
5258c2ecf20Sopenharmony_ci			mhz100 <<= 1;
5268c2ecf20Sopenharmony_ci			divider += 0x20;
5278c2ecf20Sopenharmony_ci		}
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci		temp = (unsigned int) (mhz100);
5308c2ecf20Sopenharmony_ci		temp = (unsigned int) (temp * (MIN_N_1703 + 2));
5318c2ecf20Sopenharmony_ci		temp -= (short) (mach64RefFreq << 1);
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci		tempA = MIN_N_1703;
5348c2ecf20Sopenharmony_ci		preRemainder = 0xffff;
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci		do {
5378c2ecf20Sopenharmony_ci			tempB = temp;
5388c2ecf20Sopenharmony_ci			remainder = tempB % mach64RefFreq;
5398c2ecf20Sopenharmony_ci			tempB = tempB / mach64RefFreq;
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci			if ((tempB & 0xffff) <= 127
5428c2ecf20Sopenharmony_ci			    && (remainder <= preRemainder)) {
5438c2ecf20Sopenharmony_ci				preRemainder = remainder;
5448c2ecf20Sopenharmony_ci				divider &= ~0x1f;
5458c2ecf20Sopenharmony_ci				divider |= tempA;
5468c2ecf20Sopenharmony_ci				divider =
5478c2ecf20Sopenharmony_ci				    (divider & 0x00ff) +
5488c2ecf20Sopenharmony_ci				    ((tempB & 0xff) << 8);
5498c2ecf20Sopenharmony_ci			}
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci			temp += mhz100;
5528c2ecf20Sopenharmony_ci			tempA++;
5538c2ecf20Sopenharmony_ci		} while (tempA <= (MIN_N_1703 << 1));
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci		program_bits = divider;
5568c2ecf20Sopenharmony_ci	}
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci	pll->ics2595.program_bits = program_bits;
5598c2ecf20Sopenharmony_ci	pll->ics2595.locationAddr = 0;
5608c2ecf20Sopenharmony_ci	pll->ics2595.post_divider = divider;	/* fuer nix */
5618c2ecf20Sopenharmony_ci	pll->ics2595.period_in_ps = vclk_per;
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci	return 0;
5648c2ecf20Sopenharmony_ci}
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_cistatic u32 aty_pll_1703_to_var(const struct fb_info *info,
5678c2ecf20Sopenharmony_ci			       const union aty_pll *pll)
5688c2ecf20Sopenharmony_ci{
5698c2ecf20Sopenharmony_ci	return (pll->ics2595.period_in_ps);	/* default for now */
5708c2ecf20Sopenharmony_ci}
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_cistatic void aty_set_pll_1703(const struct fb_info *info,
5738c2ecf20Sopenharmony_ci			     const union aty_pll *pll)
5748c2ecf20Sopenharmony_ci{
5758c2ecf20Sopenharmony_ci	struct atyfb_par *par = (struct atyfb_par *) info->par;
5768c2ecf20Sopenharmony_ci	u32 program_bits;
5778c2ecf20Sopenharmony_ci	u32 locationAddr;
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	char old_crtc_ext_disp;
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, par);
5828c2ecf20Sopenharmony_ci	aty_st_8(CRTC_GEN_CNTL + 3,
5838c2ecf20Sopenharmony_ci		 old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24), par);
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	program_bits = pll->ics2595.program_bits;
5868c2ecf20Sopenharmony_ci	locationAddr = pll->ics2595.locationAddr;
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	/* Program clock */
5898c2ecf20Sopenharmony_ci	aty_dac_waste4(par);
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci	(void) aty_ld_8(DAC_REGS + 2, par);
5928c2ecf20Sopenharmony_ci	aty_st_8(DAC_REGS + 2, (locationAddr << 1) + 0x20, par);
5938c2ecf20Sopenharmony_ci	aty_st_8(DAC_REGS + 2, 0, par);
5948c2ecf20Sopenharmony_ci	aty_st_8(DAC_REGS + 2, (program_bits & 0xFF00) >> 8, par);
5958c2ecf20Sopenharmony_ci	aty_st_8(DAC_REGS + 2, (program_bits & 0xFF), par);
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci	(void) aty_ld_8(DAC_REGS, par);	/* Clear DAC Counter */
5988c2ecf20Sopenharmony_ci	aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, par);
5998c2ecf20Sopenharmony_ci	return;
6008c2ecf20Sopenharmony_ci}
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ciconst struct aty_pll_ops aty_pll_stg1703 = {
6038c2ecf20Sopenharmony_ci	.var_to_pll	= aty_var_to_pll_1703,
6048c2ecf20Sopenharmony_ci	.pll_to_var	= aty_pll_1703_to_var,
6058c2ecf20Sopenharmony_ci	.set_pll	= aty_set_pll_1703,
6068c2ecf20Sopenharmony_ci};
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci    /*
6108c2ecf20Sopenharmony_ci     *  Chrontel 8398 Clock Chip
6118c2ecf20Sopenharmony_ci     */
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_cistatic int aty_var_to_pll_8398(const struct fb_info *info, u32 vclk_per,
6148c2ecf20Sopenharmony_ci			       u32 bpp, union aty_pll *pll)
6158c2ecf20Sopenharmony_ci{
6168c2ecf20Sopenharmony_ci	u32 tempA, tempB, fOut, longMHz100, diff, preDiff;
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci	u32 mhz100;		/* in 0.01 MHz */
6198c2ecf20Sopenharmony_ci	u32 program_bits;
6208c2ecf20Sopenharmony_ci	/* u32 post_divider; */
6218c2ecf20Sopenharmony_ci	u32 mach64MinFreq, mach64MaxFreq;
6228c2ecf20Sopenharmony_ci	u16 m, n, k = 0, save_m, save_n, twoToKth;
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci	/* Calculate the programming word */
6258c2ecf20Sopenharmony_ci	mhz100 = 100000000 / vclk_per;
6268c2ecf20Sopenharmony_ci	mach64MinFreq = MIN_FREQ_2595;
6278c2ecf20Sopenharmony_ci	mach64MaxFreq = MAX_FREQ_2595;
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci	save_m = 0;
6308c2ecf20Sopenharmony_ci	save_n = 0;
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	/* Calculate program word */
6338c2ecf20Sopenharmony_ci	if (mhz100 == 0)
6348c2ecf20Sopenharmony_ci		program_bits = 0xE0;
6358c2ecf20Sopenharmony_ci	else {
6368c2ecf20Sopenharmony_ci		if (mhz100 < mach64MinFreq)
6378c2ecf20Sopenharmony_ci			mhz100 = mach64MinFreq;
6388c2ecf20Sopenharmony_ci		if (mhz100 > mach64MaxFreq)
6398c2ecf20Sopenharmony_ci			mhz100 = mach64MaxFreq;
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci		longMHz100 = mhz100 * 256 / 100;	/* 8 bit scale this */
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci		while (mhz100 < (mach64MinFreq << 3)) {
6448c2ecf20Sopenharmony_ci			mhz100 <<= 1;
6458c2ecf20Sopenharmony_ci			k++;
6468c2ecf20Sopenharmony_ci		}
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci		twoToKth = 1 << k;
6498c2ecf20Sopenharmony_ci		diff = 0;
6508c2ecf20Sopenharmony_ci		preDiff = 0xFFFFFFFF;
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci		for (m = MIN_M; m <= MAX_M; m++) {
6538c2ecf20Sopenharmony_ci			for (n = MIN_N; n <= MAX_N; n++) {
6548c2ecf20Sopenharmony_ci				tempA = 938356;		/* 14.31818 * 65536 */
6558c2ecf20Sopenharmony_ci				tempA *= (n + 8);	/* 43..256 */
6568c2ecf20Sopenharmony_ci				tempB = twoToKth * 256;
6578c2ecf20Sopenharmony_ci				tempB *= (m + 2);	/* 4..32 */
6588c2ecf20Sopenharmony_ci				fOut = tempA / tempB;	/* 8 bit scale */
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci				if (longMHz100 > fOut)
6618c2ecf20Sopenharmony_ci					diff = longMHz100 - fOut;
6628c2ecf20Sopenharmony_ci				else
6638c2ecf20Sopenharmony_ci					diff = fOut - longMHz100;
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci				if (diff < preDiff) {
6668c2ecf20Sopenharmony_ci					save_m = m;
6678c2ecf20Sopenharmony_ci					save_n = n;
6688c2ecf20Sopenharmony_ci					preDiff = diff;
6698c2ecf20Sopenharmony_ci				}
6708c2ecf20Sopenharmony_ci			}
6718c2ecf20Sopenharmony_ci		}
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ci		program_bits = (k << 6) + (save_m) + (save_n << 8);
6748c2ecf20Sopenharmony_ci	}
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci	pll->ics2595.program_bits = program_bits;
6778c2ecf20Sopenharmony_ci	pll->ics2595.locationAddr = 0;
6788c2ecf20Sopenharmony_ci	pll->ics2595.post_divider = 0;
6798c2ecf20Sopenharmony_ci	pll->ics2595.period_in_ps = vclk_per;
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci	return 0;
6828c2ecf20Sopenharmony_ci}
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_cistatic u32 aty_pll_8398_to_var(const struct fb_info *info,
6858c2ecf20Sopenharmony_ci			       const union aty_pll *pll)
6868c2ecf20Sopenharmony_ci{
6878c2ecf20Sopenharmony_ci	return (pll->ics2595.period_in_ps);	/* default for now */
6888c2ecf20Sopenharmony_ci}
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_cistatic void aty_set_pll_8398(const struct fb_info *info,
6918c2ecf20Sopenharmony_ci			     const union aty_pll *pll)
6928c2ecf20Sopenharmony_ci{
6938c2ecf20Sopenharmony_ci	struct atyfb_par *par = (struct atyfb_par *) info->par;
6948c2ecf20Sopenharmony_ci	u32 program_bits;
6958c2ecf20Sopenharmony_ci	u32 locationAddr;
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci	char old_crtc_ext_disp;
6988c2ecf20Sopenharmony_ci	char tmp;
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci	old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, par);
7018c2ecf20Sopenharmony_ci	aty_st_8(CRTC_GEN_CNTL + 3,
7028c2ecf20Sopenharmony_ci		 old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24), par);
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci	program_bits = pll->ics2595.program_bits;
7058c2ecf20Sopenharmony_ci	locationAddr = pll->ics2595.locationAddr;
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci	/* Program clock */
7088c2ecf20Sopenharmony_ci	tmp = aty_ld_8(DAC_CNTL, par);
7098c2ecf20Sopenharmony_ci	aty_st_8(DAC_CNTL, tmp | DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3, par);
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci	aty_st_8(DAC_REGS, locationAddr, par);
7128c2ecf20Sopenharmony_ci	aty_st_8(DAC_REGS + 1, (program_bits & 0xff00) >> 8, par);
7138c2ecf20Sopenharmony_ci	aty_st_8(DAC_REGS + 1, (program_bits & 0xff), par);
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ci	tmp = aty_ld_8(DAC_CNTL, par);
7168c2ecf20Sopenharmony_ci	aty_st_8(DAC_CNTL, (tmp & ~DAC_EXT_SEL_RS2) | DAC_EXT_SEL_RS3,
7178c2ecf20Sopenharmony_ci		 par);
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci	(void) aty_ld_8(DAC_REGS, par);	/* Clear DAC Counter */
7208c2ecf20Sopenharmony_ci	aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, par);
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci	return;
7238c2ecf20Sopenharmony_ci}
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ciconst struct aty_pll_ops aty_pll_ch8398 = {
7268c2ecf20Sopenharmony_ci	.var_to_pll	= aty_var_to_pll_8398,
7278c2ecf20Sopenharmony_ci	.pll_to_var	= aty_pll_8398_to_var,
7288c2ecf20Sopenharmony_ci	.set_pll	= aty_set_pll_8398,
7298c2ecf20Sopenharmony_ci};
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci    /*
7338c2ecf20Sopenharmony_ci     *  AT&T 20C408 Clock Chip
7348c2ecf20Sopenharmony_ci     */
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_cistatic int aty_var_to_pll_408(const struct fb_info *info, u32 vclk_per,
7378c2ecf20Sopenharmony_ci			      u32 bpp, union aty_pll *pll)
7388c2ecf20Sopenharmony_ci{
7398c2ecf20Sopenharmony_ci	u32 mhz100;		/* in 0.01 MHz */
7408c2ecf20Sopenharmony_ci	u32 program_bits;
7418c2ecf20Sopenharmony_ci	/* u32 post_divider; */
7428c2ecf20Sopenharmony_ci	u32 mach64MinFreq, mach64MaxFreq, mach64RefFreq;
7438c2ecf20Sopenharmony_ci	u32 temp, tempB;
7448c2ecf20Sopenharmony_ci	u16 remainder, preRemainder;
7458c2ecf20Sopenharmony_ci	short divider = 0, tempA;
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ci	/* Calculate the programming word */
7488c2ecf20Sopenharmony_ci	mhz100 = 100000000 / vclk_per;
7498c2ecf20Sopenharmony_ci	mach64MinFreq = MIN_FREQ_2595;
7508c2ecf20Sopenharmony_ci	mach64MaxFreq = MAX_FREQ_2595;
7518c2ecf20Sopenharmony_ci	mach64RefFreq = REF_FREQ_2595;	/* 14.32 MHz */
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci	/* Calculate program word */
7548c2ecf20Sopenharmony_ci	if (mhz100 == 0)
7558c2ecf20Sopenharmony_ci		program_bits = 0xFF;
7568c2ecf20Sopenharmony_ci	else {
7578c2ecf20Sopenharmony_ci		if (mhz100 < mach64MinFreq)
7588c2ecf20Sopenharmony_ci			mhz100 = mach64MinFreq;
7598c2ecf20Sopenharmony_ci		if (mhz100 > mach64MaxFreq)
7608c2ecf20Sopenharmony_ci			mhz100 = mach64MaxFreq;
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci		while (mhz100 < (mach64MinFreq << 3)) {
7638c2ecf20Sopenharmony_ci			mhz100 <<= 1;
7648c2ecf20Sopenharmony_ci			divider += 0x40;
7658c2ecf20Sopenharmony_ci		}
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci		temp = (unsigned int) mhz100;
7688c2ecf20Sopenharmony_ci		temp = (unsigned int) (temp * (MIN_N_408 + 2));
7698c2ecf20Sopenharmony_ci		temp -= ((short) (mach64RefFreq << 1));
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ci		tempA = MIN_N_408;
7728c2ecf20Sopenharmony_ci		preRemainder = 0xFFFF;
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_ci		do {
7758c2ecf20Sopenharmony_ci			tempB = temp;
7768c2ecf20Sopenharmony_ci			remainder = tempB % mach64RefFreq;
7778c2ecf20Sopenharmony_ci			tempB = tempB / mach64RefFreq;
7788c2ecf20Sopenharmony_ci			if (((tempB & 0xFFFF) <= 255)
7798c2ecf20Sopenharmony_ci			    && (remainder <= preRemainder)) {
7808c2ecf20Sopenharmony_ci				preRemainder = remainder;
7818c2ecf20Sopenharmony_ci				divider &= ~0x3f;
7828c2ecf20Sopenharmony_ci				divider |= tempA;
7838c2ecf20Sopenharmony_ci				divider =
7848c2ecf20Sopenharmony_ci				    (divider & 0x00FF) +
7858c2ecf20Sopenharmony_ci				    ((tempB & 0xFF) << 8);
7868c2ecf20Sopenharmony_ci			}
7878c2ecf20Sopenharmony_ci			temp += mhz100;
7888c2ecf20Sopenharmony_ci			tempA++;
7898c2ecf20Sopenharmony_ci		} while (tempA <= 32);
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_ci		program_bits = divider;
7928c2ecf20Sopenharmony_ci	}
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci	pll->ics2595.program_bits = program_bits;
7958c2ecf20Sopenharmony_ci	pll->ics2595.locationAddr = 0;
7968c2ecf20Sopenharmony_ci	pll->ics2595.post_divider = divider;	/* fuer nix */
7978c2ecf20Sopenharmony_ci	pll->ics2595.period_in_ps = vclk_per;
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci	return 0;
8008c2ecf20Sopenharmony_ci}
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_cistatic u32 aty_pll_408_to_var(const struct fb_info *info,
8038c2ecf20Sopenharmony_ci			      const union aty_pll *pll)
8048c2ecf20Sopenharmony_ci{
8058c2ecf20Sopenharmony_ci	return (pll->ics2595.period_in_ps);	/* default for now */
8068c2ecf20Sopenharmony_ci}
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_cistatic void aty_set_pll_408(const struct fb_info *info,
8098c2ecf20Sopenharmony_ci			    const union aty_pll *pll)
8108c2ecf20Sopenharmony_ci{
8118c2ecf20Sopenharmony_ci	struct atyfb_par *par = (struct atyfb_par *) info->par;
8128c2ecf20Sopenharmony_ci	u32 program_bits;
8138c2ecf20Sopenharmony_ci	u32 locationAddr;
8148c2ecf20Sopenharmony_ci
8158c2ecf20Sopenharmony_ci	u8 tmpA, tmpB, tmpC;
8168c2ecf20Sopenharmony_ci	char old_crtc_ext_disp;
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci	old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, par);
8198c2ecf20Sopenharmony_ci	aty_st_8(CRTC_GEN_CNTL + 3,
8208c2ecf20Sopenharmony_ci		 old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24), par);
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_ci	program_bits = pll->ics2595.program_bits;
8238c2ecf20Sopenharmony_ci	locationAddr = pll->ics2595.locationAddr;
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci	/* Program clock */
8268c2ecf20Sopenharmony_ci	aty_dac_waste4(par);
8278c2ecf20Sopenharmony_ci	tmpB = aty_ld_8(DAC_REGS + 2, par) | 1;
8288c2ecf20Sopenharmony_ci	aty_dac_waste4(par);
8298c2ecf20Sopenharmony_ci	aty_st_8(DAC_REGS + 2, tmpB, par);
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci	tmpA = tmpB;
8328c2ecf20Sopenharmony_ci	tmpC = tmpA;
8338c2ecf20Sopenharmony_ci	tmpA |= 8;
8348c2ecf20Sopenharmony_ci	tmpB = 1;
8358c2ecf20Sopenharmony_ci
8368c2ecf20Sopenharmony_ci	aty_st_8(DAC_REGS, tmpB, par);
8378c2ecf20Sopenharmony_ci	aty_st_8(DAC_REGS + 2, tmpA, par);
8388c2ecf20Sopenharmony_ci
8398c2ecf20Sopenharmony_ci	udelay(400);		/* delay for 400 us */
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci	locationAddr = (locationAddr << 2) + 0x40;
8428c2ecf20Sopenharmony_ci	tmpB = locationAddr;
8438c2ecf20Sopenharmony_ci	tmpA = program_bits >> 8;
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci	aty_st_8(DAC_REGS, tmpB, par);
8468c2ecf20Sopenharmony_ci	aty_st_8(DAC_REGS + 2, tmpA, par);
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_ci	tmpB = locationAddr + 1;
8498c2ecf20Sopenharmony_ci	tmpA = (u8) program_bits;
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci	aty_st_8(DAC_REGS, tmpB, par);
8528c2ecf20Sopenharmony_ci	aty_st_8(DAC_REGS + 2, tmpA, par);
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_ci	tmpB = locationAddr + 2;
8558c2ecf20Sopenharmony_ci	tmpA = 0x77;
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_ci	aty_st_8(DAC_REGS, tmpB, par);
8588c2ecf20Sopenharmony_ci	aty_st_8(DAC_REGS + 2, tmpA, par);
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_ci	udelay(400);		/* delay for 400 us */
8618c2ecf20Sopenharmony_ci	tmpA = tmpC & (~(1 | 8));
8628c2ecf20Sopenharmony_ci	tmpB = 1;
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci	aty_st_8(DAC_REGS, tmpB, par);
8658c2ecf20Sopenharmony_ci	aty_st_8(DAC_REGS + 2, tmpA, par);
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_ci	(void) aty_ld_8(DAC_REGS, par);	/* Clear DAC Counter */
8688c2ecf20Sopenharmony_ci	aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, par);
8698c2ecf20Sopenharmony_ci	return;
8708c2ecf20Sopenharmony_ci}
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ciconst struct aty_pll_ops aty_pll_att20c408 = {
8738c2ecf20Sopenharmony_ci	.var_to_pll	= aty_var_to_pll_408,
8748c2ecf20Sopenharmony_ci	.pll_to_var	= aty_pll_408_to_var,
8758c2ecf20Sopenharmony_ci	.set_pll	= aty_set_pll_408,
8768c2ecf20Sopenharmony_ci};
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_ci    /*
8808c2ecf20Sopenharmony_ci     *  Unsupported DAC and Clock Chip
8818c2ecf20Sopenharmony_ci     */
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_cistatic int aty_set_dac_unsupported(const struct fb_info *info,
8848c2ecf20Sopenharmony_ci				   const union aty_pll *pll, u32 bpp,
8858c2ecf20Sopenharmony_ci				   u32 accel)
8868c2ecf20Sopenharmony_ci{
8878c2ecf20Sopenharmony_ci	struct atyfb_par *par = (struct atyfb_par *) info->par;
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci	aty_st_le32(BUS_CNTL, 0x890e20f1, par);
8908c2ecf20Sopenharmony_ci	aty_st_le32(DAC_CNTL, 0x47052100, par);
8918c2ecf20Sopenharmony_ci	/* new in 2.2.3p1 from Geert. ???????? */
8928c2ecf20Sopenharmony_ci	aty_st_le32(BUS_CNTL, 0x590e10ff, par);
8938c2ecf20Sopenharmony_ci	aty_st_le32(DAC_CNTL, 0x47012100, par);
8948c2ecf20Sopenharmony_ci	return 0;
8958c2ecf20Sopenharmony_ci}
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_cistatic int dummy(void)
8988c2ecf20Sopenharmony_ci{
8998c2ecf20Sopenharmony_ci	return 0;
9008c2ecf20Sopenharmony_ci}
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ciconst struct aty_dac_ops aty_dac_unsupported = {
9038c2ecf20Sopenharmony_ci	.set_dac	= aty_set_dac_unsupported,
9048c2ecf20Sopenharmony_ci};
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_ciconst struct aty_pll_ops aty_pll_unsupported = {
9078c2ecf20Sopenharmony_ci	.var_to_pll	= (void *) dummy,
9088c2ecf20Sopenharmony_ci	.pll_to_var	= (void *) dummy,
9098c2ecf20Sopenharmony_ci	.set_pll	= (void *) dummy,
9108c2ecf20Sopenharmony_ci};
911