Rev 81 |
Go to most recent revision |
Blame |
Compare with Previous |
Last modification |
View Log
| RSS feed
/*
* IBMRGB52x.c:
*
* RAMDAC definitions for IBM's RGB52x PaletteDAC.
*
* Portion of this file is derived from XFree86's source code.
* [insert XFree86's copyright here].
*/
#include <stdio.h>
#include "libvga.h"
#include "timing.h"
#include "vgaregs.h"
#include "driver.h" /* for __svgalib_driver_report */
#include "ramdac.h"
#include "IBMRGB52x.h"
#define IBMRGB52x_STATESIZE 0x101
static int IBMRGB52x_dacspeed = 170000; /* assuming 170MHz DAC */
static int IBMRGB52x_fref = 16000; /* assuming 16MHz refclock */
static int IBMRGB52x_clk = 2; /* use clock 2 */
#ifdef INCLUDE_IBMRGB52x_DAC_TEST
/*
* s3IBMRGB_Probe() from XFree86.
*
* returns 0x01xx for 525, 0x02xx for 524/528, where xx = revision.
*/
static int IBMRGB52x_probe(void)
{
unsigned char CR43, CR55, dac[3], lut[6];
unsigned char ilow, ihigh, id, rev, id2, rev2;
int i, j;
int ret = 0;
port_out(0x43, 0x3D4);
CR43 = port_in(0x3D5);
port_out(CR43 & ~0x02, 0x3D5);
port_out(0x55, 0x3D4);
CR55 = port_in(0x3D5);
port_out(CR55 & ~0x03, 0x3D5);
/* save DAC and first LUT entries */
for (i = 0; i < 3; i++)
dac[i] = port_in(IBMRGB_PIXEL_MASK + i);
for (i = j = 0; i < 2; i++) {
port_out(i, IBMRGB_READ_ADDR);
lut[j++] = port_in(IBMRGB_RAMDAC_DATA);
lut[j++] = port_in(IBMRGB_RAMDAC_DATA);
lut[j++] = port_in(IBMRGB_RAMDAC_DATA);
}
port_out(0x55, 0x3D4);
port_out((CR55 & ~0x03) | 0x01, 0x3D5); /* set RS2 */
/* read ID and revision */
ilow = port_in(IBMRGB_INDEX_LOW);
ihigh = port_in(IBMRGB_INDEX_HIGH);
port_out(0, IBMRGB_INDEX_HIGH); /* index high */
port_out(IBMRGB_rev, IBMRGB_INDEX_LOW);
rev = port_in(IBMRGB_INDEX_DATA);
port_out(IBMRGB_id, IBMRGB_INDEX_LOW);
id = port_in(IBMRGB_INDEX_DATA);
/* known IDs:
1 = RGB525
2 = RGB524, RGB528
*/
if (id >= 1 && id <= 2) {
/* check if ID and revision are read only */
port_out(IBMRGB_rev, IBMRGB_INDEX_LOW);
port_out(~rev, IBMRGB_INDEX_DATA);
port_out(IBMRGB_id, IBMRGB_INDEX_LOW);
port_out(~id, IBMRGB_INDEX_DATA);
port_out(IBMRGB_rev, IBMRGB_INDEX_LOW);
rev2 = port_in(IBMRGB_INDEX_DATA);
port_out(IBMRGB_id, IBMRGB_INDEX_LOW);
id2 = port_in(IBMRGB_INDEX_DATA);
if (id == id2 && rev == rev2) { /* IBM RGB52x found */
ret = (id << 8) | rev;
} else {
port_out(IBMRGB_rev, IBMRGB_INDEX_LOW);
port_out(rev, IBMRGB_INDEX_DATA);
port_out(IBMRGB_id, IBMRGB_INDEX_LOW);
port_out(id, IBMRGB_INDEX_DATA);
}
}
port_out(ilow, IBMRGB_INDEX_LOW);
port_out(ihigh, IBMRGB_INDEX_HIGH);
port_out(0x55, 0x3D4);
port_out(CR55 & ~0x03, 0x3D5); /* reset RS2 */
/* restore DAC and first LUT entries */
for (i = j = 0; i < 2; i++) {
port_out(i, IBMRGB_WRITE_ADDR);
port_out(lut[j++], IBMRGB_RAMDAC_DATA);
port_out(lut[j++], IBMRGB_RAMDAC_DATA);
port_out(lut[j++], IBMRGB_RAMDAC_DATA);
}
for (i = 0; i < 3; i++)
port_out(dac[i], IBMRGB_PIXEL_MASK + i);
port_out(0x43, 0x3D4);
port_out(CR43, 0x3D5);
port_out(0x55, 0x3D4);
port_out(CR55, 0x3D5);
return ret;
}
#else
#define IBMRGB52x_probe 0
#endif
#ifdef INCLUDE_IBMRGB52x_DAC
static void IBMRGBSetClock(long freq, int clk, long dacspeed, long fref,
int *best_m_out, int *best_n_out, int *best_df_out)
{
volatile double ffreq, fdacspeed, ffref;
volatile int df, n, m, max_n, min_df;
volatile int best_m = 69, best_n = 17, best_df = 0;
volatile double diff, mindiff;
#define FREQ_MIN 16250 /* 1000 * (0+65) / 4 */
#define FREQ_MAX dacspeed
if (freq < FREQ_MIN)
ffreq = FREQ_MIN / 1000.0;
else if (freq > FREQ_MAX)
ffreq = FREQ_MAX / 1000.0;
else
ffreq = freq / 1000.0;
fdacspeed = dacspeed / 1e3;
ffref = fref / 1e3;
ffreq /= ffref;
ffreq *= 16;
mindiff = ffreq;
if (freq <= dacspeed / 4)
min_df = 0;
else if (freq <= dacspeed / 2)
min_df = 1;
else
min_df = 2;
for (df = 0; df < 4; df++) {
ffreq /= 2;
mindiff /= 2;
if (df < min_df)
continue;
/* the remaining formula is ffreq = (m+65) / n */
if (df < 3)
max_n = fref / 1000 / 2;
else
max_n = fref / 1000;
if (max_n > 31)
max_n = 31;
for (n = 2; n <= max_n; n++) {
m = (int) (ffreq * n + 0.5) - 65;
if (m < 0)
m = 0;
else if (m > 63)
m = 63;
diff = (m + 65.0) / n - ffreq;
if (diff < 0)
diff = -diff;
if (diff < mindiff) {
mindiff = diff;
best_n = n;
best_m = m;
best_df = df;
}
}
}
#ifdef DEBUG
cprintf("clk %d, setting to %f, m 0x%02x %d, n 0x%02x %d, df %d\n", clk,
((best_m + 65.0) / best_n) / (8 >> best_df) * ffref,
best_m, best_m, best_n, best_n, best_df);
#endif
*best_m_out = best_m;
*best_n_out = best_n;
*best_df_out = best_df;
}
static void IBMRGB52x_init(void)
{
unsigned char tmp, CR55;
#ifdef INCLUDE_IBMRGB52x_DAC_TEST
int idrev;
idrev = IBMRGB52x_probe();
if (__svgalib_driver_report)
cprintf("svgalib: Using IBM RGB 52%d PaletteDAC, revision %d.\n",
(idrev >> 8) == 1 ? 5 : 4,
idrev & 0xff);
#else
if (__svgalib_driver_report)
cprintf("svgalib: Using IBM RGB 52x PaletteDAC.\n");
#endif
/* set RS2 */
port_out(0x55, 0x3D4);
CR55 = port_in(0x3D5) & 0xFC;
port_out(CR55 | 0x01, 0x3D5);
tmp = port_in(IBMRGB_INDEX_CONTROL);
port_out(tmp & ~0x01, IBMRGB_INDEX_CONTROL); /* turn off auto-increment */
port_out(0, IBMRGB_INDEX_HIGH); /* reset index high */
__svgalib_outCR(0x55, CR55);
}
static int IBMRGB52x_match_programmable_clock(int desiredclock)
{
int m, n, df;
IBMRGBSetClock(desiredclock, IBMRGB52x_clk, IBMRGB52x_dacspeed,
IBMRGB52x_fref, &m, &n, &df);
return ((m + 65.0) / n) / (8 >> df) * IBMRGB52x_fref;
}
static void IBMRGB52x_initialize_clock_state(unsigned char *regs, int freq)
{
int m, n, df;
IBMRGBSetClock(freq, IBMRGB52x_clk, IBMRGB52x_dacspeed,
IBMRGB52x_fref, &m, &n, &df);
if (__svgalib_driver_report)
cprintf("clk %d, setting to %.3f, m 0x%02x %d, n 0x%02x %d, df %d\n",
IBMRGB52x_clk, ((m + 65.0) / n) / (8 >> df) * IBMRGB52x_fref / 1000,
m, m, n, n, df);
regs[IBMRGB_misc_clock] |= 0x01;
regs[IBMRGB_m0 + 2 * IBMRGB52x_clk] = (df << 6) | (m & 0x3f);
regs[IBMRGB_n0 + 2 * IBMRGB52x_clk] = n;
regs[IBMRGB_pll_ctrl2] &= 0xf0;
regs[IBMRGB_pll_ctrl2] |= IBMRGB52x_clk;
regs[IBMRGB_pll_ctrl1] &= 0xf8;
regs[IBMRGB_pll_ctrl1] |= 0x03;
}
static void IBMRGB52x_savestate(unsigned char *regs)
{
int i;
unsigned char tmp;
/* set RS2 */
port_out(0x55, 0x3D4);
tmp = port_in(0x3D5) & 0xFC;
port_out(tmp | 0x01, 0x3D5);
for (i = 0; i < 0x100; i++) {
port_out(i, IBMRGB_INDEX_LOW); /* high index is set to 0 */
regs[i] = port_in(IBMRGB_INDEX_DATA);
}
regs[0x100] = __svgalib_inCR(0x22);
__svgalib_outCR(0x55, tmp);
}
/* SL: not complete, need more work for 525. */
static void IBMRGB52x_restorestate(const unsigned char *regs)
{
int i;
unsigned char tmp;
/* set RS2 */
port_out(0x55, 0x3D4);
tmp = port_in(0x3D5) & 0xFC;
port_out(tmp | 0x01, 0x3D5);
for (i = 0; i < 0x100; i++) {
port_out(i, IBMRGB_INDEX_LOW); /* high index is set to 0 */
port_out(regs[i], IBMRGB_INDEX_DATA);
}
__svgalib_outCR(0x22, regs[0x100]);
__svgalib_outCR(0x55, tmp);
}
static int IBMRGB52x_map_clock(int bpp, int pixelclock)
{
return pixelclock;
}
static int IBMRGB52x_map_horizontal_crtc(int bpp, int pixelclock, int htiming)
{
#ifdef PIXEL_MULTIPLEXING
switch (bpp) {
case 4:
break;
case 8:
return htiming / 2;
case 16:
break;
case 24:
return htiming * 3 / 2;
case 32:
return htiming * 2;
}
#endif
return htiming;
}
static void IBMRGB52x_initializestate(unsigned char *regs, int bpp, int colormode,
int pixelclock)
{
unsigned char tmp;
regs[IBMRGB_misc_clock] = (regs[IBMRGB_misc_clock] & 0xf0) | 0x03;
regs[IBMRGB_sync] = 0;
regs[IBMRGB_hsync_pos] = 0;
regs[IBMRGB_pwr_mgmt] = 0;
regs[IBMRGB_dac_op] &= ~0x08; /* no sync on green */
regs[IBMRGB_dac_op] |= 0x02; /* fast slew */
regs[IBMRGB_pal_ctrl] = 0;
regs[IBMRGB_misc1] &= ~0x43;
regs[IBMRGB_misc1] |= 1;
#ifdef PIXEL_MULTIPLEXING
if (bpp >= 8)
regs[IBMRGB_misc2] = 0x43; /* use SID bus? 0x47 for DAC_8_BIT */
#endif
tmp = __svgalib_inCR(0x22);
if (bpp <= 8) /* and 968 */
__svgalib_outCR(0x22, tmp | 0x08);
else
__svgalib_outCR(0x22, tmp & ~0x08);
regs[IBMRGB_pix_fmt] &= ~0x07;
switch (bpp) {
case 4:
case 8:
regs[IBMRGB_pix_fmt] |= 0x03;
regs[IBMRGB_8bpp] = 0x00;
break;
case 15:
regs[IBMRGB_pix_fmt] |= 0x04;
regs[IBMRGB_16bpp] = 0x02;
break;
case 16:
regs[IBMRGB_pix_fmt] |= 0x04;
regs[IBMRGB_16bpp] = 0x00;
break;
case 24:
regs[IBMRGB_pix_fmt] |= 0x05; /* SL: guess */
regs[IBMRGB_24bpp] = 0x00;
break;
case 32:
regs[IBMRGB_pix_fmt] |= 0x06;
regs[IBMRGB_32bpp] = 0x00;
break;
}
IBMRGB52x_initialize_clock_state(regs,
IBMRGB52x_map_clock(bpp, pixelclock));
}
static void IBMRGB52x_qualify_cardspecs(CardSpecs * cardspecs, int dacspeed)
{
IBMRGB52x_dacspeed = __svgalib_setDacSpeed(dacspeed, 170000); /* 220 MHz version exist also */
cardspecs->maxPixelClock4bpp = IBMRGB52x_dacspeed;
cardspecs->maxPixelClock8bpp = IBMRGB52x_dacspeed;
#ifdef PIXEL_MULTIPLEXING
cardspecs->maxPixelClock16bpp = IBMRGB52x_dacspeed;
cardspecs->maxPixelClock24bpp = IBMRGB52x_dacspeed * 3 / 2;
cardspecs->maxPixelClock32bpp = IBMRGB52x_dacspeed / 2;
#else
cardspecs->maxPixelClock16bpp = 0;
cardspecs->maxPixelClock24bpp = 0;
cardspecs->maxPixelClock32bpp = 0;
#endif
cardspecs->mapClock = IBMRGB52x_map_clock;
cardspecs->matchProgrammableClock = IBMRGB52x_match_programmable_clock;
cardspecs->mapHorizontalCrtc = IBMRGB52x_map_horizontal_crtc;
cardspecs->flags |= CLOCK_PROGRAMMABLE;
}
DacMethods __svgalib_IBMRGB52x_methods =
{
IBMRGB52x,
"IBM RGB 52x PaletteDAC",
DAC_HAS_PROGRAMMABLE_CLOCKS,
IBMRGB52x_probe,
IBMRGB52x_init,
IBMRGB52x_qualify_cardspecs,
IBMRGB52x_savestate,
IBMRGB52x_restorestate,
IBMRGB52x_initializestate,
IBMRGB52x_STATESIZE
};
#endif