1dbbd9e4bSmacallan/* 2dbbd9e4bSmacallan * Acceleration for the Creator and Creator3D framebuffer - DAC programming. 3dbbd9e4bSmacallan * 4dbbd9e4bSmacallan * Copyright (C) 2000 David S. Miller (davem@redhat.com) 5dbbd9e4bSmacallan * 6dbbd9e4bSmacallan * Permission is hereby granted, free of charge, to any person obtaining a copy 7dbbd9e4bSmacallan * of this software and associated documentation files (the "Software"), to deal 8dbbd9e4bSmacallan * in the Software without restriction, including without limitation the rights 9dbbd9e4bSmacallan * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10dbbd9e4bSmacallan * copies of the Software, and to permit persons to whom the Software is 11dbbd9e4bSmacallan * furnished to do so, subject to the following conditions: 12dbbd9e4bSmacallan * 13dbbd9e4bSmacallan * The above copyright notice and this permission notice shall be included in 14dbbd9e4bSmacallan * all copies or substantial portions of the Software. 15dbbd9e4bSmacallan * 16dbbd9e4bSmacallan * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17dbbd9e4bSmacallan * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18dbbd9e4bSmacallan * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19dbbd9e4bSmacallan * DAVID MILLER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20dbbd9e4bSmacallan * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21dbbd9e4bSmacallan * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22dbbd9e4bSmacallan * 23dbbd9e4bSmacallan */ 24dbbd9e4bSmacallan 25dbbd9e4bSmacallan#ifdef HAVE_CONFIG_H 26dbbd9e4bSmacallan#include "config.h" 27dbbd9e4bSmacallan#endif 28dbbd9e4bSmacallan 29dbbd9e4bSmacallan#include "ffb.h" 30dbbd9e4bSmacallan#include "ffb_rcache.h" 31dbbd9e4bSmacallan#include "ffb_fifo.h" 32dbbd9e4bSmacallan 33dbbd9e4bSmacallan#include "xf86.h" 34dbbd9e4bSmacallan#include "xf86_OSproc.h" 35dbbd9e4bSmacallan 36dbbd9e4bSmacallan#include "xf86DDC.h" 37f1295e53Smrg#include "xf86Privstr.h" 38dbbd9e4bSmacallan 39dbbd9e4bSmacallan/* 40dbbd9e4bSmacallan * Used for stabilize time after playing with power management on the display 41dbbd9e4bSmacallan */ 42dbbd9e4bSmacallan 43dbbd9e4bSmacallan#ifndef DPMS_SPIN_COUNT 44dbbd9e4bSmacallan#define DPMS_SPIN_COUNT 100 45dbbd9e4bSmacallan#endif /* DPMS_SPIN_COUNT */ 46dbbd9e4bSmacallan 47dbbd9e4bSmacallan/* Cursor programming */ 48dbbd9e4bSmacallan 49dbbd9e4bSmacallanvoid 50dbbd9e4bSmacallanFFBDacLoadCursorPos(FFBPtr pFfb, int x, int y) 51dbbd9e4bSmacallan{ 52dbbd9e4bSmacallan ffb_dacPtr dac = pFfb->dac; 53dbbd9e4bSmacallan int posval; 54dbbd9e4bSmacallan 55dbbd9e4bSmacallan posval = ((y & 0xffff) << 16) | (x & 0xffff); 56dbbd9e4bSmacallan posval &= (FFBDAC_CUR_POS_Y_SIGN | 57dbbd9e4bSmacallan FFBDAC_CUR_POS_Y | 58dbbd9e4bSmacallan FFBDAC_CUR_POS_X_SIGN | 59dbbd9e4bSmacallan FFBDAC_CUR_POS_X); 60dbbd9e4bSmacallan 61dbbd9e4bSmacallan DACCUR_WRITE(dac, FFBDAC_CUR_POS, posval); 62dbbd9e4bSmacallan} 63dbbd9e4bSmacallan 64dbbd9e4bSmacallanvoid 65dbbd9e4bSmacallanFFBDacLoadCursorColor(FFBPtr pFfb, int fg, int bg) 66dbbd9e4bSmacallan{ 67dbbd9e4bSmacallan ffb_dacPtr dac = pFfb->dac; 68dbbd9e4bSmacallan 69dbbd9e4bSmacallan dac->cur = FFBDAC_CUR_COLOR1; 70dbbd9e4bSmacallan dac->curdata = bg; 71dbbd9e4bSmacallan dac->curdata = fg; 72dbbd9e4bSmacallan} 73dbbd9e4bSmacallan 74dbbd9e4bSmacallanvoid 75dbbd9e4bSmacallanFFBDacCursorEnableDisable(FFBPtr pFfb, int enable) 76dbbd9e4bSmacallan{ 77dbbd9e4bSmacallan ffb_dac_info_t *p = &pFfb->dac_info; 78dbbd9e4bSmacallan ffb_dacPtr dac = pFfb->dac; 79dbbd9e4bSmacallan int val; 80dbbd9e4bSmacallan 81dbbd9e4bSmacallan val = 0; 82dbbd9e4bSmacallan if (!enable) 83dbbd9e4bSmacallan val = (FFBDAC_CUR_CTRL_P0 | FFBDAC_CUR_CTRL_P1); 84dbbd9e4bSmacallan 85dbbd9e4bSmacallan /* PAC1 ramdacs with manufacturing revision less than 86dbbd9e4bSmacallan * '3' invert these control bits, wheee... 87dbbd9e4bSmacallan */ 88dbbd9e4bSmacallan if (p->flags & FFB_DAC_ICURCTL) 89dbbd9e4bSmacallan val ^= (FFBDAC_CUR_CTRL_P0 | FFBDAC_CUR_CTRL_P1); 90dbbd9e4bSmacallan 91dbbd9e4bSmacallan DACCUR_WRITE(dac, FFBDAC_CUR_CTRL, val); 92dbbd9e4bSmacallan} 93dbbd9e4bSmacallan 94dbbd9e4bSmacallanvoid 95dbbd9e4bSmacallanFFBDacCursorLoadBitmap(FFBPtr pFfb, int xshift, int yshift, unsigned int *bitmap) 96dbbd9e4bSmacallan{ 97dbbd9e4bSmacallan ffb_dacPtr dac = pFfb->dac; 98dbbd9e4bSmacallan int i, j; 99dbbd9e4bSmacallan 100dbbd9e4bSmacallan dac->cur = FFBDAC_CUR_BITMAP_P0; 101dbbd9e4bSmacallan for (j = 0; j < 2; j++) { 102dbbd9e4bSmacallan bitmap += yshift * 2; 103dbbd9e4bSmacallan if (!xshift) { 104dbbd9e4bSmacallan for (i = yshift * 2; i < 128; i++) 105dbbd9e4bSmacallan dac->curdata = *bitmap++; 106dbbd9e4bSmacallan } else if (xshift < 32) { 107dbbd9e4bSmacallan for (i = yshift; i < 64; i++, bitmap += 2) { 108dbbd9e4bSmacallan dac->curdata = (bitmap[0] << xshift) | 109dbbd9e4bSmacallan (bitmap[1] >> (32 - xshift)); 110dbbd9e4bSmacallan dac->curdata = bitmap[1] << xshift; 111dbbd9e4bSmacallan } 112dbbd9e4bSmacallan } else { 113dbbd9e4bSmacallan for (i = yshift; i < 64; i++, bitmap += 2) { 114dbbd9e4bSmacallan dac->curdata = bitmap[1] << (xshift - 32); 115dbbd9e4bSmacallan dac->curdata = 0; 116dbbd9e4bSmacallan } 117dbbd9e4bSmacallan } 118dbbd9e4bSmacallan 119dbbd9e4bSmacallan for (i = 0; i < yshift * 2; i++) 120dbbd9e4bSmacallan dac->curdata = 0; 121dbbd9e4bSmacallan } 122dbbd9e4bSmacallan} 123dbbd9e4bSmacallan 124dbbd9e4bSmacallan/* Config space programming */ 125dbbd9e4bSmacallan 126dbbd9e4bSmacallan/* XF86 LoadPalette callback. */ 127dbbd9e4bSmacallan 128dbbd9e4bSmacallanvoid 129dbbd9e4bSmacallanFFBDacLoadPalette(ScrnInfoPtr pScrn, int ncolors, int *indices, LOCO *colors, VisualPtr pVisual) 130dbbd9e4bSmacallan{ 131dbbd9e4bSmacallan FFBPtr pFfb = GET_FFB_FROM_SCRN(pScrn); 132dbbd9e4bSmacallan ffb_dac_info_t *p = &pFfb->dac_info; 133dbbd9e4bSmacallan ffb_dacPtr dac = pFfb->dac; 134dbbd9e4bSmacallan unsigned int *cluts; 135dbbd9e4bSmacallan int i, index, palette; 136dbbd9e4bSmacallan 137dbbd9e4bSmacallan if ((pVisual->nplanes != 8 && pVisual->class != DirectColor) || 138dbbd9e4bSmacallan (pVisual->nplanes == 8 && pVisual->class == StaticGray)) 139dbbd9e4bSmacallan return; 140dbbd9e4bSmacallan 141dbbd9e4bSmacallan palette = 0; 142dbbd9e4bSmacallan if (p->flags & FFB_DAC_PAC2) { 143dbbd9e4bSmacallan if (pVisual->class == PseudoColor) 144dbbd9e4bSmacallan palette = 0; 145dbbd9e4bSmacallan if (pVisual->class == GrayScale) 146dbbd9e4bSmacallan palette = 1; 147dbbd9e4bSmacallan if (pVisual->class == DirectColor) 148dbbd9e4bSmacallan palette = 2; 149dbbd9e4bSmacallan } 150dbbd9e4bSmacallan 151dbbd9e4bSmacallan cluts = &p->x_dac_state.clut[256 * palette]; 152dbbd9e4bSmacallan for (i = 0; i < ncolors; i++) { 153dbbd9e4bSmacallan unsigned int regval; 154dbbd9e4bSmacallan 155dbbd9e4bSmacallan index = indices[i]; 156dbbd9e4bSmacallan if (pVisual->class == GrayScale) { 157dbbd9e4bSmacallan regval = cluts[index] = 158dbbd9e4bSmacallan ((colors[index].red << FFBDAC_COLOR_RED_SHFT) | 159dbbd9e4bSmacallan (colors[index].red << FFBDAC_COLOR_GREEN_SHFT) | 160dbbd9e4bSmacallan (colors[index].red << FFBDAC_COLOR_BLUE_SHFT)); 161dbbd9e4bSmacallan } else { 162dbbd9e4bSmacallan regval = cluts[index] = 163dbbd9e4bSmacallan ((colors[index].red << FFBDAC_COLOR_RED_SHFT) | 164dbbd9e4bSmacallan (colors[index].green << FFBDAC_COLOR_GREEN_SHFT) | 165dbbd9e4bSmacallan (colors[index].blue << FFBDAC_COLOR_BLUE_SHFT)); 166dbbd9e4bSmacallan } 167dbbd9e4bSmacallan 168dbbd9e4bSmacallan FFBLOG(("FFBDacLoadPalette: visclass(%d) index(%d) val[%08x]\n", 169dbbd9e4bSmacallan pVisual->class, index, regval)); 170dbbd9e4bSmacallan 171dbbd9e4bSmacallan /* Now update the hardware copy. */ 172dbbd9e4bSmacallan dac->cfg = FFBDAC_CFG_CLUP(palette) + index; 173dbbd9e4bSmacallan dac->cfgdata = regval; 174dbbd9e4bSmacallan } 175dbbd9e4bSmacallan} 176dbbd9e4bSmacallan 177dbbd9e4bSmacallan/* WARNING: Very dangerous function, use with extreme care. */ 178dbbd9e4bSmacallanstatic void 179dbbd9e4bSmacallandac_stop(FFBPtr pFfb) 180dbbd9e4bSmacallan{ 181dbbd9e4bSmacallan ffb_dacPtr dac = pFfb->dac; 182dbbd9e4bSmacallan unsigned int tgctrl; 183dbbd9e4bSmacallan 184dbbd9e4bSmacallan tgctrl = DACCFG_READ(dac, FFBDAC_CFG_TGEN); 185dbbd9e4bSmacallan if (tgctrl & FFBDAC_CFG_TGEN_TGE) { 186dbbd9e4bSmacallan long limit = 1000000; 187dbbd9e4bSmacallan 188dbbd9e4bSmacallan /* We try to shut off the timing generation 189dbbd9e4bSmacallan * precisely at the beginning of a vertical 190dbbd9e4bSmacallan * retrace. This is really just to make it 191dbbd9e4bSmacallan * look nice, it's not a functional necessity. 192dbbd9e4bSmacallan * 193dbbd9e4bSmacallan * The limit is so that malfunctioning hardware 194dbbd9e4bSmacallan * does not end up hanging the server. 195dbbd9e4bSmacallan */ 196dbbd9e4bSmacallan while (limit--) { 197dbbd9e4bSmacallan unsigned int vctr = DACCFG_READ(dac, FFBDAC_CFG_TGVC); 198dbbd9e4bSmacallan 199dbbd9e4bSmacallan if (vctr == 0) 200dbbd9e4bSmacallan break; 201dbbd9e4bSmacallan } 202dbbd9e4bSmacallan 203dbbd9e4bSmacallan DACCFG_WRITE(dac, FFBDAC_CFG_TGEN, 0); 204dbbd9e4bSmacallan } 205dbbd9e4bSmacallan} 206dbbd9e4bSmacallan 207dbbd9e4bSmacallan/* This is made slightly complex because the ordering matters 208dbbd9e4bSmacallan * between several operations. We have to stop the DAC while 209dbbd9e4bSmacallan * restoring the timing registers so that some intermediate 210dbbd9e4bSmacallan * state does not emit wild retrace signals to the monitor. 211dbbd9e4bSmacallan * 212dbbd9e4bSmacallan * Another further complication is that we need to mess with 213dbbd9e4bSmacallan * some portions of the FFB framebuffer config registers to 214dbbd9e4bSmacallan * do this all properly. 215dbbd9e4bSmacallan */ 216dbbd9e4bSmacallanstatic void 217dbbd9e4bSmacallandac_state_restore(FFBPtr pFfb, ffb_dac_hwstate_t *state) 218dbbd9e4bSmacallan{ 219dbbd9e4bSmacallan ffb_dac_info_t *p = &pFfb->dac_info; 220dbbd9e4bSmacallan ffb_dacPtr dac = pFfb->dac; 221dbbd9e4bSmacallan ffb_fbcPtr ffb = pFfb->regs; 222dbbd9e4bSmacallan int i, nluts; 223dbbd9e4bSmacallan 224dbbd9e4bSmacallan /* Step 1: Shut off all pixel timing generation. */ 225dbbd9e4bSmacallan dac_stop(pFfb); 226dbbd9e4bSmacallan ffb->fbcfg0 = 0; 227dbbd9e4bSmacallan 228dbbd9e4bSmacallan /* Step 2: Restore timing settings. */ 229dbbd9e4bSmacallan DACCFG_WRITE(dac, FFBDAC_CFG_VBNP, state->vbnp); 230dbbd9e4bSmacallan DACCFG_WRITE(dac, FFBDAC_CFG_VBAP, state->vbap); 231dbbd9e4bSmacallan DACCFG_WRITE(dac, FFBDAC_CFG_VSNP, state->vsnp); 232dbbd9e4bSmacallan DACCFG_WRITE(dac, FFBDAC_CFG_VSAP, state->vsap); 233dbbd9e4bSmacallan DACCFG_WRITE(dac, FFBDAC_CFG_HSNP, state->hsnp); 234dbbd9e4bSmacallan DACCFG_WRITE(dac, FFBDAC_CFG_HBNP, state->hbnp); 235dbbd9e4bSmacallan DACCFG_WRITE(dac, FFBDAC_CFG_HBAP, state->hbap); 236dbbd9e4bSmacallan DACCFG_WRITE(dac, FFBDAC_CFG_HSYNCNP, state->hsyncnp); 237dbbd9e4bSmacallan DACCFG_WRITE(dac, FFBDAC_CFG_HSYNCAP, state->hsyncap); 238dbbd9e4bSmacallan DACCFG_WRITE(dac, FFBDAC_CFG_HSCENNP, state->hscennp); 239dbbd9e4bSmacallan DACCFG_WRITE(dac, FFBDAC_CFG_HSCENAP, state->hscenap); 240dbbd9e4bSmacallan DACCFG_WRITE(dac, FFBDAC_CFG_EPNP, state->epnp); 241dbbd9e4bSmacallan DACCFG_WRITE(dac, FFBDAC_CFG_EINP, state->einp); 242dbbd9e4bSmacallan DACCFG_WRITE(dac, FFBDAC_CFG_EIAP, state->eiap); 243dbbd9e4bSmacallan 244dbbd9e4bSmacallan /* Step 3: Restore rest of DAC hw state. */ 245dbbd9e4bSmacallan DACCFG_WRITE(dac, FFBDAC_CFG_PPLLCTRL, state->ppllctrl); 246dbbd9e4bSmacallan DACCFG_WRITE(dac, FFBDAC_CFG_GPLLCTRL, state->gpllctrl); 247dbbd9e4bSmacallan DACCFG_WRITE(dac, FFBDAC_CFG_PFCTRL, state->pfctrl); 248dbbd9e4bSmacallan DACCFG_WRITE(dac, FFBDAC_CFG_UCTRL, state->uctrl); 249dbbd9e4bSmacallan 250dbbd9e4bSmacallan nluts = (p->flags & FFB_DAC_PAC1) ? 256 : (4 * 256); 251dbbd9e4bSmacallan dac->cfg = FFBDAC_CFG_CLUP_BASE; 252dbbd9e4bSmacallan for (i = 0; i < nluts; i++) 253dbbd9e4bSmacallan dac->cfgdata = state->clut[i]; 254dbbd9e4bSmacallan 255dbbd9e4bSmacallan if (p->flags & FFB_DAC_PAC2) { 256dbbd9e4bSmacallan dac->cfg = FFBDAC_PAC2_AOVWLUT0; 257dbbd9e4bSmacallan for (i = 0; i < 4; i++) 258dbbd9e4bSmacallan dac->cfgdata = state->ovluts[i]; 259dbbd9e4bSmacallan } 260dbbd9e4bSmacallan 261dbbd9e4bSmacallan DACCFG_WRITE(dac, FFBDAC_CFG_WTCTRL, state->wtctrl); 262dbbd9e4bSmacallan DACCFG_WRITE(dac, FFBDAC_CFG_TMCTRL, state->tmctrl); 263dbbd9e4bSmacallan DACCFG_WRITE(dac, FFBDAC_CFG_TCOLORKEY, state->tcolorkey); 264dbbd9e4bSmacallan if (p->flags & FFB_DAC_PAC2) 265dbbd9e4bSmacallan DACCFG_WRITE(dac, FFBDAC_CFG_WAMASK, state->wamask); 266dbbd9e4bSmacallan 267dbbd9e4bSmacallan if (p->flags & FFB_DAC_PAC1) { 268dbbd9e4bSmacallan dac->cfg = FFBDAC_PAC1_APWLUT_BASE; 269dbbd9e4bSmacallan for (i = 0; i < 32; i++) 270dbbd9e4bSmacallan dac->cfgdata = state->pwluts[i]; 271dbbd9e4bSmacallan } else { 272dbbd9e4bSmacallan dac->cfg = FFBDAC_PAC2_APWLUT_BASE; 273dbbd9e4bSmacallan for (i = 0; i < 64; i++) 274dbbd9e4bSmacallan dac->cfgdata = state->pwluts[i]; 275dbbd9e4bSmacallan } 276dbbd9e4bSmacallan 277dbbd9e4bSmacallan DACCFG_WRITE(dac, FFBDAC_CFG_DACCTRL, state->dacctrl); 278dbbd9e4bSmacallan 279dbbd9e4bSmacallan /* Step 4: Restore FFB framebuffer config state. */ 280dbbd9e4bSmacallan if (pFfb->ffb_type == ffb2_vertical_plus || 281dbbd9e4bSmacallan pFfb->ffb_type == ffb2_horizontal_plus || 282dbbd9e4bSmacallan pFfb->ffb_type == afb_m3 || 283dbbd9e4bSmacallan pFfb->ffb_type == afb_m6) 284dbbd9e4bSmacallan ffb->passin = p->ffb_passin_ctrl; 285dbbd9e4bSmacallan ffb->fbcfg0 = p->ffbcfg0; 286dbbd9e4bSmacallan ffb->fbcfg2 = p->ffbcfg2; 287dbbd9e4bSmacallan 288dbbd9e4bSmacallan /* Step 5: Restore the timing generator control reg. */ 289dbbd9e4bSmacallan DACCFG_WRITE(dac, FFBDAC_CFG_TGEN, state->tgen); 290dbbd9e4bSmacallan 291dbbd9e4bSmacallan /* Step 6: Pause for a bit. */ 292dbbd9e4bSmacallan for (i = 0; i < 100; i++) 293dbbd9e4bSmacallan (void) DACCFG_READ(dac, FFBDAC_CFG_TGVC); 294dbbd9e4bSmacallan} 295dbbd9e4bSmacallan 296dbbd9e4bSmacallanstatic void 297dbbd9e4bSmacallandac_state_save(FFBPtr pFfb, ffb_dac_hwstate_t *state) 298dbbd9e4bSmacallan{ 299dbbd9e4bSmacallan ffb_dac_info_t *p = &pFfb->dac_info; 300dbbd9e4bSmacallan ffb_dacPtr dac = pFfb->dac; 301dbbd9e4bSmacallan int i, nluts; 302dbbd9e4bSmacallan 303dbbd9e4bSmacallan state->ppllctrl = DACCFG_READ(dac, FFBDAC_CFG_PPLLCTRL); 304dbbd9e4bSmacallan state->gpllctrl = DACCFG_READ(dac, FFBDAC_CFG_GPLLCTRL); 305dbbd9e4bSmacallan state->pfctrl = DACCFG_READ(dac, FFBDAC_CFG_PFCTRL); 306dbbd9e4bSmacallan state->uctrl = DACCFG_READ(dac, FFBDAC_CFG_UCTRL); 307dbbd9e4bSmacallan 308dbbd9e4bSmacallan nluts = (p->flags & FFB_DAC_PAC1) ? 256 : (4 * 256); 309dbbd9e4bSmacallan dac->cfg = FFBDAC_CFG_CLUP_BASE; 310dbbd9e4bSmacallan for (i = 0; i < nluts; i++) 311dbbd9e4bSmacallan state->clut[i] = dac->cfgdata; 312dbbd9e4bSmacallan 313dbbd9e4bSmacallan if (p->flags & FFB_DAC_PAC2) { 314dbbd9e4bSmacallan dac->cfg = FFBDAC_PAC2_AOVWLUT0; 315dbbd9e4bSmacallan for (i = 0; i < 4; i++) 316dbbd9e4bSmacallan state->ovluts[i] = dac->cfgdata; 317dbbd9e4bSmacallan } 318dbbd9e4bSmacallan 319dbbd9e4bSmacallan state->wtctrl = DACCFG_READ(dac, FFBDAC_CFG_WTCTRL); 320dbbd9e4bSmacallan state->tmctrl = DACCFG_READ(dac, FFBDAC_CFG_TMCTRL); 321dbbd9e4bSmacallan state->tcolorkey = DACCFG_READ(dac, FFBDAC_CFG_TCOLORKEY); 322dbbd9e4bSmacallan if (p->flags & FFB_DAC_PAC2) 323dbbd9e4bSmacallan state->wamask = DACCFG_READ(dac, FFBDAC_CFG_WAMASK); 324dbbd9e4bSmacallan 325dbbd9e4bSmacallan if (p->flags & FFB_DAC_PAC1) { 326dbbd9e4bSmacallan dac->cfg = FFBDAC_PAC1_APWLUT_BASE; 327dbbd9e4bSmacallan for (i = 0; i < 32; i++) 328dbbd9e4bSmacallan state->pwluts[i] = dac->cfgdata; 329dbbd9e4bSmacallan } else { 330dbbd9e4bSmacallan dac->cfg = FFBDAC_PAC2_APWLUT_BASE; 331dbbd9e4bSmacallan for (i = 0; i < 64; i++) 332dbbd9e4bSmacallan state->pwluts[i] = dac->cfgdata; 333dbbd9e4bSmacallan } 334dbbd9e4bSmacallan 335dbbd9e4bSmacallan state->dacctrl = DACCFG_READ(dac, FFBDAC_CFG_DACCTRL); 336dbbd9e4bSmacallan 337dbbd9e4bSmacallan state->tgen = DACCFG_READ(dac, FFBDAC_CFG_TGEN); 338dbbd9e4bSmacallan state->vbnp = DACCFG_READ(dac, FFBDAC_CFG_VBNP); 339dbbd9e4bSmacallan state->vbap = DACCFG_READ(dac, FFBDAC_CFG_VBAP); 340dbbd9e4bSmacallan state->vsnp = DACCFG_READ(dac, FFBDAC_CFG_VSNP); 341dbbd9e4bSmacallan state->vsap = DACCFG_READ(dac, FFBDAC_CFG_VSAP); 342dbbd9e4bSmacallan state->hsnp = DACCFG_READ(dac, FFBDAC_CFG_HSNP); 343dbbd9e4bSmacallan state->hbnp = DACCFG_READ(dac, FFBDAC_CFG_HBNP); 344dbbd9e4bSmacallan state->hbap = DACCFG_READ(dac, FFBDAC_CFG_HBAP); 345dbbd9e4bSmacallan state->hsyncnp = DACCFG_READ(dac, FFBDAC_CFG_HSYNCNP); 346dbbd9e4bSmacallan state->hsyncap = DACCFG_READ(dac, FFBDAC_CFG_HSYNCAP); 347dbbd9e4bSmacallan state->hscennp = DACCFG_READ(dac, FFBDAC_CFG_HSCENNP); 348dbbd9e4bSmacallan state->hscenap = DACCFG_READ(dac, FFBDAC_CFG_HSCENAP); 349dbbd9e4bSmacallan state->epnp = DACCFG_READ(dac, FFBDAC_CFG_EPNP); 350dbbd9e4bSmacallan state->einp = DACCFG_READ(dac, FFBDAC_CFG_EINP); 351dbbd9e4bSmacallan state->eiap = DACCFG_READ(dac, FFBDAC_CFG_EIAP); 352dbbd9e4bSmacallan} 353dbbd9e4bSmacallan 354dbbd9e4bSmacallanstatic void 355dbbd9e4bSmacallaninit_dac_flags(FFBPtr pFfb) 356dbbd9e4bSmacallan{ 357dbbd9e4bSmacallan ffb_dac_info_t *p = &pFfb->dac_info; 358dbbd9e4bSmacallan ffb_dacPtr dac = pFfb->dac; 359dbbd9e4bSmacallan unsigned int did, manuf_rev, partnum; 360dbbd9e4bSmacallan char *device; 361dbbd9e4bSmacallan 362dbbd9e4bSmacallan /* Fetch kernel WID. */ 363dbbd9e4bSmacallan p->kernel_wid = *((volatile unsigned char *)pFfb->dfb8x); 364dbbd9e4bSmacallan 365dbbd9e4bSmacallan /* For AFB, assume it is PAC2 which also implies not having 366dbbd9e4bSmacallan * the inverted cursor control attribute. 367dbbd9e4bSmacallan */ 368dbbd9e4bSmacallan if (pFfb->ffb_type == afb_m3 || pFfb->ffb_type == afb_m6) { 369dbbd9e4bSmacallan p->flags = FFB_DAC_PAC2; 370dbbd9e4bSmacallan manuf_rev = 4; 371dbbd9e4bSmacallan } else { 372dbbd9e4bSmacallan p->flags = 0; 373dbbd9e4bSmacallan 374dbbd9e4bSmacallan did = DACCFG_READ(dac, FFBDAC_CFG_DID); 375dbbd9e4bSmacallan 376dbbd9e4bSmacallan manuf_rev = DACCFG_READ(dac, FFBDAC_CFG_UCTRL); 377dbbd9e4bSmacallan manuf_rev = (manuf_rev & FFBDAC_UCTRL_MANREV) >> 8; 378dbbd9e4bSmacallan 379dbbd9e4bSmacallan partnum = ((did & FFBDAC_CFG_DID_PNUM) >> 12); 380dbbd9e4bSmacallan if (partnum == 0x236e) 381dbbd9e4bSmacallan p->flags |= FFB_DAC_PAC2; 382dbbd9e4bSmacallan else 383dbbd9e4bSmacallan p->flags |= FFB_DAC_PAC1; 384dbbd9e4bSmacallan } 385dbbd9e4bSmacallan 386dbbd9e4bSmacallan device = pFfb->psdp->device; 387dbbd9e4bSmacallan if ((p->flags & FFB_DAC_PAC1) != 0) { 388dbbd9e4bSmacallan if (manuf_rev < 3) { 389dbbd9e4bSmacallan p->flags |= FFB_DAC_ICURCTL; 390dbbd9e4bSmacallan xf86Msg(X_INFO, "%s: BT9068 (PAC1) ramdac detected (with " 391dbbd9e4bSmacallan "inverted cursor control)\n", device); 392dbbd9e4bSmacallan } else { 393dbbd9e4bSmacallan xf86Msg(X_INFO, "%s: BT9068 (PAC1) ramdac detected (with " 394dbbd9e4bSmacallan "normal cursor control)\n", device); 395dbbd9e4bSmacallan } 396dbbd9e4bSmacallan } else { 397dbbd9e4bSmacallan xf86Msg(X_INFO, "%s: BT498 (PAC2) ramdac detected\n", device); 398dbbd9e4bSmacallan } 399dbbd9e4bSmacallan} 400dbbd9e4bSmacallan 401dbbd9e4bSmacallan/* The registers of the chip must be mapped, and the FFB/AFB 402dbbd9e4bSmacallan * board type must be probed before this is invoked. 403dbbd9e4bSmacallan */ 404dbbd9e4bSmacallanBool 405dbbd9e4bSmacallanFFBDacInit(FFBPtr pFfb) 406dbbd9e4bSmacallan{ 407dbbd9e4bSmacallan ffb_dac_info_t *p = &pFfb->dac_info; 408dbbd9e4bSmacallan ffb_fbcPtr ffb = pFfb->regs; 409dbbd9e4bSmacallan 410dbbd9e4bSmacallan init_dac_flags(pFfb); 411dbbd9e4bSmacallan 412dbbd9e4bSmacallan p->ffbcfg0 = ffb->fbcfg0; 413dbbd9e4bSmacallan p->ffbcfg2 = ffb->fbcfg2; 414dbbd9e4bSmacallan if (pFfb->ffb_type == ffb2_vertical_plus || 415dbbd9e4bSmacallan pFfb->ffb_type == ffb2_horizontal_plus || 416dbbd9e4bSmacallan pFfb->ffb_type == afb_m3 || 417dbbd9e4bSmacallan pFfb->ffb_type == afb_m6) 418dbbd9e4bSmacallan p->ffb_passin_ctrl = ffb->passin; 419dbbd9e4bSmacallan 420dbbd9e4bSmacallan /* Save the kernel DAC state. We also save to the 421dbbd9e4bSmacallan * X server state here as well even though we have 422dbbd9e4bSmacallan * not modified anything yet. 423dbbd9e4bSmacallan */ 424dbbd9e4bSmacallan dac_state_save(pFfb, &p->kern_dac_state); 425dbbd9e4bSmacallan dac_state_save(pFfb, &p->x_dac_state); 426dbbd9e4bSmacallan 427dbbd9e4bSmacallan /* Fire up the WID layer. */ 428dbbd9e4bSmacallan FFBWidPoolInit(pFfb); 429dbbd9e4bSmacallan 430dbbd9e4bSmacallan return TRUE; 431dbbd9e4bSmacallan} 432dbbd9e4bSmacallan 433dbbd9e4bSmacallan/* We need to reset the A buffer X planes to the value 0xff 434dbbd9e4bSmacallan * when giving the hardware back to the kernel too, thus... 435dbbd9e4bSmacallan * Also need to do this for the B buffer X planes when double 436dbbd9e4bSmacallan * buffering is available. 437dbbd9e4bSmacallan */ 438dbbd9e4bSmacallanstatic void 439dbbd9e4bSmacallanrestore_kernel_xchannel(FFBPtr pFfb) 440dbbd9e4bSmacallan{ 441dbbd9e4bSmacallan ffb_fbcPtr ffb = pFfb->regs; 442dbbd9e4bSmacallan unsigned int fbc, ppc, ppc_mask, drawop, wid; 443dbbd9e4bSmacallan 444dbbd9e4bSmacallan wid = pFfb->dac_info.kernel_wid; 445dbbd9e4bSmacallan 446dbbd9e4bSmacallan if (pFfb->has_double_buffer) 447dbbd9e4bSmacallan fbc = FFB_FBC_WB_AB; 448dbbd9e4bSmacallan else 449dbbd9e4bSmacallan fbc = FFB_FBC_WB_A; 450dbbd9e4bSmacallan 451dbbd9e4bSmacallan fbc |= (FFB_FBC_WM_COMBINED | FFB_FBC_RB_A | FFB_FBC_SB_BOTH | 452dbbd9e4bSmacallan FFB_FBC_ZE_OFF | FFB_FBC_YE_OFF | 453dbbd9e4bSmacallan FFB_FBC_XE_ON | FFB_FBC_RGBE_MASK); 454dbbd9e4bSmacallan 455dbbd9e4bSmacallan ppc = (FFB_PPC_APE_DISABLE | FFB_PPC_CS_CONST | FFB_PPC_XS_WID); 456dbbd9e4bSmacallan ppc_mask = (FFB_PPC_APE_MASK | FFB_PPC_CS_MASK | FFB_PPC_XS_MASK); 457dbbd9e4bSmacallan 458dbbd9e4bSmacallan drawop = FFB_DRAWOP_RECTANGLE; 459dbbd9e4bSmacallan 460dbbd9e4bSmacallan FFB_ATTR_RAW(pFfb, ppc, ppc_mask, ~0, 461dbbd9e4bSmacallan (FFB_ROP_EDIT_BIT | GXcopy)|(FFB_ROP_NEW<<8), 462dbbd9e4bSmacallan drawop, 0x0, fbc, wid); 463dbbd9e4bSmacallan 464dbbd9e4bSmacallan FFBFifo(pFfb, 4); 465dbbd9e4bSmacallan FFB_WRITE64(&ffb->by, 0, 0); 466dbbd9e4bSmacallan FFB_WRITE64_2(&ffb->bh, pFfb->psdp->height, pFfb->psdp->width); 467dbbd9e4bSmacallan pFfb->rp_active = 1; 468dbbd9e4bSmacallan FFBWait(pFfb, ffb); 469dbbd9e4bSmacallan} 470dbbd9e4bSmacallan 471dbbd9e4bSmacallanvoid 472dbbd9e4bSmacallanFFBDacFini(FFBPtr pFfb) 473dbbd9e4bSmacallan{ 474dbbd9e4bSmacallan ffb_dac_info_t *p = &pFfb->dac_info; 475dbbd9e4bSmacallan 476dbbd9e4bSmacallan /* Just restore the kernel ramdac/x-channel state. */ 477dbbd9e4bSmacallan dac_state_restore(pFfb, &p->kern_dac_state); 478dbbd9e4bSmacallan restore_kernel_xchannel(pFfb); 479dbbd9e4bSmacallan} 480dbbd9e4bSmacallan 481dbbd9e4bSmacallan 482dbbd9e4bSmacallan/* Restore X server DAC state. */ 483dbbd9e4bSmacallanvoid 484dbbd9e4bSmacallanFFBDacEnterVT(FFBPtr pFfb) 485dbbd9e4bSmacallan{ 486dbbd9e4bSmacallan ffb_dac_info_t *p = &pFfb->dac_info; 487dbbd9e4bSmacallan 488dbbd9e4bSmacallan /* Save kernel DAC state. */ 489dbbd9e4bSmacallan dac_state_save(pFfb, &p->kern_dac_state); 490dbbd9e4bSmacallan 491dbbd9e4bSmacallan /* Restore X DAC state. */ 492dbbd9e4bSmacallan dac_state_restore(pFfb, &p->x_dac_state); 493dbbd9e4bSmacallan} 494dbbd9e4bSmacallan 495dbbd9e4bSmacallan/* Restore kernel DAC state. */ 496dbbd9e4bSmacallanvoid 497dbbd9e4bSmacallanFFBDacLeaveVT(FFBPtr pFfb) 498dbbd9e4bSmacallan{ 499dbbd9e4bSmacallan ffb_dac_info_t *p = &pFfb->dac_info; 500dbbd9e4bSmacallan 501dbbd9e4bSmacallan /* Save X DAC state. */ 502dbbd9e4bSmacallan dac_state_save(pFfb, &p->x_dac_state); 503dbbd9e4bSmacallan 504dbbd9e4bSmacallan /* Restore kernel DAC and x-channel state. */ 505dbbd9e4bSmacallan dac_state_restore(pFfb, &p->kern_dac_state); 506dbbd9e4bSmacallan restore_kernel_xchannel(pFfb); 507dbbd9e4bSmacallan} 508dbbd9e4bSmacallan 509dbbd9e4bSmacallan/* DPMS stuff, courtesy of a hint from David S. Miller. 510dbbd9e4bSmacallan * 05.xii.01, FEM 511dbbd9e4bSmacallan */ 512dbbd9e4bSmacallan 513dbbd9e4bSmacallan/* 514dbbd9e4bSmacallan * I don't know why, if at all, this is needed, but JJ or DSM do it 515dbbd9e4bSmacallan * on restore. I observe that when just blanking/unblanking, everything 516dbbd9e4bSmacallan * works fine without it, but that sometimes DPMS -> Standby actually 517dbbd9e4bSmacallan * results in Off. Maybe related? 518dbbd9e4bSmacallan */ 519dbbd9e4bSmacallanstatic void 520dbbd9e4bSmacallanSPIN(ffb_dacPtr d, int count) { 521dbbd9e4bSmacallan while(count-- > 0) { 522dbbd9e4bSmacallan (void) DACCFG_READ(d, FFBDAC_CFG_TGVC); 523dbbd9e4bSmacallan } 524dbbd9e4bSmacallan return; 525dbbd9e4bSmacallan} 526dbbd9e4bSmacallan 527dbbd9e4bSmacallan/* Screen save (blank) restore */ 528dbbd9e4bSmacallanBool 529ec319841SmacallanFFBDacSaveScreen(ScreenPtr pScreen, int mode) { 530ec319841Smacallan ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 531ec319841Smacallan FFBPtr pFfb = GET_FFB_FROM_SCRN(pScrn); 532dbbd9e4bSmacallan int tmp; 533dbbd9e4bSmacallan ffb_dacPtr dac; 534ec319841Smacallan Bool redraw = FALSE; 535ec319841Smacallan 536dbbd9e4bSmacallan if(!pFfb) return FALSE; /* Is there any way at all this could happen? */ 537dbbd9e4bSmacallan else dac = pFfb -> dac; 538dbbd9e4bSmacallan 539ec319841Smacallan /* 540ec319841Smacallan * there seems to be a bug in ffb1 hardware which causes screen corruption 541ec319841Smacallan * when (un)blanking - so we disable/enable screen access to cause a 542ec319841Smacallan * full redraw. 543ec319841Smacallan */ 544ec319841Smacallan 545dbbd9e4bSmacallan tmp = DACCFG_READ(dac, FFBDAC_CFG_TGEN); /* Get the timing information */ 546dbbd9e4bSmacallan 547dbbd9e4bSmacallan switch(mode) { 548dbbd9e4bSmacallan case SCREEN_SAVER_ON: 549dbbd9e4bSmacallan case SCREEN_SAVER_CYCLE: 550dbbd9e4bSmacallan tmp &= ~FFBDAC_CFG_TGEN_VIDE; /* Kill the video */ 551dbbd9e4bSmacallan break; 552dbbd9e4bSmacallan 553dbbd9e4bSmacallan case SCREEN_SAVER_OFF: 554dbbd9e4bSmacallan case SCREEN_SAVER_FORCER: 555dbbd9e4bSmacallan tmp |= FFBDAC_CFG_TGEN_VIDE; /* Turn the video on */ 556ec319841Smacallan if (pFfb->ffb_type < ffb2_prototype) 557ec319841Smacallan redraw = TRUE; 558dbbd9e4bSmacallan break; 559dbbd9e4bSmacallan 560dbbd9e4bSmacallan default: 561dbbd9e4bSmacallan return FALSE; /* Don't know what to do; gently fail. */ 562dbbd9e4bSmacallan } 563ec319841Smacallan /* Restore timing register, video set as asked */ 564ec319841Smacallan DACCFG_WRITE(dac, FFBDAC_CFG_TGEN, tmp); 565dbbd9e4bSmacallan SPIN(dac, DPMS_SPIN_COUNT/10); 566ec319841Smacallan 567ec319841Smacallan if (redraw) { 568ec319841Smacallan /* this causes a complete redraw of the screen */ 569f334040fSmrg#ifdef XF86_SCRN_INTERFACE // compat-api.h 570f334040fSmrg pScrn->EnableDisableFBAccess(pScrn, FALSE); 571f334040fSmrg pScrn->EnableDisableFBAccess(pScrn, TRUE); 572f334040fSmrg#else 573ec319841Smacallan pScrn->EnableDisableFBAccess(pScreen->myNum, FALSE); 574ec319841Smacallan pScrn->EnableDisableFBAccess(pScreen->myNum, TRUE); 575f334040fSmrg#endif 576ec319841Smacallan } 577dbbd9e4bSmacallan return TRUE; 578dbbd9e4bSmacallan} 579dbbd9e4bSmacallan 580dbbd9e4bSmacallan/* DPMS Control, also hinted at by David Miller. 581dbbd9e4bSmacallan 582dbbd9e4bSmacallan The rule seems to be: 583dbbd9e4bSmacallan 584dbbd9e4bSmacallan StandBy = -HSYNC +VSYNC -VIDEO 585dbbd9e4bSmacallan Suspend = +HSYNC -VSYNC -VIDEO 586dbbd9e4bSmacallan Off = -HSYNC -VSYNC -VIDEO 587dbbd9e4bSmacallan On = +HSYNC +VSINC +VIDEO 588dbbd9e4bSmacallan 589dbbd9e4bSmacallan If you don't force video off, someone periodically tries to turn the 590dbbd9e4bSmacallan monitor on for some reason. I don't know who or why, so I kill the video 591dbbd9e4bSmacallan when trying to go into some sort of energy saving mode. (In real life, 592dbbd9e4bSmacallan 'xset s blank s xx' could well have taken care of this.) 593dbbd9e4bSmacallan 594dbbd9e4bSmacallan Also, on MY monitor, StandBy as above defined (-H+V-Vid) in fact 595dbbd9e4bSmacallan gives the same as Off, which I don't want. Hence, I just do (-Vid) 596dbbd9e4bSmacallan 597dbbd9e4bSmacallan 05.xii.01, FEM 598dbbd9e4bSmacallan 08.xii.01, FEM 59971f5331dSjdc 60071f5331dSjdc Note, that the rule for "On" is not always correct. Some modes use 60171f5331dSjdc -VSYNC normally (see FFB3 VESA modes and some EDID modes). So, we 60271f5331dSjdc take the hsync and vsync values from the saved timing generator state 60371f5331dSjdc for "DPMSModeOn". 604dbbd9e4bSmacallan*/ 605dbbd9e4bSmacallanvoid 606dbbd9e4bSmacallanFFBDacDPMSMode(FFBPtr pFfb, int DPMSMode, int flags) { 607dbbd9e4bSmacallan int tmp; 60871f5331dSjdc ffb_dac_info_t *p = &pFfb->dac_info; 60971f5331dSjdc ffb_dac_hwstate_t *state = &p->x_dac_state; 610dbbd9e4bSmacallan ffb_dacPtr dac = pFfb -> dac; 611dbbd9e4bSmacallan 612dbbd9e4bSmacallan tmp = DACCFG_READ(dac, FFBDAC_CFG_TGEN); /* Get timing control */ 613dbbd9e4bSmacallan 614dbbd9e4bSmacallan switch(DPMSMode) { 615dbbd9e4bSmacallan 616dbbd9e4bSmacallan case DPMSModeOn: 61771f5331dSjdc tmp = state -> tgen; 618dbbd9e4bSmacallan tmp |= FFBDAC_CFG_TGEN_VIDE; /* Turn the video on */ 619dbbd9e4bSmacallan break; 620dbbd9e4bSmacallan 621dbbd9e4bSmacallan case DPMSModeStandby: 622dbbd9e4bSmacallan#ifdef DPMS_TRUE_STANDBY 623dbbd9e4bSmacallan tmp |= FFBDAC_CFG_TGEN_HSD; /* HSYNC = OFF */ 624dbbd9e4bSmacallan#endif /* DPMS_TRUE_STANDBY */ 625dbbd9e4bSmacallan tmp &= ~FFBDAC_CFG_TGEN_VSD; /* VSYNC = ON */ 626dbbd9e4bSmacallan tmp &= ~FFBDAC_CFG_TGEN_VIDE; /* Kill the video */ 627dbbd9e4bSmacallan break; 628dbbd9e4bSmacallan 629dbbd9e4bSmacallan case DPMSModeSuspend: 630dbbd9e4bSmacallan tmp |= FFBDAC_CFG_TGEN_VSD; /* VSYNC = OFF */ 631dbbd9e4bSmacallan tmp &= ~FFBDAC_CFG_TGEN_HSD; /* HSYNC = ON */ 632dbbd9e4bSmacallan tmp &= ~FFBDAC_CFG_TGEN_VIDE; /* Kill the video */ 633dbbd9e4bSmacallan break; 634dbbd9e4bSmacallan 635dbbd9e4bSmacallan case DPMSModeOff: 636dbbd9e4bSmacallan tmp |= (FFBDAC_CFG_TGEN_VSD | FFBDAC_CFG_TGEN_HSD); /* Kill HSYNC, VSYNC both */ 637dbbd9e4bSmacallan tmp &= ~FFBDAC_CFG_TGEN_VIDE; /* Kill the video */ 638dbbd9e4bSmacallan break; 639dbbd9e4bSmacallan 640dbbd9e4bSmacallan default: 641dbbd9e4bSmacallan return; /* If we get here, we really should log an error */ 642dbbd9e4bSmacallan } 643dbbd9e4bSmacallan DACCFG_WRITE(dac, FFBDAC_CFG_TGEN,tmp); /* Restore timing register, video set as asked */ 644dbbd9e4bSmacallan SPIN(dac, DPMS_SPIN_COUNT); /* Is this necessary? Why? */ 645dbbd9e4bSmacallan} 646