Commit 5f8e75f2 authored by Keith Packard's avatar Keith Packard
Browse files

kdrive: add MTRR support, add clock support to trident driver

parent 02568ec5
......@@ -21,7 +21,7 @@
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $XFree86: xc/programs/Xserver/hw/kdrive/kdrive.h,v 1.8 2000/09/22 06:25:29 keithp Exp $ */
/* $XFree86: xc/programs/Xserver/hw/kdrive/kdrive.h,v 1.10 2000/09/27 20:47:37 keithp Exp $ */
#include <stdio.h>
#include "X.h"
......@@ -562,12 +562,22 @@ extern KdKeyboardFuncs VxWorksKeyboardFuncs;
extern KdOsFuncs VxWorksFuncs;
/* kmap.c */
#define KD_MAPPED_MODE_REGISTERS 0
#define KD_MAPPED_MODE_FRAMEBUFFER 1
void *
KdMapDevice (CARD32 addr, CARD32 size);
void
KdUnmapDevice (void *addr, CARD32 size);
void
KdSetMappedMode (CARD32 addr, CARD32 size, int mode);
void
KdResetMappedMode (CARD32 addr, CARD32 size, int mode);
/* kmode.c */
const KdMonitorTiming *
KdFindMode (KdScreenInfo *screen,
......
......@@ -29,6 +29,7 @@
#include <errno.h>
#include <unistd.h>
#include <sys/mman.h>
#include <asm/mtrr.h>
#endif
void *
......@@ -90,3 +91,72 @@ KdUnmapDevice (void *addr, CARD32 size)
#endif
}
#ifdef linux
static int mtrr;
#endif
void
KdSetMappedMode (CARD32 addr, CARD32 size, int mode)
{
#ifdef linux
struct mtrr_sentry sentry;
unsigned long base, bound;
unsigned int type;
if (addr < 0x100000)
return;
if (!mtrr)
mtrr = open ("/proc/mtrr", 2);
if (mtrr > 0)
{
base = addr & ~((1<22)-1);
bound = ((addr + size) + ((1<<22) - 1)) & ~((1<<22) - 1);
switch (mode) {
case KD_MAPPED_MODE_REGISTERS:
type = MTRR_TYPE_UNCACHABLE;
break;
case KD_MAPPED_MODE_FRAMEBUFFER:
type = MTRR_TYPE_WRCOMB;
break;
}
sentry.base = base;
sentry.size = bound - base;
sentry.type = type;
ioctl (mtrr, MTRRIOC_ADD_ENTRY, &sentry);
}
#endif
}
void
KdResetMappedMode (CARD32 addr, CARD32 size, int mode)
{
#ifdef linux
struct mtrr_sentry sentry;
unsigned long base, bound;
unsigned int type;
if (addr < 0x100000)
return;
if (!mtrr)
mtrr = open ("/proc/mtrr", 2);
if (mtrr > 0)
{
base = addr & ~((1<22)-1);
bound = ((addr + size) + ((1<<22) - 1)) & ~((1<<22) - 1);
switch (mode) {
case KD_MAPPED_MODE_REGISTERS:
type = MTRR_TYPE_UNCACHABLE;
break;
case KD_MAPPED_MODE_FRAMEBUFFER:
type = MTRR_TYPE_WRCOMB;
break;
}
sentry.base = base;
sentry.size = bound - base;
sentry.type = type;
ioctl (mtrr, MTRRIOC_DEL_ENTRY, &sentry);
}
#endif
}
......@@ -21,7 +21,7 @@
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $XFree86: xc/programs/Xserver/hw/kdrive/trident/trident.c,v 1.13 2000/10/11 06:04:40 keithp Exp $ */
/* $XFree86: xc/programs/Xserver/hw/kdrive/trident/trident.c,v 1.14 2000/10/20 00:19:51 keithp Exp $ */
#include "trident.h"
#define extern
......@@ -30,6 +30,15 @@
#undef TRI_DEBUG
int trident_clk = 0;
int trident_mclk = 0;
#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)))
Bool
tridentCardInit (KdCardInfo *card)
{
......@@ -45,6 +54,13 @@ tridentCardInit (KdCardInfo *card)
iopl (3);
tridentc->cop_base = (CARD8 *) KdMapDevice (TRIDENT_COP_BASE(card),
TRIDENT_COP_SIZE(card));
if (tridentc->cop_base)
{
KdSetMappedMode (TRIDENT_COP_BASE(card),
TRIDENT_COP_SIZE(card),
KD_MAPPED_MODE_REGISTERS);
}
tridentc->cop = (Cop *) (tridentc->cop_base + TRIDENT_COP_OFF(card));
tridentc->mmio = FALSE;
r39 = tridentReadIndex (tridentc, 0x3d4, 0x39);
......@@ -119,18 +135,16 @@ tridentScreenInit (KdScreenInfo *screen)
else
tridents->cursor_base = 0;
memory -= screen_size;
#if 0
if (memory > screen->fb[0].byteStride)
{
screen->off_screen = tridents->screen + screen_size;
screen->off_screen_size = memory - screen_size;
tridents->off_screen = tridents->screen + screen_size;
tridents->off_screen_size = memory;
}
else
{
screen->off_screen = 0;
screen->off_screen_size = 0;
tridents->off_screen = 0;
tridents->off_screen_size = 0;
}
#endif
screen->driver = tridents;
return TRUE;
}
......@@ -178,6 +192,36 @@ tridentWriteIndex (TridentCardInfo *tridentc, CARD16 port, CARD8 index, CARD8 va
}
}
CARD8
tridentReadReg (TridentCardInfo *tridentc, CARD16 port)
{
CARD8 value;
if (tridentc->mmio)
{
value = tridentc->cop_base[port];
}
else
{
value = inb (port);
}
return value;
}
void
tridentWriteReg (TridentCardInfo *tridentc, CARD16 port, CARD8 value)
{
if (tridentc->mmio)
{
tridentc->cop_base[port] = value;
}
else
{
outb (value, port);
}
}
void
tridentPause ()
{
......@@ -204,6 +248,16 @@ tridentPreserve (KdCardInfo *card)
tridentc->save.reg_3d4_39 = tridentReadIndex (tridentc, 0x3d4, 0x39);
tridentc->save.reg_3d4_62 = tridentReadIndex (tridentc, 0x3d4, 0x62);
tridentc->save.reg_3ce_21 = tridentReadIndex (tridentc, 0x3ce, 0x21);
tridentc->save.reg_3c2 = tridentReadReg (tridentc, 0x3cc);
tridentc->save.reg_3c4_16 = tridentReadIndex (tridentc, 0x3c4, 0x16);
tridentc->save.reg_3c4_17 = tridentReadIndex (tridentc, 0x3c4, 0x17);
tridentc->save.reg_3c4_18 = tridentReadIndex (tridentc, 0x3c4, 0x18);
tridentc->save.reg_3c4_19 = tridentReadIndex (tridentc, 0x3c4, 0x19);
ErrorF ("clk low 0x%x high 0x%x freq %d\n",
tridentc->save.reg_3c4_18,
tridentc->save.reg_3c4_19,
CLK_FREQ(tridentc->save.reg_3c4_18,
tridentc->save.reg_3c4_19));
#ifdef TRI_DEBUG
fprintf (stderr, "3c4 0e: %02x\n", tridentc->save.reg_3c4_0e);
fprintf (stderr, "3d4 36: %02x\n", tridentc->save.reg_3d4_36);
......@@ -215,6 +269,98 @@ tridentPreserve (KdCardInfo *card)
tridentPause ();
}
void
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 = 64;
endn = 255;
endm = 63;
endk = 3;
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;
}
}
ErrorF ("ffreq %d clock %d\n", s, clock);
if (s == 0)
{
FatalError("Unable to set programmable clock.\n"
"Frequency %d is not a valid clock.\n"
"Please modify XF86Config for a new clock.\n",
freq);
}
/* N is all 8bits */
*a = p;
/* M is first 6bits, with K last 2bits */
*b = (q & 0x3F) | (r << 6);
}
void
tridentSetMCLK(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 = 64;
endn = 255;
endm = 63;
endk = 3;
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 (s == 0)
{
FatalError("Unable to set memory clock.\n"
"Frequency %d is not a valid clock.\n"
"Please modify XF86Config for a new clock.\n",
freq);
}
/* N is all 8bits */
*a = p;
/* M is first 6bits, with K last 2bits */
*b = (q & 0x3F) | (r << 6);
}
void
tridentSetMMIO (TridentCardInfo *tridentc)
{
......@@ -255,6 +401,46 @@ tridentSetMMIO (TridentCardInfo *tridentc)
/* reset GE, enable GE, set GE to 0xbff00 */
tridentWriteIndex (tridentc, 0x3d4, 0x36, 0x92);
#endif
/* set clock */
if (trident_clk)
{
CARD8 a, b;
a = tridentReadIndex (tridentc, 0x3c4, 0x18);
b = tridentReadIndex (tridentc, 0x3c4, 0x19);
ErrorF ("old clock 0x%x 0x%x %d\n",
a, b, CLK_FREQ(a,b));
tridentSetCLK (trident_clk, &a, &b);
ErrorF ("clk %d-> 0x%x 0x%x %d\n", trident_clk, a, b,
CLK_FREQ(a,b));
#if 1
tridentWriteIndex (tridentc, 0x3c4, 0x18, a);
tridentWriteIndex (tridentc, 0x3c4, 0x19, b);
#endif
}
if (trident_mclk)
{
CARD8 a, b;
tridentSetMCLK (trident_mclk, &a, &b);
ErrorF ("mclk %d -> 0x%x 0x%x\n", trident_mclk, a, b);
#if 0
tridentWriteIndex (tridentc, 0x3c4, 0x16, a);
tridentWriteIndex (tridentc, 0x3c4, 0x17, b);
#endif
}
if (trident_clk || trident_mclk)
{
CARD8 mode;
mode = tridentReadReg (tridentc, 0x3cc);
ErrorF ("old mode 0x%x\n", mode);
mode = (mode & 0xf3) | 0x08;
ErrorF ("new mode 0x%x\n", mode);
#if 1
tridentWriteReg (tridentc, 0x3c2, mode);
#endif
}
#ifdef TRI_DEBUG
fprintf (stderr, "0x36: 0x%02x\n",
tridentReadIndex (tridentc, 0x3d4, 0x36));
......@@ -276,6 +462,14 @@ tridentResetMMIO (TridentCardInfo *tridentc)
fprintf (stderr, "Reset MMIO\n");
#endif
tridentPause ();
#if 0
tridentWriteIndex (tridentc, 0x3c4, 0x16, tridentc->save.reg_3c4_16);
tridentWriteIndex (tridentc, 0x3c4, 0x17, tridentc->save.reg_3c4_17);
#endif
tridentWriteIndex (tridentc, 0x3c4, 0x18, tridentc->save.reg_3c4_18);
tridentWriteIndex (tridentc, 0x3c4, 0x19, tridentc->save.reg_3c4_19);
tridentWriteReg (tridentc, 0x3c2, tridentc->save.reg_3c2);
tridentPause ();
tridentWriteIndex (tridentc, 0x3ce, 0x21, tridentc->save.reg_3ce_21);
tridentPause ();
tridentWriteIndex (tridentc, 0x3d4, 0x62, tridentc->save.reg_3d4_62);
......@@ -364,7 +558,12 @@ tridentCardFini (KdCardInfo *card)
TridentCardInfo *tridentc = card->driver;
if (tridentc->cop_base)
{
KdUnmapDevice ((void *) tridentc->cop_base, TRIDENT_COP_SIZE(card));
KdResetMappedMode (TRIDENT_COP_BASE(card),
TRIDENT_COP_SIZE(card),
KD_MAPPED_MODE_REGISTERS);
}
#ifdef VESA
vesaCardFini (card);
#else
......
......@@ -21,7 +21,7 @@
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $XFree86: xc/programs/Xserver/hw/kdrive/trident/trident.h,v 1.7 2000/10/11 06:04:40 keithp Exp $ */
/* $XFree86: xc/programs/Xserver/hw/kdrive/trident/trident.h,v 1.8 2000/10/20 00:19:51 keithp Exp $ */
#ifndef _TRIDENT_H_
#define _TRIDENT_H_
......@@ -179,6 +179,11 @@ typedef struct _tridentSave {
CARD8 reg_3d4_39;
CARD8 reg_3d4_62; /* GE setup */
CARD8 reg_3ce_21; /* DPMS */
CARD8 reg_3c2; /* clock config */
CARD8 reg_3c4_16; /* MCLKLow */
CARD8 reg_3c4_17; /* MCLKHigh */
CARD8 reg_3c4_18; /* ClockLow */
CARD8 reg_3c4_19; /* ClockHigh */
} TridentSave;
typedef struct _tridentCardInfo {
......
......@@ -21,7 +21,7 @@
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $XFree86: xc/programs/Xserver/hw/kdrive/trident/tridentdraw.c,v 1.5 2000/08/26 00:17:50 keithp Exp $ */
/* $XFree86: xc/programs/Xserver/hw/kdrive/trident/tridentdraw.c,v 1.6 2000/10/11 06:04:40 keithp Exp $ */
#include "trident.h"
#include "tridentdraw.h"
......@@ -701,25 +701,37 @@ tridentComposite (CARD8 op,
CARD16 height)
{
SetupTrident (pDst->pDrawable->pScreen);
RegionRec region;
int n;
BoxPtr pbox;
tridentScreenInfo(pScreenPriv);
RegionRec region;
int n;
BoxPtr pbox;
CARD32 rgb;
CARD8 *msk, *mskLine;
FbBits *mskBits;
FbStride mskStride;
int mskBpp;
CARD32 *src, *srcLine;
CARD32 *off, *offLine;
FbBits *srcBits;
FbStride srcStride;
FbStride offStride;
int srcBpp;
int x_msk, y_msk, x_src, y_src, x_dst, y_dst;
int x2;
int w, h, w_this, h_this, w_remain;
int win_remain;
CARD32 *window;
CARD32 *off_screen;
int off_size = tridents->off_screen_size >> 2;
int off_width, off_height;
int stride = pScreenPriv->screen->fb[0].pixelStride;
int mskExtra;
CARD32 off_screen_offset = tridents->off_screen - tridents->screen;
int mode;
#define MODE_NONE 0
#define MODE_IMAGE 1
#define MODE_MASK 2
rgb = *((CARD32 *) ((PixmapPtr) (pSrc->pDrawable))->devPrivate.ptr);
if (pMask &&
!pMask->repeat &&
pMask->format == PICT_a8 &&
......@@ -729,109 +741,11 @@ tridentComposite (CARD8 op,
pSrc->pDrawable->height == 1 &&
PICT_FORMAT_BPP(pSrc->format) == 32 &&
(PICT_FORMAT_A(pSrc->format) == 0 ||
((rgb = (*((CARD32 *) ((PixmapPtr) (pSrc->pDrawable))->devPrivate.ptr))
& 0xff000000) == 0xff000000)) &&
(rgb & 0xff000000) == 0xff000000) &&
pDst->pDrawable->bitsPerPixel == 32 &&
pDst->pDrawable->type == DRAWABLE_WINDOW)
{
xDst += pDst->pDrawable->x;
yDst += pDst->pDrawable->y;
xSrc += pSrc->pDrawable->x;
ySrc += pSrc->pDrawable->y;
if (pMask)
{
xMask += pMask->pDrawable->x;
yMask += pMask->pDrawable->y;
}
rgb = (*((CARD32 *) ((PixmapPtr) (pSrc->pDrawable))->devPrivate.ptr)
& 0xffffff);
if (!miComputeCompositeRegion (&region,
pSrc,
pMask,
pDst,
xSrc,
ySrc,
xMask,
yMask,
xDst,
yDst,
width,
height))
return;
fbGetDrawable (pMask->pDrawable, mskBits, mskStride, mskBpp);
mskStride = mskStride * sizeof (FbBits) / sizeof (CARD8);
cop->multi = (COP_MULTI_ROP | 0xcc);
cop->multi = (COP_MULTI_ALPHA |
COP_ALPHA_BLEND_ENABLE |
COP_ALPHA_WRITE_ENABLE |
0x7 << 16 |
COP_ALPHA_DST_BLEND_1_SRC_A |
COP_ALPHA_SRC_BLEND_SRC_A);
n = REGION_NUM_RECTS (&region);
pbox = REGION_RECTS (&region);
while (n--)
{
h = pbox->y2 - pbox->y1;
x2 = pbox->x2;
w = x2 - pbox->x1;
cop->multi = COP_MULTI_CLIP_TOP_LEFT | TRI_XY(0,0);
cop->clip_bottom_right = TRI_XY(x2-1, 0xfff);
if (w & 1)
{
x2++;
w++;
}
y_msk = pbox->y1 - yDst + yMask;
y_dst = pbox->y1;
x_msk = pbox->x1 - xDst + xMask;
x_dst = pbox->x1;
mskLine = (CARD8 *) mskBits + y_msk * mskStride + x_msk;
cop->dst_start_xy = TRI_XY(pbox->x1, pbox->y1);
cop->dst_end_xy = TRI_XY(x2-1,pbox->y2-1);
_tridentWaitDone(cop);
cop->command = (COP_OP_BLT | COP_SCL_OPAQUE | COP_CLIP | COP_OP_ROP);
win_remain = 0;
while (h--)
{
w_remain = w;
msk = mskLine;
mskLine += mskStride;
while (w_remain)
{
if (!win_remain)
{
window = tridentc->window;
win_remain = 0x1000 / 4;
}
w_this = w_remain;
if (w_this > win_remain)
w_this = win_remain;
win_remain -= w_this;
w_remain -= w_this;
while (w_this--)
*window++ = rgb | (*msk++ << 24);
}
}
pbox++;
}
cop->multi = TridentAlpha;
cop->clip_bottom_right = 0x0fff0fff;
KdMarkSync (pDst->pDrawable->pScreen);
mode = MODE_MASK;
}
else if (!pMask &&
op == PictOpOver &&
......@@ -840,15 +754,27 @@ tridentComposite (CARD8 op,
PICT_FORMAT_BPP(pSrc->format) == 32 &&
pDst->pDrawable->bitsPerPixel == 32 &&
pDst->pDrawable->type == DRAWABLE_WINDOW)
{
mode = MODE_IMAGE;
}
else
mode = MODE_NONE;
if (mode != MODE_NONE)
{
xDst += pDst->pDrawable->x;
yDst += pDst->pDrawable->y;
xSrc += pSrc->pDrawable->x;
ySrc += pSrc->pDrawable->y;
fbGetDrawable (pSrc->pDrawable, srcBits, srcStride, srcBpp);
if (pMask)
{
xMask += pMask->pDrawable->x;
yMask += pMask->pDrawable->y;
fbGetDrawable (pMask->pDrawable, mskBits, mskStride, mskBpp);
mskStride = mskStride * sizeof (FbBits) / sizeof (CARD8);
}
if (!miComputeCompositeRegion (&region,
......@@ -865,16 +791,30 @@ tridentComposite (CARD8 op,
height))
return;
fbGetDrawable (pSrc->pDrawable, srcBits, srcStride, srcBpp);
_tridentInit(cop,tridentc);
cop->multi = (COP_MULTI_ROP | 0xcc);
cop->multi = COP_MULTI_PATTERN;
cop->src_offset = off_screen_offset;