i128IBMDAC.c revision a73423d7
150806d53Smrg/* 250806d53Smrg * Copyright 1996-2000 by Robin Cutshaw <robin@XFree86.Org> 350806d53Smrg * 450806d53Smrg * Permission to use, copy, modify, distribute, and sell this software and its 550806d53Smrg * documentation for any purpose is hereby granted without fee, provided that 650806d53Smrg * the above copyright notice appear in all copies and that both that 750806d53Smrg * copyright notice and this permission notice appear in supporting 850806d53Smrg * documentation, and that the name of Robin Cutshaw not be used in 950806d53Smrg * advertising or publicity pertaining to distribution of the software without 1050806d53Smrg * specific, written prior permission. Robin Cutshaw makes no representations 1150806d53Smrg * about the suitability of this software for any purpose. It is provided 1250806d53Smrg * "as is" without express or implied warranty. 1350806d53Smrg * 1450806d53Smrg * ROBIN CUTSHAW DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 1550806d53Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 1650806d53Smrg * EVENT SHALL ROBIN CUTSHAW BE LIABLE FOR ANY SPECIAL, INDIRECT OR 1750806d53Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 1850806d53Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 1950806d53Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 2050806d53Smrg * PERFORMANCE OF THIS SOFTWARE. 2150806d53Smrg * 2250806d53Smrg */ 2350806d53Smrg 2450806d53Smrg 2550806d53Smrg#ifdef HAVE_CONFIG_H 2650806d53Smrg#include "config.h" 2750806d53Smrg#endif 2850806d53Smrg 2950806d53Smrg#include "xf86.h" 3050806d53Smrg#include "xf86PciInfo.h" 3150806d53Smrg#include "xf86Pci.h" 3250806d53Smrg#include "cursorstr.h" 3350806d53Smrg#include "servermd.h" 3450806d53Smrg 3550806d53Smrg#include "i128.h" 3650806d53Smrg#include "i128reg.h" 3750806d53Smrg#include "IBMRGB.h" 3850806d53Smrg 397965d9acSmrg#include <unistd.h> 4050806d53Smrg 4150806d53Smrgstatic void I128IBMShowCursor(ScrnInfoPtr pScrn); 4250806d53Smrgstatic void I128IBMHideCursor(ScrnInfoPtr pScrn); 4350806d53Smrgstatic void I128IBMSetCursorPosition(ScrnInfoPtr pScrn, int x, int y); 4450806d53Smrgstatic void I128IBMSetCursorColors(ScrnInfoPtr pScrn, int bg, int fg); 4550806d53Smrgstatic void I128IBMLoadCursorImage(ScrnInfoPtr pScrn, unsigned char *src); 4650806d53Smrgstatic Bool I128IBMUseHWCursor(ScreenPtr pScrn, CursorPtr pCurs); 4750806d53Smrg 4850806d53Smrg 4950806d53SmrgBool 5050806d53SmrgI128IBMHWCursorInit(ScrnInfoPtr pScrn) 5150806d53Smrg{ 5250806d53Smrg xf86CursorInfoPtr infoPtr; 53a73423d7Smrg ScreenPtr pScreen = xf86ScrnToScreen(pScrn); 5450806d53Smrg I128Ptr pI128 = I128PTR(pScrn); 5550806d53Smrg 5650806d53Smrg if (!pI128->HWCursor) 5750806d53Smrg return FALSE; 5850806d53Smrg 5950806d53Smrg infoPtr = xf86CreateCursorInfoRec(); 6050806d53Smrg if (!infoPtr) return FALSE; 6150806d53Smrg 6250806d53Smrg pI128->CursorInfoRec = infoPtr; 6350806d53Smrg infoPtr->MaxWidth = 64; 6450806d53Smrg infoPtr->MaxHeight = 64; 6550806d53Smrg infoPtr->SetCursorColors = I128IBMSetCursorColors; 6650806d53Smrg infoPtr->SetCursorPosition = I128IBMSetCursorPosition; 6750806d53Smrg infoPtr->LoadCursorImage = I128IBMLoadCursorImage; 6850806d53Smrg infoPtr->HideCursor = I128IBMHideCursor; 6950806d53Smrg infoPtr->ShowCursor = I128IBMShowCursor; 7050806d53Smrg infoPtr->UseHWCursor = I128IBMUseHWCursor; 7150806d53Smrg infoPtr->Flags = HARDWARE_CURSOR_TRUECOLOR_AT_8BPP | 7250806d53Smrg HARDWARE_CURSOR_AND_SOURCE_WITH_MASK | 7350806d53Smrg HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1; 7450806d53Smrg 75af1a9c97Smrg#if X_BYTE_ORDER == X_BIG_ENDIAN 76af1a9c97Smrg infoPtr->Flags |= HARDWARE_CURSOR_NIBBLE_SWAPPED; 77af1a9c97Smrg#endif 7850806d53Smrg 79af1a9c97Smrg return(xf86InitCursor(pScreen, infoPtr)); 8050806d53Smrg} 8150806d53Smrg 8250806d53Smrg 8350806d53Smrgstatic void 8450806d53SmrgI128IBMShowCursor(ScrnInfoPtr pScrn) 8550806d53Smrg{ 8650806d53Smrg CARD32 tmpl, tmph; 8750806d53Smrg I128Ptr pI128 = I128PTR(pScrn); 8850806d53Smrg 8950806d53Smrg /* Enable cursor - X11 mode */ 9050806d53Smrg tmpl = pI128->mem.rbase_g[IDXL_I] & 0xFF; 9150806d53Smrg tmph = pI128->mem.rbase_g[IDXH_I] & 0xFF; 9250806d53Smrg pI128->mem.rbase_g[IDXCTL_I] = 0; MB; 9350806d53Smrg pI128->mem.rbase_g[IDXH_I] = 0; MB; 9450806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs; MB; 9550806d53Smrg pI128->mem.rbase_g[DATA_I] = 0x27; MB; 9650806d53Smrg 9750806d53Smrg pI128->mem.rbase_g[IDXH_I] = tmph; MB; 9850806d53Smrg pI128->mem.rbase_g[IDXL_I] = tmpl; MB; 9950806d53Smrg 10050806d53Smrg return; 10150806d53Smrg} 10250806d53Smrg 10350806d53Smrgstatic void 10450806d53SmrgI128IBMHideCursor(ScrnInfoPtr pScrn) 10550806d53Smrg{ 10650806d53Smrg CARD32 tmpl, tmph, tmp1; 10750806d53Smrg I128Ptr pI128 = I128PTR(pScrn); 10850806d53Smrg 10950806d53Smrg tmpl = pI128->mem.rbase_g[IDXL_I] & 0xFF; 11050806d53Smrg tmph = pI128->mem.rbase_g[IDXH_I] & 0xFF; 11150806d53Smrg pI128->mem.rbase_g[IDXCTL_I] = 0; MB; 11250806d53Smrg pI128->mem.rbase_g[IDXH_I] = 0; MB; 11350806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs; MB; 11450806d53Smrg tmp1 = pI128->mem.rbase_g[DATA_I] & 0xFC; 11550806d53Smrg pI128->mem.rbase_g[DATA_I] = tmp1; MB; 11650806d53Smrg 11750806d53Smrg pI128->mem.rbase_g[IDXH_I] = tmph; MB; 11850806d53Smrg pI128->mem.rbase_g[IDXL_I] = tmpl; MB; 11950806d53Smrg 12050806d53Smrg return; 12150806d53Smrg} 12250806d53Smrg 12350806d53Smrgstatic void 12450806d53SmrgI128IBMSetCursorPosition(ScrnInfoPtr pScrn, int x, int y) 12550806d53Smrg{ 12650806d53Smrg CARD32 tmpl, tmph; 12750806d53Smrg I128Ptr pI128 = I128PTR(pScrn); 12850806d53Smrg 12950806d53Smrg x += 64; 13050806d53Smrg y += 64; 13150806d53Smrg 13250806d53Smrg tmpl = pI128->mem.rbase_g[IDXL_I] & 0xFF; 13350806d53Smrg tmph = pI128->mem.rbase_g[IDXH_I] & 0xFF; 13450806d53Smrg 13550806d53Smrg pI128->mem.rbase_g[IDXH_I] = 0; MB; 13650806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_hot_x; MB; 13750806d53Smrg pI128->mem.rbase_g[DATA_I] = 0x3F; MB; 13850806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_hot_y; MB; 13950806d53Smrg pI128->mem.rbase_g[DATA_I] = 0x3F; MB; 14050806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_xl; MB; 14150806d53Smrg pI128->mem.rbase_g[DATA_I] = x & 0xFF; MB; 14250806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_xh; MB; 14350806d53Smrg pI128->mem.rbase_g[DATA_I] = (x >> 8) & 0x0F; MB; 14450806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_yl; MB; 14550806d53Smrg pI128->mem.rbase_g[DATA_I] = y & 0xFF; MB; 14650806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_yh; MB; 14750806d53Smrg pI128->mem.rbase_g[DATA_I] = (y >> 8) & 0x0F; MB; 14850806d53Smrg 14950806d53Smrg pI128->mem.rbase_g[IDXH_I] = tmph; MB; 15050806d53Smrg pI128->mem.rbase_g[IDXL_I] = tmpl; MB; 15150806d53Smrg 15250806d53Smrg return; 15350806d53Smrg} 15450806d53Smrg 15550806d53Smrgstatic void 15650806d53SmrgI128IBMSetCursorColors(ScrnInfoPtr pScrn, int bg, int fg) 15750806d53Smrg{ 15850806d53Smrg CARD32 tmp; 15950806d53Smrg I128Ptr pI128 = I128PTR(pScrn); 16050806d53Smrg 16150806d53Smrg tmp = pI128->mem.rbase_g[IDXL_I] & 0xFF; 16250806d53Smrg 16350806d53Smrg /* Background color */ 16450806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_col1_r; MB; 16550806d53Smrg pI128->mem.rbase_g[DATA_I] = (bg & 0x00FF0000) >> 16; MB; 16650806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_col1_g; MB; 16750806d53Smrg pI128->mem.rbase_g[DATA_I] = (bg & 0x0000FF00) >> 8; MB; 16850806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_col1_b; MB; 16950806d53Smrg pI128->mem.rbase_g[DATA_I] = (bg & 0x000000FF); MB; 17050806d53Smrg 17150806d53Smrg /* Foreground color */ 17250806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_col2_r; MB; 17350806d53Smrg pI128->mem.rbase_g[DATA_I] = (fg & 0x00FF0000) >> 16; MB; 17450806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_col2_g; MB; 17550806d53Smrg pI128->mem.rbase_g[DATA_I] = (fg & 0x0000FF00) >> 8; MB; 17650806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_col2_b; MB; 17750806d53Smrg pI128->mem.rbase_g[DATA_I] = (fg & 0x000000FF); MB; 17850806d53Smrg 17950806d53Smrg pI128->mem.rbase_g[IDXL_I] = tmp; MB; 18050806d53Smrg 18150806d53Smrg return; 18250806d53Smrg} 18350806d53Smrg 18450806d53Smrgstatic void 18550806d53SmrgI128IBMLoadCursorImage(ScrnInfoPtr pScrn, unsigned char *src) 18650806d53Smrg{ 18750806d53Smrg I128Ptr pI128 = I128PTR(pScrn); 18850806d53Smrg register int i; 18950806d53Smrg CARD32 tmph, tmpl, tmpc; 19050806d53Smrg 19150806d53Smrg tmpc = pI128->mem.rbase_g[IDXCTL_I] & 0xFF; 19250806d53Smrg tmph = pI128->mem.rbase_g[IDXH_I] & 0xFF; 19350806d53Smrg tmpl = pI128->mem.rbase_g[IDXL_I] & 0xFF; 19450806d53Smrg 19550806d53Smrg pI128->BlockCursor = TRUE; 19650806d53Smrg 19750806d53Smrg pI128->mem.rbase_g[IDXCTL_I] = 0; MB; 19850806d53Smrg 19950806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_hot_x; MB; 20050806d53Smrg pI128->mem.rbase_g[DATA_I] = 0x00; MB; 20150806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_hot_y; MB; 20250806d53Smrg pI128->mem.rbase_g[DATA_I] = 0x00; MB; 20350806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_xl; MB; 20450806d53Smrg pI128->mem.rbase_g[DATA_I] = 0xFF; MB; 20550806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_xh; MB; 20650806d53Smrg pI128->mem.rbase_g[DATA_I] = 0x7F; MB; 20750806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_yl; MB; 20850806d53Smrg pI128->mem.rbase_g[DATA_I] = 0xFF; MB; 20950806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_yh; MB; 21050806d53Smrg pI128->mem.rbase_g[DATA_I] = 0x7F; MB; 21150806d53Smrg 21250806d53Smrg pI128->mem.rbase_g[IDXH_I] = (IBMRGB_curs_array >> 8) & 0xFF; MB; 21350806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_curs_array & 0xFF; MB; 21450806d53Smrg 21550806d53Smrg pI128->mem.rbase_g[IDXCTL_I] = 1; /* enable auto-inc */ MB; 21650806d53Smrg 21750806d53Smrg /* 21850806d53Smrg * Output the cursor data. The realize function has put the planes into 21950806d53Smrg * their correct order, so we can just blast this out. 22050806d53Smrg */ 22150806d53Smrg for (i = 0; i < 1024; i++,src++) { 22250806d53Smrg pI128->mem.rbase_g[DATA_I] = (CARD32 )*src; MB; 22350806d53Smrg } 22450806d53Smrg 22550806d53Smrg pI128->mem.rbase_g[IDXCTL_I] = tmpc; MB; 22650806d53Smrg pI128->mem.rbase_g[IDXH_I] = tmph; MB; 22750806d53Smrg pI128->mem.rbase_g[IDXL_I] = tmpl; MB; 22850806d53Smrg 22950806d53Smrg pI128->BlockCursor = FALSE; 23050806d53Smrg 23150806d53Smrg return; 23250806d53Smrg} 23350806d53Smrg 23450806d53Smrg 23550806d53Smrgstatic Bool 23650806d53SmrgI128IBMUseHWCursor(ScreenPtr pScrn, CursorPtr pCurs) 23750806d53Smrg{ 23850806d53Smrg if( XF86SCRNINFO(pScrn)->currentMode->Flags & V_DBLSCAN ) 23950806d53Smrg return FALSE; 24050806d53Smrg return TRUE; 24150806d53Smrg} 24250806d53Smrg 24350806d53Smrg 24450806d53SmrgBool I128TIHWCursorInit(ScrnInfoPtr pScrn) { return FALSE; } 24550806d53SmrgBool I128ProgramTi3025(ScrnInfoPtr pScrn, DisplayModePtr mode) { return FALSE; } 24650806d53Smrg 24750806d53SmrgBool 24850806d53SmrgI128ProgramIBMRGB(ScrnInfoPtr pScrn, DisplayModePtr mode) 24950806d53Smrg{ 25050806d53Smrg I128Ptr pI128 = I128PTR(pScrn); 25150806d53Smrg unsigned char tmp2, m, n, df, best_m, best_n, best_df, max_n; 25250806d53Smrg CARD32 tmpl, tmph, tmpc; 25350806d53Smrg long f, vrf, outf, best_diff, best_outf = 0, diff; 25450806d53Smrg long requested_freq; 25550806d53Smrg int freq = mode->SynthClock; 25650806d53Smrg int flags = mode->Flags; 25750806d53Smrg 25850806d53Smrg#define REF_FREQ 25175000 25950806d53Smrg#define MAX_VREF 3380000 26050806d53Smrg/* Actually, MIN_VREF can be as low as 1000000; 26150806d53Smrg * this allows clock speeds down to 17 MHz */ 26250806d53Smrg#define MIN_VREF 1500000 26350806d53Smrg#define MAX_VCO 220000000 26450806d53Smrg#define MIN_VCO 65000000 26550806d53Smrg 26650806d53Smrg if (freq < 25000) { 26750806d53Smrg xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 26850806d53Smrg "Specified dot clock (%.3f) too low for IBM RGB52x", 26950806d53Smrg freq / 1000.0); 27050806d53Smrg return(FALSE); 27150806d53Smrg } else if (freq > MAX_VCO) { 27250806d53Smrg xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 27350806d53Smrg "Specified dot clock (%.3f) too high for IBM RGB52x", 27450806d53Smrg freq / 1000.0); 27550806d53Smrg return(FALSE); 27650806d53Smrg } 27750806d53Smrg 27850806d53Smrg requested_freq = freq * 1000; 27950806d53Smrg 28050806d53Smrg best_m = best_n = best_df = 0; 28150806d53Smrg best_diff = requested_freq; /* worst case */ 28250806d53Smrg 28350806d53Smrg for (df=0; df<4; df++) { 28450806d53Smrg max_n = REF_FREQ / MIN_VREF; 28550806d53Smrg if (df < 3) 28650806d53Smrg max_n >>= 1; 28750806d53Smrg for (n=2; n<max_n; n++) 28850806d53Smrg for (m=65; m<=128; m++) { 28950806d53Smrg vrf = REF_FREQ / n; 29050806d53Smrg if (df < 3) 29150806d53Smrg vrf >>= 1; 29250806d53Smrg if ((vrf > MAX_VREF) || (vrf < MIN_VREF)) 29350806d53Smrg continue; 29450806d53Smrg 29550806d53Smrg f = vrf * m; 29650806d53Smrg outf = f; 29750806d53Smrg if (df < 2) 29850806d53Smrg outf >>= 2 - df; 29950806d53Smrg if ((f > MAX_VCO) || (f < MIN_VCO)) 30050806d53Smrg continue; 30150806d53Smrg 30250806d53Smrg /* outf is a valid freq, pick the closest now */ 30350806d53Smrg 30450806d53Smrg if ((diff = (requested_freq - outf)) < 0) 30550806d53Smrg diff = -diff;; 30650806d53Smrg if (diff < best_diff) { 30750806d53Smrg best_diff = diff; 30850806d53Smrg best_m = m; 30950806d53Smrg best_n = n; 31050806d53Smrg best_df = df; 31150806d53Smrg best_outf = outf; 31250806d53Smrg } 31350806d53Smrg } 31450806d53Smrg } 31550806d53Smrg 31650806d53Smrg /* do we have an acceptably close frequency? (less than 1% diff) */ 31750806d53Smrg 31850806d53Smrg if (best_diff > (requested_freq/100)) { 31950806d53Smrg xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 32050806d53Smrg "Specified dot clock (%.3f) too far (best %.3f) IBM RGB52x", 32150806d53Smrg requested_freq / 1000.0, best_outf / 1000.0); 32250806d53Smrg return(FALSE); 32350806d53Smrg } 32450806d53Smrg 32550806d53Smrg pI128->mem.rbase_g[PEL_MASK] = 0xFF; MB; 32650806d53Smrg 32750806d53Smrg tmpc = pI128->mem.rbase_g[IDXCTL_I] & 0xFF; 32850806d53Smrg tmph = pI128->mem.rbase_g[IDXH_I] & 0xFF; 32950806d53Smrg tmpl = pI128->mem.rbase_g[IDXL_I] & 0xFF; 33050806d53Smrg 33150806d53Smrg pI128->mem.rbase_g[IDXH_I] = 0; MB; 33250806d53Smrg pI128->mem.rbase_g[IDXCTL_I] = 0; MB; 33350806d53Smrg 33450806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_misc_clock; MB; 33550806d53Smrg tmp2 = pI128->mem.rbase_g[DATA_I] & 0xFF; 33650806d53Smrg pI128->mem.rbase_g[DATA_I] = tmp2 | 0x81; MB; 33750806d53Smrg 33850806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_m0+4; MB; 33950806d53Smrg pI128->mem.rbase_g[DATA_I] = (best_df<<6) | (best_m&0x3f); MB; 34050806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_n0+4; MB; 34150806d53Smrg pI128->mem.rbase_g[DATA_I] = best_n; MB; 34250806d53Smrg 34350806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_pll_ctrl1; MB; 34450806d53Smrg tmp2 = pI128->mem.rbase_g[DATA_I] & 0xFF; 34550806d53Smrg pI128->mem.rbase_g[DATA_I] = (tmp2&0xf8) | 3; /* 8 M/N pairs in PLL */ MB; 34650806d53Smrg 34750806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_pll_ctrl2; MB; 34850806d53Smrg tmp2 = pI128->mem.rbase_g[DATA_I] & 0xFF; 34950806d53Smrg pI128->mem.rbase_g[DATA_I] = (tmp2&0xf0) | 2; /* clock number 2 */ MB; 35050806d53Smrg 35150806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_misc_clock; MB; 35250806d53Smrg tmp2 = pI128->mem.rbase_g[DATA_I] & 0xf0; 35350806d53Smrg pI128->mem.rbase_g[DATA_I] = tmp2 | ((flags & V_DBLCLK) ? 0x03 : 0x01); MB; 35450806d53Smrg 35550806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_sync; MB; 35650806d53Smrg pI128->mem.rbase_g[DATA_I] = ((flags & V_PHSYNC) ? 0x10 : 0x00) 35750806d53Smrg | ((flags & V_PVSYNC) ? 0x20 : 0x00); MB; 35850806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_hsync_pos; MB; 35950806d53Smrg pI128->mem.rbase_g[DATA_I] = 0x01; /* Delay syncs by 1 pclock */ MB; 36050806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_pwr_mgmt; MB; 36150806d53Smrg pI128->mem.rbase_g[DATA_I] = 0x00; MB; 36250806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_dac_op; MB; 36350806d53Smrg tmp2 = (pI128->RamdacType == IBM528_DAC) ? 0x02 : 0x00; /* fast slew */ 36450806d53Smrg if (pI128->DACSyncOnGreen) tmp2 |= 0x08; 36550806d53Smrg pI128->mem.rbase_g[DATA_I] = tmp2; MB; 36650806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_pal_ctrl; MB; 36750806d53Smrg pI128->mem.rbase_g[DATA_I] = 0x00; MB; 36850806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_sysclk; MB; 36950806d53Smrg pI128->mem.rbase_g[DATA_I] = 0x01; MB; 37050806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_misc1; MB; 37150806d53Smrg tmp2 = pI128->mem.rbase_g[DATA_I] & 0xbc; 37250806d53Smrg tmp2 |= 0x20; 37350806d53Smrg if ((pI128->MemoryType != I128_MEMORY_DRAM) && 37450806d53Smrg (pI128->MemoryType != I128_MEMORY_SGRAM)) 37550806d53Smrg tmp2 |= (pI128->RamdacType == IBM528_DAC) ? 3 : 1; 37650806d53Smrg pI128->mem.rbase_g[DATA_I] = tmp2; MB; 37750806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_misc2; MB; 37850806d53Smrg tmp2 = 0x03; 37950806d53Smrg if (pI128->DAC8Bit) 38050806d53Smrg tmp2 |= 0x04; 38150806d53Smrg if (!((pI128->MemoryType == I128_MEMORY_DRAM) && 38250806d53Smrg (pI128->bitsPerPixel > 16))) 38350806d53Smrg tmp2 |= 0x40; 38450806d53Smrg if ((pI128->MemoryType == I128_MEMORY_SGRAM) && 38550806d53Smrg (pI128->bitsPerPixel > 16) && 38650806d53Smrg (pI128->RamdacType != SILVER_HAMMER_DAC) ) 38750806d53Smrg tmp2 &= 0x3F; 38850806d53Smrg pI128->mem.rbase_g[DATA_I] = tmp2; MB; 38950806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_misc3; MB; 39050806d53Smrg pI128->mem.rbase_g[DATA_I] = 0x00; MB; 39150806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_misc4; MB; 39250806d53Smrg pI128->mem.rbase_g[DATA_I] = 0x00; MB; 39350806d53Smrg 39450806d53Smrg /* ?? There is no write to cursor control register */ 39550806d53Smrg 39650806d53Smrg if (pI128->RamdacType == IBM526_DAC) { 39750806d53Smrg if (pI128->MemoryType == I128_MEMORY_SGRAM) { 39850806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_sysclk_ref_div; MB; 39950806d53Smrg pI128->mem.rbase_g[DATA_I] = 0x09; MB; 40050806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_sysclk_vco_div; MB; 40150806d53Smrg pI128->mem.rbase_g[DATA_I] = 0x83; MB; 40250806d53Smrg } else { 40350806d53Smrg /* program mclock to 52MHz */ 40450806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_sysclk_ref_div; MB; 40550806d53Smrg pI128->mem.rbase_g[DATA_I] = 0x08; MB; 40650806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_sysclk_vco_div; MB; 40750806d53Smrg pI128->mem.rbase_g[DATA_I] = 0x41; MB; 40850806d53Smrg } 40950806d53Smrg /* should delay at least a millisec so we'll wait 50 */ 41050806d53Smrg usleep(50000); 41150806d53Smrg } 41250806d53Smrg 41350806d53Smrg switch (pI128->depth) { 41450806d53Smrg case 24: /* 32 bit */ 41550806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_pix_fmt; MB; 41650806d53Smrg tmp2 = pI128->mem.rbase_g[DATA_I] & 0xf8; 41750806d53Smrg pI128->mem.rbase_g[DATA_I] = tmp2 | 0x06; MB; 41850806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_32bpp; MB; 41950806d53Smrg pI128->mem.rbase_g[DATA_I] = 0x03; MB; 42050806d53Smrg break; 42150806d53Smrg case 16: 42250806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_pix_fmt; MB; 42350806d53Smrg tmp2 = pI128->mem.rbase_g[DATA_I] & 0xf8; 42450806d53Smrg pI128->mem.rbase_g[DATA_I] = tmp2 | 0x04; MB; 42550806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_16bpp; MB; 42650806d53Smrg pI128->mem.rbase_g[DATA_I] = 0xC7; MB; 42750806d53Smrg break; 42850806d53Smrg case 15: 42950806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_pix_fmt; MB; 43050806d53Smrg tmp2 = pI128->mem.rbase_g[DATA_I] & 0xf8; 43150806d53Smrg pI128->mem.rbase_g[DATA_I] = tmp2 | 0x04; MB; 43250806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_16bpp; MB; 43350806d53Smrg pI128->mem.rbase_g[DATA_I] = 0xC5; MB; 43450806d53Smrg break; 43550806d53Smrg default: /* 8 bit */ 43650806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_pix_fmt; MB; 43750806d53Smrg tmp2 = pI128->mem.rbase_g[DATA_I] & 0xf8; 43850806d53Smrg pI128->mem.rbase_g[DATA_I] = tmp2 | 0x03; MB; 43950806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_8bpp; MB; 44050806d53Smrg pI128->mem.rbase_g[DATA_I] = 0x00; MB; 44150806d53Smrg break; 44250806d53Smrg } 44350806d53Smrg 44450806d53Smrg pI128->mem.rbase_g[IDXCTL_I] = tmpc; MB; 44550806d53Smrg pI128->mem.rbase_g[IDXH_I] = tmph; MB; 44650806d53Smrg pI128->mem.rbase_g[IDXL_I] = tmpl; MB; 44750806d53Smrg 44850806d53Smrg return(TRUE); 44950806d53Smrg} 45050806d53Smrg 45150806d53Smrg 45250806d53SmrgBool 45350806d53SmrgI128ProgramSilverHammer(ScrnInfoPtr pScrn, DisplayModePtr mode) 45450806d53Smrg{ 45550806d53Smrg /* The SilverHammer DAC is essentially the same as the IBMRGBxxx DACs, 45650806d53Smrg * but with fewer options and a different reference frequency. 45750806d53Smrg */ 45850806d53Smrg 45950806d53Smrg I128Ptr pI128 = I128PTR(pScrn); 46050806d53Smrg unsigned char tmp2, m, n, df, best_m, best_n, best_df, max_n; 46150806d53Smrg CARD32 tmpl, tmph, tmpc; 46250806d53Smrg long f, vrf, outf, best_diff, best_outf = 0, diff; 46350806d53Smrg long requested_freq; 46450806d53Smrg int freq = mode->SynthClock; 46550806d53Smrg int flags = mode->Flags; 46650806d53Smrg int skew = mode->HSkew; 46750806d53Smrg 46850806d53Smrg#undef REF_FREQ 46950806d53Smrg#define REF_FREQ 37500000 47050806d53Smrg#undef MAX_VREF 47150806d53Smrg#define MAX_VREF 9000000 47250806d53Smrg#define MIN_VREF 1500000 47350806d53Smrg#undef MAX_VCO 47450806d53Smrg#define MAX_VCO 270000000 47550806d53Smrg#define MIN_VCO 65000000 47650806d53Smrg 47750806d53Smrg if (freq < 25000) { 47850806d53Smrg xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 47950806d53Smrg "Specified dot clock (%.3f) too low for SilverHammer", 48050806d53Smrg freq / 1000.0); 48150806d53Smrg return(FALSE); 48250806d53Smrg } else if (freq > MAX_VCO) { 48350806d53Smrg xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 48450806d53Smrg "Specified dot clock (%.3f) too high for SilverHammer", 48550806d53Smrg freq / 1000.0); 48650806d53Smrg return(FALSE); 48750806d53Smrg } 48850806d53Smrg 48950806d53Smrg requested_freq = freq * 1000; 49050806d53Smrg 49150806d53Smrg best_m = best_n = best_df = 0; 49250806d53Smrg best_diff = requested_freq; /* worst case */ 49350806d53Smrg 49450806d53Smrg for (df=0; df<4; df++) { 49550806d53Smrg max_n = REF_FREQ / MIN_VREF; 49650806d53Smrg if (df < 3) 49750806d53Smrg max_n >>= 1; 49850806d53Smrg for (n=2; n<max_n; n++) 49950806d53Smrg for (m=65; m<=128; m++) { 50050806d53Smrg vrf = REF_FREQ / n; 50150806d53Smrg if (df < 3) 50250806d53Smrg vrf >>= 1; 50350806d53Smrg if ((vrf > MAX_VREF) || (vrf < MIN_VREF)) 50450806d53Smrg continue; 50550806d53Smrg 50650806d53Smrg f = vrf * m; 50750806d53Smrg outf = f; 50850806d53Smrg if (df < 2) 50950806d53Smrg outf >>= 2 - df; 51050806d53Smrg if ((f > MAX_VCO) || (f < MIN_VCO)) 51150806d53Smrg continue; 51250806d53Smrg 51350806d53Smrg /* outf is a valid freq, pick the closest now */ 51450806d53Smrg 51550806d53Smrg if ((diff = (requested_freq - outf)) < 0) 51650806d53Smrg diff = -diff;; 51750806d53Smrg if (diff < best_diff) { 51850806d53Smrg best_diff = diff; 51950806d53Smrg best_m = m; 52050806d53Smrg best_n = n; 52150806d53Smrg best_df = df; 52250806d53Smrg best_outf = outf; 52350806d53Smrg } 52450806d53Smrg } 52550806d53Smrg } 52650806d53Smrg 52750806d53Smrg /* do we have an acceptably close frequency? (less than 1% diff) */ 52850806d53Smrg 52950806d53Smrg if (best_diff > (requested_freq/100)) { 53050806d53Smrg xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 53150806d53Smrg "Specified dot clock (%.3f) too far (best %.3f) SilverHammer", 53250806d53Smrg requested_freq / 1000.0, best_outf / 1000.0); 53350806d53Smrg return(FALSE); 53450806d53Smrg } 53550806d53Smrg 53650806d53Smrg pI128->mem.rbase_g[PEL_MASK] = 0xFF; MB; 53750806d53Smrg 53850806d53Smrg tmpc = pI128->mem.rbase_g[IDXCTL_I] & 0xFF; 53950806d53Smrg tmph = pI128->mem.rbase_g[IDXH_I] & 0xFF; 54050806d53Smrg tmpl = pI128->mem.rbase_g[IDXL_I] & 0xFF; 54150806d53Smrg 54250806d53Smrg pI128->mem.rbase_g[IDXH_I] = 0; MB; 54350806d53Smrg pI128->mem.rbase_g[IDXCTL_I] = 0; MB; 54450806d53Smrg 54550806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_misc_clock; MB; 54650806d53Smrg tmp2 = pI128->mem.rbase_g[DATA_I] & 0xFF; 54750806d53Smrg pI128->mem.rbase_g[DATA_I] = tmp2 | 0x81; MB; 54850806d53Smrg 54950806d53Smrg if (!pI128->Primary) { 55050806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_m0; MB; 55150806d53Smrg pI128->mem.rbase_g[DATA_I] = 0x15; MB; 55250806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_m0+1; MB; 55350806d53Smrg pI128->mem.rbase_g[DATA_I] = 0x10; MB; 55450806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_m0+2; MB; 55550806d53Smrg pI128->mem.rbase_g[DATA_I] = 0x2c; MB; 55650806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_m0+3; MB; 55750806d53Smrg pI128->mem.rbase_g[DATA_I] = 0x12; MB; 55850806d53Smrg } 55950806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_m0+4; MB; 56050806d53Smrg pI128->mem.rbase_g[DATA_I] = (best_df<<6) | (best_m&0x3f); MB; 56150806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_n0+4; MB; 56250806d53Smrg pI128->mem.rbase_g[DATA_I] = best_n; MB; 56350806d53Smrg 56450806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_pll_ctrl1; MB; 56550806d53Smrg tmp2 = pI128->mem.rbase_g[DATA_I] & 0xFF; 56650806d53Smrg pI128->mem.rbase_g[DATA_I] = (tmp2&0xf8) | 3; /* 8 M/N pairs in PLL */ MB; 56750806d53Smrg 56850806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_pll_ctrl2; MB; 56950806d53Smrg tmp2 = pI128->mem.rbase_g[DATA_I] & 0xFF; 57050806d53Smrg pI128->mem.rbase_g[DATA_I] = (tmp2&0xf0) | 2; /* clock number 2 */ MB; 57150806d53Smrg 57250806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_misc_clock; MB; 57350806d53Smrg tmp2 = pI128->mem.rbase_g[DATA_I] & 0xf0; 57450806d53Smrg pI128->mem.rbase_g[DATA_I] = tmp2 | ((flags & V_DBLCLK) ? 0x03 : 0x01); MB; 57550806d53Smrg 57650806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_sync; MB; 57750806d53Smrg pI128->mem.rbase_g[DATA_I] = ((flags & V_PHSYNC) ? 0x10 : 0x00) 57850806d53Smrg | ((flags & V_PVSYNC) ? 0x20 : 0x00); MB; 57950806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_hsync_pos; MB; 58050806d53Smrg pI128->mem.rbase_g[DATA_I] = ((flags & V_HSKEW) ? skew : 0x01); MB; 58150806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_pwr_mgmt; MB; 58250806d53Smrg/* Use 0x01 below with digital flat panel to conserve energy and reduce noise */ 58350806d53Smrg pI128->mem.rbase_g[DATA_I] = (pI128->FlatPanel ? 0x01 : 0x00); MB; 58450806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_dac_op; MB; 58550806d53Smrg pI128->mem.rbase_g[DATA_I] = (pI128->DACSyncOnGreen ? 0x08 : 0x00); MB; 58650806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_pal_ctrl; MB; 58750806d53Smrg pI128->mem.rbase_g[DATA_I] = 0x00; MB; 58850806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_sysclk; MB; 58950806d53Smrg pI128->mem.rbase_g[DATA_I] = 0x01; MB; 59050806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_misc1; MB; 59150806d53Smrg tmp2 = pI128->mem.rbase_g[DATA_I] & 0xbc; 59250806d53Smrg if ((pI128->MemoryType != I128_MEMORY_DRAM) && 59350806d53Smrg (pI128->MemoryType != I128_MEMORY_SGRAM)) 59450806d53Smrg tmp2 |= (pI128->RamdacType == IBM528_DAC) ? 3 : 1; 59550806d53Smrg pI128->mem.rbase_g[DATA_I] = tmp2; MB; 59650806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_misc2; MB; 59750806d53Smrg tmp2 = 0x03; 59850806d53Smrg if (pI128->DAC8Bit) 59950806d53Smrg tmp2 |= 0x04; 60050806d53Smrg if (!((pI128->MemoryType == I128_MEMORY_DRAM) && 60150806d53Smrg (pI128->bitsPerPixel > 16))) 60250806d53Smrg tmp2 |= 0x40; 60350806d53Smrg if ((pI128->MemoryType == I128_MEMORY_SGRAM) && 60450806d53Smrg (pI128->bitsPerPixel > 16) && 60550806d53Smrg (pI128->RamdacType != SILVER_HAMMER_DAC) ) 60650806d53Smrg tmp2 &= 0x3F; 60750806d53Smrg pI128->mem.rbase_g[DATA_I] = tmp2; MB; 60850806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_misc3; MB; 60950806d53Smrg pI128->mem.rbase_g[DATA_I] = 0x00; MB; 61050806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_misc4; MB; 61150806d53Smrg pI128->mem.rbase_g[DATA_I] = 0x00; MB; 61250806d53Smrg 61350806d53Smrg /* ?? There is no write to cursor control register */ 61450806d53Smrg 61550806d53Smrg /* Set the memory clock speed to 95 MHz */ 61650806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_sysclk_ref_div; MB; 61750806d53Smrg pI128->mem.rbase_g[DATA_I] = 0x08; MB; 61850806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_sysclk_vco_div; MB; 61950806d53Smrg pI128->mem.rbase_g[DATA_I] = 0x50; MB; 62050806d53Smrg 62150806d53Smrg /* should delay at least a millisec so we'll wait 50 */ 62250806d53Smrg usleep(50000); 62350806d53Smrg 62450806d53Smrg switch (pI128->depth) { 62550806d53Smrg case 24: /* 32 bit */ 62650806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_pix_fmt; MB; 62750806d53Smrg tmp2 = pI128->mem.rbase_g[DATA_I] & 0xf8; 62850806d53Smrg pI128->mem.rbase_g[DATA_I] = tmp2 | 0x06; MB; 62950806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_32bpp; MB; 63050806d53Smrg pI128->mem.rbase_g[DATA_I] = 0x03; MB; 63150806d53Smrg break; 63250806d53Smrg case 16: 63350806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_pix_fmt; MB; 63450806d53Smrg tmp2 = pI128->mem.rbase_g[DATA_I] & 0xf8; 63550806d53Smrg pI128->mem.rbase_g[DATA_I] = tmp2 | 0x04; MB; 63650806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_16bpp; MB; 63750806d53Smrg pI128->mem.rbase_g[DATA_I] = 0xC7; MB; 63850806d53Smrg break; 63950806d53Smrg case 15: 64050806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_pix_fmt; MB; 64150806d53Smrg tmp2 = pI128->mem.rbase_g[DATA_I] & 0xf8; 64250806d53Smrg pI128->mem.rbase_g[DATA_I] = tmp2 | 0x04; MB; 64350806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_16bpp; MB; 64450806d53Smrg pI128->mem.rbase_g[DATA_I] = 0xC5; MB; 64550806d53Smrg break; 64650806d53Smrg default: /* 8 bit */ 64750806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_pix_fmt; MB; 64850806d53Smrg tmp2 = pI128->mem.rbase_g[DATA_I] & 0xf8; 64950806d53Smrg pI128->mem.rbase_g[DATA_I] = tmp2 | 0x03; MB; 65050806d53Smrg pI128->mem.rbase_g[IDXL_I] = IBMRGB_8bpp; MB; 65150806d53Smrg pI128->mem.rbase_g[DATA_I] = 0x00; MB; 65250806d53Smrg break; 65350806d53Smrg } 65450806d53Smrg 65550806d53Smrg pI128->mem.rbase_g[IDXCTL_I] = tmpc; MB; 65650806d53Smrg pI128->mem.rbase_g[IDXH_I] = tmph; MB; 65750806d53Smrg pI128->mem.rbase_g[IDXL_I] = tmpl; MB; 65850806d53Smrg 65950806d53Smrg return(TRUE); 66050806d53Smrg} 661