/*
* ATI Mach64 GX Support
*/
#include <linux/delay.h>
#include <linux/fb.h>
#include <asm/io.h>
#include <video/mach64.h>
#include "atyfb.h"
/* Definitions for the ICS 2595 == ATI 18818_1 Clockchip */
#define REF_FREQ_2595 1432 /* 14.33 MHz (exact 14.31818) */
#define REF_DIV_2595 46 /* really 43 on ICS 2595 !!! */
/* ohne Prescaler */
#define MAX_FREQ_2595 15938 /* 159.38 MHz (really 170.486) */
#define MIN_FREQ_2595 8000 /* 80.00 MHz ( 85.565) */
/* mit Prescaler 2, 4, 8 */
#define ABS_MIN_FREQ_2595 1000 /* 10.00 MHz (really 10.697) */
#define N_ADJ_2595 257
#define STOP_BITS_2595 0x1800
#define MIN_N_408 2
#define MIN_N_1703 6
#define MIN_M 2
#define MAX_M 30
#define MIN_N 35
#define MAX_N 255-8
/*
* Support Functions
*/
static void aty_dac_waste4(const struct atyfb_par *par)
{
(void) aty_ld_8(DAC_REGS, par);
(void) aty_ld_8(DAC_REGS + 2, par);
(void) aty_ld_8(DAC_REGS + 2, par);
(void) aty_ld_8(DAC_REGS + 2, par);
(void) aty_ld_8(DAC_REGS + 2, par);
}
static void aty_StrobeClock(const struct atyfb_par *par)
{
u8 tmp;
udelay(26);
tmp = aty_ld_8(CLOCK_CNTL, par);
aty_st_8(CLOCK_CNTL + par->clk_wr_offset, tmp | CLOCK_STROBE, par);
return;
}
/*
* IBM RGB514 DAC and Clock Chip
*/
static void aty_st_514(int offset, u8 val, const struct atyfb_par *par)
{
aty_st_8(DAC_CNTL, 1, par);
/* right addr byte */
aty_st_8(DAC_W_INDEX, offset & 0xff, par);
/* left addr byte */
aty_st_8(DAC_DATA, (offset >> 8) & 0xff, par);
aty_st_8(DAC_MASK, val, par);
aty_st_8(DAC_CNTL, 0, par);
}
static int aty_set_dac_514(const struct fb_info *info,
const union aty_pll *pll, u32 bpp, u32 accel)
{
struct atyfb_par *par = (struct atyfb_par *) info->par;
static struct {
u8 pixel_dly;
u8 misc2_cntl;
u8 pixel_rep;
u8 pixel_cntl_index;
u8 pixel_cntl_v1;
} tab[3] = {
{
0, 0x41, 0x03, 0x71, 0x45}, /* 8 bpp */
{
0, 0x45, 0x04, 0x0c, 0x01}, /* 555 */
{
0, 0x45, 0x06, 0x0e, 0x00}, /* XRGB */
};
int i;
switch (bpp) {
case 8:
default:
i = 0;
break;
case 16:
i = 1;
break;
case 32:
i = 2;
break;
}
aty_st_514(0x90, 0x00, par); /* VRAM Mask Low */
aty_st_514(0x04, tab[i].pixel_dly, par); /* Horizontal Sync Control */
aty_st_514(0x05, 0x00, par); /* Power Management */
aty_st_514(0x02, 0x01, par); /* Misc Clock Control */
aty_st_514(0x71, tab[i].misc2_cntl, par); /* Misc Control 2 */
aty_st_514(0x0a, tab[i].pixel_rep, par); /* Pixel Format */
aty_st_514(tab[i].pixel_cntl_index, tab[i].pixel_cntl_v1, par);
/* Misc Control 2 / 16 BPP Control / 32 BPP Control */
return 0;
}
static int aty_var_to_pll_514(const struct fb_info *info, u32 vclk_per,
u32 bpp, union aty_pll *pll)
{
/*
* FIXME: use real calculations instead of using fixed values from the old
* driver
*/
static struct {
u32 limit; /* pixlock rounding limit (arbitrary) */
u8 m; /* (df<<6) | vco_div_count */
u8 n; /* ref_div_count */
} RGB514_clocks[7] = {
{
8000, (3 << 6) | 20, 9}, /* 7395 ps / 135.2273 MHz */
{
10000, (1 << 6) | 19, 3}, /* 9977 ps / 100.2273 MHz */
{
13000, (1 << 6) | 2, 3}, /* 12509 ps / 79.9432 MHz */
{
14000, (2 << 6) | 8, 7}, /* 13394 ps / 74.6591 MHz */
{
16000, (1 << 6) | 44, 6}, /* 15378 ps / 65.0284 MHz */
{
25000, (1 << 6) | 15, 5}, /* 17460 ps / 57.2727 MHz */
{
50000, (0 << 6) | 53, 7}, /* 33145 ps / 30.1705 MHz */
};
int i;
for (i = 0; i < ARRAY_SIZE(RGB514_clocks); i++)
if (vclk_per <= RGB514_clocks[i].limit) {
pll->ibm514.m = RGB514_clocks[i].m;
pll->ibm514.n = RGB514_clocks[i].n;
return 0