xserver-multidpi/hw/kdrive/pcmcia/pcmcia.c
2003-09-11 05:12:51 +00:00

1201 lines
30 KiB
C

/*
* Copyright 2001 by Alan Hourihane, Sychdyn, North Wales, UK.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of Alan Hourihane not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Alan Hourihane makes no representations
* about the suitability of this software for any purpose. It is provided
* "as is" without express or implied warranty.
*
* ALAN HOURIHANE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL ALAN HOURIHANE BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*
* Authors: Alan Hourihane, <alanh@fairlite.demon.co.uk>
*
* A driver for the following PCMCIA cards...
* Hewlett Packards HP VGA Out (Model F1252A)
* Colorgraphics Voyager VGA
*
* Tested running under a Compaq IPAQ Pocket PC running Linux
*/
/* $RCSId: xc/programs/Xserver/hw/kdrive/pcmcia/pcmcia.c,v 1.6 2002/10/14 18:01:41 keithp Exp $ */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "pcmcia.h"
#define extern
#include <asm/io.h>
#undef extern
#define CLOCK 14318 /* KHz */
#define CLK_N(a,b) (a & 0xff)
#define CLK_M(a,b) ((b) & 0x3f)
#define CLK_K(a,b) (((b) >> 6) & 3)
#define CLK_FREQ(a,b) (((CLK_N(a,b) + 8) * CLOCK) / ((CLK_M(a,b)+2) << CLK_K(a,b)))
extern void
tridentUpdatePacked (ScreenPtr pScreen,
shadowBufPtr pBuf);
extern void
cirrusUpdatePacked (ScreenPtr pScreen,
shadowBufPtr pBuf);
static Bool
tridentSetCLK(int clock, CARD8 *a, CARD8 *b);
static Bool
CirrusFindClock(int freq, int *num_out, int *den_out);
Bool
pcmciaCardInit (KdCardInfo *card)
{
pcmciaCardInfo *pcmciac;
CARD8 r9;
pcmciac = (pcmciaCardInfo *) xalloc (sizeof (pcmciaCardInfo));
if (!pcmciac)
return FALSE;
pcmciac->cop_base = (CARD8 *) KdMapDevice (PCMCIA_COP_BASE(card),
PCMCIA_COP_SIZE(card));
r9 = pcmciaReadIndex (pcmciac, 0x3c4, 0x09);
/*
* Crude detection....
* The trident chip has a read only register at 0x09, which returns 0x4.
* If it's not that, we assume the cirrus chip.
* BREAKAGE.! If we have an anonymous PCMCIA card inserted, we could
* potentially smash something here. FIXME !
*/
if (r9 == 0x04) {
ErrorF("PCMCIA: Found HP VGA card\n");
pcmciac->HP = TRUE; /* Select HP VGA Out Card */
} else {
ErrorF("PCMCIA: Found Voyager VGA card\n");
pcmciac->HP = FALSE; /* Select Voyager VGA Card */
}
if (pcmciac->HP) {
/* needed by the accelerator - later */
pcmciac->cop = (Cop *) (pcmciac->cop_base + TRIDENT_COP_OFF(card));
}
/*
* Map frame buffer
*/
if (pcmciac->HP)
pcmciac->fb = KdMapDevice (0x2ce00000, 0x80000);
else
pcmciac->fb = KdMapDevice (0x2c0a0000, 0x10000); /*64K bank switched*/
if (!pcmciac->fb)
return FALSE;
pcmciac->window = 0;
card->driver = pcmciac;
return TRUE;
}
Bool
pcmciaModeSupported (KdScreenInfo *screen,
const KdMonitorTiming *t)
{
KdCardInfo *card = screen->card;
pcmciaCardInfo *pcmciac = (pcmciaCardInfo *) card->driver;
if (pcmciac->HP)
{
CARD8 a, b;
if (!tridentSetCLK (t->clock, &a, &b))
return FALSE;
}
else
{
int a, b;
if (!CirrusFindClock (t->clock, &a, &b))
return FALSE;
}
/* width must be a multiple of 16 */
if (t->horizontal & 0xf)
return FALSE;
return TRUE;
}
Bool
pcmciaModeUsable (KdScreenInfo *screen)
{
KdCardInfo *card = screen->card;
pcmciaCardInfo *pcmciac = (pcmciaCardInfo *) card->driver;
int screen_size;
int pixel_width;
int byte_width;
int fb;
if (screen->fb[0].depth == 8)
screen->fb[0].bitsPerPixel = 8;
else if (screen->fb[0].depth == 15 || screen->fb[0].depth == 16)
screen->fb[0].bitsPerPixel = 16;
else
return FALSE;
screen_size = 0;
screen->fb[0].pixelStride = screen->width;
screen->fb[0].byteStride = screen->width * (screen->fb[0].bitsPerPixel >>3);
screen->fb[0].frameBuffer = pcmciac->fb;
screen_size = screen->fb[0].byteStride * screen->height;
return screen_size <= pcmciac->memory;
}
Bool
pcmciaScreenInit (KdScreenInfo *screen)
{
pcmciaCardInfo *pcmciac = screen->card->driver;
pcmciaScreenInfo *pcmcias;
int screen_size, memory;
int i;
const KdMonitorTiming *t;
pcmcias = (pcmciaScreenInfo *) xalloc (sizeof (pcmciaScreenInfo));
if (!pcmcias)
return FALSE;
memset (pcmcias, '\0', sizeof (pcmciaScreenInfo));
/* if (!pcmciac->cop) */
screen->dumb = TRUE;
if (screen->fb[0].depth < 8)
screen->fb[0].depth = 8;
/* default to 16bpp */
if (!screen->fb[0].depth)
screen->fb[0].depth = 16;
/* default to 60Hz refresh */
if (!screen->width || !screen->height)
{
screen->width = 640;
screen->height = 400;
screen->rate = 60;
}
pcmciac->memory = 512 * 1024;
if (pcmciac->HP && !screen->softCursor && screen->fb[0].depth == 8)
{
/* ack, bail on the HW cursor for everything -- no ARGB falback */
pcmcias->cursor_base = 0;
#if 0
/* Let's do hw cursor for the HP card, only in 8bit mode though */
pcmcias->cursor_base = pcmcias->screen + pcmciac->memory - 4096;
pcmciac->memory -= 4096;
#endif
}
pcmcias->screen = pcmciac->fb;
screen->driver = pcmcias;
t = KdFindMode (screen, pcmciaModeSupported);
screen->rate = t->rate;
screen->width = t->horizontal;
screen->height = t->vertical;
pcmcias->randr = screen->randr;
if (!KdTuneMode (screen, pcmciaModeUsable, pcmciaModeSupported))
{
xfree (pcmcias);
return FALSE;
}
switch (screen->fb[0].depth) {
case 4:
screen->fb[0].visuals = ((1 << StaticGray) |
(1 << GrayScale) |
(1 << StaticColor));
screen->fb[0].blueMask = 0x00;
screen->fb[0].greenMask = 0x00;
screen->fb[0].redMask = 0x00;
break;
case 8:
screen->fb[0].visuals = ((1 << StaticGray) |
(1 << GrayScale) |
(1 << StaticColor) |
(1 << PseudoColor) |
(1 << TrueColor) |
(1 << DirectColor));
screen->fb[0].blueMask = 0x00;
screen->fb[0].greenMask = 0x00;
screen->fb[0].redMask = 0x00;
break;
case 15:
screen->fb[0].visuals = (1 << TrueColor);
screen->fb[0].blueMask = 0x001f;
screen->fb[0].greenMask = 0x03e0;
screen->fb[0].redMask = 0x7c00;
break;
case 16:
screen->fb[0].visuals = (1 << TrueColor);
screen->fb[0].blueMask = 0x001f;
screen->fb[0].greenMask = 0x07e0;
screen->fb[0].redMask = 0xf800;
break;
}
return TRUE;
}
void *
tridentWindowLinear (ScreenPtr pScreen,
CARD32 row,
CARD32 offset,
int mode,
CARD32 *size,
void *closure)
{
KdScreenPriv(pScreen);
pcmciaCardInfo *pcmciac = pScreenPriv->card->driver;
if (!pScreenPriv->enabled)
return 0;
*size = pScreenPriv->screen->fb[0].byteStride;
return (CARD8 *) pcmciac->fb + row * pScreenPriv->screen->fb[0].byteStride + offset;
}
void *
cirrusWindowWindowed (ScreenPtr pScreen,
CARD32 row,
CARD32 offset,
int mode,
CARD32 *size,
void *closure)
{
KdScreenPriv(pScreen);
pcmciaCardInfo *pcmciac = pScreenPriv->card->driver;
int bank, boffset;
if (!pScreenPriv->enabled)
return 0;
bank = (row * pScreenPriv->screen->fb[0].byteStride) / 0x1000;
pcmciaWriteIndex(pcmciac, 0x3ce, 0x0B, 0x0c);
pcmciaWriteIndex(pcmciac, 0x3ce, 0x09, bank);
pcmciaWriteIndex(pcmciac, 0x3ce, 0x0A, bank);
*size = pScreenPriv->screen->fb[0].byteStride;
return (CARD8 *) pcmciac->fb + (row * pScreenPriv->screen->fb[0].byteStride) - (bank * 0x1000) + offset;
}
LayerPtr
pcmciaLayerCreate (ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
KdScreenInfo *screen = pScreenPriv->screen;
pcmciaCardInfo *pcmciac = pScreenPriv->card->driver;
pcmciaScreenInfo *pcmcias = (pcmciaScreenInfo *) pScreenPriv->screen->driver;
ShadowUpdateProc update;
ShadowWindowProc window;
PixmapPtr pPixmap;
int kind;
if (pcmciac->HP) {
window = tridentWindowLinear;
if (pcmcias->randr == RR_Rotate_0)
update = tridentUpdatePacked;
else
update = pcmciaUpdateRotatePacked;
} else {
window = cirrusWindowWindowed;
if (pcmcias->randr == RR_Rotate_0)
update = cirrusUpdatePacked;
else
update = pcmciaUpdateRotatePacked;
}
if (!update)
abort ();
kind = LAYER_SHADOW;
pPixmap = 0;
return LayerCreate (pScreen, kind, screen->fb[0].depth,
pPixmap, update, window, pcmcias->randr, 0);
}
void
pcmciaConfigureScreen (ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
KdScreenInfo *screen = pScreenPriv->screen;
FbdevPriv *priv = pScreenPriv->card->driver;
pcmciaScreenInfo *pcmcias = (pcmciaScreenInfo *) screen->driver;
KdMouseMatrix m;
KdComputeMouseMatrix (&m, pcmcias->randr,
screen->width, screen->height);
if (m.matrix[0][0])
{
pScreen->width = screen->width;
pScreen->height = screen->height;
pScreen->mmWidth = screen->width_mm;
pScreen->mmHeight = screen->height_mm;
}
else
{
pScreen->width = screen->height;
pScreen->height = screen->width;
pScreen->mmWidth = screen->height_mm;
pScreen->mmHeight = screen->width_mm;
}
KdSetMouseMatrix (&m);
}
#ifdef RANDR
Bool
pcmciaRandRSupported (ScreenPtr pScreen,
const KdMonitorTiming *t)
{
KdScreenPriv(pScreen);
pcmciaCardInfo *pcmciac = pScreenPriv->card->driver;
KdScreenInfo *screen = pScreenPriv->screen;
int screen_size;
int byteStride;
/* Make sure the clock is supported */
if (!pcmciaModeSupported (screen, t))
return FALSE;
/* Check for sufficient memory */
byteStride = screen->width * (screen->fb[0].bitsPerPixel >>3);
screen_size = byteStride * screen->height;
return screen_size <= pcmciac->memory;
}
Bool
pcmciaRandRGetInfo (ScreenPtr pScreen, Rotation *rotations)
{
KdScreenPriv(pScreen);
pcmciaScreenInfo *pcmcias = (pcmciaScreenInfo *) pScreenPriv->screen->driver;
*rotations = (RR_Rotate_0|RR_Rotate_90|RR_Rotate_180|RR_Rotate_270|
RR_Reflect_X|RR_Reflect_Y);
return KdRandRGetInfo (pScreen, pcmcias->randr, pcmciaRandRSupported);
}
int
pcmciaLayerAdd (WindowPtr pWin, pointer value)
{
ScreenPtr pScreen = pWin->drawable.pScreen;
LayerPtr pLayer = (LayerPtr) value;
if (!LayerWindowAdd (pScreen, pLayer, pWin))
return WT_STOPWALKING;
return WT_WALKCHILDREN;
}
int
pcmciaLayerRemove (WindowPtr pWin, pointer value)
{
ScreenPtr pScreen = pWin->drawable.pScreen;
LayerPtr pLayer = (LayerPtr) value;
LayerWindowRemove (pScreen, pLayer, pWin);
return WT_WALKCHILDREN;
}
pcmciaRandRSetConfig (ScreenPtr pScreen,
Rotation randr,
int rate,
RRScreenSizePtr pSize)
{
KdScreenPriv(pScreen);
KdScreenInfo *screen = pScreenPriv->screen;
FbdevPriv *priv = pScreenPriv->card->driver;
pcmciaScreenInfo *pcmcias = (pcmciaScreenInfo *) pScreenPriv->screen->driver;
Bool wasEnabled = pScreenPriv->enabled;
int newwidth, newheight;
LayerPtr pNewLayer;
int kind;
int oldrandr = pcmcias->randr;
PixmapPtr pPixmap;
const KdMonitorTiming *t;
randr = KdAddRotation (screen->randr, randr);
t = KdRandRGetTiming (pScreen, pcmciaRandRSupported, rate, pSize);
if (wasEnabled)
KdDisableScreen (pScreen);
screen->rate = t->rate;
screen->width = t->horizontal;
screen->height = t->vertical;
pcmcias->randr = randr;
pcmciaConfigureScreen (pScreen);
pNewLayer = pcmciaLayerCreate (pScreen);
if (!pNewLayer)
{
pcmcias->randr = oldrandr;
pcmciaConfigureScreen (pScreen);
if (wasEnabled)
KdEnableScreen (pScreen);
return FALSE;
}
if (WalkTree (pScreen, pcmciaLayerAdd, (pointer) pNewLayer) == WT_STOPWALKING)
{
WalkTree (pScreen, pcmciaLayerRemove, (pointer) pNewLayer);
LayerDestroy (pScreen, pNewLayer);
pcmcias->randr = oldrandr;
pcmciaConfigureScreen (pScreen);
if (wasEnabled)
KdEnableScreen (pScreen);
return FALSE;
}
WalkTree (pScreen, pcmciaLayerRemove, (pointer) pcmcias->pLayer);
LayerDestroy (pScreen, pcmcias->pLayer);
pcmcias->pLayer = pNewLayer;
if (wasEnabled)
KdEnableScreen (pScreen);
return TRUE;
}
Bool
pcmciaRandRInit (ScreenPtr pScreen)
{
rrScrPrivPtr pScrPriv;
if (!RRScreenInit (pScreen))
return FALSE;
pScrPriv = rrGetScrPriv(pScreen);
pScrPriv->rrGetInfo = pcmciaRandRGetInfo;
pScrPriv->rrSetConfig = pcmciaRandRSetConfig;
return TRUE;
}
#endif
Bool
pcmciaInitScreen (ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
FbdevPriv *priv = pScreenPriv->card->driver;
pcmciaScreenInfo *pcmcias = (pcmciaScreenInfo *) pScreenPriv->screen->driver;
if (!LayerStartInit (pScreen))
return FALSE;
if (!LayerFinishInit (pScreen))
return FALSE;
pcmciaConfigureScreen (pScreen);
pcmcias->pLayer = pcmciaLayerCreate (pScreen);
if (!pcmcias->pLayer)
return FALSE;
#ifdef RANDR
if (!pcmciaRandRInit (pScreen))
return FALSE;
#endif
return TRUE;
}
CARD8
pcmciaReadIndex (pcmciaCardInfo *pcmciac, CARD16 port, CARD8 index)
{
CARD8 value;
pcmciac->cop_base[port] = index;
value = pcmciac->cop_base[port+1];
return value;
}
void
pcmciaWriteIndex (pcmciaCardInfo *pcmciac, CARD16 port, CARD8 index, CARD8 value)
{
pcmciac->cop_base[port] = index;
pcmciac->cop_base[port+1] = value;
}
CARD8
pcmciaReadReg (pcmciaCardInfo *pcmciac, CARD16 port)
{
CARD8 value;
value = pcmciac->cop_base[port];
return value;
}
void
pcmciaWriteReg (pcmciaCardInfo *pcmciac, CARD16 port, CARD8 value)
{
pcmciac->cop_base[port] = value;
}
void
pcmciaPause ()
{
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 50 * 1000;
select (1, 0, 0, 0, &tv);
}
void
pcmciaPreserve (KdCardInfo *card)
{
}
/* CLOCK_FACTOR is double the osc freq in kHz (osc = 14.31818 MHz) */
#define CLOCK_FACTOR 28636
/* stability constraints for internal VCO -- MAX_VCO also determines the maximum Video pixel clock */
#define MIN_VCO CLOCK_FACTOR
#define MAX_VCO 111000
/* clock in kHz is (numer * CLOCK_FACTOR / (denom & 0x3E)) >> (denom & 1) */
#define VCOVAL(n, d) \
((((n) & 0x7F) * CLOCK_FACTOR / ((d) & 0x3E)) )
#define CLOCKVAL(n, d) \
(VCOVAL(n, d) >> ((d) & 1))
static Bool
CirrusFindClock(int freq, int *num_out, int *den_out)
{
int n;
int num = 0, den = 0;
int mindiff;
/*
* If max_clock is greater than the MAX_VCO default, ignore
* MAX_VCO. On the other hand, if MAX_VCO is higher than max_clock,
* make use of the higher MAX_VCO value.
*/
mindiff = freq;
for (n = 0x10; n < 0x7f; n++) {
int d;
for (d = 0x14; d < 0x3f; d++) {
int c, diff;
/* Avoid combinations that can be unstable. */
if ((VCOVAL(n, d) < MIN_VCO) || (VCOVAL(n, d) > MAX_VCO))
continue;
c = CLOCKVAL(n, d);
diff = abs(c - freq);
if (diff < mindiff) {
mindiff = diff;
num = n;
den = d;
}
}
}
if (n == 0x80)
return FALSE;
*num_out = num;
*den_out = den;
return TRUE;
}
static Bool
tridentSetCLK(int clock, CARD8 *a, CARD8 *b)
{
int powerup[4] = { 1,2,4,8 };
int clock_diff = 750;
int freq, ffreq;
int m, n, k;
int p, q, r, s;
int startn, endn;
int endm, endk;
p = q = r = s = 0;
startn = 0;
endn = 121;
endm = 31;
endk = 1;
freq = clock;
for (k=0;k<=endk;k++)
for (n=startn;n<=endn;n++)
for (m=1;m<=endm;m++)
{
ffreq = ( ( ((n + 8) * CLOCK) / ((m + 2) * powerup[k]) ));
if ((ffreq > freq - clock_diff) && (ffreq < freq + clock_diff))
{
clock_diff = (freq > ffreq) ? freq - ffreq : ffreq - freq;
p = n; q = m; r = k; s = ffreq;
}
}
#if 0
ErrorF ("ffreq %d clock %d\n", s, clock);
#endif
if (s == 0)
return FALSE;
/* N is first 7bits, first M bit is 8th bit */
*a = ((1 & q) << 7) | p;
/* first 4bits are rest of M, 1bit for K value */
*b = (((q & 0xFE) >> 1) | (r << 4));
return TRUE;
}
Bool
pcmciaEnable (ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
KdScreenInfo *screen = pScreenPriv->screen;
pcmciaCardInfo *pcmciac = pScreenPriv->card->driver;
pcmciaScreenInfo *pcmcias = (pcmciaScreenInfo *) screen->driver;
int i,j;
unsigned char Sequencer[6];
unsigned char CRTC[31];
unsigned char Graphics[9];
unsigned char Attribute[21];
unsigned char MiscOutReg;
const KdMonitorTiming *t;
int hactive, hblank, hfp, hbp;
int vactive, vblank, vfp, vbp;
int h_active;
int h_total;
int h_display_end;
int h_sync_start;
int h_sync_end;
int h_skew = 0;
int v_active;
int v_total;
int v_sync_start;
int v_sync_end;
int v_skew = 0;
t = KdFindMode (screen, pcmciaModeSupported);
hactive = t->horizontal;
hfp = t->hfp;
hbp = t->hbp;
hblank = t->hblank;
h_active = hactive;
h_sync_start = hactive + hfp;
h_sync_end = hactive + hblank - hbp;
h_total = hactive + hblank;
vactive = t->vertical;
vfp = t->vfp;
vbp = t->vbp;
vblank = t->vblank;
v_active = vactive;
v_sync_start = vactive + vfp;
v_sync_end = vactive + vblank - vbp;
v_total = vactive + vblank;
/*
* compute correct Hsync & Vsync polarity
*/
MiscOutReg = 0x23;
if (t->hpol == KdSyncNegative)
MiscOutReg |= 0x40;
if (t->vpol == KdSyncNegative)
MiscOutReg |= 0x80;
/*
* Time Sequencer
*/
if (pScreenPriv->screen->fb[0].depth == 4)
Sequencer[0] = 0x02;
else
Sequencer[0] = 0x00;
Sequencer[1] = 0x01;
Sequencer[2] = 0x0F;
Sequencer[3] = 0x00; /* Font select */
if (pScreenPriv->screen->fb[0].depth < 8)
Sequencer[4] = 0x06; /* Misc */
else
Sequencer[4] = 0x0E; /* Misc */
Sequencer[5] = 0x00;
/*
* CRTC Controller
*/
CRTC[0] = ((h_total) >> 3) - 5;
CRTC[1] = (hactive >> 3) - 1;
CRTC[2] = ((min(h_sync_start,h_active)) >> 3) - 1;
CRTC[3] = ((((min(h_sync_end,h_total)) >> 3) - 1) & 0x1F) | 0x80;
i = (((h_skew << 2) + 0x10) & ~0x1F);
if (i < 0x80)
CRTC[3] |= i;
CRTC[4] = (h_sync_start >> 3);
CRTC[5] = (((((min(h_sync_end,h_total)) >> 3) - 1) & 0x20) << 2)
| (((h_sync_end >> 3)) & 0x1F);
CRTC[6] = (v_total - 2) & 0xFF;
CRTC[7] = (((v_total - 2) & 0x100) >> 8)
| (((v_active - 1) & 0x100) >> 7)
| ((v_sync_start & 0x100) >> 6)
| ((((min(v_sync_start,v_active)) - 1) & 0x100) >> 5)
| 0x10
| (((v_total - 2) & 0x200) >> 4)
| (((v_active - 1) & 0x200) >> 3)
| ((v_sync_start & 0x200) >> 2);
CRTC[8] = 0x00;
CRTC[9] = ((((min(v_sync_start,v_active))-1) & 0x200) >> 4) | 0x40;
CRTC[10] = 0x00;
CRTC[11] = 0x00;
CRTC[12] = 0x00;
CRTC[13] = 0x00;
CRTC[14] = 0x00;
CRTC[15] = 0x00;
CRTC[16] = v_sync_start & 0xFF;
CRTC[17] = (v_sync_end & 0x0F) | 0x20;
CRTC[18] = (v_active - 1) & 0xFF;
if (pScreenPriv->screen->fb[0].depth == 4)
CRTC[19] = pScreenPriv->screen->fb[0].pixelStride >> 4;
else
if (pScreenPriv->screen->fb[0].depth == 8)
CRTC[19] = pScreenPriv->screen->fb[0].pixelStride >> 3;
else
if (pScreenPriv->screen->fb[0].depth == 16 ||
pScreenPriv->screen->fb[0].depth == 15)
CRTC[19] = pScreenPriv->screen->fb[0].pixelStride >> 2;
CRTC[20] = 0x00;
CRTC[21] = ((min(v_sync_end,v_active)) - 1) & 0xFF;
CRTC[22] = ((min(v_sync_end,v_active)) - 1) & 0xFF;
if (pScreenPriv->screen->fb[0].depth < 8)
CRTC[23] = 0xE3;
else
CRTC[23] = 0xC3;
CRTC[24] = 0xFF;
CRTC[25] = 0x00;
CRTC[26] = 0x00;
#if 0
if (!pcmciac->HP)
if (mode.Flags & V_INTERLACE) CRTC[26] |= 0x01;
#endif
if (pcmciac->HP)
CRTC[27] = 0x00;
else
CRTC[27] = 0x22;
CRTC[28] = 0x00;
CRTC[29] = 0x00;
CRTC[30] = 0x80;
#if 0
if (pcmciac->HP)
if (mode.Flags & V_INTERLACE) CRTC[30] |= 0x04;
#endif
{
int nExtBits = 0;
CARD32 ExtBits;
CARD32 ExtBitMask = ((1 << nExtBits) - 1) << 6;
CRTC[3] = (CRTC[3] & ~0x1F)
| ((((min(h_sync_end,h_total)) >> 3) - 1) & 0x1F);
CRTC[5] = (CRTC[5] & ~0x80)
| (((((min(h_sync_end,h_total)) >> 3) - 1) & 0x20) << 2);
ExtBits = (((min(h_sync_end,h_total)) >> 3) - 1) & ExtBitMask;
/* First the horizontal case */
if ((((min(h_sync_end,h_total)) >> 3) == (h_total >> 3)))
{
int i = (CRTC[3] & 0x1F)
| ((CRTC[5] & 0x80) >> 2)
| ExtBits;
if ((i-- > ((((min(h_sync_start,h_active)) >> 3) - 1)
& (0x3F | ExtBitMask)))
&& ((min(h_sync_end,h_total)) == h_total))
i = 0;
CRTC[3] = (CRTC[3] & ~0x1F) | (i & 0x1F);
CRTC[5] = (CRTC[5] & ~0x80) | ((i << 2) & 0x80);
ExtBits = i & ExtBitMask;
}
}
{
CARD32 ExtBits;
CARD32 ExtBitMask = 0;
/* If width is not known nBits should be 0. In this
* case BitMask is set to 0 so we can check for it. */
CARD32 BitMask = 0;
int VBlankStart = ((min(v_sync_start,v_active)) - 1) & 0xFF;
CRTC[22] = ((min(v_sync_end,v_total)) - 1) & 0xFF;
ExtBits = ((min(v_sync_end,v_total)) - 1) & ExtBitMask;
if ((min(v_sync_end,v_total)) == v_total)
/* Null top overscan */
{
int i = CRTC[22] | ExtBits;
if (((BitMask && ((i & BitMask) > (VBlankStart & BitMask)))
|| ((i > VBlankStart) && /* 8-bit case */
((i & 0x7F) > (VBlankStart & 0x7F)))) && /* 7-bit case */
!(CRTC[9] & 0x9F)) /* 1 scanline/row */
i = 0;
else
i = (i - 1);
CRTC[22] = i & 0xFF;
ExtBits = i & 0xFF00;
}
}
/*
* Graphics Display Controller
*/
Graphics[0] = 0x00;
Graphics[1] = 0x00;
Graphics[2] = 0x00;
Graphics[3] = 0x00;
Graphics[4] = 0x00;
if (pScreenPriv->screen->fb[0].depth == 4)
Graphics[5] = 0x02;
else
Graphics[5] = 0x40;
Graphics[6] = 0x05; /* only map 64k VGA memory !!!! */
Graphics[7] = 0x0F;
Graphics[8] = 0xFF;
Attribute[0] = 0x00; /* standard colormap translation */
Attribute[1] = 0x01;
Attribute[2] = 0x02;
Attribute[3] = 0x03;
Attribute[4] = 0x04;
Attribute[5] = 0x05;
Attribute[6] = 0x06;
Attribute[7] = 0x07;
Attribute[8] = 0x08;
Attribute[9] = 0x09;
Attribute[10] = 0x0A;
Attribute[11] = 0x0B;
Attribute[12] = 0x0C;
Attribute[13] = 0x0D;
Attribute[14] = 0x0E;
Attribute[15] = 0x0F;
if (pScreenPriv->screen->fb[0].depth == 4)
Attribute[16] = 0x81;
else
Attribute[16] = 0x41;
if (pScreenPriv->screen->fb[0].bitsPerPixel == 16)
Attribute[17] = 0x00;
else
Attribute[17] = 0xFF;
Attribute[18] = 0x0F;
Attribute[19] = 0x00;
Attribute[20] = 0x00;
/* Wake up the card */
if (pcmciac->HP) {
pcmciaWriteReg(pcmciac, 0x3c3, 0x1);
pcmciaWriteReg(pcmciac, 0x46e8, 0x10);
} else {
pcmciaWriteReg(pcmciac, 0x105, 0x1);
pcmciaWriteReg(pcmciac, 0x46e8, 0x1f);
pcmciaWriteReg(pcmciac, 0x102, 0x1);
pcmciaWriteReg(pcmciac, 0x46e8, 0xf);
pcmciaWriteReg(pcmciac, 0x3c3, 0x1);
}
if (pcmciac->HP) {
/* unlock */
pcmciaWriteIndex(pcmciac, 0x3c4, 0x11, 0x92);
j = pcmciaReadIndex(pcmciac, 0x3c4, 0xb);
pcmciaWriteIndex(pcmciac, 0x3c4, 0xe, 0xc2);
/* switch on dac */
pcmciaWriteIndex(pcmciac, 0x3d4, 0x29, 0x24);
/* switch on the accelerator */
pcmciaWriteIndex(pcmciac, 0x3d4, 0x36, 0x80);
/* bump up memory clk */
pcmciaWriteReg(pcmciac, 0x43c6, 0x65);
pcmciaWriteReg(pcmciac, 0x43c7, 0x00);
} else {
/* unlock */
pcmciaWriteIndex(pcmciac, 0x3c4, 0x06, 0x12);
pcmciaWriteReg(pcmciac, 0x3c2, MiscOutReg);
}
/* synchronous reset */
pcmciaWriteIndex(pcmciac, 0x3c4, 0, 0);
pcmciaWriteReg(pcmciac, 0x3da, 0x10);
for (i=0;i<6;i++)
pcmciaWriteIndex(pcmciac, 0x3c4, i, Sequencer[i]);
if (pcmciac->HP) {
/* Stick chip into color mode */
pcmciaWriteIndex(pcmciac, 0x3ce, 0x2f, 0x06);
/* Switch on Linear addressing */
pcmciaWriteIndex(pcmciac, 0x3d4, 0x21, 0x2e);
} else {
/* Stick chip into 8bit access mode - ugh! */
pcmciaWriteIndex(pcmciac, 0x3c4, 0x0F, 0x20); /* 0x26 ? */
/* reset mclk */
pcmciaWriteIndex(pcmciac, 0x3c4, 0x1F, 0);
}
pcmciaWriteIndex(pcmciac, 0x3c4, 0, 0x3);
for (i=0;i<31;i++)
pcmciaWriteIndex(pcmciac, 0x3d4, i, CRTC[i]);
for (i=0;i<9;i++)
pcmciaWriteIndex(pcmciac, 0x3ce, i, Graphics[i]);
j = pcmciaReadReg(pcmciac, 0x3da);
for (i=0;i<21;i++) {
pcmciaWriteReg(pcmciac, 0x3c0, i);
pcmciaWriteReg(pcmciac, 0x3c0, Attribute[i]);
}
j = pcmciaReadReg(pcmciac, 0x3da);
pcmciaWriteReg(pcmciac, 0x3c0, 0x20);
j = pcmciaReadReg(pcmciac, 0x3c8);
j = pcmciaReadReg(pcmciac, 0x3c6);
j = pcmciaReadReg(pcmciac, 0x3c6);
j = pcmciaReadReg(pcmciac, 0x3c6);
j = pcmciaReadReg(pcmciac, 0x3c6);
switch (pScreenPriv->screen->fb[0].depth) {
/* This is here for completeness, when/if we ever do 4bpp */
case 4:
pcmciaWriteReg(pcmciac, 0x3c6, 0x0);
if (pcmciac->HP) {
pcmciaWriteIndex(pcmciac, 0x3ce, 0x0f, 0x90);
pcmciaWriteIndex(pcmciac, 0x3d4, 0x38, 0x00);
} else
pcmciaWriteIndex(pcmciac, 0x3c4, 0x07, 0x00);
break;
case 8:
pcmciaWriteReg(pcmciac, 0x3c6, 0x0);
if (pcmciac->HP) {
pcmciaWriteIndex(pcmciac, 0x3ce, 0x0f, 0x92);
pcmciaWriteIndex(pcmciac, 0x3d4, 0x38, 0x00);
} else
pcmciaWriteIndex(pcmciac, 0x3c4, 0x07, 0x01);
break;
case 15:
if (pcmciac->HP) {
pcmciaWriteReg(pcmciac, 0x3c6, 0x10);
pcmciaWriteIndex(pcmciac, 0x3ce, 0x0f, 0x9a);
pcmciaWriteIndex(pcmciac, 0x3d4, 0x38, 0x04);
} else {
pcmciaWriteReg(pcmciac, 0x3c6, 0xC0);
pcmciaWriteIndex(pcmciac, 0x3c4, 0x07, 0x03);
}
break;
case 16:
if (pcmciac->HP) {
pcmciaWriteReg(pcmciac, 0x3c6, 0x30);
pcmciaWriteIndex(pcmciac, 0x3ce, 0x0f, 0x9a);
pcmciaWriteIndex(pcmciac, 0x3d4, 0x38, 0x04);
} else {
pcmciaWriteReg(pcmciac, 0x3c6, 0xC1);
pcmciaWriteIndex(pcmciac, 0x3c4, 0x07, 0x03);
}
break;
}
j = pcmciaReadReg(pcmciac, 0x3c8);
pcmciaWriteReg(pcmciac, 0x3c6, 0xff);
for (i=0;i<256;i++) {
pcmciaWriteReg(pcmciac, 0x3c8, i);
pcmciaWriteReg(pcmciac, 0x3c9, i);
pcmciaWriteReg(pcmciac, 0x3c9, i);
pcmciaWriteReg(pcmciac, 0x3c9, i);
}
/* Set the Clock */
if (pcmciac->HP) {
CARD8 a,b;
int clock = t->clock;
if (pScreenPriv->screen->fb[0].bitsPerPixel == 16)
clock *= 2;
tridentSetCLK(clock, &a, &b);
pcmciaWriteReg(pcmciac, 0x43c8, a);
pcmciaWriteReg(pcmciac, 0x43c9, b);
} else {
int num, den;
unsigned char tmp;
int clock = t->clock;
if (pScreenPriv->screen->fb[0].bitsPerPixel == 16)
clock *= 2;
CirrusFindClock(clock, &num, &den);
tmp = pcmciaReadIndex(pcmciac, 0x3c4, 0x0d);
pcmciaWriteIndex(pcmciac, 0x3c4, 0x0d, (tmp & 0x80) | num);
tmp = pcmciaReadIndex(pcmciac, 0x3c4, 0x1d);
pcmciaWriteIndex(pcmciac, 0x3c4, 0x1d, (tmp & 0xc0) | den);
}
pcmciaWriteReg(pcmciac, 0x3c2, MiscOutReg | 0x08);
#if 1
for (i=1;i<0x3f;i++)
ErrorF("0x3c4:%02x: 0x%x\n",i,pcmciaReadIndex(pcmciac, 0x3c4, i));
ErrorF("\n");
for (i=0;i<0x3f;i++)
ErrorF("0x3ce:%02x: 0x%x\n",i,pcmciaReadIndex(pcmciac, 0x3ce, i));
ErrorF("\n");
for (i=0;i<0x3f;i++)
ErrorF("0x3d4:%02x: 0x%x\n",i,pcmciaReadIndex(pcmciac, 0x3d4, i));
#endif
return TRUE;
}
void
pcmciaDisable (ScreenPtr pScreen)
{
}
const CARD8 tridentDPMSModes[4] = {
0x00, /* KD_DPMS_NORMAL */
0x01, /* KD_DPMS_STANDBY */
0x02, /* KD_DPMS_SUSPEND */
0x03, /* KD_DPMS_POWERDOWN */
};
Bool
pcmciaDPMS (ScreenPtr pScreen, int mode)
{
KdScreenPriv(pScreen);
pcmciaCardInfo *pcmciac = pScreenPriv->card->driver;
if (pcmciac->HP) {
pcmciaWriteIndex (pcmciac, 0x3ce, 0x23, tridentDPMSModes[mode]);
pcmciaPause ();
} else {
/* Voyager */
}
return TRUE;
}
void
pcmciaRestore (KdCardInfo *card)
{
}
void
pcmciaScreenFini (KdScreenInfo *screen)
{
pcmciaScreenInfo *pcmcias = (pcmciaScreenInfo *) screen->driver;
xfree (pcmcias);
screen->driver = 0;
}
void
pcmciaCardFini (KdCardInfo *card)
{
pcmciaCardInfo *pcmciac = card->driver;
if (pcmciac->cop_base)
KdUnmapDevice ((void *) pcmciac->cop_base, PCMCIA_COP_SIZE(card));
}
void
pcmciaGetColors (ScreenPtr pScreen, int fb, int ndef, xColorItem *pdefs)
{
KdScreenPriv(pScreen);
pcmciaCardInfo *pcmciac = pScreenPriv->card->driver;
while (ndef--)
{
pcmciaWriteReg (pcmciac, 0x3C7, pdefs->pixel);
pdefs->red = pcmciaReadReg (pcmciac, 0x3C9) << 10;
pdefs->green = pcmciaReadReg (pcmciac, 0x3C9) << 10;
pdefs->blue = pcmciaReadReg (pcmciac, 0x3C9) << 10;
pdefs++;
}
}
void
pcmciaPutColors (ScreenPtr pScreen, int fb, int ndef, xColorItem *pdefs)
{
KdScreenPriv(pScreen);
pcmciaCardInfo *pcmciac = pScreenPriv->card->driver;
while (ndef--)
{
pcmciaWriteReg (pcmciac, 0x3C8, pdefs->pixel);
pcmciaWriteReg (pcmciac, 0x3C9, pdefs->red >> 10);
pcmciaWriteReg (pcmciac, 0x3C9, pdefs->green >> 10);
pcmciaWriteReg (pcmciac, 0x3C9, pdefs->blue >> 10);
pdefs++;
}
}
KdCardFuncs pcmciaFuncs = {
pcmciaCardInit, /* cardinit */
pcmciaScreenInit, /* scrinit */
pcmciaInitScreen, /* initScreen */
pcmciaPreserve, /* preserve */
pcmciaEnable, /* enable */
pcmciaDPMS, /* dpms */
pcmciaDisable, /* disable */
pcmciaRestore, /* restore */
pcmciaScreenFini, /* scrfini */
pcmciaCardFini, /* cardfini */
pcmciaCursorInit, /* initCursor */
pcmciaCursorEnable, /* enableCursor */
pcmciaCursorDisable, /* disableCursor */
pcmciaCursorFini, /* finiCursor */
pcmciaRecolorCursor, /* recolorCursor */
#if 0 /* not yet */
pcmciaDrawInit, /* initAccel */
pcmciaDrawEnable, /* enableAccel */
pcmciaDrawSync, /* syncAccel */
pcmciaDrawDisable, /* disableAccel */
pcmciaDrawFini, /* finiAccel */
#else
0,
0,
0,
0,
0,
#endif
pcmciaGetColors, /* getColors */
pcmciaPutColors, /* putColors */
};