162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci
362306a36Sopenharmony_ci/*
462306a36Sopenharmony_ci *  ATI Mach64 GX Support
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/delay.h>
862306a36Sopenharmony_ci#include <linux/fb.h>
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <asm/io.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <video/mach64.h>
1362306a36Sopenharmony_ci#include "atyfb.h"
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci/* Definitions for the ICS 2595 == ATI 18818_1 Clockchip */
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#define REF_FREQ_2595       1432	/*  14.33 MHz  (exact   14.31818) */
1862306a36Sopenharmony_ci#define REF_DIV_2595          46	/* really 43 on ICS 2595 !!!  */
1962306a36Sopenharmony_ci				  /* ohne Prescaler */
2062306a36Sopenharmony_ci#define MAX_FREQ_2595      15938	/* 159.38 MHz  (really 170.486) */
2162306a36Sopenharmony_ci#define MIN_FREQ_2595       8000	/*  80.00 MHz  (        85.565) */
2262306a36Sopenharmony_ci				  /* mit Prescaler 2, 4, 8 */
2362306a36Sopenharmony_ci#define ABS_MIN_FREQ_2595   1000	/*  10.00 MHz  (really  10.697) */
2462306a36Sopenharmony_ci#define N_ADJ_2595           257
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#define STOP_BITS_2595     0x1800
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#define MIN_N_408		2
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#define MIN_N_1703		6
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#define MIN_M		2
3462306a36Sopenharmony_ci#define MAX_M		30
3562306a36Sopenharmony_ci#define MIN_N		35
3662306a36Sopenharmony_ci#define MAX_N		255-8
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci    /*
4062306a36Sopenharmony_ci     *  Support Functions
4162306a36Sopenharmony_ci     */
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistatic void aty_dac_waste4(const struct atyfb_par *par)
4462306a36Sopenharmony_ci{
4562306a36Sopenharmony_ci	(void) aty_ld_8(DAC_REGS, par);
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	(void) aty_ld_8(DAC_REGS + 2, par);
4862306a36Sopenharmony_ci	(void) aty_ld_8(DAC_REGS + 2, par);
4962306a36Sopenharmony_ci	(void) aty_ld_8(DAC_REGS + 2, par);
5062306a36Sopenharmony_ci	(void) aty_ld_8(DAC_REGS + 2, par);
5162306a36Sopenharmony_ci}
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistatic void aty_StrobeClock(const struct atyfb_par *par)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	u8 tmp;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	udelay(26);
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	tmp = aty_ld_8(CLOCK_CNTL, par);
6062306a36Sopenharmony_ci	aty_st_8(CLOCK_CNTL + par->clk_wr_offset, tmp | CLOCK_STROBE, par);
6162306a36Sopenharmony_ci	return;
6262306a36Sopenharmony_ci}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci    /*
6662306a36Sopenharmony_ci     *  IBM RGB514 DAC and Clock Chip
6762306a36Sopenharmony_ci     */
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistatic void aty_st_514(int offset, u8 val, const struct atyfb_par *par)
7062306a36Sopenharmony_ci{
7162306a36Sopenharmony_ci	aty_st_8(DAC_CNTL, 1, par);
7262306a36Sopenharmony_ci	/* right addr byte */
7362306a36Sopenharmony_ci	aty_st_8(DAC_W_INDEX, offset & 0xff, par);
7462306a36Sopenharmony_ci	/* left addr byte */
7562306a36Sopenharmony_ci	aty_st_8(DAC_DATA, (offset >> 8) & 0xff, par);
7662306a36Sopenharmony_ci	aty_st_8(DAC_MASK, val, par);
7762306a36Sopenharmony_ci	aty_st_8(DAC_CNTL, 0, par);
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cistatic int aty_set_dac_514(const struct fb_info *info,
8162306a36Sopenharmony_ci			   const union aty_pll *pll, u32 bpp, u32 accel)
8262306a36Sopenharmony_ci{
8362306a36Sopenharmony_ci	struct atyfb_par *par = (struct atyfb_par *) info->par;
8462306a36Sopenharmony_ci	static struct {
8562306a36Sopenharmony_ci		u8 pixel_dly;
8662306a36Sopenharmony_ci		u8 misc2_cntl;
8762306a36Sopenharmony_ci		u8 pixel_rep;
8862306a36Sopenharmony_ci		u8 pixel_cntl_index;
8962306a36Sopenharmony_ci		u8 pixel_cntl_v1;
9062306a36Sopenharmony_ci	} tab[3] = {
9162306a36Sopenharmony_ci		{
9262306a36Sopenharmony_ci		0, 0x41, 0x03, 0x71, 0x45},	/* 8 bpp */
9362306a36Sopenharmony_ci		{
9462306a36Sopenharmony_ci		0, 0x45, 0x04, 0x0c, 0x01},	/* 555 */
9562306a36Sopenharmony_ci		{
9662306a36Sopenharmony_ci		0, 0x45, 0x06, 0x0e, 0x00},	/* XRGB */
9762306a36Sopenharmony_ci	};
9862306a36Sopenharmony_ci	int i;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	switch (bpp) {
10162306a36Sopenharmony_ci	case 8:
10262306a36Sopenharmony_ci	default:
10362306a36Sopenharmony_ci		i = 0;
10462306a36Sopenharmony_ci		break;
10562306a36Sopenharmony_ci	case 16:
10662306a36Sopenharmony_ci		i = 1;
10762306a36Sopenharmony_ci		break;
10862306a36Sopenharmony_ci	case 32:
10962306a36Sopenharmony_ci		i = 2;
11062306a36Sopenharmony_ci		break;
11162306a36Sopenharmony_ci	}
11262306a36Sopenharmony_ci	aty_st_514(0x90, 0x00, par);	/* VRAM Mask Low */
11362306a36Sopenharmony_ci	aty_st_514(0x04, tab[i].pixel_dly, par);	/* Horizontal Sync Control */
11462306a36Sopenharmony_ci	aty_st_514(0x05, 0x00, par);	/* Power Management */
11562306a36Sopenharmony_ci	aty_st_514(0x02, 0x01, par);	/* Misc Clock Control */
11662306a36Sopenharmony_ci	aty_st_514(0x71, tab[i].misc2_cntl, par);	/* Misc Control 2 */
11762306a36Sopenharmony_ci	aty_st_514(0x0a, tab[i].pixel_rep, par);	/* Pixel Format */
11862306a36Sopenharmony_ci	aty_st_514(tab[i].pixel_cntl_index, tab[i].pixel_cntl_v1, par);
11962306a36Sopenharmony_ci	/* Misc Control 2 / 16 BPP Control / 32 BPP Control */
12062306a36Sopenharmony_ci	return 0;
12162306a36Sopenharmony_ci}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_cistatic int aty_var_to_pll_514(const struct fb_info *info, u32 vclk_per,
12462306a36Sopenharmony_ci			      u32 bpp, union aty_pll *pll)
12562306a36Sopenharmony_ci{
12662306a36Sopenharmony_ci	/*
12762306a36Sopenharmony_ci	 *  FIXME: use real calculations instead of using fixed values from the old
12862306a36Sopenharmony_ci	 *         driver
12962306a36Sopenharmony_ci	 */
13062306a36Sopenharmony_ci	static struct {
13162306a36Sopenharmony_ci		u32 limit;	/* pixlock rounding limit (arbitrary) */
13262306a36Sopenharmony_ci		u8 m;		/* (df<<6) | vco_div_count */
13362306a36Sopenharmony_ci		u8 n;		/* ref_div_count */
13462306a36Sopenharmony_ci	} RGB514_clocks[7] = {
13562306a36Sopenharmony_ci		{
13662306a36Sopenharmony_ci		8000, (3 << 6) | 20, 9},	/*  7395 ps / 135.2273 MHz */
13762306a36Sopenharmony_ci		{
13862306a36Sopenharmony_ci		10000, (1 << 6) | 19, 3},	/*  9977 ps / 100.2273 MHz */
13962306a36Sopenharmony_ci		{
14062306a36Sopenharmony_ci		13000, (1 << 6) | 2, 3},	/* 12509 ps /  79.9432 MHz */
14162306a36Sopenharmony_ci		{
14262306a36Sopenharmony_ci		14000, (2 << 6) | 8, 7},	/* 13394 ps /  74.6591 MHz */
14362306a36Sopenharmony_ci		{
14462306a36Sopenharmony_ci		16000, (1 << 6) | 44, 6},	/* 15378 ps /  65.0284 MHz */
14562306a36Sopenharmony_ci		{
14662306a36Sopenharmony_ci		25000, (1 << 6) | 15, 5},	/* 17460 ps /  57.2727 MHz */
14762306a36Sopenharmony_ci		{
14862306a36Sopenharmony_ci		50000, (0 << 6) | 53, 7},	/* 33145 ps /  30.1705 MHz */
14962306a36Sopenharmony_ci	};
15062306a36Sopenharmony_ci	int i;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(RGB514_clocks); i++)
15362306a36Sopenharmony_ci		if (vclk_per <= RGB514_clocks[i].limit) {
15462306a36Sopenharmony_ci			pll->ibm514.m = RGB514_clocks[i].m;
15562306a36Sopenharmony_ci			pll->ibm514.n = RGB514_clocks[i].n;
15662306a36Sopenharmony_ci			return 0;
15762306a36Sopenharmony_ci		}
15862306a36Sopenharmony_ci	return -EINVAL;
15962306a36Sopenharmony_ci}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_cistatic u32 aty_pll_514_to_var(const struct fb_info *info,
16262306a36Sopenharmony_ci			      const union aty_pll *pll)
16362306a36Sopenharmony_ci{
16462306a36Sopenharmony_ci	struct atyfb_par *par = (struct atyfb_par *) info->par;
16562306a36Sopenharmony_ci	u8 df, vco_div_count, ref_div_count;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	df = pll->ibm514.m >> 6;
16862306a36Sopenharmony_ci	vco_div_count = pll->ibm514.m & 0x3f;
16962306a36Sopenharmony_ci	ref_div_count = pll->ibm514.n;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	return ((par->ref_clk_per * ref_div_count) << (3 - df))/
17262306a36Sopenharmony_ci	    		(vco_div_count + 65);
17362306a36Sopenharmony_ci}
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_cistatic void aty_set_pll_514(const struct fb_info *info,
17662306a36Sopenharmony_ci			    const union aty_pll *pll)
17762306a36Sopenharmony_ci{
17862306a36Sopenharmony_ci	struct atyfb_par *par = (struct atyfb_par *) info->par;
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	aty_st_514(0x06, 0x02, par);	/* DAC Operation */
18162306a36Sopenharmony_ci	aty_st_514(0x10, 0x01, par);	/* PLL Control 1 */
18262306a36Sopenharmony_ci	aty_st_514(0x70, 0x01, par);	/* Misc Control 1 */
18362306a36Sopenharmony_ci	aty_st_514(0x8f, 0x1f, par);	/* PLL Ref. Divider Input */
18462306a36Sopenharmony_ci	aty_st_514(0x03, 0x00, par);	/* Sync Control */
18562306a36Sopenharmony_ci	aty_st_514(0x05, 0x00, par);	/* Power Management */
18662306a36Sopenharmony_ci	aty_st_514(0x20, pll->ibm514.m, par);	/* F0 / M0 */
18762306a36Sopenharmony_ci	aty_st_514(0x21, pll->ibm514.n, par);	/* F1 / N0 */
18862306a36Sopenharmony_ci}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ciconst struct aty_dac_ops aty_dac_ibm514 = {
19162306a36Sopenharmony_ci	.set_dac	= aty_set_dac_514,
19262306a36Sopenharmony_ci};
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ciconst struct aty_pll_ops aty_pll_ibm514 = {
19562306a36Sopenharmony_ci	.var_to_pll	= aty_var_to_pll_514,
19662306a36Sopenharmony_ci	.pll_to_var	= aty_pll_514_to_var,
19762306a36Sopenharmony_ci	.set_pll	= aty_set_pll_514,
19862306a36Sopenharmony_ci};
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci    /*
20262306a36Sopenharmony_ci     *  ATI 68860-B DAC
20362306a36Sopenharmony_ci     */
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_cistatic int aty_set_dac_ATI68860_B(const struct fb_info *info,
20662306a36Sopenharmony_ci				  const union aty_pll *pll, u32 bpp,
20762306a36Sopenharmony_ci				  u32 accel)
20862306a36Sopenharmony_ci{
20962306a36Sopenharmony_ci	struct atyfb_par *par = (struct atyfb_par *) info->par;
21062306a36Sopenharmony_ci	u32 gModeReg, devSetupRegA, temp, mask;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	gModeReg = 0;
21362306a36Sopenharmony_ci	devSetupRegA = 0;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	switch (bpp) {
21662306a36Sopenharmony_ci	case 8:
21762306a36Sopenharmony_ci		gModeReg = 0x83;
21862306a36Sopenharmony_ci		devSetupRegA =
21962306a36Sopenharmony_ci		    0x60 | 0x00 /*(info->mach64DAC8Bit ? 0x00 : 0x01) */ ;
22062306a36Sopenharmony_ci		break;
22162306a36Sopenharmony_ci	case 15:
22262306a36Sopenharmony_ci		gModeReg = 0xA0;
22362306a36Sopenharmony_ci		devSetupRegA = 0x60;
22462306a36Sopenharmony_ci		break;
22562306a36Sopenharmony_ci	case 16:
22662306a36Sopenharmony_ci		gModeReg = 0xA1;
22762306a36Sopenharmony_ci		devSetupRegA = 0x60;
22862306a36Sopenharmony_ci		break;
22962306a36Sopenharmony_ci	case 24:
23062306a36Sopenharmony_ci		gModeReg = 0xC0;
23162306a36Sopenharmony_ci		devSetupRegA = 0x60;
23262306a36Sopenharmony_ci		break;
23362306a36Sopenharmony_ci	case 32:
23462306a36Sopenharmony_ci		gModeReg = 0xE3;
23562306a36Sopenharmony_ci		devSetupRegA = 0x60;
23662306a36Sopenharmony_ci		break;
23762306a36Sopenharmony_ci	}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	if (!accel) {
24062306a36Sopenharmony_ci		gModeReg = 0x80;
24162306a36Sopenharmony_ci		devSetupRegA = 0x61;
24262306a36Sopenharmony_ci	}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	temp = aty_ld_8(DAC_CNTL, par);
24562306a36Sopenharmony_ci	aty_st_8(DAC_CNTL, (temp & ~DAC_EXT_SEL_RS2) | DAC_EXT_SEL_RS3,
24662306a36Sopenharmony_ci		 par);
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	aty_st_8(DAC_REGS + 2, 0x1D, par);
24962306a36Sopenharmony_ci	aty_st_8(DAC_REGS + 3, gModeReg, par);
25062306a36Sopenharmony_ci	aty_st_8(DAC_REGS, 0x02, par);
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	temp = aty_ld_8(DAC_CNTL, par);
25362306a36Sopenharmony_ci	aty_st_8(DAC_CNTL, temp | DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3, par);
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	if (info->fix.smem_len < ONE_MB)
25662306a36Sopenharmony_ci		mask = 0x04;
25762306a36Sopenharmony_ci	else if (info->fix.smem_len == ONE_MB)
25862306a36Sopenharmony_ci		mask = 0x08;
25962306a36Sopenharmony_ci	else
26062306a36Sopenharmony_ci		mask = 0x0C;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	/* The following assumes that the BIOS has correctly set R7 of the
26362306a36Sopenharmony_ci	 * Device Setup Register A at boot time.
26462306a36Sopenharmony_ci	 */
26562306a36Sopenharmony_ci#define A860_DELAY_L	0x80
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	temp = aty_ld_8(DAC_REGS, par);
26862306a36Sopenharmony_ci	aty_st_8(DAC_REGS, (devSetupRegA | mask) | (temp & A860_DELAY_L),
26962306a36Sopenharmony_ci		 par);
27062306a36Sopenharmony_ci	temp = aty_ld_8(DAC_CNTL, par);
27162306a36Sopenharmony_ci	aty_st_8(DAC_CNTL, (temp & ~(DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3)),
27262306a36Sopenharmony_ci		 par);
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	aty_st_le32(BUS_CNTL, 0x890e20f1, par);
27562306a36Sopenharmony_ci	aty_st_le32(DAC_CNTL, 0x47052100, par);
27662306a36Sopenharmony_ci	return 0;
27762306a36Sopenharmony_ci}
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ciconst struct aty_dac_ops aty_dac_ati68860b = {
28062306a36Sopenharmony_ci	.set_dac	= aty_set_dac_ATI68860_B,
28162306a36Sopenharmony_ci};
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci    /*
28562306a36Sopenharmony_ci     *  AT&T 21C498 DAC
28662306a36Sopenharmony_ci     */
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_cistatic int aty_set_dac_ATT21C498(const struct fb_info *info,
28962306a36Sopenharmony_ci				 const union aty_pll *pll, u32 bpp,
29062306a36Sopenharmony_ci				 u32 accel)
29162306a36Sopenharmony_ci{
29262306a36Sopenharmony_ci	struct atyfb_par *par = (struct atyfb_par *) info->par;
29362306a36Sopenharmony_ci	u32 dotClock;
29462306a36Sopenharmony_ci	int muxmode = 0;
29562306a36Sopenharmony_ci	int DACMask = 0;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	dotClock = 100000000 / pll->ics2595.period_in_ps;
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	switch (bpp) {
30062306a36Sopenharmony_ci	case 8:
30162306a36Sopenharmony_ci		if (dotClock > 8000) {
30262306a36Sopenharmony_ci			DACMask = 0x24;
30362306a36Sopenharmony_ci			muxmode = 1;
30462306a36Sopenharmony_ci		} else
30562306a36Sopenharmony_ci			DACMask = 0x04;
30662306a36Sopenharmony_ci		break;
30762306a36Sopenharmony_ci	case 15:
30862306a36Sopenharmony_ci		DACMask = 0x16;
30962306a36Sopenharmony_ci		break;
31062306a36Sopenharmony_ci	case 16:
31162306a36Sopenharmony_ci		DACMask = 0x36;
31262306a36Sopenharmony_ci		break;
31362306a36Sopenharmony_ci	case 24:
31462306a36Sopenharmony_ci		DACMask = 0xE6;
31562306a36Sopenharmony_ci		break;
31662306a36Sopenharmony_ci	case 32:
31762306a36Sopenharmony_ci		DACMask = 0xE6;
31862306a36Sopenharmony_ci		break;
31962306a36Sopenharmony_ci	}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	if (1 /* info->mach64DAC8Bit */ )
32262306a36Sopenharmony_ci		DACMask |= 0x02;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	aty_dac_waste4(par);
32562306a36Sopenharmony_ci	aty_st_8(DAC_REGS + 2, DACMask, par);
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	aty_st_le32(BUS_CNTL, 0x890e20f1, par);
32862306a36Sopenharmony_ci	aty_st_le32(DAC_CNTL, 0x00072000, par);
32962306a36Sopenharmony_ci	return muxmode;
33062306a36Sopenharmony_ci}
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ciconst struct aty_dac_ops aty_dac_att21c498 = {
33362306a36Sopenharmony_ci	.set_dac	= aty_set_dac_ATT21C498,
33462306a36Sopenharmony_ci};
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci    /*
33862306a36Sopenharmony_ci     *  ATI 18818 / ICS 2595 Clock Chip
33962306a36Sopenharmony_ci     */
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_cistatic int aty_var_to_pll_18818(const struct fb_info *info, u32 vclk_per,
34262306a36Sopenharmony_ci				u32 bpp, union aty_pll *pll)
34362306a36Sopenharmony_ci{
34462306a36Sopenharmony_ci	u32 MHz100;		/* in 0.01 MHz */
34562306a36Sopenharmony_ci	u32 program_bits;
34662306a36Sopenharmony_ci	u32 post_divider;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	/* Calculate the programming word */
34962306a36Sopenharmony_ci	MHz100 = 100000000 / vclk_per;
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	program_bits = -1;
35262306a36Sopenharmony_ci	post_divider = 1;
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	if (MHz100 > MAX_FREQ_2595) {
35562306a36Sopenharmony_ci		return -EINVAL;
35662306a36Sopenharmony_ci	} else if (MHz100 < ABS_MIN_FREQ_2595) {
35762306a36Sopenharmony_ci		return -EINVAL;
35862306a36Sopenharmony_ci	} else {
35962306a36Sopenharmony_ci		while (MHz100 < MIN_FREQ_2595) {
36062306a36Sopenharmony_ci			MHz100 *= 2;
36162306a36Sopenharmony_ci			post_divider *= 2;
36262306a36Sopenharmony_ci		}
36362306a36Sopenharmony_ci	}
36462306a36Sopenharmony_ci	MHz100 *= 1000;
36562306a36Sopenharmony_ci	MHz100 = (REF_DIV_2595 * MHz100) / REF_FREQ_2595;
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	MHz100 += 500;		/* + 0.5 round */
36862306a36Sopenharmony_ci	MHz100 /= 1000;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	if (program_bits == -1) {
37162306a36Sopenharmony_ci		program_bits = MHz100 - N_ADJ_2595;
37262306a36Sopenharmony_ci		switch (post_divider) {
37362306a36Sopenharmony_ci		case 1:
37462306a36Sopenharmony_ci			program_bits |= 0x0600;
37562306a36Sopenharmony_ci			break;
37662306a36Sopenharmony_ci		case 2:
37762306a36Sopenharmony_ci			program_bits |= 0x0400;
37862306a36Sopenharmony_ci			break;
37962306a36Sopenharmony_ci		case 4:
38062306a36Sopenharmony_ci			program_bits |= 0x0200;
38162306a36Sopenharmony_ci			break;
38262306a36Sopenharmony_ci		case 8:
38362306a36Sopenharmony_ci		default:
38462306a36Sopenharmony_ci			break;
38562306a36Sopenharmony_ci		}
38662306a36Sopenharmony_ci	}
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	program_bits |= STOP_BITS_2595;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	pll->ics2595.program_bits = program_bits;
39162306a36Sopenharmony_ci	pll->ics2595.locationAddr = 0;
39262306a36Sopenharmony_ci	pll->ics2595.post_divider = post_divider;
39362306a36Sopenharmony_ci	pll->ics2595.period_in_ps = vclk_per;
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	return 0;
39662306a36Sopenharmony_ci}
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_cistatic u32 aty_pll_18818_to_var(const struct fb_info *info,
39962306a36Sopenharmony_ci				const union aty_pll *pll)
40062306a36Sopenharmony_ci{
40162306a36Sopenharmony_ci	return (pll->ics2595.period_in_ps);	/* default for now */
40262306a36Sopenharmony_ci}
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_cistatic void aty_ICS2595_put1bit(u8 data, const struct atyfb_par *par)
40562306a36Sopenharmony_ci{
40662306a36Sopenharmony_ci	u8 tmp;
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	data &= 0x01;
40962306a36Sopenharmony_ci	tmp = aty_ld_8(CLOCK_CNTL, par);
41062306a36Sopenharmony_ci	aty_st_8(CLOCK_CNTL + par->clk_wr_offset,
41162306a36Sopenharmony_ci		 (tmp & ~0x04) | (data << 2), par);
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	tmp = aty_ld_8(CLOCK_CNTL, par);
41462306a36Sopenharmony_ci	aty_st_8(CLOCK_CNTL + par->clk_wr_offset, (tmp & ~0x08) | (0 << 3),
41562306a36Sopenharmony_ci		 par);
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	aty_StrobeClock(par);
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	tmp = aty_ld_8(CLOCK_CNTL, par);
42062306a36Sopenharmony_ci	aty_st_8(CLOCK_CNTL + par->clk_wr_offset, (tmp & ~0x08) | (1 << 3),
42162306a36Sopenharmony_ci		 par);
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	aty_StrobeClock(par);
42462306a36Sopenharmony_ci	return;
42562306a36Sopenharmony_ci}
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_cistatic void aty_set_pll18818(const struct fb_info *info,
42862306a36Sopenharmony_ci			     const union aty_pll *pll)
42962306a36Sopenharmony_ci{
43062306a36Sopenharmony_ci	struct atyfb_par *par = (struct atyfb_par *) info->par;
43162306a36Sopenharmony_ci	u32 program_bits;
43262306a36Sopenharmony_ci	u32 locationAddr;
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	u32 i;
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	u8 old_clock_cntl;
43762306a36Sopenharmony_ci	u8 old_crtc_ext_disp;
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	old_clock_cntl = aty_ld_8(CLOCK_CNTL, par);
44062306a36Sopenharmony_ci	aty_st_8(CLOCK_CNTL + par->clk_wr_offset, 0, par);
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, par);
44362306a36Sopenharmony_ci	aty_st_8(CRTC_GEN_CNTL + 3,
44462306a36Sopenharmony_ci		 old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24), par);
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	mdelay(15);		/* delay for 50 (15) ms */
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	program_bits = pll->ics2595.program_bits;
44962306a36Sopenharmony_ci	locationAddr = pll->ics2595.locationAddr;
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	/* Program the clock chip */
45262306a36Sopenharmony_ci	aty_st_8(CLOCK_CNTL + par->clk_wr_offset, 0, par);	/* Strobe = 0 */
45362306a36Sopenharmony_ci	aty_StrobeClock(par);
45462306a36Sopenharmony_ci	aty_st_8(CLOCK_CNTL + par->clk_wr_offset, 1, par);	/* Strobe = 0 */
45562306a36Sopenharmony_ci	aty_StrobeClock(par);
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	aty_ICS2595_put1bit(1, par);	/* Send start bits */
45862306a36Sopenharmony_ci	aty_ICS2595_put1bit(0, par);	/* Start bit */
45962306a36Sopenharmony_ci	aty_ICS2595_put1bit(0, par);	/* Read / ~Write */
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	for (i = 0; i < 5; i++) {	/* Location 0..4 */
46262306a36Sopenharmony_ci		aty_ICS2595_put1bit(locationAddr & 1, par);
46362306a36Sopenharmony_ci		locationAddr >>= 1;
46462306a36Sopenharmony_ci	}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	for (i = 0; i < 8 + 1 + 2 + 2; i++) {
46762306a36Sopenharmony_ci		aty_ICS2595_put1bit(program_bits & 1, par);
46862306a36Sopenharmony_ci		program_bits >>= 1;
46962306a36Sopenharmony_ci	}
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	mdelay(1);		/* delay for 1 ms */
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	(void) aty_ld_8(DAC_REGS, par);	/* Clear DAC Counter */
47462306a36Sopenharmony_ci	aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, par);
47562306a36Sopenharmony_ci	aty_st_8(CLOCK_CNTL + par->clk_wr_offset,
47662306a36Sopenharmony_ci		 old_clock_cntl | CLOCK_STROBE, par);
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	mdelay(50);		/* delay for 50 (15) ms */
47962306a36Sopenharmony_ci	aty_st_8(CLOCK_CNTL + par->clk_wr_offset,
48062306a36Sopenharmony_ci		 ((pll->ics2595.locationAddr & 0x0F) | CLOCK_STROBE), par);
48162306a36Sopenharmony_ci	return;
48262306a36Sopenharmony_ci}
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ciconst struct aty_pll_ops aty_pll_ati18818_1 = {
48562306a36Sopenharmony_ci	.var_to_pll	= aty_var_to_pll_18818,
48662306a36Sopenharmony_ci	.pll_to_var	= aty_pll_18818_to_var,
48762306a36Sopenharmony_ci	.set_pll	= aty_set_pll18818,
48862306a36Sopenharmony_ci};
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci    /*
49262306a36Sopenharmony_ci     *  STG 1703 Clock Chip
49362306a36Sopenharmony_ci     */
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_cistatic int aty_var_to_pll_1703(const struct fb_info *info, u32 vclk_per,
49662306a36Sopenharmony_ci			       u32 bpp, union aty_pll *pll)
49762306a36Sopenharmony_ci{
49862306a36Sopenharmony_ci	u32 mhz100;		/* in 0.01 MHz */
49962306a36Sopenharmony_ci	u32 program_bits;
50062306a36Sopenharmony_ci	/* u32 post_divider; */
50162306a36Sopenharmony_ci	u32 mach64MinFreq, mach64MaxFreq, mach64RefFreq;
50262306a36Sopenharmony_ci	u32 temp, tempB;
50362306a36Sopenharmony_ci	u16 remainder, preRemainder;
50462306a36Sopenharmony_ci	short divider = 0, tempA;
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	/* Calculate the programming word */
50762306a36Sopenharmony_ci	mhz100 = 100000000 / vclk_per;
50862306a36Sopenharmony_ci	mach64MinFreq = MIN_FREQ_2595;
50962306a36Sopenharmony_ci	mach64MaxFreq = MAX_FREQ_2595;
51062306a36Sopenharmony_ci	mach64RefFreq = REF_FREQ_2595;	/* 14.32 MHz */
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	/* Calculate program word */
51362306a36Sopenharmony_ci	if (mhz100 == 0)
51462306a36Sopenharmony_ci		program_bits = 0xE0;
51562306a36Sopenharmony_ci	else {
51662306a36Sopenharmony_ci		if (mhz100 < mach64MinFreq)
51762306a36Sopenharmony_ci			mhz100 = mach64MinFreq;
51862306a36Sopenharmony_ci		if (mhz100 > mach64MaxFreq)
51962306a36Sopenharmony_ci			mhz100 = mach64MaxFreq;
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci		divider = 0;
52262306a36Sopenharmony_ci		while (mhz100 < (mach64MinFreq << 3)) {
52362306a36Sopenharmony_ci			mhz100 <<= 1;
52462306a36Sopenharmony_ci			divider += 0x20;
52562306a36Sopenharmony_ci		}
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci		temp = (unsigned int) (mhz100);
52862306a36Sopenharmony_ci		temp = (unsigned int) (temp * (MIN_N_1703 + 2));
52962306a36Sopenharmony_ci		temp -= (short) (mach64RefFreq << 1);
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci		tempA = MIN_N_1703;
53262306a36Sopenharmony_ci		preRemainder = 0xffff;
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci		do {
53562306a36Sopenharmony_ci			tempB = temp;
53662306a36Sopenharmony_ci			remainder = tempB % mach64RefFreq;
53762306a36Sopenharmony_ci			tempB = tempB / mach64RefFreq;
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci			if ((tempB & 0xffff) <= 127
54062306a36Sopenharmony_ci			    && (remainder <= preRemainder)) {
54162306a36Sopenharmony_ci				preRemainder = remainder;
54262306a36Sopenharmony_ci				divider &= ~0x1f;
54362306a36Sopenharmony_ci				divider |= tempA;
54462306a36Sopenharmony_ci				divider =
54562306a36Sopenharmony_ci				    (divider & 0x00ff) +
54662306a36Sopenharmony_ci				    ((tempB & 0xff) << 8);
54762306a36Sopenharmony_ci			}
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci			temp += mhz100;
55062306a36Sopenharmony_ci			tempA++;
55162306a36Sopenharmony_ci		} while (tempA <= (MIN_N_1703 << 1));
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci		program_bits = divider;
55462306a36Sopenharmony_ci	}
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	pll->ics2595.program_bits = program_bits;
55762306a36Sopenharmony_ci	pll->ics2595.locationAddr = 0;
55862306a36Sopenharmony_ci	pll->ics2595.post_divider = divider;	/* fuer nix */
55962306a36Sopenharmony_ci	pll->ics2595.period_in_ps = vclk_per;
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	return 0;
56262306a36Sopenharmony_ci}
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_cistatic u32 aty_pll_1703_to_var(const struct fb_info *info,
56562306a36Sopenharmony_ci			       const union aty_pll *pll)
56662306a36Sopenharmony_ci{
56762306a36Sopenharmony_ci	return (pll->ics2595.period_in_ps);	/* default for now */
56862306a36Sopenharmony_ci}
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_cistatic void aty_set_pll_1703(const struct fb_info *info,
57162306a36Sopenharmony_ci			     const union aty_pll *pll)
57262306a36Sopenharmony_ci{
57362306a36Sopenharmony_ci	struct atyfb_par *par = (struct atyfb_par *) info->par;
57462306a36Sopenharmony_ci	u32 program_bits;
57562306a36Sopenharmony_ci	u32 locationAddr;
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	char old_crtc_ext_disp;
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, par);
58062306a36Sopenharmony_ci	aty_st_8(CRTC_GEN_CNTL + 3,
58162306a36Sopenharmony_ci		 old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24), par);
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	program_bits = pll->ics2595.program_bits;
58462306a36Sopenharmony_ci	locationAddr = pll->ics2595.locationAddr;
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	/* Program clock */
58762306a36Sopenharmony_ci	aty_dac_waste4(par);
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	(void) aty_ld_8(DAC_REGS + 2, par);
59062306a36Sopenharmony_ci	aty_st_8(DAC_REGS + 2, (locationAddr << 1) + 0x20, par);
59162306a36Sopenharmony_ci	aty_st_8(DAC_REGS + 2, 0, par);
59262306a36Sopenharmony_ci	aty_st_8(DAC_REGS + 2, (program_bits & 0xFF00) >> 8, par);
59362306a36Sopenharmony_ci	aty_st_8(DAC_REGS + 2, (program_bits & 0xFF), par);
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	(void) aty_ld_8(DAC_REGS, par);	/* Clear DAC Counter */
59662306a36Sopenharmony_ci	aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, par);
59762306a36Sopenharmony_ci	return;
59862306a36Sopenharmony_ci}
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ciconst struct aty_pll_ops aty_pll_stg1703 = {
60162306a36Sopenharmony_ci	.var_to_pll	= aty_var_to_pll_1703,
60262306a36Sopenharmony_ci	.pll_to_var	= aty_pll_1703_to_var,
60362306a36Sopenharmony_ci	.set_pll	= aty_set_pll_1703,
60462306a36Sopenharmony_ci};
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci    /*
60862306a36Sopenharmony_ci     *  Chrontel 8398 Clock Chip
60962306a36Sopenharmony_ci     */
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_cistatic int aty_var_to_pll_8398(const struct fb_info *info, u32 vclk_per,
61262306a36Sopenharmony_ci			       u32 bpp, union aty_pll *pll)
61362306a36Sopenharmony_ci{
61462306a36Sopenharmony_ci	u32 tempA, tempB, fOut, longMHz100, diff, preDiff;
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	u32 mhz100;		/* in 0.01 MHz */
61762306a36Sopenharmony_ci	u32 program_bits;
61862306a36Sopenharmony_ci	/* u32 post_divider; */
61962306a36Sopenharmony_ci	u32 mach64MinFreq, mach64MaxFreq;
62062306a36Sopenharmony_ci	u16 m, n, k = 0, save_m, save_n, twoToKth;
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	/* Calculate the programming word */
62362306a36Sopenharmony_ci	mhz100 = 100000000 / vclk_per;
62462306a36Sopenharmony_ci	mach64MinFreq = MIN_FREQ_2595;
62562306a36Sopenharmony_ci	mach64MaxFreq = MAX_FREQ_2595;
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	save_m = 0;
62862306a36Sopenharmony_ci	save_n = 0;
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	/* Calculate program word */
63162306a36Sopenharmony_ci	if (mhz100 == 0)
63262306a36Sopenharmony_ci		program_bits = 0xE0;
63362306a36Sopenharmony_ci	else {
63462306a36Sopenharmony_ci		if (mhz100 < mach64MinFreq)
63562306a36Sopenharmony_ci			mhz100 = mach64MinFreq;
63662306a36Sopenharmony_ci		if (mhz100 > mach64MaxFreq)
63762306a36Sopenharmony_ci			mhz100 = mach64MaxFreq;
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci		longMHz100 = mhz100 * 256 / 100;	/* 8 bit scale this */
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci		while (mhz100 < (mach64MinFreq << 3)) {
64262306a36Sopenharmony_ci			mhz100 <<= 1;
64362306a36Sopenharmony_ci			k++;
64462306a36Sopenharmony_ci		}
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci		twoToKth = 1 << k;
64762306a36Sopenharmony_ci		diff = 0;
64862306a36Sopenharmony_ci		preDiff = 0xFFFFFFFF;
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci		for (m = MIN_M; m <= MAX_M; m++) {
65162306a36Sopenharmony_ci			for (n = MIN_N; n <= MAX_N; n++) {
65262306a36Sopenharmony_ci				tempA = 938356;		/* 14.31818 * 65536 */
65362306a36Sopenharmony_ci				tempA *= (n + 8);	/* 43..256 */
65462306a36Sopenharmony_ci				tempB = twoToKth * 256;
65562306a36Sopenharmony_ci				tempB *= (m + 2);	/* 4..32 */
65662306a36Sopenharmony_ci				fOut = tempA / tempB;	/* 8 bit scale */
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci				if (longMHz100 > fOut)
65962306a36Sopenharmony_ci					diff = longMHz100 - fOut;
66062306a36Sopenharmony_ci				else
66162306a36Sopenharmony_ci					diff = fOut - longMHz100;
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci				if (diff < preDiff) {
66462306a36Sopenharmony_ci					save_m = m;
66562306a36Sopenharmony_ci					save_n = n;
66662306a36Sopenharmony_ci					preDiff = diff;
66762306a36Sopenharmony_ci				}
66862306a36Sopenharmony_ci			}
66962306a36Sopenharmony_ci		}
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci		program_bits = (k << 6) + (save_m) + (save_n << 8);
67262306a36Sopenharmony_ci	}
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	pll->ics2595.program_bits = program_bits;
67562306a36Sopenharmony_ci	pll->ics2595.locationAddr = 0;
67662306a36Sopenharmony_ci	pll->ics2595.post_divider = 0;
67762306a36Sopenharmony_ci	pll->ics2595.period_in_ps = vclk_per;
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	return 0;
68062306a36Sopenharmony_ci}
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_cistatic u32 aty_pll_8398_to_var(const struct fb_info *info,
68362306a36Sopenharmony_ci			       const union aty_pll *pll)
68462306a36Sopenharmony_ci{
68562306a36Sopenharmony_ci	return (pll->ics2595.period_in_ps);	/* default for now */
68662306a36Sopenharmony_ci}
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_cistatic void aty_set_pll_8398(const struct fb_info *info,
68962306a36Sopenharmony_ci			     const union aty_pll *pll)
69062306a36Sopenharmony_ci{
69162306a36Sopenharmony_ci	struct atyfb_par *par = (struct atyfb_par *) info->par;
69262306a36Sopenharmony_ci	u32 program_bits;
69362306a36Sopenharmony_ci	u32 locationAddr;
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	char old_crtc_ext_disp;
69662306a36Sopenharmony_ci	char tmp;
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, par);
69962306a36Sopenharmony_ci	aty_st_8(CRTC_GEN_CNTL + 3,
70062306a36Sopenharmony_ci		 old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24), par);
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	program_bits = pll->ics2595.program_bits;
70362306a36Sopenharmony_ci	locationAddr = pll->ics2595.locationAddr;
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	/* Program clock */
70662306a36Sopenharmony_ci	tmp = aty_ld_8(DAC_CNTL, par);
70762306a36Sopenharmony_ci	aty_st_8(DAC_CNTL, tmp | DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3, par);
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	aty_st_8(DAC_REGS, locationAddr, par);
71062306a36Sopenharmony_ci	aty_st_8(DAC_REGS + 1, (program_bits & 0xff00) >> 8, par);
71162306a36Sopenharmony_ci	aty_st_8(DAC_REGS + 1, (program_bits & 0xff), par);
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	tmp = aty_ld_8(DAC_CNTL, par);
71462306a36Sopenharmony_ci	aty_st_8(DAC_CNTL, (tmp & ~DAC_EXT_SEL_RS2) | DAC_EXT_SEL_RS3,
71562306a36Sopenharmony_ci		 par);
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	(void) aty_ld_8(DAC_REGS, par);	/* Clear DAC Counter */
71862306a36Sopenharmony_ci	aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, par);
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	return;
72162306a36Sopenharmony_ci}
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ciconst struct aty_pll_ops aty_pll_ch8398 = {
72462306a36Sopenharmony_ci	.var_to_pll	= aty_var_to_pll_8398,
72562306a36Sopenharmony_ci	.pll_to_var	= aty_pll_8398_to_var,
72662306a36Sopenharmony_ci	.set_pll	= aty_set_pll_8398,
72762306a36Sopenharmony_ci};
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci    /*
73162306a36Sopenharmony_ci     *  AT&T 20C408 Clock Chip
73262306a36Sopenharmony_ci     */
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_cistatic int aty_var_to_pll_408(const struct fb_info *info, u32 vclk_per,
73562306a36Sopenharmony_ci			      u32 bpp, union aty_pll *pll)
73662306a36Sopenharmony_ci{
73762306a36Sopenharmony_ci	u32 mhz100;		/* in 0.01 MHz */
73862306a36Sopenharmony_ci	u32 program_bits;
73962306a36Sopenharmony_ci	/* u32 post_divider; */
74062306a36Sopenharmony_ci	u32 mach64MinFreq, mach64MaxFreq, mach64RefFreq;
74162306a36Sopenharmony_ci	u32 temp, tempB;
74262306a36Sopenharmony_ci	u16 remainder, preRemainder;
74362306a36Sopenharmony_ci	short divider = 0, tempA;
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci	/* Calculate the programming word */
74662306a36Sopenharmony_ci	mhz100 = 100000000 / vclk_per;
74762306a36Sopenharmony_ci	mach64MinFreq = MIN_FREQ_2595;
74862306a36Sopenharmony_ci	mach64MaxFreq = MAX_FREQ_2595;
74962306a36Sopenharmony_ci	mach64RefFreq = REF_FREQ_2595;	/* 14.32 MHz */
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	/* Calculate program word */
75262306a36Sopenharmony_ci	if (mhz100 == 0)
75362306a36Sopenharmony_ci		program_bits = 0xFF;
75462306a36Sopenharmony_ci	else {
75562306a36Sopenharmony_ci		if (mhz100 < mach64MinFreq)
75662306a36Sopenharmony_ci			mhz100 = mach64MinFreq;
75762306a36Sopenharmony_ci		if (mhz100 > mach64MaxFreq)
75862306a36Sopenharmony_ci			mhz100 = mach64MaxFreq;
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci		while (mhz100 < (mach64MinFreq << 3)) {
76162306a36Sopenharmony_ci			mhz100 <<= 1;
76262306a36Sopenharmony_ci			divider += 0x40;
76362306a36Sopenharmony_ci		}
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci		temp = (unsigned int) mhz100;
76662306a36Sopenharmony_ci		temp = (unsigned int) (temp * (MIN_N_408 + 2));
76762306a36Sopenharmony_ci		temp -= ((short) (mach64RefFreq << 1));
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci		tempA = MIN_N_408;
77062306a36Sopenharmony_ci		preRemainder = 0xFFFF;
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci		do {
77362306a36Sopenharmony_ci			tempB = temp;
77462306a36Sopenharmony_ci			remainder = tempB % mach64RefFreq;
77562306a36Sopenharmony_ci			tempB = tempB / mach64RefFreq;
77662306a36Sopenharmony_ci			if (((tempB & 0xFFFF) <= 255)
77762306a36Sopenharmony_ci			    && (remainder <= preRemainder)) {
77862306a36Sopenharmony_ci				preRemainder = remainder;
77962306a36Sopenharmony_ci				divider &= ~0x3f;
78062306a36Sopenharmony_ci				divider |= tempA;
78162306a36Sopenharmony_ci				divider =
78262306a36Sopenharmony_ci				    (divider & 0x00FF) +
78362306a36Sopenharmony_ci				    ((tempB & 0xFF) << 8);
78462306a36Sopenharmony_ci			}
78562306a36Sopenharmony_ci			temp += mhz100;
78662306a36Sopenharmony_ci			tempA++;
78762306a36Sopenharmony_ci		} while (tempA <= 32);
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci		program_bits = divider;
79062306a36Sopenharmony_ci	}
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	pll->ics2595.program_bits = program_bits;
79362306a36Sopenharmony_ci	pll->ics2595.locationAddr = 0;
79462306a36Sopenharmony_ci	pll->ics2595.post_divider = divider;	/* fuer nix */
79562306a36Sopenharmony_ci	pll->ics2595.period_in_ps = vclk_per;
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci	return 0;
79862306a36Sopenharmony_ci}
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_cistatic u32 aty_pll_408_to_var(const struct fb_info *info,
80162306a36Sopenharmony_ci			      const union aty_pll *pll)
80262306a36Sopenharmony_ci{
80362306a36Sopenharmony_ci	return (pll->ics2595.period_in_ps);	/* default for now */
80462306a36Sopenharmony_ci}
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_cistatic void aty_set_pll_408(const struct fb_info *info,
80762306a36Sopenharmony_ci			    const union aty_pll *pll)
80862306a36Sopenharmony_ci{
80962306a36Sopenharmony_ci	struct atyfb_par *par = (struct atyfb_par *) info->par;
81062306a36Sopenharmony_ci	u32 program_bits;
81162306a36Sopenharmony_ci	u32 locationAddr;
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci	u8 tmpA, tmpB, tmpC;
81462306a36Sopenharmony_ci	char old_crtc_ext_disp;
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci	old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, par);
81762306a36Sopenharmony_ci	aty_st_8(CRTC_GEN_CNTL + 3,
81862306a36Sopenharmony_ci		 old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24), par);
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	program_bits = pll->ics2595.program_bits;
82162306a36Sopenharmony_ci	locationAddr = pll->ics2595.locationAddr;
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci	/* Program clock */
82462306a36Sopenharmony_ci	aty_dac_waste4(par);
82562306a36Sopenharmony_ci	tmpB = aty_ld_8(DAC_REGS + 2, par) | 1;
82662306a36Sopenharmony_ci	aty_dac_waste4(par);
82762306a36Sopenharmony_ci	aty_st_8(DAC_REGS + 2, tmpB, par);
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	tmpA = tmpB;
83062306a36Sopenharmony_ci	tmpC = tmpA;
83162306a36Sopenharmony_ci	tmpA |= 8;
83262306a36Sopenharmony_ci	tmpB = 1;
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	aty_st_8(DAC_REGS, tmpB, par);
83562306a36Sopenharmony_ci	aty_st_8(DAC_REGS + 2, tmpA, par);
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci	udelay(400);		/* delay for 400 us */
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci	locationAddr = (locationAddr << 2) + 0x40;
84062306a36Sopenharmony_ci	tmpB = locationAddr;
84162306a36Sopenharmony_ci	tmpA = program_bits >> 8;
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci	aty_st_8(DAC_REGS, tmpB, par);
84462306a36Sopenharmony_ci	aty_st_8(DAC_REGS + 2, tmpA, par);
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci	tmpB = locationAddr + 1;
84762306a36Sopenharmony_ci	tmpA = (u8) program_bits;
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci	aty_st_8(DAC_REGS, tmpB, par);
85062306a36Sopenharmony_ci	aty_st_8(DAC_REGS + 2, tmpA, par);
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci	tmpB = locationAddr + 2;
85362306a36Sopenharmony_ci	tmpA = 0x77;
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	aty_st_8(DAC_REGS, tmpB, par);
85662306a36Sopenharmony_ci	aty_st_8(DAC_REGS + 2, tmpA, par);
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci	udelay(400);		/* delay for 400 us */
85962306a36Sopenharmony_ci	tmpA = tmpC & (~(1 | 8));
86062306a36Sopenharmony_ci	tmpB = 1;
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_ci	aty_st_8(DAC_REGS, tmpB, par);
86362306a36Sopenharmony_ci	aty_st_8(DAC_REGS + 2, tmpA, par);
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	(void) aty_ld_8(DAC_REGS, par);	/* Clear DAC Counter */
86662306a36Sopenharmony_ci	aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, par);
86762306a36Sopenharmony_ci	return;
86862306a36Sopenharmony_ci}
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ciconst struct aty_pll_ops aty_pll_att20c408 = {
87162306a36Sopenharmony_ci	.var_to_pll	= aty_var_to_pll_408,
87262306a36Sopenharmony_ci	.pll_to_var	= aty_pll_408_to_var,
87362306a36Sopenharmony_ci	.set_pll	= aty_set_pll_408,
87462306a36Sopenharmony_ci};
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci    /*
87862306a36Sopenharmony_ci     *  Unsupported DAC and Clock Chip
87962306a36Sopenharmony_ci     */
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_cistatic int aty_set_dac_unsupported(const struct fb_info *info,
88262306a36Sopenharmony_ci				   const union aty_pll *pll, u32 bpp,
88362306a36Sopenharmony_ci				   u32 accel)
88462306a36Sopenharmony_ci{
88562306a36Sopenharmony_ci	struct atyfb_par *par = (struct atyfb_par *) info->par;
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	aty_st_le32(BUS_CNTL, 0x890e20f1, par);
88862306a36Sopenharmony_ci	aty_st_le32(DAC_CNTL, 0x47052100, par);
88962306a36Sopenharmony_ci	/* new in 2.2.3p1 from Geert. ???????? */
89062306a36Sopenharmony_ci	aty_st_le32(BUS_CNTL, 0x590e10ff, par);
89162306a36Sopenharmony_ci	aty_st_le32(DAC_CNTL, 0x47012100, par);
89262306a36Sopenharmony_ci	return 0;
89362306a36Sopenharmony_ci}
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_cistatic int dummy(void)
89662306a36Sopenharmony_ci{
89762306a36Sopenharmony_ci	return 0;
89862306a36Sopenharmony_ci}
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ciconst struct aty_dac_ops aty_dac_unsupported = {
90162306a36Sopenharmony_ci	.set_dac	= aty_set_dac_unsupported,
90262306a36Sopenharmony_ci};
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ciconst struct aty_pll_ops aty_pll_unsupported = {
90562306a36Sopenharmony_ci	.var_to_pll	= (void *) dummy,
90662306a36Sopenharmony_ci	.pll_to_var	= (void *) dummy,
90762306a36Sopenharmony_ci	.set_pll	= (void *) dummy,
90862306a36Sopenharmony_ci};
909