#include "ffb.h"
#include "ffb_rcache.h"
#include "ffb_fifo.h"
#include "xf86.h"
#include "xf86_OSproc.h"
#include "xf86_ansic.h"
#include "xf86DDC.h"
#ifndef DPMS_SPIN_COUNT
#define DPMS_SPIN_COUNT 100
#endif
void
FFBDacLoadCursorPos(FFBPtr pFfb, int x, int y)
{
ffb_dacPtr dac = pFfb->dac;
int posval;
posval = ((y & 0xffff) << 16) | (x & 0xffff);
posval &= (FFBDAC_CUR_POS_Y_SIGN |
FFBDAC_CUR_POS_Y |
FFBDAC_CUR_POS_X_SIGN |
FFBDAC_CUR_POS_X);
DACCUR_WRITE(dac, FFBDAC_CUR_POS, posval);
}
void
FFBDacLoadCursorColor(FFBPtr pFfb, int fg, int bg)
{
ffb_dacPtr dac = pFfb->dac;
dac->cur = FFBDAC_CUR_COLOR1;
dac->curdata = bg;
dac->curdata = fg;
}
void
FFBDacCursorEnableDisable(FFBPtr pFfb, int enable)
{
ffb_dac_info_t *p = &pFfb->dac_info;
ffb_dacPtr dac = pFfb->dac;
int val;
val = 0;
if (!enable)
val = (FFBDAC_CUR_CTRL_P0 | FFBDAC_CUR_CTRL_P1);
if (p->flags & FFB_DAC_ICURCTL)
val ^= (FFBDAC_CUR_CTRL_P0 | FFBDAC_CUR_CTRL_P1);
DACCUR_WRITE(dac, FFBDAC_CUR_CTRL, val);
}
void
FFBDacCursorLoadBitmap(FFBPtr pFfb, int xshift, int yshift, unsigned int *bitmap)
{
ffb_dacPtr dac = pFfb->dac;
int i, j;
dac->cur = FFBDAC_CUR_BITMAP_P0;
for (j = 0; j < 2; j++) {
bitmap += yshift * 2;
if (!xshift) {
for (i = yshift * 2; i < 128; i++)
dac->curdata = *bitmap++;
} else if (xshift < 32) {
for (i = yshift; i < 64; i++, bitmap += 2) {
dac->curdata = (bitmap[0] << xshift) |
(bitmap[1] >> (32 - xshift));
dac->curdata = bitmap[1] << xshift;
}
} else {
for (i = yshift; i < 64; i++, bitmap += 2) {
dac->curdata = bitmap[1] << (xshift - 32);
dac->curdata = 0;
}
}
for (i = 0; i < yshift * 2; i++)
dac->curdata = 0;
}
}
void
FFBDacLoadPalette(ScrnInfoPtr pScrn, int ncolors, int *indices, LOCO *colors, VisualPtr pVisual)
{
FFBPtr pFfb = GET_FFB_FROM_SCRN(pScrn);
ffb_dac_info_t *p = &pFfb->dac_info;
ffb_dacPtr dac = pFfb->dac;
unsigned int *cluts;
int i, index, palette;
if ((pVisual->nplanes != 8 && pVisual->class != DirectColor) ||
(pVisual->nplanes == 8 && pVisual->class == StaticGray))
return;
palette = 0;
if (p->flags & FFB_DAC_PAC2) {
if (pVisual->class == PseudoColor)
palette = 0;
if (pVisual->class == GrayScale)
palette = 1;
if (pVisual->class == DirectColor)
palette = 2;
}
cluts = &p->x_dac_state.clut[256 * palette];
for (i = 0; i < ncolors; i++) {
unsigned int regval;
index = indices[i];
if (pVisual->class == GrayScale) {
regval = cluts[index] =
((colors[index].red << FFBDAC_COLOR_RED_SHFT) |
(colors[index].red << FFBDAC_COLOR_GREEN_SHFT) |
(colors[index].red << FFBDAC_COLOR_BLUE_SHFT));
} else {
regval = cluts[index] =
((colors[index].red << FFBDAC_COLOR_RED_SHFT) |
(colors[index].green << FFBDAC_COLOR_GREEN_SHFT) |
(colors[index].blue << FFBDAC_COLOR_BLUE_SHFT));
}
FFBLOG(("FFBDacLoadPalette: visclass(%d) index(%d) val[%08x]\n",
pVisual->class, index, regval));
dac->cfg = FFBDAC_CFG_CLUP(palette) + index;
dac->cfgdata = regval;
}
}
static void
dac_stop(FFBPtr pFfb)
{
ffb_dacPtr dac = pFfb->dac;
unsigned int tgctrl;
tgctrl = DACCFG_READ(dac, FFBDAC_CFG_TGEN);
if (tgctrl & FFBDAC_CFG_TGEN_TGE) {
long limit = 1000000;
while (limit--) {
unsigned int vctr = DACCFG_READ(dac, FFBDAC_CFG_TGVC);
if (vctr == 0)
break;
}
DACCFG_WRITE(dac, FFBDAC_CFG_TGEN, 0);
}
}
static void
dac_state_restore(FFBPtr pFfb, ffb_dac_hwstate_t *state)
{
ffb_dac_info_t *p = &pFfb->dac_info;
ffb_dacPtr dac = pFfb->dac;
ffb_fbcPtr ffb = pFfb->regs;
int i, nluts;
dac_stop(pFfb);
ffb->fbcfg0 = 0;
DACCFG_WRITE(dac, FFBDAC_CFG_VBNP, state->vbnp);
DACCFG_WRITE(dac, FFBDAC_CFG_VBAP, state->vbap);
DACCFG_WRITE(dac, FFBDAC_CFG_VSNP, state->vsnp);
DACCFG_WRITE(dac, FFBDAC_CFG_VSAP, state->vsap);
DACCFG_WRITE(dac, FFBDAC_CFG_HSNP, state->hsnp);
DACCFG_WRITE(dac, FFBDAC_CFG_HBNP, state->hbnp);
DACCFG_WRITE(dac, FFBDAC_CFG_HBAP, state->hbap);
DACCFG_WRITE(dac, FFBDAC_CFG_HSYNCNP, state->hsyncnp);
DACCFG_WRITE(dac, FFBDAC_CFG_HSYNCAP, state->hsyncap);
DACCFG_WRITE(dac, FFBDAC_CFG_HSCENNP, state->hscennp);
DACCFG_WRITE(dac, FFBDAC_CFG_HSCENAP, state->hscenap);
DACCFG_WRITE(dac, FFBDAC_CFG_EPNP, state->epnp);
DACCFG_WRITE(dac, FFBDAC_CFG_EINP, state->einp);
DACCFG_WRITE(dac, FFBDAC_CFG_EIAP, state->eiap);
DACCFG_WRITE(dac, FFBDAC_CFG_PPLLCTRL, state->ppllctrl);
DACCFG_WRITE(dac, FFBDAC_CFG_GPLLCTRL, state->gpllctrl);
DACCFG_WRITE(dac, FFBDAC_CFG_PFCTRL, state->pfctrl);
DACCFG_WRITE(dac, FFBDAC_CFG_UCTRL, state->uctrl);
nluts = (p->flags & FFB_DAC_PAC1) ? 256 : (4 * 256);
dac->cfg = FFBDAC_CFG_CLUP_BASE;
for (i = 0; i < nluts; i++)
dac->cfgdata = state->clut[i];
if (p->flags & FFB_DAC_PAC2) {
dac->cfg = FFBDAC_PAC2_AOVWLUT0;
for (i = 0; i < 4; i++)
dac->cfgdata = state->ovluts[i];
}
DACCFG_WRITE(dac, FFBDAC_CFG_WTCTRL, state->wtctrl);
DACCFG_WRITE(dac, FFBDAC_CFG_TMCTRL, state->tmctrl);
DACCFG_WRITE(dac, FFBDAC_CFG_TCOLORKEY, state->tcolorkey);
if (p->flags & FFB_DAC_PAC2)
DACCFG_WRITE(dac, FFBDAC_CFG_WAMASK, state->wamask);
if (p->flags & FFB_DAC_PAC1) {
dac->cfg = FFBDAC_PAC1_APWLUT_BASE;
for (i = 0; i < 32; i++)
dac->cfgdata = state->pwluts[i];
} else {
dac->cfg = FFBDAC_PAC2_APWLUT_BASE;
for (i = 0; i < 64; i++)
dac->cfgdata = state->pwluts[i];
}
DACCFG_WRITE(dac, FFBDAC_CFG_DACCTRL, state->dacctrl);
if (pFfb->ffb_type == ffb2_vertical_plus ||
pFfb->ffb_type == ffb2_horizontal_plus ||
pFfb->ffb_type == afb_m3 ||
pFfb->ffb_type == afb_m6)
ffb->passin = p->ffb_passin_ctrl;
ffb->fbcfg0 = p->ffbcfg0;
ffb->fbcfg2 = p->ffbcfg2;
DACCFG_WRITE(dac, FFBDAC_CFG_TGEN, state->tgen);
for (i = 0; i < 100; i++)
(void) DACCFG_READ(dac, FFBDAC_CFG_TGVC);
}
static void
dac_state_save(FFBPtr pFfb, ffb_dac_hwstate_t *state)
{
ffb_dac_info_t *p = &pFfb->dac_info;
ffb_dacPtr dac = pFfb->dac;
int i, nluts;
state->ppllctrl = DACCFG_READ(dac, FFBDAC_CFG_PPLLCTRL);
state->gpllctrl = DACCFG_READ(dac, FFBDAC_CFG_GPLLCTRL);
state->pfctrl = DACCFG_READ(dac, FFBDAC_CFG_PFCTRL);
state->uctrl = DACCFG_READ(dac, FFBDAC_CFG_UCTRL);
nluts = (p->flags & FFB_DAC_PAC1) ? 256 : (4 * 256);
dac->cfg = FFBDAC_CFG_CLUP_BASE;
for (i = 0; i < nluts; i++)
state->clut[i] = dac->cfgdata;
if (p->flags & FFB_DAC_PAC2) {
dac->cfg = FFBDAC_PAC2_AOVWLUT0;
for (i = 0; i < 4; i++)
state->ovluts[i] = dac->cfgdata;
}
state->wtctrl = DACCFG_READ(dac, FFBDAC_CFG_WTCTRL);
state->tmctrl = DACCFG_READ(dac, FFBDAC_CFG_TMCTRL);
state->tcolorkey = DACCFG_READ(dac, FFBDAC_CFG_TCOLORKEY);
if (p->flags & FFB_DAC_PAC2)
state->wamask = DACCFG_READ(dac, FFBDAC_CFG_WAMASK);
if (p->flags & FFB_DAC_PAC1) {
dac->cfg = FFBDAC_PAC1_APWLUT_BASE;
for (i = 0; i < 32; i++)
state->pwluts[i] = dac->cfgdata;
} else {
dac->cfg = FFBDAC_PAC2_APWLUT_BASE;
for (i = 0; i < 64; i++)
state->pwluts[i] = dac->cfgdata;
}
state->dacctrl = DACCFG_READ(dac, FFBDAC_CFG_DACCTRL);
state->tgen = DACCFG_READ(dac, FFBDAC_CFG_TGEN);
state->vbnp = DACCFG_READ(dac, FFBDAC_CFG_VBNP);
state->vbap = DACCFG_READ(dac, FFBDAC_CFG_VBAP);
state->vsnp = DACCFG_READ(dac, FFBDAC_CFG_VSNP);
state->vsap = DACCFG_READ(dac, FFBDAC_CFG_VSAP);
state->hsnp = DACCFG_READ(dac, FFBDAC_CFG_HSNP);
state->hbnp = DACCFG_READ(dac, FFBDAC_CFG_HBNP);
state->hbap = DACCFG_READ(dac, FFBDAC_CFG_HBAP);
state->hsyncnp = DACCFG_READ(dac, FFBDAC_CFG_HSYNCNP);
state->hsyncap = DACCFG_READ(dac, FFBDAC_CFG_HSYNCAP);
state->hscennp = DACCFG_READ(dac, FFBDAC_CFG_HSCENNP);
state->hscenap = DACCFG_READ(dac, FFBDAC_CFG_HSCENAP);
state->epnp = DACCFG_READ(dac, FFBDAC_CFG_EPNP);
state->einp = DACCFG_READ(dac, FFBDAC_CFG_EINP);
state->eiap = DACCFG_READ(dac, FFBDAC_CFG_EIAP);
}
static void
init_dac_flags(FFBPtr pFfb)
{
ffb_dac_info_t *p = &pFfb->dac_info;
ffb_dacPtr dac = pFfb->dac;
unsigned int did, manuf_rev, partnum;
char *device;
p->kernel_wid = *((volatile unsigned char *)pFfb->dfb8x);
if (pFfb->ffb_type == afb_m3 || pFfb->ffb_type == afb_m6) {
p->flags = FFB_DAC_PAC2;
manuf_rev = 4;
} else {
p->flags = 0;
did = DACCFG_READ(dac, FFBDAC_CFG_DID);
manuf_rev = DACCFG_READ(dac, FFBDAC_CFG_UCTRL);
manuf_rev = (manuf_rev & FFBDAC_UCTRL_MANREV) >> 8;
partnum = ((did & FFBDAC_CFG_DID_PNUM) >> 12);
if (partnum == 0x236e)
p->flags |= FFB_DAC_PAC2;
else
p->flags |= FFB_DAC_PAC1;
}
device = pFfb->psdp->device;
if ((p->flags & FFB_DAC_PAC1) != 0) {
if (manuf_rev < 3) {
p->flags |= FFB_DAC_ICURCTL;
xf86Msg(X_INFO, "%s: BT9068 (PAC1) ramdac detected (with "
"inverted cursor control)\n", device);
} else {
xf86Msg(X_INFO, "%s: BT9068 (PAC1) ramdac detected (with "
"normal cursor control)\n", device);
}
} else {
xf86Msg(X_INFO, "%s: BT498 (PAC2) ramdac detected\n", device);
}
}
Bool
FFBDacInit(FFBPtr pFfb)
{
ffb_dac_info_t *p = &pFfb->dac_info;
ffb_fbcPtr ffb = pFfb->regs;
init_dac_flags(pFfb);
p->ffbcfg0 = ffb->fbcfg0;
p->ffbcfg2 = ffb->fbcfg2;
if (pFfb->ffb_type == ffb2_vertical_plus ||
pFfb->ffb_type == ffb2_horizontal_plus ||
pFfb->ffb_type == afb_m3 ||
pFfb->ffb_type == afb_m6)
p->ffb_passin_ctrl = ffb->passin;
dac_state_save(pFfb, &p->kern_dac_state);
dac_state_save(pFfb, &p->x_dac_state);
FFBWidPoolInit(pFfb);
return TRUE;
}
static void
restore_kernel_xchannel(FFBPtr pFfb)
{
ffb_fbcPtr ffb = pFfb->regs;
unsigned int fbc, ppc, ppc_mask, drawop, wid;
wid = pFfb->dac_info.kernel_wid;
if (pFfb->has_double_buffer)
fbc = FFB_FBC_WB_AB;
else
fbc = FFB_FBC_WB_A;
fbc |= (FFB_FBC_WM_COMBINED | FFB_FBC_RB_A | FFB_FBC_SB_BOTH |
FFB_FBC_ZE_OFF | FFB_FBC_YE_OFF |
FFB_FBC_XE_ON | FFB_FBC_RGBE_MASK);
ppc = (FFB_PPC_APE_DISABLE | FFB_PPC_CS_CONST | FFB_PPC_XS_WID);
ppc_mask = (FFB_PPC_APE_MASK | FFB_PPC_CS_MASK | FFB_PPC_XS_MASK);
drawop = FFB_DRAWOP_RECTANGLE;
FFB_ATTR_RAW(pFfb, ppc, ppc_mask, ~0,
(FFB_ROP_EDIT_BIT | GXcopy)|(FFB_ROP_NEW<<8),
drawop, 0x0, fbc, wid);
FFBFifo(pFfb, 4);
FFB_WRITE64(&ffb->by, 0, 0);
FFB_WRITE64_2(&ffb->bh, pFfb->psdp->height, pFfb->psdp->width);
pFfb->rp_active = 1;
FFBWait(pFfb, ffb);
}
void
FFBDacFini(FFBPtr pFfb)
{
ffb_dac_info_t *p = &pFfb->dac_info;
dac_state_restore(pFfb, &p->kern_dac_state);
restore_kernel_xchannel(pFfb);
}
void
FFBDacEnterVT(FFBPtr pFfb)
{
ffb_dac_info_t *p = &pFfb->dac_info;
dac_state_save(pFfb, &p->kern_dac_state);
dac_state_restore(pFfb, &p->x_dac_state);
}
void
FFBDacLeaveVT(FFBPtr pFfb)
{
ffb_dac_info_t *p = &pFfb->dac_info;
dac_state_save(pFfb, &p->x_dac_state);
dac_state_restore(pFfb, &p->kern_dac_state);
restore_kernel_xchannel(pFfb);
}
static void
SPIN(ffb_dacPtr d, int count) {
while(count-- > 0) {
(void) DACCFG_READ(d, FFBDAC_CFG_TGVC);
}
return;
}
Bool
FFBDacSaveScreen(FFBPtr pFfb, int mode) {
int tmp;
ffb_dacPtr dac;
if(!pFfb) return FALSE;
else dac = pFfb -> dac;
tmp = DACCFG_READ(dac, FFBDAC_CFG_TGEN);
switch(mode) {
case SCREEN_SAVER_ON:
case SCREEN_SAVER_CYCLE:
tmp &= ~FFBDAC_CFG_TGEN_VIDE;
break;
case SCREEN_SAVER_OFF:
case SCREEN_SAVER_FORCER:
tmp |= FFBDAC_CFG_TGEN_VIDE;
break;
default:
return FALSE;
}
DACCFG_WRITE(dac, FFBDAC_CFG_TGEN, tmp);
SPIN(dac, DPMS_SPIN_COUNT/10);
return TRUE;
}
void
FFBDacDPMSMode(FFBPtr pFfb, int DPMSMode, int flags) {
int tmp;
ffb_dacPtr dac = pFfb -> dac;
tmp = DACCFG_READ(dac, FFBDAC_CFG_TGEN);
switch(DPMSMode) {
case DPMSModeOn:
tmp &= ~(FFBDAC_CFG_TGEN_VSD | FFBDAC_CFG_TGEN_HSD);
tmp |= FFBDAC_CFG_TGEN_VIDE;
break;
case DPMSModeStandby:
#ifdef DPMS_TRUE_STANDBY
tmp |= FFBDAC_CFG_TGEN_HSD;
#endif
tmp &= ~FFBDAC_CFG_TGEN_VSD;
tmp &= ~FFBDAC_CFG_TGEN_VIDE;
break;
case DPMSModeSuspend:
tmp |= FFBDAC_CFG_TGEN_VSD;
tmp &= ~FFBDAC_CFG_TGEN_HSD;
tmp &= ~FFBDAC_CFG_TGEN_VIDE;
break;
case DPMSModeOff:
tmp |= (FFBDAC_CFG_TGEN_VSD | FFBDAC_CFG_TGEN_HSD);
tmp &= ~FFBDAC_CFG_TGEN_VIDE;
break;
default:
return;
}
DACCFG_WRITE(dac, FFBDAC_CFG_TGEN,tmp);
SPIN(dac, DPMS_SPIN_COUNT);
}