diff options
author | Kaleb Keithley <kaleb@freedesktop.org> | 2003-11-14 16:48:55 +0000 |
---|---|---|
committer | Kaleb Keithley <kaleb@freedesktop.org> | 2003-11-14 16:48:55 +0000 |
commit | 3ad0d9a73bc0a4f3edb858d5f3a7c36827b7a429 (patch) | |
tree | c6951ce1ecfa6a5887b0b7b69f338268bf123786 |
Initial revisionXORG-STABLE
-rw-r--r-- | README.sgml | 127 | ||||
-rw-r--r-- | man/i810.man | 74 | ||||
-rw-r--r-- | src/common.h | 327 | ||||
-rw-r--r-- | src/i810.h | 324 | ||||
-rw-r--r-- | src/i810_accel.c | 662 | ||||
-rw-r--r-- | src/i810_common.h | 188 | ||||
-rw-r--r-- | src/i810_cursor.c | 202 | ||||
-rw-r--r-- | src/i810_dga.c | 293 | ||||
-rw-r--r-- | src/i810_dri.c | 1220 | ||||
-rw-r--r-- | src/i810_dri.h | 122 | ||||
-rw-r--r-- | src/i810_driver.c | 2397 | ||||
-rw-r--r-- | src/i810_hwmc.c | 417 | ||||
-rw-r--r-- | src/i810_io.c | 144 | ||||
-rw-r--r-- | src/i810_memory.c | 399 | ||||
-rw-r--r-- | src/i810_reg.h | 992 | ||||
-rw-r--r-- | src/i810_video.c | 1399 | ||||
-rw-r--r-- | src/i810_wmark.c | 321 | ||||
-rw-r--r-- | src/i830.h | 395 | ||||
-rw-r--r-- | src/i830_accel.c | 770 | ||||
-rw-r--r-- | src/i830_common.h | 288 | ||||
-rw-r--r-- | src/i830_cursor.c | 281 | ||||
-rw-r--r-- | src/i830_dga.c | 293 | ||||
-rw-r--r-- | src/i830_dri.c | 1664 | ||||
-rw-r--r-- | src/i830_dri.h | 146 | ||||
-rw-r--r-- | src/i830_driver.c | 3586 | ||||
-rw-r--r-- | src/i830_memory.c | 1458 | ||||
-rw-r--r-- | src/i830_video.c | 1840 | ||||
-rw-r--r-- | src/xvmc/I810XvMC.c | 4507 | ||||
-rw-r--r-- | src/xvmc/I810XvMC.h | 469 |
29 files changed, 25305 insertions, 0 deletions
diff --git a/README.sgml b/README.sgml new file mode 100644 index 00000000..575989f6 --- /dev/null +++ b/README.sgml @@ -0,0 +1,127 @@ +<!DOCTYPE linuxdoc PUBLIC "-//XFree86//DTD linuxdoc//EN" [ +<!ENTITY % defs SYSTEM "defs.ent"> %defs; +]> + +<article> +<title>Information for i810 Users +<author>Precision Insight, Inc. +<date>3 March 2000 +<ident> +$XFree86: xc/programs/Xserver/hw/xfree86/doc/sgml/i810.sgml,v 1.3 2001/04/04 01:34:18 dawes Exp $ +</ident> +<toc> + +<sect>Supported Hardware +<p> +<itemize> + <item>Intel 810 motherboards: + <itemize> + <item>i810, + <item>i810-dc100, + <item>i810e + <item>i815 + </itemize> +</itemize> + + +<sect>Features +<p> +<itemize> + <item>Full support for 8, 15, 16, and 24 bit pixel depths. + <item>Hardware cursor support to reduce sprite flicker. + <item>Hardware accelerated 2D drawing engine support for 8, 15, 16 and + 24 bit pixel depths. + <item>Support for high resolution video modes up to 1600x1200. + <item>Fully programmable clock supported. + <item>Robust text mode restore for VT switching. +</itemize> + + +<sect>Technical Notes +<p> +<itemize> + <item>Hardware acceleration is not possible when using the framebuffer + in 32 bit per pixel format, and this mode is not supported by + this driver. + <item>Interlace modes cannot be supported. + <item>This driver currently only works for Linux/ix86 and recent versions + of FreeBSD. It requires the agpgart kernel support, which is + included in Linux kernels 2.3.42 and higher, and FreeBSD 4.1 + and higher. +</itemize> + + +<sect>Reported Working Video Cards +<p> +<itemize> + <item>Intel evaluation hardware - i810, i810-dc100, i810e and i815. + <item>Tyan Tomcat Motherboard. + <item>HappyPC set-top box. +</itemize> + + +<sect>Configuration +<p> +The driver auto-detects all device information necessary to +initialize the card. The only lines you need in the "Device" +section of your XF86Config file are: +<verb> + Section "Device" + Identifier "Intel i810" + Driver "i810" + EndSection +</verb> +or let <tt>xf86config</tt> do this for you. + +However, if you have problems with auto-detection, you can specify: +<itemize> + <item>DacSpeed - in MHz + <item>MemBase - physical address of the linear framebuffer + <item>IOBase - physical address of the memory mapped IO registers +</itemize> + +In order to use most resolutions, it is necessary to install the +'agpgart.o' module. You will probably have to compile the module yourself +(see the notes in the module). + +Note: the i810 driver detects whether your motherboard has display cache +video memory. This memory is has reduced bandwidth compared to normal +system memory, and isn't used by the server. The main function of this +memory is for ancillary buffers (eg. z buffer) in a forthcoming 3d +capable server. + + +<sect>Driver Options +<p> +<itemize> + <item>"NoAccel" - Turn off hardware acceleration + <item>"SWCursor" - Request a software cursor (hardware is default) + <item>"Dac6Bit" - Force the use of a 6 Bit Dac (8 Bit is the default) +</itemize> + +<sect>Known Limitations +<p> +<itemize> + <item>No 3D support in this release. + <item>Running two X servers on different VTs is not supported at this time. +</itemize> + + +<sect>Author +<p> +<itemize> + <item>Keith Whitwell +</itemize> + +This driver was donated to The XFree86 Project by: +<verb> + Precision Insight, Inc. + Cedar Park, TX + USA +</verb> + +<htmlurl name="http://www.precisioninsight.com" + url="http://www.precisioninsight.com"> + + +</article> diff --git a/man/i810.man b/man/i810.man new file mode 100644 index 00000000..b10e6421 --- /dev/null +++ b/man/i810.man @@ -0,0 +1,74 @@ +.\" $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i810/i810.man,v 1.3 2003/02/17 19:19:02 dawes Exp $ +.\" shorthand for double quote that works everywhere. +.ds q \N'34' +.TH I810 __drivermansuffix__ __vendorversion__ +.SH NAME +i810 \- Intel 8xx integrated graphics chipsets +.SH SYNOPSIS +.nf +.B "Section \*qDevice\*q" +.BI " Identifier \*q" devname \*q +.B " Driver \*qi810\*q" +\ \ ... +.B EndSection +.fi +.SH DESCRIPTION +.B i810 +is an XFree86 driver for Intel integrated graphics chipsets. +The driver supports depths 8, 15, 16 and 24. All visual types are +supported in depth 8, other depths only support TrueColor. The driver +supports hardware accelerated 3D via the Direct Rendering Infrastructure (DRI), +but only in depth 16 for the i810/i815 and depths 16 and 24 for later chipsets. +.SH SUPPORTED HARDWARE +.B i810 +supports the i810, i810-DC100, i810e, i815, 830M, 845G, 852GM, 855GM, +and 865G chipsets. + +.SH CONFIGURATION DETAILS +Please refer to XF86Config(__filemansuffix__) for general configuration +details. This section only covers configuration details specific to this +driver. +.PP +The Intel 8xx family of integrated graphics chipsets has a unified memory +architecture and uses system memory for video ram. By default 8 Megabytes +of system memory are used for graphics. For the 830M and later, the +default is 8 Megabytes when DRI is not enabled and 32 Megabytes with +DRI is enabled. This amount may be changed with the +.B VideoRam +entry in the config file +.B "Device" +section. It may be set to any reasonable value up to 64MB for older +chipsets or 128MB for newer chipets. Note that increasing this value +will reduce the amount of system memory available for other applications. +.PP +The following driver +.B Options +are supported +.TP +.BI "Option \*qNoAccel\*q \*q" boolean \*q +Disable or enable acceleration. Default: acceleration is enabled. +.TP +.BI "Option \*qSWCursor\*q \*q" boolean \*q +Disable or enable software cursor. Default: software cursor is disable +and a hardware cursor is used. +.TP +.BI "Option \*qColorKey\*q \*q" integer \*q +This sets the default pixel value for the YUV video overlay key. +Default: undefined. +.TP +.BI "Option \*qCacheLines\*q \*q" integer \*q +This allows the user to change the amount of graphics memory used for +2D acceleration and video. Decreasing this amount leaves more for 3D +textures. Increasing it can improve 2D performance at the expense of +3D performance. +Default: 256 to 768 depending on the resolution and depth. + + + +.SH "SEE ALSO" +XFree86(1), XF86Config(__filemansuffix__), xf86config(1), Xserver(1), X(__miscmansuffix__) +.SH AUTHORS +Authors include: Keith Whitwell, and also Jonathan Bian, Matthew J Sottek, +Jeff Hartmann, Mark Vojkovich, Alan Hourihane, H. J. Lu. 830M and 845G +support reworked for XFree86 4.3 by David Dawes and Keith Whitwell. +852GM, 855GM, and 865G support added by David Dawes and Keith Whitwell. diff --git a/src/common.h b/src/common.h new file mode 100644 index 00000000..5e71cad8 --- /dev/null +++ b/src/common.h @@ -0,0 +1,327 @@ + +/************************************************************************** + +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +Copyright © 2002 David Dawes + +All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sub license, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice (including the +next paragraph) shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i810/common.h,v 1.6 2003/02/06 04:18:04 dawes Exp $ */ + +/* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + * David Dawes <dawes@tungstengraphics.com> + * + */ + +#ifndef _INTEL_COMMON_H_ +#define _INTEL_COMMON_H_ + +#ifdef __GNUC__ +#define PFX __FILE__,__LINE__,__FUNCTION__ +#define FUNCTION_NAME __FUNCTION__ +#else +#define PFX __FILE__,__LINE__,"" +#define FUNCTION_NAME "" +#endif + +#ifdef I830DEBUG +#define MARKER() ErrorF("\n### %s:%d: >>> %s <<< ###\n\n", \ + __FILE__, __LINE__,__FUNCTION__) +#define DPRINTF I830DPRINTF_stub +#else /* #ifdef I830DEBUG */ +#define MARKER() +/* this is a real ugly hack to get the compiler to optimize the debugging statements into oblivion */ +#define DPRINTF if(0) I830DPRINTF_stub +#endif /* #ifdef I830DEBUG */ + +#define KB(x) ((x) * 1024) +#define MB(x) ((x) * KB(1024)) + +/* Using usleep() makes things noticably slow. */ +#if 0 +#define DELAY(x) usleep(x) +#else +#define DELAY(x) do {;} while (0) +#endif + +/* I830 hooks for the I810 driver setup/probe. */ +extern const OptionInfoRec *I830BIOSAvailableOptions(int chipid, int busid); +extern void I830InitpScrn(ScrnInfoPtr pScrn); + +/* Symbol lists shared by the i810 and i830 parts. */ +extern const char *I810vgahwSymbols[]; +extern const char *I810ramdacSymbols[]; +extern const char *I810int10Symbols[]; +extern const char *I810vbeSymbols[]; +extern const char *I810ddcSymbols[]; +extern const char *I810fbSymbols[]; +extern const char *I810xaaSymbols[]; +extern const char *I810shadowSymbols[]; + +extern void I830DPRINTF_stub(const char *filename, int line, + const char *function, const char *fmt, ...); + +#ifdef _I830_H_ +#define PrintErrorState I830PrintErrorState +#define WaitRingFunc I830WaitLpRing +#define RecPtr pI830 +#else +#define PrintErrorState I810PrintErrorState +#define WaitRingFunc I810WaitLpRing +#define RecPtr pI810 +#endif + +/* BIOS debug macro */ +#define xf86ExecX86int10_wrapper(pInt, pScrn) do { \ + if (I810_DEBUG & DEBUG_VERBOSE_BIOS) { \ + ErrorF("\n\n\n\nExecuting (ax == 0x%x) BIOS call\n", pInt->ax); \ + ErrorF("Checking Error state before execution\n"); \ + PrintErrorState(pScrn); \ + } \ + xf86ExecX86int10(pInt); \ + if(I810_DEBUG & DEBUG_VERBOSE_BIOS) { \ + ErrorF("Checking Error state after execution\n"); \ + usleep(50000); \ + PrintErrorState(pScrn); \ + } \ +} while (0) + +#define OUT_RING(n) do { \ + if (I810_DEBUG & DEBUG_VERBOSE_RING) \ + ErrorF( "OUT_RING %x: %x, (mask %x)\n", outring, n, ringmask); \ + *(volatile unsigned int *)(virt + outring) = n; \ + outring += 4; \ + outring &= ringmask; \ +} while (0) + +#if 1 +#define ADVANCE_LP_RING() do { \ + RecPtr->LpRing.tail = outring; \ + if (outring & 0x07) \ + ErrorF("ADVANCE_LP_RING: " \ + "outring (0x%x) isn't on a QWord boundary", outring); \ + OUTREG(LP_RING + RING_TAIL, outring); \ +} while (0) +#else +#define ADVANCE_LP_RING() { \ + RecPtr->LpRing.tail = outring; \ + if (outring & 0x07) \ + ErrorF("ADVANCE_LP_RING: " \ + "outring (0x%x) isn't on a QWord boundary", outring); \ + ErrorF("head is %d, tail is %d [%d]\n", INREG(LP_RING + RING_HEAD), INREG(LP_RING + RING_TAIL), outring); \ + OUTREG(LP_RING + RING_TAIL, outring); \ + ErrorF("head is %d, tail is %d [%d]\n", INREG(LP_RING + RING_HEAD), INREG(LP_RING + RING_TAIL), outring); \ +} +#endif + +/* + * XXX Note: the head/tail masks are different for 810 and i830. + * If the i810 always sets the higher bits to 0, then this shouldn't be + * a problem. Check this! + */ +#define DO_RING_IDLE() do { \ + int _head; \ + int _tail; \ + do { \ + _head = INREG(LP_RING + RING_HEAD) & I830_HEAD_MASK; \ + _tail = INREG(LP_RING + RING_TAIL) & I830_TAIL_MASK; \ + DELAY(10); \ + } while (_head != _tail); \ +} while( 0) + +/* + * This is for debugging a potential problem writing the tail pointer + * close to the end of the ring buffer. + */ +#ifndef AVOID_TAIL_END +#define AVOID_TAIL_END 0 +#endif +#ifndef AVOID_SIZE +#define AVOID_SIZE 64 +#endif + +#if AVOID_TAIL_END + +#define BEGIN_LP_RING(n) \ + unsigned int outring, ringmask; \ + volatile unsigned char *virt; \ + unsigned int needed; \ + if ((n) & 1) \ + ErrorF("BEGIN_LP_RING called with odd argument: %d\n", n); \ + if ((n) > 2 && (I810_DEBUG&DEBUG_ALWAYS_SYNC)) \ + DO_RING_IDLE(); \ + needed = (n) * 4; \ + if ((RecPtr->LpRing.tail > RecPtr->LpRing.tail_mask - AVOID_SIZE) || \ + (RecPtr->LpRing.tail + needed) > \ + RecPtr->LpRing.tail_mask - AVOID_SIZE) { \ + needed += RecPtr->LpRing.tail_mask + 1 - RecPtr->LpRing.tail; \ + ErrorF("BEGIN_LP_RING: skipping last 64 bytes of " \ + "ring (%d vs %d)\n", needed, (n) * 4); \ + } \ + if (RecPtr->LpRing.space < needed) \ + WaitRingFunc(pScrn, needed, 0); \ + RecPtr->LpRing.space -= needed; \ + outring = RecPtr->LpRing.tail; \ + ringmask = RecPtr->LpRing.tail_mask; \ + virt = RecPtr->LpRing.virtual_start; \ + while (needed > (n) * 4) { \ + ErrorF("BEGIN_LP_RING: putting MI_NOOP at 0x%x (remaining %d)\n", \ + outring, needed - (n) * 4); \ + OUT_RING(MI_NOOP); \ + needed -= 4; \ + } \ + if (I810_DEBUG & DEBUG_VERBOSE_RING) \ + ErrorF( "BEGIN_LP_RING %d in %s\n", n, FUNCTION_NAME); + +#else /* AVOID_TAIL_END */ + +#define BEGIN_LP_RING(n) \ + unsigned int outring, ringmask; \ + volatile unsigned char *virt; \ + unsigned int needed; \ + if ((n) & 1) \ + ErrorF("BEGIN_LP_RING called with odd argument: %d\n", n); \ + if ((n) > 2 && (I810_DEBUG&DEBUG_ALWAYS_SYNC)) \ + DO_RING_IDLE(); \ + needed = (n) * 4; \ + if (RecPtr->LpRing.space < needed) \ + WaitRingFunc(pScrn, needed, 0); \ + RecPtr->LpRing.space -= needed; \ + outring = RecPtr->LpRing.tail; \ + ringmask = RecPtr->LpRing.tail_mask; \ + virt = RecPtr->LpRing.virtual_start; \ + if (I810_DEBUG & DEBUG_VERBOSE_RING) \ + ErrorF( "BEGIN_LP_RING %d in %s\n", n, FUNCTION_NAME); + +#endif /* AVOID_TAIL_END */ + + +/* Memory mapped register access macros */ +#define INREG8(addr) *(volatile CARD8 *)(RecPtr->MMIOBase + (addr)) +#define INREG16(addr) *(volatile CARD16 *)(RecPtr->MMIOBase + (addr)) +#define INREG(addr) *(volatile CARD32 *)(RecPtr->MMIOBase + (addr)) + +#define OUTREG8(addr, val) do { \ + *(volatile CARD8 *)(RecPtr->MMIOBase + (addr)) = (val); \ + if (I810_DEBUG&DEBUG_VERBOSE_OUTREG) { \ + ErrorF("OUTREG8(0x%x, 0x%x) in %s\n", addr, val, FUNCTION_NAME); \ + } \ +} while (0) + +#define OUTREG16(addr, val) do { \ + *(volatile CARD16 *)(RecPtr->MMIOBase + (addr)) = (val); \ + if (I810_DEBUG&DEBUG_VERBOSE_OUTREG) { \ + ErrorF("OUTREG16(0x%x, 0x%x) in %s\n", addr, val, FUNCTION_NAME); \ + } \ +} while (0) + +#define OUTREG(addr, val) do { \ + *(volatile CARD32 *)(RecPtr->MMIOBase + (addr)) = (val); \ + if (I810_DEBUG&DEBUG_VERBOSE_OUTREG) { \ + ErrorF("OUTREG(0x%x, 0x%x) in %s\n", addr, val, FUNCTION_NAME); \ + } \ +} while (0) + +/* To remove all debugging, make sure I810_DEBUG is defined as a + * preprocessor symbol, and equal to zero. + */ +#if 1 +#define I810_DEBUG 0 +#endif +#ifndef I810_DEBUG +#warning "Debugging enabled - expect reduced performance" +extern int I810_DEBUG; +#endif + +#define DEBUG_VERBOSE_ACCEL 0x1 +#define DEBUG_VERBOSE_SYNC 0x2 +#define DEBUG_VERBOSE_VGA 0x4 +#define DEBUG_VERBOSE_RING 0x8 +#define DEBUG_VERBOSE_OUTREG 0x10 +#define DEBUG_VERBOSE_MEMORY 0x20 +#define DEBUG_VERBOSE_CURSOR 0x40 +#define DEBUG_ALWAYS_SYNC 0x80 +#define DEBUG_VERBOSE_DRI 0x100 +#define DEBUG_VERBOSE_BIOS 0x200 + +/* Size of the mmio region. + */ +#define I810_REG_SIZE 0x80000 + +#ifndef PCI_CHIP_I810 +#define PCI_CHIP_I810 0x7121 +#define PCI_CHIP_I810_DC100 0x7123 +#define PCI_CHIP_I810_E 0x7125 +#define PCI_CHIP_I815 0x1132 +#define PCI_CHIP_I810_BRIDGE 0x7120 +#define PCI_CHIP_I810_DC100_BRIDGE 0x7122 +#define PCI_CHIP_I810_E_BRIDGE 0x7124 +#define PCI_CHIP_I815_BRIDGE 0x1130 +#endif + +#ifndef PCI_CHIP_I855_GM +#define PCI_CHIP_I855_GM 0x3582 +#define PCI_CHIP_I855_GM_BRIDGE 0x3580 +#endif + +#ifndef PCI_CHIP_I865_G +#define PCI_CHIP_I865_G 0x2572 +#define PCI_CHIP_I865_G_BRIDGE 0x2570 +#endif + +#define IS_I810(pI810) (pI810->PciInfo->chipType == PCI_CHIP_I810 || \ + pI810->PciInfo->chipType == PCI_CHIP_I810_DC100 || \ + pI810->PciInfo->chipType == PCI_CHIP_I810_E) +#define IS_I815(pI810) (pI810->PciInfo->chipType == PCI_CHIP_I815) +#define IS_I830(pI810) (pI810->PciInfo->chipType == PCI_CHIP_I830_M) +#define IS_845G(pI810) (pI810->PciInfo->chipType == PCI_CHIP_845_G) +#define IS_I85X(pI810) (pI810->PciInfo->chipType == PCI_CHIP_I855_GM) +#define IS_I865G(pI810) (pI810->PciInfo->chipType == PCI_CHIP_I865_G) + +#define IS_MOBILE(pI810) (IS_I830(pI810) || IS_I85X(pI810)) + +#define GTT_PAGE_SIZE KB(4) +#define ROUND_TO(x, y) (((x) + (y) - 1) / (y) * (y)) +#define ROUND_DOWN_TO(x, y) ((x) / (y) * (y)) +#define ROUND_TO_PAGE(x) ROUND_TO((x), GTT_PAGE_SIZE) +#define ROUND_TO_MB(x) ROUND_TO((x), MB(1)) +#define PRIMARY_RINGBUFFER_SIZE KB(128) +#define MIN_SCRATCH_BUFFER_SIZE KB(16) +#define MAX_SCRATCH_BUFFER_SIZE KB(64) +#define HWCURSOR_SIZE GTT_PAGE_SIZE +#define OVERLAY_SIZE GTT_PAGE_SIZE + +/* Use a 64x64 HW cursor */ +#define I810_CURSOR_X 64 +#define I810_CURSOR_Y I810_CURSOR_X + +/* XXX Need to check if these are reasonable. */ +#define MAX_DISPLAY_PITCH 2048 +#define MAX_DISPLAY_HEIGHT 2048 + +#define PIPE_NAME(n) ('A' + (n)) + +#endif /* _INTEL_COMMON_H_ */ diff --git a/src/i810.h b/src/i810.h new file mode 100644 index 00000000..128b659a --- /dev/null +++ b/src/i810.h @@ -0,0 +1,324 @@ + +/************************************************************************** + +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +Copyright © 2002 David Dawes + +All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sub license, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice (including the +next paragraph) shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i810/i810.h,v 1.38 2003/02/26 04:19:36 dawes Exp $ */ + +/* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + * David Dawes <dawes@tungstengraphics.com> + * + */ + +#ifndef _I810_H_ +#define _I810_H_ + +#include "xf86_ansic.h" +#include "compiler.h" +#include "xf86PciInfo.h" +#include "xf86Pci.h" +#include "i810_reg.h" +#include "xaa.h" +#include "xf86Cursor.h" +#include "xf86xv.h" +#include "xf86int10.h" +#include "vbe.h" +#include "vgaHW.h" + +#ifdef XF86DRI +#include "xf86drm.h" +#include "sarea.h" +#define _XF86DRI_SERVER_ +#include "xf86dri.h" +#include "dri.h" +#include "GL/glxint.h" +#include "i810_dri.h" +#endif + +#include "common.h" + +#define I810_VERSION 4000 +#define I810_NAME "I810" +#define I810_DRIVER_NAME "i810" +#define I810_MAJOR_VERSION 1 +#define I810_MINOR_VERSION 3 +#define I810_PATCHLEVEL 0 + + +/* HWMC Surfaces */ +#define I810_MAX_SURFACES 7 +#define I810_MAX_SUBPICTURES 2 +#define I810_TOTAL_SURFACES 9 + +/* Globals */ + +typedef struct _I810Rec *I810Ptr; + +typedef void (*I810WriteIndexedByteFunc)(I810Ptr pI810, IOADDRESS addr, + CARD8 index, CARD8 value); +typedef CARD8(*I810ReadIndexedByteFunc)(I810Ptr pI810, IOADDRESS addr, + CARD8 index); +typedef void (*I810WriteByteFunc)(I810Ptr pI810, IOADDRESS addr, CARD8 value); +typedef CARD8(*I810ReadByteFunc)(I810Ptr pI810, IOADDRESS addr); + +extern void I810SetTiledMemory(ScrnInfoPtr pScrn, int nr, unsigned start, + unsigned pitch, unsigned size); + +typedef struct { + unsigned long Start; + unsigned long End; + unsigned long Size; +} I810MemRange; + +typedef struct { + int tail_mask; + I810MemRange mem; + unsigned char *virtual_start; + int head; + int tail; + int space; +} I810RingBuffer; + +typedef struct { + unsigned char DisplayControl; + unsigned char PixelPipeCfg0; + unsigned char PixelPipeCfg1; + unsigned char PixelPipeCfg2; + unsigned short VideoClk2_M; + unsigned short VideoClk2_N; + unsigned char VideoClk2_DivisorSel; + unsigned char AddressMapping; + unsigned char IOControl; + unsigned char BitBLTControl; + unsigned char ExtVertTotal; + unsigned char ExtVertDispEnd; + unsigned char ExtVertSyncStart; + unsigned char ExtVertBlankStart; + unsigned char ExtHorizTotal; + unsigned char ExtHorizBlank; + unsigned char ExtOffset; + unsigned char InterlaceControl; + unsigned int LMI_FIFO_Watermark; + + unsigned int LprbTail; + unsigned int LprbHead; + unsigned int LprbStart; + unsigned int LprbLen; + + unsigned int Fence[8]; + + unsigned short OverlayActiveStart; + unsigned short OverlayActiveEnd; + +} I810RegRec, *I810RegPtr; + +typedef struct _I810Rec { + unsigned char *MMIOBase; + unsigned char *FbBase; + long FbMapSize; + long DepthOffset; + long BackOffset; + int cpp; + int MaxClock; + + unsigned int bufferOffset; /* for I810SelectBuffer */ + Bool DoneFrontAlloc; + BoxRec FbMemBox; + I810MemRange FrontBuffer; + I810MemRange BackBuffer; + I810MemRange DepthBuffer; + I810MemRange TexMem; + I810MemRange Scratch; + I810MemRange BufferMem; + I810MemRange ContextMem; + I810MemRange MC; + + int auxPitch; + int auxPitchBits; + + int CursorOffset; + unsigned long CursorPhysical; + unsigned long CursorStart; + unsigned long OverlayPhysical; + unsigned long OverlayStart; + int colorKey; + int surfaceAllocation[I810_TOTAL_SURFACES]; + int numSurfaces; + + DGAModePtr DGAModes; + int numDGAModes; + Bool DGAactive; + int DGAViewportStatus; + + int Chipset; + unsigned long LinearAddr; + unsigned long MMIOAddr; + IOADDRESS ioBase; + EntityInfoPtr pEnt; + pciVideoPtr PciInfo; + PCITAG PciTag; + + I810RingBuffer LpRing; + unsigned int BR[20]; + + int LmFreqSel; + + int VramKey; + unsigned long VramOffset; + int DcacheKey; + unsigned long DcacheOffset; + int HwcursKey; + unsigned long HwcursOffset; + + int GttBound; + + I810MemRange DcacheMem; + I810MemRange SysMem; + + I810MemRange SavedDcacheMem; + I810MemRange SavedSysMem; + + unsigned char **ScanlineColorExpandBuffers; + int NumScanlineColorExpandBuffers; + int nextColorExpandBuf; + + I810RegRec SavedReg; + I810RegRec ModeReg; + + XAAInfoRecPtr AccelInfoRec; + xf86CursorInfoPtr CursorInfoRec; + CloseScreenProcPtr CloseScreen; + ScreenBlockHandlerProcPtr BlockHandler; + + I810WriteIndexedByteFunc writeControl; + I810ReadIndexedByteFunc readControl; + I810WriteByteFunc writeStandard; + I810ReadByteFunc readStandard; + + Bool directRenderingEnabled; /* false if XF86DRI not defined. */ + +#ifdef XF86DRI + int LockHeld; + DRIInfoPtr pDRIInfo; + int drmSubFD; + int numVisualConfigs; + __GLXvisualConfig *pVisualConfigs; + I810ConfigPrivPtr pVisualConfigsPriv; + unsigned long dcacheHandle; + unsigned long backHandle; + unsigned long zHandle; + unsigned long cursorHandle; + unsigned long xvmcHandle; + unsigned long sysmemHandle; + Bool agpAcquired; + drmHandle buffer_map; + drmHandle ring_map; + drmHandle overlay_map; + drmHandle mc_map; + drmHandle xvmcContext; +#endif + Bool agpAcquired2d; + + XF86VideoAdaptorPtr adaptor; + OptionInfoPtr Options; + + int configured_device; + + Bool showCache; + Bool noAccel; +} I810Rec; + +#define I810PTR(p) ((I810Ptr)((p)->driverPrivate)) + +#define I810_SELECT_FRONT 0 +#define I810_SELECT_BACK 1 +#define I810_SELECT_DEPTH 2 + +extern Bool I810DRIScreenInit(ScreenPtr pScreen); +extern void I810DRICloseScreen(ScreenPtr pScreen); +extern Bool I810DRIFinishScreenInit(ScreenPtr pScreen); +extern Bool I810InitDma(ScrnInfoPtr pScrn); +extern Bool I810CleanupDma(ScrnInfoPtr pScrn); + +#define I810PTR(p) ((I810Ptr)((p)->driverPrivate)) +#define I810REGPTR(p) (&(I810PTR(p)->ModeReg)) + +extern Bool I810CursorInit(ScreenPtr pScreen); +extern Bool I810AccelInit(ScreenPtr pScreen); +extern void I810SetPIOAccess(I810Ptr pI810); +extern void I810SetMMIOAccess(I810Ptr pI810); +extern unsigned int I810CalcWatermark(ScrnInfoPtr pScrn, double freq, + Bool dcache); +extern void I810PrintErrorState(ScrnInfoPtr pScrn); +extern int I810WaitLpRing(ScrnInfoPtr pScrn, int n, int timeout_millis); +extern void I810Sync(ScrnInfoPtr pScrn); +extern unsigned long I810LocalToPhysical(ScrnInfoPtr pScrn, + unsigned long local); +extern int I810AllocLow(I810MemRange * result, I810MemRange * pool, int size); +extern int I810AllocHigh(I810MemRange * result, I810MemRange * pool, + int size); +extern Bool I810AllocateFront(ScrnInfoPtr pScrn); + +extern int I810AllocateGARTMemory(ScrnInfoPtr pScrn); +extern void I810FreeGARTMemory(ScrnInfoPtr pScrn); + +extern Bool I810BindGARTMemory(ScrnInfoPtr pScrn); +extern Bool I810UnbindGARTMemory(ScrnInfoPtr pScrn); + +extern int I810CheckAvailableMemory(ScrnInfoPtr pScrn); + +extern Bool I810SwitchMode(int scrnIndex, DisplayModePtr mode, int flags); +extern void I810AdjustFrame(int scrnIndex, int x, int y, int flags); + +extern void I810SetupForScreenToScreenCopy(ScrnInfoPtr pScrn, int xdir, + int ydir, int rop, + unsigned int planemask, + int trans_color); +extern void I810SubsequentScreenToScreenCopy(ScrnInfoPtr pScrn, int srcX, + int srcY, int dstX, int dstY, + int w, int h); +extern void I810SetupForSolidFill(ScrnInfoPtr pScrn, int color, int rop, + unsigned int planemask); +extern void I810SubsequentSolidFillRect(ScrnInfoPtr pScrn, int x, int y, + int w, int h); + +extern void I810SelectBuffer(ScrnInfoPtr pScrn, int buffer); + +extern void I810RefreshRing(ScrnInfoPtr pScrn); +extern void I810EmitFlush(ScrnInfoPtr pScrn); +extern void I810EmitInvarientState(ScrnInfoPtr pScrn); + +extern Bool I810DGAInit(ScreenPtr pScreen); + +extern void I810InitVideo(ScreenPtr pScreen); +extern void I810InitMC(ScreenPtr pScreen); + +extern const OptionInfoRec *I810AvailableOptions(int chipid, int busid); + +#endif /* _I810_H_ */ diff --git a/src/i810_accel.c b/src/i810_accel.c new file mode 100644 index 00000000..17c24b37 --- /dev/null +++ b/src/i810_accel.c @@ -0,0 +1,662 @@ + +/************************************************************************** + +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sub license, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice (including the +next paragraph) shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i810/i810_accel.c,v 1.17 2002/11/25 14:04:59 eich Exp $ */ + +/* + * Reformatted with GNU indent (2.2.8), using the following options: + * + * -bad -bap -c41 -cd0 -ncdb -ci6 -cli0 -cp0 -ncs -d0 -di3 -i3 -ip3 -l78 + * -lp -npcs -psl -sob -ss -br -ce -sc -hnl + * + * This provides a good match with the original i810 code and preferred + * XFree86 formatting conventions. + * + * When editing this driver, please follow the existing formatting, and edit + * with <TAB> characters expanded at 8-column intervals. + */ + +/* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + * + */ + +#include "xf86_ansic.h" +#include "xf86.h" + +#include "i810.h" + +static unsigned int i810Rop[16] = { + 0x00, /* GXclear */ + 0x88, /* GXand */ + 0x44, /* GXandReverse */ + 0xCC, /* GXcopy */ + 0x22, /* GXandInvert */ + 0xAA, /* GXnoop */ + 0x66, /* GXxor */ + 0xEE, /* GXor */ + 0x11, /* GXnor */ + 0x99, /* GXequiv */ + 0x55, /* GXinvert */ + 0xDD, /* GXorReverse */ + 0x33, /* GXcopyInvert */ + 0xBB, /* GXorInverted */ + 0x77, /* GXnand */ + 0xFF /* GXset */ +}; + +static unsigned int i810PatternRop[16] = { + 0x00, /* GXclear */ + 0xA0, /* GXand */ + 0x50, /* GXandReverse */ + 0xF0, /* GXcopy */ + 0x0A, /* GXandInvert */ + 0xAA, /* GXnoop */ + 0x5A, /* GXxor */ + 0xFA, /* GXor */ + 0x05, /* GXnor */ + 0xA5, /* GXequiv */ + 0x55, /* GXinvert */ + 0xF5, /* GXorReverse */ + 0x0F, /* GXcopyInvert */ + 0xAF, /* GXorInverted */ + 0x5F, /* GXnand */ + 0xFF /* GXset */ +}; + +static void I810SetupForMono8x8PatternFill(ScrnInfoPtr pScrn, + int pattx, int patty, + int fg, int bg, int rop, + unsigned int planemask); +static void I810SubsequentMono8x8PatternFillRect(ScrnInfoPtr pScrn, + int pattx, int patty, + int x, int y, int w, int h); + +static void I810SetupForScanlineCPUToScreenColorExpandFill(ScrnInfoPtr pScrn, + int fg, int bg, + int rop, + unsigned int mask); + +static void I810SubsequentScanlineCPUToScreenColorExpandFill(ScrnInfoPtr + pScrn, int x, + int y, int w, + int h, + int skipleft); + +static void I810SubsequentColorExpandScanline(ScrnInfoPtr pScrn, int bufno); + +/* The following function sets up the supported acceleration. Call it + * from the FbInit() function in the SVGA driver, or before ScreenInit + * in a monolithic server. + */ +Bool +I810AccelInit(ScreenPtr pScreen) +{ + XAAInfoRecPtr infoPtr; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I810Ptr pI810 = I810PTR(pScrn); + + if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) + ErrorF("I810AccelInit\n"); + + pI810->AccelInfoRec = infoPtr = XAACreateInfoRec(); + if (!infoPtr) + return FALSE; + + pI810->bufferOffset = 0; + infoPtr->Flags = LINEAR_FRAMEBUFFER | OFFSCREEN_PIXMAPS; + /* There is a bit blt bug in 24 bpp. This is a problem, but + * at least without the pixmap cache we can pass the test suite */ + if (pScrn->depth != 24) + infoPtr->Flags |= PIXMAP_CACHE; + + /* Sync + */ + infoPtr->Sync = I810Sync; + + /* Solid filled rectangles + */ + { + infoPtr->SolidFillFlags = NO_PLANEMASK; + infoPtr->SetupForSolidFill = I810SetupForSolidFill; + infoPtr->SubsequentSolidFillRect = I810SubsequentSolidFillRect; + } + + /* Screen to screen copy + * - the transparency op hangs the blit engine, disable for now. + */ + { + infoPtr->ScreenToScreenCopyFlags = (0 + | NO_PLANEMASK + | NO_TRANSPARENCY | 0); + + infoPtr->SetupForScreenToScreenCopy = I810SetupForScreenToScreenCopy; + infoPtr->SubsequentScreenToScreenCopy = + I810SubsequentScreenToScreenCopy; + } + + /* 8x8 pattern fills + */ + { + infoPtr->SetupForMono8x8PatternFill = I810SetupForMono8x8PatternFill; + infoPtr->SubsequentMono8x8PatternFillRect = + I810SubsequentMono8x8PatternFillRect; + + infoPtr->Mono8x8PatternFillFlags = (HARDWARE_PATTERN_PROGRAMMED_BITS | + HARDWARE_PATTERN_SCREEN_ORIGIN | + BIT_ORDER_IN_BYTE_MSBFIRST | + NO_PLANEMASK | 0); + } + + /* 8x8 color fills - not considered useful for XAA. + */ + + /* Scanline color expansion - Use the same scheme as the 3.3 driver. + * + */ + if (pI810->Scratch.Size != 0) { + int i; + int width = ((pScrn->displayWidth + 31) & ~31) / 8; + int nr_buffers = pI810->Scratch.Size / width; + unsigned char *ptr = pI810->FbBase + pI810->Scratch.Start; + + pI810->NumScanlineColorExpandBuffers = nr_buffers; + pI810->ScanlineColorExpandBuffers = (unsigned char **) + xnfcalloc(nr_buffers, sizeof(unsigned char *)); + + for (i = 0; i < nr_buffers; i++, ptr += width) + pI810->ScanlineColorExpandBuffers[i] = ptr; + + infoPtr->ScanlineCPUToScreenColorExpandFillFlags = (NO_PLANEMASK | + ROP_NEEDS_SOURCE | + BIT_ORDER_IN_BYTE_MSBFIRST + | 0); + + infoPtr->ScanlineColorExpandBuffers = (unsigned char **) + xnfcalloc(1, sizeof(unsigned char *)); + infoPtr->NumScanlineColorExpandBuffers = 1; + + infoPtr->ScanlineColorExpandBuffers[0] = + pI810->ScanlineColorExpandBuffers[0]; + pI810->nextColorExpandBuf = 0; + + infoPtr->SetupForScanlineCPUToScreenColorExpandFill = + I810SetupForScanlineCPUToScreenColorExpandFill; + + infoPtr->SubsequentScanlineCPUToScreenColorExpandFill = + I810SubsequentScanlineCPUToScreenColorExpandFill; + + infoPtr->SubsequentColorExpandScanline = + I810SubsequentColorExpandScanline; + } + + /* Possible todo: Image writes w/ non-GXCOPY rop. + */ + + I810SelectBuffer(pScrn, I810_SELECT_FRONT); + + return XAAInit(pScreen, infoPtr); +} + +int +I810WaitLpRing(ScrnInfoPtr pScrn, int n, int timeout_millis) +{ + I810Ptr pI810 = I810PTR(pScrn); + I810RingBuffer *ring = &(pI810->LpRing); + int iters = 0; + int start = 0; + int now = 0; + int last_head = 0; + int first = 0; + + /* If your system hasn't moved the head pointer in 2 seconds, I'm going to + * call it crashed. + */ + if (timeout_millis == 0) + timeout_millis = 2000; + + if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) { + ErrorF("I810WaitLpRing %d\n", n); + first = GetTimeInMillis(); + } + + while (ring->space < n) { + ring->head = INREG(LP_RING + RING_HEAD) & HEAD_ADDR; + ring->space = ring->head - (ring->tail + 8); + + if (ring->space < 0) + ring->space += ring->mem.Size; + + iters++; + now = GetTimeInMillis(); + if (start == 0 || now < start || ring->head != last_head) { + if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) + if (now > start) + ErrorF("space: %d wanted %d\n", ring->space, n); + start = now; + last_head = ring->head; + } else if (now - start > timeout_millis) { + ErrorF("Error in I810WaitLpRing(), now is %d, start is %d\n", now, + start); + I810PrintErrorState(pScrn); + ErrorF("space: %d wanted %d\n", ring->space, n); +#ifdef XF86DRI + if (pI810->directRenderingEnabled) { + DRIUnlock(screenInfo.screens[pScrn->scrnIndex]); + DRICloseScreen(screenInfo.screens[pScrn->scrnIndex]); + } +#endif + pI810->AccelInfoRec = NULL; /* Stops recursive behavior */ + FatalError("lockup\n"); + } + + DELAY(10000); + } + + if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) { + now = GetTimeInMillis(); + if (now - first) { + ErrorF("Elapsed %d ms\n", now - first); + ErrorF("space: %d wanted %d\n", ring->space, n); + } + } + + return iters; +} + +void +I810Sync(ScrnInfoPtr pScrn) +{ + I810Ptr pI810 = I810PTR(pScrn); + + if (I810_DEBUG & (DEBUG_VERBOSE_ACCEL | DEBUG_VERBOSE_SYNC)) + ErrorF("I810Sync\n"); + +#ifdef XF86DRI + /* VT switching tries to do this. + */ + if (!pI810->LockHeld && pI810->directRenderingEnabled) { + return; + } +#endif + + /* Send a flush instruction and then wait till the ring is empty. + * This is stronger than waiting for the blitter to finish as it also + * flushes the internal graphics caches. + */ + { + BEGIN_LP_RING(2); + OUT_RING(INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE); + OUT_RING(0); /* pad to quadword */ + ADVANCE_LP_RING(); + } + + I810WaitLpRing(pScrn, pI810->LpRing.mem.Size - 8, 0); + + pI810->LpRing.space = pI810->LpRing.mem.Size - 8; + pI810->nextColorExpandBuf = 0; +} + +void +I810SetupForSolidFill(ScrnInfoPtr pScrn, int color, int rop, + unsigned int planemask) +{ + I810Ptr pI810 = I810PTR(pScrn); + + if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) + ErrorF("I810SetupForFillRectSolid color: %x rop: %x mask: %x\n", + color, rop, planemask); + + /* Color blit, p166 */ + pI810->BR[13] = (BR13_SOLID_PATTERN | + (i810PatternRop[rop] << 16) | + (pScrn->displayWidth * pI810->cpp)); + pI810->BR[16] = color; +} + +void +I810SubsequentSolidFillRect(ScrnInfoPtr pScrn, int x, int y, int w, int h) +{ + I810Ptr pI810 = I810PTR(pScrn); + + if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) + ErrorF("I810SubsequentFillRectSolid %d,%d %dx%d\n", x, y, w, h); + + { + BEGIN_LP_RING(6); + + OUT_RING(BR00_BITBLT_CLIENT | BR00_OP_COLOR_BLT | 0x3); + OUT_RING(pI810->BR[13]); + OUT_RING((h << 16) | (w * pI810->cpp)); + OUT_RING(pI810->bufferOffset + + (y * pScrn->displayWidth + x) * pI810->cpp); + + OUT_RING(pI810->BR[16]); + OUT_RING(0); /* pad to quadword */ + + ADVANCE_LP_RING(); + } +} + +void +I810SetupForScreenToScreenCopy(ScrnInfoPtr pScrn, int xdir, int ydir, int rop, + unsigned int planemask, int transparency_color) +{ + I810Ptr pI810 = I810PTR(pScrn); + + if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) + ErrorF("I810SetupForScreenToScreenCopy %d %d %x %x %d\n", + xdir, ydir, rop, planemask, transparency_color); + + pI810->BR[13] = (pScrn->displayWidth * pI810->cpp); + + if (ydir == -1) + pI810->BR[13] = (-pI810->BR[13]) & 0xFFFF; + if (xdir == -1) + pI810->BR[13] |= BR13_RIGHT_TO_LEFT; + + pI810->BR[13] |= i810Rop[rop] << 16; + + pI810->BR[18] = 0; +} + +void +I810SubsequentScreenToScreenCopy(ScrnInfoPtr pScrn, int x1, int y1, + int x2, int y2, int w, int h) +{ + I810Ptr pI810 = I810PTR(pScrn); + int src, dst; + int w_back = w; + + if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) + ErrorF( "I810SubsequentScreenToScreenCopy %d,%d - %d,%d %dx%d\n", + x1,y1,x2,y2,w,h); + /* + * This works around a bug in the i810 drawing engine. + * This was developed empirically so it may not catch all + * cases. + */ + if ( !(pI810->BR[13] & BR13_RIGHT_TO_LEFT) && (y2 - y1) < 3 + && (y2 - y1) >= 0 && (x2 - x1) <= (w + 4) && (w > 4)) + w = 4; + do { + + if (pI810->BR[13] & BR13_PITCH_SIGN_BIT) { + src = (y1 + h - 1) * pScrn->displayWidth * pI810->cpp; + dst = (y2 + h - 1) * pScrn->displayWidth * pI810->cpp; + } else { + src = y1 * pScrn->displayWidth * pI810->cpp; + dst = y2 * pScrn->displayWidth * pI810->cpp; + } + + if (pI810->BR[13] & BR13_RIGHT_TO_LEFT) { + src += (x1 + w - 1) * pI810->cpp + pI810->cpp - 1; + dst += (x2 + w - 1) * pI810->cpp + pI810->cpp - 1; + } else { + src += x1 * pI810->cpp; + dst += x2 * pI810->cpp; + } + + + /* SRC_COPY_BLT, p169 */ + { + BEGIN_LP_RING(6); + OUT_RING( BR00_BITBLT_CLIENT | BR00_OP_SRC_COPY_BLT | 0x4 ); + OUT_RING( pI810->BR[13]); + + OUT_RING( (h << 16) | (w * pI810->cpp)); + OUT_RING( pI810->bufferOffset + dst); + + OUT_RING( pI810->BR[13] & 0xFFFF); + OUT_RING( pI810->bufferOffset + src); + ADVANCE_LP_RING(); + } + w_back -= w; + if (w_back <= 0) + break; + x2 += w; + x1 += w; + w = w_back; + } while (1); +} + +static void +I810SetupForMono8x8PatternFill(ScrnInfoPtr pScrn, int pattx, int patty, + int fg, int bg, int rop, + unsigned int planemask) +{ + I810Ptr pI810 = I810PTR(pScrn); + + if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) + ErrorF("I810SetupFor8x8PatternColorExpand\n"); + + /* FULL_MONO_PAT_BLT, p176 */ + pI810->BR[0] = (BR00_BITBLT_CLIENT | BR00_OP_MONO_PAT_BLT | 0x9); + pI810->BR[18] = bg; + pI810->BR[19] = fg; + pI810->BR[13] = (pScrn->displayWidth * pI810->cpp); + pI810->BR[13] |= i810PatternRop[rop] << 16; + if (bg == -1) + pI810->BR[13] |= BR13_MONO_TRANSPCY; +} + +static void +I810SubsequentMono8x8PatternFillRect(ScrnInfoPtr pScrn, int pattx, int patty, + int x, int y, int w, int h) +{ + I810Ptr pI810 = I810PTR(pScrn); + int addr = + pI810->bufferOffset + (y * pScrn->displayWidth + x) * pI810->cpp; + + if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) + ErrorF("I810Subsequent8x8PatternColorExpand\n"); + + { + BEGIN_LP_RING(12); + OUT_RING(pI810->BR[0] | ((y << 5) & BR00_PAT_VERT_ALIGN)); + OUT_RING(pI810->BR[13]); + OUT_RING((h << 16) | (w * pI810->cpp)); + OUT_RING(addr); + OUT_RING(pI810->BR[13] & 0xFFFF); /* src pitch */ + OUT_RING(addr); /* src addr */ + OUT_RING(0); /* transparency color */ + OUT_RING(pI810->BR[18]); /* bg */ + OUT_RING(pI810->BR[19]); /* fg */ + OUT_RING(pattx); /* pattern data */ + OUT_RING(patty); + OUT_RING(0); + ADVANCE_LP_RING(); + } +} + +static void +I810GetNextScanlineColorExpandBuffer(ScrnInfoPtr pScrn) +{ + I810Ptr pI810 = I810PTR(pScrn); + XAAInfoRecPtr infoPtr = pI810->AccelInfoRec; + + if (pI810->nextColorExpandBuf == pI810->NumScanlineColorExpandBuffers) + I810Sync(pScrn); + + infoPtr->ScanlineColorExpandBuffers[0] = + pI810->ScanlineColorExpandBuffers[pI810->nextColorExpandBuf]; + + if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) + ErrorF("using color expand buffer %d\n", pI810->nextColorExpandBuf); + + pI810->nextColorExpandBuf++; +} + +static void +I810SetupForScanlineCPUToScreenColorExpandFill(ScrnInfoPtr pScrn, + int fg, int bg, int rop, + unsigned int planemask) +{ + I810Ptr pI810 = I810PTR(pScrn); + + if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) + ErrorF("I810SetupForScanlineScreenToScreenColorExpand %d %d %x %x\n", + fg, bg, rop, planemask); + + pI810->BR[13] = (pScrn->displayWidth * pI810->cpp); + pI810->BR[13] |= i810Rop[rop] << 16; + pI810->BR[13] |= (1 << 27); + if (bg == -1) + pI810->BR[13] |= BR13_MONO_TRANSPCY; + + pI810->BR[18] = bg; + pI810->BR[19] = fg; + + I810GetNextScanlineColorExpandBuffer(pScrn); +} + +static void +I810SubsequentScanlineCPUToScreenColorExpandFill(ScrnInfoPtr pScrn, + int x, int y, + int w, int h, int skipleft) +{ + I810Ptr pI810 = I810PTR(pScrn); + + if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) + ErrorF("I810SubsequentScanlineCPUToScreenColorExpandFill " + "%d,%d %dx%x %d\n", x, y, w, h, skipleft); + + pI810->BR[0] = BR00_BITBLT_CLIENT | BR00_OP_MONO_SRC_COPY_BLT | 0x06; + pI810->BR[9] = (pI810->bufferOffset + + (y * pScrn->displayWidth + x) * pI810->cpp); + pI810->BR[14] = ((1 << 16) | (w * pI810->cpp)); + pI810->BR[11] = ((w + 31) / 32) - 1; +} + +static void +I810SubsequentColorExpandScanline(ScrnInfoPtr pScrn, int bufno) +{ + I810Ptr pI810 = I810PTR(pScrn); + + pI810->BR[12] = (pI810->AccelInfoRec->ScanlineColorExpandBuffers[0] - + pI810->FbBase); + + if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) + ErrorF("I810SubsequentColorExpandScanline %d (addr %x)\n", + bufno, pI810->BR[12]); + + { + BEGIN_LP_RING(8); + OUT_RING(pI810->BR[0]); + OUT_RING(pI810->BR[13]); + OUT_RING(pI810->BR[14]); + OUT_RING(pI810->BR[9]); + OUT_RING(pI810->BR[11]); + OUT_RING(pI810->BR[12]); /* srcaddr */ + OUT_RING(pI810->BR[18]); + OUT_RING(pI810->BR[19]); + ADVANCE_LP_RING(); + } + + /* Advance to next scanline. + */ + pI810->BR[9] += pScrn->displayWidth * pI810->cpp; + I810GetNextScanlineColorExpandBuffer(pScrn); +} + +void +I810EmitFlush(ScrnInfoPtr pScrn) +{ + I810Ptr pI810 = I810PTR(pScrn); + + BEGIN_LP_RING(2); + OUT_RING(INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE); + OUT_RING(0); + ADVANCE_LP_RING(); +} + +void +I810SelectBuffer(ScrnInfoPtr pScrn, int buffer) +{ + I810Ptr pI810 = I810PTR(pScrn); + + switch (buffer) { + case I810_SELECT_BACK: + pI810->bufferOffset = pI810->BackBuffer.Start; + break; + case I810_SELECT_DEPTH: + pI810->bufferOffset = pI810->DepthBuffer.Start; + break; + default: + case I810_SELECT_FRONT: + pI810->bufferOffset = pI810->FrontBuffer.Start; + break; + } + + if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) + ErrorF("I810SelectBuffer %d --> offset %x\n", + buffer, pI810->bufferOffset); +} + +void +I810RefreshRing(ScrnInfoPtr pScrn) +{ + I810Ptr pI810 = I810PTR(pScrn); + + pI810->LpRing.head = INREG(LP_RING + RING_HEAD) & HEAD_ADDR; + pI810->LpRing.tail = INREG(LP_RING + RING_TAIL); + pI810->LpRing.space = pI810->LpRing.head - (pI810->LpRing.tail + 8); + if (pI810->LpRing.space < 0) + pI810->LpRing.space += pI810->LpRing.mem.Size; + + pI810->AccelInfoRec->NeedToSync = TRUE; +} + +/* Emit on gaining VT? + */ +void +I810EmitInvarientState(ScrnInfoPtr pScrn) +{ + I810Ptr pI810 = I810PTR(pScrn); + + BEGIN_LP_RING(10); + + OUT_RING(INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE); + OUT_RING(GFX_CMD_CONTEXT_SEL | CS_UPDATE_USE | CS_USE_CTX0); + OUT_RING(INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE); + OUT_RING(0); + + OUT_RING(GFX_OP_COLOR_CHROMA_KEY); + OUT_RING(CC1_UPDATE_KILL_WRITE | + CC1_DISABLE_KILL_WRITE | + CC1_UPDATE_COLOR_IDX | + CC1_UPDATE_CHROMA_LOW | CC1_UPDATE_CHROMA_HI | 0); + OUT_RING(0); + OUT_RING(0); + +/* OUT_RING( CMD_OP_Z_BUFFER_INFO ); */ +/* OUT_RING( pI810->DepthBuffer.Start | pI810->auxPitchBits); */ + + ADVANCE_LP_RING(); +} + diff --git a/src/i810_common.h b/src/i810_common.h new file mode 100644 index 00000000..2a2e21a5 --- /dev/null +++ b/src/i810_common.h @@ -0,0 +1,188 @@ +/* i810_common.h -- common header definitions for I810 2D/3D/DRM suite + * + * Copyright 2002 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Converted to common header format: + * Jens Owen <jens@tungstengraphics.com> + * + * $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i810/i810_common.h,v 1.1 2002/09/11 00:29:31 dawes Exp $ + * + */ + +/* WARNING: If you change any of these defines, make sure to change + * the kernel include file as well (i810_drm.h) + */ + +#ifndef _I810_COMMON_H_ +#define _I810_COMMON_H_ + +#ifndef _I810_DEFINES_ +#define _I810_DEFINES_ +#define I810_USE_BATCH 1 + +#define I810_DMA_BUF_ORDER 12 +#define I810_DMA_BUF_SZ (1<<I810_DMA_BUF_ORDER) +#define I810_DMA_BUF_NR 256 + +#define I810_NR_SAREA_CLIPRECTS 8 + +/* Each region is a minimum of 64k, and there are at most 64 of them. + */ +#define I810_NR_TEX_REGIONS 64 +#define I810_LOG_MIN_TEX_REGION_SIZE 16 + +/* Destbuffer state + * - backbuffer linear offset and pitch -- invarient in the current dri + * - zbuffer linear offset and pitch -- also invarient + * - drawing origin in back and depth buffers. + * + * Keep the depth/back buffer state here to acommodate private buffers + * in the future. + */ +#define I810_DESTREG_DI0 0 /* CMD_OP_DESTBUFFER_INFO (2 dwords) */ +#define I810_DESTREG_DI1 1 +#define I810_DESTREG_DV0 2 /* GFX_OP_DESTBUFFER_VARS (2 dwords) */ +#define I810_DESTREG_DV1 3 +#define I810_DESTREG_DR0 4 /* GFX_OP_DRAWRECT_INFO (4 dwords) */ +#define I810_DESTREG_DR1 5 +#define I810_DESTREG_DR2 6 +#define I810_DESTREG_DR3 7 +#define I810_DESTREG_DR4 8 +#define I810_DEST_SETUP_SIZE 10 + +/* Context state + */ +#define I810_CTXREG_CF0 0 /* GFX_OP_COLOR_FACTOR */ +#define I810_CTXREG_CF1 1 +#define I810_CTXREG_ST0 2 /* GFX_OP_STIPPLE */ +#define I810_CTXREG_ST1 3 +#define I810_CTXREG_VF 4 /* GFX_OP_VERTEX_FMT */ +#define I810_CTXREG_MT 5 /* GFX_OP_MAP_TEXELS */ +#define I810_CTXREG_MC0 6 /* GFX_OP_MAP_COLOR_STAGES - stage 0 */ +#define I810_CTXREG_MC1 7 /* GFX_OP_MAP_COLOR_STAGES - stage 1 */ +#define I810_CTXREG_MC2 8 /* GFX_OP_MAP_COLOR_STAGES - stage 2 */ +#define I810_CTXREG_MA0 9 /* GFX_OP_MAP_ALPHA_STAGES - stage 0 */ +#define I810_CTXREG_MA1 10 /* GFX_OP_MAP_ALPHA_STAGES - stage 1 */ +#define I810_CTXREG_MA2 11 /* GFX_OP_MAP_ALPHA_STAGES - stage 2 */ +#define I810_CTXREG_SDM 12 /* GFX_OP_SRC_DEST_MONO */ +#define I810_CTXREG_FOG 13 /* GFX_OP_FOG_COLOR */ +#define I810_CTXREG_B1 14 /* GFX_OP_BOOL_1 */ +#define I810_CTXREG_B2 15 /* GFX_OP_BOOL_2 */ +#define I810_CTXREG_LCS 16 /* GFX_OP_LINEWIDTH_CULL_SHADE_MODE */ +#define I810_CTXREG_PV 17 /* GFX_OP_PV_RULE -- Invarient! */ +#define I810_CTXREG_ZA 18 /* GFX_OP_ZBIAS_ALPHAFUNC */ +#define I810_CTXREG_AA 19 /* GFX_OP_ANTIALIAS */ +#define I810_CTX_SETUP_SIZE 20 + +/* Texture state (per tex unit) + */ +#define I810_TEXREG_MI0 0 /* GFX_OP_MAP_INFO (4 dwords) */ +#define I810_TEXREG_MI1 1 +#define I810_TEXREG_MI2 2 +#define I810_TEXREG_MI3 3 +#define I810_TEXREG_MF 4 /* GFX_OP_MAP_FILTER */ +#define I810_TEXREG_MLC 5 /* GFX_OP_MAP_LOD_CTL */ +#define I810_TEXREG_MLL 6 /* GFX_OP_MAP_LOD_LIMITS */ +#define I810_TEXREG_MCS 7 /* GFX_OP_MAP_COORD_SETS ??? */ +#define I810_TEX_SETUP_SIZE 8 + +/* Driver specific DRM command indices + * NOTE: these are not OS specific, but they are driver specific + */ +#define DRM_I810_INIT 0x00 +#define DRM_I810_VERTEX 0x01 +#define DRM_I810_CLEAR 0x02 +#define DRM_I810_FLUSH 0x03 +#define DRM_I810_GETAGE 0x04 +#define DRM_I810_GETBUF 0x05 +#define DRM_I810_SWAP 0x06 +#define DRM_I810_COPY 0x07 +#define DRM_I810_DOCOPY 0x08 +#define DRM_I810_OV0INFO 0x09 +#define DRM_I810_FSTATUS 0x0a +#define DRM_I810_OV0FLIP 0x0b +#define DRM_I810_MC 0x0c +#define DRM_I810_RSTATUS 0x0d + +#endif + +typedef struct { + enum { + I810_INIT_DMA = 0x01, + I810_CLEANUP_DMA = 0x02 + } func; + unsigned int mmio_offset; + unsigned int buffers_offset; + int sarea_priv_offset; + unsigned int ring_start; + unsigned int ring_end; + unsigned int ring_size; + unsigned int front_offset; + unsigned int back_offset; + unsigned int depth_offset; + unsigned int overlay_offset; + unsigned int overlay_physical; + unsigned int w; + unsigned int h; + unsigned int pitch; + unsigned int pitch_bits; +} drmI810Init; + +typedef struct { + void *virtual; + int request_idx; + int request_size; + int granted; +} drmI810DMA; + +/* Flags for clear ioctl + */ +#define I810_FRONT 0x1 +#define I810_BACK 0x2 +#define I810_DEPTH 0x4 + +typedef struct { + int clear_color; + int clear_depth; + int flags; +} drmI810Clear; + +typedef struct { + int idx; /* buffer index */ + int used; /* nr bytes in use */ + int discard; /* client is finished with the buffer? */ +} drmI810Vertex; + +/* Flags for vertex ioctl + */ +#define PR_TRIANGLES (0x0<<18) +#define PR_TRISTRIP_0 (0x1<<18) +#define PR_TRISTRIP_1 (0x2<<18) +#define PR_TRIFAN (0x3<<18) +#define PR_POLYGON (0x4<<18) +#define PR_LINES (0x5<<18) +#define PR_LINESTRIP (0x6<<18) +#define PR_RECTS (0x7<<18) +#define PR_MASK (0x7<<18) + +#endif diff --git a/src/i810_cursor.c b/src/i810_cursor.c new file mode 100644 index 00000000..26023f3f --- /dev/null +++ b/src/i810_cursor.c @@ -0,0 +1,202 @@ + +/************************************************************************** + +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sub license, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice (including the +next paragraph) shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i810/i810_cursor.c,v 1.7 2002/10/30 12:52:17 alanh Exp $ */ + +/* + * Reformatted with GNU indent (2.2.8), using the following options: + * + * -bad -bap -c41 -cd0 -ncdb -ci6 -cli0 -cp0 -ncs -d0 -di3 -i3 -ip3 -l78 + * -lp -npcs -psl -sob -ss -br -ce -sc -hnl + * + * This provides a good match with the original i810 code and preferred + * XFree86 formatting conventions. + * + * When editing this driver, please follow the existing formatting, and edit + * with <TAB> characters expanded at 8-column intervals. + */ + +/* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + * + */ + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86_ansic.h" +#include "compiler.h" + +#include "xf86fbman.h" + +#include "i810.h" + +static void I810LoadCursorImage(ScrnInfoPtr pScrn, unsigned char *src); +static void I810ShowCursor(ScrnInfoPtr pScrn); +static void I810HideCursor(ScrnInfoPtr pScrn); +static void I810SetCursorColors(ScrnInfoPtr pScrn, int bg, int fb); +static void I810SetCursorPosition(ScrnInfoPtr pScrn, int x, int y); +static Bool I810UseHWCursor(ScreenPtr pScrn, CursorPtr pCurs); + +Bool +I810CursorInit(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn; + I810Ptr pI810; + xf86CursorInfoPtr infoPtr; + + pScrn = xf86Screens[pScreen->myNum]; + pI810 = I810PTR(pScrn); + pI810->CursorInfoRec = infoPtr = xf86CreateCursorInfoRec(); + if (!infoPtr) + return FALSE; + + infoPtr->MaxWidth = 64; + infoPtr->MaxHeight = 64; + infoPtr->Flags = (HARDWARE_CURSOR_TRUECOLOR_AT_8BPP | + HARDWARE_CURSOR_BIT_ORDER_MSBFIRST | + HARDWARE_CURSOR_INVERT_MASK | + HARDWARE_CURSOR_SWAP_SOURCE_AND_MASK | + HARDWARE_CURSOR_AND_SOURCE_WITH_MASK | + HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64 | 0); + + infoPtr->SetCursorColors = I810SetCursorColors; + infoPtr->SetCursorPosition = I810SetCursorPosition; + infoPtr->LoadCursorImage = I810LoadCursorImage; + infoPtr->HideCursor = I810HideCursor; + infoPtr->ShowCursor = I810ShowCursor; + infoPtr->UseHWCursor = I810UseHWCursor; + + return xf86InitCursor(pScreen, infoPtr); +} + +static Bool +I810UseHWCursor(ScreenPtr pScreen, CursorPtr pCurs) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I810Ptr pI810 = I810PTR(pScrn); + + if (!pI810->CursorPhysical) + return FALSE; + else + return TRUE; +} + +static void +I810LoadCursorImage(ScrnInfoPtr pScrn, unsigned char *src) +{ + I810Ptr pI810 = I810PTR(pScrn); + CARD8 *pcurs = (CARD8 *) (pI810->FbBase + pI810->CursorStart); + int x, y; + + for (y = 0; y < 64; y++) { + for (x = 0; x < 64 / 4; x++) { + *pcurs++ = *src++; + } + } +} + +static void +I810SetCursorPosition(ScrnInfoPtr pScrn, int x, int y) +{ + I810Ptr pI810 = I810PTR(pScrn); + int flag; + + x += pI810->CursorOffset; + + if (x >= 0) + flag = CURSOR_X_POS; + else { + flag = CURSOR_X_NEG; + x = -x; + } + + OUTREG8(CURSOR_X_LO, x & 0xFF); + OUTREG8(CURSOR_X_HI, (((x >> 8) & 0x07) | flag)); + + if (y >= 0) + flag = CURSOR_Y_POS; + else { + flag = CURSOR_Y_NEG; + y = -y; + } + OUTREG8(CURSOR_Y_LO, y & 0xFF); + OUTREG8(CURSOR_Y_HI, (((y >> 8) & 0x07) | flag)); + + OUTREG(CURSOR_BASEADDR, pI810->CursorPhysical); +} + +static void +I810ShowCursor(ScrnInfoPtr pScrn) +{ + I810Ptr pI810 = I810PTR(pScrn); + unsigned char tmp; + + OUTREG(CURSOR_BASEADDR, pI810->CursorPhysical); + OUTREG8(CURSOR_CONTROL, CURSOR_ORIGIN_DISPLAY | CURSOR_MODE_64_3C); + + tmp = INREG8(PIXPIPE_CONFIG_0); + tmp |= HW_CURSOR_ENABLE; + OUTREG8(PIXPIPE_CONFIG_0, tmp); +} + +static void +I810HideCursor(ScrnInfoPtr pScrn) +{ + unsigned char tmp; + I810Ptr pI810 = I810PTR(pScrn); + + tmp = INREG8(PIXPIPE_CONFIG_0); + tmp &= ~HW_CURSOR_ENABLE; + OUTREG8(PIXPIPE_CONFIG_0, tmp); +} + +static void +I810SetCursorColors(ScrnInfoPtr pScrn, int bg, int fg) +{ + int tmp; + I810Ptr pI810 = I810PTR(pScrn); + + tmp = INREG8(PIXPIPE_CONFIG_0); + tmp |= EXTENDED_PALETTE; + OUTREG8(PIXPIPE_CONFIG_0, tmp); + + pI810->writeStandard(pI810, DACMASK, 0xFF); + pI810->writeStandard(pI810, DACWX, 0x04); + + pI810->writeStandard(pI810, DACDATA, (bg & 0x00FF0000) >> 16); + pI810->writeStandard(pI810, DACDATA, (bg & 0x0000FF00) >> 8); + pI810->writeStandard(pI810, DACDATA, (bg & 0x000000FF)); + + pI810->writeStandard(pI810, DACDATA, (fg & 0x00FF0000) >> 16); + pI810->writeStandard(pI810, DACDATA, (fg & 0x0000FF00) >> 8); + pI810->writeStandard(pI810, DACDATA, (fg & 0x000000FF)); + + tmp = INREG8(PIXPIPE_CONFIG_0); + tmp &= ~EXTENDED_PALETTE; + OUTREG8(PIXPIPE_CONFIG_0, tmp); +} diff --git a/src/i810_dga.c b/src/i810_dga.c new file mode 100644 index 00000000..0abac2bf --- /dev/null +++ b/src/i810_dga.c @@ -0,0 +1,293 @@ +/* + * Copyright 2000 by Alan Hourihane, Sychdyn, North Wales, UK. + * + * 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 Alan Hourihane not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Alan Hourihane makes no representations + * about the suitability of this software for any purpose. It is provided + * "as is" without express or implied warranty. + * + * ALAN HOURIHANE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL ALAN HOURIHANE 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. + * + * Authors: Alan Hourihane, <alanh@fairlite.demon.co.uk> + */ +/* + * Reformatted with GNU indent (2.2.8), using the following options: + * + * -bad -bap -c41 -cd0 -ncdb -ci6 -cli0 -cp0 -ncs -d0 -di3 -i3 -ip3 -l78 + * -lp -npcs -psl -sob -ss -br -ce -sc -hnl + * + * This provides a good match with the original i810 code and preferred + * XFree86 formatting conventions. + * + * When editing this driver, please follow the existing formatting, and edit + * with <TAB> characters expanded at 8-column intervals. + */ + +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i810/i810_dga.c,v 1.6 2003/02/26 04:19:36 dawes Exp $ */ + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86_ansic.h" +#include "xf86Pci.h" +#include "xf86PciInfo.h" +#include "xaa.h" +#include "xaalocal.h" +#include "i810.h" +#include "i810_reg.h" +#include "dgaproc.h" +#include "vgaHW.h" + +static Bool I810_OpenFramebuffer(ScrnInfoPtr, char **, unsigned char **, + int *, int *, int *); +static Bool I810_SetMode(ScrnInfoPtr, DGAModePtr); +static void I810_Sync(ScrnInfoPtr); +static int I810_GetViewport(ScrnInfoPtr); +static void I810_SetViewport(ScrnInfoPtr, int, int, int); +static void I810_FillRect(ScrnInfoPtr, int, int, int, int, unsigned long); +static void I810_BlitRect(ScrnInfoPtr, int, int, int, int, int, int); + +#if 0 +static void I810_BlitTransRect(ScrnInfoPtr, int, int, int, int, int, int, + unsigned long); +#endif + +static +DGAFunctionRec I810DGAFuncs = { + I810_OpenFramebuffer, + NULL, + I810_SetMode, + I810_SetViewport, + I810_GetViewport, + I810_Sync, + I810_FillRect, + I810_BlitRect, +#if 0 + I810_BlitTransRect +#else + NULL +#endif +}; + +Bool +I810DGAInit(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I810Ptr pI810 = I810PTR(pScrn); + DGAModePtr modes = NULL, newmodes = NULL, currentMode; + DisplayModePtr pMode, firstMode; + int Bpp = pScrn->bitsPerPixel >> 3; + int num = 0; + + MARKER(); + + pMode = firstMode = pScrn->modes; + + while (pMode) { + + newmodes = xrealloc(modes, (num + 1) * sizeof(DGAModeRec)); + + if (!newmodes) { + xfree(modes); + return FALSE; + } + modes = newmodes; + + currentMode = modes + num; + num++; + + currentMode->mode = pMode; + currentMode->flags = DGA_CONCURRENT_ACCESS | DGA_PIXMAP_AVAILABLE; + if (!pI810->noAccel) + currentMode->flags |= DGA_FILL_RECT | DGA_BLIT_RECT; + if (pMode->Flags & V_DBLSCAN) + currentMode->flags |= DGA_DOUBLESCAN; + if (pMode->Flags & V_INTERLACE) + currentMode->flags |= DGA_INTERLACED; + currentMode->byteOrder = pScrn->imageByteOrder; + currentMode->depth = pScrn->depth; + currentMode->bitsPerPixel = pScrn->bitsPerPixel; + currentMode->red_mask = pScrn->mask.red; + currentMode->green_mask = pScrn->mask.green; + currentMode->blue_mask = pScrn->mask.blue; + currentMode->visualClass = (Bpp == 1) ? PseudoColor : TrueColor; + currentMode->viewportWidth = pMode->HDisplay; + currentMode->viewportHeight = pMode->VDisplay; + currentMode->xViewportStep = (Bpp == 3) ? 2 : 1; + currentMode->yViewportStep = 1; + currentMode->viewportFlags = DGA_FLIP_RETRACE; + currentMode->offset = 0; + currentMode->address = pI810->FbBase; + + currentMode->bytesPerScanline = ((pScrn->displayWidth * Bpp) + 3) & ~3L; + currentMode->imageWidth = pI810->FbMemBox.x2; + currentMode->imageHeight = pI810->FbMemBox.y2; + currentMode->pixmapWidth = currentMode->imageWidth; + currentMode->pixmapHeight = currentMode->imageHeight; + currentMode->maxViewportX = currentMode->imageWidth - + currentMode->viewportWidth; + /* this might need to get clamped to some maximum */ + currentMode->maxViewportY = currentMode->imageHeight - + currentMode->viewportHeight; + + pMode = pMode->next; + if (pMode == firstMode) + break; + } + + pI810->numDGAModes = num; + pI810->DGAModes = modes; + + return DGAInit(pScreen, &I810DGAFuncs, modes, num); +} + +static DisplayModePtr I810SavedDGAModes[MAXSCREENS]; + +static Bool +I810_SetMode(ScrnInfoPtr pScrn, DGAModePtr pMode) +{ + int index = pScrn->pScreen->myNum; + I810Ptr pI810 = I810PTR(pScrn); + + MARKER(); + + if (!pMode) { /* restore the original mode */ + DPRINTF(PFX, "Restoring original mode (from DGA mode)\n"); + if (pI810->DGAactive) { + pScrn->currentMode = I810SavedDGAModes[index]; + pScrn->SwitchMode(index, pScrn->currentMode, 0); + pScrn->AdjustFrame(index, 0, 0, 0); + pI810->DGAactive = FALSE; + } + } else { + if (!pI810->DGAactive) { + DPRINTF(PFX, "Setting DGA mode\n"); + I810SavedDGAModes[index] = pScrn->currentMode; + pI810->DGAactive = TRUE; + } + + pScrn->SwitchMode(index, pMode->mode, 0); + } + + return TRUE; +} + +static int +I810_GetViewport(ScrnInfoPtr pScrn) +{ + I810Ptr pI810 = I810PTR(pScrn); + + MARKER(); + + return pI810->DGAViewportStatus; +} + +static void +I810_SetViewport(ScrnInfoPtr pScrn, int x, int y, int flags) +{ + I810Ptr pI810 = I810PTR(pScrn); + vgaHWPtr hwp = VGAHWPTR(pScrn); + + MARKER(); + + pScrn->AdjustFrame(pScrn->pScreen->myNum, x, y, flags); + + /* wait for retrace */ + while ((hwp->readST01(hwp) & 0x08)) ; + while (!(hwp->readST01(hwp) & 0x08)) ; + + pI810->DGAViewportStatus = 0; +} + +static void +I810_FillRect(ScrnInfoPtr pScrn, + int x, int y, int w, int h, unsigned long color) +{ + I810Ptr pI810 = I810PTR(pScrn); + + MARKER(); + + if (pI810->AccelInfoRec) { + (*pI810->AccelInfoRec->SetupForSolidFill) (pScrn, color, GXcopy, ~0); + (*pI810->AccelInfoRec->SubsequentSolidFillRect) (pScrn, x, y, w, h); + SET_SYNC_FLAG(pI810->AccelInfoRec); + } +} + +static void +I810_Sync(ScrnInfoPtr pScrn) +{ + I810Ptr pI810 = I810PTR(pScrn); + + MARKER(); + + if (pI810->AccelInfoRec) { + (*pI810->AccelInfoRec->Sync) (pScrn); + } +} + +static void +I810_BlitRect(ScrnInfoPtr pScrn, + int srcx, int srcy, int w, int h, int dstx, int dsty) +{ + I810Ptr pI810 = I810PTR(pScrn); + + MARKER(); + + if (pI810->AccelInfoRec) { + int xdir = ((srcx < dstx) && (srcy == dsty)) ? -1 : 1; + int ydir = (srcy < dsty) ? -1 : 1; + + (*pI810->AccelInfoRec->SetupForScreenToScreenCopy) (pScrn, xdir, ydir, + GXcopy, ~0, -1); + (*pI810->AccelInfoRec->SubsequentScreenToScreenCopy) (pScrn, srcx, srcy, + dstx, dsty, w, h); + SET_SYNC_FLAG(pI810->AccelInfoRec); + } +} + +#if 0 +static void +I810_BlitTransRect(ScrnInfoPtr pScrn, + int srcx, int srcy, + int w, int h, int dstx, int dsty, unsigned long color) +{ + + MARKER(); + + /* this one should be separate since the XAA function would + * prohibit usage of ~0 as the key */ +} +#endif + +static Bool +I810_OpenFramebuffer(ScrnInfoPtr pScrn, + char **name, + unsigned char **mem, int *size, int *offset, int *flags) +{ + I810Ptr pI810 = I810PTR(pScrn); + + MARKER(); + + *name = NULL; /* no special device */ + *mem = (unsigned char *)pI810->LinearAddr; + *size = pI810->FbMapSize; + *offset = 0; + *flags = DGA_NEED_ROOT; + + DPRINTF(PFX, + " mem == 0x%.8x (pI810->LinearAddr)\n" + "size == %lu (pI810->FbMapSize)\n", *mem, *size); + + return TRUE; +} diff --git a/src/i810_dri.c b/src/i810_dri.c new file mode 100644 index 00000000..11ecacf0 --- /dev/null +++ b/src/i810_dri.c @@ -0,0 +1,1220 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i810/i810_dri.c,v 1.33 2002/12/10 01:27:04 dawes Exp $ */ +/* + * Reformatted with GNU indent (2.2.8), using the following options: + * + * -bad -bap -c41 -cd0 -ncdb -ci6 -cli0 -cp0 -ncs -d0 -di3 -i3 -ip3 -l78 + * -lp -npcs -psl -sob -ss -br -ce -sc -hnl + * + * This provides a good match with the original i810 code and preferred + * XFree86 formatting conventions. + * + * When editing this driver, please follow the existing formatting, and edit + * with <TAB> characters expanded at 8-column intervals. + */ + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86_ansic.h" +#include "xf86Priv.h" + +#include "xf86PciInfo.h" +#include "xf86Pci.h" + +#include "windowstr.h" + +#include "GL/glxtokens.h" + +#include "i810.h" +#include "i810_dri.h" + +static char I810KernelDriverName[] = "i810"; +static char I810ClientDriverName[] = "i810"; + +static Bool I810InitVisualConfigs(ScreenPtr pScreen); +static Bool I810CreateContext(ScreenPtr pScreen, VisualPtr visual, + drmContext hwContext, void *pVisualConfigPriv, + DRIContextType contextStore); +static void I810DestroyContext(ScreenPtr pScreen, drmContext hwContext, + DRIContextType contextStore); +static void I810DRISwapContext(ScreenPtr pScreen, DRISyncType syncType, + DRIContextType readContextType, + void *readContextStore, + DRIContextType writeContextType, + void *writeContextStore); +static void I810DRIInitBuffers(WindowPtr pWin, RegionPtr prgn, CARD32 index); +static void I810DRIMoveBuffers(WindowPtr pParent, DDXPointRec ptOldOrg, + RegionPtr prgnSrc, CARD32 index); + +extern void GlxSetVisualConfigs(int nconfigs, + __GLXvisualConfig * configs, + void **configprivs); + +static int i810_pitches[] = { + 512, + 1024, + 2048, + 4096, + 0 +}; + +static int i810_pitch_flags[] = { + 0x0, + 0x1, + 0x2, + 0x3, + 0 +}; + +Bool +I810CleanupDma(ScrnInfoPtr pScrn) +{ + I810Ptr pI810 = I810PTR(pScrn); + drmI810Init info; + + memset(&info, 0, sizeof(drmI810Init)); + info.func = I810_CLEANUP_DMA; + + if (drmCommandWrite(pI810->drmSubFD, DRM_I810_INIT, + &info, sizeof(drmI810Init))) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "[dri] I810 Dma Cleanup Failed\n"); + return FALSE; + } + + return TRUE; +} + +Bool +I810InitDma(ScrnInfoPtr pScrn) +{ + I810Ptr pI810 = I810PTR(pScrn); + I810RingBuffer *ring = &(pI810->LpRing); + I810DRIPtr pI810DRI = (I810DRIPtr) pI810->pDRIInfo->devPrivate; + drmI810Init info; + + memset(&info, 0, sizeof(drmI810Init)); + + info.func = I810_INIT_DMA; + + info.ring_start = ring->mem.Start; + info.ring_end = ring->mem.End; + info.ring_size = ring->mem.Size; + info.mmio_offset = (unsigned int)pI810DRI->regs; + info.buffers_offset = (unsigned int)pI810->buffer_map; + info.sarea_priv_offset = sizeof(XF86DRISAREARec); + + info.front_offset = 0; + info.back_offset = pI810->BackBuffer.Start; + info.depth_offset = pI810->DepthBuffer.Start; + info.overlay_offset = pI810->OverlayStart; + info.overlay_physical = pI810->OverlayPhysical; + info.w = pScrn->virtualX; + info.h = pScrn->virtualY; + info.pitch = pI810->auxPitch; + info.pitch_bits = pI810->auxPitchBits; + + if (drmCommandWrite(pI810->drmSubFD, DRM_I810_INIT, + &info, sizeof(drmI810Init))) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "[drm] I810 Dma Initialization failed.\n"); + return FALSE; + } + + return TRUE; +} + +static Bool +I810InitVisualConfigs(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I810Ptr pI810 = I810PTR(pScrn); + int numConfigs = 0; + __GLXvisualConfig *pConfigs = 0; + I810ConfigPrivPtr pI810Configs = 0; + I810ConfigPrivPtr *pI810ConfigPtrs = 0; + int accum, stencil, db, depth; + int i; + + switch (pScrn->bitsPerPixel) { + case 8: + case 24: + case 32: + break; + case 16: + numConfigs = 8; + + pConfigs = + (__GLXvisualConfig *) xcalloc(sizeof(__GLXvisualConfig), + numConfigs); + if (!pConfigs) + return FALSE; + + pI810Configs = + (I810ConfigPrivPtr) xcalloc(sizeof(I810ConfigPrivRec), + numConfigs); + if (!pI810Configs) { + xfree(pConfigs); + return FALSE; + } + + pI810ConfigPtrs = + (I810ConfigPrivPtr *) xcalloc(sizeof(I810ConfigPrivPtr), + numConfigs); + if (!pI810ConfigPtrs) { + xfree(pConfigs); + xfree(pI810Configs); + return FALSE; + } + + for (i = 0; i < numConfigs; i++) + pI810ConfigPtrs[i] = &pI810Configs[i]; + + i = 0; + depth = 1; + for (accum = 0; accum <= 1; accum++) { + for (stencil = 0; stencil <= 1; stencil++) { + for (db = 1; db >= 0; db--) { + pConfigs[i].vid = -1; + pConfigs[i].class = -1; + pConfigs[i].rgba = TRUE; + pConfigs[i].redSize = 5; + pConfigs[i].greenSize = 6; + pConfigs[i].blueSize = 5; + pConfigs[i].redMask = 0x0000F800; + pConfigs[i].greenMask = 0x000007E0; + pConfigs[i].blueMask = 0x0000001F; + pConfigs[i].alphaMask = 0; + if (accum) { + pConfigs[i].accumRedSize = 16; + pConfigs[i].accumGreenSize = 16; + pConfigs[i].accumBlueSize = 16; + pConfigs[i].accumAlphaSize = 16; + } else { + pConfigs[i].accumRedSize = 0; + pConfigs[i].accumGreenSize = 0; + pConfigs[i].accumBlueSize = 0; + pConfigs[i].accumAlphaSize = 0; + } + pConfigs[i].doubleBuffer = db ? TRUE : FALSE; + pConfigs[i].stereo = FALSE; + pConfigs[i].bufferSize = 16; + if (depth) + pConfigs[i].depthSize = 16; + else + pConfigs[i].depthSize = 0; + if (stencil) + pConfigs[i].stencilSize = 8; + else + pConfigs[i].stencilSize = 0; + pConfigs[i].auxBuffers = 0; + pConfigs[i].level = 0; + if (stencil || accum) + pConfigs[i].visualRating = GLX_SLOW_VISUAL_EXT; + else + pConfigs[i].visualRating = GLX_NONE_EXT; + pConfigs[i].transparentPixel = 0; + pConfigs[i].transparentRed = 0; + pConfigs[i].transparentGreen = 0; + pConfigs[i].transparentBlue = 0; + pConfigs[i].transparentAlpha = 0; + pConfigs[i].transparentIndex = 0; + i++; + } + } + } + assert(i == numConfigs); + break; + } + pI810->numVisualConfigs = numConfigs; + pI810->pVisualConfigs = pConfigs; + pI810->pVisualConfigsPriv = pI810Configs; + GlxSetVisualConfigs(numConfigs, pConfigs, (void **)pI810ConfigPtrs); + return TRUE; +} + +static unsigned int +mylog2(unsigned int n) +{ + unsigned int log2 = 1; + + while (n > 1) + n >>= 1, log2++; + return log2; +} + +Bool +I810DRIScreenInit(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I810Ptr pI810 = I810PTR(pScrn); + DRIInfoPtr pDRIInfo; + I810DRIPtr pI810DRI; + unsigned long tom; + unsigned long agpHandle; + unsigned long dcacheHandle; + int sysmem_size = 0; + int back_size = 0; + int pitch_idx = 0; + int bufs; + int width = pScrn->displayWidth * pI810->cpp; + int i; + + /* Hardware 3D rendering only implemented for 16bpp */ + /* And it only works for 5:6:5 (Mark) */ + if (pScrn->depth != 16) + return FALSE; + + /* Check that the GLX, DRI, and DRM modules have been loaded by testing + * for known symbols in each module. */ + if (!xf86LoaderCheckSymbol("GlxSetVisualConfigs")) + return FALSE; + if (!xf86LoaderCheckSymbol("DRIScreenInit")) + return FALSE; + if (!xf86LoaderCheckSymbol("drmAvailable")) + return FALSE; + if (!xf86LoaderCheckSymbol("DRIQueryVersion")) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[dri] I810DRIScreenInit failed (libdri.a too old)\n"); + return FALSE; + } + + /* Check the DRI version */ + { + int major, minor, patch; + + DRIQueryVersion(&major, &minor, &patch); + if (major != 4 || minor < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[dri] I810DRIScreenInit failed because of a version mismatch.\n" + "[dri] libDRI version is %d.%d.%d bug version 4.0.x is needed.\n" + "[dri] Disabling DRI.\n", major, minor, patch); + return FALSE; + } + } + + pDRIInfo = DRICreateInfoRec(); + if (!pDRIInfo) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[dri] DRICreateInfoRec failed. Disabling DRI.\n"); + return FALSE; + } + +/* pDRIInfo->wrap.ValidateTree = 0; */ +/* pDRIInfo->wrap.PostValidateTree = 0; */ + + pI810->pDRIInfo = pDRIInfo; + pI810->LockHeld = 0; + + pDRIInfo->drmDriverName = I810KernelDriverName; + pDRIInfo->clientDriverName = I810ClientDriverName; + pDRIInfo->busIdString = xalloc(64); + + sprintf(pDRIInfo->busIdString, "PCI:%d:%d:%d", + ((pciConfigPtr) pI810->PciInfo->thisCard)->busnum, + ((pciConfigPtr) pI810->PciInfo->thisCard)->devnum, + ((pciConfigPtr) pI810->PciInfo->thisCard)->funcnum); + pDRIInfo->ddxDriverMajorVersion = I810_MAJOR_VERSION; + pDRIInfo->ddxDriverMinorVersion = I810_MINOR_VERSION; + pDRIInfo->ddxDriverPatchVersion = I810_PATCHLEVEL; + pDRIInfo->frameBufferPhysicalAddress = pI810->LinearAddr; + pDRIInfo->frameBufferSize = (((pScrn->displayWidth * + pScrn->virtualY * pI810->cpp) + + 4096 - 1) / 4096) * 4096; + + pDRIInfo->frameBufferStride = pScrn->displayWidth * pI810->cpp; + pDRIInfo->ddxDrawableTableEntry = I810_MAX_DRAWABLES; + + if (SAREA_MAX_DRAWABLES < I810_MAX_DRAWABLES) + pDRIInfo->maxDrawableTableEntry = SAREA_MAX_DRAWABLES; + else + pDRIInfo->maxDrawableTableEntry = I810_MAX_DRAWABLES; + + /* For now the mapping works by using a fixed size defined + * in the SAREA header + */ + if (sizeof(XF86DRISAREARec) + sizeof(I810SAREARec) > SAREA_MAX) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[dri] Data does not fit in SAREA\n"); + return FALSE; + } + pDRIInfo->SAREASize = SAREA_MAX; + + if (!(pI810DRI = (I810DRIPtr) xcalloc(sizeof(I810DRIRec), 1))) { + DRIDestroyInfoRec(pI810->pDRIInfo); + pI810->pDRIInfo = 0; + return FALSE; + } + pDRIInfo->devPrivate = pI810DRI; + pDRIInfo->devPrivateSize = sizeof(I810DRIRec); + pDRIInfo->contextSize = sizeof(I810DRIContextRec); + + pDRIInfo->CreateContext = I810CreateContext; + pDRIInfo->DestroyContext = I810DestroyContext; + pDRIInfo->SwapContext = I810DRISwapContext; + pDRIInfo->InitBuffers = I810DRIInitBuffers; + pDRIInfo->MoveBuffers = I810DRIMoveBuffers; + pDRIInfo->bufferRequests = DRI_ALL_WINDOWS; + + pDRIInfo->createDummyCtx = TRUE; + pDRIInfo->createDummyCtxPriv = FALSE; + + /* This adds the framebuffer as a drm map *before* we have asked agp + * to allocate it. Scary stuff, hold on... + */ + if (!DRIScreenInit(pScreen, pDRIInfo, &pI810->drmSubFD)) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[dri] DRIScreenInit failed. Disabling DRI.\n"); + xfree(pDRIInfo->devPrivate); + pDRIInfo->devPrivate = 0; + DRIDestroyInfoRec(pI810->pDRIInfo); + pI810->pDRIInfo = 0; + return FALSE; + } + + /* Check the i810 DRM versioning */ + { + drmVersionPtr version; + + /* Check the DRM lib version. + * drmGetLibVersion was not supported in version 1.0, so check for + * symbol first to avoid possible crash or hang. + */ + if (xf86LoaderCheckSymbol("drmGetLibVersion")) { + version = drmGetLibVersion(pI810->drmSubFD); + } else + { + /* drmlib version 1.0.0 didn't have the drmGetLibVersion + * entry point. Fake it by allocating a version record + * via drmGetVersion and changing it to version 1.0.0 + */ + version = drmGetVersion(pI810->drmSubFD); + version->version_major = 1; + version->version_minor = 0; + version->version_patchlevel = 0; + } + +#define REQ_MAJ 1 +#define REQ_MIN 1 + if (version) { + if (version->version_major != REQ_MAJ || + version->version_minor < REQ_MIN) { + /* incompatible drm library version */ + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[dri] I810DRIScreenInit failed because of a version mismatch.\n" + "[dri] libdrm.a module version is %d.%d.%d but version %d.%d.x is needed.\n" + "[dri] Disabling DRI.\n", + version->version_major, + version->version_minor, version->version_patchlevel, + REQ_MAJ, REQ_MIN); + drmFreeVersion(version); + I810DRICloseScreen(pScreen); + return FALSE; + } + drmFreeVersion(version); + } + + /* Check the i810 DRM version */ + version = drmGetVersion(pI810->drmSubFD); + if (version) { + if (version->version_major != 1 || version->version_minor < 2) { + /* incompatible drm version */ + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[dri] I810DRIScreenInit failed because of a version mismatch.\n" + "[dri] i810.o kernel module version is %d.%d.%d but version 1.2.0 or greater is needed.\n" + "[dri] Disabling DRI.\n", + version->version_major, + version->version_minor, version->version_patchlevel); + I810DRICloseScreen(pScreen); + drmFreeVersion(version); + return FALSE; + } + drmFreeVersion(version); + } + } + + pI810DRI->regsSize = I810_REG_SIZE; + if (drmAddMap(pI810->drmSubFD, (drmHandle) pI810->MMIOAddr, + pI810DRI->regsSize, DRM_REGISTERS, 0, &pI810DRI->regs) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, "[drm] drmAddMap(regs) failed\n"); + DRICloseScreen(pScreen); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, "[drm] Registers = 0x%08lx\n", + pI810DRI->regs); + + pI810->backHandle = 0; + pI810->zHandle = 0; + pI810->cursorHandle = 0; + pI810->xvmcHandle = 0; + pI810->sysmemHandle = 0; + pI810->agpAcquired = FALSE; + pI810->dcacheHandle = 0; + + /* Agp Support - Need this just to get the framebuffer. + */ + if (drmAgpAcquire(pI810->drmSubFD) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, "[agp] drmAgpAquire failed\n"); + DRICloseScreen(pScreen); + return FALSE; + } + pI810->agpAcquired = TRUE; + + if (drmAgpEnable(pI810->drmSubFD, 0) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, "[agp] drmAgpEnable failed\n"); + DRICloseScreen(pScreen); + return FALSE; + } + + memset(&pI810->DcacheMem, 0, sizeof(I810MemRange)); + memset(&pI810->BackBuffer, 0, sizeof(I810MemRange)); + memset(&pI810->DepthBuffer, 0, sizeof(I810MemRange)); + pI810->CursorPhysical = 0; + + /* Dcache - half the speed of normal ram, but has use as a Z buffer + * under the DRI. + */ + + drmAgpAlloc(pI810->drmSubFD, 4096 * 1024, 1, NULL, &dcacheHandle); + pI810->dcacheHandle = dcacheHandle; + xf86DrvMsg(pScreen->myNum, X_INFO, "[agp] dcacheHandle : %p\n", + dcacheHandle); + +#define Elements(x) sizeof(x)/sizeof(*x) + for (pitch_idx = 0; pitch_idx < Elements(i810_pitches); pitch_idx++) + if (width <= i810_pitches[pitch_idx]) + break; + + if (pitch_idx == Elements(i810_pitches)) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[dri] Couldn't find depth/back buffer pitch"); + DRICloseScreen(pScreen); + return FALSE; + } else { + back_size = i810_pitches[pitch_idx] * (pScrn->virtualY + 4); + back_size = ((back_size + 4096 - 1) / 4096) * 4096; + } + + sysmem_size = pScrn->videoRam * 1024; + if (dcacheHandle != 0) { + if (back_size > 4 * 1024 * 1024) { + xf86DrvMsg(pScreen->myNum, X_INFO, + "[dri] Backsize is larger then 4 meg\n"); + sysmem_size = sysmem_size - 2 * back_size; + drmAgpFree(pI810->drmSubFD, dcacheHandle); + pI810->dcacheHandle = dcacheHandle = 0; + } else { + sysmem_size = sysmem_size - back_size; + } + } else { + sysmem_size = sysmem_size - 2 * back_size; + } + + /* Max size is 48 without XvMC, 41 with 6 surfaces, 40 with 7 surfaces */ + if (pI810->numSurfaces && (pI810->numSurfaces == 6)) { + if (sysmem_size > (pI810->FbMapSize - 7 * 1024 * 1024)) { + sysmem_size = (pI810->FbMapSize - 7 * 1024 * 1024); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "User requested more memory then fits in the agp aperture\n" + "Truncating to %d bytes of memory\n", sysmem_size); + } + } + if (pI810->numSurfaces && (pI810->numSurfaces == 7)) { + if (sysmem_size > (pI810->FbMapSize - 8 * 1024 * 1024)) { + sysmem_size = (pI810->FbMapSize - 8 * 1024 * 1024); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "User requested more memory then fits in the agp aperture\n" + "Truncating to %d bytes of memory\n", sysmem_size); + } + } + + if (sysmem_size > pI810->FbMapSize) { + sysmem_size = pI810->FbMapSize; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[dri] User requested more memory then fits in the agp" + " aperture\n\tTruncating to %d bytes of memory\n", + sysmem_size); + } + + sysmem_size -= 4096; /* remove 4k for the hw cursor */ + + pI810->SysMem.Start = 0; + pI810->SysMem.Size = sysmem_size; + pI810->SysMem.End = sysmem_size; + tom = sysmem_size; + + pI810->SavedSysMem = pI810->SysMem; + + if (dcacheHandle != 0) { + if (drmAgpBind(pI810->drmSubFD, dcacheHandle, pI810->DepthOffset) == 0) { + memset(&pI810->DcacheMem, 0, sizeof(I810MemRange)); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[agp] GART: Found 4096K Z buffer memory\n"); + pI810->DcacheMem.Start = pI810->DepthOffset; + pI810->DcacheMem.Size = 1024 * 4096; + pI810->DcacheMem.End = + pI810->DcacheMem.Start + pI810->DcacheMem.Size; + if (!I810AllocLow + (&(pI810->DepthBuffer), &(pI810->DcacheMem), back_size)) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[agp] Depth buffer allocation failed\n"); + DRICloseScreen(pScreen); + return FALSE; + } + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[agp] GART: dcache bind failed\n"); + drmAgpFree(pI810->drmSubFD, dcacheHandle); + pI810->dcacheHandle = dcacheHandle = 0; + } + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[agp] GART: no dcache memory found\n"); + } + + drmAgpAlloc(pI810->drmSubFD, back_size, 0, NULL, &agpHandle); + pI810->backHandle = agpHandle; + + if (agpHandle != 0) { + if (drmAgpBind(pI810->drmSubFD, agpHandle, pI810->BackOffset) == 0) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[agp] Bound backbuffer memory\n"); + + pI810->BackBuffer.Start = pI810->BackOffset; + pI810->BackBuffer.Size = back_size; + pI810->BackBuffer.End = (pI810->BackBuffer.Start + + pI810->BackBuffer.Size); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[agp] Unable to bind backbuffer. Disabling DRI.\n"); + DRICloseScreen(pScreen); + return FALSE; + } + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[dri] Unable to allocate backbuffer memory. Disabling DRI.\n"); + DRICloseScreen(pScreen); + return FALSE; + } + + if (dcacheHandle == 0) { + drmAgpAlloc(pI810->drmSubFD, back_size, 0, NULL, &agpHandle); + pI810->zHandle = agpHandle; + + if (agpHandle != 0) { + if (drmAgpBind(pI810->drmSubFD, agpHandle, pI810->DepthOffset) == 0) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[agp] Bound depthbuffer memory\n"); + pI810->DepthBuffer.Start = pI810->DepthOffset; + pI810->DepthBuffer.Size = back_size; + pI810->DepthBuffer.End = (pI810->DepthBuffer.Start + + pI810->DepthBuffer.Size); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[agp] Unable to bind depthbuffer. Disabling DRI.\n"); + DRICloseScreen(pScreen); + return FALSE; + } + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[agp] Unable to allocate depthbuffer memory. Disabling DRI.\n"); + DRICloseScreen(pScreen); + return FALSE; + } + } + + /* Now allocate and bind the agp space. This memory will include the + * regular framebuffer as well as texture memory. + */ + drmAgpAlloc(pI810->drmSubFD, sysmem_size, 0, NULL, &agpHandle); + if (agpHandle == 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, "[agp] drmAgpAlloc failed\n"); + DRICloseScreen(pScreen); + return FALSE; + } + pI810->sysmemHandle = agpHandle; + + if (drmAgpBind(pI810->drmSubFD, agpHandle, 0) != 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, "[agp] drmAgpBind failed\n"); + DRICloseScreen(pScreen); + return FALSE; + } + +/* Allocate 7 or 8MB for XvMC this is setup as follows to best use tiled + regions and required surface pitches. (Numbers are adjusted if the + AGP region is only 32MB + For numSurfaces == 6 + 44 - 48MB = 4MB Fence, 8 Tiles wide + 43 - 44MB = 1MB Fence, 8 Tiles wide + 42 - 43MB = 1MB Fence, 4 Tiles wide + 41 - 42MB = 1MB Fence, 4 Tiles wide + For numSurfaces == 7 + 44 - 48MB = 4MB Fence, 8 Tiles wide + 43 - 44MB = 1MB Fence, 8 Tiles wide + 42.5 - 43MB = 0.5MB Fence, 8 Tiles wide + 42 - 42.5MB = 0.5MB Fence, 4 Tiles wide + 40 - 42MB = 2MB Fence, 4 Tiles wide + */ + if (pI810->numSurfaces) { + if (pI810->numSurfaces == 6) { + pI810->MC.Size = 7 * 1024 * 1024; + pI810->MC.Start = pI810->FbMapSize - 7 * 1024 * 1024; + + } + if (pI810->numSurfaces == 7) { + pI810->MC.Size = 8 * 1024 * 1024; + pI810->MC.Start = pI810->FbMapSize - 8 * 1024 * 1024; + } + drmAgpAlloc(pI810->drmSubFD, pI810->MC.Size, 0, NULL, &agpHandle); + pI810->xvmcHandle = agpHandle; + + if (agpHandle != 0) { + if (drmAgpBind(pI810->drmSubFD, agpHandle, pI810->MC.Start) == 0) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "GART: Allocated 7MB for HWMC\n"); + pI810->MC.End = pI810->MC.Start + pI810->MC.Size; + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "GART: HWMC bind failed\n"); + pI810->MC.Start = 0; + pI810->MC.Size = 0; + pI810->MC.End = 0; + } + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "GART: HWMC alloc failed\n"); + pI810->MC.Start = 0; + pI810->MC.Size = 0; + pI810->MC.End = 0; + } + pI810->xvmcContext = 0; + } + + drmAgpAlloc(pI810->drmSubFD, 4096, 2, + (unsigned long *)&pI810->CursorPhysical, &agpHandle); + pI810->cursorHandle = agpHandle; + + if (agpHandle != 0) { + tom = sysmem_size; + + if (drmAgpBind(pI810->drmSubFD, agpHandle, tom) == 0) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[agp] GART: Allocated 4K for mouse cursor image\n"); + pI810->CursorStart = tom; + tom += 4096; + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[agp] GART: cursor bind failed\n"); + pI810->CursorPhysical = 0; + } + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[agp] GART: cursor alloc failed\n"); + pI810->CursorPhysical = 0; + } + + /* Steal some of the excess cursor space for the overlay regs. + */ + pI810->OverlayPhysical = pI810->CursorPhysical + 1024; + pI810->OverlayStart = pI810->CursorStart + 1024; + + I810SetTiledMemory(pScrn, 1, + pI810->DepthBuffer.Start, + i810_pitches[pitch_idx], 8 * 1024 * 1024); + + I810SetTiledMemory(pScrn, 2, + pI810->BackBuffer.Start, + i810_pitches[pitch_idx], 8 * 1024 * 1024); + + /* These are for HWMC surfaces */ + if (pI810->numSurfaces == 6) { + I810SetTiledMemory(pScrn, 3, pI810->MC.Start, 512, 1024 * 1024); + + I810SetTiledMemory(pScrn, 4, + pI810->MC.Start + 1024 * 1024, 512, 1024 * 1024); + + I810SetTiledMemory(pScrn, 5, + pI810->MC.Start + 1024 * 1024 * 2, + 1024, 1024 * 1024); + + I810SetTiledMemory(pScrn, 6, + pI810->MC.Start + 1024 * 1024 * 3, + 1024, 4 * 1024 * 1024); + } + if (pI810->numSurfaces == 7) { + I810SetTiledMemory(pScrn, 3, pI810->MC.Start, 512, 2 * 1024 * 1024); + + I810SetTiledMemory(pScrn, 4, + pI810->MC.Start + 2 * 1024 * 1024, 512, 512 * 1024); + + I810SetTiledMemory(pScrn, 5, + pI810->MC.Start + 2 * 1024 * 1024 + 512 * 1024, + 1024, 512 * 1024); + + I810SetTiledMemory(pScrn, 6, + pI810->MC.Start + 3 * 1024 * 1024, + 1024, 1 * 1024 * 1024); + + I810SetTiledMemory(pScrn, 7, + pI810->MC.Start + 4 * 1024 * 1024, + 1024, 4 * 1024 * 1024); + + } + + pI810->auxPitch = i810_pitches[pitch_idx]; + pI810->auxPitchBits = i810_pitch_flags[pitch_idx]; + pI810->SavedDcacheMem = pI810->DcacheMem; + pI810DRI->backbufferSize = pI810->BackBuffer.Size; + + if (drmAddMap(pI810->drmSubFD, (drmHandle) pI810->BackBuffer.Start, + pI810->BackBuffer.Size, DRM_AGP, 0, + &pI810DRI->backbuffer) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[drm] drmAddMap(backbuffer) failed. Disabling DRI\n"); + DRICloseScreen(pScreen); + return FALSE; + } + + pI810DRI->depthbufferSize = pI810->DepthBuffer.Size; + if (drmAddMap(pI810->drmSubFD, (drmHandle) pI810->DepthBuffer.Start, + pI810->DepthBuffer.Size, DRM_AGP, 0, + &pI810DRI->depthbuffer) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[drm] drmAddMap(depthbuffer) failed. Disabling DRI.\n"); + DRICloseScreen(pScreen); + return FALSE; + } + + /* Allocate FrontBuffer etc. */ + if (!I810AllocateFront(pScrn)) { + DRICloseScreen(pScreen); + return FALSE; + } + + /* Allocate buffer memory */ + I810AllocHigh(&(pI810->BufferMem), &(pI810->SysMem), + I810_DMA_BUF_NR * I810_DMA_BUF_SZ); + + xf86DrvMsg(pScreen->myNum, X_INFO, "[dri] Buffer map : %lx\n", + pI810->BufferMem.Start); + + if (pI810->BufferMem.Start == 0 || + pI810->BufferMem.End - pI810->BufferMem.Start > + I810_DMA_BUF_NR * I810_DMA_BUF_SZ) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[dri] Not enough memory for dma buffers. Disabling DRI.\n"); + DRICloseScreen(pScreen); + return FALSE; + } + if (drmAddMap(pI810->drmSubFD, (drmHandle) pI810->BufferMem.Start, + pI810->BufferMem.Size, DRM_AGP, 0, &pI810->buffer_map) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[drm] drmAddMap(buffer_map) failed. Disabling DRI.\n"); + DRICloseScreen(pScreen); + return FALSE; + } + + pI810DRI->agp_buffers = pI810->buffer_map; + pI810DRI->agp_buf_size = pI810->BufferMem.Size; + + if (drmAddMap(pI810->drmSubFD, (drmHandle) pI810->LpRing.mem.Start, + pI810->LpRing.mem.Size, DRM_AGP, 0, &pI810->ring_map) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[drm] drmAddMap(ring_map) failed. Disabling DRI.\n"); + DRICloseScreen(pScreen); + return FALSE; + } + + /* Use the rest of memory for textures. */ + pI810DRI->textureSize = pI810->SysMem.Size; + + i = mylog2(pI810DRI->textureSize / I810_NR_TEX_REGIONS); + + if (i < I810_LOG_MIN_TEX_REGION_SIZE) + i = I810_LOG_MIN_TEX_REGION_SIZE; + + pI810DRI->logTextureGranularity = i; + pI810DRI->textureSize = (pI810DRI->textureSize >> i) << i; /* truncate */ + + if (pI810DRI->textureSize < 512 * 1024) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[drm] Less then 512k memory left for textures. Disabling DRI.\n"); + DRICloseScreen(pScreen); + return FALSE; + } + + I810AllocLow(&(pI810->TexMem), &(pI810->SysMem), pI810DRI->textureSize); + + if (drmAddMap(pI810->drmSubFD, (drmHandle) pI810->TexMem.Start, + pI810->TexMem.Size, DRM_AGP, 0, &pI810DRI->textures) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[drm] drmAddMap(textures) failed. Disabling DRI.\n"); + DRICloseScreen(pScreen); + return FALSE; + } + + if ((bufs = drmAddBufs(pI810->drmSubFD, + I810_DMA_BUF_NR, + I810_DMA_BUF_SZ, + DRM_AGP_BUFFER, pI810->BufferMem.Start)) <= 0) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[drm] failure adding %d %d byte DMA buffers. Disabling DRI.\n", + I810_DMA_BUF_NR, I810_DMA_BUF_SZ); + DRICloseScreen(pScreen); + return FALSE; + } + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[drm] added %d %d byte DMA buffers\n", bufs, I810_DMA_BUF_SZ); + + I810InitDma(pScrn); + + /* Okay now initialize the dma engine */ + + if (!pI810DRI->irq) { + pI810DRI->irq = drmGetInterruptFromBusID(pI810->drmSubFD, + ((pciConfigPtr) pI810-> + PciInfo->thisCard)->busnum, + ((pciConfigPtr) pI810-> + PciInfo->thisCard)->devnum, + ((pciConfigPtr) pI810-> + PciInfo->thisCard)->funcnum); + if ((drmCtlInstHandler(pI810->drmSubFD, pI810DRI->irq)) != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[drm] failure adding irq handler, there is a device " + "already using that irq\n Consider rearranging your " + "PCI cards. Disabling DRI.\n"); + DRICloseScreen(pScreen); + return FALSE; + } + } + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[drm] dma control initialized, using IRQ %d\n", pI810DRI->irq); + + pI810DRI->deviceID = pI810->PciInfo->chipType; + pI810DRI->width = pScrn->virtualX; + pI810DRI->height = pScrn->virtualY; + pI810DRI->mem = pScrn->videoRam * 1024; + pI810DRI->cpp = pI810->cpp; + + pI810DRI->fbOffset = pI810->FrontBuffer.Start; + pI810DRI->fbStride = pI810->auxPitch; + + pI810DRI->bitsPerPixel = pScrn->bitsPerPixel; + + pI810DRI->textureOffset = pI810->TexMem.Start; + + pI810DRI->backOffset = pI810->BackBuffer.Start; + pI810DRI->depthOffset = pI810->DepthBuffer.Start; + + pI810DRI->ringOffset = pI810->LpRing.mem.Start; + pI810DRI->ringSize = pI810->LpRing.mem.Size; + + pI810DRI->auxPitch = pI810->auxPitch; + pI810DRI->auxPitchBits = pI810->auxPitchBits; + pI810DRI->sarea_priv_offset = sizeof(XF86DRISAREARec); + + if (!(I810InitVisualConfigs(pScreen))) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[dri] I810InitVisualConfigs failed. Disabling DRI.\n"); + DRICloseScreen(pScreen); + return FALSE; + } + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[dri] visual configs initialized.\n"); + pI810->pDRIInfo->driverSwapMethod = DRI_HIDE_X_CONTEXT; + + return TRUE; +} + +void +I810DRICloseScreen(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I810Ptr pI810 = I810PTR(pScrn); + + I810CleanupDma(pScrn); + + if (pI810->dcacheHandle) + drmAgpFree(pI810->drmSubFD, pI810->dcacheHandle); + if (pI810->backHandle) + drmAgpFree(pI810->drmSubFD, pI810->backHandle); + if (pI810->zHandle) + drmAgpFree(pI810->drmSubFD, pI810->zHandle); + if (pI810->cursorHandle) + drmAgpFree(pI810->drmSubFD, pI810->cursorHandle); + if (pI810->xvmcHandle) + drmAgpFree(pI810->drmSubFD, pI810->xvmcHandle); + if (pI810->sysmemHandle) + drmAgpFree(pI810->drmSubFD, pI810->sysmemHandle); + + if (pI810->agpAcquired == TRUE) + drmAgpRelease(pI810->drmSubFD); + + pI810->backHandle = 0; + pI810->zHandle = 0; + pI810->cursorHandle = 0; + pI810->xvmcHandle = 0; + pI810->sysmemHandle = 0; + pI810->agpAcquired = FALSE; + pI810->dcacheHandle = 0; + + DRICloseScreen(pScreen); + + if (pI810->pDRIInfo) { + if (pI810->pDRIInfo->devPrivate) { + xfree(pI810->pDRIInfo->devPrivate); + pI810->pDRIInfo->devPrivate = 0; + } + DRIDestroyInfoRec(pI810->pDRIInfo); + pI810->pDRIInfo = 0; + } + if (pI810->pVisualConfigs) + xfree(pI810->pVisualConfigs); + if (pI810->pVisualConfigsPriv) + xfree(pI810->pVisualConfigsPriv); +} + +static Bool +I810CreateContext(ScreenPtr pScreen, VisualPtr visual, + drmContext hwContext, void *pVisualConfigPriv, + DRIContextType contextStore) +{ + return TRUE; +} + +static void +I810DestroyContext(ScreenPtr pScreen, drmContext hwContext, + DRIContextType contextStore) +{ +} + +Bool +I810DRIFinishScreenInit(ScreenPtr pScreen) +{ + I810SAREARec *sPriv = (I810SAREARec *) DRIGetSAREAPrivate(pScreen); + + memset(sPriv, 0, sizeof(sPriv)); + return DRIFinishScreenInit(pScreen); +} + +void +I810DRISwapContext(ScreenPtr pScreen, DRISyncType syncType, + DRIContextType oldContextType, void *oldContext, + DRIContextType newContextType, void *newContext) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I810Ptr pI810 = I810PTR(pScrn); + + if (syncType == DRI_3D_SYNC && + oldContextType == DRI_2D_CONTEXT && newContextType == DRI_2D_CONTEXT) { + if (I810_DEBUG & DEBUG_VERBOSE_DRI) + ErrorF("I810DRISwapContext (in)\n"); + + if (!pScrn->vtSema) + return; + pI810->LockHeld = 1; + I810RefreshRing(pScrn); + } else if (syncType == DRI_2D_SYNC && + oldContextType == DRI_NO_CONTEXT && + newContextType == DRI_2D_CONTEXT) { + pI810->LockHeld = 0; + if (I810_DEBUG & DEBUG_VERBOSE_DRI) + ErrorF("I810DRISwapContext (out)\n"); + } else if (I810_DEBUG & DEBUG_VERBOSE_DRI) + ErrorF("I810DRISwapContext (other)\n"); +} + +static void +I810DRIInitBuffers(WindowPtr pWin, RegionPtr prgn, CARD32 index) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I810Ptr pI810 = I810PTR(pScrn); + BoxPtr pbox = REGION_RECTS(prgn); + int nbox = REGION_NUM_RECTS(prgn); + + if (I810_DEBUG & DEBUG_VERBOSE_DRI) + ErrorF("I810DRIInitBuffers\n"); + + I810SetupForSolidFill(pScrn, 0, GXcopy, -1); + while (nbox--) { + I810SelectBuffer(pScrn, I810_SELECT_BACK); + I810SubsequentSolidFillRect(pScrn, pbox->x1, pbox->y1, + pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); + pbox++; + } + + /* Clear the depth buffer - uses 0xffff rather than 0. + */ + pbox = REGION_RECTS(prgn); + nbox = REGION_NUM_RECTS(prgn); + I810SelectBuffer(pScrn, I810_SELECT_DEPTH); + I810SetupForSolidFill(pScrn, 0xffff, GXcopy, -1); + while (nbox--) { + I810SubsequentSolidFillRect(pScrn, pbox->x1, pbox->y1, + pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); + pbox++; + } + I810SelectBuffer(pScrn, I810_SELECT_FRONT); + pI810->AccelInfoRec->NeedToSync = TRUE; +} + +/* This routine is a modified form of XAADoBitBlt with the calls to + * ScreenToScreenBitBlt built in. My routine has the prgnSrc as source + * instead of destination. My origin is upside down so the ydir cases + * are reversed. + * + * KW: can you believe that this is called even when a 2d window moves? + */ +static void +I810DRIMoveBuffers(WindowPtr pParent, DDXPointRec ptOldOrg, + RegionPtr prgnSrc, CARD32 index) +{ + ScreenPtr pScreen = pParent->drawable.pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I810Ptr pI810 = I810PTR(pScrn); + BoxPtr pboxTmp, pboxNext, pboxBase; + DDXPointPtr pptTmp, pptNew2; + int xdir, ydir; + + int screenwidth = pScrn->virtualX; + int screenheight = pScrn->virtualY; + + BoxPtr pbox = REGION_RECTS(prgnSrc); + int nbox = REGION_NUM_RECTS(prgnSrc); + + BoxPtr pboxNew1 = 0; + BoxPtr pboxNew2 = 0; + DDXPointPtr pptNew1 = 0; + DDXPointPtr pptSrc = &ptOldOrg; + + int dx = pParent->drawable.x - ptOldOrg.x; + int dy = pParent->drawable.y - ptOldOrg.y; + + /* If the copy will overlap in Y, reverse the order */ + if (dy > 0) { + ydir = -1; + + if (nbox > 1) { + /* Keep ordering in each band, reverse order of bands */ + pboxNew1 = (BoxPtr) ALLOCATE_LOCAL(sizeof(BoxRec) * nbox); + if (!pboxNew1) + return; + pptNew1 = (DDXPointPtr) ALLOCATE_LOCAL(sizeof(DDXPointRec) * nbox); + if (!pptNew1) { + DEALLOCATE_LOCAL(pboxNew1); + return; + } + pboxBase = pboxNext = pbox + nbox - 1; + while (pboxBase >= pbox) { + while ((pboxNext >= pbox) && (pboxBase->y1 == pboxNext->y1)) + pboxNext--; + pboxTmp = pboxNext + 1; + pptTmp = pptSrc + (pboxTmp - pbox); + while (pboxTmp <= pboxBase) { + *pboxNew1++ = *pboxTmp++; + *pptNew1++ = *pptTmp++; + } + pboxBase = pboxNext; + } + pboxNew1 -= nbox; + pbox = pboxNew1; + pptNew1 -= nbox; + pptSrc = pptNew1; + } + } else { + /* No changes required */ + ydir = 1; + } + + /* If the regions will overlap in X, reverse the order */ + if (dx > 0) { + xdir = -1; + + if (nbox > 1) { + /*reverse orderof rects in each band */ + pboxNew2 = (BoxPtr) ALLOCATE_LOCAL(sizeof(BoxRec) * nbox); + pptNew2 = (DDXPointPtr) ALLOCATE_LOCAL(sizeof(DDXPointRec) * nbox); + if (!pboxNew2 || !pptNew2) { + if (pptNew2) + DEALLOCATE_LOCAL(pptNew2); + if (pboxNew2) + DEALLOCATE_LOCAL(pboxNew2); + if (pboxNew1) { + DEALLOCATE_LOCAL(pptNew1); + DEALLOCATE_LOCAL(pboxNew1); + } + return; + } + pboxBase = pboxNext = pbox; + while (pboxBase < pbox + nbox) { + while ((pboxNext < pbox + nbox) && (pboxNext->y1 == pboxBase->y1)) + pboxNext++; + pboxTmp = pboxNext; + pptTmp = pptSrc + (pboxTmp - pbox); + while (pboxTmp != pboxBase) { + *pboxNew2++ = *--pboxTmp; + *pptNew2++ = *--pptTmp; + } + pboxBase = pboxNext; + } + pboxNew2 -= nbox; + pbox = pboxNew2; + pptNew2 -= nbox; + pptSrc = pptNew2; + } + } else { + /* No changes are needed */ + xdir = 1; + } + + /* SelectBuffer isn't really a good concept for the i810. + */ + I810EmitFlush(pScrn); + I810SetupForScreenToScreenCopy(pScrn, xdir, ydir, GXcopy, -1, -1); + for (; nbox--; pbox++) { + + int x1 = pbox->x1; + int y1 = pbox->y1; + int destx = x1 + dx; + int desty = y1 + dy; + int w = pbox->x2 - x1 + 1; + int h = pbox->y2 - y1 + 1; + + if (destx < 0) + x1 -= destx, w += destx, destx = 0; + if (desty < 0) + y1 -= desty, h += desty, desty = 0; + if (destx + w > screenwidth) + w = screenwidth - destx; + if (desty + h > screenheight) + h = screenheight - desty; + if (w <= 0) + continue; + if (h <= 0) + continue; + + if (I810_DEBUG & DEBUG_VERBOSE_DRI) + ErrorF("MoveBuffers %d,%d %dx%d dx: %d dy: %d\n", + x1, y1, w, h, dx, dy); + + I810SelectBuffer(pScrn, I810_SELECT_BACK); + I810SubsequentScreenToScreenCopy(pScrn, x1, y1, destx, desty, w, h); + I810SelectBuffer(pScrn, I810_SELECT_DEPTH); + I810SubsequentScreenToScreenCopy(pScrn, x1, y1, destx, desty, w, h); + } + I810SelectBuffer(pScrn, I810_SELECT_FRONT); + I810EmitFlush(pScrn); + + if (pboxNew2) { + DEALLOCATE_LOCAL(pptNew2); + DEALLOCATE_LOCAL(pboxNew2); + } + if (pboxNew1) { + DEALLOCATE_LOCAL(pptNew1); + DEALLOCATE_LOCAL(pboxNew1); + } + + pI810->AccelInfoRec->NeedToSync = TRUE; +} diff --git a/src/i810_dri.h b/src/i810_dri.h new file mode 100644 index 00000000..cf0532cb --- /dev/null +++ b/src/i810_dri.h @@ -0,0 +1,122 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i810/i810_dri.h,v 1.10 2002/12/10 01:27:04 dawes Exp $ */ + +#ifndef _I810_DRI_ +#define _I810_DRI_ + +#include "xf86drm.h" +#include "i810_common.h" + +#define I810_MAX_DRAWABLES 256 + +typedef struct { + drmHandle regs; + drmSize regsSize; + drmAddress regsMap; + + drmSize backbufferSize; + drmHandle backbuffer; + + drmSize depthbufferSize; + drmHandle depthbuffer; + + drmHandle textures; + int textureSize; + + drmHandle agp_buffers; + drmSize agp_buf_size; + + int deviceID; + int width; + int height; + int mem; + int cpp; + int bitsPerPixel; + int fbOffset; + int fbStride; + + int backOffset; + int depthOffset; + + int auxPitch; + int auxPitchBits; + + int logTextureGranularity; + int textureOffset; + + /* For non-dma direct rendering. + */ + int ringOffset; + int ringSize; + + drmBufMapPtr drmBufs; + int irq; + unsigned int sarea_priv_offset; + +} I810DRIRec, *I810DRIPtr; + +/* WARNING: Do not change the SAREA structure without changing the kernel + * as well */ + +#define I810_UPLOAD_TEX0IMAGE 0x1 /* handled clientside */ +#define I810_UPLOAD_TEX1IMAGE 0x2 /* handled clientside */ +#define I810_UPLOAD_CTX 0x4 +#define I810_UPLOAD_BUFFERS 0x8 +#define I810_UPLOAD_TEX0 0x10 +#define I810_UPLOAD_TEX1 0x20 +#define I810_UPLOAD_CLIPRECTS 0x40 + +typedef struct { + unsigned char next, prev; /* indices to form a circular LRU */ + unsigned char in_use; /* owned by a client, or free? */ + int age; /* tracked by clients to update local LRU's */ +} I810TexRegionRec, *I810TexRegionPtr; + +typedef struct { + unsigned int ContextState[I810_CTX_SETUP_SIZE]; + unsigned int BufferState[I810_DEST_SETUP_SIZE]; + unsigned int TexState[2][I810_TEX_SETUP_SIZE]; + unsigned int dirty; + + unsigned int nbox; + XF86DRIClipRectRec boxes[I810_NR_SAREA_CLIPRECTS]; + + /* Maintain an LRU of contiguous regions of texture space. If + * you think you own a region of texture memory, and it has an + * age different to the one you set, then you are mistaken and + * it has been stolen by another client. If global texAge + * hasn't changed, there is no need to walk the list. + * + * These regions can be used as a proxy for the fine-grained + * texture information of other clients - by maintaining them + * in the same lru which is used to age their own textures, + * clients have an approximate lru for the whole of global + * texture space, and can make informed decisions as to which + * areas to kick out. There is no need to choose whether to + * kick out your own texture or someone else's - simply eject + * them all in LRU order. + */ + I810TexRegionRec texList[I810_NR_TEX_REGIONS + 1]; /* Last elt is sentinal */ + + int texAge; /* last time texture was uploaded */ + + int last_enqueue; /* last time a buffer was enqueued */ + int last_dispatch; /* age of the most recently dispatched buffer */ + int last_quiescent; /* */ + + int ctxOwner; /* last context to upload state */ + + int vertex_prim; + +} I810SAREARec, *I810SAREAPtr; + +typedef struct { + /* Nothing here yet */ + int dummy; +} I810ConfigPrivRec, *I810ConfigPrivPtr; + +typedef struct { + /* Nothing here yet */ + int dummy; +} I810DRIContextRec, *I810DRIContextPtr; + +#endif diff --git a/src/i810_driver.c b/src/i810_driver.c new file mode 100644 index 00000000..746e186f --- /dev/null +++ b/src/i810_driver.c @@ -0,0 +1,2397 @@ + +/************************************************************************** + +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sub license, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice (including the +next paragraph) shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i810/i810_driver.c,v 1.80 2003/02/26 04:19:36 dawes Exp $ */ + +/* + * Reformatted with GNU indent (2.2.8), using the following options: + * + * -bad -bap -c41 -cd0 -ncdb -ci6 -cli0 -cp0 -ncs -d0 -di3 -i3 -ip3 -l78 + * -lp -npcs -psl -sob -ss -br -ce -sc -hnl + * + * This provides a good match with the original i810 code and preferred + * XFree86 formatting conventions. + * + * When editing this driver, please follow the existing formatting, and edit + * with <TAB> characters expanded at 8-column intervals. + */ + +/* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + * + */ + +/* + * This server does not support these XFree86 4.0 features yet + * shadowFb (if requested or acceleration is off) + * Overlay planes + * DGA + */ + +/* + * These are X and server generic header files. + */ +#include "xf86.h" +#include "xf86_ansic.h" +#include "xf86_OSproc.h" +#include "xf86Resources.h" +#include "xf86RAC.h" +#include "xf86cmap.h" +#include "compiler.h" +#include "mibstore.h" +#include "vgaHW.h" +#include "mipointer.h" +#include "micmap.h" + +#include "fb.h" +#include "miscstruct.h" +#include "xf86xv.h" +#include "Xv.h" +#include "vbe.h" + +#include "i810.h" + +#ifdef XF86DRI +#include "dri.h" +#endif + +/* Required Functions: */ + +static void I810Identify(int flags); +static Bool I810Probe(DriverPtr drv, int flags); +#ifndef I830_ONLY +static Bool I810PreInit(ScrnInfoPtr pScrn, int flags); +static Bool I810ScreenInit(int Index, ScreenPtr pScreen, int argc, + char **argv); +static Bool I810EnterVT(int scrnIndex, int flags); +static void I810LeaveVT(int scrnIndex, int flags); +static Bool I810CloseScreen(int scrnIndex, ScreenPtr pScreen); +static Bool I810SaveScreen(ScreenPtr pScreen, Bool unblank); +static void I810FreeScreen(int scrnIndex, int flags); +static void I810DisplayPowerManagementSet(ScrnInfoPtr pScrn, + int PowerManagermentMode, + int flags); +static int I810ValidMode(int scrnIndex, DisplayModePtr mode, Bool + verbose, int flags); +#endif /* I830_ONLY */ + + +DriverRec I810 = { + I810_VERSION, + I810_DRIVER_NAME, + I810Identify, + I810Probe, + I810AvailableOptions, + NULL, + 0 +}; + +/* *INDENT-OFF* */ +/* Chipsets */ +static SymTabRec I810Chipsets[] = { +#ifndef I830_ONLY + {PCI_CHIP_I810, "i810"}, + {PCI_CHIP_I810_DC100, "i810-dc100"}, + {PCI_CHIP_I810_E, "i810e"}, + {PCI_CHIP_I815, "i815"}, +#endif + {PCI_CHIP_I830_M, "i830M"}, + {PCI_CHIP_845_G, "845G"}, + {PCI_CHIP_I855_GM, "852GM/855GM"}, + {PCI_CHIP_I865_G, "865G"}, + {-1, NULL} +}; + +static PciChipsets I810PciChipsets[] = { +#ifndef I830_ONLY + {PCI_CHIP_I810, PCI_CHIP_I810, RES_SHARED_VGA}, + {PCI_CHIP_I810_DC100, PCI_CHIP_I810_DC100, RES_SHARED_VGA}, + {PCI_CHIP_I810_E, PCI_CHIP_I810_E, RES_SHARED_VGA}, + {PCI_CHIP_I815, PCI_CHIP_I815, RES_SHARED_VGA}, +#endif + {PCI_CHIP_I830_M, PCI_CHIP_I830_M, RES_SHARED_VGA}, + {PCI_CHIP_845_G, PCI_CHIP_845_G, RES_SHARED_VGA}, + {PCI_CHIP_I855_GM, PCI_CHIP_I855_GM, RES_SHARED_VGA}, + {PCI_CHIP_I865_G, PCI_CHIP_I865_G, RES_SHARED_VGA}, + {-1, -1, RES_UNDEFINED } +}; + +#ifndef I830_ONLY +typedef enum { + OPTION_NOACCEL, + OPTION_SW_CURSOR, + OPTION_COLOR_KEY, + OPTION_CACHE_LINES, + OPTION_DAC_6BIT, + OPTION_DRI, + OPTION_NO_DDC, + OPTION_SHOW_CACHE, + OPTION_XVMC_SURFACES +} I810Opts; + +static const OptionInfoRec I810Options[] = { + {OPTION_NOACCEL, "NoAccel", OPTV_BOOLEAN, {0}, FALSE}, + {OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN, {0}, FALSE}, + {OPTION_COLOR_KEY, "ColorKey", OPTV_INTEGER, {0}, FALSE}, + {OPTION_CACHE_LINES, "CacheLines", OPTV_INTEGER, {0}, FALSE}, + {OPTION_DAC_6BIT, "Dac6Bit", OPTV_BOOLEAN, {0}, FALSE}, + {OPTION_DRI, "DRI", OPTV_BOOLEAN, {0}, FALSE}, + {OPTION_NO_DDC, "NoDDC", OPTV_BOOLEAN, {0}, FALSE}, + {OPTION_SHOW_CACHE, "ShowCache", OPTV_BOOLEAN, {0}, FALSE}, + {OPTION_XVMC_SURFACES, "XvMCSurfaces", OPTV_INTEGER, {0}, FALSE}, + {-1, NULL, OPTV_NONE, {0}, FALSE} +}; +/* *INDENT-ON* */ +#endif + +const char *I810vgahwSymbols[] = { + "vgaHWFreeHWRec", + "vgaHWGetHWRec", + "vgaHWGetIOBase", + "vgaHWGetIndex", + "vgaHWInit", + "vgaHWLock", + "vgaHWMapMem", + "vgaHWProtect", + "vgaHWRestore", + "vgaHWSave", + "vgaHWSaveScreen", + "vgaHWSetMmioFuncs", + "vgaHWUnlock", + "vgaHWUnmapMem", + NULL +}; + +const char *I810fbSymbols[] = { + "fbPictureInit", + "fbScreenInit", + NULL +}; + +const char *I810vbeSymbols[] = { + "VBEFreeModeInfo", + "VBEFreeVBEInfo", + "VBEGetModeInfo", + "VBEGetModePool", + "VBEGetVBEInfo", + "VBEGetVBEMode", + "VBEInit", + "VBEPrintModes", + "VBESaveRestore", + "VBESetDisplayStart", + "VBESetGetDACPaletteFormat", + "VBESetGetLogicalScanlineLength", + "VBESetGetPaletteData", + "VBESetModeNames", + "VBESetModeParameters", + "VBESetVBEMode", + "VBEValidateModes", + "vbeDoEDID", + "vbeFree", + NULL +}; + +#ifdef XFree86LOADER +static const char *vbeOptionalSymbols[] = { + "VBEDPMSSet", + "VBEGetPixelClock", + NULL +}; +#endif + +const char *I810ddcSymbols[] = { + "xf86PrintEDID", + "xf86SetDDCproperties", + NULL +}; + +const char *I810int10Symbols[] = { + "xf86ExecX86int10", + "xf86InitInt10", + "xf86Int10AllocPages", + "xf86int10Addr", + NULL +}; + +const char *I810xaaSymbols[] = { + "XAACreateInfoRec", + "XAADestroyInfoRec", + "XAAFillSolidRects", + "XAAInit", + NULL +}; + +const char *I810ramdacSymbols[] = { + "xf86CreateCursorInfoRec", + "xf86DestroyCursorInfoRec", + "xf86InitCursor", + NULL +}; + +#ifndef I830_ONLY +#ifdef XFree86LOADER +#ifdef XF86DRI +static const char *drmSymbols[] = { + "drmAddBufs", + "drmAddMap", + "drmAgpAcquire", + "drmAgpAlloc", + "drmAgpBind", + "drmAgpEnable", + "drmAgpFree", + "drmAgpRelease", + "drmAuthMagic", + "drmCommandWrite", + "drmCreateContext", + "drmCtlInstHandler", + "drmDestroyContext", + "drmFreeVersion", + "drmGetInterruptFromBusID", + "drmGetLibVersion", + "drmGetVersion", + NULL +}; + + +static const char *driSymbols[] = { + "DRICloseScreen", + "DRICreateInfoRec", + "DRIDestroyInfoRec", + "DRIFinishScreenInit", + "DRIGetSAREAPrivate", + "DRILock", + "DRIQueryVersion", + "DRIScreenInit", + "DRIUnlock", + "GlxSetVisualConfigs", + NULL +}; + +#endif +#endif + +#ifdef XF86DRI +const char *I810shadowSymbols[] = { + "shadowInit", + "shadowSetup", + "shadowAdd", + NULL +}; +#endif + +#endif /* I830_ONLY */ + +#ifndef I810_DEBUG +int I810_DEBUG = (0 +/* | DEBUG_ALWAYS_SYNC */ +/* | DEBUG_VERBOSE_ACCEL */ +/* | DEBUG_VERBOSE_SYNC */ +/* | DEBUG_VERBOSE_VGA */ +/* | DEBUG_VERBOSE_RING */ +/* | DEBUG_VERBOSE_OUTREG */ +/* | DEBUG_VERBOSE_MEMORY */ +/* | DEBUG_VERBOSE_CURSOR */ + ); +#endif + +#ifndef I830_ONLY +#ifdef XF86DRI +static int i810_pitches[] = { + 512, + 1024, + 2048, + 4096, + 0 +}; +#endif +#endif + +#ifdef XFree86LOADER + +static MODULESETUPPROTO(i810Setup); + +static XF86ModuleVersionInfo i810VersRec = { + "i810", + MODULEVENDORSTRING, + MODINFOSTRING1, + MODINFOSTRING2, + XF86_VERSION_CURRENT, + I810_MAJOR_VERSION, I810_MINOR_VERSION, I810_PATCHLEVEL, + ABI_CLASS_VIDEODRV, + ABI_VIDEODRV_VERSION, + MOD_CLASS_VIDEODRV, + {0, 0, 0, 0} +}; + +XF86ModuleData i810ModuleData = { &i810VersRec, i810Setup, 0 }; + +static pointer +i810Setup(pointer module, pointer opts, int *errmaj, int *errmin) +{ + static Bool setupDone = 0; + + /* This module should be loaded only once, but check to be sure. + */ + if (!setupDone) { + setupDone = 1; + xf86AddDriver(&I810, module, 0); + + /* + * Tell the loader about symbols from other modules that this module + * might refer to. + */ + LoaderRefSymLists(I810vgahwSymbols, + I810fbSymbols, I810xaaSymbols, I810ramdacSymbols, +#ifdef XF86DRI + drmSymbols, + driSymbols, + I810shadowSymbols, +#endif + I810vbeSymbols, vbeOptionalSymbols, + I810ddcSymbols, I810int10Symbols, NULL); + + /* + * The return value must be non-NULL on success even though there + * is no TearDownProc. + */ + return (pointer) 1; + } else { + if (errmaj) + *errmaj = LDR_ONCEONLY; + return NULL; + } +} + +#endif + +#ifndef I830_ONLY +/* + * I810GetRec and I810FreeRec -- + * + * Private data for the driver is stored in the screen structure. + * These two functions create and destroy that private data. + * + */ +static Bool +I810GetRec(ScrnInfoPtr pScrn) +{ + if (pScrn->driverPrivate) + return TRUE; + + pScrn->driverPrivate = xnfcalloc(sizeof(I810Rec), 1); + return TRUE; +} + +static void +I810FreeRec(ScrnInfoPtr pScrn) +{ + if (!pScrn) + return; + if (!pScrn->driverPrivate) + return; + xfree(pScrn->driverPrivate); + pScrn->driverPrivate = 0; +} +#endif + +/* + * I810Identify -- + * + * Returns the string name for the driver based on the chipset. In this + * case it will always be an I810, so we can return a static string. + * + */ +static void +I810Identify(int flags) +{ + xf86PrintChipsets(I810_NAME, "Driver for Intel Integrated Graphics Chipsets", + I810Chipsets); +} + +const OptionInfoRec * +I810AvailableOptions(int chipid, int busid) +{ +#ifndef I830_ONLY + const OptionInfoRec *pOptions; + + if ((pOptions = I830BIOSAvailableOptions(chipid, busid))) + return pOptions; + return I810Options; +#else + return I830BIOSAvailableOptions(chipid, busid); +#endif +} + +/* + * I810Probe -- + * + * Look through the PCI bus to find cards that are I810 boards. + * Setup the dispatch table for the rest of the driver functions. + * + */ +static Bool +I810Probe(DriverPtr drv, int flags) +{ + int i, numUsed, numDevSections, *usedChips; + GDevPtr *devSections; + Bool foundScreen = FALSE; + pciVideoPtr *VideoInfo; + pciVideoPtr *ppPci; + PciChipsets *id; + + /* + * Find the config file Device sections that match this + * driver, and return if there are none. + */ + if ((numDevSections = + xf86MatchDevice(I810_DRIVER_NAME, &devSections)) <= 0) { + return FALSE; + } + + /* + * This probing is just checking the PCI data the server already + * collected. + */ + if (!(VideoInfo = xf86GetPciVideoInfo())) + return FALSE; + + /* + * Mobile platforms may have both function 0 and 1 active, but they + * are handled as a single entity. To make sure that the function 1 + * entity isn't assigned to a screen, check for and claim it here + * first. + * + * XXX If function 1's resources are ever needed, they'll need to be + * added to the screen and marked active. + */ + for (ppPci = VideoInfo; ppPci != NULL && *ppPci != NULL; ppPci++) { + if ((*ppPci)->vendor == PCI_VENDOR_INTEL && + (*ppPci)->func == 1) { + for (id = I810PciChipsets; id->PCIid != -1; id++) { + if (id->PCIid == (*ppPci)->chipType) { + /* Claim slot */ + if (xf86CheckPciSlot((*ppPci)->bus, (*ppPci)->device, + (*ppPci)->func)) { + xf86ClaimPciSlot((*ppPci)->bus, (*ppPci)->device, + (*ppPci)->func, drv, id->PCIid, + NULL, FALSE); + } + break; + } + } + } + } + + /* Look for Intel i8xx devices. */ + numUsed = xf86MatchPciInstances(I810_NAME, PCI_VENDOR_INTEL, + I810Chipsets, I810PciChipsets, + devSections, numDevSections, + drv, &usedChips); + + if (flags & PROBE_DETECT) { + if (numUsed > 0) + foundScreen = TRUE; + } else { + for (i = 0; i < numUsed; i++) { + ScrnInfoPtr pScrn = NULL; + + /* Allocate new ScrnInfoRec and claim the slot */ + if ((pScrn = xf86ConfigPciEntity(pScrn, 0, usedChips[i], + I810PciChipsets, 0, 0, 0, 0, 0))) { + EntityInfoPtr pEnt; + + pEnt = xf86GetEntityInfo(usedChips[i]); + + pScrn->driverVersion = I810_VERSION; + pScrn->driverName = I810_DRIVER_NAME; + pScrn->name = I810_NAME; + pScrn->Probe = I810Probe; + foundScreen = TRUE; + switch (pEnt->chipset) { + case PCI_CHIP_I830_M: + case PCI_CHIP_845_G: + case PCI_CHIP_I855_GM: + case PCI_CHIP_I865_G: + I830InitpScrn(pScrn); + break; +#ifndef I830_ONLY + default: + pScrn->PreInit = I810PreInit; + pScrn->ScreenInit = I810ScreenInit; + pScrn->SwitchMode = I810SwitchMode; + pScrn->AdjustFrame = I810AdjustFrame; + pScrn->EnterVT = I810EnterVT; + pScrn->LeaveVT = I810LeaveVT; + pScrn->FreeScreen = I810FreeScreen; + pScrn->ValidMode = I810ValidMode; + break; +#endif + } + } + } + } + + xfree(usedChips); + xfree(devSections); + + return foundScreen; +} + +#ifndef I830_ONLY +static void +I810ProbeDDC(ScrnInfoPtr pScrn, int index) +{ + vbeInfoPtr pVbe; + + if (xf86LoadSubModule(pScrn, "vbe")) { + pVbe = VBEInit(NULL, index); + ConfiguredMonitor = vbeDoEDID(pVbe, NULL); + vbeFree(pVbe); + } +} + +static xf86MonPtr +I810DoDDC(ScrnInfoPtr pScrn, int index) +{ + vbeInfoPtr pVbe; + xf86MonPtr MonInfo = NULL; + I810Ptr pI810 = I810PTR(pScrn); + + /* Honour Option "noDDC" */ + if (xf86ReturnOptValBool(pI810->Options, OPTION_NO_DDC, FALSE)) { + return MonInfo; + } + + if (xf86LoadSubModule(pScrn, "vbe") && (pVbe = VBEInit(NULL, index))) { + xf86LoaderReqSymLists(I810vbeSymbols, NULL); + MonInfo = vbeDoEDID(pVbe, NULL); + xf86PrintEDID(MonInfo); + xf86SetDDCproperties(pScrn, MonInfo); + vbeFree(pVbe); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "this driver cannot do DDC without VBE\n"); + } + + return MonInfo; +} + +/* + * I810PreInit -- + * + * Do initial setup of the board before we know what resolution we will + * be running at. + * + */ +static Bool +I810PreInit(ScrnInfoPtr pScrn, int flags) +{ + vgaHWPtr hwp; + I810Ptr pI810; + ClockRangePtr clockRanges; + int i; + MessageType from; + int flags24; + rgb defaultWeight = { 0, 0, 0 }; + int mem; + + if (pScrn->numEntities != 1) + return FALSE; + + /* Allocate driverPrivate */ + if (!I810GetRec(pScrn)) + return FALSE; + + pI810 = I810PTR(pScrn); + + pI810->pEnt = xf86GetEntityInfo(pScrn->entityList[0]); + if (pI810->pEnt->location.type != BUS_PCI) + return FALSE; + + if (flags & PROBE_DETECT) { + I810ProbeDDC(pScrn, pI810->pEnt->index); + return TRUE; + } + + /* The vgahw module should be loaded here when needed */ + if (!xf86LoadSubModule(pScrn, "vgahw")) + return FALSE; + + xf86LoaderReqSymLists(I810vgahwSymbols, NULL); + + /* Allocate a vgaHWRec */ + if (!vgaHWGetHWRec(pScrn)) + return FALSE; + hwp = VGAHWPTR(pScrn); + pI810->ioBase = hwp->PIOOffset; + + pI810->PciInfo = xf86GetPciInfoForEntity(pI810->pEnt->index); + pI810->PciTag = pciTag(pI810->PciInfo->bus, pI810->PciInfo->device, + pI810->PciInfo->func); + + if (xf86RegisterResources(pI810->pEnt->index, 0, ResNone)) + return FALSE; + pScrn->racMemFlags = RAC_FB | RAC_COLORMAP; + + /* Set pScrn->monitor */ + pScrn->monitor = pScrn->confScreen->monitor; + + flags24 = Support24bppFb | PreferConvert32to24 | SupportConvert32to24; + if (!xf86SetDepthBpp(pScrn, 8, 8, 8, flags24)) { + return FALSE; + } else { + switch (pScrn->depth) { + case 8: + case 15: + case 16: + case 24: + break; + default: + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Given depth (%d) is not supported by i810 driver\n", + pScrn->depth); + return FALSE; + } + } + xf86PrintDepthBpp(pScrn); + + switch (pScrn->bitsPerPixel) { + case 8: + case 16: + case 24: + break; + default: + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Given bpp (%d) is not supported by i810 driver\n", + pScrn->bitsPerPixel); + return FALSE; + } + + if (!xf86SetWeight(pScrn, defaultWeight, defaultWeight)) + return FALSE; + + if (!xf86SetDefaultVisual(pScrn, -1)) + return FALSE; + + /* We use a programmable clock */ + pScrn->progClock = TRUE; + + pI810->cpp = pScrn->bitsPerPixel / 8; + + /* Process the options */ + xf86CollectOptions(pScrn, NULL); + if (!(pI810->Options = xalloc(sizeof(I810Options)))) + return FALSE; + memcpy(pI810->Options, I810Options, sizeof(I810Options)); + xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, pI810->Options); + + pScrn->rgbBits = 8; + if (xf86ReturnOptValBool(pI810->Options, OPTION_DAC_6BIT, FALSE)) + pScrn->rgbBits = 6; + + if (xf86ReturnOptValBool(pI810->Options, OPTION_SHOW_CACHE, FALSE)) + pI810->showCache = TRUE; + else + pI810->showCache = FALSE; + + /* 6-BIT dac isn't reasonable for modes with > 8bpp */ + if (xf86ReturnOptValBool(pI810->Options, OPTION_DAC_6BIT, FALSE) && + pScrn->bitsPerPixel > 8) { + OptionInfoPtr ptr; + + ptr = xf86TokenToOptinfo(pI810->Options, OPTION_DAC_6BIT); + ptr->found = FALSE; + } + + /* Get DDC info from monitor */ + /* after xf86ProcessOptions, + * because it is controlled by options [no]vbe and [no]ddc + */ + pScrn->monitor->DDC = I810DoDDC(pScrn, pI810->pEnt->index); + + /* We have to use PIO to probe, because we haven't mapped yet */ + I810SetPIOAccess(pI810); + + /* + * Set the Chipset and ChipRev, allowing config file entries to + * override. + */ + if (pI810->pEnt->device->chipset && *pI810->pEnt->device->chipset) { + pScrn->chipset = pI810->pEnt->device->chipset; + from = X_CONFIG; + } else if (pI810->pEnt->device->chipID >= 0) { + pScrn->chipset = (char *)xf86TokenToString(I810Chipsets, + pI810->pEnt->device->chipID); + from = X_CONFIG; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipID override: 0x%04X\n", + pI810->pEnt->device->chipID); + } else { + from = X_PROBED; + pScrn->chipset = (char *)xf86TokenToString(I810Chipsets, + pI810->PciInfo->chipType); + } + if (pI810->pEnt->device->chipRev >= 0) { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipRev override: %d\n", + pI810->pEnt->device->chipRev); + } + + xf86DrvMsg(pScrn->scrnIndex, from, "Chipset: \"%s\"\n", + (pScrn->chipset != NULL) ? pScrn->chipset : "Unknown i810"); + + if (pI810->pEnt->device->MemBase != 0) { + pI810->LinearAddr = pI810->pEnt->device->MemBase; + from = X_CONFIG; + } else { + if (pI810->PciInfo->memBase[1] != 0) { + pI810->LinearAddr = pI810->PciInfo->memBase[0] & 0xFF000000; + from = X_PROBED; + } else { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "No valid FB address in PCI config space\n"); + I810FreeRec(pScrn); + return FALSE; + } + } + xf86DrvMsg(pScrn->scrnIndex, from, "Linear framebuffer at 0x%lX\n", + (unsigned long)pI810->LinearAddr); + + if (pI810->pEnt->device->IOBase != 0) { + pI810->MMIOAddr = pI810->pEnt->device->IOBase; + from = X_CONFIG; + } else { + if (pI810->PciInfo->memBase[1]) { + pI810->MMIOAddr = pI810->PciInfo->memBase[1] & 0xFFF80000; + from = X_PROBED; + } else { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "No valid MMIO address in PCI config space\n"); + I810FreeRec(pScrn); + return FALSE; + } + } + xf86DrvMsg(pScrn->scrnIndex, from, "IO registers at addr 0x%lX\n", + (unsigned long)pI810->MMIOAddr); + + /* AGP GART support is required. Don't proceed any further if it isn't + * present. + */ + if (!xf86AgpGARTSupported()) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "AGP GART support is not available. Make sure your kernel has\n" + "\tagpgart support or that the agpgart kernel module is loaded.\n"); + return FALSE; + } + + /* Find out memory bus frequency. + */ + { + unsigned long whtcfg_pamr_drp = pciReadLong(pI810->PciTag, + WHTCFG_PAMR_DRP); + + /* Need this for choosing watermarks. + */ + if ((whtcfg_pamr_drp & LM_FREQ_MASK) == LM_FREQ_133) + pI810->LmFreqSel = 133; + else + pI810->LmFreqSel = 100; + } + + /* Default to 4MB framebuffer, which is sufficient for all + * supported 2d resolutions. If the user has specified a different + * size in the XF86Config, use that amount instead. + * + * Changed to 8 Meg so we can have acceleration by default (Mark). + */ + pScrn->videoRam = 8192; + from = X_DEFAULT; + if (pI810->pEnt->device->videoRam) { + pScrn->videoRam = pI810->pEnt->device->videoRam; + from = X_CONFIG; + } + + mem = I810CheckAvailableMemory(pScrn); + if (mem > 0 && mem < pScrn->videoRam) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "%dk of memory was requested," + " but the\n\t maximum AGP memory available is %dk.\n", + pScrn->videoRam, mem); + from = X_PROBED; + if (mem > (6 * 1024)) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Reducing video memory to 4MB\n"); + pScrn->videoRam = 4096; + } else { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Less than 6MB of AGP memory" + "is available. Cannot proceed.\n"); + I810FreeRec(pScrn); + return FALSE; + } + } + + xf86DrvMsg(pScrn->scrnIndex, from, + "Will alloc AGP framebuffer: %d kByte\n", pScrn->videoRam); + + /* Calculate Fixed Offsets depending on graphics aperture size */ + { + PCITAG bridge; + long smram_miscc; + + bridge = pciTag(0, 0, 0); /* This is always the host bridge */ + smram_miscc = pciReadLong(bridge, SMRAM_MISCC); + if ((smram_miscc & GFX_MEM_WIN_SIZE) == GFX_MEM_WIN_32M) { + pI810->FbMapSize = 0x1000000; + pI810->DepthOffset = 0x1000000; + pI810->BackOffset = 0x1800000; + } else { + pI810->FbMapSize = 0x3000000; + pI810->DepthOffset = 0x3000000; + pI810->BackOffset = 0x3800000; + } + } + + /* + * If the driver can do gamma correction, it should call xf86SetGamma() + * here. + */ + { + Gamma zeros = { 0.0, 0.0, 0.0 }; + + if (!xf86SetGamma(pScrn, zeros)) { + return FALSE; + } + } + + pI810->MaxClock = 0; + if (pI810->pEnt->device->dacSpeeds[0]) { + switch (pScrn->bitsPerPixel) { + case 8: + pI810->MaxClock = pI810->pEnt->device->dacSpeeds[DAC_BPP8]; + break; + case 16: + pI810->MaxClock = pI810->pEnt->device->dacSpeeds[DAC_BPP16]; + break; + case 24: + pI810->MaxClock = pI810->pEnt->device->dacSpeeds[DAC_BPP24]; + break; + case 32: /* not supported */ + pI810->MaxClock = pI810->pEnt->device->dacSpeeds[DAC_BPP32]; + break; + } + if (!pI810->MaxClock) + pI810->MaxClock = pI810->pEnt->device->dacSpeeds[0]; + from = X_CONFIG; + } else { + switch (pScrn->bitsPerPixel) { + case 8: + pI810->MaxClock = 203000; + break; + case 16: + pI810->MaxClock = 163000; + break; + case 24: + pI810->MaxClock = 136000; + break; + case 32: /* not supported */ + pI810->MaxClock = 86000; + } + } + clockRanges = xnfcalloc(sizeof(ClockRange), 1); + clockRanges->next = NULL; + clockRanges->minClock = 12000; /* !!! What's the min clock? !!! */ + clockRanges->maxClock = pI810->MaxClock; + clockRanges->clockIndex = -1; + clockRanges->interlaceAllowed = TRUE; + clockRanges->doubleScanAllowed = FALSE; + + i = xf86ValidateModes(pScrn, pScrn->monitor->Modes, + pScrn->display->modes, clockRanges, +#ifndef XF86DRI + 0, 320, 1600, 64 * pScrn->bitsPerPixel, +#else + i810_pitches, 0, 0, 64 * pScrn->bitsPerPixel, +#endif + 200, 1200, + pScrn->display->virtualX, pScrn->display->virtualY, + pScrn->videoRam * 1024, LOOKUP_BEST_REFRESH); + + if (i == -1) { + I810FreeRec(pScrn); + return FALSE; + } + + xf86PruneDriverModes(pScrn); + + if (!i || !pScrn->modes) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n"); + I810FreeRec(pScrn); + return FALSE; + } + + xf86SetCrtcForModes(pScrn, INTERLACE_HALVE_V); + + pScrn->currentMode = pScrn->modes; + + xf86PrintModes(pScrn); + + xf86SetDpi(pScrn, 0, 0); + + if (!xf86LoadSubModule(pScrn, "fb")) { + I810FreeRec(pScrn); + return FALSE; + } + xf86LoaderReqSymLists(I810fbSymbols, NULL); + + if (xf86ReturnOptValBool(pI810->Options, OPTION_NOACCEL, FALSE)) + pI810->noAccel = TRUE; + + if (!pI810->noAccel) { + if (!xf86LoadSubModule(pScrn, "xaa")) { + I810FreeRec(pScrn); + return FALSE; + } + xf86LoaderReqSymLists(I810xaaSymbols, NULL); + } + + if (!xf86ReturnOptValBool(pI810->Options, OPTION_SW_CURSOR, FALSE)) { + if (!xf86LoadSubModule(pScrn, "ramdac")) { + I810FreeRec(pScrn); + return FALSE; + } + xf86LoaderReqSymLists(I810ramdacSymbols, NULL); + } + + if (xf86GetOptValInteger + (pI810->Options, OPTION_COLOR_KEY, &(pI810->colorKey))) { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, + "video overlay key set to 0x%x\n", pI810->colorKey); + } else { + pI810->colorKey = (1 << pScrn->offset.red) | + (1 << pScrn->offset.green) | + (((pScrn->mask.blue >> pScrn->offset.blue) - + 1) << pScrn->offset.blue); + } + + if (xf86GetOptValInteger(pI810->Options, OPTION_XVMC_SURFACES, + &(pI810->numSurfaces))) { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "%d XvMC Surfaces Requested.\n", + pI810->numSurfaces); + if (pI810->numSurfaces > 7) { + xf86DrvMsg(pScrn->scrnIndex, X_PROBED, + "Using 7 XvMC Surfaces (Maximum Allowed).\n"); + pI810->numSurfaces = 7; + } + if (pI810->numSurfaces < 6) { + xf86DrvMsg(pScrn->scrnIndex, X_PROBED, + "Using 6 XvMC Surfaces (Minimum Allowed).\n"); + pI810->numSurfaces = 6; + } + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "XvMC is Disabled: use XvMCSurfaces config option to enable.\n"); + pI810->numSurfaces = 0; + } + + /* We won't be using the VGA access after the probe */ + I810SetMMIOAccess(pI810); + xf86SetOperatingState(resVgaIo, pI810->pEnt->index, ResUnusedOpr); + xf86SetOperatingState(resVgaMem, pI810->pEnt->index, ResDisableOpr); + + return TRUE; +} + +static Bool +I810MapMMIO(ScrnInfoPtr pScrn) +{ + int mmioFlags; + I810Ptr pI810 = I810PTR(pScrn); + +#if !defined(__alpha__) + mmioFlags = VIDMEM_MMIO | VIDMEM_READSIDEEFFECT; +#else + mmioFlags = VIDMEM_MMIO | VIDMEM_READSIDEEFFECT | VIDMEM_SPARSE; +#endif + + pI810->MMIOBase = xf86MapPciMem(pScrn->scrnIndex, mmioFlags, + pI810->PciTag, + pI810->MMIOAddr, I810_REG_SIZE); + if (!pI810->MMIOBase) + return FALSE; + return TRUE; +} + +static Bool +I810MapMem(ScrnInfoPtr pScrn) +{ + I810Ptr pI810 = I810PTR(pScrn); + unsigned i; + + for (i = 2; i < pI810->FbMapSize; i <<= 1) ; + pI810->FbMapSize = i; + + if (!I810MapMMIO(pScrn)) + return FALSE; + + pI810->FbBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER, + pI810->PciTag, + pI810->LinearAddr, pI810->FbMapSize); + if (!pI810->FbBase) + return FALSE; + + pI810->LpRing.virtual_start = pI810->FbBase + pI810->LpRing.mem.Start; + + return TRUE; +} + +static void +I810UnmapMMIO(ScrnInfoPtr pScrn) +{ + I810Ptr pI810 = I810PTR(pScrn); + + xf86UnMapVidMem(pScrn->scrnIndex, (pointer) pI810->MMIOBase, + I810_REG_SIZE); + pI810->MMIOBase = 0; +} + +static Bool +I810UnmapMem(ScrnInfoPtr pScrn) +{ + I810Ptr pI810 = I810PTR(pScrn); + + xf86UnMapVidMem(pScrn->scrnIndex, (pointer) pI810->FbBase, + pI810->FbMapSize); + pI810->FbBase = 0; + I810UnmapMMIO(pScrn); + return TRUE; +} + +/* Famous last words + */ +void +I810PrintErrorState(ScrnInfoPtr pScrn) +{ + I810Ptr pI810 = I810PTR(pScrn); + + ErrorF("pgetbl_ctl: 0x%lx pgetbl_err: 0x%lx\n", + INREG(PGETBL_CTL), INREG(PGE_ERR)); + + ErrorF("ipeir: %lx iphdr: %lx\n", INREG(IPEIR), INREG(IPEHR)); + + ErrorF("LP ring tail: %lx head: %lx len: %lx start %lx\n", + INREG(LP_RING + RING_TAIL), + INREG(LP_RING + RING_HEAD) & HEAD_ADDR, + INREG(LP_RING + RING_LEN), INREG(LP_RING + RING_START)); + + ErrorF("eir: %x esr: %x emr: %x\n", + INREG16(EIR), INREG16(ESR), INREG16(EMR)); + + ErrorF("instdone: %x instpm: %x\n", INREG16(INST_DONE), INREG8(INST_PM)); + + ErrorF("memmode: %lx instps: %lx\n", INREG(MEMMODE), INREG(INST_PS)); + + ErrorF("hwstam: %x ier: %x imr: %x iir: %x\n", + INREG16(HWSTAM), INREG16(IER), INREG16(IMR), INREG16(IIR)); +} + +/* + * I810Save -- + * + * This function saves the video state. It reads all of the SVGA registers + * into the vgaI810Rec data structure. There is in general no need to + * mask out bits here - just read the registers. + */ +static void +DoSave(ScrnInfoPtr pScrn, vgaRegPtr vgaReg, I810RegPtr i810Reg, + Bool saveFonts) +{ + I810Ptr pI810; + vgaHWPtr hwp; + int i; + + pI810 = I810PTR(pScrn); + hwp = VGAHWPTR(pScrn); + + /* + * This function will handle creating the data structure and filling + * in the generic VGA portion. + */ + if (saveFonts) + vgaHWSave(pScrn, vgaReg, VGA_SR_MODE | VGA_SR_FONTS | VGA_SR_CMAP); + else + vgaHWSave(pScrn, vgaReg, VGA_SR_MODE | VGA_SR_CMAP); + + /* + * The port I/O code necessary to read in the extended registers + * into the fields of the vgaI810Rec structure goes here. + */ + i810Reg->IOControl = hwp->readCrtc(hwp, IO_CTNL); + i810Reg->AddressMapping = pI810->readControl(pI810, GRX, ADDRESS_MAPPING); + i810Reg->BitBLTControl = INREG8(BITBLT_CNTL); + i810Reg->VideoClk2_M = INREG16(VCLK2_VCO_M); + i810Reg->VideoClk2_N = INREG16(VCLK2_VCO_N); + i810Reg->VideoClk2_DivisorSel = INREG8(VCLK2_VCO_DIV_SEL); + + i810Reg->ExtVertTotal = hwp->readCrtc(hwp, EXT_VERT_TOTAL); + i810Reg->ExtVertDispEnd = hwp->readCrtc(hwp, EXT_VERT_DISPLAY); + i810Reg->ExtVertSyncStart = hwp->readCrtc(hwp, EXT_VERT_SYNC_START); + i810Reg->ExtVertBlankStart = hwp->readCrtc(hwp, EXT_VERT_BLANK_START); + i810Reg->ExtHorizTotal = hwp->readCrtc(hwp, EXT_HORIZ_TOTAL); + i810Reg->ExtHorizBlank = hwp->readCrtc(hwp, EXT_HORIZ_BLANK); + i810Reg->ExtOffset = hwp->readCrtc(hwp, EXT_OFFSET); + i810Reg->InterlaceControl = hwp->readCrtc(hwp, INTERLACE_CNTL); + + i810Reg->PixelPipeCfg0 = INREG8(PIXPIPE_CONFIG_0); + i810Reg->PixelPipeCfg1 = INREG8(PIXPIPE_CONFIG_1); + i810Reg->PixelPipeCfg2 = INREG8(PIXPIPE_CONFIG_2); + i810Reg->DisplayControl = INREG8(DISPLAY_CNTL); + i810Reg->LMI_FIFO_Watermark = INREG(FWATER_BLC); + + for (i = 0; i < 8; i++) + i810Reg->Fence[i] = INREG(FENCE + i * 4); + + i810Reg->LprbTail = INREG(LP_RING + RING_TAIL); + i810Reg->LprbHead = INREG(LP_RING + RING_HEAD); + i810Reg->LprbStart = INREG(LP_RING + RING_START); + i810Reg->LprbLen = INREG(LP_RING + RING_LEN); + + if ((i810Reg->LprbTail & TAIL_ADDR) != (i810Reg->LprbHead & HEAD_ADDR) && + i810Reg->LprbLen & RING_VALID) { + I810PrintErrorState(pScrn); + FatalError("Active ring not flushed\n"); + } +} + +static void +I810Save(ScrnInfoPtr pScrn) +{ + vgaHWPtr hwp; + I810Ptr pI810; + CARD32 temp; + + hwp = VGAHWPTR(pScrn); + pI810 = I810PTR(pScrn); + DoSave(pScrn, &hwp->SavedReg, &pI810->SavedReg, TRUE); + + temp = INREG(MEMMODE); + temp |= 4; + OUTREG(MEMMODE, temp); +} + +static void +i810PrintMode(vgaRegPtr vgaReg, I810RegPtr mode) +{ + int i; + + ErrorF(" MiscOut: %x\n", vgaReg->MiscOutReg); + + ErrorF("SEQ: "); + for (i = 0; i < vgaReg->numSequencer; i++) { + if ((i & 7) == 0) + ErrorF("\n"); + ErrorF(" %d: %x", i, vgaReg->Sequencer[i]); + } + ErrorF("\n"); + + ErrorF("CRTC: "); + for (i = 0; i < vgaReg->numCRTC; i++) { + if ((i & 3) == 0) + ErrorF("\n"); + ErrorF(" %d: %x", i, vgaReg->CRTC[i]); + } + ErrorF("\n"); + + ErrorF("GFX: "); + for (i = 0; i < vgaReg->numGraphics; i++) { + if ((i & 7) == 0) + ErrorF("\n"); + ErrorF(" %d: %x", i, vgaReg->Graphics[i]); + } + ErrorF("\n"); + + ErrorF("ATTR: "); + for (i = 0; i < vgaReg->numAttribute; i++) { + if ((i & 7) == 0) + ErrorF("\n"); + ErrorF(" %d: %x", i, vgaReg->Attribute[i]); + } + ErrorF("\n"); + + ErrorF(" DisplayControl: %x\n", mode->DisplayControl); + ErrorF(" PixelPipeCfg0: %x\n", mode->PixelPipeCfg0); + ErrorF(" PixelPipeCfg1: %x\n", mode->PixelPipeCfg1); + ErrorF(" PixelPipeCfg2: %x\n", mode->PixelPipeCfg2); + ErrorF(" VideoClk2_M: %x\n", mode->VideoClk2_M); + ErrorF(" VideoClk2_N: %x\n", mode->VideoClk2_N); + ErrorF(" VideoClk2_DivisorSel: %x\n", mode->VideoClk2_DivisorSel); + ErrorF(" AddressMapping: %x\n", mode->AddressMapping); + ErrorF(" IOControl: %x\n", mode->IOControl); + ErrorF(" BitBLTControl: %x\n", mode->BitBLTControl); + ErrorF(" ExtVertTotal: %x\n", mode->ExtVertTotal); + ErrorF(" ExtVertDispEnd: %x\n", mode->ExtVertDispEnd); + ErrorF(" ExtVertSyncStart: %x\n", mode->ExtVertSyncStart); + ErrorF(" ExtVertBlankStart: %x\n", mode->ExtVertBlankStart); + ErrorF(" ExtHorizTotal: %x\n", mode->ExtHorizTotal); + ErrorF(" ExtHorizBlank: %x\n", mode->ExtHorizBlank); + ErrorF(" ExtOffset: %x\n", mode->ExtOffset); + ErrorF(" InterlaceControl: %x\n", mode->InterlaceControl); + ErrorF(" LMI_FIFO_Watermark: %x\n", mode->LMI_FIFO_Watermark); + ErrorF(" LprbTail: %x\n", mode->LprbTail); + ErrorF(" LprbHead: %x\n", mode->LprbHead); + ErrorF(" LprbStart: %x\n", mode->LprbStart); + ErrorF(" LprbLen: %x\n", mode->LprbLen); +} + +static void +DoRestore(ScrnInfoPtr pScrn, vgaRegPtr vgaReg, I810RegPtr i810Reg, + Bool restoreFonts) +{ + I810Ptr pI810; + vgaHWPtr hwp; + unsigned char temp; + unsigned int itemp; + int i; + + pI810 = I810PTR(pScrn); + hwp = VGAHWPTR(pScrn); + + if (I810_DEBUG & DEBUG_VERBOSE_VGA) { + ErrorF("Setting mode in I810Restore:\n"); + i810PrintMode(vgaReg, i810Reg); + } + + vgaHWProtect(pScrn, TRUE); + + usleep(50000); + + /* Turn off DRAM Refresh */ + temp = INREG8(DRAM_ROW_CNTL_HI); + temp &= ~DRAM_REFRESH_RATE; + temp |= DRAM_REFRESH_DISABLE; + OUTREG8(DRAM_ROW_CNTL_HI, temp); + + usleep(1000); /* Wait 1 ms */ + + /* Write the M, N and P values */ + OUTREG16(VCLK2_VCO_M, i810Reg->VideoClk2_M); + OUTREG16(VCLK2_VCO_N, i810Reg->VideoClk2_N); + OUTREG8(VCLK2_VCO_DIV_SEL, i810Reg->VideoClk2_DivisorSel); + + /* + * Turn on 8 bit dac mode, if requested. This is needed to make + * sure that vgaHWRestore writes the values into the DAC properly. + * The problem occurs if 8 bit dac mode is requested and the HW is + * in 6 bit dac mode. If this happens, all the values are + * automatically shifted left twice by the HW and incorrect colors + * will be displayed on the screen. The only time this can happen + * is at server startup time and when switching back from a VT. + */ + temp = INREG8(PIXPIPE_CONFIG_0); + temp &= 0x7F; /* Save all but the 8 bit dac mode bit */ + temp |= (i810Reg->PixelPipeCfg0 & DAC_8_BIT); + OUTREG8(PIXPIPE_CONFIG_0, temp); + + /* + * Code to restore any SVGA registers that have been saved/modified + * goes here. Note that it is allowable, and often correct, to + * only modify certain bits in a register by a read/modify/write cycle. + * + * A special case - when using an external clock-setting program, + * this function must not change bits associated with the clock + * selection. This condition can be checked by the condition: + * + * if (i810Reg->std.NoClock >= 0) + * restore clock-select bits. + */ + if (restoreFonts) + vgaHWRestore(pScrn, vgaReg, VGA_SR_FONTS | VGA_SR_MODE | VGA_SR_CMAP); + else + vgaHWRestore(pScrn, vgaReg, VGA_SR_MODE | VGA_SR_CMAP); + + hwp->writeCrtc(hwp, EXT_VERT_TOTAL, i810Reg->ExtVertTotal); + hwp->writeCrtc(hwp, EXT_VERT_DISPLAY, i810Reg->ExtVertDispEnd); + hwp->writeCrtc(hwp, EXT_VERT_SYNC_START, i810Reg->ExtVertSyncStart); + hwp->writeCrtc(hwp, EXT_VERT_BLANK_START, i810Reg->ExtVertBlankStart); + hwp->writeCrtc(hwp, EXT_HORIZ_TOTAL, i810Reg->ExtHorizTotal); + hwp->writeCrtc(hwp, EXT_HORIZ_BLANK, i810Reg->ExtHorizBlank); + hwp->writeCrtc(hwp, EXT_OFFSET, i810Reg->ExtOffset); + + temp = hwp->readCrtc(hwp, INTERLACE_CNTL); + temp &= ~INTERLACE_ENABLE; + temp |= i810Reg->InterlaceControl; + hwp->writeCrtc(hwp, INTERLACE_CNTL, temp); + + temp = pI810->readControl(pI810, GRX, ADDRESS_MAPPING); + temp &= 0xE0; /* Save reserved bits 7:5 */ + temp |= i810Reg->AddressMapping; + pI810->writeControl(pI810, GRX, ADDRESS_MAPPING, temp); + + /* Setting the OVRACT Register for video overlay */ + { + CARD32 LCD_TV_Control = INREG(LCD_TV_C); + + if(!(LCD_TV_Control & LCD_TV_ENABLE) + || (LCD_TV_Control & LCD_TV_VGAMOD)) { + OUTREG(LCD_TV_OVRACT, + (i810Reg->OverlayActiveEnd << 16) + | i810Reg->OverlayActiveStart); + } + } + + /* Turn on DRAM Refresh */ + temp = INREG8(DRAM_ROW_CNTL_HI); + temp &= ~DRAM_REFRESH_RATE; + temp |= DRAM_REFRESH_60HZ; + OUTREG8(DRAM_ROW_CNTL_HI, temp); + + temp = INREG8(BITBLT_CNTL); + temp &= ~COLEXP_MODE; + temp |= i810Reg->BitBLTControl; + OUTREG8(BITBLT_CNTL, temp); + + temp = INREG8(DISPLAY_CNTL); + temp &= ~(VGA_WRAP_MODE | GUI_MODE); + temp |= i810Reg->DisplayControl; + OUTREG8(DISPLAY_CNTL, temp); + + temp = INREG8(PIXPIPE_CONFIG_0); + temp &= 0x64; /* Save reserved bits 6:5,2 */ + temp |= i810Reg->PixelPipeCfg0; + OUTREG8(PIXPIPE_CONFIG_0, temp); + + temp = INREG8(PIXPIPE_CONFIG_2); + temp &= 0xF3; /* Save reserved bits 7:4,1:0 */ + temp |= i810Reg->PixelPipeCfg2; + OUTREG8(PIXPIPE_CONFIG_2, temp); + + temp = INREG8(PIXPIPE_CONFIG_1); + temp &= ~DISPLAY_COLOR_MODE; + temp &= 0xEF; /* Restore the CRT control bit */ + temp |= i810Reg->PixelPipeCfg1; + OUTREG8(PIXPIPE_CONFIG_1, temp); + + OUTREG16(EIR, 0); + + itemp = INREG(FWATER_BLC); + itemp &= ~(LM_BURST_LENGTH | LM_FIFO_WATERMARK | + MM_BURST_LENGTH | MM_FIFO_WATERMARK); + itemp |= i810Reg->LMI_FIFO_Watermark; + OUTREG(FWATER_BLC, itemp); + + for (i = 0; i < 8; i++) { + OUTREG(FENCE + i * 4, i810Reg->Fence[i]); + if (I810_DEBUG & DEBUG_VERBOSE_VGA) + ErrorF("Fence Register : %x\n", i810Reg->Fence[i]); + } + + /* First disable the ring buffer (Need to wait for empty first?, if so + * should probably do it before entering this section) + */ + itemp = INREG(LP_RING + RING_LEN); + itemp &= ~RING_VALID_MASK; + OUTREG(LP_RING + RING_LEN, itemp); + + /* Set up the low priority ring buffer. + */ + OUTREG(LP_RING + RING_TAIL, 0); + OUTREG(LP_RING + RING_HEAD, 0); + + pI810->LpRing.head = 0; + pI810->LpRing.tail = 0; + + itemp = INREG(LP_RING + RING_START); + itemp &= ~(START_ADDR); + itemp |= i810Reg->LprbStart; + OUTREG(LP_RING + RING_START, itemp); + + itemp = INREG(LP_RING + RING_LEN); + itemp &= ~(RING_NR_PAGES | RING_REPORT_MASK | RING_VALID_MASK); + itemp |= i810Reg->LprbLen; + OUTREG(LP_RING + RING_LEN, itemp); + + if (!(vgaReg->Attribute[0x10] & 0x1)) { + usleep(50000); + if (restoreFonts) + vgaHWRestore(pScrn, vgaReg, + VGA_SR_FONTS | VGA_SR_MODE | VGA_SR_CMAP); + else + vgaHWRestore(pScrn, vgaReg, VGA_SR_MODE | VGA_SR_CMAP); + } + + vgaHWProtect(pScrn, FALSE); + + temp = hwp->readCrtc(hwp, IO_CTNL); + temp &= ~(EXTENDED_ATTR_CNTL | EXTENDED_CRTC_CNTL); + temp |= i810Reg->IOControl; + hwp->writeCrtc(hwp, IO_CTNL, temp); +} + +static void +I810SetRingRegs(ScrnInfoPtr pScrn) +{ + unsigned int itemp; + I810Ptr pI810 = I810PTR(pScrn); + + OUTREG(LP_RING + RING_TAIL, 0); + OUTREG(LP_RING + RING_HEAD, 0); + + itemp = INREG(LP_RING + RING_START); + itemp &= ~(START_ADDR); + itemp |= pI810->LpRing.mem.Start; + OUTREG(LP_RING + RING_START, itemp); + + itemp = INREG(LP_RING + RING_LEN); + itemp &= ~(RING_NR_PAGES | RING_REPORT_MASK | RING_VALID_MASK); + itemp |= ((pI810->LpRing.mem.Size - 4096) | RING_NO_REPORT | RING_VALID); + OUTREG(LP_RING + RING_LEN, itemp); +} + +static void +I810Restore(ScrnInfoPtr pScrn) +{ + vgaHWPtr hwp; + I810Ptr pI810; + + hwp = VGAHWPTR(pScrn); + pI810 = I810PTR(pScrn); + + DoRestore(pScrn, &hwp->SavedReg, &pI810->SavedReg, TRUE); +} + +/* + * I810CalcVCLK -- + * + * Determine the closest clock frequency to the one requested. + */ + +#define MAX_VCO_FREQ 600.0 +#define TARGET_MAX_N 30 +#define REF_FREQ 24.0 + +#define CALC_VCLK(m,n,p) \ + (double)m / ((double)n * (1 << p)) * 4 * REF_FREQ + +static void +I810CalcVCLK(ScrnInfoPtr pScrn, double freq) +{ + I810Ptr pI810 = I810PTR(pScrn); + I810RegPtr i810Reg = &pI810->ModeReg; + int m, n, p; + double f_out, f_best; + double f_err; + double f_vco; + int m_best = 0, n_best = 0, p_best = 0; + double f_target = freq; + double err_max = 0.005; + double err_target = 0.001; + double err_best = 999999.0; + + p_best = p = log(MAX_VCO_FREQ / f_target) / log((double)2); + f_vco = f_target * (1 << p); + + n = 2; + do { + n++; + m = f_vco / (REF_FREQ / (double)n) / (double)4.0 + 0.5; + if (m < 3) + m = 3; + f_out = CALC_VCLK(m, n, p); + f_err = 1.0 - (f_target / f_out); + if (fabs(f_err) < err_max) { + m_best = m; + n_best = n; + f_best = f_out; + err_best = f_err; + } + } while ((fabs(f_err) >= err_target) && + ((n <= TARGET_MAX_N) || (fabs(err_best) > err_max))); + + if (fabs(f_err) < err_target) { + m_best = m; + n_best = n; + } + + i810Reg->VideoClk2_M = (m_best - 2) & 0x3FF; + i810Reg->VideoClk2_N = (n_best - 2) & 0x3FF; + i810Reg->VideoClk2_DivisorSel = (p_best << 4); + + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, + "Setting dot clock to %.1lf MHz " "[ 0x%x 0x%x 0x%x ] " + "[ %d %d %d ]\n", CALC_VCLK(m_best, n_best, p_best), + i810Reg->VideoClk2_M, i810Reg->VideoClk2_N, + i810Reg->VideoClk2_DivisorSel, m_best, n_best, p_best); +} + +static Bool +I810SetMode(ScrnInfoPtr pScrn, DisplayModePtr mode) +{ + I810Ptr pI810 = I810PTR(pScrn); + I810RegPtr i810Reg = &pI810->ModeReg; + vgaRegPtr pVga = &VGAHWPTR(pScrn)->ModeReg; + double dclk = mode->Clock / 1000.0; + + switch (pScrn->bitsPerPixel) { + case 8: + pVga->CRTC[0x13] = pScrn->displayWidth >> 3; + i810Reg->ExtOffset = pScrn->displayWidth >> 11; + i810Reg->PixelPipeCfg1 = DISPLAY_8BPP_MODE; + i810Reg->BitBLTControl = COLEXP_8BPP; + break; + case 16: + if (pScrn->weight.green == 5) { + i810Reg->PixelPipeCfg1 = DISPLAY_15BPP_MODE; + } else { + i810Reg->PixelPipeCfg1 = DISPLAY_16BPP_MODE; + } + pVga->CRTC[0x13] = pScrn->displayWidth >> 2; + i810Reg->ExtOffset = pScrn->displayWidth >> 10; + i810Reg->BitBLTControl = COLEXP_16BPP; + + /* Enable Palette Programming for Direct Color visuals. -jens */ + i810Reg->PixelPipeCfg2 = DISPLAY_GAMMA_ENABLE; + break; + case 24: + pVga->CRTC[0x13] = (pScrn->displayWidth * 3) >> 3; + i810Reg->ExtOffset = (pScrn->displayWidth * 3) >> 11; + + i810Reg->PixelPipeCfg1 = DISPLAY_24BPP_MODE; + i810Reg->BitBLTControl = COLEXP_24BPP; + + /* Enable Palette Programming for Direct Color visuals. -jens */ + i810Reg->PixelPipeCfg2 = DISPLAY_GAMMA_ENABLE; + break; + default: + break; + } + + /* Turn on 8 bit dac if requested */ + if (xf86ReturnOptValBool(pI810->Options, OPTION_DAC_6BIT, FALSE)) + i810Reg->PixelPipeCfg0 = DAC_6_BIT; + else + i810Reg->PixelPipeCfg0 = DAC_8_BIT; + + /* Do not delay CRT Blank: needed for video overlay */ + i810Reg->PixelPipeCfg1 |= 0x10; + + /* Turn on Extended VGA Interpretation */ + i810Reg->IOControl = EXTENDED_CRTC_CNTL; + + /* Turn on linear and page mapping */ + i810Reg->AddressMapping = (LINEAR_MODE_ENABLE | GTT_MEM_MAP_ENABLE); + + /* Turn on GUI mode */ + i810Reg->DisplayControl = HIRES_MODE; + + /* Calculate the extended CRTC regs */ + i810Reg->ExtVertTotal = (mode->CrtcVTotal - 2) >> 8; + i810Reg->ExtVertDispEnd = (mode->CrtcVDisplay - 1) >> 8; + i810Reg->ExtVertSyncStart = mode->CrtcVSyncStart >> 8; + i810Reg->ExtVertBlankStart = mode->CrtcVBlankStart >> 8; + i810Reg->ExtHorizTotal = ((mode->CrtcHTotal >> 3) - 5) >> 8; + i810Reg->ExtHorizBlank = (((mode->CrtcHBlankEnd >> 3) - 1) & 0x40) >> 6; + + /* + * The following workarounds are needed to get video overlay working + * at 1024x768 and 1280x1024 display resolutions. + */ + if ((mode->CrtcVDisplay == 768) && (i810Reg->ExtVertBlankStart == 3)) { + i810Reg->ExtVertBlankStart = 2; + } + if ((mode->CrtcVDisplay == 1024) && (i810Reg->ExtVertBlankStart == 4)) { + i810Reg->ExtVertBlankStart = 3; + } + + /* OVRACT Register */ + i810Reg->OverlayActiveStart = mode->CrtcHTotal - 32; + i810Reg->OverlayActiveEnd = mode->CrtcHDisplay - 32; + + /* Turn on interlaced mode if necessary */ + if (mode->Flags & V_INTERLACE) + i810Reg->InterlaceControl = INTERLACE_ENABLE; + else + i810Reg->InterlaceControl = INTERLACE_DISABLE; + + /* + * Set the overscan color to 0. + * NOTE: This only affects >8bpp mode. + */ + pVga->Attribute[0x11] = 0; + + /* + * Calculate the VCLK that most closely matches the requested dot + * clock. + */ + I810CalcVCLK(pScrn, dclk); + + /* Since we program the clocks ourselves, always use VCLK2. */ + pVga->MiscOutReg |= 0x0C; + + /* Calculate the FIFO Watermark and Burst Length. */ + i810Reg->LMI_FIFO_Watermark = I810CalcWatermark(pScrn, dclk, FALSE); + + /* Setup the ring buffer */ + i810Reg->LprbTail = 0; + i810Reg->LprbHead = 0; + i810Reg->LprbStart = pI810->LpRing.mem.Start; + + if (i810Reg->LprbStart) + i810Reg->LprbLen = ((pI810->LpRing.mem.Size - 4096) | + RING_NO_REPORT | RING_VALID); + else + i810Reg->LprbLen = RING_INVALID; + + return TRUE; +} + +static Bool +I810ModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode) +{ + vgaHWPtr hwp; + I810Ptr pI810; + vgaRegPtr pVga; + + hwp = VGAHWPTR(pScrn); + pI810 = I810PTR(pScrn); + + vgaHWUnlock(hwp); + + if (!vgaHWInit(pScrn, mode)) + return FALSE; + /* + * the KGA fix in vgaHW.c results in the first + * scanline and the first character clock (8 pixels) + * of each scanline thereafter on display with an i810 + * to be blank. Restoring CRTC 3, 5, & 22 to their + * "theoretical" values corrects the problem. KAO. + */ + pVga = &VGAHWPTR(pScrn)->ModeReg; + pVga->CRTC[3] = (((mode->CrtcHBlankEnd >> 3) - 1) & 0x1F) | 0x80; + pVga->CRTC[5] = ((((mode->CrtcHBlankEnd >> 3) - 1) & 0x20) << 2) + | (((mode->CrtcHSyncEnd >> 3)) & 0x1F); + pVga->CRTC[22] = (mode->CrtcVBlankEnd - 1) & 0xFF; + + pScrn->vtSema = TRUE; + + if (!I810SetMode(pScrn, mode)) + return FALSE; + +#ifdef XF86DRI + if (pI810->directRenderingEnabled) { + DRILock(screenInfo.screens[pScrn->scrnIndex], 0); + pI810->LockHeld = 1; + } +#endif + + DoRestore(pScrn, &hwp->ModeReg, &pI810->ModeReg, FALSE); + +#ifdef XF86DRI + if (pI810->directRenderingEnabled) { + DRIUnlock(screenInfo.screens[pScrn->scrnIndex]); + pI810->LockHeld = 0; + } +#endif + + return TRUE; +} + +static void +I810LoadPalette15(ScrnInfoPtr pScrn, int numColors, int *indices, + LOCO * colors, VisualPtr pVisual) +{ + I810Ptr pI810; + vgaHWPtr hwp; + int i, j, index; + unsigned char r, g, b; + + pI810 = I810PTR(pScrn); + hwp = VGAHWPTR(pScrn); + + for (i = 0; i < numColors; i++) { + index = indices[i]; + r = colors[index].red; + g = colors[index].green; + b = colors[index].blue; + for (j = 0; j < 8; j++) { + hwp->writeDacWriteAddr(hwp, (index << 3) + j); + hwp->writeDacData(hwp, r); + hwp->writeDacData(hwp, g); + hwp->writeDacData(hwp, b); + } + } +} + +static void +I810LoadPalette16(ScrnInfoPtr pScrn, int numColors, int *indices, + LOCO * colors, VisualPtr pVisual) +{ + I810Ptr pI810; + vgaHWPtr hwp; + int i, index; + unsigned char r, g, b; + + pI810 = I810PTR(pScrn); + hwp = VGAHWPTR(pScrn); + + /* Load all four entries in each of the 64 color ranges. -jens */ + for (i = 0; i < numColors; i++) { + index = indices[i / 2]; + r = colors[index].red; + b = colors[index].blue; + index = indices[i]; + g = colors[index].green; + + hwp->writeDacWriteAddr(hwp, index << 2); + hwp->writeDacData(hwp, r); + hwp->writeDacData(hwp, g); + hwp->writeDacData(hwp, b); + + hwp->writeDacWriteAddr(hwp, (index << 2) + 1); + hwp->writeDacData(hwp, r); + hwp->writeDacData(hwp, g); + hwp->writeDacData(hwp, b); + + hwp->writeDacWriteAddr(hwp, (index << 2) + 2); + hwp->writeDacData(hwp, r); + hwp->writeDacData(hwp, g); + hwp->writeDacData(hwp, b); + + hwp->writeDacWriteAddr(hwp, (index << 2) + 3); + hwp->writeDacData(hwp, r); + hwp->writeDacData(hwp, g); + hwp->writeDacData(hwp, b); + + i++; + index = indices[i]; + g = colors[index].green; + + hwp->writeDacWriteAddr(hwp, index << 2); + hwp->writeDacData(hwp, r); + hwp->writeDacData(hwp, g); + hwp->writeDacData(hwp, b); + + hwp->writeDacWriteAddr(hwp, (index << 2) + 1); + hwp->writeDacData(hwp, r); + hwp->writeDacData(hwp, g); + hwp->writeDacData(hwp, b); + + hwp->writeDacWriteAddr(hwp, (index << 2) + 2); + hwp->writeDacData(hwp, r); + hwp->writeDacData(hwp, g); + hwp->writeDacData(hwp, b); + + hwp->writeDacWriteAddr(hwp, (index << 2) + 3); + hwp->writeDacData(hwp, r); + hwp->writeDacData(hwp, g); + hwp->writeDacData(hwp, b); + } +} + +static void +I810LoadPalette24(ScrnInfoPtr pScrn, int numColors, int *indices, + LOCO * colors, VisualPtr pVisual) +{ + I810Ptr pI810; + vgaHWPtr hwp; + int i, index; + unsigned char r, g, b; + + pI810 = I810PTR(pScrn); + hwp = VGAHWPTR(pScrn); + + for (i = 0; i < numColors; i++) { + index = indices[i]; + r = colors[index].red; + g = colors[index].green; + b = colors[index].blue; + hwp->writeDacWriteAddr(hwp, index); + hwp->writeDacData(hwp, r); + hwp->writeDacData(hwp, g); + hwp->writeDacData(hwp, b); + } +} + +Bool +I810AllocateFront(ScrnInfoPtr pScrn) +{ + I810Ptr pI810 = I810PTR(pScrn); + int cache_lines = -1; + + if (pI810->DoneFrontAlloc) + return TRUE; + + memset(&(pI810->FbMemBox), 0, sizeof(BoxRec)); + /* Alloc FrontBuffer/Ring/Accel memory */ + pI810->FbMemBox.x1 = 0; + pI810->FbMemBox.x2 = pScrn->displayWidth; + pI810->FbMemBox.y1 = 0; + pI810->FbMemBox.y2 = pScrn->virtualY; + + xf86GetOptValInteger(pI810->Options, OPTION_CACHE_LINES, &cache_lines); + + if (cache_lines < 0) { + /* make sure there is enough for two DVD sized YUV buffers */ + cache_lines = (pScrn->depth == 24) ? 256 : 384; + if (pScrn->displayWidth <= 1024) + cache_lines *= 2; + } + /* Make sure there's enough space for cache_lines. + * + * Had a bug here where maxCacheLines was computed to be less than 0. + * Not sure why 256 was initially subtracted from videoRam in the + * maxCacheLines calculation, but that was causing a problem + * for configurations that have exactly enough Ram for the framebuffer. + * Common code should catch the case where there isn't enough space for + * framebuffer, we'll just check for no space for cache_lines. -jens + * + */ + { + int maxCacheLines; + + maxCacheLines = (pScrn->videoRam * 1024 / + (pScrn->bitsPerPixel / 8) / + pScrn->displayWidth) - pScrn->virtualY; + if (maxCacheLines < 0) + maxCacheLines = 0; + if (cache_lines > maxCacheLines) + cache_lines = maxCacheLines; + } + pI810->FbMemBox.y2 += cache_lines; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Adding %i scanlines for pixmap caching\n", cache_lines); + + /* Reserve room for the framebuffer and pixcache. Put at the top + * of memory so we can have nice alignment for the tiled regions at + * the start of memory. + */ + + if (!I810AllocLow(&(pI810->FrontBuffer), + &(pI810->SysMem), + ((pI810->FbMemBox.x2 * + pI810->FbMemBox.y2 * pI810->cpp) + 4095) & ~4095)) { + xf86DrvMsg(pScrn->scrnIndex, + X_WARNING, "Framebuffer allocation failed\n"); + return FALSE; + } else + DPRINTF(PFX, + "Frame buffer at 0x%.8x (%luk, %lu bytes)\n", + pI810->FrontBuffer.Start, + pI810->FrontBuffer.Size / 1024, pI810->FrontBuffer.Size); + + memset(&(pI810->LpRing), 0, sizeof(I810RingBuffer)); + if (I810AllocLow(&(pI810->LpRing.mem), &(pI810->SysMem), 16 * 4096)) { + DPRINTF(PFX, + "Ring buffer at 0x%.8x (%luk, %lu bytes)\n", + pI810->LpRing.mem.Start, + pI810->LpRing.mem.Size / 1024, pI810->LpRing.mem.Size); + + pI810->LpRing.tail_mask = pI810->LpRing.mem.Size - 1; + pI810->LpRing.virtual_start = pI810->FbBase + pI810->LpRing.mem.Start; + pI810->LpRing.head = 0; + pI810->LpRing.tail = 0; + pI810->LpRing.space = 0; + } else { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Ring buffer allocation failed\n"); + return (FALSE); + } + + if (I810AllocLow(&pI810->Scratch, &(pI810->SysMem), 64 * 1024) || + I810AllocLow(&pI810->Scratch, &(pI810->SysMem), 16 * 1024)) { + DPRINTF(PFX, + "Scratch memory at 0x%.8x (%luk, %lu bytes)\n", + pI810->Scratch.Start, + pI810->Scratch.Size / 1024, pI810->Scratch.Size); + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Allocated Scratch Memory\n"); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Scratch memory allocation failed\n"); + return (FALSE); + } + + pI810->DoneFrontAlloc = TRUE; + return TRUE; +} + +static Bool +I810ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) +{ + ScrnInfoPtr pScrn; + vgaHWPtr hwp; + I810Ptr pI810; + VisualPtr visual; + MessageType driFrom = X_DEFAULT; + + pScrn = xf86Screens[pScreen->myNum]; + pI810 = I810PTR(pScrn); + hwp = VGAHWPTR(pScrn); + + miClearVisualTypes(); + + /* Re-implemented Direct Color support, -jens */ + if (!miSetVisualTypes(pScrn->depth, miGetDefaultVisualMask(pScrn->depth), + pScrn->rgbBits, pScrn->defaultVisual)) + return FALSE; + + if (!miSetPixmapDepths()) + return FALSE; + + { + I810RegPtr i810Reg = &pI810->ModeReg; + int i; + + for (i = 0; i < 8; i++) + i810Reg->Fence[i] = 0; + } + + /* Have to init the DRM earlier than in other drivers to get agp + * memory. Wonder if this is going to be a problem... + */ + +#ifdef XF86DRI + /* + * Setup DRI after visuals have been established, but before cfbScreenInit + * is called. cfbScreenInit will eventually call into the drivers + * InitGLXVisuals call back. + */ + + if (xf86ReturnOptValBool(pI810->Options, OPTION_NOACCEL, FALSE) || + !xf86ReturnOptValBool(pI810->Options, OPTION_DRI, TRUE)) { + pI810->directRenderingEnabled = FALSE; + driFrom = X_CONFIG; + } else { + pI810->directRenderingEnabled = I810DRIScreenInit(pScreen); + } + +#else + pI810->directRenderingEnabled = FALSE; + if (!I810AllocateGARTMemory(pScrn)) + return FALSE; + if (!I810AllocateFront(pScrn)) + return FALSE; +#endif + + if (!I810MapMem(pScrn)) + return FALSE; + + pScrn->memPhysBase = (unsigned long)pI810->LinearAddr; + pScrn->fbOffset = 0; + + vgaHWSetMmioFuncs(hwp, pI810->MMIOBase, 0); + vgaHWGetIOBase(hwp); + if (!vgaHWMapMem(pScrn)) + return FALSE; + + I810Save(pScrn); + if (!I810ModeInit(pScrn, pScrn->currentMode)) + return FALSE; + + I810SaveScreen(pScreen, FALSE); + I810AdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); + + if (!fbScreenInit(pScreen, pI810->FbBase + pScrn->fbOffset, + pScrn->virtualX, pScrn->virtualY, + pScrn->xDpi, pScrn->yDpi, + pScrn->displayWidth, pScrn->bitsPerPixel)) + return FALSE; + + if (pScrn->bitsPerPixel > 8) { + /* Fixup RGB ordering */ + visual = pScreen->visuals + pScreen->numVisuals; + while (--visual >= pScreen->visuals) { + if ((visual->class | DynamicClass) == DirectColor) { + visual->offsetRed = pScrn->offset.red; + visual->offsetGreen = pScrn->offset.green; + visual->offsetBlue = pScrn->offset.blue; + visual->redMask = pScrn->mask.red; + visual->greenMask = pScrn->mask.green; + visual->blueMask = pScrn->mask.blue; + } + } + } + + fbPictureInit(pScreen, 0, 0); + + xf86SetBlackWhitePixels(pScreen); + +#ifdef XF86DRI + if (pI810->LpRing.mem.Start == 0 && pI810->directRenderingEnabled) { + pI810->directRenderingEnabled = FALSE; + driFrom = X_PROBED; + I810DRICloseScreen(pScreen); + } + + if (!pI810->directRenderingEnabled) { + pI810->DoneFrontAlloc = FALSE; + if (!I810AllocateGARTMemory(pScrn)) + return FALSE; + if (!I810AllocateFront(pScrn)) + return FALSE; + } +#endif + + I810DGAInit(pScreen); + + if (!xf86InitFBManager(pScreen, &(pI810->FbMemBox))) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to init memory manager\n"); + return FALSE; + } + + if (!xf86ReturnOptValBool(pI810->Options, OPTION_NOACCEL, FALSE)) { + if (pI810->LpRing.mem.Size != 0) { + I810SetRingRegs(pScrn); + + if (!I810AccelInit(pScreen)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Hardware acceleration initialization failed\n"); + } + } + } + + miInitializeBackingStore(pScreen); + xf86SetBackingStore(pScreen); + xf86SetSilkenMouse(pScreen); + + miDCInitialize(pScreen, xf86GetPointerScreenFuncs()); + + if (!xf86ReturnOptValBool(pI810->Options, OPTION_SW_CURSOR, FALSE)) { + if (!I810CursorInit(pScreen)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Hardware cursor initialization failed\n"); + } + } + + if (!miCreateDefColormap(pScreen)) + return FALSE; + + /* Use driver specific palette load routines for Direct Color support. -jens */ + if (pScrn->bitsPerPixel == 16) { + if (pScrn->depth == 15) { + if (!xf86HandleColormaps(pScreen, 256, 8, I810LoadPalette15, 0, + CMAP_PALETTED_TRUECOLOR | + CMAP_RELOAD_ON_MODE_SWITCH)) + return FALSE; + } else { + if (!xf86HandleColormaps(pScreen, 256, 8, I810LoadPalette16, 0, + CMAP_PALETTED_TRUECOLOR | + CMAP_RELOAD_ON_MODE_SWITCH)) + return FALSE; + } + } else { + if (!xf86HandleColormaps(pScreen, 256, 8, I810LoadPalette24, 0, + CMAP_PALETTED_TRUECOLOR | + CMAP_RELOAD_ON_MODE_SWITCH)) + return FALSE; + } + + xf86DPMSInit(pScreen, I810DisplayPowerManagementSet, 0); + + I810InitVideo(pScreen); + +#ifdef XF86DRI + if (pI810->directRenderingEnabled) { + /* Now that mi, cfb, drm and others have done their thing, + * complete the DRI setup. + */ + pI810->directRenderingEnabled = I810DRIFinishScreenInit(pScreen); + } +#ifdef XvMCExtension + if ((pI810->directRenderingEnabled) && (pI810->numSurfaces)) { + /* Initialize the hardware motion compensation code */ + I810InitMC(pScreen); + } +#endif +#endif + + if (pI810->directRenderingEnabled) { + xf86DrvMsg(pScrn->scrnIndex, driFrom, "Direct rendering enabled\n"); + } else { + xf86DrvMsg(pScrn->scrnIndex, driFrom, "Direct rendering disabled\n"); + } + + pScreen->SaveScreen = I810SaveScreen; + pI810->CloseScreen = pScreen->CloseScreen; + pScreen->CloseScreen = I810CloseScreen; + + if (serverGeneration == 1) + xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options); + + return TRUE; +} + +Bool +I810SwitchMode(int scrnIndex, DisplayModePtr mode, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + + if (I810_DEBUG & DEBUG_VERBOSE_CURSOR) + ErrorF("I810SwitchMode %p %x\n", mode, flags); + + return I810ModeInit(pScrn, mode); +} + +void +I810AdjustFrame(int scrnIndex, int x, int y, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + I810Ptr pI810 = I810PTR(pScrn); + vgaHWPtr hwp = VGAHWPTR(pScrn); + int Base; +#if 1 + if (pI810->showCache) { + int lastline = pI810->FbMapSize / + ((pScrn->displayWidth * pScrn->bitsPerPixel) / 8); + lastline -= pScrn->currentMode->VDisplay; + if (y > 0) + y += pScrn->currentMode->VDisplay; + if (y > lastline) y = lastline; + } +#endif + Base = (y * pScrn->displayWidth + x) >> 2; + + if (I810_DEBUG & DEBUG_VERBOSE_CURSOR) + ErrorF("I810AdjustFrame %d,%d %x\n", x, y, flags); + + switch (pScrn->bitsPerPixel) { + case 8: + break; + case 16: + Base *= 2; + break; + case 24: + /* KW: Need to do 16-pixel alignment for i810, otherwise you + * get bad watermark problems. Need to fixup the mouse + * pointer positioning to take this into account. + */ + pI810->CursorOffset = (Base & 0x3) * 4; + Base &= ~0x3; + Base *= 3; + break; + case 32: + Base *= 4; + break; + } + + hwp->writeCrtc(hwp, START_ADDR_LO, Base & 0xFF); + hwp->writeCrtc(hwp, START_ADDR_HI, (Base & 0xFF00) >> 8); + hwp->writeCrtc(hwp, EXT_START_ADDR_HI, (Base & 0x3FC00000) >> 22); + hwp->writeCrtc(hwp, EXT_START_ADDR, + ((Base & 0x00eF0000) >> 16 | EXT_START_ADDR_ENABLE)); +} + +/* These functions are usually called with the lock **not held**. + */ +static Bool +I810EnterVT(int scrnIndex, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + +#ifdef XF86DRI + I810Ptr pI810 = I810PTR(pScrn); +#endif + + if (I810_DEBUG & DEBUG_VERBOSE_DRI) + ErrorF("\n\nENTER VT\n"); + + if (!I810BindGARTMemory(pScrn)) + return FALSE; + +#ifdef XF86DRI + if (pI810->directRenderingEnabled) { + if (I810_DEBUG & DEBUG_VERBOSE_DRI) + ErrorF("calling dri unlock\n"); + DRIUnlock(screenInfo.screens[scrnIndex]); + pI810->LockHeld = 0; + } +#endif + + if (!I810ModeInit(pScrn, pScrn->currentMode)) + return FALSE; + I810AdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); + return TRUE; +} + +static void +I810LeaveVT(int scrnIndex, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + vgaHWPtr hwp = VGAHWPTR(pScrn); + I810Ptr pI810 = I810PTR(pScrn); + + if (I810_DEBUG & DEBUG_VERBOSE_DRI) + ErrorF("\n\n\nLeave VT\n"); + +#ifdef XF86DRI + if (pI810->directRenderingEnabled) { + if (I810_DEBUG & DEBUG_VERBOSE_DRI) + ErrorF("calling dri lock\n"); + DRILock(screenInfo.screens[scrnIndex], 0); + pI810->LockHeld = 1; + } +#endif + + if (pI810->AccelInfoRec != NULL) { + I810RefreshRing(pScrn); + I810Sync(pScrn); + pI810->AccelInfoRec->NeedToSync = FALSE; + } + I810Restore(pScrn); + + if (!I810UnbindGARTMemory(pScrn)) + return; + + vgaHWLock(hwp); +} + +static Bool +I810CloseScreen(int scrnIndex, ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + vgaHWPtr hwp = VGAHWPTR(pScrn); + I810Ptr pI810 = I810PTR(pScrn); + XAAInfoRecPtr infoPtr = pI810->AccelInfoRec; + + if (pScrn->vtSema == TRUE) { + I810Restore(pScrn); + vgaHWLock(hwp); + } +#ifdef XF86DRI + if (pI810->directRenderingEnabled) { + I810DRICloseScreen(pScreen); + pI810->directRenderingEnabled = FALSE; + } +#endif + + if (pScrn->vtSema == TRUE) { + I810UnbindGARTMemory(pScrn); + I810Restore(pScrn); + vgaHWLock(hwp); + } + + I810UnmapMem(pScrn); + vgaHWUnmapMem(pScrn); + + if (pI810->ScanlineColorExpandBuffers) { + xfree(pI810->ScanlineColorExpandBuffers); + pI810->ScanlineColorExpandBuffers = 0; + } + + if (infoPtr) { + if (infoPtr->ScanlineColorExpandBuffers) + xfree(infoPtr->ScanlineColorExpandBuffers); + XAADestroyInfoRec(infoPtr); + pI810->AccelInfoRec = 0; + } + + if (pI810->CursorInfoRec) { + xf86DestroyCursorInfoRec(pI810->CursorInfoRec); + pI810->CursorInfoRec = 0; + } + + /* Free all allocated video ram. + */ + pI810->SysMem = pI810->SavedSysMem; + pI810->DcacheMem = pI810->SavedDcacheMem; + pI810->DoneFrontAlloc = FALSE; + + /* Need to actually close the gart fd, or the unbound memory will just sit + * around. Will prevent the Xserver from recycling. + */ + xf86GARTCloseScreen(scrnIndex); + + pScrn->vtSema = FALSE; + pScreen->CloseScreen = pI810->CloseScreen; + return (*pScreen->CloseScreen) (scrnIndex, pScreen); +} + +static void +I810FreeScreen(int scrnIndex, int flags) +{ + I810FreeRec(xf86Screens[scrnIndex]); + if (xf86LoaderCheckSymbol("vgaHWFreeHWRec")) + vgaHWFreeHWRec(xf86Screens[scrnIndex]); +} + +static int +I810ValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags) +{ + if (mode->Flags & V_INTERLACE) { + if (verbose) { + xf86DrvMsg(scrnIndex, X_PROBED, + "Removing interlaced mode \"%s\"\n", mode->name); + } + return MODE_BAD; + } + return MODE_OK; +} + +static Bool +I810SaveScreen(ScreenPtr pScreen, Bool unblack) +{ + return vgaHWSaveScreen(pScreen, unblack); +} + +static void +I810DisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode, + int flags) +{ + I810Ptr pI810; + unsigned char SEQ01 = 0; + int DPMSSyncSelect = 0; + + pI810 = I810PTR(pScrn); + switch (PowerManagementMode) { + case DPMSModeOn: + /* Screen: On; HSync: On, VSync: On */ + SEQ01 = 0x00; + DPMSSyncSelect = HSYNC_ON | VSYNC_ON; + break; + case DPMSModeStandby: + /* Screen: Off; HSync: Off, VSync: On */ + SEQ01 = 0x20; + DPMSSyncSelect = HSYNC_OFF | VSYNC_ON; + break; + case DPMSModeSuspend: + /* Screen: Off; HSync: On, VSync: Off */ + SEQ01 = 0x20; + DPMSSyncSelect = HSYNC_ON | VSYNC_OFF; + break; + case DPMSModeOff: + /* Screen: Off; HSync: Off, VSync: Off */ + SEQ01 = 0x20; + DPMSSyncSelect = HSYNC_OFF | VSYNC_OFF; + break; + } + + /* Turn the screen on/off */ + SEQ01 |= pI810->readControl(pI810, SRX, 0x01) & ~0x20; + pI810->writeControl(pI810, SRX, 0x01, SEQ01); + + /* Set the DPMS mode */ + OUTREG8(DPMS_SYNC_SELECT, DPMSSyncSelect); +} +#endif /* I830_ONLY */ diff --git a/src/i810_hwmc.c b/src/i810_hwmc.c new file mode 100644 index 00000000..525ad361 --- /dev/null +++ b/src/i810_hwmc.c @@ -0,0 +1,417 @@ +/*************************************************************************** + +Copyright 2000 Intel Corporation. All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sub license, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice (including the +next paragraph) shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +IN NO EVENT SHALL INTEL, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR +THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ + +/* + * i810_hwmc.c: i810 HWMC Driver + * + * Authors: + * Matt Sottek <matthew.j.sottek@intel.com> + * + * + */ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i810/i810_hwmc.c,v 1.4 2002/09/11 00:29:32 dawes Exp $ */ + + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86Resources.h" +#include "xf86_ansic.h" +#include "compiler.h" +#include "xf86PciInfo.h" +#include "xf86Pci.h" +#include "xf86fbman.h" +#include "regionstr.h" + +#include "i810.h" +#include "i810_dri.h" + +#include "xf86xv.h" +#include "xf86xvmc.h" +#include "Xv.h" +#include "XvMC.h" +#include "xaa.h" +#include "xaalocal.h" +#include "dixstruct.h" +#include "fourcc.h" + +int I810XvMCCreateContext (ScrnInfoPtr pScrn, XvMCContextPtr pContext, + int *num_priv, long **priv ); +void I810XvMCDestroyContext (ScrnInfoPtr pScrn, XvMCContextPtr pContext); + +int I810XvMCCreateSurface (ScrnInfoPtr pScrn, XvMCSurfacePtr pSurf, + int *num_priv, long **priv ); +void I810XvMCDestroySurface (ScrnInfoPtr pScrn, XvMCSurfacePtr pSurf); + +int I810XvMCCreateSubpicture (ScrnInfoPtr pScrn, XvMCSubpicturePtr pSurf, + int *num_priv, long **priv ); +void I810XvMCDestroySubpicture (ScrnInfoPtr pScrn, XvMCSubpicturePtr pSurf); + + +typedef struct { + drmContext drmcontext; + unsigned int fbBase; + unsigned int OverlayOffset; + unsigned int OverlaySize; + unsigned int SurfacesOffset; + unsigned int SurfacesSize; + char busIdString[10]; + char pad[2]; +} I810XvMCCreateContextRec; + + +static int yv12_subpicture_index_list[2] = +{ + FOURCC_IA44, + FOURCC_AI44 +}; + +static XF86MCImageIDList yv12_subpicture_list = +{ + 2, + yv12_subpicture_index_list +}; + +static XF86MCSurfaceInfoRec i810_YV12_mpg2_surface = +{ + FOURCC_YV12, + XVMC_CHROMA_FORMAT_420, + 0, + 720, + 576, + 720, + 576, + XVMC_MPEG_2, + XVMC_OVERLAID_SURFACE | XVMC_SUBPICTURE_INDEPENDENT_SCALING | + XVMC_INTRA_UNSIGNED, + &yv12_subpicture_list +}; + +static XF86MCSurfaceInfoRec i810_YV12_mpg1_surface = +{ + FOURCC_YV12, + XVMC_CHROMA_FORMAT_420, + 0, + 720, + 576, + 720, + 576, + XVMC_MPEG_1, + XVMC_OVERLAID_SURFACE | XVMC_SUBPICTURE_INDEPENDENT_SCALING | + XVMC_INTRA_UNSIGNED, + &yv12_subpicture_list +}; + +static XF86MCSurfaceInfoPtr ppSI[2] = +{ + (XF86MCSurfaceInfoPtr)&i810_YV12_mpg2_surface, + (XF86MCSurfaceInfoPtr)&i810_YV12_mpg1_surface +}; + +/* List of subpicture types that we support */ +static XF86ImageRec ia44_subpicture = XVIMAGE_IA44; +static XF86ImageRec ai44_subpicture = XVIMAGE_AI44; + +static XF86ImagePtr i810_subpicture_list[2] = +{ + (XF86ImagePtr)&ia44_subpicture, + (XF86ImagePtr)&ai44_subpicture +}; + +/* Fill in the device dependent adaptor record. + * This is named "I810 Video Overlay" because this code falls under the + * XV extenstion, the name must match or it won't be used. + * + * Surface and Subpicture - see above + * Function pointers to functions below + */ +static XF86MCAdaptorRec pAdapt = +{ + "I810 Video Overlay", /* name */ + 2, /* num_surfaces */ + ppSI, /* surfaces */ + 2, /* num_subpictures */ + i810_subpicture_list, /* subpictures */ + (xf86XvMCCreateContextProcPtr)I810XvMCCreateContext, + (xf86XvMCDestroyContextProcPtr)I810XvMCDestroyContext, + (xf86XvMCCreateSurfaceProcPtr)I810XvMCCreateSurface, + (xf86XvMCDestroySurfaceProcPtr)I810XvMCDestroySurface, + (xf86XvMCCreateSubpictureProcPtr)I810XvMCCreateSubpicture, + (xf86XvMCDestroySubpictureProcPtr)I810XvMCDestroySubpicture +}; + +static XF86MCAdaptorPtr ppAdapt[1] = +{ + (XF86MCAdaptorPtr)&pAdapt +}; + +/************************************************************************** + * + * I810InitMC + * + * Initialize the hardware motion compenstation extention for this + * hardware. The initialization routines want the address of the pointers + * to the structures, not the address of the structures. This means we + * allocate (or create static?) the pointer memory and pass that + * address. This seems a little convoluted. + * + * We need to allocate memory for the device depended adaptor record. + * This is what holds the pointers to all our device functions. + * + * We need to map the overlay registers into the drm. + * + * We need to map the surfaces into the drm. + * + * Inputs: + * Screen pointer + * + * Outputs: + * None, this calls the device independent screen initialization + * function. + * + * Revisions: + * + **************************************************************************/ +void I810InitMC(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I810Ptr pI810 = I810PTR(pScrn); + int i; + + /* Clear the Surface Allocation */ + for(i=0; i<I810_MAX_SURFACES; i++) { + pI810->surfaceAllocation[i] = 0; + } + + /* Cursor is at a page boundary, Overlay regs are not, don't forget */ + if (drmAddMap(pI810->drmSubFD, (drmHandle)pI810->CursorStart, + 4096, DRM_AGP, 0, &pI810->overlay_map) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, "drmAddMap(overlay) failed\n"); + return; + } + if (drmAddMap(pI810->drmSubFD, (drmHandle)pI810->MC.Start, + pI810->MC.Size, DRM_AGP, 0, &pI810->mc_map) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, "drmAddMap(MC) failed\n"); + return; + } + xf86XvMCScreenInit(pScreen, 1, ppAdapt); +} + +/************************************************************************** + * + * I810XvMCCreateContext + * + * Some info about the private data: + * + * Set *num_priv to the number of 32bit words that make up the size of + * of the data that priv will point to. + * + * *priv = (long *) xcalloc (elements, sizeof(element)) + * *num_priv = (elements * sizeof(element)) >> 2; + * + **************************************************************************/ + +int I810XvMCCreateContext (ScrnInfoPtr pScrn, XvMCContextPtr pContext, + int *num_priv, long **priv ) +{ + I810Ptr pI810 = I810PTR(pScrn); + DRIInfoPtr pDRIInfo = pI810->pDRIInfo; + I810XvMCCreateContextRec *contextRec; + + + if(!pI810->directRenderingEnabled) { + xf86DrvMsg(X_ERROR, pScrn->scrnIndex, + "I810XvMCCreateContext: Cannot use XvMC without DRI!\n"); + return BadAlloc; + } + + /* Context Already in use! */ + if(pI810->xvmcContext) { + xf86DrvMsg(X_WARNING, pScrn->scrnIndex, + "I810XvMCCreateContext: 2 XvMC Contexts Attempted, not supported.\n"); + return BadAlloc; + } + + *priv = xcalloc(1,sizeof(I810XvMCCreateContextRec)); + contextRec = (I810XvMCCreateContextRec *)*priv; + + if(!*priv) { + *num_priv = 0; + return BadAlloc; + } + + *num_priv = sizeof(I810XvMCCreateContextRec) >> 2; + if(drmCreateContext(pI810->drmSubFD, &(contextRec->drmcontext) ) < 0) { + xf86DrvMsg(X_ERROR, pScrn->scrnIndex, + "I810XvMCCreateContext: Unable to create DRMContext!\n"); + xfree(*priv); + return BadAlloc; + } + + drmAuthMagic(pI810->drmSubFD, pContext->flags); + + pI810->xvmcContext = contextRec->drmcontext; + contextRec->fbBase = pScrn->memPhysBase; + + /* Overlay Regs are at 1024 offset into the Cursor Space */ + contextRec->OverlayOffset = pI810->CursorStart; + contextRec->OverlaySize = 4096; + + contextRec->SurfacesOffset = pI810->MC.Start; + contextRec->SurfacesSize = pI810->MC.Size; + strncpy (contextRec->busIdString, pDRIInfo->busIdString, 9); + + return Success; +} + + +int I810XvMCCreateSurface (ScrnInfoPtr pScrn, XvMCSurfacePtr pSurf, + int *num_priv, long **priv ) +{ + I810Ptr pI810 = I810PTR(pScrn); + int i; + + *priv = (long *)xcalloc(2,sizeof(long)); + + if(!*priv) { + xf86DrvMsg(X_ERROR, pScrn->scrnIndex, + "I810XvMCCreateSurface: Unable to allocate memory!\n"); + *num_priv = 0; + return BadAlloc; + } + *num_priv = 2; + + /* Surface Arrangement is different based on 6 or 7 Surfaces */ + if(pI810->numSurfaces == 6) { + for(i=0; i<pI810->numSurfaces; i++) { + if(!pI810->surfaceAllocation[i]) { + pI810->surfaceAllocation[i] = pSurf->surface_id; + /* Y data starts at 2MB offset, each surface is 576k */ + (*priv)[0] = (2*1024*1024 + 576*1024 * i); + /* UV data starts at 0 offset, each set is 288k */ + (*priv)[1] = (576*512 * i); + return Success; + } + } + } + if(pI810->numSurfaces == 7) { + for(i=0; i<pI810->numSurfaces; i++) { + if(!pI810->surfaceAllocation[i]) { + pI810->surfaceAllocation[i] = pSurf->surface_id; + /* Y data starts at 2.5MB offset, each surface is 576k */ + (*priv)[0] = (2*1024*1024 + 512*1024 + 576*1024 * i); + /* UV data starts at 0 offset, each set is 288k */ + (*priv)[1] = (576*512 * i); + return Success; + } + } + } + (*priv)[0] = 0; + (*priv)[1] = 0; + return BadAlloc; +} + +int I810XvMCCreateSubpicture (ScrnInfoPtr pScrn, XvMCSubpicturePtr pSubp, + int *num_priv, long **priv ) +{ + I810Ptr pI810 = I810PTR(pScrn); + int i; + + *priv = (long *)xcalloc(1,sizeof(long)); + + if(!*priv) { + xf86DrvMsg(X_ERROR, pScrn->scrnIndex, + "I810XvMCCreateSubpicture: Unable to allocate memory!\n"); + *num_priv = 0; + return BadAlloc; + } + *num_priv = 1; + + if(pI810->numSurfaces == 6) { + for(i=6; i<8; i++) { + if(!pI810->surfaceAllocation[i]) { + pI810->surfaceAllocation[i] = pSubp->subpicture_id; + /* Subpictures are after the Y surfaces in memory */ + (*priv)[0] = (2*1024*1024 + 576*1024 * i); + return Success; + } + } + } + if(pI810->numSurfaces == 7) { + for(i=7; i<9; i++) { + if(!pI810->surfaceAllocation[i]) { + pI810->surfaceAllocation[i] = pSubp->subpicture_id; + /* Subpictures are after the Y surfaces in memory */ + (*priv)[0] = (2*1024*1024 + 512*1024 + 576*1024 * i); + return Success; + } + } + } + + (*priv)[0] = 0; + return BadAlloc; +} + +void I810XvMCDestroyContext (ScrnInfoPtr pScrn, XvMCContextPtr pContext) +{ + I810Ptr pI810 = I810PTR(pScrn); + + drmDestroyContext(pI810->drmSubFD,pI810->xvmcContext); + pI810->xvmcContext = 0; +} + +void I810XvMCDestroySurface (ScrnInfoPtr pScrn, XvMCSurfacePtr pSurf) +{ + I810Ptr pI810 = I810PTR(pScrn); + int i; + + for(i=0; i<I810_MAX_SURFACES; i++) { + if(pI810->surfaceAllocation[i] == pSurf->surface_id) { + pI810->surfaceAllocation[i] = 0; + return; + } + } + return; +} + +void I810XvMCDestroySubpicture (ScrnInfoPtr pScrn, XvMCSubpicturePtr pSubp) +{ + I810Ptr pI810 = I810PTR(pScrn); + int i; + + for(i=pI810->numSurfaces; i<I810_MAX_SURFACES + I810_MAX_SUBPICTURES; i++) { + if(pI810->surfaceAllocation[i] == pSubp->subpicture_id) { + pI810->surfaceAllocation[i] = 0; + return; + } + } + return; +} + + + + + + diff --git a/src/i810_io.c b/src/i810_io.c new file mode 100644 index 00000000..de947dde --- /dev/null +++ b/src/i810_io.c @@ -0,0 +1,144 @@ +/************************************************************************** + +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sub license, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice (including the +next paragraph) shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i810/i810_io.c,v 1.5 2002/09/11 00:29:32 dawes Exp $ */ + +/* + * Reformatted with GNU indent (2.2.8), using the following options: + * + * -bad -bap -c41 -cd0 -ncdb -ci6 -cli0 -cp0 -ncs -d0 -di3 -i3 -ip3 -l78 + * -lp -npcs -psl -sob -ss -br -ce -sc -hnl + * + * This provides a good match with the original i810 code and preferred + * XFree86 formatting conventions. + * + * When editing this driver, please follow the existing formatting, and edit + * with <TAB> characters expanded at 8-column intervals. + */ + +/* + * Authors: + * Daryll Strauss <daryll@precisioninsight.com> + * + */ + +#include "xf86.h" +#include "xf86_ansic.h" +#include "xf86_OSproc.h" +#include "compiler.h" + +#ifdef BUILD_FOR_I830 +#include "i830.h" +#define pI810 pI830 +#define I810Ptr I830Ptr +#define I810WriteControlPIO I830WriteControlPIO +#define I810ReadControlPIO I830ReadControlPIO +#define I810WriteStandardPIO I830WriteStandardPIO +#define I810ReadStandardPIO I830ReadStandardPIO +#define I810SetPIOAccess I830SetPIOAccess +#define I810WriteControlMMIO I830WriteControlMMIO +#define I810ReadControlMMIO I830ReadControlMMIO +#define I810WriteStandardMMIO I830WriteStandardMMIO +#define I810ReadStandardMMIO I830ReadStandardMMIO +#define I810SetMMIOAccess I830SetMMIOAccess +#else +#include "i810.h" +#endif + +#define minb(p) *(volatile CARD8 *)(pI810->MMIOBase + (p)) +#define moutb(p,v) *(volatile CARD8 *)(pI810->MMIOBase + (p)) = (v) + +static void +I810WriteControlPIO(I810Ptr pI810, IOADDRESS addr, CARD8 index, CARD8 val) +{ + addr += pI810->ioBase; + outb(addr, index); + outb(addr + 1, val); +} + +static CARD8 +I810ReadControlPIO(I810Ptr pI810, IOADDRESS addr, CARD8 index) +{ + addr += pI810->ioBase; + outb(addr, index); + return inb(addr + 1); +} + +static void +I810WriteStandardPIO(I810Ptr pI810, IOADDRESS addr, CARD8 val) +{ + outb(pI810->ioBase + addr, val); +} + +static CARD8 +I810ReadStandardPIO(I810Ptr pI810, IOADDRESS addr) +{ + return inb(pI810->ioBase + addr); +} + +void +I810SetPIOAccess(I810Ptr pI810) +{ + pI810->writeControl = I810WriteControlPIO; + pI810->readControl = I810ReadControlPIO; + pI810->writeStandard = I810WriteStandardPIO; + pI810->readStandard = I810ReadStandardPIO; +} + +static void +I810WriteControlMMIO(I810Ptr pI810, IOADDRESS addr, CARD8 index, CARD8 val) +{ + moutb(addr, index); + moutb(addr + 1, val); +} + +static CARD8 +I810ReadControlMMIO(I810Ptr pI810, IOADDRESS addr, CARD8 index) +{ + moutb(addr, index); + return minb(addr + 1); +} + +static void +I810WriteStandardMMIO(I810Ptr pI810, IOADDRESS addr, CARD8 val) +{ + moutb(addr, val); +} + +static CARD8 +I810ReadStandardMMIO(I810Ptr pI810, IOADDRESS addr) +{ + return minb(addr); +} + +void +I810SetMMIOAccess(I810Ptr pI810) +{ + pI810->writeControl = I810WriteControlMMIO; + pI810->readControl = I810ReadControlMMIO; + pI810->writeStandard = I810WriteStandardMMIO; + pI810->readStandard = I810ReadStandardMMIO; +} diff --git a/src/i810_memory.c b/src/i810_memory.c new file mode 100644 index 00000000..5efa23a9 --- /dev/null +++ b/src/i810_memory.c @@ -0,0 +1,399 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i810/i810_memory.c,v 1.27 2002/12/10 01:27:05 dawes Exp $ */ +/************************************************************************** + +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sub license, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice (including the +next paragraph) shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ + +/* + * Reformatted with GNU indent (2.2.8), using the following options: + * + * -bad -bap -c41 -cd0 -ncdb -ci6 -cli0 -cp0 -ncs -d0 -di3 -i3 -ip3 -l78 + * -lp -npcs -psl -sob -ss -br -ce -sc -hnl + * + * This provides a good match with the original i810 code and preferred + * XFree86 formatting conventions. + * + * When editing this driver, please follow the existing formatting, and edit + * with <TAB> characters expanded at 8-column intervals. + */ + +/* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + * + */ + +#include "xf86.h" +#include "xf86_ansic.h" +#include "xf86_OSproc.h" + +#include "i810.h" +#include "i810_reg.h" + +int +I810AllocLow(I810MemRange * result, I810MemRange * pool, int size) +{ + if (size > pool->Size) + return 0; + + pool->Size -= size; + result->Size = size; + result->Start = pool->Start; + result->End = pool->Start += size; + + return 1; +} + +int +I810AllocHigh(I810MemRange * result, I810MemRange * pool, int size) +{ + if (size > pool->Size) + return 0; + + pool->Size -= size; + result->Size = size; + result->End = pool->End; + result->Start = pool->End -= size; + + return 1; +} + +int +I810AllocateGARTMemory(ScrnInfoPtr pScrn) +{ + unsigned long size = pScrn->videoRam * 1024; + I810Ptr pI810 = I810PTR(pScrn); + int key; + long tom = 0; + unsigned long physical; + + if (!xf86AgpGARTSupported() || !xf86AcquireGART(pScrn->scrnIndex)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "AGP GART support is either not available or cannot be used.\n" + "\tMake sure your kernel has agpgart support or has the\n" + "\tagpgart module loaded.\n"); + return FALSE; + } + + /* This allows the 2d only Xserver to regen */ + pI810->agpAcquired2d = TRUE; + + /* + * I810/I815 + * + * Treat the gart like video memory - we assume we own all that is + * there, so ignore EBUSY errors. Don't try to remove it on + * failure, either, as other X server may be using it. + */ + + if ((key = xf86AllocateGARTMemory(pScrn->scrnIndex, size, 0, NULL)) == -1) + return FALSE; + + pI810->VramOffset = 0; + pI810->VramKey = key; + + if (!xf86BindGARTMemory(pScrn->scrnIndex, key, 0)) + return FALSE; + + pI810->SysMem.Start = 0; + pI810->SysMem.Size = size; + pI810->SysMem.End = size; + pI810->SavedSysMem = pI810->SysMem; + + tom = pI810->SysMem.End; + + pI810->DcacheMem.Start = 0; + pI810->DcacheMem.End = 0; + pI810->DcacheMem.Size = 0; + pI810->CursorPhysical = 0; + + /* + * Dcache - half the speed of normal ram, so not really useful for + * a 2d server. Don't bother reporting its presence. This is + * mapped in addition to the requested amount of system ram. + */ + + size = 1024 * 4096; + + /* + * Keep it 512K aligned for the sake of tiled regions. + */ + + tom += 0x7ffff; + tom &= ~0x7ffff; + + if ((key = xf86AllocateGARTMemory(pScrn->scrnIndex, size, 1, NULL)) != -1) { + pI810->DcacheOffset = tom; + pI810->DcacheKey = key; + if (!xf86BindGARTMemory(pScrn->scrnIndex, key, tom)) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Allocation of %d bytes for DCACHE failed\n", size); + pI810->DcacheKey = -1; + } else { + pI810->DcacheMem.Start = tom; + pI810->DcacheMem.Size = size; + pI810->DcacheMem.End = pI810->DcacheMem.Start + pI810->DcacheMem.Size; + tom = pI810->DcacheMem.End; + } + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "No physical memory available for %d bytes of DCACHE\n", + size); + pI810->DcacheKey = -1; + } + + /* + * Mouse cursor -- The i810 (crazy) needs a physical address in + * system memory from which to upload the cursor. We get this from + * the agpgart module using a special memory type. + */ + + /* + * 4k for the cursor is excessive, I'm going to steal 3k for + * overlay registers later + */ + + size = 4096; + + if ((key = + xf86AllocateGARTMemory(pScrn->scrnIndex, size, 2, &physical)) == -1) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "No physical memory available for HW cursor\n"); + pI810->HwcursKey = -1; + pI810->CursorStart = 0; + } else { + pI810->HwcursOffset = tom; + pI810->HwcursKey = key; + if (!xf86BindGARTMemory(pScrn->scrnIndex, key, tom)) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Allocation of %d bytes for HW cursor failed\n", size); + pI810->HwcursKey = -1; + } else { + pI810->CursorPhysical = physical; + pI810->CursorStart = tom; + tom += size; + } + } + + /* + * Overlay register buffer -- Just like the cursor, the i810 needs a + * physical address in system memory from which to upload the overlay + * registers. + */ + + if (pI810->CursorStart != 0) { + pI810->OverlayPhysical = pI810->CursorPhysical + 1024; + pI810->OverlayStart = pI810->CursorStart + 1024; + } + + pI810->GttBound = 1; + + return TRUE; +} + +/* Tiled memory is good... really, really good... + * + * Need to make it less likely that we miss out on this - probably + * need to move the frontbuffer away from the 'guarenteed' alignment + * of the first memory segment, or perhaps allocate a discontigous + * framebuffer to get more alignment 'sweet spots'. + */ +void +I810SetTiledMemory(ScrnInfoPtr pScrn, int nr, unsigned int start, + unsigned int pitch, unsigned int size) +{ + I810Ptr pI810 = I810PTR(pScrn); + I810RegPtr i810Reg = &pI810->ModeReg; + CARD32 val; + CARD32 fence_mask = 0; + + if (nr < 0 || nr > 7) { + xf86DrvMsg(X_WARNING, pScrn->scrnIndex, "%s - fence %d out of range\n", + "I810SetTiledMemory", nr); + return; + } + + i810Reg->Fence[nr] = 0; + + fence_mask = ~FENCE_START_MASK; + + if (start & fence_mask) { + xf86DrvMsg(X_WARNING, pScrn->scrnIndex, + "%s %d: start (%x) is not 512k aligned\n", + "I810SetTiledMemory", nr, start); + return; + } + + if (start % size) { + xf86DrvMsg(X_WARNING, pScrn->scrnIndex, + "%s %d: start (%x) is not size (%x) aligned\n", + "I810SetTiledMemory", nr, start, size); + return; + } + + if (pitch & 127) { + xf86DrvMsg(X_WARNING, pScrn->scrnIndex, + "%s %d: pitch (%x) not a multiple of 128 bytes\n", + "I810SetTiledMemory", nr, pitch); + return; + } + + val = (start | FENCE_X_MAJOR | FENCE_VALID); + + switch (size) { + case KB(512): + val |= FENCE_SIZE_512K; + break; + case MB(1): + val |= FENCE_SIZE_1M; + break; + case MB(2): + val |= FENCE_SIZE_2M; + break; + case MB(4): + val |= FENCE_SIZE_4M; + break; + case MB(8): + val |= FENCE_SIZE_8M; + break; + case MB(16): + val |= FENCE_SIZE_16M; + break; + case MB(32): + val |= FENCE_SIZE_32M; + break; + default: + xf86DrvMsg(X_WARNING, pScrn->scrnIndex, + "%s %d: illegal size (0x%x)\n", "I810SetTiledMemory", nr, + size); + return; + } + + switch (pitch / 128) { + case 1: + val |= FENCE_PITCH_1; + break; + case 2: + val |= FENCE_PITCH_2; + break; + case 4: + val |= FENCE_PITCH_4; + break; + case 8: + val |= FENCE_PITCH_8; + break; + case 16: + val |= FENCE_PITCH_16; + break; + case 32: + val |= FENCE_PITCH_32; + break; + default: + xf86DrvMsg(X_WARNING, pScrn->scrnIndex, + "%s %d: illegal size (0x%x)\n", "I810SetTiledMemory", nr, + size); + return; + } + + i810Reg->Fence[nr] = val; +} + +Bool +I810BindGARTMemory(ScrnInfoPtr pScrn) +{ + I810Ptr pI810 = I810PTR(pScrn); + + if (xf86AgpGARTSupported() && !pI810->directRenderingEnabled + && !pI810->GttBound) { + if (!xf86AcquireGART(pScrn->scrnIndex)) + return FALSE; + + if (pI810->VramKey != -1 + && !xf86BindGARTMemory(pScrn->scrnIndex, pI810->VramKey, + pI810->VramOffset)) + return FALSE; + + if (pI810->DcacheKey != -1 + && !xf86BindGARTMemory(pScrn->scrnIndex, pI810->DcacheKey, + pI810->DcacheOffset)) + return FALSE; + + if (pI810->HwcursKey != -1 + && !xf86BindGARTMemory(pScrn->scrnIndex, pI810->HwcursKey, + pI810->HwcursOffset)) + return FALSE; + + pI810->GttBound = 1; + } + + return TRUE; +} + +Bool +I810UnbindGARTMemory(ScrnInfoPtr pScrn) +{ + I810Ptr pI810 = I810PTR(pScrn); + + if (xf86AgpGARTSupported() && !pI810->directRenderingEnabled + && pI810->GttBound) { + if (pI810->VramKey != -1 + && !xf86UnbindGARTMemory(pScrn->scrnIndex, pI810->VramKey)) + return FALSE; + + if (pI810->DcacheKey != -1 + && !xf86UnbindGARTMemory(pScrn->scrnIndex, pI810->DcacheKey)) + return FALSE; + + if (pI810->HwcursKey != -1 + && !xf86UnbindGARTMemory(pScrn->scrnIndex, pI810->HwcursKey)) + return FALSE; + + if (!xf86ReleaseGART(pScrn->scrnIndex)) + return FALSE; + + pI810->GttBound = 0; + } + + return TRUE; +} + +int +I810CheckAvailableMemory(ScrnInfoPtr pScrn) +{ + AgpInfoPtr agpinf; + int maxPages; + + if (!xf86AgpGARTSupported() || + !xf86AcquireGART(pScrn->scrnIndex) || + (agpinf = xf86GetAGPInfo(pScrn->scrnIndex)) == NULL || + !xf86ReleaseGART(pScrn->scrnIndex)) + return -1; + + maxPages = agpinf->totalPages - agpinf->usedPages; + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 2, "%s: %dk available\n", + "I810CheckAvailableMemory", maxPages * 4); + + return maxPages * 4; +} diff --git a/src/i810_reg.h b/src/i810_reg.h new file mode 100644 index 00000000..c935982a --- /dev/null +++ b/src/i810_reg.h @@ -0,0 +1,992 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i810/i810_reg.h,v 1.13 2003/02/06 04:18:04 dawes Exp $ */ +/************************************************************************** + +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sub license, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice (including the +next paragraph) shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ + +/* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + * + * based on the i740 driver by + * Kevin E. Martin <kevin@precisioninsight.com> + * + * + */ + +#ifndef _I810_REG_H +#define _I810_REG_H + +/* I/O register offsets + */ +#define SRX 0x3C4 /* p208 */ +#define GRX 0x3CE /* p213 */ +#define ARX 0x3C0 /* p224 */ + +/* VGA Color Palette Registers */ +#define DACMASK 0x3C6 /* p232 */ +#define DACSTATE 0x3C7 /* p232 */ +#define DACRX 0x3C7 /* p233 */ +#define DACWX 0x3C8 /* p233 */ +#define DACDATA 0x3C9 /* p233 */ + +/* CRT Controller Registers (CRX) */ +#define START_ADDR_HI 0x0C /* p246 */ +#define START_ADDR_LO 0x0D /* p247 */ +#define VERT_SYNC_END 0x11 /* p249 */ +#define EXT_VERT_TOTAL 0x30 /* p257 */ +#define EXT_VERT_DISPLAY 0x31 /* p258 */ +#define EXT_VERT_SYNC_START 0x32 /* p259 */ +#define EXT_VERT_BLANK_START 0x33 /* p260 */ +#define EXT_HORIZ_TOTAL 0x35 /* p261 */ +#define EXT_HORIZ_BLANK 0x39 /* p261 */ +#define EXT_START_ADDR 0x40 /* p262 */ +#define EXT_START_ADDR_ENABLE 0x80 +#define EXT_OFFSET 0x41 /* p263 */ +#define EXT_START_ADDR_HI 0x42 /* p263 */ +#define INTERLACE_CNTL 0x70 /* p264 */ +#define INTERLACE_ENABLE 0x80 +#define INTERLACE_DISABLE 0x00 + +/* Miscellaneous Output Register + */ +#define MSR_R 0x3CC /* p207 */ +#define MSR_W 0x3C2 /* p207 */ +#define IO_ADDR_SELECT 0x01 + +#define MDA_BASE 0x3B0 /* p207 */ +#define CGA_BASE 0x3D0 /* p207 */ + +/* CR80 - IO Control, p264 + */ +#define IO_CTNL 0x80 +#define EXTENDED_ATTR_CNTL 0x02 +#define EXTENDED_CRTC_CNTL 0x01 + +/* GR10 - Address mapping, p221 + */ +#define ADDRESS_MAPPING 0x10 +#define PAGE_TO_LOCAL_MEM_ENABLE 0x10 +#define GTT_MEM_MAP_ENABLE 0x08 +#define PACKED_MODE_ENABLE 0x04 +#define LINEAR_MODE_ENABLE 0x02 +#define PAGE_MAPPING_ENABLE 0x01 + +/* Blitter control, p378 + */ +#define BITBLT_CNTL 0x7000c +#define COLEXP_MODE 0x30 +#define COLEXP_8BPP 0x00 +#define COLEXP_16BPP 0x10 +#define COLEXP_24BPP 0x20 +#define COLEXP_RESERVED 0x30 +#define BITBLT_STATUS 0x01 + +/* p375. + */ +#define DISPLAY_CNTL 0x70008 +#define VGA_WRAP_MODE 0x02 +#define VGA_WRAP_AT_256KB 0x00 +#define VGA_NO_WRAP 0x02 +#define GUI_MODE 0x01 +#define STANDARD_VGA_MODE 0x00 +#define HIRES_MODE 0x01 + +/* p375 + */ +#define PIXPIPE_CONFIG_0 0x70009 +#define DAC_8_BIT 0x80 +#define DAC_6_BIT 0x00 +#define HW_CURSOR_ENABLE 0x10 +#define EXTENDED_PALETTE 0x01 + +/* p375 + */ +#define PIXPIPE_CONFIG_1 0x7000a +#define DISPLAY_COLOR_MODE 0x0F +#define DISPLAY_VGA_MODE 0x00 +#define DISPLAY_8BPP_MODE 0x02 +#define DISPLAY_15BPP_MODE 0x04 +#define DISPLAY_16BPP_MODE 0x05 +#define DISPLAY_24BPP_MODE 0x06 +#define DISPLAY_32BPP_MODE 0x07 + +/* p375 + */ +#define PIXPIPE_CONFIG_2 0x7000b +#define DISPLAY_GAMMA_ENABLE 0x08 +#define DISPLAY_GAMMA_DISABLE 0x00 +#define OVERLAY_GAMMA_ENABLE 0x04 +#define OVERLAY_GAMMA_DISABLE 0x00 + + +/* p380 + */ +#define DISPLAY_BASE 0x70020 +#define DISPLAY_BASE_MASK 0x03fffffc + + +/* Cursor control registers, pp383-384 + */ +/* Desktop (845G, 865G) */ +#define CURSOR_CONTROL 0x70080 +#define CURSOR_ENABLE 0x80000000 +#define CURSOR_GAMMA_ENABLE 0x40000000 +#define CURSOR_STRIDE_MASK 0x30000000 +#define CURSOR_FORMAT_SHIFT 24 +#define CURSOR_FORMAT_MASK (0x07 << CURSOR_FORMAT_SHIFT) +#define CURSOR_FORMAT_2C (0x00 << CURSOR_FORMAT_SHIFT) +#define CURSOR_FORMAT_3C (0x01 << CURSOR_FORMAT_SHIFT) +#define CURSOR_FORMAT_4C (0x02 << CURSOR_FORMAT_SHIFT) +#define CURSOR_FORMAT_ARGB (0x04 << CURSOR_FORMAT_SHIFT) +#define CURSOR_FORMAT_XRGB (0x05 << CURSOR_FORMAT_SHIFT) + +/* Mobile and i810 */ +#define CURSOR_A_CONTROL CURSOR_CONTROL +#define CURSOR_ORIGIN_SCREEN 0x00 /* i810 only */ +#define CURSOR_ORIGIN_DISPLAY 0x1 /* i810 only */ +#define CURSOR_MODE 0x27 +#define CURSOR_MODE_DISABLE 0x00 +#define CURSOR_MODE_32_4C_AX 0x01 /* i810 only */ +#define CURSOR_MODE_64_3C 0x04 +#define CURSOR_MODE_64_4C_AX 0x05 +#define CURSOR_MODE_64_4C 0x06 +#define CURSOR_MODE_64_32B_AX 0x07 +#define CURSOR_MODE_64_ARGB_AX (0x20 | CURSOR_MODE_64_32B_AX) +#define MCURSOR_PIPE_SELECT (1 << 28) +#define MCURSOR_PIPE_A 0x00 +#define MCURSOR_PIPE_B (1 << 28) +#define MCURSOR_GAMMA_ENABLE (1 << 26) +#define MCURSOR_MEM_TYPE_LOCAL (1 << 25) + + +#define CURSOR_BASEADDR 0x70084 +#define CURSOR_A_BASE CURSOR_BASEADDR +#define CURSOR_BASEADDR_MASK 0x1FFFFF00 +#define CURSOR_A_POSITION 0x70088 +#define CURSOR_POS_SIGN 0x8000 +#define CURSOR_POS_MASK 0x007FF +#define CURSOR_X_SHIFT 0 +#define CURSOR_Y_SHIFT 16 +#define CURSOR_X_LO 0x70088 +#define CURSOR_X_HI 0x70089 +#define CURSOR_X_POS 0x00 +#define CURSOR_X_NEG 0x80 +#define CURSOR_Y_LO 0x7008A +#define CURSOR_Y_HI 0x7008B +#define CURSOR_Y_POS 0x00 +#define CURSOR_Y_NEG 0x80 + +#define CURSOR_A_PALETTE0 0x70090 +#define CURSOR_A_PALETTE1 0x70094 +#define CURSOR_A_PALETTE2 0x70098 +#define CURSOR_A_PALETTE3 0x7009C + +#define CURSOR_SIZE 0x700A0 +#define CURSOR_SIZE_MASK 0x3FF +#define CURSOR_SIZE_HSHIFT 0 +#define CURSOR_SIZE_VSHIFT 12 + + +/* Similar registers exist in Device 0 on the i810 (pp55-65), but I'm + * not sure they refer to local (graphics) memory. + * + * These details are for the local memory control registers, + * (pp301-310). The test machines are not equiped with local memory, + * so nothing is tested. Only a single row seems to be supported. + */ +#define DRAM_ROW_TYPE 0x3000 +#define DRAM_ROW_0 0x01 +#define DRAM_ROW_0_SDRAM 0x01 +#define DRAM_ROW_0_EMPTY 0x00 +#define DRAM_ROW_CNTL_LO 0x3001 +#define DRAM_PAGE_MODE_CTRL 0x10 +#define DRAM_RAS_TO_CAS_OVRIDE 0x08 +#define DRAM_CAS_LATENCY 0x04 +#define DRAM_RAS_TIMING 0x02 +#define DRAM_RAS_PRECHARGE 0x01 +#define DRAM_ROW_CNTL_HI 0x3002 +#define DRAM_REFRESH_RATE 0x18 +#define DRAM_REFRESH_DISABLE 0x00 +#define DRAM_REFRESH_60HZ 0x08 +#define DRAM_REFRESH_FAST_TEST 0x10 +#define DRAM_REFRESH_RESERVED 0x18 +#define DRAM_SMS 0x07 +#define DRAM_SMS_NORMAL 0x00 +#define DRAM_SMS_NOP_ENABLE 0x01 +#define DRAM_SMS_ABPCE 0x02 +#define DRAM_SMS_MRCE 0x03 +#define DRAM_SMS_CBRCE 0x04 + +/* p307 + */ +#define DPMS_SYNC_SELECT 0x5002 +#define VSYNC_CNTL 0x08 +#define VSYNC_ON 0x00 +#define VSYNC_OFF 0x08 +#define HSYNC_CNTL 0x02 +#define HSYNC_ON 0x00 +#define HSYNC_OFF 0x02 + + + +/* p317, 319 + */ +#define VCLK2_VCO_M 0x6008 /* treat as 16 bit? (includes msbs) */ +#define VCLK2_VCO_N 0x600a +#define VCLK2_VCO_DIV_SEL 0x6012 + +#define VCLK_DIVISOR_VGA0 0x6000 +#define VCLK_DIVISOR_VGA1 0x6004 +#define VCLK_POST_DIV 0x6010 + +#define POST_DIV_SELECT 0x70 +#define POST_DIV_1 0x00 +#define POST_DIV_2 0x10 +#define POST_DIV_4 0x20 +#define POST_DIV_8 0x30 +#define POST_DIV_16 0x40 +#define POST_DIV_32 0x50 +#define VCO_LOOP_DIV_BY_4M 0x00 +#define VCO_LOOP_DIV_BY_16M 0x04 + + +/* Instruction Parser Mode Register + * - p281 + * - 2 new bits. + */ +#define INST_PM 0x20c0 +#define AGP_SYNC_PACKET_FLUSH_ENABLE 0x20 /* reserved */ +#define SYNC_PACKET_FLUSH_ENABLE 0x10 +#define TWO_D_INST_DISABLE 0x08 +#define THREE_D_INST_DISABLE 0x04 +#define STATE_VAR_UPDATE_DISABLE 0x02 +#define PAL_STIP_DISABLE 0x01 + +#define INST_DONE 0x2090 +#define INST_PS 0x20c4 + +#define MEMMODE 0x20dc + + +/* Instruction parser error register. p279 + */ +#define IPEIR 0x2088 +#define IPEHR 0x208C + + +/* General error reporting regs, p296 + */ +#define EIR 0x20B0 +#define EMR 0x20B4 +#define ESR 0x20B8 +#define IP_ERR 0x0001 +#define ERROR_RESERVED 0xffc6 + + +/* Interrupt Control Registers + * - new bits for i810 + * - new register hwstam (mask) + */ +#define HWSTAM 0x2098 /* p290 */ +#define IER 0x20a0 /* p291 */ +#define IIR 0x20a4 /* p292 */ +#define IMR 0x20a8 /* p293 */ +#define ISR 0x20ac /* p294 */ +#define HW_ERROR 0x8000 +#define SYNC_STATUS_TOGGLE 0x1000 +#define DPY_0_FLIP_PENDING 0x0800 +#define DPY_1_FLIP_PENDING 0x0400 /* not implemented on i810 */ +#define OVL_0_FLIP_PENDING 0x0200 +#define OVL_1_FLIP_PENDING 0x0100 /* not implemented on i810 */ +#define DPY_0_VBLANK 0x0080 +#define DPY_0_EVENT 0x0040 +#define DPY_1_VBLANK 0x0020 /* not implemented on i810 */ +#define DPY_1_EVENT 0x0010 /* not implemented on i810 */ +#define HOST_PORT_EVENT 0x0008 /* */ +#define CAPTURE_EVENT 0x0004 /* */ +#define USER_DEFINED 0x0002 +#define BREAKPOINT 0x0001 + + +#define INTR_RESERVED (0x6000 | \ + DPY_1_FLIP_PENDING | \ + OVL_1_FLIP_PENDING | \ + DPY_1_VBLANK | \ + DPY_1_EVENT | \ + HOST_PORT_EVENT | \ + CAPTURE_EVENT ) + +/* FIFO Watermark and Burst Length Control Register + * + * - different offset and contents on i810 (p299) (fewer bits per field) + * - some overlay fields added + * - what does it all mean? + */ +#define FWATER_BLC 0x20d8 +#define FWATER_BLC2 0x20dc +#define MM_BURST_LENGTH 0x00700000 +#define MM_FIFO_WATERMARK 0x0001F000 +#define LM_BURST_LENGTH 0x00000700 +#define LM_FIFO_WATERMARK 0x0000001F + + +/* Fence/Tiling ranges [0..7] + */ +#define FENCE 0x2000 +#define FENCE_NR 8 + +#define I830_FENCE_START_MASK 0x07f80000 + +#define FENCE_START_MASK 0x03F80000 +#define FENCE_X_MAJOR 0x00000000 +#define FENCE_Y_MAJOR 0x00001000 +#define FENCE_SIZE_MASK 0x00000700 +#define FENCE_SIZE_512K 0x00000000 +#define FENCE_SIZE_1M 0x00000100 +#define FENCE_SIZE_2M 0x00000200 +#define FENCE_SIZE_4M 0x00000300 +#define FENCE_SIZE_8M 0x00000400 +#define FENCE_SIZE_16M 0x00000500 +#define FENCE_SIZE_32M 0x00000600 +#define FENCE_SIZE_64M 0x00000700 +#define FENCE_PITCH_MASK 0x00000070 +#define FENCE_PITCH_1 0x00000000 +#define FENCE_PITCH_2 0x00000010 +#define FENCE_PITCH_4 0x00000020 +#define FENCE_PITCH_8 0x00000030 +#define FENCE_PITCH_16 0x00000040 +#define FENCE_PITCH_32 0x00000050 +#define FENCE_PITCH_64 0x00000060 +#define FENCE_VALID 0x00000001 + + +/* Registers to control page table, p274 + */ +#define PGETBL_CTL 0x2020 +#define PGETBL_ADDR_MASK 0xFFFFF000 +#define PGETBL_ENABLE_MASK 0x00000001 +#define PGETBL_ENABLED 0x00000001 + +/* Register containing pge table error results, p276 + */ +#define PGE_ERR 0x2024 +#define PGE_ERR_ADDR_MASK 0xFFFFF000 +#define PGE_ERR_ID_MASK 0x00000038 +#define PGE_ERR_CAPTURE 0x00000000 +#define PGE_ERR_OVERLAY 0x00000008 +#define PGE_ERR_DISPLAY 0x00000010 +#define PGE_ERR_HOST 0x00000018 +#define PGE_ERR_RENDER 0x00000020 +#define PGE_ERR_BLITTER 0x00000028 +#define PGE_ERR_MAPPING 0x00000030 +#define PGE_ERR_CMD_PARSER 0x00000038 +#define PGE_ERR_TYPE_MASK 0x00000007 +#define PGE_ERR_INV_TABLE 0x00000000 +#define PGE_ERR_INV_PTE 0x00000001 +#define PGE_ERR_MIXED_TYPES 0x00000002 +#define PGE_ERR_PAGE_MISS 0x00000003 +#define PGE_ERR_ILLEGAL_TRX 0x00000004 +#define PGE_ERR_LOCAL_MEM 0x00000005 +#define PGE_ERR_TILED 0x00000006 + + + +/* Page table entries loaded via mmio region, p323 + */ +#define PTE_BASE 0x10000 +#define PTE_ADDR_MASK 0x3FFFF000 +#define PTE_TYPE_MASK 0x00000006 +#define PTE_LOCAL 0x00000002 +#define PTE_MAIN_UNCACHED 0x00000000 +#define PTE_MAIN_CACHED 0x00000006 +#define PTE_VALID_MASK 0x00000001 +#define PTE_VALID 0x00000001 + + +/* Ring buffer registers, p277, overview p19 + */ +#define LP_RING 0x2030 +#define HP_RING 0x2040 + +#define RING_TAIL 0x00 +#define TAIL_ADDR 0x000FFFF8 +#define I830_TAIL_MASK 0x001FFFF8 + +#define RING_HEAD 0x04 +#define HEAD_WRAP_COUNT 0xFFE00000 +#define HEAD_WRAP_ONE 0x00200000 +#define HEAD_ADDR 0x001FFFFC +#define I830_HEAD_MASK 0x001FFFFC + +#define RING_START 0x08 +#define START_ADDR 0x00FFFFF8 +#define I830_RING_START_MASK 0xFFFFF000 + +#define RING_LEN 0x0C +#define RING_NR_PAGES 0x000FF000 +#define I830_RING_NR_PAGES 0x001FF000 +#define RING_REPORT_MASK 0x00000006 +#define RING_REPORT_64K 0x00000002 +#define RING_REPORT_128K 0x00000004 +#define RING_NO_REPORT 0x00000000 +#define RING_VALID_MASK 0x00000001 +#define RING_VALID 0x00000001 +#define RING_INVALID 0x00000000 + + + +/* BitBlt Instructions + * + * There are many more masks & ranges yet to add. + */ +#define BR00_BITBLT_CLIENT 0x40000000 +#define BR00_OP_COLOR_BLT 0x10000000 +#define BR00_OP_SRC_COPY_BLT 0x10C00000 +#define BR00_OP_FULL_BLT 0x11400000 +#define BR00_OP_MONO_SRC_BLT 0x11800000 +#define BR00_OP_MONO_SRC_COPY_BLT 0x11000000 +#define BR00_OP_MONO_PAT_BLT 0x11C00000 +#define BR00_OP_MONO_SRC_COPY_IMMEDIATE_BLT (0x61 << 22) +#define BR00_OP_TEXT_IMMEDIATE_BLT 0xc000000 + + +#define BR00_TPCY_DISABLE 0x00000000 +#define BR00_TPCY_ENABLE 0x00000010 + +#define BR00_TPCY_ROP 0x00000000 +#define BR00_TPCY_NO_ROP 0x00000020 +#define BR00_TPCY_EQ 0x00000000 +#define BR00_TPCY_NOT_EQ 0x00000040 + +#define BR00_PAT_MSB_FIRST 0x00000000 /* ? */ + +#define BR00_PAT_VERT_ALIGN 0x000000e0 + +#define BR00_LENGTH 0x0000000F + +#define BR09_DEST_ADDR 0x03FFFFFF + +#define BR11_SOURCE_PITCH 0x00003FFF + +#define BR12_SOURCE_ADDR 0x03FFFFFF + +#define BR13_SOLID_PATTERN 0x80000000 +#define BR13_RIGHT_TO_LEFT 0x40000000 +#define BR13_LEFT_TO_RIGHT 0x00000000 +#define BR13_MONO_TRANSPCY 0x20000000 +#define BR13_USE_DYN_DEPTH 0x04000000 +#define BR13_DYN_8BPP 0x00000000 +#define BR13_DYN_16BPP 0x01000000 +#define BR13_DYN_24BPP 0x02000000 +#define BR13_ROP_MASK 0x00FF0000 +#define BR13_DEST_PITCH 0x0000FFFF +#define BR13_PITCH_SIGN_BIT 0x00008000 + +#define BR14_DEST_HEIGHT 0xFFFF0000 +#define BR14_DEST_WIDTH 0x0000FFFF + +#define BR15_PATTERN_ADDR 0x03FFFFFF + +#define BR16_SOLID_PAT_COLOR 0x00FFFFFF +#define BR16_BACKGND_PAT_CLR 0x00FFFFFF + +#define BR17_FGND_PAT_CLR 0x00FFFFFF + +#define BR18_SRC_BGND_CLR 0x00FFFFFF +#define BR19_SRC_FGND_CLR 0x00FFFFFF + + +/* Instruction parser instructions + */ + +#define INST_PARSER_CLIENT 0x00000000 +#define INST_OP_FLUSH 0x02000000 +#define INST_FLUSH_MAP_CACHE 0x00000001 + + +#define GFX_OP_USER_INTERRUPT ((0<<29)|(2<<23)) + + +/* Registers in the i810 host-pci bridge pci config space which affect + * the i810 graphics operations. + */ +#define SMRAM_MISCC 0x70 +#define GMS 0x000000c0 +#define GMS_DISABLE 0x00000000 +#define GMS_ENABLE_BARE 0x00000040 +#define GMS_ENABLE_512K 0x00000080 +#define GMS_ENABLE_1M 0x000000c0 +#define USMM 0x00000030 +#define USMM_DISABLE 0x00000000 +#define USMM_TSEG_ZERO 0x00000010 +#define USMM_TSEG_512K 0x00000020 +#define USMM_TSEG_1M 0x00000030 +#define GFX_MEM_WIN_SIZE 0x00010000 +#define GFX_MEM_WIN_32M 0x00010000 +#define GFX_MEM_WIN_64M 0x00000000 + +/* Overkill? I don't know. Need to figure out top of mem to make the + * SMRAM calculations come out. Linux seems to have problems + * detecting it all on its own, so this seems a reasonable double + * check to any user supplied 'mem=...' boot param. + * + * ... unfortunately this reg doesn't work according to spec on the + * test hardware. + */ +#define WHTCFG_PAMR_DRP 0x50 +#define SYS_DRAM_ROW_0_SHIFT 16 +#define SYS_DRAM_ROW_1_SHIFT 20 +#define DRAM_MASK 0x0f +#define DRAM_VALUE_0 0 +#define DRAM_VALUE_1 8 +/* No 2 value defined */ +#define DRAM_VALUE_3 16 +#define DRAM_VALUE_4 16 +#define DRAM_VALUE_5 24 +#define DRAM_VALUE_6 32 +#define DRAM_VALUE_7 32 +#define DRAM_VALUE_8 48 +#define DRAM_VALUE_9 64 +#define DRAM_VALUE_A 64 +#define DRAM_VALUE_B 96 +#define DRAM_VALUE_C 128 +#define DRAM_VALUE_D 128 +#define DRAM_VALUE_E 192 +#define DRAM_VALUE_F 256 /* nice one, geezer */ +#define LM_FREQ_MASK 0x10 +#define LM_FREQ_133 0x10 +#define LM_FREQ_100 0x00 + + + + +/* These are 3d state registers, but the state is invarient, so we let + * the X server handle it: + */ + + + +/* GFXRENDERSTATE_COLOR_CHROMA_KEY, p135 + */ +#define GFX_OP_COLOR_CHROMA_KEY ((0x3<<29)|(0x1d<<24)|(0x2<<16)|0x1) +#define CC1_UPDATE_KILL_WRITE (1<<28) +#define CC1_ENABLE_KILL_WRITE (1<<27) +#define CC1_DISABLE_KILL_WRITE 0 +#define CC1_UPDATE_COLOR_IDX (1<<26) +#define CC1_UPDATE_CHROMA_LOW (1<<25) +#define CC1_UPDATE_CHROMA_HI (1<<24) +#define CC1_CHROMA_LOW_MASK ((1<<24)-1) +#define CC2_COLOR_IDX_SHIFT 24 +#define CC2_COLOR_IDX_MASK (0xff<<24) +#define CC2_CHROMA_HI_MASK ((1<<24)-1) + + +#define GFX_CMD_CONTEXT_SEL ((0<<29)|(0x5<<23)) +#define CS_UPDATE_LOAD (1<<17) +#define CS_UPDATE_USE (1<<16) +#define CS_UPDATE_LOAD (1<<17) +#define CS_LOAD_CTX0 0 +#define CS_LOAD_CTX1 (1<<8) +#define CS_USE_CTX0 0 +#define CS_USE_CTX1 (1<<0) + +/* I810 LCD/TV registers */ +#define LCD_TV_HTOTAL 0x60000 +#define LCD_TV_C 0x60018 +#define LCD_TV_OVRACT 0x6001C + +#define LCD_TV_ENABLE (1 << 31) +#define LCD_TV_VGAMOD (1 << 28) + +/* I830 CRTC registers */ +#define HTOTAL_A 0x60000 +#define HBLANK_A 0x60004 +#define HSYNC_A 0x60008 +#define VTOTAL_A 0x6000c +#define VBLANK_A 0x60010 +#define VSYNC_A 0x60014 +#define PIPEASRC 0x6001c +#define BCLRPAT_A 0x60020 + +#define HTOTAL_B 0x61000 +#define HBLANK_B 0x61004 +#define HSYNC_B 0x61008 +#define VTOTAL_B 0x6100c +#define VBLANK_B 0x61010 +#define VSYNC_B 0x61014 +#define PIPEBSRC 0x6101c +#define BCLRPAT_B 0x61020 + +#define DPLL_A 0x06014 +#define DPLL_B 0x06018 +#define FPA0 0x06040 +#define FPA1 0x06044 + +#define I830_HTOTAL_MASK 0xfff0000 +#define I830_HACTIVE_MASK 0x7ff + +#define I830_HBLANKEND_MASK 0xfff0000 +#define I830_HBLANKSTART_MASK 0xfff + +#define I830_HSYNCEND_MASK 0xfff0000 +#define I830_HSYNCSTART_MASK 0xfff + +#define I830_VTOTAL_MASK 0xfff0000 +#define I830_VACTIVE_MASK 0x7ff + +#define I830_VBLANKEND_MASK 0xfff0000 +#define I830_VBLANKSTART_MASK 0xfff + +#define I830_VSYNCEND_MASK 0xfff0000 +#define I830_VSYNCSTART_MASK 0xfff + +#define I830_PIPEA_HORZ_MASK 0x7ff0000 +#define I830_PIPEA_VERT_MASK 0x7ff + +#define ADPA 0x61100 +#define ADPA_DAC_ENABLE (1<<31) +#define ADPA_DAC_DISABLE 0 +#define ADPA_PIPE_SELECT_MASK (1<<30) +#define ADPA_PIPE_A_SELECT 0 +#define ADPA_PIPE_B_SELECT (1<<30) +#define ADPA_USE_VGA_HVPOLARITY (1<<15) +#define ADPA_SETS_HVPOLARITY 0 +#define ADPA_VSYNC_CNTL_DISABLE (1<<11) +#define ADPA_VSYNC_CNTL_ENABLE 0 +#define ADPA_HSYNC_CNTL_DISABLE (1<<10) +#define ADPA_HSYNC_CNTL_ENABLE 0 +#define ADPA_VSYNC_ACTIVE_HIGH (1<<4) +#define ADPA_VSYNC_ACTIVE_LOW 0 +#define ADPA_HSYNC_ACTIVE_HIGH (1<<3) +#define ADPA_HSYNC_ACTIVE_LOW 0 + + +#define DVOA 0x61120 +#define DVOB 0x61140 +#define DVOC 0x61160 +#define DVO_ENABLE (1<<31) + +#define DVOA_SRCDIM 0x61124 +#define DVOB_SRCDIM 0x61144 +#define DVOC_SRCDIM 0x61164 + +#define LVDS 0x61180 + +#define PIPEACONF 0x70008 +#define PIPEACONF_ENABLE (1<<31) +#define PIPEACONF_DISABLE 0 +#define PIPEACONF_DOUBLE_WIDE (1<<30) +#define PIPEACONF_SINGLE_WIDE 0 +#define PIPEACONF_PIPE_UNLOCKED 0 +#define PIPEACONF_PIPE_LOCKED (1<<25) +#define PIPEACONF_PALETTE 0 +#define PIPEACONF_GAMMA (1<<24) + +#define PIPEBCONF 0x71008 +#define PIPEBCONF_ENABLE (1<<31) +#define PIPEBCONF_DISABLE 0 +#define PIPEBCONF_GAMMA (1<<24) +#define PIPEBCONF_PALETTE 0 + +#define DSPACNTR 0x70180 +#define DSPBCNTR 0x71180 +#define DISPLAY_PLANE_ENABLE (1<<31) +#define DISPLAY_PLANE_DISABLE 0 +#define DISPPLANE_GAMMA_ENABLE (1<<30) +#define DISPPLANE_GAMMA_DISABLE 0 +#define DISPPLANE_PIXFORMAT_MASK (0xf<<26) +#define DISPPLANE_8BPP (0x2<<26) +#define DISPPLANE_15_16BPP (0x4<<26) +#define DISPPLANE_16BPP (0x5<<26) +#define DISPPLANE_32BPP_NO_ALPHA (0x6<<26) +#define DISPPLANE_32BPP (0x7<<26) +#define DISPPLANE_STEREO_ENABLE (1<<25) +#define DISPPLANE_STEREO_DISABLE 0 +#define DISPPLANE_SEL_PIPE_MASK (1<<24) +#define DISPPLANE_SEL_PIPE_A 0 +#define DISPPLANE_SEL_PIPE_B (1<<24) +#define DISPPLANE_SRC_KEY_ENABLE (1<<22) +#define DISPPLANE_SRC_KEY_DISABLE 0 +#define DISPPLANE_LINE_DOUBLE (1<<20) +#define DISPPLANE_NO_LINE_DOUBLE 0 +#define DISPPLANE_STEREO_POLARITY_FIRST 0 +#define DISPPLANE_STEREO_POLARITY_SECOND (1<<18) +/* plane B only */ +#define DISPPLANE_ALPHA_TRANS_ENABLE (1<<15) +#define DISPPLANE_ALPHA_TRANS_DISABLE 0 +#define DISPPLANE_SPRITE_ABOVE_DISPLAYA 0 +#define DISPPLANE_SPRITE_ABOVE_OVERLAY (1) + +#define DSPABASE 0x70184 +#define DSPASTRIDE 0x70188 + +#define DSPBBASE 0x71184 +#define DSPBADDR DSPBBASE +#define DSPBSTRIDE 0x71188 + +/* Various masks for reserved bits, etc. */ +#define I830_FWATER1_MASK (~((1<<11)|(1<<10)|(1<<9)| \ + (1<<8)|(1<<26)|(1<<25)|(1<<24)|(1<<5)|(1<<4)|(1<<3)| \ + (1<<2)|(1<<1)|1|(1<<20)|(1<<19)|(1<<18)|(1<<17)|(1<<16))) +#define I830_FWATER2_MASK ~(0) + +#define DV0A_RESERVED ((1<<26)|(1<<25)|(1<<24)|(1<<23)|(1<<22)|(1<<21)|(1<<20)|(1<<19)|(1<<18)|(1<<16)|(1<<5)|(1<<1)|1) +#define DV0B_RESERVED ((1<<27)|(1<<26)|(1<<25)|(1<<24)|(1<<23)|(1<<22)|(1<<21)|(1<<20)|(1<<19)|(1<<18)|(1<<16)|(1<<5)|(1<<1)|1) +#define VGA0_N_DIVISOR_MASK ((1<<21)|(1<<20)|(1<<19)|(1<<18)|(1<<17)|(1<<16)) +#define VGA0_M1_DIVISOR_MASK ((1<<13)|(1<<12)|(1<<11)|(1<<10)|(1<<9)|(1<<8)) +#define VGA0_M2_DIVISOR_MASK ((1<<5)|(1<<4)|(1<<3)|(1<<2)|(1<<1)|1) +#define VGA0_M1M2N_RESERVED ~(VGA0_N_DIVISOR_MASK|VGA0_M1_DIVISOR_MASK|VGA0_M2_DIVISOR_MASK) +#define VGA0_POSTDIV_MASK ((1<<7)|(1<<5)|(1<<4)|(1<<3)|(1<<2)|(1<<1)|1) +#define VGA1_POSTDIV_MASK ((1<<15)|(1<<13)|(1<<12)|(1<<11)|(1<<10)|(1<<9)|(1<<8)) +#define VGA_POSTDIV_RESERVED ~(VGA0_POSTDIV_MASK|VGA1_POSTDIV_MASK|(1<<7)|(1<<15)) +#define DPLLA_POSTDIV_MASK ((1<<23)|(1<<21)|(1<<20)|(1<<19)|(1<<18)|(1<<17)|(1<<16)) +#define DPLLA_RESERVED ((1<<27)|(1<<26)|(1<<25)|(1<<24)|(1<<22)|(1<<15)|(1<<12)|(1<<11)|(1<<10)|(1<<9)|(1<<8)|(1<<7)|(1<<6)|(1<<5)|(1<<4)|(1<<3)|(1<<2)|(1<<1)|1) +#define ADPA_RESERVED ((1<<2)|(1<<1)|1|(1<<9)|(1<<8)|(1<<7)|(1<<6)|(1<<5)|(1<<30)|(1<<29)|(1<<28)|(1<<27)|(1<<26)|(1<<25)|(1<<24)|(1<<23)|(1<<22)|(1<<21)|(1<<20)|(1<<19)|(1<<18)|(1<<17)|(1<<16)) +#define SUPER_WORD 32 +#define BURST_A_MASK ((1<<11)|(1<<10)|(1<<9)|(1<<8)) +#define BURST_B_MASK ((1<<26)|(1<<25)|(1<<24)) +#define WATER_A_MASK ((1<<5)|(1<<4)|(1<<3)|(1<<2)|(1<<1)|1) +#define WATER_B_MASK ((1<<20)|(1<<19)|(1<<18)|(1<<17)|(1<<16)) +#define WATER_RESERVED ((1<<31)|(1<<30)|(1<<29)|(1<<28)|(1<<27)|(1<<23)|(1<<22)|(1<<21)|(1<<15)|(1<<14)|(1<<13)|(1<<12)|(1<<7)|(1<<6)) +#define PIPEACONF_RESERVED ((1<<29)|(1<<28)|(1<<27)|(1<<23)|(1<<22)|(1<<21)|(1<<20)|(1<<19)|(1<<18)|(1<<17)|(1<<16)|0xffff) +#define PIPEBCONF_RESERVED ((1<<30)|(1<<29)|(1<<28)|(1<<27)|(1<<26)|(1<<25)|(1<<23)|(1<<22)|(1<<21)|(1<<20)|(1<<19)|(1<<18)|(1<<17)|(1<<16)|0xffff) +#define DSPACNTR_RESERVED ((1<<23)|(1<<19)|(1<<17)|(1<<16)|0xffff) +#define DSPBCNTR_RESERVED ((1<<23)|(1<<19)|(1<<17)|(1<<16)|0x7ffe) + +#define I830_GMCH_CTRL 0x52 + +#define I830_GMCH_ENABLED 0x4 +#define I830_GMCH_MEM_MASK 0x1 +#define I830_GMCH_MEM_64M 0x1 +#define I830_GMCH_MEM_128M 0 + +#define I830_GMCH_GMS_MASK 0x70 +#define I830_GMCH_GMS_DISABLED 0x00 +#define I830_GMCH_GMS_LOCAL 0x10 +#define I830_GMCH_GMS_STOLEN_512 0x20 +#define I830_GMCH_GMS_STOLEN_1024 0x30 +#define I830_GMCH_GMS_STOLEN_8192 0x40 + +#define I830_RDRAM_CHANNEL_TYPE 0x03010 +#define I830_RDRAM_ND(x) (((x) & 0x20) >> 5) +#define I830_RDRAM_DDT(x) (((x) & 0x18) >> 3) + +#define I855_GMCH_GMS_MASK (0x7 << 4) +#define I855_GMCH_GMS_DISABLED 0x00 +#define I855_GMCH_GMS_STOLEN_1M (0x1 << 4) +#define I855_GMCH_GMS_STOLEN_4M (0x2 << 4) +#define I855_GMCH_GMS_STOLEN_8M (0x3 << 4) +#define I855_GMCH_GMS_STOLEN_16M (0x4 << 4) +#define I855_GMCH_GMS_STOLEN_32M (0x5 << 4) + +#define I85X_CAPID 0x44 +#define I85X_VARIANT_MASK 0x7 +#define I85X_VARIANT_SHIFT 5 +#define I855_GME 0x0 +#define I855_GM 0x4 +#define I852_GME 0x2 +#define I852_GM 0x5 + +/* BLT commands */ +#define COLOR_BLT_CMD ((2<<29)|(0x40<<22)|(0x3)) +#define COLOR_BLT_WRITE_ALPHA (1<<21) +#define COLOR_BLT_WRITE_RGB (1<<20) + +#define XY_COLOR_BLT_CMD ((2<<29)|(0x50<<22)|(0x4)) +#define XY_COLOR_BLT_WRITE_ALPHA (1<<21) +#define XY_COLOR_BLT_WRITE_RGB (1<<20) + +#define XY_SETUP_CLIP_BLT_CMD ((2<<29)|(3<<22)|1) + +#define XY_SRC_COPY_BLT_CMD ((2<<29)|(0x53<<22)|6) +#define XY_SRC_COPY_BLT_WRITE_ALPHA (1<<21) +#define XY_SRC_COPY_BLT_WRITE_RGB (1<<20) + +#define SRC_COPY_BLT_CMD ((2<<29)|(0x43<<22)|0x4) +#define SRC_COPY_BLT_WRITE_ALPHA (1<<21) +#define SRC_COPY_BLT_WRITE_RGB (1<<20) + +#define XY_MONO_PAT_BLT_CMD ((0x2<<29)|(0x52<<22)|0x7) +#define XY_MONO_PAT_VERT_SEED ((1<<10)|(1<<9)|(1<<8)) +#define XY_MONO_PAT_HORT_SEED ((1<<14)|(1<<13)|(1<<12)) +#define XY_MONO_PAT_BLT_WRITE_ALPHA (1<<21) +#define XY_MONO_PAT_BLT_WRITE_RGB (1<<20) + +#define XY_MONO_SRC_BLT_CMD ((0x2<<29)|(0x54<<22)|(0x6)) +#define XY_MONO_SRC_BLT_WRITE_ALPHA (1<<21) +#define XY_MONO_SRC_BLT_WRITE_RGB (1<<20) + +/* 3d state */ +#define STATE3D_FOG_MODE ((3<<29)|(0x1d<<24)|(0x89<<16)|2) +#define FOG_MODE_VERTEX (1<<31) +#define STATE3D_MAP_COORD_TRANSFORM ((3<<29)|(0x1d<<24)|(0x8c<<16)) +#define DISABLE_TEX_TRANSFORM (1<<28) +#define TEXTURE_SET(x) (x<<29) +#define STATE3D_RASTERIZATION_RULES ((3<<29)|(0x07<<24)) +#define POINT_RASTER_ENABLE (1<<15) +#define POINT_RASTER_OGL (1<<13) +#define STATE3D_VERTEX_TRANSFORM ((3<<29)|(0x1d<<24)|(0x8b<<16)) +#define DISABLE_VIEWPORT_TRANSFORM (1<<31) +#define DISABLE_PERSPECTIVE_DIVIDE (1<<29) + +#define MI_SET_CONTEXT (0x18<<23) +#define CTXT_NO_RESTORE (1) +#define CTXT_PALETTE_SAVE_DISABLE (1<<3) +#define CTXT_PALETTE_RESTORE_DISABLE (1<<2) + +/* Dword 0 */ +#define MI_VERTEX_BUFFER (0x17<<23) +#define MI_VERTEX_BUFFER_IDX(x) (x<<20) +#define MI_VERTEX_BUFFER_PITCH(x) (x<<13) +#define MI_VERTEX_BUFFER_WIDTH(x) (x<<6) +/* Dword 1 */ +#define MI_VERTEX_BUFFER_DISABLE (1) + +/* Overlay Flip */ +#define MI_OVERLAY_FLIP (0x11<<23) +#define MI_OVERLAY_FLIP_CONTINUE (0<<21) +#define MI_OVERLAY_FLIP_ON (1<<21) +#define MI_OVERLAY_FLIP_OFF (2<<21) + +/* Wait for Events */ +#define MI_WAIT_FOR_EVENT (0x03<<23) +#define MI_WAIT_FOR_OVERLAY_FLIP (1<<16) + +/* Flush */ +#define MI_FLUSH (0x04<<23) +#define MI_WRITE_DIRTY_STATE (1<<4) +#define MI_END_SCENE (1<<3) +#define MI_INHIBIT_RENDER_CACHE_FLUSH (1<<2) +#define MI_INVALIDATE_MAP_CACHE (1<<0) + +/* Noop */ +#define MI_NOOP 0x00 +#define MI_NOOP_WRITE_ID (1<<22) +#define MI_NOOP_ID_MASK (1<<22 - 1) + +#define STATE3D_COLOR_FACTOR ((0x3<<29)|(0x1d<<24)|(0x01<<16)) + +/* STATE3D_FOG_MODE stuff */ +#define ENABLE_FOG_SOURCE (1<<27) +#define ENABLE_FOG_CONST (1<<24) +#define ENABLE_FOG_DENSITY (1<<23) + + +#define MAX_DISPLAY_PIPES 2 + +typedef enum { + CrtIndex = 0, + TvIndex, + DfpIndex, + LfpIndex, + Tv2Index, + Dfp2Index, + UnknownIndex, + Unknown2Index, + NumDisplayTypes, + NumKnownDisplayTypes = UnknownIndex +} DisplayType; + +/* What's connected to the pipes (as reported by the BIOS) */ +#define PIPE_ACTIVE_MASK 0xff +#define PIPE_CRT_ACTIVE (1 << CrtIndex) +#define PIPE_TV_ACTIVE (1 << TvIndex) +#define PIPE_DFP_ACTIVE (1 << DfpIndex) +#define PIPE_LCD_ACTIVE (1 << LfpIndex) +#define PIPE_TV2_ACTIVE (1 << Tv2Index) +#define PIPE_DFP2_ACTIVE (1 << Dfp2Index) +#define PIPE_UNKNOWN_ACTIVE ((1 << UnknownIndex) | \ + (1 << Unknown2Index)) + +#define PIPE_SIZED_DISP_MASK (PIPE_DFP_ACTIVE | \ + PIPE_LCD_ACTIVE | \ + PIPE_DFP2_ACTIVE) + +#define PIPE_A_SHIFT 0 +#define PIPE_B_SHIFT 8 +#define PIPE_SHIFT(n) ((n) == 0 ? \ + PIPE_A_SHIFT : PIPE_B_SHIFT) + +/* + * Some BIOS scratch area registers. The 845 (and 830?) store the amount + * of video memory available to the BIOS in SWF1. + */ + +#define SWF0 0x71410 +#define SWF1 0x71414 +#define SWF2 0x71418 +#define SWF3 0x7141c +#define SWF4 0x71420 +#define SWF5 0x71424 +#define SWF6 0x71428 + +/* + * 855 scratch registers. + */ +#define SWF00 0x70410 +#define SWF01 0x70414 +#define SWF02 0x70418 +#define SWF03 0x7041c +#define SWF04 0x70420 +#define SWF05 0x70424 +#define SWF06 0x70428 + +#define SWF10 SWF0 +#define SWF11 SWF1 +#define SWF12 SWF2 +#define SWF13 SWF3 +#define SWF14 SWF4 +#define SWF15 SWF5 +#define SWF16 SWF6 + +#define SWF30 0x72414 +#define SWF31 0x72418 +#define SWF32 0x7241c + +/* + * Overlay registers. These are overlay registers accessed via MMIO. + * Those loaded via the overlay register page are defined in i830_video.c. + */ +#define OVADD 0x30000 + +#define DOVSTA 0x30008 +#define OC_BUF (0x3<<20) + +#define OGAMC5 0x30010 +#define OGAMC4 0x30014 +#define OGAMC3 0x30018 +#define OGAMC2 0x3001c +#define OGAMC1 0x30020 +#define OGAMC0 0x30024 + + +/* + * Palette registers + */ +#define PALETTE_A 0x0a000 +#define PALETTE_B 0x0a800 + +#endif /* _I810_REG_H */ diff --git a/src/i810_video.c b/src/i810_video.c new file mode 100644 index 00000000..9ae60bc5 --- /dev/null +++ b/src/i810_video.c @@ -0,0 +1,1399 @@ +/*************************************************************************** + +Copyright 2000 Intel Corporation. All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sub license, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice (including the +next paragraph) shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +IN NO EVENT SHALL INTEL, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR +THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i810/i810_video.c,v 1.22 2002/09/11 00:29:32 dawes Exp $ */ + +/* + * i810_video.c: i810 Xv driver. Based on the mga Xv driver by Mark Vojkovich. + * + * Authors: + * Jonathan Bian <jonathan.bian@intel.com> + * Offscreen Images: + * Matt Sottek <matthew.j.sottek@intel.com> + */ + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86Resources.h" +#include "xf86_ansic.h" +#include "compiler.h" +#include "xf86PciInfo.h" +#include "xf86Pci.h" +#include "xf86fbman.h" +#include "regionstr.h" + +#include "i810.h" +#include "xf86xv.h" +#include "Xv.h" +#include "xaa.h" +#include "xaalocal.h" +#include "dixstruct.h" +#include "fourcc.h" + +#define OFF_DELAY 250 /* milliseconds */ +#define FREE_DELAY 15000 + +#define OFF_TIMER 0x01 +#define FREE_TIMER 0x02 +#define CLIENT_VIDEO_ON 0x04 + +#define TIMER_MASK (OFF_TIMER | FREE_TIMER) + +static void I810InitOffscreenImages(ScreenPtr); + +static XF86VideoAdaptorPtr I810SetupImageVideo(ScreenPtr); +static void I810StopVideo(ScrnInfoPtr, pointer, Bool); +static int I810SetPortAttribute(ScrnInfoPtr, Atom, INT32, pointer); +static int I810GetPortAttribute(ScrnInfoPtr, Atom ,INT32 *, pointer); +static void I810QueryBestSize(ScrnInfoPtr, Bool, + short, short, short, short, unsigned int *, unsigned int *, pointer); +static int I810PutImage( ScrnInfoPtr, + short, short, short, short, short, short, short, short, + int, unsigned char*, short, short, Bool, RegionPtr, pointer); +static int I810QueryImageAttributes(ScrnInfoPtr, + int, unsigned short *, unsigned short *, int *, int *); + +static void I810BlockHandler(int, pointer, pointer, pointer); + +#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE) + +static Atom xvBrightness, xvContrast, xvColorKey; + +#define IMAGE_MAX_WIDTH 1440 +#define IMAGE_FAST_WIDTH 720 +#define IMAGE_MAX_HEIGHT 1080 +#define Y_BUF_SIZE (IMAGE_MAX_WIDTH * IMAGE_MAX_HEIGHT) + +#define OVERLAY_UPDATE(p) OUTREG(0x30000, p | 0x80000000); + +/* + * OV0CMD - Overlay Command Register + */ +#define VERTICAL_CHROMINANCE_FILTER 0x70000000 +#define VC_SCALING_OFF 0x00000000 +#define VC_LINE_REPLICATION 0x10000000 +#define VC_UP_INTERPOLATION 0x20000000 +#define VC_PIXEL_DROPPING 0x50000000 +#define VC_DOWN_INTERPOLATION 0x60000000 +#define VERTICAL_LUMINANCE_FILTER 0x0E000000 +#define VL_SCALING_OFF 0x00000000 +#define VL_LINE_REPLICATION 0x02000000 +#define VL_UP_INTERPOLATION 0x04000000 +#define VL_PIXEL_DROPPING 0x0A000000 +#define VL_DOWN_INTERPOLATION 0x0C000000 +#define HORIZONTAL_CHROMINANCE_FILTER 0x01C00000 +#define HC_SCALING_OFF 0x00000000 +#define HC_LINE_REPLICATION 0x00400000 +#define HC_UP_INTERPOLATION 0x00800000 +#define HC_PIXEL_DROPPING 0x01400000 +#define HC_DOWN_INTERPOLATION 0x01800000 +#define HORIZONTAL_LUMINANCE_FILTER 0x00380000 +#define HL_SCALING_OFF 0x00000000 +#define HL_LINE_REPLICATION 0x00080000 +#define HL_UP_INTERPOLATION 0x00100000 +#define HL_PIXEL_DROPPING 0x00280000 +#define HL_DOWN_INTERPOLATION 0x00300000 + +#define Y_ADJUST 0x00010000 +#define OV_BYTE_ORDER 0x0000C000 +#define UV_SWAP 0x00004000 +#define Y_SWAP 0x00008000 +#define Y_AND_UV_SWAP 0x0000C000 +#define SOURCE_FORMAT 0x00003C00 +#define RGB_555 0x00000800 +#define RGB_565 0x00000C00 +#define YUV_422 0x00002000 +#define YUV_411 0x00002400 +#define YUV_420 0x00003000 +#define YUV_410 0x00003800 +#define BUFFER_AND_FIELD 0x00000006 +#define BUFFER0_FIELD0 0x00000000 +#define BUFFER1_FIELD0 0x00000004 +#define OVERLAY_ENABLE 0x00000001 + +#define UV_VERT_BUF1 0x02 +#define UV_VERT_BUF0 0x04 + +/* + * DOV0STA - Display/Overlay 0 Status Register + */ +#define DOV0STA 0x30008 + +#define MINUV_SCALE 0x1 + +#define RGB16ToColorKey(c) \ + (((c & 0xF800) << 8) | ((c & 0x07E0) << 5) | ((c & 0x001F) << 3)) + +#define RGB15ToColorKey(c) \ + (((c & 0x7c00) << 9) | ((c & 0x03E0) << 6) | ((c & 0x001F) << 3)) + +void I810InitVideo(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL; + XF86VideoAdaptorPtr newAdaptor = NULL; + int num_adaptors; + + if (pScrn->bitsPerPixel != 8) + { + newAdaptor = I810SetupImageVideo(pScreen); + I810InitOffscreenImages(pScreen); + } + + num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors); + + if(newAdaptor) { + if(!num_adaptors) { + num_adaptors = 1; + adaptors = &newAdaptor; + } else { + newAdaptors = /* need to free this someplace */ + xalloc((num_adaptors + 1) * sizeof(XF86VideoAdaptorPtr*)); + if(newAdaptors) { + memcpy(newAdaptors, adaptors, num_adaptors * + sizeof(XF86VideoAdaptorPtr)); + newAdaptors[num_adaptors] = newAdaptor; + adaptors = newAdaptors; + num_adaptors++; + } + } + } + + if(num_adaptors) + xf86XVScreenInit(pScreen, adaptors, num_adaptors); + + if(newAdaptors) + xfree(newAdaptors); +} + +/* *INDENT-OFF* */ +/* client libraries expect an encoding */ +static XF86VideoEncodingRec DummyEncoding[1] = +{ + { + 0, + "XV_IMAGE", + IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT, + {1, 1} + } +}; + +#define NUM_FORMATS 3 + +static XF86VideoFormatRec Formats[NUM_FORMATS] = +{ + {15, TrueColor}, {16, TrueColor}, {24, TrueColor} +}; + +#define NUM_ATTRIBUTES 3 + +static XF86AttributeRec Attributes[NUM_ATTRIBUTES] = +{ + {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"}, + {XvSettable | XvGettable, -128, 127, "XV_BRIGHTNESS"}, + {XvSettable | XvGettable, 0, 255, "XV_CONTRAST"} +}; + +#define NUM_IMAGES 4 + +static XF86ImageRec Images[NUM_IMAGES] = +{ + XVIMAGE_YUY2, + XVIMAGE_YV12, + XVIMAGE_I420, + XVIMAGE_UYVY +}; +/* *INDENT-ON* */ + +typedef struct { + CARD32 OBUF_0Y; + CARD32 OBUF_1Y; + CARD32 OBUF_0U; + CARD32 OBUF_0V; + CARD32 OBUF_1U; + CARD32 OBUF_1V; + CARD32 OV0STRIDE; + CARD32 YRGB_VPH; + CARD32 UV_VPH; + CARD32 HORZ_PH; + CARD32 INIT_PH; + CARD32 DWINPOS; + CARD32 DWINSZ; + CARD32 SWID; + CARD32 SWIDQW; + CARD32 SHEIGHT; + CARD32 YRGBSCALE; + CARD32 UVSCALE; + CARD32 OV0CLRC0; + CARD32 OV0CLRC1; + CARD32 DCLRKV; + CARD32 DCLRKM; + CARD32 SCLRKVH; + CARD32 SCLRKVL; + CARD32 SCLRKM; + CARD32 OV0CONF; + CARD32 OV0CMD; +} I810OverlayRegRec, *I810OverlayRegPtr; + +typedef struct { + CARD32 YBuf0offset; + CARD32 UBuf0offset; + CARD32 VBuf0offset; + + CARD32 YBuf1offset; + CARD32 UBuf1offset; + CARD32 VBuf1offset; + + unsigned char currentBuf; + + int brightness; + int contrast; + + RegionRec clip; + CARD32 colorKey; + + CARD32 videoStatus; + Time offTime; + Time freeTime; + FBLinearPtr linear; +} I810PortPrivRec, *I810PortPrivPtr; + +#define GET_PORT_PRIVATE(pScrn) \ + (I810PortPrivPtr)((I810PTR(pScrn))->adaptor->pPortPrivates[0].ptr) + +static void I810ResetVideo(ScrnInfoPtr pScrn) +{ + I810Ptr pI810 = I810PTR(pScrn); + I810PortPrivPtr pPriv = pI810->adaptor->pPortPrivates[0].ptr; + I810OverlayRegPtr overlay = (I810OverlayRegPtr) (pI810->FbBase + pI810->OverlayStart); + + /* + * Default to maximum image size in YV12 + */ + + overlay->YRGB_VPH = 0; + overlay->UV_VPH = 0; + overlay->HORZ_PH = 0; + overlay->INIT_PH = 0; + overlay->DWINPOS = 0; + overlay->DWINSZ = (IMAGE_MAX_HEIGHT << 16) | IMAGE_MAX_WIDTH; + overlay->SWID = IMAGE_MAX_WIDTH | (IMAGE_MAX_WIDTH << 15); + overlay->SWIDQW = (IMAGE_MAX_WIDTH >> 3) | (IMAGE_MAX_WIDTH << 12); + overlay->SHEIGHT = IMAGE_MAX_HEIGHT | (IMAGE_MAX_HEIGHT << 15); + overlay->YRGBSCALE = 0x80004000; /* scale factor 1 */ + overlay->UVSCALE = 0x80004000; /* scale factor 1 */ + overlay->OV0CLRC0 = 0x4000; /* brightness: 0 contrast: 1.0 */ + overlay->OV0CLRC1 = 0x80; /* saturation: bypass */ + + /* + * Enable destination color keying + */ + switch(pScrn->depth) { + case 16: overlay->DCLRKV = RGB16ToColorKey(pPriv->colorKey); + overlay->DCLRKM = 0x80070307; + break; + case 15: overlay->DCLRKV = RGB15ToColorKey(pPriv->colorKey); + overlay->DCLRKM = 0x80070707; + break; + default: overlay->DCLRKV = pPriv->colorKey; + overlay->DCLRKM = 0x80000000; + break; + } + + overlay->SCLRKVH = 0; + overlay->SCLRKVL = 0; + overlay->SCLRKM = 0; /* source color key disable */ + overlay->OV0CONF = 0; /* two 720 pixel line buffers */ + + overlay->OV0CMD = VC_UP_INTERPOLATION | HC_UP_INTERPOLATION | Y_ADJUST | + YUV_420; + + OVERLAY_UPDATE(pI810->OverlayPhysical); +} + + +static XF86VideoAdaptorPtr +I810SetupImageVideo(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I810Ptr pI810 = I810PTR(pScrn); + XF86VideoAdaptorPtr adapt; + I810PortPrivPtr pPriv; + + if(!(adapt = xcalloc(1, sizeof(XF86VideoAdaptorRec) + + sizeof(I810PortPrivRec) + + sizeof(DevUnion)))) + return NULL; + + adapt->type = XvWindowMask | XvInputMask | XvImageMask; + adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT; + adapt->name = "I810 Video Overlay"; + adapt->nEncodings = 1; + adapt->pEncodings = DummyEncoding; + adapt->nFormats = NUM_FORMATS; + adapt->pFormats = Formats; + adapt->nPorts = 1; + adapt->pPortPrivates = (DevUnion*)(&adapt[1]); + + pPriv = (I810PortPrivPtr)(&adapt->pPortPrivates[1]); + + adapt->pPortPrivates[0].ptr = (pointer)(pPriv); + adapt->pAttributes = Attributes; + adapt->nImages = NUM_IMAGES; + adapt->nAttributes = NUM_ATTRIBUTES; + adapt->pImages = Images; + adapt->PutVideo = NULL; + adapt->PutStill = NULL; + adapt->GetVideo = NULL; + adapt->GetStill = NULL; + adapt->StopVideo = I810StopVideo; + adapt->SetPortAttribute = I810SetPortAttribute; + adapt->GetPortAttribute = I810GetPortAttribute; + adapt->QueryBestSize = I810QueryBestSize; + adapt->PutImage = I810PutImage; + adapt->QueryImageAttributes = I810QueryImageAttributes; + + pPriv->colorKey = pI810->colorKey & ((1 << pScrn->depth) - 1); + pPriv->videoStatus = 0; + pPriv->brightness = 0; + pPriv->contrast = 64; + pPriv->linear = NULL; + pPriv->currentBuf = 0; + + /* gotta uninit this someplace */ + REGION_INIT(pScreen, &pPriv->clip, NullBox, 0); + + pI810->adaptor = adapt; + + pI810->BlockHandler = pScreen->BlockHandler; + pScreen->BlockHandler = I810BlockHandler; + + xvBrightness = MAKE_ATOM("XV_BRIGHTNESS"); + xvContrast = MAKE_ATOM("XV_CONTRAST"); + xvColorKey = MAKE_ATOM("XV_COLORKEY"); + + I810ResetVideo(pScrn); + + return adapt; +} + + +static Bool +RegionsEqual(RegionPtr A, RegionPtr B) +{ + int *dataA, *dataB; + int num; + + num = REGION_NUM_RECTS(A); + if(num != REGION_NUM_RECTS(B)) + return FALSE; + + if((A->extents.x1 != B->extents.x1) || + (A->extents.x2 != B->extents.x2) || + (A->extents.y1 != B->extents.y1) || + (A->extents.y2 != B->extents.y2)) + return FALSE; + + dataA = (int*)REGION_RECTS(A); + dataB = (int*)REGION_RECTS(B); + + while(num--) { + if((dataA[0] != dataB[0]) || (dataA[1] != dataB[1])) + return FALSE; + dataA += 2; + dataB += 2; + } + + return TRUE; +} + + +/* I810ClipVideo - + + Takes the dst box in standard X BoxRec form (top and left + edges inclusive, bottom and right exclusive). The new dst + box is returned. The source boundaries are given (x1, y1 + inclusive, x2, y2 exclusive) and returned are the new source + boundaries in 16.16 fixed point. +*/ + +static void +I810ClipVideo( + BoxPtr dst, + INT32 *x1, + INT32 *x2, + INT32 *y1, + INT32 *y2, + BoxPtr extents, /* extents of the clip region */ + INT32 width, + INT32 height +){ + INT32 vscale, hscale, delta; + int diff; + + hscale = ((*x2 - *x1) << 16) / (dst->x2 - dst->x1); + vscale = ((*y2 - *y1) << 16) / (dst->y2 - dst->y1); + + *x1 <<= 16; *x2 <<= 16; + *y1 <<= 16; *y2 <<= 16; + + diff = extents->x1 - dst->x1; + if(diff > 0) { + dst->x1 = extents->x1; + *x1 += diff * hscale; + } + diff = dst->x2 - extents->x2; + if(diff > 0) { + dst->x2 = extents->x2; + *x2 -= diff * hscale; + } + diff = extents->y1 - dst->y1; + if(diff > 0) { + dst->y1 = extents->y1; + *y1 += diff * vscale; + } + diff = dst->y2 - extents->y2; + if(diff > 0) { + dst->y2 = extents->y2; + *y2 -= diff * vscale; + } + + if(*x1 < 0) { + diff = (- *x1 + hscale - 1)/ hscale; + dst->x1 += diff; + *x1 += diff * hscale; + } + delta = *x2 - (width << 16); + if(delta > 0) { + diff = (delta + hscale - 1)/ hscale; + dst->x2 -= diff; + *x2 -= diff * hscale; + } + if(*y1 < 0) { + diff = (- *y1 + vscale - 1)/ vscale; + dst->y1 += diff; + *y1 += diff * vscale; + } + delta = *y2 - (height << 16); + if(delta > 0) { + diff = (delta + vscale - 1)/ vscale; + dst->y2 -= diff; + *y2 -= diff * vscale; + } +} + +static void +I810StopVideo(ScrnInfoPtr pScrn, pointer data, Bool shutdown) +{ + I810PortPrivPtr pPriv = (I810PortPrivPtr)data; + I810Ptr pI810 = I810PTR(pScrn); + + I810OverlayRegPtr overlay = (I810OverlayRegPtr) (pI810->FbBase + pI810->OverlayStart); + + REGION_EMPTY(pScrn->pScreen, &pPriv->clip); + + if(shutdown) { + if(pPriv->videoStatus & CLIENT_VIDEO_ON) { + overlay->OV0CMD &= 0xFFFFFFFE; + OVERLAY_UPDATE(pI810->OverlayPhysical); + } + if(pPriv->linear) { + xf86FreeOffscreenLinear(pPriv->linear); + pPriv->linear = NULL; + } + pPriv->videoStatus = 0; + } else { + if(pPriv->videoStatus & CLIENT_VIDEO_ON) { + pPriv->videoStatus |= OFF_TIMER; + pPriv->offTime = currentTime.milliseconds + OFF_DELAY; + } + } + +} + +static int +I810SetPortAttribute( + ScrnInfoPtr pScrn, + Atom attribute, + INT32 value, + pointer data +){ + I810PortPrivPtr pPriv = (I810PortPrivPtr)data; + I810Ptr pI810 = I810PTR(pScrn); + I810OverlayRegPtr overlay = (I810OverlayRegPtr) (pI810->FbBase + pI810->OverlayStart); + + if(attribute == xvBrightness) { + if((value < -128) || (value > 127)) + return BadValue; + pPriv->brightness = value; + overlay->OV0CLRC0 = (pPriv->contrast << 8) | (pPriv->brightness & 0xff); + OVERLAY_UPDATE(pI810->OverlayPhysical); + } else + if(attribute == xvContrast) { + if((value < 0) || (value > 255)) + return BadValue; + pPriv->contrast = value; + overlay->OV0CLRC0 = (pPriv->contrast << 8) | (pPriv->brightness & 0xff); + OVERLAY_UPDATE(pI810->OverlayPhysical); + } else + if(attribute == xvColorKey) { + pPriv->colorKey = value; + switch(pScrn->depth) { + case 16: overlay->DCLRKV = RGB16ToColorKey(pPriv->colorKey); + break; + case 15: overlay->DCLRKV = RGB15ToColorKey(pPriv->colorKey); + break; + default: overlay->DCLRKV = pPriv->colorKey; + break; + } + OVERLAY_UPDATE(pI810->OverlayPhysical); + REGION_EMPTY(pScrn->pScreen, &pPriv->clip); + } else return BadMatch; + + return Success; +} + +static int +I810GetPortAttribute( + ScrnInfoPtr pScrn, + Atom attribute, + INT32 *value, + pointer data +){ + I810PortPrivPtr pPriv = (I810PortPrivPtr)data; + + if(attribute == xvBrightness) { + *value = pPriv->brightness; + } else + if(attribute == xvContrast) { + *value = pPriv->contrast; + } else + if(attribute == xvColorKey) { + *value = pPriv->colorKey; + } else return BadMatch; + + return Success; +} + +static void +I810QueryBestSize( + ScrnInfoPtr pScrn, + Bool motion, + short vid_w, short vid_h, + short drw_w, short drw_h, + unsigned int *p_w, unsigned int *p_h, + pointer data +){ + if(vid_w > (drw_w << 1)) drw_w = vid_w >> 1; + if(vid_h > (drw_h << 1)) drw_h = vid_h >> 1; + + *p_w = drw_w; + *p_h = drw_h; +} + + +static void +I810CopyPackedData( + ScrnInfoPtr pScrn, + unsigned char *buf, + int srcPitch, + int dstPitch, + int top, + int left, + int h, + int w + ) +{ + I810Ptr pI810 = I810PTR(pScrn); + I810PortPrivPtr pPriv = pI810->adaptor->pPortPrivates[0].ptr; + unsigned char *src, *dst; + + src = buf + (top*srcPitch) + (left<<1); + + if (pPriv->currentBuf == 0) + dst = pI810->FbBase + pPriv->YBuf0offset; + else + dst = pI810->FbBase + pPriv->YBuf1offset; + + w <<= 1; + while(h--) { + memcpy(dst, src, w); + src += srcPitch; + dst += dstPitch; + } +} + +static void +I810CopyPlanarData( + ScrnInfoPtr pScrn, + unsigned char *buf, + int srcPitch, + int dstPitch, /* of chroma */ + int srcH, + int top, + int left, + int h, + int w, + int id + ) +{ + I810Ptr pI810 = I810PTR(pScrn); + I810PortPrivPtr pPriv = pI810->adaptor->pPortPrivates[0].ptr; + int i; + unsigned char *src1, *src2, *src3, *dst1, *dst2, *dst3; + + /* Copy Y data */ + src1 = buf + (top*srcPitch) + left; + if (pPriv->currentBuf == 0) + dst1 = pI810->FbBase + pPriv->YBuf0offset; + else + dst1 = pI810->FbBase + pPriv->YBuf1offset; + + for (i = 0; i < h; i++) { + memcpy(dst1, src1, w); + src1 += srcPitch; + dst1 += dstPitch << 1; + } + + /* Copy V data for YV12, or U data for I420 */ + src2 = buf + (srcH*srcPitch) + ((top*srcPitch)>>2) + (left>>1); + if (pPriv->currentBuf == 0) { + if (id == FOURCC_I420) + dst2 = pI810->FbBase + pPriv->UBuf0offset; + else + dst2 = pI810->FbBase + pPriv->VBuf0offset; + } else { + if (id == FOURCC_I420) + dst2 = pI810->FbBase + pPriv->UBuf1offset; + else + dst2 = pI810->FbBase + pPriv->VBuf1offset; + } + + for (i = 0; i < h/2; i++) { + memcpy(dst2, src2, w/2); + src2 += srcPitch>>1; + dst2 += dstPitch; + } + + /* Copy U data for YV12, or V data for I420 */ + src3 = buf + (srcH*srcPitch) + ((srcH*srcPitch)>>2) + ((top*srcPitch)>>2) + (left>>1); + if (pPriv->currentBuf == 0) { + if (id == FOURCC_I420) + dst3 = pI810->FbBase + pPriv->VBuf0offset; + else + dst3 = pI810->FbBase + pPriv->UBuf0offset; + } else { + if (id == FOURCC_I420) + dst3 = pI810->FbBase + pPriv->VBuf1offset; + else + dst3 = pI810->FbBase + pPriv->UBuf1offset; + } + + for (i = 0; i < h/2; i++) { + memcpy(dst3, src3, w/2); + src3 += srcPitch>>1; + dst3 += dstPitch; + } +} + +static void +I810DisplayVideo( + ScrnInfoPtr pScrn, + int id, + short width, short height, + int dstPitch, /* of chroma for 4:2:0 */ + int x1, int y1, int x2, int y2, + BoxPtr dstBox, + short src_w, short src_h, + short drw_w, short drw_h +){ + I810Ptr pI810 = I810PTR(pScrn); + I810PortPrivPtr pPriv = pI810->adaptor->pPortPrivates[0].ptr; + I810OverlayRegPtr overlay = (I810OverlayRegPtr) (pI810->FbBase + pI810->OverlayStart); + int xscaleInt, xscaleFract, yscaleInt, yscaleFract; + int xscaleIntUV = 0, xscaleFractUV = 0, yscaleIntUV = 0, yscaleFractUV = 0; + unsigned int swidth; + + switch(id) { + case FOURCC_YV12: + case FOURCC_I420: + swidth = (width + 7) & ~7; + overlay->SWID = (swidth << 15) | swidth; + overlay->SWIDQW = (swidth << 12) | (swidth >> 3); + break; + case FOURCC_UYVY: + case FOURCC_YUY2: + default: + swidth = ((width + 3) & ~3) << 1; + overlay->SWID = swidth; + overlay->SWIDQW = swidth >> 3; + break; + } + + /* wide video formats (>720 pixels) are special */ + if( swidth > IMAGE_FAST_WIDTH ) { + overlay->OV0CONF = 1; /* one 1440 pixel line buffer */ + } else { + overlay->OV0CONF = 0; /* two 720 pixel line buffers */ + } + + overlay->SHEIGHT = height | (height << 15); + overlay->DWINPOS = (dstBox->y1 << 16) | dstBox->x1; + overlay->DWINSZ = ((dstBox->y2 - dstBox->y1) << 16) | + (dstBox->x2 - dstBox->x1); + + /* buffer locations */ + overlay->OBUF_0Y = pPriv->YBuf0offset; + overlay->OBUF_1Y = pPriv->YBuf1offset; + overlay->OBUF_0U = pPriv->UBuf0offset; + overlay->OBUF_0V = pPriv->VBuf0offset; + overlay->OBUF_1U = pPriv->UBuf1offset; + overlay->OBUF_1V = pPriv->VBuf1offset; + + /* + * Calculate horizontal and vertical scaling factors, default to 1:1 + */ + overlay->YRGBSCALE = 0x80004000; + overlay->UVSCALE = 0x80004000; + + /* + * Initially, YCbCr and Overlay Enable and + * vertical chrominance up interpolation and horozontal chrominance + * up interpolation + */ + overlay->OV0CMD = VC_UP_INTERPOLATION | HC_UP_INTERPOLATION | Y_ADJUST | + OVERLAY_ENABLE; + + if ((drw_w != src_w) || (drw_h != src_h)) + { + xscaleInt = (src_w / drw_w) & 0x3; + xscaleFract = (src_w << 12) / drw_w; + yscaleInt = (src_h / drw_h) & 0x3; + yscaleFract = (src_h << 12) / drw_h; + + overlay->YRGBSCALE = (xscaleInt << 15) | + ((xscaleFract & 0xFFF) << 3) | + (yscaleInt) | + ((yscaleFract & 0xFFF) << 20); + + if (drw_w > src_w) + { + /* horizontal up-scaling */ + overlay->OV0CMD &= ~HORIZONTAL_CHROMINANCE_FILTER; + overlay->OV0CMD &= ~HORIZONTAL_LUMINANCE_FILTER; + overlay->OV0CMD |= (HC_UP_INTERPOLATION | HL_UP_INTERPOLATION); + } + + if (drw_h > src_h) + { + /* vertical up-scaling */ + overlay->OV0CMD &= ~VERTICAL_CHROMINANCE_FILTER; + overlay->OV0CMD &= ~VERTICAL_LUMINANCE_FILTER; + overlay->OV0CMD |= (VC_UP_INTERPOLATION | VL_UP_INTERPOLATION); + } + + if (drw_w < src_w) + { + /* horizontal down-scaling */ + overlay->OV0CMD &= ~HORIZONTAL_CHROMINANCE_FILTER; + overlay->OV0CMD &= ~HORIZONTAL_LUMINANCE_FILTER; + overlay->OV0CMD |= (HC_DOWN_INTERPOLATION | HL_DOWN_INTERPOLATION); + } + + if (drw_h < src_h) + { + /* vertical down-scaling */ + overlay->OV0CMD &= ~VERTICAL_CHROMINANCE_FILTER; + overlay->OV0CMD &= ~VERTICAL_LUMINANCE_FILTER; + overlay->OV0CMD |= (VC_DOWN_INTERPOLATION | VL_DOWN_INTERPOLATION); + } + + /* now calculate the UV scaling factor */ + + if (xscaleFract) + { + xscaleFractUV = xscaleFract >> MINUV_SCALE; + overlay->OV0CMD &= ~HC_DOWN_INTERPOLATION; + overlay->OV0CMD |= HC_UP_INTERPOLATION; + } + + if (xscaleInt) + { + xscaleIntUV = xscaleInt >> MINUV_SCALE; + if (xscaleIntUV) + { + overlay->OV0CMD &= ~HC_UP_INTERPOLATION; + } + } + + if (yscaleFract) + { + yscaleFractUV = yscaleFract >> MINUV_SCALE; + overlay->OV0CMD &= ~VC_DOWN_INTERPOLATION; + overlay->OV0CMD |= VC_UP_INTERPOLATION; + } + + if (yscaleInt) + { + yscaleIntUV = yscaleInt >> MINUV_SCALE; + if (yscaleIntUV) + { + overlay->OV0CMD &= ~VC_UP_INTERPOLATION; + overlay->OV0CMD |= VC_DOWN_INTERPOLATION; + } + } + + overlay->UVSCALE = yscaleIntUV | ((xscaleFractUV & 0xFFF) << 3) | + ((yscaleFractUV & 0xFFF) << 20); + } + + switch(id) { + case FOURCC_YV12: + case FOURCC_I420: + /* set UV vertical phase to -0.25 */ + overlay->UV_VPH = 0x30003000; + overlay->INIT_PH = UV_VERT_BUF0 | UV_VERT_BUF1; + overlay->OV0STRIDE = (dstPitch << 1) | (dstPitch << 16); + overlay->OV0CMD &= ~SOURCE_FORMAT; + overlay->OV0CMD |= YUV_420; + break; + case FOURCC_UYVY: + case FOURCC_YUY2: + default: + overlay->UV_VPH = 0; + overlay->INIT_PH = 0; + overlay->OV0STRIDE = dstPitch; + overlay->OV0CMD &= ~SOURCE_FORMAT; + overlay->OV0CMD |= YUV_422; + overlay->OV0CMD &= ~OV_BYTE_ORDER; + if (id == FOURCC_UYVY) + overlay->OV0CMD |= Y_SWAP; + break; + } + + overlay->OV0CMD &= ~BUFFER_AND_FIELD; + if (pPriv->currentBuf == 0) + overlay->OV0CMD |= BUFFER0_FIELD0; + else + overlay->OV0CMD |= BUFFER1_FIELD0; + + OVERLAY_UPDATE(pI810->OverlayPhysical); + +} + +static FBLinearPtr +I810AllocateMemory( + ScrnInfoPtr pScrn, + FBLinearPtr linear, + int size +){ + ScreenPtr pScreen; + FBLinearPtr new_linear; + + if(linear) { + if(linear->size >= size) + return linear; + + if(xf86ResizeOffscreenLinear(linear, size)) + return linear; + + xf86FreeOffscreenLinear(linear); + } + + pScreen = screenInfo.screens[pScrn->scrnIndex]; + + new_linear = xf86AllocateOffscreenLinear(pScreen, size, 4, + NULL, NULL, NULL); + + if(!new_linear) { + int max_size; + + xf86QueryLargestOffscreenLinear(pScreen, &max_size, 4, + PRIORITY_EXTREME); + + if(max_size < size) return NULL; + + xf86PurgeUnlockedOffscreenAreas(pScreen); + new_linear = xf86AllocateOffscreenLinear(pScreen, size, 4, + NULL, NULL, NULL); + } + + return new_linear; +} + +static int +I810PutImage( + ScrnInfoPtr pScrn, + short src_x, short src_y, + short drw_x, short drw_y, + short src_w, short src_h, + short drw_w, short drw_h, + int id, unsigned char* buf, + short width, short height, + Bool sync, + RegionPtr clipBoxes, pointer data +){ + I810Ptr pI810 = I810PTR(pScrn); + I810PortPrivPtr pPriv = (I810PortPrivPtr)data; + INT32 x1, x2, y1, y2; + int srcPitch, dstPitch; + int top, left, npixels, nlines, size, loops; + BoxRec dstBox; + + + /* Clip */ + x1 = src_x; + x2 = src_x + src_w; + y1 = src_y; + y2 = src_y + src_h; + + dstBox.x1 = drw_x; + dstBox.x2 = drw_x + drw_w; + dstBox.y1 = drw_y; + dstBox.y2 = drw_y + drw_h; + + I810ClipVideo(&dstBox, &x1, &x2, &y1, &y2, + REGION_EXTENTS(pScreen, clipBoxes), width, height); + + if((x1 >= x2) || (y1 >= y2)) + return Success; + + dstBox.x1 -= pScrn->frameX0; + dstBox.x2 -= pScrn->frameX0; + dstBox.y1 -= pScrn->frameY0; + dstBox.y2 -= pScrn->frameY0; + + switch(id) { + case FOURCC_YV12: + case FOURCC_I420: + srcPitch = (width + 3) & ~3; + dstPitch = ((width >> 1) + 7) & ~7; /* of chroma */ + size = dstPitch * height * 3; + break; + case FOURCC_UYVY: + case FOURCC_YUY2: + default: + srcPitch = (width << 1); + dstPitch = (srcPitch + 7) & ~7; + size = dstPitch * height; + break; + } + + if(!(pPriv->linear = I810AllocateMemory(pScrn, pPriv->linear, + (pScrn->bitsPerPixel == 16) ? size : (size >> 1)))) + return BadAlloc; + + /* fixup pointers */ + pPriv->YBuf0offset = pPriv->linear->offset * pI810->cpp; + pPriv->UBuf0offset = pPriv->YBuf0offset + (dstPitch * 2 * height); + pPriv->VBuf0offset = pPriv->UBuf0offset + (dstPitch * height >> 1); + + pPriv->YBuf1offset = (pPriv->linear->offset * pI810->cpp) + size; + pPriv->UBuf1offset = pPriv->YBuf1offset + (dstPitch * 2 * height); + pPriv->VBuf1offset = pPriv->UBuf1offset + (dstPitch * height >> 1); + + + /* Make sure this buffer isn't in use */ + loops = 0; + while (loops < 1000000) { + if(((INREG(DOV0STA)&0x00100000)>>20) == pPriv->currentBuf) { + break; + } + loops++; + } + if(loops >= 1000000) { + pPriv->currentBuf = !pPriv->currentBuf; + } + + + /* buffer swap */ + if (pPriv->currentBuf == 0) + pPriv->currentBuf = 1; + else + pPriv->currentBuf = 0; + + /* copy data */ + top = y1 >> 16; + left = (x1 >> 16) & ~1; + npixels = ((((x2 + 0xffff) >> 16) + 1) & ~1) - left; + + switch(id) { + case FOURCC_YV12: + case FOURCC_I420: + top &= ~1; + nlines = ((((y2 + 0xffff) >> 16) + 1) & ~1) - top; + I810CopyPlanarData(pScrn, buf, srcPitch, dstPitch, height, top, left, + nlines, npixels, id); + break; + case FOURCC_UYVY: + case FOURCC_YUY2: + default: + nlines = ((y2 + 0xffff) >> 16) - top; + I810CopyPackedData(pScrn, buf, srcPitch, dstPitch, top, left, nlines, + npixels); + break; + } + + /* update cliplist */ + if(!RegionsEqual(&pPriv->clip, clipBoxes)) { + REGION_COPY(pScreen, &pPriv->clip, clipBoxes); + /* draw these */ + XAAFillSolidRects(pScrn, pPriv->colorKey, GXcopy, ~0, + REGION_NUM_RECTS(clipBoxes), + REGION_RECTS(clipBoxes)); + } + + + I810DisplayVideo(pScrn, id, width, height, dstPitch, + x1, y1, x2, y2, &dstBox, src_w, src_h, drw_w, drw_h); + + pPriv->videoStatus = CLIENT_VIDEO_ON; + + return Success; +} + + +static int +I810QueryImageAttributes( + ScrnInfoPtr pScrn, + int id, + unsigned short *w, unsigned short *h, + int *pitches, int *offsets +){ + int size, tmp; + + if(*w > IMAGE_MAX_WIDTH) *w = IMAGE_MAX_WIDTH; + if(*h > IMAGE_MAX_HEIGHT) *h = IMAGE_MAX_HEIGHT; + + *w = (*w + 1) & ~1; + if(offsets) offsets[0] = 0; + + switch(id) { + /* IA44 is for XvMC only */ + case FOURCC_IA44: + case FOURCC_AI44: + if(pitches) pitches[0] = *w; + size = *w * *h; + break; + case FOURCC_YV12: + case FOURCC_I420: + *h = (*h + 1) & ~1; + size = (*w + 3) & ~3; + if(pitches) pitches[0] = size; + size *= *h; + if(offsets) offsets[1] = size; + tmp = ((*w >> 1) + 3) & ~3; + if(pitches) pitches[1] = pitches[2] = tmp; + tmp *= (*h >> 1); + size += tmp; + if(offsets) offsets[2] = size; + size += tmp; + break; + case FOURCC_UYVY: + case FOURCC_YUY2: + default: + size = *w << 1; + if(pitches) pitches[0] = size; + size *= *h; + break; + } + + return size; +} + +static void +I810BlockHandler ( + int i, + pointer blockData, + pointer pTimeout, + pointer pReadmask +){ + ScreenPtr pScreen = screenInfo.screens[i]; + ScrnInfoPtr pScrn = xf86Screens[i]; + I810Ptr pI810 = I810PTR(pScrn); + I810PortPrivPtr pPriv = GET_PORT_PRIVATE(pScrn); + I810OverlayRegPtr overlay = (I810OverlayRegPtr) (pI810->FbBase + pI810->OverlayStart); + + pScreen->BlockHandler = pI810->BlockHandler; + + (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask); + + pScreen->BlockHandler = I810BlockHandler; + + if(pPriv->videoStatus & TIMER_MASK) { + UpdateCurrentTime(); + if(pPriv->videoStatus & OFF_TIMER) { + if(pPriv->offTime < currentTime.milliseconds) { + /* Turn off the overlay */ + overlay->OV0CMD &= 0xFFFFFFFE; + OVERLAY_UPDATE(pI810->OverlayPhysical); + + pPriv->videoStatus = FREE_TIMER; + pPriv->freeTime = currentTime.milliseconds + FREE_DELAY; + } + } else { /* FREE_TIMER */ + if(pPriv->freeTime < currentTime.milliseconds) { + if(pPriv->linear) { + xf86FreeOffscreenLinear(pPriv->linear); + pPriv->linear = NULL; + } + pPriv->videoStatus = 0; + } + } + } +} + + +/*************************************************************************** + * Offscreen Images + ***************************************************************************/ + +typedef struct { + FBLinearPtr linear; + Bool isOn; +} OffscreenPrivRec, * OffscreenPrivPtr; + +static int +I810AllocateSurface( + ScrnInfoPtr pScrn, + int id, + unsigned short w, + unsigned short h, + XF86SurfacePtr surface +){ + FBLinearPtr linear; + int pitch, fbpitch, size, bpp; + OffscreenPrivPtr pPriv; + I810Ptr pI810 = I810PTR(pScrn); + + if((w > 1024) || (h > 1024)) + return BadAlloc; + + w = (w + 1) & ~1; + pitch = ((w << 1) + 15) & ~15; + bpp = pScrn->bitsPerPixel >> 3; + fbpitch = bpp * pScrn->displayWidth; + size = ((pitch * h) + bpp - 1) / bpp; + + if(!(linear = I810AllocateMemory(pScrn, NULL, size))) + return BadAlloc; + + surface->width = w; + surface->height = h; + + if(!(surface->pitches = xalloc(sizeof(int)))) { + xf86FreeOffscreenLinear(linear); + return BadAlloc; + } + if(!(surface->offsets = xalloc(sizeof(int)))) { + xfree(surface->pitches); + xf86FreeOffscreenLinear(linear); + return BadAlloc; + } + if(!(pPriv = xalloc(sizeof(OffscreenPrivRec)))) { + xfree(surface->pitches); + xfree(surface->offsets); + xf86FreeOffscreenLinear(linear); + return BadAlloc; + } + + pPriv->linear = linear; + pPriv->isOn = FALSE; + + surface->pScrn = pScrn; + surface->id = id; + surface->pitches[0] = pitch; + surface->offsets[0] = linear->offset * bpp; + surface->devPrivate.ptr = (pointer)pPriv; + + memset(pI810->FbBase + surface->offsets[0],0,size); + + return Success; +} + +static int +I810StopSurface( + XF86SurfacePtr surface +){ + OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr; + + if(pPriv->isOn) { + I810Ptr pI810 = I810PTR(surface->pScrn); + + I810OverlayRegPtr overlay = (I810OverlayRegPtr) (pI810->FbBase + pI810->OverlayStart); + + overlay->OV0CMD &= 0xFFFFFFFE; + OVERLAY_UPDATE(pI810->OverlayPhysical); + + pPriv->isOn = FALSE; + } + + return Success; +} + + +static int +I810FreeSurface( + XF86SurfacePtr surface +){ + OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr; + + if(pPriv->isOn) { + I810StopSurface(surface); + } + xf86FreeOffscreenLinear(pPriv->linear); + xfree(surface->pitches); + xfree(surface->offsets); + xfree(surface->devPrivate.ptr); + + return Success; +} + +static int +I810GetSurfaceAttribute( + ScrnInfoPtr pScrn, + Atom attribute, + INT32 *value +){ + return I810GetPortAttribute(pScrn, attribute, value, 0); +} + +static int +I810SetSurfaceAttribute( + ScrnInfoPtr pScrn, + Atom attribute, + INT32 value +){ + return I810SetPortAttribute(pScrn, attribute, value, 0); +} + + +static int +I810DisplaySurface( + XF86SurfacePtr surface, + short src_x, short src_y, + short drw_x, short drw_y, + short src_w, short src_h, + short drw_w, short drw_h, + RegionPtr clipBoxes +){ + OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr; + ScrnInfoPtr pScrn = surface->pScrn; + I810Ptr pI810 = I810PTR(pScrn); + I810PortPrivPtr pI810Priv = GET_PORT_PRIVATE(pScrn); + + INT32 x1, y1, x2, y2; + INT32 loops = 0; + BoxRec dstBox; + + x1 = src_x; + x2 = src_x + src_w; + y1 = src_y; + y2 = src_y + src_h; + + dstBox.x1 = drw_x; + dstBox.x2 = drw_x + drw_w; + dstBox.y1 = drw_y; + dstBox.y2 = drw_y + drw_h; + + I810ClipVideo(&dstBox, &x1, &x2, &y1, &y2, + REGION_EXTENTS(screenInfo.screens[0], clipBoxes), + surface->width, surface->height); + + dstBox.x1 -= pScrn->frameX0; + dstBox.x2 -= pScrn->frameX0; + dstBox.y1 -= pScrn->frameY0; + dstBox.y2 -= pScrn->frameY0; + + /* fixup pointers */ + pI810Priv->YBuf0offset = surface->offsets[0]; + pI810Priv->YBuf1offset = pI810Priv->YBuf0offset; + + /* wait for the last rendered buffer to be flipped in */ + while (((INREG(DOV0STA)&0x00100000)>>20) != pI810Priv->currentBuf) { + if(loops == 200000) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Overlay Lockup\n"); + break; + } + loops++; + } + + /* buffer swap */ + if (pI810Priv->currentBuf == 0) + pI810Priv->currentBuf = 1; + else + pI810Priv->currentBuf = 0; + + I810ResetVideo(pScrn); + + I810DisplayVideo(pScrn, surface->id, surface->width, surface->height, + surface->pitches[0], x1, y1, x2, y2, &dstBox, + src_w, src_h, drw_w, drw_h); + + XAAFillSolidRects(pScrn, pI810Priv->colorKey, GXcopy, ~0, + REGION_NUM_RECTS(clipBoxes), + REGION_RECTS(clipBoxes)); + + pPriv->isOn = TRUE; + /* we've prempted the XvImage stream so set its free timer */ + if(pI810Priv->videoStatus & CLIENT_VIDEO_ON) { + REGION_EMPTY(pScrn->pScreen, & pI810Priv->clip); + UpdateCurrentTime(); + pI810Priv->videoStatus = FREE_TIMER; + pI810Priv->freeTime = currentTime.milliseconds + FREE_DELAY; + pScrn->pScreen->BlockHandler = I810BlockHandler; + } + + return Success; +} + + +static void +I810InitOffscreenImages(ScreenPtr pScreen) +{ + XF86OffscreenImagePtr offscreenImages; + + /* need to free this someplace */ + if(!(offscreenImages = xalloc(sizeof(XF86OffscreenImageRec)))) { + return; + } + + offscreenImages[0].image = &Images[0]; + offscreenImages[0].flags = VIDEO_OVERLAID_IMAGES | + VIDEO_CLIP_TO_VIEWPORT; + offscreenImages[0].alloc_surface = I810AllocateSurface; + offscreenImages[0].free_surface = I810FreeSurface; + offscreenImages[0].display = I810DisplaySurface; + offscreenImages[0].stop = I810StopSurface; + offscreenImages[0].setAttribute = I810SetSurfaceAttribute; + offscreenImages[0].getAttribute = I810GetSurfaceAttribute; + offscreenImages[0].max_width = 1024; + offscreenImages[0].max_height = 1024; + offscreenImages[0].num_attributes = 1; + offscreenImages[0].attributes = Attributes; + + xf86XVRegisterOffscreenImages(pScreen, offscreenImages, 1); +} + diff --git a/src/i810_wmark.c b/src/i810_wmark.c new file mode 100644 index 00000000..9a6bdd34 --- /dev/null +++ b/src/i810_wmark.c @@ -0,0 +1,321 @@ + +/************************************************************************** + +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sub license, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice (including the +next paragraph) shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i810/i810_wmark.c,v 1.8 2002/10/30 12:52:18 alanh Exp $ */ + +/* + * Reformatted with GNU indent (2.2.8), using the following options: + * + * -bad -bap -c41 -cd0 -ncdb -ci6 -cli0 -cp0 -ncs -d0 -di3 -i3 -ip3 -l78 + * -lp -npcs -psl -sob -ss -br -ce -sc -hnl + * + * This provides a good match with the original i810 code and preferred + * XFree86 formatting conventions. + * + * When editing this driver, please follow the existing formatting, and edit + * with <TAB> characters expanded at 8-column intervals. + */ + +/* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + */ + +#include "xf86.h" +#include "i810.h" + +struct wm_info { + double freq; + unsigned int wm; +}; + +struct wm_info i810_wm_8_100[] = { + {0, 0x22003000}, + {25.2, 0x22003000}, + {28.0, 0x22003000}, + {31.5, 0x22003000}, + {36.0, 0x22007000}, + {40.0, 0x22007000}, + {45.0, 0x22007000}, + {49.5, 0x22008000}, + {50.0, 0x22008000}, + {56.3, 0x22008000}, + {65.0, 0x22008000}, + {75.0, 0x22008000}, + {78.8, 0x22008000}, + {80.0, 0x22008000}, + {94.0, 0x22008000}, + {96.0, 0x22107000}, + {99.0, 0x22107000}, + {108.0, 0x22107000}, + {121.0, 0x22107000}, + {128.9, 0x22107000}, + {132.0, 0x22109000}, + {135.0, 0x22109000}, + {157.5, 0x2210b000}, + {162.0, 0x2210b000}, + {175.5, 0x2210b000}, + {189.0, 0x2220e000}, + {202.5, 0x2220e000} +}; + +struct wm_info i810_wm_16_100[] = { + {0, 0x22004000}, + {25.2, 0x22006000}, + {28.0, 0x22006000}, + {31.5, 0x22007000}, + {36.0, 0x22007000}, + {40.0, 0x22007000}, + {45.0, 0x22007000}, + {49.5, 0x22009000}, + {50.0, 0x22009000}, + {56.3, 0x22108000}, + {65.0, 0x2210e000}, + {75.0, 0x2210e000}, + {78.8, 0x2210e000}, + {80.0, 0x22210000}, + {94.5, 0x22210000}, + {96.0, 0x22210000}, + {99.0, 0x22210000}, + {108.0, 0x22210000}, + {121.0, 0x22210000}, + {128.9, 0x22210000}, + {132.0, 0x22314000}, + {135.0, 0x22314000}, + {157.5, 0x22415000}, + {162.0, 0x22416000}, + {175.5, 0x22416000}, + {189.0, 0x22416000}, + {195.0, 0x22416000}, + {202.5, 0x22416000} +}; + +struct wm_info i810_wm_24_100[] = { + {0, 0x22006000}, + {25.2, 0x22009000}, + {28.0, 0x22009000}, + {31.5, 0x2200a000}, + {36.0, 0x2210c000}, + {40.0, 0x2210c000}, + {45.0, 0x2210c000}, + {49.5, 0x22111000}, + {50.0, 0x22111000}, + {56.3, 0x22111000}, + {65.0, 0x22214000}, + {75.0, 0x22214000}, + {78.8, 0x22215000}, + {80.0, 0x22216000}, + {94.5, 0x22218000}, + {96.0, 0x22418000}, + {99.0, 0x22418000}, + {108.0, 0x22418000}, + {121.0, 0x22418000}, + {128.9, 0x22419000}, + {132.0, 0x22519000}, + {135.0, 0x4441d000}, + {157.5, 0x44419000}, + {162.0, 0x44419000}, + {175.5, 0x44419000}, + {189.0, 0x44419000}, + {195.0, 0x44419000}, + {202.5, 0x44419000} +}; + +struct wm_info i810_wm_32_100[] = { + {0, 0x2210b000}, + {60, 0x22415000}, /* 0x314000 works too */ + {80, 0x22419000} /* 0x518000 works too */ +}; + +struct wm_info i810_wm_8_133[] = { + {0, 0x22003000}, + {25.2, 0x22003000}, + {28.0, 0x22003000}, + {31.5, 0x22003000}, + {36.0, 0x22007000}, + {40.0, 0x22007000}, + {45.0, 0x22007000}, + {49.5, 0x22008000}, + {50.0, 0x22008000}, + {56.3, 0x22008000}, + {65.0, 0x22008000}, + {75.0, 0x22008000}, + {78.8, 0x22008000}, + {80.0, 0x22008000}, + {94.0, 0x22008000}, + {96.0, 0x22107000}, + {99.0, 0x22107000}, + {108.0, 0x22107000}, + {121.0, 0x22107000}, + {128.9, 0x22107000}, + {132.0, 0x22109000}, + {135.0, 0x22109000}, + {157.5, 0x2210b000}, + {162.0, 0x2210b000}, + {175.5, 0x2210b000}, + {189.0, 0x2220e000}, + {202.5, 0x2220e000} +}; + +struct wm_info i810_wm_16_133[] = { + {0, 0x22004000}, + {25.2, 0x22006000}, + {28.0, 0x22006000}, + {31.5, 0x22007000}, + {36.0, 0x22007000}, + {40.0, 0x22007000}, + {45.0, 0x22007000}, + {49.5, 0x22009000}, + {50.0, 0x22009000}, + {56.3, 0x22108000}, + {65.0, 0x2210e000}, + {75.0, 0x2210e000}, + {78.8, 0x2210e000}, + {80.0, 0x22210000}, + {94.5, 0x22210000}, + {96.0, 0x22210000}, + {99.0, 0x22210000}, + {108.0, 0x22210000}, + {121.0, 0x22210000}, + {128.9, 0x22210000}, + {132.0, 0x22314000}, + {135.0, 0x22314000}, + {157.5, 0x22415000}, + {162.0, 0x22416000}, + {175.5, 0x22416000}, + {189.0, 0x22416000}, + {195.0, 0x22416000}, + {202.5, 0x22416000} +}; + +struct wm_info i810_wm_24_133[] = { + {0, 0x22006000}, + {25.2, 0x22009000}, + {28.0, 0x22009000}, + {31.5, 0x2200a000}, + {36.0, 0x2210c000}, + {40.0, 0x2210c000}, + {45.0, 0x2210c000}, + {49.5, 0x22111000}, + {50.0, 0x22111000}, + {56.3, 0x22111000}, + {65.0, 0x22214000}, + {75.0, 0x22214000}, + {78.8, 0x22215000}, + {80.0, 0x22216000}, + {94.5, 0x22218000}, + {96.0, 0x22418000}, + {99.0, 0x22418000}, + {108.0, 0x22418000}, + {121.0, 0x22418000}, + {128.9, 0x22419000}, + {132.0, 0x22519000}, + {135.0, 0x4441d000}, + {157.5, 0x44419000}, + {162.0, 0x44419000}, + {175.5, 0x44419000}, + {189.0, 0x44419000}, + {195.0, 0x44419000}, + {202.5, 0x44419000} +}; + +#define Elements(x) (sizeof(x)/sizeof(*x)) + +/* + * I810CalcFIFO -- + * + * Calculate burst length and FIFO watermark. + */ + +unsigned int +I810CalcWatermark(ScrnInfoPtr pScrn, double freq, Bool dcache) +{ + I810Ptr pI810 = I810PTR(pScrn); + struct wm_info *tab; + int nr; + int i; + + if (pI810->LmFreqSel == 100) { + switch (pScrn->bitsPerPixel) { + case 8: + tab = i810_wm_8_100; + nr = Elements(i810_wm_8_100); + break; + case 16: + tab = i810_wm_16_100; + nr = Elements(i810_wm_16_100); + break; + case 24: + tab = i810_wm_24_100; + nr = Elements(i810_wm_24_100); + break; + default: + return 0; + } + } else { + switch (pScrn->bitsPerPixel) { + case 8: + tab = i810_wm_8_133; + nr = Elements(i810_wm_8_133); + break; + case 16: + tab = i810_wm_16_133; + nr = Elements(i810_wm_16_133); + break; + case 24: + tab = i810_wm_24_133; + nr = Elements(i810_wm_24_133); + break; + default: + return 0; + } + } + + for (i = 0; i < nr && tab[i].freq < freq; i++) ; + + if (i == nr) + i--; + + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, + "chose watermark 0x%x: (tab.freq %.1f)\n", + tab[i].wm, tab[i].freq); + + /* None of these values (sourced from intel) have watermarks for + * the dcache memory. Fake it for now by using the same watermark + * for both... + * + * Update: this is probably because dcache isn't real useful as + * framebuffer memory, so intel's drivers don't need watermarks + * for that memory because they never use it to feed the ramdacs. + * We do use it in the fallback mode, so keep the watermarks for + * now. + */ + if (dcache) + return (tab[i].wm & ~0xffffff) | ((tab[i].wm >> 12) & 0xfff); + else + return tab[i].wm; +} diff --git a/src/i830.h b/src/i830.h new file mode 100644 index 00000000..e141931a --- /dev/null +++ b/src/i830.h @@ -0,0 +1,395 @@ + +/************************************************************************** + +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +Copyright © 2002 David Dawes + +All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sub license, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice (including the +next paragraph) shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i810/i830.h,v 1.7 2003/01/28 22:47:09 dawes Exp $ */ + +/* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + * David Dawes <dawes@tungstengraphics.com> + * + */ + +#if 0 +#define I830DEBUG +#endif + +#ifndef REMAP_RESERVED +#define REMAP_RESERVED 0 +#endif + +#ifndef _I830_H_ +#define _I830_H_ + +#include "xf86_ansic.h" +#include "compiler.h" +#include "xf86PciInfo.h" +#include "xf86Pci.h" +#include "i810_reg.h" +#include "xaa.h" +#include "xf86Cursor.h" +#include "xf86xv.h" +#include "xf86int10.h" +#include "vbe.h" +#include "vgaHW.h" + +#ifdef XF86DRI +#include "xf86drm.h" +#include "sarea.h" +#define _XF86DRI_SERVER_ +#include "xf86dri.h" +#include "dri.h" +#include "GL/glxint.h" +#include "i830_dri.h" +#endif + +#include "common.h" + +/* I830 Video BIOS support */ + +/* + * The mode handling is based upon the VESA driver written by + * Paulo César Pereira de Andrade <pcpa@conectiva.com.br>. + */ + +typedef struct _VESARec { + /* SVGA state */ + pointer state, pstate; + int statePage, stateSize, stateMode; + CARD32 *savedPal; + int savedScanlinePitch; + xf86MonPtr monitor; + /* Don't try to set the refresh rate for any modes. */ + Bool useDefaultRefresh; +} VESARec, *VESAPtr; + + +typedef struct _I830Rec *I830Ptr; + +typedef void (*I830WriteIndexedByteFunc)(I830Ptr pI830, IOADDRESS addr, + CARD8 index, CARD8 value); +typedef CARD8(*I830ReadIndexedByteFunc)(I830Ptr pI830, IOADDRESS addr, + CARD8 index); +typedef void (*I830WriteByteFunc)(I830Ptr pI830, IOADDRESS addr, CARD8 value); +typedef CARD8(*I830ReadByteFunc)(I830Ptr pI830, IOADDRESS addr); + +/* Linear region allocated in framebuffer. */ +typedef struct _I830MemPool *I830MemPoolPtr; +typedef struct _I830MemRange *I830MemRangePtr; +typedef struct _I830MemRange { + long Start; + long End; + long Size; + unsigned long Physical; + unsigned long Offset; /* Offset of AGP-allocated portion */ + unsigned long Alignment; + int Key; + I830MemPoolPtr Pool; +} I830MemRange; + +typedef struct _I830MemPool { + I830MemRange Total; + I830MemRange Free; + I830MemRange Fixed; + I830MemRange Allocated; +} I830MemPool; + +typedef struct { + int tail_mask; + I830MemRange mem; + unsigned char *virtual_start; + int head; + int tail; + int space; +} I830RingBuffer; + +typedef struct { + unsigned int Fence[8]; +} I830RegRec, *I830RegPtr; + +typedef struct _I830Rec { + unsigned char *MMIOBase; + unsigned char *FbBase; + int cpp; + + unsigned int bufferOffset; /* for I830SelectBuffer */ + BoxRec FbMemBox; + int CacheLines; + + /* These are set in PreInit and never changed. */ + unsigned long FbMapSize; + unsigned long TotalVideoRam; + I830MemRange StolenMemory; /* pre-allocated memory */ + unsigned long BIOSMemorySize; /* min stolen pool size */ + + /* These change according to what has been allocated. */ + long FreeMemory; + I830MemRange MemoryAperture; + I830MemPool StolenPool; + unsigned long allocatedMemory; + + /* Regions allocated either from the above pools, or from agpgart. */ + I830MemRange FrontBuffer; + I830MemRange CursorMem; + I830RingBuffer LpRing; + I830MemRange Scratch; + +#if REMAP_RESERVED + I830MemRange Dummy; +#endif + +#ifdef I830_XV + /* For Xvideo */ + I830MemRange OverlayMem; +#endif + +#ifdef XF86DRI + I830MemRange BackBuffer; + I830MemRange DepthBuffer; + I830MemRange TexMem; + I830MemRange BufferMem; + I830MemRange ContextMem; + int TexGranularity; + int drmMinor; + Bool have3DWindows; +#endif + + Bool NeedRingBufferLow; + Bool allowPageFlip; + + int auxPitch; + int auxPitchBits; + + Bool CursorNeedsPhysical; + + DGAModePtr DGAModes; + int numDGAModes; + Bool DGAactive; + int DGAViewportStatus; + + int Chipset; + unsigned long LinearAddr; + unsigned long MMIOAddr; + IOADDRESS ioBase; + EntityInfoPtr pEnt; + pciVideoPtr PciInfo; + PCITAG PciTag; + CARD8 variant; + + unsigned int BR[20]; + + int GttBound; + + unsigned char **ScanlineColorExpandBuffers; + int NumScanlineColorExpandBuffers; + int nextColorExpandBuf; + + I830RegRec SavedReg; + I830RegRec ModeReg; + + Bool noAccel; + Bool SWCursor; + Bool cursorOn; + XAAInfoRecPtr AccelInfoRec; + xf86CursorInfoPtr CursorInfoRec; + CloseScreenProcPtr CloseScreen; + ScreenBlockHandlerProcPtr BlockHandler; + + I830WriteIndexedByteFunc writeControl; + I830ReadIndexedByteFunc readControl; + I830WriteByteFunc writeStandard; + I830ReadByteFunc readStandard; + + Bool XvDisabled; /* Xv disabled in PreInit. */ + Bool XvEnabled; /* Xv enabled for this generation. */ + +#ifdef I830_XV + int colorKey; + XF86VideoAdaptorPtr adaptor; + Bool overlayOn; +#endif + + Bool directRenderingDisabled; /* DRI disabled in PreInit. */ + Bool directRenderingEnabled; /* DRI enabled this generation. */ + +#ifdef XF86DRI + Bool directRenderingOpen; + int LockHeld; + DRIInfoPtr pDRIInfo; + int drmSubFD; + int numVisualConfigs; + __GLXvisualConfig *pVisualConfigs; + I830ConfigPrivPtr pVisualConfigsPriv; + drmHandle buffer_map; + drmHandle ring_map; +#endif + + OptionInfoPtr Options; + + /* Stolen memory support */ + Bool StolenOnly; + + /* Video BIOS support. */ + vbeInfoPtr pVbe; + VbeInfoBlock *vbeInfo; + VESAPtr vesa; + + Bool overrideBIOSMemSize; + int saveBIOSMemSize; + int newBIOSMemSize; + Bool useSWF1; + int saveSWF1; + + Bool swfSaved; + CARD32 saveSWF0; + CARD32 saveSWF4; + + /* Use BIOS call 0x5f64 to explicitly enable displays. */ + Bool enableDisplays; + /* Use BIOS call 0x5f05 to set the refresh rate. */ + Bool useExtendedRefresh; + + int configuredDevices; + + /* These are indexed by the display types */ + Bool displayAttached[NumDisplayTypes]; + Bool displayPresent[NumDisplayTypes]; + BoxRec displaySize[NumDisplayTypes]; + + /* [0] is Pipe A, [1] is Pipe B. */ + int availablePipes; + int pipeDevices[MAX_DISPLAY_PIPES]; + /* [0] is display plane A, [1] is display plane B. */ + Bool pipeEnabled[MAX_DISPLAY_PIPES]; + BoxRec pipeDisplaySize[MAX_DISPLAY_PIPES]; + int planeEnabled[MAX_DISPLAY_PIPES]; + + /* Driver phase/state information */ + Bool starting; + Bool closing; + Bool suspended; + +} I830Rec; + +#define I830PTR(p) ((I830Ptr)((p)->driverPrivate)) +#define I830REGPTR(p) (&(I830PTR(p)->ModeReg)) + +#define I830_SELECT_FRONT 0 +#define I830_SELECT_BACK 1 +#define I830_SELECT_DEPTH 2 + +/* I830 specific functions */ +extern int I830WaitLpRing(ScrnInfoPtr pScrn, int n, int timeout_millis); +extern void I830SetPIOAccess(I830Ptr pI830); +extern void I830SetMMIOAccess(I830Ptr pI830); +extern void I830PrintErrorState(ScrnInfoPtr pScrn); +extern void I830Sync(ScrnInfoPtr pScrn); +extern void I830InitHWCursor(ScrnInfoPtr pScrn); +extern Bool I830CursorInit(ScreenPtr pScreen); +extern void I830EmitInvarientState(ScrnInfoPtr pScrn); +extern void I830SelectBuffer(ScrnInfoPtr pScrn, int buffer); + +extern void I830RefreshRing(ScrnInfoPtr pScrn); +extern void I830EmitFlush(ScrnInfoPtr pScrn); + +extern Bool I830DGAInit(ScreenPtr pScreen); + +#ifdef I830_XV +extern void I830InitVideo(ScreenPtr pScreen); +extern void I830VideoSwitchModeBefore(ScrnInfoPtr pScrn, DisplayModePtr mode); +extern void I830VideoSwitchModeAfter(ScrnInfoPtr pScrn, DisplayModePtr mode); +#endif + +#ifdef XF86DRI +extern Bool I830Allocate3DMemory(ScrnInfoPtr pScrn, const int flags); +extern void I830SetupMemoryTiling(ScrnInfoPtr pScrn); +extern Bool I830DRIScreenInit(ScreenPtr pScreen); +extern Bool I830DRIDoMappings(ScreenPtr pScreen); +extern void I830DRICloseScreen(ScreenPtr pScreen); +extern Bool I830DRIFinishScreenInit(ScreenPtr pScreen); +#endif +extern Bool I830AccelInit(ScreenPtr pScreen); +extern void I830SetupForScreenToScreenCopy(ScrnInfoPtr pScrn, int xdir, + int ydir, int rop, + unsigned int planemask, + int trans_color); +extern void I830SubsequentScreenToScreenCopy(ScrnInfoPtr pScrn, int srcX, + int srcY, int dstX, int dstY, + int w, int h); +extern void I830SetupForSolidFill(ScrnInfoPtr pScrn, int color, int rop, + unsigned int planemask); +extern void I830SubsequentSolidFillRect(ScrnInfoPtr pScrn, int x, int y, + int w, int h); + +extern void I830ResetAllocations(ScrnInfoPtr pScrn, const int flags); +extern long I830CheckAvailableMemory(ScrnInfoPtr pScrn); +extern long I830GetExcessMemoryAllocations(ScrnInfoPtr pScrn); +extern Bool I830Allocate2DMemory(ScrnInfoPtr pScrn, const int flags); +extern Bool I830DoPoolAllocation(ScrnInfoPtr pScrn, I830MemPool *pool); +extern Bool I830FixupOffsets(ScrnInfoPtr pScrn); +extern Bool I830BindGARTMemory(ScrnInfoPtr pScrn); +extern Bool I830UnbindGARTMemory(ScrnInfoPtr pScrn); +extern unsigned long I830AllocVidMem(ScrnInfoPtr pScrn, I830MemRange *result, + I830MemPool *pool, unsigned long size, + unsigned long alignment, int flags); + +extern void I830PrintAllRegisters(I830RegPtr i830Reg); +extern void I830ReadAllRegisters(I830Ptr pI830, I830RegPtr i830Reg); + +extern void I830ChangeFrontbuffer(ScrnInfoPtr pScrn,int buffer); + +/* + * 12288 is set as the maximum, chosen because it is enough for + * 1920x1440@32bpp with a 2048 pixel line pitch with some to spare. + */ +#define I830_MAXIMUM_VBIOS_MEM 12288 +#define I830_DEFAULT_VIDEOMEM_2D (MB(8) / 1024) +#define I830_DEFAULT_VIDEOMEM_3D (MB(32) / 1024) + +/* Flags for memory allocation function */ +#define FROM_ANYWHERE 0x00000000 +#define FROM_POOL_ONLY 0x00000001 +#define FROM_NEW_ONLY 0x00000002 +#define FROM_MASK 0x0000000f + +#define ALLOCATE_AT_TOP 0x00000010 +#define ALLOCATE_AT_BOTTOM 0x00000020 +#define FORCE_GAPS 0x00000040 + +#define NEED_PHYSICAL_ADDR 0x00000100 +#define ALIGN_BOTH_ENDS 0x00000200 +#define FORCE_LOW 0x00000400 + +#define ALLOC_NO_TILING 0x00001000 +#define ALLOC_INITIAL 0x00002000 + +#define ALLOCATE_DRY_RUN 0x80000000 + + +#endif /* _I830_H_ */ diff --git a/src/i830_accel.c b/src/i830_accel.c new file mode 100644 index 00000000..1a071497 --- /dev/null +++ b/src/i830_accel.c @@ -0,0 +1,770 @@ +/* + * XXX So far, for GXxor this is about 40% of the speed of SW, but CPU + * utilisation falls from 95% to < 5%. + */ +#ifndef DO_SCANLINE_IMAGE_WRITE +#define DO_SCANLINE_IMAGE_WRITE 0 +#endif + +/************************************************************************** + +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sub license, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice (including the +next paragraph) shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i810/i830_accel.c,v 1.4 2002/12/10 01:27:05 dawes Exp $ */ + +/* + * Reformatted with GNU indent (2.2.8), using the following options: + * + * -bad -bap -c41 -cd0 -ncdb -ci6 -cli0 -cp0 -ncs -d0 -di3 -i3 -ip3 -l78 + * -lp -npcs -psl -sob -ss -br -ce -sc -hnl + * + * This provides a good match with the original i810 code and preferred + * XFree86 formatting conventions. + * + * When editing this driver, please follow the existing formatting, and edit + * with <TAB> characters expanded at 8-column intervals. + */ + +/* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + * + */ + +#include "xf86_ansic.h" +#include "xf86.h" + +#include "i830.h" +#include "i810_reg.h" + +static unsigned int i810Rop[16] = { + 0x00, /* GXclear */ + 0x88, /* GXand */ + 0x44, /* GXandReverse */ + 0xCC, /* GXcopy */ + 0x22, /* GXandInvert */ + 0xAA, /* GXnoop */ + 0x66, /* GXxor */ + 0xEE, /* GXor */ + 0x11, /* GXnor */ + 0x99, /* GXequiv */ + 0x55, /* GXinvert */ + 0xDD, /* GXorReverse */ + 0x33, /* GXcopyInvert */ + 0xBB, /* GXorInverted */ + 0x77, /* GXnand */ + 0xFF /* GXset */ +}; + +static unsigned int i810PatternRop[16] = { + 0x00, /* GXclear */ + 0xA0, /* GXand */ + 0x50, /* GXandReverse */ + 0xF0, /* GXcopy */ + 0x0A, /* GXandInvert */ + 0xAA, /* GXnoop */ + 0x5A, /* GXxor */ + 0xFA, /* GXor */ + 0x05, /* GXnor */ + 0xA5, /* GXequiv */ + 0x55, /* GXinvert */ + 0xF5, /* GXorReverse */ + 0x0F, /* GXcopyInvert */ + 0xAF, /* GXorInverted */ + 0x5F, /* GXnand */ + 0xFF /* GXset */ +}; + +int +I830WaitLpRing(ScrnInfoPtr pScrn, int n, int timeout_millis) +{ + I830Ptr pI830 = I830PTR(pScrn); + I830RingBuffer *ring = &(pI830->LpRing); + int iters = 0; + int start = 0; + int now = 0; + int last_head = 0; + int first = 0; + + /* If your system hasn't moved the head pointer in 2 seconds, I'm going to + * call it crashed. + */ + if (timeout_millis == 0) + timeout_millis = 2000; + + if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) { + ErrorF("I830WaitLpRing %d\n", n); + first = GetTimeInMillis(); + } + + while (ring->space < n) { + ring->head = INREG(LP_RING + RING_HEAD) & I830_HEAD_MASK; + ring->space = ring->head - (ring->tail + 8); + + if (ring->space < 0) + ring->space += ring->mem.Size; + + iters++; + now = GetTimeInMillis(); + if (start == 0 || now < start || ring->head != last_head) { + if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) + if (now > start) + ErrorF("space: %d wanted %d\n", ring->space, n); + start = now; + last_head = ring->head; + } else if (now - start > timeout_millis) { + ErrorF("Error in I830WaitLpRing(), now is %d, start is %d\n", now, + start); + I830PrintErrorState(pScrn); + ErrorF("space: %d wanted %d\n", ring->space, n); +#ifdef XF86DRI + if (pI830->directRenderingEnabled) { + DRIUnlock(screenInfo.screens[pScrn->scrnIndex]); + DRICloseScreen(screenInfo.screens[pScrn->scrnIndex]); + } +#endif + pI830->AccelInfoRec = NULL; /* Stops recursive behavior */ + FatalError("lockup\n"); + } + + DELAY(10); + } + + if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) { + now = GetTimeInMillis(); + if (now - first) { + ErrorF("Elapsed %d ms\n", now - first); + ErrorF("space: %d wanted %d\n", ring->space, n); + } + } + + return iters; +} + +void +I830Sync(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + + if (I810_DEBUG & (DEBUG_VERBOSE_ACCEL | DEBUG_VERBOSE_SYNC)) + ErrorF("I830Sync\n"); + +#ifdef XF86DRI + /* VT switching tries to do this. + */ + if (!pI830->LockHeld && pI830->directRenderingEnabled) { + return; + } +#endif + + /* Send a flush instruction and then wait till the ring is empty. + * This is stronger than waiting for the blitter to finish as it also + * flushes the internal graphics caches. + */ + { + BEGIN_LP_RING(2); + OUT_RING(MI_FLUSH | MI_WRITE_DIRTY_STATE | MI_INVALIDATE_MAP_CACHE); + OUT_RING(MI_NOOP); /* pad to quadword */ + ADVANCE_LP_RING(); + } + + I830WaitLpRing(pScrn, pI830->LpRing.mem.Size - 8, 0); + + pI830->LpRing.space = pI830->LpRing.mem.Size - 8; + pI830->nextColorExpandBuf = 0; +} + +void +I830EmitFlush(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + + BEGIN_LP_RING(2); + OUT_RING(MI_FLUSH | MI_WRITE_DIRTY_STATE | MI_INVALIDATE_MAP_CACHE); + OUT_RING(MI_NOOP); /* pad to quadword */ + ADVANCE_LP_RING(); +} + +void +I830SelectBuffer(ScrnInfoPtr pScrn, int buffer) +{ + I830Ptr pI830 = I830PTR(pScrn); + + switch (buffer) { +#ifdef XF86DRI + case I830_SELECT_BACK: + pI830->bufferOffset = pI830->BackBuffer.Start; + break; + case I830_SELECT_DEPTH: + pI830->bufferOffset = pI830->DepthBuffer.Start; + break; +#endif + default: + case I830_SELECT_FRONT: + pI830->bufferOffset = pI830->FrontBuffer.Start; + break; + } + + if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) + ErrorF("I830SelectBuffer %d --> offset %x\n", + buffer, pI830->bufferOffset); +} + +void +I830RefreshRing(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + + pI830->LpRing.head = INREG(LP_RING + RING_HEAD) & I830_HEAD_MASK; + pI830->LpRing.tail = INREG(LP_RING + RING_TAIL); + pI830->LpRing.space = pI830->LpRing.head - (pI830->LpRing.tail + 8); + if (pI830->LpRing.space < 0) + pI830->LpRing.space += pI830->LpRing.mem.Size; + + if (pI830->AccelInfoRec) + pI830->AccelInfoRec->NeedToSync = TRUE; +} + +/* I830 Accel Functions */ + +static void I830SetupForMono8x8PatternFill(ScrnInfoPtr pScrn, + int pattx, int patty, + int fg, int bg, int rop, + unsigned int planemask); +static void I830SubsequentMono8x8PatternFillRect(ScrnInfoPtr pScrn, + int pattx, int patty, + int x, int y, int w, int h); + +static void I830SetupForScanlineCPUToScreenColorExpandFill(ScrnInfoPtr pScrn, + int fg, int bg, + int rop, + unsigned int mask); + +static void I830SubsequentScanlineCPUToScreenColorExpandFill(ScrnInfoPtr + pScrn, int x, + int y, int w, + int h, + int skipleft); + +static void I830SubsequentColorExpandScanline(ScrnInfoPtr pScrn, int bufno); + +#if DO_SCANLINE_IMAGE_WRITE +static void I830SetupForScanlineImageWrite(ScrnInfoPtr pScrn, int rop, + unsigned int planemask, + int trans_color, int bpp, + int depth); +static void I830SubsequentScanlineImageWriteRect(ScrnInfoPtr pScrn, + int x, int y, int w, int h, + int skipleft); +static void I830SubsequentImageWriteScanline(ScrnInfoPtr pScrn, int bufno); +#endif + + +/* The following function sets up the supported acceleration. Call it + * from the FbInit() function in the SVGA driver, or before ScreenInit + * in a monolithic server. + */ +Bool +I830AccelInit(ScreenPtr pScreen) +{ + XAAInfoRecPtr infoPtr; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I830Ptr pI830 = I830PTR(pScrn); + + if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) + ErrorF("I830AccelInit\n"); + + pI830->AccelInfoRec = infoPtr = XAACreateInfoRec(); + if (!infoPtr) + return FALSE; + + pI830->bufferOffset = 0; + infoPtr->Flags = LINEAR_FRAMEBUFFER | OFFSCREEN_PIXMAPS | PIXMAP_CACHE; + + /* Use the same sync function as the I830. + */ + infoPtr->Sync = I830Sync; + + /* Everything else is different enough to justify different functions */ + { + infoPtr->SolidFillFlags = NO_PLANEMASK; + infoPtr->SetupForSolidFill = I830SetupForSolidFill; + infoPtr->SubsequentSolidFillRect = I830SubsequentSolidFillRect; + } + + { + infoPtr->ScreenToScreenCopyFlags = (NO_PLANEMASK | NO_TRANSPARENCY); + + infoPtr->SetupForScreenToScreenCopy = I830SetupForScreenToScreenCopy; + infoPtr->SubsequentScreenToScreenCopy = + I830SubsequentScreenToScreenCopy; + } + + { + infoPtr->SetupForMono8x8PatternFill = I830SetupForMono8x8PatternFill; + infoPtr->SubsequentMono8x8PatternFillRect = + I830SubsequentMono8x8PatternFillRect; + + infoPtr->Mono8x8PatternFillFlags = (HARDWARE_PATTERN_PROGRAMMED_BITS | + HARDWARE_PATTERN_SCREEN_ORIGIN | + HARDWARE_PATTERN_PROGRAMMED_ORIGIN | + BIT_ORDER_IN_BYTE_MSBFIRST | + NO_PLANEMASK); + + } + + if (pI830->Scratch.Size != 0) { + int i; + int width = ((pScrn->displayWidth + 31) & ~31) / 8; + int nr_buffers = pI830->Scratch.Size / width; + unsigned char *ptr = pI830->FbBase + pI830->Scratch.Start; + + pI830->NumScanlineColorExpandBuffers = nr_buffers; + pI830->ScanlineColorExpandBuffers = (unsigned char **) + xnfcalloc(nr_buffers, sizeof(unsigned char *)); + + for (i = 0; i < nr_buffers; i++, ptr += width) + pI830->ScanlineColorExpandBuffers[i] = ptr; + + infoPtr->ScanlineCPUToScreenColorExpandFillFlags = + (NO_PLANEMASK | ROP_NEEDS_SOURCE | BIT_ORDER_IN_BYTE_MSBFIRST); + + infoPtr->ScanlineColorExpandBuffers = (unsigned char **) + xnfcalloc(1, sizeof(unsigned char *)); + infoPtr->NumScanlineColorExpandBuffers = 1; + + infoPtr->ScanlineColorExpandBuffers[0] = + pI830->ScanlineColorExpandBuffers[0]; + pI830->nextColorExpandBuf = 0; + + infoPtr->SetupForScanlineCPUToScreenColorExpandFill = + I830SetupForScanlineCPUToScreenColorExpandFill; + + infoPtr->SubsequentScanlineCPUToScreenColorExpandFill = + I830SubsequentScanlineCPUToScreenColorExpandFill; + + infoPtr->SubsequentColorExpandScanline = + I830SubsequentColorExpandScanline; + +#if DO_SCANLINE_IMAGE_WRITE + infoPtr->NumScanlineImageWriteBuffers = 1; + infoPtr->ScanlineImageWriteBuffers = infoPtr->ScanlineColorExpandBuffers; + infoPtr->SetupForScanlineImageWrite = I830SetupForScanlineImageWrite; + infoPtr->SubsequentScanlineImageWriteRect = + I830SubsequentScanlineImageWriteRect; + infoPtr->SubsequentImageWriteScanline = I830SubsequentImageWriteScanline; + infoPtr->ScanlineImageWriteFlags = NO_GXCOPY | + NO_PLANEMASK | + ROP_NEEDS_SOURCE | + SCANLINE_PAD_DWORD; +#endif + } + + I830SelectBuffer(pScrn, I830_SELECT_FRONT); + + return XAAInit(pScreen, infoPtr); +} + +void +I830SetupForSolidFill(ScrnInfoPtr pScrn, int color, int rop, + unsigned int planemask) +{ + I830Ptr pI830 = I830PTR(pScrn); + + if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) + ErrorF("I830SetupForFillRectSolid color: %x rop: %x mask: %x\n", + color, rop, planemask); + + pI830->BR[13] = ((i810PatternRop[rop] << 16) | + (pScrn->displayWidth * pI830->cpp)); + + pI830->BR[16] = color; + + switch (pScrn->bitsPerPixel) { + case 8: + break; + case 16: + pI830->BR[13] |= (1 << 24); + break; + case 32: + pI830->BR[13] |= ((1 << 25) | (1 << 24)); + break; + } +} + +void +I830SubsequentSolidFillRect(ScrnInfoPtr pScrn, int x, int y, int w, int h) +{ + I830Ptr pI830 = I830PTR(pScrn); + + if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) + ErrorF("I830SubsequentFillRectSolid %d,%d %dx%d\n", x, y, w, h); + + { + BEGIN_LP_RING(6); + + if (pScrn->bitsPerPixel == 32) { + OUT_RING(COLOR_BLT_CMD | COLOR_BLT_WRITE_ALPHA | + COLOR_BLT_WRITE_RGB); + } else { + OUT_RING(COLOR_BLT_CMD); + } + OUT_RING(pI830->BR[13]); + OUT_RING((h << 16) | (w * pI830->cpp)); + OUT_RING(pI830->bufferOffset + (y * pScrn->displayWidth + x) * + pI830->cpp); + OUT_RING(pI830->BR[16]); + OUT_RING(0); + + ADVANCE_LP_RING(); + } +} + +void +I830SetupForScreenToScreenCopy(ScrnInfoPtr pScrn, int xdir, int ydir, int rop, + unsigned int planemask, int transparency_color) +{ + I830Ptr pI830 = I830PTR(pScrn); + + if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) + ErrorF("I830SetupForScreenToScreenCopy %d %d %x %x %d\n", + xdir, ydir, rop, planemask, transparency_color); + + pI830->BR[13] = (pScrn->displayWidth * pI830->cpp); + pI830->BR[13] |= i810Rop[rop] << 16; + + switch (pScrn->bitsPerPixel) { + case 8: + break; + case 16: + pI830->BR[13] |= (1 << 24); + break; + case 32: + pI830->BR[13] |= ((1 << 25) | (1 << 24)); + break; + } + +} + +void +I830SubsequentScreenToScreenCopy(ScrnInfoPtr pScrn, int src_x1, int src_y1, + int dst_x1, int dst_y1, int w, int h) +{ + I830Ptr pI830 = I830PTR(pScrn); + int dst_x2, dst_y2; + + if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) + ErrorF("I830SubsequentScreenToScreenCopy %d,%d - %d,%d %dx%d\n", + src_x1, src_y1, dst_x1, dst_y1, w, h); + + dst_x2 = dst_x1 + w; + dst_y2 = dst_y1 + h; + + { + BEGIN_LP_RING(8); + + if (pScrn->bitsPerPixel == 32) { + OUT_RING(XY_SRC_COPY_BLT_CMD | XY_SRC_COPY_BLT_WRITE_ALPHA | + XY_SRC_COPY_BLT_WRITE_RGB); + } else { + OUT_RING(XY_SRC_COPY_BLT_CMD); + } + OUT_RING(pI830->BR[13]); + OUT_RING((dst_y1 << 16) | (dst_x1 & 0xffff)); + OUT_RING((dst_y2 << 16) | (dst_x2 & 0xffff)); + OUT_RING(pI830->bufferOffset); + OUT_RING((src_y1 << 16) | (src_x1 & 0xffff)); + OUT_RING(pI830->BR[13] & 0xFFFF); + OUT_RING(pI830->bufferOffset); + + ADVANCE_LP_RING(); + } +} + +static void +I830SetupForMono8x8PatternFill(ScrnInfoPtr pScrn, int pattx, int patty, + int fg, int bg, int rop, + unsigned int planemask) +{ + I830Ptr pI830 = I830PTR(pScrn); + + if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) + ErrorF("I830SetupForMono8x8PatternFill\n"); + + pI830->BR[16] = pattx; + pI830->BR[17] = patty; + pI830->BR[18] = bg; + pI830->BR[19] = fg; + + pI830->BR[13] = (pScrn->displayWidth * pI830->cpp); /* In bytes */ + pI830->BR[13] |= i810PatternRop[rop] << 16; + if (bg == -1) + pI830->BR[13] |= (1 << 28); + + switch (pScrn->bitsPerPixel) { + case 8: + break; + case 16: + pI830->BR[13] |= (1 << 24); + break; + case 32: + pI830->BR[13] |= ((1 << 25) | (1 << 24)); + break; + } + +} + +static void +I830SubsequentMono8x8PatternFillRect(ScrnInfoPtr pScrn, int pattx, int patty, + int x, int y, int w, int h) +{ + I830Ptr pI830 = I830PTR(pScrn); + int x1, x2, y1, y2; + + x1 = x; + x2 = x + w; + y1 = y; + y2 = y + h; + + if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) + ErrorF("I830SubsequentMono8x8PatternFillRect\n"); + + { + BEGIN_LP_RING(10); + + if (pScrn->bitsPerPixel == 32) { + OUT_RING(XY_MONO_PAT_BLT_CMD | XY_MONO_PAT_BLT_WRITE_ALPHA | + XY_MONO_PAT_BLT_WRITE_RGB | + ((patty << 8) & XY_MONO_PAT_VERT_SEED) | + ((pattx << 12) & XY_MONO_PAT_HORT_SEED)); + } else { + OUT_RING(XY_MONO_PAT_BLT_CMD | + ((patty << 8) & XY_MONO_PAT_VERT_SEED) | + ((pattx << 12) & XY_MONO_PAT_HORT_SEED)); + } + OUT_RING(pI830->BR[13]); + OUT_RING((y1 << 16) | x1); + OUT_RING((y2 << 16) | x2); + OUT_RING(pI830->bufferOffset); + OUT_RING(pI830->BR[18]); /* bg */ + OUT_RING(pI830->BR[19]); /* fg */ + OUT_RING(pI830->BR[16]); /* pattern data */ + OUT_RING(pI830->BR[17]); + OUT_RING(0); + ADVANCE_LP_RING(); + } +} + +static void +I830GetNextScanlineColorExpandBuffer(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + XAAInfoRecPtr infoPtr = pI830->AccelInfoRec; + + if (pI830->nextColorExpandBuf == pI830->NumScanlineColorExpandBuffers) + I830Sync(pScrn); + + infoPtr->ScanlineColorExpandBuffers[0] = + pI830->ScanlineColorExpandBuffers[pI830->nextColorExpandBuf]; + + if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) + ErrorF("using color expand buffer %d\n", pI830->nextColorExpandBuf); + + pI830->nextColorExpandBuf++; +} + +static void +I830SetupForScanlineCPUToScreenColorExpandFill(ScrnInfoPtr pScrn, + int fg, int bg, int rop, + unsigned int planemask) +{ + I830Ptr pI830 = I830PTR(pScrn); + + if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) + ErrorF("I830SetupForScanlineScreenToScreenColorExpand %d %d %x %x\n", + fg, bg, rop, planemask); + + /* Fill out register values */ + pI830->BR[13] = (pScrn->displayWidth * pI830->cpp); + pI830->BR[13] |= i810Rop[rop] << 16; + if (bg == -1) + pI830->BR[13] |= (1 << 29); + + switch (pScrn->bitsPerPixel) { + case 8: + break; + case 16: + pI830->BR[13] |= (1 << 24); + break; + case 32: + pI830->BR[13] |= ((1 << 25) | (1 << 24)); + break; + } + + pI830->BR[18] = bg; + pI830->BR[19] = fg; + + I830GetNextScanlineColorExpandBuffer(pScrn); +} + +static void +I830SubsequentScanlineCPUToScreenColorExpandFill(ScrnInfoPtr pScrn, + int x, int y, + int w, int h, int skipleft) +{ + I830Ptr pI830 = I830PTR(pScrn); + + if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) + ErrorF("I830SubsequentScanlineCPUToScreenColorExpandFill " + "%d,%d %dx%x %d\n", x, y, w, h, skipleft); + + /* Fill out register values */ + pI830->BR[9] = (pI830->bufferOffset + + (y * pScrn->displayWidth + x) * pI830->cpp); + pI830->BR[11] = ((1 << 16) | w); +} + +static void +I830SubsequentColorExpandScanline(ScrnInfoPtr pScrn, int bufno) +{ + I830Ptr pI830 = I830PTR(pScrn); + + pI830->BR[12] = (pI830->AccelInfoRec->ScanlineColorExpandBuffers[0] - + pI830->FbBase); + + if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) + ErrorF("I830SubsequentColorExpandScanline %d (addr %x)\n", + bufno, pI830->BR[12]); + + { + BEGIN_LP_RING(8); + + if (pScrn->bitsPerPixel == 32) { + OUT_RING(XY_MONO_SRC_BLT_CMD | XY_MONO_SRC_BLT_WRITE_ALPHA | + XY_MONO_SRC_BLT_WRITE_RGB); + } else { + OUT_RING(XY_MONO_SRC_BLT_CMD); + } + OUT_RING(pI830->BR[13]); + OUT_RING(0); /* x1 = 0, y1 = 0 */ + OUT_RING(pI830->BR[11]); /* x2 = w, y2 = 1 */ + OUT_RING(pI830->BR[9]); /* dst addr */ + OUT_RING(pI830->BR[12]); /* src addr */ + OUT_RING(pI830->BR[18]); /* bg */ + OUT_RING(pI830->BR[19]); /* fg */ + + ADVANCE_LP_RING(); + } + + /* Advance to next scanline. + */ + pI830->BR[9] += pScrn->displayWidth * pI830->cpp; + I830GetNextScanlineColorExpandBuffer(pScrn); +} + +#if DO_SCANLINE_IMAGE_WRITE +static void +I830SetupForScanlineImageWrite(ScrnInfoPtr pScrn, int rop, + unsigned int planemask, int trans_color, + int bpp, int depth) +{ + I830Ptr pI830 = I830PTR(pScrn); + + if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) + ErrorF("I830SetupForScanlineImageWrite %x %x\n", rop, planemask); + + /* Fill out register values */ + pI830->BR[13] = (pScrn->displayWidth * pI830->cpp); + pI830->BR[13] |= i810Rop[rop] << 16; + + switch (pScrn->bitsPerPixel) { + case 8: + break; + case 16: + pI830->BR[13] |= (1 << 24); + break; + case 32: + pI830->BR[13] |= ((1 << 25) | (1 << 24)); + break; + } + + I830GetNextScanlineColorExpandBuffer(pScrn); +} + +static void +I830SubsequentScanlineImageWriteRect(ScrnInfoPtr pScrn, int x, int y, + int w, int h, int skipleft) +{ + I830Ptr pI830 = I830PTR(pScrn); + + if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) + ErrorF("I830SubsequentScanlineImageWriteRect " + "%d,%d %dx%x %d\n", x, y, w, h, skipleft); + + /* Fill out register values */ + pI830->BR[9] = (pI830->bufferOffset + + (y * pScrn->displayWidth + x) * pI830->cpp); + pI830->BR[11] = ((1 << 16) | w); +} + +static void +I830SubsequentImageWriteScanline(ScrnInfoPtr pScrn, int bufno) +{ + I830Ptr pI830 = I830PTR(pScrn); + + pI830->BR[12] = (pI830->AccelInfoRec->ScanlineColorExpandBuffers[0] - + pI830->FbBase); + + if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) + ErrorF("I830SubsequentImageWriteScanline %d (addr %x)\n", + bufno, pI830->BR[12]); + + { + BEGIN_LP_RING(8); + + if (pScrn->bitsPerPixel == 32) { + OUT_RING(XY_SRC_COPY_BLT_CMD | XY_SRC_COPY_BLT_WRITE_ALPHA | + XY_SRC_COPY_BLT_WRITE_RGB); + } else { + OUT_RING(XY_SRC_COPY_BLT_CMD); + } + OUT_RING(pI830->BR[13]); + OUT_RING(0); /* x1 = 0, y1 = 0 */ + OUT_RING(pI830->BR[11]); /* x2 = w, y2 = 1 */ + OUT_RING(pI830->BR[9]); /* dst addr */ + OUT_RING(0); /* source origin (0,0) */ + OUT_RING(pI830->BR[11] & 0xffff); /* source pitch */ + OUT_RING(pI830->BR[12]); /* src addr */ + + ADVANCE_LP_RING(); + } + + /* Advance to next scanline. + */ + pI830->BR[9] += pScrn->displayWidth * pI830->cpp; + I830GetNextScanlineColorExpandBuffer(pScrn); +} + +#endif diff --git a/src/i830_common.h b/src/i830_common.h new file mode 100644 index 00000000..3367bfc1 --- /dev/null +++ b/src/i830_common.h @@ -0,0 +1,288 @@ +/************************************************************************** + +Copyright 2001 VA Linux Systems Inc., Fremont, California. +Copyright 2002 Tungsten Graphics Inc., Cedar Park, Texas. + +All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +on the rights to use, copy, modify, merge, publish, distribute, sub +license, and/or sell copies of the Software, and to permit persons to whom +the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice (including the next +paragraph) shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +ATI, VA LINUX SYSTEMS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ + +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i810/i830_common.h,v 1.2 2002/12/10 01:27:05 dawes Exp $ */ + +/* Author: Jeff Hartmann <jhartmann@valinux.com> + + Converted to common header format: + Jens Owen <jens@tungstengraphics.com> + */ + +#ifndef _I830_COMMON_H_ +#define _I830_COMMON_H_ + +/* WARNING: These defines must be the same as what the Xserver uses. + * if you change them, you must change the defines in the Xserver. + */ + +#ifndef _I830_DEFINES_ +#define _I830_DEFINES_ + +#define I830_DMA_BUF_ORDER 12 +#define I830_DMA_BUF_SZ (1<<I830_DMA_BUF_ORDER) +#define I830_DMA_BUF_NR 256 +#define I830_NR_SAREA_CLIPRECTS 8 + +/* Each region is a minimum of 64k, and there are at most 64 of them. + */ +#define I830_NR_TEX_REGIONS 64 +#define I830_LOG_MIN_TEX_REGION_SIZE 16 + +/* if defining I830_ENABLE_4_TEXTURES, do it in i830_3d_reg.h, too */ +#if !defined(I830_ENABLE_4_TEXTURES) +#define I830_TEXTURE_COUNT 2 +#define I830_TEXBLEND_COUNT 2 /* always same as TEXTURE_COUNT? */ +#else /* defined(I830_ENABLE_4_TEXTURES) */ +#define I830_TEXTURE_COUNT 4 +#define I830_TEXBLEND_COUNT 4 /* always same as TEXTURE_COUNT? */ +#endif /* I830_ENABLE_4_TEXTURES */ + +#define I830_TEXBLEND_SIZE 12 /* (4 args + op) * 2 + COLOR_FACTOR */ + +#define I830_UPLOAD_CTX 0x1 +#define I830_UPLOAD_BUFFERS 0x2 +#define I830_UPLOAD_CLIPRECTS 0x4 +#define I830_UPLOAD_TEX0_IMAGE 0x100 /* handled clientside */ +#define I830_UPLOAD_TEX0_CUBE 0x200 /* handled clientside */ +#define I830_UPLOAD_TEX1_IMAGE 0x400 /* handled clientside */ +#define I830_UPLOAD_TEX1_CUBE 0x800 /* handled clientside */ +#define I830_UPLOAD_TEX2_IMAGE 0x1000 /* handled clientside */ +#define I830_UPLOAD_TEX2_CUBE 0x2000 /* handled clientside */ +#define I830_UPLOAD_TEX3_IMAGE 0x4000 /* handled clientside */ +#define I830_UPLOAD_TEX3_CUBE 0x8000 /* handled clientside */ +#define I830_UPLOAD_TEX_N_IMAGE(n) (0x100 << (n * 2)) +#define I830_UPLOAD_TEX_N_CUBE(n) (0x200 << (n * 2)) +#define I830_UPLOAD_TEXIMAGE_MASK 0xff00 +#define I830_UPLOAD_TEX0 0x10000 +#define I830_UPLOAD_TEX1 0x20000 +#define I830_UPLOAD_TEX2 0x40000 +#define I830_UPLOAD_TEX3 0x80000 +#define I830_UPLOAD_TEX_N(n) (0x10000 << (n)) +#define I830_UPLOAD_TEX_MASK 0xf0000 +#define I830_UPLOAD_TEXBLEND0 0x100000 +#define I830_UPLOAD_TEXBLEND1 0x200000 +#define I830_UPLOAD_TEXBLEND2 0x400000 +#define I830_UPLOAD_TEXBLEND3 0x800000 +#define I830_UPLOAD_TEXBLEND_N(n) (0x100000 << (n)) +#define I830_UPLOAD_TEXBLEND_MASK 0xf00000 +#define I830_UPLOAD_TEX_PALETTE_N(n) (0x1000000 << (n)) +#define I830_UPLOAD_TEX_PALETTE_SHARED 0x4000000 +#define I830_UPLOAD_STIPPLE 0x8000000 + +/* Indices into buf.Setup where various bits of state are mirrored per + * context and per buffer. These can be fired at the card as a unit, + * or in a piecewise fashion as required. + */ + +/* Destbuffer state + * - backbuffer linear offset and pitch -- invarient in the current dri + * - zbuffer linear offset and pitch -- also invarient + * - drawing origin in back and depth buffers. + * + * Keep the depth/back buffer state here to acommodate private buffers + * in the future. + */ + +#define I830_DESTREG_CBUFADDR 0 +/* Invarient */ +#define I830_DESTREG_DBUFADDR 1 +#define I830_DESTREG_DV0 2 +#define I830_DESTREG_DV1 3 +#define I830_DESTREG_SENABLE 4 +#define I830_DESTREG_SR0 5 +#define I830_DESTREG_SR1 6 +#define I830_DESTREG_SR2 7 +#define I830_DESTREG_DR0 8 +#define I830_DESTREG_DR1 9 +#define I830_DESTREG_DR2 10 +#define I830_DESTREG_DR3 11 +#define I830_DESTREG_DR4 12 +#define I830_DEST_SETUP_SIZE 13 + +/* Context state + */ +#define I830_CTXREG_STATE1 0 +#define I830_CTXREG_STATE2 1 +#define I830_CTXREG_STATE3 2 +#define I830_CTXREG_STATE4 3 +#define I830_CTXREG_STATE5 4 +#define I830_CTXREG_IALPHAB 5 +#define I830_CTXREG_STENCILTST 6 +#define I830_CTXREG_ENABLES_1 7 +#define I830_CTXREG_ENABLES_2 8 +#define I830_CTXREG_AA 9 +#define I830_CTXREG_FOGCOLOR 10 +#define I830_CTXREG_BLENDCOLR0 11 +#define I830_CTXREG_BLENDCOLR 12 /* Dword 1 of 2 dword command */ +#define I830_CTXREG_VF 13 +#define I830_CTXREG_VF2 14 +#define I830_CTXREG_MCSB0 15 +#define I830_CTXREG_MCSB1 16 +#define I830_CTX_SETUP_SIZE 17 + +/* 1.3: Stipple state + */ +#define I830_STPREG_ST0 0 +#define I830_STPREG_ST1 1 +#define I830_STP_SETUP_SIZE 2 + +/* Texture state (per tex unit) + */ +#define I830_TEXREG_MI0 0 /* GFX_OP_MAP_INFO (6 dwords) */ +#define I830_TEXREG_MI1 1 +#define I830_TEXREG_MI2 2 +#define I830_TEXREG_MI3 3 +#define I830_TEXREG_MI4 4 +#define I830_TEXREG_MI5 5 +#define I830_TEXREG_MF 6 /* GFX_OP_MAP_FILTER */ +#define I830_TEXREG_MLC 7 /* GFX_OP_MAP_LOD_CTL */ +#define I830_TEXREG_MLL 8 /* GFX_OP_MAP_LOD_LIMITS */ +#define I830_TEXREG_MCS 9 /* GFX_OP_MAP_COORD_SETS */ +#define I830_TEX_SETUP_SIZE 10 + +/* New version. Kernel auto-detects. + */ +#define I830_TEXREG_TM0LI 0 /* load immediate 2 texture map n */ +#define I830_TEXREG_TM0S0 1 +#define I830_TEXREG_TM0S1 2 +#define I830_TEXREG_TM0S2 3 +#define I830_TEXREG_TM0S3 4 +#define I830_TEXREG_TM0S4 5 +#define I830_TEXREG_NOP0 6 /* noop */ +#define I830_TEXREG_NOP1 7 /* noop */ +#define I830_TEXREG_NOP2 8 /* noop */ +#define __I830_TEXREG_MCS 9 /* GFX_OP_MAP_COORD_SETS -- shared */ +#define __I830_TEX_SETUP_SIZE 10 + + +#define I830_FRONT 0x1 +#define I830_BACK 0x2 +#define I830_DEPTH 0x4 + +/* Driver specific DRM command indices + * NOTE: these are not OS specific, but they are driver specific + */ +#define DRM_I830_INIT 0x00 +#define DRM_I830_VERTEX 0x01 +#define DRM_I830_CLEAR 0x02 +#define DRM_I830_FLUSH 0x03 +#define DRM_I830_GETAGE 0x04 +#define DRM_I830_GETBUF 0x05 +#define DRM_I830_SWAP 0x06 +#define DRM_I830_COPY 0x07 +#define DRM_I830_DOCOPY 0x08 +#define DRM_I830_FLIP 0x09 +#define DRM_I830_IRQ_EMIT 0x0a +#define DRM_I830_IRQ_WAIT 0x0b +#define DRM_I830_GETPARAM 0x0c +#define DRM_I830_SETPARAM 0x0d + +#endif /* _I830_DEFINES_ */ + +typedef struct { + enum { + I830_INIT_DMA = 0x01, + I830_CLEANUP_DMA = 0x02 + } func; + unsigned int mmio_offset; + unsigned int buffers_offset; + int sarea_priv_offset; + unsigned int ring_start; + unsigned int ring_end; + unsigned int ring_size; + unsigned int front_offset; + unsigned int back_offset; + unsigned int depth_offset; + unsigned int w; + unsigned int h; + unsigned int pitch; + unsigned int pitch_bits; + unsigned int back_pitch; + unsigned int depth_pitch; + unsigned int cpp; +} drmI830Init; + +typedef struct { + int clear_color; + int clear_depth; + int flags; + unsigned int clear_colormask; + unsigned int clear_depthmask; +} drmI830Clear; + +/* These may be placeholders if we have more cliprects than + * I830_NR_SAREA_CLIPRECTS. In that case, the client sets discard to + * false, indicating that the buffer will be dispatched again with a + * new set of cliprects. + */ +typedef struct { + int idx; /* buffer index */ + int used; /* nr bytes in use */ + int discard; /* client is finished with the buffer? */ +} drmI830Vertex; + +typedef struct { + int idx; /* buffer index */ + int used; /* nr bytes in use */ + void *address; /* Address to copy from */ +} drmI830Copy; + +typedef struct { + void *virtual; + int request_idx; + int request_size; + int granted; +} drmI830DMA; + +typedef struct drm_i830_irq_emit { + int *irq_seq; +} drmI830IrqEmit; + +typedef struct drm_i830_irq_wait { + int irq_seq; +} drmI830IrqWait; + +typedef struct drm_i830_getparam { + int param; + int *value; +} drmI830GetParam; + +#define I830_PARAM_IRQ_ACTIVE 1 + + +typedef struct drm_i830_setparam { + int param; + int value; +} drmI830SetParam; + +#define I830_SETPARAM_USE_MI_BATCHBUFFER_START 1 + + + +#endif /* _I830_DRM_H_ */ diff --git a/src/i830_cursor.c b/src/i830_cursor.c new file mode 100644 index 00000000..419fd583 --- /dev/null +++ b/src/i830_cursor.c @@ -0,0 +1,281 @@ + +/************************************************************************** + +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +Copyright © 2002 David Dawes +All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sub license, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice (including the +next paragraph) shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i810/i830_cursor.c,v 1.6 2002/12/18 15:49:01 dawes Exp $ */ + +/* + * Reformatted with GNU indent (2.2.8), using the following options: + * + * -bad -bap -c41 -cd0 -ncdb -ci6 -cli0 -cp0 -ncs -d0 -di3 -i3 -ip3 -l78 + * -lp -npcs -psl -sob -ss -br -ce -sc -hnl + * + * This provides a good match with the original i810 code and preferred + * XFree86 formatting conventions. + * + * When editing this driver, please follow the existing formatting, and edit + * with <TAB> characters expanded at 8-column intervals. + */ + +/* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + * David Dawes <dawes@tungstengraphics.com> + * + */ + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86_ansic.h" +#include "compiler.h" + +#include "xf86fbman.h" + +#include "i830.h" + +static void I830LoadCursorImage(ScrnInfoPtr pScrn, unsigned char *src); +static void I830ShowCursor(ScrnInfoPtr pScrn); +static void I830HideCursor(ScrnInfoPtr pScrn); +static void I830SetCursorColors(ScrnInfoPtr pScrn, int bg, int fb); +static void I830SetCursorPosition(ScrnInfoPtr pScrn, int x, int y); +static Bool I830UseHWCursor(ScreenPtr pScrn, CursorPtr pCurs); + +void +I830InitHWCursor(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + CARD32 temp; + + DPRINTF(PFX, "I830InitHWCursor\n"); + + /* Initialise the HW cursor registers, leaving the cursor hidden. */ + if (IS_MOBILE(pI830)) { + temp = INREG(CURSOR_A_CONTROL); + temp &= ~(CURSOR_MODE | MCURSOR_GAMMA_ENABLE | MCURSOR_MEM_TYPE_LOCAL | + MCURSOR_PIPE_SELECT); + temp |= CURSOR_MODE_DISABLE; + /* + * XXX Should enable cursor B when both pipes are enabled. + * For now, give pipe A preference. + */ + if (pI830->pipeEnabled[0]) + temp |= MCURSOR_PIPE_A; + else if (pI830->pipeEnabled[1]) + temp |= MCURSOR_PIPE_B; + /* Need to set control, then address. */ + OUTREG(CURSOR_A_CONTROL, temp); + OUTREG(CURSOR_A_BASE, pI830->CursorMem.Physical); + } else { + temp = INREG(CURSOR_CONTROL); + temp &= ~(CURSOR_FORMAT_MASK | CURSOR_GAMMA_ENABLE | + CURSOR_ENABLE | CURSOR_STRIDE_MASK); + temp |= (CURSOR_FORMAT_3C); + /* This initialises the format and leave the cursor disabled. */ + OUTREG(CURSOR_CONTROL, temp); + /* Need to set address and size after disabling. */ + OUTREG(CURSOR_BASEADDR, pI830->CursorMem.Start); + temp = ((I810_CURSOR_X & CURSOR_SIZE_MASK) << CURSOR_SIZE_HSHIFT) | + ((I810_CURSOR_Y & CURSOR_SIZE_MASK) << CURSOR_SIZE_VSHIFT); + OUTREG(CURSOR_SIZE, temp); + } +} + +Bool +I830CursorInit(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn; + I830Ptr pI830; + xf86CursorInfoPtr infoPtr; + + DPRINTF(PFX, "I830CursorInit\n"); + pScrn = xf86Screens[pScreen->myNum]; + pI830 = I830PTR(pScrn); + pI830->CursorInfoRec = infoPtr = xf86CreateCursorInfoRec(); + if (!infoPtr) + return FALSE; + + infoPtr->MaxWidth = 64; + infoPtr->MaxHeight = 64; + infoPtr->Flags = (HARDWARE_CURSOR_TRUECOLOR_AT_8BPP | + HARDWARE_CURSOR_BIT_ORDER_MSBFIRST | + HARDWARE_CURSOR_INVERT_MASK | + HARDWARE_CURSOR_SWAP_SOURCE_AND_MASK | + HARDWARE_CURSOR_AND_SOURCE_WITH_MASK | + HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64 | 0); + + infoPtr->SetCursorColors = I830SetCursorColors; + infoPtr->SetCursorPosition = I830SetCursorPosition; + infoPtr->LoadCursorImage = I830LoadCursorImage; + infoPtr->HideCursor = I830HideCursor; + infoPtr->ShowCursor = I830ShowCursor; + infoPtr->UseHWCursor = I830UseHWCursor; + + if (pI830->CursorNeedsPhysical && !pI830->CursorMem.Physical) + return FALSE; + + I830HideCursor(pScrn); + + return xf86InitCursor(pScreen, infoPtr); +} + +static Bool +I830UseHWCursor(ScreenPtr pScreen, CursorPtr pCurs) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I830Ptr pI830 = I830PTR(pScrn); + + DPRINTF(PFX, "I830UseHWCursor\n"); + if (pI830->CursorNeedsPhysical && !pI830->CursorMem.Physical) + return FALSE; + + return TRUE; +} + +static void +I830LoadCursorImage(ScrnInfoPtr pScrn, unsigned char *src) +{ + I830Ptr pI830 = I830PTR(pScrn); + CARD8 *pcurs = (CARD8 *) (pI830->FbBase + pI830->CursorMem.Start); + int x, y; + + DPRINTF(PFX, "I830LoadCursorImage\n"); + for (y = 0; y < 64; y++) { + for (x = 0; x < 64 / 4; x++) { + *pcurs++ = *src++; + } + } +} + + +static void +I830SetCursorPosition(ScrnInfoPtr pScrn, int x, int y) +{ + I830Ptr pI830 = I830PTR(pScrn); + CARD32 temp = 0; + static Bool outsideViewport = FALSE; + Bool hide = FALSE, show = FALSE; + + /* + * There is a screen display problem when the cursor position is set + * wholely outside of the viewport. We trap that here, turning the + * cursor off when that happens, and back on when it comes back into + * the viewport. + */ + if (x >= pScrn->currentMode->HDisplay || + y >= pScrn->currentMode->VDisplay || + x <= -I810_CURSOR_X || y <= -I810_CURSOR_Y) { + hide = TRUE; + outsideViewport = TRUE; + } else if (outsideViewport) { + show = TRUE; + outsideViewport = FALSE; + } + + if (x < 0) { + temp |= (CURSOR_POS_SIGN << CURSOR_X_SHIFT); + x = -x; + } + if (y < 0) { + temp |= (CURSOR_POS_SIGN << CURSOR_Y_SHIFT); + y = -y; + } + temp |= ((x & CURSOR_POS_MASK) << CURSOR_X_SHIFT); + temp |= ((y & CURSOR_POS_MASK) << CURSOR_Y_SHIFT); + + OUTREG(CURSOR_A_POSITION, temp); + + if (pI830->cursorOn) { + if (hide) + pI830->CursorInfoRec->HideCursor(pScrn); + else if (show) + pI830->CursorInfoRec->ShowCursor(pScrn); + pI830->cursorOn = TRUE; + } +} + +static void +I830ShowCursor(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + CARD32 temp; + + DPRINTF(PFX, "I830ShowCursor\n"); + DPRINTF(PFX, + "Value of CursorMem.Physical is %x, " + " Value of CursorMem.Start is %x ", + pI830->CursorMem.Physical, pI830->CursorMem.Start); + + pI830->cursorOn = TRUE; + if (IS_MOBILE(pI830)) { + temp = INREG(CURSOR_A_CONTROL); + temp &= ~CURSOR_MODE; + temp |= CURSOR_MODE_64_4C_AX; + /* Need to set mode, then address. */ + OUTREG(CURSOR_A_CONTROL, temp); + OUTREG(CURSOR_A_BASE, pI830->CursorMem.Physical); + } else { + temp = INREG(CURSOR_CONTROL); + temp |= CURSOR_ENABLE; + OUTREG(CURSOR_CONTROL, temp); + } +} + +static void +I830HideCursor(ScrnInfoPtr pScrn) +{ + CARD32 temp; + I830Ptr pI830 = I830PTR(pScrn); + + DPRINTF(PFX, "I830HideCursor\n"); + + pI830->cursorOn = FALSE; + if (IS_MOBILE(pI830)) { + temp = INREG(CURSOR_A_CONTROL); + temp &= ~CURSOR_MODE; + temp |= CURSOR_MODE_DISABLE; + OUTREG(CURSOR_A_CONTROL, temp); + /* This is needed to flush the above change. */ + OUTREG(CURSOR_A_BASE, pI830->CursorMem.Physical); + } else { + temp = INREG(CURSOR_CONTROL); + temp &= ~CURSOR_ENABLE; + OUTREG(CURSOR_CONTROL, temp); + } +} + +static void +I830SetCursorColors(ScrnInfoPtr pScrn, int bg, int fg) +{ + I830Ptr pI830 = I830PTR(pScrn); + + DPRINTF(PFX, "I830SetCursorColors\n"); + + OUTREG(CURSOR_A_PALETTE0, bg & 0x00ffffff); + OUTREG(CURSOR_A_PALETTE1, fg & 0x00ffffff); + OUTREG(CURSOR_A_PALETTE2, fg & 0x00ffffff); + OUTREG(CURSOR_A_PALETTE3, bg & 0x00ffffff); +} diff --git a/src/i830_dga.c b/src/i830_dga.c new file mode 100644 index 00000000..bb4c103a --- /dev/null +++ b/src/i830_dga.c @@ -0,0 +1,293 @@ +/* + * Copyright 2000 by Alan Hourihane, Sychdyn, North Wales, UK. + * + * 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 Alan Hourihane not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Alan Hourihane makes no representations + * about the suitability of this software for any purpose. It is provided + * "as is" without express or implied warranty. + * + * ALAN HOURIHANE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL ALAN HOURIHANE 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. + * + * Authors: Alan Hourihane, <alanh@fairlite.demon.co.uk> + */ +/* + * Reformatted with GNU indent (2.2.8), using the following options: + * + * -bad -bap -c41 -cd0 -ncdb -ci6 -cli0 -cp0 -ncs -d0 -di3 -i3 -ip3 -l78 + * -lp -npcs -psl -sob -ss -br -ce -sc -hnl + * + * This provides a good match with the original i810 code and preferred + * XFree86 formatting conventions. + * + * When editing this driver, please follow the existing formatting, and edit + * with <TAB> characters expanded at 8-column intervals. + */ + +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i810/i830_dga.c,v 1.3 2003/02/26 04:11:23 dawes Exp $ */ + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86_ansic.h" +#include "xf86Pci.h" +#include "xf86PciInfo.h" +#include "xaa.h" +#include "xaalocal.h" +#include "i830.h" +#include "i810_reg.h" +#include "dgaproc.h" +#include "vgaHW.h" + +static Bool I830_OpenFramebuffer(ScrnInfoPtr, char **, unsigned char **, + int *, int *, int *); +static Bool I830_SetMode(ScrnInfoPtr, DGAModePtr); +static void I830_Sync(ScrnInfoPtr); +static int I830_GetViewport(ScrnInfoPtr); +static void I830_SetViewport(ScrnInfoPtr, int, int, int); +static void I830_FillRect(ScrnInfoPtr, int, int, int, int, unsigned long); +static void I830_BlitRect(ScrnInfoPtr, int, int, int, int, int, int); + +#if 0 +static void I830_BlitTransRect(ScrnInfoPtr, int, int, int, int, int, int, + unsigned long); +#endif + +static +DGAFunctionRec I830DGAFuncs = { + I830_OpenFramebuffer, + NULL, + I830_SetMode, + I830_SetViewport, + I830_GetViewport, + I830_Sync, + I830_FillRect, + I830_BlitRect, +#if 0 + I830_BlitTransRect +#else + NULL +#endif +}; + +Bool +I830DGAInit(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I830Ptr pI830 = I830PTR(pScrn); + DGAModePtr modes = NULL, newmodes = NULL, currentMode; + DisplayModePtr pMode, firstMode; + int Bpp = pScrn->bitsPerPixel >> 3; + int num = 0; + + MARKER(); + + pMode = firstMode = pScrn->modes; + + while (pMode) { + + newmodes = xrealloc(modes, (num + 1) * sizeof(DGAModeRec)); + + if (!newmodes) { + xfree(modes); + return FALSE; + } + modes = newmodes; + + currentMode = modes + num; + num++; + + currentMode->mode = pMode; + currentMode->flags = DGA_CONCURRENT_ACCESS | DGA_PIXMAP_AVAILABLE; + if (!pI830->noAccel) + currentMode->flags |= DGA_FILL_RECT | DGA_BLIT_RECT; + if (pMode->Flags & V_DBLSCAN) + currentMode->flags |= DGA_DOUBLESCAN; + if (pMode->Flags & V_INTERLACE) + currentMode->flags |= DGA_INTERLACED; + currentMode->byteOrder = pScrn->imageByteOrder; + currentMode->depth = pScrn->depth; + currentMode->bitsPerPixel = pScrn->bitsPerPixel; + currentMode->red_mask = pScrn->mask.red; + currentMode->green_mask = pScrn->mask.green; + currentMode->blue_mask = pScrn->mask.blue; + currentMode->visualClass = (Bpp == 1) ? PseudoColor : TrueColor; + currentMode->viewportWidth = pMode->HDisplay; + currentMode->viewportHeight = pMode->VDisplay; + currentMode->xViewportStep = (Bpp == 3) ? 2 : 1; + currentMode->yViewportStep = 1; + currentMode->viewportFlags = DGA_FLIP_RETRACE; + currentMode->offset = 0; + currentMode->address = pI830->FbBase + pScrn->fbOffset; + + currentMode->bytesPerScanline = ((pScrn->displayWidth * Bpp) + 3) & ~3L; + currentMode->imageWidth = pI830->FbMemBox.x2; + currentMode->imageHeight = pI830->FbMemBox.y2; + currentMode->pixmapWidth = currentMode->imageWidth; + currentMode->pixmapHeight = currentMode->imageHeight; + currentMode->maxViewportX = currentMode->imageWidth - + currentMode->viewportWidth; + /* this might need to get clamped to some maximum */ + currentMode->maxViewportY = currentMode->imageHeight - + currentMode->viewportHeight; + + pMode = pMode->next; + if (pMode == firstMode) + break; + } + + pI830->numDGAModes = num; + pI830->DGAModes = modes; + + return DGAInit(pScreen, &I830DGAFuncs, modes, num); +} + +static DisplayModePtr I830SavedDGAModes[MAXSCREENS]; + +static Bool +I830_SetMode(ScrnInfoPtr pScrn, DGAModePtr pMode) +{ + int index = pScrn->pScreen->myNum; + I830Ptr pI830 = I830PTR(pScrn); + + MARKER(); + + if (!pMode) { /* restore the original mode */ + DPRINTF(PFX, "Restoring original mode (from DGA mode)\n"); + if (pI830->DGAactive) { + pScrn->currentMode = I830SavedDGAModes[index]; + pScrn->SwitchMode(index, pScrn->currentMode, 0); + pScrn->AdjustFrame(index, 0, 0, 0); + pI830->DGAactive = FALSE; + } + } else { + if (!pI830->DGAactive) { + DPRINTF(PFX, "Setting DGA mode\n"); + I830SavedDGAModes[index] = pScrn->currentMode; + pI830->DGAactive = TRUE; + } + + pScrn->SwitchMode(index, pMode->mode, 0); + } + + return TRUE; +} + +static int +I830_GetViewport(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + + MARKER(); + + return pI830->DGAViewportStatus; +} + +static void +I830_SetViewport(ScrnInfoPtr pScrn, int x, int y, int flags) +{ + I830Ptr pI830 = I830PTR(pScrn); + vgaHWPtr hwp = VGAHWPTR(pScrn); + + MARKER(); + + pScrn->AdjustFrame(pScrn->pScreen->myNum, x, y, flags); + + /* wait for retrace */ + while ((hwp->readST01(hwp) & 0x08)) ; + while (!(hwp->readST01(hwp) & 0x08)) ; + + pI830->DGAViewportStatus = 0; +} + +static void +I830_FillRect(ScrnInfoPtr pScrn, + int x, int y, int w, int h, unsigned long color) +{ + I830Ptr pI830 = I830PTR(pScrn); + + MARKER(); + + if (pI830->AccelInfoRec) { + (*pI830->AccelInfoRec->SetupForSolidFill) (pScrn, color, GXcopy, ~0); + (*pI830->AccelInfoRec->SubsequentSolidFillRect) (pScrn, x, y, w, h); + SET_SYNC_FLAG(pI830->AccelInfoRec); + } +} + +static void +I830_Sync(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + + MARKER(); + + if (pI830->AccelInfoRec) { + (*pI830->AccelInfoRec->Sync) (pScrn); + } +} + +static void +I830_BlitRect(ScrnInfoPtr pScrn, + int srcx, int srcy, int w, int h, int dstx, int dsty) +{ + I830Ptr pI830 = I830PTR(pScrn); + + MARKER(); + + if (pI830->AccelInfoRec) { + int xdir = ((srcx < dstx) && (srcy == dsty)) ? -1 : 1; + int ydir = (srcy < dsty) ? -1 : 1; + + (*pI830->AccelInfoRec->SetupForScreenToScreenCopy) (pScrn, xdir, ydir, + GXcopy, ~0, -1); + (*pI830->AccelInfoRec->SubsequentScreenToScreenCopy) (pScrn, srcx, srcy, + dstx, dsty, w, h); + SET_SYNC_FLAG(pI830->AccelInfoRec); + } +} + +#if 0 +static void +I830_BlitTransRect(ScrnInfoPtr pScrn, + int srcx, int srcy, + int w, int h, int dstx, int dsty, unsigned long color) +{ + + MARKER(); + + /* this one should be separate since the XAA function would + * prohibit usage of ~0 as the key */ +} +#endif + +static Bool +I830_OpenFramebuffer(ScrnInfoPtr pScrn, + char **name, + unsigned char **mem, int *size, int *offset, int *flags) +{ + I830Ptr pI830 = I830PTR(pScrn); + + MARKER(); + + *name = NULL; /* no special device */ + *mem = (unsigned char *)(pI830->LinearAddr + pScrn->fbOffset); + *size = pI830->FrontBuffer.Size; + *offset = 0; + *flags = DGA_NEED_ROOT; + + DPRINTF(PFX, + " mem == 0x%.8x (pI830->LinearAddr)\n" + "size == %lu (pI830->FbMapSize)\n", *mem, *size); + + return TRUE; +} diff --git a/src/i830_dri.c b/src/i830_dri.c new file mode 100644 index 00000000..197a8252 --- /dev/null +++ b/src/i830_dri.c @@ -0,0 +1,1664 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i810/i830_dri.c,v 1.12 2003/02/08 21:26:57 dawes Exp $ */ +/************************************************************************** + +Copyright 2001 VA Linux Systems Inc., Fremont, California. +Copyright © 2002 by David Dawes + +All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +on the rights to use, copy, modify, merge, publish, distribute, sub +license, and/or sell copies of the Software, and to permit persons to whom +the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice (including the next +paragraph) shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +ATI, VA LINUX SYSTEMS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ + +/* + * Reformatted with GNU indent (2.2.8), using the following options: + * + * -bad -bap -c41 -cd0 -ncdb -ci6 -cli0 -cp0 -ncs -d0 -di3 -i3 -ip3 -l78 + * -lp -npcs -psl -sob -ss -br -ce -sc -hnl + * + * This provides a good match with the original i810 code and preferred + * XFree86 formatting conventions. + * + * When editing this driver, please follow the existing formatting, and edit + * with <TAB> characters expanded at 8-column intervals. + */ + +/* + * Authors: Jeff Hartmann <jhartmann@valinux.com> + * David Dawes <dawes@tungstengraphics.com> + * Keith Whitwell <keith@tungstengraphics.com> + */ + +/* + * This driver does AGP memory allocation a little differently from most + * others. The 2D and 3D allocations have been unified (see i830_memory.c). + * The driver does the AGP allocations and binding directly, then passes + * on the mappings to the DRM module. The DRM's AGP interfaces are not used. + * The main difference with this is that the offsets need to include + * the AGP aperture base address because that won't be known or added on + * by the DRM module. + * + * DHD 07/2002 + */ + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86_ansic.h" +#include "xf86Priv.h" + +#include "xf86PciInfo.h" +#include "xf86Pci.h" + +#include "windowstr.h" +#include "shadow.h" + +#include "GL/glxtokens.h" + +#include "i830.h" +#include "i830_dri.h" +#include "i830_3d_reg.h" + +static char I830KernelDriverName[] = "i830"; +static char I830ClientDriverName[] = "i830"; + +static Bool I830InitVisualConfigs(ScreenPtr pScreen); +static Bool I830CreateContext(ScreenPtr pScreen, VisualPtr visual, + drmContext hwContext, void *pVisualConfigPriv, + DRIContextType contextStore); +static void I830DestroyContext(ScreenPtr pScreen, drmContext hwContext, + DRIContextType contextStore); +static void I830DRISwapContext(ScreenPtr pScreen, DRISyncType syncType, + DRIContextType readContextType, + void *readContextStore, + DRIContextType writeContextType, + void *writeContextStore); +static void I830DRIInitBuffers(WindowPtr pWin, RegionPtr prgn, CARD32 index); +static void I830DRIMoveBuffers(WindowPtr pParent, DDXPointRec ptOldOrg, + RegionPtr prgnSrc, CARD32 index); + +static Bool I830DRICloseFullScreen(ScreenPtr pScreen); +static Bool I830DRIOpenFullScreen(ScreenPtr pScreen); +static void I830DRITransitionTo2d(ScreenPtr pScreen); +static void I830DRITransitionTo3d(ScreenPtr pScreen); +static void I830DRITransitionMultiToSingle3d(ScreenPtr pScreen); +static void I830DRITransitionSingleToMulti3d(ScreenPtr pScreen); + +static void I830DRIShadowUpdate (ScreenPtr pScreen, shadowBufPtr pBuf); + +extern void GlxSetVisualConfigs(int nconfigs, + __GLXvisualConfig * configs, + void **configprivs); + +static Bool +I830CleanupDma(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + drmI830Init info; + + memset(&info, 0, sizeof(drmI830Init)); + info.func = I830_CLEANUP_DMA; + + if (drmCommandWrite(pI830->drmSubFD, DRM_I830_INIT, + &info, sizeof(drmI830Init))) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "I830 Dma Cleanup Failed\n"); + return FALSE; + } + + return TRUE; +} + +static Bool +I830InitDma(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + I830RingBuffer *ring = &(pI830->LpRing); + I830DRIPtr pI830DRI = (I830DRIPtr) pI830->pDRIInfo->devPrivate; + drmI830Init info; + + memset(&info, 0, sizeof(drmI830Init)); + info.func = I830_INIT_DMA; + + info.ring_start = ring->mem.Start + pI830->LinearAddr; + info.ring_end = ring->mem.End + pI830->LinearAddr; + info.ring_size = ring->mem.Size; + + info.mmio_offset = (unsigned int)pI830DRI->regs; + info.buffers_offset = (unsigned int)pI830->buffer_map; + + info.sarea_priv_offset = sizeof(XF86DRISAREARec); + + info.front_offset = pI830->FrontBuffer.Start; + info.back_offset = pI830->BackBuffer.Start; + info.depth_offset = pI830->DepthBuffer.Start; + info.w = pScrn->virtualX; + info.h = pScrn->virtualY; + info.pitch = pI830->auxPitch; + info.pitch_bits = pI830->auxPitchBits; + info.back_pitch = pI830->auxPitch; + info.depth_pitch = pI830->auxPitch; + info.cpp = pI830->cpp; + + if (drmCommandWrite(pI830->drmSubFD, DRM_I830_INIT, + &info, sizeof(drmI830Init))) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "I830 Dma Initialization Failed\n"); + return FALSE; + } + + return TRUE; +} + +static Bool +I830SetParam(ScrnInfoPtr pScrn, int param, int value) +{ + I830Ptr pI830 = I830PTR(pScrn); + drmI830SetParam sp; + + memset(&sp, 0, sizeof(sp)); + sp.param = param; + sp.value = value; + + if (drmCommandWrite(pI830->drmSubFD, DRM_I830_SETPARAM, &sp, sizeof(sp))) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "I830 SetParam Failed\n"); + return FALSE; + } + + return TRUE; +} + + +static Bool +I830InitVisualConfigs(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I830Ptr pI830 = I830PTR(pScrn); + int numConfigs = 0; + __GLXvisualConfig *pConfigs = 0; + I830ConfigPrivPtr pI830Configs = 0; + I830ConfigPrivPtr *pI830ConfigPtrs = 0; + int accum, stencil, db, depth; + int i; + + switch (pScrn->bitsPerPixel) { + case 8: + case 24: + break; + + case 16: + numConfigs = 8; + + pConfigs = + (__GLXvisualConfig *) xcalloc(sizeof(__GLXvisualConfig), + numConfigs); + if (!pConfigs) + return FALSE; + + pI830Configs = + (I830ConfigPrivPtr) xcalloc(sizeof(I830ConfigPrivRec), + numConfigs); + if (!pI830Configs) { + xfree(pConfigs); + return FALSE; + } + + pI830ConfigPtrs = + (I830ConfigPrivPtr *) xcalloc(sizeof(I830ConfigPrivPtr), + numConfigs); + if (!pI830ConfigPtrs) { + xfree(pConfigs); + xfree(pI830Configs); + return FALSE; + } + + for (i = 0; i < numConfigs; i++) + pI830ConfigPtrs[i] = &pI830Configs[i]; + + i = 0; + depth = 1; + for (accum = 0; accum <= 1; accum++) { + for (stencil = 0; stencil <= 1; stencil++) { + for (db = 1; db >= 0; db--) { + pConfigs[i].vid = -1; + pConfigs[i].class = -1; + pConfigs[i].rgba = TRUE; + pConfigs[i].redSize = 5; + pConfigs[i].greenSize = 6; + pConfigs[i].blueSize = 5; + pConfigs[i].redMask = 0x0000F800; + pConfigs[i].greenMask = 0x000007E0; + pConfigs[i].blueMask = 0x0000001F; + pConfigs[i].alphaMask = 0; + if (accum) { + pConfigs[i].accumRedSize = 16; + pConfigs[i].accumGreenSize = 16; + pConfigs[i].accumBlueSize = 16; + pConfigs[i].accumAlphaSize = 16; + } else { + pConfigs[i].accumRedSize = 0; + pConfigs[i].accumGreenSize = 0; + pConfigs[i].accumBlueSize = 0; + pConfigs[i].accumAlphaSize = 0; + } + pConfigs[i].doubleBuffer = db ? TRUE : FALSE; + pConfigs[i].stereo = FALSE; + pConfigs[i].bufferSize = 16; + if (depth) + pConfigs[i].depthSize = 16; + else + pConfigs[i].depthSize = 0; + if (stencil) + pConfigs[i].stencilSize = 8; + else + pConfigs[i].stencilSize = 0; + pConfigs[i].auxBuffers = 0; + pConfigs[i].level = 0; + if (stencil || accum) + pConfigs[i].visualRating = GLX_SLOW_VISUAL_EXT; + else + pConfigs[i].visualRating = GLX_NONE_EXT; + pConfigs[i].transparentPixel = 0; + pConfigs[i].transparentRed = 0; + pConfigs[i].transparentGreen = 0; + pConfigs[i].transparentBlue = 0; + pConfigs[i].transparentAlpha = 0; + pConfigs[i].transparentIndex = 0; + i++; + } + } + } + assert(i == numConfigs); + break; + + case 32: + numConfigs = 8; + + pConfigs = (__GLXvisualConfig *) xcalloc(sizeof(__GLXvisualConfig), + numConfigs); + if (!pConfigs) { + return FALSE; + } + + pI830Configs = (I830ConfigPrivPtr) xcalloc(sizeof(I830ConfigPrivRec), + numConfigs); + if (!pI830Configs) { + xfree(pConfigs); + return FALSE; + } + + pI830ConfigPtrs = (I830ConfigPrivPtr *) + xcalloc(sizeof(I830ConfigPrivPtr), numConfigs); + if (!pI830ConfigPtrs) { + xfree(pConfigs); + xfree(pI830Configs); + return FALSE; + } + + for (i = 0; i < numConfigs; i++) { + pI830ConfigPtrs[i] = &pI830Configs[i]; + } + + i = 0; + for (accum = 0; accum <= 1; accum++) { + for (depth = 0; depth <= 1; depth++) { /* and stencil */ + for (db = 1; db >= 0; db--) { + pConfigs[i].vid = -1; + pConfigs[i].class = -1; + pConfigs[i].rgba = TRUE; + pConfigs[i].redSize = 8; + pConfigs[i].greenSize = 8; + pConfigs[i].blueSize = 8; + pConfigs[i].alphaSize = 0; + pConfigs[i].redMask = 0x00FF0000; + pConfigs[i].greenMask = 0x0000FF00; + pConfigs[i].blueMask = 0x000000FF; + pConfigs[i].alphaMask = 0x00000000;; + if (accum) { + pConfigs[i].accumRedSize = 16; + pConfigs[i].accumGreenSize = 16; + pConfigs[i].accumBlueSize = 16; + pConfigs[i].accumAlphaSize = 0; + } else { + pConfigs[i].accumRedSize = 0; + pConfigs[i].accumGreenSize = 0; + pConfigs[i].accumBlueSize = 0; + pConfigs[i].accumAlphaSize = 0; + } + if (db) { + pConfigs[i].doubleBuffer = TRUE; + } else { + pConfigs[i].doubleBuffer = FALSE; + } + pConfigs[i].stereo = FALSE; + pConfigs[i].bufferSize = 24; + if (depth) { + pConfigs[i].depthSize = 24; + pConfigs[i].stencilSize = 8; + } else { + pConfigs[i].depthSize = 0; + pConfigs[i].stencilSize = 0; + } + pConfigs[i].auxBuffers = 0; + pConfigs[i].level = 0; + if (accum) { + pConfigs[i].visualRating = GLX_SLOW_VISUAL_EXT; + } else { + pConfigs[i].visualRating = GLX_NONE_EXT; + } + pConfigs[i].transparentPixel = 0; + pConfigs[i].transparentRed = 0; + pConfigs[i].transparentGreen = 0; + pConfigs[i].transparentBlue = 0; + pConfigs[i].transparentAlpha = 0; + pConfigs[i].transparentIndex = 0; + i++; + } + } + } + if (i != numConfigs) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "[drm] Incorrect initialization of visuals\n"); + return FALSE; + } + break; + + } + pI830->numVisualConfigs = numConfigs; + pI830->pVisualConfigs = pConfigs; + pI830->pVisualConfigsPriv = pI830Configs; + GlxSetVisualConfigs(numConfigs, pConfigs, (void **)pI830ConfigPtrs); + return TRUE; +} + +Bool +I830DRIScreenInit(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I830Ptr pI830 = I830PTR(pScrn); + DRIInfoPtr pDRIInfo; + I830DRIPtr pI830DRI; + + DPRINTF(PFX, "I830DRIScreenInit\n"); + /* Hardware 3D rendering only implemented for 16bpp and 32 bpp */ + if (((pScrn->bitsPerPixel / 8) != 2 && pScrn->depth != 16) && + (pScrn->bitsPerPixel / 8) != 4) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[drm] Direct rendering only supported in 16 and 32 bpp modes\n"); + return FALSE; + } + + /* Check that the GLX, DRI, and DRM modules have been loaded by testing + * for known symbols in each module. */ + if (!xf86LoaderCheckSymbol("GlxSetVisualConfigs")) + return FALSE; + if (!xf86LoaderCheckSymbol("DRIScreenInit")) + return FALSE; + if (!xf86LoaderCheckSymbol("drmAvailable")) + return FALSE; + if (!xf86LoaderCheckSymbol("DRIQueryVersion")) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[dri] %s failed (libdri.a too old)\n", "I830DRIScreenInit"); + return FALSE; + } + + /* Check the DRI version */ + { + int major, minor, patch; + + DRIQueryVersion(&major, &minor, &patch); + if (major != 4 || minor < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[dri] %s failed because of a version mismatch.\n" + "[dri] libDRI version is %d.%d.%d bug version 4.0.x is needed.\n" + "[dri] Disabling DRI.\n", + "I830DRIScreenInit", major, minor, patch); + return FALSE; + } + } + + pDRIInfo = DRICreateInfoRec(); + if (!pDRIInfo) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[dri] DRICreateInfoRec failed. Disabling DRI.\n"); + return FALSE; + } + + pI830->pDRIInfo = pDRIInfo; + pI830->LockHeld = 0; + + pDRIInfo->drmDriverName = I830KernelDriverName; + pDRIInfo->clientDriverName = I830ClientDriverName; + pDRIInfo->busIdString = xalloc(64); + + sprintf(pDRIInfo->busIdString, "PCI:%d:%d:%d", + ((pciConfigPtr) pI830->PciInfo->thisCard)->busnum, + ((pciConfigPtr) pI830->PciInfo->thisCard)->devnum, + ((pciConfigPtr) pI830->PciInfo->thisCard)->funcnum); + pDRIInfo->ddxDriverMajorVersion = I830_MAJOR_VERSION; + pDRIInfo->ddxDriverMinorVersion = I830_MINOR_VERSION; + pDRIInfo->ddxDriverPatchVersion = I830_PATCHLEVEL; + pDRIInfo->frameBufferPhysicalAddress = pI830->LinearAddr + + pI830->FrontBuffer.Start; + pDRIInfo->frameBufferSize = ROUND_TO_PAGE(pScrn->displayWidth * + pScrn->virtualY * pI830->cpp); + pDRIInfo->frameBufferStride = pScrn->displayWidth * pI830->cpp; + pDRIInfo->ddxDrawableTableEntry = I830_MAX_DRAWABLES; + + if (SAREA_MAX_DRAWABLES < I830_MAX_DRAWABLES) + pDRIInfo->maxDrawableTableEntry = SAREA_MAX_DRAWABLES; + else + pDRIInfo->maxDrawableTableEntry = I830_MAX_DRAWABLES; + + if (sizeof(XF86DRISAREARec) + sizeof(I830SAREARec) > SAREA_MAX) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[dri] Data does not fit in SAREA\n"); + return FALSE; + } + /* This is a hack for now. We have to have more than a 4k page here + * because of the size of the state. However, the state should be + * in a per-context mapping. This will be added in the Mesa 3.5 port + * of the I830 driver. + */ + pDRIInfo->SAREASize = SAREA_MAX; + + if (!(pI830DRI = (I830DRIPtr) xcalloc(sizeof(I830DRIRec), 1))) { + DRIDestroyInfoRec(pI830->pDRIInfo); + pI830->pDRIInfo = 0; + return FALSE; + } + pDRIInfo->devPrivate = pI830DRI; + pDRIInfo->devPrivateSize = sizeof(I830DRIRec); + pDRIInfo->contextSize = sizeof(I830DRIContextRec); + + pDRIInfo->CreateContext = I830CreateContext; + pDRIInfo->DestroyContext = I830DestroyContext; + pDRIInfo->SwapContext = I830DRISwapContext; + pDRIInfo->InitBuffers = I830DRIInitBuffers; + pDRIInfo->MoveBuffers = I830DRIMoveBuffers; + pDRIInfo->bufferRequests = DRI_ALL_WINDOWS; + pDRIInfo->OpenFullScreen = I830DRIOpenFullScreen; + pDRIInfo->CloseFullScreen = I830DRICloseFullScreen; + pDRIInfo->TransitionTo2d = I830DRITransitionTo2d; + pDRIInfo->TransitionTo3d = I830DRITransitionTo3d; + pDRIInfo->TransitionSingleToMulti3D = I830DRITransitionSingleToMulti3d; + pDRIInfo->TransitionMultiToSingle3D = I830DRITransitionMultiToSingle3d; + + if (!DRIScreenInit(pScreen, pDRIInfo, &pI830->drmSubFD)) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[dri] DRIScreenInit failed. Disabling DRI.\n"); + xfree(pDRIInfo->devPrivate); + pDRIInfo->devPrivate = 0; + DRIDestroyInfoRec(pI830->pDRIInfo); + pI830->pDRIInfo = 0; + return FALSE; + } + + /* Check the i830 DRM versioning */ + { + drmVersionPtr version; + + /* Check the DRM lib version. + * drmGetLibVersion was not supported in version 1.0, so check for + * symbol first to avoid possible crash or hang. + */ + if (xf86LoaderCheckSymbol("drmGetLibVersion")) { + version = drmGetLibVersion(pI830->drmSubFD); + } else + { + /* drmlib version 1.0.0 didn't have the drmGetLibVersion + * entry point. Fake it by allocating a version record + * via drmGetVersion and changing it to version 1.0.0 + */ + version = drmGetVersion(pI830->drmSubFD); + version->version_major = 1; + version->version_minor = 0; + version->version_patchlevel = 0; + } + +#define REQ_MAJ 1 +#define REQ_MIN 1 + if (version) { + if (version->version_major != REQ_MAJ || + version->version_minor < REQ_MIN) { + /* incompatible drm library version */ + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[dri] I830DRIScreenInit failed because of a version mismatch.\n" + "[dri] libdrm.a module version is %d.%d.%d but version %d.%d.x is needed.\n" + "[dri] Disabling DRI.\n", + version->version_major, + version->version_minor, version->version_patchlevel, + REQ_MAJ, REQ_MIN); + drmFreeVersion(version); + I830DRICloseScreen(pScreen); + return FALSE; + } + drmFreeVersion(version); + } + + /* Check the i830 DRM version */ + version = drmGetVersion(pI830->drmSubFD); + if (version) { + if (version->version_major != 1 || version->version_minor < 3) { + /* incompatible drm version */ + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[dri] %s failed because of a version mismatch.\n" + "[dri] i830.o kernel module version is %d.%d.%d but version 1.3 or greater is needed.\n" + "[dri] Disabling DRI.\n", + "I830DRIScreenInit", + version->version_major, + version->version_minor, version->version_patchlevel); + I830DRICloseScreen(pScreen); + drmFreeVersion(version); + return FALSE; + } + pI830->drmMinor = version->version_minor; + drmFreeVersion(version); + } + } + return TRUE; +} + +Bool +I830DRIDoMappings(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I830Ptr pI830 = I830PTR(pScrn); + DRIInfoPtr pDRIInfo = pI830->pDRIInfo; + I830DRIPtr pI830DRI = pDRIInfo->devPrivate; + int bufs; + + DPRINTF(PFX, "I830DRIDoMappings\n"); + pI830DRI->regsSize = I830_REG_SIZE; + if (drmAddMap(pI830->drmSubFD, (drmHandle)pI830->MMIOAddr, + pI830DRI->regsSize, DRM_REGISTERS, 0, &pI830DRI->regs) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, "[drm] drmAddMap(regs) failed\n"); + DRICloseScreen(pScreen); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, "[drm] Registers = 0x%08lx\n", + pI830DRI->regs); + + /* + * The tile setup is now initiated from I830BIOSScreenInit(). + */ + + pI830->auxPitch = pScrn->displayWidth; + pI830->auxPitchBits = 0; + + pI830DRI->backbufferSize = pI830->BackBuffer.Size; + + if (drmAddMap(pI830->drmSubFD, + (drmHandle)pI830->BackBuffer.Start + pI830->LinearAddr, + pI830->BackBuffer.Size, DRM_AGP, 0, + &pI830DRI->backbuffer) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[drm] drmAddMap(backbuffer) failed. Disabling DRI\n"); + DRICloseScreen(pScreen); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, "[drm] Back Buffer = 0x%08lx\n", + pI830DRI->backbuffer); + + pI830DRI->depthbufferSize = pI830->DepthBuffer.Size; + if (drmAddMap(pI830->drmSubFD, + (drmHandle)pI830->DepthBuffer.Start + pI830->LinearAddr, + pI830->DepthBuffer.Size, DRM_AGP, 0, + &pI830DRI->depthbuffer) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[drm] drmAddMap(depthbuffer) failed. Disabling DRI\n"); + DRICloseScreen(pScreen); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, "[drm] Depth Buffer = 0x%08lx\n", + pI830DRI->depthbuffer); + + if (drmAddMap(pI830->drmSubFD, + (drmHandle)pI830->BufferMem.Start + pI830->LinearAddr, + pI830->BufferMem.Size, DRM_AGP, 0, + &pI830->buffer_map) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[drm] drmAddMap(buffer_map) failed. Disabling DRI\n"); + DRICloseScreen(pScreen); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, "[drm] DMA Buffers = 0x%08lx\n", + pI830->buffer_map); + + pI830DRI->agp_buffers = pI830->buffer_map; + pI830DRI->agp_buf_size = pI830->BufferMem.Size; + + if (drmAddMap(pI830->drmSubFD, + (drmHandle)pI830->LpRing.mem.Start + pI830->LinearAddr, + pI830->LpRing.mem.Size, DRM_AGP, 0, + &pI830->ring_map) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[drm] drmAddMap(ring_map) failed. Disabling DRI\n"); + DRICloseScreen(pScreen); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, "[drm] ring buffer = 0x%08lx\n", + pI830->ring_map); + + pI830DRI->textureSize = pI830->TexMem.Size; + pI830DRI->logTextureGranularity = pI830->TexGranularity; + + if (drmAddMap(pI830->drmSubFD, + (drmHandle)pI830->TexMem.Start + pI830->LinearAddr, + pI830->TexMem.Size, DRM_AGP, 0, + &pI830DRI->textures) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[drm] drmAddMap(textures) failed. Disabling DRI\n"); + DRICloseScreen(pScreen); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, "[drm] textures = 0x%08lx\n", + pI830DRI->textures); + + if ((bufs = drmAddBufs(pI830->drmSubFD, + I830_DMA_BUF_NR, + I830_DMA_BUF_SZ, + DRM_AGP_BUFFER, pI830DRI->agp_buffers)) <= 0) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[drm] failure adding %d %d byte DMA buffers\n", + I830_DMA_BUF_NR, I830_DMA_BUF_SZ); + DRICloseScreen(pScreen); + return FALSE; + } + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[drm] added %d %d byte DMA buffers\n", bufs, I830_DMA_BUF_SZ); + + I830InitDma(pScrn); + + if (pI830->PciInfo->chipType != PCI_CHIP_845_G && + pI830->PciInfo->chipType != PCI_CHIP_I830_M) { + I830SetParam(pScrn, I830_SETPARAM_USE_MI_BATCHBUFFER_START, 1 ); + } + + /* Okay now initialize the dma engine */ + if (!pI830DRI->irq) { + pI830DRI->irq = drmGetInterruptFromBusID(pI830->drmSubFD, + ((pciConfigPtr) pI830-> + PciInfo->thisCard)->busnum, + ((pciConfigPtr) pI830-> + PciInfo->thisCard)->devnum, + ((pciConfigPtr) pI830-> + PciInfo->thisCard)->funcnum); +#if 1 + if ((drmCtlInstHandler(pI830->drmSubFD, pI830DRI->irq)) != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[drm] failure adding irq handler, there is a device already using that irq\n" + "[drm] Consider rearranging your PCI cards\n"); + DRICloseScreen(pScreen); + return FALSE; + } +#endif + } + + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[drm] dma control initialized, using IRQ %d\n", pI830DRI->irq); + + pI830DRI = (I830DRIPtr) pI830->pDRIInfo->devPrivate; + pI830DRI->deviceID = pI830->PciInfo->chipType; + pI830DRI->width = pScrn->virtualX; + pI830DRI->height = pScrn->virtualY; + pI830DRI->mem = pScrn->videoRam * 1024; + pI830DRI->cpp = pI830->cpp; + + pI830DRI->fbOffset = pI830->FrontBuffer.Start; + pI830DRI->fbStride = pI830->auxPitch; + + pI830DRI->bitsPerPixel = pScrn->bitsPerPixel; + + pI830DRI->textureOffset = pI830->TexMem.Start; + + pI830DRI->backOffset = pI830->BackBuffer.Start; + pI830DRI->depthOffset = pI830->DepthBuffer.Start; + + pI830DRI->ringOffset = pI830->LpRing.mem.Start; + pI830DRI->ringSize = pI830->LpRing.mem.Size; + + pI830DRI->auxPitch = pI830->auxPitch; + pI830DRI->auxPitchBits = pI830->auxPitchBits; + pI830DRI->sarea_priv_offset = sizeof(XF86DRISAREARec); + + if (!(I830InitVisualConfigs(pScreen))) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[dri] I830InitVisualConfigs failed. Disabling DRI\n"); + DRICloseScreen(pScreen); + return FALSE; + } + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[dri] visual configs initialized\n"); + pI830->pDRIInfo->driverSwapMethod = DRI_HIDE_X_CONTEXT; + + return TRUE; +} + +void +I830DRICloseScreen(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I830Ptr pI830 = I830PTR(pScrn); + + DPRINTF(PFX, "I830DRICloseScreen\n"); + + I830CleanupDma(pScrn); + + DRICloseScreen(pScreen); + + if (pI830->pDRIInfo) { + if (pI830->pDRIInfo->devPrivate) { + xfree(pI830->pDRIInfo->devPrivate); + pI830->pDRIInfo->devPrivate = 0; + } + DRIDestroyInfoRec(pI830->pDRIInfo); + pI830->pDRIInfo = 0; + } + if (pI830->pVisualConfigs) + xfree(pI830->pVisualConfigs); + if (pI830->pVisualConfigsPriv) + xfree(pI830->pVisualConfigsPriv); +} + +static Bool +I830CreateContext(ScreenPtr pScreen, VisualPtr visual, + drmContext hwContext, void *pVisualConfigPriv, + DRIContextType contextStore) +{ + return TRUE; +} + +static void +I830DestroyContext(ScreenPtr pScreen, drmContext hwContext, + DRIContextType contextStore) +{ +} + +Bool +I830DRIFinishScreenInit(ScreenPtr pScreen) +{ + I830SAREARec *sPriv = (I830SAREARec *) DRIGetSAREAPrivate(pScreen); + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I830Ptr pI830 = I830PTR(pScrn); + + DPRINTF(PFX, "I830DRIFinishScreenInit\n"); + + memset(sPriv, 0, sizeof(sPriv)); + + /* Have shadow run only while there is 3d active. + */ + if (pI830->allowPageFlip && pI830->drmMinor >= 3) { + shadowSetup(pScreen); + shadowAdd(pScreen, 0, I830DRIShadowUpdate, 0, 0, 0); + } + else + pI830->allowPageFlip = 0; + + return DRIFinishScreenInit(pScreen); +} + +void +I830DRISwapContext(ScreenPtr pScreen, DRISyncType syncType, + DRIContextType oldContextType, void *oldContext, + DRIContextType newContextType, void *newContext) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I830Ptr pI830 = I830PTR(pScrn); + + if (syncType == DRI_3D_SYNC && + oldContextType == DRI_2D_CONTEXT && newContextType == DRI_2D_CONTEXT) { + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + + if (I810_DEBUG & DEBUG_VERBOSE_DRI) + ErrorF("i830DRISwapContext (in)\n"); + + pI830->LockHeld = 1; + I830RefreshRing(pScrn); + } else if (syncType == DRI_2D_SYNC && + oldContextType == DRI_NO_CONTEXT && + newContextType == DRI_2D_CONTEXT) { + pI830->LockHeld = 0; + if (I810_DEBUG & DEBUG_VERBOSE_DRI) + ErrorF("i830DRISwapContext (out)\n"); + } else if (I810_DEBUG & DEBUG_VERBOSE_DRI) + ErrorF("i830DRISwapContext (other)\n"); +} + +static void +I830DRIInitBuffers(WindowPtr pWin, RegionPtr prgn, CARD32 index) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I830Ptr pI830 = I830PTR(pScrn); + BoxPtr pbox = REGION_RECTS(prgn); + int nbox = REGION_NUM_RECTS(prgn); + + if (I810_DEBUG & DEBUG_VERBOSE_DRI) + ErrorF("I830DRIInitBuffers\n"); + + I830SetupForSolidFill(pScrn, 0, GXcopy, -1); + while (nbox--) { + I830SelectBuffer(pScrn, I830_SELECT_BACK); + I830SubsequentSolidFillRect(pScrn, pbox->x1, pbox->y1, + pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); + pbox++; + } + + /* Clear the depth buffer - uses 0xffff rather than 0. + */ + pbox = REGION_RECTS(prgn); + nbox = REGION_NUM_RECTS(prgn); + + I830SelectBuffer(pScrn, I830_SELECT_DEPTH); + + switch (pScrn->bitsPerPixel) { + case 16: + I830SetupForSolidFill(pScrn, 0xffff, GXcopy, -1); + break; + case 32: + I830SetupForSolidFill(pScrn, 0xffffff, GXcopy, -1); + break; + } + + while (nbox--) { + I830SubsequentSolidFillRect(pScrn, pbox->x1, pbox->y1, + pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); + pbox++; + } + + I830SelectBuffer(pScrn, I830_SELECT_FRONT); + pI830->AccelInfoRec->NeedToSync = TRUE; +} + +/* This routine is a modified form of XAADoBitBlt with the calls to + * ScreenToScreenBitBlt built in. My routine has the prgnSrc as source + * instead of destination. My origin is upside down so the ydir cases + * are reversed. + */ +static void +I830DRIMoveBuffers(WindowPtr pParent, DDXPointRec ptOldOrg, + RegionPtr prgnSrc, CARD32 index) +{ + ScreenPtr pScreen = pParent->drawable.pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I830Ptr pI830 = I830PTR(pScrn); + BoxPtr pboxTmp, pboxNext, pboxBase; + DDXPointPtr pptTmp, pptNew2; + int xdir, ydir; + + int screenwidth = pScrn->virtualX; + int screenheight = pScrn->virtualY; + + BoxPtr pbox = REGION_RECTS(prgnSrc); + int nbox = REGION_NUM_RECTS(prgnSrc); + + BoxPtr pboxNew1 = 0; + BoxPtr pboxNew2 = 0; + DDXPointPtr pptNew1 = 0; + DDXPointPtr pptSrc = &ptOldOrg; + + int dx = pParent->drawable.x - ptOldOrg.x; + int dy = pParent->drawable.y - ptOldOrg.y; + + /* If the copy will overlap in Y, reverse the order */ + if (dy > 0) { + ydir = -1; + + if (nbox > 1) { + /* Keep ordering in each band, reverse order of bands */ + pboxNew1 = (BoxPtr) ALLOCATE_LOCAL(sizeof(BoxRec) * nbox); + if (!pboxNew1) + return; + pptNew1 = (DDXPointPtr) ALLOCATE_LOCAL(sizeof(DDXPointRec) * nbox); + if (!pptNew1) { + DEALLOCATE_LOCAL(pboxNew1); + return; + } + pboxBase = pboxNext = pbox + nbox - 1; + while (pboxBase >= pbox) { + while ((pboxNext >= pbox) && (pboxBase->y1 == pboxNext->y1)) + pboxNext--; + pboxTmp = pboxNext + 1; + pptTmp = pptSrc + (pboxTmp - pbox); + while (pboxTmp <= pboxBase) { + *pboxNew1++ = *pboxTmp++; + *pptNew1++ = *pptTmp++; + } + pboxBase = pboxNext; + } + pboxNew1 -= nbox; + pbox = pboxNew1; + pptNew1 -= nbox; + pptSrc = pptNew1; + } + } else { + /* No changes required */ + ydir = 1; + } + + /* If the regions will overlap in X, reverse the order */ + if (dx > 0) { + xdir = -1; + + if (nbox > 1) { + /*reverse orderof rects in each band */ + pboxNew2 = (BoxPtr) ALLOCATE_LOCAL(sizeof(BoxRec) * nbox); + pptNew2 = (DDXPointPtr) ALLOCATE_LOCAL(sizeof(DDXPointRec) * nbox); + if (!pboxNew2 || !pptNew2) { + if (pptNew2) + DEALLOCATE_LOCAL(pptNew2); + if (pboxNew2) + DEALLOCATE_LOCAL(pboxNew2); + if (pboxNew1) { + DEALLOCATE_LOCAL(pptNew1); + DEALLOCATE_LOCAL(pboxNew1); + } + return; + } + pboxBase = pboxNext = pbox; + while (pboxBase < pbox + nbox) { + while ((pboxNext < pbox + nbox) && (pboxNext->y1 == pboxBase->y1)) + pboxNext++; + pboxTmp = pboxNext; + pptTmp = pptSrc + (pboxTmp - pbox); + while (pboxTmp != pboxBase) { + *pboxNew2++ = *--pboxTmp; + *pptNew2++ = *--pptTmp; + } + pboxBase = pboxNext; + } + pboxNew2 -= nbox; + pbox = pboxNew2; + pptNew2 -= nbox; + pptSrc = pptNew2; + } + } else { + /* No changes are needed */ + xdir = 1; + } + + /* SelectBuffer isn't really a good concept for the i810. + */ + I830EmitFlush(pScrn); + I830SetupForScreenToScreenCopy(pScrn, xdir, ydir, GXcopy, -1, -1); + for (; nbox--; pbox++) { + + int x1 = pbox->x1; + int y1 = pbox->y1; + int destx = x1 + dx; + int desty = y1 + dy; + int w = pbox->x2 - x1 + 1; + int h = pbox->y2 - y1 + 1; + + if (destx < 0) + x1 -= destx, w += destx, destx = 0; + if (desty < 0) + y1 -= desty, h += desty, desty = 0; + if (destx + w > screenwidth) + w = screenwidth - destx; + if (desty + h > screenheight) + h = screenheight - desty; + if (w <= 0) + continue; + if (h <= 0) + continue; + + if (I810_DEBUG & DEBUG_VERBOSE_DRI) + ErrorF("MoveBuffers %d,%d %dx%d dx: %d dy: %d\n", + x1, y1, w, h, dx, dy); + + I830SelectBuffer(pScrn, I830_SELECT_BACK); + I830SubsequentScreenToScreenCopy(pScrn, x1, y1, destx, desty, w, h); + I830SelectBuffer(pScrn, I830_SELECT_DEPTH); + I830SubsequentScreenToScreenCopy(pScrn, x1, y1, destx, desty, w, h); + } + I830SelectBuffer(pScrn, I830_SELECT_FRONT); + I830EmitFlush(pScrn); + + if (pboxNew2) { + DEALLOCATE_LOCAL(pptNew2); + DEALLOCATE_LOCAL(pboxNew2); + } + if (pboxNew1) { + DEALLOCATE_LOCAL(pptNew1); + DEALLOCATE_LOCAL(pboxNew1); + } + + pI830->AccelInfoRec->NeedToSync = TRUE; +} + +/* Completely Initialize the first context */ +void +I830EmitInvarientState(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + I830DRIPtr pI830DRI = (I830DRIPtr) pI830->pDRIInfo->devPrivate; + CARD32 ctx_addr, temp; + + BEGIN_LP_RING(128-2); + + ctx_addr = pI830->ContextMem.Start; + /* Align to a 2k boundry */ + ctx_addr = ((ctx_addr + 2048 - 1) / 2048) * 2048; + + OUT_RING(MI_SET_CONTEXT); + OUT_RING(ctx_addr | + CTXT_NO_RESTORE | + CTXT_PALETTE_SAVE_DISABLE | CTXT_PALETTE_RESTORE_DISABLE); + + OUT_RING(STATE3D_AA_CMD | + AA_LINE_ECAAR_WIDTH_ENABLE | + AA_LINE_ECAAR_WIDTH_1_0 | + AA_LINE_REGION_WIDTH_ENABLE | + AA_LINE_REGION_WIDTH_1_0 | AA_LINE_DISABLE); + + OUT_RING(STATE3D_BUF_INFO_CMD); + OUT_RING(BUF_3D_ID_COLOR_BACK | + BUF_3D_USE_FENCE | + BUF_3D_PITCH((pI830->cpp * pScrn->displayWidth) / 4)); + OUT_RING(BUF_3D_ADDR(pI830DRI->backOffset)); + + OUT_RING(STATE3D_BUF_INFO_CMD); + OUT_RING(BUF_3D_ID_DEPTH | + BUF_3D_USE_FENCE | + BUF_3D_PITCH((pI830->cpp * pScrn->displayWidth) / 4)); + OUT_RING(BUF_3D_ADDR(pI830DRI->depthOffset)); + + OUT_RING(STATE3D_COLOR_FACTOR); + OUT_RING(0); + + OUT_RING(STATE3D_COLOR_FACTOR_CMD(0)); + OUT_RING(0); + + OUT_RING(STATE3D_COLOR_FACTOR_CMD(1)); + OUT_RING(0); + + OUT_RING(STATE3D_COLOR_FACTOR_CMD(2)); + OUT_RING(0); + + OUT_RING(STATE3D_COLOR_FACTOR_CMD(3)); + OUT_RING(0); + + OUT_RING(STATE3D_CONST_BLEND_COLOR_CMD); + OUT_RING(0); + + OUT_RING(STATE3D_DFLT_DIFFUSE_CMD); + OUT_RING(0); + + OUT_RING(STATE3D_DFLT_SPEC_CMD); + OUT_RING(0); + + OUT_RING(STATE3D_DFLT_Z_CMD); + OUT_RING(0); + + switch (pScrn->bitsPerPixel) { + case 15: + temp = DEPTH_FRMT_16_FIXED | COLR_BUF_RGB555; + break; + case 16: + temp = DEPTH_FRMT_16_FIXED | COLR_BUF_RGB565; + break; + case 32: + temp = DEPTH_FRMT_24_FIXED_8_OTHER | COLR_BUF_ARGB8888; + break; + default: + temp = DEPTH_FRMT_16_FIXED | COLR_BUF_RGB565; + break; + } + + OUT_RING(STATE3D_DST_BUF_VARS_CMD); + OUT_RING(DSTORG_HORT_BIAS(0x8) | + DSTORG_VERT_BIAS(0x8) | DEPTH_IS_Z | temp); + + OUT_RING(STATE3D_DRAW_RECT_CMD); + OUT_RING(DRAW_RECT_DIS_DEPTH_OFS); + OUT_RING(0); + OUT_RING((pI830DRI->height << 16) | pI830DRI->width); + OUT_RING(0); + + OUT_RING(STATE3D_ENABLES_1_CMD | + DISABLE_LOGIC_OP | + DISABLE_STENCIL_TEST | + DISABLE_DEPTH_BIAS | + DISABLE_SPEC_ADD | + I830_DISABLE_FOG | + DISABLE_ALPHA_TEST | DISABLE_COLOR_BLEND | DISABLE_DEPTH_TEST); + + OUT_RING(STATE3D_ENABLES_2_CMD | + DISABLE_STENCIL_WRITE | + ENABLE_TEX_CACHE | + ENABLE_DITHER | + ENABLE_COLOR_MASK | ENABLE_COLOR_WRITE | ENABLE_DEPTH_WRITE); + + OUT_RING(STATE3D_FOG_COLOR_CMD | + FOG_COLOR_RED(0) | FOG_COLOR_GREEN(0) | FOG_COLOR_BLUE(0)); + + OUT_RING(STATE3D_FOG_MODE); + OUT_RING(FOG_MODE_VERTEX | + ENABLE_FOG_CONST | ENABLE_FOG_SOURCE | ENABLE_FOG_DENSITY); + OUT_RING(0); + OUT_RING(0); + + OUT_RING(STATE3D_INDPT_ALPHA_BLEND_CMD | + DISABLE_INDPT_ALPHA_BLEND | + ENABLE_ALPHA_BLENDFUNC | + ABLENDFUNC_ADD | + ENABLE_SRC_ABLEND_FACTOR | + SRC_ABLEND_FACT(BLENDFACT_ONE) | + ENABLE_DST_ABLEND_FACTOR | SRC_ABLEND_FACT(BLENDFACT_ZERO)); + + /* I need to come back to texture state */ + OUT_RING(STATE3D_MAP_BLEND_ARG_CMD(0) | + TEXPIPE_COLOR | + TEXBLEND_ARG1 | TEXBLENDARG_MODIFY_PARMS | TEXBLENDARG_DIFFUSE); + OUT_RING(STATE3D_MAP_BLEND_ARG_CMD(1) | + TEXPIPE_COLOR | + TEXBLEND_ARG1 | TEXBLENDARG_MODIFY_PARMS | TEXBLENDARG_DIFFUSE); + OUT_RING(STATE3D_MAP_BLEND_ARG_CMD(2) | + TEXPIPE_COLOR | + TEXBLEND_ARG1 | TEXBLENDARG_MODIFY_PARMS | TEXBLENDARG_DIFFUSE); + OUT_RING(STATE3D_MAP_BLEND_ARG_CMD(3) | + TEXPIPE_COLOR | + TEXBLEND_ARG1 | TEXBLENDARG_MODIFY_PARMS | TEXBLENDARG_DIFFUSE); + + OUT_RING(STATE3D_MAP_BLEND_ARG_CMD(0) | + TEXPIPE_ALPHA | + TEXBLEND_ARG1 | TEXBLENDARG_MODIFY_PARMS | TEXBLENDARG_DIFFUSE); + OUT_RING(STATE3D_MAP_BLEND_ARG_CMD(1) | + TEXPIPE_ALPHA | + TEXBLEND_ARG1 | TEXBLENDARG_MODIFY_PARMS | TEXBLENDARG_DIFFUSE); + OUT_RING(STATE3D_MAP_BLEND_ARG_CMD(2) | + TEXPIPE_ALPHA | + TEXBLEND_ARG1 | TEXBLENDARG_MODIFY_PARMS | TEXBLENDARG_DIFFUSE); + OUT_RING(STATE3D_MAP_BLEND_ARG_CMD(3) | + TEXPIPE_ALPHA | + TEXBLEND_ARG1 | TEXBLENDARG_MODIFY_PARMS | TEXBLENDARG_DIFFUSE); + + OUT_RING(STATE3D_MAP_BLEND_OP_CMD(0) | + TEXPIPE_COLOR | + ENABLE_TEXOUTPUT_WRT_SEL | + TEXOP_OUTPUT_CURRENT | + DISABLE_TEX_CNTRL_STAGE | + TEXOP_SCALE_1X | + TEXOP_MODIFY_PARMS | TEXOP_LAST_STAGE | TEXBLENDOP_ARG1); + OUT_RING(STATE3D_MAP_BLEND_OP_CMD(0) | + TEXPIPE_ALPHA | + ENABLE_TEXOUTPUT_WRT_SEL | + TEXOP_OUTPUT_CURRENT | + TEXOP_SCALE_1X | TEXOP_MODIFY_PARMS | TEXBLENDOP_ARG1); + + OUT_RING(STATE3D_MAP_COORD_SETBIND_CMD); + OUT_RING(TEXBIND_SET3(TEXCOORDSRC_DEFAULT) | + TEXBIND_SET2(TEXCOORDSRC_DEFAULT) | + TEXBIND_SET1(TEXCOORDSRC_DEFAULT) | + TEXBIND_SET0(TEXCOORDSRC_DEFAULT)); + + OUT_RING(STATE3D_MAP_COORD_SET_CMD | + MAP_UNIT(0) | + TEXCOORDS_ARE_IN_TEXELUNITS | + TEXCOORDTYPE_CARTESIAN | + ENABLE_ADDR_V_CNTL | + ENABLE_ADDR_U_CNTL | + TEXCOORD_ADDR_V_MODE(TEXCOORDMODE_CLAMP) | + TEXCOORD_ADDR_U_MODE(TEXCOORDMODE_CLAMP)); + OUT_RING(STATE3D_MAP_COORD_SET_CMD | + MAP_UNIT(1) | + TEXCOORDS_ARE_IN_TEXELUNITS | + TEXCOORDTYPE_CARTESIAN | + ENABLE_ADDR_V_CNTL | + ENABLE_ADDR_U_CNTL | + TEXCOORD_ADDR_V_MODE(TEXCOORDMODE_CLAMP) | + TEXCOORD_ADDR_U_MODE(TEXCOORDMODE_CLAMP)); + OUT_RING(STATE3D_MAP_COORD_SET_CMD | + MAP_UNIT(2) | + TEXCOORDS_ARE_IN_TEXELUNITS | + TEXCOORDTYPE_CARTESIAN | + ENABLE_ADDR_V_CNTL | + ENABLE_ADDR_U_CNTL | + TEXCOORD_ADDR_V_MODE(TEXCOORDMODE_CLAMP) | + TEXCOORD_ADDR_U_MODE(TEXCOORDMODE_CLAMP)); + OUT_RING(STATE3D_MAP_COORD_SET_CMD | + MAP_UNIT(3) | + TEXCOORDS_ARE_IN_TEXELUNITS | + TEXCOORDTYPE_CARTESIAN | + ENABLE_ADDR_V_CNTL | + ENABLE_ADDR_U_CNTL | + TEXCOORD_ADDR_V_MODE(TEXCOORDMODE_CLAMP) | + TEXCOORD_ADDR_U_MODE(TEXCOORDMODE_CLAMP)); + + OUT_RING(STATE3D_MAP_TEX_STREAM_CMD | + MAP_UNIT(0) | + DISABLE_TEX_STREAM_BUMP | + ENABLE_TEX_STREAM_COORD_SET | + TEX_STREAM_COORD_SET(0) | + ENABLE_TEX_STREAM_MAP_IDX | TEX_STREAM_MAP_IDX(0)); + OUT_RING(STATE3D_MAP_TEX_STREAM_CMD | + MAP_UNIT(1) | + DISABLE_TEX_STREAM_BUMP | + ENABLE_TEX_STREAM_COORD_SET | + TEX_STREAM_COORD_SET(1) | + ENABLE_TEX_STREAM_MAP_IDX | TEX_STREAM_MAP_IDX(1)); + OUT_RING(STATE3D_MAP_TEX_STREAM_CMD | + MAP_UNIT(2) | + DISABLE_TEX_STREAM_BUMP | + ENABLE_TEX_STREAM_COORD_SET | + TEX_STREAM_COORD_SET(2) | + ENABLE_TEX_STREAM_MAP_IDX | TEX_STREAM_MAP_IDX(2)); + OUT_RING(STATE3D_MAP_TEX_STREAM_CMD | + MAP_UNIT(3) | + DISABLE_TEX_STREAM_BUMP | + ENABLE_TEX_STREAM_COORD_SET | + TEX_STREAM_COORD_SET(3) | + ENABLE_TEX_STREAM_MAP_IDX | TEX_STREAM_MAP_IDX(3)); + +#if 0 + OUT_RING(STATE3D_MAP_FILTER_CMD | + MAP_UNIT(0) | + ENABLE_CHROMA_KEY_PARAMS | + ENABLE_MIP_MODE_FILTER | + MIPFILTER_NEAREST | + ENABLE_MAG_MODE_FILTER | + ENABLE_MIN_MODE_FILTER | + MAG_FILTER(FILTER_NEAREST) | MIN_FILTER(FILTER_NEAREST)); + OUT_RING(STATE3D_MAP_FILTER_CMD | + MAP_UNIT(1) | + ENABLE_CHROMA_KEY_PARAMS | + ENABLE_MIP_MODE_FILTER | + MIPFILTER_NEAREST | + ENABLE_MAG_MODE_FILTER | + ENABLE_MIN_MODE_FILTER | + MAG_FILTER(FILTER_NEAREST) | MIN_FILTER(FILTER_NEAREST)); + OUT_RING(STATE3D_MAP_FILTER_CMD | + MAP_UNIT(2) | + ENABLE_CHROMA_KEY_PARAMS | + ENABLE_MIP_MODE_FILTER | + MIPFILTER_NEAREST | + ENABLE_MAG_MODE_FILTER | + ENABLE_MIN_MODE_FILTER | + MAG_FILTER(FILTER_NEAREST) | MIN_FILTER(FILTER_NEAREST)); + OUT_RING(STATE3D_MAP_FILTER_CMD | + MAP_UNIT(3) | + ENABLE_CHROMA_KEY_PARAMS | + ENABLE_MIP_MODE_FILTER | + MIPFILTER_NEAREST | + ENABLE_MAG_MODE_FILTER | + ENABLE_MIN_MODE_FILTER | + MAG_FILTER(FILTER_NEAREST) | MIN_FILTER(FILTER_NEAREST)); + + OUT_RING(STATE3D_MAP_INFO_COLR_CMD); + OUT_RING(MAP_INFO_TEX(0) | + MAPSURF_32BIT | + MT_32BIT_ARGB8888 | + MAP_INFO_OUTMUX_F0F1F2F3 | + MAP_INFO_VERTLINESTRIDEOFS_0 | + MAP_INFO_FORMAT_2D | MAP_INFO_USE_FENCE); + OUT_RING(MAP_INFO_HEIGHT(0) | MAP_INFO_WIDTH(0)); + OUT_RING(MAP_INFO_BASEADDR(pI830->TexMem.Start)); + OUT_RING(MAP_INFO_DWORD_PITCH(31)); + OUT_RING(MAP_INFO_DFLT_COLR(0)); + + OUT_RING(STATE3D_MAP_INFO_COLR_CMD); + OUT_RING(MAP_INFO_TEX(1) | + MAPSURF_32BIT | + MT_32BIT_ARGB8888 | + MAP_INFO_OUTMUX_F0F1F2F3 | + MAP_INFO_VERTLINESTRIDEOFS_0 | + MAP_INFO_FORMAT_2D | MAP_INFO_USE_FENCE); + OUT_RING(MAP_INFO_HEIGHT(0) | MAP_INFO_WIDTH(0)); + OUT_RING(MAP_INFO_BASEADDR(pI830->TexMem.Start)); + OUT_RING(MAP_INFO_DWORD_PITCH(31)); + OUT_RING(MAP_INFO_DFLT_COLR(0)); + + OUT_RING(STATE3D_MAP_INFO_COLR_CMD); + OUT_RING(MAP_INFO_TEX(2) | + MAPSURF_32BIT | + MT_32BIT_ARGB8888 | + MAP_INFO_OUTMUX_F0F1F2F3 | + MAP_INFO_VERTLINESTRIDEOFS_0 | + MAP_INFO_FORMAT_2D | MAP_INFO_USE_FENCE); + OUT_RING(MAP_INFO_HEIGHT(0) | MAP_INFO_WIDTH(0)); + OUT_RING(MAP_INFO_BASEADDR(pI830->TexMem.Start)); + OUT_RING(MAP_INFO_DWORD_PITCH(31)); + OUT_RING(MAP_INFO_DFLT_COLR(0)); + + OUT_RING(STATE3D_MAP_INFO_COLR_CMD); + OUT_RING(MAP_INFO_TEX(3) | + MAPSURF_32BIT | + MT_32BIT_ARGB8888 | + MAP_INFO_OUTMUX_F0F1F2F3 | + MAP_INFO_VERTLINESTRIDEOFS_0 | + MAP_INFO_FORMAT_2D | MAP_INFO_USE_FENCE); + OUT_RING(MAP_INFO_HEIGHT(0) | MAP_INFO_WIDTH(0)); + OUT_RING(MAP_INFO_BASEADDR(pI830->TexMem.Start)); + OUT_RING(MAP_INFO_DWORD_PITCH(31)); + OUT_RING(MAP_INFO_DFLT_COLR(0)); + + OUT_RING(STATE3D_MAP_LOD_CNTL_CMD | + MAP_UNIT(0) | ENABLE_TEXLOD_BIAS | MAP_LOD_BIAS(0)); + OUT_RING(STATE3D_MAP_LOD_CNTL_CMD | + MAP_UNIT(1) | ENABLE_TEXLOD_BIAS | MAP_LOD_BIAS(0)); + OUT_RING(STATE3D_MAP_LOD_CNTL_CMD | + MAP_UNIT(2) | ENABLE_TEXLOD_BIAS | MAP_LOD_BIAS(0)); + OUT_RING(STATE3D_MAP_LOD_CNTL_CMD | + MAP_UNIT(3) | ENABLE_TEXLOD_BIAS | MAP_LOD_BIAS(0)); + + OUT_RING(STATE3D_MAP_LOD_LIMITS_CMD | + MAP_UNIT(0) | + ENABLE_MAX_MIP_LVL | + ENABLE_MIN_MIP_LVL | LOD_MAX(0) | LOD_MIN(0)); + OUT_RING(STATE3D_MAP_LOD_LIMITS_CMD | + MAP_UNIT(1) | + ENABLE_MAX_MIP_LVL | + ENABLE_MIN_MIP_LVL | LOD_MAX(0) | LOD_MIN(0)); + OUT_RING(STATE3D_MAP_LOD_LIMITS_CMD | + MAP_UNIT(2) | + ENABLE_MAX_MIP_LVL | + ENABLE_MIN_MIP_LVL | LOD_MAX(0) | LOD_MIN(0)); + OUT_RING(STATE3D_MAP_LOD_LIMITS_CMD | + MAP_UNIT(3) | + ENABLE_MAX_MIP_LVL | + ENABLE_MIN_MIP_LVL | LOD_MAX(0) | LOD_MIN(0)); +#endif + + OUT_RING(STATE3D_MAP_COORD_TRANSFORM); + OUT_RING(DISABLE_TEX_TRANSFORM | TEXTURE_SET(0)); + OUT_RING(STATE3D_MAP_COORD_TRANSFORM); + OUT_RING(DISABLE_TEX_TRANSFORM | TEXTURE_SET(1)); + OUT_RING(STATE3D_MAP_COORD_TRANSFORM); + OUT_RING(DISABLE_TEX_TRANSFORM | TEXTURE_SET(2)); + OUT_RING(STATE3D_MAP_COORD_TRANSFORM); + OUT_RING(DISABLE_TEX_TRANSFORM | TEXTURE_SET(3)); + + /* End texture state */ + + OUT_RING(STATE3D_MODES_1_CMD | + ENABLE_COLR_BLND_FUNC | + BLENDFUNC_ADD | + ENABLE_SRC_BLND_FACTOR | + ENABLE_DST_BLND_FACTOR | + SRC_BLND_FACT(BLENDFACT_ONE) | DST_BLND_FACT(BLENDFACT_ZERO)); + + OUT_RING(STATE3D_MODES_2_CMD | + ENABLE_GLOBAL_DEPTH_BIAS | + GLOBAL_DEPTH_BIAS(0) | + ENABLE_ALPHA_TEST_FUNC | + ALPHA_TEST_FUNC(COMPAREFUNC_ALWAYS) | ALPHA_REF_VALUE(0)); + + OUT_RING(STATE3D_MODES_3_CMD | + ENABLE_DEPTH_TEST_FUNC | + DEPTH_TEST_FUNC(COMPAREFUNC_LESS) | + ENABLE_ALPHA_SHADE_MODE | + ALPHA_SHADE_MODE(SHADE_MODE_LINEAR) | + ENABLE_FOG_SHADE_MODE | + FOG_SHADE_MODE(SHADE_MODE_LINEAR) | + ENABLE_SPEC_SHADE_MODE | + SPEC_SHADE_MODE(SHADE_MODE_LINEAR) | + ENABLE_COLOR_SHADE_MODE | + COLOR_SHADE_MODE(SHADE_MODE_LINEAR) | + ENABLE_CULL_MODE | CULLMODE_NONE); + + OUT_RING(STATE3D_MODES_4_CMD | + ENABLE_LOGIC_OP_FUNC | + LOGIC_OP_FUNC(LOGICOP_COPY) | + ENABLE_STENCIL_TEST_MASK | + STENCIL_TEST_MASK(0xff) | + ENABLE_STENCIL_WRITE_MASK | STENCIL_WRITE_MASK(0xff)); + + OUT_RING(STATE3D_MODES_5_CMD | + ENABLE_SPRITE_POINT_TEX | + SPRITE_POINT_TEX_OFF | + FLUSH_RENDER_CACHE | + FLUSH_TEXTURE_CACHE | + ENABLE_FIXED_LINE_WIDTH | + FIXED_LINE_WIDTH(0x2) | + ENABLE_FIXED_POINT_WIDTH | FIXED_POINT_WIDTH(1)); + + OUT_RING(STATE3D_RASTER_RULES_CMD | + ENABLE_POINT_RASTER_RULE | + OGL_POINT_RASTER_RULE | + ENABLE_LINE_STRIP_PROVOKE_VRTX | + ENABLE_TRI_FAN_PROVOKE_VRTX | + ENABLE_TRI_STRIP_PROVOKE_VRTX | + LINE_STRIP_PROVOKE_VRTX(1) | + TRI_FAN_PROVOKE_VRTX(2) | TRI_STRIP_PROVOKE_VRTX(2)); + + OUT_RING(STATE3D_SCISSOR_ENABLE_CMD | DISABLE_SCISSOR_RECT); + + OUT_RING(STATE3D_SCISSOR_RECT_0_CMD); + OUT_RING(0); + OUT_RING(0); + + OUT_RING(STATE3D_STENCIL_TEST_CMD | + ENABLE_STENCIL_PARMS | + STENCIL_FAIL_OP(STENCILOP_KEEP) | + STENCIL_PASS_DEPTH_FAIL_OP(STENCILOP_KEEP) | + STENCIL_PASS_DEPTH_PASS_OP(STENCILOP_KEEP) | + ENABLE_STENCIL_TEST_FUNC | + STENCIL_TEST_FUNC(COMPAREFUNC_ALWAYS) | + ENABLE_STENCIL_REF_VALUE | STENCIL_REF_VALUE(0)); + + OUT_RING(VRTX_FORMAT_NTEX(1)); + + OUT_RING(STATE3D_VERTEX_FORMAT_2_CMD | + VRTX_TEX_SET_0_FMT(TEXCOORDFMT_2D) | + VRTX_TEX_SET_1_FMT(TEXCOORDFMT_2D) | + VRTX_TEX_SET_2_FMT(TEXCOORDFMT_2D) | + VRTX_TEX_SET_3_FMT(TEXCOORDFMT_2D) | + VRTX_TEX_SET_4_FMT(TEXCOORDFMT_2D) | + VRTX_TEX_SET_5_FMT(TEXCOORDFMT_2D) | + VRTX_TEX_SET_6_FMT(TEXCOORDFMT_2D) | + VRTX_TEX_SET_7_FMT(TEXCOORDFMT_2D)); + + OUT_RING(STATE3D_VERTEX_TRANSFORM); + OUT_RING(DISABLE_VIEWPORT_TRANSFORM | DISABLE_PERSPECTIVE_DIVIDE); + + OUT_RING(STATE3D_W_STATE_CMD); + OUT_RING(MAGIC_W_STATE_DWORD1); + OUT_RING(0x3f800000 /* 1.0 in IEEE float */ ); + +#define GFX_OP_STIPPLE ((0x3<<29)|(0x1d<<24)|(0x83<<16)) + + OUT_RING(GFX_OP_STIPPLE); + OUT_RING(0); + + ADVANCE_LP_RING(); +} + +/* Fullscreen hooks. The DRI fullscreen mode can probably be removed + * as it adds little or nothing above the mechanism below. (and isn't + * widely used) + */ +static Bool +I830DRIOpenFullScreen(ScreenPtr pScreen) +{ + return TRUE; +} + +static Bool +I830DRICloseFullScreen(ScreenPtr pScreen) +{ + return TRUE; +} + + + +/* Use callbacks from dri.c to support pageflipping mode for a single + * 3d context without need for any specific full-screen extension. + * + * Also see tdfx driver for example of using these callbacks to + * allocate and free 3d-specific memory on demand. + */ + + + + + +/* Use the miext/shadow module to maintain a list of dirty rectangles. + * These are blitted to the back buffer to keep both buffers clean + * during page-flipping when the 3d application isn't fullscreen. + * + * Unlike most use of the shadow code, both buffers are in video + * memory. + * + * An alternative to this would be to organize for all on-screen + * drawing operations to be duplicated for the two buffers. That + * might be faster, but seems like a lot more work... + */ + + +/* This should be done *before* XAA syncs, + * Otherwise will have to sync again??? + */ +static void +I830DRIShadowUpdate (ScreenPtr pScreen, shadowBufPtr pBuf) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I830Ptr pI830 = I830PTR(pScrn); + RegionPtr damage = &pBuf->damage; + int i, num = REGION_NUM_RECTS(damage); + BoxPtr pbox = REGION_RECTS(damage); + I830SAREARec *pSAREAPriv = DRIGetSAREAPrivate(pScreen); + int cmd, br13; + + /* Don't want to do this when no 3d is active and pages are + * right-way-round : + */ + if (!pSAREAPriv->pf_active && pSAREAPriv->pf_current_page == 0) + return; + + br13 = (pScrn->displayWidth * pI830->cpp) | (0xcc << 16); + + if (pScrn->bitsPerPixel == 32) { + cmd = (XY_SRC_COPY_BLT_CMD | XY_SRC_COPY_BLT_WRITE_ALPHA | + XY_SRC_COPY_BLT_WRITE_RGB); + br13 |= 3 << 24; + } else { + cmd = (XY_SRC_COPY_BLT_CMD); + br13 |= 1 << 24; + } + + for (i = 0 ; i < num ; i++, pbox++) { + BEGIN_LP_RING(8); + OUT_RING(cmd); + OUT_RING(br13); + OUT_RING((pbox->y1 << 16) | pbox->x1); + OUT_RING((pbox->y2 << 16) | pbox->x2); + OUT_RING(pI830->BackBuffer.Start); + OUT_RING((pbox->y1 << 16) | pbox->x1); + OUT_RING(br13 & 0xffff); + OUT_RING(pI830->FrontBuffer.Start); + ADVANCE_LP_RING(); + } +} + + +static void +I830EnablePageFlip(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I830Ptr pI830 = I830PTR(pScrn); + I830SAREARec *pSAREAPriv = DRIGetSAREAPrivate(pScreen); + + pSAREAPriv->pf_enabled = pI830->allowPageFlip; + pSAREAPriv->pf_active = 0; + + if (pI830->allowPageFlip) { + int br13 = (pScrn->displayWidth * pI830->cpp) | (0xcc << 16); + + BEGIN_LP_RING(8); + if (pScrn->bitsPerPixel == 32) { + OUT_RING(XY_SRC_COPY_BLT_CMD | XY_SRC_COPY_BLT_WRITE_ALPHA | + XY_SRC_COPY_BLT_WRITE_RGB); + br13 |= 3 << 24; + } else { + OUT_RING(XY_SRC_COPY_BLT_CMD); + br13 |= 1 << 24; + } + + OUT_RING(br13); + OUT_RING(0); + OUT_RING((pScrn->virtualY << 16) | pScrn->virtualX); + OUT_RING(pI830->BackBuffer.Start); + OUT_RING(0); + OUT_RING(br13 & 0xffff); + OUT_RING(pI830->FrontBuffer.Start); + ADVANCE_LP_RING(); + + pSAREAPriv->pf_active = 1; + } +} + +static void +I830DisablePageFlip(ScreenPtr pScreen) +{ + I830SAREARec *pSAREAPriv = DRIGetSAREAPrivate(pScreen); + + pSAREAPriv->pf_active = 0; +} + + +static void +I830DRITransitionSingleToMulti3d(ScreenPtr pScreen) +{ + /* Tell the clients not to pageflip. How? + * -- Field in sarea, plus bumping the window counters. + * -- DRM needs to cope with Front-to-Back swapbuffers. + */ + I830DisablePageFlip(pScreen); +} + +static void +I830DRITransitionMultiToSingle3d(ScreenPtr pScreen) +{ + /* Let the remaining 3d app start page flipping again. + */ + I830EnablePageFlip(pScreen); +} + + +static void +I830DRITransitionTo3d(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I830Ptr pI830 = I830PTR(pScrn); + + I830EnablePageFlip(pScreen); + pI830->have3DWindows = 1; +} + + +static void +I830DRITransitionTo2d(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I830Ptr pI830 = I830PTR(pScrn); + I830SAREARec *sPriv = (I830SAREARec *) DRIGetSAREAPrivate(pScreen); + + /* Shut down shadowing if we've made it back to the front page: + */ + if (sPriv->pf_current_page == 0) { + I830DisablePageFlip(pScreen); + } + + pI830->have3DWindows = 0; +} + + diff --git a/src/i830_dri.h b/src/i830_dri.h new file mode 100644 index 00000000..b60c7201 --- /dev/null +++ b/src/i830_dri.h @@ -0,0 +1,146 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i810/i830_dri.h,v 1.5 2002/12/10 01:27:05 dawes Exp $ */ + +#ifndef _I830_DRI_H +#define _I830_DRI_H + +#include "xf86drm.h" +#include "i830_common.h" + +#define I830_MAX_DRAWABLES 256 + +#define I830_MAJOR_VERSION 1 +#define I830_MINOR_VERSION 3 +#define I830_PATCHLEVEL 0 + +#define I830_REG_SIZE 0x80000 + +typedef struct _I830DRIRec { + drmHandle regs; + drmSize regsSize; + drmAddress regsMap; + + drmSize backbufferSize; + drmHandle backbuffer; + + drmSize depthbufferSize; + drmHandle depthbuffer; + + drmHandle textures; + int textureSize; + + drmHandle agp_buffers; + drmSize agp_buf_size; + + int deviceID; + int width; + int height; + int mem; + int cpp; + int bitsPerPixel; + int fbOffset; + int fbStride; + + int backOffset; + int depthOffset; + + int auxPitch; + int auxPitchBits; + + int logTextureGranularity; + int textureOffset; + + /* For non-dma direct rendering. + */ + int ringOffset; + int ringSize; + + drmBufMapPtr drmBufs; + int irq; + int sarea_priv_offset; +} I830DRIRec, *I830DRIPtr; + +typedef struct { + /* Nothing here yet */ + int dummy; +} I830ConfigPrivRec, *I830ConfigPrivPtr; + +typedef struct { + /* Nothing here yet */ + int dummy; +} I830DRIContextRec, *I830DRIContextPtr; + +/* Warning: If you change the SAREA structure you must change the kernel + * structure as well */ + +typedef struct _I830TexRegion { + unsigned char next, prev; /* indices to form a circular LRU */ + unsigned char in_use; /* owned by a client, or free? */ + int age; /* tracked by clients to update local LRU's */ +} I830TexRegion; + +typedef struct _I830SAREA { + unsigned int ContextState[I830_CTX_SETUP_SIZE]; + unsigned int BufferState[I830_DEST_SETUP_SIZE]; + unsigned int TexState[I830_TEXTURE_COUNT][I830_TEX_SETUP_SIZE]; + unsigned int TexBlendState[I830_TEXBLEND_COUNT][I830_TEXBLEND_SIZE]; + unsigned int TexBlendStateWordsUsed[I830_TEXBLEND_COUNT]; + unsigned int Palette[2][256]; + unsigned int dirty; + + unsigned int nbox; + XF86DRIClipRectRec boxes[I830_NR_SAREA_CLIPRECTS]; + + /* Maintain an LRU of contiguous regions of texture space. If + * you think you own a region of texture memory, and it has an + * age different to the one you set, then you are mistaken and + * it has been stolen by another client. If global texAge + * hasn't changed, there is no need to walk the list. + * + * These regions can be used as a proxy for the fine-grained + * texture information of other clients - by maintaining them + * in the same lru which is used to age their own textures, + * clients have an approximate lru for the whole of global + * texture space, and can make informed decisions as to which + * areas to kick out. There is no need to choose whether to + * kick out your own texture or someone else's - simply eject + * them all in LRU order. + */ + + I830TexRegion texList[I830_NR_TEX_REGIONS + 1]; + /* Last elt is sentinal */ + int texAge; /* last time texture was uploaded */ + int last_enqueue; /* last time a buffer was enqueued */ + int last_dispatch; /* age of the most recently dispatched buffer */ + int last_quiescent; /* */ + int ctxOwner; /* last context to upload state */ + + int vertex_prim; + + int pf_enabled; /* is pageflipping allowed? */ + int pf_active; /* is pageflipping active right now? */ + int pf_current_page; /* which buffer is being displayed? */ + + int perf_boxes; /* performance boxes to be displayed */ + + /* Here's the state for texunits 2,3: + */ + unsigned int TexState2[I830_TEX_SETUP_SIZE]; + unsigned int TexBlendState2[I830_TEXBLEND_SIZE]; + unsigned int TexBlendStateWordsUsed2; + + unsigned int TexState3[I830_TEX_SETUP_SIZE]; + unsigned int TexBlendState3[I830_TEXBLEND_SIZE]; + unsigned int TexBlendStateWordsUsed3; + + unsigned int StippleState[I830_STP_SETUP_SIZE]; +} I830SAREARec, *I830SAREAPtr; + +/* Flags for perf_boxes + */ +#define I830_BOX_RING_EMPTY 0x1 /* populated by kernel */ +#define I830_BOX_FLIP 0x2 /* populated by kernel */ +#define I830_BOX_WAIT 0x4 /* populated by kernel & client */ +#define I830_BOX_TEXTURE_LOAD 0x8 /* populated by kernel */ +#define I830_BOX_LOST_CONTEXT 0x10 /* populated by client */ + +#endif diff --git a/src/i830_driver.c b/src/i830_driver.c new file mode 100644 index 00000000..073f8eb6 --- /dev/null +++ b/src/i830_driver.c @@ -0,0 +1,3586 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i810/i830_driver.c,v 1.27 2003/02/14 17:12:42 dawes Exp $ */ +/************************************************************************** + +Copyright 2001 VA Linux Systems Inc., Fremont, California. +Copyright © 2002 by David Dawes + +All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +on the rights to use, copy, modify, merge, publish, distribute, sub +license, and/or sell copies of the Software, and to permit persons to whom +the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice (including the next +paragraph) shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +THE COPYRIGHT HOLDERS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ + +/* + * Reformatted with GNU indent (2.2.8), using the following options: + * + * -bad -bap -c41 -cd0 -ncdb -ci6 -cli0 -cp0 -ncs -d0 -di3 -i3 -ip3 -l78 + * -lp -npcs -psl -sob -ss -br -ce -sc -hnl + * + * This provides a good match with the original i810 code and preferred + * XFree86 formatting conventions. + * + * When editing this driver, please follow the existing formatting, and edit + * with <TAB> characters expanded at 8-column intervals. + */ + +/* + * Authors: Jeff Hartmann <jhartmann@valinux.com> + * Abraham van der Merwe <abraham@2d3d.co.za> + * David Dawes <dawes@tungstengraphics.com> + */ + +/* + * Mode handling is based on the VESA driver written by: + * Paulo César Pereira de Andrade <pcpa@conectiva.com.br> + */ + +/* + * Changes: + * + * 23/08/2001 Abraham van der Merwe <abraham@2d3d.co.za> + * - Fixed display timing bug (mode information for some + * modes were not initialized correctly) + * - Added workarounds for GTT corruptions (I don't adjust + * the pitches for 1280x and 1600x modes so we don't + * need extra memory) + * - The code will now default to 60Hz if LFP is connected + * - Added different refresh rate setting code to work + * around 0x4f02 BIOS bug + * - BIOS workaround for some mode sets (I use legacy BIOS + * calls for setting those) + * - Removed 0x4f04, 0x01 (save state) BIOS call which causes + * LFP to malfunction (do some house keeping and restore + * modes ourselves instead - not perfect, but at least the + * LFP is working now) + * - Several other smaller bug fixes + * + * 06/09/2001 Abraham van der Merwe <abraham@2d3d.co.za> + * - Preliminary local memory support (works without agpgart) + * - DGA fixes (the code were still using i810 mode sets, etc.) + * - agpgart fixes + * + * 18/09/2001 + * - Proper local memory support (should work correctly now + * with/without agpgart module) + * - more agpgart fixes + * - got rid of incorrect GTT adjustments + * + * 09/10/2001 + * - Changed the DPRINTF() variadic macro to an ANSI C compatible + * version + * + * 10/10/2001 + * - Fixed DPRINTF_stub(). I forgot the __...__ macros in there + * instead of the function arguments :P + * - Added a workaround for the 1600x1200 bug (Text mode corrupts + * when you exit from any 1600x1200 mode and 1280x1024@85Hz. I + * suspect this is a BIOS bug (hence the 1280x1024@85Hz case)). + * For now I'm switching to 800x600@60Hz then to 80x25 text mode + * and then restoring the registers - very ugly indeed. + * + * 15/10/2001 + * - Improved 1600x1200 mode set workaround. The previous workaround + * was causing mode set problems later on. + * + * 18/10/2001 + * - Fixed a bug in I830BIOSLeaveVT() which caused a bug when you + * switched VT's + */ +/* + * 07/2002 David Dawes + * - Add Intel(R) 855GM/852GM support. + */ +/* + * 07/2002 David Dawes + * - Cleanup code formatting. + * - Improve VESA mode selection, and fix refresh rate selection. + * - Don't duplicate functions provided in 4.2 vbe modules. + * - Don't duplicate functions provided in the vgahw module. + * - Rewrite memory allocation. + * - Rewrite initialisation and save/restore state handling. + * - Decouple the i810 support from i830 and later. + * - Remove various unnecessary hacks and workarounds. + * - Fix an 845G problem with the ring buffer not in pre-allocated + * memory. + * - Fix screen blanking. + * - Clear the screen at startup so you don't see the previous session. + * - Fix some HW cursor glitches, and turn HW cursor off at VT switch + * and exit. + * + * 08/2002 Keith Whitwell + * - Fix DRI initialisation. + */ +/* + * 08/2002 Alan Hourihane and David Dawes + * - Add XVideo support. + */ +/* + * 10/2002 David Dawes + * - Add Intel(R) 865G support. + */ + + +#ifndef PRINT_MODE_INFO +#define PRINT_MODE_INFO 0 +#endif + +#include "xf86.h" +#include "xf86_ansic.h" +#include "xf86_OSproc.h" +#include "xf86Resources.h" +#include "xf86RAC.h" +#include "xf86cmap.h" +#include "compiler.h" +#include "mibstore.h" +#include "vgaHW.h" +#include "mipointer.h" +#include "micmap.h" + +#include "fb.h" +#include "miscstruct.h" +#include "xf86xv.h" +#include "Xv.h" +#include "vbe.h" +#include "vbeModes.h" + +#include "i830.h" + +#ifdef XF86DRI +#include "dri.h" +#endif + +#define BIT(x) (1 << (x)) +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#define NB_OF(x) (sizeof (x) / sizeof (*x)) + +/* *INDENT-OFF* */ +static SymTabRec I830BIOSChipsets[] = { + {PCI_CHIP_I830_M, "i830"}, + {PCI_CHIP_845_G, "845G"}, + {PCI_CHIP_I855_GM, "852GM/855GM"}, + {PCI_CHIP_I865_G, "865G"}, + {-1, NULL} +}; + +static PciChipsets I830BIOSPciChipsets[] = { + {PCI_CHIP_I830_M, PCI_CHIP_I830_M, RES_SHARED_VGA}, + {PCI_CHIP_845_G, PCI_CHIP_845_G, RES_SHARED_VGA}, + {PCI_CHIP_I855_GM, PCI_CHIP_I855_GM, RES_SHARED_VGA}, + {PCI_CHIP_I865_G, PCI_CHIP_I865_G, RES_SHARED_VGA}, + {-1, -1, RES_UNDEFINED} +}; + +/* + * Note: "ColorKey" is provided for compatibility with the i810 driver. + * However, the correct option name is "VideoKey". "ColorKey" usually + * refers to the tranparency key for 8+24 overlays, not for video overlays. + */ + +typedef enum { + OPTION_NOACCEL, + OPTION_SW_CURSOR, + OPTION_CACHE_LINES, + OPTION_DRI, + OPTION_PAGEFLIP, + OPTION_XVIDEO, + OPTION_VIDEO_KEY, + OPTION_COLOR_KEY, + OPTION_STRETCH, + OPTION_CENTER +} I830Opts; + +static OptionInfoRec I830BIOSOptions[] = { + {OPTION_NOACCEL, "NoAccel", OPTV_BOOLEAN, {0}, FALSE}, + {OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN, {0}, FALSE}, + {OPTION_CACHE_LINES, "CacheLines", OPTV_INTEGER, {0}, FALSE}, + {OPTION_DRI, "DRI", OPTV_BOOLEAN, {0}, TRUE}, + {OPTION_PAGEFLIP, "PageFlip", OPTV_BOOLEAN, {0}, FALSE}, + {OPTION_XVIDEO, "XVideo", OPTV_BOOLEAN, {0}, TRUE}, + {OPTION_COLOR_KEY, "ColorKey", OPTV_INTEGER, {0}, FALSE}, + {OPTION_VIDEO_KEY, "VideoKey", OPTV_INTEGER, {0}, FALSE}, + {OPTION_STRETCH, "Stretch", OPTV_BOOLEAN, {0}, FALSE}, + {OPTION_CENTER, "Center", OPTV_BOOLEAN, {0}, FALSE}, + {-1, NULL, OPTV_NONE, {0}, FALSE} +}; +/* *INDENT-ON* */ + +static void I830DisplayPowerManagementSet(ScrnInfoPtr pScrn, + int PowerManagementMode, int flags); +static void I830BIOSAdjustFrame(int scrnIndex, int x, int y, int flags); +static Bool I830BIOSCloseScreen(int scrnIndex, ScreenPtr pScreen); +static Bool I830BIOSSaveScreen(ScreenPtr pScreen, int unblack); +static Bool I830BIOSEnterVT(int scrnIndex, int flags); +static Bool I830VESASetVBEMode(ScrnInfoPtr pScrn, int mode, + VbeCRTCInfoBlock *block); + +static Bool OffsetFrame = FALSE; + + + +#ifdef I830DEBUG +void +I830DPRINTF_stub(const char *filename, int line, const char *function, + const char *fmt, ...) +{ + va_list ap; + + ErrorF("\n##############################################\n" + "*** In function %s, on line %d, in file %s ***\n", + function, line, filename); + va_start(ap, fmt); + VErrorF(fmt, ap); + va_end(ap); + ErrorF("##############################################\n\n"); +} +#else /* #ifdef I830DEBUG */ +void +I830DPRINTF_stub(const char *filename, int line, const char *function, + const char *fmt, ...) +{ + /* do nothing */ +} +#endif /* #ifdef I830DEBUG */ + +/* XXX Check if this is still needed. */ +const OptionInfoRec * +I830BIOSAvailableOptions(int chipid, int busid) +{ + int i; + + for (i = 0; I830BIOSPciChipsets[i].PCIid > 0; i++) { + if (chipid == I830BIOSPciChipsets[i].PCIid) + return I830BIOSOptions; + } + return NULL; +} + +static Bool +I830BIOSGetRec(ScrnInfoPtr pScrn) +{ + I830Ptr pI830; + + if (pScrn->driverPrivate) + return TRUE; + pI830 = pScrn->driverPrivate = xnfcalloc(sizeof(I830Rec), 1); + pI830->vesa = xnfcalloc(sizeof(VESARec), 1); + return TRUE; +} + +static void +I830BIOSFreeRec(ScrnInfoPtr pScrn) +{ + I830Ptr pI830; + VESAPtr pVesa; + DisplayModePtr mode; + + if (!pScrn) + return; + if (!pScrn->driverPrivate) + return; + + pI830 = I830PTR(pScrn); + mode = pScrn->modes; + + if (mode) { + do { + if (mode->Private) { + VbeModeInfoData *data = (VbeModeInfoData *) mode->Private; + + if (data->block) + xfree(data->block); + xfree(data); + mode->Private = NULL; + } + mode = mode->next; + } while (mode && mode != pScrn->modes); + } + + if (pI830->vbeInfo) + VBEFreeVBEInfo(pI830->vbeInfo); + if (pI830->pVbe) + vbeFree(pI830->pVbe); + + pVesa = pI830->vesa; + if (pVesa->monitor) + xfree(pVesa->monitor); + if (pVesa->savedPal) + xfree(pVesa->savedPal); + xfree(pVesa); + + xfree(pScrn->driverPrivate); + pScrn->driverPrivate = NULL; +} + +static void +I830BIOSProbeDDC(ScrnInfoPtr pScrn, int index) +{ + vbeInfoPtr pVbe; + + /* The vbe module gets loaded in PreInit(), so no need to load it here. */ + + pVbe = VBEInit(NULL, index); + ConfiguredMonitor = vbeDoEDID(pVbe, NULL); +} + +/* Various extended video BIOS functions. */ +static const int refreshes[] = { + 43, 56, 60, 70, 72, 75, 85, 100, 120 +}; +static const int nrefreshes = sizeof(refreshes) / sizeof(refreshes[0]); + +static Bool +Check5fStatus(ScrnInfoPtr pScrn, int func, int ax) +{ + if (ax == 0x005f) + return TRUE; + else if (ax == 0x015f) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Extended BIOS function 0x%04x failed.\n", func); + return FALSE; + } else if ((ax & 0xff) != 0x5f) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Extended BIOS function 0x%04x not supported.\n", func); + return FALSE; + } else { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Extended BIOS function 0x%04x returns 0x%04x.\n", + func, ax & 0xffff); + return FALSE; + } +} + +#if 0 +static int +BitToRefresh(int bits) +{ + int i; + + for (i = 0; i < nrefreshes; i++) + if (bits & (1 << i)) + return refreshes[i]; + return 0; +} + +static int +GetRefreshRate(ScrnInfoPtr pScrn, int mode, int refresh, int *availRefresh) +{ + vbeInfoPtr pVbe = I830PTR(pScrn)->pVbe; + + DPRINTF(PFX, "GetRefreshRate\n"); + + /* Only 8-bit mode numbers are supported. */ + if (mode & 0x100) + return 0; + + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x5f05; + pVbe->pInt10->bx = (mode & 0xff) | 0x100; + + xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); + if (Check5fStatus(pScrn, 0x5f05, pVbe->pInt10->ax)) { + if (availRefresh) + *availRefresh = pVbe->pInt10->bx; + return BitToRefresh(pVbe->pInt10->cx); + } else + return 0; +} +#endif + +static int +SetRefreshRate(ScrnInfoPtr pScrn, int mode, int refresh) +{ + int i; + vbeInfoPtr pVbe = I830PTR(pScrn)->pVbe; + + DPRINTF(PFX, "SetRefreshRate: mode 0x%x, refresh: %d\n", mode, refresh); + + /* Only 8-bit mode numbers are supported. */ + if (mode & 0x100) + return 0; + + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x5f05; + pVbe->pInt10->bx = mode & 0xff; + + for (i = nrefreshes - 1; i >= 0; i--) { + /* + * Look for the highest value that the requested (refresh + 2) is + * greater than or equal to. + */ + if (refreshes[i] <= (refresh + 2)) + break; + } + /* i can be 0 if the requested refresh was higher than the max. */ + if (i == 0) { + if (refresh >= refreshes[nrefreshes - 1]) + i = nrefreshes - 1; + } + DPRINTF(PFX, "Setting refresh rate to %dHz for mode 0x%02x\n", + refreshes[i], mode & 0xff); + pVbe->pInt10->cx = 1 << i; + xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); + if (Check5fStatus(pScrn, 0x5f05, pVbe->pInt10->ax)) + return refreshes[i]; + else + return 0; +} + +static Bool +GetModeSupport(ScrnInfoPtr pScrn, int modePipeA, int modePipeB, + int devicesPipeA, int devicesPipeB, int *maxBandwidth, + int *bandwidthPipeA, int *bandwidthPipeB) +{ + vbeInfoPtr pVbe = I830PTR(pScrn)->pVbe; + + DPRINTF(PFX, "GetModeSupport: modes 0x%x, 0x%x, devices: 0x%x, 0x%x\n", + modePipeA, modePipeB, devicesPipeA, devicesPipeB); + + /* Only 8-bit mode numbers are supported. */ + if ((modePipeA & 0x100) || (modePipeB & 0x100)) + return 0; + + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x5f28; + pVbe->pInt10->bx = (modePipeA & 0xff) | ((modePipeB & 0xff) << 8); + if ((devicesPipeA & 0x80) || (devicesPipeB & 0x80)) + pVbe->pInt10->cx = 0x8000; + else + pVbe->pInt10->cx = (devicesPipeA & 0xff) | ((devicesPipeB & 0xff) << 8); + + xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); + if (Check5fStatus(pScrn, 0x5f28, pVbe->pInt10->ax)) { + if (maxBandwidth) + *maxBandwidth = pVbe->pInt10->cx; + if (bandwidthPipeA) + *bandwidthPipeA = pVbe->pInt10->dx & 0xffff; + /* XXX For XFree86 4.2.0 and earlier, ->dx is truncated to 16 bits. */ + if (bandwidthPipeB) + *bandwidthPipeB = (pVbe->pInt10->dx >> 16) & 0xffff; + return TRUE; + } else + return FALSE; +} + +static int +GetLFPCompMode(ScrnInfoPtr pScrn) +{ + vbeInfoPtr pVbe = I830PTR(pScrn)->pVbe; + + DPRINTF(PFX, "GetLFPCompMode\n"); + + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x5f61; + pVbe->pInt10->bx = 0x100; + + xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); + if (Check5fStatus(pScrn, 0x5f61, pVbe->pInt10->ax)) + return pVbe->pInt10->cx & 0xffff; + else + return -1; +} + +#if 0 +static Bool +SetLFPCompMode(ScrnInfoPtr pScrn, int compMode) +{ + vbeInfoPtr pVbe = I830PTR(pScrn)->pVbe; + + DPRINTF(PFX, "SetLFPCompMode: compMode %d\n", compMode); + + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x5f61; + pVbe->pInt10->bx = 0; + pVbe->pInt10->cx = compMode; + + xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); + return Check5fStatus(pScrn, 0x5f61, pVbe->pInt10->ax); +} +#endif + +static int +GetDisplayDevices(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + vbeInfoPtr pVbe = pI830->pVbe; + + DPRINTF(PFX, "GetDisplayDevices\n"); + +#if 0 + { + CARD32 temp; + ErrorF("ADPA is 0x%08x\n", INREG(ADPA)); + ErrorF("DVOA is 0x%08x\n", INREG(DVOA)); + ErrorF("DVOB is 0x%08x\n", INREG(DVOB)); + ErrorF("DVOC is 0x%08x\n", INREG(DVOC)); + ErrorF("LVDS is 0x%08x\n", INREG(LVDS)); + temp = INREG(DVOA_SRCDIM); + ErrorF("DVOA_SRCDIM is 0x%08x (%d x %d)\n", temp, + (temp >> 12) & 0xfff, temp & 0xfff); + temp = INREG(DVOB_SRCDIM); + ErrorF("DVOB_SRCDIM is 0x%08x (%d x %d)\n", temp, + (temp >> 12) & 0xfff, temp & 0xfff); + temp = INREG(DVOC_SRCDIM); + ErrorF("DVOC_SRCDIM is 0x%08x (%d x %d)\n", temp, + (temp >> 12) & 0xfff, temp & 0xfff); + ErrorF("SWF0 is 0x%08x\n", INREG(SWF0)); + ErrorF("SWF4 is 0x%08x\n", INREG(SWF4)); + } +#endif + + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x5f64; + pVbe->pInt10->bx = 0x100; + + xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); + if (Check5fStatus(pScrn, 0x5f64, pVbe->pInt10->ax)) + return pVbe->pInt10->cx & 0xffff; + else + return -1; +} + +static Bool +SetDisplayDevices(ScrnInfoPtr pScrn, int devices) +{ + I830Ptr pI830 = I830PTR(pScrn); + vbeInfoPtr pVbe = pI830->pVbe; + CARD32 temp; + + DPRINTF(PFX, "SetDisplayDevices: devices 0x%x\n", devices); + + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x5f64; + pVbe->pInt10->bx = 0x1; + pVbe->pInt10->cx = devices; + + xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); + if (Check5fStatus(pScrn, 0x5f64, pVbe->pInt10->ax)) + return TRUE; + else { + ErrorF("Writing config directly to SWF0\n"); + temp = INREG(SWF0); + OUTREG(SWF0, (temp & ~(0xffff)) | (devices & 0xffff)); + ErrorF("SetDisplayDevices failed. devices is 0x%x instead of 0x%x\n", + GetDisplayDevices(pScrn), devices); + return FALSE; + } +} + +#if 0 +static Bool +GetDevicePresence(ScrnInfoPtr pScrn, Bool *required, int *attached, + int *encoderPresent) +{ + vbeInfoPtr pVbe = I830PTR(pScrn)->pVbe; + + DPRINTF(PFX, "GetDevicePresence\n"); + + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x5f64; + pVbe->pInt10->bx = 0x200; + + xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); + if (Check5fStatus(pScrn, 0x5f64, pVbe->pInt10->ax)) { + if (required) + *required = ((pVbe->pInt10->bx & 0x1) == 0); + if (attached) + *attached = (pVbe->pInt10->cx >> 8) & 0xff; + if (encoderPresent) + *encoderPresent = pVbe->pInt10->cx & 0xff; + return TRUE; + } else + return FALSE; +} +#endif + +static Bool +GetDisplayInfo(ScrnInfoPtr pScrn, int device, Bool *attached, Bool *present, + short *x, short *y) +{ + vbeInfoPtr pVbe = I830PTR(pScrn)->pVbe; + + DPRINTF(PFX, "GetDisplayInfo: device: 0x%x\n", device); + + switch (device & 0xff) { + case 0x01: + case 0x02: + case 0x04: + case 0x08: + case 0x10: + case 0x20: + break; + default: + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "GetDisplayInfo: invalid device: 0x%x\n", device & 0xff); + return FALSE; + } + + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x5f64; + pVbe->pInt10->bx = 0x300; + pVbe->pInt10->cx = device & 0xff; + + xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); + if (Check5fStatus(pScrn, 0x5f64, pVbe->pInt10->ax)) { + if (attached) + *attached = ((pVbe->pInt10->bx & 0x2) != 0); + if (present) + *present = ((pVbe->pInt10->bx & 0x1) != 0); + if (pVbe->pInt10->cx != (device & 0xff)) { + if (y) { + *y = pVbe->pInt10->cx & 0xffff; + } + if (x) { + *x = (pVbe->pInt10->cx >> 16) & 0xffff; + } + } + return TRUE; + } else + return FALSE; +} + +/* + * Returns a string matching the device corresponding to the first bit set + * in "device". savedDevice is then set to device with that bit cleared. + * Subsequent calls with device == -1 will use savedDevice. + */ + +static const char *displayDevices[] = { + "CRT", + "TV", + "DFP (digital flat panel)", + "LFP (local flat panel)", + "TV2 (second TV)", + "DFP2 (second digital flat panel)", + NULL +}; + +static const char * +DeviceToString(int device) +{ + static int savedDevice = -1; + static int bit = 0; + const char *name; + + if (device == -1) { + device = savedDevice; + bit = 0; + } + + if (device == -1) + return NULL; + + while (displayDevices[bit]) { + if (device & (1 << bit)) { + name = displayDevices[bit]; + savedDevice = device & ~(1 << bit); + bit++; + return name; + } + bit++; + } + return NULL; +} + +static void +PrintDisplayDeviceInfo(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + int pipe, n; + int displays; + + DPRINTF(PFX, "PrintDisplayDeviceInfo\n"); + + displays = pI830->configuredDevices; + if (displays == -1) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "No active display devices.\n"); + return; + } + + /* Check for active devices connected to each display pipe. */ + for (n = 0; n < pI830->availablePipes; n++) { + pipe = ((displays >> PIPE_SHIFT(n)) & PIPE_ACTIVE_MASK); + if (pipe) { + const char *name; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Currently active displays on Pipe %c:\n", PIPE_NAME(n)); + name = DeviceToString(pipe); + do { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "\t%s\n", name); + name = DeviceToString(-1); + } while (name); + + if (pipe & PIPE_UNKNOWN_ACTIVE) + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "\tSome unknown display devices may also be present\n"); + + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "No active displays on Pipe %c.\n", PIPE_NAME(n)); + } + + if (pI830->pipeDisplaySize[n].x2 != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Lowest common panel size for pipe %c is %d x %d\n", + PIPE_NAME(n), pI830->pipeDisplaySize[n].x2, + pI830->pipeDisplaySize[n].y2); + } else if (pI830->pipeEnabled[n] && pipe & ~PIPE_CRT_ACTIVE) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "No display size information available for pipe %c.\n", + PIPE_NAME(n)); + } + } +} + +static void +GetPipeSizes(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + int pipe, n; + DisplayType i; + + DPRINTF(PFX, "GetPipeSizes\n"); + + + for (n = 0; n < pI830->availablePipes; n++) { + pipe = (pI830->configuredDevices >> PIPE_SHIFT(n)) & PIPE_ACTIVE_MASK; + pI830->pipeDisplaySize[n].x1 = pI830->pipeDisplaySize[n].y1 = 0; + pI830->pipeDisplaySize[n].x2 = pI830->pipeDisplaySize[n].y2 = 4096; + for (i = 0; i < NumKnownDisplayTypes; i++) { + if (pipe & (1 << i) & PIPE_SIZED_DISP_MASK) { + if (pI830->displaySize[i].x2 != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Size of device %s is %d x %d\n", + displayDevices[i], + pI830->displaySize[i].x2, + pI830->displaySize[i].y2); + if (pI830->displaySize[i].x2 < pI830->pipeDisplaySize[n].x2) + pI830->pipeDisplaySize[n].x2 = pI830->displaySize[i].x2; + if (pI830->displaySize[i].y2 < pI830->pipeDisplaySize[n].y2) + pI830->pipeDisplaySize[n].y2 = pI830->displaySize[i].y2; + } + } + } + + if (pI830->pipeDisplaySize[n].x2 == 4096) + pI830->pipeDisplaySize[n].x2 = 0; + if (pI830->pipeDisplaySize[n].y2 == 4096) + pI830->pipeDisplaySize[n].y2 = 0; + } +} + +static Bool +I830DetectDisplayDevice(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + int pipe, n; + DisplayType i; + + for (i = 0; i < NumKnownDisplayTypes; i++) { + if (GetDisplayInfo(pScrn, 1 << i, &pI830->displayAttached[i], + &pI830->displayPresent[i], + &pI830->displaySize[i].x2, + &pI830->displaySize[i].y2)) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Display Info: %s: attached: %s, present: %s, size: " + "(%d,%d)\n", displayDevices[i], + BOOLTOSTRING(pI830->displayAttached[i]), + BOOLTOSTRING(pI830->displayPresent[i]), + pI830->displaySize[i].x2, pI830->displaySize[i].y2); + } + } + + pI830->configuredDevices = GetDisplayDevices(pScrn); + if (pI830->configuredDevices == -1) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Failed to detect active display devices\n"); + return FALSE; + } + + /* Check for active devices connected to each display pipe. */ + for (n = 0; n < pI830->availablePipes; n++) { + pipe = ((pI830->configuredDevices >> PIPE_SHIFT(n)) & PIPE_ACTIVE_MASK); + if (pipe) { + pI830->pipeEnabled[n] = TRUE; + } + } + + GetPipeSizes(pScrn); + PrintDisplayDeviceInfo(pScrn); + +#if 0 + /* A quick hack to change the set of enabled devices. */ + enabledDevices = PIPE_CRT_ACTIVE; + if (!SetDisplayDevices(pScrn, enabledDevices)) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Failed to switch to configured display devices\n"); + } +#endif + + return TRUE; +} + +static int +I830DetectMemory(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + PCITAG bridge; + CARD16 gmch_ctrl; + int memsize = 0; + + bridge = pciTag(0, 0, 0); /* This is always the host bridge */ + gmch_ctrl = pciReadWord(bridge, I830_GMCH_CTRL); + + if (IS_I85X(pI830) || IS_I865G(pI830)) + { + switch (gmch_ctrl & I830_GMCH_GMS_MASK) { + case I855_GMCH_GMS_STOLEN_1M: + memsize = MB(1) - KB(132); + break; + case I855_GMCH_GMS_STOLEN_4M: + memsize = MB(4) - KB(132); + break; + case I855_GMCH_GMS_STOLEN_8M: + memsize = MB(8) - KB(132); + break; + case I855_GMCH_GMS_STOLEN_16M: + memsize = MB(16) - KB(132); + break; + case I855_GMCH_GMS_STOLEN_32M: + memsize = MB(32) - KB(132); + break; + } + } else + { + switch (gmch_ctrl & I830_GMCH_GMS_MASK) { + case I830_GMCH_GMS_STOLEN_512: + memsize = KB(512) - KB(132); + break; + case I830_GMCH_GMS_STOLEN_1024: + memsize = MB(1) - KB(132); + break; + case I830_GMCH_GMS_STOLEN_8192: + memsize = MB(8) - KB(132); + break; + case I830_GMCH_GMS_LOCAL: + memsize = 0; + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Local memory found, but won't be used.\n"); + break; + } + } + if (memsize > 0) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "detected %d kB stolen memory.\n", memsize / 1024); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "no video memory detected.\n"); + } + return memsize; +} + +static Bool +I830MapMMIO(ScrnInfoPtr pScrn) +{ + int mmioFlags; + I830Ptr pI830 = I830PTR(pScrn); + +#if !defined(__alpha__) + mmioFlags = VIDMEM_MMIO | VIDMEM_READSIDEEFFECT; +#else + mmioFlags = VIDMEM_MMIO | VIDMEM_READSIDEEFFECT | VIDMEM_SPARSE; +#endif + + pI830->MMIOBase = xf86MapPciMem(pScrn->scrnIndex, mmioFlags, + pI830->PciTag, + pI830->MMIOAddr, I810_REG_SIZE); + if (!pI830->MMIOBase) + return FALSE; + return TRUE; +} + +static Bool +I830MapMem(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + unsigned i; + + for (i = 2; i < pI830->FbMapSize; i <<= 1) ; + pI830->FbMapSize = i; + + if (!I830MapMMIO(pScrn)) + return FALSE; + + pI830->FbBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER, + pI830->PciTag, + pI830->LinearAddr, pI830->FbMapSize); + if (!pI830->FbBase) + return FALSE; + + pI830->LpRing.virtual_start = pI830->FbBase + pI830->LpRing.mem.Start; + + return TRUE; +} + +static void +I830UnmapMMIO(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + + xf86UnMapVidMem(pScrn->scrnIndex, (pointer) pI830->MMIOBase, + I810_REG_SIZE); + pI830->MMIOBase = 0; +} + +static Bool +I830UnmapMem(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + + xf86UnMapVidMem(pScrn->scrnIndex, (pointer) pI830->FbBase, + pI830->FbMapSize); + pI830->FbBase = 0; + I830UnmapMMIO(pScrn); + return TRUE; +} + +#ifndef HAVE_GET_PUT_BIOSMEMSIZE +#define HAVE_GET_PUT_BIOSMEMSIZE 1 +#endif + +#if HAVE_GET_PUT_BIOSMEMSIZE +/* + * Tell the BIOS how much video memory is available. The BIOS call used + * here won't always be available. + */ +static Bool +PutBIOSMemSize(ScrnInfoPtr pScrn, int memSize) +{ + vbeInfoPtr pVbe = I830PTR(pScrn)->pVbe; + + DPRINTF(PFX, "PutBIOSMemSize: %d kB\n", memSize / 1024); + + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x5f11; + pVbe->pInt10->bx = 0; + pVbe->pInt10->cx = memSize / GTT_PAGE_SIZE; + + xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); + return Check5fStatus(pScrn, 0x5f11, pVbe->pInt10->ax); +} + +/* + * This reports what the previous VBEGetVBEInfo() found. Be sure to call + * VBEGetVBEInfo() after changing the BIOS memory size view. If + * a separate BIOS call is added for this, it can be put here. Only + * return a valid value if the funtionality for PutBIOSMemSize() + * is available. + */ +static int +GetBIOSMemSize(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + int memSize = KB(pI830->vbeInfo->TotalMemory * 64); + + DPRINTF(PFX, "GetBIOSMemSize\n"); + + if (PutBIOSMemSize(pScrn, memSize)) + return memSize; + else + return -1; +} +#endif + +/* + * These three functions allow the video BIOS's view of the available video + * memory to be changed. This is currently implemented only for the 830 + * and 845G, which can do this via a BIOS scratch register that holds the + * BIOS's view of the (pre-reserved) memory size. If another mechanism + * is available in the future, it can be plugged in here. + * + * The mapping used for the 830/845G scratch register's low 4 bits is: + * + * 320k => 0 + * 832k => 1 + * 8000k => 8 + * + * The "unusual" values are the 512k, 1M, 8M pre-reserved memory, less + * overhead, rounded down to the BIOS-reported 64k granularity. + */ + +static Bool +SaveBIOSMemSize(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + + DPRINTF(PFX, "SaveBIOSMemSize\n"); + + pI830->useSWF1 = FALSE; + +#if HAVE_GET_PUT_BIOSMEMSIZE + if ((pI830->saveBIOSMemSize = GetBIOSMemSize(pScrn)) != -1) + return TRUE; +#endif + + if (IS_I830(pI830) || IS_845G(pI830)) { + pI830->useSWF1 = TRUE; + pI830->saveSWF1 = INREG(SWF1) & 0x0f; + + /* + * This is for sample purposes only. pI830->saveBIOSMemSize isn't used + * when pI830->useSWF1 is TRUE. + */ + switch (pI830->saveSWF1) { + case 0: + pI830->saveBIOSMemSize = KB(320); + break; + case 1: + pI830->saveBIOSMemSize = KB(832); + break; + case 8: + pI830->saveBIOSMemSize = KB(8000); + break; + default: + pI830->saveBIOSMemSize = 0; + break; + } + return TRUE; + } + return FALSE; +} + +static void +RestoreBIOSMemSize(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + CARD32 swf1; + + DPRINTF(PFX, "RestoreBIOSMemSize\n"); + + if (!pI830->overrideBIOSMemSize) + return; + +#if HAVE_GET_PUT_BIOSMEMSIZE + if (!pI830->useSWF1) { + PutBIOSMemSize(pScrn, pI830->saveBIOSMemSize); + return; + } +#endif + + if ((IS_I830(pI830) || IS_845G(pI830)) && pI830->useSWF1) { + swf1 = INREG(SWF1); + swf1 &= ~0x0f; + swf1 |= (pI830->saveSWF1 & 0x0f); + OUTREG(SWF1, swf1); + } +} + +static void +SetBIOSMemSize(ScrnInfoPtr pScrn, int newSize) +{ + I830Ptr pI830 = I830PTR(pScrn); + CARD32 swf1; + Bool mapped; + + DPRINTF(PFX, "SetBIOSMemSize: %d kB\n", newSize / 1024); + + if (!pI830->overrideBIOSMemSize) + return; + +#if HAVE_GET_PUT_BIOSMEMSIZE + if (!pI830->useSWF1) { + PutBIOSMemSize(pScrn, newSize); + return; + } +#endif + + if ((IS_I830(pI830) || IS_845G(pI830)) && pI830->useSWF1) { + CARD32 newSWF1; + + /* Need MMIO access here. */ + mapped = (pI830->MMIOBase != NULL); + if (!mapped) + I830MapMMIO(pScrn); + + if (newSize <= KB(832)) + newSWF1 = 1; + else + newSWF1 = 8; + + swf1 = INREG(SWF1); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Before: SWF1 is 0x%08x\n", swf1); + swf1 &= ~0x0f; + swf1 |= (newSWF1 & 0x0f); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "After: SWF1 is 0x%08x\n", swf1); + OUTREG(SWF1, swf1); + if (!mapped) + I830UnmapMMIO(pScrn); + } +} + +/* + * Use the native method instead of the vgahw method. So far this is + * only used for 8-bit mode. + * + * XXX Look into using the 10-bit gamma correction mode for 15/16/24 bit, + * and see if a DirectColor visual can be offered. + */ +static void +I830LoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, + LOCO * colors, VisualPtr pVisual) +{ + I830Ptr pI830; + int i, index; + unsigned char r, g, b; + CARD32 val, temp; + + DPRINTF(PFX, "I830LoadPalette: numColors: %d\n", numColors); + pI830 = I830PTR(pScrn); + + if (pI830->pipeEnabled[0]) { + /* It seems that an initial read is needed. */ + temp = INREG(PALETTE_A); + for (i = 0; i < numColors; i++) { + index = indices[i]; + r = colors[index].red; + g = colors[index].green; + b = colors[index].blue; + val = (r << 16) | (g << 8) | b; + OUTREG(PALETTE_A + index * 4, val); + } + } + if (pI830->pipeEnabled[1]) { + /* It seems that an initial read is needed. */ + temp = INREG(PALETTE_B); + for (i = 0; i < numColors; i++) { + index = indices[i]; + r = colors[index].red; + g = colors[index].green; + b = colors[index].blue; + val = (r << 16) | (g << 8) | b; + OUTREG(PALETTE_B + index * 4, val); + } + } +} + +static void +PreInitCleanup(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + + RestoreBIOSMemSize(pScrn); + if (pI830->swfSaved) { + OUTREG(SWF0, pI830->saveSWF0); + OUTREG(SWF4, pI830->saveSWF4); + } + if (pI830->MMIOBase) + I830UnmapMMIO(pScrn); + I830BIOSFreeRec(pScrn); +} + +static Bool +I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) +{ + vgaHWPtr hwp; + I830Ptr pI830; + MessageType from; + rgb defaultWeight = { 0, 0, 0 }; + vbeInfoPtr pVbe; + EntityInfoPtr pEnt; + int mem, memsize; + int flags24; + int i, n; + pointer pDDCModule, pVBEModule; + Bool enable; + const char *chipname; + + if (pScrn->numEntities != 1) + return FALSE; + + /* Load int10 module */ + if (!xf86LoadSubModule(pScrn, "int10")) + return FALSE; + xf86LoaderReqSymLists(I810int10Symbols, NULL); + + /* Load vbe module */ + if (!(pVBEModule = xf86LoadSubModule(pScrn, "vbe"))) + return FALSE; + xf86LoaderReqSymLists(I810vbeSymbols, NULL); + + pEnt = xf86GetEntityInfo(pScrn->entityList[0]); + + if (flags & PROBE_DETECT) { + I830BIOSProbeDDC(pScrn, pEnt->index); + return TRUE; + } + + /* The vgahw module should be loaded here when needed */ + if (!xf86LoadSubModule(pScrn, "vgahw")) + return FALSE; + xf86LoaderReqSymLists(I810vgahwSymbols, NULL); + + + /* Allocate a vgaHWRec */ + if (!vgaHWGetHWRec(pScrn)) + return FALSE; + + /* Allocate driverPrivate */ + if (!I830BIOSGetRec(pScrn)) + return FALSE; + + pI830 = I830PTR(pScrn); + pI830->pEnt = pEnt; + + if (pI830->pEnt->location.type != BUS_PCI) + return FALSE; + + pI830->PciInfo = xf86GetPciInfoForEntity(pI830->pEnt->index); + pI830->PciTag = pciTag(pI830->PciInfo->bus, pI830->PciInfo->device, + pI830->PciInfo->func); + + if (xf86RegisterResources(pI830->pEnt->index, 0, ResNone)) { + PreInitCleanup(pScrn); + return FALSE; + + } + + pScrn->racMemFlags = RAC_FB | RAC_COLORMAP; + pScrn->monitor = pScrn->confScreen->monitor; + pScrn->progClock = TRUE; + pScrn->rgbBits = 8; + + flags24 = Support32bppFb | PreferConvert24to32 | SupportConvert24to32; + + if (!xf86SetDepthBpp(pScrn, 0, 0, 0, flags24)) + return FALSE; + + switch (pScrn->depth) { + case 8: + case 15: + case 16: + case 24: + break; + default: + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Given depth (%d) is not supported by I830 driver\n", + pScrn->depth); + return FALSE; + } + xf86PrintDepthBpp(pScrn); + + if (!xf86SetWeight(pScrn, defaultWeight, defaultWeight)) + return FALSE; + if (!xf86SetDefaultVisual(pScrn, -1)) + return FALSE; + + hwp = VGAHWPTR(pScrn); + pI830->cpp = pScrn->bitsPerPixel / 8; + + /* Process the options */ + xf86CollectOptions(pScrn, NULL); + if (!(pI830->Options = xalloc(sizeof(I830BIOSOptions)))) + return FALSE; + memcpy(pI830->Options, I830BIOSOptions, sizeof(I830BIOSOptions)); + xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, pI830->Options); + + /* We have to use PIO to probe, because we haven't mapped yet. */ + I830SetPIOAccess(pI830); + + /* Initialize VBE record */ + if ((pI830->pVbe = VBEInit(NULL, pI830->pEnt->index)) == NULL) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "VBE initialization failed.\n"); + return FALSE; + } + + switch (pI830->PciInfo->chipType) { + case PCI_CHIP_I830_M: + chipname = "830M"; + break; + case PCI_CHIP_845_G: + chipname = "845G"; + break; + case PCI_CHIP_I855_GM: + /* Check capid register to find the chipset variant */ + pI830->variant = (pciReadLong(pI830->PciTag, I85X_CAPID) + >> I85X_VARIANT_SHIFT) & I85X_VARIANT_MASK; + switch (pI830->variant) { + case I855_GM: + chipname = "855GM"; + break; + case I855_GME: + chipname = "855GME"; + break; + case I852_GM: + chipname = "852GM"; + break; + case I852_GME: + chipname = "852GME"; + break; + default: + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Unknown 852GM/855GM variant: 0x%x)\n", pI830->variant); + chipname = "852GM/855GM (unknown variant)"; + break; + } + break; + case PCI_CHIP_I865_G: + chipname = "865G"; + break; + default: + chipname = "unknown chipset"; + break; + } + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Integrated Graphics Chipset: Intel(R) %s\n", chipname); + + pVbe = pI830->pVbe; + + pI830->vbeInfo = VBEGetVBEInfo(pVbe); + + /* Set the Chipset and ChipRev, allowing config file entries to override. */ + if (pI830->pEnt->device->chipset && *pI830->pEnt->device->chipset) { + pScrn->chipset = pI830->pEnt->device->chipset; + from = X_CONFIG; + } else if (pI830->pEnt->device->chipID >= 0) { + pScrn->chipset = (char *)xf86TokenToString(I830BIOSChipsets, + pI830->pEnt->device->chipID); + from = X_CONFIG; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipID override: 0x%04X\n", + pI830->pEnt->device->chipID); + } else { + from = X_PROBED; + pScrn->chipset = (char *)xf86TokenToString(I830BIOSChipsets, + pI830->PciInfo->chipType); + } + + if (pI830->pEnt->device->chipRev >= 0) { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipRev override: %d\n", + pI830->pEnt->device->chipRev); + } + + xf86DrvMsg(pScrn->scrnIndex, from, "Chipset: \"%s\"\n", + (pScrn->chipset != NULL) ? pScrn->chipset : "Unknown i8xx"); + + if (pI830->pEnt->device->MemBase != 0) { + pI830->LinearAddr = pI830->pEnt->device->MemBase; + from = X_CONFIG; + } else { + if (pI830->PciInfo->memBase[1] != 0) { + /* XXX Check mask. */ + pI830->LinearAddr = pI830->PciInfo->memBase[0] & 0xFF000000; + from = X_PROBED; + } else { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "No valid FB address in PCI config space\n"); + PreInitCleanup(pScrn); + return FALSE; + } + } + + xf86DrvMsg(pScrn->scrnIndex, from, "Linear framebuffer at 0x%lX\n", + (unsigned long)pI830->LinearAddr); + + if (pI830->pEnt->device->IOBase != 0) { + pI830->MMIOAddr = pI830->pEnt->device->IOBase; + from = X_CONFIG; + } else { + if (pI830->PciInfo->memBase[1]) { + pI830->MMIOAddr = pI830->PciInfo->memBase[1] & 0xFFF80000; + from = X_PROBED; + } else { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "No valid MMIO address in PCI config space\n"); + PreInitCleanup(pScrn); + return FALSE; + } + } + + xf86DrvMsg(pScrn->scrnIndex, from, "IO registers at addr 0x%lX\n", + (unsigned long)pI830->MMIOAddr); + + /* Some of the probing needs MMIO access, so map it here. */ + I830MapMMIO(pScrn); + +#if 1 + pI830->saveSWF0 = INREG(SWF0); + pI830->saveSWF4 = INREG(SWF4); + pI830->swfSaved = TRUE; + + /* Set "extended desktop" */ + OUTREG(SWF0, pI830->saveSWF0 | (1 << 21)); + + /* Set "driver loaded", "OS unknown", "APM 1.2" */ + OUTREG(SWF4, (pI830->saveSWF4 & ~((3 << 19) | (7 << 16))) | + (1 << 23) | (2 << 16)); +#endif + + if (IS_I830(pI830) || IS_845G(pI830)) { + PCITAG bridge; + CARD16 gmch_ctrl; + + bridge = pciTag(0, 0, 0); /* This is always the host bridge */ + gmch_ctrl = pciReadWord(bridge, I830_GMCH_CTRL); + if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_128M) { + pI830->FbMapSize = 0x8000000; + } else { + pI830->FbMapSize = 0x4000000; + } + } + else { + /* 128MB aperture for later chips */ + pI830->FbMapSize = 0x8000000; + } + + /* + * Get the pre-allocated (stolen) memory size. + */ + pI830->StolenMemory.Size = I830DetectMemory(pScrn); + pI830->StolenMemory.Start = 0; + pI830->StolenMemory.End = pI830->StolenMemory.Size; + + /* Sanity check: compare with what the BIOS thinks. */ + if (pI830->vbeInfo->TotalMemory != pI830->StolenMemory.Size / 1024 / 64) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Detected stolen memory (%d kB) doesn't match what the BIOS" + " reports (%d kB)\n", + ROUND_DOWN_TO(pI830->StolenMemory.Size / 1024, 64), + pI830->vbeInfo->TotalMemory * 64); + } + + /* Find the maximum amount of agpgart memory available. */ + mem = I830CheckAvailableMemory(pScrn); + pI830->StolenOnly = FALSE; + + if (mem <= 0) { + if (pI830->StolenMemory.Size <= 0) { + /* Shouldn't happen. */ + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "/dev/agpgart is either not available, or no memory " + "is available\nfor allocation, " + "and no pre-allocated memory is available.\n"); + PreInitCleanup(pScrn); + return FALSE; + } + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "/dev/agpgart is either not available, or no memory " + "is available\nfor allocation. " + "Using pre-allocated memory only.\n"); + mem = 0; + pI830->StolenOnly = TRUE; + } + + if (xf86ReturnOptValBool(pI830->Options, OPTION_NOACCEL, FALSE)) { + pI830->noAccel = TRUE; + } + if (xf86ReturnOptValBool(pI830->Options, OPTION_SW_CURSOR, FALSE)) { + pI830->SWCursor = TRUE; + } + + pI830->directRenderingDisabled = + !xf86ReturnOptValBool(pI830->Options, OPTION_DRI, TRUE); + +#ifdef XF86DRI + if (!pI830->directRenderingDisabled) { + if (pI830->noAccel || pI830->SWCursor) { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "DRI is disabled because it " + "needs HW cursor and 2D acceleration.\n"); + pI830->directRenderingDisabled = TRUE; + } else if (pScrn->depth != 16 && pScrn->depth != 24) { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "DRI is disabled because it " + "runs only at depths 16 and 24.\n"); + pI830->directRenderingDisabled = TRUE; + } + } +#endif + + /* + * The "VideoRam" config file parameter specifies the total amount of + * memory that will be used/allocated. When agpgart support isn't + * available (StolenOnly == TRUE), this is limited to the amount of + * pre-allocated ("stolen") memory. + */ + + /* + * Default to I830_DEFAULT_VIDEOMEM_2D (8192KB) for 2D-only, + * or I830_DEFAULT_VIDEOMEM_3D (32768KB) for 3D. If the stolen memory + * amount is higher, default to it rounded up to the nearest MB. This + * guarantees that by default there will be at least some run-time + * space for things that need a physical address. + */ + if (!pI830->pEnt->device->videoRam) { + from = X_DEFAULT; +#ifdef XF86DRI + if (!pI830->directRenderingDisabled) + pScrn->videoRam = I830_DEFAULT_VIDEOMEM_3D; + else +#endif + pScrn->videoRam = I830_DEFAULT_VIDEOMEM_2D; + if (pI830->StolenMemory.Size / 1024 > pScrn->videoRam) + pScrn->videoRam = ROUND_TO(pI830->StolenMemory.Size / 1024, 1024); + } else { + from = X_CONFIG; + pScrn->videoRam = pI830->pEnt->device->videoRam; + } + + DPRINTF(PFX, + "Available memory: %dk\n" + "Requested memory: %dk\n", mem, pScrn->videoRam); + + + if (mem + (pI830->StolenMemory.Size / 1024) < pScrn->videoRam) { + pScrn->videoRam = mem + (pI830->StolenMemory.Size / 1024); + from = X_PROBED; + if (mem + (pI830->StolenMemory.Size / 1024) < + pI830->pEnt->device->videoRam) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "VideoRAM reduced to %d kByte " + "(limited to available sysmem)\n", pScrn->videoRam); + } + } + + if (pScrn->videoRam > pI830->FbMapSize / 1024) { + pScrn->videoRam = pI830->FbMapSize / 1024; + if (pI830->FbMapSize / 1024 < pI830->pEnt->device->videoRam) + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "VideoRam reduced to %d kByte (limited to aperture size)\n", + pScrn->videoRam); + } + + if (mem > 0) { + /* + * If the reserved (BIOS accessible) memory is less than the desired + * amount, try to increase it. So far this is only implemented for + * the 845G and 830, but those details are handled in SetBIOSMemSize(). + * + * The BIOS-accessible amount is only important for setting video + * modes. The maximum amount we try to set is limited to what would + * be enough for 1920x1440 with a 2048 pitch. + * + * If ALLOCATE_ALL_BIOSMEM is enabled in i830_memory.c, all of the + * BIOS-aware memory will get allocated. If it isn't then it may + * not be, and in that case there is an assumption that the video + * BIOS won't attempt to access memory beyond what is needed for + * modes that are actually used. ALLOCATE_ALL_BIOSMEM is enabled by + * default. + */ + + /* Try to keep HW cursor and Overlay amounts separate from this. */ + int reserve = (HWCURSOR_SIZE + OVERLAY_SIZE) / 1024; + + if (pScrn->videoRam - reserve >= I830_MAXIMUM_VBIOS_MEM) + pI830->newBIOSMemSize = KB(I830_MAXIMUM_VBIOS_MEM); + else + pI830->newBIOSMemSize = + KB(ROUND_DOWN_TO(pScrn->videoRam - reserve, 64)); + + if (pI830->vbeInfo->TotalMemory * 64 < pI830->newBIOSMemSize / 1024) { + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Will attempt to tell the BIOS that there is " + "%d kB VideoRAM\n", pI830->newBIOSMemSize / 1024); + + if (SaveBIOSMemSize(pScrn)) { + pI830->overrideBIOSMemSize = TRUE; + SetBIOSMemSize(pScrn, pI830->newBIOSMemSize); + + VBEFreeVBEInfo(pI830->vbeInfo); + vbeFree(pI830->pVbe); + pI830->pVbe = VBEInit(NULL, pI830->pEnt->index); + pVbe = pI830->pVbe; + pI830->vbeInfo = VBEGetVBEInfo(pVbe); + + pI830->BIOSMemorySize = KB(pI830->vbeInfo->TotalMemory * 64); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "BIOS now sees %d kB VideoRAM\n", + pI830->BIOSMemorySize / 1024); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "BIOS view of memory size can't be changed " + "(this is not an error).\n"); + } + } + } + + xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Pre-allocated VideoRAM: %d kByte\n", + pI830->StolenMemory.Size / 1024); + xf86DrvMsg(pScrn->scrnIndex, from, "VideoRAM: %d kByte\n", pScrn->videoRam); + pI830->TotalVideoRam = KB(pScrn->videoRam); + + /* + * If the requested videoRam amount is less than the stolen memory size, + * reduce the stolen memory size accordingly. + */ + if (pI830->StolenMemory.Size > pI830->TotalVideoRam) { + pI830->StolenMemory.Size = pI830->TotalVideoRam; + pI830->StolenMemory.End = pI830->TotalVideoRam; + } + + if (xf86GetOptValInteger(pI830->Options, OPTION_CACHE_LINES, + &(pI830->CacheLines))) { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Requested %d cache lines\n", + pI830->CacheLines); + } else { + pI830->CacheLines = -1; + } + + pI830->XvDisabled = + !xf86ReturnOptValBool(pI830->Options, OPTION_XVIDEO, TRUE); + +#ifdef I830_XV + if (xf86GetOptValInteger(pI830->Options, OPTION_VIDEO_KEY, + &(pI830->colorKey))) { + from = X_CONFIG; + } else if (xf86GetOptValInteger(pI830->Options, OPTION_COLOR_KEY, + &(pI830->colorKey))) { + from = X_CONFIG; + } else { + pI830->colorKey = (1 << pScrn->offset.red) | + (1 << pScrn->offset.green) | + (((pScrn->mask.blue >> pScrn->offset.blue) - 1) << + pScrn->offset.blue); + from = X_DEFAULT; + } + xf86DrvMsg(pScrn->scrnIndex, from, "video overlay key set to 0x%x\n", + pI830->colorKey); +#endif + + pI830->allowPageFlip = FALSE; + enable = xf86ReturnOptValBool(pI830->Options, OPTION_PAGEFLIP, FALSE); +#ifdef XF86DRI + if (!pI830->directRenderingDisabled) { + pI830->allowPageFlip = enable; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "page flipping %s\n", + enable ? "enabled" : "disabled"); + } +#endif + + /* Check if the HW cursor needs physical address. */ + if (IS_MOBILE(pI830)) + pI830->CursorNeedsPhysical = TRUE; + else + pI830->CursorNeedsPhysical = FALSE; + + /* Force ring buffer to be in low memory for the 845G. */ + if (IS_845G(pI830)) + pI830->NeedRingBufferLow = TRUE; + + /* + * XXX If we knew the pre-initialised GTT format for certain, we could + * probably figure out the physical address even in the StolenOnly case. + */ + if (pI830->StolenOnly && pI830->CursorNeedsPhysical && !pI830->SWCursor) { + xf86DrvMsg(pScrn->scrnIndex, X_PROBED, + "HW Cursor disabled because it needs agpgart memory.\n"); + pI830->SWCursor = TRUE; + } + + /* + * Reduce the maximum videoram available for video modes by the ring buffer, + * minimum scratch space and HW cursor amounts. + */ + if (!pI830->SWCursor) + pScrn->videoRam -= (HWCURSOR_SIZE / 1024); + if (!pI830->XvDisabled) + pScrn->videoRam -= (OVERLAY_SIZE / 1024); + if (!pI830->noAccel) { + pScrn->videoRam -= (PRIMARY_RINGBUFFER_SIZE / 1024); + pScrn->videoRam -= (MIN_SCRATCH_BUFFER_SIZE / 1024); + } + + xf86DrvMsg(pScrn->scrnIndex, X_PROBED, + "Maximum frambuffer space: %d kByte\n", pScrn->videoRam); + + /* + * If the driver can do gamma correction, it should call xf86SetGamma() here. + */ + + { + Gamma zeros = { 0.0, 0.0, 0.0 }; + + if (!xf86SetGamma(pScrn, zeros)) + return FALSE; + } + + if (IS_MOBILE(pI830)) + pI830->availablePipes = 2; + else + pI830->availablePipes = 1; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%d display pipe%s available.\n", + pI830->availablePipes, pI830->availablePipes > 1 ? "s" : ""); + + if (!I830DetectDisplayDevice(pScrn)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Couldn't detect display devices.\n"); + PreInitCleanup(pScrn); + return FALSE; + } + + if ((pDDCModule = xf86LoadSubModule(pScrn, "ddc")) == NULL) { + PreInitCleanup(pScrn); + return FALSE; + } + + if ((pI830->vesa->monitor = vbeDoEDID(pVbe, pDDCModule)) != NULL) { + xf86PrintEDID(pI830->vesa->monitor); + } + if ((pScrn->monitor->DDC = pI830->vesa->monitor) != NULL) + xf86SetDDCproperties(pScrn, pI830->vesa->monitor); + xf86UnloadSubModule(pDDCModule); + + /* XXX Move this to a header. */ +#define VIDEO_BIOS_SCRATCH 0x18 + +#if 1 + /* + * XXX This should be in ScreenInit/EnterVT. PreInit should not leave the + * state changed. + */ + /* Enable hot keys by writing the proper value to GR18 */ + { + CARD8 gr18; + + gr18 = pI830->readControl(pI830, GRX, VIDEO_BIOS_SCRATCH); + gr18 &= ~0x80; /* + * Clear Hot key bit so that Video + * BIOS performs the hot key + * servicing + */ + pI830->writeControl(pI830, GRX, VIDEO_BIOS_SCRATCH, gr18); + } +#endif + + for (i = 0; i < pI830->availablePipes; i++) { + int pipe = + (pI830->configuredDevices >> PIPE_SHIFT(i)) & PIPE_ACTIVE_MASK; + if (pipe & ~PIPE_CRT_ACTIVE) { + xf86DrvMsg(pScrn->scrnIndex, X_PROBED, + "A non-CRT device is attached to pipe %c.\n" + "\tNo refresh rate overrides will be attempted.\n", + PIPE_NAME(i)); + pI830->vesa->useDefaultRefresh = TRUE; + } + /* + * Some desktop platforms might not have 0x5f05, so useExtendedRefresh + * would need to be set to FALSE for those cases. + */ + if (!pI830->vesa->useDefaultRefresh) + pI830->useExtendedRefresh = TRUE; + } + + if (pI830->useExtendedRefresh) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Will use BIOS call 0x5f05 to set refresh rates for CRTs.\n"); + } + + /* + * Calling 0x5f64 can reset the refresh rate, so only do this when + * using 0x5f05, or when not overriding the default refresh rate. + * Also, 0x5f64 doesn't work correctly in i830 platforms. + */ + pI830->enableDisplays = !IS_I830(pI830) && pI830->useExtendedRefresh; + + if (pI830->enableDisplays) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Will use BIOS call 0x5f64 to enable displays.\n"); + } + + /* + * Limit videoram available for mode selection to what the video + * BIOS can see. + */ + if (pScrn->videoRam > (pI830->vbeInfo->TotalMemory * 64)) + memsize = pI830->vbeInfo->TotalMemory * 64; + else + memsize = pScrn->videoRam; + xf86DrvMsg(pScrn->scrnIndex, X_PROBED, + "Maximum space available for video modes: %d kByte\n", memsize); + + /* + * Note: VBE modes (> 0x7f) won't work with Intel's extended BIOS + * functions. For that reason it's important to set only + * V_MODETYPE_VGA in the flags for VBEGetModePool(). + */ + pScrn->modePool = VBEGetModePool(pScrn, pVbe, pI830->vbeInfo, + V_MODETYPE_VGA); + + if (!pScrn->modePool) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "No Video BIOS modes for chosen depth.\n"); + PreInitCleanup(pScrn); + return FALSE; + } + + VBESetModeNames(pScrn->modePool); + + /* + * XXX DDC information: There's code in xf86ValidateModes + * (VBEValidateModes) to set monitor defaults based on DDC information + * where available. If we need something that does better than this, + * there's code in vesa/vesa.c. + */ + + /* XXX Need to get relevant modes and virtual parameters. */ + /* Do the mode validation without regard to special scanline pitches. */ + n = VBEValidateModes(pScrn, NULL, pScrn->display->modes, NULL, + NULL, 0, MAX_DISPLAY_PITCH, 1, + 0, MAX_DISPLAY_HEIGHT, + pScrn->display->virtualX, + pScrn->display->virtualY, + memsize, LOOKUP_BEST_REFRESH); + if (n <= 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes.\n"); + PreInitCleanup(pScrn); + return FALSE; + } + + xf86PruneDriverModes(pScrn); + + pScrn->currentMode = pScrn->modes; + + if (pScrn->modes == NULL) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No modes.\n"); + PreInitCleanup(pScrn); + return FALSE; + } + +#ifndef USE_PITCHES +#define USE_PITCHES 1 +#endif + + /* + * If DRI is potentially usable, check if there is enough memory available + * for it, and if there's also enough to allow tiling to be enabled. + */ +#if defined(XF86DRI) + if (!pI830->directRenderingDisabled) { + int savedDisplayWidth = pScrn->displayWidth; + int memNeeded = 0; + /* Good pitches to allow tiling. Don't care about pitches < 256. */ + static const int pitches[] = { + 128 * 2, + 128 * 4, + 128 * 8, + 128 * 16, + 128 * 32, + 128 * 64, + 0 + }; + +#ifdef I830_XV + /* + * Set this so that the overlay allocation is factored in when + * appropriate. + */ + pI830->XvEnabled = !pI830->XvDisabled; +#endif + + for (i = 0; pitches[i] != 0; i++) { +#if USE_PITCHES + if (pitches[i] >= pScrn->displayWidth) { + pScrn->displayWidth = pitches[i]; + break; + } +#else + if (pitches[i] == pScrn->displayWidth) + break; +#endif + } + + /* + * If the displayWidth is a tilable pitch, test if there's enough + * memory available to enable tiling. + */ + if (pScrn->displayWidth == pitches[i]) { + I830ResetAllocations(pScrn, 0); + if (I830Allocate2DMemory(pScrn, ALLOCATE_DRY_RUN | ALLOC_INITIAL) && + I830Allocate3DMemory(pScrn, ALLOCATE_DRY_RUN)) { + memNeeded = I830GetExcessMemoryAllocations(pScrn); + if (memNeeded > 0 || pI830->MemoryAperture.Size < 0) { + if (memNeeded > 0) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "%d kBytes additional video memory is " + "required to\n\tenable tiling mode for DRI.\n", + (memNeeded + 1023) / 1024); + } + if (pI830->MemoryAperture.Size < 0) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Allocation with DRI tiling enabled would " + "exceed the\n" + "\tmemory aperture size (%d kB) by %d kB.\n" + "\tReduce VideoRam amount to avoid this!\n", + pI830->FbMapSize / 1024, + -pI830->MemoryAperture.Size / 1024); + } + pScrn->displayWidth = savedDisplayWidth; + pI830->allowPageFlip = FALSE; + } else if (pScrn->displayWidth != savedDisplayWidth) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Increasing the scanline pitch to allow tiling mode " + "(%d -> %d).\n", + savedDisplayWidth, pScrn->displayWidth); + } + } else { + memNeeded = 0; + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Unexpected dry run allocation failure (1).\n"); + } + } + if (memNeeded > 0 || pI830->MemoryAperture.Size < 0) { + /* + * Tiling can't be enabled. Check if there's enough memory for DRI + * without tiling. + */ + I830ResetAllocations(pScrn, 0); + if (I830Allocate2DMemory(pScrn, ALLOCATE_DRY_RUN | ALLOC_INITIAL) && + I830Allocate3DMemory(pScrn, ALLOCATE_DRY_RUN | ALLOC_NO_TILING)) { + memNeeded = I830GetExcessMemoryAllocations(pScrn); + if (memNeeded > 0 || pI830->MemoryAperture.Size < 0) { + if (memNeeded > 0) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "%d kBytes additional video memory is required " + "to enable DRI.\n", + (memNeeded + 1023) / 1024); + } + if (pI830->MemoryAperture.Size < 0) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Allocation with DRI enabled would " + "exceed the\n" + "\tmemory aperture size (%d kB) by %d kB.\n" + "\tReduce VideoRam amount to avoid this!\n", + pI830->FbMapSize / 1024, + -pI830->MemoryAperture.Size / 1024); + } + pI830->directRenderingDisabled = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Disabling DRI.\n"); + } + } else { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Unexpected dry run allocation failure (2).\n"); + } + } + } +#endif + + VBEPrintModes(pScrn); + + if (!pI830->vesa->useDefaultRefresh) { + /* + * This sets the parameters for the VBE modes according to the best + * usable parameters from the Monitor sections modes (usually the + * default VESA modes), allowing for better than default refresh rates. + * This only works for VBE 3.0 and later. Also, we only do this + * if there are no non-CRT devices attached. + */ + VBESetModeParameters(pScrn, pVbe); + } + + /* PreInit shouldn't leave any state changes, so restore this. */ + RestoreBIOSMemSize(pScrn); + + /* Don't need MMIO access anymore. */ + if (pI830->swfSaved) { + OUTREG(SWF0, pI830->saveSWF0); + OUTREG(SWF4, pI830->saveSWF4); + } + I830UnmapMMIO(pScrn); + + /* Set display resolution */ + xf86SetDpi(pScrn, 0, 0); + + /* Load the required sub modules */ + if (!xf86LoadSubModule(pScrn, "fb")) { + PreInitCleanup(pScrn); + return FALSE; + } + + xf86LoaderReqSymLists(I810fbSymbols, NULL); + + if (!pI830->noAccel) { + if (!xf86LoadSubModule(pScrn, "xaa")) { + PreInitCleanup(pScrn); + return FALSE; + } + xf86LoaderReqSymLists(I810xaaSymbols, NULL); + } + + if (!pI830->SWCursor) { + if (!xf86LoadSubModule(pScrn, "ramdac")) { + PreInitCleanup(pScrn); + return FALSE; + } + xf86LoaderReqSymLists(I810ramdacSymbols, NULL); + } + + /* We won't be using the VGA access after the probe. */ + I830SetMMIOAccess(pI830); + xf86SetOperatingState(resVgaIo, pI830->pEnt->index, ResUnusedOpr); + xf86SetOperatingState(resVgaMem, pI830->pEnt->index, ResDisableOpr); + + VBEFreeVBEInfo(pI830->vbeInfo); + vbeFree(pVbe); + +#if defined(XF86DRI) + if (!pI830->directRenderingDisabled) { + if (!xf86LoadSubModule(pScrn, "shadow")) { + PreInitCleanup(pScrn); + return FALSE; + } + xf86LoaderReqSymLists(I810shadowSymbols, NULL); + } +#endif + + return TRUE; +} + +/* + * As the name says. Check that the initial state is reasonable. + * If any unrecoverable problems are found, bail out here. + */ +static Bool +CheckInheritedState(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + int errors = 0, fatal = 0; + unsigned long temp, head, tail; + + /* Check first for page table errors */ + temp = INREG(PGE_ERR); + if (temp != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "PGTBL_ER is 0x%08x\n", temp); + errors++; + } + temp = INREG(PGETBL_CTL); + if (!(temp & 1)) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "PGTBL_CTL (0x%08x) indicates GTT is disabled\n", temp); + errors++; + } + temp = INREG(LP_RING + RING_LEN); + if (temp & 1) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "PRB0_CTL (0x%08x) indicates ring buffer enabled\n", temp); + errors++; + } + head = INREG(LP_RING + RING_HEAD); + tail = INREG(LP_RING + RING_TAIL); + if ((tail & I830_TAIL_MASK) != (head & I830_HEAD_MASK)) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "PRB0_HEAD (0x%08x) and PRB0_TAIL (0x%08x) indicate " + "ring buffer not flushed\n", head, tail); + errors++; + } +#if 0 + if (errors) + I830PrintErrorState(pScrn); +#endif + + if (fatal) + FatalError("CheckInheritedState: can't recover from the above\n"); + + return (errors != 0); +} + +/* + * Reset registers that it doesn't make sense to save/restore to a sane state. + * This is basically the ring buffer and fence registers. Restoring these + * doesn't make sense without restoring GTT mappings. This is something that + * whoever gets control next should do. + */ +static void +ResetState(ScrnInfoPtr pScrn, Bool flush) +{ + I830Ptr pI830 = I830PTR(pScrn); + int i; + unsigned long temp; + + DPRINTF(PFX, "ResetState: flush is %s\n", BOOLTOSTRING(flush)); + + /* Reset the fence registers to 0 */ + for (i = 0; i < 8; i++) + OUTREG(FENCE + i * 4, 0); + + /* Flush the ring buffer (if enabled), then disable it. */ + if (pI830->AccelInfoRec != NULL && flush) { + temp = INREG(LP_RING + RING_LEN); + if (temp & 1) { + I830RefreshRing(pScrn); + I830Sync(pScrn); + DO_RING_IDLE(); + } + } + OUTREG(LP_RING + RING_LEN, 0); + OUTREG(LP_RING + RING_HEAD, 0); + OUTREG(LP_RING + RING_TAIL, 0); + OUTREG(LP_RING + RING_START, 0); + + if (pI830->CursorInfoRec && pI830->CursorInfoRec->HideCursor) + pI830->CursorInfoRec->HideCursor(pScrn); +} + +static void +SetFenceRegs(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + int i; + + DPRINTF(PFX, "SetFenceRegs\n"); + + for (i = 0; i < 8; i++) { + OUTREG(FENCE + i * 4, pI830->ModeReg.Fence[i]); + if (I810_DEBUG & DEBUG_VERBOSE_VGA) + ErrorF("Fence Register : %x\n", pI830->ModeReg.Fence[i]); + } +} + +static void +SetRingRegs(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + unsigned int itemp; + + DPRINTF(PFX, "SetRingRegs\n"); + + if (pI830->noAccel) + return; + + OUTREG(LP_RING + RING_LEN, 0); + OUTREG(LP_RING + RING_TAIL, 0); + OUTREG(LP_RING + RING_HEAD, 0); + + if ((pI830->LpRing.mem.Start & I830_RING_START_MASK) != + pI830->LpRing.mem.Start) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "I830SetRingRegs: Ring buffer start (%x) violates its " + "mask (%x)\n", pI830->LpRing.mem.Start, I830_RING_START_MASK); + } + /* Don't care about the old value. Reserved bits must be zero anyway. */ + itemp = pI830->LpRing.mem.Start & I830_RING_START_MASK; + OUTREG(LP_RING + RING_START, itemp); + + if (((pI830->LpRing.mem.Size - 4096) & I830_RING_NR_PAGES) != + pI830->LpRing.mem.Size - 4096) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "I830SetRingRegs: Ring buffer size - 4096 (%x) violates its " + "mask (%x)\n", pI830->LpRing.mem.Size - 4096, + I830_RING_NR_PAGES); + } + /* Don't care about the old value. Reserved bits must be zero anyway. */ + itemp = (pI830->LpRing.mem.Size - 4096) & I830_RING_NR_PAGES; + itemp |= (RING_NO_REPORT | RING_VALID); + OUTREG(LP_RING + RING_LEN, itemp); + I830RefreshRing(pScrn); +} + +/* + * This should be called everytime the X server gains control of the screen, + * before any video modes are programmed (ScreenInit, EnterVT). + */ +static void +SetHWOperatingState(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + + DPRINTF(PFX, "SetHWOperatingState\n"); + + if (!pI830->noAccel) + SetRingRegs(pScrn); + SetFenceRegs(pScrn); + if (!pI830->SWCursor) + I830InitHWCursor(pScrn); +} + +static Bool +SaveHWState(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + vbeInfoPtr pVbe = pI830->pVbe; + vgaHWPtr hwp = VGAHWPTR(pScrn); + vgaRegPtr vgaReg = &hwp->SavedReg; + VbeModeInfoBlock *modeInfo; + VESAPtr pVesa; + + DPRINTF(PFX, "SaveHWState\n"); + + pVesa = pI830->vesa; + /* Make sure we save at least this information in case of failure. */ + VBEGetVBEMode(pVbe, &pVesa->stateMode); + modeInfo = VBEGetModeInfo(pVbe, pVesa->stateMode); + pVesa->savedScanlinePitch = 0; + if (modeInfo) { + if (VBE_MODE_GRAPHICS(modeInfo)) { + VBEGetLogicalScanline(pVbe, &pVesa->savedScanlinePitch, NULL, NULL); + } + VBEFreeModeInfo(modeInfo); + } + + vgaHWUnlock(hwp); + vgaHWSave(pScrn, vgaReg, VGA_SR_FONTS); + +#ifndef I845G_VBE_WORKAROUND +#define I845G_VBE_WORKAROUND 1 +#endif + + pVesa = pI830->vesa; + /* This save/restore method doesn't work for 845G BIOS */ + /* + * XXX If it's fixed in production versions, this could be removed. + * + * KW: This may have been because of the behaviour I've found on my + * board: The 'save' command actually modifies the interrupt + * registers, turning off the irq & breaking the kernel module + * behaviour. + */ + if (!I845G_VBE_WORKAROUND || !IS_845G(pI830)) { + CARD16 imr = INREG16(IMR); + CARD16 ier = INREG16(IER); + CARD16 hwstam = INREG16(HWSTAM); + + if (!VBESaveRestore(pVbe, MODE_SAVE, &pVesa->state, &pVesa->stateSize, + &pVesa->statePage)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "SaveHWState: VBESaveRestore(MODE_SAVE) failed.\n"); + return FALSE; + } + + OUTREG16(IMR, imr); + OUTREG16(IER, ier); + OUTREG16(HWSTAM, hwstam); + } + + pVesa->savedPal = VBESetGetPaletteData(pVbe, FALSE, 0, 256, + NULL, FALSE, FALSE); + if (!pVesa->savedPal) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "SaveHWState: VBESetGetPaletteData(GET) failed.\n"); + return FALSE; + } + + return TRUE; +} + +static Bool +RestoreHWState(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + vbeInfoPtr pVbe = pI830->pVbe; + vgaHWPtr hwp = VGAHWPTR(pScrn); + vgaRegPtr vgaReg = &hwp->SavedReg; + VESAPtr pVesa; + Bool restored = FALSE; + + DPRINTF(PFX, "RestoreHWState\n"); + + pVesa = pI830->vesa; + + /* + * Workaround for text mode restoration with some flat panels. + * Temporarily program a 640x480 mode before switching back to + * text mode. + */ + if (pVesa->useDefaultRefresh) { + int mode = 0; + + switch (pScrn->depth) { + case 8: + mode = 0x30; + break; + case 15: + mode = 0x40; + break; + case 16: + mode = 0x41; + break; + case 24: + mode = 0x50; + break; + } + mode |= (1 << 15) | (1 << 14); + I830VESASetVBEMode(pScrn, mode, NULL); + } + + if (pVesa->state && pVesa->stateSize) { + CARD16 imr = INREG16(IMR); + CARD16 ier = INREG16(IER); + CARD16 hwstam = INREG16(HWSTAM); + + /* Make a copy of the state. Don't rely on it not being touched. */ + if (!pVesa->pstate) { + pVesa->pstate = xalloc(pVesa->stateSize); + if (pVesa->pstate) + memcpy(pVesa->pstate, pVesa->state, pVesa->stateSize); + } + restored = VBESaveRestore(pVbe, MODE_RESTORE, &pVesa->state, + &pVesa->stateSize, &pVesa->statePage); + if (!restored) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "RestoreHWState: VBESaveRestore failed.\n"); + } + /* Copy back */ + if (pVesa->pstate) + memcpy(pVesa->state, pVesa->pstate, pVesa->stateSize); + + OUTREG16(IMR, imr); + OUTREG16(IER, ier); + OUTREG16(HWSTAM, hwstam); + } + /* If that failed, restore the original mode. */ + if (!restored) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Setting the original video mode instead of restoring\n\t" + "the saved state\n"); + I830VESASetVBEMode(pScrn, pVesa->stateMode, NULL); + } + if (pVesa->savedScanlinePitch) + VBESetLogicalScanline(pVbe, pVesa->savedScanlinePitch); + + if (pVesa->savedPal) + VBESetGetPaletteData(pVbe, TRUE, 0, 256, pVesa->savedPal, FALSE, TRUE); + + vgaHWRestore(pScrn, vgaReg, VGA_SR_FONTS); + vgaHWLock(hwp); + return TRUE; +} + +#ifndef USE_VBE +#define USE_VBE 1 +#endif + +static Bool +I830VESASetVBEMode(ScrnInfoPtr pScrn, int mode, VbeCRTCInfoBlock * block) +{ + I830Ptr pI830 = I830PTR(pScrn); + + DPRINTF(PFX, "Setting mode 0x%.8x\n", mode); +#if USE_VBE + return VBESetVBEMode(pI830->pVbe, mode, block); +#else + { + vbeInfoPtr pVbe = pI830->pVbe; + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x80 | (mode & 0x7f); + xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); + pVbe->pInt10->ax = 0x0f00; + xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); + if ((pVbe->pInt10->ax & 0x7f) == (mode & 0x7f)) + return TRUE; + else + return FALSE; + } +#endif +} + +static Bool +I830VESASetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode) +{ + I830Ptr pI830 = I830PTR(pScrn); + vbeInfoPtr pVbe = pI830->pVbe; + VbeModeInfoData *data; + int mode, i; + CARD32 planeA, planeB, temp; + int refresh = 60; +#ifdef XF86DRI + Bool didLock = FALSE; +#endif + + DPRINTF(PFX, "I830VESASetMode\n"); + + data = (VbeModeInfoData *) pMode->Private; + + /* Always Enable Linear Addressing */ + mode = data->mode | (1 << 15) | (1 << 14); + +#ifdef XF86DRI + if (pI830->directRenderingEnabled && !pI830->LockHeld) { + DRILock(screenInfo.screens[pScrn->scrnIndex], 0); + pI830->LockHeld = 1; + didLock = TRUE; + } +#endif + +#ifndef MODESWITCH_RESET_STATE +#define MODESWITCH_RESET_STATE 0 +#endif +#if MODESWITCH_RESET_STATE + ResetState(pScrn, TRUE); +#endif + + /* XXX Add macros for the various mode parameter bits. */ + + if (pI830->vesa->useDefaultRefresh) + mode &= ~(1 << 11); + + if (I830VESASetVBEMode(pScrn, mode, data->block) == FALSE) { + if ((data->block && (mode & (1 << 11))) && + I830VESASetVBEMode(pScrn, (mode & ~(1 << 11)), NULL) == TRUE) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Set VBE Mode rejected this modeline.\n\t" + "Trying standard mode instead!\n"); + DPRINTF(PFX, "OOPS!\n"); + xfree(data->block); + data->block = NULL; + data->mode &= ~(1 << 11); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Set VBE Mode failed!\n"); + return FALSE; + } + } + + /* + * The BIOS may not set a scanline pitch that would require more video + * memory than it's aware of. We check for this later, and set it + * explicitly if necessary. + */ + if (data->data->XResolution != pScrn->displayWidth) + VBESetLogicalScanline(pVbe, pScrn->displayWidth); + + if (pScrn->bitsPerPixel >= 8 && pI830->vbeInfo->Capabilities[0] & 0x01) + VBESetGetDACPaletteFormat(pVbe, 8); + + /* + * XXX This location of this isn't correct. + * + * Turn on the configured displays. This has the effect of resetting + * the default refresh rates to values that the configured displays + * can handle. This seems to be the safest way to make sure that this + * happens. When it's safe to set higher values, we do that after this. + * + * Note: When a DFP is connected to an 830, this causes the mode setting + * to be trashed. So, we don't do it on the 830. + * + * XXX Need to test an 830 with a LFP. + */ + if (pI830->enableDisplays) { + if (!SetDisplayDevices(pScrn, pI830->configuredDevices)) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Failed to switch to configured display devices\n"); + } + } + + /* + * When it's OK to set better than default refresh rates, set them here. + */ + if (pI830->useExtendedRefresh && !pI830->vesa->useDefaultRefresh && + (mode & (1 << 11)) && data && data->data && data->block) { + refresh = SetRefreshRate(pScrn, mode, data->block->RefreshRate / 100); + if (!refresh) { + refresh = 60; + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Failed to set refresh rate to %dHz.\n", + data->block->RefreshRate / 100); + } + } + + + /* XXX Fix plane A with pipe A, and plane B with pipe B. */ + planeA = INREG(DSPACNTR); + planeB = INREG(DSPBCNTR); + + pI830->planeEnabled[0] = ((planeA & DISPLAY_PLANE_ENABLE) != 0); + pI830->planeEnabled[1] = ((planeB & DISPLAY_PLANE_ENABLE) != 0); + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Display plane A is %s.\n", + pI830->planeEnabled[0] ? "enabled" : "disabled"); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Display plane B is %s.\n", + pI830->planeEnabled[1] ? "enabled" : "disabled"); + + /* + * Sometimes it seems that no display planes are enabled at this point. + * For mobile platforms pick the plane(s) connected to enabled pipes. + * For others choose plane A. + */ + if (!pI830->planeEnabled[0] && !pI830->planeEnabled[1]) { + if (IS_MOBILE(pI830)) { + if ((pI830->pipeEnabled[0] && + ((planeA & DISPPLANE_SEL_PIPE_MASK) == DISPPLANE_SEL_PIPE_A)) || + (pI830->pipeEnabled[1] && + ((planeA & DISPPLANE_SEL_PIPE_MASK) == DISPPLANE_SEL_PIPE_B))) { + pI830->planeEnabled[0] = TRUE; + } + if ((pI830->pipeEnabled[0] && + ((planeB & DISPPLANE_SEL_PIPE_MASK) == DISPPLANE_SEL_PIPE_A)) || + (pI830->pipeEnabled[1] && + ((planeB & DISPPLANE_SEL_PIPE_MASK) == DISPPLANE_SEL_PIPE_B))) { + pI830->planeEnabled[1] = TRUE; + } + } else { + pI830->planeEnabled[0] = TRUE; + } + if (pI830->planeEnabled[0]) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Enabling plane A.\n"); + planeA |= DISPLAY_PLANE_ENABLE; + OUTREG(DSPACNTR, planeA); + /* flush the change. */ + temp = INREG(DSPABASE); + OUTREG(DSPABASE, temp); + } + if (pI830->planeEnabled[1]) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Enabling plane B.\n"); + planeB |= DISPLAY_PLANE_ENABLE; + OUTREG(DSPBCNTR, planeB); + /* flush the change. */ + temp = INREG(DSPBADDR); + OUTREG(DSPBADDR, temp); + } + } + + /* XXX Plane C is ignored for now (overlay). */ + + /* + * Print out the PIPEACONF and PIPEBCONF registers. + */ + temp = INREG(PIPEACONF); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "PIPEACONF is 0x%08x\n", temp); + if (IS_MOBILE(pI830)) { + temp = INREG(PIPEBCONF); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "PIPEBCONF is 0x%08x\n", temp); + } + +#if PRINT_MODE_INFO + /* Print out some CRTC/display information. */ + temp = INREG(HTOTAL_A); + ErrorF("Horiz active: %d, Horiz total: %d\n", temp & 0x7ff, + (temp >> 16) & 0xfff); + temp = INREG(HBLANK_A); + ErrorF("Horiz blank start: %d, Horiz blank end: %d\n", temp & 0xfff, + (temp >> 16) & 0xfff); + temp = INREG(HSYNC_A); + ErrorF("Horiz sync start: %d, Horiz sync end: %d\n", temp & 0xfff, + (temp >> 16) & 0xfff); + temp = INREG(VTOTAL_A); + ErrorF("Vert active: %d, Vert total: %d\n", temp & 0x7ff, + (temp >> 16) & 0xfff); + temp = INREG(VBLANK_A); + ErrorF("Vert blank start: %d, Vert blank end: %d\n", temp & 0xfff, + (temp >> 16) & 0xfff); + temp = INREG(VSYNC_A); + ErrorF("Vert sync start: %d, Vert sync end: %d\n", temp & 0xfff, + (temp >> 16) & 0xfff); + temp = INREG(PIPEASRC); + ErrorF("Image size: %dx%d (%dx%d)\n", + (temp >> 16) & 0x7ff, temp & 0x7ff, + (((temp >> 16) & 0x7ff) + 1), ((temp & 0x7ff) + 1)); + ErrorF("Pixel multiply is %d\n", (planeA >> 20) & 0x3); + temp = INREG(DSPABASE); + ErrorF("Plane A start offset is %d\n", temp); + temp = INREG(DSPASTRIDE); + ErrorF("Plane A stride is %d bytes (%d pixels)\n", temp, temp / pI830->cpp); +#endif + + for (i = 0; i < MAX_DISPLAY_PIPES; i++) { + CARD32 stridereg = i ? DSPBSTRIDE : DSPASTRIDE; + CARD32 basereg = i ? DSPBBASE : DSPABASE; + + if (!pI830->planeEnabled[i]) + continue; + + temp = INREG(stridereg); + if (temp / pI830->cpp != pScrn->displayWidth) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Correcting plane %c stride (%d -> %d)\n", PIPE_NAME(i), + temp / pI830->cpp, pScrn->displayWidth); + OUTREG(stridereg, pScrn->displayWidth * pI830->cpp); + /* Trigger update */ + temp = INREG(basereg); + OUTREG(basereg, temp); + } + } + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Mode bandwidth is %d Mpixel/s\n", + pMode->HDisplay * pMode->VDisplay * refresh / 1000000); + + { + int maxBandwidth, bandwidthA, bandwidthB; + + if (GetModeSupport(pScrn, 0x80, 0x80, 0x80, 0x80, + &maxBandwidth, &bandwidthA, &bandwidthB)) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "maxBandwidth is %d Mbyte/s, " + "pipe bandwidths are %d Mbyte/s, %d Mbyte/s\n", + maxBandwidth, bandwidthA, bandwidthB); + } + } + + { + int ret; + + ret = GetLFPCompMode(pScrn); + if (ret != -1) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "LFP compensation mode: 0x%x\n", ret); + } + } + +#if MODESWITCH_RESET_STATE + ResetState(pScrn, TRUE); + SetHWOperatingState(pScrn); +#endif + +#ifdef XF86DRI + if (pI830->directRenderingEnabled && didLock) { + DRIUnlock(screenInfo.screens[pScrn->scrnIndex]); + pI830->LockHeld = 0; + } +#endif + + pScrn->vtSema = TRUE; + return TRUE; +} + +static void +InitRegisterRec(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + I830RegPtr i830Reg = &pI830->ModeReg; + int i; + + for (i = 0; i < 8; i++) + i830Reg->Fence[i] = 0; +} + +/* Famous last words + */ +void +I830PrintErrorState(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + + ErrorF("pgetbl_ctl: 0x%lx pgetbl_err: 0x%lx\n", + INREG(PGETBL_CTL), INREG(PGE_ERR)); + + ErrorF("ipeir: %lx iphdr: %lx\n", INREG(IPEIR), INREG(IPEHR)); + + ErrorF("LP ring tail: %lx head: %lx len: %lx start %lx\n", + INREG(LP_RING + RING_TAIL), + INREG(LP_RING + RING_HEAD) & HEAD_ADDR, + INREG(LP_RING + RING_LEN), INREG(LP_RING + RING_START)); + + ErrorF("eir: %x esr: %x emr: %x\n", + INREG16(EIR), INREG16(ESR), INREG16(EMR)); + + ErrorF("instdone: %x instpm: %x\n", INREG16(INST_DONE), INREG8(INST_PM)); + + ErrorF("memmode: %lx instps: %lx\n", INREG(MEMMODE), INREG(INST_PS)); + + ErrorF("hwstam: %x ier: %x imr: %x iir: %x\n", + INREG16(HWSTAM), INREG16(IER), INREG16(IMR), INREG16(IIR)); +} + +#ifdef I830DEBUG +static void +dump_DSPACNTR(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + unsigned int tmp; + + /* Display A Control */ + tmp = INREG(0x70180); + ErrorF("Display A Plane Control Register (0x%.8x)\n", tmp); + + if (tmp & BIT(31)) + ErrorF(" Display Plane A (Primary) Enable\n"); + else + ErrorF(" Display Plane A (Primary) Disabled\n"); + + if (tmp & BIT(30)) + ErrorF(" Display A pixel data is gamma corrected\n"); + else + ErrorF(" Display A pixel data bypasses gamma correction logic (default)\n"); + + switch ((tmp & 0x3c000000) >> 26) { /* bit 29:26 */ + case 0x00: + case 0x01: + case 0x03: + ErrorF(" Reserved\n"); + break; + case 0x02: + ErrorF(" 8-bpp Indexed\n"); + break; + case 0x04: + ErrorF(" 15-bit (5-5-5) pixel format (Targa compatible)\n"); + break; + case 0x05: + ErrorF(" 16-bit (5-6-5) pixel format (XGA compatible)\n"); + break; + case 0x06: + ErrorF(" 32-bit format (X:8:8:8)\n"); + break; + case 0x07: + ErrorF(" 32-bit format (8:8:8:8)\n"); + break; + default: + ErrorF(" Unknown - Invalid register value maybe?\n"); + } + + if (tmp & BIT(25)) + ErrorF(" Stereo Enable\n"); + else + ErrorF(" Stereo Disable\n"); + + if (tmp & BIT(24)) + ErrorF(" Display A, Pipe B Select\n"); + else + ErrorF(" Display A, Pipe A Select\n"); + + if (tmp & BIT(22)) + ErrorF(" Source key is enabled\n"); + else + ErrorF(" Source key is disabled\n"); + + switch ((tmp & 0x00300000) >> 20) { /* bit 21:20 */ + case 0x00: + ErrorF(" No line duplication\n"); + break; + case 0x01: + ErrorF(" Line/pixel Doubling\n"); + break; + case 0x02: + case 0x03: + ErrorF(" Reserved\n"); + break; + } + + if (tmp & BIT(18)) + ErrorF(" Stereo output is high during second image\n"); + else + ErrorF(" Stereo output is high during first image\n"); +} + +static void +dump_DSPBCNTR(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + unsigned int tmp; + + /* Display B/Sprite Control */ + tmp = INREG(0x71180); + ErrorF("Display B/Sprite Plane Control Register (0x%.8x)\n", tmp); + + if (tmp & BIT(31)) + ErrorF(" Display B/Sprite Enable\n"); + else + ErrorF(" Display B/Sprite Disable\n"); + + if (tmp & BIT(30)) + ErrorF(" Display B pixel data is gamma corrected\n"); + else + ErrorF(" Display B pixel data bypasses gamma correction logic (default)\n"); + + switch ((tmp & 0x3c000000) >> 26) { /* bit 29:26 */ + case 0x00: + case 0x01: + case 0x03: + ErrorF(" Reserved\n"); + break; + case 0x02: + ErrorF(" 8-bpp Indexed\n"); + break; + case 0x04: + ErrorF(" 15-bit (5-5-5) pixel format (Targa compatible)\n"); + break; + case 0x05: + ErrorF(" 16-bit (5-6-5) pixel format (XGA compatible)\n"); + break; + case 0x06: + ErrorF(" 32-bit format (X:8:8:8)\n"); + break; + case 0x07: + ErrorF(" 32-bit format (8:8:8:8)\n"); + break; + default: + ErrorF(" Unknown - Invalid register value maybe?\n"); + } + + if (tmp & BIT(25)) + ErrorF(" Stereo is enabled and both start addresses are used in a two frame sequence\n"); + else + ErrorF(" Stereo disable and only a single start address is used\n"); + + if (tmp & BIT(24)) + ErrorF(" Display B/Sprite, Pipe B Select\n"); + else + ErrorF(" Display B/Sprite, Pipe A Select\n"); + + if (tmp & BIT(22)) + ErrorF(" Sprite source key is enabled\n"); + else + ErrorF(" Sprite source key is disabled (default)\n"); + + switch ((tmp & 0x00300000) >> 20) { /* bit 21:20 */ + case 0x00: + ErrorF(" No line duplication\n"); + break; + case 0x01: + ErrorF(" Line/pixel Doubling\n"); + break; + case 0x02: + case 0x03: + ErrorF(" Reserved\n"); + break; + } + + if (tmp & BIT(18)) + ErrorF(" Stereo output is high during second image\n"); + else + ErrorF(" Stereo output is high during first image\n"); + + if (tmp & BIT(15)) + ErrorF(" Alpha transfer mode enabled\n"); + else + ErrorF(" Alpha transfer mode disabled\n"); + + if (tmp & BIT(0)) + ErrorF(" Sprite is above overlay\n"); + else + ErrorF(" Sprite is above display A (default)\n"); +} + +void +I830_dump_registers(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + unsigned int i; + + ErrorF("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"); + + dump_DSPACNTR(pScrn); + dump_DSPBCNTR(pScrn); + + ErrorF("0x71400 == 0x%.8x\n", INREG(0x71400)); + ErrorF("0x70008 == 0x%.8x\n", INREG(0x70008)); + for (i = 0x71410; i <= 0x71428; i += 4) + ErrorF("0x%x == 0x%.8x\n", i, INREG(i)); + + ErrorF("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"); +} +#endif + +static Bool +I830BIOSScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) +{ + ScrnInfoPtr pScrn; + vgaHWPtr hwp; + I830Ptr pI830; + VisualPtr visual; +#ifdef XF86DRI + Bool driDisabled; +#endif + + pScrn = xf86Screens[pScreen->myNum]; + pI830 = I830PTR(pScrn); + hwp = VGAHWPTR(pScrn); + + pI830->starting = TRUE; + + /* + * If we're changing the BIOS's view of the video memory size, do that + * first, then re-initialise the VBE information. + */ + pI830->pVbe = VBEInit(NULL, pI830->pEnt->index); + SetBIOSMemSize(pScrn, pI830->newBIOSMemSize); + if (!pI830->pVbe) + return FALSE; + pI830->vbeInfo = VBEGetVBEInfo(pI830->pVbe); + + miClearVisualTypes(); + if (!xf86SetDefaultVisual(pScrn, -1)) + return FALSE; + if (pScrn->bitsPerPixel > 8) { + if (!miSetVisualTypes(pScrn->depth, TrueColorMask, + pScrn->rgbBits, TrueColor)) + return FALSE; + } else { + if (!miSetVisualTypes(pScrn->depth, + miGetDefaultVisualMask(pScrn->depth), + pScrn->rgbBits, pScrn->defaultVisual)) + return FALSE; + } + if (!miSetPixmapDepths()) + return FALSE; + +#ifdef I830_XV + pI830->XvEnabled = !pI830->XvDisabled; + if (pI830->XvEnabled) { + if (pI830->noAccel || pI830->StolenOnly) { + xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Xv is disabled because it " + "needs 2D accel and AGPGART.\n"); + pI830->XvEnabled = FALSE; + } + } +#else + pI830->XvEnabled = FALSE; +#endif + + I830ResetAllocations(pScrn, 0); + + I830Allocate2DMemory(pScrn, ALLOC_INITIAL); + + if (!pI830->noAccel) { + if (pI830->LpRing.mem.Size == 0) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Disabling acceleration because the ring buffer " + "allocation failed.\n"); + pI830->noAccel = TRUE; + } + } + + if (!pI830->SWCursor) { + if (pI830->CursorMem.Size == 0) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Disabling HW cursor because the cursor memory " + "allocation failed.\n"); + pI830->SWCursor = TRUE; + } + } + +#ifdef I830_XV + if (pI830->XvEnabled) { + if (pI830->noAccel) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Disabling Xv because it " + "needs 2D acceleration.\n"); + pI830->XvEnabled = FALSE; + } + if (pI830->OverlayMem.Physical == 0) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Disabling Xv because the overlay register buffer " + "allocation failed.\n"); + pI830->XvEnabled = FALSE; + } + } +#endif + + InitRegisterRec(pScrn); + +#ifdef XF86DRI + /* + * pI830->directRenderingDisabled is set once in PreInit. Reinitialise + * pI830->directRenderingEnabled based on it each generation. + */ + pI830->directRenderingEnabled = !pI830->directRenderingDisabled; + /* + * Setup DRI after visuals have been established, but before fbScreenInit + * is called. fbScreenInit will eventually call into the drivers + * InitGLXVisuals call back. + */ + + if (pI830->directRenderingEnabled) { + if (pI830->noAccel || pI830->SWCursor || pI830->StolenOnly) { + xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "DRI is disabled because it " + "needs HW cursor, 2D accel and AGPGART.\n"); + pI830->directRenderingEnabled = FALSE; + } + } + + driDisabled = !pI830->directRenderingEnabled; + + if (pI830->directRenderingEnabled) + pI830->directRenderingEnabled = I830DRIScreenInit(pScreen); + + if (pI830->directRenderingEnabled) + if (!(pI830->directRenderingEnabled = I830Allocate3DMemory(pScrn, 0))) + I830DRICloseScreen(pScreen); + +#else + pI830->directRenderingEnabled = FALSE; +#endif + + /* + * After the 3D allocations have been done, see if there's any free space + * that can be added to the framebuffer allocation. + */ + I830Allocate2DMemory(pScrn, 0); + + DPRINTF(PFX, "assert(if(!I830DoPoolAllocation(pScrn, pI830->StolenPool)))\n"); + if (!I830DoPoolAllocation(pScrn, &(pI830->StolenPool))) + return FALSE; + + DPRINTF(PFX, "assert( if(!I830FixupOffsets(pScrn)) )\n"); + if (!I830FixupOffsets(pScrn)) + return FALSE; + +#ifdef XF86DRI + if (pI830->directRenderingEnabled) { + I830SetupMemoryTiling(pScrn); + pI830->directRenderingEnabled = I830DRIDoMappings(pScreen); + } +#endif + + DPRINTF(PFX, "assert( if(!I830MapMem(pScrn)) )\n"); + if (!I830MapMem(pScrn)) + return FALSE; + + pScrn->memPhysBase = (unsigned long)pI830->FbBase; + pScrn->fbOffset = pI830->FrontBuffer.Start; + + vgaHWSetMmioFuncs(hwp, pI830->MMIOBase, 0); + vgaHWGetIOBase(hwp); + DPRINTF(PFX, "assert( if(!vgaHWMapMem(pScrn)) )\n"); + if (!vgaHWMapMem(pScrn)) + return FALSE; + + /* Clear SavedReg */ + memset(&pI830->SavedReg, 0, sizeof(pI830->SavedReg)); + + DPRINTF(PFX, "assert( if(!I830BIOSEnterVT(scrnIndex, 0)) )\n"); + if (!I830BIOSEnterVT(scrnIndex, 0)) + return FALSE; + + DPRINTF(PFX, "assert( if(!fbScreenInit(pScreen, ...) )\n"); + if (!fbScreenInit(pScreen, pI830->FbBase + pScrn->fbOffset, + pScrn->virtualX, pScrn->virtualY, + pScrn->xDpi, pScrn->yDpi, + pScrn->displayWidth, pScrn->bitsPerPixel)) + return FALSE; + + if (pScrn->bitsPerPixel > 8) { + /* Fixup RGB ordering */ + visual = pScreen->visuals + pScreen->numVisuals; + while (--visual >= pScreen->visuals) { + if ((visual->class | DynamicClass) == DirectColor) { + visual->offsetRed = pScrn->offset.red; + visual->offsetGreen = pScrn->offset.green; + visual->offsetBlue = pScrn->offset.blue; + visual->redMask = pScrn->mask.red; + visual->greenMask = pScrn->mask.green; + visual->blueMask = pScrn->mask.blue; + } + } + } + + fbPictureInit(pScreen, 0, 0); + + xf86SetBlackWhitePixels(pScreen); + +#if 1 + I830DGAInit(pScreen); +#endif + + DPRINTF(PFX, + "assert( if(!xf86InitFBManager(pScreen, &(pI830->FbMemBox))) )\n"); + if (!xf86InitFBManager(pScreen, &(pI830->FbMemBox))) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to init memory manager\n"); + return FALSE; + } + + if (!pI830->noAccel) { + if (!I830AccelInit(pScreen)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Hardware acceleration initialization failed\n"); + } + } + + miInitializeBackingStore(pScreen); + xf86SetBackingStore(pScreen); + xf86SetSilkenMouse(pScreen); + miDCInitialize(pScreen, xf86GetPointerScreenFuncs()); + + if (!pI830->SWCursor) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Initializing HW Cursor\n"); + if (!I830CursorInit(pScreen)) + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Hardware cursor initialization failed\n"); + } else + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Initializing SW Cursor!\n"); + + DPRINTF(PFX, "assert( if(!miCreateDefColormap(pScreen)) )\n"); + if (!miCreateDefColormap(pScreen)) + return FALSE; + + DPRINTF(PFX, "assert( if(!xf86HandleColormaps(pScreen, ...)) )\n"); + if (!xf86HandleColormaps(pScreen, 256, 8, I830LoadPalette, 0, + CMAP_RELOAD_ON_MODE_SWITCH)) { + return FALSE; + } + +#ifdef DPMSExtension + xf86DPMSInit(pScreen, I830DisplayPowerManagementSet, 0); +#endif + +#ifdef I830_XV + /* Init video */ + if (pI830->XvEnabled) + I830InitVideo(pScreen); +#endif + +#ifdef XF86DRI + if (pI830->directRenderingEnabled) { + pI830->directRenderingEnabled = I830DRIFinishScreenInit(pScreen); + } +#endif + +#ifdef XF86DRI + if (pI830->directRenderingEnabled) { + pI830->directRenderingOpen = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "direct rendering: Enabled\n"); + /* Setup 3D engine */ + I830EmitInvarientState(pScrn); + } else { + if (driDisabled) + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "direct rendering: Disabled\n"); + else + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "direct rendering: Failed\n"); + } +#else + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "direct rendering: Not available\n"); +#endif + + pScreen->SaveScreen = I830BIOSSaveScreen; + pI830->CloseScreen = pScreen->CloseScreen; + pScreen->CloseScreen = I830BIOSCloseScreen; + + if (serverGeneration == 1) + xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options); +#if 0 +#ifdef I830DEBUG + I830_dump_registers(pScrn); +#endif +#endif + + pI830->starting = FALSE; + pI830->closing = FALSE; + pI830->suspended = FALSE; + return TRUE; +} + +static void +I830BIOSAdjustFrame(int scrnIndex, int x, int y, int flags) +{ + ScrnInfoPtr pScrn; + I830Ptr pI830; + vbeInfoPtr pVbe; + static int xoffset = 0, yoffset = 0; + static int adjustGeneration = -1; + + pScrn = xf86Screens[scrnIndex]; + pI830 = I830PTR(pScrn); + pVbe = pI830->pVbe; + + DPRINTF(PFX, "I830BIOSAdjustFrame: y = %d (+ %d), x = %d (+ %d)\n", + x, xoffset, y, yoffset); + + /* Calculate the offsets once per server generation. */ + if (adjustGeneration != serverGeneration) { + adjustGeneration = serverGeneration; + xoffset = (pScrn->fbOffset / pI830->cpp) % pScrn->displayWidth; + yoffset = (pScrn->fbOffset / pI830->cpp) / pScrn->displayWidth; + } + + if (OffsetFrame) { + y = (pI830->FbMemBox.y2 - pScrn->currentMode->VDisplay); + ErrorF("AdjustFrame: OffsetFrame is set, setting y to %d\n", y); + } + x += xoffset; + y += yoffset; +#if 0 + x >>= 4; + x <<= 4; +#endif + VBESetDisplayStart(pVbe, x, y, TRUE); +} + +static void +I830BIOSFreeScreen(int scrnIndex, int flags) +{ + I830BIOSFreeRec(xf86Screens[scrnIndex]); + if (xf86LoaderCheckSymbol("vgaHWFreeHWRec")) + vgaHWFreeHWRec(xf86Screens[scrnIndex]); +} + +#ifndef SAVERESTORE_HWSTATE +#define SAVERESTORE_HWSTATE 0 +#endif + +#if SAVERESTORE_HWSTATE +static void +SaveHWOperatingState(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + I830RegPtr save = &pI830->SavedReg; + + DPRINTF(PFX, "SaveHWOperatingState\n"); + + return; +} + +static void +RestoreHWOperatingState(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + I830RegPtr save = &pI830->SavedReg; + + DPRINTF(PFX, "RestoreHWOperatingState\n"); + + return; +} +#endif + +static void +I830BIOSLeaveVT(int scrnIndex, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; +#ifdef XF86DRI + I830Ptr pI830 = I830PTR(pScrn); +#endif + + DPRINTF(PFX, "Leave VT\n"); + +#ifdef XF86DRI + if (pI830->directRenderingOpen) { + DPRINTF(PFX, "calling dri lock\n"); + DRILock(screenInfo.screens[scrnIndex], 0); + pI830->LockHeld = 1; + } +#endif + +#if SAVERESTORE_HWSTATE + if (!pI830->closing) + SaveHWOperatingState(pScrn); +#endif + + ResetState(pScrn, TRUE); + RestoreHWState(pScrn); + RestoreBIOSMemSize(pScrn); + I830UnbindGARTMemory(pScrn); +} + +/* + * This gets called when gaining control of the VT, and from ScreenInit(). + */ +static Bool +I830BIOSEnterVT(int scrnIndex, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + I830Ptr pI830 = I830PTR(pScrn); + static int SaveGeneration = -1; + + DPRINTF(PFX, "Enter VT\n"); + + if (!I830BindGARTMemory(pScrn)) + return FALSE; + + CheckInheritedState(pScrn); + SetBIOSMemSize(pScrn, pI830->newBIOSMemSize); + + /* + * Only save state once per server generation since that's what most + * drivers do. Could change this to save state at each VT enter. + */ + if (SaveGeneration != serverGeneration) { + SaveGeneration = serverGeneration; + SaveHWState(pScrn); + } + ResetState(pScrn, FALSE); + SetHWOperatingState(pScrn); + +#if 1 + /* Clear the framebuffer */ + memset(pI830->FbBase + pScrn->fbOffset, 0, + pScrn->virtualY * pScrn->displayWidth * pI830->cpp); +#endif + + if (!I830VESASetMode(pScrn, pScrn->currentMode)) + return FALSE; +#ifdef I830_XV + I830VideoSwitchModeAfter(pScrn, pScrn->currentMode); +#endif + + ResetState(pScrn, TRUE); + SetHWOperatingState(pScrn); + + pScrn->AdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); + +#if SAVERESTORE_HWSTATE + RestoreHWOperatingState(pScrn); +#endif + +#ifdef XF86DRI + if (pI830->directRenderingEnabled) { + if (!pI830->starting) { + I830EmitInvarientState(pScrn); + I830RefreshRing(pScrn); + I830Sync(pScrn); + DO_RING_IDLE(); + + DPRINTF(PFX, "calling dri unlock\n"); + DRIUnlock(screenInfo.screens[scrnIndex]); + } + pI830->LockHeld = 0; + } +#endif + + return TRUE; +} + +static Bool +I830BIOSSwitchMode(int scrnIndex, DisplayModePtr mode, int flags) +{ + + int _head; + int _tail; + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + I830Ptr pI830 = I830PTR(pScrn); + int ret = TRUE; + + DPRINTF(PFX, "I830BIOSSwitchMode: mode == %p\n", mode); + + /* Stops head pointer freezes for 845G */ + if (!pI830->noAccel && (1 || IS_845G(pI830))) { + do { + _head = INREG(LP_RING + RING_HEAD) & I830_HEAD_MASK; + _tail = INREG(LP_RING + RING_TAIL) & I830_TAIL_MASK; + DELAY(1000); + } while (_head != _tail); + } + +#if 0 + OffsetFrame = !OffsetFrame; + pScrn->AdjustFrame(scrnIndex, 0, 0, 0); +#endif + +#ifndef BINDUNBIND +#define BINDUNBIND 0 +#endif +#if BINDUNBIND + I830UnbindGARTMemory(pScrn); +#endif +#ifdef I830_XV + /* Give the video overlay code a chance to see the new mode. */ + I830VideoSwitchModeBefore(pScrn, mode); +#endif + if (!I830VESASetMode(pScrn, mode)) + ret = FALSE; +#ifdef I830_XV + /* Give the video overlay code a chance to see the new mode. */ + I830VideoSwitchModeAfter(pScrn, mode); +#endif +#if BINDUNBIND + I830BindGARTMemory(pScrn); +#endif + + return ret; +} + +static Bool +I830BIOSSaveScreen(ScreenPtr pScreen, int mode) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I830Ptr pI830 = I830PTR(pScrn); + Bool on = xf86IsUnblank(mode); + CARD32 temp, ctrl, base, i; + + DPRINTF(PFX, "I830BIOSSaveScreen: %d, on is %s\n", mode, BOOLTOSTRING(on)); + + for (i = 0; i < MAX_DISPLAY_PIPES; i++) { + if (i == 0) { + ctrl = DSPACNTR; + base = DSPABASE; + } else { + ctrl = DSPBCNTR; + base = DSPBADDR; + } + if (pI830->planeEnabled[i]) { + temp = INREG(ctrl); + if (on) + temp |= DISPLAY_PLANE_ENABLE; + else + temp &= ~DISPLAY_PLANE_ENABLE; + OUTREG(ctrl, temp); + /* Flush changes */ + temp = INREG(base); + OUTREG(base, temp); + } + } + + if (pI830->CursorInfoRec && !pI830->SWCursor && pI830->cursorOn) { + if (on) + pI830->CursorInfoRec->ShowCursor(pScrn); + else + pI830->CursorInfoRec->HideCursor(pScrn); + pI830->cursorOn = TRUE; + } + + return TRUE; +} + +/* Use the VBE version when available. */ +static void +I830DisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode, + int flags) +{ + I830Ptr pI830 = I830PTR(pScrn); + vbeInfoPtr pVbe = pI830->pVbe; + + if (xf86LoaderCheckSymbol("VBEDPMSSet")) { + VBEDPMSSet(pVbe, PowerManagementMode); + } else { + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x4f10; + pVbe->pInt10->bx = 0x01; + + switch (PowerManagementMode) { + case DPMSModeOn: + break; + case DPMSModeStandby: + pVbe->pInt10->bx |= 0x0100; + break; + case DPMSModeSuspend: + pVbe->pInt10->bx |= 0x0200; + break; + case DPMSModeOff: + pVbe->pInt10->bx |= 0x0400; + break; + } + xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); + } +} + +static Bool +I830BIOSCloseScreen(int scrnIndex, ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + I830Ptr pI830 = I830PTR(pScrn); + XAAInfoRecPtr infoPtr = pI830->AccelInfoRec; + + pI830->closing = TRUE; +#ifdef XF86DRI + if (pI830->directRenderingOpen) { + pI830->directRenderingOpen = FALSE; + I830DRICloseScreen(pScreen); + } +#endif + + if (pScrn->vtSema == TRUE) { + I830BIOSLeaveVT(scrnIndex, 0); + } + + DPRINTF(PFX, "\nUnmapping memory\n"); + I830UnmapMem(pScrn); + vgaHWUnmapMem(pScrn); + + if (pI830->ScanlineColorExpandBuffers) { + xfree(pI830->ScanlineColorExpandBuffers); + pI830->ScanlineColorExpandBuffers = 0; + } + + if (infoPtr) { + if (infoPtr->ScanlineColorExpandBuffers) + xfree(infoPtr->ScanlineColorExpandBuffers); + XAADestroyInfoRec(infoPtr); + pI830->AccelInfoRec = NULL; + } + + if (pI830->CursorInfoRec) { + xf86DestroyCursorInfoRec(pI830->CursorInfoRec); + pI830->CursorInfoRec = 0; + } + + xf86GARTCloseScreen(scrnIndex); + + pScrn->vtSema = FALSE; + pI830->closing = FALSE; + pScreen->CloseScreen = pI830->CloseScreen; + return (*pScreen->CloseScreen) (scrnIndex, pScreen); +} + +static int +I830ValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags) +{ + if (mode->Flags & V_INTERLACE) { + if (verbose) { + xf86DrvMsg(scrnIndex, X_PROBED, + "Removing interlaced mode \"%s\"\n", mode->name); + } + return MODE_BAD; + } + return MODE_OK; +} + +#ifndef SUSPEND_SLEEP +#define SUSPEND_SLEEP 0 +#endif +#ifndef RESUME_SLEEP +#define RESUME_SLEEP 0 +#endif + +/* + * This function is only required if we need to do anything differently from + * DoApmEvent() in common/xf86PM.c, including if we want to see events other + * than suspend/resume. + */ +static Bool +I830PMEvent(int scrnIndex, pmEvent event, Bool undo) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + I830Ptr pI830 = I830PTR(pScrn); + + DPRINTF(PFX, "Enter VT, event %d, undo: %s\n", event, BOOLTOSTRING(undo)); + + switch(event) { + case XF86_APM_SYS_SUSPEND: + case XF86_APM_CRITICAL_SUSPEND: /*do we want to delay a critical suspend?*/ + case XF86_APM_USER_SUSPEND: + case XF86_APM_SYS_STANDBY: + case XF86_APM_USER_STANDBY: + if (!undo && !pI830->suspended) { + pScrn->LeaveVT(scrnIndex, 0); + pI830->suspended = TRUE; + sleep(SUSPEND_SLEEP); + } else if (undo && pI830->suspended) { + sleep(RESUME_SLEEP); + pScrn->EnterVT(scrnIndex, 0); + pI830->suspended = FALSE; + } + break; + case XF86_APM_STANDBY_RESUME: + case XF86_APM_NORMAL_RESUME: + case XF86_APM_CRITICAL_RESUME: + if (pI830->suspended) { + sleep(RESUME_SLEEP); + pScrn->EnterVT(scrnIndex, 0); + pI830->suspended = FALSE; + /* + * Turn the screen saver off when resuming. This seems to be + * needed to stop xscreensaver kicking in (when used). + * + * XXX DoApmEvent() should probably call this just like + * xf86VTSwitch() does. Maybe do it here only in 4.2 + * compatibility mode. + */ + SaveScreens(SCREEN_SAVER_FORCER, ScreenSaverReset); + } + break; + default: + ErrorF("I830PMEvent: received APM event %d\n", event); + } + return TRUE; +} + +void +I830InitpScrn(ScrnInfoPtr pScrn) +{ + pScrn->PreInit = I830BIOSPreInit; + pScrn->ScreenInit = I830BIOSScreenInit; + pScrn->SwitchMode = I830BIOSSwitchMode; + pScrn->AdjustFrame = I830BIOSAdjustFrame; + pScrn->EnterVT = I830BIOSEnterVT; + pScrn->LeaveVT = I830BIOSLeaveVT; + pScrn->FreeScreen = I830BIOSFreeScreen; + pScrn->ValidMode = I830ValidMode; + pScrn->PMEvent = I830PMEvent; +} diff --git a/src/i830_memory.c b/src/i830_memory.c new file mode 100644 index 00000000..16693d4a --- /dev/null +++ b/src/i830_memory.c @@ -0,0 +1,1458 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i810/i830_memory.c,v 1.6 2003/02/08 02:26:56 dawes Exp $ */ +/************************************************************************** + +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +Copyright © 2002 by David Dawes. + +All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sub license, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice (including the +next paragraph) shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND/OR THEIR SUPPLIERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ + +/* + * Reformatted with GNU indent (2.2.8), using the following options: + * + * -bad -bap -c41 -cd0 -ncdb -ci6 -cli0 -cp0 -ncs -d0 -di3 -i3 -ip3 -l78 + * -lp -npcs -psl -sob -ss -br -ce -sc -hnl + * + * This provides a good match with the original i810 code and preferred + * XFree86 formatting conventions. + * + * When editing this driver, please follow the existing formatting, and edit + * with <TAB> characters expanded at 8-column intervals. + */ + +/* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + * David Dawes <dawes@tungstengraphics.com> + * + */ + +#include "xf86.h" +#include "xf86_ansic.h" +#include "xf86_OSproc.h" + +#include "i830.h" +#include "i810_reg.h" + +/* + * Allocate memory from the given pool. Grow the pool if needed and if + * possible. + */ +static unsigned long +AllocFromPool(ScrnInfoPtr pScrn, I830MemRange *result, I830MemPool *pool, + unsigned long size, unsigned long alignment, int flags) +{ + I830Ptr pI830 = I830PTR(pScrn); + unsigned long needed, start, end; + Bool dryrun = ((flags & ALLOCATE_DRY_RUN) != 0); + + if (!result || !pool || !size) + return 0; + + /* Calculate how much space is needed. */ + if (alignment <= GTT_PAGE_SIZE) + needed = size; + else { + if (flags & ALLOCATE_AT_BOTTOM) { + start = ROUND_TO(pool->Free.Start, alignment); + if (flags & ALIGN_BOTH_ENDS) + end = ROUND_TO(start + size, alignment); + else + end = start + size; + needed = end - pool->Free.Start; + } else { /* allocate at top */ + if (flags & ALIGN_BOTH_ENDS) + end = ROUND_DOWN_TO(pool->Free.End, alignment); + else + end = pool->Free.End; + + start = ROUND_DOWN_TO(end - size, alignment); + needed = pool->Free.End - start; + } + } + if (needed > pool->Free.Size) { + unsigned long extra; + /* See if the pool can be grown. */ + if (pI830->StolenOnly && !dryrun) + return 0; + extra = needed - pool->Free.Size; + extra = ROUND_TO_PAGE(extra); + if (extra > pI830->FreeMemory) { + if (dryrun) + pI830->FreeMemory = extra; + else + return 0; + } + + if (!dryrun && (extra > pI830->MemoryAperture.Size)) + return 0; + + pool->Free.Size += extra; + pool->Free.End += extra; + pool->Total.Size += extra; + pool->Total.End += extra; + pI830->FreeMemory -= extra; + pI830->MemoryAperture.Start += extra; + pI830->MemoryAperture.Size -= extra; + } + if (flags & ALLOCATE_AT_BOTTOM) { + result->Start = ROUND_TO(pool->Free.Start, alignment); + pool->Free.Start += needed; + result->End = pool->Free.Start; + } else { + result->Start = ROUND_DOWN_TO(pool->Free.End - size, alignment) - + pool->Total.End; + result->End = pool->Free.End - pool->Total.End; + pool->Free.End -= needed; + } + pool->Free.Size = pool->Free.End - pool->Free.Start; + result->Size = result->End - result->Start; + result->Pool = pool; + result->Alignment = alignment; + return needed; +} + +static unsigned long +AllocFromAGP(ScrnInfoPtr pScrn, I830MemRange *result, unsigned long size, + unsigned long alignment, int flags) +{ + I830Ptr pI830 = I830PTR(pScrn); + unsigned long start, end; + unsigned long newApStart, newApEnd; + Bool dryrun = ((flags & ALLOCATE_DRY_RUN) != 0); + + if (!result || !size) + return 0; + + if ((flags & ALLOCATE_AT_BOTTOM) && pI830->StolenMemory.Size != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "AllocFromAGP(): can't allocate from " + "bottom when there is stolen memory\n"); + return 0; + } + + if (size > pI830->FreeMemory) { + if (dryrun) + pI830->FreeMemory = size; + else + return 0; + } + + /* Calculate offset */ + if (flags & ALLOCATE_AT_BOTTOM) { + start = ROUND_TO(pI830->MemoryAperture.Start, alignment); + if (flags & ALIGN_BOTH_ENDS) + end = ROUND_TO(start + size, alignment); + else + end = start + size; + newApStart = end; + newApEnd = pI830->MemoryAperture.End; + } else { + if (flags & ALIGN_BOTH_ENDS) + end = ROUND_DOWN_TO(pI830->MemoryAperture.End, alignment); + else + end = pI830->MemoryAperture.End; + start = ROUND_DOWN_TO(end - size, alignment); + newApStart = pI830->MemoryAperture.Start; + newApEnd = start; + } + + if (!dryrun) { + if (newApStart > newApEnd) + return 0; + + if (flags & NEED_PHYSICAL_ADDR) { + result->Key = xf86AllocateGARTMemory(pScrn->scrnIndex, size, 2, + &(result->Physical)); + } else { + result->Key = xf86AllocateGARTMemory(pScrn->scrnIndex, size, 0, NULL); + } + if (result->Key == -1) + return 0; + } + + pI830->allocatedMemory += size; + pI830->MemoryAperture.Start = newApStart; + pI830->MemoryAperture.End = newApEnd; + pI830->MemoryAperture.Size = newApEnd - newApStart; + pI830->FreeMemory -= size; + result->Start = start; + result->End = start + size; + result->Size = size; + result->Offset = start; + result->Alignment = alignment; + result->Pool = NULL; + + return size; +} + + +unsigned long +I830AllocVidMem(ScrnInfoPtr pScrn, I830MemRange *result, I830MemPool *pool, + unsigned long size, unsigned long alignment, int flags) +{ + I830Ptr pI830 = I830PTR(pScrn); + Bool dryrun = ((flags & ALLOCATE_DRY_RUN) != 0); + + if (!result) + return 0; + + /* Make sure these are initialised. */ + result->Size = 0; + result->Key = -1; + + if (!size) { + return 0; + } + + switch (flags & FROM_MASK) { + case FROM_POOL_ONLY: + return AllocFromPool(pScrn, result, pool, size, alignment, flags); + case FROM_NEW_ONLY: + if (!dryrun && (pI830->StolenOnly || (pI830->FreeMemory <= 0))) + return 0; + return AllocFromAGP(pScrn, result, size, alignment, flags); + case FROM_ANYWHERE: + if ((!(flags & ALLOCATE_AT_BOTTOM) && (pI830->FreeMemory >= size)) || + (flags & NEED_PHYSICAL_ADDR)) + return AllocFromAGP(pScrn, result, size, alignment, flags); + else + return AllocFromPool(pScrn, result, pool, size, alignment, flags); + default: + /* Shouldn't happen. */ + return 0; + } +} + +static Bool +AllocateRingBuffer(ScrnInfoPtr pScrn, int flags) +{ + I830Ptr pI830 = I830PTR(pScrn); + unsigned long size, alloced; + Bool dryrun = ((flags & ALLOCATE_DRY_RUN) != 0); + int verbosity = dryrun ? 4 : 1; + const char *s = dryrun ? "[dryrun] " : ""; + + /* Clear ring buffer info */ + memset(&(pI830->LpRing), 0, sizeof(pI830->LpRing)); + pI830->LpRing.mem.Key = -1; + + if (pI830->noAccel) + return TRUE; + + /* Ring buffer */ + size = PRIMARY_RINGBUFFER_SIZE; + if (flags & FORCE_LOW) + flags |= FROM_POOL_ONLY | ALLOCATE_AT_BOTTOM; + else + flags |= FROM_ANYWHERE | ALLOCATE_AT_TOP; + + alloced = I830AllocVidMem(pScrn, &(pI830->LpRing.mem), + &(pI830->StolenPool), size, + GTT_PAGE_SIZE, flags); + if (alloced < size) { + if (!dryrun) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to allocate Ring Buffer space\n"); + } + return FALSE; + } + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, verbosity, + "%sAllocated %d kB for the ring buffer at 0x%x\n", s, + alloced / 1024, pI830->LpRing.mem.Start); + pI830->LpRing.tail_mask = pI830->LpRing.mem.Size - 1; + return TRUE; +} + +#ifdef I830_XV +/* + * Note, the FORCE_LOW flag is currently not used or supported. + */ +static Bool +AllocateOverlay(ScrnInfoPtr pScrn, int flags) +{ + I830Ptr pI830 = I830PTR(pScrn); + unsigned long size, alloced; + Bool dryrun = ((flags & ALLOCATE_DRY_RUN) != 0); + int verbosity = dryrun ? 4 : 1; + const char *s = dryrun ? "[dryrun] " : ""; + + /* Clear overlay info */ + memset(&(pI830->OverlayMem), 0, sizeof(pI830->OverlayMem)); + pI830->OverlayMem.Key = -1; + + if (!pI830->XvEnabled) + return TRUE; + + /* + * The overlay register space needs a physical address in + * system memory. We get this from the agpgart module using + * a special memory type. + */ + + size = OVERLAY_SIZE; + if (flags & FORCE_LOW) + flags |= FROM_POOL_ONLY | ALLOCATE_AT_BOTTOM | NEED_PHYSICAL_ADDR; + else + flags |= FROM_ANYWHERE | ALLOCATE_AT_TOP | NEED_PHYSICAL_ADDR; + + alloced = I830AllocVidMem(pScrn, &(pI830->OverlayMem), + &(pI830->StolenPool), size, GTT_PAGE_SIZE, flags); + + /* + * XXX For testing only. Don't enable this unless you know how to set + * physBase. + */ + if (flags & FORCE_LOW) { + ErrorF("AllocateOverlay() doesn't support setting FORCE_LOW\n"); + return FALSE; + } + + if (!dryrun && (alloced < size)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to allocate Overlay register space.\n"); + /* This failure isn't fatal. */ + } else { + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, verbosity, + "%sAllocated %d kB for Overlay registers at 0x%x " + "(0x%08x).\n", s, + alloced / 1024, pI830->OverlayMem.Start, + pI830->OverlayMem.Physical); + } + return TRUE; +} +#endif + +static unsigned long +GetFreeSpace(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + unsigned long extra = 0; + + /* First check for free space in StolenPool. */ + if (pI830->StolenPool.Free.Size > 0) + extra = pI830->StolenPool.Free.Size; + /* Next check for unallocated space. */ + if (pI830->FreeMemory > 0) + extra += pI830->FreeMemory; + + return extra; +} + +static Bool +IsTileable(int pitch) +{ + /* + * Allow tiling for pitches that are a power of 2 multiple of 128 bytes, + * up to 64 * 128 (= 8192) bytes. + */ + switch (pitch) { + case 128 * 1: + case 128 * 2: + case 128 * 4: + case 128 * 8: + case 128 * 16: + case 128 * 32: + case 128 * 64: + return TRUE; + default: + return FALSE; + } +} + +/* + * Allocate memory for 2D operation. This includes the (front) framebuffer, + * ring buffer, scratch memory, HW cursor. + */ + +Bool +I830Allocate2DMemory(ScrnInfoPtr pScrn, const int flags) +{ + I830Ptr pI830 = I830PTR(pScrn); + unsigned long size, alloced; + Bool dryrun = ((flags & ALLOCATE_DRY_RUN) != 0); + int verbosity = dryrun ? 4 : 1; + const char *s = dryrun ? "[dryrun] " : ""; + Bool tileable; + int align, alignflags; + + DPRINTF(PFX, "I830Allocate2DMemory: inital is %s\n", + BOOLTOSTRING(flags & ALLOC_INITIAL)); + + if (!pI830->StolenOnly && + (!xf86AgpGARTSupported() || !xf86AcquireGART(pScrn->scrnIndex))) { + if (!dryrun) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "AGP GART support is either not available or cannot " + "be used.\n" + "\tMake sure your kernel has agpgart support or has the\n" + "\tagpgart module loaded.\n"); + } + return FALSE; + } + + + /* + * The I830 is slightly different from the I830/I815, it has no + * dcache and it has stolen memory by default in its gtt. All + * additional memory must go after it. + */ + + DPRINTF(PFX, + "size == %luk (%lu bytes == pScrn->videoRam)\n" + "pI830->StolenSize == %luk (%lu bytes)\n", + pScrn->videoRam, pScrn->videoRam * 1024, + pI830->StolenPool.Free.Size / 1024, + pI830->StolenPool.Free.Size); + + if (flags & ALLOC_INITIAL) { + unsigned long minspace, avail, lineSize; + int cacheLines, maxCacheLines; + + if (pI830->NeedRingBufferLow) + AllocateRingBuffer(pScrn, flags | FORCE_LOW); + + /* Clear everything first. */ + memset(&(pI830->FbMemBox), 0, sizeof(pI830->FbMemBox)); + memset(&(pI830->FrontBuffer), 0, sizeof(pI830->FrontBuffer)); + pI830->FrontBuffer.Key = -1; + + pI830->FbMemBox.x1 = 0; + pI830->FbMemBox.x2 = pScrn->displayWidth; + pI830->FbMemBox.y1 = 0; + pI830->FbMemBox.y2 = pScrn->virtualY; + + /* + * Calculate how much framebuffer memory to allocate. For the + * initial allocation, calculate a reasonable minimum. This is + * enough for the virtual screen size, plus some pixmap cache + * space. + */ + + lineSize = pScrn->displayWidth * pI830->cpp; + minspace = lineSize * pScrn->virtualY; + avail = pScrn->videoRam * 1024; + maxCacheLines = (avail - minspace) / lineSize; + /* This shouldn't happen. */ + if (maxCacheLines < 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Internal Error: " + "maxCacheLines < 0 in I830Allocate2DMemory()\n"); + maxCacheLines = 0; + } + if (maxCacheLines > (MAX_DISPLAY_HEIGHT - pScrn->virtualY)) + maxCacheLines = MAX_DISPLAY_HEIGHT - pScrn->virtualY; + + if (pI830->CacheLines >= 0) { + cacheLines = pI830->CacheLines; + } else { +#if 1 + /* Make sure there is enough for two DVD sized YUV buffers */ + cacheLines = (pScrn->depth == 24) ? 256 : 384; + if (pScrn->displayWidth <= 1024) + cacheLines *= 2; +#else + /* + * Make sure there is enough for two DVD sized YUV buffers. + * Make that 1.5MB, which is around what was allocated with + * the old algorithm + */ + cacheLines = (MB(1) + KB(512)) / pI830->cpp / pScrn->displayWidth; +#endif + } + if (cacheLines > maxCacheLines) + cacheLines = maxCacheLines; + + pI830->FbMemBox.y2 += cacheLines; + + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, verbosity, + "%sAllocating at least %d scanlines for pixmap cache\n", + s, cacheLines); + + tileable = !(flags & ALLOC_NO_TILING) && pI830->allowPageFlip && + IsTileable(pScrn->displayWidth * pI830->cpp); + if (tileable) { + align = KB(512); + alignflags = ALIGN_BOTH_ENDS; + } else { + align = KB(64); + alignflags = 0; + } + + size = lineSize * (pScrn->virtualY + cacheLines); + size = ROUND_TO_PAGE(size); + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, verbosity, + "%sInitial framebuffer allocation size: %d kByte\n", s, + size / 1024); + alloced = I830AllocVidMem(pScrn, &(pI830->FrontBuffer), + &(pI830->StolenPool), size, align, + flags | alignflags | + FROM_ANYWHERE | ALLOCATE_AT_BOTTOM); + if (alloced < size) { + if (!dryrun) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to allocate framebuffer.\n"); + } + return FALSE; + } + } else { + unsigned long lineSize; + unsigned long extra = 0; + unsigned long maxFb = 0; + + /* + * XXX Need to "free" up any 3D allocations if the DRI ended up + * and make them available for 2D. The best way to do this would + * be position all of those regions contiguously at the end of the + * StolenPool. + */ + extra = GetFreeSpace(pScrn); + + if (extra == 0) + return TRUE; + + maxFb = pI830->FrontBuffer.Size + extra; + lineSize = pScrn->displayWidth * pI830->cpp; + maxFb = ROUND_DOWN_TO(maxFb, lineSize); + if (maxFb > lineSize * MAX_DISPLAY_HEIGHT) + maxFb = lineSize * MAX_DISPLAY_HEIGHT; + if (maxFb > pI830->FrontBuffer.Size) { + unsigned long oldsize; + /* + * Sanity check -- the fb should be the last thing allocated at + * the bottom of the stolen pool. + */ + if (pI830->StolenPool.Free.Start != pI830->FrontBuffer.End) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Internal error in I830Allocate2DMemory():\n\t" + "Framebuffer isn't the last allocation at the bottom" + " of StolenPool\n\t(%x != %x).\n", + pI830->FrontBuffer.End, + pI830->StolenPool.Free.Start); + return FALSE; + } + /* + * XXX Maybe should have a "Free" function. This should be + * the only place where a region is resized, and we know that + * the fb is always at the bottom of the aperture/stolen pool, + * and is the only region that is allocated bottom-up. + * Allowing for more general realloction would require a smarter + * allocation system. + */ + oldsize = pI830->FrontBuffer.Size; + pI830->StolenPool.Free.Size += pI830->FrontBuffer.Size; + pI830->StolenPool.Free.Start -= pI830->FrontBuffer.Size; + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, verbosity, + "%sUpdated framebuffer allocation size from %d " + "to %d kByte\n", s, oldsize / 1024, maxFb / 1024); + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, verbosity, + "%sUpdated pixmap cache from %d scanlines to %d " + "scanlines\n", s, + oldsize / lineSize - pScrn->virtualY, + maxFb / lineSize - pScrn->virtualY); + pI830->FbMemBox.y2 = maxFb / lineSize; + tileable = !(flags & ALLOC_NO_TILING) && pI830->allowPageFlip && + IsTileable(pScrn->displayWidth * pI830->cpp); + if (tileable) { + align = KB(512); + alignflags = ALIGN_BOTH_ENDS; + } else { + align = KB(64); + alignflags = 0; + } + alloced = I830AllocVidMem(pScrn, &(pI830->FrontBuffer), + &(pI830->StolenPool), maxFb, align, + flags | alignflags | + FROM_ANYWHERE | ALLOCATE_AT_BOTTOM); + if (alloced < maxFb) { + if (!dryrun) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to re-allocate framebuffer\n"); + } + return FALSE; + } + } + return TRUE; + } + +#if REMAP_RESERVED + /* + * Allocate a dummy page to pass when attempting to rebind the + * pre-allocated region. + */ + if (!dryrun) { + memset(&(pI830->Dummy), 0, sizeof(pI830->Dummy)); + pI830->Dummy.Key = + xf86AllocateGARTMemory(pScrn->scrnIndex, size, 0, NULL); + pI830->Dummy.Offset = 0; + } +#endif + + /* Clear cursor info */ + memset(&(pI830->CursorMem), 0, sizeof(pI830->CursorMem)); + pI830->CursorMem.Key = -1; + + if (!pI830->SWCursor) { + int cursFlags = 0; + /* + * Mouse cursor -- The i810-i830 need a physical address in system + * memory from which to upload the cursor. We get this from + * the agpgart module using a special memory type. + */ + + size = HWCURSOR_SIZE; + cursFlags = FROM_ANYWHERE | ALLOCATE_AT_TOP; + if (pI830->CursorNeedsPhysical) + cursFlags |= NEED_PHYSICAL_ADDR; + + alloced = I830AllocVidMem(pScrn, &(pI830->CursorMem), + &(pI830->StolenPool), size, + GTT_PAGE_SIZE, flags | cursFlags); + if (alloced < size) { + if (!dryrun) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to allocate HW cursor space.\n"); + } + } else { + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, verbosity, + "%sAllocated %d kB for HW cursor at 0x%x", s, + alloced / 1024, pI830->CursorMem.Start); + if (pI830->CursorNeedsPhysical) + xf86ErrorFVerb(verbosity, " (0x%08x)", pI830->CursorMem.Physical); + xf86ErrorFVerb(verbosity, "\n"); + } + } + +#ifdef I830_XV + AllocateOverlay(pScrn, flags); +#endif + + if (!pI830->NeedRingBufferLow) + AllocateRingBuffer(pScrn, flags); + + /* Clear scratch info */ + memset(&(pI830->Scratch), 0, sizeof(pI830->Scratch)); + pI830->Scratch.Key = -1; + + if (!pI830->noAccel) { + size = MAX_SCRATCH_BUFFER_SIZE; + alloced = I830AllocVidMem(pScrn, &(pI830->Scratch), &(pI830->StolenPool), + size, GTT_PAGE_SIZE, + flags | FROM_ANYWHERE | ALLOCATE_AT_TOP); + if (alloced < size) { + size = MIN_SCRATCH_BUFFER_SIZE; + alloced = I830AllocVidMem(pScrn, &(pI830->Scratch), + &(pI830->StolenPool), size, + GTT_PAGE_SIZE, + flags | FROM_ANYWHERE | ALLOCATE_AT_TOP); + } + if (alloced < size) { + if (!dryrun) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to allocate scratch buffer space\n"); + } + return FALSE; + } + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, verbosity, + "%sAllocated %d kB for the scratch buffer at 0x%x\n", s, + alloced / 1024, pI830->Scratch.Start); + } + return TRUE; +} + +#ifndef ALLOCATE_ALL_BIOSMEM +#define ALLOCATE_ALL_BIOSMEM 1 +#endif + +void +I830ResetAllocations(ScrnInfoPtr pScrn, const int flags) +{ + I830Ptr pI830 = I830PTR(pScrn); + + pI830->MemoryAperture.Start = pI830->StolenMemory.End; + pI830->MemoryAperture.End = pI830->FbMapSize; + pI830->MemoryAperture.Size = pI830->FbMapSize - pI830->StolenMemory.Size; + pI830->StolenPool.Fixed = pI830->StolenMemory; + pI830->StolenPool.Total = pI830->StolenMemory; +#if ALLOCATE_ALL_BIOSMEM + if (pI830->overrideBIOSMemSize && + pI830->BIOSMemorySize > pI830->StolenMemory.Size) { + pI830->StolenPool.Total.End = pI830->BIOSMemorySize; + pI830->StolenPool.Total.Size = pI830->BIOSMemorySize; + } +#endif + pI830->StolenPool.Free = pI830->StolenPool.Total; + pI830->FreeMemory = pI830->TotalVideoRam - pI830->StolenPool.Total.Size; + pI830->allocatedMemory = 0; +} + +long +I830GetExcessMemoryAllocations(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + unsigned long allocated; + + allocated = pI830->StolenPool.Total.Size + pI830->allocatedMemory; + if (allocated > pI830->TotalVideoRam) + return allocated - pI830->TotalVideoRam; + else + return 0; +} + +#ifdef XF86DRI +static unsigned long +GetBestTileAlignment(unsigned long size) +{ + unsigned long i; + + for (i = KB(512); i < size; i <<= 1) + ; + + if (i > MB(64)) + i = MB(64); + + return i; +} + +static unsigned int +myLog2(unsigned int n) +{ + unsigned int log2 = 1; + + while (n > 1) { + n >>= 1; + log2++; + } + return log2; +} + +Bool +I830Allocate3DMemory(ScrnInfoPtr pScrn, const int flags) +{ + I830Ptr pI830 = I830PTR(pScrn); + unsigned long size, alloced, align = 0; + int i; + Bool tileable; + Bool dryrun = ((flags & ALLOCATE_DRY_RUN) != 0); + int verbosity = dryrun ? 4 : 1; + const char *s = dryrun ? "[dryrun] " : ""; + int lines; + + DPRINTF(PFX, "I830Allocate3DMemory\n"); + + /* Back Buffer */ + memset(&(pI830->BackBuffer), 0, sizeof(pI830->BackBuffer)); + pI830->BackBuffer.Key = -1; + tileable = !(flags & ALLOC_NO_TILING) && + IsTileable(pScrn->displayWidth * pI830->cpp); + if (tileable) { + /* Make the height a multiple of the tile height (16) */ + lines = (pScrn->virtualY + 15) / 16 * 16; + } else { + lines = pScrn->virtualY; + } + + size = ROUND_TO_PAGE(pScrn->displayWidth * lines * pI830->cpp); + /* + * Try to allocate on the best tile-friendly boundaries. + */ + alloced = 0; + if (tileable) { + align = GetBestTileAlignment(size); + for (align = GetBestTileAlignment(size); align >= KB(512); align >>= 1) { + alloced = I830AllocVidMem(pScrn, &(pI830->BackBuffer), + &(pI830->StolenPool), size, align, + flags | FROM_ANYWHERE | ALLOCATE_AT_TOP | + ALIGN_BOTH_ENDS); + if (alloced >= size) + break; + } + } + if (alloced < size) { + /* Give up on trying to tile */ + tileable = FALSE; + size = ROUND_TO_PAGE(pScrn->displayWidth * pScrn->virtualY * pI830->cpp); + align = GTT_PAGE_SIZE; + alloced = I830AllocVidMem(pScrn, &(pI830->BackBuffer), + &(pI830->StolenPool), size, align, + flags | FROM_ANYWHERE | ALLOCATE_AT_TOP); + } + if (alloced < size) { + if (!dryrun) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to allocate back buffer space.\n"); + } + return FALSE; + } + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, verbosity, + "%sAllocated %d kB for the back buffer at 0x%x.\n", s, + alloced / 1024, pI830->BackBuffer.Start); + + /* Depth Buffer -- same size as the back buffer */ + memset(&(pI830->DepthBuffer), 0, sizeof(pI830->DepthBuffer)); + pI830->DepthBuffer.Key = -1; + /* + * Try to allocate on the best tile-friendly boundaries. + */ + alloced = 0; + if (tileable) { + /* Start with the previous align value. */ + for (; align >= KB(512); align >>= 1) { + alloced = I830AllocVidMem(pScrn, &(pI830->DepthBuffer), + &(pI830->StolenPool), size, align, + flags | FROM_ANYWHERE | ALLOCATE_AT_TOP | + ALIGN_BOTH_ENDS); + if (alloced >= size) + break; + } + } + if (alloced < size) { + /* Give up on trying to tile */ + tileable = FALSE; + size = ROUND_TO_PAGE(pScrn->displayWidth * pScrn->virtualY * pI830->cpp); + align = GTT_PAGE_SIZE; + alloced = I830AllocVidMem(pScrn, &(pI830->DepthBuffer), + &(pI830->StolenPool), size, align, + flags | FROM_ANYWHERE | ALLOCATE_AT_TOP); + } + if (alloced < size) { + if (!dryrun) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to allocate depth buffer space.\n"); + } + return FALSE; + } + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, verbosity, + "%sAllocated %d kB for the depth buffer at 0x%x.\n", s, + alloced / 1024, pI830->DepthBuffer.Start); + + /* Space for logical context. 32k is fine for right now. */ + memset(&(pI830->ContextMem), 0, sizeof(pI830->ContextMem)); + pI830->ContextMem.Key = -1; + size = KB(32); + alloced = I830AllocVidMem(pScrn, &(pI830->ContextMem), + &(pI830->StolenPool), size, GTT_PAGE_SIZE, + flags | FROM_ANYWHERE | ALLOCATE_AT_TOP); + if (alloced < size) { + if (!dryrun) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to allocate logical context space.\n"); + } + return FALSE; + } + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, verbosity, + "%sAllocated %d kB for the logical context at 0x%x.\n", s, + alloced / 1024, pI830->ContextMem.Start); + + /* + * Space for DMA buffers, only if there's enough free for at least 1MB + * of texture space. + */ + memset(&(pI830->BufferMem), 0, sizeof(pI830->BufferMem)); + pI830->BufferMem.Key = -1; + /* This should already be a page multiple */ + size = I830_DMA_BUF_NR * I830_DMA_BUF_SZ; + if (dryrun || (GetFreeSpace(pScrn) >= size + MB(1))) { + alloced = I830AllocVidMem(pScrn, &(pI830->BufferMem), + &(pI830->StolenPool), size, + GTT_PAGE_SIZE, + flags | FROM_ANYWHERE | ALLOCATE_AT_TOP); + if (alloced < size) { + if (!dryrun) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to allocate DMA buffer space.\n"); + } + return FALSE; + } + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, verbosity, + "%sAllocated %d kB for the DMA buffers at 0x%x.\n", s, + alloced / 1024, pI830->BufferMem.Start); + } else { + if (!dryrun) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Not enough free space for DMA buffers.\n"); + } + return FALSE; + } + + /* Allocate the remaining space for textures. */ + memset(&(pI830->TexMem), 0, sizeof(pI830->TexMem)); + pI830->TexMem.Key = -1; + size = GetFreeSpace(pScrn); + if (dryrun && (size < MB(1))) + size = MB(1); + i = myLog2(size / I830_NR_TEX_REGIONS); + if (i < I830_LOG_MIN_TEX_REGION_SIZE) + i = I830_LOG_MIN_TEX_REGION_SIZE; + pI830->TexGranularity = i; + /* Truncate size */ + size >>= i; + size <<= i; + if (size < KB(512)) { + if (!dryrun) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Less than %d kBytes for texture space.\n", size / 1024); + } + return FALSE; + } + alloced = I830AllocVidMem(pScrn, &(pI830->TexMem), + &(pI830->StolenPool), size, GTT_PAGE_SIZE, + flags | FROM_ANYWHERE | ALLOCATE_AT_TOP); + if (alloced < size) { + if (!dryrun) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to allocate texture space.\n"); + } + return FALSE; + } + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, verbosity, + "%sAllocated %d kB for textures at 0x%x\n", s, + alloced / 1024, pI830->TexMem.Start); + + return TRUE; +} +#endif + +/* Allocate pool space that isn't pre-allocated */ +Bool +I830DoPoolAllocation(ScrnInfoPtr pScrn, I830MemPool *pool) +{ + I830Ptr pI830 = I830PTR(pScrn); + + DPRINTF(PFX, "I830DoPoolAllocation\n"); + + if (!pool) + return FALSE; + + /* + * Sanity check: there shouldn't be an allocation required when + * there is only stolen memory. + */ + if (pI830->StolenOnly && (pool->Total.Size > pool->Fixed.Size)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "I830DoPoolAllocation(): pool size is greater than the " + "preallocated size,\n\t" + "and there is no allocatable memory.\n"); + return FALSE; + } + + if (pool->Total.Size > pool->Fixed.Size) { + pool->Allocated.Size = pool->Total.Size - pool->Fixed.Size; + pool->Allocated.Key = + xf86AllocateGARTMemory(pScrn->scrnIndex, pool->Allocated.Size, + 0, NULL); + if (pool->Allocated.Key == -1) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Pool allocation failed\n"); + return FALSE; + } + pool->Allocated.Start = pool->Fixed.End; + pool->Allocated.End = pool->Total.Size; + pool->Allocated.Offset = pool->Allocated.Start; + } else + pool->Allocated.Key = -1; + return TRUE; +} + +static unsigned long topOfMem = 0; + +/* + * These modify the way memory is positioned within the aperture. + * + * By default, memory allocated from the bottom or specifically within + * the pool at the bottom gets allocated from the "stolen pool", which is + * actually the stolen memory plus any extra allocated to make it a larger + * contiguous region. Memory allocated from the AGP is allocated top-down + * from the end of the aperture space. Memory allocated "from top" defaults + * to AGP if there is enough "free space". The total allocation (stolen + + * extra) doesn't exceed the orignal pScrn->videoRam amount (this isn't true + * when memory allocated from AGP gets moved into the pool by one of the + * following options. + * + * XXX Write a better description. + * + */ +#define PACK_RANGES 0 +#define POOL_RANGES 0 + +static Bool +FixOffset(ScrnInfoPtr pScrn, I830MemRange *mem) +{ +#if POOL_RANGES + I830Ptr pI830 = I830PTR(pScrn); +#endif + + if (!mem) + return FALSE; + + if (mem->Pool && mem->Key == -1 && mem->Start < 0) { + mem->Start = mem->Pool->Total.End + mem->Start; + mem->End = mem->Start + mem->Size; + } +#if PACK_RANGES + /* + * Map AGP-allocated areas at the top of the stolen area, resulting in + * a contiguous region in the aperture. Normally most AGP-allocated areas + * will be at the top of the aperture, making alignment requirements + * easier to achieve. This optin is primarily for debugging purposes, + * and using this option can break any special alignment requirements. + */ + if (!mem->Pool && mem->Start != 0 && mem->Key != -1 && mem->Physical == 0 && + mem->Offset != 0) { + long diff; + if (mem->Offset != mem->Start) + ErrorF("mem %p, Offset != Start\n", mem); + diff = mem->Offset - topOfMem; + mem->Start -= diff; + mem->End -= diff; + mem->Offset -= diff; + topOfMem += mem->Size; + } +#elif POOL_RANGES + /* + * Move AGP-allocated regions (that don't need a physical address) into + * the pre-allocated pool when there's enough space to do so. Note: the + * AGP-allocated areas aren't freed. This option is primarily for + * debugging purposes, and using it can break any special alignment + * requirements. + */ + if (!mem->Pool && mem->Start >= pI830->StolenPool.Free.End && + mem->Key != -1 && mem->Physical == 0 && mem->Offset != 0 && + pI830->StolenPool.Free.Size >= mem->Size) { + long diff; + if (mem->Offset != mem->Start) + ErrorF("mem %p, Offset != Start\n", mem); + diff = mem->Offset - pI830->StolenPool.Free.Start; + mem->Start -= diff; + mem->End -= diff; + mem->Offset -= diff; + mem->Key = -1; + pI830->StolenPool.Free.Start += mem->Size; + pI830->StolenPool.Free.Size -= mem->Size; + } +#endif + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "%p: Memory at offset 0x%08x, size %d kBytes\n", mem, + mem->Start, mem->Size / 1024); + return TRUE; +} + +Bool +I830FixupOffsets(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + + DPRINTF(PFX, "I830FixupOffsets\n"); + + topOfMem = pI830->StolenPool.Total.End; + FixOffset(pScrn, &(pI830->FrontBuffer)); + FixOffset(pScrn, &(pI830->CursorMem)); + FixOffset(pScrn, &(pI830->LpRing.mem)); + FixOffset(pScrn, &(pI830->Scratch)); +#ifdef I830_XV + if (pI830->XvEnabled) { + FixOffset(pScrn, &(pI830->OverlayMem)); + } +#endif +#ifdef XF86DRI + if (pI830->directRenderingEnabled) { + FixOffset(pScrn, &(pI830->BackBuffer)); + FixOffset(pScrn, &(pI830->DepthBuffer)); + FixOffset(pScrn, &(pI830->ContextMem)); + FixOffset(pScrn, &(pI830->BufferMem)); + FixOffset(pScrn, &(pI830->TexMem)); + } +#endif + return TRUE; +} + +#ifdef XF86DRI +/* Tiled memory is good... really, really good... + * + * Need to make it less likely that we miss out on this - probably + * need to move the frontbuffer away from the 'guarenteed' alignment + * of the first memory segment, or perhaps allocate a discontigous + * framebuffer to get more alignment 'sweet spots'. + */ +static void +SetFence(ScrnInfoPtr pScrn, int nr, unsigned int start, unsigned int pitch, + unsigned int size) +{ + I830Ptr pI830 = I830PTR(pScrn); + I830RegPtr i830Reg = &pI830->ModeReg; + CARD32 val; + CARD32 fence_mask = 0; + + DPRINTF(PFX, "SetFence: %d, 0x%08x, %d, %d kByte\n", + nr, start, pitch, size / 1024); + + if (nr < 0 || nr > 7) { + xf86DrvMsg(X_WARNING, pScrn->scrnIndex, + "SetFence: fence %d out of range\n"); + return; + } + + i830Reg->Fence[nr] = 0; + + fence_mask = ~I830_FENCE_START_MASK; + + if (start & fence_mask) { + xf86DrvMsg(X_WARNING, pScrn->scrnIndex, + "SetFence: %d: start (0x%08x) is not 512k aligned\n", + nr, start); + return; + } + + if (start % size) { + xf86DrvMsg(X_WARNING, pScrn->scrnIndex, + "SetFence: %d: start (0x%08x) is not size (%dk) aligned\n", + nr, start, size / 1024); + return; + } + + if (pitch & 127) { + xf86DrvMsg(X_WARNING, pScrn->scrnIndex, + "SetFence: %d: pitch (%d) not a multiple of 128 bytes\n", + nr, pitch); + return; + } + + val = (start | FENCE_X_MAJOR | FENCE_VALID); + + switch (size) { + case KB(512): + val |= FENCE_SIZE_512K; + break; + case MB(1): + val |= FENCE_SIZE_1M; + break; + case MB(2): + val |= FENCE_SIZE_2M; + break; + case MB(4): + val |= FENCE_SIZE_4M; + break; + case MB(8): + val |= FENCE_SIZE_8M; + break; + case MB(16): + val |= FENCE_SIZE_16M; + break; + case MB(32): + val |= FENCE_SIZE_32M; + break; + case MB(64): + val |= FENCE_SIZE_64M; + break; + default: + xf86DrvMsg(X_WARNING, pScrn->scrnIndex, + "SetFence: %d: illegal size (%d kByte)\n", nr, size / 1024); + return; + } + + switch (pitch / 128) { + case 1: + val |= FENCE_PITCH_1; + break; + case 2: + val |= FENCE_PITCH_2; + break; + case 4: + val |= FENCE_PITCH_4; + break; + case 8: + val |= FENCE_PITCH_8; + break; + case 16: + val |= FENCE_PITCH_16; + break; + case 32: + val |= FENCE_PITCH_32; + break; + case 64: + val |= FENCE_PITCH_64; + break; + default: + xf86DrvMsg(X_WARNING, pScrn->scrnIndex, + "SetFence: %d: illegal pitch (%d)\n", nr, pitch); + return; + } + + i830Reg->Fence[nr] = val; +} + +static Bool +MakeTiles(ScrnInfoPtr pScrn, I830MemRange *pMem) +{ + I830Ptr pI830 = I830PTR(pScrn); + int pitch, ntiles, i; + static int nextTile = 0; + static int tileGeneration = -1; + +#if 0 + /* Hack to "improve" the alignment of the front buffer. + */ + while (!(pMem->Start & ~pMem->Alignment) && pMem->Alignment < 0x00400000 ) + pMem->Alignment <<= 1; +#endif + + if (tileGeneration != serverGeneration) { + tileGeneration = serverGeneration; + nextTile = 0; + } + + pitch = pScrn->displayWidth * pI830->cpp; + /* + * Simply try to break the region up into at most four pieces of size + * equal to the alignment. + */ + ntiles = ROUND_TO(pMem->Size, pMem->Alignment) / pMem->Alignment; + if (ntiles >= 4) { + return FALSE; + } + + for (i = 0; i < ntiles; i++, nextTile++) { + SetFence(pScrn, nextTile, pMem->Start + i * pMem->Alignment, + pitch, pMem->Alignment); + } + return TRUE; +} + +void +I830SetupMemoryTiling(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + + /* We currently only attempt to tile the back and depth buffers. */ + if (!pI830->directRenderingEnabled) + return; + + if (!IsTileable(pScrn->displayWidth * pI830->cpp)) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "I830SetupMemoryTiling: Not tileable 0x%x\n", + pScrn->displayWidth * pI830->cpp); + pI830->allowPageFlip = FALSE; + return; + } + + if (pI830->allowPageFlip) { + if (pI830->allowPageFlip && pI830->FrontBuffer.Alignment >= KB(512)) { + if (MakeTiles(pScrn, &(pI830->FrontBuffer))) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Activating tiled memory for the FRONT buffer\n"); + } else { + pI830->allowPageFlip = FALSE; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "MakeTiles failed for the FRONT buffer\n"); + } + } else { + pI830->allowPageFlip = FALSE; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Alignment bad for the FRONT buffer\n"); + } + } + + /* + * We tried to get the best alignment during the allocation. Check + * the alignment values to tell. If well-aligned allocations were + * successful, the address range reserved is a multiple of the align + * value. + */ + if (pI830->BackBuffer.Alignment >= KB(512)) { + if (MakeTiles(pScrn, &(pI830->BackBuffer))) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Activating tiled memory for the back buffer.\n"); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "MakeTiles failed for the back buffer.\n"); + pI830->allowPageFlip = FALSE; + } + } + + if (pI830->DepthBuffer.Alignment >= KB(512)) { + if (MakeTiles(pScrn, &(pI830->DepthBuffer))) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Activating tiled memory for the depth buffer.\n"); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "MakeTiles failed for the back buffer.\n"); + } + } + +} +#endif /* XF86DRI */ + +static Bool +BindMemRange(ScrnInfoPtr pScrn, I830MemRange *mem) +{ + if (!mem) + return FALSE; + + if (mem->Key == -1) + return TRUE; + + return xf86BindGARTMemory(pScrn->scrnIndex, mem->Key, mem->Offset); +} + +Bool +I830BindGARTMemory(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + + DPRINTF(PFX, + "I830BindGARTMemory: StolenOnly is %s, pI830->GttBound is %s\n", + BOOLTOSTRING(pI830->StolenOnly), BOOLTOSTRING(pI830->GttBound)); + + if (pI830->StolenOnly == TRUE) + return TRUE; + + if (xf86AgpGARTSupported() && !pI830->GttBound) { + if (!xf86AcquireGART(pScrn->scrnIndex)) + return FALSE; + +#if REMAP_RESERVED + /* Rebind the pre-allocated region. */ + BindMemRange(pScrn, &(pI830->Dummy)); +#endif + + if (!BindMemRange(pScrn, &(pI830->StolenPool.Allocated))) + return FALSE; + if (!BindMemRange(pScrn, &(pI830->FrontBuffer))) + return FALSE; + if (!BindMemRange(pScrn, &(pI830->CursorMem))) + return FALSE; + if (!BindMemRange(pScrn, &(pI830->LpRing.mem))) + return FALSE; + if (!BindMemRange(pScrn, &(pI830->Scratch))) + return FALSE; +#ifdef I830_XV + if (!BindMemRange(pScrn, &(pI830->OverlayMem))) + return FALSE; +#endif +#ifdef XF86DRI + if (pI830->directRenderingEnabled) { + if (!BindMemRange(pScrn, &(pI830->BackBuffer))) + return FALSE; + if (!BindMemRange(pScrn, &(pI830->DepthBuffer))) + return FALSE; + if (!BindMemRange(pScrn, &(pI830->ContextMem))) + return FALSE; + if (!BindMemRange(pScrn, &(pI830->BufferMem))) + return FALSE; + if (!BindMemRange(pScrn, &(pI830->TexMem))) + return FALSE; + } +#endif + pI830->GttBound = 1; + } + + return TRUE; +} + +static Bool +UnbindMemRange(ScrnInfoPtr pScrn, I830MemRange *mem) +{ + if (!mem) + return FALSE; + + if (mem->Key == -1) + return TRUE; + + return xf86UnbindGARTMemory(pScrn->scrnIndex, mem->Key); +} + + +Bool +I830UnbindGARTMemory(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + + DPRINTF(PFX, + "I830UnbindGARTMemory: StolenOnly is %s, pI830->GttBound is %s\n", + BOOLTOSTRING(pI830->StolenOnly), BOOLTOSTRING(pI830->GttBound)); + + if (pI830->StolenOnly == TRUE) + return TRUE; + + if (xf86AgpGARTSupported() && pI830->GttBound) { + +#if REMAP_RESERVED + /* "unbind" the pre-allocated region. */ + UnbindMemRange(pScrn, &(pI830->Dummy)); +#endif + + if (!UnbindMemRange(pScrn, &(pI830->StolenPool.Allocated))) + return FALSE; + if (!UnbindMemRange(pScrn, &(pI830->FrontBuffer))) + return FALSE; + if (!UnbindMemRange(pScrn, &(pI830->CursorMem))) + return FALSE; + if (!UnbindMemRange(pScrn, &(pI830->LpRing.mem))) + return FALSE; + if (!UnbindMemRange(pScrn, &(pI830->Scratch))) + return FALSE; +#ifdef I830_XV + if (!UnbindMemRange(pScrn, &(pI830->OverlayMem))) + return FALSE; +#endif +#ifdef XF86DRI + if (pI830->directRenderingEnabled) { + if (!UnbindMemRange(pScrn, &(pI830->BackBuffer))) + return FALSE; + if (!UnbindMemRange(pScrn, &(pI830->DepthBuffer))) + return FALSE; + if (!UnbindMemRange(pScrn, &(pI830->ContextMem))) + return FALSE; + if (!UnbindMemRange(pScrn, &(pI830->BufferMem))) + return FALSE; + if (!UnbindMemRange(pScrn, &(pI830->TexMem))) + return FALSE; + } +#endif + if (!xf86ReleaseGART(pScrn->scrnIndex)) + return FALSE; + + pI830->GttBound = 0; + } + + return TRUE; +} + +long +I830CheckAvailableMemory(ScrnInfoPtr pScrn) +{ + AgpInfoPtr agpinf; + int maxPages; + + if (!xf86AgpGARTSupported() || + !xf86AcquireGART(pScrn->scrnIndex) || + (agpinf = xf86GetAGPInfo(pScrn->scrnIndex)) == NULL || + !xf86ReleaseGART(pScrn->scrnIndex)) + return -1; + + maxPages = agpinf->totalPages - agpinf->usedPages; + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 2, "%s: %d kB available\n", + "I830CheckAvailableMemory", maxPages * 4); + + return maxPages * 4; +} diff --git a/src/i830_video.c b/src/i830_video.c new file mode 100644 index 00000000..25f9716b --- /dev/null +++ b/src/i830_video.c @@ -0,0 +1,1840 @@ +#define VIDEO_DEBUG 0 +/*************************************************************************** + +Copyright 2000 Intel Corporation. All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sub license, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice (including the +next paragraph) shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +IN NO EVENT SHALL INTEL, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR +THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i810/i830_video.c,v 1.6 2003/02/06 04:18:05 dawes Exp $ */ + +/* + * Reformatted with GNU indent (2.2.8), using the following options: + * + * -bad -bap -c41 -cd0 -ncdb -ci6 -cli0 -cp0 -ncs -d0 -di3 -i3 -ip3 -l78 + * -lp -npcs -psl -sob -ss -br -ce -sc -hnl + * + * This provides a good match with the original i810 code and preferred + * XFree86 formatting conventions. + * + * When editing this driver, please follow the existing formatting, and edit + * with <TAB> characters expanded at 8-column intervals. + */ + +/* + * i830_video.c: i830/i845 Xv driver. + * + * Copyright © 2002 by Alan Hourihane and David Dawes + * + * Authors: + * Alan Hourihane <alanh@tungstengraphics.com> + * David Dawes <dawes@tungstengraphics.com> + * + * Derived from i810 Xv driver: + * + * Authors of i810 code: + * Jonathan Bian <jonathan.bian@intel.com> + * Offscreen Images: + * Matt Sottek <matthew.j.sottek@intel.com> + */ + +/* + * XXX Could support more formats. + */ + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86Resources.h" +#include "xf86_ansic.h" +#include "compiler.h" +#include "xf86PciInfo.h" +#include "xf86Pci.h" +#include "xf86fbman.h" +#include "regionstr.h" + +#include "i830.h" +#include "xf86xv.h" +#include "Xv.h" +#include "xaa.h" +#include "xaalocal.h" +#include "dixstruct.h" +#include "fourcc.h" + +#ifndef USE_USLEEP_FOR_VIDEO +#define USE_USLEEP_FOR_VIDEO 0 +#endif + +#define OFF_DELAY 250 /* milliseconds */ +#define FREE_DELAY 15000 + +#define OFF_TIMER 0x01 +#define FREE_TIMER 0x02 +#define CLIENT_VIDEO_ON 0x04 + +#define TIMER_MASK (OFF_TIMER | FREE_TIMER) + +static void I830InitOffscreenImages(ScreenPtr); + +static XF86VideoAdaptorPtr I830SetupImageVideo(ScreenPtr); +static void I830StopVideo(ScrnInfoPtr, pointer, Bool); +static int I830SetPortAttribute(ScrnInfoPtr, Atom, INT32, pointer); +static int I830GetPortAttribute(ScrnInfoPtr, Atom, INT32 *, pointer); +static void I830QueryBestSize(ScrnInfoPtr, Bool, + short, short, short, short, unsigned int *, + unsigned int *, pointer); +static int I830PutImage(ScrnInfoPtr, short, short, short, short, short, short, + short, short, int, unsigned char *, short, short, + Bool, RegionPtr, pointer); +static int I830QueryImageAttributes(ScrnInfoPtr, int, unsigned short *, + unsigned short *, int *, int *); + +static void I830BlockHandler(int, pointer, pointer, pointer); + +#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE) + +static Atom xvBrightness, xvContrast, xvColorKey; + +#define IMAGE_MAX_WIDTH 1440 +#define IMAGE_MAX_HEIGHT 1080 +#define Y_BUF_SIZE (IMAGE_MAX_WIDTH * IMAGE_MAX_HEIGHT) + +#if !VIDEO_DEBUG +#define ErrorF Edummy +static void +Edummy(const char *dummy, ...) +{ +} +#endif + +/* + * This is more or less the correct way to initalise, update, and shut down + * the overlay. Note OVERLAY_OFF should be used only after disabling the + * overlay in OCMD and calling OVERLAY_UPDATE. + * + * XXX Need to make sure that the overlay engine is cleanly shutdown in + * all modes of server exit. + */ + +#define OVERLAY_UPDATE \ + do { \ + BEGIN_LP_RING(6); \ + OUT_RING(MI_FLUSH | MI_WRITE_DIRTY_STATE); \ + OUT_RING(MI_NOOP); \ + if (!pI830->overlayOn) { \ + OUT_RING(MI_NOOP); \ + OUT_RING(MI_NOOP); \ + OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_FLIP_ON); \ + ErrorF("Overlay goes from off to on\n"); \ + pI830->overlayOn = TRUE; \ + } else { \ + OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); \ + OUT_RING(MI_NOOP); \ + OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_FLIP_CONTINUE); \ + } \ + OUT_RING(pI830->OverlayMem.Physical | 1); \ + ADVANCE_LP_RING(); \ + ErrorF("OVERLAY_UPDATE\n"); \ + } while(0) + +#define OVERLAY_OFF \ + do { \ + if (pI830->overlayOn) { \ + BEGIN_LP_RING(8); \ + OUT_RING(MI_FLUSH | MI_WRITE_DIRTY_STATE); \ + OUT_RING(MI_NOOP); \ + OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); \ + OUT_RING(MI_NOOP); \ + OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_FLIP_OFF); \ + OUT_RING(pI830->OverlayMem.Physical); \ + OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); \ + OUT_RING(MI_NOOP); \ + ADVANCE_LP_RING(); \ + pI830->overlayOn = FALSE; \ + ErrorF("Overlay goes from on to off\n"); \ + ErrorF("OVERLAY_OFF\n"); \ + } \ + } while(0) + +/* + * OCMD - Overlay Command Register + */ +#define MIRROR_MODE (0x3<<17) +#define MIRROR_HORIZONTAL (0x1<<17) +#define MIRROR_VERTICAL (0x2<<17) +#define MIRROR_BOTH (0x3<<17) +#define OV_BYTE_ORDER (0x3<<14) +#define UV_SWAP (0x1<<14) +#define Y_SWAP (0x2<<14) +#define Y_AND_UV_SWAP (0x3<<14) +#define SOURCE_FORMAT (0xf<<10) +#define RGB_888 (0x1<<10) +#define RGB_555 (0x2<<10) +#define RGB_565 (0x3<<10) +#define YUV_422 (0x8<<10) +#define YUV_411 (0x9<<10) +#define YUV_420 (0xc<<10) +#define YUV_422_PLANAR (0xd<<10) +#define YUV_410 (0xe<<10) +#define TVSYNC_FLIP_PARITY (0x1<<9) +#define TVSYNC_FLIP_ENABLE (0x1<<7) +#define BUF_TYPE (0x1<<5) +#define BUF_TYPE_FRAME (0x0<<5) +#define BUF_TYPE_FIELD (0x1<<5) +#define TEST_MODE (0x1<<4) +#define BUFFER_SELECT (0x3<<2) +#define BUFFER0 (0x0<<2) +#define BUFFER1 (0x1<<2) +#define FIELD_SELECT (0x1<<1) +#define FIELD0 (0x0<<1) +#define FIELD1 (0x1<<1) +#define OVERLAY_ENABLE 0x1 + +/* OCONFIG register */ +#define CC_OUT_8BIT (0x1<<3) +#define OVERLAY_PIPE_MASK (0x1<<18) +#define OVERLAY_PIPE_A (0x0<<18) +#define OVERLAY_PIPE_B (0x1<<18) + +/* DCLRKM register */ +#define DEST_KEY_ENABLE (0x1<<31) + +/* Polyphase filter coefficients */ +#define N_HORIZ_Y_TAPS 5 +#define N_VERT_Y_TAPS 3 +#define N_HORIZ_UV_TAPS 3 +#define N_VERT_UV_TAPS 3 +#define N_PHASES 17 +#define MAX_TAPS 5 + +/* Filter cutoff frequency limits. */ +#define MIN_CUTOFF_FREQ 1.0 +#define MAX_CUTOFF_FREQ 3.0 + +#define RGB16ToColorKey(c) \ + (((c & 0xF800) << 8) | ((c & 0x07E0) << 5) | ((c & 0x001F) << 3)) + +#define RGB15ToColorKey(c) \ + (((c & 0x7c00) << 9) | ((c & 0x03E0) << 6) | ((c & 0x001F) << 3)) + +/* client libraries expect an encoding */ +static XF86VideoEncodingRec DummyEncoding[1] = { + { + 0, + "XV_IMAGE", + IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT, + {1, 1} + } +}; + +#define NUM_FORMATS 3 + +static XF86VideoFormatRec Formats[NUM_FORMATS] = { + {15, TrueColor}, {16, TrueColor}, {24, TrueColor} +}; + +#define NUM_ATTRIBUTES 3 + +static XF86AttributeRec Attributes[NUM_ATTRIBUTES] = { + {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"}, + {XvSettable | XvGettable, -128, 127, "XV_BRIGHTNESS"}, + {XvSettable | XvGettable, 0, 255, "XV_CONTRAST"} +}; + +#define NUM_IMAGES 4 + +static XF86ImageRec Images[NUM_IMAGES] = { + XVIMAGE_YUY2, + XVIMAGE_YV12, + XVIMAGE_I420, + XVIMAGE_UYVY +}; + +typedef struct { + CARD32 OBUF_0Y; + CARD32 OBUF_1Y; + CARD32 OBUF_0U; + CARD32 OBUF_0V; + CARD32 OBUF_1U; + CARD32 OBUF_1V; + CARD32 OSTRIDE; + CARD32 YRGB_VPH; + CARD32 UV_VPH; + CARD32 HORZ_PH; + CARD32 INIT_PHS; + CARD32 DWINPOS; + CARD32 DWINSZ; + CARD32 SWIDTH; + CARD32 SWIDTHSW; + CARD32 SHEIGHT; + CARD32 YRGBSCALE; + CARD32 UVSCALE; + CARD32 OCLRC0; + CARD32 OCLRC1; + CARD32 DCLRKV; + CARD32 DCLRKM; + CARD32 SCLRKVH; + CARD32 SCLRKVL; + CARD32 SCLRKEN; + CARD32 OCONFIG; + CARD32 OCMD; + CARD32 RESERVED1; /* 0x6C */ + CARD32 AWINPOS; + CARD32 AWINSZ; + CARD32 RESERVED2; /* 0x78 */ + CARD32 RESERVED3; /* 0x7C */ + CARD32 RESERVED4; /* 0x80 */ + CARD32 RESERVED5; /* 0x84 */ + CARD32 RESERVED6; /* 0x88 */ + CARD32 RESERVED7; /* 0x8C */ + CARD32 RESERVED8; /* 0x90 */ + CARD32 RESERVED9; /* 0x94 */ + CARD32 RESERVEDA; /* 0x98 */ + CARD32 RESERVEDB; /* 0x9C */ + CARD32 FASTHSCALE; /* 0xA0 */ + CARD32 UVSCALEV; /* 0xA4 */ + + CARD32 RESERVEDC[(0x200 - 0xA8) / 4]; /* 0xA8 - 0x1FC */ + CARD16 Y_VCOEFS[N_VERT_Y_TAPS * N_PHASES]; /* 0x200 */ + CARD16 RESERVEDD[0x100 / 2 - N_VERT_Y_TAPS * N_PHASES]; + CARD16 Y_HCOEFS[N_HORIZ_Y_TAPS * N_PHASES]; /* 0x300 */ + CARD16 RESERVEDE[0x200 / 2 - N_HORIZ_Y_TAPS * N_PHASES]; + CARD16 UV_VCOEFS[N_VERT_UV_TAPS * N_PHASES]; /* 0x500 */ + CARD16 RESERVEDF[0x100 / 2 - N_VERT_UV_TAPS * N_PHASES]; + CARD16 UV_HCOEFS[N_HORIZ_UV_TAPS * N_PHASES]; /* 0x600 */ + CARD16 RESERVEDG[0x100 / 2 - N_HORIZ_UV_TAPS * N_PHASES]; +} I830OverlayRegRec, *I830OverlayRegPtr; + +typedef struct { + CARD32 GAMC5; + CARD32 GAMC4; + CARD32 GAMC3; + CARD32 GAMC2; + CARD32 GAMC1; + CARD32 GAMC0; +} I830OverlayStateRec, *I830OverlayStatePtr; + +typedef struct { + CARD32 YBuf0offset; + CARD32 UBuf0offset; + CARD32 VBuf0offset; + + CARD32 YBuf1offset; + CARD32 UBuf1offset; + CARD32 VBuf1offset; + + unsigned char currentBuf; + + int brightness; + int contrast; + + RegionRec clip; + CARD32 colorKey; + + CARD32 videoStatus; + Time offTime; + Time freeTime; + FBLinearPtr linear; + + I830OverlayStateRec hwstate; + + Bool refreshOK; + int maxRate; +} I830PortPrivRec, *I830PortPrivPtr; + +#define GET_PORT_PRIVATE(pScrn) \ + (I830PortPrivPtr)((I830PTR(pScrn))->adaptor->pPortPrivates[0].ptr) + +static void +CompareOverlay(I830Ptr pI830, CARD32 * overlay, int size) +{ + int i; + CARD32 val; + int bad = 0; + + for (i = 0; i < size; i += 4) { + val = INREG(0x30100 + i); + if (val != overlay[i / 4]) { + ErrorF("0x%05x value doesn't match (0x%08x != 0x%08x)\n", + 0x30100 + i, val, overlay[i / 4]); + bad++; + } + } + if (!bad) + ErrorF("CompareOverlay: no differences\n"); +} + +void +I830InitVideo(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL; + XF86VideoAdaptorPtr newAdaptor = NULL; + int num_adaptors; + + DPRINTF(PFX, "I830InitVideo\n"); + +#if 0 + { + I830OverlayRegRec tmp; + + ErrorF("sizeof I830OverlayRegRec is 0x%x\n", sizeof(I830OverlayRegRec)); + ErrorF("Reserved C, D, E, F, G are %x, %x, %x, %x, %x\n", + (unsigned long)&(tmp.RESERVEDC[0]) - (unsigned long)&tmp, + (unsigned long)&(tmp.RESERVEDD[0]) - (unsigned long)&tmp, + (unsigned long)&(tmp.RESERVEDE[0]) - (unsigned long)&tmp, + (unsigned long)&(tmp.RESERVEDF[0]) - (unsigned long)&tmp, + (unsigned long)&(tmp.RESERVEDG[0]) - (unsigned long)&tmp); + } +#endif + + if (pScrn->bitsPerPixel != 8) { + newAdaptor = I830SetupImageVideo(pScreen); + I830InitOffscreenImages(pScreen); + } + + num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors); + + if (newAdaptor) { + if (!num_adaptors) { + num_adaptors = 1; + adaptors = &newAdaptor; + } else { + newAdaptors = /* need to free this someplace */ + xalloc((num_adaptors + 1) * sizeof(XF86VideoAdaptorPtr *)); + if (newAdaptors) { + memcpy(newAdaptors, adaptors, num_adaptors * + sizeof(XF86VideoAdaptorPtr)); + newAdaptors[num_adaptors] = newAdaptor; + adaptors = newAdaptors; + num_adaptors++; + } + } + } + + if (num_adaptors) + xf86XVScreenInit(pScreen, adaptors, num_adaptors); + + if (newAdaptors) + xfree(newAdaptors); +} + +static void +I830ResetVideo(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + I830PortPrivPtr pPriv = pI830->adaptor->pPortPrivates[0].ptr; + I830OverlayRegPtr overlay = + (I830OverlayRegPtr) (pI830->FbBase + pI830->OverlayMem.Start); + I830OverlayStatePtr hwstate = &(pPriv->hwstate); + + DPRINTF(PFX, "I830ResetVideo: base: %p, offset: 0x%08x, obase: %p\n", + pI830->FbBase, pI830->OverlayMem.Start, overlay); + /* + * Default to maximum image size in YV12 + */ + + memset(overlay, 0, sizeof(*overlay)); + overlay->YRGB_VPH = 0; + overlay->UV_VPH = 0; + overlay->HORZ_PH = 0; + overlay->INIT_PHS = 0; + overlay->DWINPOS = 0; + overlay->DWINSZ = (IMAGE_MAX_HEIGHT << 16) | IMAGE_MAX_WIDTH; + overlay->SWIDTH = IMAGE_MAX_WIDTH | (IMAGE_MAX_WIDTH << 16); + overlay->SWIDTHSW = (IMAGE_MAX_WIDTH >> 3) | (IMAGE_MAX_WIDTH << 12); + overlay->SHEIGHT = IMAGE_MAX_HEIGHT | (IMAGE_MAX_HEIGHT << 15); + overlay->OCLRC0 = 0x01000000; /* brightness: 0 contrast: 1.0 */ + overlay->OCLRC1 = 0x00000080; /* saturation: bypass */ + overlay->AWINPOS = 0; + overlay->AWINSZ = 0; + overlay->FASTHSCALE = 0; + + /* + * Enable destination color keying + */ + switch (pScrn->depth) { + case 8: + overlay->DCLRKV = 0; + overlay->DCLRKM = 0xffffff | DEST_KEY_ENABLE; + break; + case 15: + overlay->DCLRKV = RGB15ToColorKey(pPriv->colorKey); + overlay->DCLRKM = 0x070707 | DEST_KEY_ENABLE; + break; + case 16: + overlay->DCLRKV = RGB16ToColorKey(pPriv->colorKey); + overlay->DCLRKM = 0x070307 | DEST_KEY_ENABLE; + break; + default: + overlay->DCLRKV = pPriv->colorKey; + overlay->DCLRKM = DEST_KEY_ENABLE; + break; + } + + overlay->SCLRKVH = 0; + overlay->SCLRKVL = 0; + overlay->SCLRKEN = 0; /* source color key disable */ + overlay->OCONFIG = CC_OUT_8BIT; + + /* + * Select which pipe the overlay is enabled on. Give preference to + * pipe A. + */ + if (pI830->pipeEnabled[0]) + overlay->OCONFIG |= OVERLAY_PIPE_A; + else if (pI830->pipeEnabled[1]) + overlay->OCONFIG |= OVERLAY_PIPE_B; + + overlay->OCMD = YUV_420; + + /* setup hwstate */ + /* Default gamma correction values. */ + hwstate->GAMC5 = 0xc0c0c0; + hwstate->GAMC4 = 0x808080; + hwstate->GAMC3 = 0x404040; + hwstate->GAMC2 = 0x202020; + hwstate->GAMC1 = 0x101010; + hwstate->GAMC0 = 0x080808; + +#if 0 + /* + * XXX DUMP REGISTER CODE !!! + * This allows us to dump the complete i845 registers and compare + * with warm boot situations before we upload our first copy. + */ + { + int i; + for (i = 0x30000; i < 0x31000; i += 4) + ErrorF("0x%x 0x%08x\n", i, INREG(i)); + } +#endif + + OUTREG(OGAMC5, hwstate->GAMC5); + OUTREG(OGAMC4, hwstate->GAMC4); + OUTREG(OGAMC3, hwstate->GAMC3); + OUTREG(OGAMC2, hwstate->GAMC2); + OUTREG(OGAMC1, hwstate->GAMC1); + OUTREG(OGAMC0, hwstate->GAMC0); + +} + +/* + * Each chipset has a limit on the pixel rate that the video overlay can + * be used for. Enabling the overlay above that limit can result in a + * lockup. These two functions check the pixel rate for the new mode + * and turn the overlay off before switching to the new mode if it exceeds + * the limit, or turn it back on if the new mode is below the limit. + */ + +/* + * Approximate pixel rate limits for the video overlay. + * The rate is calculated based on the mode resolution and refresh rate. + */ +#define I830_OVERLAY_RATE 79 /* 1024x768@85, 1280x1024@60 */ +#define I845_OVERLAY_RATE 120 /* 1280x1024@85, 1600x1200@60 */ +#define I852_OVERLAY_RATE 79 /* 1024x768@85, 1280x1024@60 */ +#define I855_OVERLAY_RATE 120 /* 1280x1024@85, 1600x1200@60 */ +#define I865_OVERLAY_RATE 170 /* 1600x1200@85, 1920x1440@60 */ +#define DEFAULT_OVERLAY_RATE 120 + +static XF86VideoAdaptorPtr +I830SetupImageVideo(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I830Ptr pI830 = I830PTR(pScrn); + XF86VideoAdaptorPtr adapt; + I830PortPrivPtr pPriv; + + DPRINTF(PFX, "I830SetupImageVideo\n"); + + if (!(adapt = xcalloc(1, sizeof(XF86VideoAdaptorRec) + + sizeof(I830PortPrivRec) + sizeof(DevUnion)))) + return NULL; + + adapt->type = XvWindowMask | XvInputMask | XvImageMask; + adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT; + adapt->name = "Intel(R) 830M/845G/852GM/855GM/865G Video Overlay"; + adapt->nEncodings = 1; + adapt->pEncodings = DummyEncoding; + adapt->nFormats = NUM_FORMATS; + adapt->pFormats = Formats; + adapt->nPorts = 1; + adapt->pPortPrivates = (DevUnion *) (&adapt[1]); + + pPriv = (I830PortPrivPtr) (&adapt->pPortPrivates[1]); + + adapt->pPortPrivates[0].ptr = (pointer) (pPriv); + adapt->pAttributes = Attributes; + adapt->nImages = NUM_IMAGES; + adapt->nAttributes = NUM_ATTRIBUTES; + adapt->pImages = Images; + adapt->PutVideo = NULL; + adapt->PutStill = NULL; + adapt->GetVideo = NULL; + adapt->GetStill = NULL; + adapt->StopVideo = I830StopVideo; + adapt->SetPortAttribute = I830SetPortAttribute; + adapt->GetPortAttribute = I830GetPortAttribute; + adapt->QueryBestSize = I830QueryBestSize; + adapt->PutImage = I830PutImage; + adapt->QueryImageAttributes = I830QueryImageAttributes; + + pPriv->colorKey = pI830->colorKey & ((1 << pScrn->depth) - 1); + pPriv->videoStatus = 0; + pPriv->brightness = 0; + pPriv->contrast = 64; + pPriv->linear = NULL; + pPriv->currentBuf = 0; + + switch (pI830->PciInfo->chipType) { + case PCI_CHIP_I830_M: + pPriv->maxRate = I830_OVERLAY_RATE; + break; + case PCI_CHIP_845_G: + pPriv->maxRate = I845_OVERLAY_RATE; + break; + case PCI_CHIP_I855_GM: + switch (pI830->variant) { + case I852_GM: + case I852_GME: + pPriv->maxRate = I852_OVERLAY_RATE; + break; + default: + pPriv->maxRate = I855_OVERLAY_RATE; + break; + } + break; + case PCI_CHIP_I865_G: + pPriv->maxRate = I865_OVERLAY_RATE; + break; + default: + pPriv->maxRate = DEFAULT_OVERLAY_RATE; + break; + } + + /* gotta uninit this someplace */ + REGION_INIT(pScreen, &pPriv->clip, NullBox, 0); + + pI830->adaptor = adapt; + + /* Initialise pPriv->refreshOK */ + I830VideoSwitchModeAfter(pScrn, pScrn->currentMode); + + pI830->BlockHandler = pScreen->BlockHandler; + pScreen->BlockHandler = I830BlockHandler; + + xvBrightness = MAKE_ATOM("XV_BRIGHTNESS"); + xvContrast = MAKE_ATOM("XV_CONTRAST"); + xvColorKey = MAKE_ATOM("XV_COLORKEY"); + + I830ResetVideo(pScrn); + + return adapt; +} + +static Bool +RegionsEqual(RegionPtr A, RegionPtr B) +{ + int *dataA, *dataB; + int num; + + num = REGION_NUM_RECTS(A); + if (num != REGION_NUM_RECTS(B)) + return FALSE; + + if ((A->extents.x1 != B->extents.x1) || + (A->extents.x2 != B->extents.x2) || + (A->extents.y1 != B->extents.y1) || (A->extents.y2 != B->extents.y2)) + return FALSE; + + dataA = (int *)REGION_RECTS(A); + dataB = (int *)REGION_RECTS(B); + + while (num--) { + if ((dataA[0] != dataB[0]) || (dataA[1] != dataB[1])) + return FALSE; + dataA += 2; + dataB += 2; + } + + return TRUE; +} + +static void +I830StopVideo(ScrnInfoPtr pScrn, pointer data, Bool shutdown) +{ + I830PortPrivPtr pPriv = (I830PortPrivPtr) data; + I830Ptr pI830 = I830PTR(pScrn); + + I830OverlayRegPtr overlay = + (I830OverlayRegPtr) (pI830->FbBase + pI830->OverlayMem.Start); + + DPRINTF(PFX, "I830StopVideo\n"); + + REGION_EMPTY(pScrn->pScreen, &pPriv->clip); + + if (shutdown) { + if (pPriv->videoStatus & CLIENT_VIDEO_ON) { + overlay->OCMD &= ~OVERLAY_ENABLE; + OVERLAY_UPDATE; + + OVERLAY_OFF; + } + if (pPriv->linear) { + xf86FreeOffscreenLinear(pPriv->linear); + pPriv->linear = NULL; + } + pPriv->videoStatus = 0; + } else { + if (pPriv->videoStatus & CLIENT_VIDEO_ON) { + pPriv->videoStatus |= OFF_TIMER; + pPriv->offTime = currentTime.milliseconds + OFF_DELAY; + } + } + +} + +static int +I830SetPortAttribute(ScrnInfoPtr pScrn, + Atom attribute, INT32 value, pointer data) +{ + I830PortPrivPtr pPriv = (I830PortPrivPtr) data; + I830Ptr pI830 = I830PTR(pScrn); + I830OverlayRegPtr overlay = + (I830OverlayRegPtr) (pI830->FbBase + pI830->OverlayMem.Start); + + if (attribute == xvBrightness) { + if ((value < -128) || (value > 127)) + return BadValue; + pPriv->brightness = value; + overlay->OCLRC0 = (pPriv->contrast << 18) | (pPriv->brightness & 0xff); + if (pPriv->refreshOK) + OVERLAY_UPDATE; + } else if (attribute == xvContrast) { + if ((value < 0) || (value > 255)) + return BadValue; + pPriv->contrast = value; + overlay->OCLRC0 = (pPriv->contrast << 18) | (pPriv->brightness & 0xff); + if (pPriv->refreshOK) + OVERLAY_UPDATE; + } else if (attribute == xvColorKey) { + pPriv->colorKey = value; + switch (pScrn->depth) { + case 16: + overlay->DCLRKV = RGB16ToColorKey(pPriv->colorKey); + break; + case 15: + overlay->DCLRKV = RGB15ToColorKey(pPriv->colorKey); + break; + default: + overlay->DCLRKV = pPriv->colorKey; + break; + } + if (pPriv->refreshOK) + OVERLAY_UPDATE; + REGION_EMPTY(pScrn->pScreen, &pPriv->clip); + } else + return BadMatch; + + return Success; +} + +static int +I830GetPortAttribute(ScrnInfoPtr pScrn, + Atom attribute, INT32 * value, pointer data) +{ + I830PortPrivPtr pPriv = (I830PortPrivPtr) data; + + if (attribute == xvBrightness) { + *value = pPriv->brightness; + } else if (attribute == xvContrast) { + *value = pPriv->contrast; + } else if (attribute == xvColorKey) { + *value = pPriv->colorKey; + } else + return BadMatch; + + return Success; +} + +static void +I830QueryBestSize(ScrnInfoPtr pScrn, + Bool motion, + short vid_w, short vid_h, + short drw_w, short drw_h, + unsigned int *p_w, unsigned int *p_h, pointer data) +{ + if (vid_w > (drw_w << 1)) + drw_w = vid_w >> 1; + if (vid_h > (drw_h << 1)) + drw_h = vid_h >> 1; + + *p_w = drw_w; + *p_h = drw_h; +} + +static void +I830CopyPackedData(ScrnInfoPtr pScrn, + unsigned char *buf, + int srcPitch, + int dstPitch, int top, int left, int h, int w) +{ + I830Ptr pI830 = I830PTR(pScrn); + I830PortPrivPtr pPriv = pI830->adaptor->pPortPrivates[0].ptr; + unsigned char *src, *dst; + + DPRINTF(PFX, "I830CopyPackedData: (%d,%d) (%d,%d)\n" + "srcPitch: %d, dstPitch: %d\n", top, left, h, w, srcPitch, dstPitch); + + src = buf + (top * srcPitch) + (left << 1); + + if (pPriv->currentBuf == 0) + dst = pI830->FbBase + pPriv->YBuf0offset; + else + dst = pI830->FbBase + pPriv->YBuf1offset; + + w <<= 1; + while (h--) { + memcpy(dst, src, w); + src += srcPitch; + dst += dstPitch; + } +} + +static void +I830CopyPlanarData(ScrnInfoPtr pScrn, unsigned char *buf, int srcPitch, + int dstPitch, int srcH, int top, int left, + int h, int w, int id) +{ + I830Ptr pI830 = I830PTR(pScrn); + I830PortPrivPtr pPriv = pI830->adaptor->pPortPrivates[0].ptr; + int i; + unsigned char *src1, *src2, *src3, *dst1, *dst2, *dst3; + + DPRINTF(PFX, "I830CopyPlanarData: srcPitch %d, dstPitch %d\n" + "nlines %d, npixels %d, top %d, left %d\n", srcPitch, dstPitch, + h, w, top, left); + + /* Copy Y data */ + src1 = buf + (top * srcPitch) + left; + ErrorF("src1 is %p, offset is %d\n", src1, + (unsigned long)src1 - (unsigned long)buf); + if (pPriv->currentBuf == 0) + dst1 = pI830->FbBase + pPriv->YBuf0offset; + else + dst1 = pI830->FbBase + pPriv->YBuf1offset; + + for (i = 0; i < h; i++) { + memcpy(dst1, src1, w); + src1 += srcPitch; + dst1 += dstPitch << 1; + } + + /* Copy V data for YV12, or U data for I420 */ + src2 = buf + (srcH * srcPitch) + ((top * srcPitch) >> 2) + (left >> 1); + ErrorF("src2 is %p, offset is %d\n", src2, + (unsigned long)src2 - (unsigned long)buf); + if (pPriv->currentBuf == 0) { + if (id == FOURCC_I420) + dst2 = pI830->FbBase + pPriv->UBuf0offset; + else + dst2 = pI830->FbBase + pPriv->VBuf0offset; + } else { + if (id == FOURCC_I420) + dst2 = pI830->FbBase + pPriv->UBuf1offset; + else + dst2 = pI830->FbBase + pPriv->VBuf1offset; + } + + for (i = 0; i < h / 2; i++) { + memcpy(dst2, src2, w / 2); + src2 += srcPitch >> 1; + dst2 += dstPitch; + } + + /* Copy U data for YV12, or V data for I420 */ + src3 = buf + (srcH * srcPitch) + ((srcH * srcPitch) >> 2) + + ((top * srcPitch) >> 2) + (left >> 1); + ErrorF("src3 is %p, offset is %d\n", src3, + (unsigned long)src3 - (unsigned long)buf); + if (pPriv->currentBuf == 0) { + if (id == FOURCC_I420) + dst3 = pI830->FbBase + pPriv->VBuf0offset; + else + dst3 = pI830->FbBase + pPriv->UBuf0offset; + } else { + if (id == FOURCC_I420) + dst3 = pI830->FbBase + pPriv->VBuf1offset; + else + dst3 = pI830->FbBase + pPriv->UBuf1offset; + } + + for (i = 0; i < h / 2; i++) { + memcpy(dst3, src3, w / 2); + src3 += srcPitch >> 1; + dst3 += dstPitch; + } +} + +typedef struct { + CARD8 sign; + CARD16 mantissa; + CARD8 exponent; +} coeffRec, *coeffPtr; + +static Bool +SetCoeffRegs(double *coeff, int mantSize, coeffPtr pCoeff, int pos) +{ + int maxVal, icoeff, res; + int sign; + double c; + + sign = 0; + maxVal = 1 << mantSize; + c = *coeff; + if (c < 0.0) { + sign = 1; + c = -c; + } + + res = 12 - mantSize; + if ((icoeff = (int)(c * 4 * maxVal + 0.5)) < maxVal) { + pCoeff[pos].exponent = 3; + pCoeff[pos].mantissa = icoeff << res; + *coeff = (double)icoeff / (double)(4 * maxVal); + } else if ((icoeff = (int)(c * 2 * maxVal + 0.5)) < maxVal) { + pCoeff[pos].exponent = 2; + pCoeff[pos].mantissa = icoeff << res; + *coeff = (double)icoeff / (double)(2 * maxVal); + } else if ((icoeff = (int)(c * maxVal + 0.5)) < maxVal) { + pCoeff[pos].exponent = 1; + pCoeff[pos].mantissa = icoeff << res; + *coeff = (double)icoeff / (double)(maxVal); + } else if ((icoeff = (int)(c * maxVal * 0.5 + 0.5)) < maxVal) { + pCoeff[pos].exponent = 0; + pCoeff[pos].mantissa = icoeff << res; + *coeff = (double)icoeff / (double)(maxVal / 2); + } else { + /* Coeff out of range */ + return FALSE; + } + + pCoeff[pos].sign = sign; + if (sign) + *coeff = -(*coeff); + return TRUE; +} + +static void +UpdateCoeff(int taps, double fCutoff, Bool isHoriz, Bool isY, coeffPtr pCoeff) +{ + int i, j, j1, num, pos, mantSize; + double pi = 3.1415926535, val, sinc, window, sum; + double rawCoeff[MAX_TAPS * 32], coeffs[N_PHASES][MAX_TAPS]; + double diff; + int tapAdjust[MAX_TAPS], tap2Fix; + Bool isVertAndUV; + + if (isHoriz) + mantSize = 7; + else + mantSize = 6; + + isVertAndUV = !isHoriz && !isY; + num = taps * 16; + for (i = 0; i < num * 2; i++) { + val = (1.0 / fCutoff) * taps * pi * (i - num) / (2 * num); + if (val == 0.0) + sinc = 1.0; + else + sinc = sin(val) / val; + + /* Hamming window */ + window = (0.5 - 0.5 * cos(i * pi / num)); + rawCoeff[i] = sinc * window; + } + + for (i = 0; i < N_PHASES; i++) { + /* Normalise the coefficients. */ + sum = 0.0; + for (j = 0; j < taps; j++) { + pos = i + j * 32; + sum += rawCoeff[pos]; + } + for (j = 0; j < taps; j++) { + pos = i + j * 32; + coeffs[i][j] = rawCoeff[pos] / sum; + } + + /* Set the register values. */ + for (j = 0; j < taps; j++) { + pos = j + i * taps; + if ((j == (taps - 1) / 2) && !isVertAndUV) + SetCoeffRegs(&coeffs[i][j], mantSize + 2, pCoeff, pos); + else + SetCoeffRegs(&coeffs[i][j], mantSize, pCoeff, pos); + } + + tapAdjust[0] = (taps - 1) / 2; + for (j = 1, j1 = 1; j <= tapAdjust[0]; j++, j1++) { + tapAdjust[j1] = tapAdjust[0] - j; + tapAdjust[++j1] = tapAdjust[0] + j; + } + + /* Adjust the coefficients. */ + sum = 0.0; + for (j = 0; j < taps; j++) + sum += coeffs[i][j]; + if (sum != 1.0) { + for (j1 = 0; j1 < taps; j1++) { + tap2Fix = tapAdjust[j1]; + diff = 1.0 - sum; + coeffs[i][tap2Fix] += diff; + pos = tap2Fix + i * taps; + if ((tap2Fix == (taps - 1) / 2) && !isVertAndUV) + SetCoeffRegs(&coeffs[i][tap2Fix], mantSize + 2, pCoeff, pos); + else + SetCoeffRegs(&coeffs[i][tap2Fix], mantSize, pCoeff, pos); + + sum = 0.0; + for (j = 0; j < taps; j++) + sum += coeffs[i][j]; + if (sum == 1.0) + break; + } + } + } +} + +static void +I830DisplayVideo(ScrnInfoPtr pScrn, int id, short width, short height, + int dstPitch, int x1, int y1, int x2, int y2, BoxPtr dstBox, + short src_w, short src_h, short drw_w, short drw_h) +{ + I830Ptr pI830 = I830PTR(pScrn); + I830PortPrivPtr pPriv = pI830->adaptor->pPortPrivates[0].ptr; + I830OverlayRegPtr overlay = + (I830OverlayRegPtr) (pI830->FbBase + pI830->OverlayMem.Start); + unsigned int swidth; + + DPRINTF(PFX, "I830DisplayVideo: %dx%d (pitch %d)\n", width, height, + dstPitch); + + if (!pPriv->refreshOK) + return; + + CompareOverlay(pI830, (CARD32 *) overlay, 0x100); + + switch (id) { + case FOURCC_YV12: + case FOURCC_I420: + swidth = (width + 1) & ~1 & 0xfff; + overlay->SWIDTH = swidth; + swidth /= 2; + overlay->SWIDTH |= (swidth & 0x7ff) << 16; + + swidth = ((pPriv->YBuf0offset + width + 0x1f) >> 5) - + (pPriv->YBuf0offset >> 5) - 1; + + ErrorF("Y width is %d, swidthsw is %d\n", width, swidth); + + overlay->SWIDTHSW = swidth << 2; + + swidth = ((pPriv->UBuf0offset + (width / 2) + 0x1f) >> 5) - + (pPriv->UBuf0offset >> 5) - 1; + ErrorF("UV width is %d, swidthsw is %d\n", width / 2, swidth); + + overlay->SWIDTHSW |= swidth << 18; + break; + case FOURCC_UYVY: + case FOURCC_YUY2: + default: + /* XXX Check for i845 */ + + swidth = ((width + 31) & ~31) << 1; + overlay->SWIDTH = swidth; + overlay->SWIDTHSW = swidth >> 3; + break; + } + + overlay->SHEIGHT = height | ((height / 2) << 16); + + overlay->DWINPOS = (dstBox->y1 << 16) | dstBox->x1; + overlay->DWINSZ = ((dstBox->y2 - dstBox->y1) << 16) | + (dstBox->x2 - dstBox->x1); + + /* buffer locations */ + overlay->OBUF_0Y = pPriv->YBuf0offset; + overlay->OBUF_1Y = pPriv->YBuf1offset; + overlay->OBUF_0U = pPriv->UBuf0offset; + overlay->OBUF_0V = pPriv->VBuf0offset; + overlay->OBUF_1U = pPriv->UBuf1offset; + overlay->OBUF_1V = pPriv->VBuf1offset; + + ErrorF("Buffers: Y0: 0x%08x, U0: 0x%08x, V0: 0x%08x\n", overlay->OBUF_0Y, + overlay->OBUF_0U, overlay->OBUF_0V); + ErrorF("Buffers: Y1: 0x%08x, U1: 0x%08x, V1: 0x%08x\n", overlay->OBUF_1Y, + overlay->OBUF_1U, overlay->OBUF_1V); + +#if 0 + { + int i; + + ErrorF("First 32 bytes of Y data:\n"); + for (i = 0; i < 32; i++) + ErrorF(" %02x", + ((unsigned char *)pI830->FbBase + pPriv->YBuf0offset)[i]); + ErrorF("\n"); + ErrorF("First 16 bytes of U data:\n"); + for (i = 0; i < 16; i++) + ErrorF(" %02x", + ((unsigned char *)pI830->FbBase + pPriv->UBuf0offset)[i]); + ErrorF("\n"); + ErrorF("First 16 bytes of V data:\n"); + for (i = 0; i < 16; i++) + ErrorF(" %02x", + ((unsigned char *)pI830->FbBase + pPriv->VBuf0offset)[i]); + ErrorF("\n"); + } +#endif + +#if 1 + overlay->OCMD = OVERLAY_ENABLE; +#endif + + ErrorF("pos: 0x%08x, size: 0x%08x\n", overlay->DWINPOS, overlay->DWINSZ); + ErrorF("dst: %d x %d, src: %d x %d\n", drw_w, drw_h, src_w, src_h); + + /* + * Calculate horizontal and vertical scaling factors and polyphase + * coefficients. + */ + + { + Bool scaleChanged = FALSE; + int xscaleInt, xscaleFract, yscaleInt, yscaleFract; + int xscaleIntUV, xscaleFractUV; + int yscaleIntUV, yscaleFractUV; + /* UV is half the size of Y -- YUV420 */ + int uvratio = 2; + CARD32 newval; + coeffRec xcoeffY[N_HORIZ_Y_TAPS * N_PHASES]; + coeffRec xcoeffUV[N_HORIZ_UV_TAPS * N_PHASES]; + int i, j, pos; + + /* + * Y down-scale factor as a multiple of 4096. + */ + xscaleFract = (src_w << 12) / drw_w; + yscaleFract = (src_h << 12) / drw_h; + + /* Calculate the UV scaling factor. */ + xscaleFractUV = xscaleFract / uvratio; + yscaleFractUV = yscaleFract / uvratio; + + /* + * To keep the relative Y and UV ratios exact, round the Y scales + * to a multiple of the Y/UV ratio. + */ + xscaleFract = xscaleFractUV * uvratio; + yscaleFract = yscaleFractUV * uvratio; + + /* Integer (un-multiplied) values. */ + xscaleInt = xscaleFract >> 12; + yscaleInt = yscaleFract >> 12; + + xscaleIntUV = xscaleFractUV >> 12; + yscaleIntUV = yscaleFractUV >> 12; + + ErrorF("xscale: 0x%x.%03x, yscale: 0x%x.%03x\n", xscaleInt, + xscaleFract & 0xFFF, yscaleInt, yscaleFract & 0xFFF); + ErrorF("UV xscale: 0x%x.%03x, UV yscale: 0x%x.%03x\n", xscaleIntUV, + xscaleFractUV & 0xFFF, yscaleIntUV, yscaleFractUV & 0xFFF); + + newval = (xscaleInt << 16) | + ((xscaleFract & 0xFFF) << 3) | ((yscaleFract & 0xFFF) << 20); + if (newval != overlay->YRGBSCALE) { + scaleChanged = TRUE; + overlay->YRGBSCALE = newval; + } + + newval = (xscaleIntUV << 16) | ((xscaleFractUV & 0xFFF) << 3) | + ((yscaleFractUV & 0xFFF) << 20); + if (newval != overlay->UVSCALE) { + scaleChanged = TRUE; + overlay->UVSCALE = newval; + } + + newval = yscaleInt << 16 | yscaleIntUV; + if (newval != overlay->UVSCALEV) { + scaleChanged = TRUE; + overlay->UVSCALEV = newval; + } + + /* Recalculate coefficients if the scaling changed. */ + + /* + * Only Horizontal coefficients so far. + */ + if (scaleChanged) { + double fCutoffY; + double fCutoffUV; + + fCutoffY = xscaleFract / 4096.0; + fCutoffUV = xscaleFractUV / 4096.0; + + /* Limit to between 1.0 and 3.0. */ + if (fCutoffY < MIN_CUTOFF_FREQ) + fCutoffY = MIN_CUTOFF_FREQ; + if (fCutoffY > MAX_CUTOFF_FREQ) + fCutoffY = MAX_CUTOFF_FREQ; + if (fCutoffUV < MIN_CUTOFF_FREQ) + fCutoffUV = MIN_CUTOFF_FREQ; + if (fCutoffUV > MAX_CUTOFF_FREQ) + fCutoffUV = MAX_CUTOFF_FREQ; + + UpdateCoeff(N_HORIZ_Y_TAPS, fCutoffY, TRUE, TRUE, xcoeffY); + UpdateCoeff(N_HORIZ_UV_TAPS, fCutoffUV, TRUE, FALSE, xcoeffUV); + + for (i = 0; i < N_PHASES; i++) { + for (j = 0; j < N_HORIZ_Y_TAPS; j++) { + pos = i * N_HORIZ_Y_TAPS + j; + overlay->Y_HCOEFS[pos] = xcoeffY[pos].sign << 15 | + xcoeffY[pos].exponent << 12 | + xcoeffY[pos].mantissa; + } + } + for (i = 0; i < N_PHASES; i++) { + for (j = 0; j < N_HORIZ_UV_TAPS; j++) { + pos = i * N_HORIZ_UV_TAPS + j; + overlay->UV_HCOEFS[pos] = xcoeffUV[pos].sign << 15 | + xcoeffUV[pos].exponent << 12 | + xcoeffUV[pos].mantissa; + } + } + } + } + + switch (id) { + case FOURCC_YV12: + case FOURCC_I420: + ErrorF("YUV420\n"); +#if 0 + /* set UV vertical phase to -0.25 */ + overlay->UV_VPH = 0x30003000; +#endif + ErrorF("UV stride is %d, Y stride is %d\n", dstPitch, dstPitch * 2); + overlay->OSTRIDE = (dstPitch * 2) | (dstPitch << 16); + overlay->OCMD &= ~SOURCE_FORMAT; + overlay->OCMD &= ~OV_BYTE_ORDER; + overlay->OCMD |= YUV_420; + break; + case FOURCC_UYVY: + case FOURCC_YUY2: + default: + ErrorF("YUV422\n"); + overlay->OSTRIDE = dstPitch; + overlay->OCMD &= ~SOURCE_FORMAT; + overlay->OCMD |= YUV_422; + overlay->OCMD &= ~OV_BYTE_ORDER; + if (id == FOURCC_UYVY) + overlay->OCMD |= Y_SWAP; + break; + } + + overlay->OCMD &= ~(BUFFER_SELECT | FIELD_SELECT); + if (pPriv->currentBuf == 0) + overlay->OCMD |= BUFFER0; + else + overlay->OCMD |= BUFFER1; + + ErrorF("OCMD is 0x%08x\n", overlay->OCMD); + + OVERLAY_UPDATE; +} + +static FBLinearPtr +I830AllocateMemory(ScrnInfoPtr pScrn, FBLinearPtr linear, int size) +{ + ScreenPtr pScreen; + FBLinearPtr new_linear; + + DPRINTF(PFX, "I830AllocateMemory\n"); + if (linear) { + if (linear->size >= size) + return linear; + + if (xf86ResizeOffscreenLinear(linear, size)) + return linear; + + xf86FreeOffscreenLinear(linear); + } + + pScreen = screenInfo.screens[pScrn->scrnIndex]; + + new_linear = xf86AllocateOffscreenLinear(pScreen, size, 4, + NULL, NULL, NULL); + + if (!new_linear) { + int max_size; + + xf86QueryLargestOffscreenLinear(pScreen, &max_size, 4, + PRIORITY_EXTREME); + + if (max_size < size) + return NULL; + + xf86PurgeUnlockedOffscreenAreas(pScreen); + new_linear = xf86AllocateOffscreenLinear(pScreen, size, 4, + NULL, NULL, NULL); + } + + return new_linear; +} + +static int +I830PutImage(ScrnInfoPtr pScrn, + short src_x, short src_y, + short drw_x, short drw_y, + short src_w, short src_h, + short drw_w, short drw_h, + int id, unsigned char *buf, + short width, short height, + Bool sync, RegionPtr clipBoxes, pointer data) +{ + I830Ptr pI830 = I830PTR(pScrn); + I830PortPrivPtr pPriv = (I830PortPrivPtr) data; + ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex]; + INT32 x1, x2, y1, y2; + int srcPitch, dstPitch; + int top, left, npixels, nlines, size, loops; + BoxRec dstBox; + + DPRINTF(PFX, "I830PutImage: src: (%d,%d)(%d,%d), dst: (%d,%d)(%d,%d)\n" + "width %d, height %d\n", src_x, src_y, src_w, src_h, drw_x, drw_y, + drw_w, drw_h, width, height); + + /* Clip */ + x1 = src_x; + x2 = src_x + src_w; + y1 = src_y; + y2 = src_y + src_h; + + dstBox.x1 = drw_x; + dstBox.x2 = drw_x + drw_w; + dstBox.y1 = drw_y; + dstBox.y2 = drw_y + drw_h; + + if (!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2, clipBoxes, + width, height)) + return Success; + + dstBox.x1 -= pScrn->frameX0; + dstBox.x2 -= pScrn->frameX0; + dstBox.y1 -= pScrn->frameY0; + dstBox.y2 -= pScrn->frameY0; + + switch (id) { + case FOURCC_YV12: + case FOURCC_I420: + srcPitch = (width + 3) & ~3; + dstPitch = ((width / 2) + 255) & ~255; /* of chroma */ + size = dstPitch * height * 3; + break; + case FOURCC_UYVY: + case FOURCC_YUY2: + default: + srcPitch = (width << 1); + dstPitch = (srcPitch + 255) & ~255; + size = dstPitch * height; + break; + } + ErrorF("srcPitch: %d, dstPitch: %d, size: %d\n", srcPitch, dstPitch, size); + + if (!(pPriv->linear = I830AllocateMemory(pScrn, pPriv->linear, + size * 2 / pI830->cpp))) + return BadAlloc; + + /* fixup pointers */ + pPriv->YBuf0offset = pScrn->fbOffset + pPriv->linear->offset * pI830->cpp; + pPriv->UBuf0offset = pPriv->YBuf0offset + (dstPitch * 2 * height); + pPriv->VBuf0offset = pPriv->UBuf0offset + (dstPitch * height / 2); + + pPriv->YBuf1offset = pPriv->YBuf0offset + size; + pPriv->UBuf1offset = pPriv->YBuf1offset + (dstPitch * 2 * height); + pPriv->VBuf1offset = pPriv->UBuf1offset + (dstPitch * height / 2); + + /* XXX We could potentially use MI_WAIT_FOR_OVERLAY here instead + * of this code....*/ + + /* Make sure this buffer isn't in use */ + loops = 0; + while (loops < 1000000) { +#if USE_USLEEP_FOR_VIDEO + usleep(10); +#endif + if (((INREG(DOVSTA) & OC_BUF) >> 20) == pPriv->currentBuf) { + break; + } + loops++; + } + if (loops >= 1000000) { + ErrorF("loops (1) maxed out for buffer %d\n", pPriv->currentBuf); +#if 0 + pPriv->currentBuf = !pPriv->currentBuf; +#endif + } + + /* buffer swap */ + if (pPriv->currentBuf == 0) + pPriv->currentBuf = 1; + else + pPriv->currentBuf = 0; + + /* copy data */ + top = y1 >> 16; + left = (x1 >> 16) & ~1; + npixels = ((((x2 + 0xffff) >> 16) + 1) & ~1) - left; + + switch (id) { + case FOURCC_YV12: + case FOURCC_I420: + top &= ~1; + nlines = ((((y2 + 0xffff) >> 16) + 1) & ~1) - top; + I830CopyPlanarData(pScrn, buf, srcPitch, dstPitch, height, top, left, + nlines, npixels, id); + break; + case FOURCC_UYVY: + case FOURCC_YUY2: + default: + nlines = ((y2 + 0xffff) >> 16) - top; + I830CopyPackedData(pScrn, buf, srcPitch, dstPitch, top, left, nlines, + npixels); + break; + } + + /* update cliplist */ + /* + * XXX Always draw the key. LinDVD seems to fill the window background + * with a colour different from the key. This works around that. + */ + if (1 || !RegionsEqual(&pPriv->clip, clipBoxes)) { + REGION_COPY(pScreen, &pPriv->clip, clipBoxes); + xf86XVFillKeyHelper(pScreen, pPriv->colorKey, clipBoxes); + } + + I830DisplayVideo(pScrn, id, width, height, dstPitch, + x1, y1, x2, y2, &dstBox, src_w, src_h, drw_w, drw_h); + + pPriv->videoStatus = CLIENT_VIDEO_ON; + + return Success; +} + +static int +I830QueryImageAttributes(ScrnInfoPtr pScrn, + int id, + unsigned short *w, unsigned short *h, + int *pitches, int *offsets) +{ + int size, tmp; + + DPRINTF(PFX, "I830QueryImageAttributes: w is %d, h is %d\n", *w, *h); + + if (*w > IMAGE_MAX_WIDTH) + *w = IMAGE_MAX_WIDTH; + if (*h > IMAGE_MAX_HEIGHT) + *h = IMAGE_MAX_HEIGHT; + + *w = (*w + 1) & ~1; + if (offsets) + offsets[0] = 0; + + switch (id) { + /* IA44 is for XvMC only */ + case FOURCC_IA44: + case FOURCC_AI44: + if (pitches) + pitches[0] = *w; + size = *w * *h; + break; + case FOURCC_YV12: + case FOURCC_I420: + *h = (*h + 1) & ~1; +#if 1 + size = (*w + 3) & ~3; +#else + size = (*w + 255) & ~255; +#endif + if (pitches) + pitches[0] = size; + size *= *h; + if (offsets) + offsets[1] = size; +#if 1 + tmp = ((*w >> 1) + 3) & ~3; +#else + tmp = ((*w >> 1) + 255) & ~255; +#endif + if (pitches) + pitches[1] = pitches[2] = tmp; + tmp *= (*h >> 1); + size += tmp; + if (offsets) + offsets[2] = size; + size += tmp; + if (pitches) + ErrorF("pitch 0 is %d, pitch 1 is %d, pitch 2 is %d\n", pitches[0], + pitches[1], pitches[2]); + if (offsets) + ErrorF("offset 1 is %d, offset 2 is %d\n", offsets[1], offsets[2]); + if (offsets) + ErrorF("size is %d\n", size); + break; + case FOURCC_UYVY: + case FOURCC_YUY2: + default: + size = *w << 1; + if (pitches) + pitches[0] = size; + size *= *h; + break; + } + + return size; +} + +static void +I830BlockHandler(int i, + pointer blockData, pointer pTimeout, pointer pReadmask) +{ + ScreenPtr pScreen = screenInfo.screens[i]; + ScrnInfoPtr pScrn = xf86Screens[i]; + I830Ptr pI830 = I830PTR(pScrn); + I830PortPrivPtr pPriv = GET_PORT_PRIVATE(pScrn); + I830OverlayRegPtr overlay = + (I830OverlayRegPtr) (pI830->FbBase + pI830->OverlayMem.Start); + + pScreen->BlockHandler = pI830->BlockHandler; + + (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask); + + pScreen->BlockHandler = I830BlockHandler; + + if (pPriv->videoStatus & TIMER_MASK) { + UpdateCurrentTime(); + if (pPriv->videoStatus & OFF_TIMER) { + if (pPriv->offTime < currentTime.milliseconds) { + /* Turn off the overlay */ + overlay->OCMD &= ~OVERLAY_ENABLE; + + OVERLAY_UPDATE; + + OVERLAY_OFF; + + pPriv->videoStatus = FREE_TIMER; + pPriv->freeTime = currentTime.milliseconds + FREE_DELAY; + } + } else { /* FREE_TIMER */ + if (pPriv->freeTime < currentTime.milliseconds) { + if (pPriv->linear) { + xf86FreeOffscreenLinear(pPriv->linear); + pPriv->linear = NULL; + } + pPriv->videoStatus = 0; + } + } + } +} + +/*************************************************************************** + * Offscreen Images + ***************************************************************************/ + +typedef struct { + FBLinearPtr linear; + Bool isOn; +} OffscreenPrivRec, *OffscreenPrivPtr; + +static int +I830AllocateSurface(ScrnInfoPtr pScrn, + int id, + unsigned short w, + unsigned short h, XF86SurfacePtr surface) +{ + FBLinearPtr linear; + int pitch, fbpitch, size, bpp; + OffscreenPrivPtr pPriv; + I830Ptr pI830 = I830PTR(pScrn); + + DPRINTF(PFX, "I830AllocateSurface\n"); + + if ((w > 1024) || (h > 1024)) + return BadAlloc; + + w = (w + 1) & ~1; + pitch = ((w << 1) + 15) & ~15; + bpp = pScrn->bitsPerPixel >> 3; + fbpitch = bpp * pScrn->displayWidth; + size = ((pitch * h) + bpp - 1) / bpp; + + if (!(linear = I830AllocateMemory(pScrn, NULL, size))) + return BadAlloc; + + surface->width = w; + surface->height = h; + + if (!(surface->pitches = xalloc(sizeof(int)))) { + xf86FreeOffscreenLinear(linear); + return BadAlloc; + } + if (!(surface->offsets = xalloc(sizeof(int)))) { + xfree(surface->pitches); + xf86FreeOffscreenLinear(linear); + return BadAlloc; + } + if (!(pPriv = xalloc(sizeof(OffscreenPrivRec)))) { + xfree(surface->pitches); + xfree(surface->offsets); + xf86FreeOffscreenLinear(linear); + return BadAlloc; + } + + pPriv->linear = linear; + pPriv->isOn = FALSE; + + surface->pScrn = pScrn; + surface->id = id; + surface->pitches[0] = pitch; + surface->offsets[0] = linear->offset * bpp; + surface->devPrivate.ptr = (pointer) pPriv; + + memset(pI830->FbBase + pScrn->fbOffset + surface->offsets[0], 0, size); + + return Success; +} + +static int +I830StopSurface(XF86SurfacePtr surface) +{ + OffscreenPrivPtr pPriv = (OffscreenPrivPtr) surface->devPrivate.ptr; + ScrnInfoPtr pScrn = surface->pScrn; + + if (pPriv->isOn) { + I830Ptr pI830 = I830PTR(pScrn); + + I830OverlayRegPtr overlay = + (I830OverlayRegPtr) (pI830->FbBase + pI830->OverlayMem.Start); + + overlay->OCMD &= ~OVERLAY_ENABLE; + + OVERLAY_UPDATE; + + OVERLAY_OFF; + + pPriv->isOn = FALSE; + } + + return Success; +} + +static int +I830FreeSurface(XF86SurfacePtr surface) +{ + OffscreenPrivPtr pPriv = (OffscreenPrivPtr) surface->devPrivate.ptr; + + if (pPriv->isOn) { + I830StopSurface(surface); + } + xf86FreeOffscreenLinear(pPriv->linear); + xfree(surface->pitches); + xfree(surface->offsets); + xfree(surface->devPrivate.ptr); + + return Success; +} + +static int +I830GetSurfaceAttribute(ScrnInfoPtr pScrn, Atom attribute, INT32 * value) +{ + return I830GetPortAttribute(pScrn, attribute, value, 0); +} + +static int +I830SetSurfaceAttribute(ScrnInfoPtr pScrn, Atom attribute, INT32 value) +{ + return I830SetPortAttribute(pScrn, attribute, value, 0); +} + +static int +I830DisplaySurface(XF86SurfacePtr surface, + short src_x, short src_y, + short drw_x, short drw_y, + short src_w, short src_h, + short drw_w, short drw_h, RegionPtr clipBoxes) +{ + OffscreenPrivPtr pPriv = (OffscreenPrivPtr) surface->devPrivate.ptr; + ScrnInfoPtr pScrn = surface->pScrn; + ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex]; + I830Ptr pI830 = I830PTR(pScrn); + I830PortPrivPtr pI830Priv = GET_PORT_PRIVATE(pScrn); + + INT32 x1, y1, x2, y2; + INT32 loops = 0; + BoxRec dstBox; + + DPRINTF(PFX, "I830DisplaySurface\n"); + x1 = src_x; + x2 = src_x + src_w; + y1 = src_y; + y2 = src_y + src_h; + + dstBox.x1 = drw_x; + dstBox.x2 = drw_x + drw_w; + dstBox.y1 = drw_y; + dstBox.y2 = drw_y + drw_h; + + if (!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2, clipBoxes, + surface->width, surface->height)) + return Success; + + dstBox.x1 -= pScrn->frameX0; + dstBox.x2 -= pScrn->frameX0; + dstBox.y1 -= pScrn->frameY0; + dstBox.y2 -= pScrn->frameY0; + + /* fixup pointers */ + pI830Priv->YBuf0offset = surface->offsets[0]; + pI830Priv->YBuf1offset = pI830Priv->YBuf0offset; + + /* XXX We could potentially use MI_WAIT_FOR_OVERLAY here instead + * of this code....*/ + + /* wait for the last rendered buffer to be flipped in */ + while (((INREG(DOVSTA) & OC_BUF) >> 20) != pI830Priv->currentBuf) { +#if USE_USLEEP_FOR_VIDEO + usleep(10); +#endif + if (loops == 200000) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Overlay Lockup\n"); + break; + } + loops++; + } + + /* buffer swap */ + if (pI830Priv->currentBuf == 0) + pI830Priv->currentBuf = 1; + else + pI830Priv->currentBuf = 0; + + I830ResetVideo(pScrn); + + I830DisplayVideo(pScrn, surface->id, surface->width, surface->height, + surface->pitches[0], x1, y1, x2, y2, &dstBox, + src_w, src_h, drw_w, drw_h); + + xf86XVFillKeyHelper(pScreen, pI830Priv->colorKey, clipBoxes); + + pPriv->isOn = TRUE; + /* we've prempted the XvImage stream so set its free timer */ + if (pI830Priv->videoStatus & CLIENT_VIDEO_ON) { + REGION_EMPTY(pScrn->pScreen, &pI830Priv->clip); + UpdateCurrentTime(); + pI830Priv->videoStatus = FREE_TIMER; + pI830Priv->freeTime = currentTime.milliseconds + FREE_DELAY; + pScrn->pScreen->BlockHandler = I830BlockHandler; + } + + return Success; +} + +static void +I830InitOffscreenImages(ScreenPtr pScreen) +{ + XF86OffscreenImagePtr offscreenImages; + + /* need to free this someplace */ + if (!(offscreenImages = xalloc(sizeof(XF86OffscreenImageRec)))) { + return; + } + + offscreenImages[0].image = &Images[0]; + offscreenImages[0].flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT; + offscreenImages[0].alloc_surface = I830AllocateSurface; + offscreenImages[0].free_surface = I830FreeSurface; + offscreenImages[0].display = I830DisplaySurface; + offscreenImages[0].stop = I830StopSurface; + offscreenImages[0].setAttribute = I830SetSurfaceAttribute; + offscreenImages[0].getAttribute = I830GetSurfaceAttribute; + offscreenImages[0].max_width = 1024; + offscreenImages[0].max_height = 1024; + offscreenImages[0].num_attributes = 1; + offscreenImages[0].attributes = Attributes; + + xf86XVRegisterOffscreenImages(pScreen, offscreenImages, 1); +} + +void +I830VideoSwitchModeBefore(ScrnInfoPtr pScrn, DisplayModePtr mode) +{ + I830PortPrivPtr pPriv; + int pixrate; + + if (!I830PTR(pScrn)->adaptor) { + return; + } + + pPriv = GET_PORT_PRIVATE(pScrn); + + if (!pPriv) { + xf86ErrorF("pPriv isn't set\n"); + return; + } + + pixrate = mode->HDisplay * mode->VDisplay * mode->VRefresh; + if (pixrate > pPriv->maxRate && pPriv->refreshOK) { + I830StopVideo(pScrn, pPriv, TRUE); + pPriv->refreshOK = FALSE; + } +} + +void +I830VideoSwitchModeAfter(ScrnInfoPtr pScrn, DisplayModePtr mode) +{ + I830PortPrivPtr pPriv; + int pixrate; + + if (!I830PTR(pScrn)->adaptor) { + return; + } + pPriv = GET_PORT_PRIVATE(pScrn); + if (!pPriv) + return; + + /* If this isn't initialised, assume 60Hz. */ + if (mode->VRefresh == 0) + mode->VRefresh = 60; + + pixrate = (mode->HDisplay * mode->VDisplay * mode->VRefresh) / 1000000; + pPriv->refreshOK = (pixrate <= pPriv->maxRate); +} + diff --git a/src/xvmc/I810XvMC.c b/src/xvmc/I810XvMC.c new file mode 100644 index 00000000..e6731c62 --- /dev/null +++ b/src/xvmc/I810XvMC.c @@ -0,0 +1,4507 @@ +/*************************************************************************** + +Copyright 2001 Intel Corporation. All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sub license, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice (including the +next paragraph) shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +IN NO EVENT SHALL INTEL, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR +THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ + +/************************************************************************* +** File libI810XvMC.c +** +** Authors: +** Matt Sottek <matthew.j.sottek@intel.com> +** Bob Paauwe <bob.j.paauwe@intel.com> +** +** +***************************************************************************/ +/* $XFree86: xc/lib/XvMC/hw/i810/I810XvMC.c,v 1.11 2002/11/19 09:35:49 alanh Exp $ */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <signal.h> +#include <fcntl.h> +#include <dirent.h> +#include <string.h> + +#include <sys/ioctl.h> +#include <X11/Xlibint.h> +#include <fourcc.h> +#include <Xv.h> +#include <Xvlib.h> +#include <XvMC.h> +#include <XvMClib.h> +#include "I810XvMC.h" + +static int error_base; +static int event_base; + +/*************************************************************************** +// Function: i810_get_free_buffer +// Description: Allocates a free dma page using kernel ioctls, then +// programs the data into the already allocated dma buffer list. +// Arguments: pI810XvMC private data structure from the current context. +// Notes: We faked the drmMapBufs for the i810's security so now we have +// to insert an allocated page into the correct spot in the faked +// list to keep up appearences. +// Concept for this function was taken from Mesa sources. +// Returns: drmBufPtr containing the information about the allocated page. +***************************************************************************/ +drmBufPtr i810_get_free_buffer(i810XvMCContext *pI810XvMC) { + drmI810DMA dma; + drmBufPtr buf; + + dma.granted = 0; + dma.request_size = 4096; + while(!dma.granted) { + if(GET_BUFFER(pI810XvMC, dma) || !dma.granted) + FLUSH(pI810XvMC); + } /* No DMA granted */ + + buf = &(pI810XvMC->dmabufs->list[dma.request_idx]); + buf->idx = dma.request_idx; + buf->used = 0; + buf->total = dma.request_size; + buf->address = (drmAddress)dma.virtual; + return buf; +} + +/*************************************************************************** +// Function: free_privContext +// Description: Free's the private context structure if the reference +// count is 0. +***************************************************************************/ +void i810_free_privContext(i810XvMCContext *pI810XvMC) { + + I810_LOCK(pI810XvMC,DRM_LOCK_QUIESCENT); + + + pI810XvMC->ref--; + if(!pI810XvMC->ref) { + drmUnmapBufs(pI810XvMC->dmabufs); + drmUnmap(pI810XvMC->overlay.address,pI810XvMC->overlay.size); + drmUnmap(pI810XvMC->surfaces.address,pI810XvMC->surfaces.size); + drmClose(pI810XvMC->fd); + + free(pI810XvMC->dmabufs->list); + free(pI810XvMC); + } + + I810_UNLOCK(pI810XvMC); +} + + +/*************************************************************************** +// Function: XvMCCreateContext +// Description: Create a XvMC context for the given surface parameters. +// Arguments: +// display - Connection to the X server. +// port - XvPortID to use as avertised by the X connection. +// surface_type_id - Unique identifier for the Surface type. +// width - Width of the surfaces. +// height - Height of the surfaces. +// flags - one or more of the following +// XVMC_DIRECT - A direct rendered context is requested. +// +// Notes: surface_type_id and width/height parameters must match those +// returned by XvMCListSurfaceTypes. +// Returns: Status +***************************************************************************/ +Status XvMCCreateContext(Display *display, XvPortID port, + int surface_type_id, int width, int height, int flags, + XvMCContext *context) { + i810XvMCContext *pI810XvMC; + char busIdString[10]; + int priv_count; + uint *priv_data; + uint magic; + Status ret; + int major, minor; + + /* Verify Obvious things first */ + if(context == NULL) { + return XvMCBadContext; + } + + if(!flags & XVMC_DIRECT) { + /* Indirect */ + printf("Indirect Rendering not supported!\nUsing Direct."); + } + + /* Limit use to root for now */ + if(geteuid()) { + printf("Use of XvMC on i810 is currently limited to root\n"); + return BadAccess; + } + + /* FIXME: Check $DISPLAY for legal values here */ + + context->surface_type_id = surface_type_id; + context->width = (unsigned short)width; + context->height = (unsigned short)height; + context->flags = flags; + context->port = port; + /* + Width, Height, and flags are checked against surface_type_id + and port for validity inside the X server, no need to check + here. + */ + + /* Allocate private Context data */ + context->privData = (void *)malloc(sizeof(i810XvMCContext)); + if(!context->privData) { + printf("Unable to allocate resources for XvMC context.\n"); + return BadAlloc; + } + pI810XvMC = (i810XvMCContext *)context->privData; + + + /* Verify the XvMC extension exists */ + if(! XvMCQueryExtension(display, &event_base, + &error_base)) { + printf("XvMC Extension is not available!\n"); + return BadAlloc; + } + /* Verify XvMC version */ + ret = XvMCQueryVersion(display, &major, &minor); + if(ret) { + printf("XvMCQuery Version Failed, unable to determine protocol version\n"); + } + /* FIXME: Check Major and Minor here */ + + /* Check for drm */ + if(! drmAvailable()) { + printf("Direct Rendering is not avilable on this system!\n"); + return BadAlloc; + } + + /* + Build the Attribute Atoms, and Initialize the ones that exist + in Xv. + */ + pI810XvMC->xv_colorkey = XInternAtom(display,"XV_COLORKEY",0); + if(!pI810XvMC->xv_colorkey) { + return XvBadPort; + } + ret = XvGetPortAttribute(display,port,pI810XvMC->xv_colorkey, + &pI810XvMC->colorkey); + if(ret) { + return ret; + } + pI810XvMC->xv_brightness = XInternAtom(display,"XV_BRIGHTNESS",0); + pI810XvMC->xv_saturation = XInternAtom(display,"XV_SATURATION",0); + pI810XvMC->xv_contrast = XInternAtom(display,"XV_CONTRAST",0); + pI810XvMC->brightness = 0; + pI810XvMC->saturation = 0x80; /* 1.0 in 3.7 format */ + pI810XvMC->contrast = 0x40; /* 1.0 in 3.6 format */ + + /* Open DRI Device */ + if((pI810XvMC->fd = drmOpen("i810",NULL)) < 0) { + printf("DRM Device for i810 could not be opened.\n"); + free(busIdString); + free(pI810XvMC); + return BadAccess; + } /* !pI810XvMC->fd */ + + /* Get magic number and put it in privData for passing */ + drmGetMagic(pI810XvMC->fd,&magic); + context->flags = (unsigned long)magic; + + /* + Pass control to the X server to create a drmContext for us and + validate the with/height and flags. + */ + if((ret = _xvmc_create_context(display, context, &priv_count, &priv_data))) { + printf("Unable to create XvMC Context.\n"); + return ret; + } + + /* + X server returns a structure like this: + drmContext + fbBase + OverlayOffset + OverlaySize + SurfacesOffset + SurfacesSize + busIdString = 9 char + 1 + */ + if(priv_count != 9) { + printf("_xvmc_create_context() returned incorrect data size!\n"); + printf("\tExpected 9, got %d\n",priv_count); + _xvmc_destroy_context(display, context); + free(pI810XvMC); + return BadAlloc; + } + pI810XvMC->drmcontext = priv_data[0]; + pI810XvMC->fb_base = priv_data[1]; + pI810XvMC->overlay.offset = priv_data[2] + priv_data[1]; + pI810XvMC->overlay.size = priv_data[3]; + pI810XvMC->surfaces.offset = priv_data[4] + priv_data[1]; + pI810XvMC->surfaces.size = priv_data[5]; + strncpy(pI810XvMC->busIdString,(char *)&priv_data[6],9); + pI810XvMC->busIdString[9] = '\0'; + + /* Must free the private data we were passed from X */ + free(priv_data); + + /* Initialize private context values */ + pI810XvMC->current = 0; + pI810XvMC->lock = 0; + pI810XvMC->last_flip = 0; + pI810XvMC->dual_prime = 0; + + /* + Map dma Buffers: Not really, this would be a drmMapBufs + but due to the i810 security model we have to just create an + empty data structure to fake it. + */ + pI810XvMC->dmabufs = (drmBufMapPtr)malloc(sizeof(drmBufMap)); + if(pI810XvMC->dmabufs == NULL) { + printf("Dma Bufs could not be mapped.\n"); + _xvmc_destroy_context(display, context); + free(pI810XvMC); + return BadAlloc; + } /* pI810XvMC->dmabufs == NULL */ + memset(pI810XvMC->dmabufs, 0, sizeof(drmBufMap)); + pI810XvMC->dmabufs->list = (drmBufPtr)malloc(sizeof(drmBuf) * + I810_DMA_BUF_NR); + if(pI810XvMC->dmabufs->list == NULL) { + printf("Dma Bufs could not be mapped.\n"); + _xvmc_destroy_context(display, context); + free(pI810XvMC); + return BadAlloc; + } /* pI810XvMC->dmabufs->list == NULL */ + memset(pI810XvMC->dmabufs->list, 0, sizeof(drmBuf) * I810_DMA_BUF_NR); + + /* Map the Overlay memory */ + if(drmMap(pI810XvMC->fd,pI810XvMC->overlay.offset, + pI810XvMC->overlay.size,&(pI810XvMC->overlay.address)) < 0) { + printf("Unable to map Overlay at offset 0x%x and size 0x%x\n", + (unsigned int)pI810XvMC->overlay.offset,pI810XvMC->overlay.size); + _xvmc_destroy_context(display, context); + free(pI810XvMC->dmabufs->list); + free(pI810XvMC); + return BadAlloc; + } /* drmMap() < 0 */ + + /* Overlay Regs are offset 1024 into Overlay Map */ + pI810XvMC->oregs = (i810OverlayRec *) + ((unsigned char *)pI810XvMC->overlay.address + 1024); + + /* Map Surfaces */ + if(drmMap(pI810XvMC->fd,pI810XvMC->surfaces.offset, + pI810XvMC->surfaces.size,&(pI810XvMC->surfaces.address)) < 0) { + printf("Unable to map XvMC Surfaces.\n"); + _xvmc_destroy_context(display, context); + free(pI810XvMC->dmabufs->list); + free(pI810XvMC); + return BadAlloc; + } /* drmMap() < 0 */ + + /* + There is a tiny chance that someone was using the overlay and + issued a flip that hasn't finished. To be 100% sure I'll just + take the lock and sleep for the worst case time for a flip. + */ + I810_LOCK(pI810XvMC,DRM_LOCK_QUIESCENT); + usleep(20000); /* 1/50th Sec for 50hz refresh */ + + /* Set up Overlay regs with Initial Values */ + pI810XvMC->oregs->YRGB_VPH = 0; + pI810XvMC->oregs->UV_VPH = 0; + pI810XvMC->oregs->HORZ_PH = 0; + pI810XvMC->oregs->INIT_PH = 0; + pI810XvMC->oregs->DWINPOS = 0; + pI810XvMC->oregs->DWINSZ = (I810_XVMC_MAXHEIGHT << 16) | + I810_XVMC_MAXWIDTH; + pI810XvMC->oregs->SWID = I810_XVMC_MAXWIDTH | (I810_XVMC_MAXWIDTH << 15); + pI810XvMC->oregs->SWIDQW = (I810_XVMC_MAXWIDTH >> 3) | + (I810_XVMC_MAXWIDTH << 12); + pI810XvMC->oregs->SHEIGHT = I810_XVMC_MAXHEIGHT | + (I810_XVMC_MAXHEIGHT << 15); + pI810XvMC->oregs->YRGBSCALE = 0x80004000; /* scale factor 1 */ + pI810XvMC->oregs->UVSCALE = 0x80004000; /* scale factor 1 */ + pI810XvMC->oregs->OV0CLRC0 = 0x4000; /* brightness: 0 contrast: 1.0 */ + pI810XvMC->oregs->OV0CLRC1 = 0x80; /* saturation: bypass */ + + /* Destination Colorkey Setup */ + pI810XvMC->oregs->DCLRKV = RGB16ToColorKey(pI810XvMC->colorkey); + pI810XvMC->oregs->DCLRKM = 0x80070307; + + + pI810XvMC->oregs->SCLRKVH = 0; + pI810XvMC->oregs->SCLRKVL = 0; + pI810XvMC->oregs->SCLRKM = 0; /* source color key disable */ + pI810XvMC->oregs->OV0CONF = 0; /* two 720 pixel line buffers */ + + pI810XvMC->oregs->OV0CMD = VC_UP_INTERPOLATION | HC_UP_INTERPOLATION | + Y_ADJUST | YUV_420; + + pI810XvMC->ref = 1; + + I810_UNLOCK(pI810XvMC); + + return Success; + +} + +/*************************************************************************** +// Function: XvMCDestroyContext +// Description: Destorys the specified context. +// +// Arguments: +// display - Specifies the connection to the server. +// context - The context to be destroyed. +// +// Returns: Status +***************************************************************************/ +Status XvMCDestroyContext(Display *display, XvMCContext *context) { + i810XvMCContext *pI810XvMC; + + if(context == NULL) { + return (error_base + XvMCBadContext); + } + if(context->privData == NULL) { + return (error_base + XvMCBadContext); + } + pI810XvMC = (i810XvMCContext *)context->privData; + + /* Turn off the overlay */ + if(pI810XvMC->last_flip) { + I810_LOCK(pI810XvMC,DRM_LOCK_QUIESCENT); + + /* Make sure last flip is done */ + BLOCK_OVERLAY(pI810XvMC,pI810XvMC->current); + + pI810XvMC->oregs->OV0CMD = VC_UP_INTERPOLATION | HC_UP_INTERPOLATION | + Y_ADJUST; + pI810XvMC->current = !pI810XvMC->current; + if(pI810XvMC->current == 1) { + pI810XvMC->oregs->OV0CMD |= BUFFER1_FIELD0; + } + else { + pI810XvMC->oregs->OV0CMD |= BUFFER0_FIELD0; + } + OVERLAY_FLIP(pI810XvMC); + pI810XvMC->last_flip++; + + /* Wait for the flip */ + BLOCK_OVERLAY(pI810XvMC,pI810XvMC->current); + + I810_UNLOCK(pI810XvMC); + } + + /* Pass Control to the X server to destroy the drmContext */ + _xvmc_destroy_context(display, context); + + i810_free_privContext(pI810XvMC); + context->privData = NULL; + + return Success; +} + + +/*************************************************************************** +// Function: XvMCCreateSurface +***************************************************************************/ +Status XvMCCreateSurface( Display *display, XvMCContext *context, + XvMCSurface *surface) { + i810XvMCContext *pI810XvMC; + i810XvMCSurface *pI810Surface; + int priv_count; + uint *priv_data; + Status ret; + + if((surface == NULL) || (context == NULL) || (display == NULL)){ + return BadValue; + } + + pI810XvMC = (i810XvMCContext *)context->privData; + if(pI810XvMC == NULL) { + return (error_base + XvMCBadContext); + } + + + surface->privData = (i810XvMCSurface *)malloc(sizeof(i810XvMCSurface)); + if(!surface->privData) { + return BadAlloc; + } + pI810Surface = (i810XvMCSurface *)surface->privData; + + /* Initialize private values */ + pI810Surface->privContext = pI810XvMC; + pI810Surface->last_render = 0; + pI810Surface->last_flip = 0; + pI810Surface->second_field = 0; + + if((ret = _xvmc_create_surface(display, context, surface, + &priv_count, &priv_data))) { + free(pI810Surface); + printf("Unable to create XvMCSurface.\n"); + return ret; + } + + /* + _xvmc_create_subpicture returns 2 uints with the offset into + the DRM map for the Y surface and UV surface. + */ + if(priv_count != 2) { + printf("_xvmc_create_surface() return incorrect data size.\n"); + printf("Expected 2 got %d\n",priv_count); + free(priv_data); + free(pI810Surface); + return BadAlloc; + } + /* Data == Client Address, offset == Physical address offset */ + pI810Surface->data = pI810XvMC->surfaces.address; + pI810Surface->offset = pI810XvMC->surfaces.offset; + + + /* + i810's MC Engine needs surfaces of 2^x (x= 9,10,11,12) pitch + and the Tiler need 512k aligned surfaces, basically we are + stuck with fixed memory with pitch 1024 for Y data. UV = 512. + */ + pI810Surface->pitch = 10; + if((surface->surface_type_id == FOURCC_UYVY) || + (surface->surface_type_id == FOURCC_YUY2)) { + /* This is not implemented server side. */ + pI810Surface->pitch++; + } + + /* + offsets[0,1,2] == Offsets from either data or offset for the Y + U and V surfaces. + */ + pI810Surface->offsets[0] = priv_data[0]; + if(((unsigned long)pI810Surface->data + pI810Surface->offsets[0]) & 4095) { + printf("XvMCCreateSurface: Surface offset 0 is not 4096 aligned\n"); + } + + if((surface->surface_type_id == FOURCC_UYVY) || + (surface->surface_type_id == FOURCC_YUY2)) { + /* Packed surface, not fully implemented */ + pI810Surface->offsets[1] = 0; + pI810Surface->offsets[2] = 0; + } + else { + /* Planar surface */ + pI810Surface->offsets[1] = priv_data[1]; + if(((unsigned long)pI810Surface->data + pI810Surface->offsets[1]) & 2047) { + printf("XvMCCreateSurface: Surface offset 1 is not 2048 aligned\n"); + } + + pI810Surface->offsets[2] = ((unsigned long)pI810Surface->offsets[1] + + (1<<(pI810Surface->pitch - 1)) * 288); + if(((unsigned long)pI810Surface->data + pI810Surface->offsets[2]) & 2047) { + printf("XvMCCreateSurface: Surface offset 2 is not 2048 aligned\n"); + } + + } + + /* Free data returned from xvmc_create_surface */ + free(priv_data); + + /* Clear the surface to 0 */ + memset((void *)((unsigned long)pI810Surface->data + (unsigned long)pI810Surface->offsets[0]), + 0, ((1<<pI810Surface->pitch) * surface->height)); + + switch(surface->surface_type_id) { + case FOURCC_YV12: + case FOURCC_I420: + /* Destination buffer info command */ + pI810Surface->dbi1y = ((((unsigned int)pI810Surface->offset + + pI810Surface->offsets[0]) & ~0xfc000fff) | + (pI810Surface->pitch - 9)); + pI810Surface->dbi1u = ((((unsigned int)pI810Surface->offset + + pI810Surface->offsets[1]) & ~0xfc000fff) | + (pI810Surface->pitch - 10)); + pI810Surface->dbi1v = ((((unsigned int)pI810Surface->offset + + pI810Surface->offsets[2]) & ~0xfc000fff) | + (pI810Surface->pitch - 10)); + + /* Destination buffer variables command */ + pI810Surface->dbv1 = (0x8<<20) | (0x8<<16); + /* Map info command */ + pI810Surface->mi1y = (0x1<<24) | (1<<9) | (pI810Surface->pitch - 3); + pI810Surface->mi1u = (0x1<<24) | (1<<9) | (pI810Surface->pitch - 4); + pI810Surface->mi1v = (0x1<<24) | (1<<9) | (pI810Surface->pitch - 4); + + pI810Surface->mi2y = (((unsigned int)surface->height - 1)<<16) | + ((unsigned int)surface->width - 1); + pI810Surface->mi2u = (((unsigned int)surface->height - 1)<<15) | + (((unsigned int)surface->width - 1)>>1); + pI810Surface->mi2v = pI810Surface->mi2u; + + pI810Surface->mi3y = ((unsigned int)pI810Surface->offset + + pI810Surface->offsets[0]) & ~0x0000000f; + pI810Surface->mi3u = ((unsigned int)pI810Surface->offset + + pI810Surface->offsets[1]) & ~0x0000000f; + pI810Surface->mi3v = ((unsigned int)pI810Surface->offset + + pI810Surface->offsets[2]) & ~0x0000000f; + break; + case FOURCC_UYVY: + case FOURCC_YUY2: + default: + /* Destination buffer info command */ + pI810Surface->dbi1y = ((((unsigned int)pI810Surface->offset + + pI810Surface->offsets[0]) & ~0xfc000fff) | + (pI810Surface->pitch - 9)); + /* Destination buffer variables command */ + if(surface->surface_type_id == FOURCC_YUY2) { + pI810Surface->dbv1 = 0x5<<8; + pI810Surface->mi1y = 0x5<<24 | pI810Surface->pitch | 0x1<<21; + } + else { + pI810Surface->dbv1 = 0x4<<8; + pI810Surface->mi1y = 0x5<<24 | (pI810Surface->pitch - 3); + } + pI810Surface->mi2y = (((unsigned int)surface->width - 1)<<16) | + ((unsigned int)surface->height - 1); + pI810Surface->mi3y = ((unsigned int)pI810Surface->offset + + pI810Surface->offsets[0]) & ~0xfc000fff; + break; + } + pI810XvMC->ref++; + + return Success; +} + + +/*************************************************************************** +// Function: XvMCDestroySurface +***************************************************************************/ +Status XvMCDestroySurface(Display *display, XvMCSurface *surface) { + i810XvMCSurface *pI810Surface; + i810XvMCContext *pI810XvMC; + + if((display == NULL) || (surface == NULL)) { + return BadValue; + } + if(surface->privData == NULL) { + return (error_base + XvMCBadSurface); + } + + pI810Surface = (i810XvMCSurface *)surface->privData; + if(pI810Surface->last_flip) { + XvMCSyncSurface(display,surface); + } + pI810XvMC = (i810XvMCContext *)pI810Surface->privContext; + + _xvmc_destroy_surface(display,surface); + + i810_free_privContext(pI810XvMC); + + free(pI810Surface); + surface->privData = NULL; + return Success; +} + +/*************************************************************************** +// Function: XvMCCreateBlocks +***************************************************************************/ +Status XvMCCreateBlocks(Display *display, XvMCContext *context, + unsigned int num_blocks, + XvMCBlockArray *block) { + + if((display == NULL) || (context == NULL) || (num_blocks == 0)) { + return BadValue; + } + + block->blocks = (short *)malloc(num_blocks<<6 * sizeof(short)); + if(block->blocks == NULL) { + return BadAlloc; + } + + block->num_blocks = num_blocks; + block->context_id = context->context_id; + + block->privData = NULL; + + return Success; +} + +/*************************************************************************** +// Function: XvMCDestroyBlocks +***************************************************************************/ +Status XvMCDestroyBlocks(Display *display, XvMCBlockArray *block) { + if(display == NULL) { + return BadValue; + } + + free(block->blocks); + block->num_blocks = 0; + block->context_id = 0; + block->privData = NULL; + return Success; +} + +/*************************************************************************** +// Function: XvMCCreateMacroBlocks +***************************************************************************/ +Status XvMCCreateMacroBlocks(Display *display, XvMCContext *context, + unsigned int num_blocks, + XvMCMacroBlockArray *blocks) { + + if((display == NULL) || (context == NULL) || (blocks == NULL) || + (num_blocks == 0)) { + return BadValue; + } + memset(blocks,0,sizeof(XvMCMacroBlockArray)); + blocks->context_id = context->context_id; + blocks->privData = NULL; + + blocks->macro_blocks = (XvMCMacroBlock *) + malloc(num_blocks * sizeof(XvMCMacroBlock)); + if(blocks->macro_blocks == NULL) { + return BadAlloc; + } + blocks->num_blocks = num_blocks; + + return Success; +} + +/*************************************************************************** +// Function: XvMCDestroyMacroBlocks +***************************************************************************/ +Status XvMCDestroyMacroBlocks(Display *display, XvMCMacroBlockArray *block) { + if((display == NULL) || (block == NULL)) { + return BadValue; + } + if(block->macro_blocks) { + free(block->macro_blocks); + } + block->context_id = 0; + block->num_blocks = 0; + block->privData = NULL; + + return Success; +} + + +/*************************************************************************** +// Function: dp (Debug Print) +// Description: This function prints out in hex i * uint32_t at the address +// supplied. This enables you to print out the dma buffers from +// within the debugger even though they are not in your address space. +***************************************************************************/ +void dp(unsigned int *address, unsigned int i) { + int j; + + printf("DebugPrint:\n"); + for(j=0; j<i; j++) { + printf("0x%8.8x ",address[j]); + if(j && !(j & 7)) { printf("\n");} + } +} + +/*************************************************************************** +// Macro: PACK_* +// Description: Packs 16bit signed data from blocks into either 8bit unsigned +// intra data or 16bit signed correction data, both packed into +// 32 bit integers. +***************************************************************************/ +#define PACK_INTRA_DATA(d,b,n) \ + do { \ + char *dp = (char *)d; \ + char *bp = (char *)b; \ + int counter; \ + for(counter = 0; counter < n; counter++) { \ + *dp++ = *bp; \ + bp += 2; \ + } \ + }while(0); + +#define PACK_CORR_DATA(d,b,n) \ + memcpy(d,b,n); \ + d = (uint *)((unsigned long)d + n); + +#define MARK_CORR_DATA(d,n) \ + do { \ + uint* q = (uint*)((unsigned long)d - n); \ + while((unsigned long)q < (unsigned long)d) { \ + *q++ += 0x00330033; \ + } \ + }while(0); + +#define MARK_INTRA_BLOCK(d) \ + do { \ + int q; \ + for(q=0; q<16; q++) { \ + d[q] += 0x33333333; \ + } \ + }while(0); + +/* + Used for DCT 1 when we need DCT 0. Instead + of reading from one block we read from two and + interlace. +*/ +#define PACK_CORR_DATA_1to0(d,top,bottom) \ + do { \ + short *t = top,*b = bottom; \ + PACK_CORR_DATA(d,t,16); \ + t = (short *)((unsigned long)t + 16); \ + PACK_CORR_DATA(d,b,16); \ + b = (short *)((unsigned long)b + 16); \ + PACK_CORR_DATA(d,t,16); \ + t = (short *)((unsigned long)t + 16); \ + PACK_CORR_DATA(d,b,16); \ + b = (short *)((unsigned long)b + 16); \ + PACK_CORR_DATA(d,t,16); \ + t = (short *)((unsigned long)t + 16); \ + PACK_CORR_DATA(d,b,16); \ + b = (short *)((unsigned long)b + 16); \ + PACK_CORR_DATA(d,t,16); \ + t = (short *)((unsigned long)t + 16); \ + PACK_CORR_DATA(d,b,16); \ + b = (short *)((unsigned long)b + 16); \ + }while(0); + +/* Used for DCT 0 when we need DCT 1. */ +#define PACK_CORR_DATA_0to1(d,top,bottom) \ + do{ \ + short *t = top,*b = bottom; \ + PACK_CORR_DATA(d,t,16); \ + t = (short *)((unsigned long)t + 32); \ + PACK_CORR_DATA(d,t,16); \ + t = (short *)((unsigned long)t + 32); \ + PACK_CORR_DATA(d,t,16); \ + t = (short *)((unsigned long)t + 32); \ + PACK_CORR_DATA(d,t,16); \ + t = (short *)((unsigned long)t + 32); \ + PACK_CORR_DATA(d,b,16); \ + b = (short *)((unsigned long)b + 32); \ + PACK_CORR_DATA(d,b,16); \ + b = (short *)((unsigned long)b + 32); \ + PACK_CORR_DATA(d,b,16); \ + b = (short *)((unsigned long)b + 32); \ + PACK_CORR_DATA(d,b,16); \ + b = (short *)((unsigned long)b + 32); \ + }while(0); + +#define PACK_CORR_DATA_SHORT(d,block) \ + do { \ + short *b = block; \ + PACK_CORR_DATA(d,b,16); \ + b = (short *)((unsigned long)b + 32); \ + PACK_CORR_DATA(d,b,16); \ + b = (short *)((unsigned long)b + 32); \ + PACK_CORR_DATA(d,b,16); \ + b = (short *)((unsigned long)b + 32); \ + PACK_CORR_DATA(d,b,16); \ + b = (short *)((unsigned long)b + 32); \ + }while(0); + +/* Lookup tables to speed common calculations */ +static unsigned int drps_table[] = {2<<6,3<<6}; + +static unsigned int mvfs_table[] = { + 0x12, + 0x1a, + 0x13, + 0x1b +}; + +static unsigned int type_table[] = { + 0x1<<12, /* This is an error so make it Forward motion */ + 0x1<<12, + 0x1<<12, + 0x1<<12, + 0x2<<12, + 0x2<<12, + 0x3<<12, + 0x3<<12, + 0x1<<12, /* Pattern but no Motion, Make motion Forward */ + 0x1<<12, + 0x1<<12, + 0x1<<12, + 0x2<<12, + 0x2<<12, + 0x3<<12, + 0x3<<12 +}; + +static unsigned int y_frame_bytes[] = { + 0,0,0,0,128,128,128,128, + 128,128,128,128,256,256,256,256, + 128,128,128,128,256,256,256,256, + 256,256,256,256,384,384,384,384, + 128,128,128,128,256,256,256,256, + 256,256,256,256,384,384,384,384, + 256,256,256,256,384,384,384,384, + 384,384,384,384,512,512,512,512 +}; + +static unsigned int u_frame_bytes[] = { + 0,0,128,128,0,0,128,128, + 0,0,128,128,0,0,128,128, + 0,0,128,128,0,0,128,128, + 0,0,128,128,0,0,128,128, + 0,0,128,128,0,0,128,128, + 0,0,128,128,0,0,128,128, + 0,0,128,128,0,0,128,128, + 0,0,128,128,0,0,128,128 +}; + +static unsigned int v_frame_bytes[] = { + 0,128,0,128,0,128,0,128, + 0,128,0,128,0,128,0,128, + 0,128,0,128,0,128,0,128, + 0,128,0,128,0,128,0,128, + 0,128,0,128,0,128,0,128, + 0,128,0,128,0,128,0,128, + 0,128,0,128,0,128,0,128, + 0,128,0,128,0,128,0,128 +}; + +static unsigned int y_first_field_bytes[] = { + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128, + 256,256,256,256,256,256,256,256, + 256,256,256,256,256,256,256,256 +}; + +static unsigned int y_second_field_bytes[] = { + 0,0,0,0,128,128,128,128, + 128,128,128,128,256,256,256,256, + 0,0,0,0,128,128,128,128, + 128,128,128,128,256,256,256,256, + 0,0,0,0,128,128,128,128, + 128,128,128,128,256,256,256,256, + 0,0,0,0,128,128,128,128, + 128,128,128,128,256,256,256,256 +}; + +static unsigned int y_dct0_field_bytes[] = { + 0,0,0,0,128,128,128,128, + 128,128,128,128,256,256,256,256, + 128,128,128,128,128,128,128,128, + 256,256,256,256,256,256,256,256, + 128,128,128,128,256,256,256,256, + 128,128,128,128,256,256,256,256, + 256,256,256,256,256,256,256,256, + 256,256,256,256,256,256,256,256 +}; + +static unsigned int y_dct1_frame_bytes[] = { + 0,0,0,0,256,256,256,256, + 256,256,256,256,512,512,512,512, + 256,256,256,256,256,256,256,256, + 512,512,512,512,512,512,512,512, + 256,256,256,256,512,512,512,512, + 256,256,256,256,512,512,512,512, + 512,512,512,512,512,512,512,512, + 512,512,512,512,512,512,512,512 +}; + +static unsigned int u_field_bytes[] = { + 0,0,64,64,0,0,64,64, + 0,0,64,64,0,0,64,64, + 0,0,64,64,0,0,64,64, + 0,0,64,64,0,0,64,64, + 0,0,64,64,0,0,64,64, + 0,0,64,64,0,0,64,64, + 0,0,64,64,0,0,64,64, + 0,0,64,64,0,0,64,64 +}; + +static unsigned int v_field_bytes[] = { + 0,64,0,64,0,64,0,64, + 0,64,0,64,0,64,0,64, + 0,64,0,64,0,64,0,64, + 0,64,0,64,0,64,0,64, + 0,64,0,64,0,64,0,64, + 0,64,0,64,0,64,0,64, + 0,64,0,64,0,64,0,64, + 0,64,0,64,0,64,0,64 +}; + +static short empty_block[] = { + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0 +}; + + +/*************************************************************************** +// Function: dispatchYContext +// Description: Allocate a DMA buffer write the Y MC Context info in it, +// and dispatch it to hardware. +***************************************************************************/ + +static __inline__ void dispatchYContext(i810XvMCSurface *privTarget, + i810XvMCSurface *privPast, + i810XvMCSurface *privFuture, + i810XvMCContext *pI810XvMC) { + uint *data; + drmBufPtr pDMA; + drm_i810_mc_t mc; + + pDMA = i810_get_free_buffer(pI810XvMC); + data = pDMA->address; + *data++ = CMD_FLUSH; + *data++ = BOOLEAN_ENA_2; + *data++ = CMD_FLUSH; + *data++ = DEST_BUFFER_INFO; + *data++ = privTarget->dbi1y; + *data++ = DEST_BUFFER_VAR; + *data++ = privTarget->dbv1; + /* Past Surface */ + *data++ = CMD_MAP_INFO; + *data++ = privPast->mi1y; + *data++ = privPast->mi2y; + *data++ = privPast->mi3y; + /* Future Surface */ + *data++ = CMD_MAP_INFO; + *data++ = privFuture->mi1y | 0x1<<28; + *data++ = privFuture->mi2y; + *data++ = privFuture->mi3y; + + mc.idx = pDMA->idx; + mc.used = (unsigned long)data - (unsigned long)pDMA->address; + mc.last_render = ++pI810XvMC->last_render; + privTarget->last_render = pI810XvMC->last_render; + I810_MC(pI810XvMC,mc); +} + +static __inline__ void renderError(void) { + printf("Invalid Macroblock Parameters found.\n"); + return; +} + +/*************************************************************************** +// Function: renderIntrainFrame +// Description: inline function that sets hardware parameters for an Intra +// encoded macroblock in a Frame picture. +***************************************************************************/ +static __inline__ void renderIntrainFrame(uint **datay,uint **datau, + uint **datav, + XvMCMacroBlock *mb, + short *block_ptr) { + + register uint *dy = *datay; + register uint *du = *datau; + register uint *dv = *datav; + + /* Y Blocks */ + *dy++ = GFXBLOCK + 68; + *dy++ = (1<<30) | (3<<28) | (0xf<<24); + *dy++ = ((uint)mb->x<<20) | ((uint)mb->y<<4); + *dy++ = (16<<16) | 16; + *dy++ = 0; + *dy++ = 0; + PACK_INTRA_DATA(dy,block_ptr,256); + dy += 64; + block_ptr += 256; + /* End Y Blocks */ + + /* U Block */ + *du++ = GFXBLOCK + 20; + *du++ = (2<<30) | (1<<28) | (1<<23); + *du++ = (((uint)mb->x)<<19) | (((uint)mb->y)<<3); + *du++ = (8<<16) | 8; + *du++ = 0; + *du++ = 0; + PACK_INTRA_DATA(du,block_ptr,64); + du += 16; + block_ptr += 64; + + /* V Block */ + *dv++ = GFXBLOCK + 20; + *dv++ = (3<<30) | (1<<28) | (1<<22); + *dv++ = (((uint)mb->x)<<19) | (((uint)mb->y)<<3); + *dv++ = (8<<16) | 8; + *dv++ = 0; + *dv++ = 0; + PACK_INTRA_DATA(dv,block_ptr,64); + dv += 16; + block_ptr += 64; + + *datay = dy; + *datau = du; + *datav = dv; +} + +/*************************************************************************** +// Function: renderIntrainFrameDCT1 +// Description: inline function that sets hardware parameters for an Intra +// encoded macroblock in a Frame picture with DCT type 1. +***************************************************************************/ +static __inline__ void renderIntrainFrameDCT1(uint **datay,uint **datau, + uint **datav,XvMCMacroBlock *mb, + short *block_ptr,uint flags) { + + register uint *dy = *datay; + register uint *du = *datau; + register uint *dv = *datav; + + + /* Y Blocks */ + *dy++ = GFXBLOCK + 36; + *dy++ = (1<<30) | (2<<28) | (0x3<<26) | (0x2<<6); + *dy++ = ((uint)mb->x<<20) | ((uint)mb->y<<3); + *dy++ = (8<<16) | 16; + *dy++ = 0; + *dy++ = 0; + PACK_INTRA_DATA(dy,block_ptr,128); + dy += 32; + block_ptr += 128; + + /* Second Y block */ + *dy++ = GFXBLOCK + 36; + *dy++ = (1<<30) | (2<<28) | (0x3<<26) | (0x3<<6); + *dy++ = ((uint)mb->x<<20) | ((uint)mb->y<<3); + *dy++ = (8<<16) | 16; + *dy++ = 0; + *dy++ = 0; + PACK_INTRA_DATA(dy,block_ptr,128); + dy += 32; + block_ptr += 128; + /* End Y Blocks */ + + + /* U Block */ + *du++ = GFXBLOCK + 20; + *du++ = (2<<30) | (1<<28) | (1<<23); + *du++ = (((uint)mb->x)<<19) | (((uint)mb->y)<<3); + *du++ = (8<<16) | 8; + *du++ = 0; + *du++ = 0; + PACK_INTRA_DATA(du,block_ptr,64); + du += 16; + block_ptr += 64; + + /* V Block */ + *dv++ = GFXBLOCK + 20; + *dv++ = (3<<30) | (1<<28) | (1<<22); + *dv++ = (((uint)mb->x)<<19) | (((uint)mb->y)<<3); + *dv++ = (8<<16) | 8; + *dv++ = 0; + *dv++ = 0; + PACK_INTRA_DATA(dv,block_ptr,64); + dv += 16; + block_ptr += 64; + + *datay = dy; + *datau = du; + *datav = dv; +} + + +/*************************************************************************** +// Function: renderIntrainField +// Description: inline function that sets hardware parameters for an Intra +// encoded macroblock in Field pictures. +***************************************************************************/ +static __inline__ void renderIntrainField(uint **datay,uint **datau, + uint **datav, + XvMCMacroBlock *mb,short *block_ptr, + uint ps) { + + register uint *dy = *datay; + register uint *du = *datau; + register uint *dv = *datav; + + uint xy = ((uint)mb->x<<20) | ((uint)mb->y<<4); + uint dw1 = drps_table[~ps & 0x1]; + + /* Y Blocks */ + *dy++ = GFXBLOCK + 68; + *dy++ = (1<<30) | (3<<28) | (0xf<<24) | dw1; + *dy++ = xy; + *dy++ = (16<<16) | 16; + *dy++ = 0; + *dy++ = 0; + PACK_INTRA_DATA(dy,block_ptr,256); + dy += 64; + block_ptr += 256; + /* End Y Blocks */ + + xy >>= 1; + + /* U Block */ + *du++ = GFXBLOCK + 20; + *du++ = (2<<30) | (1<<28) | (1<<23) | dw1; + *du++ = xy; + *du++ = (8<<16) | 8; + *du++ = 0; + *du++ = 0; + PACK_INTRA_DATA(du,block_ptr,64); + du += 16; + block_ptr += 64; + + /* V Block */ + *dv++ = GFXBLOCK + 20; + *dv++ = (3<<30) | (1<<28) | (1<<22) | dw1; + *dv++ = xy; + *dv++ = (8<<16) | 8; + *dv++ = 0; + *dv++ = 0; + PACK_INTRA_DATA(dv,block_ptr,64); + dv += 16; + block_ptr += 64; + + *datay = dy; + *datau = du; + *datav = dv; +} + + +/*************************************************************************** +// Function: renderFieldinField +// Description: inline function that sets hardware parameters for a Field +// encoded macroblock in a Field Picture. +***************************************************************************/ +static __inline__ void renderFieldinField(uint **datay,uint **datau, + uint **datav, + XvMCMacroBlock *mb,short *block_ptr, + uint ps, uint flags) { + + register uint *dy = *datay; + register uint *du = *datau; + register uint *dv = *datav; + + /* Motion Vectors */ + short fmv[2]; + short bmv[2]; + /* gfxblock dword 1 */ + uint dw1; + + uint parity = ~ps & XVMC_TOP_FIELD; + + uint ysize = y_frame_bytes[mb->coded_block_pattern]; + uint usize = u_frame_bytes[mb->coded_block_pattern]; + uint vsize = v_frame_bytes[mb->coded_block_pattern]; + + uint xy = ((uint)mb->x<<20) | ((uint)mb->y<<4); + + /* i810 Specific flag used to identify the second field in a P frame */ + if(flags & 0x80000000) { + /* P Frame */ + if((mb->motion_vertical_field_select & XVMC_SELECT_FIRST_FORWARD) == + parity) { + /* Same parity, use reference field (map0) */ + dw1 = 1<<12 | ((0x2 + parity)<<6) | ((0x2 + parity)<<3) | + (((uint)mb->coded_block_pattern)<<22); + fmv[0] = mb->PMV[0][0][1]; + fmv[1] = mb->PMV[0][0][0]; + bmv[0] = 0; + bmv[1] = 0; + } + else { + /* + Opposite parity, set up as if it were backward + motion and use map1. + */ + dw1 = 2<<12 | ((0x2 + parity)<<6) | (0x3 - parity) | + (((uint)mb->coded_block_pattern)<<22); + bmv[0] = mb->PMV[0][0][1]; + bmv[1] = mb->PMV[0][0][0]; + fmv[0] = 0; + fmv[1] = 0; + } + } + else { + dw1 = type_table[mb->macroblock_type & 0xf] | + drps_table[~ps & 0x1] | + mvfs_table[mb->motion_vertical_field_select & 3] | + (((uint)mb->coded_block_pattern)<<22); + + fmv[0] = mb->PMV[0][0][1]; + fmv[1] = mb->PMV[0][0][0]; + + bmv[0] = mb->PMV[0][1][1]; + bmv[1] = mb->PMV[0][1][0]; + } + + /* Y Block */ + *dy++ = GFXBLOCK + 4 + (ysize>>2); + *dy++ = (1<<30) | (3<<28) | dw1; + *dy++ = xy; + *dy++ = (16<<16) | 16; + *dy++ = *(uint *)fmv; + *dy++ = *(uint *)bmv; + PACK_CORR_DATA(dy,block_ptr,ysize); + block_ptr = (short *)((unsigned long)block_ptr + ysize); + /* End Y Blocks */ + + fmv[0] /= 2; + fmv[1] /= 2; + bmv[0] /= 2; + bmv[1] /= 2; + xy >>= 1; + + /* U Block */ + *du++ = GFXBLOCK + 4 + (usize>>2); + *du++ = (2<<30) | (1<<28) | dw1; + *du++ = xy; + *du++ = (8<<16) | 8; + *du++ = *(uint *)fmv; + *du++ = *(uint *)bmv; + PACK_CORR_DATA(du,block_ptr,usize); + block_ptr = (short *)((unsigned long)block_ptr + usize); + + /* V Block */ + *dv++ = GFXBLOCK + 4 + (vsize>>2); + *dv++ = (3<<30) | (1<<28) | dw1; + *dv++ = xy; + *dv++ = (8<<16) | 8; + *dv++ = *(uint *)fmv; + *dv++ = *(uint *)bmv; + PACK_CORR_DATA(dv,block_ptr,vsize); + block_ptr = (short *)((unsigned long)block_ptr + vsize); + + *datay = dy; + *datau = du; + *datav = dv; +} + +/*************************************************************************** +// Function: render16x8inField +// Description: inline function that sets hardware parameters for a 16x8 +// encoded macroblock in a field picture. +***************************************************************************/ +static __inline__ void render16x8inField(uint **datay,uint **datau, + uint **datav, + XvMCMacroBlock *mb,short *block_ptr, + uint ps, uint flags) { + + register uint *dy = *datay; + register uint *du = *datau; + register uint *dv = *datav; + + /* Motion Vectors */ + short fmv[4]; + short bmv[4]; + /* gfxblock dword 1 */ + uint dw1[2]; + + uint y1size = y_first_field_bytes[mb->coded_block_pattern]; + uint y2size = y_second_field_bytes[mb->coded_block_pattern]; + uint usize = u_field_bytes[mb->coded_block_pattern]; + uint vsize = v_field_bytes[mb->coded_block_pattern]; + + uint parity = ~ps & XVMC_TOP_FIELD; + + uint xy = ((uint)mb->x<<20) | ((uint)mb->y<<4); + + /* i810 Specific flag used to identify the second field in a P frame */ + if(flags & 0x80000000) { + /* P Frame */ + if((mb->motion_vertical_field_select & XVMC_SELECT_FIRST_FORWARD) == + parity) { + /* Same parity, use reference field (map0) */ + dw1[0] = 1<<12 | ((0x2 + parity)<<6) | ((0x2 + parity)<<3) | + (((uint)mb->coded_block_pattern)<<22); + + fmv[0] = mb->PMV[0][0][1]; + fmv[1] = mb->PMV[0][0][0]; + bmv[0] = 0; + bmv[1] = 0; + } + else { + /* + Opposite parity, set up as if it were backward + motion and use map1. + */ + dw1[0] = 2<<12 | ((0x2 + parity)<<6) | (0x3 - parity) | + (((uint)mb->coded_block_pattern)<<22); + + bmv[0] = mb->PMV[0][0][1]; + bmv[1] = mb->PMV[0][0][0]; + fmv[0] = 0; + fmv[1] = 0; + } + if((mb->motion_vertical_field_select & XVMC_SELECT_SECOND_FORWARD) == + (parity<<2)) { + /* Same parity, use reference field (map0) */ + dw1[1] = 1<<12 | ((0x2 + parity)<<6) | ((0x2 + parity)<<3) | + ((((uint)mb->coded_block_pattern<<22) & (0x3<<22)) | + (((uint)mb->coded_block_pattern<<24) & (0x3<<26))); + + fmv[2] = mb->PMV[1][0][1]; + fmv[3] = mb->PMV[1][0][0]; + bmv[2] = 0; + bmv[3] = 0; + } + else { + /* + Opposite parity, set up as if it were backward + motion and use map1. + */ + dw1[1] = 2<<12 | ((0x2 + parity)<<6) | (0x3 - parity) | + ((((uint)mb->coded_block_pattern<<22) & (0x3<<22)) | + (((uint)mb->coded_block_pattern<<24) & (0x3<<26))); + + bmv[2] = mb->PMV[1][0][1]; + bmv[3] = mb->PMV[1][0][0]; + fmv[2] = 0; + fmv[3] = 0; + } + } + else { + dw1[0] = type_table[mb->macroblock_type & 0xf] | + drps_table[~ps & 0x1] | + mvfs_table[mb->motion_vertical_field_select & 3] | + (((uint)mb->coded_block_pattern)<<22); + + dw1[1] = type_table[mb->macroblock_type & 0xf] | + drps_table[~ps & 0x1] | + mvfs_table[(mb->motion_vertical_field_select>>2) & 0x3] | + ((((uint)mb->coded_block_pattern<<22) & (0x3<<22)) | + (((uint)mb->coded_block_pattern<<24) & (0x3<<26))); + + fmv[0] = mb->PMV[0][0][1]; + fmv[1] = mb->PMV[0][0][0]; + fmv[2] = mb->PMV[1][0][1]; + fmv[3] = mb->PMV[1][0][0]; + + bmv[0] = mb->PMV[0][1][1]; + bmv[1] = mb->PMV[0][1][0]; + bmv[2] = mb->PMV[1][1][1]; + bmv[3] = mb->PMV[1][1][0]; + } + + /* First Y Block */ + *dy++ = GFXBLOCK + 4 + (y1size>>2); + *dy++ = (1<<30) | (2<<28) | dw1[0]; + *dy++ = xy; + *dy++ = (8<<16) | 16; + *dy++ = *(uint *)fmv; + *dy++ = *(uint *)bmv; + PACK_CORR_DATA(dy,block_ptr,y1size); + block_ptr = (short *)((unsigned long)block_ptr + y1size); + + /* Second Y Block */ + *dy++ = GFXBLOCK + 4 + (y2size>>2); + *dy++ = (1<<30) | (2<<28) | dw1[1]; + *dy++ = (xy + 8); + *dy++ = (8<<16) | 16; + *dy++ = *(uint *)&fmv[2]; + *dy++ = *(uint *)&bmv[2]; + PACK_CORR_DATA(dy,block_ptr,y2size); + block_ptr = (short *)((unsigned long)block_ptr + y2size); + /* End Y Blocks */ + + fmv[0] /= 2; + fmv[1] /= 2; + fmv[2] /= 2; + fmv[3] /= 2; + + bmv[0] /= 2; + bmv[1] /= 2; + bmv[2] /= 2; + bmv[3] /= 2; + + xy >>= 1; + + /* U Blocks */ + *du++ = GFXBLOCK + 4 + (usize>>2); + *du++ = (2<<30) | (1<<28) | dw1[0]; + *du++ = xy; + *du++ = (4<<16) | 8; + *du++ = *(uint *)fmv; + *du++ = *(uint *)bmv; + PACK_CORR_DATA(du,block_ptr,usize); + block_ptr = (short *)((unsigned long)block_ptr + usize); + + /* Second U block */ + *du++ = GFXBLOCK + 4 + (usize>>2); + *du++ = (2<<30) | (1<<28) | dw1[1]; + *du++ = (xy + 4); + *du++ = (4<<16) | 8; + *du++ = *(uint *)&fmv[2]; + *du++ = *(uint *)&bmv[2]; + PACK_CORR_DATA(du,block_ptr,usize); + block_ptr = (short *)((unsigned long)block_ptr + usize); + /* End U Blocks */ + + /* V Blocks */ + *dv++ = GFXBLOCK + 4 + (vsize>>2); + *dv++ = (3<<30) | (1<<28) | dw1[0]; + *dv++ = xy; + *dv++ = (4<<16) | 8; + *dv++ = *(uint *)fmv; + *dv++ = *(uint *)bmv; + PACK_CORR_DATA(dv,block_ptr,vsize); + block_ptr = (short *)((unsigned long)block_ptr + vsize); + + /* Second V Block */ + *dv++ = GFXBLOCK + 4 + (vsize>>2); + *dv++ = (3<<30) | (1<<28) | dw1[1]; + *dv++ = (xy + 4); + *dv++ = (4<<16) | 8; + *dv++ = *(uint *)&fmv[2]; + *dv++ = *(uint *)&bmv[2]; + PACK_CORR_DATA(dv,block_ptr,vsize); + block_ptr = (short *)((unsigned long)block_ptr + vsize); + /* End V Blocks */ + + *datay = dy; + *datau = du; + *datav = dv; +} + +/*************************************************************************** +// Function: renderDualPrimeinField +// Description: inline function that sets hardware parameters for a Dual +// prime encoded macroblock in a field picture. +***************************************************************************/ +static __inline__ void renderDualPrimeinField(uint **datay,uint **datau, + uint **datav,XvMCMacroBlock *mb, + short *block_ptr,uint ps, + uint flags) { + + register uint *dy = *datay; + register uint *du = *datau; + register uint *dv = *datav; + + /* Motion Vectors */ + short fmv[2]; + short bmv[2]; + /* gfxblock dword 1 */ + uint dw1; + + + uint ysize = y_frame_bytes[mb->coded_block_pattern]; + uint usize = u_frame_bytes[mb->coded_block_pattern]; + uint vsize = v_frame_bytes[mb->coded_block_pattern]; + + uint xy = ((uint)mb->x<<20) | ((uint)mb->y<<4); + + + if(ps & XVMC_TOP_FIELD) { + dw1 = (mb->coded_block_pattern<<22) | 3<<12 | 2<<6 | 2<<3 | 3; + } + else { + dw1 = (mb->coded_block_pattern<<22) | 3<<12 | 3<<6 | 3<<3 | 2; + } + fmv[0] = mb->PMV[0][0][1]; + fmv[1] = mb->PMV[0][0][0]; + bmv[0] = mb->PMV[0][1][1]; + bmv[1] = mb->PMV[0][1][0]; + + /* Y Block */ + *dy++ = GFXBLOCK + 4 + (ysize>>2); + *dy++ = (1<<30) | (3<<28) | dw1; + *dy++ = xy; + *dy++ = (16<<16) | 16; + *dy++ = *(uint *)fmv; + *dy++ = *(uint *)bmv; + PACK_CORR_DATA(dy,block_ptr,ysize); + block_ptr = (short *)((unsigned long)block_ptr + ysize); + /* End Y Blocks */ + + fmv[0] /= 2; + fmv[1] /= 2; + bmv[0] /= 2; + bmv[1] /= 2; + xy >>= 1; + + /* U Block */ + *du++ = GFXBLOCK + 4 + (usize>>2); + *du++ = (2<<30) | (1<<28) | dw1; + *du++ = xy; + *du++ = (8<<16) | 8; + *du++ = *(uint *)fmv; + *du++ = *(uint *)bmv; + PACK_CORR_DATA(du,block_ptr,usize); + block_ptr = (short *)((unsigned long)block_ptr + usize); + + /* V Block */ + *dv++ = GFXBLOCK + 4 + (vsize>>2); + *dv++ = (3<<30) | (1<<28) | dw1; + *dv++ = xy; + *dv++ = (8<<16) | 8; + *dv++ = *(uint *)fmv; + *dv++ = *(uint *)bmv; + PACK_CORR_DATA(dv,block_ptr,vsize); + block_ptr = (short *)((unsigned long)block_ptr + vsize); + + *datay = dy; + *datau = du; + *datav = dv; +} + +/*************************************************************************** +// Function: renderFieldinFrame +// Description: inline function that sets hardware parameters for a Field +// encoded macroblock in a frame picture. +***************************************************************************/ +static __inline__ void renderFieldinFrame(uint **datay,uint **datau, + uint **datav, + XvMCMacroBlock *mb,short *block_ptr, + uint flags) { + + register uint *dy = *datay; + register uint *du = *datau; + register uint *dv = *datav; + + /* Motion Vectors */ + short fmv[4]; + short bmv[4]; + /* gfxblock dword 1 */ + uint dw1[2]; + + uint y1size = y_first_field_bytes[mb->coded_block_pattern]; + uint y2size = y_second_field_bytes[mb->coded_block_pattern]; + uint usize = u_field_bytes[mb->coded_block_pattern]; + uint vsize = v_field_bytes[mb->coded_block_pattern]; + + uint xy = ((uint)mb->x<<20) | ((uint)mb->y<<3); + + dw1[0] = type_table[mb->macroblock_type & 0xf] | (0x2<<6) | + mvfs_table[mb->motion_vertical_field_select & 3] | + (((uint)mb->coded_block_pattern)<<22); + + dw1[1] = type_table[mb->macroblock_type & 0xf] | (0x3<<6) | + mvfs_table[mb->motion_vertical_field_select>>2] | + (((mb->coded_block_pattern & 0x3) | + ((mb->coded_block_pattern & 0xc)<<2))<<22); + + fmv[0] = mb->PMV[0][0][1]/2; + fmv[1] = mb->PMV[0][0][0]; + fmv[2] = mb->PMV[1][0][1]/2; + fmv[3] = mb->PMV[1][0][0]; + + bmv[0] = mb->PMV[0][1][1]/2; + bmv[1] = mb->PMV[0][1][0]; + bmv[2] = mb->PMV[1][1][1]/2; + bmv[3] = mb->PMV[1][1][0]; + + /* First Y Block */ + *dy++ = GFXBLOCK + 4 + (y1size>>2); + *dy++ = (1<<30) | (2<<28) | dw1[0]; + *dy++ = xy; + *dy++ = (8<<16) | 16; + *dy++ = *(uint *)&fmv[0]; + *dy++ = *(uint *)&bmv[0]; + PACK_CORR_DATA(dy,block_ptr,y1size); + block_ptr = (short *)((unsigned long)block_ptr + y1size); + + /* Second Y Block */ + *dy++ = GFXBLOCK + 4 + (y2size>>2); + *dy++ = (1<<30) | (2<<28) | dw1[1]; + *dy++ = xy; + *dy++ = (8<<16) | 16; + *dy++ = *(uint *)&fmv[2]; + *dy++ = *(uint *)&bmv[2]; + PACK_CORR_DATA(dy,block_ptr,y2size); + block_ptr = (short *)((unsigned long)block_ptr + y2size); + /* End Y Blocks */ + + fmv[0] /= 2; + fmv[1] /= 2; + fmv[2] /= 2; + fmv[3] /= 2; + + bmv[0] /= 2; + bmv[1] /= 2; + bmv[2] /= 2; + bmv[3] /= 2; + + xy >>= 1; + + /* U Blocks */ + *du++ = GFXBLOCK + 4 + (usize>>2); + *du++ = (2<<30) | (1<<28) | dw1[0]; + *du++ = xy; + *du++ = (4<<16) | 8; + *du++ = *(uint *)&fmv[0]; + *du++ = *(uint *)&bmv[0]; + if(usize) { + PACK_CORR_DATA_SHORT(du,block_ptr); + } + + /* Second U Block */ + *du++ = GFXBLOCK + 4 + (usize>>2); + *du++ = (2<<30) | (1<<28) | dw1[1]; + *du++ = xy; + *du++ = (4<<16) | 8; + *du++ = *(uint *)&fmv[2]; + *du++ = *(uint *)&bmv[2]; + if(usize) { + block_ptr = (short *)((unsigned long)block_ptr + 16); + PACK_CORR_DATA_SHORT(du,block_ptr); + block_ptr = (short *)((unsigned long)block_ptr + 112); + } + /* End U Blocks */ + + /* V Blocks */ + *dv++ = GFXBLOCK + 4 + (vsize>>2); + *dv++ = (3<<30) | (1<<28) | dw1[0]; + *dv++ = xy; + *dv++ = (4<<16) | 8; + *dv++ = *(uint *)&fmv[0]; + *dv++ = *(uint *)&bmv[0]; + if(vsize) { + PACK_CORR_DATA_SHORT(dv,block_ptr); + } + + /* Second V Block */ + *dv++ = GFXBLOCK + 4 + (vsize>>2); + *dv++ = (3<<30) | (1<<28) | dw1[1]; + *dv++ = xy; + *dv++ = (4<<16) | 8; + *dv++ = *(uint *)&fmv[2]; + *dv++ = *(uint *)&bmv[2]; + if(vsize) { + block_ptr = (short *)((unsigned long)block_ptr + 16); + PACK_CORR_DATA_SHORT(dv,block_ptr); + block_ptr = (short *)((unsigned long)block_ptr + 112); + } + /* End V Blocks */ + + *datay = dy; + *datau = du; + *datav = dv; +} + +/*************************************************************************** +// Function: renderFieldinFrameDCT0 +// Description: inline function that sets hardware parameters for a Field +// encoded macroblock in a frame picture with DCT0. +***************************************************************************/ +static __inline__ void renderFieldinFrameDCT0(uint **datay,uint **datau, + uint **datav,XvMCMacroBlock *mb, + short *block_ptr,uint flags) { + + register uint *dy = *datay; + register uint *du = *datau; + register uint *dv = *datav; + + /* Motion Vectors */ + short fmv[4]; + short bmv[4]; + /* CBP */ + uint cbp = (uint)mb->coded_block_pattern; + /* gfxblock dword 1 */ + uint dw1[2]; + + short * top_left_b = NULL; + short * top_right_b = NULL; + short * bottom_left_b = NULL; + short * bottom_right_b = NULL; + + unsigned int ysize = y_dct0_field_bytes[cbp]; + unsigned int usize = u_field_bytes[cbp]; + unsigned int vsize = v_field_bytes[cbp]; + + uint xy = ((uint)mb->x<<20) | ((uint)mb->y<<3); + + dw1[0] = type_table[mb->macroblock_type & 0xf] | (0x2<<6) | + mvfs_table[mb->motion_vertical_field_select & 3] | + ((cbp | ((cbp<<2) & 0x30))<<22); + + dw1[1] = type_table[mb->macroblock_type & 0xf] | (0x3<<6) | + mvfs_table[mb->motion_vertical_field_select>>2] | + ((cbp | ((cbp<<2) & 0x30))<<22); + + + fmv[0] = mb->PMV[0][0][1]/2; + fmv[1] = mb->PMV[0][0][0]; + fmv[2] = mb->PMV[1][0][1]/2; + fmv[3] = mb->PMV[1][0][0]; + + bmv[0] = mb->PMV[0][1][1]/2; + bmv[1] = mb->PMV[0][1][0]; + bmv[2] = mb->PMV[1][1][1]/2; + bmv[3] = mb->PMV[1][1][0]; + + /* + The i810 cannot use DCT0 directly with field motion, we have to + interlace the data for it. We use a zero block when the CBP has + one half of the to-be-interlaced data but not the other half. + */ + top_left_b = &empty_block[0]; + if(cbp & 0x20) { + top_left_b = block_ptr; + block_ptr += 64; + } + + top_right_b = &empty_block[0]; + if(cbp & 0x10) { + top_right_b = block_ptr; + block_ptr += 64; + } + + bottom_left_b = &empty_block[0]; + if(cbp & 0x8) { + bottom_left_b = block_ptr; + block_ptr += 64; + } + + bottom_right_b = &empty_block[0]; + if(cbp & 0x4) { + bottom_right_b = block_ptr; + block_ptr += 64; + } + + /* First Y Block */ + *dy++ = GFXBLOCK + 4 + (ysize>>2); + *dy++ = (1<<30) | (2<<28) | dw1[0]; + *dy++ = xy; + *dy++ = (8<<16) | 16; + *dy++ = *(uint *)&fmv[0]; + *dy++ = *(uint *)&bmv[0]; + if(dw1[0] & (1<<27)) { + PACK_CORR_DATA_0to1(dy,top_left_b,bottom_left_b); + } + if(dw1[0] & (1<<26)) { + PACK_CORR_DATA_0to1(dy,top_right_b,bottom_right_b); + } + + /* Second Y Block */ + *dy++ = GFXBLOCK + 4 + (ysize>>2); + *dy++ = (1<<30) | (2<<28) | dw1[1]; + *dy++ = xy; + *dy++ = (8<<16) | 16; + *dy++ = *(uint *)&fmv[2]; + *dy++ = *(uint *)&bmv[2]; + if(dw1[1] & (1<<27)) { + top_left_b = (short *)((unsigned long)top_left_b + 16); + bottom_left_b = (short *)((unsigned long)bottom_left_b + 16); + PACK_CORR_DATA_0to1(dy,top_left_b,bottom_left_b); + } + if(dw1[1] & (1<<26)) { + top_right_b = (short *)((unsigned long)top_right_b + 16); + bottom_right_b = (short *)((unsigned long)bottom_right_b + 16); + PACK_CORR_DATA_0to1(dy,top_right_b,bottom_right_b); + } + /* End Y Blocks */ + + fmv[0] /= 2; + fmv[1] /= 2; + fmv[2] /= 2; + fmv[3] /= 2; + + bmv[0] /= 2; + bmv[1] /= 2; + bmv[2] /= 2; + bmv[3] /= 2; + + xy >>= 1; + + /* U Blocks */ + *du++ = GFXBLOCK + 4 + (usize>>2); + *du++ = (2<<30) | (1<<28) | dw1[0]; + *du++ = xy; + *du++ = (4<<16) | 8; + *du++ = *(uint *)&fmv[0]; + *du++ = *(uint *)&bmv[0]; + if(usize) { + PACK_CORR_DATA_SHORT(du,block_ptr); + } + + /* Second U Block */ + *du++ = GFXBLOCK + 4 + (usize>>2); + *du++ = (2<<30) | (1<<28) | dw1[1]; + *du++ = xy; + *du++ = (4<<16) | 8; + *du++ = *(uint *)&fmv[2]; + *du++ = *(uint *)&bmv[2]; + if(usize) { + block_ptr = (short *)((unsigned long)block_ptr + 16); + PACK_CORR_DATA_SHORT(du,block_ptr); + block_ptr = (short *)((unsigned long)block_ptr + 112); + } + /* End U Blocks */ + + /* V Blocks */ + *dv++ = GFXBLOCK + 4 + (vsize>>2); + *dv++ = (3<<30) | (1<<28) | dw1[0]; + *dv++ = xy; + *dv++ = (4<<16) | 8; + *dv++ = *(uint *)&fmv[0]; + *dv++ = *(uint *)&bmv[0]; + if(vsize) { + PACK_CORR_DATA_SHORT(dv,block_ptr); + } + + /* Second V Block */ + *dv++ = GFXBLOCK + 4 + (vsize>>2); + *dv++ = (3<<30) | (1<<28) | dw1[1]; + *dv++ = xy; + *dv++ = (4<<16) | 8; + *dv++ = *(uint *)&fmv[2]; + *dv++ = *(uint *)&bmv[2]; + if(vsize) { + block_ptr = (short *)((unsigned long)block_ptr + 16); + PACK_CORR_DATA_SHORT(dv,block_ptr); + block_ptr = (short *)((unsigned long)block_ptr + 112); + } + /* End V Blocks */ + + *datay = dy; + *datau = du; + *datav = dv; +} + +/*************************************************************************** +// Function: renderFrameinFrame +// Description: inline function that sets hardware parameters for a Frame +// encoded macroblock in a frame picture. +***************************************************************************/ +static __inline__ void renderFrameinFrame(uint **datay,uint **datau, + uint **datav, + XvMCMacroBlock *mb,short *block_ptr, + uint flags) { + + register uint *dy = *datay; + register uint *du = *datau; + register uint *dv = *datav; + + /* Motion Vectors */ + short fmv[2]; + short bmv[2]; + /* gfxblock dword 1 */ + uint dw1; + + unsigned int ysize = y_frame_bytes[mb->coded_block_pattern]; + unsigned int usize = u_frame_bytes[mb->coded_block_pattern]; + unsigned int vsize = v_frame_bytes[mb->coded_block_pattern]; + + uint xy = ((uint)mb->x<<20) | ((uint)mb->y<<4); + + dw1 = type_table[mb->macroblock_type & 0xf] | + (((uint)mb->coded_block_pattern)<<22); + + + fmv[0] = mb->PMV[0][0][1]; + fmv[1] = mb->PMV[0][0][0]; + + bmv[0] = mb->PMV[0][1][1]; + bmv[1] = mb->PMV[0][1][0]; + + /* Y Block */ + *dy++ = GFXBLOCK + 4 + (ysize>>2); + *dy++ = (1<<30) | (3<<28) | dw1; + *dy++ = xy; + *dy++ = (16<<16) | 16; + *dy++ = *(uint *)fmv; + *dy++ = *(uint *)bmv; + PACK_CORR_DATA(dy,block_ptr,ysize); + block_ptr = (short *)((unsigned long)block_ptr + ysize); + /* End Y Blocks */ + + fmv[0] /= 2; + fmv[1] /= 2; + + bmv[0] /= 2; + bmv[1] /= 2; + + xy >>= 1; + + /* U Block */ + *du++ = GFXBLOCK + 4 + (usize>>2); + *du++ = (2<<30) | (1<<28) | dw1; + *du++ = xy; + *du++ = (8<<16) | 8; + *du++ = *(uint *)fmv; + *du++ = *(uint *)bmv; + PACK_CORR_DATA(du,block_ptr,usize); + block_ptr = (short *)((unsigned long)block_ptr + usize); + /* End U Block */ + + /* V Block */ + *dv++ = GFXBLOCK + 4 + (vsize>>2); + *dv++ = (3<<30) | (1<<28) | dw1; + *dv++ = xy; + *dv++ = (8<<16) | 8; + *dv++ = *(uint *)fmv; + *dv++ = *(uint *)bmv; + PACK_CORR_DATA(dv,block_ptr,vsize); + block_ptr = (short *)((unsigned long)block_ptr + vsize); + /* End V Block */ + + *datay = dy; + *datau = du; + *datav = dv; +} + +/*************************************************************************** +// Function: renderFrameinFrameDCT1 +// Description: inline function that sets hardware parameters for a Frame +// encoded macroblock in a frame picture with DCT type 1. +***************************************************************************/ +static __inline__ void renderFrameinFrameDCT1(uint **datay,uint **datau, + uint **datav,XvMCMacroBlock *mb, + short *block_ptr,uint flags) { + + register uint *dy = *datay; + register uint *du = *datau; + register uint *dv = *datav; + + /* Motion Vectors */ + short fmv[4]; + short bmv[4]; + + short * top_left_b = NULL; + short * top_right_b = NULL; + short * bottom_left_b = NULL; + short * bottom_right_b = NULL; + + uint temp_bp = 0; + + uint ysize = y_dct1_frame_bytes[mb->coded_block_pattern]; + uint usize = u_frame_bytes[mb->coded_block_pattern]; + uint vsize = v_frame_bytes[mb->coded_block_pattern]; + + uint xy = ((uint)mb->x<<20) | ((uint)mb->y<<4); + + uint dw1 = type_table[mb->macroblock_type & 0xf] | + (((uint)mb->coded_block_pattern)<<22); + + fmv[0] = mb->PMV[0][0][1]; + fmv[1] = mb->PMV[0][0][0]; + + bmv[0] = mb->PMV[0][1][1]; + bmv[1] = mb->PMV[0][1][0]; + + /* + It is easiest to find out what blocks are in need of reading first + rather than as we go. + */ + top_left_b = &empty_block[0]; + if(dw1 & (1<<27)) { + temp_bp |= (1<<25); + top_left_b = block_ptr; + block_ptr += 64; + } + + top_right_b = &empty_block[0]; + if(dw1 & (1<<26)) { + temp_bp |= (1<<24); + top_right_b = block_ptr; + block_ptr += 64; + } + + bottom_left_b = &empty_block[0]; + if(dw1 & (1<<25)) { + temp_bp |= (1<<27); + bottom_left_b = block_ptr; + block_ptr += 64; + } + + bottom_right_b = &empty_block[0]; + if(dw1 & (1<<24)) { + temp_bp |= (1<<26); + bottom_right_b = block_ptr; + block_ptr += 64; + } + dw1 |= temp_bp; + + /* Y Block */ + *dy++ = GFXBLOCK + 4 + (ysize>>2); + *dy++ = (1<<30) | (3<<28) | dw1; + *dy++ = xy; + *dy++ = (16<<16) | 16; + *dy++ = *(uint *)fmv; + *dy++ = *(uint *)bmv; + if(dw1 & (1<<27)) { + PACK_CORR_DATA_1to0(dy,top_left_b,bottom_left_b); + top_left_b = (short *)((unsigned long)top_left_b + 64); + bottom_left_b = (short *)((unsigned long)bottom_left_b + 64); + } + if(dw1 & (1<<26)) { + PACK_CORR_DATA_1to0(dy,top_right_b,bottom_right_b); + top_right_b = (short *)((unsigned long)top_right_b + 64); + bottom_right_b = (short *)((unsigned long)bottom_right_b + 64); + } + if(dw1 & (1<<27)) { + PACK_CORR_DATA_1to0(dy,top_left_b,bottom_left_b); + } + if(dw1 & (1<<26)) { + PACK_CORR_DATA_1to0(dy,top_right_b,bottom_right_b); + } + /* End Y Block */ + + fmv[0] /= 2; + fmv[1] /= 2; + + bmv[0] /= 2; + bmv[1] /= 2; + + xy >>= 1; + + /* U Block */ + *du++ = GFXBLOCK + 4 + (usize>>2); + *du++ = (2<<30) | (1<<28) | dw1; + *du++ = xy; + *du++ = (8<<16) | 8; + *du++ = *(uint *)fmv; + *du++ = *(uint *)bmv; + PACK_CORR_DATA(du,block_ptr,usize); + block_ptr = (short *)((unsigned long)block_ptr + usize); + + /* V Block */ + *dv++ = GFXBLOCK + 4 + (vsize>>2); + *dv++ = (3<<30) | (1<<28) | dw1; + *dv++ = xy; + *dv++ = (8<<16) | 8; + *dv++ = *(uint *)fmv; + *dv++ = *(uint *)bmv; + PACK_CORR_DATA(dv,block_ptr,vsize); + block_ptr = (short *)((unsigned long)block_ptr + vsize); + + *datay = dy; + *datau = du; + *datav = dv; +} + +/*************************************************************************** +// Function: renderDualPrimeinFrame +// Description: inline function that sets hardware parameters for a Dual +// Prime encoded macroblock in a frame picture with dct 1. +***************************************************************************/ +static __inline__ void renderDualPrimeinFrame(uint **datay,uint **datau, + uint **datav,XvMCMacroBlock *mb, + short *block_ptr,uint flags) { + + register uint *dy = *datay; + register uint *du = *datau; + register uint *dv = *datav; + + /* Motion Vectors */ + short fmv[4]; + short bmv[4]; + /* gfxblock dword 1 */ + uint dw1[2]; + + uint y1size = y_first_field_bytes[mb->coded_block_pattern]; + uint y2size = y_second_field_bytes[mb->coded_block_pattern]; + uint usize = u_field_bytes[mb->coded_block_pattern]; + uint vsize = v_field_bytes[mb->coded_block_pattern]; + + uint xy = ((uint)mb->x<<20) | ((uint)mb->y<<3); + + /* + Past Surface (map 0) is used for same parity prediction, + Future surface (map 1) is used for opposite. + */ + dw1[0] = (((uint)mb->coded_block_pattern)<<22) | + 3<<12 | 2<<6 | 2<<3 | 3; + dw1[1] = (((mb->coded_block_pattern & 0x3) | + ((mb->coded_block_pattern & 0xc)<<2))<<22) | + 3<<12 | 3<<6 | 3<<3 | 2; + + fmv[0] = mb->PMV[0][0][1]; + fmv[1] = mb->PMV[0][0][0]; + bmv[0] = mb->PMV[1][0][1]; + bmv[1] = mb->PMV[1][0][0]; + + fmv[2] = mb->PMV[0][0][1]; + fmv[3] = mb->PMV[0][0][0]; + bmv[2] = mb->PMV[1][1][1]; + bmv[3] = mb->PMV[1][1][0]; + + /* First Y Block */ + *dy++ = GFXBLOCK + 4 + (y1size>>2); + *dy++ = (1<<30) | (2<<28) | dw1[0]; + *dy++ = xy; + *dy++ = (8<<16) | 16; + *dy++ = *(uint *)fmv; + *dy++ = *(uint *)bmv;; + PACK_CORR_DATA(dy,block_ptr,y1size); + block_ptr = (short *)((unsigned long)block_ptr + y1size); + + /* Second Y Block */ + *dy++ = GFXBLOCK + 4 + (y2size>>2); + *dy++ = (1<<30) | (2<<28) | dw1[1]; + *dy++ = xy; + *dy++ = (8<<16) | 16; + *dy++ = *(uint *)&fmv[2]; + *dy++ = *(uint *)&bmv[2]; + PACK_CORR_DATA(dy,block_ptr,y2size); + block_ptr = (short *)((unsigned long)block_ptr + y2size); + + fmv[0] /= 2; + fmv[1] /= 2; + bmv[0] /= 2; + bmv[1] /= 2; + + fmv[2] /= 2; + fmv[3] /= 2; + bmv[2] /= 2; + bmv[3] /= 2; + + xy >>= 1; + + /* U Blocks */ + *du++ = GFXBLOCK + 4 + (usize>>2); + *du++ = (2<<30) | (1<<28) | dw1[0]; + *du++ = xy; + *du++ = (4<<16) | 8; + *du++ = *(uint *)fmv; + *du++ = *(uint *)bmv; + if(dw1[0] & (1<<23)) { + PACK_CORR_DATA_SHORT(du,block_ptr); + } + + /* Second U Block */ + *du++ = GFXBLOCK + 4 + (usize>>2); + *du++ = (2<<30) | (1<<28) | dw1[1]; + *du++ = xy; + *du++ = (4<<16) | 8; + *du++ = *(uint *)&fmv[2]; + *du++ = *(uint *)&bmv[2]; + if(dw1[1] & (1<<23)) { + block_ptr = (short *)((unsigned long)block_ptr + 16); + PACK_CORR_DATA_SHORT(du,block_ptr); + block_ptr = (short *)((unsigned long)block_ptr + 112); + } + /* End U Blocks */ + + /* V Blocks */ + *dv++ = GFXBLOCK + 4 + (vsize>>2); + *dv++ = (3<<30) | (1<<28) | dw1[0]; + *dv++ = xy; + *dv++ = (4<<16) | 8; + *dv++ = *(uint *)fmv; + *dv++ = *(uint *)bmv; + if(dw1[0] & (1<<22)) { + PACK_CORR_DATA_SHORT(dv,block_ptr); + } + + /* Second V Block */ + *dv++ = GFXBLOCK + 4 + (vsize>>2); + *dv++ = (3<<30) | (1<<28) | dw1[1]; + *dv++ = xy; + *dv++ = (4<<16) | 8; + *dv++ = *(uint *)&fmv[2]; + *dv++ = *(uint *)&bmv[2]; + if(dw1[1] & (1<<22)) { + block_ptr = (short *)((unsigned long)block_ptr + 16); + PACK_CORR_DATA_SHORT(dv,block_ptr); + block_ptr = (short *)((unsigned long)block_ptr + 112); + } + /* End V Blocks */ + + *datay = dy; + *datau = du; + *datav = dv; +} + +/*************************************************************************** +// Function: renderDualPrimeinFrameDCT0 +// Description: inline function that sets hardware parameters for a Dual +// Prime encoded macroblock in a frame picture with dct 0. +***************************************************************************/ +static __inline__ void renderDualPrimeinFrameDCT0(uint **datay,uint **datau, + uint **datav, + XvMCMacroBlock *mb, + short *block_ptr, + uint flags) { + + register uint *dy = *datay; + register uint *du = *datau; + register uint *dv = *datav; + + /* Motion Vectors */ + short fmv[4]; + short bmv[4]; + /* gfxblock dword 1 */ + uint dw1[2]; + + short * top_left_b = NULL; + short * top_right_b = NULL; + short * bottom_left_b = NULL; + short * bottom_right_b = NULL; + + uint cbp = (uint)mb->coded_block_pattern; + + uint ysize = y_dct0_field_bytes[cbp]; + uint usize = u_field_bytes[cbp]; + uint vsize = v_field_bytes[cbp]; + + uint xy = ((uint)mb->x<<20) | ((uint)mb->y<<3); + + /* + Past Surface (map 0) is used for same parity prediction, + Future surface (map 1) is used for opposite. + */ + dw1[0] = ((cbp | ((cbp<<2) & 0x30))<<22) | + 3<<12 | 2<<6 | 2<<3 | 3; + dw1[1] = ((cbp | ((cbp<<2) & 0x30))<<22) | + 3<<12 | 3<<6 | 3<<3 | 2; + + fmv[0] = mb->PMV[0][0][1]; + fmv[1] = mb->PMV[0][0][0]; + bmv[0] = mb->PMV[1][0][1]; + bmv[1] = mb->PMV[1][0][0]; + + fmv[2] = mb->PMV[0][0][1]; + fmv[3] = mb->PMV[0][0][0]; + bmv[2] = mb->PMV[1][1][1]; + bmv[3] = mb->PMV[1][1][0]; + + /* + The i810 cannot use DCT0 directly with field motion, we have to + interlace the data for it. We use a zero block when the CBP has + one half of the to-be-interlaced data but not the other half. + */ + top_left_b = &empty_block[0]; + if(cbp & 0x20) { + top_left_b = block_ptr; + block_ptr += 64; + } + + top_right_b = &empty_block[0]; + if(cbp & 0x10) { + top_right_b = block_ptr; + block_ptr += 64; + } + + bottom_left_b = &empty_block[0]; + if(cbp & 0x8) { + bottom_left_b = block_ptr; + block_ptr += 64; + } + + bottom_right_b = &empty_block[0]; + if(cbp & 0x4) { + bottom_right_b = block_ptr; + block_ptr += 64; + } + + /* First Y Block */ + *dy++ = GFXBLOCK + 4 + (ysize>>2); + *dy++ = (1<<30) | (2<<28) | dw1[0]; + *dy++ = xy; + *dy++ = (8<<16) | 16; + *dy++ = *(uint *)fmv; + *dy++ = *(uint *)bmv; + if(cbp & 0x20) { + PACK_CORR_DATA_0to1(dy,top_left_b,bottom_left_b); + } + if(cbp & 0x10) { + PACK_CORR_DATA_0to1(dy,top_right_b,bottom_right_b); + } + + /* Second Y Block */ + *dy++ = GFXBLOCK + 4 + (ysize>>2); + *dy++ = (1<<30) | (2<<28) | dw1[1]; + *dy++ = xy; + *dy++ = (8<<16) | 16; + *dy++ = *(uint *)&fmv[2]; + *dy++ = *(uint *)&bmv[2]; + if(cbp & 0x20) { + top_left_b = (short *)((unsigned long)top_left_b + 16); + bottom_left_b = (short *)((unsigned long)bottom_left_b + 16); + PACK_CORR_DATA_0to1(dy,top_left_b,bottom_left_b); + } + if(cbp & 0x10) { + top_right_b = (short *)((unsigned long)top_right_b + 16); + bottom_right_b = (short *)((unsigned long)bottom_right_b + 16); + PACK_CORR_DATA_0to1(dy,top_right_b,bottom_right_b); + } + /* End Y Blocks */ + + + fmv[0] /= 2; + fmv[1] /= 2; + bmv[0] /= 2; + bmv[1] /= 2; + + fmv[2] /= 2; + fmv[3] /= 2; + bmv[2] /= 2; + bmv[3] /= 2; + + xy >>= 1; + + /* U Blocks */ + *du++ = GFXBLOCK + 4 + (usize>>2); + *du++ = (2<<30) | (1<<28) | dw1[0]; + *du++ = xy; + *du++ = (4<<16) | 8; + *du++ = *(uint *)fmv; + *du++ = *(uint *)bmv; + if(cbp & (1<<23)) { + PACK_CORR_DATA_SHORT(du,block_ptr); + } + + /* Second U Block */ + *du++ = GFXBLOCK + 4 + (usize>>2); + *du++ = (2<<30) | (1<<28) | dw1[1]; + *du++ = xy; + *du++ = (4<<16) | 8; + *du++ = *(uint *)&fmv[2]; + *du++ = *(uint *)&bmv[2]; + if(cbp & (1<<23)) { + block_ptr = (short *)((unsigned long)block_ptr + 16); + PACK_CORR_DATA_SHORT(du,block_ptr); + block_ptr = (short *)((unsigned long)block_ptr + 112); + } + /* End U Blocks */ + + /* V Blocks */ + *dv++ = GFXBLOCK + 4 + (vsize>>2); + *dv++ = (3<<30) | (1<<28) | dw1[0]; + *dv++ = xy; + *dv++ = (4<<16) | 8; + *dv++ = *(uint *)fmv; + *dv++ = *(uint *)bmv; + if(cbp & (1<<22)) { + PACK_CORR_DATA_SHORT(dv,block_ptr); + } + + /* Second V Block */ + *dv++ = GFXBLOCK + 4 + (vsize>>2); + *dv++ = (3<<30) | (1<<28) | dw1[1]; + *dv++ = xy; + *dv++ = (4<<16) | 8; + *dv++ = *(uint *)&fmv[2]; + *dv++ = *(uint *)&bmv[2]; + if(cbp & (1<<22)) { + block_ptr = (short *)((unsigned long)block_ptr + 16); + PACK_CORR_DATA_SHORT(dv,block_ptr); + block_ptr = (short *)((unsigned long)block_ptr + 112); + } + /* End V Blocks */ + + *datay = dy; + *datau = du; + *datav = dv; +} + + +/*************************************************************************** +// Function: XvMCRenderSurface +// Description: This function does the actual HWMC. Given a list of +// macroblock structures it dispatched the hardware commands to execute +// them. DMA buffer containing Y data are dispatched as they fill up +// U and V DMA buffers are queued until all Y's are done. This minimizes +// the context flipping and flushing required when switching between Y +// U and V surfaces. +***************************************************************************/ +#define UV_QUEUE 14 +Status XvMCRenderSurface(Display *display, XvMCContext *context, + unsigned int picture_structure, + XvMCSurface *target_surface, + XvMCSurface *past_surface, + XvMCSurface *future_surface, + unsigned int flags, + unsigned int num_macroblocks, + unsigned int first_macroblock, + XvMCMacroBlockArray *macroblock_array, + XvMCBlockArray *blocks) { + /* Dma Data Structures */ + drmBufPtr pDMAy = NULL,pDMAu[UV_QUEUE],pDMAv[UV_QUEUE]; + int u_index = 0,v_index = 0; + int dirty_context = 1; + + /* Block Pointer */ + short *block_ptr; + /* Current Macroblock Pointer */ + XvMCMacroBlock *mb; + + drm_i810_mc_t mc; + int i,j; + i810XvMCSurface *privTarget; + i810XvMCSurface *privFuture = NULL; + i810XvMCSurface *privPast = NULL; + i810XvMCContext *pI810XvMC; + + /* DMA Pointers set to NULL */ + uint *datay = NULL; + uint *datau = NULL; + uint *datav = NULL; + + + /* Check Parameters for validity */ + if((target_surface == NULL) || (context == NULL) || (display == NULL)) { + printf("Error, Invalid Target,Context, or DIsplay!\n"); + return BadValue; + } + + if(num_macroblocks == 0) {return Success;} + if((macroblock_array == NULL) || (blocks == NULL)) {return BadValue;} + if(context->privData == NULL) {return BadValue;} + pI810XvMC = (i810XvMCContext *)context->privData; + + + if(target_surface->privData == NULL) { + printf("Error, Invalid Target Surface!\n"); + return BadValue; + } + privTarget = (i810XvMCSurface *)target_surface->privData; + + if(macroblock_array->num_blocks < (num_macroblocks + first_macroblock)) { + printf("Error, Too many macroblocks requested for MB array size.\n"); + return BadValue; + } + + /* Test For YV12 Surface */ + if(context->surface_type_id != FOURCC_YV12) { + printf("Error, HWMC only possible on YV12 Surfaces\n"); + return BadValue; + } + + /* P Frame Test */ + if(past_surface == NULL) { + /* Just to avoid some ifs later. */ + privPast = privTarget; + } + else { + if(past_surface->privData == NULL) { + printf("Error, Invalid Past Surface!\n"); + return BadValue; + } + privPast = (i810XvMCSurface *)past_surface->privData; + } + + + /* B Frame Test */ + if(future_surface == NULL) { + privFuture = privTarget; + if(pI810XvMC->dual_prime) { + privFuture = privPast; + /* I810 Specific flag for marking when dual prime is in use. */ + flags |= 0x40000000; + } + + /* + References are different for the Second Field Picture. The + i810 needs to know if it is the second field picture in a + P picture. We use a Private flag to mark this. + */ + if(flags & XVMC_SECOND_FIELD) { + /* I810 Specific flag for marking second fields. */ + flags |= 0x80000000; + } + } + else { + if((future_surface->privData == NULL) || (past_surface == NULL)) { + printf("Error, Invalid Future Surface or No Past Surface!\n"); + return BadValue; + } + privFuture = (i810XvMCSurface *)future_surface->privData; + + /* + Undo Second Field flag since the second field in B frames is just like + the first. + */ + flags &= ~0x80000000; + } + + /* Lock For DMA */ + I810_LOCK(pI810XvMC,0); + + for(i=first_macroblock; i<(num_macroblocks + first_macroblock); i++) { + /* Set up values needed for each macroblock */ + mb = ¯oblock_array->macro_blocks[i]; + block_ptr = &(blocks->blocks[mb->index<<6]); + + /* Lockup can happen if the coordinates are too far out of range */ + if(mb->x > target_surface->width>>4) { + mb->x = 0; + } + if(mb->y > target_surface->height>>4) { + mb->y = 0; + } + + /* If buffers are almost full dispatch them */ + if(datay) { + pDMAy->used = (unsigned long)datay - (unsigned long)pDMAy->address; + if(pDMAy->used > 3520) { + if(dirty_context) { + dispatchYContext(privTarget,privPast,privFuture,pI810XvMC); + } + dirty_context = 0; + mc.idx = pDMAy->idx; + mc.used = pDMAy->used; + datay = NULL; + mc.last_render = ++pI810XvMC->last_render; + privTarget->last_render = pI810XvMC->last_render; + I810_MC(pI810XvMC,mc); + } /* datay near full */ + } /* if(datay) */ + if(datau) { + pDMAu[u_index]->used = (unsigned long)datau - (unsigned long)pDMAu[u_index]->address; + if(pDMAu[u_index]->used > 3904) { + u_index++; + datau = NULL; + if(u_index == UV_QUEUE) { + for(j=0; j<UV_QUEUE; j++) { + mc.idx = pDMAu[j]->idx; + mc.used = pDMAu[j]->used; + mc.last_render = ++pI810XvMC->last_render; + privTarget->last_render = pI810XvMC->last_render; + I810_MC(pI810XvMC,mc); + } + u_index = 0; + dirty_context = 1; + } /* if(u_index == UV_QUEUE) */ + } /* datau near full */ + } /* if(datau) */ + if(datav) { + pDMAv[v_index]->used = (unsigned long)datav - (unsigned long)pDMAv[v_index]->address; + if(pDMAv[v_index]->used > 3904) { + v_index++; + datav = NULL; + if(v_index == UV_QUEUE) { + for(j=0; j<UV_QUEUE; j++) { + mc.idx = pDMAv[j]->idx; + mc.used = pDMAv[j]->used; + mc.last_render = ++pI810XvMC->last_render; + privTarget->last_render = pI810XvMC->last_render; + I810_MC(pI810XvMC,mc); + } + v_index = 0; + dirty_context = 1; + } /* if(v_index == UV_QUEUE) */ + } /* datav near full */ + } /* if(datav) */ + + /* Allocate buffers if this is the first loop,or if we just dispatched */ + if(datay == NULL) { + pDMAy = i810_get_free_buffer(pI810XvMC); + datay = pDMAy->address; + }/* if(datay == NULL) */ + if(datau == NULL) { + pDMAu[u_index] = i810_get_free_buffer(pI810XvMC); + datau = pDMAu[u_index]->address; + if(u_index == 0) { + *datau++ = CMD_FLUSH; + *datau++ = BOOLEAN_ENA_2; + *datau++ = CMD_FLUSH; + *datau++ = DEST_BUFFER_INFO; + *datau++ = privTarget->dbi1u; + *datau++ = DEST_BUFFER_VAR; + *datau++ = privTarget->dbv1; + /* Past Surface */ + *datau++ = CMD_MAP_INFO; + *datau++ = privPast->mi1u; + *datau++ = privPast->mi2u; + *datau++ = privPast->mi3u; + /* Future Surface */ + *datau++ = CMD_MAP_INFO; + *datau++ = privFuture->mi1u | 0x1<<28; + *datau++ = privFuture->mi2u; + *datau++ = privFuture->mi3u; + } + } /* if(datau == NULL) */ + if(datav == NULL) { + pDMAv[v_index] = i810_get_free_buffer(pI810XvMC); + datav = pDMAv[v_index]->address; + if(v_index == 0) { + *datav++ = CMD_FLUSH; + *datav++ = BOOLEAN_ENA_2; + *datav++ = CMD_FLUSH; + *datav++ = DEST_BUFFER_INFO; + *datav++ = privTarget->dbi1v; + *datav++ = DEST_BUFFER_VAR; + *datav++ = privTarget->dbv1; + /* Past Surface */ + *datav++ = CMD_MAP_INFO; + *datav++ = privPast->mi1v; + *datav++ = privPast->mi2v; + *datav++ = privPast->mi3v; + /* Future Surface */ + *datav++ = CMD_MAP_INFO; + *datav++ = privFuture->mi1v | 0x1<<28; + *datav++ = privFuture->mi2v; + *datav++ = privFuture->mi3v; + } + }/* if(datav == NULL) */ + + /* Catch no pattern case */ + if(!(mb->macroblock_type & 0x8)) { + mb->coded_block_pattern = 0; + } + + + if(mb->motion_type == XVMC_PREDICTION_DUAL_PRIME) { + /* + By default the maps will not be set up for dual + prime. We have to change them. + */ + if(!pI810XvMC->dual_prime) { + pI810XvMC->dual_prime = 1; + privFuture = privPast; + /* Y */ + *datay++ = CMD_MAP_INFO; + *datay++ = privFuture->mi1y | 0x1<<28; + *datay++ = privFuture->mi2y; + *datay++ = privFuture->mi3y; + /* U */ + *datau++ = CMD_MAP_INFO; + *datau++ = privFuture->mi1u | 0x1<<28; + *datau++ = privFuture->mi2u; + *datau++ = privFuture->mi3u; + /* V */ + *datav++ = CMD_MAP_INFO; + *datav++ = privFuture->mi1v | 0x1<<28; + *datav++ = privFuture->mi2v; + *datav++ = privFuture->mi3v; + } + } + if((pI810XvMC->dual_prime) && + (mb->motion_type != XVMC_PREDICTION_DUAL_PRIME)) { + pI810XvMC->dual_prime = 0; + privFuture = privTarget; + /* Y */ + *datay++ = CMD_MAP_INFO; + *datay++ = privFuture->mi1y | 0x1<<28; + *datay++ = privFuture->mi2y; + *datay++ = privFuture->mi3y; + /* U */ + *datau++ = CMD_MAP_INFO; + *datau++ = privFuture->mi1u | 0x1<<28; + *datau++ = privFuture->mi2u; + *datau++ = privFuture->mi3u; + /* V */ + *datav++ = CMD_MAP_INFO; + *datav++ = privFuture->mi1v | 0x1<<28; + *datav++ = privFuture->mi2v; + *datav++ = privFuture->mi3v; + } + + + /* Frame Picture */ + if((picture_structure & XVMC_FRAME_PICTURE) == XVMC_FRAME_PICTURE) { + /* Intra Blocks */ + if(mb->macroblock_type & XVMC_MB_TYPE_INTRA) { + if(mb->dct_type) { + renderIntrainFrameDCT1(&datay,&datau,&datav,mb,block_ptr,flags); + continue; + } + renderIntrainFrame(&datay,&datau,&datav,mb,block_ptr); + continue; + } + switch((mb->motion_type & 0x3) | (mb->dct_type<<2)) { + case 0x2: /* Frame DCT0 */ + renderFrameinFrame(&datay,&datau,&datav,mb,block_ptr,flags); + continue; + case 0x5: /* Field DCT1 */ + renderFieldinFrame(&datay,&datau,&datav,mb,block_ptr,flags); + continue; + case 0x6: /* Frame DCT1 */ + renderFrameinFrameDCT1(&datay,&datau,&datav,mb,block_ptr,flags); + continue; + case 0x1: /* Field DCT0 */ + renderFieldinFrameDCT0(&datay,&datau,&datav,mb,block_ptr,flags); + continue; + case 0x3: /* Dual Prime DCT0 */ + renderDualPrimeinFrame(&datay,&datau,&datav,mb,block_ptr,flags); + continue; + case 0x7: /* Dual Prime DCT1 */ + renderDualPrimeinFrameDCT0(&datay,&datau,&datav,mb,block_ptr,flags); + continue; + default: /* No Motion Type */ + renderError(); + continue; + } /* Switch */ + } /* Frame Picture */ + + /* Field Pictures */ + if(mb->macroblock_type & XVMC_MB_TYPE_INTRA) { + renderIntrainField(&datay,&datau,&datav,mb,block_ptr,picture_structure); + continue; + } + switch(mb->motion_type & 0x3) { + case 0x1: /* Field Motion */ + renderFieldinField(&datay,&datau,&datav,mb,block_ptr,picture_structure, + flags); + continue; + case 0x2: /* 16x8 Motion */ + render16x8inField(&datay,&datau,&datav,mb,block_ptr,picture_structure, + flags); + continue; + case 0x3: /* Dual Prime */ + renderDualPrimeinField(&datay,&datau,&datav,mb,block_ptr, + picture_structure,flags); + continue; + default: /* No Motion Type */ + renderError(); + continue; + } + continue; + + } /* for each Macroblock */ + + /* Dispatch remaining DMA buffers */ + if(dirty_context) { + dispatchYContext(privTarget,privPast,privFuture,pI810XvMC); + } + mc.idx = pDMAy->idx; + mc.used = (unsigned long)datay - (unsigned long)pDMAy->address; + mc.last_render = ++pI810XvMC->last_render; + privTarget->last_render = pI810XvMC->last_render; + I810_MC(pI810XvMC,mc); + + pDMAu[u_index]->used = (unsigned long)datau - (unsigned long)pDMAu[u_index]->address; + for(j=0; j<=u_index; j++) { + mc.idx = pDMAu[j]->idx; + mc.used = pDMAu[j]->used; + mc.last_render = ++pI810XvMC->last_render; + privTarget->last_render = pI810XvMC->last_render; + I810_MC(pI810XvMC,mc); + } + pDMAv[v_index]->used = (unsigned long)datav - (unsigned long)pDMAv[v_index]->address; + for(j=0; j<=v_index; j++) { + mc.idx = pDMAv[j]->idx; + mc.used = pDMAv[j]->used; + mc.last_render = ++pI810XvMC->last_render; + privTarget->last_render = pI810XvMC->last_render; + I810_MC(pI810XvMC,mc); + } + + I810_UNLOCK(pI810XvMC); + + return Success; +} + +/*************************************************************************** +// Function: XvMCPutSurface +// Description: +// Arguments: +// display: Connection to X server +// surface: Surface to be displayed +// draw: X Drawable on which to display the surface +// srcx: X coordinate of the top left corner of the region to be +// displayed within the surface. +// srcy: Y coordinate of the top left corner of the region to be +// displayed within the surface. +// srcw: Width of the region to be displayed. +// srch: Height of the region to be displayed. +// destx: X cordinate of the top left corner of the destination region +// in the drawable coordinates. +// desty: Y cordinate of the top left corner of the destination region +// in the drawable coordinates. +// destw: Width of the destination region. +// desth: Height of the destination region. +// flags: One or more of the following. +// XVMC_TOP_FIELD - Display only the Top field of the surface. +// XVMC_BOTTOM_FIELD - Display only the Bottom Field of the surface. +// XVMC_FRAME_PICTURE - Display both fields or frame. +// +// Info: Portions of this function derived from i810_video.c (XFree86) +// +// This function is organized so that we wait as long as possible before +// touching the overlay registers. Since we don't know that the last +// flip has happened yet we want to give the overlay as long as +// possible to catch up before we have to check on its progress. This +// makes it unlikely that we have to wait on the last flip. +***************************************************************************/ +Status XvMCPutSurface(Display *display,XvMCSurface *surface, + Drawable draw, short srcx, short srcy, + unsigned short srcw, unsigned short srch, + short destx, short desty, + unsigned short destw, unsigned short desth, + int flags) { + i810XvMCContext *pI810XvMC; + i810XvMCSurface *pI810Surface; + i810OverlayRecPtr pORegs; + unsigned int ysrc_offset,uvsrc_offset; + Box extents; + uint window_width,window_height; + unsigned int xscaleInt = 0,xscaleFract = 0,yscaleInt = 0,yscaleFract = 0; + unsigned int xscaleFractUV = 0,xscaleIntUV = 0,yscaleFractUV = 0; + unsigned int yscaleIntUV = 0,yPitch = 0,uvPitch = 0; + unsigned int ovcmd = 0; + uint d; + double xscale,yscale; + int diff; + int clipped_srcx, clipped_srcy, clipped_destx, clipped_desty; + int clipped_srcw, clipped_srch, clipped_destw, clipped_desth; + uint x1,y1,root_width,root_height; + int x2 = 0, y2 = 0,unused; + uint nChilds; + int stat; + Window win,root,parent,*pChilds; + + + if((display == NULL) || (surface == NULL)) { + return BadValue; + } + + if(surface->privData == NULL) { + return (error_base + XvMCBadSurface); + } + pI810Surface = (i810XvMCSurface *)surface->privData; + pI810XvMC = (i810XvMCContext *)pI810Surface->privContext; + pORegs = (i810OverlayRecPtr)pI810XvMC->oregs; + + + switch(surface->surface_type_id) { + case FOURCC_YV12: + case FOURCC_I420: + yPitch = (srcw + 7) & ~7; + uvPitch = ((srcw>>1) + 7) & ~7; + if((flags & XVMC_FRAME_PICTURE) != XVMC_FRAME_PICTURE) { + srch = srch>>1; + } + break; + case FOURCC_UYVY: + case FOURCC_YUY2: + default: + /* FIXME: Non Planar not fully implemented. */ + return BadValue; + yPitch = ((srcw + 7) & ~7) << 1; + break; + }/* switch(surface->surface_type_id) */ + + /* + FIXME: This should be using the DRI's clip rect but that isn't + all hooked up yet. This has some latency but we get by. + */ + win = draw; + XQueryTree(display,win,&root,&parent,&pChilds,&nChilds); + if(nChilds) XFree(pChilds); + XGetGeometry(display,win, &root, &x2, &y2, &window_width, + &window_height, &d, &d); + x1 = x2; + y1 = y2; + win = parent; + do { + XQueryTree(display,win,&root,&parent,&pChilds,&nChilds); + if(nChilds) XFree(pChilds); + XGetGeometry(display,win, &root, &x2, &y2, &d, &d, &d, &d); + x1 += x2; + y1 += y2; + win = parent; + }while(win != root); + XGetGeometry(display,root, &root, &unused, &unused, + &root_width, &root_height, &d, &d); + + /* Left edge of Video window clipped to screen */ + extents.x1 = 0; + if(x1 > extents.x1) { + extents.x1 = x1; + } + /* Right edge of Video window clipped to screen */ + extents.x2 = root_width; + if(extents.x2 > (x1 + window_width)) { + extents.x2 = x1 + window_width; + } + /* Top edge of Video window clipped to screen */ + extents.y1 = 0; + if(y1 > extents.y1) { + extents.y1 = y1; + } + /* Bottom edge of Video window clipped to screen */ + extents.y2 = root_height; + if(extents.y2 > (y1 + window_height)) { + extents.y2 = y1 + window_height; + } + + /* + Clipping is more difficult than is seems. We need to keep the + scaling factors even if the destination window needs to be clipped. + We clip the destination window first then apply a scaled version + to the source window. + */ + + /* Put destination coords in screen coords */ + destx += x1; + desty += y1; + + /* Scale factors requested */ + xscale = (double)srcw / (double)destw; + yscale = (double)srch / (double)desth; + + /* + If destination window needs to be clipped we actually adjust both + the src and dest window so as to keep the scaling that was requested + */ + clipped_srcx = srcx; + clipped_srcy = srcy; + clipped_destx = destx; + clipped_desty = desty; + clipped_srcw = srcw; + clipped_srch = srch; + clipped_destw = destw; + clipped_desth = desth; + + /* Clip to the source surface boundaries */ + if(clipped_srcx < 0) { + clipped_destx += (0 - clipped_srcx) / xscale; + clipped_srcw -= clipped_srcx; + clipped_destw -= clipped_srcx / xscale; + clipped_srcx = 0; + } + if((clipped_srcw + clipped_srcx) > surface->width) { + clipped_srcw = surface->width - clipped_srcx; + clipped_destw -= (clipped_srcw - srcw) / xscale; + } + if(clipped_srcy < 0) { + clipped_desty += (0 - clipped_srcy) / yscale; + clipped_srch -= clipped_srcy; + clipped_desth -= clipped_srcy / yscale; + clipped_srcy = 0; + } + if((clipped_srch + clipped_srcy) > surface->height) { + clipped_srch = surface->height - clipped_srcy; + clipped_desth -= (clipped_srch - srch) / yscale; + } + + /* Clip to the extents */ + if(clipped_destx < extents.x1) { + diff = extents.x1 - clipped_destx; + clipped_srcx += diff * xscale; + clipped_srcw -= diff * xscale; + clipped_destw -= diff; + clipped_destx = extents.x1; + } + + diff = (clipped_destx + clipped_destw) - extents.x2; + if(diff > 0) { + clipped_destw -= diff; + clipped_srcw -= diff * xscale; + } + + if(clipped_desty < extents.y1) { + diff = extents.y1 - clipped_desty; + clipped_srcy += diff * yscale; + clipped_srch -= diff * yscale; + clipped_desth -= diff; + clipped_desty = 0; + } + + diff = (clipped_desty + clipped_desth) - extents.y2; + if(diff > 0) { + clipped_desth -= diff; + clipped_srch -= diff * yscale; + } + + /* If the whole window is clipped turn off the overlay */ + if((clipped_destx + clipped_destw < extents.x1) || + (clipped_desty + clipped_desth < extents.y1) || + (clipped_destx > extents.x2) || + (clipped_desty > extents.y2)) { + return XvMCHideSurface(display, surface); + } + + /* + Adjust the source offset width and height according to the clipped + destination window. + */ + ysrc_offset = ((clipped_srcx + 1) & ~1) + + ((clipped_srcy + 1) & ~1) * (1<<pI810Surface->pitch); + uvsrc_offset = (clipped_srcx>>1) + + (clipped_srcy>>1) * (1<<(pI810Surface->pitch - 1)); + + /* + Initially, YCbCr and Overlay Enable and + vertical chrominance up interpolation and horozontal chrominance + up interpolation + */ + ovcmd = VC_UP_INTERPOLATION | HC_UP_INTERPOLATION | + Y_ADJUST | OVERLAY_ENABLE; + + if ((clipped_destw != clipped_srcw) || + (clipped_desth != clipped_srch)) { + xscaleInt = (clipped_srcw / clipped_destw) & 0x3; + xscaleFract = (clipped_srcw << 12) / clipped_destw; + yscaleInt = (clipped_srch / clipped_desth) & 0x3; + yscaleFract = (clipped_srch << 12) / clipped_desth; + + if (clipped_destw > clipped_srcw) { + /* horizontal up-scaling */ + ovcmd &= ~HORIZONTAL_CHROMINANCE_FILTER; + ovcmd &= ~HORIZONTAL_LUMINANCE_FILTER; + ovcmd |= (HC_UP_INTERPOLATION | HL_UP_INTERPOLATION); + } + + if (clipped_desth > clipped_srch) { + /* vertical up-scaling */ + ovcmd &= ~VERTICAL_CHROMINANCE_FILTER; + ovcmd &= ~VERTICAL_LUMINANCE_FILTER; + ovcmd |= (VC_UP_INTERPOLATION | VL_UP_INTERPOLATION); + } + + if (clipped_destw < clipped_srcw) { + /* horizontal down-scaling */ + ovcmd &= ~HORIZONTAL_CHROMINANCE_FILTER; + ovcmd &= ~HORIZONTAL_LUMINANCE_FILTER; + ovcmd |= (HC_DOWN_INTERPOLATION | HL_DOWN_INTERPOLATION); + } + + if (clipped_desth < clipped_srch) { + /* vertical down-scaling */ + ovcmd &= ~VERTICAL_CHROMINANCE_FILTER; + ovcmd &= ~VERTICAL_LUMINANCE_FILTER; + ovcmd |= (VC_DOWN_INTERPOLATION | VL_DOWN_INTERPOLATION); + } + + /* now calculate the UV scaling factor */ + if (xscaleFract) { + xscaleFractUV = xscaleFract >> MINUV_SCALE; + ovcmd &= ~HC_DOWN_INTERPOLATION; + ovcmd |= HC_UP_INTERPOLATION; + } + + if (xscaleInt) { + xscaleIntUV = xscaleInt >> MINUV_SCALE; + if (xscaleIntUV) { + ovcmd &= ~HC_UP_INTERPOLATION; + } + } + + if (yscaleFract) { + yscaleFractUV = yscaleFract >> MINUV_SCALE; + ovcmd &= ~VC_DOWN_INTERPOLATION; + ovcmd |= VC_UP_INTERPOLATION; + } + + if (yscaleInt) { + yscaleIntUV = yscaleInt >> MINUV_SCALE; + if (yscaleIntUV) { + ovcmd &= ~VC_UP_INTERPOLATION; + ovcmd |= VC_DOWN_INTERPOLATION; + } + } + + }/* if((destw != srcw) || (desth != srch)) */ + + /* Lock the DRM */ + I810_LOCK(pI810XvMC,0); + + /* Block until rendering on this surface is finished */ + stat = XVMC_RENDERING; + while(stat & XVMC_RENDERING) { + XvMCGetSurfaceStatus(display,surface,&stat); + } + /* Block until the last flip is finished */ + if(pI810XvMC->last_flip) { + BLOCK_OVERLAY(pI810XvMC,pI810XvMC->current); + } + + pI810XvMC->current = !pI810XvMC->current; + pORegs->OV0CMD = ovcmd; + + if ((clipped_destw != clipped_srcw) || + (clipped_desth != clipped_srch)) { + pORegs->YRGBSCALE = (xscaleInt << 15) | + ((xscaleFract & 0xFFF) << 3) | (yscaleInt) | + ((yscaleFract & 0xFFF) << 20); + + pORegs->UVSCALE = yscaleIntUV | ((xscaleFractUV & 0xFFF) << 3) | + ((yscaleFractUV & 0xFFF) << 20); + } + else { + /* Normal 1:1 scaling */ + pORegs->YRGBSCALE = 0x80004000; + pORegs->UVSCALE = 0x80004000; + } + + pORegs->SHEIGHT = clipped_srch | (clipped_srch << 15); + pORegs->DWINPOS = (clipped_desty << 16) | clipped_destx; + pORegs->DWINSZ = ((clipped_desth<< 16) | (clipped_destw)); + + /* Attributes */ + pORegs->OV0CLRC0 = ((pI810XvMC->contrast & 0x1ff)<<8) | + (pI810XvMC->brightness & 0xff); + pORegs->OV0CLRC1 = (pI810XvMC->saturation & 0x3ff); + + /* Destination Colorkey Setup */ + pI810XvMC->oregs->DCLRKV = RGB16ToColorKey(pI810XvMC->colorkey); + + /* buffer locations, add the offset from the clipping */ + if(pI810XvMC->current) { + pORegs->OBUF_1Y = (unsigned long)pI810Surface->offset + + (unsigned long)pI810Surface->offsets[0] + ysrc_offset; + pORegs->OBUF_1V = (unsigned long)pI810Surface->offset + + (unsigned long)pI810Surface->offsets[2] + uvsrc_offset; + pORegs->OBUF_1U = (unsigned long)pI810Surface->offset + + (unsigned long)pI810Surface->offsets[1] + uvsrc_offset; + } + else { + pORegs->OBUF_0Y = (unsigned long)pI810Surface->offset + + (unsigned long)pI810Surface->offsets[0] + ysrc_offset; + pORegs->OBUF_0V = (unsigned long)pI810Surface->offset + + (unsigned long)pI810Surface->offsets[2] + uvsrc_offset; + pORegs->OBUF_0U = (unsigned long)pI810Surface->offset + + (unsigned long)pI810Surface->offsets[1] + uvsrc_offset; + } + + switch(surface->surface_type_id) { + case FOURCC_YV12: + case FOURCC_I420: + pORegs->SWID = (uvPitch << 16) | yPitch; + pORegs->SWIDQW = (uvPitch << 13) | (yPitch >> 3); + pORegs->OV0STRIDE = (1<<pI810Surface->pitch) | + ((1<<pI810Surface->pitch) << 15); + pORegs->OV0CMD &= ~SOURCE_FORMAT; + pORegs->OV0CMD |= YUV_420; + if((flags & XVMC_FRAME_PICTURE) != XVMC_FRAME_PICTURE) { + /* Top Field Only */ + if(flags & XVMC_TOP_FIELD) { + if(pI810XvMC->current == 1) { + pORegs->OV0CMD |= (VERTICAL_PHASE_BOTH | FLIP_TYPE_FIELD | + BUFFER1_FIELD0); + } + else { + pORegs->OV0CMD |= (VERTICAL_PHASE_BOTH | FLIP_TYPE_FIELD | + BUFFER0_FIELD0); + } + pORegs->YRGB_VPH = 1<<15 | 1<<31; + pORegs->UV_VPH = 3<<14 | 3<<30; + pORegs->INIT_PH = 0x06 | 0x18; + } + /* Bottom Field Only */ + else { + if(pI810XvMC->current == 1) { + pORegs->OV0CMD |= (VERTICAL_PHASE_BOTH | FLIP_TYPE_FIELD | + BUFFER1_FIELD1); + } + else { + pORegs->OV0CMD |= (VERTICAL_PHASE_BOTH | FLIP_TYPE_FIELD | + BUFFER0_FIELD1); + } + pORegs->YRGB_VPH = 0; + pORegs->UV_VPH = 7<<29 | 7<<13; + pORegs->INIT_PH = 0x06; + } + } + /* Frame Picture */ + else { + if(pI810XvMC->current == 1) { + pORegs->OV0CMD |= BUFFER1_FIELD0; + } + else { + pORegs->OV0CMD |= BUFFER0_FIELD0; + } + pORegs->YRGB_VPH = 0; + pORegs->UV_VPH = 0; + pORegs->INIT_PH = 0; + } + break; + case FOURCC_UYVY: + case FOURCC_YUY2: + default: + pORegs->SWID = srcw; + pORegs->SWIDQW = srcw >> 3; + pORegs->OV0STRIDE = pI810Surface->pitch; + pORegs->OV0CMD &= ~SOURCE_FORMAT; + pORegs->OV0CMD |= YUV_422; + pORegs->OV0CMD &= ~OV_BYTE_ORDER; + if (surface->surface_type_id == FOURCC_UYVY) { + pORegs->OV0CMD |= Y_SWAP; + } + + pORegs->OV0CMD &= ~BUFFER_AND_FIELD; + if(pI810XvMC->current == 1) { + pORegs->OV0CMD |= BUFFER1_FIELD0; + } + else { + pORegs->OV0CMD |= BUFFER0_FIELD0; + } + + break; + } /* switch(surface->surface_type_id) */ + + + + OVERLAY_FLIP(pI810XvMC); + + /* + The Overlay only flips when it knows you changed + something. So the first time change stuff while it + is watching to be sure. + */ + if(!pI810XvMC->last_flip) { + pORegs->OV0CMD &= ~0x4; + if(pI810XvMC->current == 1) { + pORegs->OV0CMD |= BUFFER1_FIELD0; + } + else { + pORegs->OV0CMD |= BUFFER0_FIELD0; + } + } + pI810Surface->last_flip = ++pI810XvMC->last_flip; + I810_UNLOCK(pI810XvMC); + + return Success; +} + +/*************************************************************************** +// Function: XvMCSyncSurface +// Arguments: +// display - Connection to the X server +// surface - The surface to synchronize +// Info: +// Returns: Status +***************************************************************************/ +Status XvMCSyncSurface(Display *display,XvMCSurface *surface) { + Status ret; + int stat=0; + /* + FIXME: Perhaps a timer here to prevent lockup? + FIXME: Perhaps a usleep to not be busy waiting? + */ + do { + ret = XvMCGetSurfaceStatus(display,surface,&stat); + }while(!ret && (stat & XVMC_RENDERING)); + return ret; +} + +/*************************************************************************** +// Function: XvMCFlushSurface +// Description: +// This function commits pending rendering requests to ensure that they +// wll be completed in a finite amount of time. +// Arguments: +// display - Connection to X server +// surface - Surface to flush +// Info: +// This command is a noop for i810 becuase we always dispatch buffers in +// render. There is little gain to be had with 4k buffers. +// Returns: Status +***************************************************************************/ +Status XvMCFlushSurface(Display * display, XvMCSurface *surface) { + return Success; +} + +/*************************************************************************** +// Function: XvMCGetSurfaceStatus +// Description: +// Arguments: +// display: connection to X server +// surface: The surface to query +// stat: One of the Following +// XVMC_RENDERING - The last XvMCRenderSurface command has not +// completed. +// XVMC_DISPLAYING - The surface is currently being displayed or a +// display is pending. +***************************************************************************/ +Status XvMCGetSurfaceStatus(Display *display, XvMCSurface *surface, + int *stat) { + i810XvMCSurface *privSurface; + i810XvMCContext *pI810XvMC; + int temp; + + if((display == NULL) || (surface == NULL) || (stat == NULL)) { + return BadValue; + } + if(surface->privData == NULL) { + return BadValue; + } + *stat = 0; + privSurface = surface->privData; + + pI810XvMC = privSurface->privContext; + if(pI810XvMC == NULL) { + return (error_base + XvMCBadSurface); + } + + I810_LOCK(pI810XvMC,0); + if(privSurface->last_flip) { + /* This can not happen */ + if(pI810XvMC->last_flip < privSurface->last_flip) { + printf("Error: Context last flip is less than surface last flip.\n"); + return BadValue; + } + /* + If the context has 2 or more flips after this surface it + cannot be displaying. Don't bother to check. + */ + if(!(pI810XvMC->last_flip > (privSurface->last_flip + 1))) { + /* + If this surface was the last flipped it is either displaying + or about to be so don't bother checking. + */ + if(pI810XvMC->last_flip == privSurface->last_flip) { + *stat |= XVMC_DISPLAYING; + } + else { + /* + In this case there has been one more flip since our surface's + but we need to check if it is finished or not. + */ + temp = GET_FSTATUS(pI810XvMC); + if(((temp & (1<<20))>>20) != pI810XvMC->current) { + *stat |= XVMC_DISPLAYING; + } + } + } + } + + if(privSurface->last_render && + (privSurface->last_render > GET_RSTATUS(pI810XvMC))) { + *stat |= XVMC_RENDERING; + } + I810_UNLOCK(pI810XvMC); + + return Success; +} + +/*************************************************************************** +// +// Surface manipulation functions +// +***************************************************************************/ + +/*************************************************************************** +// Function: XvMCHideSurface +// Description: Stops the display of a surface. +// Arguments: +// display - Connection to the X server. +// surface - surface to be hidden. +// +// Returns: Status +***************************************************************************/ +Status XvMCHideSurface(Display *display, XvMCSurface *surface) { + i810XvMCSurface *pI810Surface; + i810XvMCContext *pI810XvMC; + int ss, xx; + + /* Did we get a good display and surface passed into us? */ + if(display == NULL) { + return BadValue; + } + + if(surface == NULL) { + return (error_base + XvMCBadSurface); + } + + XvMCSyncSurface(display, surface); + + /* Get surface private data pointer */ + if(surface->privData == NULL) { + return (error_base + XvMCBadSurface); + } + pI810Surface = (i810XvMCSurface *)surface->privData; + + /* + Get the status of the surface, if it is not currently displayed + we don't need to worry about it. + */ + if((xx = XvMCGetSurfaceStatus(display, surface, &ss)) != Success) { + return xx; + } + if(! (ss & XVMC_DISPLAYING)) { + return Success; + } + + /* Get the associated context pointer */ + pI810XvMC = (i810XvMCContext *)pI810Surface->privContext; + if(pI810XvMC == NULL) { + return (error_base + XvMCBadSurface); + } + + if(pI810XvMC->last_flip) { + I810_LOCK(pI810XvMC,DRM_LOCK_QUIESCENT); + + /* Make sure last flip is done */ + BLOCK_OVERLAY(pI810XvMC,pI810XvMC->current); + + /* Set the registers to turn the overlay off */ + pI810XvMC->oregs->OV0CMD = VC_UP_INTERPOLATION | HC_UP_INTERPOLATION | + Y_ADJUST; + pI810XvMC->current = !pI810XvMC->current; + if(pI810XvMC->current == 1) { + pI810XvMC->oregs->OV0CMD |= BUFFER1_FIELD0; + } + else { + pI810XvMC->oregs->OV0CMD |= BUFFER0_FIELD0; + } + OVERLAY_FLIP(pI810XvMC); + /* + Increment the context flip but not the surface. This way no + surface has the last flip #. + */ + pI810XvMC->last_flip++; + + + /* Now wait until the hardware reads the registers and makes the change. */ + BLOCK_OVERLAY(pI810XvMC,pI810XvMC->current) + + I810_UNLOCK(pI810XvMC); + } + + return Success; +} + + + + +/*************************************************************************** +// +// Functions that deal with subpictures +// +***************************************************************************/ + + + +/*************************************************************************** +// Function: XvMCCreateSubpicture +// Description: This creates a subpicture by filling out the XvMCSubpicture +// structure passed to it and returning Success. +// Arguments: +// display - Connection to the X server. +// context - The context to create the subpicture for. +// subpicture - Pre-allocated XvMCSubpicture structure to be filled in. +// width - of subpicture +// height - of subpicture +// xvimage_id - The id describing the XvImage format. +// +// Returns: Status +***************************************************************************/ +Status XvMCCreateSubpicture(Display *display, XvMCContext *context, + XvMCSubpicture *subpicture, + unsigned short width, unsigned short height, + int xvimage_id) { + i810XvMCContext *pI810XvMC; + i810XvMCSubpicture *pI810Subpicture; + int priv_count; + uint *priv_data; + Status ret; + + if((subpicture == NULL) || (context == NULL) || (display == NULL)){ + return BadValue; + } + + pI810XvMC = (i810XvMCContext *)context->privData; + if(pI810XvMC == NULL) { + return (error_base + XvMCBadContext); + } + + + subpicture->context_id = context->context_id; + subpicture->xvimage_id = xvimage_id; + + /* These need to be checked to make sure they are not too big! */ + subpicture->width = width; + subpicture->height = height; + + subpicture->privData = + (i810XvMCSubpicture *)malloc(sizeof(i810XvMCSubpicture)); + + if(!subpicture->privData) { + return BadAlloc; + } + pI810Subpicture = (i810XvMCSubpicture *)subpicture->privData; + + + if((ret = _xvmc_create_subpicture(display, context, subpicture, + &priv_count, &priv_data))) { + printf("Unable to create XvMCSubpicture.\n"); + return ret; + } + + if(priv_count != 1) { + printf("_xvmc_create_subpicture() returned incorrect data size.\n"); + printf("Expected 1 got %d\n",priv_count); + free(priv_data); + return BadAlloc; + } + /* Data == Client Address, offset == Physical address offset */ + pI810Subpicture->data = pI810XvMC->surfaces.address; + pI810Subpicture->offset = pI810XvMC->surfaces.offset; + + /* Initialize private values */ + pI810Subpicture->privContext = pI810XvMC; + + pI810Subpicture->last_render = 0; + pI810Subpicture->last_flip = 0; + + /* Based on the xvimage_id we will need to set the other values */ + subpicture->num_palette_entries = 16; + subpicture->entry_bytes = 3; + strcpy(subpicture->component_order,"YUV"); + + /* + i810's MC Engine needs surfaces of 2^x (x= 9,10,11,12) pitch + and the Tiler need 512k aligned surfaces, basically we are + stuck with fixed memory with pitch 1024. + */ + pI810Subpicture->pitch = 10; + + /* + offsets[0] == offset into the map described by either + address (Client memeory address) or offset (physical offset from fb base) + */ + pI810Subpicture->offsets[0] = priv_data[0]; + if(((unsigned long)pI810Subpicture->data + pI810Subpicture->offsets[0]) & 4095) { + printf("XvMCCreateSubpicture: Subpicture offset 0 is not 4096 aligned\n"); + } + + /* Free data returned from xvmc_create_surface */ + free(priv_data); + + /* Clear the surface to 0 */ + memset((void *)((unsigned long)pI810Subpicture->data + (unsigned long)pI810Subpicture->offsets[0]), + 0, ((1<<pI810Subpicture->pitch) * subpicture->height)); + + switch(subpicture->xvimage_id) { + case FOURCC_IA44: + case FOURCC_AI44: + /* Destination buffer info command */ + pI810Subpicture->dbi1 = ((((unsigned int)pI810Subpicture->offset + + pI810Subpicture->offsets[0]) & ~0xfc000fff) | + (pI810Subpicture->pitch - 9)); + + /* Destination buffer variables command */ + pI810Subpicture->dbv1 = (0x8<<20) | (0x8<<16); + + /* Map info command */ + pI810Subpicture->mi1 = (0x0<<24) | (3<<21) | (1<<9) | + (pI810Subpicture->pitch - 3); + + pI810Subpicture->mi2 = (((unsigned int)subpicture->height - 1)<<16) | + ((unsigned int)subpicture->width - 1); + + pI810Subpicture->mi3 = ((unsigned int)pI810Subpicture->offset + + pI810Subpicture->offsets[0]) & ~0xfc00000f; + break; + default: + free(subpicture->privData); + return BadMatch; + } + + pI810XvMC->ref++; + return Success; +} + + + +/*************************************************************************** +// Function: XvMCClearSubpicture +// Description: Clear the area of the given subpicture to "color". +// structure passed to it and returning Success. +// Arguments: +// display - Connection to the X server. +// subpicture - Subpicture to clear. +// x, y, width, height - rectangle in the subpicture to clear. +// color - The data to file the rectangle with. +// +// Returns: Status +***************************************************************************/ +Status XvMCClearSubpicture(Display *display, XvMCSubpicture *subpicture, + short x, short y, + unsigned short width, unsigned short height, + unsigned int color) { + + i810XvMCContext *pI810XvMC; + i810XvMCSubpicture *pI810Subpicture; + int i; + + if((subpicture == NULL) || (display == NULL)){ + return BadValue; + } + + if(!subpicture->privData) { + return (error_base + XvMCBadSubpicture); + } + pI810Subpicture = (i810XvMCSubpicture *)subpicture->privData; + + pI810XvMC = (i810XvMCContext *)pI810Subpicture->privContext; + if(pI810XvMC == NULL) { + return (error_base + XvMCBadSubpicture); + } + + if((x < 0) || (x + width > subpicture->width)) { + return BadValue; + } + + if((y < 0) || (y + height > subpicture->height)) { + return BadValue; + } + + for(i=y; i<y + height; i++) { + memset((void *)((unsigned long)pI810Subpicture->data + + (unsigned long)pI810Subpicture->offsets[0] + x + + (1<<pI810Subpicture->pitch) * i),(char)color,width); + } + + return Success; +} + +/*************************************************************************** +// Function: XvMCCompositeSubpicture +// Description: Composite the XvImae on the subpicture. This composit uses +// non-premultiplied alpha. Destination alpha is utilized +// except for with indexed subpictures. Indexed subpictures +// use a simple "replace". +// Arguments: +// display - Connection to the X server. +// subpicture - Subpicture to clear. +// image - the XvImage to be used as the source of the composite. +// srcx, srcy, width, height - The rectangle from the image to be used. +// dstx, dsty - location in the subpicture to composite the source. +// +// Returns: Status +***************************************************************************/ +Status XvMCCompositeSubpicture(Display *display, XvMCSubpicture *subpicture, + XvImage *image, + short srcx, short srcy, + unsigned short width, unsigned short height, + short dstx, short dsty) { + + i810XvMCContext *pI810XvMC; + i810XvMCSubpicture *pI810Subpicture; + int i; + + if((subpicture == NULL) || (display == NULL)){ + return BadValue; + } + + if(!subpicture->privData) { + return (error_base + XvMCBadSubpicture); + } + pI810Subpicture = (i810XvMCSubpicture *)subpicture->privData; + + pI810XvMC = (i810XvMCContext *)pI810Subpicture->privContext; + if(pI810XvMC == NULL) { + return (error_base + XvMCBadSubpicture); + } + + if((srcx < 0) || (srcx + width > image->width)) { + return BadValue; + } + + if((dstx < 0) || (dstx + width > subpicture->width)) { + return BadValue; + } + + if((srcy < 0) || (srcy + height > image->height)) { + return BadValue; + } + + if((dsty < 0) || (dsty + height > subpicture->height)) { + return BadValue; + } + + for(i=0; i<height; i++) { + memcpy((void *)((unsigned long)pI810Subpicture->data + + (unsigned long)pI810Subpicture->offsets[0] + dstx + + (1<<pI810Subpicture->pitch) * (i + dsty)), + (void *)((unsigned long)image->data + + (unsigned long)image->offsets[0] + srcx + + image->pitches[0] * (i + srcy)) + ,width); + } + + return Success; + +} + + +/*************************************************************************** +// Function: XvMCDestroySubpicture +// Description: Destroys the specified subpicture. +// Arguments: +// display - Connection to the X server. +// subpicture - Subpicture to be destroyed. +// +// Returns: Status +***************************************************************************/ +Status XvMCDestroySubpicture(Display *display, XvMCSubpicture *subpicture) { + + i810XvMCSubpicture *pI810Subpicture; + i810XvMCContext *pI810XvMC; + + if((display == NULL) || (subpicture == NULL)) { + return BadValue; + } + if(!subpicture->privData) { + return (error_base + XvMCBadSubpicture); + } + pI810Subpicture = (i810XvMCSubpicture *)subpicture->privData; + + pI810XvMC = (i810XvMCContext *)pI810Subpicture->privContext; + if(!pI810XvMC) { + return (error_base + XvMCBadSubpicture); + } + + + if(pI810Subpicture->last_render) { + XvMCSyncSubpicture(display,subpicture); + } + + _xvmc_destroy_subpicture(display,subpicture); + + i810_free_privContext(pI810XvMC); + + free(pI810Subpicture); + subpicture->privData = NULL; + return Success; +} + + +/*************************************************************************** +// Function: XvMCSetSubpicturePalette +// Description: Set the subpictures palette +// Arguments: +// display - Connection to the X server. +// subpicture - Subpiture to set palette for. +// palette - A pointer to an array holding the palette data. The array +// is num_palette_entries * entry_bytes in size. +// Returns: Status +***************************************************************************/ + +Status XvMCSetSubpicturePalette(Display *display, XvMCSubpicture *subpicture, + unsigned char *palette) { + i810XvMCSubpicture *privSubpicture; + int i,j; + + if((display == NULL) || (subpicture == NULL)) { + return BadValue; + } + if(subpicture->privData == NULL) { + return (error_base + XvMCBadSubpicture); + } + privSubpicture = (i810XvMCSubpicture *)subpicture->privData; + + j=0; + for(i=0; i<16; i++) { + privSubpicture->palette[0][i] = palette[j++]; + privSubpicture->palette[1][i] = palette[j++]; + privSubpicture->palette[2][i] = palette[j++]; + } + return Success; +} + +/*************************************************************************** +// Function: XvMCBlendSubpicture +// Description: +// The behavior of this function is different depending on whether +// or not the XVMC_BACKEND_SUBPICTURE flag is set in the XvMCSurfaceInfo. +// i810 only support frontend behavior. +// +// XVMC_BACKEND_SUBPICTURE not set ("frontend" behavior): +// +// XvMCBlendSubpicture is a no-op in this case. +// +// Arguments: +// display - Connection to the X server. +// subpicture - The subpicture to be blended into the video. +// target_surface - The surface to be displayed with the blended subpic. +// source_surface - Source surface prior to blending. +// subx, suby, subw, subh - The rectangle from the subpicture to use. +// surfx, surfy, surfw, surfh - The rectangle in the surface to blend +// blend the subpicture rectangle into. Scaling can ocure if +// XVMC_SUBPICTURE_INDEPENDENT_SCALING is set. +// +// Returns: Status +***************************************************************************/ +Status XvMCBlendSubpicture(Display *display, XvMCSurface *target_surface, + XvMCSubpicture *subpicture, + short subx, short suby, + unsigned short subw, unsigned short subh, + short surfx, short surfy, + unsigned short surfw, unsigned short surfh) { + + return BadMatch; +} + + + +/*************************************************************************** +// Function: XvMCBlendSubpicture2 +// Description: +// The behavior of this function is different depending on whether +// or not the XVMC_BACKEND_SUBPICTURE flag is set in the XvMCSurfaceInfo. +// i810 only supports frontend blending. +// +// XVMC_BACKEND_SUBPICTURE not set ("frontend" behavior): +// +// XvMCBlendSubpicture2 blends the source_surface and subpicture and +// puts it in the target_surface. This does not effect the status of +// the source surface but will cause the target_surface to query +// XVMC_RENDERING until the blend is completed. +// +// Arguments: +// display - Connection to the X server. +// subpicture - The subpicture to be blended into the video. +// target_surface - The surface to be displayed with the blended subpic. +// source_surface - Source surface prior to blending. +// subx, suby, subw, subh - The rectangle from the subpicture to use. +// surfx, surfy, surfw, surfh - The rectangle in the surface to blend +// blend the subpicture rectangle into. Scaling can ocure if +// XVMC_SUBPICTURE_INDEPENDENT_SCALING is set. +// +// Returns: Status +***************************************************************************/ +Status XvMCBlendSubpicture2(Display *display, + XvMCSurface *source_surface, + XvMCSurface *target_surface, + XvMCSubpicture *subpicture, + short subx, short suby, + unsigned short subw, unsigned short subh, + short surfx, short surfy, + unsigned short surfw, unsigned short surfh) { + drmBufPtr pDMA; + unsigned int *data; + i810XvMCContext *pI810XvMC; + i810XvMCSubpicture *privSubpicture; + i810XvMCSurface *privTarget; + i810XvMCSurface *privSource; + drm_i810_mc_t mc; + int i,j; + + if(display == NULL) { + return BadValue; + } + + if(subpicture == NULL) { + return (error_base + XvMCBadSubpicture); + } + + if((target_surface == NULL) || (source_surface == NULL)) { + return (error_base + XvMCBadSurface); + } + + if((subpicture->xvimage_id != FOURCC_AI44) && + (subpicture->xvimage_id != FOURCC_IA44)) { + return (error_base + XvMCBadSubpicture); + } + + if(!subpicture->privData) { + return (error_base + XvMCBadSubpicture); + } + privSubpicture = (i810XvMCSubpicture *)subpicture->privData; + + pI810XvMC = (i810XvMCContext *)privSubpicture->privContext; + if(pI810XvMC == NULL) { + return (error_base + XvMCBadSubpicture); + } + + if(!target_surface->privData) { + return (error_base + XvMCBadSurface); + } + privTarget = (i810XvMCSurface *)target_surface->privData; + + if(!source_surface->privData) { + return (error_base + XvMCBadSurface); + } + privSource = (i810XvMCSurface *)source_surface->privData; + + + /* Check that size isn't bigger than subpicture */ + if((subx + subw) > subpicture->width) { + return BadValue; + } + if((suby + subh) > subpicture->height) { + return BadValue; + } + /* Check that dest isn't bigger than surface */ + if((surfx + surfw) > target_surface->width) { + return BadValue; + } + if((surfy + surfh) > target_surface->height) { + return BadValue; + } + /* Make sure surfaces match */ + if(target_surface->width != source_surface->width) { + return BadValue; + } + if(target_surface->height != source_surface->height) { + return BadValue; + } + + /* Lock For DMA */ + I810_LOCK(pI810XvMC,0); + + /* Allocate DMA buffer */ + pDMA = i810_get_free_buffer(pI810XvMC); + data = pDMA->address; + + /* Copy Y data first */ + /* SOURCE_COPY_BLT */ + *data++ = (2<<29) | (0x43<<22) | 0x4; + *data++ = (0xcc<<16) | (1<<26) | (1<<privTarget->pitch); + *data++ = (target_surface->height<<16) | target_surface->width; + *data++ = privTarget->offset + privTarget->offsets[0]; + *data++ = (1<<privSource->pitch); + *data++ = privSource->offset + privSource->offsets[0]; + + /* Select Context 1 for loading */ + *data++ = CMD_FLUSH; + *data++ = (5<<23) | (1<<17) | (1<<8); + *data++ = CMD_FLUSH; + + /* Load Palette */ + *data++ = MAP_PALETTE_LOAD; + /* 16 levels of alpha for each Y */ + switch(subpicture->xvimage_id) { + case FOURCC_IA44: + for(i=0; i<16; i++) { + for(j=0; j<16; j++) { + *data++ = (j<<12) | (j<<8) | privSubpicture->palette[0][i]; + } + } + break; + case FOURCC_AI44: + for(i=0; i<16; i++) { + for(j=0; j<16; j++) { + *data++ = (i<<12) | (i<<8) | privSubpicture->palette[0][j]; + } + } + break; + } + /* TARGET */ + /* *data++ = CMD_FLUSH; */ + /* *data++ = BOOLEAN_ENA_2; */ + *data++ = CMD_FLUSH; + *data++ = DEST_BUFFER_INFO; + *data++ = privTarget->dbi1y; + *data++ = DEST_BUFFER_VAR; + *data++ = privTarget->dbv1; + + /* ALPHA */ + *data++ = CMD_MAP_INFO; + *data++ = privSubpicture->mi1; + *data++ = privSubpicture->mi2; + *data++ = privSubpicture->mi3; + + *data++ = VERTEX_FORMAT | (1<<8) | (3<<1); + *data++ = BOOLEAN_ENA_1; + *data++ = SRC_DEST_BLEND_MONO | (0x940); + /* Map Filter */ + *data++ = (3<<29) | (0x1c<<24) | (2<<19) | (0x224); + + /* Use context 1 */ + *data++ = CMD_FLUSH; + *data++ = (5<<23) | (1<<16) | 1; + *data++ = CMD_FLUSH; + + /* Drawing Rect Info */ + *data++ = DRAWING_RECT_INFO; + *data++ = 0x0; + *data++ = 0x0; + *data++ = 0x0; + *data++ = 0x0; + *data++ = 0x0; + + /* GFXPRIMITIVE RECTANGLE */ + *data++ = (3<<29) | (0x1f<<24) | (0x7<<18) | 11; + /* Bottom Right Vertex */ + *(float *)data++ = (float) (surfx + surfw); + *(float *)data++ = (float) (surfy + surfh); + *(float *)data++ = (float) (subx + subw); + *(float *)data++ = (float) (suby + subh); + /* Bottom Left Vertex */ + *(float *)data++ = (float) surfx; + *(float *)data++ = (float) (surfy + surfh); + *(float *)data++ = (float) subx; + *(float *)data++ = (float) (suby + subh); + /* Top Left Vertex */ + *(float *)data++ = (float) surfx; + *(float *)data++ = (float) surfy; + *(float *)data++ = (float) subx; + *(float *)data++ = (float) suby; + + /* Load and Use Context 0 */ + *data++ = CMD_FLUSH; + *data++ = (5<<23) | (1<<17) | (1<<16); + *data++ = CMD_FLUSH; + + /* U data */ + /* SOURCE_COPY_BLT */ + *data++ = (2<<29) | (0x43<<22) | 0x4; + *data++ = (0xcc<<16) | (1<<26) | (1<<(privTarget->pitch - 1)); + *data++ = (target_surface->height<<15) | (target_surface->width>>1); + *data++ = (unsigned long)privTarget->offset + (unsigned long)privTarget->offsets[1]; + *data++ = (1<<(privSource->pitch - 1)); + *data++ = (unsigned long)privSource->offset + (unsigned long)privSource->offsets[1]; + + /* Context 1 select */ + *data++ = CMD_FLUSH; + *data++ = (5<<23) | (1<<17) | (1<<8); + *data++ = CMD_FLUSH; + /* ALPHA PALETTE */ + *data++ = MAP_PALETTE_LOAD; + /* 16 levels of alpha for each Y */ + switch(subpicture->xvimage_id) { + case FOURCC_IA44: + for(i=0; i<16; i++) { + for(j=0; j<16; j++) { + *data++ = (j<<12) | (j<<8) | privSubpicture->palette[2][i]; + } + } + break; + case FOURCC_AI44: + for(i=0; i<16; i++) { + for(j=0; j<16; j++) { + *data++ = (i<<12) | (i<<8) | privSubpicture->palette[2][j]; + } + } + break; + } + /* TARGET */ + *data++ = CMD_FLUSH; + *data++ = BOOLEAN_ENA_2; + *data++ = CMD_FLUSH; + *data++ = DEST_BUFFER_INFO; + *data++ = privTarget->dbi1u; + *data++ = DEST_BUFFER_VAR; + *data++ = privTarget->dbv1; + + /* ALPHA */ + *data++ = CMD_MAP_INFO; + *data++ = privSubpicture->mi1; + *data++ = privSubpicture->mi2; + *data++ = privSubpicture->mi3; + + *data++ = VERTEX_FORMAT | (1<<8) | (3<<1); + *data++ = BOOLEAN_ENA_1; + *data++ = SRC_DEST_BLEND_MONO | (0x940); + /* Map Filter */ + *data++ = (3<<29) | (0x1c<<24) | (2<<19) | (1<<16) | (0x224); + + /* Use context 1 */ + *data++ = CMD_FLUSH; + *data++ = (5<<23) | (1<<16) | 1; + *data++ = CMD_FLUSH; + + /* Drawing Rect Info */ + *data++ = (3<<29) | (0x1d<<24) | (0x80<<16) | 3; + *data++ = 0; + *data++ = 0; + *data++ = 0; + *data++ = 0; + *data++ = 0; + + /* Rectangle */ + *data++ = (3<<29) | (0x1f<<24) | (0x7<<18) | 11; + /* Bottom Right */ + *(float *)data++ = (float) ((surfx + surfw)>>1); + *(float *)data++ = (float) ((surfy + surfh)>>1); + *(float *)data++ = (float) subx + subw; + *(float *)data++ = (float) suby + subh; + /* Bottom Left */ + *(float *)data++ = (float) (surfx>>1); + *(float *)data++ = (float) ((surfy + surfh)>>1); + *(float *)data++ = (float) subx; + *(float *)data++ = (float) suby + subh; + /* Top Left */ + *(float *)data++ = (float) (surfx>>1); + *(float *)data++ = (float) (surfy>>1); + *(float *)data++ = (float) subx; + *(float *)data++ = (float) suby; + + /* Load and Use Context 0 */ + *data++ = CMD_FLUSH; + *data++ = (5<<23) | (1<<17) | (1<<16); + *data++ = CMD_FLUSH; + + /* V data */ + /* SOURCE_COPY_BLT */ + *data++ = (2<<29) | (0x43<<22) | 0x4; + *data++ = (0xcc<<16) | (1<<26) | (1<<(privTarget->pitch - 1)); + *data++ = (target_surface->height<<15) | (target_surface->width>>1); + *data++ = (unsigned long)privTarget->offset + (unsigned long)privTarget->offsets[2]; + *data++ = (1<<(privSource->pitch - 1)); + *data++ = (unsigned long)privSource->offset + (unsigned long)privSource->offsets[2]; + + /* Context 1 select */ + *data++ = CMD_FLUSH; + *data++ = (5<<23) | (1<<17) | (1<<8); + *data++ = CMD_FLUSH; + + /* ALPHA PALETTE */ + *data++ = MAP_PALETTE_LOAD; + /* 16 levels of alpha for each Y */ + switch(subpicture->xvimage_id) { + case FOURCC_IA44: + for(i=0; i<16; i++) { + for(j=0; j<16; j++) { + *data++ = (j<<12) | (j<<8) | privSubpicture->palette[1][i]; + } + } + break; + case FOURCC_AI44: + for(i=0; i<16; i++) { + for(j=0; j<16; j++) { + *data++ = (i<<12) | (i<<8) | privSubpicture->palette[1][j]; + } + } + break; + } + /* TARGET */ + *data++ = CMD_FLUSH; + *data++ = BOOLEAN_ENA_2; + *data++ = CMD_FLUSH; + *data++ = DEST_BUFFER_INFO; + *data++ = privTarget->dbi1v; + *data++ = DEST_BUFFER_VAR; + *data++ = privTarget->dbv1; + + /* ALPHA */ + *data++ = CMD_MAP_INFO; + *data++ = privSubpicture->mi1; + *data++ = privSubpicture->mi2; + *data++ = privSubpicture->mi3; + + *data++ = VERTEX_FORMAT | (1<<8) | (3<<1); + *data++ = BOOLEAN_ENA_1; + *data++ = SRC_DEST_BLEND_MONO | (0x940); + /* Map Filter */ + *data++ = (3<<29) | (0x1c<<24) | (2<<19) | (1<<16) | (0x224); + + /* Use context 1 */ + *data++ = CMD_FLUSH; + *data++ = (5<<23) | (1<<16) | 1; + *data++ = CMD_FLUSH; + + /* Drawing Rect Info */ + *data++ = (3<<29) | (0x1d<<24) | (0x80<<16) | 3; + *data++ = 0; + *data++ = 0; + *data++ = 0; + *data++ = 0; + *data++ = 0; + + /* Rectangle */ + *data++ = (3<<29) | (0x1f<<24) | (0x7<<18) | 11; + /* Bottom Right */ + *(float *)data++ = (float) ((surfx + surfw)>>1); + *(float *)data++ = (float) ((surfy + surfh)>>1); + *(float *)data++ = (float) subx + subw; + *(float *)data++ = (float) suby + subh; + /* Bottom Left */ + *(float *)data++ = (float) (surfx>>1); + *(float *)data++ = (float) ((surfy + surfh)>>1); + *(float *)data++ = (float) subx; + *(float *)data++ = (float) suby + subh; + /* Top Left */ + *(float *)data++ = (float) (surfx>>1); + *(float *)data++ = (float) (surfy>>1); + *(float *)data++ = (float) subx; + *(float *)data++ = (float) suby; + + /* Load and Use Context 0 */ + *data++ = CMD_FLUSH; + *data++ = (5<<23) | (1<<17) | (1<<16); + *data++ = CMD_FLUSH; + + + /* Dispatch */ + pDMA->used = (unsigned long)data - (unsigned long)pDMA->address; + mc.idx = pDMA->idx; + mc.used = pDMA->used; + mc.last_render = ++pI810XvMC->last_render; + privTarget->last_render = pI810XvMC->last_render; + I810_MC(pI810XvMC,mc); + + I810_UNLOCK(pI810XvMC); + return Success; +} + + + +/*************************************************************************** +// Function: XvMCSyncSubpicture +// Description: This function blocks until all composite/clear requests on +// the subpicture have been complete. +// Arguments: +// display - Connection to the X server. +// subpicture - The subpicture to synchronize +// +// Returns: Status +***************************************************************************/ +Status XvMCSyncSubpicture(Display *display, XvMCSubpicture *subpicture) { + Status ret; + int stat=0; + do { + ret = XvMCGetSubpictureStatus(display,subpicture,&stat); + }while(!ret && (stat & XVMC_RENDERING)); + return ret; +} + + + +/*************************************************************************** +// Function: XvMCFlushSubpicture +// Description: This function commits pending composite/clear requests to +// ensure that they will be completed in a finite amount of +// time. +// Arguments: +// display - Connection to the X server. +// subpicture - The subpicture whos compsiting should be flushed +// +// Returns: Status +// NOTES: i810 always dispatches commands so flush is a no-op +***************************************************************************/ +Status XvMCFlushSubpicture(Display *display, XvMCSubpicture *subpicture) { + if(display == NULL) { + return BadValue; + } + if(subpicture == NULL) { + return (error_base + XvMCBadSubpicture); + } + + return Success; +} + + + +/*************************************************************************** +// Function: XvMCGetSubpictureStatus +// Description: This function gets the current status of a subpicture +// +// Arguments: +// display - Connection to the X server. +// subpicture - The subpicture whos status is being queried +// stat - The status of the subpicture. It can be any of the following +// OR'd together: +// XVMC_RENDERING - Last composite or clear request not completed +// XVMC_DISPLAYING - Suppicture currently being displayed. +// +// Returns: Status +// Notes: i810 always blends into a third surface so the subpicture is +// never actually displaying, only a copy of it is displaying. We only +// have to worry about the rendering case. +***************************************************************************/ +Status XvMCGetSubpictureStatus(Display *display, XvMCSubpicture *subpicture, + int *stat) { + + i810XvMCSubpicture *privSubpicture; + i810XvMCContext *pI810XvMC; + + if((display == NULL) || (stat == NULL)) { + return BadValue; + } + if((subpicture == NULL) || (subpicture->privData == NULL)) { + return (error_base + XvMCBadSubpicture); + } + *stat = 0; + privSubpicture = (i810XvMCSubpicture *)subpicture->privData; + + pI810XvMC = (i810XvMCContext *)privSubpicture->privContext; + if(pI810XvMC == NULL) { + return (error_base + XvMCBadSubpicture); + } + + I810_LOCK(pI810XvMC,0); + + if(privSubpicture->last_render && + (privSubpicture->last_render > GET_RSTATUS(pI810XvMC))) { + *stat |= XVMC_RENDERING; + } + I810_UNLOCK(pI810XvMC); + + return Success; +} + +#define NUM_XVMC_ATTRIBUTES 4 +static XvAttribute I810_XVMC_ATTRIBUTES[] = { + {XvGettable | XvSettable, 0, 0xffffff, "XV_COLORKEY"}, + {XvGettable | XvSettable, -127, +127, "XV_BRIGHTNESS"}, + {XvGettable | XvSettable, 0, 0x1ff, "XV_CONTRAST"}, + {XvGettable | XvSettable, 0, 0x3ff, "XV_SATURATION"} +}; + + +/*************************************************************************** +// Function: XvMCQueryAttributes +// Description: An array of XvAttributes of size "number" is returned by +// this function. If there are no attributes, NULL is returned and number +// is set to 0. The array may be freed with xfree(). +// +// Arguments: +// display - Connection to the X server. +// context - The context whos attributes we are querying. +// number - The number of returned atoms. +// +// Returns: +// An array of XvAttributes. +// Notes: +// For i810 we support these Attributes: +// XV_COLORKEY: The colorkey value, initialized from the Xv value at +// context creation time. +// XV_BRIGHTNESS +// XV_CONTRAST +// XV_SATURATION +***************************************************************************/ +XvAttribute *XvMCQueryAttributes(Display *display, XvMCContext *context, + int *number) { + i810XvMCContext *pI810XvMC; + XvAttribute *attributes; + + if(number == NULL) { + return NULL; + } + if(display == NULL) { + *number = 0; + return NULL; + } + if(context == NULL) { + *number = 0; + return NULL; + } + pI810XvMC = context->privData; + if(pI810XvMC == NULL) { + *number = 0; + return NULL; + } + + attributes = (XvAttribute *)malloc(NUM_XVMC_ATTRIBUTES * + sizeof(XvAttribute)); + if(attributes == NULL) { + *number = 0; + return NULL; + } + + memcpy(attributes,I810_XVMC_ATTRIBUTES,(NUM_XVMC_ATTRIBUTES * + sizeof(XvAttribute))); + + *number = NUM_XVMC_ATTRIBUTES; + return attributes; +} + +/*************************************************************************** +// Function: XvMCSetAttribute +// Description: This function sets a context-specific attribute. +// +// Arguments: +// display - Connection to the X server. +// context - The context whos attributes we are querying. +// attribute - The X atom of the attribute to be changed. +// value - The new value for the attribute. +// +// Returns: +// Status +// Notes: +// For i810 we support these Attributes: +// XV_COLORKEY: The colorkey value, initialized from the Xv value at +// context creation time. +// XV_BRIGHTNESS +// XV_CONTRAST +// XV_SATURATION +***************************************************************************/ +Status XvMCSetAttribute(Display *display, XvMCContext *context, + Atom attribute, int value) { + i810XvMCContext *pI810XvMC; + + if(display == NULL) { + return BadValue; + } + if(context == NULL) { + return (error_base + XvMCBadContext); + } + pI810XvMC = context->privData; + if(pI810XvMC == NULL) { + return (error_base + XvMCBadContext); + } + + if(attribute == pI810XvMC->xv_colorkey) { + if((value < I810_XVMC_ATTRIBUTES[0].min_value) || + (value > I810_XVMC_ATTRIBUTES[0].max_value)) { + return BadValue; + } + pI810XvMC->colorkey = value; + return Success; + } + if(attribute == pI810XvMC->xv_brightness) { + if((value < I810_XVMC_ATTRIBUTES[1].min_value) || + (value > I810_XVMC_ATTRIBUTES[1].max_value)) { + return BadValue; + } + pI810XvMC->brightness = value; + return Success; + } + if(attribute == pI810XvMC->xv_saturation) { + if((value < I810_XVMC_ATTRIBUTES[2].min_value) || + (value > I810_XVMC_ATTRIBUTES[2].max_value)) { + return BadValue; + } + pI810XvMC->saturation = value; + return Success; + } + if(attribute == pI810XvMC->xv_contrast) { + if((value < I810_XVMC_ATTRIBUTES[3].min_value) || + (value > I810_XVMC_ATTRIBUTES[3].max_value)) { + return BadValue; + } + pI810XvMC->contrast = value; + return Success; + } + return BadValue; +} + +/*************************************************************************** +// Function: XvMCGetAttribute +// Description: This function queries a context-specific attribute and +// returns the value. +// +// Arguments: +// display - Connection to the X server. +// context - The context whos attributes we are querying. +// attribute - The X atom of the attribute to be queried +// value - The returned attribute value +// +// Returns: +// Status +// Notes: +// For i810 we support these Attributes: +// XV_COLORKEY: The colorkey value, initialized from the Xv value at +// context creation time. +// XV_BRIGHTNESS +// XV_CONTRAST +// XV_SATURATION +***************************************************************************/ +Status XvMCGetAttribute(Display *display, XvMCContext *context, + Atom attribute, int *value) { + i810XvMCContext *pI810XvMC; + + if(display == NULL) { + return BadValue; + } + if(context == NULL) { + return (error_base + XvMCBadContext); + } + pI810XvMC = context->privData; + if(pI810XvMC == NULL) { + return (error_base + XvMCBadContext); + } + if(value == NULL) { + return BadValue; + } + + if(attribute == pI810XvMC->xv_colorkey) { + *value = pI810XvMC->colorkey; + return Success; + } + if(attribute == pI810XvMC->xv_brightness) { + *value = pI810XvMC->brightness; + return Success; + } + if(attribute == pI810XvMC->xv_saturation) { + *value = pI810XvMC->saturation; + return Success; + } + if(attribute == pI810XvMC->xv_contrast) { + *value = pI810XvMC->contrast; + return Success; + } + return BadValue; +} + + + + diff --git a/src/xvmc/I810XvMC.h b/src/xvmc/I810XvMC.h new file mode 100644 index 00000000..018c80e9 --- /dev/null +++ b/src/xvmc/I810XvMC.h @@ -0,0 +1,469 @@ +/*************************************************************************** + +Copyright 2001 Intel Corporation. All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sub license, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice (including the +next paragraph) shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +IN NO EVENT SHALL INTEL, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR +THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ + +/*************************************************************************** + * libI810XvMC.h: MC Driver i810 includes + * + * Authors: + * Matt Sottek <matthew.j.sottek@intel.com> + * + * + ***************************************************************************/ +/* $XFree86: xc/lib/XvMC/hw/i810/I810XvMC.h,v 1.4 2002/11/19 09:35:49 alanh Exp $ */ + + +#ifndef I810XVMC_H +#define I810XVMC_H + +/* #define XVMC_DEBUG(x) do {x; }while(0); */ +#define XVMC_DEBUG(x) + +#include "xf86drm.h" +#include "i810_common.h" +#include <X11/Xlibint.h> + + +/*************************************************************************** +// i810OverlayRec: Structure that is used to reference the overlay +// register memory. A i810OverlayRecPtr is set to the address of the +// allocated overlay registers. +***************************************************************************/ +typedef struct _i810OverlayRec { + unsigned int OBUF_0Y; + unsigned int OBUF_1Y; + unsigned int OBUF_0U; + unsigned int OBUF_0V; + unsigned int OBUF_1U; + unsigned int OBUF_1V; + unsigned int OV0STRIDE; + unsigned int YRGB_VPH; + unsigned int UV_VPH; + unsigned int HORZ_PH; + unsigned int INIT_PH; + unsigned int DWINPOS; + unsigned int DWINSZ; + unsigned int SWID; + unsigned int SWIDQW; + unsigned int SHEIGHT; + unsigned int YRGBSCALE; + unsigned int UVSCALE; + unsigned int OV0CLRC0; + unsigned int OV0CLRC1; + unsigned int DCLRKV; + unsigned int DCLRKM; + unsigned int SCLRKVH; + unsigned int SCLRKVL; + unsigned int SCLRKM; + unsigned int OV0CONF; + unsigned int OV0CMD; +} i810OverlayRec, *i810OverlayRecPtr; + + +/*************************************************************************** +// i810XvMCDrmMap: Holds the data about the DRM maps +***************************************************************************/ +typedef struct _i810XvMCDrmMap { + drmHandle offset; + drmAddress address; + unsigned int size; +} i810XvMCDrmMap, *i810XvMCDrmMapPtr; + +/*************************************************************************** +// i810XvMCContext: Private Context data referenced via the privData +// pointer in the XvMCContext structure. +***************************************************************************/ +typedef struct _i810XvMCContext { + int fd; /* File descriptor for /dev/dri */ + i810XvMCDrmMap overlay; + i810XvMCDrmMap surfaces; + drmBufMapPtr dmabufs; /* Data structure to hold available dma buffers */ + drmContext drmcontext; + unsigned int last_render; + unsigned int last_flip; + unsigned short ref; + unsigned short current; + int lock; /* Lightweight lock to avoid locking twice */ + char busIdString[10]; /* PCI:0:1:0 or PCI:0:2:0 */ + i810OverlayRecPtr oregs; + unsigned int dual_prime; /* Flag to identify when dual prime is in use. */ + unsigned int fb_base; + Atom xv_colorkey; + Atom xv_brightness; + Atom xv_contrast; + Atom xv_saturation; + int brightness; + int saturation; + int contrast; + int colorkey; +} i810XvMCContext; + +/*************************************************************************** +// i810XvMCSurface: Private data structure for each XvMCSurface. This +// structure is referenced by the privData pointer in the XvMCSurface +// structure. +***************************************************************************/ +typedef struct _i810XvMCSurface { + unsigned int pitch; + unsigned int dbi1y; /* Destination buffer info command word 1 for Y */ + unsigned int dbi1u; /* Destination buffer info command word 1 for U */ + unsigned int dbi1v; /* Destination buffer info command word 1 for V */ + unsigned int dbv1; /* Destination buffer variables command word 1 */ + unsigned int mi1y; /* Map Info command word 1 (Minus bit 28) for Y */ + unsigned int mi1u; /* Map Info command word 1 (Minus bit 28) for U */ + unsigned int mi1v; /* Map Info command word 1 (Minus bit 28) for V */ + unsigned int mi2y; /* Map info command word 2 for y */ + unsigned int mi2u; /* Map info command word 2 for y */ + unsigned int mi2v; /* Map info command word 2 for y */ + unsigned int mi3y; /* Map info command word 3 */ + unsigned int mi3u; /* Map info command word 3 */ + unsigned int mi3v; /* Map info command word 3 */ + unsigned int last_render; + unsigned int last_flip; + unsigned int second_field; /* Flags a surface that is only half done */ + drmAddress data; + drmHandle offset; + unsigned int offsets[3]; + i810XvMCContext *privContext; +} i810XvMCSurface; + +/*************************************************************************** +// i810XvMCSubpicture: Private data structure for each XvMCSubpicture. This +// structure is referenced by the privData pointer in the XvMCSubpicture +// structure. +***************************************************************************/ +typedef struct _i810XvMCSubpicture { + unsigned int pitch; + unsigned int dbi1; /* Destination buffer info command word 1 */ + unsigned int dbv1; /* Destination buffer variables command word */ + unsigned int mi1; /* Map Info command word 1 (Minus bit 28) */ + unsigned int mi2; /* Map info command word 2 */ + unsigned int mi3; /* Map info command word 3 */ + unsigned int last_render; + unsigned int last_flip; + drmAddress data; + drmHandle offset; + unsigned int offsets[1]; + unsigned char palette[3][16]; + i810XvMCContext *privContext; +} i810XvMCSubpicture; + +typedef struct _Box { + int x1,y1,x2,y2; +} Box, *BoxPtr; + +/*************************************************************************** +// drm_i810_overlay_t: Structure returned by overlay info ioctl. +// NOTE: If you change this structure you will have to change the equiv. +// structure in the kernel. +***************************************************************************/ +typedef struct _drm_i810_overlay_t { + unsigned int offset; + unsigned int physical; +} drm_i810_overlay_t; + +/*************************************************************************** +// drm_i810_dma_t: Structure used by dma allocation ioctl. +// NOTE: If you change this structure you will have to change the equiv. +// structure in the kernel. +***************************************************************************/ +typedef struct _drm_i810_dma { + void *virtual; + int request_idx; + int request_size; + int granted; +} drm_i810_dma_t; + +/*************************************************************************** +// drm_i810_mc_t: Structure used by mc dispatch ioctl. +// NOTE: If you change this structure you will have to change the equiv. +// structure in the kernel. +***************************************************************************/ +typedef struct _drm_i810_mc { + int idx; /* buffer index */ + int used; /* nr bytes in use */ + int num_blocks; /* number of GFXBlocks */ + int *length; /* List of lengths for GFXBlocks */ + unsigned int last_render; /* Last render request */ +} drm_i810_mc_t; + +/* Subpicture fourcc */ +#define FOURCC_IA44 0x34344149 + +/* Static Parameters */ +#define I810_XVMC_MAXWIDTH 720 +#define I810_XVMC_MAXHEIGHT 576 +#define I810_DEFAULT16_COLORKEY 31 +#define I810_DMA_BUF_NR 256 + +/* COMMANDS */ +#define CMD_FLUSH ((4<<23) | 0x1) +#define BOOLEAN_ENA_1 ((3<<29) | (3<<24) | (3<<2)) +#define BOOLEAN_ENA_2 ((3<<29) | (4<<24) | (3<<16) | (1<<3) | (1<<2)) +#define DEST_BUFFER_INFO (0x15<<23) +#define DEST_BUFFER_VAR ((0x3<<29) | (0x1d<<24) | (0x85<<16)) +#define DRAWING_RECT_INFO ((3<<29) | (0x1d<<24) | (0x80<<16) | 3) +#define GFXBLOCK ((0x3<<29) | (0x1e<<24)) +#define CMD_MAP_INFO ((0x3<<29) | (0x1d<<24) | 0x2) +#define MAP_PALETTE_LOAD ((3<<29) | (0x1d<<24) | (0x82<<16) | 0xff) +#define VERTEX_FORMAT ((3<<29) | (0x5<<24)) +#define SRC_DEST_BLEND_MONO ((3<<29) | (8<<24)) + +/* Bit Patterns */ + +/* + * OV0CMD - Overlay Command Register + */ +#define VERTICAL_CHROMINANCE_FILTER 0x70000000 +#define VC_SCALING_OFF 0x00000000 +#define VC_LINE_REPLICATION 0x10000000 +#define VC_UP_INTERPOLATION 0x20000000 +#define VC_PIXEL_DROPPING 0x50000000 +#define VC_DOWN_INTERPOLATION 0x60000000 +#define VERTICAL_LUMINANCE_FILTER 0x0E000000 +#define VL_SCALING_OFF 0x00000000 +#define VL_LINE_REPLICATION 0x02000000 +#define VL_UP_INTERPOLATION 0x04000000 +#define VL_PIXEL_DROPPING 0x0A000000 +#define VL_DOWN_INTERPOLATION 0x0C000000 +#define HORIZONTAL_CHROMINANCE_FILTER 0x01C00000 +#define HC_SCALING_OFF 0x00000000 +#define HC_LINE_REPLICATION 0x00400000 +#define HC_UP_INTERPOLATION 0x00800000 +#define HC_PIXEL_DROPPING 0x01400000 +#define HC_DOWN_INTERPOLATION 0x01800000 +#define HORIZONTAL_LUMINANCE_FILTER 0x00380000 +#define HL_SCALING_OFF 0x00000000 +#define HL_LINE_REPLICATION 0x00080000 +#define HL_UP_INTERPOLATION 0x00100000 +#define HL_PIXEL_DROPPING 0x00280000 +#define HL_DOWN_INTERPOLATION 0x00300000 + +#define Y_ADJUST 0x00010000 +#define OV_BYTE_ORDER 0x0000C000 +#define UV_SWAP 0x00004000 +#define Y_SWAP 0x00008000 +#define Y_AND_UV_SWAP 0x0000C000 +#define SOURCE_FORMAT 0x00003C00 +#define RGB_555 0x00000800 +#define RGB_565 0x00000C00 +#define YUV_422 0x00002000 +#define YUV_411 0x00002400 +#define YUV_420 0x00003000 +#define YUV_410 0x00003800 +#define VERTICAL_PHASE_BOTH 0x00000020 +#define FLIP_TYPE_FIELD 0x00000020 +#define FLIP_TYPE_FRAME 0x00000000 +#define BUFFER_AND_FIELD 0x00000006 +#define BUFFER0_FIELD0 0x00000000 +#define BUFFER0_FIELD1 0x00000002 +#define BUFFER1_FIELD0 0x00000004 +#define BUFFER1_FIELD1 0x00000006 +#define OVERLAY_ENABLE 0x00000001 + +/* + * DOV0STA - Display/Overlay 0 Status Register + */ +#define DOV0STA 0x30008 +#define OV0ADD 0x30000 +#define MINUV_SCALE 0x1 + +#define RGB16ToColorKey(c) \ + (((c & 0xF800) << 8) | ((c & 0x07E0) << 5) | ((c & 0x001F) << 3)) + +/* Locking Macros lightweight lock used to prevent relocking */ +#define I810_LOCK(c,f) \ + if(!c->lock) { \ + drmGetLock(c->fd, c->drmcontext, f); \ + } \ + c->lock++; + +#define I810_UNLOCK(c) \ + c->lock--; \ + if(!c->lock) { \ + drmUnlock(c->fd, c->drmcontext); \ + } + +/* + Block until the passed in value (n) is the active + buffer on the overlay. +*/ +#define BLOCK_OVERLAY(c,n) \ + do { \ + int temp,i=0; \ + while(i < 100000) { \ + temp = GET_FSTATUS(c); \ + if(((temp & (1<<20))>>20) == n) { \ + break; \ + } \ + usleep(10); \ + } \ + if(i == 100000) { \ + printf("Overlay Lockup.\n"); \ + return BadAlloc; \ + } \ + }while(0); + +#define OVERLAY_INFO(c,i) drmCommandRead(c->fd, DRM_I810_OV0INFO, &i, sizeof(i)) +#define OVERLAY_FLIP(c) drmCommandNone(c->fd, DRM_I810_OV0FLIP) +#define GET_FSTATUS(c) drmCommandNone(c->fd, DRM_I810_FSTATUS) +#define I810_MC(c,mc) drmCommandWrite(c->fd, DRM_I810_MC, &mc, sizeof(mc)) +#define GET_RSTATUS(c) drmCommandNone(c->fd, DRM_I810_RSTATUS) +#define GET_BUFFER(c,dma) drmCommandWriteRead(c->fd, DRM_I810_GETBUF, &dma, sizeof(drmI810DMA)) +#define FLUSH(c) drmCommandNone(c->fd, DRM_I810_FLUSH) + +/* + Definitions for temporary wire protocol hooks to be replaced + when a HW independent libXvMC is created. +*/ +extern Status _xvmc_create_context(Display *dpy, XvMCContext *context, + int *priv_count, uint **priv_data); + +extern Status _xvmc_destroy_context(Display *dpy, XvMCContext *context); + +extern Status _xvmc_create_surface(Display *dpy, XvMCContext *context, + XvMCSurface *surface, int *priv_count, + uint **priv_data); + +extern Status _xvmc_destroy_surface(Display *dpy, XvMCSurface *surface); + +extern Status _xvmc_create_subpicture(Display *dpy, XvMCContext *context, + XvMCSubpicture *subpicture, + int *priv_count, uint **priv_data); + +extern Status _xvmc_destroy_subpicture(Display *dpy, + XvMCSubpicture *subpicture); + +/* + Prototypes +*/ +drmBufPtr i810_get_free_buffer(i810XvMCContext *pI810XvMC); +void i810_free_privContext(i810XvMCContext *pI810XvMC); +void dp(unsigned int *address, unsigned int i); + +#endif + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + |