/* * $RCSId: xc/programs/Xserver/hw/kdrive/igs/igs.c,v 1.2 2000/05/24 23:52:47 keithp Exp $ * * Copyright © 1999 SuSE, Inc. * * 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 SuSE not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. SuSE makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE * 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. * * Author: Keith Packard, SuSE, Inc. */ #ifdef HAVE_CONFIG_H #include #endif #include "igs.h" Bool igsCardInit (KdCardInfo *card) { int k; char *pixels; IgsCardInfo *igsc; igsc = (IgsCardInfo *) xalloc (sizeof (IgsCardInfo)); if (!igsc) return FALSE; memset (igsc, '\0', sizeof (IgsCardInfo)); igsc->frameBuffer = (CARD8 *) KdMapDevice (card->attr.address[0] + IGS_FB, IGS_MEM); igsc->vga = (VOL8 *) KdMapDevice (card->attr.address[0] + IGS_VGA, 64 * 1024); igsc->cop = (Cop5xxx *) KdMapDevice (card->attr.address[0] + IGS_COP_OFFSET, sizeof (Cop5xxx)); igsc->copData = (VOL32 *) KdMapDevice (card->attr.address[0] + IGS_COP_DATA, IGS_COP_DATA_LEN); igsRegInit (&igsc->igsvga, igsc->vga); card->driver = igsc; return TRUE; } Bool igsModeSupported (KdScreenInfo *screen, const KdMonitorTiming *t) { /* make sure the clock isn't too fast */ if (t->clock > IGS_MAX_CLOCK) return FALSE; /* width must be a multiple of 16 */ if (t->horizontal & 0xf) return FALSE; return TRUE; } Bool igsModeUsable (KdScreenInfo *screen) { KdCardInfo *card = screen->card; int screen_size; int pixel_width; int byte_width; int fb = 0; screen_size = 0; if (screen->fb[fb].depth >= 24) { screen->fb[fb].depth = 24; if (screen->fb[fb].bitsPerPixel != 24) screen->fb[fb].bitsPerPixel = 32; } else if (screen->fb[fb].depth >= 16) { screen->fb[fb].depth = 16; screen->fb[fb].bitsPerPixel = 16; } else if (screen->fb[fb].depth >= 15) { screen->fb[fb].depth = 15; screen->fb[fb].bitsPerPixel = 16; } else if (screen->fb[fb].depth >= 12) { screen->fb[fb].depth = 12; screen->fb[fb].bitsPerPixel = 16; } else { screen->fb[fb].depth = 8; screen->fb[fb].bitsPerPixel = 8; } byte_width = screen->width * (screen->fb[fb].bitsPerPixel >> 3); pixel_width = screen->width; screen->fb[fb].pixelStride = pixel_width; screen->fb[fb].byteStride = byte_width; screen_size += byte_width * screen->height; return TRUE; } Bool igsScreenInit (KdScreenInfo *screen) { IgsCardInfo *igsc = screen->card->driver; int fb = 0; IgsScreenInfo *igss; int screen_size, memory; int pattern_size; int tile_size; int stipple_size; int poffset, boffset; const KdMonitorTiming *t; if (!screen->width || !screen->height) { screen->width = 800; screen->height = 600; screen->rate = 72; } if (!screen->fb[0].depth) screen->fb[0].depth = 8; t = KdFindMode (screen, igsModeSupported); screen->rate = t->rate; screen->width = t->horizontal; screen->height = t->vertical; if (!KdTuneMode (screen, igsModeUsable, igsModeSupported)) { return FALSE; } igss = (IgsScreenInfo *) xalloc (sizeof (IgsScreenInfo)); if (!igss) return FALSE; memset (igss, '\0', sizeof (IgsScreenInfo)); screen_size = screen->fb[fb].byteStride * screen->height; memory = IGS_MEM; memory -= screen_size; if (memory >= 1024) { igss->cursor_offset = memory - 1024; #if BITMAP_BIT_ORDER == MSBFirst igss->cursor_base = (CARD8 *) KdMapDevice (card->attr.address[0] + igss->cursor_offset, 1024); #else igss->cursor_base = igsc->frameBuffer + igss->cursor_offset; #endif memory -= 1024; } else igss->cursor_base = 0; tile_size = IgsTileSize(screen->fb[fb].bitsPerPixel) * IGS_NUM_PATTERN; stipple_size = IgsStippleSize(screen->fb[fb].bitsPerPixel) * IGS_NUM_PATTERN; pattern_size = tile_size + stipple_size; if (memory >= pattern_size) { boffset = screen_size; poffset = boffset * 8 / screen->fb[fb].bitsPerPixel; igss->tile.offset = poffset; igss->tile.base = igsc->frameBuffer + boffset; boffset = screen_size + tile_size; poffset = boffset * 8 / screen->fb[fb].bitsPerPixel; igss->stipple.offset = poffset; igss->stipple.base = igsc->frameBuffer + boffset; memory -= pattern_size; } else { igss->tile.base = 0; igss->stipple.base = 0; } switch (screen->fb[fb].depth) { case 8: screen->fb[fb].visuals = ((1 << StaticGray) | (1 << GrayScale) | (1 << StaticColor) | (1 << PseudoColor) | (1 << TrueColor) | (1 << DirectColor)); screen->fb[fb].blueMask = 0x00; screen->fb[fb].greenMask = 0x00; screen->fb[fb].redMask = 0x00; break; case 15: screen->fb[fb].visuals = (1 << TrueColor); screen->fb[fb].blueMask = 0x001f; screen->fb[fb].greenMask = 0x03e0; screen->fb[fb].redMask = 0x7c00; break; case 16: screen->fb[fb].visuals = (1 << TrueColor); screen->fb[fb].blueMask = 0x001f; screen->fb[fb].greenMask = 0x07e0; screen->fb[fb].redMask = 0xf800; break; case 24: screen->fb[fb].visuals = (1 << TrueColor); screen->fb[fb].blueMask = 0x0000ff; screen->fb[fb].greenMask = 0x00ff00; screen->fb[fb].redMask = 0xff0000; break; } screen->fb[fb].pixelStride = screen->width; screen->fb[fb].byteStride = screen->width * (screen->fb[fb].bitsPerPixel >> 3); screen->fb[fb].frameBuffer = igsc->frameBuffer; if (!igsc->cop) screen->dumb = TRUE; screen->driver = igss; return TRUE; } Bool igsInitScreen(ScreenPtr pScreen) { return TRUE; } void igsPreserve (KdCardInfo *card) { IgsCardInfo *igsc = card->driver; IgsVga *igsvga = &igsc->igsvga; igsSave (igsvga); } void igsSetBlank (IgsVga *igsvga, Bool blank) { igsSetImm(igsvga, igs_screen_off, blank ? 1 : 0); } void igsSetSync (IgsCardInfo *igsc, int hsync, int vsync) { IgsVga *igsvga = &igsc->igsvga; igsSet (igsvga, igs_mexhsyn, hsync); igsSet (igsvga, igs_mexvsyn, vsync); VgaFlush (&igsvga->card); } /* * Clock synthesis: * * scale = p ? (2 * p) : 1 * f_out = f_ref * ((M + 1) / ((N + 1) * scale)) * * Constraints: * * 1. 115MHz <= f_ref * ((M + 1) / (N + 1)) <= 260 MHz * 2. N >= 1 * * Vertical refresh rate = clock / ((hsize + hblank) * (vsize + vblank)) * Horizontal refresh rate = clock / (hsize + hblank) */ /* all in kHz */ void igsGetClock (int target, int *Mp, int *Np, int *Pp, int maxM, int maxN, int maxP, int minVco) { int M, N, P, bestM, bestN; int f_vco, f_out; int err, abserr, besterr; /* * Compute correct P value to keep VCO in range */ for (P = 0; P <= maxP; P++) { f_vco = target * IGS_SCALE(P); if (f_vco >= minVco) break; } /* M = f_out / f_ref * ((N + 1) * IGS_SCALE(P)); */ besterr = target; for (N = 1; N <= maxN; N++) { M = ((target * (N + 1) * IGS_SCALE(P) + (IGS_CLOCK_REF/2)) + IGS_CLOCK_REF/2) / IGS_CLOCK_REF - 1; if (0 <= M && M <= maxM) { f_out = IGS_CLOCK(M,N,P); err = target - f_out; if (err < 0) err = -err; if (err < besterr) { besterr = err; bestM = M; bestN = N; } } } *Mp = bestM; *Np = bestN; *Pp = P; } Bool igsEnable (ScreenPtr pScreen) { KdScreenPriv(pScreen); KdCardInfo *card = pScreenPriv->card; KdScreenInfo *screen = pScreenPriv->screen; IgsCardInfo *igsc = card->driver; IgsVga *igsvga = &igsc->igsvga; const KdMonitorTiming *t; int hactive, hblank, hfp, hbp; int vactive, vblank, vfp, vbp; int hsize; int fb = 0; int m, n, r; int h_total; int h_display_end; int h_blank_start; int h_blank_end; int h_sync_start; int h_sync_end; int h_screen_off; int v_total; int v_retrace_start; int v_retrace_end; int v_display_end; int v_blank_start; int v_blank_end; int offset; int num_fetch; int m_m, m_n, m_r; igsSetBlank (igsvga, TRUE); t = KdFindMode (screen, igsModeSupported); igsGetClock (t->clock, &m, &n, &r, 2047, 255, 7, IGS_MIN_VCO); /* * Set the chip so that 0x400000 is a big-endian frame buffer * with the correct byte swapping enabled */ igsSet (igsvga, igs_biga22force, 0); igsSet (igsvga, igs_biga22en, 1); igsSet (igsvga, igs_biga24en, 1); /* * Enable 8-bit DACs */ igsSet (igsvga, igs_rampwdn, 0); igsSet (igsvga, igs_dac6_8, 1); igsSet (igsvga, igs_dacpwdn, 0); /* * Set overscan to black */ igsSet (igsvga, igs_overscan_red, 0x00); igsSet (igsvga, igs_overscan_green, 0x00); igsSet (igsvga, igs_overscan_blue, 0x00); /* * Enable PCI retries */ igsSet (igsvga, igs_iow_retry, 1); igsSet (igsvga, igs_mw_retry, 1); igsSet (igsvga, igs_mr_retry, 1); igsSet (igsvga, igs_pci_burst_write, 1); igsSet (igsvga, igs_pci_burst_read, 1); /* * Set FIFO */ igsSet (igsvga, igs_memgopg, 1); igsSet (igsvga, igs_memr2wpg, 0); igsSet (igsvga, igs_crtff16, 0); igsSet (igsvga, igs_fifomust, 0xff); igsSet (igsvga, igs_fifogen, 0xff); /* * Enable CRT reg access */ igsSetImm (igsvga, igs_ena_vr_access, 1); igsSetImm (igsvga, igs_crt_protect, 0); hfp = t->hfp; hbp = t->hbp; hblank = t->hblank; hactive = t->horizontal; offset = screen->fb[0].byteStride; vfp = t->vfp; vbp = t->vbp; vblank = t->vblank; vactive = t->vertical; /* * Compute character lengths for horizontal timing values */ hactive = screen->width / 8; hblank /= 8; hfp /= 8; hbp /= 8; offset /= 8; switch (screen->fb[fb].bitsPerPixel) { case 8: igsSet (igsvga, igs_overscan_red, pScreen->blackPixel); igsSet (igsvga, igs_overscan_green, pScreen->blackPixel); igsSet (igsvga, igs_overscan_blue, pScreen->blackPixel); igsSet (igsvga, igs_bigswap, IGS_BIGSWAP_8); igsSet (igsvga, igs_mode_sel, IGS_MODE_8); igsSet (igsvga, igs_ramdacbypass, 0); break; case 16: igsSet (igsvga, igs_bigswap, IGS_BIGSWAP_16); igsSet (igsvga, igs_ramdacbypass, 1); switch (screen->fb[fb].depth) { case 12: igsSet (igsvga, igs_mode_sel, IGS_MODE_4444); break; case 15: igsSet (igsvga, igs_mode_sel, IGS_MODE_5551); break; case 16: igsSet (igsvga, igs_mode_sel, IGS_MODE_565); break; } break; case 24: igsSet (igsvga, igs_ramdacbypass, 1); igsSet (igsvga, igs_bigswap, IGS_BIGSWAP_8); igsSet (igsvga, igs_mode_sel, IGS_MODE_888); break; case 32: igsSet (igsvga, igs_ramdacbypass, 1); igsSet (igsvga, igs_bigswap, IGS_BIGSWAP_32); igsSet (igsvga, igs_mode_sel, IGS_MODE_8888); break; } /* * Compute horizontal register values from timings */ h_total = hactive + hblank - 5; h_display_end = hactive - 1; h_sync_start = hactive + hfp; h_sync_end = hactive + hblank - hbp; /* * pad the blank values narrow a bit and use the border_select to * eliminate the remaining border; don't know why, but it doesn't * work in the documented fashion */ h_blank_start = hactive - 1; h_blank_end = hactive + hblank - 1 - 1; num_fetch = (t->horizontal * screen->fb[fb].bitsPerPixel / 64) + 1; v_total = vactive + vblank - 2; v_display_end = vactive - 1; v_blank_start = vactive - 1; v_blank_end = v_blank_start + vblank - 1; v_retrace_start = vactive + vfp; v_retrace_end = vactive + vblank - vbp; #if 0 #define chk(a,b,c) fprintf (stderr, "%20.20s: BIOS %6d X %6d\n", a, igsGet(igsvga, b), c); chk("h_total", igs_h_total, h_total); chk("h_display_end", igs_h_de_end, h_display_end); chk("h_sync_start", igs_h_rstart, h_sync_start); chk("h_sync_end", igs_h_rend, h_sync_end&0x1f); chk("h_blank_start", igs_h_bstart, h_blank_start); chk("h_blank_end", igs_h_bend, h_blank_end&0x3f); chk("offset", igs_offset, offset); chk("num_fetch", igs_num_fetch, num_fetch); chk("v_total", igs_v_total, v_total); chk("v_display_end", igs_v_de_end, v_display_end); chk("v_blank_start", igs_v_bstart, v_blank_start); chk("v_blank_end", igs_v_bend, v_blank_end&0xf); chk("v_retrace_start", igs_v_rstart, v_retrace_start); chk("v_retrace_end", igs_v_rend, v_retrace_end&0xf); chk("vclk_m", igs_vclk_m, m); chk("vclk_n", igs_vclk_n, n); chk("vclk_p", igs_vclk_p, r); fprintf (stderr, "%20.20s: BIOS %6d X %6d\n", "vclk", IGS_CLOCK(igsGet(igsvga,igs_vclk_m), igsGet(igsvga,igs_vclk_n), igsGet(igsvga,igs_vclk_p)), IGS_CLOCK(m,n,r)); #endif igsSet (igsvga, igs_h_total, h_total); igsSet (igsvga, igs_h_de_end, h_display_end); igsSet (igsvga, igs_h_rstart, h_sync_start); igsSet (igsvga, igs_h_rend, h_sync_end); igsSet (igsvga, igs_h_bstart, h_blank_start); igsSet (igsvga, igs_h_bend, h_blank_end); igsSet (igsvga, igs_offset, offset); igsSet (igsvga, igs_num_fetch, num_fetch); igsSet (igsvga, igs_v_total, v_total); igsSet (igsvga, igs_v_de_end, v_display_end); igsSet (igsvga, igs_v_bstart, v_blank_start); igsSet (igsvga, igs_v_bend, v_blank_end&0xf); igsSet (igsvga, igs_v_rstart, v_retrace_start); igsSet (igsvga, igs_v_rend, v_retrace_end&0xf); igsSet (igsvga, igs_vclk_m, m); igsSet (igsvga, igs_vclk_n, n); igsSet (igsvga, igs_vclk_p, r); igsSet (igsvga, igs_vfsel, IGS_CLOCK(m, n, 0) >= 180000); VgaFlush (&igsvga->card); igsSetImm (igsvga, igs_frqlat, 0); igsSetImm (igsvga, igs_frqlat, 1); igsSetImm (igsvga, igs_frqlat, 0); igsSetBlank (igsvga, FALSE); #if 0 #define dbg(a,b) fprintf(stderr, "%20.20s = 0x%x\n", a, igsGet(igsvga,b)) #include "reg.dbg" { VGA16 reg; char buf[128]; for (reg = 0; reg < IGS_NREG; reg++) fprintf(stderr, "%20.20s = 0x%02x\n", igsRegName(buf, reg), VgaFetch (&igsvga->card, reg)); } #endif return TRUE; } Bool igsDPMS (ScreenPtr pScreen, int mode) { KdScreenPriv(pScreen); IgsCardInfo *igsc = pScreenPriv->card->driver; IgsVga *igsvga = &igsc->igsvga; switch (mode) { case KD_DPMS_NORMAL: igsSetSync (igsc, 0, 0); igsSetBlank (igsvga, FALSE); break; case KD_DPMS_STANDBY: igsSetBlank (igsvga, TRUE); igsSetSync (igsc, 1, 0); break; case KD_DPMS_SUSPEND: igsSetBlank (igsvga, TRUE); igsSetSync (igsc, 0, 1); break; case KD_DPMS_POWERDOWN: igsSetBlank (igsvga, TRUE); igsSetSync (igsc, 1, 1); break; } return TRUE; } void igsDisable (ScreenPtr pScreen) { } void igsRestore (KdCardInfo *card) { IgsCardInfo *igsc = card->driver; IgsVga *igsvga = &igsc->igsvga; igsReset (igsvga); } void igsScreenFini (KdScreenInfo *screen) { IgsScreenInfo *igss = (IgsScreenInfo *) screen->driver; #if BITMAP_BIT_ORDER == MSBFirst if (igss->cursor_base) KdUnmapDevice ((void *) igss->cursor_base, 1024); #endif xfree (igss); screen->driver = 0; } void igsCardFini (KdCardInfo *card) { IgsCardInfo *igsc = card->driver; if (igsc->copData) KdUnmapDevice ((void *) igsc->copData, IGS_COP_DATA_LEN); if (igsc->cop) KdUnmapDevice ((void *) igsc->cop, sizeof (Cop5xxx)); if (igsc->vga) KdUnmapDevice ((void *) igsc->vga, 64 * 1024); if (igsc->frameBuffer) KdUnmapDevice (igsc->frameBuffer, IGS_MEM); xfree (igsc); card->driver = 0; } KdCardFuncs igsFuncs = { igsCardInit, /* cardinit */ igsScreenInit, /* scrinit */ igsInitScreen, igsPreserve, /* preserve */ igsEnable, /* enable */ igsDPMS, /* dpms */ igsDisable, /* disable */ igsRestore, /* restore */ igsScreenFini, /* scrfini */ igsCardFini, /* cardfini */ igsCursorInit, /* initCursor */ igsCursorEnable, /* enableCursor */ igsCursorDisable, /* disableCursor */ igsCursorFini, /* finiCursor */ 0, /* recolorCursor */ igsDrawInit, /* initAccel */ igsDrawEnable, /* enableAccel */ igsDrawSync, /* drawSync */ igsDrawDisable, /* disableAccel */ igsDrawFini, /* finiAccel */ igsGetColors, /* getColors */ igsPutColors, /* putColors */ };