diff options
author | Matthieu Herrb <matthieu@cvs.openbsd.org> | 2007-11-24 19:45:09 +0000 |
---|---|---|
committer | Matthieu Herrb <matthieu@cvs.openbsd.org> | 2007-11-24 19:45:09 +0000 |
commit | 621df55ad49646572010dd46760717472a2cf8f4 (patch) | |
tree | a225c44e797ed935a3730d1c30fa22fffc997cea /driver | |
parent | 1411a42453b397a8d9010bb67204759600520dcd (diff) |
xf86-video-intel 2.2.0
Diffstat (limited to 'driver')
91 files changed, 30759 insertions, 0 deletions
diff --git a/driver/xf86-video-intel/man/intel.man b/driver/xf86-video-intel/man/intel.man new file mode 100644 index 000000000..6245736b7 --- /dev/null +++ b/driver/xf86-video-intel/man/intel.man @@ -0,0 +1,217 @@ +.\" shorthand for double quote that works everywhere. +.ds q \N'34' +.TH intel __drivermansuffix__ __vendorversion__ +.SH NAME +intel \- Intel integrated graphics chipsets +.SH SYNOPSIS +.nf +.B "Section \*qDevice\*q" +.BI " Identifier \*q" devname \*q +.B " Driver \*qintel\*q" +\ \ ... +.B EndSection +.fi +.SH DESCRIPTION +.B intel +is an __xservername__ driver for Intel integrated graphics chipsets. +The driver supports depths 8, 15, 16 and 24. All visual types are +supported in depth 8. For the i810/i815 other depths support the +TrueColor and DirectColor visuals. For the i830M and later, only the +TrueColor visual is supported for depths greater than 8. 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 +the 830M and later. +.SH SUPPORTED HARDWARE +.B intel +supports the i810, i810-DC100, i810e, i815, i830M, 845G, 852GM, 855GM, +865G, 915G, 915GM, 945G, 945GM, 965G, 965Q, 946GZ, 965GM, 945GME, +G33, Q33, and Q35 chipsets. + +.SH CONFIGURATION DETAILS +Please refer to __xconfigfile__(__filemansuffix__) for general configuration +details. This section only covers configuration details specific to this +driver. +.PP +The Intel 8xx and 9xx families of integrated graphics chipsets have a unified +memory architecture and uses system memory for video ram. For the i810 and +i815 family of chipset, operating system support for allocating system +memory for video use is required in order to use this driver. For the 830M +and later, this is required in order for the driver to use more video ram +than has been pre-allocated at boot time by the BIOS. This is usually +achieved with an "agpgart" or "agp" kernel driver. Linux, FreeBSD, OpenBSD, +NetBSD, and Solaris have such kernel drivers available. +.PP +By default, the i810 will use 8 megabytes +of system memory for graphics. For the 830M and later, the driver will +automatically size its memory allocation according to the features it will +support. The +.B VideoRam +option, which in the past had been necessary to allow more than some small +amount of memory to be allocated, is now ignored. +.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 for configurations where the hardware cursor +is available. +.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 when XAA acceleration is enabled. Decreasing this +amount leaves more for 3D textures. Increasing it can improve 2D performance +at the expense of 3D performance. +Default: depends on the resolution, depth, and available video memory. The +driver attempts to allocate space for at 3 screenfuls of pixmaps plus an +HD-sized XV video. The default used for a specific configuration can be found +by examining the __xservername__ log file. +.TP +.BI "Option \*qFramebufferCompression\*q \*q" boolean \*q +This option controls whether the framebuffer compression feature is enabled. +If possible, the front buffer will be allocated in a tiled format and compressed +periodically to save memory bandwidth and power. +This option is only available on mobile chipsets. +Default: enabled on supported configurations. +.TP +.BI "Option \*qTiling\*q \*q" boolean \*q +This option controls whether memory buffers are allocated in tiled mode. In +many cases (especially for complex rendering), tiling can improve performance. +Default: enabled. +.TP +.BI "Option \*qDRI\*q \*q" boolean \*q +Disable or enable DRI support. +Default: DRI is enabled for configurations where it is supported. + +.PP +The following driver +.B Options +are supported for the i810 and i815 chipsets: +.TP +.BI "Option \*qDDC\*q \*q" boolean \*q +Disable or enable DDC support. +Default: enabled. +.TP +.BI "Option \*qDac6Bit\*q \*q" boolean \*q +Enable or disable 6-bits per RGB for 8-bit modes. +Default: 8-bits per RGB for 8-bit modes. +.TP +.BI "Option \*qXvMCSurfaces\*q \*q" integer \*q +This option enables XvMC. The integer parameter specifies the number of +surfaces to use. Valid values are 6 and 7. +Default: XvMC is disabled. + +.PP +The following driver +.B Options +are supported for the 830M and later chipsets: +.TP +.BI "Option \*qVideoKey\*q \*q" integer \*q +This is the same as the +.B \*qColorKey\*q +option described above. It is provided for compatibility with most +other drivers. +.TP +.BI "Option \*qXVideo\*q \*q" boolean \*q +Disable or enable XVideo support. +Default: XVideo is enabled for configurations where it is supported. +.TP +.BI "Option \*qLegacy3D\*q \*q" boolean \*q +Enable support for the legacy i915_dri.so 3D driver. +This will, among other things, make the 2D driver tell libGL to +load the 3D driver i915_dri.so instead of the newer i915tex_dri.so. +This option is only used for chipsets in the range i830-i945. +Default for i830-i945 series: Enabled. +Default for i810: The option is not used. +Default for i965: The option is always true. +.TP +.BI "Option \*qAperTexSize\*q \*q" integer \*q +Give the size in kiB of the AGP aperture area that is reserved for the +DRM memory manager present in i915 drm from version 1.7.0 and upwards, +and that is used with the 3D driver in Mesa from version 6.5.2 and +upwards. If the size is set too high to make room for pre-allocated +VideoRam, the driver will try to reduce it automatically. If you use only +older Mesa or DRM versions, you may set this value to zero, and +activate the legacy texture pool (see +.B "Option \*qLegacy3D\*q" +). If you run 3D programs with large texture memory requirements, you might +gain some performance by increasing this value. +Default: 32768. +.TP +.BI "Option \*qPageFlip\*q \*q" boolean \*q +Enable support for page flipping. This should improve 3D performance at the +potential cost of worse performance with mixed 2D/3D. Also note that this gives +no benefit without corresponding support in the Mesa 3D driver and may not give +the full benefit without triple buffering (see +.B "Option \*qTripleBuffer\*q" +). +Default for i810: The option is not used. +Default for i830 and above: Disabled (This option is currently unstable). +.TP +.BI "Option \*qTripleBuffer\*q \*q" boolean \*q +Enable support for triple buffering. This should improve 3D performance at the +potential cost of worse performance with mixed 2D/3D. Also note that this gives +no benefit without corresponding support in the Mesa 3D driver and may not give +any benefit without page flipping either (see +.B "Option \*qPageFlip\*q" +). +Default for i810: The option is not used. +Default for i830 and above: Disabled. +.TP +.BI "Option \*qAccelMethod\*q \*q" string \*q +Choose acceleration architecture, either "XAA" or "EXA". XAA is the old +XFree86 based acceleration architecture. EXA is a newer and simpler +acceleration architecture designed to better accelerate the X Render extension. +Default: "EXA". +.TP +.BI "Option \*qModeDebug\*q \*q" boolean \*q +Enable printing of additional debugging information about modesetting to +the server log. + +.PP +The 830M and newer driver supports the following outputs through RandR 1.2: +.PP +.TP +.BI "VGA" +Analog VGA output +.TP +.BI "LVDS" +Laptop panel. Properties: + BACKLIGHT - set backlight level + BACKLIGHT_CONTROL - set backlight level control method (i.e. use kernel interfaces, native LVDS power register, legacy register, or combination) +.TP +.BI "TV" +Integrated TV output +.TP +.BI "TMDS-1" +First DVI SDVO output +.TP +.BI "TMDS-2" +Second DVI SDVO output +.PP +SDVO and DVO TV outputs are not supported by the driver at this time. +.PP +See __xconfigfile__(__filemansuffix__) for information on associating Monitor +sections with these outputs for configuration. + +.SH "SEE ALSO" +__xservername__(__appmansuffix__), __xconfigfile__(__filemansuffix__), xorgconfig(__appmansuffix__), Xserver(__appmansuffix__), 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. 915G, +915GM, 945G, 945GM, 965G, 965Q and 946GZ support added by Alan Hourihane and +Keith Whitwell. Lid status support added by Alan Hourihane. Textured video +support for 915G and later chips, RandR 1.2 and hardware modesetting added +by Eric Anholt and Keith Packard. EXA and Render acceleration added by Wang +Zhenyu. TV out support added by Zou Nan Hai and Keith Packard. 965GM, G33, +Q33, and Q35 support added by Wang Zhenyu. diff --git a/driver/xf86-video-intel/src/bios_reader/Makefile.am b/driver/xf86-video-intel/src/bios_reader/Makefile.am new file mode 100644 index 000000000..76ad15f7f --- /dev/null +++ b/driver/xf86-video-intel/src/bios_reader/Makefile.am @@ -0,0 +1,13 @@ +AM_CFLAGS = @WARN_CFLAGS@ @XORG_CFLAGS@ @XMODES_CFLAGS@ + +noinst_PROGRAMS = bios_reader $(BIOS_DUMPER) + +if LIBPCIACCESS +BIOS_DUMPER = bios_dumper + +bios_dumper_SOURCES = bios_dumper.c + +bios_dumper_CFLAGS = $(PCIACCESS_CFLAGS) +bios_dumper_LDADD = $(PCIACCESS_LIBS) + +endif diff --git a/driver/xf86-video-intel/src/bios_reader/Makefile.in b/driver/xf86-video-intel/src/bios_reader/Makefile.in new file mode 100644 index 000000000..32beb0b5c --- /dev/null +++ b/driver/xf86-video-intel/src/bios_reader/Makefile.in @@ -0,0 +1,495 @@ +# Makefile.in generated by automake 1.10 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +noinst_PROGRAMS = bios_reader$(EXEEXT) $(am__EXEEXT_1) +subdir = src/bios_reader +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +@LIBPCIACCESS_TRUE@am__EXEEXT_1 = bios_dumper$(EXEEXT) +PROGRAMS = $(noinst_PROGRAMS) +am__bios_dumper_SOURCES_DIST = bios_dumper.c +@LIBPCIACCESS_TRUE@am_bios_dumper_OBJECTS = \ +@LIBPCIACCESS_TRUE@ bios_dumper-bios_dumper.$(OBJEXT) +bios_dumper_OBJECTS = $(am_bios_dumper_OBJECTS) +am__DEPENDENCIES_1 = +@LIBPCIACCESS_TRUE@bios_dumper_DEPENDENCIES = $(am__DEPENDENCIES_1) +bios_dumper_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(bios_dumper_CFLAGS) \ + $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +bios_reader_SOURCES = bios_reader.c +bios_reader_OBJECTS = bios_reader.$(OBJEXT) +bios_reader_LDADD = $(LDADD) +DEFAULT_INCLUDES = -I. -I$(top_builddir)@am__isrc@ +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(bios_dumper_SOURCES) bios_reader.c +DIST_SOURCES = $(am__bios_dumper_SOURCES_DIST) bios_reader.c +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ADMIN_MAN_DIR = @ADMIN_MAN_DIR@ +ADMIN_MAN_SUFFIX = @ADMIN_MAN_SUFFIX@ +AMTAR = @AMTAR@ +APP_MAN_DIR = @APP_MAN_DIR@ +APP_MAN_SUFFIX = @APP_MAN_SUFFIX@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DRIVER_MAN_DIR = @DRIVER_MAN_DIR@ +DRIVER_MAN_SUFFIX = @DRIVER_MAN_SUFFIX@ +DRIVER_NAME = @DRIVER_NAME@ +DRI_CFLAGS = @DRI_CFLAGS@ +DRI_LIBS = @DRI_LIBS@ +DRI_MM_CFLAGS = @DRI_MM_CFLAGS@ +DRI_MM_LIBS = @DRI_MM_LIBS@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +FILE_MAN_DIR = @FILE_MAN_DIR@ +FILE_MAN_SUFFIX = @FILE_MAN_SUFFIX@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIB_MAN_DIR = @LIB_MAN_DIR@ +LIB_MAN_SUFFIX = @LIB_MAN_SUFFIX@ +LINUXDOC = @LINUXDOC@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MAKE_HTML = @MAKE_HTML@ +MAKE_PDF = @MAKE_PDF@ +MAKE_PS = @MAKE_PS@ +MAKE_TEXT = @MAKE_TEXT@ +MISC_MAN_DIR = @MISC_MAN_DIR@ +MISC_MAN_SUFFIX = @MISC_MAN_SUFFIX@ +MKDIR_P = @MKDIR_P@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PCIACCESS_CFLAGS = @PCIACCESS_CFLAGS@ +PCIACCESS_LIBS = @PCIACCESS_LIBS@ +PKG_CONFIG = @PKG_CONFIG@ +PS2PDF = @PS2PDF@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +WARN_CFLAGS = @WARN_CFLAGS@ +XMODES_CFLAGS = @XMODES_CFLAGS@ +XORG_CFLAGS = @XORG_CFLAGS@ +XORG_LIBS = @XORG_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +gen4asm = @gen4asm@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +moduledir = @moduledir@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AM_CFLAGS = @WARN_CFLAGS@ @XORG_CFLAGS@ @XMODES_CFLAGS@ +@LIBPCIACCESS_TRUE@BIOS_DUMPER = bios_dumper +@LIBPCIACCESS_TRUE@bios_dumper_SOURCES = bios_dumper.c +@LIBPCIACCESS_TRUE@bios_dumper_CFLAGS = $(PCIACCESS_CFLAGS) +@LIBPCIACCESS_TRUE@bios_dumper_LDADD = $(PCIACCESS_LIBS) +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/bios_reader/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/bios_reader/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstPROGRAMS: + @list='$(noinst_PROGRAMS)'; for p in $$list; do \ + f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f $$p $$f"; \ + rm -f $$p $$f ; \ + done +bios_dumper$(EXEEXT): $(bios_dumper_OBJECTS) $(bios_dumper_DEPENDENCIES) + @rm -f bios_dumper$(EXEEXT) + $(bios_dumper_LINK) $(bios_dumper_OBJECTS) $(bios_dumper_LDADD) $(LIBS) +bios_reader$(EXEEXT): $(bios_reader_OBJECTS) $(bios_reader_DEPENDENCIES) + @rm -f bios_reader$(EXEEXT) + $(LINK) $(bios_reader_OBJECTS) $(bios_reader_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bios_dumper-bios_dumper.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bios_reader.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +bios_dumper-bios_dumper.o: bios_dumper.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(bios_dumper_CFLAGS) $(CFLAGS) -MT bios_dumper-bios_dumper.o -MD -MP -MF $(DEPDIR)/bios_dumper-bios_dumper.Tpo -c -o bios_dumper-bios_dumper.o `test -f 'bios_dumper.c' || echo '$(srcdir)/'`bios_dumper.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/bios_dumper-bios_dumper.Tpo $(DEPDIR)/bios_dumper-bios_dumper.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='bios_dumper.c' object='bios_dumper-bios_dumper.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(bios_dumper_CFLAGS) $(CFLAGS) -c -o bios_dumper-bios_dumper.o `test -f 'bios_dumper.c' || echo '$(srcdir)/'`bios_dumper.c + +bios_dumper-bios_dumper.obj: bios_dumper.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(bios_dumper_CFLAGS) $(CFLAGS) -MT bios_dumper-bios_dumper.obj -MD -MP -MF $(DEPDIR)/bios_dumper-bios_dumper.Tpo -c -o bios_dumper-bios_dumper.obj `if test -f 'bios_dumper.c'; then $(CYGPATH_W) 'bios_dumper.c'; else $(CYGPATH_W) '$(srcdir)/bios_dumper.c'; fi` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/bios_dumper-bios_dumper.Tpo $(DEPDIR)/bios_dumper-bios_dumper.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='bios_dumper.c' object='bios_dumper-bios_dumper.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(bios_dumper_CFLAGS) $(CFLAGS) -c -o bios_dumper-bios_dumper.obj `if test -f 'bios_dumper.c'; then $(CYGPATH_W) 'bios_dumper.c'; else $(CYGPATH_W) '$(srcdir)/bios_dumper.c'; fi` + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-exec-am: + +install-html: install-html-am + +install-info: install-info-am + +install-man: + +install-pdf: install-pdf-am + +install-ps: install-ps-am + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstPROGRAMS ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/driver/xf86-video-intel/src/bios_reader/bios_dumper.c b/driver/xf86-video-intel/src/bios_reader/bios_dumper.c new file mode 100644 index 000000000..6f163d56b --- /dev/null +++ b/driver/xf86-video-intel/src/bios_reader/bios_dumper.c @@ -0,0 +1,99 @@ +/* + * Copyright © 2007 Intel Corporation + * + * 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 + * THE AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> +#include <pciaccess.h> +#include <err.h> + +static void usage(void) +{ + fprintf(stderr, "usage: bios_dumper <filename>\n"); + exit(1); +} + +int main(int argc, char **argv) +{ + struct pci_device *dev; + void *bios; + int err, fd; + + if (argc != 2) + usage(); + + err = pci_system_init(); + if (err != 0) { + fprintf(stderr, "Couldn't initialize PCI system: %s\n", strerror(err)); + exit(1); + } + + /* Grab the graphics card */ + dev = pci_device_find_by_slot(0, 0, 2, 0); + if (dev == NULL) + errx(1, "Couldn't find graphics card"); + + err = pci_device_probe(dev); + if (err != 0) { + fprintf(stderr, "Couldn't probe graphics card: %s\n", strerror(err)); + exit(1); + } + + if (dev->vendor_id != 0x8086) + errx(1, "Graphics card is non-intel"); + + bios = malloc(dev->rom_size); + if (bios == NULL) + errx(1, "Couldn't allocate memory for BIOS data\n"); + + err = pci_device_read_rom(dev, bios); + if (err != 0) { + fprintf(stderr, "Couldn't read graphics card ROM: %s\n", + strerror(err)); + exit(1); + } + + fd = open(argv[1], O_RDWR | O_CREAT | O_TRUNC, DEFFILEMODE); + if (fd < 0) { + fprintf(stderr, "Couldn't open output: %s\n", strerror(errno)); + exit(1); + } + + if (write(fd, bios, dev->rom_size) < dev->rom_size) { + fprintf(stderr, "Couldn't write BIOS data: %s\n", strerror(errno)); + exit(1); + } + + close(fd); + pci_system_cleanup(); + + return 0; +} diff --git a/driver/xf86-video-intel/src/bios_reader/bios_reader.c b/driver/xf86-video-intel/src/bios_reader/bios_reader.c new file mode 100644 index 000000000..9ec73c132 --- /dev/null +++ b/driver/xf86-video-intel/src/bios_reader/bios_reader.c @@ -0,0 +1,158 @@ +/* + * Copyright © 2006 Intel Corporation + * + * 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 + * THE AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +#include "../i830_bios.h" + +#define _PARSE_EDID_ +#include "edid.h" + + +/* Make a fake pI830 so we can easily pull i830_bios.c code in here. */ +struct _fake_i830 { + CARD8 *VBIOS; +}; +struct _fake_i830 I830; +struct _fake_i830 *pI830 = &I830; + +#define INTEL_BIOS_8(_addr) (pI830->VBIOS[_addr]) +#define INTEL_BIOS_16(_addr) (pI830->VBIOS[_addr] | \ + (pI830->VBIOS[_addr + 1] << 8)) +#define INTEL_BIOS_32(_addr) (pI830->VBIOS[_addr] | \ + (pI830->VBIOS[_addr + 1] << 8) \ + (pI830->VBIOS[_addr + 2] << 16) \ + (pI830->VBIOS[_addr + 3] << 24)) + +int main(int argc, char **argv) +{ + FILE *f; + int bios_size = 65536; + struct vbt_header *vbt; + struct bdb_header *bdb; + int vbt_off, bdb_off, bdb_block_off, block_size; + int panel_type = -1, i; + char *filename = "bios"; + + if (argc == 2) + filename = argv[1]; + + f = fopen(filename, "r"); + if (!f) { + printf("Couldn't open %s\n", filename); + return 1; + } + + pI830->VBIOS = calloc(1, bios_size); + if (fread(pI830->VBIOS, 1, bios_size, f) != bios_size) + return 1; + + vbt_off = INTEL_BIOS_16(0x1a); + printf("VBT offset: %08x\n", vbt_off); + vbt = (struct vbt_header *)(pI830->VBIOS + vbt_off); + printf("VBT sig: %20s\n", vbt->signature); + printf("VBT vers: %d.%d\n", vbt->version / 100, vbt->version % 100); + + bdb_off = vbt_off + vbt->bdb_offset; + bdb = (struct bdb_header *)(pI830->VBIOS + bdb_off); + printf("BDB sig: %16s\n", bdb->signature); + printf("BDB vers: %d.%d\n", bdb->version / 100, bdb->version % 100); + for (bdb_block_off = bdb->header_size; bdb_block_off < bdb->bdb_size; + bdb_block_off += block_size) + { + int start = bdb_off + bdb_block_off; + int id; + struct lvds_bdb_1 *lvds1; + struct lvds_bdb_2 *lvds2; + struct lvds_bdb_2_fp_params *fpparam; + struct lvds_bdb_2_fp_edid_dtd *fptiming; + CARD8 *timing_ptr; + + id = INTEL_BIOS_8(start); + block_size = INTEL_BIOS_16(start + 1) + 3; + printf("BDB block type %03d size %d\n", id, block_size); + switch (id) { + case 40: + lvds1 = (struct lvds_bdb_1 *)(pI830->VBIOS + start); + panel_type = lvds1->panel_type; + printf("Panel type: %d, caps %04x\n", panel_type, lvds1->caps); + break; + case 41: + if (panel_type == -1) { + printf("Found panel block with no panel type\n"); + break; + } + + lvds2 = (struct lvds_bdb_2 *)(pI830->VBIOS + start); + + printf("Entries per table: %d\n", lvds2->table_size); + for (i = 0; i < 16; i++) { + char marker; + fpparam = (struct lvds_bdb_2_fp_params *)(pI830->VBIOS + + bdb_off + lvds2->panels[i].fp_params_offset); + fptiming = (struct lvds_bdb_2_fp_edid_dtd *)(pI830->VBIOS + + bdb_off + lvds2->panels[i].fp_edid_dtd_offset); + timing_ptr = pI830->VBIOS + bdb_off + + lvds2->panels[i].fp_edid_dtd_offset; + if (fpparam->terminator != 0xffff) { + /* Apparently the offsets are wrong for some BIOSes, so we + * try the other offsets if we find a bad terminator. + */ + fpparam = (struct lvds_bdb_2_fp_params *)(pI830->VBIOS + + bdb_off + lvds2->panels[i].fp_params_offset + 8); + fptiming = (struct lvds_bdb_2_fp_edid_dtd *)(pI830->VBIOS + + bdb_off + lvds2->panels[i].fp_edid_dtd_offset + 8); + timing_ptr = pI830->VBIOS + bdb_off + + lvds2->panels[i].fp_edid_dtd_offset + 8; + + if (fpparam->terminator != 0xffff) + continue; + } + if (i == panel_type) + marker = '*'; + else + marker = ' '; + printf("%c Panel index %02i xres %d yres %d clock %d\n", marker, + i, fpparam->x_res, fpparam->y_res, + _PIXEL_CLOCK(timing_ptr)); + printf(" %d %d %d %d %d %d %d %d\n", + _H_ACTIVE(timing_ptr), _H_BLANK(timing_ptr), + _H_SYNC_OFF(timing_ptr), _H_SYNC_WIDTH(timing_ptr), + _V_ACTIVE(timing_ptr), _V_BLANK(timing_ptr), + _V_SYNC_OFF(timing_ptr), _V_SYNC_WIDTH(timing_ptr)); + } + + printf("Panel of size %dx%d\n", fpparam->x_res, fpparam->y_res); + break; + } + } + + return 0; +} diff --git a/driver/xf86-video-intel/src/ch7017/Makefile.am b/driver/xf86-video-intel/src/ch7017/Makefile.am new file mode 100644 index 000000000..71c508538 --- /dev/null +++ b/driver/xf86-video-intel/src/ch7017/Makefile.am @@ -0,0 +1,15 @@ +# this is obnoxious: +# -module lets us name the module exactly how we want +# -avoid-version prevents gratuitous .0.0.0 version numbers on the end +# _ladir passes a dummy rpath to libtool so the thing will actually link +# TODO: -nostdlib/-Bstatic/-lgcc platform magic, not installing the .a, etc. +AM_CFLAGS = @WARN_CFLAGS@ @XMODES_CFLAGS@ @XORG_CFLAGS@ @DRI_CFLAGS@ + +ch7017_la_LTLIBRARIES = ch7017.la +ch7017_la_LDFLAGS = -module -avoid-version +ch7017_ladir = @moduledir@/drivers + +ch7017_la_SOURCES = \ + ch7017.c \ + ch7017_module.c \ + ch7017_reg.h diff --git a/driver/xf86-video-intel/src/ch7017/Makefile.in b/driver/xf86-video-intel/src/ch7017/Makefile.in new file mode 100644 index 000000000..243aca457 --- /dev/null +++ b/driver/xf86-video-intel/src/ch7017/Makefile.in @@ -0,0 +1,512 @@ +# Makefile.in generated by automake 1.10 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/ch7017 +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; +am__installdirs = "$(DESTDIR)$(ch7017_ladir)" +ch7017_laLTLIBRARIES_INSTALL = $(INSTALL) +LTLIBRARIES = $(ch7017_la_LTLIBRARIES) +ch7017_la_LIBADD = +am_ch7017_la_OBJECTS = ch7017.lo ch7017_module.lo +ch7017_la_OBJECTS = $(am_ch7017_la_OBJECTS) +ch7017_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(ch7017_la_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I. -I$(top_builddir)@am__isrc@ +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(ch7017_la_SOURCES) +DIST_SOURCES = $(ch7017_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ADMIN_MAN_DIR = @ADMIN_MAN_DIR@ +ADMIN_MAN_SUFFIX = @ADMIN_MAN_SUFFIX@ +AMTAR = @AMTAR@ +APP_MAN_DIR = @APP_MAN_DIR@ +APP_MAN_SUFFIX = @APP_MAN_SUFFIX@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DRIVER_MAN_DIR = @DRIVER_MAN_DIR@ +DRIVER_MAN_SUFFIX = @DRIVER_MAN_SUFFIX@ +DRIVER_NAME = @DRIVER_NAME@ +DRI_CFLAGS = @DRI_CFLAGS@ +DRI_LIBS = @DRI_LIBS@ +DRI_MM_CFLAGS = @DRI_MM_CFLAGS@ +DRI_MM_LIBS = @DRI_MM_LIBS@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +FILE_MAN_DIR = @FILE_MAN_DIR@ +FILE_MAN_SUFFIX = @FILE_MAN_SUFFIX@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIB_MAN_DIR = @LIB_MAN_DIR@ +LIB_MAN_SUFFIX = @LIB_MAN_SUFFIX@ +LINUXDOC = @LINUXDOC@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MAKE_HTML = @MAKE_HTML@ +MAKE_PDF = @MAKE_PDF@ +MAKE_PS = @MAKE_PS@ +MAKE_TEXT = @MAKE_TEXT@ +MISC_MAN_DIR = @MISC_MAN_DIR@ +MISC_MAN_SUFFIX = @MISC_MAN_SUFFIX@ +MKDIR_P = @MKDIR_P@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PCIACCESS_CFLAGS = @PCIACCESS_CFLAGS@ +PCIACCESS_LIBS = @PCIACCESS_LIBS@ +PKG_CONFIG = @PKG_CONFIG@ +PS2PDF = @PS2PDF@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +WARN_CFLAGS = @WARN_CFLAGS@ +XMODES_CFLAGS = @XMODES_CFLAGS@ +XORG_CFLAGS = @XORG_CFLAGS@ +XORG_LIBS = @XORG_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +gen4asm = @gen4asm@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +moduledir = @moduledir@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ + +# this is obnoxious: +# -module lets us name the module exactly how we want +# -avoid-version prevents gratuitous .0.0.0 version numbers on the end +# _ladir passes a dummy rpath to libtool so the thing will actually link +# TODO: -nostdlib/-Bstatic/-lgcc platform magic, not installing the .a, etc. +AM_CFLAGS = @WARN_CFLAGS@ @XMODES_CFLAGS@ @XORG_CFLAGS@ @DRI_CFLAGS@ +ch7017_la_LTLIBRARIES = ch7017.la +ch7017_la_LDFLAGS = -module -avoid-version +ch7017_ladir = @moduledir@/drivers +ch7017_la_SOURCES = \ + ch7017.c \ + ch7017_module.c \ + ch7017_reg.h + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/ch7017/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/ch7017/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-ch7017_laLTLIBRARIES: $(ch7017_la_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(ch7017_ladir)" || $(MKDIR_P) "$(DESTDIR)$(ch7017_ladir)" + @list='$(ch7017_la_LTLIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + f=$(am__strip_dir) \ + echo " $(LIBTOOL) --mode=install $(ch7017_laLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(ch7017_ladir)/$$f'"; \ + $(LIBTOOL) --mode=install $(ch7017_laLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(ch7017_ladir)/$$f"; \ + else :; fi; \ + done + +uninstall-ch7017_laLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(ch7017_la_LTLIBRARIES)'; for p in $$list; do \ + p=$(am__strip_dir) \ + echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(ch7017_ladir)/$$p'"; \ + $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(ch7017_ladir)/$$p"; \ + done + +clean-ch7017_laLTLIBRARIES: + -test -z "$(ch7017_la_LTLIBRARIES)" || rm -f $(ch7017_la_LTLIBRARIES) + @list='$(ch7017_la_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +ch7017.la: $(ch7017_la_OBJECTS) $(ch7017_la_DEPENDENCIES) + $(ch7017_la_LINK) -rpath $(ch7017_ladir) $(ch7017_la_OBJECTS) $(ch7017_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ch7017.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ch7017_module.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(ch7017_ladir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-ch7017_laLTLIBRARIES clean-generic clean-libtool \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-ch7017_laLTLIBRARIES + +install-dvi: install-dvi-am + +install-exec-am: + +install-html: install-html-am + +install-info: install-info-am + +install-man: + +install-pdf: install-pdf-am + +install-ps: install-ps-am + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-ch7017_laLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean \ + clean-ch7017_laLTLIBRARIES clean-generic clean-libtool ctags \ + distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am \ + install-ch7017_laLTLIBRARIES install-data install-data-am \ + install-dvi install-dvi-am install-exec install-exec-am \ + install-html install-html-am install-info install-info-am \ + install-man install-pdf install-pdf-am install-ps \ + install-ps-am install-strip installcheck installcheck-am \ + installdirs maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-ch7017_laLTLIBRARIES + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/driver/xf86-video-intel/src/ch7017/ch7017.c b/driver/xf86-video-intel/src/ch7017/ch7017.c new file mode 100644 index 000000000..6fc34223a --- /dev/null +++ b/driver/xf86-video-intel/src/ch7017/ch7017.c @@ -0,0 +1,325 @@ +/* + * Copyright © 2006 Intel Corporation + * + * 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 + * THE AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <unistd.h> + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86Resources.h" +#include "compiler.h" +#include "miscstruct.h" +#include "xf86i2c.h" +#include "xf86Crtc.h" +#define DPMS_SERVER +#include <X11/extensions/dpms.h> + +#include "../i2c_vid.h" +#include "ch7017_reg.h" + +struct ch7017_priv { + I2CDevRec d; + + CARD8 save_hapi; + CARD8 save_vali; + CARD8 save_valo; + CARD8 save_ailo; + CARD8 save_lvds_pll_vco; + CARD8 save_feedback_div; + CARD8 save_lvds_control_2; + CARD8 save_outputs_enable; + CARD8 save_lvds_power_down; + CARD8 save_power_management; +}; + +static void +ch7017_dump_regs(I2CDevPtr d); +static void +ch7017_dpms(I2CDevPtr d, int mode); + +static Bool +ch7017_read(struct ch7017_priv *priv, int addr, CARD8 *val) +{ + if (!xf86I2CReadByte(&priv->d, addr, val)) { + xf86DrvMsg(priv->d.pI2CBus->scrnIndex, X_ERROR, + "Unable to read from %s Slave %d.\n", + priv->d.pI2CBus->BusName, priv->d.SlaveAddr); + return FALSE; + } + return TRUE; +} + +static Bool +ch7017_write(struct ch7017_priv *priv, int addr, CARD8 val) +{ + if (!xf86I2CWriteByte(&priv->d, addr, val)) { + xf86DrvMsg(priv->d.pI2CBus->scrnIndex, X_ERROR, + "Unable to write to %s Slave %d.\n", + priv->d.pI2CBus->BusName, priv->d.SlaveAddr); + return FALSE; + } + return TRUE; +} + +/** Probes for a CH7017 on the given bus and slave address. */ +static void * +ch7017_init(I2CBusPtr b, I2CSlaveAddr addr) +{ + struct ch7017_priv *priv; + CARD8 val; + + priv = xcalloc(1, sizeof(struct ch7017_priv)); + if (priv == NULL) + return NULL; + + priv->d.DevName = "CH7017/7018/7019 LVDS Controller"; + priv->d.SlaveAddr = addr; + priv->d.pI2CBus = b; + priv->d.StartTimeout = b->StartTimeout; + priv->d.BitTimeout = b->BitTimeout; + priv->d.AcknTimeout = b->AcknTimeout; + priv->d.ByteTimeout = b->ByteTimeout; + priv->d.DriverPrivate.ptr = priv; + + if (!xf86I2CReadByte(&priv->d, CH7017_DEVICE_ID, &val)) + goto fail; + + if (val != CH7017_DEVICE_ID_VALUE && + val != CH7018_DEVICE_ID_VALUE && + val != CH7019_DEVICE_ID_VALUE) { + xf86DrvMsg(priv->d.pI2CBus->scrnIndex, X_ERROR, + "ch701x not detected, got %d: from %s Slave %d.\n", + val, priv->d.pI2CBus->BusName, priv->d.SlaveAddr); + goto fail; + } + + if (!xf86I2CDevInit(&(priv->d))) + goto fail; + + return priv; + +fail: + xfree(priv); + return NULL; +} + +static xf86OutputStatus +ch7017_detect(I2CDevPtr d) +{ + return XF86OutputStatusUnknown; +} + +static ModeStatus +ch7017_mode_valid(I2CDevPtr d, DisplayModePtr mode) +{ + if (mode->Clock > 160000) + return MODE_CLOCK_HIGH; + + return MODE_OK; +} + +static void +ch7017_mode_set(I2CDevPtr d, DisplayModePtr mode, DisplayModePtr adjusted_mode) +{ + struct ch7017_priv *priv = d->DriverPrivate.ptr; + CARD8 lvds_pll_feedback_div, lvds_pll_vco_control; + CARD8 outputs_enable, lvds_control_2, lvds_power_down; + CARD8 horizontal_active_pixel_input; + CARD8 horizontal_active_pixel_output, vertical_active_line_output; + CARD8 active_input_line_output; + + xf86DrvMsg(priv->d.pI2CBus->scrnIndex, X_INFO, + "Registers before mode setting\n"); + ch7017_dump_regs(d); + + /* LVDS PLL settings from page 75 of 7017-7017ds.pdf*/ + if (mode->Clock < 100000) { + outputs_enable = CH7017_LVDS_CHANNEL_A | CH7017_CHARGE_PUMP_LOW; + lvds_pll_feedback_div = CH7017_LVDS_PLL_FEEDBACK_DEFAULT_RESERVED | + (2 << CH7017_LVDS_PLL_FEED_BACK_DIVIDER_SHIFT) | + (13 << CH7017_LVDS_PLL_FEED_FORWARD_DIVIDER_SHIFT); + lvds_pll_vco_control = CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED | + (2 << CH7017_LVDS_PLL_VCO_SHIFT) | + (3 << CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT); + lvds_control_2 = (1 << CH7017_LOOP_FILTER_SHIFT) | + (0 << CH7017_PHASE_DETECTOR_SHIFT); + } else { + outputs_enable = CH7017_LVDS_CHANNEL_A | CH7017_CHARGE_PUMP_HIGH; + lvds_pll_feedback_div = CH7017_LVDS_PLL_FEEDBACK_DEFAULT_RESERVED | + (2 << CH7017_LVDS_PLL_FEED_BACK_DIVIDER_SHIFT) | + (3 << CH7017_LVDS_PLL_FEED_FORWARD_DIVIDER_SHIFT); + lvds_pll_feedback_div = 35; + lvds_control_2 = (3 << CH7017_LOOP_FILTER_SHIFT) | + (0 << CH7017_PHASE_DETECTOR_SHIFT); + if (1) { /* XXX: dual channel panel detection. Assume yes for now. */ + outputs_enable |= CH7017_LVDS_CHANNEL_B; + lvds_pll_vco_control = CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED | + (2 << CH7017_LVDS_PLL_VCO_SHIFT) | + (13 << CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT); + } else { + lvds_pll_vco_control = CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED | + (1 << CH7017_LVDS_PLL_VCO_SHIFT) | + (13 << CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT); + } + } + + horizontal_active_pixel_input = mode->HDisplay & 0x00ff; + + vertical_active_line_output = mode->VDisplay & 0x00ff; + horizontal_active_pixel_output = mode->HDisplay & 0x00ff; + + active_input_line_output = ((mode->HDisplay & 0x0700) >> 8) | + (((mode->VDisplay & 0x0700) >> 8) << 3); + + lvds_power_down = CH7017_LVDS_POWER_DOWN_DEFAULT_RESERVED | + (mode->HDisplay & 0x0700) >> 8; + + ch7017_dpms(d, DPMSModeOff); + ch7017_write(priv, CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT, + horizontal_active_pixel_input); + ch7017_write(priv, CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT, + horizontal_active_pixel_output); + ch7017_write(priv, CH7017_VERTICAL_ACTIVE_LINE_OUTPUT, + vertical_active_line_output); + ch7017_write(priv, CH7017_ACTIVE_INPUT_LINE_OUTPUT, + active_input_line_output); + ch7017_write(priv, CH7017_LVDS_PLL_VCO_CONTROL, lvds_pll_vco_control); + ch7017_write(priv, CH7017_LVDS_PLL_FEEDBACK_DIV, lvds_pll_feedback_div); + ch7017_write(priv, CH7017_LVDS_CONTROL_2, lvds_control_2); + ch7017_write(priv, CH7017_OUTPUTS_ENABLE, outputs_enable); + + /* Turn the LVDS back on with new settings. */ + ch7017_write(priv, CH7017_LVDS_POWER_DOWN, lvds_power_down); + + xf86DrvMsg(priv->d.pI2CBus->scrnIndex, X_INFO, + "Registers after mode setting\n"); + ch7017_dump_regs(d); +} + +/* set the CH7017 power state */ +static void +ch7017_dpms(I2CDevPtr d, int mode) +{ + struct ch7017_priv *priv = d->DriverPrivate.ptr; + CARD8 val; + + ch7017_read(priv, CH7017_LVDS_POWER_DOWN, &val); + + /* Turn off TV/VGA, and never turn it on since we don't support it. */ + ch7017_write(priv, CH7017_POWER_MANAGEMENT, + CH7017_DAC0_POWER_DOWN | + CH7017_DAC1_POWER_DOWN | + CH7017_DAC2_POWER_DOWN | + CH7017_DAC3_POWER_DOWN | + CH7017_TV_POWER_DOWN_EN); + + if (mode == DPMSModeOn) { + /* Turn on the LVDS */ + ch7017_write(priv, CH7017_LVDS_POWER_DOWN, + val & ~CH7017_LVDS_POWER_DOWN_EN); + } else { + /* Turn off the LVDS */ + ch7017_write(priv, CH7017_LVDS_POWER_DOWN, + val | CH7017_LVDS_POWER_DOWN_EN); + } + + /* XXX: Should actually wait for update power status somehow */ + usleep(50000); +} + +static void +ch7017_dump_regs(I2CDevPtr d) +{ + struct ch7017_priv *priv = d->DriverPrivate.ptr; + CARD8 val; + +#define DUMP(reg) \ +do { \ + ch7017_read(priv, reg, &val); \ + xf86DrvMsg(priv->d.pI2CBus->scrnIndex, X_INFO, \ + #reg ": %02x\n", val); \ +} while (0) + + DUMP(CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT); + DUMP(CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT); + DUMP(CH7017_VERTICAL_ACTIVE_LINE_OUTPUT); + DUMP(CH7017_ACTIVE_INPUT_LINE_OUTPUT); + DUMP(CH7017_LVDS_PLL_VCO_CONTROL); + DUMP(CH7017_LVDS_PLL_FEEDBACK_DIV); + DUMP(CH7017_LVDS_CONTROL_2); + DUMP(CH7017_OUTPUTS_ENABLE); + DUMP(CH7017_LVDS_POWER_DOWN); +} + +static void +ch7017_save(I2CDevPtr d) +{ + struct ch7017_priv *priv = d->DriverPrivate.ptr; + + ch7017_read(priv, CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT, &priv->save_hapi); + ch7017_read(priv, CH7017_VERTICAL_ACTIVE_LINE_OUTPUT, &priv->save_valo); + ch7017_read(priv, CH7017_ACTIVE_INPUT_LINE_OUTPUT, &priv->save_ailo); + ch7017_read(priv, CH7017_LVDS_PLL_VCO_CONTROL, &priv->save_lvds_pll_vco); + ch7017_read(priv, CH7017_LVDS_PLL_FEEDBACK_DIV, &priv->save_feedback_div); + ch7017_read(priv, CH7017_LVDS_CONTROL_2, &priv->save_lvds_control_2); + ch7017_read(priv, CH7017_OUTPUTS_ENABLE, &priv->save_outputs_enable); + ch7017_read(priv, CH7017_LVDS_POWER_DOWN, &priv->save_lvds_power_down); + ch7017_read(priv, CH7017_POWER_MANAGEMENT, &priv->save_power_management); +} + +static void +ch7017_restore(I2CDevPtr d) +{ + struct ch7017_priv *priv = d->DriverPrivate.ptr; + + /* Power down before changing mode */ + ch7017_dpms(d, DPMSModeOff); + + ch7017_write(priv, CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT, priv->save_hapi); + ch7017_write(priv, CH7017_VERTICAL_ACTIVE_LINE_OUTPUT, priv->save_valo); + ch7017_write(priv, CH7017_ACTIVE_INPUT_LINE_OUTPUT, priv->save_ailo); + ch7017_write(priv, CH7017_LVDS_PLL_VCO_CONTROL, priv->save_lvds_pll_vco); + ch7017_write(priv, CH7017_LVDS_PLL_FEEDBACK_DIV, priv->save_feedback_div); + ch7017_write(priv, CH7017_LVDS_CONTROL_2, priv->save_lvds_control_2); + ch7017_write(priv, CH7017_OUTPUTS_ENABLE, priv->save_outputs_enable); + ch7017_write(priv, CH7017_LVDS_POWER_DOWN, priv->save_lvds_power_down); + ch7017_write(priv, CH7017_POWER_MANAGEMENT, priv->save_power_management); +} + +I830I2CVidOutputRec ch7017_methods = { + .init = ch7017_init, + .detect = ch7017_detect, + .mode_valid = ch7017_mode_valid, + .mode_set = ch7017_mode_set, + .dpms = ch7017_dpms, + .dump_regs = ch7017_dump_regs, + .save = ch7017_save, + .restore = ch7017_restore, +}; diff --git a/driver/xf86-video-intel/src/ch7017/ch7017_module.c b/driver/xf86-video-intel/src/ch7017/ch7017_module.c new file mode 100644 index 000000000..135f3c656 --- /dev/null +++ b/driver/xf86-video-intel/src/ch7017/ch7017_module.c @@ -0,0 +1,36 @@ +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "xf86Module.h" + +static MODULESETUPPROTO(ch7017Setup); + +static XF86ModuleVersionInfo ch7017VersRec = + { + "ch7017", + MODULEVENDORSTRING, + MODINFOSTRING1, + MODINFOSTRING2, + XORG_VERSION_CURRENT, + 1, 0, 0, + ABI_CLASS_VIDEODRV, + ABI_VIDEODRV_VERSION, + MOD_CLASS_NONE, + { 0,0,0,0 } + }; + +_X_EXPORT XF86ModuleData ch7017ModuleData = { + &ch7017VersRec, + ch7017Setup, + NULL +}; + +static pointer +ch7017Setup(pointer module, pointer opts, int *errmaj, int *errmin) { + return (pointer)1; +} diff --git a/driver/xf86-video-intel/src/ch7017/ch7017_reg.h b/driver/xf86-video-intel/src/ch7017/ch7017_reg.h new file mode 100644 index 000000000..7b536bdb2 --- /dev/null +++ b/driver/xf86-video-intel/src/ch7017/ch7017_reg.h @@ -0,0 +1,162 @@ +/* + * Copyright © 2006 Intel Corporation + * + * 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 + * THE AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +#ifndef CH7017_REG_H +#define CH7017_REG_H + +#define CH7017_TV_DISPLAY_MODE 0x00 +#define CH7017_FLICKER_FILTER 0x01 +#define CH7017_VIDEO_BANDWIDTH 0x02 +#define CH7017_TEXT_ENHANCEMENT 0x03 +#define CH7017_START_ACTIVE_VIDEO 0x04 +#define CH7017_HORIZONTAL_POSITION 0x05 +#define CH7017_VERTICAL_POSITION 0x06 +#define CH7017_BLACK_LEVEL 0x07 +#define CH7017_CONTRAST_ENHANCEMENT 0x08 +#define CH7017_TV_PLL 0x09 +#define CH7017_TV_PLL_M 0x0a +#define CH7017_TV_PLL_N 0x0b +#define CH7017_SUB_CARRIER_0 0x0c +#define CH7017_CIV_CONTROL 0x10 +#define CH7017_CIV_0 0x11 +#define CH7017_CHROMA_BOOST 0x14 +#define CH7017_CLOCK_MODE 0x1c +#define CH7017_INPUT_CLOCK 0x1d +#define CH7017_GPIO_CONTROL 0x1e +#define CH7017_INPUT_DATA_FORMAT 0x1f +#define CH7017_CONNECTION_DETECT 0x20 +#define CH7017_DAC_CONTROL 0x21 +#define CH7017_BUFFERED_CLOCK_OUTPUT 0x22 +#define CH7017_DEFEAT_VSYNC 0x47 +#define CH7017_TEST_PATTERN 0x48 + +#define CH7017_POWER_MANAGEMENT 0x49 +/** Enables the TV output path. */ +#define CH7017_TV_EN (1 << 0) +#define CH7017_DAC0_POWER_DOWN (1 << 1) +#define CH7017_DAC1_POWER_DOWN (1 << 2) +#define CH7017_DAC2_POWER_DOWN (1 << 3) +#define CH7017_DAC3_POWER_DOWN (1 << 4) +/** Powers down the TV out block, and DAC0-3 */ +#define CH7017_TV_POWER_DOWN_EN (1 << 5) + +#define CH7017_VERSION_ID 0x4a + +#define CH7017_DEVICE_ID 0x4b +#define CH7017_DEVICE_ID_VALUE 0x1b +#define CH7018_DEVICE_ID_VALUE 0x1a +#define CH7019_DEVICE_ID_VALUE 0x19 + +#define CH7017_XCLK_D2_ADJUST 0x53 +#define CH7017_UP_SCALER_COEFF_0 0x55 +#define CH7017_UP_SCALER_COEFF_1 0x56 +#define CH7017_UP_SCALER_COEFF_2 0x57 +#define CH7017_UP_SCALER_COEFF_3 0x58 +#define CH7017_UP_SCALER_COEFF_4 0x59 +#define CH7017_UP_SCALER_VERTICAL_INC_0 0x5a +#define CH7017_UP_SCALER_VERTICAL_INC_1 0x5b +#define CH7017_GPIO_INVERT 0x5c +#define CH7017_UP_SCALER_HORIZONTAL_INC_0 0x5d +#define CH7017_UP_SCALER_HORIZONTAL_INC_1 0x5e + +#define CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT 0x5f +/**< Low bits of horizontal active pixel input */ + +#define CH7017_ACTIVE_INPUT_LINE_OUTPUT 0x60 +/** High bits of horizontal active pixel input */ +#define CH7017_LVDS_HAP_INPUT_MASK (0x7 << 0) +/** High bits of vertical active line output */ +#define CH7017_LVDS_VAL_HIGH_MASK (0x7 << 3) + +#define CH7017_VERTICAL_ACTIVE_LINE_OUTPUT 0x61 +/**< Low bits of vertical active line output */ + +#define CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT 0x62 +/**< Low bits of horizontal active pixel output */ + +#define CH7017_LVDS_POWER_DOWN 0x63 +/** High bits of horizontal active pixel output */ +#define CH7017_LVDS_HAP_HIGH_MASK (0x7 << 0) +/** Enables the LVDS power down state transition */ +#define CH7017_LVDS_POWER_DOWN_EN (1 << 6) +/** Enables the LVDS upscaler */ +#define CH7017_LVDS_UPSCALER_EN (1 << 7) +#define CH7017_LVDS_POWER_DOWN_DEFAULT_RESERVED 0x08 + +#define CH7017_LVDS_ENCODING 0x64 +#define CH7017_LVDS_DITHER_2D (1 << 2) +#define CH7017_LVDS_DITHER_DIS (1 << 3) +#define CH7017_LVDS_DUAL_CHANNEL_EN (1 << 4) +#define CH7017_LVDS_24_BIT (1 << 5) + +#define CH7017_LVDS_ENCODING_2 0x65 + +#define CH7017_LVDS_PLL_CONTROL 0x66 +/** Enables the LVDS panel output path */ +#define CH7017_LVDS_PANEN (1 << 0) +/** Enables the LVDS panel backlight */ +#define CH7017_LVDS_BKLEN (1 << 3) + +#define CH7017_POWER_SEQUENCING_T1 0x67 +#define CH7017_POWER_SEQUENCING_T2 0x68 +#define CH7017_POWER_SEQUENCING_T3 0x69 +#define CH7017_POWER_SEQUENCING_T4 0x6a +#define CH7017_POWER_SEQUENCING_T5 0x6b +#define CH7017_GPIO_DRIVER_TYPE 0x6c +#define CH7017_GPIO_DATA 0x6d +#define CH7017_GPIO_DIRECTION_CONTROL 0x6e + +#define CH7017_LVDS_PLL_FEEDBACK_DIV 0x71 +# define CH7017_LVDS_PLL_FEED_BACK_DIVIDER_SHIFT 4 +# define CH7017_LVDS_PLL_FEED_FORWARD_DIVIDER_SHIFT 0 +# define CH7017_LVDS_PLL_FEEDBACK_DEFAULT_RESERVED 0x80 + +#define CH7017_LVDS_PLL_VCO_CONTROL 0x72 +# define CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED 0x80 +# define CH7017_LVDS_PLL_VCO_SHIFT 4 +# define CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT 0 + +#define CH7017_OUTPUTS_ENABLE 0x73 +# define CH7017_CHARGE_PUMP_LOW 0x0 +# define CH7017_CHARGE_PUMP_HIGH 0x3 +# define CH7017_LVDS_CHANNEL_A (1 << 3) +# define CH7017_LVDS_CHANNEL_B (1 << 4) +# define CH7017_TV_DAC_A (1 << 5) +# define CH7017_TV_DAC_B (1 << 6) +# define CH7017_DDC_SELECT_DC2 (1 << 7) + +#define CH7017_LVDS_OUTPUT_AMPLITUDE 0x74 +#define CH7017_LVDS_PLL_EMI_REDUCTION 0x75 +#define CH7017_LVDS_POWER_DOWN_FLICKER 0x76 + +#define CH7017_LVDS_CONTROL_2 0x78 +# define CH7017_LOOP_FILTER_SHIFT 5 +# define CH7017_PHASE_DETECTOR_SHIFT 0 + +#define CH7017_BANG_LIMIT_CONTROL 0x7f + +#endif /* CH7017_REG_H */ diff --git a/driver/xf86-video-intel/src/ch7xxx/Makefile.am b/driver/xf86-video-intel/src/ch7xxx/Makefile.am new file mode 100644 index 000000000..fdf6e9e5b --- /dev/null +++ b/driver/xf86-video-intel/src/ch7xxx/Makefile.am @@ -0,0 +1,16 @@ +# this is obnoxious: +# -module lets us name the module exactly how we want +# -avoid-version prevents gratuitous .0.0.0 version numbers on the end +# _ladir passes a dummy rpath to libtool so the thing will actually link +# TODO: -nostdlib/-Bstatic/-lgcc platform magic, not installing the .a, etc. +AM_CFLAGS = @WARN_CFLAGS@ @XMODES_CFLAGS@ @XORG_CFLAGS@ @DRI_CFLAGS@ + +ch7xxx_la_LTLIBRARIES = ch7xxx.la +ch7xxx_la_LDFLAGS = -module -avoid-version +ch7xxx_ladir = @moduledir@/drivers + +ch7xxx_la_SOURCES = \ + ch7xxx.c \ + ch7xxx_module.c \ + ch7xxx.h \ + ch7xxx_reg.h diff --git a/driver/xf86-video-intel/src/ch7xxx/Makefile.in b/driver/xf86-video-intel/src/ch7xxx/Makefile.in new file mode 100644 index 000000000..eccc3e6af --- /dev/null +++ b/driver/xf86-video-intel/src/ch7xxx/Makefile.in @@ -0,0 +1,513 @@ +# Makefile.in generated by automake 1.10 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/ch7xxx +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; +am__installdirs = "$(DESTDIR)$(ch7xxx_ladir)" +ch7xxx_laLTLIBRARIES_INSTALL = $(INSTALL) +LTLIBRARIES = $(ch7xxx_la_LTLIBRARIES) +ch7xxx_la_LIBADD = +am_ch7xxx_la_OBJECTS = ch7xxx.lo ch7xxx_module.lo +ch7xxx_la_OBJECTS = $(am_ch7xxx_la_OBJECTS) +ch7xxx_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(ch7xxx_la_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I. -I$(top_builddir)@am__isrc@ +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(ch7xxx_la_SOURCES) +DIST_SOURCES = $(ch7xxx_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ADMIN_MAN_DIR = @ADMIN_MAN_DIR@ +ADMIN_MAN_SUFFIX = @ADMIN_MAN_SUFFIX@ +AMTAR = @AMTAR@ +APP_MAN_DIR = @APP_MAN_DIR@ +APP_MAN_SUFFIX = @APP_MAN_SUFFIX@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DRIVER_MAN_DIR = @DRIVER_MAN_DIR@ +DRIVER_MAN_SUFFIX = @DRIVER_MAN_SUFFIX@ +DRIVER_NAME = @DRIVER_NAME@ +DRI_CFLAGS = @DRI_CFLAGS@ +DRI_LIBS = @DRI_LIBS@ +DRI_MM_CFLAGS = @DRI_MM_CFLAGS@ +DRI_MM_LIBS = @DRI_MM_LIBS@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +FILE_MAN_DIR = @FILE_MAN_DIR@ +FILE_MAN_SUFFIX = @FILE_MAN_SUFFIX@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIB_MAN_DIR = @LIB_MAN_DIR@ +LIB_MAN_SUFFIX = @LIB_MAN_SUFFIX@ +LINUXDOC = @LINUXDOC@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MAKE_HTML = @MAKE_HTML@ +MAKE_PDF = @MAKE_PDF@ +MAKE_PS = @MAKE_PS@ +MAKE_TEXT = @MAKE_TEXT@ +MISC_MAN_DIR = @MISC_MAN_DIR@ +MISC_MAN_SUFFIX = @MISC_MAN_SUFFIX@ +MKDIR_P = @MKDIR_P@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PCIACCESS_CFLAGS = @PCIACCESS_CFLAGS@ +PCIACCESS_LIBS = @PCIACCESS_LIBS@ +PKG_CONFIG = @PKG_CONFIG@ +PS2PDF = @PS2PDF@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +WARN_CFLAGS = @WARN_CFLAGS@ +XMODES_CFLAGS = @XMODES_CFLAGS@ +XORG_CFLAGS = @XORG_CFLAGS@ +XORG_LIBS = @XORG_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +gen4asm = @gen4asm@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +moduledir = @moduledir@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ + +# this is obnoxious: +# -module lets us name the module exactly how we want +# -avoid-version prevents gratuitous .0.0.0 version numbers on the end +# _ladir passes a dummy rpath to libtool so the thing will actually link +# TODO: -nostdlib/-Bstatic/-lgcc platform magic, not installing the .a, etc. +AM_CFLAGS = @WARN_CFLAGS@ @XMODES_CFLAGS@ @XORG_CFLAGS@ @DRI_CFLAGS@ +ch7xxx_la_LTLIBRARIES = ch7xxx.la +ch7xxx_la_LDFLAGS = -module -avoid-version +ch7xxx_ladir = @moduledir@/drivers +ch7xxx_la_SOURCES = \ + ch7xxx.c \ + ch7xxx_module.c \ + ch7xxx.h \ + ch7xxx_reg.h + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/ch7xxx/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/ch7xxx/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-ch7xxx_laLTLIBRARIES: $(ch7xxx_la_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(ch7xxx_ladir)" || $(MKDIR_P) "$(DESTDIR)$(ch7xxx_ladir)" + @list='$(ch7xxx_la_LTLIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + f=$(am__strip_dir) \ + echo " $(LIBTOOL) --mode=install $(ch7xxx_laLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(ch7xxx_ladir)/$$f'"; \ + $(LIBTOOL) --mode=install $(ch7xxx_laLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(ch7xxx_ladir)/$$f"; \ + else :; fi; \ + done + +uninstall-ch7xxx_laLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(ch7xxx_la_LTLIBRARIES)'; for p in $$list; do \ + p=$(am__strip_dir) \ + echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(ch7xxx_ladir)/$$p'"; \ + $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(ch7xxx_ladir)/$$p"; \ + done + +clean-ch7xxx_laLTLIBRARIES: + -test -z "$(ch7xxx_la_LTLIBRARIES)" || rm -f $(ch7xxx_la_LTLIBRARIES) + @list='$(ch7xxx_la_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +ch7xxx.la: $(ch7xxx_la_OBJECTS) $(ch7xxx_la_DEPENDENCIES) + $(ch7xxx_la_LINK) -rpath $(ch7xxx_ladir) $(ch7xxx_la_OBJECTS) $(ch7xxx_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ch7xxx.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ch7xxx_module.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(ch7xxx_ladir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-ch7xxx_laLTLIBRARIES clean-generic clean-libtool \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-ch7xxx_laLTLIBRARIES + +install-dvi: install-dvi-am + +install-exec-am: + +install-html: install-html-am + +install-info: install-info-am + +install-man: + +install-pdf: install-pdf-am + +install-ps: install-ps-am + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-ch7xxx_laLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean \ + clean-ch7xxx_laLTLIBRARIES clean-generic clean-libtool ctags \ + distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am \ + install-ch7xxx_laLTLIBRARIES install-data install-data-am \ + install-dvi install-dvi-am install-exec install-exec-am \ + install-html install-html-am install-info install-info-am \ + install-man install-pdf install-pdf-am install-ps \ + install-ps-am install-strip installcheck installcheck-am \ + installdirs maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-ch7xxx_laLTLIBRARIES + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/driver/xf86-video-intel/src/ch7xxx/ch7xxx.c b/driver/xf86-video-intel/src/ch7xxx/ch7xxx.c new file mode 100644 index 000000000..3c58165d1 --- /dev/null +++ b/driver/xf86-video-intel/src/ch7xxx/ch7xxx.c @@ -0,0 +1,318 @@ +/************************************************************************** + +Copyright © 2006 Dave Airlie + +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 AUTHOR 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. + +**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <string.h> +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86Resources.h" +#include "compiler.h" +#include "miscstruct.h" +#include "xf86i2c.h" +#include "xf86Crtc.h" +#define DPMS_SERVER +#include <X11/extensions/dpms.h> + +#include "../i2c_vid.h" +#include "ch7xxx.h" +#include "ch7xxx_reg.h" + +/** @file + * driver for the Chrontel 7xxx DVI chip over DVO. + */ + +static struct ch7xxx_id_struct { + int vid; + char *name; +} ch7xxx_ids[] = { + { CH7011_VID, "CH7011" }, + { CH7009A_VID, "CH7009A" }, + { CH7009B_VID, "CH7009B" }, + { CH7301_VID, "CH7301" }, +}; + +#define ID_ARRAY_SIZE (sizeof(ch7xxx_ids) / sizeof(ch7xxx_ids[0])) + +struct ch7xxx_reg_state { + CARD8 regs[CH7xxx_NUM_REGS]; +}; + +struct ch7xxx_priv { + I2CDevRec d; + Bool quiet; + + struct ch7xxx_reg_state SavedReg; + struct ch7xxx_reg_state ModeReg; + CARD8 save_TCTL, save_TPCP, save_TPD, save_TPVT; + CARD8 save_TLPF, save_TCT, save_PM, save_IDF; +}; + +static void ch7xxx_save(I2CDevPtr d); + +static char *ch7xxx_get_id(int vid) +{ + int i; + + for (i = 0; i < ID_ARRAY_SIZE; i++) { + if (ch7xxx_ids[i].vid == vid) + return ch7xxx_ids[i].name; + } + + return NULL; +} + +/** Reads an 8 bit register */ +static Bool +ch7xxx_read(struct ch7xxx_priv *dev_priv, int addr, unsigned char *ch) +{ + if (!xf86I2CReadByte(&dev_priv->d, addr, ch)) { + if (!dev_priv->quiet) { + xf86DrvMsg(dev_priv->d.pI2CBus->scrnIndex, + X_ERROR, "Unable to read from %s Slave %d.\n", + dev_priv->d.pI2CBus->BusName, dev_priv->d.SlaveAddr); + } + return FALSE; + } + + return TRUE; +} + +/** Writes an 8 bit register */ +static Bool +ch7xxx_write(struct ch7xxx_priv *dev_priv, int addr, unsigned char ch) +{ + if (!xf86I2CWriteByte(&dev_priv->d, addr, ch)) { + if (!dev_priv->quiet) { + xf86DrvMsg(dev_priv->d.pI2CBus->scrnIndex, X_ERROR, + "Unable to write to %s Slave %d.\n", + dev_priv->d.pI2CBus->BusName, dev_priv->d.SlaveAddr); + } + return FALSE; + } + + return TRUE; +} + +static void * +ch7xxx_init(I2CBusPtr b, I2CSlaveAddr addr) +{ + /* this will detect the CH7xxx chip on the specified i2c bus */ + struct ch7xxx_priv *dev_priv; + CARD8 vendor, device; + char *name; + + dev_priv = xcalloc(1, sizeof(struct ch7xxx_priv)); + if (dev_priv == NULL) + return NULL; + + dev_priv->d.DevName = "CH7xxx TMDS Controller"; + dev_priv->d.SlaveAddr = addr; + dev_priv->d.pI2CBus = b; + dev_priv->d.StartTimeout = b->StartTimeout; + dev_priv->d.BitTimeout = b->BitTimeout; + dev_priv->d.AcknTimeout = b->AcknTimeout; + dev_priv->d.ByteTimeout = b->ByteTimeout; + dev_priv->d.DriverPrivate.ptr = dev_priv; + + dev_priv->quiet = TRUE; + if (!ch7xxx_read(dev_priv, CH7xxx_REG_VID, &vendor)) + goto out; + + name = ch7xxx_get_id(vendor); + if (!name) { + xf86DrvMsg(dev_priv->d.pI2CBus->scrnIndex, X_INFO, + "ch7xxx not detected; got 0x%02x from %s slave %d.\n", + vendor, dev_priv->d.pI2CBus->BusName, + dev_priv->d.SlaveAddr); + goto out; + } + + + if (!ch7xxx_read(dev_priv, CH7xxx_REG_DID, &device)) + goto out; + + if (device != CH7xxx_DID) { + xf86DrvMsg(dev_priv->d.pI2CBus->scrnIndex, X_INFO, + "ch7xxx not detected; got 0x%02x from %s slave %d.\n", + device, dev_priv->d.pI2CBus->BusName, + dev_priv->d.SlaveAddr); + goto out; + } + dev_priv->quiet = FALSE; + + xf86DrvMsg(dev_priv->d.pI2CBus->scrnIndex, X_INFO, + "Detected %s chipset, vendor/device ID 0x%02x/0x%02x\n", + name, vendor, device); + + if (!xf86I2CDevInit(&dev_priv->d)) { + goto out; + } + + return dev_priv; + +out: + xfree(dev_priv); + return NULL; +} + +static xf86OutputStatus +ch7xxx_detect(I2CDevPtr d) +{ + struct ch7xxx_priv *dev_priv = d->DriverPrivate.ptr; + CARD8 cdet, orig_pm, pm; + + ch7xxx_read(dev_priv, CH7xxx_PM, &orig_pm); + + pm = orig_pm; + pm &= ~CH7xxx_PM_FPD; + pm |= CH7xxx_PM_DVIL | CH7xxx_PM_DVIP; + + ch7xxx_write(dev_priv, CH7xxx_PM, pm); + + ch7xxx_read(dev_priv, CH7xxx_CONNECTION_DETECT, &cdet); + + ch7xxx_write(dev_priv, CH7xxx_PM, orig_pm); + + if (cdet & CH7xxx_CDET_DVI) + return XF86OutputStatusConnected; + return XF86OutputStatusDisconnected; +} + +static ModeStatus +ch7xxx_mode_valid(I2CDevPtr d, DisplayModePtr mode) +{ + if (mode->Clock > 165000) + return MODE_CLOCK_HIGH; + + return MODE_OK; +} + +static void +ch7xxx_mode_set(I2CDevPtr d, DisplayModePtr mode, DisplayModePtr adjusted_mode) +{ + struct ch7xxx_priv *dev_priv = d->DriverPrivate.ptr; + CARD8 tvco, tpcp, tpd, tlpf, idf; + + if (mode->Clock <= 65000) { + tvco = 0x23; + tpcp = 0x08; + tpd = 0x16; + tlpf = 0x60; + } else { + tvco = 0x2d; + tpcp = 0x06; + tpd = 0x26; + tlpf = 0xa0; + } + + ch7xxx_write(dev_priv, CH7xxx_TCTL, 0x00); + ch7xxx_write(dev_priv, CH7xxx_TVCO, tvco); + ch7xxx_write(dev_priv, CH7xxx_TPCP, tpcp); + ch7xxx_write(dev_priv, CH7xxx_TPD, tpd); + ch7xxx_write(dev_priv, CH7xxx_TPVT, 0x30); + ch7xxx_write(dev_priv, CH7xxx_TLPF, tlpf); + ch7xxx_write(dev_priv, CH7xxx_TCT, 0x00); + + ch7xxx_read(dev_priv, CH7xxx_IDF, &idf); + + idf &= ~(CH7xxx_IDF_HSP | CH7xxx_IDF_VSP); + if (mode->Flags & V_PHSYNC) + idf |= CH7xxx_IDF_HSP; + + if (mode->Flags & V_PVSYNC) + idf |= CH7xxx_IDF_HSP; + + ch7xxx_write(dev_priv, CH7xxx_IDF, idf); +} + +/* set the CH7xxx power state */ +static void +ch7xxx_dpms(I2CDevPtr d, int mode) +{ + struct ch7xxx_priv *dev_priv = d->DriverPrivate.ptr; + + if (mode == DPMSModeOn) + ch7xxx_write(dev_priv, CH7xxx_PM, CH7xxx_PM_DVIL | CH7xxx_PM_DVIP); + else + ch7xxx_write(dev_priv, CH7xxx_PM, CH7xxx_PM_FPD); +} + +static void +ch7xxx_dump_regs(I2CDevPtr d) +{ + struct ch7xxx_priv *dev_priv = d->DriverPrivate.ptr; + int i; + + for (i = 0; i < CH7xxx_NUM_REGS; i++) { + if (( i % 8 ) == 0 ) + ErrorF("\n %02X: ", i); + ErrorF("%02X ", dev_priv->ModeReg.regs[i]); + } +} + +static void +ch7xxx_save(I2CDevPtr d) +{ + struct ch7xxx_priv *dev_priv = d->DriverPrivate.ptr; + + ch7xxx_read(dev_priv, CH7xxx_TCTL, &dev_priv->save_TCTL); + ch7xxx_read(dev_priv, CH7xxx_TPCP, &dev_priv->save_TPCP); + ch7xxx_read(dev_priv, CH7xxx_TPD, &dev_priv->save_TPD); + ch7xxx_read(dev_priv, CH7xxx_TPVT, &dev_priv->save_TPVT); + ch7xxx_read(dev_priv, CH7xxx_TLPF, &dev_priv->save_TLPF); + ch7xxx_read(dev_priv, CH7xxx_PM, &dev_priv->save_PM); + ch7xxx_read(dev_priv, CH7xxx_IDF, &dev_priv->save_IDF); +} + +static void +ch7xxx_restore(I2CDevPtr d) +{ + struct ch7xxx_priv *dev_priv = d->DriverPrivate.ptr; + + ch7xxx_write(dev_priv, CH7xxx_TCTL, dev_priv->save_TCTL); + ch7xxx_write(dev_priv, CH7xxx_TPCP, dev_priv->save_TPCP); + ch7xxx_write(dev_priv, CH7xxx_TPD, dev_priv->save_TPD); + ch7xxx_write(dev_priv, CH7xxx_TPVT, dev_priv->save_TPVT); + ch7xxx_write(dev_priv, CH7xxx_TLPF, dev_priv->save_TLPF); + ch7xxx_write(dev_priv, CH7xxx_IDF, dev_priv->save_IDF); + ch7xxx_write(dev_priv, CH7xxx_PM, dev_priv->save_PM); +} + +I830I2CVidOutputRec CH7xxxVidOutput = { + .init = ch7xxx_init, + .detect = ch7xxx_detect, + .mode_valid = ch7xxx_mode_valid, + .mode_set = ch7xxx_mode_set, + .dpms = ch7xxx_dpms, + .dump_regs = ch7xxx_dump_regs, + .save = ch7xxx_save, + .restore = ch7xxx_restore, +}; diff --git a/driver/xf86-video-intel/src/ch7xxx/ch7xxx.h b/driver/xf86-video-intel/src/ch7xxx/ch7xxx.h new file mode 100644 index 000000000..679c5313e --- /dev/null +++ b/driver/xf86-video-intel/src/ch7xxx/ch7xxx.h @@ -0,0 +1,31 @@ +/************************************************************************** + + Copyright 2006 Dave Airlie <airlied@linux.ie> + +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. + +**************************************************************************/ + +#ifndef CH7xxx_H +#define CH7xxx_H + +#define CH7xxx_ADDR_1 0x76 + +#endif diff --git a/driver/xf86-video-intel/src/ch7xxx/ch7xxx_module.c b/driver/xf86-video-intel/src/ch7xxx/ch7xxx_module.c new file mode 100644 index 000000000..2613d9e79 --- /dev/null +++ b/driver/xf86-video-intel/src/ch7xxx/ch7xxx_module.c @@ -0,0 +1,35 @@ +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "xf86Module.h" + +static MODULESETUPPROTO(ch7xxxSetup); + +static XF86ModuleVersionInfo ch7xxxVersRec = { + "ch7xxx", + MODULEVENDORSTRING, + MODINFOSTRING1, + MODINFOSTRING2, + XORG_VERSION_CURRENT, + 1, 0, 0, + ABI_CLASS_VIDEODRV, + ABI_VIDEODRV_VERSION, + MOD_CLASS_NONE, + { 0,0,0,0 } +}; + +_X_EXPORT XF86ModuleData ch7xxxModuleData = { + &ch7xxxVersRec, + ch7xxxSetup, + NULL +}; + +static pointer +ch7xxxSetup(pointer module, pointer opts, int *errmaj, int *errmin) { + return (pointer)1; +} diff --git a/driver/xf86-video-intel/src/ch7xxx/ch7xxx_reg.h b/driver/xf86-video-intel/src/ch7xxx/ch7xxx_reg.h new file mode 100644 index 000000000..328b65334 --- /dev/null +++ b/driver/xf86-video-intel/src/ch7xxx/ch7xxx_reg.h @@ -0,0 +1,80 @@ +/************************************************************************** + + Copyright 2006 Dave Airlie <airlied@linux.ie> + +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. + +**************************************************************************/ + +#ifndef CH7xxx_REG_H +#define CH7xxx_REG_H + +#define CH7xxx_REG_VID 0x4a +#define CH7xxx_REG_DID 0x4b + +#define CH7011_VID 0x83 /* 7010 as well */ +#define CH7009A_VID 0x84 +#define CH7009B_VID 0x85 +#define CH7301_VID 0x95 + +#define CH7xxx_VID 0x84 +#define CH7xxx_DID 0x17 + +#define CH7xxx_NUM_REGS 0x4c + +#define CH7xxx_CM 0x1C +#define CH7xxx_CM_XCM (1<<0) +#define CH7xxx_CM_MCP (1<<2) +#define CH7xxx_INPUT_CLOCK 0x1D +#define CH7xxx_GPIO 0x1E +#define CH7xxx_GPIO_HPIR (1<<3) +#define CH7xxx_IDF 0x1F + +#define CH7xxx_IDF_HSP (1<<3) +#define CH7xxx_IDF_VSP (1<<4) + +#define CH7xxx_CONNECTION_DETECT 0x20 +#define CH7xxx_CDET_DVI (1<<5) + +#define CH7301_DAC_CNTL 0x21 +#define CH7301_HOTPLUG 0x23 +#define CH7xxx_TCTL 0x31 +#define CH7xxx_TVCO 0x32 +#define CH7xxx_TPCP 0x33 +#define CH7xxx_TPD 0x34 +#define CH7xxx_TPVT 0x35 +#define CH7xxx_TLPF 0x36 +#define CH7xxx_TCT 0x37 +#define CH7301_TEST_PATTERN 0x48 +#define CH7xxx_PM 0x49 + +#define CH7xxx_PM_FPD (1<<0) +#define CH7301_PM_DACPD0 (1<<1) +#define CH7301_PM_DACPD1 (1<<2) +#define CH7301_PM_DACPD2 (1<<3) +#define CH7xxx_PM_DVIL (1<<6) +#define CH7xxx_PM_DVIP (1<<7) + +#define CH7301_SYNC_POLARITY 0x56 + +#define CH7301_SYNC_RGB_YUV (1<<0) +#define CH7301_SYNC_POL_DVI (1<<5) + +#endif diff --git a/driver/xf86-video-intel/src/exa_sf.g4a b/driver/xf86-video-intel/src/exa_sf.g4a new file mode 100644 index 000000000..5a023992f --- /dev/null +++ b/driver/xf86-video-intel/src/exa_sf.g4a @@ -0,0 +1,45 @@ +/* + * Copyright © 2006 Intel Corporation + * + * 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 + * THE AUTHORS OR COPYRIGHT HOLDERS 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 Packard <keithp@keithp.com> + * Eric Anholt <eric@anholt.net> + * + */ + +send (1) 0 g6<1>F g1.12<0,1,0>F math inv scalar mlen 1 rlen 1 { align1 }; +send (1) 0 g6.4<1>F g1.20<0,1,0>F math inv scalar mlen 1 rlen 1 { align1 }; +add (8) g7<1>F g4<8,8,1>F -g3<8,8,1>F { align1 }; +mul (1) g7<1>F g7<0,1,0>F g6<0,1,0>F { align1 }; +mul (1) g7.4<1>F g7.4<0,1,0>F g6.4<0,1,0>F { align1 }; +mov (8) m1<1>F g7<0,1,0>F { align1 }; +mov (8) m2<1>F g7.4<0,1,0>F { align1 }; +mov (8) m3<1>F g3<8,8,1>F { align1 }; +send (8) 0 null g0<8,8,1>F urb 0 transpose used complete mlen 4 rlen 0 { align1 EOT }; +nop; +nop; +nop; +nop; +nop; +nop; +nop; +nop; diff --git a/driver/xf86-video-intel/src/exa_sf_mask.g4a b/driver/xf86-video-intel/src/exa_sf_mask.g4a new file mode 100644 index 000000000..a0d6efc4f --- /dev/null +++ b/driver/xf86-video-intel/src/exa_sf_mask.g4a @@ -0,0 +1,78 @@ +/* + * Copyright © 2006 Intel Corporation + * + * 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 + * THE AUTHORS OR COPYRIGHT HOLDERS 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: + * Wang Zhenyu <zhenyu.z.wang@intel.com> + */ + +/* FIXME how to setup second coeffient for mask tex coord */ + +/* + g3 (v0) { u0, v0, 1.0, 1.0 } ==> {u0, v0, 1.0, 1.0, mu0, mv0, 1.0, 1.0} Co[0](u0) Co[1](v0) Co[2](mu0) Co[3](mv0) + g4 (v1) { u1, v1, 1.0, 1.0 } ==> {u1, v1, 1.0, 1.0, mu1, mv1, 1.0, 1.0} + g5 (v2) { u2, v2 } ==> (u2, v2, mu2, mv2} + g6 { 1/(x1-x0), 1/(y1-y0) } + g7 { u1-u0, v1-v0, 0, 0} ==>{u1-u0, v1-v0,0, 0, mu1-mu0, mv1-mv0, 0, 0} + -> { (u1-u0)/(x1-x0), (v1-v0)/(y1-y0) } ==>{(u1-u0)/(x1-x0), (v1-v0)/(y1-y0),(mu1-mu0)/(x1-x0), (mv1-mv0)/(y1-y0) + Cx, Cy Cx[0], Cy[0], Cx[1], Cy[1] + */ + +/* assign Cx[0], Cx[1] to src, same to Cy, Co + Cx[2], Cx[3] to mask, same to Cy, Co */ + +send (1) 0 g6<1>F g1.12<0,1,0>F math inv scalar mlen 1 rlen 1 { align1 }; +send (1) 0 g6.4<1>F g1.20<0,1,0>F math inv scalar mlen 1 rlen 1 { align1 }; +add (8) g7<1>F g4<8,8,1>F -g3<8,8,1>F { align1 }; +/* Cx[0] */ +mul (1) g7<1>F g7<0,1,0>F g6<0,1,0>F { align1 }; +/* Cy[0] */ +mul (1) g7.4<1>F g7.4<0,1,0>F g6.4<0,1,0>F { align1 }; +/* Cx[2] */ +mul (1) g7.8<1>F g7.8<0,1,0>F g6<0,1,0>F { align1 }; +/* Cy[2] */ +mul (1) g7.12<1>F g7.12<0,1,0>F g6.4<0,1,0>F { align1 }; + +/* src Cx[0], Cx[1] */ +mov (8) m1<1>F g7<0,1,0>F { align1 }; +/* mask Cx[2], Cx[3] */ +mov (1) m1.8<1>F g7.8<0,1,0>F { align1 }; +mov (1) m1.12<1>F g7.8<0,1,0>F { align1 }; +/* src Cy[0], Cy[1] */ +mov (8) m2<1>F g7.4<0,1,0>F { align1 }; +/* mask Cy[2], Cy[3] */ +mov (1) m2.8<1>F g7.12<0,1,0>F { align1 }; +mov (1) m2.12<1>F g7.12<0,1,0>F { align1 }; +/* src Co[0], Co[1] */ +mov (8) m3<1>F g3<8,8,1>F { align1 }; +/* mask Co[2], Co[3] */ +mov (1) m3.8<1>F g3.8<0,1,0>F { align1 }; +mov (1) m3.12<1>F g3.12<0,1,0>F { align1 }; + +send (8) 0 null g0<8,8,1>F urb 0 transpose used complete mlen 4 rlen 0 { align1 EOT }; +nop; +nop; +nop; +nop; +nop; +nop; +nop; +nop; diff --git a/driver/xf86-video-intel/src/exa_sf_mask_prog.h b/driver/xf86-video-intel/src/exa_sf_mask_prog.h new file mode 100644 index 000000000..4e9114d61 --- /dev/null +++ b/driver/xf86-video-intel/src/exa_sf_mask_prog.h @@ -0,0 +1,25 @@ + { 0x00000031, 0x20c01fbd, 0x0000002c, 0x01110081 }, + { 0x00000031, 0x20c41fbd, 0x00000034, 0x01110081 }, + { 0x00600040, 0x20e077bd, 0x008d0080, 0x008d4060 }, + { 0x00000041, 0x20e077bd, 0x000000e0, 0x000000c0 }, + { 0x00000041, 0x20e477bd, 0x000000e4, 0x000000c4 }, + { 0x00000041, 0x20e877bd, 0x000000e8, 0x000000c0 }, + { 0x00000041, 0x20ec77bd, 0x000000ec, 0x000000c4 }, + { 0x00600001, 0x202003be, 0x000000e0, 0x00000000 }, + { 0x00000001, 0x202803be, 0x000000e8, 0x00000000 }, + { 0x00000001, 0x202c03be, 0x000000e8, 0x00000000 }, + { 0x00600001, 0x204003be, 0x000000e4, 0x00000000 }, + { 0x00000001, 0x204803be, 0x000000ec, 0x00000000 }, + { 0x00000001, 0x204c03be, 0x000000ec, 0x00000000 }, + { 0x00600001, 0x206003be, 0x008d0060, 0x00000000 }, + { 0x00000001, 0x206803be, 0x00000068, 0x00000000 }, + { 0x00000001, 0x206c03be, 0x0000006c, 0x00000000 }, + { 0x00600031, 0x20001fbc, 0x008d0000, 0x8640c800 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, diff --git a/driver/xf86-video-intel/src/exa_sf_prog.h b/driver/xf86-video-intel/src/exa_sf_prog.h new file mode 100644 index 000000000..830d1760d --- /dev/null +++ b/driver/xf86-video-intel/src/exa_sf_prog.h @@ -0,0 +1,17 @@ + { 0x00000031, 0x20c01fbd, 0x0000002c, 0x01110081 }, + { 0x00000031, 0x20c41fbd, 0x00000034, 0x01110081 }, + { 0x00600040, 0x20e077bd, 0x008d0080, 0x008d4060 }, + { 0x00000041, 0x20e077bd, 0x000000e0, 0x000000c0 }, + { 0x00000041, 0x20e477bd, 0x000000e4, 0x000000c4 }, + { 0x00600001, 0x202003be, 0x000000e0, 0x00000000 }, + { 0x00600001, 0x204003be, 0x000000e4, 0x00000000 }, + { 0x00600001, 0x206003be, 0x008d0060, 0x00000000 }, + { 0x00600031, 0x20001fbc, 0x008d0000, 0x8640c800 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, diff --git a/driver/xf86-video-intel/src/exa_sf_rotation.g4a b/driver/xf86-video-intel/src/exa_sf_rotation.g4a new file mode 100644 index 000000000..59d40d47b --- /dev/null +++ b/driver/xf86-video-intel/src/exa_sf_rotation.g4a @@ -0,0 +1,55 @@ +/* + * Copyright © 2007 Intel Corporation + * + * 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 + * THE AUTHORS OR COPYRIGHT HOLDERS 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: + * Wang Zhenyu <zhenyu.z.wang@intel.com> + */ + +/* 1/dx */ +send (1) 0 g6<1>F g1.12<0,1,0>F math inv scalar mlen 1 rlen 1 { align1 }; +/* 1/dy */ +send (1) 0 g6.4<1>F g1.20<0,1,0>F math inv scalar mlen 1 rlen 1 { align1 }; +/* du, dv */ +mul (1) g7<1>F g3<0,1,0>F -1.0F { align1 }; +mul (1) g7.4<1>F g3.4<0,1,0>F -1.0F { align1 }; +add (1) g7<1>F g4<0,1,0>F g7<0,1,0>F { align1 }; +add (1) g7.4<1>F g4.4<0,1,0>F g7.4<0,1,0>F { align1 }; + +/* du/dy */ +mul (1) g7<1>F g7<0,1,0>F g6.4<0,1,0>F { align1 }; +/* dv/dx */ +mul (1) g7.4<1>F g7.4<0,1,0>F g6<0,1,0>F { align1 }; +/* Cx */ +mov (8) m1<1>F g7<0,1,0>F { align1 }; +/* Cy */ +mov (8) m2<1>F g7.4<0,1,0>F { align1 }; +/* Co */ +mov (8) m3<1>F g3<8,8,1>F { align1 }; +send (8) 0 null g0<8,8,1>F urb 0 transpose used complete mlen 4 rlen 0 { align1 EOT }; +nop; +nop; +nop; +nop; +nop; +nop; +nop; +nop; diff --git a/driver/xf86-video-intel/src/exa_sf_rotation_prog.h b/driver/xf86-video-intel/src/exa_sf_rotation_prog.h new file mode 100644 index 000000000..958913053 --- /dev/null +++ b/driver/xf86-video-intel/src/exa_sf_rotation_prog.h @@ -0,0 +1,20 @@ + { 0x00000031, 0x20c01fbd, 0x0000002c, 0x01110081 }, + { 0x00000031, 0x20c41fbd, 0x00000034, 0x01110081 }, + { 0x00000041, 0x20e07fbd, 0x00000060, 0xbf800000 }, + { 0x00000041, 0x20e47fbd, 0x00000064, 0xbf800000 }, + { 0x00000040, 0x20e077bd, 0x00000080, 0x000000e0 }, + { 0x00000040, 0x20e477bd, 0x00000084, 0x000000e4 }, + { 0x00000041, 0x20e077bd, 0x000000e0, 0x000000c4 }, + { 0x00000041, 0x20e477bd, 0x000000e4, 0x000000c0 }, + { 0x00600001, 0x202003be, 0x000000e0, 0x00000000 }, + { 0x00600001, 0x204003be, 0x000000e4, 0x00000000 }, + { 0x00600001, 0x206003be, 0x008d0060, 0x00000000 }, + { 0x00600031, 0x20001fbc, 0x008d0000, 0x8640c800 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, diff --git a/driver/xf86-video-intel/src/exa_wm_maskca.g4a b/driver/xf86-video-intel/src/exa_wm_maskca.g4a new file mode 100644 index 000000000..0e96aa04c --- /dev/null +++ b/driver/xf86-video-intel/src/exa_wm_maskca.g4a @@ -0,0 +1,228 @@ +/* + * Copyright © 2007 Intel Corporation + * + * 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 + * THE AUTHORS OR COPYRIGHT HOLDERS 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: + * Wang Zhenyu <zhenyu.z.wang@intel.com> + */ + +/* + * This's for exa composite operation in no mask picture case. + * The simplest case is just sending what src picture has to dst picture. + * XXX: This is still experimental, and should be fixed to support multiple texture + * map, and conditional mul actions. + */ + +/* I think this should be same as in g4a program for texture video, + as we also use 16-pixel dispatch. and SF scale in g3 is useful for us. */ + +/* The initial payload of the thread is always g0. + * WM_URB (incoming URB entries) is g3 + As mask texture coeffient needs extra setup urb starting from g4, we should + shift this location. + + * X0_R is g4->g6 + * X1_R is g5->g7 + * Y0_R is g6->g8 + * Y1_R is g7->g9 + + * X0: {ss0.x, ss0.x+1, ss0.x, ss0.x+1, ss1.x, ss1.x+1, ss1.x, ss1.x+y} + * Y0: {ss0.y, ss0.y, ss0.y+1, ss0.y+1, ss1.y, ss1.y, ss1.y+1, ss1.y+1} + * X1: {ss2.x, ss2.x+1, ss2.x, ss2.x+1, ss3.x, ss3.x+1, ss3.x, ss3.x+y} + * Y1: {ss2.y, ss2.y, ss2.y+1, ss2.y+1, ss3.y, ss3.y, ss3.y+1, ss3.y+1} + */ + +/* multitexture program with src and mask texture */ +/* - load src texture */ +/* - load mask texture */ +/* - mul src.X with mask's alpha */ +/* - write out src.X */ + + /* Set up ss0.x coordinates*/ +mov (1) g6<1>F g1.8<0,1,0>UW { align1 }; +add (1) g6.4<1>F g1.8<0,1,0>UW 1UB { align1 }; +mov (1) g6.8<1>F g1.8<0,1,0>UW { align1 }; +add (1) g6.12<1>F g1.8<0,1,0>UW 1UB { align1 }; + /* Set up ss0.y coordinates */ +mov (1) g8<1>F g1.10<0,1,0>UW { align1 }; +mov (1) g8.4<1>F g1.10<0,1,0>UW { align1 }; +add (1) g8.8<1>F g1.10<0,1,0>UW 1UB { align1 }; +add (1) g8.12<1>F g1.10<0,1,0>UW 1UB { align1 }; + /* set up ss1.x coordinates */ +mov (1) g6.16<1>F g1.12<0,1,0>UW { align1 }; +add (1) g6.20<1>F g1.12<0,1,0>UW 1UB { align1 }; +mov (1) g6.24<1>F g1.12<0,1,0>UW { align1 }; +add (1) g6.28<1>F g1.12<0,1,0>UW 1UB { align1 }; + /* set up ss1.y coordinates */ +mov (1) g8.16<1>F g1.14<0,1,0>UW { align1 }; +mov (1) g8.20<1>F g1.14<0,1,0>UW { align1 }; +add (1) g8.24<1>F g1.14<0,1,0>UW 1UB { align1 }; +add (1) g8.28<1>F g1.14<0,1,0>UW 1UB { align1 }; + /* Set up ss2.x coordinates */ +mov (1) g7<1>F g1.16<0,1,0>UW { align1 }; +add (1) g7.4<1>F g1.16<0,1,0>UW 1UB { align1 }; +mov (1) g7.8<1>F g1.16<0,1,0>UW { align1 }; +add (1) g7.12<1>F g1.16<0,1,0>UW 1UB { align1 }; + /* Set up ss2.y coordinates */ +mov (1) g9<1>F g1.18<0,1,0>UW { align1 }; +mov (1) g9.4<1>F g1.18<0,1,0>UW { align1 }; +add (1) g9.8<1>F g1.18<0,1,0>UW 1UB { align1 }; +add (1) g9.12<1>F g1.18<0,1,0>UW 1UB { align1 }; + /* Set up ss3.x coordinates */ +mov (1) g7.16<1>F g1.20<0,1,0>UW { align1 }; +add (1) g7.20<1>F g1.20<0,1,0>UW 1UB { align1 }; +mov (1) g7.24<1>F g1.20<0,1,0>UW { align1 }; +add (1) g7.28<1>F g1.20<0,1,0>UW 1UB { align1 }; + /* Set up ss3.y coordinates */ +mov (1) g9.16<1>F g1.22<0,1,0>UW { align1 }; +mov (1) g9.20<1>F g1.22<0,1,0>UW { align1 }; +add (1) g9.24<1>F g1.22<0,1,0>UW 1UB { align1 }; +add (1) g9.28<1>F g1.22<0,1,0>UW 1UB { align1 }; + + /* Now, map these screen space coordinates into texture coordinates. */ +/* This is for src texture */ +/* I don't want to change origin ssX coords, as it will be used later in mask */ +/* so store tex coords in g10, g11, g12, g13 */ + + /* subtract screen-space X origin of vertex 0. */ +add (8) g10<1>F g6<8,8,1>F -g1<0,1,0>F { align1 }; +add (8) g11<1>F g7<8,8,1>F -g1<0,1,0>F { align1 }; + /* scale by texture X increment */ +/* Cx[0] */ +mul (8) g10<1>F g10<8,8,1>F g3<0,1,0>F { align1 }; +mul (8) g11<1>F g11<8,8,1>F g3<0,1,0>F { align1 }; + /* add in texture X offset */ +/* Co[0] */ +add (8) g10<1>F g10<8,8,1>F g3.12<0,1,0>F { align1 }; +add (8) g11<1>F g11<8,8,1>F g3.12<0,1,0>F { align1 }; + /* subtract screen-space Y origin of vertex 0. */ +add (8) g12<1>F g8<8,8,1>F -g1.4<0,1,0>F { align1 }; +add (8) g13<1>F g9<8,8,1>F -g1.4<0,1,0>F { align1 }; + /* scale by texture Y increment */ +/* Cy[0] */ +mul (8) g12<1>F g12<8,8,1>F g3.4<0,1,0>F { align1 }; +mul (8) g13<1>F g13<8,8,1>F g3.4<0,1,0>F { align1 }; + /* add in texture Y offset */ +/* Co[1] */ +add (8) g12<1>F g12<8,8,1>F g3.28<0,1,0>F { align1 }; +add (8) g13<1>F g13<8,8,1>F g3.28<0,1,0>F { align1 }; + +/* prepare sampler read back gX register, which would be written back to output */ + +/* use simd16 sampler, param 0 is u, param 1 is v. */ +/* 'payload' loading, assuming tex coord start from g4 */ +mov (8) m1<1>F g10<8,8,1>F { align1 }; +mov (8) m2<1>F g11<8,8,1>F { align1 }; /* param 0 u in m1, m2 */ +mov (8) m3<1>F g12<8,8,1>F { align1 }; +mov (8) m4<1>F g13<8,8,1>F { align1 }; /* param 1 v in m3, m4 */ + +/* m0 will be copied with g0, as it contains send desc */ +/* emit sampler 'send' cmd */ + +/* src texture readback: g14-g21 */ +send (16) 0 /* msg reg index */ + g14<1>UW /* readback */ + g0<8,8,1>UW /* copy to msg start reg*/ + sampler (1,0,F) /* sampler message description, + (binding_table,sampler_index,datatype). + here(src->dst) we should use src_sampler and + src_surface */ + mlen 5 rlen 8 { align1 }; /* required message len 5, readback len 8 */ + +mov (8) g21<1>UD g21<8,8,1>UD { align1 }; /* wait sampler return */ + +/* sampler mask texture, use g10, g11, g12, g13 */ + /* subtract screen-space X origin of vertex 0. */ +add (8) g10<1>F g6<8,8,1>F -g1<0,1,0>F { align1 }; +add (8) g11<1>F g7<8,8,1>F -g1<0,1,0>F { align1 }; + /* scale by texture X increment */ +/* Cx[2] */ +mul (8) g10<1>F g10<8,8,1>F g4<0,1,0>F { align1 }; +mul (8) g11<1>F g11<8,8,1>F g4<0,1,0>F { align1 }; + /* add in texture X offset */ +/* Co[2] */ +add (8) g10<1>F g10<8,8,1>F g4.12<0,1,0>F { align1 }; +add (8) g11<1>F g11<8,8,1>F g4.12<0,1,0>F { align1 }; + /* subtract screen-space Y origin of vertex 0. */ +add (8) g12<1>F g8<8,8,1>F -g1.4<0,1,0>F { align1 }; +add (8) g13<1>F g9<8,8,1>F -g1.4<0,1,0>F { align1 }; + /* scale by texture Y increment */ +/* Cy[2] */ +mul (8) g12<1>F g12<8,8,1>F g4.4<0,1,0>F { align1 }; +mul (8) g13<1>F g13<8,8,1>F g4.4<0,1,0>F { align1 }; + /* add in texture Y offset */ +/* Co[3] */ +add (8) g12<1>F g12<8,8,1>F g4.28<0,1,0>F { align1 }; +add (8) g13<1>F g13<8,8,1>F g4.28<0,1,0>F { align1 }; + +mov (8) m1<1>F g10<8,8,1>F { align1 }; +mov (8) m2<1>F g11<8,8,1>F { align1 }; +mov (8) m3<1>F g12<8,8,1>F { align1 }; +mov (8) m4<1>F g13<8,8,1>F { align1 }; + +/* mask sampler g22-g29 */ +/* binding_table (2), sampler (1) */ +send (16) 0 g22<1>UW g0<8,8,1>UW sampler (2,1,F) mlen 5 rlen 8 { align1 }; +mov (8) g29<1>UD g29<8,8,1>UD { align1 }; /* wait sampler return */ + +/* mul mask's channel to src, then write out src */ +mul (8) g14<1>F g14<8,8,1>F g22<8,8,1>F { align1 }; +mul (8) g15<1>F g15<8,8,1>F g23<8,8,1>F { align1 }; +mul (8) g16<1>F g16<8,8,1>F g24<8,8,1>F { align1 }; +mul (8) g17<1>F g17<8,8,1>F g25<8,8,1>F { align1 }; +mul (8) g18<1>F g18<8,8,1>F g26<8,8,1>F { align1 }; +mul (8) g19<1>F g19<8,8,1>F g27<8,8,1>F { align1 }; +mul (8) g20<1>F g20<8,8,1>F g28<8,8,1>F { align1 }; +mul (8) g21<1>F g21<8,8,1>F g29<8,8,1>F { align1 }; + +/* prepare data in m2-m5 for subspan(1,0), m6-m9 for subspan(3,2), then it's ready to write */ +mov (8) m2<1>F g14<8,8,1>F { align1 }; +mov (8) m3<1>F g16<8,8,1>F { align1 }; +mov (8) m4<1>F g18<8,8,1>F { align1 }; +mov (8) m5<1>F g20<8,8,1>F { align1 }; +mov (8) m6<1>F g15<8,8,1>F { align1 }; +mov (8) m7<1>F g17<8,8,1>F { align1 }; +mov (8) m8<1>F g19<8,8,1>F { align1 }; +mov (8) m9<1>F g21<8,8,1>F { align1 }; + +/* m0, m1 are all direct passed by PS thread payload */ +mov (8) m1<1>UD g1<8,8,1>UD { align1 mask_disable }; + +/* write */ +send (16) 0 acc0<1>UW g0<8,8,1>UW write ( + 0, /* binding_table */ + 8, /* pixel scordboard clear, msg type simd16 single source */ + 4, /* render target write */ + 0 /* no write commit message */ + ) + mlen 10 + rlen 0 + { align1 EOT }; + +nop; +nop; +nop; +nop; +nop; +nop; +nop; +nop; +nop; diff --git a/driver/xf86-video-intel/src/exa_wm_maskca_prog.h b/driver/xf86-video-intel/src/exa_wm_maskca_prog.h new file mode 100644 index 000000000..d936412c4 --- /dev/null +++ b/driver/xf86-video-intel/src/exa_wm_maskca_prog.h @@ -0,0 +1,95 @@ + { 0x00000001, 0x20c0013d, 0x00000028, 0x00000000 }, + { 0x00000040, 0x20c40d3d, 0x00000028, 0x00000001 }, + { 0x00000001, 0x20c8013d, 0x00000028, 0x00000000 }, + { 0x00000040, 0x20cc0d3d, 0x00000028, 0x00000001 }, + { 0x00000001, 0x2100013d, 0x0000002a, 0x00000000 }, + { 0x00000001, 0x2104013d, 0x0000002a, 0x00000000 }, + { 0x00000040, 0x21080d3d, 0x0000002a, 0x00000001 }, + { 0x00000040, 0x210c0d3d, 0x0000002a, 0x00000001 }, + { 0x00000001, 0x20d0013d, 0x0000002c, 0x00000000 }, + { 0x00000040, 0x20d40d3d, 0x0000002c, 0x00000001 }, + { 0x00000001, 0x20d8013d, 0x0000002c, 0x00000000 }, + { 0x00000040, 0x20dc0d3d, 0x0000002c, 0x00000001 }, + { 0x00000001, 0x2110013d, 0x0000002e, 0x00000000 }, + { 0x00000001, 0x2114013d, 0x0000002e, 0x00000000 }, + { 0x00000040, 0x21180d3d, 0x0000002e, 0x00000001 }, + { 0x00000040, 0x211c0d3d, 0x0000002e, 0x00000001 }, + { 0x00000001, 0x20e0013d, 0x00000030, 0x00000000 }, + { 0x00000040, 0x20e40d3d, 0x00000030, 0x00000001 }, + { 0x00000001, 0x20e8013d, 0x00000030, 0x00000000 }, + { 0x00000040, 0x20ec0d3d, 0x00000030, 0x00000001 }, + { 0x00000001, 0x2120013d, 0x00000032, 0x00000000 }, + { 0x00000001, 0x2124013d, 0x00000032, 0x00000000 }, + { 0x00000040, 0x21280d3d, 0x00000032, 0x00000001 }, + { 0x00000040, 0x212c0d3d, 0x00000032, 0x00000001 }, + { 0x00000001, 0x20f0013d, 0x00000034, 0x00000000 }, + { 0x00000040, 0x20f40d3d, 0x00000034, 0x00000001 }, + { 0x00000001, 0x20f8013d, 0x00000034, 0x00000000 }, + { 0x00000040, 0x20fc0d3d, 0x00000034, 0x00000001 }, + { 0x00000001, 0x2130013d, 0x00000036, 0x00000000 }, + { 0x00000001, 0x2134013d, 0x00000036, 0x00000000 }, + { 0x00000040, 0x21380d3d, 0x00000036, 0x00000001 }, + { 0x00000040, 0x213c0d3d, 0x00000036, 0x00000001 }, + { 0x00600040, 0x214077bd, 0x008d00c0, 0x00004020 }, + { 0x00600040, 0x216077bd, 0x008d00e0, 0x00004020 }, + { 0x00600041, 0x214077bd, 0x008d0140, 0x00000060 }, + { 0x00600041, 0x216077bd, 0x008d0160, 0x00000060 }, + { 0x00600040, 0x214077bd, 0x008d0140, 0x0000006c }, + { 0x00600040, 0x216077bd, 0x008d0160, 0x0000006c }, + { 0x00600040, 0x218077bd, 0x008d0100, 0x00004024 }, + { 0x00600040, 0x21a077bd, 0x008d0120, 0x00004024 }, + { 0x00600041, 0x218077bd, 0x008d0180, 0x00000064 }, + { 0x00600041, 0x21a077bd, 0x008d01a0, 0x00000064 }, + { 0x00600040, 0x218077bd, 0x008d0180, 0x0000007c }, + { 0x00600040, 0x21a077bd, 0x008d01a0, 0x0000007c }, + { 0x00600001, 0x202003be, 0x008d0140, 0x00000000 }, + { 0x00600001, 0x204003be, 0x008d0160, 0x00000000 }, + { 0x00600001, 0x206003be, 0x008d0180, 0x00000000 }, + { 0x00600001, 0x208003be, 0x008d01a0, 0x00000000 }, + { 0x00800031, 0x21c01d29, 0x008d0000, 0x02580001 }, + { 0x00600001, 0x22a00021, 0x008d02a0, 0x00000000 }, + { 0x00600040, 0x214077bd, 0x008d00c0, 0x00004020 }, + { 0x00600040, 0x216077bd, 0x008d00e0, 0x00004020 }, + { 0x00600041, 0x214077bd, 0x008d0140, 0x00000080 }, + { 0x00600041, 0x216077bd, 0x008d0160, 0x00000080 }, + { 0x00600040, 0x214077bd, 0x008d0140, 0x0000008c }, + { 0x00600040, 0x216077bd, 0x008d0160, 0x0000008c }, + { 0x00600040, 0x218077bd, 0x008d0100, 0x00004024 }, + { 0x00600040, 0x21a077bd, 0x008d0120, 0x00004024 }, + { 0x00600041, 0x218077bd, 0x008d0180, 0x00000084 }, + { 0x00600041, 0x21a077bd, 0x008d01a0, 0x00000084 }, + { 0x00600040, 0x218077bd, 0x008d0180, 0x0000009c }, + { 0x00600040, 0x21a077bd, 0x008d01a0, 0x0000009c }, + { 0x00600001, 0x202003be, 0x008d0140, 0x00000000 }, + { 0x00600001, 0x204003be, 0x008d0160, 0x00000000 }, + { 0x00600001, 0x206003be, 0x008d0180, 0x00000000 }, + { 0x00600001, 0x208003be, 0x008d01a0, 0x00000000 }, + { 0x00800031, 0x22c01d29, 0x008d0000, 0x02580102 }, + { 0x00600001, 0x23a00021, 0x008d03a0, 0x00000000 }, + { 0x00600041, 0x21c077bd, 0x008d01c0, 0x008d02c0 }, + { 0x00600041, 0x21e077bd, 0x008d01e0, 0x008d02e0 }, + { 0x00600041, 0x220077bd, 0x008d0200, 0x008d0300 }, + { 0x00600041, 0x222077bd, 0x008d0220, 0x008d0320 }, + { 0x00600041, 0x224077bd, 0x008d0240, 0x008d0340 }, + { 0x00600041, 0x226077bd, 0x008d0260, 0x008d0360 }, + { 0x00600041, 0x228077bd, 0x008d0280, 0x008d0380 }, + { 0x00600041, 0x22a077bd, 0x008d02a0, 0x008d03a0 }, + { 0x00600001, 0x204003be, 0x008d01c0, 0x00000000 }, + { 0x00600001, 0x206003be, 0x008d0200, 0x00000000 }, + { 0x00600001, 0x208003be, 0x008d0240, 0x00000000 }, + { 0x00600001, 0x20a003be, 0x008d0280, 0x00000000 }, + { 0x00600001, 0x20c003be, 0x008d01e0, 0x00000000 }, + { 0x00600001, 0x20e003be, 0x008d0220, 0x00000000 }, + { 0x00600001, 0x210003be, 0x008d0260, 0x00000000 }, + { 0x00600001, 0x212003be, 0x008d02a0, 0x00000000 }, + { 0x00600201, 0x20200022, 0x008d0020, 0x00000000 }, + { 0x00800031, 0x24001d28, 0x008d0000, 0x85a04800 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, diff --git a/driver/xf86-video-intel/src/exa_wm_maskca_srcalpha.g4a b/driver/xf86-video-intel/src/exa_wm_maskca_srcalpha.g4a new file mode 100644 index 000000000..a92c9e4f5 --- /dev/null +++ b/driver/xf86-video-intel/src/exa_wm_maskca_srcalpha.g4a @@ -0,0 +1,228 @@ +/* + * Copyright © 2007 Intel Corporation + * + * 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 + * THE AUTHORS OR COPYRIGHT HOLDERS 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: + * Wang Zhenyu <zhenyu.z.wang@intel.com> + */ + +/* + * This's for exa composite operation in no mask picture case. + * The simplest case is just sending what src picture has to dst picture. + * XXX: This is still experimental, and should be fixed to support multiple texture + * map, and conditional mul actions. + */ + +/* I think this should be same as in g4a program for texture video, + as we also use 16-pixel dispatch. and SF scale in g3 is useful for us. */ + +/* The initial payload of the thread is always g0. + * WM_URB (incoming URB entries) is g3 + As mask texture coeffient needs extra setup urb starting from g4, we should + shift this location. + + * X0_R is g4->g6 + * X1_R is g5->g7 + * Y0_R is g6->g8 + * Y1_R is g7->g9 + + * X0: {ss0.x, ss0.x+1, ss0.x, ss0.x+1, ss1.x, ss1.x+1, ss1.x, ss1.x+y} + * Y0: {ss0.y, ss0.y, ss0.y+1, ss0.y+1, ss1.y, ss1.y, ss1.y+1, ss1.y+1} + * X1: {ss2.x, ss2.x+1, ss2.x, ss2.x+1, ss3.x, ss3.x+1, ss3.x, ss3.x+y} + * Y1: {ss2.y, ss2.y, ss2.y+1, ss2.y+1, ss3.y, ss3.y, ss3.y+1, ss3.y+1} + */ + +/* multitexture program with src and mask texture */ +/* - load src texture */ +/* - load mask texture */ +/* - mul src.X with mask's alpha */ +/* - write out src.X */ + + /* Set up ss0.x coordinates*/ +mov (1) g6<1>F g1.8<0,1,0>UW { align1 }; +add (1) g6.4<1>F g1.8<0,1,0>UW 1UB { align1 }; +mov (1) g6.8<1>F g1.8<0,1,0>UW { align1 }; +add (1) g6.12<1>F g1.8<0,1,0>UW 1UB { align1 }; + /* Set up ss0.y coordinates */ +mov (1) g8<1>F g1.10<0,1,0>UW { align1 }; +mov (1) g8.4<1>F g1.10<0,1,0>UW { align1 }; +add (1) g8.8<1>F g1.10<0,1,0>UW 1UB { align1 }; +add (1) g8.12<1>F g1.10<0,1,0>UW 1UB { align1 }; + /* set up ss1.x coordinates */ +mov (1) g6.16<1>F g1.12<0,1,0>UW { align1 }; +add (1) g6.20<1>F g1.12<0,1,0>UW 1UB { align1 }; +mov (1) g6.24<1>F g1.12<0,1,0>UW { align1 }; +add (1) g6.28<1>F g1.12<0,1,0>UW 1UB { align1 }; + /* set up ss1.y coordinates */ +mov (1) g8.16<1>F g1.14<0,1,0>UW { align1 }; +mov (1) g8.20<1>F g1.14<0,1,0>UW { align1 }; +add (1) g8.24<1>F g1.14<0,1,0>UW 1UB { align1 }; +add (1) g8.28<1>F g1.14<0,1,0>UW 1UB { align1 }; + /* Set up ss2.x coordinates */ +mov (1) g7<1>F g1.16<0,1,0>UW { align1 }; +add (1) g7.4<1>F g1.16<0,1,0>UW 1UB { align1 }; +mov (1) g7.8<1>F g1.16<0,1,0>UW { align1 }; +add (1) g7.12<1>F g1.16<0,1,0>UW 1UB { align1 }; + /* Set up ss2.y coordinates */ +mov (1) g9<1>F g1.18<0,1,0>UW { align1 }; +mov (1) g9.4<1>F g1.18<0,1,0>UW { align1 }; +add (1) g9.8<1>F g1.18<0,1,0>UW 1UB { align1 }; +add (1) g9.12<1>F g1.18<0,1,0>UW 1UB { align1 }; + /* Set up ss3.x coordinates */ +mov (1) g7.16<1>F g1.20<0,1,0>UW { align1 }; +add (1) g7.20<1>F g1.20<0,1,0>UW 1UB { align1 }; +mov (1) g7.24<1>F g1.20<0,1,0>UW { align1 }; +add (1) g7.28<1>F g1.20<0,1,0>UW 1UB { align1 }; + /* Set up ss3.y coordinates */ +mov (1) g9.16<1>F g1.22<0,1,0>UW { align1 }; +mov (1) g9.20<1>F g1.22<0,1,0>UW { align1 }; +add (1) g9.24<1>F g1.22<0,1,0>UW 1UB { align1 }; +add (1) g9.28<1>F g1.22<0,1,0>UW 1UB { align1 }; + + /* Now, map these screen space coordinates into texture coordinates. */ +/* This is for src texture */ +/* I don't want to change origin ssX coords, as it will be used later in mask */ +/* so store tex coords in g10, g11, g12, g13 */ + + /* subtract screen-space X origin of vertex 0. */ +add (8) g10<1>F g6<8,8,1>F -g1<0,1,0>F { align1 }; +add (8) g11<1>F g7<8,8,1>F -g1<0,1,0>F { align1 }; + /* scale by texture X increment */ +/* Cx[0] */ +mul (8) g10<1>F g10<8,8,1>F g3<0,1,0>F { align1 }; +mul (8) g11<1>F g11<8,8,1>F g3<0,1,0>F { align1 }; + /* add in texture X offset */ +/* Co[0] */ +add (8) g10<1>F g10<8,8,1>F g3.12<0,1,0>F { align1 }; +add (8) g11<1>F g11<8,8,1>F g3.12<0,1,0>F { align1 }; + /* subtract screen-space Y origin of vertex 0. */ +add (8) g12<1>F g8<8,8,1>F -g1.4<0,1,0>F { align1 }; +add (8) g13<1>F g9<8,8,1>F -g1.4<0,1,0>F { align1 }; + /* scale by texture Y increment */ +/* Cy[0] */ +mul (8) g12<1>F g12<8,8,1>F g3.4<0,1,0>F { align1 }; +mul (8) g13<1>F g13<8,8,1>F g3.4<0,1,0>F { align1 }; + /* add in texture Y offset */ +/* Co[1] */ +add (8) g12<1>F g12<8,8,1>F g3.28<0,1,0>F { align1 }; +add (8) g13<1>F g13<8,8,1>F g3.28<0,1,0>F { align1 }; + +/* prepare sampler read back gX register, which would be written back to output */ + +/* use simd16 sampler, param 0 is u, param 1 is v. */ +/* 'payload' loading, assuming tex coord start from g4 */ +mov (8) m1<1>F g10<8,8,1>F { align1 }; +mov (8) m2<1>F g11<8,8,1>F { align1 }; /* param 0 u in m1, m2 */ +mov (8) m3<1>F g12<8,8,1>F { align1 }; +mov (8) m4<1>F g13<8,8,1>F { align1 }; /* param 1 v in m3, m4 */ + +/* m0 will be copied with g0, as it contains send desc */ +/* emit sampler 'send' cmd */ + +/* src texture readback: g14-g21 */ +send (16) 0 /* msg reg index */ + g14<1>UW /* readback */ + g0<8,8,1>UW /* copy to msg start reg*/ + sampler (1,0,F) /* sampler message description, + (binding_table,sampler_index,datatype). + here(src->dst) we should use src_sampler and + src_surface */ + mlen 5 rlen 8 { align1 }; /* required message len 5, readback len 8 */ + +mov (8) g21<1>UD g21<8,8,1>UD { align1 }; /* wait sampler return */ + +/* sampler mask texture, use g10, g11, g12, g13 */ + /* subtract screen-space X origin of vertex 0. */ +add (8) g10<1>F g6<8,8,1>F -g1<0,1,0>F { align1 }; +add (8) g11<1>F g7<8,8,1>F -g1<0,1,0>F { align1 }; + /* scale by texture X increment */ +/* Cx[2] */ +mul (8) g10<1>F g10<8,8,1>F g4<0,1,0>F { align1 }; +mul (8) g11<1>F g11<8,8,1>F g4<0,1,0>F { align1 }; + /* add in texture X offset */ +/* Co[2] */ +add (8) g10<1>F g10<8,8,1>F g4.12<0,1,0>F { align1 }; +add (8) g11<1>F g11<8,8,1>F g4.12<0,1,0>F { align1 }; + /* subtract screen-space Y origin of vertex 0. */ +add (8) g12<1>F g8<8,8,1>F -g1.4<0,1,0>F { align1 }; +add (8) g13<1>F g9<8,8,1>F -g1.4<0,1,0>F { align1 }; + /* scale by texture Y increment */ +/* Cy[2] */ +mul (8) g12<1>F g12<8,8,1>F g4.4<0,1,0>F { align1 }; +mul (8) g13<1>F g13<8,8,1>F g4.4<0,1,0>F { align1 }; + /* add in texture Y offset */ +/* Co[3] */ +add (8) g12<1>F g12<8,8,1>F g4.28<0,1,0>F { align1 }; +add (8) g13<1>F g13<8,8,1>F g4.28<0,1,0>F { align1 }; + +mov (8) m1<1>F g10<8,8,1>F { align1 }; +mov (8) m2<1>F g11<8,8,1>F { align1 }; +mov (8) m3<1>F g12<8,8,1>F { align1 }; +mov (8) m4<1>F g13<8,8,1>F { align1 }; + +/* mask sampler g22-g29 */ +/* binding_table (2), sampler (1) */ +send (16) 0 g22<1>UW g0<8,8,1>UW sampler (2,1,F) mlen 5 rlen 8 { align1 }; +mov (8) g29<1>UD g29<8,8,1>UD { align1 }; /* wait sampler return */ + +/* src channel has no more use, src.A * mask.C */ +mul (8) g14<1>F g22<8,8,1>F g20<8,8,1>F { align1 }; +mul (8) g15<1>F g23<8,8,1>F g21<8,8,1>F { align1 }; +mul (8) g16<1>F g24<8,8,1>F g20<8,8,1>F { align1 }; +mul (8) g17<1>F g25<8,8,1>F g21<8,8,1>F { align1 }; +mul (8) g18<1>F g26<8,8,1>F g20<8,8,1>F { align1 }; +mul (8) g19<1>F g27<8,8,1>F g21<8,8,1>F { align1 }; +mul (8) g20<1>F g28<8,8,1>F g20<8,8,1>F { align1 }; +mul (8) g21<1>F g29<8,8,1>F g21<8,8,1>F { align1 }; + +/* prepare data in m2-m5 for subspan(1,0), m6-m9 for subspan(3,2), then it's ready to write */ +mov (8) m2<1>F g14<8,8,1>F { align1 }; +mov (8) m3<1>F g16<8,8,1>F { align1 }; +mov (8) m4<1>F g18<8,8,1>F { align1 }; +mov (8) m5<1>F g20<8,8,1>F { align1 }; +mov (8) m6<1>F g15<8,8,1>F { align1 }; +mov (8) m7<1>F g17<8,8,1>F { align1 }; +mov (8) m8<1>F g19<8,8,1>F { align1 }; +mov (8) m9<1>F g21<8,8,1>F { align1 }; + +/* m0, m1 are all direct passed by PS thread payload */ +mov (8) m1<1>UD g1<8,8,1>UD { align1 mask_disable }; + +/* write */ +send (16) 0 acc0<1>UW g0<8,8,1>UW write ( + 0, /* binding_table */ + 8, /* pixel scordboard clear, msg type simd16 single source */ + 4, /* render target write */ + 0 /* no write commit message */ + ) + mlen 10 + rlen 0 + { align1 EOT }; + +nop; +nop; +nop; +nop; +nop; +nop; +nop; +nop; +nop; diff --git a/driver/xf86-video-intel/src/exa_wm_maskca_srcalpha_prog.h b/driver/xf86-video-intel/src/exa_wm_maskca_srcalpha_prog.h new file mode 100644 index 000000000..d83b119f2 --- /dev/null +++ b/driver/xf86-video-intel/src/exa_wm_maskca_srcalpha_prog.h @@ -0,0 +1,95 @@ + { 0x00000001, 0x20c0013d, 0x00000028, 0x00000000 }, + { 0x00000040, 0x20c40d3d, 0x00000028, 0x00000001 }, + { 0x00000001, 0x20c8013d, 0x00000028, 0x00000000 }, + { 0x00000040, 0x20cc0d3d, 0x00000028, 0x00000001 }, + { 0x00000001, 0x2100013d, 0x0000002a, 0x00000000 }, + { 0x00000001, 0x2104013d, 0x0000002a, 0x00000000 }, + { 0x00000040, 0x21080d3d, 0x0000002a, 0x00000001 }, + { 0x00000040, 0x210c0d3d, 0x0000002a, 0x00000001 }, + { 0x00000001, 0x20d0013d, 0x0000002c, 0x00000000 }, + { 0x00000040, 0x20d40d3d, 0x0000002c, 0x00000001 }, + { 0x00000001, 0x20d8013d, 0x0000002c, 0x00000000 }, + { 0x00000040, 0x20dc0d3d, 0x0000002c, 0x00000001 }, + { 0x00000001, 0x2110013d, 0x0000002e, 0x00000000 }, + { 0x00000001, 0x2114013d, 0x0000002e, 0x00000000 }, + { 0x00000040, 0x21180d3d, 0x0000002e, 0x00000001 }, + { 0x00000040, 0x211c0d3d, 0x0000002e, 0x00000001 }, + { 0x00000001, 0x20e0013d, 0x00000030, 0x00000000 }, + { 0x00000040, 0x20e40d3d, 0x00000030, 0x00000001 }, + { 0x00000001, 0x20e8013d, 0x00000030, 0x00000000 }, + { 0x00000040, 0x20ec0d3d, 0x00000030, 0x00000001 }, + { 0x00000001, 0x2120013d, 0x00000032, 0x00000000 }, + { 0x00000001, 0x2124013d, 0x00000032, 0x00000000 }, + { 0x00000040, 0x21280d3d, 0x00000032, 0x00000001 }, + { 0x00000040, 0x212c0d3d, 0x00000032, 0x00000001 }, + { 0x00000001, 0x20f0013d, 0x00000034, 0x00000000 }, + { 0x00000040, 0x20f40d3d, 0x00000034, 0x00000001 }, + { 0x00000001, 0x20f8013d, 0x00000034, 0x00000000 }, + { 0x00000040, 0x20fc0d3d, 0x00000034, 0x00000001 }, + { 0x00000001, 0x2130013d, 0x00000036, 0x00000000 }, + { 0x00000001, 0x2134013d, 0x00000036, 0x00000000 }, + { 0x00000040, 0x21380d3d, 0x00000036, 0x00000001 }, + { 0x00000040, 0x213c0d3d, 0x00000036, 0x00000001 }, + { 0x00600040, 0x214077bd, 0x008d00c0, 0x00004020 }, + { 0x00600040, 0x216077bd, 0x008d00e0, 0x00004020 }, + { 0x00600041, 0x214077bd, 0x008d0140, 0x00000060 }, + { 0x00600041, 0x216077bd, 0x008d0160, 0x00000060 }, + { 0x00600040, 0x214077bd, 0x008d0140, 0x0000006c }, + { 0x00600040, 0x216077bd, 0x008d0160, 0x0000006c }, + { 0x00600040, 0x218077bd, 0x008d0100, 0x00004024 }, + { 0x00600040, 0x21a077bd, 0x008d0120, 0x00004024 }, + { 0x00600041, 0x218077bd, 0x008d0180, 0x00000064 }, + { 0x00600041, 0x21a077bd, 0x008d01a0, 0x00000064 }, + { 0x00600040, 0x218077bd, 0x008d0180, 0x0000007c }, + { 0x00600040, 0x21a077bd, 0x008d01a0, 0x0000007c }, + { 0x00600001, 0x202003be, 0x008d0140, 0x00000000 }, + { 0x00600001, 0x204003be, 0x008d0160, 0x00000000 }, + { 0x00600001, 0x206003be, 0x008d0180, 0x00000000 }, + { 0x00600001, 0x208003be, 0x008d01a0, 0x00000000 }, + { 0x00800031, 0x21c01d29, 0x008d0000, 0x02580001 }, + { 0x00600001, 0x22a00021, 0x008d02a0, 0x00000000 }, + { 0x00600040, 0x214077bd, 0x008d00c0, 0x00004020 }, + { 0x00600040, 0x216077bd, 0x008d00e0, 0x00004020 }, + { 0x00600041, 0x214077bd, 0x008d0140, 0x00000080 }, + { 0x00600041, 0x216077bd, 0x008d0160, 0x00000080 }, + { 0x00600040, 0x214077bd, 0x008d0140, 0x0000008c }, + { 0x00600040, 0x216077bd, 0x008d0160, 0x0000008c }, + { 0x00600040, 0x218077bd, 0x008d0100, 0x00004024 }, + { 0x00600040, 0x21a077bd, 0x008d0120, 0x00004024 }, + { 0x00600041, 0x218077bd, 0x008d0180, 0x00000084 }, + { 0x00600041, 0x21a077bd, 0x008d01a0, 0x00000084 }, + { 0x00600040, 0x218077bd, 0x008d0180, 0x0000009c }, + { 0x00600040, 0x21a077bd, 0x008d01a0, 0x0000009c }, + { 0x00600001, 0x202003be, 0x008d0140, 0x00000000 }, + { 0x00600001, 0x204003be, 0x008d0160, 0x00000000 }, + { 0x00600001, 0x206003be, 0x008d0180, 0x00000000 }, + { 0x00600001, 0x208003be, 0x008d01a0, 0x00000000 }, + { 0x00800031, 0x22c01d29, 0x008d0000, 0x02580102 }, + { 0x00600001, 0x23a00021, 0x008d03a0, 0x00000000 }, + { 0x00600041, 0x21c077bd, 0x008d02c0, 0x008d0280 }, + { 0x00600041, 0x21e077bd, 0x008d02e0, 0x008d02a0 }, + { 0x00600041, 0x220077bd, 0x008d0300, 0x008d0280 }, + { 0x00600041, 0x222077bd, 0x008d0320, 0x008d02a0 }, + { 0x00600041, 0x224077bd, 0x008d0340, 0x008d0280 }, + { 0x00600041, 0x226077bd, 0x008d0360, 0x008d02a0 }, + { 0x00600041, 0x228077bd, 0x008d0380, 0x008d0280 }, + { 0x00600041, 0x22a077bd, 0x008d03a0, 0x008d02a0 }, + { 0x00600001, 0x204003be, 0x008d01c0, 0x00000000 }, + { 0x00600001, 0x206003be, 0x008d0200, 0x00000000 }, + { 0x00600001, 0x208003be, 0x008d0240, 0x00000000 }, + { 0x00600001, 0x20a003be, 0x008d0280, 0x00000000 }, + { 0x00600001, 0x20c003be, 0x008d01e0, 0x00000000 }, + { 0x00600001, 0x20e003be, 0x008d0220, 0x00000000 }, + { 0x00600001, 0x210003be, 0x008d0260, 0x00000000 }, + { 0x00600001, 0x212003be, 0x008d02a0, 0x00000000 }, + { 0x00600201, 0x20200022, 0x008d0020, 0x00000000 }, + { 0x00800031, 0x24001d28, 0x008d0000, 0x85a04800 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, diff --git a/driver/xf86-video-intel/src/exa_wm_masknoca.g4a b/driver/xf86-video-intel/src/exa_wm_masknoca.g4a new file mode 100644 index 000000000..2e9e3c9ab --- /dev/null +++ b/driver/xf86-video-intel/src/exa_wm_masknoca.g4a @@ -0,0 +1,228 @@ +/* + * Copyright © 2006 Intel Corporation + * + * 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 + * THE AUTHORS OR COPYRIGHT HOLDERS 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: + * Wang Zhenyu <zhenyu.z.wang@intel.com> + */ + +/* + * This's for exa composite operation in no mask picture case. + * The simplest case is just sending what src picture has to dst picture. + * XXX: This is still experimental, and should be fixed to support multiple texture + * map, and conditional mul actions. + */ + +/* I think this should be same as in g4a program for texture video, + as we also use 16-pixel dispatch. and SF scale in g3 is useful for us. */ + +/* The initial payload of the thread is always g0. + * WM_URB (incoming URB entries) is g3 + As mask texture coeffient needs extra setup urb starting from g4, we should + shift this location. + + * X0_R is g4->g6 + * X1_R is g5->g7 + * Y0_R is g6->g8 + * Y1_R is g7->g9 + + * X0: {ss0.x, ss0.x+1, ss0.x, ss0.x+1, ss1.x, ss1.x+1, ss1.x, ss1.x+y} + * Y0: {ss0.y, ss0.y, ss0.y+1, ss0.y+1, ss1.y, ss1.y, ss1.y+1, ss1.y+1} + * X1: {ss2.x, ss2.x+1, ss2.x, ss2.x+1, ss3.x, ss3.x+1, ss3.x, ss3.x+y} + * Y1: {ss2.y, ss2.y, ss2.y+1, ss2.y+1, ss3.y, ss3.y, ss3.y+1, ss3.y+1} + */ + +/* multitexture program with src and mask texture */ +/* - load src texture */ +/* - load mask texture */ +/* - mul src.X with mask's alpha */ +/* - write out src.X */ + + /* Set up ss0.x coordinates*/ +mov (1) g6<1>F g1.8<0,1,0>UW { align1 }; +add (1) g6.4<1>F g1.8<0,1,0>UW 1UB { align1 }; +mov (1) g6.8<1>F g1.8<0,1,0>UW { align1 }; +add (1) g6.12<1>F g1.8<0,1,0>UW 1UB { align1 }; + /* Set up ss0.y coordinates */ +mov (1) g8<1>F g1.10<0,1,0>UW { align1 }; +mov (1) g8.4<1>F g1.10<0,1,0>UW { align1 }; +add (1) g8.8<1>F g1.10<0,1,0>UW 1UB { align1 }; +add (1) g8.12<1>F g1.10<0,1,0>UW 1UB { align1 }; + /* set up ss1.x coordinates */ +mov (1) g6.16<1>F g1.12<0,1,0>UW { align1 }; +add (1) g6.20<1>F g1.12<0,1,0>UW 1UB { align1 }; +mov (1) g6.24<1>F g1.12<0,1,0>UW { align1 }; +add (1) g6.28<1>F g1.12<0,1,0>UW 1UB { align1 }; + /* set up ss1.y coordinates */ +mov (1) g8.16<1>F g1.14<0,1,0>UW { align1 }; +mov (1) g8.20<1>F g1.14<0,1,0>UW { align1 }; +add (1) g8.24<1>F g1.14<0,1,0>UW 1UB { align1 }; +add (1) g8.28<1>F g1.14<0,1,0>UW 1UB { align1 }; + /* Set up ss2.x coordinates */ +mov (1) g7<1>F g1.16<0,1,0>UW { align1 }; +add (1) g7.4<1>F g1.16<0,1,0>UW 1UB { align1 }; +mov (1) g7.8<1>F g1.16<0,1,0>UW { align1 }; +add (1) g7.12<1>F g1.16<0,1,0>UW 1UB { align1 }; + /* Set up ss2.y coordinates */ +mov (1) g9<1>F g1.18<0,1,0>UW { align1 }; +mov (1) g9.4<1>F g1.18<0,1,0>UW { align1 }; +add (1) g9.8<1>F g1.18<0,1,0>UW 1UB { align1 }; +add (1) g9.12<1>F g1.18<0,1,0>UW 1UB { align1 }; + /* Set up ss3.x coordinates */ +mov (1) g7.16<1>F g1.20<0,1,0>UW { align1 }; +add (1) g7.20<1>F g1.20<0,1,0>UW 1UB { align1 }; +mov (1) g7.24<1>F g1.20<0,1,0>UW { align1 }; +add (1) g7.28<1>F g1.20<0,1,0>UW 1UB { align1 }; + /* Set up ss3.y coordinates */ +mov (1) g9.16<1>F g1.22<0,1,0>UW { align1 }; +mov (1) g9.20<1>F g1.22<0,1,0>UW { align1 }; +add (1) g9.24<1>F g1.22<0,1,0>UW 1UB { align1 }; +add (1) g9.28<1>F g1.22<0,1,0>UW 1UB { align1 }; + + /* Now, map these screen space coordinates into texture coordinates. */ +/* This is for src texture */ +/* I don't want to change origin ssX coords, as it will be used later in mask */ +/* so store tex coords in g10, g11, g12, g13 */ + + /* subtract screen-space X origin of vertex 0. */ +add (8) g10<1>F g6<8,8,1>F -g1<0,1,0>F { align1 }; +add (8) g11<1>F g7<8,8,1>F -g1<0,1,0>F { align1 }; + /* scale by texture X increment */ +/* Cx[0] */ +mul (8) g10<1>F g10<8,8,1>F g3<0,1,0>F { align1 }; +mul (8) g11<1>F g11<8,8,1>F g3<0,1,0>F { align1 }; + /* add in texture X offset */ +/* Co[0] */ +add (8) g10<1>F g10<8,8,1>F g3.12<0,1,0>F { align1 }; +add (8) g11<1>F g11<8,8,1>F g3.12<0,1,0>F { align1 }; + /* subtract screen-space Y origin of vertex 0. */ +add (8) g12<1>F g8<8,8,1>F -g1.4<0,1,0>F { align1 }; +add (8) g13<1>F g9<8,8,1>F -g1.4<0,1,0>F { align1 }; + /* scale by texture Y increment */ +/* Cy[0] */ +mul (8) g12<1>F g12<8,8,1>F g3.4<0,1,0>F { align1 }; +mul (8) g13<1>F g13<8,8,1>F g3.4<0,1,0>F { align1 }; + /* add in texture Y offset */ +/* Co[1] */ +add (8) g12<1>F g12<8,8,1>F g3.28<0,1,0>F { align1 }; +add (8) g13<1>F g13<8,8,1>F g3.28<0,1,0>F { align1 }; + +/* prepare sampler read back gX register, which would be written back to output */ + +/* use simd16 sampler, param 0 is u, param 1 is v. */ +/* 'payload' loading, assuming tex coord start from g4 */ +mov (8) m1<1>F g10<8,8,1>F { align1 }; +mov (8) m2<1>F g11<8,8,1>F { align1 }; /* param 0 u in m1, m2 */ +mov (8) m3<1>F g12<8,8,1>F { align1 }; +mov (8) m4<1>F g13<8,8,1>F { align1 }; /* param 1 v in m3, m4 */ + +/* m0 will be copied with g0, as it contains send desc */ +/* emit sampler 'send' cmd */ + +/* src texture readback: g14-g21 */ +send (16) 0 /* msg reg index */ + g14<1>UW /* readback */ + g0<8,8,1>UW /* copy to msg start reg*/ + sampler (1,0,F) /* sampler message description, + (binding_table,sampler_index,datatype). + here(src->dst) we should use src_sampler and + src_surface */ + mlen 5 rlen 8 { align1 }; /* required message len 5, readback len 8 */ + +mov (8) g21<1>UD g21<8,8,1>UD { align1 }; /* wait sampler return */ + +/* sampler mask texture, use g10, g11, g12, g13 */ + /* subtract screen-space X origin of vertex 0. */ +add (8) g10<1>F g6<8,8,1>F -g1<0,1,0>F { align1 }; +add (8) g11<1>F g7<8,8,1>F -g1<0,1,0>F { align1 }; + /* scale by texture X increment */ +/* Cx[2] */ +mul (8) g10<1>F g10<8,8,1>F g4<0,1,0>F { align1 }; +mul (8) g11<1>F g11<8,8,1>F g4<0,1,0>F { align1 }; + /* add in texture X offset */ +/* Co[2] */ +add (8) g10<1>F g10<8,8,1>F g4.12<0,1,0>F { align1 }; +add (8) g11<1>F g11<8,8,1>F g4.12<0,1,0>F { align1 }; + /* subtract screen-space Y origin of vertex 0. */ +add (8) g12<1>F g8<8,8,1>F -g1.4<0,1,0>F { align1 }; +add (8) g13<1>F g9<8,8,1>F -g1.4<0,1,0>F { align1 }; + /* scale by texture Y increment */ +/* Cy[2] */ +mul (8) g12<1>F g12<8,8,1>F g4.4<0,1,0>F { align1 }; +mul (8) g13<1>F g13<8,8,1>F g4.4<0,1,0>F { align1 }; + /* add in texture Y offset */ +/* Co[3] */ +add (8) g12<1>F g12<8,8,1>F g4.28<0,1,0>F { align1 }; +add (8) g13<1>F g13<8,8,1>F g4.28<0,1,0>F { align1 }; + +mov (8) m1<1>F g10<8,8,1>F { align1 }; +mov (8) m2<1>F g11<8,8,1>F { align1 }; +mov (8) m3<1>F g12<8,8,1>F { align1 }; +mov (8) m4<1>F g13<8,8,1>F { align1 }; + +/* mask sampler g22-g29 */ +/* binding_table (2), sampler (1) */ +send (16) 0 g22<1>UW g0<8,8,1>UW sampler (2,1,F) mlen 5 rlen 8 { align1 }; +mov (8) g29<1>UD g29<8,8,1>UD { align1 }; /* wait sampler return */ + +/* mul mask's alpha channel g28,g29 to src (g14-g21), then write out src */ +mul (8) g14<1>F g14<8,8,1>F g28<8,8,1>F { align1 }; +mul (8) g15<1>F g15<8,8,1>F g29<8,8,1>F { align1 }; +mul (8) g16<1>F g16<8,8,1>F g28<8,8,1>F { align1 }; +mul (8) g17<1>F g17<8,8,1>F g29<8,8,1>F { align1 }; +mul (8) g18<1>F g18<8,8,1>F g28<8,8,1>F { align1 }; +mul (8) g19<1>F g19<8,8,1>F g29<8,8,1>F { align1 }; +mul (8) g20<1>F g20<8,8,1>F g28<8,8,1>F { align1 }; +mul (8) g21<1>F g21<8,8,1>F g29<8,8,1>F { align1 }; + +/* prepare data in m2-m5 for subspan(1,0), m6-m9 for subspan(3,2), then it's ready to write */ +mov (8) m2<1>F g14<8,8,1>F { align1 }; +mov (8) m3<1>F g16<8,8,1>F { align1 }; +mov (8) m4<1>F g18<8,8,1>F { align1 }; +mov (8) m5<1>F g20<8,8,1>F { align1 }; +mov (8) m6<1>F g15<8,8,1>F { align1 }; +mov (8) m7<1>F g17<8,8,1>F { align1 }; +mov (8) m8<1>F g19<8,8,1>F { align1 }; +mov (8) m9<1>F g21<8,8,1>F { align1 }; + +/* m0, m1 are all direct passed by PS thread payload */ +mov (8) m1<1>UD g1<8,8,1>UD { align1 mask_disable }; + +/* write */ +send (16) 0 acc0<1>UW g0<8,8,1>UW write ( + 0, /* binding_table */ + 8, /* pixel scordboard clear, msg type simd16 single source */ + 4, /* render target write */ + 0 /* no write commit message */ + ) + mlen 10 + rlen 0 + { align1 EOT }; + +nop; +nop; +nop; +nop; +nop; +nop; +nop; +nop; +nop; diff --git a/driver/xf86-video-intel/src/exa_wm_masknoca_prog.h b/driver/xf86-video-intel/src/exa_wm_masknoca_prog.h new file mode 100644 index 000000000..5fcf3b52d --- /dev/null +++ b/driver/xf86-video-intel/src/exa_wm_masknoca_prog.h @@ -0,0 +1,95 @@ + { 0x00000001, 0x20c0013d, 0x00000028, 0x00000000 }, + { 0x00000040, 0x20c40d3d, 0x00000028, 0x00000001 }, + { 0x00000001, 0x20c8013d, 0x00000028, 0x00000000 }, + { 0x00000040, 0x20cc0d3d, 0x00000028, 0x00000001 }, + { 0x00000001, 0x2100013d, 0x0000002a, 0x00000000 }, + { 0x00000001, 0x2104013d, 0x0000002a, 0x00000000 }, + { 0x00000040, 0x21080d3d, 0x0000002a, 0x00000001 }, + { 0x00000040, 0x210c0d3d, 0x0000002a, 0x00000001 }, + { 0x00000001, 0x20d0013d, 0x0000002c, 0x00000000 }, + { 0x00000040, 0x20d40d3d, 0x0000002c, 0x00000001 }, + { 0x00000001, 0x20d8013d, 0x0000002c, 0x00000000 }, + { 0x00000040, 0x20dc0d3d, 0x0000002c, 0x00000001 }, + { 0x00000001, 0x2110013d, 0x0000002e, 0x00000000 }, + { 0x00000001, 0x2114013d, 0x0000002e, 0x00000000 }, + { 0x00000040, 0x21180d3d, 0x0000002e, 0x00000001 }, + { 0x00000040, 0x211c0d3d, 0x0000002e, 0x00000001 }, + { 0x00000001, 0x20e0013d, 0x00000030, 0x00000000 }, + { 0x00000040, 0x20e40d3d, 0x00000030, 0x00000001 }, + { 0x00000001, 0x20e8013d, 0x00000030, 0x00000000 }, + { 0x00000040, 0x20ec0d3d, 0x00000030, 0x00000001 }, + { 0x00000001, 0x2120013d, 0x00000032, 0x00000000 }, + { 0x00000001, 0x2124013d, 0x00000032, 0x00000000 }, + { 0x00000040, 0x21280d3d, 0x00000032, 0x00000001 }, + { 0x00000040, 0x212c0d3d, 0x00000032, 0x00000001 }, + { 0x00000001, 0x20f0013d, 0x00000034, 0x00000000 }, + { 0x00000040, 0x20f40d3d, 0x00000034, 0x00000001 }, + { 0x00000001, 0x20f8013d, 0x00000034, 0x00000000 }, + { 0x00000040, 0x20fc0d3d, 0x00000034, 0x00000001 }, + { 0x00000001, 0x2130013d, 0x00000036, 0x00000000 }, + { 0x00000001, 0x2134013d, 0x00000036, 0x00000000 }, + { 0x00000040, 0x21380d3d, 0x00000036, 0x00000001 }, + { 0x00000040, 0x213c0d3d, 0x00000036, 0x00000001 }, + { 0x00600040, 0x214077bd, 0x008d00c0, 0x00004020 }, + { 0x00600040, 0x216077bd, 0x008d00e0, 0x00004020 }, + { 0x00600041, 0x214077bd, 0x008d0140, 0x00000060 }, + { 0x00600041, 0x216077bd, 0x008d0160, 0x00000060 }, + { 0x00600040, 0x214077bd, 0x008d0140, 0x0000006c }, + { 0x00600040, 0x216077bd, 0x008d0160, 0x0000006c }, + { 0x00600040, 0x218077bd, 0x008d0100, 0x00004024 }, + { 0x00600040, 0x21a077bd, 0x008d0120, 0x00004024 }, + { 0x00600041, 0x218077bd, 0x008d0180, 0x00000064 }, + { 0x00600041, 0x21a077bd, 0x008d01a0, 0x00000064 }, + { 0x00600040, 0x218077bd, 0x008d0180, 0x0000007c }, + { 0x00600040, 0x21a077bd, 0x008d01a0, 0x0000007c }, + { 0x00600001, 0x202003be, 0x008d0140, 0x00000000 }, + { 0x00600001, 0x204003be, 0x008d0160, 0x00000000 }, + { 0x00600001, 0x206003be, 0x008d0180, 0x00000000 }, + { 0x00600001, 0x208003be, 0x008d01a0, 0x00000000 }, + { 0x00800031, 0x21c01d29, 0x008d0000, 0x02580001 }, + { 0x00600001, 0x22a00021, 0x008d02a0, 0x00000000 }, + { 0x00600040, 0x214077bd, 0x008d00c0, 0x00004020 }, + { 0x00600040, 0x216077bd, 0x008d00e0, 0x00004020 }, + { 0x00600041, 0x214077bd, 0x008d0140, 0x00000080 }, + { 0x00600041, 0x216077bd, 0x008d0160, 0x00000080 }, + { 0x00600040, 0x214077bd, 0x008d0140, 0x0000008c }, + { 0x00600040, 0x216077bd, 0x008d0160, 0x0000008c }, + { 0x00600040, 0x218077bd, 0x008d0100, 0x00004024 }, + { 0x00600040, 0x21a077bd, 0x008d0120, 0x00004024 }, + { 0x00600041, 0x218077bd, 0x008d0180, 0x00000084 }, + { 0x00600041, 0x21a077bd, 0x008d01a0, 0x00000084 }, + { 0x00600040, 0x218077bd, 0x008d0180, 0x0000009c }, + { 0x00600040, 0x21a077bd, 0x008d01a0, 0x0000009c }, + { 0x00600001, 0x202003be, 0x008d0140, 0x00000000 }, + { 0x00600001, 0x204003be, 0x008d0160, 0x00000000 }, + { 0x00600001, 0x206003be, 0x008d0180, 0x00000000 }, + { 0x00600001, 0x208003be, 0x008d01a0, 0x00000000 }, + { 0x00800031, 0x22c01d29, 0x008d0000, 0x02580102 }, + { 0x00600001, 0x23a00021, 0x008d03a0, 0x00000000 }, + { 0x00600041, 0x21c077bd, 0x008d01c0, 0x008d0380 }, + { 0x00600041, 0x21e077bd, 0x008d01e0, 0x008d03a0 }, + { 0x00600041, 0x220077bd, 0x008d0200, 0x008d0380 }, + { 0x00600041, 0x222077bd, 0x008d0220, 0x008d03a0 }, + { 0x00600041, 0x224077bd, 0x008d0240, 0x008d0380 }, + { 0x00600041, 0x226077bd, 0x008d0260, 0x008d03a0 }, + { 0x00600041, 0x228077bd, 0x008d0280, 0x008d0380 }, + { 0x00600041, 0x22a077bd, 0x008d02a0, 0x008d03a0 }, + { 0x00600001, 0x204003be, 0x008d01c0, 0x00000000 }, + { 0x00600001, 0x206003be, 0x008d0200, 0x00000000 }, + { 0x00600001, 0x208003be, 0x008d0240, 0x00000000 }, + { 0x00600001, 0x20a003be, 0x008d0280, 0x00000000 }, + { 0x00600001, 0x20c003be, 0x008d01e0, 0x00000000 }, + { 0x00600001, 0x20e003be, 0x008d0220, 0x00000000 }, + { 0x00600001, 0x210003be, 0x008d0260, 0x00000000 }, + { 0x00600001, 0x212003be, 0x008d02a0, 0x00000000 }, + { 0x00600201, 0x20200022, 0x008d0020, 0x00000000 }, + { 0x00800031, 0x24001d28, 0x008d0000, 0x85a04800 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, diff --git a/driver/xf86-video-intel/src/exa_wm_nomask.g4a b/driver/xf86-video-intel/src/exa_wm_nomask.g4a new file mode 100644 index 000000000..f92dc1a68 --- /dev/null +++ b/driver/xf86-video-intel/src/exa_wm_nomask.g4a @@ -0,0 +1,169 @@ +/* + * Copyright © 2006 Intel Corporation + * + * 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 + * THE AUTHORS OR COPYRIGHT HOLDERS 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: + * Wang Zhenyu <zhenyu.z.wang@intel.com> + */ + +/* + * This's for exa composite operation in no mask picture case. + * The simplest case is just sending what src picture has to dst picture. + */ + +/* I think this should be same as in g4a program for texture video, + as we also use 16-pixel dispatch. and SF scale in g3 is useful for us. */ + +/* The initial payload of the thread is always g0. + * WM_URB (incoming URB entries) is g3 + * X0_R is g4 + * X1_R is g5 + * Y0_R is g6 + * Y1_R is g7 + */ + + /* Set up ss0.x coordinates*/ +mov (1) g4<1>F g1.8<0,1,0>UW { align1 }; +add (1) g4.4<1>F g1.8<0,1,0>UW 1UB { align1 }; +mov (1) g4.8<1>F g1.8<0,1,0>UW { align1 }; +add (1) g4.12<1>F g1.8<0,1,0>UW 1UB { align1 }; + /* Set up ss0.y coordinates */ +mov (1) g6<1>F g1.10<0,1,0>UW { align1 }; +mov (1) g6.4<1>F g1.10<0,1,0>UW { align1 }; +add (1) g6.8<1>F g1.10<0,1,0>UW 1UB { align1 }; +add (1) g6.12<1>F g1.10<0,1,0>UW 1UB { align1 }; + /* set up ss1.x coordinates */ +mov (1) g4.16<1>F g1.12<0,1,0>UW { align1 }; +add (1) g4.20<1>F g1.12<0,1,0>UW 1UB { align1 }; +mov (1) g4.24<1>F g1.12<0,1,0>UW { align1 }; +add (1) g4.28<1>F g1.12<0,1,0>UW 1UB { align1 }; + /* set up ss1.y coordinates */ +mov (1) g6.16<1>F g1.14<0,1,0>UW { align1 }; +mov (1) g6.20<1>F g1.14<0,1,0>UW { align1 }; +add (1) g6.24<1>F g1.14<0,1,0>UW 1UB { align1 }; +add (1) g6.28<1>F g1.14<0,1,0>UW 1UB { align1 }; + /* Set up ss2.x coordinates */ +mov (1) g5<1>F g1.16<0,1,0>UW { align1 }; +add (1) g5.4<1>F g1.16<0,1,0>UW 1UB { align1 }; +mov (1) g5.8<1>F g1.16<0,1,0>UW { align1 }; +add (1) g5.12<1>F g1.16<0,1,0>UW 1UB { align1 }; + /* Set up ss2.y coordinates */ +mov (1) g7<1>F g1.18<0,1,0>UW { align1 }; +mov (1) g7.4<1>F g1.18<0,1,0>UW { align1 }; +add (1) g7.8<1>F g1.18<0,1,0>UW 1UB { align1 }; +add (1) g7.12<1>F g1.18<0,1,0>UW 1UB { align1 }; + /* Set up ss3.x coordinates */ +mov (1) g5.16<1>F g1.20<0,1,0>UW { align1 }; +add (1) g5.20<1>F g1.20<0,1,0>UW 1UB { align1 }; +mov (1) g5.24<1>F g1.20<0,1,0>UW { align1 }; +add (1) g5.28<1>F g1.20<0,1,0>UW 1UB { align1 }; + /* Set up ss3.y coordinates */ +mov (1) g7.16<1>F g1.22<0,1,0>UW { align1 }; +mov (1) g7.20<1>F g1.22<0,1,0>UW { align1 }; +add (1) g7.24<1>F g1.22<0,1,0>UW 1UB { align1 }; +add (1) g7.28<1>F g1.22<0,1,0>UW 1UB { align1 }; + + /* Now, map these screen space coordinates into texture coordinates. */ + /* subtract screen-space X origin of vertex 0. */ +add (8) g4<1>F g4<8,8,1>F -g1<0,1,0>F { align1 }; +add (8) g5<1>F g5<8,8,1>F -g1<0,1,0>F { align1 }; + /* scale by texture X increment */ +mul (8) g4<1>F g4<8,8,1>F g3<0,1,0>F { align1 }; +mul (8) g5<1>F g5<8,8,1>F g3<0,1,0>F { align1 }; + /* add in texture X offset */ +add (8) g4<1>F g4<8,8,1>F g3.12<0,1,0>F { align1 }; +add (8) g5<1>F g5<8,8,1>F g3.12<0,1,0>F { align1 }; + /* subtract screen-space Y origin of vertex 0. */ +add (8) g6<1>F g6<8,8,1>F -g1.4<0,1,0>F { align1 }; +add (8) g7<1>F g7<8,8,1>F -g1.4<0,1,0>F { align1 }; + /* scale by texture Y increment */ +mul (8) g6<1>F g6<8,8,1>F g3.20<0,1,0>F { align1 }; +mul (8) g7<1>F g7<8,8,1>F g3.20<0,1,0>F { align1 }; + /* add in texture Y offset */ +add (8) g6<1>F g6<8,8,1>F g3.28<0,1,0>F { align1 }; +add (8) g7<1>F g7<8,8,1>F g3.28<0,1,0>F { align1 }; + +/* prepare sampler read back gX register, which would be written back to output */ + +/* use simd16 sampler, param 0 is u, param 1 is v. */ +/* 'payload' loading, assuming tex coord start from g4 */ +mov (8) m1<1>F g4<8,8,1>F { align1 }; +mov (8) m2<1>F g5<8,8,1>F { align1 }; /* param 0 u in m1, m2 */ +mov (8) m3<1>F g6<8,8,1>F { align1 }; +mov (8) m4<1>F g7<8,8,1>F { align1 }; /* param 1 v in m3, m4 */ + +/* m0 will be copied with g0, as it contains send desc */ +/* emit sampler 'send' cmd */ +send (16) 0 /* msg reg index */ + g12<1>UW /* readback */ + g0<8,8,1>UW /* copy to msg start reg*/ + sampler (1,0,F) /* sampler message description, (binding_table,sampler_index,datatype) + /* here(src->dst) we should use src_sampler and src_surface */ + mlen 5 rlen 8 { align1 }; /* required message len 5, readback len 8 */ + +mov (8) g19<1>UD g19<8,8,1>UD { align1 }; /* wait sampler return */ +/* if we set up read-back reg correctly, emit dataport write 'send' cmd with EOT */ + +/* m0, m1 are all direct passed by PS thread payload */ +mov (8) m1<1>F g1<8,8,1>F { align1 }; + +/* prepare data in m2-m5 for subspan(1,0), m6-m9 for subspan(3,2), then it's ready to write */ +/* g12 -> m2 + g13 -> m6 + g14 -> m3 + g15 -> m7 + g16 -> m4 + g17 -> m8 + g18 -> m5 + g19 -> m9 +*/ +mov (8) m2<1>F g12<8,8,1>F { align1 }; +mov (8) m3<1>F g14<8,8,1>F { align1 }; +mov (8) m4<1>F g16<8,8,1>F { align1 }; +mov (8) m5<1>F g18<8,8,1>F { align1 }; +mov (8) m6<1>F g13<8,8,1>F { align1 }; +mov (8) m7<1>F g15<8,8,1>F { align1 }; +mov (8) m8<1>F g17<8,8,1>F { align1 }; +mov (8) m9<1>F g19<8,8,1>F { align1 }; + +/* m0, m1 are all direct passed by PS thread payload */ +mov (8) m1<1>UD g1<8,8,1>UD { align1 mask_disable }; + +/* write */ +send (16) 0 acc0<1>UW g0<8,8,1>UW write ( + 0, /* binding_table */ + 8, /* pixel scordboard clear, msg type simd16 single source */ + 4, /* render target write */ + 0 /* no write commit message */ + ) + mlen 10 + rlen 0 + { align1 EOT }; + +nop; +nop; +nop; +nop; +nop; +nop; +nop; +nop; +nop; diff --git a/driver/xf86-video-intel/src/exa_wm_nomask_prog.h b/driver/xf86-video-intel/src/exa_wm_nomask_prog.h new file mode 100644 index 000000000..7870b3b71 --- /dev/null +++ b/driver/xf86-video-intel/src/exa_wm_nomask_prog.h @@ -0,0 +1,70 @@ + { 0x00000001, 0x2080013d, 0x00000028, 0x00000000 }, + { 0x00000040, 0x20840d3d, 0x00000028, 0x00000001 }, + { 0x00000001, 0x2088013d, 0x00000028, 0x00000000 }, + { 0x00000040, 0x208c0d3d, 0x00000028, 0x00000001 }, + { 0x00000001, 0x20c0013d, 0x0000002a, 0x00000000 }, + { 0x00000001, 0x20c4013d, 0x0000002a, 0x00000000 }, + { 0x00000040, 0x20c80d3d, 0x0000002a, 0x00000001 }, + { 0x00000040, 0x20cc0d3d, 0x0000002a, 0x00000001 }, + { 0x00000001, 0x2090013d, 0x0000002c, 0x00000000 }, + { 0x00000040, 0x20940d3d, 0x0000002c, 0x00000001 }, + { 0x00000001, 0x2098013d, 0x0000002c, 0x00000000 }, + { 0x00000040, 0x209c0d3d, 0x0000002c, 0x00000001 }, + { 0x00000001, 0x20d0013d, 0x0000002e, 0x00000000 }, + { 0x00000001, 0x20d4013d, 0x0000002e, 0x00000000 }, + { 0x00000040, 0x20d80d3d, 0x0000002e, 0x00000001 }, + { 0x00000040, 0x20dc0d3d, 0x0000002e, 0x00000001 }, + { 0x00000001, 0x20a0013d, 0x00000030, 0x00000000 }, + { 0x00000040, 0x20a40d3d, 0x00000030, 0x00000001 }, + { 0x00000001, 0x20a8013d, 0x00000030, 0x00000000 }, + { 0x00000040, 0x20ac0d3d, 0x00000030, 0x00000001 }, + { 0x00000001, 0x20e0013d, 0x00000032, 0x00000000 }, + { 0x00000001, 0x20e4013d, 0x00000032, 0x00000000 }, + { 0x00000040, 0x20e80d3d, 0x00000032, 0x00000001 }, + { 0x00000040, 0x20ec0d3d, 0x00000032, 0x00000001 }, + { 0x00000001, 0x20b0013d, 0x00000034, 0x00000000 }, + { 0x00000040, 0x20b40d3d, 0x00000034, 0x00000001 }, + { 0x00000001, 0x20b8013d, 0x00000034, 0x00000000 }, + { 0x00000040, 0x20bc0d3d, 0x00000034, 0x00000001 }, + { 0x00000001, 0x20f0013d, 0x00000036, 0x00000000 }, + { 0x00000001, 0x20f4013d, 0x00000036, 0x00000000 }, + { 0x00000040, 0x20f80d3d, 0x00000036, 0x00000001 }, + { 0x00000040, 0x20fc0d3d, 0x00000036, 0x00000001 }, + { 0x00600040, 0x208077bd, 0x008d0080, 0x00004020 }, + { 0x00600040, 0x20a077bd, 0x008d00a0, 0x00004020 }, + { 0x00600041, 0x208077bd, 0x008d0080, 0x00000060 }, + { 0x00600041, 0x20a077bd, 0x008d00a0, 0x00000060 }, + { 0x00600040, 0x208077bd, 0x008d0080, 0x0000006c }, + { 0x00600040, 0x20a077bd, 0x008d00a0, 0x0000006c }, + { 0x00600040, 0x20c077bd, 0x008d00c0, 0x00004024 }, + { 0x00600040, 0x20e077bd, 0x008d00e0, 0x00004024 }, + { 0x00600041, 0x20c077bd, 0x008d00c0, 0x00000074 }, + { 0x00600041, 0x20e077bd, 0x008d00e0, 0x00000074 }, + { 0x00600040, 0x20c077bd, 0x008d00c0, 0x0000007c }, + { 0x00600040, 0x20e077bd, 0x008d00e0, 0x0000007c }, + { 0x00600001, 0x202003be, 0x008d0080, 0x00000000 }, + { 0x00600001, 0x204003be, 0x008d00a0, 0x00000000 }, + { 0x00600001, 0x206003be, 0x008d00c0, 0x00000000 }, + { 0x00600001, 0x208003be, 0x008d00e0, 0x00000000 }, + { 0x00800031, 0x21801d29, 0x008d0000, 0x02580001 }, + { 0x00600001, 0x22600021, 0x008d0260, 0x00000000 }, + { 0x00600001, 0x202003be, 0x008d0020, 0x00000000 }, + { 0x00600001, 0x204003be, 0x008d0180, 0x00000000 }, + { 0x00600001, 0x206003be, 0x008d01c0, 0x00000000 }, + { 0x00600001, 0x208003be, 0x008d0200, 0x00000000 }, + { 0x00600001, 0x20a003be, 0x008d0240, 0x00000000 }, + { 0x00600001, 0x20c003be, 0x008d01a0, 0x00000000 }, + { 0x00600001, 0x20e003be, 0x008d01e0, 0x00000000 }, + { 0x00600001, 0x210003be, 0x008d0220, 0x00000000 }, + { 0x00600001, 0x212003be, 0x008d0260, 0x00000000 }, + { 0x00600201, 0x20200022, 0x008d0020, 0x00000000 }, + { 0x00800031, 0x24001d28, 0x008d0000, 0x85a04800 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, diff --git a/driver/xf86-video-intel/src/exa_wm_rotation.g4a b/driver/xf86-video-intel/src/exa_wm_rotation.g4a new file mode 100644 index 000000000..613a5cb2e --- /dev/null +++ b/driver/xf86-video-intel/src/exa_wm_rotation.g4a @@ -0,0 +1,184 @@ +/* + * Copyright © 2007 Intel Corporation + * + * 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 + * THE AUTHORS OR COPYRIGHT HOLDERS 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: + * Wang Zhenyu <zhenyu.z.wang@intel.com> + */ + +/* + * This's for exa composite operation in no mask picture case. + * The simplest case is just sending what src picture has to dst picture. + */ + +/* I think this should be same as in g4a program for texture video, + as we also use 16-pixel dispatch. and SF scale in g3 is useful for us. */ + +/* The initial payload of the thread is always g0. + * WM_URB (incoming URB entries) is g3 + * X0_R is g4 + * X1_R is g5 + * Y0_R is g6 + * Y1_R is g7 + */ + + /* Set up the X/Y screen coordinates of the pixels in our 4 subspans. Each + * subspan is a 2x2 rectangle, and the screen x/y of the upper left of each + * subspan are given in GRF register 1.2 through 1.5 (which, with the word + * addressing below, are 1.4 through 1.11). + * + * The result is WM_X*_R and WM_Y*R being: + * + * X0: {ss0.x, ss0.x+1, ss0.x, ss0.x+1, ss1.x, ss1.x+1, ss1.x, ss1.x+y} + * Y0: {ss0.y, ss0.y, ss0.y+1, ss0.y+1, ss1.y, ss1.y, ss1.y+1, ss1.y+1} + * X1: {ss2.x, ss2.x+1, ss2.x, ss2.x+1, ss3.x, ss3.x+1, ss3.x, ss3.x+y} + * Y1: {ss2.y, ss2.y, ss2.y+1, ss2.y+1, ss3.y, ss3.y, ss3.y+1, ss3.y+1} + */ + /* Set up ss0.x coordinates*/ +mov (1) g4<1>F g1.8<0,1,0>UW { align1 }; +add (1) g4.4<1>F g1.8<0,1,0>UW 1UB { align1 }; +mov (1) g4.8<1>F g1.8<0,1,0>UW { align1 }; +add (1) g4.12<1>F g1.8<0,1,0>UW 1UB { align1 }; + /* Set up ss0.y coordinates */ +mov (1) g6<1>F g1.10<0,1,0>UW { align1 }; +mov (1) g6.4<1>F g1.10<0,1,0>UW { align1 }; +add (1) g6.8<1>F g1.10<0,1,0>UW 1UB { align1 }; +add (1) g6.12<1>F g1.10<0,1,0>UW 1UB { align1 }; + /* set up ss1.x coordinates */ +mov (1) g4.16<1>F g1.12<0,1,0>UW { align1 }; +add (1) g4.20<1>F g1.12<0,1,0>UW 1UB { align1 }; +mov (1) g4.24<1>F g1.12<0,1,0>UW { align1 }; +add (1) g4.28<1>F g1.12<0,1,0>UW 1UB { align1 }; + /* set up ss1.y coordinates */ +mov (1) g6.16<1>F g1.14<0,1,0>UW { align1 }; +mov (1) g6.20<1>F g1.14<0,1,0>UW { align1 }; +add (1) g6.24<1>F g1.14<0,1,0>UW 1UB { align1 }; +add (1) g6.28<1>F g1.14<0,1,0>UW 1UB { align1 }; + /* Set up ss2.x coordinates */ +mov (1) g5<1>F g1.16<0,1,0>UW { align1 }; +add (1) g5.4<1>F g1.16<0,1,0>UW 1UB { align1 }; +mov (1) g5.8<1>F g1.16<0,1,0>UW { align1 }; +add (1) g5.12<1>F g1.16<0,1,0>UW 1UB { align1 }; + /* Set up ss2.y coordinates */ +mov (1) g7<1>F g1.18<0,1,0>UW { align1 }; +mov (1) g7.4<1>F g1.18<0,1,0>UW { align1 }; +add (1) g7.8<1>F g1.18<0,1,0>UW 1UB { align1 }; +add (1) g7.12<1>F g1.18<0,1,0>UW 1UB { align1 }; + /* Set up ss3.x coordinates */ +mov (1) g5.16<1>F g1.20<0,1,0>UW { align1 }; +add (1) g5.20<1>F g1.20<0,1,0>UW 1UB { align1 }; +mov (1) g5.24<1>F g1.20<0,1,0>UW { align1 }; +add (1) g5.28<1>F g1.20<0,1,0>UW 1UB { align1 }; + /* Set up ss3.y coordinates */ +mov (1) g7.16<1>F g1.22<0,1,0>UW { align1 }; +mov (1) g7.20<1>F g1.22<0,1,0>UW { align1 }; +add (1) g7.24<1>F g1.22<0,1,0>UW 1UB { align1 }; +add (1) g7.28<1>F g1.22<0,1,0>UW 1UB { align1 }; + + /* Now, map these screen space coordinates into texture coordinates. */ + /* subtract screen-space X origin of vertex 0. */ +/* for rotation, texture y is from ssX.x, so g4,g5 will be Y */ +add (8) g4<1>F g4<8,8,1>F -g1<0,1,0>F { align1 }; +add (8) g5<1>F g5<8,8,1>F -g1<0,1,0>F { align1 }; + /* scale by texture X increment */ +mul (8) g4<1>F g4<8,8,1>F g3.20<0,1,0>F { align1 }; +mul (8) g5<1>F g5<8,8,1>F g3.20<0,1,0>F { align1 }; + /* add in texture X offset */ +add (8) g4<1>F g4<8,8,1>F g3.28<0,1,0>F { align1 }; +add (8) g5<1>F g5<8,8,1>F g3.28<0,1,0>F { align1 }; + +/* texture Y is from ssX.x */ + /* subtract screen-space Y origin of vertex 0. */ +add (8) g6<1>F g6<8,8,1>F -g1.4<0,1,0>F { align1 }; +add (8) g7<1>F g7<8,8,1>F -g1.4<0,1,0>F { align1 }; + /* scale by texture Y increment */ +mul (8) g6<1>F g6<8,8,1>F g3.16<0,1,0>F { align1 }; +mul (8) g7<1>F g7<8,8,1>F g3.16<0,1,0>F { align1 }; + /* add in texture Y offset */ +add (8) g6<1>F g6<8,8,1>F g3.12<0,1,0>F { align1 }; +add (8) g7<1>F g7<8,8,1>F g3.12<0,1,0>F { align1 }; + +/* prepare sampler read back gX register, which would be written back to output */ + +/* use simd16 sampler, param 0 is u, param 1 is v. */ +/* 'payload' loading, assuming tex coord start from g4 */ +mov (8) m1<1>F g6<8,8,1>F { align1 }; +mov (8) m2<1>F g7<8,8,1>F { align1 }; +mov (8) m3<1>F g4<8,8,1>F { align1 }; +mov (8) m4<1>F g5<8,8,1>F { align1 }; + +/* m0 will be copied with g0, as it contains send desc */ +/* emit sampler 'send' cmd */ +send (16) 0 /* msg reg index */ + g12<1>UW /* readback */ + g0<8,8,1>UW /* copy to msg start reg*/ + sampler (1,0,F) /* sampler message description, (binding_table,sampler_index,datatype) + /* here(src->dst) we should use src_sampler and src_surface */ + mlen 5 rlen 8 { align1 }; /* required message len 5, readback len 8 */ + +mov (8) g19<1>UD g19<8,8,1>UD { align1 }; /* wait sampler return */ +/* if we set up read-back reg correctly, emit dataport write 'send' cmd with EOT */ + +/* m0, m1 are all direct passed by PS thread payload */ +mov (8) m1<1>F g1<8,8,1>F { align1 }; + +/* prepare data in m2-m5 for subspan(1,0), m6-m9 for subspan(3,2), then it's ready to write */ +/* g12 -> m2 + g13 -> m6 + g14 -> m3 + g15 -> m7 + g16 -> m4 + g17 -> m8 + g18 -> m5 + g19 -> m9 +*/ +mov (8) m2<1>F g12<8,8,1>F { align1 }; +mov (8) m3<1>F g14<8,8,1>F { align1 }; +mov (8) m4<1>F g16<8,8,1>F { align1 }; +mov (8) m5<1>F g18<8,8,1>F { align1 }; +mov (8) m6<1>F g13<8,8,1>F { align1 }; +mov (8) m7<1>F g15<8,8,1>F { align1 }; +mov (8) m8<1>F g17<8,8,1>F { align1 }; +mov (8) m9<1>F g19<8,8,1>F { align1 }; + +/* m0, m1 are all direct passed by PS thread payload */ +mov (8) m1<1>UD g1<8,8,1>UD { align1 mask_disable }; + +/* write */ +send (16) 0 acc0<1>UW g0<8,8,1>UW write ( + 0, /* binding_table */ + 8, /* pixel scordboard clear, msg type simd16 single source */ + 4, /* render target write */ + 0 /* no write commit message */ + ) + mlen 10 + rlen 0 + { align1 EOT }; + +nop; +nop; +nop; +nop; +nop; +nop; +nop; +nop; +nop; diff --git a/driver/xf86-video-intel/src/exa_wm_rotation_prog.h b/driver/xf86-video-intel/src/exa_wm_rotation_prog.h new file mode 100644 index 000000000..890d2cf03 --- /dev/null +++ b/driver/xf86-video-intel/src/exa_wm_rotation_prog.h @@ -0,0 +1,70 @@ + { 0x00000001, 0x2080013d, 0x00000028, 0x00000000 }, + { 0x00000040, 0x20840d3d, 0x00000028, 0x00000001 }, + { 0x00000001, 0x2088013d, 0x00000028, 0x00000000 }, + { 0x00000040, 0x208c0d3d, 0x00000028, 0x00000001 }, + { 0x00000001, 0x20c0013d, 0x0000002a, 0x00000000 }, + { 0x00000001, 0x20c4013d, 0x0000002a, 0x00000000 }, + { 0x00000040, 0x20c80d3d, 0x0000002a, 0x00000001 }, + { 0x00000040, 0x20cc0d3d, 0x0000002a, 0x00000001 }, + { 0x00000001, 0x2090013d, 0x0000002c, 0x00000000 }, + { 0x00000040, 0x20940d3d, 0x0000002c, 0x00000001 }, + { 0x00000001, 0x2098013d, 0x0000002c, 0x00000000 }, + { 0x00000040, 0x209c0d3d, 0x0000002c, 0x00000001 }, + { 0x00000001, 0x20d0013d, 0x0000002e, 0x00000000 }, + { 0x00000001, 0x20d4013d, 0x0000002e, 0x00000000 }, + { 0x00000040, 0x20d80d3d, 0x0000002e, 0x00000001 }, + { 0x00000040, 0x20dc0d3d, 0x0000002e, 0x00000001 }, + { 0x00000001, 0x20a0013d, 0x00000030, 0x00000000 }, + { 0x00000040, 0x20a40d3d, 0x00000030, 0x00000001 }, + { 0x00000001, 0x20a8013d, 0x00000030, 0x00000000 }, + { 0x00000040, 0x20ac0d3d, 0x00000030, 0x00000001 }, + { 0x00000001, 0x20e0013d, 0x00000032, 0x00000000 }, + { 0x00000001, 0x20e4013d, 0x00000032, 0x00000000 }, + { 0x00000040, 0x20e80d3d, 0x00000032, 0x00000001 }, + { 0x00000040, 0x20ec0d3d, 0x00000032, 0x00000001 }, + { 0x00000001, 0x20b0013d, 0x00000034, 0x00000000 }, + { 0x00000040, 0x20b40d3d, 0x00000034, 0x00000001 }, + { 0x00000001, 0x20b8013d, 0x00000034, 0x00000000 }, + { 0x00000040, 0x20bc0d3d, 0x00000034, 0x00000001 }, + { 0x00000001, 0x20f0013d, 0x00000036, 0x00000000 }, + { 0x00000001, 0x20f4013d, 0x00000036, 0x00000000 }, + { 0x00000040, 0x20f80d3d, 0x00000036, 0x00000001 }, + { 0x00000040, 0x20fc0d3d, 0x00000036, 0x00000001 }, + { 0x00600040, 0x208077bd, 0x008d0080, 0x00004020 }, + { 0x00600040, 0x20a077bd, 0x008d00a0, 0x00004020 }, + { 0x00600041, 0x208077bd, 0x008d0080, 0x00000074 }, + { 0x00600041, 0x20a077bd, 0x008d00a0, 0x00000074 }, + { 0x00600040, 0x208077bd, 0x008d0080, 0x0000007c }, + { 0x00600040, 0x20a077bd, 0x008d00a0, 0x0000007c }, + { 0x00600040, 0x20c077bd, 0x008d00c0, 0x00004024 }, + { 0x00600040, 0x20e077bd, 0x008d00e0, 0x00004024 }, + { 0x00600041, 0x20c077bd, 0x008d00c0, 0x00000070 }, + { 0x00600041, 0x20e077bd, 0x008d00e0, 0x00000070 }, + { 0x00600040, 0x20c077bd, 0x008d00c0, 0x0000006c }, + { 0x00600040, 0x20e077bd, 0x008d00e0, 0x0000006c }, + { 0x00600001, 0x202003be, 0x008d00c0, 0x00000000 }, + { 0x00600001, 0x204003be, 0x008d00e0, 0x00000000 }, + { 0x00600001, 0x206003be, 0x008d0080, 0x00000000 }, + { 0x00600001, 0x208003be, 0x008d00a0, 0x00000000 }, + { 0x00800031, 0x21801d29, 0x008d0000, 0x02580001 }, + { 0x00600001, 0x22600021, 0x008d0260, 0x00000000 }, + { 0x00600001, 0x202003be, 0x008d0020, 0x00000000 }, + { 0x00600001, 0x204003be, 0x008d0180, 0x00000000 }, + { 0x00600001, 0x206003be, 0x008d01c0, 0x00000000 }, + { 0x00600001, 0x208003be, 0x008d0200, 0x00000000 }, + { 0x00600001, 0x20a003be, 0x008d0240, 0x00000000 }, + { 0x00600001, 0x20c003be, 0x008d01a0, 0x00000000 }, + { 0x00600001, 0x20e003be, 0x008d01e0, 0x00000000 }, + { 0x00600001, 0x210003be, 0x008d0220, 0x00000000 }, + { 0x00600001, 0x212003be, 0x008d0260, 0x00000000 }, + { 0x00600201, 0x20200022, 0x008d0020, 0x00000000 }, + { 0x00800031, 0x24001d28, 0x008d0000, 0x85a04800 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000007e, 0x00000000, 0x00000000, 0x00000000 }, diff --git a/driver/xf86-video-intel/src/i2c_vid.h b/driver/xf86-video-intel/src/i2c_vid.h new file mode 100644 index 000000000..6c4e95dfc --- /dev/null +++ b/driver/xf86-video-intel/src/i2c_vid.h @@ -0,0 +1,136 @@ +/* + * Copyright © 2006 Eric Anholt + * + * 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 the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS 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. + */ + +#ifndef I2C_VID_H +#define I2C_VID_H +#include <randrstr.h> + +typedef struct _I830I2CVidOutputRec { + /** + * Initialize the device at startup time. + * Returns NULL if the device does not exist. + */ + void *(*init)(I2CBusPtr b, I2CSlaveAddr addr); + + /** + * Called to allow the output a chance to create properties after the + * RandR objects have been created. + */ + void + (*create_resources)(I2CDevPtr d); + + /** + * Turns the output on/off, or sets intermediate power levels if available. + * + * Unsupported intermediate modes drop to the lower power setting. If the + * mode is DPMSModeOff, the output must be disabled, as the DPLL may be + * disabled afterwards. + */ + void (*dpms)(I2CDevPtr d, int mode); + + /** + * Saves the output's state for restoration on VT switch. + */ + void (*save)(I2CDevPtr d); + + /** + * Restore's the output's state at VT switch. + */ + void (*restore)(I2CDevPtr d); + + /** + * Callback for testing a video mode for a given output. + * + * This function should only check for cases where a mode can't be supported + * on the output specifically, and not represent generic CRTC limitations. + * + * \return MODE_OK if the mode is valid, or another MODE_* otherwise. + */ + int (*mode_valid)(I2CDevPtr d, DisplayModePtr mode); + + /** + * Callback to adjust the mode to be set in the CRTC. + * + * This allows an output to adjust the clock or even the entire set of + * timings, which is used for panels with fixed timings or for + * buses with clock limitations. + */ + Bool (*mode_fixup)(I2CDevPtr d, DisplayModePtr mode, DisplayModePtr adjusted_mode); + + /** + * Callback for preparing mode changes on an output + */ + void (*prepare)(I2CDevPtr d); + + /** + * Callback for committing mode changes on an output + */ + void (*commit)(I2CDevPtr d); + + /** + * Callback for setting up a video mode after fixups have been made. + * + * This is only called while the output is disabled. The dpms callback + * must be all that's necessary for the output, to turn the output on + * after this function is called. + */ + void (*mode_set)(I2CDevPtr d, DisplayModePtr mode, DisplayModePtr adjusted_mode); + + /** + * Probe for a connected output, and return detect_status. + */ + xf86OutputStatus (*detect)(I2CDevPtr d); + + /** + * Query the device for the modes it provides. + * + * This function may also update MonInfo, mm_width, and mm_height. + * + * \return singly-linked list of modes or NULL if no modes found. + */ + DisplayModePtr + (*get_modes)(I2CDevPtr d); + +#ifdef RANDR_12_INTERFACE + /** + * Callback when an output's property has changed. + */ + Bool + (*set_property)(I2CDevPtr d, Atom property, RRPropertyValuePtr value); +#endif + + /** + * Clean up driver-specific bits of the output + */ + void (*destroy) (I2CDevPtr d); + + /** + * Debugging hook to dump device registers to log file + */ + void (*dump_regs)(I2CDevPtr d); +} I830I2CVidOutputRec, *I830I2CVidOutputPtr; + +/* XXX change this name to avoid driver-specific prefix */ +DisplayModePtr +i830_dvo_get_current_mode (xf86OutputPtr output); + +#endif diff --git a/driver/xf86-video-intel/src/i830_bios.c b/driver/xf86-video-intel/src/i830_bios.c new file mode 100644 index 000000000..7ed791e67 --- /dev/null +++ b/driver/xf86-video-intel/src/i830_bios.c @@ -0,0 +1,298 @@ +/* + * Copyright © 2006 Intel Corporation + * + * 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 + * THE AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#undef VERSION /* XXX edid.h has a VERSION too */ +#endif + +#include <stdio.h> +#include <string.h> + +#define _PARSE_EDID_ +#include "xf86.h" +#include "i830.h" +#include "i830_bios.h" +#include "edid.h" + +#define INTEL_BIOS_8(_addr) (bios[_addr]) +#define INTEL_BIOS_16(_addr) (bios[_addr] | \ + (bios[_addr + 1] << 8)) +#define INTEL_BIOS_32(_addr) (bios[_addr] | \ + (bios[_addr + 1] << 8) \ + (bios[_addr + 2] << 16) \ + (bios[_addr + 3] << 24)) + +/* XXX */ +#define INTEL_VBIOS_SIZE (64 * 1024) + +static void +i830DumpBIOSToFile(ScrnInfoPtr pScrn, unsigned char *bios) +{ + const char *filename = "/tmp/xf86-video-intel-VBIOS"; + FILE *f; + + f = fopen(filename, "w"); + if (f == NULL) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Couldn't open %s\n", filename); + return; + } + if (fwrite(bios, INTEL_VBIOS_SIZE, 1, f) != 1) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Couldn't write BIOS data\n"); + } + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Wrote BIOS contents to %s\n", + filename); + fclose(f); +} + +/** + * Loads the Video BIOS and checks that the VBT exists. + * + * VBT existence is a sanity check that is relied on by other i830_bios.c code. + * Note that it would be better to use a BIOS call to get the VBT, as BIOSes may + * feed an updated VBT back through that, compared to what we'll fetch using + * this method of groping around in the BIOS data. + */ +unsigned char * +i830_bios_get (ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + struct vbt_header *vbt; + int vbt_off; + unsigned char *bios; + vbeInfoPtr pVbe; + + bios = xalloc(INTEL_VBIOS_SIZE); + if (bios == NULL) + return NULL; + + pVbe = VBEInit (NULL, pI830->pEnt->index); + if (pVbe != NULL) { + memcpy(bios, xf86int10Addr(pVbe->pInt10, + pVbe->pInt10->BIOSseg << 4), + INTEL_VBIOS_SIZE); + vbeFree (pVbe); + } else { +#if XSERVER_LIBPCIACCESS + pci_device_read_rom (pI830->PciInfo, bios); +#else + xf86ReadPciBIOS(0, pI830->PciTag, 0, bios, INTEL_VBIOS_SIZE); +#endif + } + + if (0) + i830DumpBIOSToFile(pScrn, bios); + + vbt_off = INTEL_BIOS_16(0x1a); + if (vbt_off >= INTEL_VBIOS_SIZE) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Bad VBT offset: 0x%x\n", + vbt_off); + xfree(bios); + return NULL; + } + + vbt = (struct vbt_header *)(bios + vbt_off); + + if (memcmp(vbt->signature, "$VBT", 4) != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Bad VBT signature\n"); + xfree(bios); + return NULL; + } + + return bios; +} + +/** + * Returns the BIOS's fixed panel mode. + * + * Note that many BIOSes will have the appropriate tables for a panel even when + * a panel is not attached. Additionally, many BIOSes adjust table sizes or + * offsets, such that this parsing fails. Thus, almost any other method for + * detecting the panel mode is preferable. + */ +DisplayModePtr +i830_bios_get_panel_mode(ScrnInfoPtr pScrn, Bool *wants_dither) +{ + I830Ptr pI830 = I830PTR(pScrn); + struct vbt_header *vbt; + struct bdb_header *bdb; + int vbt_off, bdb_off, bdb_block_off, block_size; + int panel_type = -1; + unsigned char *bios; + + bios = i830_bios_get (pScrn); + + if (bios == NULL) + return NULL; + + vbt_off = INTEL_BIOS_16(0x1a); + vbt = (struct vbt_header *)(bios + vbt_off); + bdb_off = vbt_off + vbt->bdb_offset; + bdb = (struct bdb_header *)(bios + bdb_off); + + if (memcmp(bdb->signature, "BIOS_DATA_BLOCK ", 16) != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Bad BDB signature\n"); + xfree(bios); + return NULL; + } + + *wants_dither = FALSE; + for (bdb_block_off = bdb->header_size; bdb_block_off < bdb->bdb_size; + bdb_block_off += block_size) + { + int start = bdb_off + bdb_block_off; + int id; + struct lvds_bdb_1 *lvds1; + struct lvds_bdb_2 *lvds2; + struct lvds_bdb_2_fp_params *fpparam; + struct lvds_bdb_2_fp_edid_dtd *fptiming; + DisplayModePtr fixed_mode; + CARD8 *timing_ptr; + + id = INTEL_BIOS_8(start); + block_size = INTEL_BIOS_16(start + 1) + 3; + switch (id) { + case 40: + lvds1 = (struct lvds_bdb_1 *)(bios + start); + panel_type = lvds1->panel_type; + if (lvds1->caps & LVDS_CAP_DITHER) + *wants_dither = TRUE; + break; + case 41: + if (panel_type == -1) + break; + + lvds2 = (struct lvds_bdb_2 *)(bios + start); + fpparam = (struct lvds_bdb_2_fp_params *)(bios + + bdb_off + lvds2->panels[panel_type].fp_params_offset); + fptiming = (struct lvds_bdb_2_fp_edid_dtd *)(bios + + bdb_off + lvds2->panels[panel_type].fp_edid_dtd_offset); + timing_ptr = bios + bdb_off + + lvds2->panels[panel_type].fp_edid_dtd_offset; + + if (fpparam->terminator != 0xffff) { + /* Apparently the offsets are wrong for some BIOSes, so we + * try the other offsets if we find a bad terminator. + */ + fpparam = (struct lvds_bdb_2_fp_params *)(bios + + bdb_off + lvds2->panels[panel_type].fp_params_offset + 8); + fptiming = (struct lvds_bdb_2_fp_edid_dtd *)(bios + + bdb_off + lvds2->panels[panel_type].fp_edid_dtd_offset + 8); + timing_ptr = bios + bdb_off + + lvds2->panels[panel_type].fp_edid_dtd_offset + 8; + + if (fpparam->terminator != 0xffff) + continue; + } + + fixed_mode = xnfalloc(sizeof(DisplayModeRec)); + memset(fixed_mode, 0, sizeof(*fixed_mode)); + + /* Since lvds_bdb_2_fp_edid_dtd is just an EDID detailed timing + * block, pull the contents out using EDID macros. + */ + fixed_mode->HDisplay = _H_ACTIVE(timing_ptr); + fixed_mode->VDisplay = _V_ACTIVE(timing_ptr); + fixed_mode->HSyncStart = fixed_mode->HDisplay + + _H_SYNC_OFF(timing_ptr); + fixed_mode->HSyncEnd = fixed_mode->HSyncStart + + _H_SYNC_WIDTH(timing_ptr); + fixed_mode->HTotal = fixed_mode->HDisplay + + _H_BLANK(timing_ptr); + fixed_mode->VSyncStart = fixed_mode->VDisplay + + _V_SYNC_OFF(timing_ptr); + fixed_mode->VSyncEnd = fixed_mode->VSyncStart + + _V_SYNC_WIDTH(timing_ptr); + fixed_mode->VTotal = fixed_mode->VDisplay + + _V_BLANK(timing_ptr); + fixed_mode->Clock = _PIXEL_CLOCK(timing_ptr) / 1000; + fixed_mode->type = M_T_PREFERRED; + + xf86SetModeDefaultName(fixed_mode); + + if (pI830->debug_modes) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Found panel mode in BIOS VBT tables:\n"); + xf86PrintModeline(pScrn->scrnIndex, fixed_mode); + } + + xfree(bios); + return fixed_mode; + } + } + + xfree(bios); + return NULL; +} + +unsigned char * +i830_bios_get_aim_data_block (ScrnInfoPtr pScrn, int aim, int data_block) +{ + unsigned char *bios; + int bdb_off; + int vbt_off; + int aim_off; + struct vbt_header *vbt; + struct aimdb_header *aimdb; + struct aimdb_block *aimdb_block; + + bios = i830_bios_get (pScrn); + if (!bios) + return NULL; + + vbt_off = INTEL_BIOS_16(0x1a); + vbt = (struct vbt_header *)(bios + vbt_off); + + aim_off = vbt->aim_offset[aim]; + if (!aim_off) + { + free (bios); + return NULL; + } + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "aim_off %d\n", aim_off); + aimdb = (struct aimdb_header *) (bios + vbt_off + aim_off); + bdb_off = aimdb->aimdb_header_size; + while (bdb_off < aimdb->aimdb_size) + { + aimdb_block = (struct aimdb_block *) (bios + vbt_off + aim_off + bdb_off); + if (aimdb_block->aimdb_id == data_block) + { + unsigned char *aim = malloc (aimdb_block->aimdb_size + sizeof (struct aimdb_block)); + if (!aim) + { + free (bios); + return NULL; + } + memcpy (aim, aimdb_block, aimdb_block->aimdb_size + sizeof (struct aimdb_block)); + free (bios); + return aim; + } + bdb_off += aimdb_block->aimdb_size + sizeof (struct aimdb_block); + } + free (bios); + return NULL; +} diff --git a/driver/xf86-video-intel/src/i830_bios.h b/driver/xf86-video-intel/src/i830_bios.h new file mode 100644 index 000000000..9e8356a11 --- /dev/null +++ b/driver/xf86-video-intel/src/i830_bios.h @@ -0,0 +1,157 @@ +/* + * Copyright © 2006 Intel Corporation + * + * 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 + * THE AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +#ifndef _I830_BIOS_H_ +#define _I830_BIOS_H_ + +#include <xf86str.h> + +struct vbt_header { + char signature[20]; /**< Always starts with 'VBT$' */ + CARD16 version; /**< decimal */ + CARD16 header_size; /**< in bytes */ + CARD16 vbt_size; /**< in bytes */ + CARD8 vbt_checksum; + CARD8 reserved0; + CARD32 bdb_offset; /**< from beginning of VBT */ + CARD32 aim_offset[4]; /**< from beginning of VBT */ +} __attribute__((packed)); + +struct bdb_header { + char signature[16]; /**< Always 'BIOS_DATA_BLOCK' */ + CARD16 version; /**< decimal */ + CARD16 header_size; /**< in bytes */ + CARD16 bdb_size; /**< in bytes */ +} __attribute__((packed)); + +#define LVDS_CAP_EDID (1 << 6) +#define LVDS_CAP_DITHER (1 << 5) +#define LVDS_CAP_PFIT_AUTO_RATIO (1 << 4) +#define LVDS_CAP_PFIT_GRAPHICS_MODE (1 << 3) +#define LVDS_CAP_PFIT_TEXT_MODE (1 << 2) +#define LVDS_CAP_PFIT_GRAPHICS (1 << 1) +#define LVDS_CAP_PFIT_TEXT (1 << 0) +struct lvds_bdb_1 { + CARD8 id; /**< 40 */ + CARD16 size; + CARD8 panel_type; + CARD8 reserved0; + CARD16 caps; +} __attribute__((packed)); + +struct lvds_bdb_2_fp_params { + CARD16 x_res; + CARD16 y_res; + CARD32 lvds_reg; + CARD32 lvds_reg_val; + CARD32 pp_on_reg; + CARD32 pp_on_reg_val; + CARD32 pp_off_reg; + CARD32 pp_off_reg_val; + CARD32 pp_cycle_reg; + CARD32 pp_cycle_reg_val; + CARD32 pfit_reg; + CARD32 pfit_reg_val; + CARD16 terminator; +} __attribute__((packed)); + +struct lvds_bdb_2_fp_edid_dtd { + CARD16 dclk; /**< In 10khz */ + CARD8 hactive; + CARD8 hblank; + CARD8 high_h; /**< 7:4 = hactive 11:8, 3:0 = hblank 11:8 */ + CARD8 vactive; + CARD8 vblank; + CARD8 high_v; /**< 7:4 = vactive 11:8, 3:0 = vblank 11:8 */ + CARD8 hsync_off; + CARD8 hsync_pulse_width; + CARD8 vsync_off; + CARD8 high_hsync_off; /**< 7:6 = hsync off 9:8 */ + CARD8 h_image; + CARD8 v_image; + CARD8 max_hv; + CARD8 h_border; + CARD8 v_border; + CARD8 flags; +#define FP_EDID_FLAG_VSYNC_POSITIVE (1 << 2) +#define FP_EDID_FLAG_HSYNC_POSITIVE (1 << 1) +} __attribute__((packed)); + +struct lvds_bdb_2_entry { + CARD16 fp_params_offset; /**< From beginning of BDB */ + CARD8 fp_params_size; + CARD16 fp_edid_dtd_offset; + CARD8 fp_edid_dtd_size; + CARD16 fp_edid_pid_offset; + CARD8 fp_edid_pid_size; +} __attribute__((packed)); + +struct lvds_bdb_2 { + CARD8 id; /**< 41 */ + CARD16 size; + CARD8 table_size; /* not sure on this one */ + struct lvds_bdb_2_entry panels[16]; +} __attribute__((packed)); + +struct aimdb_header { + char signature[16]; + char oem_device[20]; + CARD16 aimdb_version; + CARD16 aimdb_header_size; + CARD16 aimdb_size; +} __attribute__((packed)); + +struct aimdb_block { + CARD8 aimdb_id; + CARD16 aimdb_size; +} __attribute__((packed)); + +struct vch_panel_data { + CARD16 fp_timing_offset; + CARD8 fp_timing_size; + CARD16 dvo_timing_offset; + CARD8 dvo_timing_size; + CARD16 text_fitting_offset; + CARD8 text_fitting_size; + CARD16 graphics_fitting_offset; + CARD8 graphics_fitting_size; +} __attribute__((packed)); + +struct vch_bdb_22 { + struct aimdb_block aimdb_block; + struct vch_panel_data panels[16]; +} __attribute__((packed)); + +unsigned char * +i830_bios_get (ScrnInfoPtr pScrn); + +DisplayModePtr i830_bios_get_panel_mode(ScrnInfoPtr pScrn, Bool *wants_dither); + +unsigned char * +i830_bios_get_aim_data_block (ScrnInfoPtr pScrn, int aim, int data_block); + +#endif /* _I830_BIOS_H_ */ diff --git a/driver/xf86-video-intel/src/i830_crt.c b/driver/xf86-video-intel/src/i830_crt.c new file mode 100644 index 000000000..d7762a070 --- /dev/null +++ b/driver/xf86-video-intel/src/i830_crt.c @@ -0,0 +1,434 @@ +/* + * Copyright © 2006 Intel Corporation + * + * 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 + * THE AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "xf86.h" +#include "i830.h" +#include "xf86Modes.h" +#include "i830_display.h" + +static void +i830_crt_dpms(xf86OutputPtr output, int mode) +{ + ScrnInfoPtr pScrn = output->scrn; + I830Ptr pI830 = I830PTR(pScrn); + CARD32 temp; + + temp = INREG(ADPA); + temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE); + temp &= ~ADPA_DAC_ENABLE; + + switch(mode) { + case DPMSModeOn: + temp |= ADPA_DAC_ENABLE; + break; + case DPMSModeStandby: + temp |= ADPA_DAC_ENABLE | ADPA_HSYNC_CNTL_DISABLE; + break; + case DPMSModeSuspend: + temp |= ADPA_DAC_ENABLE | ADPA_VSYNC_CNTL_DISABLE; + break; + case DPMSModeOff: + temp |= ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE; + break; + } + + OUTREG(ADPA, temp); +} + +static void +i830_crt_save (xf86OutputPtr output) +{ + ScrnInfoPtr pScrn = output->scrn; + I830Ptr pI830 = I830PTR(pScrn); + + pI830->saveADPA = INREG(ADPA); +} + +static void +i830_crt_restore (xf86OutputPtr output) +{ + ScrnInfoPtr pScrn = output->scrn; + I830Ptr pI830 = I830PTR(pScrn); + + OUTREG(ADPA, pI830->saveADPA); +} + +static int +i830_crt_mode_valid(xf86OutputPtr output, DisplayModePtr pMode) +{ + if (pMode->Flags & V_DBLSCAN) + return MODE_NO_DBLESCAN; + + if (pMode->Clock > 400000 || pMode->Clock < 25000) + return MODE_CLOCK_RANGE; + + return MODE_OK; +} + +static Bool +i830_crt_mode_fixup(xf86OutputPtr output, DisplayModePtr mode, + DisplayModePtr adjusted_mode) +{ + return TRUE; +} + +static void +i830_crt_mode_set(xf86OutputPtr output, DisplayModePtr mode, + DisplayModePtr adjusted_mode) +{ + ScrnInfoPtr pScrn = output->scrn; + I830Ptr pI830 = I830PTR(pScrn); + xf86CrtcPtr crtc = output->crtc; + I830CrtcPrivatePtr i830_crtc = crtc->driver_private; + int dpll_md_reg; + CARD32 adpa, dpll_md; + + if (i830_crtc->pipe == 0) + dpll_md_reg = DPLL_A_MD; + else + dpll_md_reg = DPLL_B_MD; + /* + * Disable separate mode multiplier used when cloning SDVO to CRT + * XXX this needs to be adjusted when we really are cloning + */ + if (IS_I965G(pI830)) + { + dpll_md = INREG(dpll_md_reg); + OUTREG(dpll_md_reg, dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK); + } + + adpa = 0; + if (adjusted_mode->Flags & V_PHSYNC) + adpa |= ADPA_HSYNC_ACTIVE_HIGH; + if (adjusted_mode->Flags & V_PVSYNC) + adpa |= ADPA_VSYNC_ACTIVE_HIGH; + + if (i830_crtc->pipe == 0) + { + adpa |= ADPA_PIPE_A_SELECT; + OUTREG(BCLRPAT_A, 0); + } + else + { + adpa |= ADPA_PIPE_B_SELECT; + OUTREG(BCLRPAT_B, 0); + } + + OUTREG(ADPA, adpa); +} + +/** + * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect CRT presence. + * + * Only for I945G/GM. + * + * \return TRUE if CRT is connected. + * \return FALSE if CRT is disconnected. + */ +static Bool +i830_crt_detect_hotplug(xf86OutputPtr output) +{ + ScrnInfoPtr pScrn = output->scrn; + I830Ptr pI830 = I830PTR(pScrn); + CARD32 temp; + const int timeout_ms = 1000; + int starttime, curtime; + + temp = INREG(PORT_HOTPLUG_EN); + + OUTREG(PORT_HOTPLUG_EN, temp | CRT_HOTPLUG_FORCE_DETECT | (1 << 5)); + + for (curtime = starttime = GetTimeInMillis(); + (curtime - starttime) < timeout_ms; curtime = GetTimeInMillis()) + { + if ((INREG(PORT_HOTPLUG_EN) & CRT_HOTPLUG_FORCE_DETECT) == 0) + break; + } + + if ((INREG(PORT_HOTPLUG_STAT) & CRT_HOTPLUG_MONITOR_MASK) == + CRT_HOTPLUG_MONITOR_COLOR) + { + return TRUE; + } else { + return FALSE; + } +} + +/** + * Detects CRT presence by checking for load. + * + * Requires that the current pipe's DPLL is active. This will cause flicker + * on the CRT, so it should not be used while the display is being used. Only + * color (not monochrome) displays are detected. + * + * \return TRUE if CRT is connected. + * \return FALSE if CRT is disconnected. + */ +static Bool +i830_crt_detect_load (xf86CrtcPtr crtc, + xf86OutputPtr output) +{ + ScrnInfoPtr pScrn = output->scrn; + I830Ptr pI830 = I830PTR(pScrn); + I830CrtcPrivatePtr i830_crtc = I830CrtcPrivate(crtc); + CARD32 save_bclrpat; + CARD32 save_vtotal; + CARD32 vtotal, vactive; + CARD32 vsample; + CARD32 vblank, vblank_start, vblank_end; + CARD32 dsl; + CARD8 st00; + int bclrpat_reg, pipeconf_reg, pipe_dsl_reg; + int vtotal_reg, vblank_reg, vsync_reg; + int pipe = i830_crtc->pipe; + Bool present; + + if (pipe == 0) + { + bclrpat_reg = BCLRPAT_A; + vtotal_reg = VTOTAL_A; + vblank_reg = VBLANK_A; + vsync_reg = VSYNC_A; + pipeconf_reg = PIPEACONF; + pipe_dsl_reg = PIPEA_DSL; + } + else + { + bclrpat_reg = BCLRPAT_B; + vtotal_reg = VTOTAL_B; + vblank_reg = VBLANK_B; + vsync_reg = VSYNC_B; + pipeconf_reg = PIPEBCONF; + pipe_dsl_reg = PIPEB_DSL; + } + + save_bclrpat = INREG(bclrpat_reg); + save_vtotal = INREG(vtotal_reg); + vblank = INREG(vblank_reg); + + vtotal = ((save_vtotal >> 16) & 0xfff) + 1; + vactive = (save_vtotal & 0x7ff) + 1; + + vblank_start = (vblank & 0xfff) + 1; + vblank_end = ((vblank >> 16) & 0xfff) + 1; + + /* Set the border color to purple. */ + OUTREG(bclrpat_reg, 0x500050); + + if (IS_I9XX (pI830)) + { + CARD32 pipeconf = INREG(pipeconf_reg); + OUTREG(pipeconf_reg, pipeconf | PIPECONF_FORCE_BORDER); + + st00 = pI830->readStandard (pI830, 0x3c2); + present = (st00 & (1 << 4)) != 0; + OUTREG(pipeconf_reg, pipeconf); + } + else + { + Bool restore_vblank = FALSE; + int count, detect; + + /* + * If there isn't any border, add some. + * Yes, this will flicker + */ + if (vblank_start <= vactive && vblank_end >= vtotal) + { + CARD32 vsync = INREG(vsync_reg); + CARD32 vsync_start = (vsync & 0xffff) + 1; + + vblank_start = vsync_start; + OUTREG(vblank_reg, (vblank_start - 1) | ((vblank_end - 1) << 16)); + restore_vblank = TRUE; + } + + /* sample in the vertical border, selecting the larger one */ + if (vblank_start - vactive >= vtotal - vblank_end) + vsample = (vblank_start + vactive) >> 1; + else + vsample = (vtotal + vblank_end) >> 1; + + /* + * Wait for the border to be displayed + */ + while (INREG(pipe_dsl_reg) >= vactive) + ; + while ((dsl = INREG(pipe_dsl_reg)) <= vsample) + ; + /* + * Watch ST00 for an entire scanline + */ + detect = 0; + count = 0; + do { + count++; + /* Read the ST00 VGA status register */ + st00 = pI830->readStandard(pI830, 0x3c2); + if (st00 & (1 << 4)) + detect++; + } while ((INREG(pipe_dsl_reg) == dsl)); + + /* restore vblank if necessary */ + if (restore_vblank) + OUTREG(vblank_reg, vblank); + /* + * If more than 3/4 of the scanline detected a monitor, + * then it is assumed to be present. This works even on i830, + * where there isn't any way to force the border color across + * the screen + */ + present = detect * 4 > count * 3; + } + + /* Restore previous settings */ + OUTREG(bclrpat_reg, save_bclrpat); + + return present; +} + +/** + * Detects CRT presence by probing for a response on the DDC address. + * + * This takes approximately 5ms in testing on an i915GM, with CRT connected or + * not. + * + * \return TRUE if the CRT is connected and responded to DDC. + * \return FALSE if no DDC response was detected. + */ +static Bool +i830_crt_detect_ddc(xf86OutputPtr output) +{ + I830OutputPrivatePtr i830_output = output->driver_private; + + /* CRT should always be at 0, but check anyway */ + if (i830_output->type != I830_OUTPUT_ANALOG) + return FALSE; + + return xf86I2CProbeAddress(i830_output->pDDCBus, 0x00A0); +} + +/** + * Attempts to detect CRT presence through any method available. + * + * @param allow_disturb enables detection methods that may cause flickering + * on active displays. + */ +static xf86OutputStatus +i830_crt_detect(xf86OutputPtr output) +{ + ScrnInfoPtr pScrn = output->scrn; + I830Ptr pI830 = I830PTR(pScrn); + xf86CrtcPtr crtc; + int dpms_mode; + + if (IS_I945G(pI830) || IS_I945GM(pI830) || IS_I965G(pI830) || + IS_G33CLASS(pI830)) { + if (i830_crt_detect_hotplug(output)) + return XF86OutputStatusConnected; + else + return XF86OutputStatusDisconnected; + } + + if (i830_crt_detect_ddc(output)) + return XF86OutputStatusConnected; + + /* Use the load-detect method if we have no other way of telling. */ + crtc = i830GetLoadDetectPipe (output, NULL, &dpms_mode); + + if (crtc) + { + Bool connected; + + connected = i830_crt_detect_load (crtc, output); + i830ReleaseLoadDetectPipe (output, dpms_mode); + if (connected) + return XF86OutputStatusConnected; + else + return XF86OutputStatusDisconnected; + } + + return XF86OutputStatusUnknown; +} + +static void +i830_crt_destroy (xf86OutputPtr output) +{ + if (output->driver_private) + xfree (output->driver_private); +} + +static const xf86OutputFuncsRec i830_crt_output_funcs = { + .dpms = i830_crt_dpms, + .save = i830_crt_save, + .restore = i830_crt_restore, + .mode_valid = i830_crt_mode_valid, + .mode_fixup = i830_crt_mode_fixup, + .prepare = i830_output_prepare, + .mode_set = i830_crt_mode_set, + .commit = i830_output_commit, + .detect = i830_crt_detect, + .get_modes = i830_ddc_get_modes, + .destroy = i830_crt_destroy +}; + +void +i830_crt_init(ScrnInfoPtr pScrn) +{ + xf86OutputPtr output; + I830OutputPrivatePtr i830_output; + I830Ptr pI830 = I830PTR(pScrn); + + output = xf86OutputCreate (pScrn, &i830_crt_output_funcs, "VGA"); + if (!output) + return; + i830_output = xnfcalloc (sizeof (I830OutputPrivateRec), 1); + if (!i830_output) + { + xf86OutputDestroy (output); + return; + } + i830_output->type = I830_OUTPUT_ANALOG; + /* i830 (almador) cannot place the analog adaptor on pipe B */ + if (IS_I830(pI830)) + i830_output->pipe_mask = (1 << 0); + else + i830_output->pipe_mask = ((1 << 0) | (1 << 1)); + i830_output->clone_mask = ((1 << I830_OUTPUT_ANALOG) | + (1 << I830_OUTPUT_DVO_TMDS)); + + output->driver_private = i830_output; + output->interlaceAllowed = FALSE; + output->doubleScanAllowed = FALSE; + + /* Set up the DDC bus. */ + I830I2CInit(pScrn, &i830_output->pDDCBus, GPIOA, "CRTDDC_A"); +} diff --git a/driver/xf86-video-intel/src/i830_debug.c b/driver/xf86-video-intel/src/i830_debug.c new file mode 100644 index 000000000..8f8ef9bbb --- /dev/null +++ b/driver/xf86-video-intel/src/i830_debug.c @@ -0,0 +1,1012 @@ +/* + * Copyright © 2006 Intel Corporation + * + * 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 + * THE AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +#ifdef REG_DUMPER +#include "reg_dumper/reg_dumper.h" + +#else + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "xf86.h" +#include "i830.h" +#include "i830_debug.h" +#include <strings.h> + +#endif + +#include "i810_reg.h" + +#define DEBUGSTRING(func) static char *func(I830Ptr pI830, int reg, CARD32 val) + +DEBUGSTRING(i830_debug_xyminus1) +{ + return XNFprintf("%d, %d", (val & 0xffff) + 1, + ((val & 0xffff0000) >> 16) + 1); +} + +DEBUGSTRING(i830_debug_yxminus1) +{ + return XNFprintf("%d, %d", ((val & 0xffff0000) >> 16) + 1, + (val & 0xffff) + 1); +} + +DEBUGSTRING(i830_debug_xy) +{ + return XNFprintf("%d, %d", (val & 0xffff), + ((val & 0xffff0000) >> 16)); +} + +DEBUGSTRING(i830_debug_dspstride) +{ + return XNFprintf("%d bytes", val); +} + +DEBUGSTRING(i830_debug_dspcntr) +{ + char *enabled = val & DISPLAY_PLANE_ENABLE ? "enabled" : "disabled"; + char plane = val & DISPPLANE_SEL_PIPE_B ? 'B' : 'A'; + return XNFprintf("%s, pipe %c", enabled, plane); +} + +DEBUGSTRING(i830_debug_pipeconf) +{ + char *enabled = val & PIPEACONF_ENABLE ? "enabled" : "disabled"; + char *bit30; + if (IS_I965G(pI830)) + bit30 = val & I965_PIPECONF_ACTIVE ? "active" : "inactive"; + else + bit30 = val & PIPEACONF_DOUBLE_WIDE ? "double-wide" : "single-wide"; + return XNFprintf("%s, %s", enabled, bit30); +} + +DEBUGSTRING(i830_debug_hvtotal) +{ + return XNFprintf("%d active, %d total", (val & 0xffff) + 1, + ((val & 0xffff0000) >> 16) + 1); +} + +DEBUGSTRING(i830_debug_hvsyncblank) +{ + return XNFprintf("%d start, %d end", (val & 0xffff) + 1, + ((val & 0xffff0000) >> 16) + 1); +} + +DEBUGSTRING(i830_debug_vgacntrl) +{ + return XNFprintf("%s", val & VGA_DISP_DISABLE ? "disabled" : "enabled"); +} + +DEBUGSTRING(i830_debug_fp) +{ + return XNFprintf("n = %d, m1 = %d, m2 = %d", + ((val & FP_N_DIV_MASK) >> FP_N_DIV_SHIFT), + ((val & FP_M1_DIV_MASK) >> FP_M1_DIV_SHIFT), + ((val & FP_M2_DIV_MASK) >> FP_M2_DIV_SHIFT)); +} + +DEBUGSTRING(i830_debug_vga_pd) +{ + int vga0_p1, vga0_p2, vga1_p1, vga1_p2; + + /* XXX: i9xx version */ + + if (val & VGA0_PD_P1_DIV_2) + vga0_p1 = 2; + else + vga0_p1 = ((val & VGA0_PD_P1_MASK) >> VGA0_PD_P1_SHIFT) + 2; + vga0_p2 = (val & VGA0_PD_P2_DIV_4) ? 4 : 2; + + if (val & VGA1_PD_P1_DIV_2) + vga1_p1 = 2; + else + vga1_p1 = ((val & VGA1_PD_P1_MASK) >> VGA1_PD_P1_SHIFT) + 2; + vga1_p2 = (val & VGA1_PD_P2_DIV_4) ? 4 : 2; + + return XNFprintf("vga0 p1 = %d, p2 = %d, vga1 p1 = %d, p2 = %d", + vga0_p1, vga0_p2, vga1_p1, vga1_p2); +} + +DEBUGSTRING(i830_debug_pp_status) +{ + char *status = val & PP_ON ? "on" : "off"; + char *ready = val & PP_READY ? "ready" : "not ready"; + char *seq = "unknown"; + + switch (val & PP_SEQUENCE_MASK) { + case PP_SEQUENCE_NONE: + seq = "idle"; + break; + case PP_SEQUENCE_ON: + seq = "on"; + break; + case PP_SEQUENCE_OFF: + seq = "off"; + break; + } + + return XNFprintf("%s, %s, sequencing %s", status, ready, seq); +} + +DEBUGSTRING(i830_debug_pp_control) +{ + return XNFprintf("power target: %s", + val & POWER_TARGET_ON ? "on" : "off"); +} + +DEBUGSTRING(i830_debug_dpll) +{ + char *enabled = val & DPLL_VCO_ENABLE ? "enabled" : "disabled"; + char *dvomode = val & DPLL_DVO_HIGH_SPEED ? "dvo" : "non-dvo"; + char *vgamode = val & DPLL_VGA_MODE_DIS ? "" : ", VGA"; + char *mode = "unknown"; + char *clock = "unknown"; + char *fpextra = val & DISPLAY_RATE_SELECT_FPA1 ? ", using FPx1!" : ""; + char sdvoextra[20]; + int p1, p2 = 0; + + if (IS_I9XX(pI830)) { + p1 = ffs((val & DPLL_FPA01_P1_POST_DIV_MASK) >> + DPLL_FPA01_P1_POST_DIV_SHIFT); + switch (val & DPLL_MODE_MASK) { + case DPLLB_MODE_DAC_SERIAL: + mode = "DAC/serial"; + p2 = val & DPLL_DAC_SERIAL_P2_CLOCK_DIV_5 ? 5 : 10; + break; + case DPLLB_MODE_LVDS: + mode = "LVDS"; + p2 = val & DPLLB_LVDS_P2_CLOCK_DIV_7 ? 7 : 14; + break; + } + } else { + Bool is_lvds = (INREG(LVDS) & LVDS_PORT_EN) && (reg == DPLL_B); + + if (is_lvds) { + mode = "LVDS"; + p1 = ffs((val & DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS) >> + DPLL_FPA01_P1_POST_DIV_SHIFT); + p2 = 14; + } else { + mode = "DAC/serial"; + if (val & PLL_P1_DIVIDE_BY_TWO) { + p1 = 2; + } else { + /* Map the number in the field to (3, 33) */ + p1 = ((val & DPLL_FPA01_P1_POST_DIV_MASK_I830) >> + DPLL_FPA01_P1_POST_DIV_SHIFT) + 2; + } + if (val & PLL_P2_DIVIDE_BY_4) + p2 = 4; + else + p2 = 2; + } + } + + switch (val & PLL_REF_INPUT_MASK) { + case PLL_REF_INPUT_DREFCLK: + clock = "default"; + break; + case PLL_REF_INPUT_TVCLKINA: + clock = "TV A"; + break; + case PLL_REF_INPUT_TVCLKINBC: + clock = "TV B/C"; + break; + case PLLB_REF_INPUT_SPREADSPECTRUMIN: + if (reg == DPLL_B) + clock = "spread spectrum"; + break; + } + + if (IS_I945G(pI830) || IS_I945GM(pI830) || IS_G33CLASS(pI830)) { + sprintf(sdvoextra, ", SDVO mult %d", + (int)((val & SDVO_MULTIPLIER_MASK) >> + SDVO_MULTIPLIER_SHIFT_HIRES) + 1); + } else { + sdvoextra[0] = '\0'; + } + + return XNFprintf("%s, %s%s, %s clock, %s mode, p1 = %d, " + "p2 = %d%s%s", + enabled, dvomode, vgamode, clock, mode, p1, p2, + fpextra, sdvoextra); +} + +DEBUGSTRING(i830_debug_dpll_test) +{ + char *dpllandiv = val & DPLLA_TEST_N_BYPASS ? ", DPLLA N bypassed" : ""; + char *dpllamdiv = val & DPLLA_TEST_M_BYPASS ? ", DPLLA M bypassed" : ""; + char *dpllainput = val & DPLLA_INPUT_BUFFER_ENABLE ? + "" : ", DPLLA input buffer disabled"; + char *dpllbndiv = val & DPLLB_TEST_N_BYPASS ? ", DPLLB N bypassed" : ""; + char *dpllbmdiv = val & DPLLB_TEST_M_BYPASS ? ", DPLLB M bypassed" : ""; + char *dpllbinput = val & DPLLB_INPUT_BUFFER_ENABLE ? + "" : ", DPLLB input buffer disabled"; + + return XNFprintf("%s%s%s%s%s%s", + dpllandiv, dpllamdiv, dpllainput, + dpllbndiv, dpllbmdiv, dpllbinput); +} + +DEBUGSTRING(i830_debug_adpa) +{ + char pipe = (val & ADPA_PIPE_B_SELECT) ? 'B' : 'A'; + char *enable = (val & ADPA_DAC_ENABLE) ? "enabled" : "disabled"; + char hsync = (val & ADPA_HSYNC_ACTIVE_HIGH) ? '+' : '-'; + char vsync = (val & ADPA_VSYNC_ACTIVE_HIGH) ? '+' : '-'; + + return XNFprintf("%s, pipe %c, %chsync, %cvsync", + enable, pipe, hsync, vsync); +} + +DEBUGSTRING(i830_debug_lvds) +{ + char pipe = val & LVDS_PIPEB_SELECT ? 'B' : 'A'; + char *enable = val & LVDS_PORT_EN ? "enabled" : "disabled"; + int depth; + char *channels; + + if ((val & LVDS_A3_POWER_MASK) == LVDS_A3_POWER_UP) + depth = 24; + else + depth = 18; + if ((val & LVDS_B0B3_POWER_MASK) == LVDS_B0B3_POWER_UP) + channels = "2 channels"; + else + channels = "1 channel"; + + + return XNFprintf("%s, pipe %c, %d bit, %s", + enable, pipe, depth, channels); +} + +DEBUGSTRING(i830_debug_dvo) +{ + char *enable = val & DVO_ENABLE ? "enabled" : "disabled"; + char pipe = val & DVO_PIPE_B_SELECT ? 'B' : 'A'; + char *stall; + char hsync = val & DVO_HSYNC_ACTIVE_HIGH ? '+' : '-'; + char vsync = val & DVO_VSYNC_ACTIVE_HIGH ? '+' : '-'; + + switch (val & DVO_PIPE_STALL_MASK) { + case DVO_PIPE_STALL_UNUSED: + stall = "no stall"; + break; + case DVO_PIPE_STALL: + stall = "stall"; + break; + case DVO_PIPE_STALL_TV: + stall = "TV stall"; + break; + default: + stall = "unknown stall"; + break; + } + + return XNFprintf("%s, pipe %c, %s, %chsync, %cvsync", + enable, pipe, stall, hsync, vsync); +} + +DEBUGSTRING(i830_debug_sdvo) +{ + char *enable = val & SDVO_ENABLE ? "enabled" : "disabled"; + char pipe = val & SDVO_PIPE_B_SELECT ? 'B' : 'A'; + char *stall = val & SDVO_STALL_SELECT ? "enabled" : "disabled"; + char *detected = val & SDVO_DETECTED ? "" : "not "; + char *gang = val & SDVOC_GANG_MODE ? ", gang mode" : ""; + char sdvoextra[20]; + + if (IS_I915G(pI830) || IS_I915GM(pI830)) { + sprintf(sdvoextra, ", SDVO mult %d", + (int)((val & SDVO_PORT_MULTIPLY_MASK) >> + SDVO_PORT_MULTIPLY_SHIFT) + 1); + } else { + sdvoextra[0] = '\0'; + } + + return XNFprintf("%s, pipe %c, stall %s, %sdetected%s%s", + enable, pipe, stall, detected, sdvoextra, gang); +} + +#if 0 +DEBUGSTRING(i810_debug_fence_new) +{ + char *enable = (val & FENCE_VALID) ? "enabled" : "disabled"; + char format = (val & I965_FENCE_Y_MAJOR) ? 'Y' : 'X'; + int pitch = ((val & 0xffc) >> 2) * 128; + unsigned int offset = val & 0xfffff000; + + return XNFprintf("%s, %c tile walk, %d pitch, 0x%08x offset", + enable, format, pitch, offset); +} +#endif + +#define DEFINEREG(reg) \ + { reg, #reg, NULL, 0 } +#define DEFINEREG2(reg, func) \ + { reg, #reg, func, 0 } + +static struct i830SnapshotRec { + int reg; + char *name; + char *(*debug_output)(I830Ptr pI830, int reg, CARD32 val); + CARD32 val; +} i830_snapshot[] = { + DEFINEREG2(VCLK_DIVISOR_VGA0, i830_debug_fp), + DEFINEREG2(VCLK_DIVISOR_VGA1, i830_debug_fp), + DEFINEREG2(VCLK_POST_DIV, i830_debug_vga_pd), + DEFINEREG2(DPLL_TEST, i830_debug_dpll_test), + DEFINEREG(D_STATE), + DEFINEREG(DSPCLK_GATE_D), + DEFINEREG(RENCLK_GATE_D1), + DEFINEREG(RENCLK_GATE_D2), +/* DEFINEREG(RAMCLK_GATE_D), CRL only */ + DEFINEREG2(SDVOB, i830_debug_sdvo), + DEFINEREG2(SDVOC, i830_debug_sdvo), +/* DEFINEREG(UDIB_SVB_SHB_CODES), CRL only */ +/* DEFINEREG(UDIB_SHA_BLANK_CODES), CRL only */ + DEFINEREG(SDVOUDI), + DEFINEREG(DSPARB), + DEFINEREG(DSPFW1), + DEFINEREG(DSPFW2), + DEFINEREG(DSPFW3), + + DEFINEREG2(ADPA, i830_debug_adpa), + DEFINEREG2(LVDS, i830_debug_lvds), + DEFINEREG2(DVOA, i830_debug_dvo), + DEFINEREG2(DVOB, i830_debug_dvo), + DEFINEREG2(DVOC, i830_debug_dvo), + DEFINEREG(DVOA_SRCDIM), + DEFINEREG(DVOB_SRCDIM), + DEFINEREG(DVOC_SRCDIM), + + DEFINEREG2(PP_CONTROL, i830_debug_pp_control), + DEFINEREG2(PP_STATUS, i830_debug_pp_status), + DEFINEREG(PFIT_CONTROL), + DEFINEREG(PFIT_PGM_RATIOS), + DEFINEREG(PORT_HOTPLUG_EN), + DEFINEREG(PORT_HOTPLUG_STAT), + + DEFINEREG2(DSPACNTR, i830_debug_dspcntr), + DEFINEREG2(DSPASTRIDE, i830_debug_dspstride), + DEFINEREG2(DSPAPOS, i830_debug_xy), + DEFINEREG2(DSPASIZE, i830_debug_xyminus1), + DEFINEREG(DSPABASE), + DEFINEREG(DSPASURF), + DEFINEREG(DSPATILEOFF), + DEFINEREG2(PIPEACONF, i830_debug_pipeconf), + DEFINEREG2(PIPEASRC, i830_debug_yxminus1), + + DEFINEREG(FBC_CFB_BASE), + DEFINEREG(FBC_LL_BASE), + DEFINEREG(FBC_CONTROL), + DEFINEREG(FBC_COMMAND), + DEFINEREG(FBC_STATUS), + DEFINEREG(FBC_CONTROL2), + DEFINEREG(FBC_FENCE_OFF), + DEFINEREG(FBC_MOD_NUM), + + DEFINEREG2(FPA0, i830_debug_fp), + DEFINEREG2(FPA1, i830_debug_fp), + DEFINEREG2(DPLL_A, i830_debug_dpll), + DEFINEREG(DPLL_A_MD), + DEFINEREG2(HTOTAL_A, i830_debug_hvtotal), + DEFINEREG2(HBLANK_A, i830_debug_hvsyncblank), + DEFINEREG2(HSYNC_A, i830_debug_hvsyncblank), + DEFINEREG2(VTOTAL_A, i830_debug_hvtotal), + DEFINEREG2(VBLANK_A, i830_debug_hvsyncblank), + DEFINEREG2(VSYNC_A, i830_debug_hvsyncblank), + DEFINEREG(BCLRPAT_A), + DEFINEREG(VSYNCSHIFT_A), + + DEFINEREG2(DSPBCNTR, i830_debug_dspcntr), + DEFINEREG2(DSPBSTRIDE, i830_debug_dspstride), + DEFINEREG2(DSPBPOS, i830_debug_xy), + DEFINEREG2(DSPBSIZE, i830_debug_xyminus1), + DEFINEREG(DSPBBASE), + DEFINEREG(DSPBSURF), + DEFINEREG(DSPBTILEOFF), + DEFINEREG2(PIPEBCONF, i830_debug_pipeconf), + DEFINEREG2(PIPEBSRC, i830_debug_yxminus1), + + DEFINEREG2(FPB0, i830_debug_fp), + DEFINEREG2(FPB1, i830_debug_fp), + DEFINEREG2(DPLL_B, i830_debug_dpll), + DEFINEREG(DPLL_B_MD), + DEFINEREG2(HTOTAL_B, i830_debug_hvtotal), + DEFINEREG2(HBLANK_B, i830_debug_hvsyncblank), + DEFINEREG2(HSYNC_B, i830_debug_hvsyncblank), + DEFINEREG2(VTOTAL_B, i830_debug_hvtotal), + DEFINEREG2(VBLANK_B, i830_debug_hvsyncblank), + DEFINEREG2(VSYNC_B, i830_debug_hvsyncblank), + DEFINEREG(BCLRPAT_B), + DEFINEREG(VSYNCSHIFT_B), + + DEFINEREG(VCLK_DIVISOR_VGA0), + DEFINEREG(VCLK_DIVISOR_VGA1), + DEFINEREG(VCLK_POST_DIV), + DEFINEREG2(VGACNTRL, i830_debug_vgacntrl), + + DEFINEREG(TV_CTL), + DEFINEREG(TV_DAC), + DEFINEREG(TV_CSC_Y), + DEFINEREG(TV_CSC_Y2), + DEFINEREG(TV_CSC_U), + DEFINEREG(TV_CSC_U2), + DEFINEREG(TV_CSC_V), + DEFINEREG(TV_CSC_V2), + DEFINEREG(TV_CLR_KNOBS), + DEFINEREG(TV_CLR_LEVEL), + DEFINEREG(TV_H_CTL_1), + DEFINEREG(TV_H_CTL_2), + DEFINEREG(TV_H_CTL_3), + DEFINEREG(TV_V_CTL_1), + DEFINEREG(TV_V_CTL_2), + DEFINEREG(TV_V_CTL_3), + DEFINEREG(TV_V_CTL_4), + DEFINEREG(TV_V_CTL_5), + DEFINEREG(TV_V_CTL_6), + DEFINEREG(TV_V_CTL_7), + DEFINEREG(TV_SC_CTL_1), + DEFINEREG(TV_SC_CTL_2), + DEFINEREG(TV_SC_CTL_3), + DEFINEREG(TV_WIN_POS), + DEFINEREG(TV_WIN_SIZE), + DEFINEREG(TV_FILTER_CTL_1), + DEFINEREG(TV_FILTER_CTL_2), + DEFINEREG(TV_FILTER_CTL_3), + DEFINEREG(TV_CC_CONTROL), + DEFINEREG(TV_CC_DATA), + DEFINEREG(TV_H_LUMA_0), + DEFINEREG(TV_H_LUMA_59), + DEFINEREG(TV_H_CHROMA_0), + DEFINEREG(TV_H_CHROMA_59), + +#if 0 + DEFINEREG2(FENCE_NEW + 0, i810_debug_fence_new), + DEFINEREG2(FENCE_NEW + 8, i810_debug_fence_new), + DEFINEREG2(FENCE_NEW + 16, i810_debug_fence_new), + DEFINEREG2(FENCE_NEW + 24, i810_debug_fence_new), + DEFINEREG2(FENCE_NEW + 32, i810_debug_fence_new), + DEFINEREG2(FENCE_NEW + 40, i810_debug_fence_new), + DEFINEREG2(FENCE_NEW + 48, i810_debug_fence_new), + DEFINEREG2(FENCE_NEW + 56, i810_debug_fence_new), + DEFINEREG2(FENCE_NEW + 64, i810_debug_fence_new), + DEFINEREG2(FENCE_NEW + 72, i810_debug_fence_new), + DEFINEREG2(FENCE_NEW + 80, i810_debug_fence_new), + DEFINEREG2(FENCE_NEW + 88, i810_debug_fence_new), + DEFINEREG2(FENCE_NEW + 96, i810_debug_fence_new), + DEFINEREG2(FENCE_NEW + 104, i810_debug_fence_new), + DEFINEREG2(FENCE_NEW + 112, i810_debug_fence_new), + DEFINEREG2(FENCE_NEW + 120, i810_debug_fence_new), +#endif +}; +#undef DEFINEREG +#define NUM_I830_SNAPSHOTREGS (sizeof(i830_snapshot) / sizeof(i830_snapshot[0])) + +#ifndef REG_DUMPER +void i830TakeRegSnapshot(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + int i; + + for (i = 0; i < NUM_I830_SNAPSHOTREGS; i++) { + i830_snapshot[i].val = INREG(i830_snapshot[i].reg); + } +} + +void i830CompareRegsToSnapshot(ScrnInfoPtr pScrn, char *where) +{ + I830Ptr pI830 = I830PTR(pScrn); + int i; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Comparing regs from server start up to %s\n", where); + for (i = 0; i < NUM_I830_SNAPSHOTREGS; i++) { + CARD32 val = INREG(i830_snapshot[i].reg); + if (i830_snapshot[i].val == val) + continue; + + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Register 0x%x (%s) changed from 0x%08x to 0x%08x\n", + i830_snapshot[i].reg, i830_snapshot[i].name, + (int)i830_snapshot[i].val, (int)val); + + if (i830_snapshot[i].debug_output != NULL) { + char *before, *after; + + before = i830_snapshot[i].debug_output(pI830, + i830_snapshot[i].reg, + i830_snapshot[i].val); + after = i830_snapshot[i].debug_output(pI830, + i830_snapshot[i].reg, + val); + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "%s before: %s\n", i830_snapshot[i].name, before); + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "%s after: %s\n", i830_snapshot[i].name, after); + + } + } +} +#endif /* !REG_DUMPER */ + +static void i830DumpIndexed (ScrnInfoPtr pScrn, char *name, int id, int val, int min, int max) +{ + I830Ptr pI830 = I830PTR(pScrn); + int i; + + for (i = min; i <= max; i++) { + OUTREG8 (id, i); + xf86DrvMsg (pScrn->scrnIndex, X_INFO, "%18.18s%02x: 0x%02x\n", + name, i, INREG8(val)); + } +} + +static void i830DumpAR(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + int i; + uint16_t st01; + unsigned char orig_arx, msr; + + msr = INREG8(0x3cc); + if (msr & 1) + st01 = 0x3da; + else + st01 = 0x3ba; + + INREG8(st01); /* make sure index/write register is in index mode */ + orig_arx = INREG8(0x3c0); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%19.19sX: 0x%02x\n", + "AR", orig_arx); + + for (i = 0; i <= 0x14; i++) { + INREG8(st01); + OUTREG8(0x3c0, i); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%18.18s%02x: 0x%02x\n", + "AR", i, INREG8(0x3c1)); + } + INREG8(st01); + OUTREG8(0x3c0, orig_arx); +} + +void i830DumpRegs (ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + int i; + int fp, dpll; + int pipe; + int n, m1, m2, m, p1, p2; + int ref; + int dot; + int phase; + int msr; + int crt; + + xf86DrvMsg (pScrn->scrnIndex, X_INFO, "DumpRegsBegin\n"); + for (i = 0; i < NUM_I830_SNAPSHOTREGS; i++) { + CARD32 val = INREG(i830_snapshot[i].reg); + + if (i830_snapshot[i].debug_output != NULL) { + char *debug = i830_snapshot[i].debug_output(pI830, + i830_snapshot[i].reg, + val); + xf86DrvMsg (pScrn->scrnIndex, X_INFO, "%20.20s: 0x%08x (%s)\n", + i830_snapshot[i].name, (unsigned int)val, debug); + xfree(debug); + } else { + xf86DrvMsg (pScrn->scrnIndex, X_INFO, "%20.20s: 0x%08x\n", + i830_snapshot[i].name, (unsigned int)val); + } + } + i830DumpIndexed (pScrn, "SR", 0x3c4, 0x3c5, 0, 7); + msr = INREG8(0x3cc); + xf86DrvMsg (pScrn->scrnIndex, X_INFO, "%20.20s: 0x%02x\n", + "MSR", (unsigned int) msr); + + i830DumpAR (pScrn); + if (msr & 1) + crt = 0x3d0; + else + crt = 0x3b0; + i830DumpIndexed (pScrn, "CR", crt + 4, crt + 5, 0, 0x24); + for (pipe = 0; pipe <= 1; pipe++) + { + fp = INREG(pipe == 0 ? FPA0 : FPB0); + dpll = INREG(pipe == 0 ? DPLL_A : DPLL_B); + if (IS_I9XX(pI830)) + { + CARD32 lvds = INREG(LVDS); + if ((lvds & LVDS_PORT_EN) && + (lvds & LVDS_PIPEB_SELECT) == (pipe << 30)) + { + if ((lvds & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP) + p2 = 7; + else + p2 = 14; + } + else + { + switch ((dpll >> 24) & 0x3) { + case 0: + p2 = 10; + break; + case 1: + p2 = 5; + break; + default: + p2 = 1; + xf86DrvMsg (pScrn->scrnIndex, X_WARNING, "p2 out of range\n"); + break; + } + } + switch ((dpll >> 16) & 0xff) { + case 1: + p1 = 1; break; + case 2: + p1 = 2; break; + case 4: + p1 = 3; break; + case 8: + p1 = 4; break; + case 16: + p1 = 5; break; + case 32: + p1 = 6; break; + case 64: + p1 = 7; break; + case 128: + p1 = 8; break; + default: + p1 = 1; + xf86DrvMsg (pScrn->scrnIndex, X_WARNING, "p1 out of range\n"); + break; + } + } + else + { + CARD32 lvds = INREG(LVDS); + if (IS_I85X (pI830) && + (lvds & LVDS_PORT_EN) && + (lvds & LVDS_PIPEB_SELECT) == (pipe << 30)) + { + if ((lvds & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP) + p2 = 7; + else + p2 = 14; + switch ((dpll >> 16) & 0x3f) { + case 0x01: p1 = 1; break; + case 0x02: p1 = 2; break; + case 0x04: p1 = 3; break; + case 0x08: p1 = 4; break; + case 0x10: p1 = 5; break; + case 0x20: p1 = 6; break; + default: + p1 = 1; + xf86DrvMsg (pScrn->scrnIndex, X_WARNING, "LVDS P1 0x%x invalid encoding\n", + (dpll >> 16) & 0x3f); + break; + } + } + else + { + if (dpll & (1 << 23)) + p2 = 4; + else + p2 = 2; + if (dpll & PLL_P1_DIVIDE_BY_TWO) + p1 = 2; + else + p1 = ((dpll >> 16) & 0x3f) + 2; + } + } + switch ((dpll >> 13) & 0x3) { + case 0: + ref = 96000; + break; + case 3: + ref = 100000; + break; + default: + ref = 0; + xf86DrvMsg (pScrn->scrnIndex, X_WARNING, "ref out of range\n"); + break; + } + if (IS_I965G(pI830)) { + phase = (dpll >> 9) & 0xf; + switch (phase) { + case 6: + break; + default: + xf86DrvMsg (pScrn->scrnIndex, X_INFO, + "SDVO phase shift %d out of range -- probobly not " + "an issue.\n", phase); + break; + } + } + switch ((dpll >> 8) & 1) { + case 0: + break; + default: + xf86DrvMsg (pScrn->scrnIndex, X_WARNING, + "fp select out of range\n"); + break; + } + n = ((fp >> 16) & 0x3f); + m1 = ((fp >> 8) & 0x3f); + m2 = ((fp >> 0) & 0x3f); + m = 5 * (m1 + 2) + (m2 + 2); + dot = (ref * (5 * (m1 + 2) + (m2 + 2)) / (n + 2)) / (p1 * p2); + xf86DrvMsg (pScrn->scrnIndex, X_INFO, "pipe %s dot %d n %d m1 %d m2 %d p1 %d p2 %d\n", + pipe == 0 ? "A" : "B", dot, n, m1, m2, p1, p2); + } + xf86DrvMsg (pScrn->scrnIndex, X_INFO, "DumpRegsEnd\n"); +} + +#ifndef REG_DUMPER + +#define NUM_RING_DUMP 64 + +static void +i830_dump_ring(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + unsigned int head, tail, ring, mask; + volatile unsigned char *virt; + + head = (INREG (LP_RING + RING_HEAD)) & I830_HEAD_MASK; + tail = INREG (LP_RING + RING_TAIL) & I830_TAIL_MASK; + mask = pI830->LpRing->tail_mask; + + virt = pI830->LpRing->virtual_start; + ErrorF ("Ring at virtual 0x%x head 0x%x tail 0x%x count %d\n", + (unsigned int) virt, head, tail, (((tail + mask + 1) - head) & mask) >> 2); + for (ring = (head - 128) & mask; ring != ((head + 4) & mask); + ring = (ring + 4) & mask) + { + ErrorF ("\t%08x: %08x\n", ring, *(volatile unsigned int *) (virt + ring)); + } + ErrorF ("Ring end\n"); +} + +/* Famous last words + */ +void +i830_dump_error_state(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + + ErrorF("pgetbl_ctl: 0x%lx pgetbl_err: 0x%lx\n", + (unsigned long)INREG(PGETBL_CTL), (unsigned long)INREG(PGE_ERR)); + + ErrorF("ipeir: %lx iphdr: %lx\n", (unsigned long)INREG(IPEIR), + (unsigned long)INREG(IPEHR)); + + ErrorF("LP ring tail: %lx head: %lx len: %lx start %lx\n", + (unsigned long)INREG(LP_RING + RING_TAIL), + (unsigned long)INREG(LP_RING + RING_HEAD) & HEAD_ADDR, + (unsigned long)INREG(LP_RING + RING_LEN), + (unsigned long)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", (unsigned long)INREG(MEMMODE), + (unsigned long)INREG(INST_PS)); + + ErrorF("hwstam: %x ier: %x imr: %x iir: %x\n", + INREG16(HWSTAM), INREG16(IER), INREG16(IMR), INREG16(IIR)); + i830_dump_ring (pScrn); +} + +void +i965_dump_error_state(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_I965), INREG(IPEHR_I965)); + + 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("Err ID (eir): %x Err Status (esr): %x Err Mask (emr): %x\n", + (int)INREG(EIR), (int)INREG(ESR), (int)INREG(EMR)); + + ErrorF("instdone: %x instdone_1: %x\n", (int)INREG(INST_DONE_I965), + (int)INREG(INST_DONE_1)); + ErrorF("instpm: %x\n", (int)INREG(INST_PM)); + + ErrorF("memmode: %lx instps: %lx\n", INREG(MEMMODE), INREG(INST_PS_I965)); + + ErrorF("HW Status mask (hwstam): %x\nIRQ enable (ier): %x " + "imr: %x iir: %x\n", + (int)INREG(HWSTAM), (int)INREG(IER), (int)INREG(IMR), + (int)INREG(IIR)); + + ErrorF("acthd: %lx dma_fadd_p: %lx\n", INREG(ACTHD), INREG(DMA_FADD_P)); + ErrorF("ecoskpd: %lx excc: %lx\n", INREG(ECOSKPD), INREG(EXCC)); + + ErrorF("cache_mode: %x/%x\n", (int)INREG(CACHE_MODE_0), + (int)INREG(CACHE_MODE_1)); + ErrorF("mi_arb_state: %x\n", (int)INREG(MI_ARB_STATE)); + + ErrorF("IA_VERTICES_COUNT_QW %x/%x\n", + (int)INREG(IA_VERTICES_COUNT_QW), + (int)INREG(IA_VERTICES_COUNT_QW+4)); + ErrorF("IA_PRIMITIVES_COUNT_QW %x/%x\n", + (int)INREG(IA_PRIMITIVES_COUNT_QW), + (int)INREG(IA_PRIMITIVES_COUNT_QW+4)); + + ErrorF("VS_INVOCATION_COUNT_QW %x/%x\n", + (int)INREG(VS_INVOCATION_COUNT_QW), + (int)INREG(VS_INVOCATION_COUNT_QW+4)); + + ErrorF("GS_INVOCATION_COUNT_QW %x/%x\n", + (int)INREG(GS_INVOCATION_COUNT_QW), + (int)INREG(GS_INVOCATION_COUNT_QW+4)); + ErrorF("GS_PRIMITIVES_COUNT_QW %x/%x\n", + (int)INREG(GS_PRIMITIVES_COUNT_QW), + (int)INREG(GS_PRIMITIVES_COUNT_QW+4)); + + ErrorF("CL_INVOCATION_COUNT_QW %x/%x\n", + (int)INREG(CL_INVOCATION_COUNT_QW), + (int)INREG(CL_INVOCATION_COUNT_QW+4)); + ErrorF("CL_PRIMITIVES_COUNT_QW %x/%x\n", + (int)INREG(CL_PRIMITIVES_COUNT_QW), + (int)INREG(CL_PRIMITIVES_COUNT_QW+4)); + + ErrorF("PS_INVOCATION_COUNT_QW %x/%x\n", + (int)INREG(PS_INVOCATION_COUNT_QW), + (int)INREG(PS_INVOCATION_COUNT_QW+4)); + ErrorF("PS_DEPTH_COUNT_QW %x/%x\n", + (int)INREG(PS_DEPTH_COUNT_QW), + (int)INREG(PS_DEPTH_COUNT_QW+4)); + + ErrorF("WIZ_CTL %x\n", (int)INREG(WIZ_CTL)); + ErrorF("TS_CTL %x TS_DEBUG_DATA %x\n", (int)INREG(TS_CTL), + (int)INREG(TS_DEBUG_DATA)); + ErrorF("TD_CTL %x / %x\n", (int)INREG(TD_CTL), (int)INREG(TD_CTL2)); +} + +/** + * Checks the hardware error state bits. + * + * \return TRUE if any errors were found. + */ +Bool +i830_check_error_state(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + int errors = 0; + unsigned long temp, head, tail; + + if (!I830IsPrimary(pScrn)) return TRUE; + + temp = INREG16(ESR); + if (temp != 0) { + Bool vertex_max = !IS_I965G(pI830) && (temp & ERR_VERTEX_MAX); + Bool pgtbl = temp & ERR_PGTBL_ERROR; + Bool underrun = !IS_I965G(pI830) && + (temp & ERR_DISPLAY_OVERLAY_UNDERRUN); + Bool instruction = !IS_I965G(pI830) && (temp & ERR_INSTRUCTION_ERROR); + + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "ESR is 0x%08lx%s%s%s%s\n", temp, + vertex_max ? ", max vertices exceeded" : "", + pgtbl ? ", page table error" : "", + underrun ? ", display/overlay underrun" : "", + instruction ? ", instruction error" : ""); + errors++; + } + /* Check first for page table errors */ + if (!IS_I9XX(pI830)) { + temp = INREG(PGE_ERR); + if (temp != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "PGTBL_ER is 0x%08lx\n", temp); + errors++; + } + } else { + temp = INREG(PGTBL_ER); + if (temp != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "PGTBL_ER is 0x%08lx" + "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", temp, + temp & PGTBL_ERR_HOST_GTT_PTE ? ", host gtt pte" : "", + temp & PGTBL_ERR_HOST_PTE_DATA ? ", host pte data" : "", + temp & PGTBL_ERR_DISPA_GTT_PTE ? ", display A pte" : "", + temp & PGTBL_ERR_DISPA_TILING ? + ", display A tiling" : "", + temp & PGTBL_ERR_DISPB_GTT_PTE ? ", display B pte" : "", + temp & PGTBL_ERR_DISPB_TILING ? + ", display B tiling" : "", + temp & PGTBL_ERR_DISPC_GTT_PTE ? ", display C pte" : "", + temp & PGTBL_ERR_DISPC_TILING ? + ", display C tiling" : "", + temp & PGTBL_ERR_OVERLAY_GTT_PTE ? + ", overlay GTT PTE" : "", + temp & PGTBL_ERR_OVERLAY_TILING ? + ", overlay tiling" : "", + temp & PGTBL_ERR_CS_GTT ? ", CS GTT" : "", + temp & PGTBL_ERR_CS_INSTRUCTION_GTT_PTE ? + ", CS instruction GTT PTE" : "", + temp & PGTBL_ERR_CS_VERTEXDATA_GTT_PTE ? + ", CS vertex data GTT PTE" : "", + temp & PGTBL_ERR_BIN_INSTRUCTION_GTT_PTE ? + ", BIN instruction GTT PTE" : "", + temp & PGTBL_ERR_BIN_VERTEXDATA_GTT_PTE ? + ", BIN vertex data GTT PTE" : "", + temp & PGTBL_ERR_LC_GTT_PTE ? ", LC pte" : "", + temp & PGTBL_ERR_LC_TILING ? ", LC tiling" : "", + temp & PGTBL_ERR_MT_GTT_PTE ? ", MT pte" : "", + temp & PGTBL_ERR_MT_TILING ? ", MT tiling" : ""); + errors++; + } + } + temp = INREG(PGETBL_CTL); + if (!(temp & 1)) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "PGTBL_CTL (0x%08lx) indicates GTT is disabled\n", temp); + errors++; + } + temp = INREG(LP_RING + RING_LEN); + if (temp & 1) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "PRB0_CTL (0x%08lx) 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%08lx) and PRB0_TAIL (0x%08lx) indicate " + "ring buffer not flushed\n", head, tail); + errors++; + } + +#if 0 + if (errors) { + if (IS_I965G(pI830)) + i965_dump_error_state(pScrn); + else + i830_dump_error_state(pScrn); + } +#endif + + return (errors != 0); +} +#endif /* !REG_DUMPER */ diff --git a/driver/xf86-video-intel/src/i830_debug.h b/driver/xf86-video-intel/src/i830_debug.h new file mode 100644 index 000000000..2d2e72bf1 --- /dev/null +++ b/driver/xf86-video-intel/src/i830_debug.h @@ -0,0 +1,34 @@ +/* + * Copyright © 2006 Intel Corporation + * + * 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 + * THE AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +void i830TakeRegSnapshot(ScrnInfoPtr pScrn); +void i830CompareRegsToSnapshot(ScrnInfoPtr pScrn, char *where); +void i830DumpRegs (ScrnInfoPtr pScrn); +void i830_dump_error_state(ScrnInfoPtr pScrn); +void i965_dump_error_state(ScrnInfoPtr pScrn); +Bool i830_check_error_state(ScrnInfoPtr pScrn); + diff --git a/driver/xf86-video-intel/src/i830_display.c b/driver/xf86-video-intel/src/i830_display.c new file mode 100644 index 000000000..0e4262498 --- /dev/null +++ b/driver/xf86-video-intel/src/i830_display.c @@ -0,0 +1,1732 @@ +/* -*- c-basic-offset: 4 -*- */ +/* + * Copyright © 2006 Intel Corporation + * + * 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 + * THE AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <unistd.h> +#include <string.h> +#include <assert.h> +#include <stdlib.h> +#include <math.h> + +#include "xf86.h" +#include "i830.h" +#include "i830_bios.h" +#include "i830_display.h" +#include "i830_debug.h" +#include "xf86Modes.h" + +typedef struct { + /* given values */ + int n; + int m1, m2; + int p1, p2; + /* derived values */ + int dot; + int vco; + int m; + int p; +} intel_clock_t; + +typedef struct { + int min, max; +} intel_range_t; + +typedef struct { + int dot_limit; + int p2_slow, p2_fast; +} intel_p2_t; + +#define INTEL_P2_NUM 2 + +typedef struct { + intel_range_t dot, vco, n, m, m1, m2, p, p1; + intel_p2_t p2; +} intel_limit_t; + +#define I8XX_DOT_MIN 25000 +#define I8XX_DOT_MAX 350000 +#define I8XX_VCO_MIN 930000 +#define I8XX_VCO_MAX 1400000 +#define I8XX_N_MIN 3 +#define I8XX_N_MAX 16 +#define I8XX_M_MIN 96 +#define I8XX_M_MAX 140 +#define I8XX_M1_MIN 18 +#define I8XX_M1_MAX 26 +#define I8XX_M2_MIN 6 +#define I8XX_M2_MAX 16 +#define I8XX_P_MIN 4 +#define I8XX_P_MAX 128 +#define I8XX_P1_MIN 2 +#define I8XX_P1_MAX 33 +#define I8XX_P1_LVDS_MIN 1 +#define I8XX_P1_LVDS_MAX 6 +#define I8XX_P2_SLOW 4 +#define I8XX_P2_FAST 2 +#define I8XX_P2_LVDS_SLOW 14 +#define I8XX_P2_LVDS_FAST 7 +#define I8XX_P2_SLOW_LIMIT 165000 + +#define I9XX_DOT_MIN 20000 +#define I9XX_DOT_MAX 400000 +#define I9XX_VCO_MIN 1400000 +#define I9XX_VCO_MAX 2800000 + +/* Haven't found any reason to go this fast, but newer chips support it */ +#define I96X_VCO_MAX 3200000 + +/* + * These values are taken from the broadwater/crestline PLL spreadsheet. + * All of the defines here are for the programmed register value, not + * the 'counter' value (e.g. Ncounter = Nregister + 2) + */ +#define I9XX_N_MIN 1 +#define I9XX_N_MAX 6 +#define I9XX_M_MIN 70 +#define I9XX_M_MAX 120 + +/* these two come from the calm1 macro */ +#define I9XX_M1_MIN 10 +#define I9XX_M1_MAX 22 +#define I9XX_M2_MIN 5 +#define I9XX_M2_MAX 9 + +#define I9XX_P_SDVO_DAC_MIN 5 +#define I9XX_P_SDVO_DAC_MAX 80 +#define I9XX_P_LVDS_MIN 7 +#define I9XX_P_LVDS_MAX 98 +#define I9XX_P1_MIN 1 +#define I9XX_P1_MAX 8 +#define I9XX_P2_SDVO_DAC_SLOW 10 +#define I9XX_P2_SDVO_DAC_FAST 5 +#define I9XX_P2_SDVO_DAC_SLOW_LIMIT 200000 +#define I9XX_P2_LVDS_SLOW 14 +#define I9XX_P2_LVDS_FAST 7 +#define I9XX_P2_LVDS_SLOW_LIMIT 112000 + +#define INTEL_LIMIT_I8XX_DVO_DAC 0 +#define INTEL_LIMIT_I8XX_LVDS 1 +#define INTEL_LIMIT_I9XX_SDVO_DAC 2 +#define INTEL_LIMIT_I9XX_LVDS 3 + +static const intel_limit_t intel_limits[] = { + { /* INTEL_LIMIT_I8XX_DVO_DAC */ + .dot = { .min = I8XX_DOT_MIN, .max = I8XX_DOT_MAX }, + .vco = { .min = I8XX_VCO_MIN, .max = I8XX_VCO_MAX }, + .n = { .min = I8XX_N_MIN, .max = I8XX_N_MAX }, + .m = { .min = I8XX_M_MIN, .max = I8XX_M_MAX }, + .m1 = { .min = I8XX_M1_MIN, .max = I8XX_M1_MAX }, + .m2 = { .min = I8XX_M2_MIN, .max = I8XX_M2_MAX }, + .p = { .min = I8XX_P_MIN, .max = I8XX_P_MAX }, + .p1 = { .min = I8XX_P1_MIN, .max = I8XX_P1_MAX }, + .p2 = { .dot_limit = I8XX_P2_SLOW_LIMIT, + .p2_slow = I8XX_P2_SLOW, .p2_fast = I8XX_P2_FAST }, + }, + { /* INTEL_LIMIT_I8XX_LVDS */ + .dot = { .min = I8XX_DOT_MIN, .max = I8XX_DOT_MAX }, + .vco = { .min = I8XX_VCO_MIN, .max = I8XX_VCO_MAX }, + .n = { .min = I8XX_N_MIN, .max = I8XX_N_MAX }, + .m = { .min = I8XX_M_MIN, .max = I8XX_M_MAX }, + .m1 = { .min = I8XX_M1_MIN, .max = I8XX_M1_MAX }, + .m2 = { .min = I8XX_M2_MIN, .max = I8XX_M2_MAX }, + .p = { .min = I8XX_P_MIN, .max = I8XX_P_MAX }, + .p1 = { .min = I8XX_P1_LVDS_MIN, .max = I8XX_P1_LVDS_MAX }, + .p2 = { .dot_limit = I8XX_P2_SLOW_LIMIT, + .p2_slow = I8XX_P2_LVDS_SLOW, .p2_fast = I8XX_P2_LVDS_FAST }, + }, + { /* INTEL_LIMIT_I9XX_SDVO_DAC */ + .dot = { .min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX }, + .vco = { .min = I9XX_VCO_MIN, .max = I9XX_VCO_MAX }, + .n = { .min = I9XX_N_MIN, .max = I9XX_N_MAX }, + .m = { .min = I9XX_M_MIN, .max = I9XX_M_MAX }, + .m1 = { .min = I9XX_M1_MIN, .max = I9XX_M1_MAX }, + .m2 = { .min = I9XX_M2_MIN, .max = I9XX_M2_MAX }, + .p = { .min = I9XX_P_SDVO_DAC_MIN, .max = I9XX_P_SDVO_DAC_MAX }, + .p1 = { .min = I9XX_P1_MIN, .max = I9XX_P1_MAX }, + .p2 = { .dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT, + .p2_slow = I9XX_P2_SDVO_DAC_SLOW, .p2_fast = I9XX_P2_SDVO_DAC_FAST }, + }, + { /* INTEL_LIMIT_I9XX_LVDS */ + .dot = { .min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX }, + .vco = { .min = I9XX_VCO_MIN, .max = I9XX_VCO_MAX }, + .n = { .min = I9XX_N_MIN, .max = I9XX_N_MAX }, + .m = { .min = I9XX_M_MIN, .max = I9XX_M_MAX }, + .m1 = { .min = I9XX_M1_MIN, .max = I9XX_M1_MAX }, + .m2 = { .min = I9XX_M2_MIN, .max = I9XX_M2_MAX }, + .p = { .min = I9XX_P_LVDS_MIN, .max = I9XX_P_LVDS_MAX }, + .p1 = { .min = I9XX_P1_MIN, .max = I9XX_P1_MAX }, + /* The single-channel range is 25-112Mhz, and dual-channel + * is 80-224Mhz. Prefer single channel as much as possible. + */ + .p2 = { .dot_limit = I9XX_P2_LVDS_SLOW_LIMIT, + .p2_slow = I9XX_P2_LVDS_SLOW, .p2_fast = I9XX_P2_LVDS_FAST }, + }, +}; + +static const intel_limit_t *intel_limit (xf86CrtcPtr crtc) +{ + ScrnInfoPtr pScrn = crtc->scrn; + I830Ptr pI830 = I830PTR(pScrn); + const intel_limit_t *limit; + + if (IS_I9XX(pI830)) { + if (i830PipeHasType (crtc, I830_OUTPUT_LVDS)) + limit = &intel_limits[INTEL_LIMIT_I9XX_LVDS]; + else + limit = &intel_limits[INTEL_LIMIT_I9XX_SDVO_DAC]; + } else { + if (i830PipeHasType (crtc, I830_OUTPUT_LVDS)) + limit = &intel_limits[INTEL_LIMIT_I8XX_LVDS]; + else + limit = &intel_limits[INTEL_LIMIT_I8XX_DVO_DAC]; + } + + return limit; +} + +/** Derive the pixel clock for the given refclk and divisors for 8xx chips. */ + +static void i8xx_clock(int refclk, intel_clock_t *clock) +{ + clock->m = 5 * (clock->m1 + 2) + (clock->m2 + 2); + clock->p = clock->p1 * clock->p2; + clock->vco = refclk * clock->m / (clock->n + 2); + clock->dot = clock->vco / clock->p; +} + +/** Derive the pixel clock for the given refclk and divisors for 9xx chips. */ + +static void i9xx_clock(int refclk, intel_clock_t *clock) +{ + clock->m = 5 * (clock->m1 + 2) + (clock->m2 + 2); + clock->p = clock->p1 * clock->p2; + clock->vco = refclk * clock->m / (clock->n + 2); + clock->dot = clock->vco / clock->p; +} + +static void intel_clock(I830Ptr pI830, int refclk, intel_clock_t *clock) +{ + if (IS_I9XX(pI830)) + i9xx_clock (refclk, clock); + else + i8xx_clock (refclk, clock); +} + +static void +i830PrintPll(char *prefix, intel_clock_t *clock) +{ + ErrorF("%s: dotclock %d vco %d ((m %d, m1 %d, m2 %d), n %d, (p %d, p1 %d, p2 %d))\n", + prefix, clock->dot, clock->vco, + clock->m, clock->m1, clock->m2, + clock->n, + clock->p, clock->p1, clock->p2); +} + +/** + * Returns whether any output on the specified pipe is of the specified type + */ +Bool +i830PipeHasType (xf86CrtcPtr crtc, int type) +{ + ScrnInfoPtr pScrn = crtc->scrn; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + int i; + + for (i = 0; i < xf86_config->num_output; i++) + { + xf86OutputPtr output = xf86_config->output[i]; + if (output->crtc == crtc) + { + I830OutputPrivatePtr intel_output = output->driver_private; + if (intel_output->type == type) + return TRUE; + } + } + return FALSE; +} + +#define i830PllInvalid(s) { /* ErrorF (s) */; return FALSE; } +/** + * Returns whether the given set of divisors are valid for a given refclk with + * the given outputs. + */ + +static Bool +i830PllIsValid(xf86CrtcPtr crtc, intel_clock_t *clock) +{ + const intel_limit_t *limit = intel_limit (crtc); + + if (clock->p1 < limit->p1.min || limit->p1.max < clock->p1) + i830PllInvalid ("p1 out of range\n"); + if (clock->p < limit->p.min || limit->p.max < clock->p) + i830PllInvalid ("p out of range\n"); + if (clock->m2 < limit->m2.min || limit->m2.max < clock->m2) + i830PllInvalid ("m2 out of range\n"); + if (clock->m1 < limit->m1.min || limit->m1.max < clock->m1) + i830PllInvalid ("m1 out of range\n"); + if (clock->m1 <= clock->m2) + i830PllInvalid ("m1 <= m2\n"); + if (clock->m < limit->m.min || limit->m.max < clock->m) + i830PllInvalid ("m out of range\n"); + if (clock->n < limit->n.min || limit->n.max < clock->n) + i830PllInvalid ("n out of range\n"); + if (clock->vco < limit->vco.min || limit->vco.max < clock->vco) + i830PllInvalid ("vco out of range\n"); + /* XXX: We may need to be checking "Dot clock" depending on the multiplier, + * output, etc., rather than just a single range. + */ + if (clock->dot < limit->dot.min || limit->dot.max < clock->dot) + i830PllInvalid ("dot out of range\n"); + + return TRUE; +} + +/** + * Returns a set of divisors for the desired target clock with the given + * refclk, or FALSE. The returned values represent the clock equation: + * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2. + */ +static Bool +i830FindBestPLL(xf86CrtcPtr crtc, int target, int refclk, intel_clock_t *best_clock) +{ + ScrnInfoPtr pScrn = crtc->scrn; + I830Ptr pI830 = I830PTR(pScrn); + intel_clock_t clock; + const intel_limit_t *limit = intel_limit (crtc); + int err = target; + + if (i830PipeHasType(crtc, I830_OUTPUT_LVDS)) + { + /* For LVDS, if the panel is on, just rely on its current settings for + * dual-channel. We haven't figured out how to reliably set up + * different single/dual channel state, if we even can. + */ + if ((INREG(LVDS) & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP) + clock.p2 = limit->p2.p2_fast; + else + clock.p2 = limit->p2.p2_slow; + } else { + if (target < limit->p2.dot_limit) + clock.p2 = limit->p2.p2_slow; + else + clock.p2 = limit->p2.p2_fast; + } + + memset (best_clock, 0, sizeof (*best_clock)); + + for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; clock.m1++) + { + for (clock.m2 = limit->m2.min; clock.m2 < clock.m1 && clock.m2 <= limit->m2.max; clock.m2++) + { + for (clock.n = limit->n.min; clock.n <= limit->n.max; clock.n++) + { + for (clock.p1 = limit->p1.min; clock.p1 <= limit->p1.max; clock.p1++) + { + int this_err; + + intel_clock (pI830, refclk, &clock); + + if (!i830PllIsValid(crtc, &clock)) + continue; + + this_err = abs(clock.dot - target); + if (this_err < err) { + *best_clock = clock; + err = this_err; + } + } + } + } + } + return (err != target); +} + +void +i830WaitForVblank(ScrnInfoPtr pScreen) +{ + /* Wait for 20ms, i.e. one cycle at 50hz. */ + usleep(30000); +} + +void +i830PipeSetBase(xf86CrtcPtr crtc, int x, int y) +{ + ScrnInfoPtr pScrn = crtc->scrn; + I830Ptr pI830 = I830PTR(pScrn); + I830CrtcPrivatePtr intel_crtc = crtc->driver_private; + int pipe = intel_crtc->pipe; + int plane = intel_crtc->plane; + unsigned long Start, Offset; + int dspbase = (plane == 0 ? DSPABASE : DSPBBASE); + int dspsurf = (plane == 0 ? DSPASURF : DSPBSURF); + int dsptileoff = (plane == 0 ? DSPATILEOFF : DSPBTILEOFF); + + Offset = ((y * pScrn->displayWidth + x) * pI830->cpp); + if (pI830->front_buffer == NULL) { + /* During startup we may be called as part of monitor detection while + * there is no memory allocation done, so just supply a dummy base + * address. + */ + Start = 0; + } else if (crtc->rotatedData != NULL) { + /* offset is done by shadow painting code, not here */ + Start = (char *)crtc->rotatedData - (char *)pI830->FbBase; + Offset = 0; + } else if (I830IsPrimary(pScrn)) { + Start = pI830->front_buffer->offset; + } else { + I830Ptr pI8301 = I830PTR(pI830->entityPrivate->pScrn_1); + Start = pI8301->front_buffer_2->offset; + } + + if (IS_I965G(pI830)) { + OUTREG(dspbase, Offset); + POSTING_READ(dspbase); + OUTREG(dspsurf, Start); + POSTING_READ(dspsurf); + OUTREG(dsptileoff, (y << 16) | x); + } else { + OUTREG(dspbase, Start + Offset); + POSTING_READ(dspbase); + } + +#ifdef XF86DRI + if (pI830->directRenderingEnabled) { + drmI830Sarea *sPriv = (drmI830Sarea *) DRIGetSAREAPrivate(pScrn->pScreen); + + if (!sPriv) + return; + + switch (plane) { + case 0: + sPriv->planeA_x = x; + sPriv->planeA_y = y; + break; + case 1: + sPriv->planeB_x = x; + sPriv->planeB_y = y; + break; + default: + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Can't update pipe %d in SAREA\n", pipe); + break; + } + } +#endif +} + +/* + * Both crtc activation and video overlay enablement on pipe B + * will fail on i830 if pipe A is not running. This function + * makes sure pipe A is active for these cases + */ + +int +i830_crtc_pipe (xf86CrtcPtr crtc) +{ + if (crtc == NULL) + return 0; + return ((I830CrtcPrivatePtr) crtc->driver_private)->pipe; +} + +static xf86CrtcPtr +i830_crtc_for_pipe (ScrnInfoPtr scrn, int pipe) +{ + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + int c; + + for (c = 0; c < xf86_config->num_crtc; c++) + { + xf86CrtcPtr crtc = xf86_config->crtc[c]; + if (i830_crtc_pipe (crtc) == pipe) + return crtc; + } + return NULL; +} + +Bool +i830_pipe_a_require_activate (ScrnInfoPtr scrn) +{ + xf86CrtcPtr crtc = i830_crtc_for_pipe (scrn, 0); + /* VESA 640x480x72Hz mode to set on the pipe */ + static DisplayModeRec mode = { + NULL, NULL, "640x480", MODE_OK, M_T_DEFAULT, + 31500, + 640, 664, 704, 832, 0, + 480, 489, 491, 520, 0, + V_NHSYNC | V_NVSYNC, + 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + FALSE, FALSE, 0, NULL, 0, 0.0, 0.0 + }; + + if (!crtc) + return FALSE; + if (crtc->enabled) + return FALSE; + xf86SetModeCrtc (&mode, INTERLACE_HALVE_V); + crtc->funcs->mode_set (crtc, &mode, &mode, 0, 0); + crtc->funcs->dpms (crtc, DPMSModeOn); + return TRUE; +} + +void +i830_pipe_a_require_deactivate (ScrnInfoPtr scrn) +{ + xf86CrtcPtr crtc = i830_crtc_for_pipe (scrn, 0); + + if (!crtc) + return; + if (crtc->enabled) + return; + crtc->funcs->dpms (crtc, DPMSModeOff); + return; +} + +/* FIXME: use pixmap private instead if possible */ +static Bool +i830_display_tiled(xf86CrtcPtr crtc) +{ + ScrnInfoPtr pScrn = crtc->scrn; + I830Ptr pI830 = I830PTR(pScrn); + + /* Rotated data is currently linear, allocated either via XAA or EXA */ + if (crtc->rotatedData) + return FALSE; + + if (pI830->front_buffer && pI830->front_buffer->tiling != TILE_NONE) + return TRUE; + + return FALSE; +} + +static Bool +i830_use_fb_compression(xf86CrtcPtr crtc) +{ + ScrnInfoPtr pScrn = crtc->scrn; + I830Ptr pI830 = I830PTR(pScrn); + I830CrtcPrivatePtr intel_crtc = crtc->driver_private; + int plane = (intel_crtc->plane == 0 ? FBC_CTL_PLANEA : FBC_CTL_PLANEB); + + if (!pI830->fb_compression) + return FALSE; + + if (!i830_display_tiled(crtc)) + return FALSE; + + /* Pre-965 only supports plane A */ + if (!IS_I965GM(pI830) && plane != FBC_CTL_PLANEA) + return FALSE; + + /* Need 15, 16, or 32 (w/alpha) pixel format */ + if (!(pScrn->bitsPerPixel == 16 || /* covers 15 bit mode as well */ + pScrn->bitsPerPixel == 32)) /* mode_set dtrt if fbc is in use */ + return FALSE; + + /* + * No checks for pixel multiply, incl. horizontal, or interlaced modes + * since they're currently unused. + */ + return TRUE; +} + +/* + * Several restrictions: + * - DSP[AB]CNTR - no line duplication && no pixel multiplier + * - pixel format == 15 bit, 16 bit, or 32 bit xRGB_8888 + * - no alpha buffer discard + * - no dual wide display + * - progressive mode only (DSP[AB]CNTR) + * - uncompressed fb is <= 2048 in width, 0 mod 8 + * - uncompressed fb is <= 1536 in height, 0 mod 2 + * - SR display watermarks must be equal between 16bpp and 32bpp? + * + * FIXME: verify above conditions are true + */ +static void +i830_enable_fb_compression(xf86CrtcPtr crtc) +{ + ScrnInfoPtr pScrn = crtc->scrn; + I830Ptr pI830 = I830PTR(pScrn); + I830CrtcPrivatePtr intel_crtc = crtc->driver_private; + uint32_t fbc_ctl = 0; + unsigned long compressed_stride; + int plane = (intel_crtc->plane == 0 ? FBC_CTL_PLANEA : FBC_CTL_PLANEB); + unsigned long uncompressed_stride = pScrn->displayWidth * pI830->cpp; + unsigned long interval = 1000; + + if (INREG(FBC_CONTROL) & FBC_CTL_EN) { + char cur_plane = (INREG(FBC_CONTROL2) & 1) ? 'b' : 'a'; + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "fbc already enabled on " + "plane %c, not enabling on plane %c\n", cur_plane, + plane ? 'b' : 'a'); + return; + } + + compressed_stride = pI830->compressed_front_buffer->size / + FBC_LL_SIZE; + + if (uncompressed_stride < compressed_stride) + compressed_stride = uncompressed_stride; + + /* FBC_CTL wants 64B units */ + compressed_stride = (compressed_stride / 64) - 1; + + /* Set it up... */ + /* Wait for compressing bit to clear */ + while (INREG(FBC_STATUS) & FBC_STAT_COMPRESSING) + ; /* nothing */ + i830WaitForVblank(pScrn); + OUTREG(FBC_CFB_BASE, pI830->compressed_front_buffer->bus_addr); + OUTREG(FBC_LL_BASE, pI830->compressed_ll_buffer->bus_addr + 6); + OUTREG(FBC_CONTROL2, FBC_CTL_FENCE_DBL | FBC_CTL_IDLE_FULL | + FBC_CTL_CPU_FENCE | plane); + + /* Zero buffers */ + memset(pI830->FbBase + pI830->compressed_front_buffer->offset, 0, + pI830->compressed_front_buffer->size); + memset(pI830->FbBase + pI830->compressed_ll_buffer->offset, 0, + pI830->compressed_ll_buffer->size); + + /* enable it... */ + fbc_ctl |= FBC_CTL_EN | FBC_CTL_PERIODIC; + fbc_ctl |= (compressed_stride & 0xff) << FBC_CTL_STRIDE_SHIFT; + fbc_ctl |= (interval & 0x2fff) << FBC_CTL_INTERVAL_SHIFT; + fbc_ctl |= FBC_CTL_UNCOMPRESSIBLE; + fbc_ctl |= pI830->front_buffer->fence_nr; + OUTREG(FBC_CONTROL, fbc_ctl); + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "fbc enabled on plane %c\n", plane ? + 'b' : 'a'); +} + +static void +i830_disable_fb_compression(xf86CrtcPtr crtc) +{ + ScrnInfoPtr pScrn = crtc->scrn; + I830Ptr pI830 = I830PTR(pScrn); + uint32_t fbc_ctl; + char plane = (INREG(FBC_CONTROL2) & 1) ? 'b' : 'a'; + + /* Disable compression */ + fbc_ctl = INREG(FBC_CONTROL); + fbc_ctl &= ~FBC_CTL_EN; + OUTREG(FBC_CONTROL, fbc_ctl); + + /* Wait for compressing bit to clear */ + while (INREG(FBC_STATUS) & FBC_STAT_COMPRESSING) + ; /* nothing */ + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "fbc disabled on plane %c\n", plane); +} + +/** + * Sets the power management mode of the pipe and plane. + * + * This code should probably grow support for turning the cursor off and back + * on appropriately at the same time as we're turning the pipe off/on. + */ +static void +i830_crtc_dpms(xf86CrtcPtr crtc, int mode) +{ + ScrnInfoPtr pScrn = crtc->scrn; + I830Ptr pI830 = I830PTR(pScrn); + I830CrtcPrivatePtr intel_crtc = crtc->driver_private; + int pipe = intel_crtc->pipe; + int plane = intel_crtc->plane; + int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B; + int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF; + int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR; + int dspbase_reg = (plane == 0) ? DSPABASE : DSPBBASE; + CARD32 temp; + + /* XXX: When our outputs are all unaware of DPMS modes other than off and + * on, we should map those modes to DPMSModeOff in the CRTC. + */ + switch (mode) { + case DPMSModeOn: + case DPMSModeStandby: + case DPMSModeSuspend: + /* Enable the DPLL */ + temp = INREG(dpll_reg); + if ((temp & DPLL_VCO_ENABLE) == 0) + { + OUTREG(dpll_reg, temp); + POSTING_READ(dpll_reg); + /* Wait for the clocks to stabilize. */ + usleep(150); + OUTREG(dpll_reg, temp | DPLL_VCO_ENABLE); + POSTING_READ(dpll_reg); + /* Wait for the clocks to stabilize. */ + usleep(150); + OUTREG(dpll_reg, temp | DPLL_VCO_ENABLE); + POSTING_READ(dpll_reg); + /* Wait for the clocks to stabilize. */ + usleep(150); + } + + /* Enable the pipe */ + temp = INREG(pipeconf_reg); + if ((temp & PIPEACONF_ENABLE) == 0) + OUTREG(pipeconf_reg, temp | PIPEACONF_ENABLE); + + /* Enable the plane */ + temp = INREG(dspcntr_reg); + if ((temp & DISPLAY_PLANE_ENABLE) == 0) + { + OUTREG(dspcntr_reg, temp | DISPLAY_PLANE_ENABLE); + /* Flush the plane changes */ + OUTREG(dspbase_reg, INREG(dspbase_reg)); + } + + i830_crtc_load_lut(crtc); + + /* Give the overlay scaler a chance to enable if it's on this pipe */ + i830_crtc_dpms_video(crtc, TRUE); + + /* Reenable compression if needed */ + if (i830_use_fb_compression(crtc)) + i830_enable_fb_compression(crtc); + break; + case DPMSModeOff: + /* Shut off compression if in use */ + if (i830_use_fb_compression(crtc)) + i830_disable_fb_compression(crtc); + + /* Give the overlay scaler a chance to disable if it's on this pipe */ + i830_crtc_dpms_video(crtc, FALSE); + + /* Disable the VGA plane that we never use */ + OUTREG(VGACNTRL, VGA_DISP_DISABLE); + + /* Disable display plane */ + temp = INREG(dspcntr_reg); + if ((temp & DISPLAY_PLANE_ENABLE) != 0) + { + OUTREG(dspcntr_reg, temp & ~DISPLAY_PLANE_ENABLE); + /* Flush the plane changes */ + OUTREG(dspbase_reg, INREG(dspbase_reg)); + POSTING_READ(dspbase_reg); + } + + if (!IS_I9XX(pI830)) { + /* Wait for vblank for the disable to take effect */ + i830WaitForVblank(pScrn); + } + + /* Next, disable display pipes */ + temp = INREG(pipeconf_reg); + if ((temp & PIPEACONF_ENABLE) != 0) { + OUTREG(pipeconf_reg, temp & ~PIPEACONF_ENABLE); + POSTING_READ(pipeconf_reg); + } + + /* Wait for vblank for the disable to take effect. */ + i830WaitForVblank(pScrn); + + temp = INREG(dpll_reg); + if ((temp & DPLL_VCO_ENABLE) != 0) { + OUTREG(dpll_reg, temp & ~DPLL_VCO_ENABLE); + POSTING_READ(dpll_reg); + } + + /* Wait for the clocks to turn off. */ + usleep(150); + break; + } + + intel_crtc->dpms_mode = mode; + +#ifdef XF86DRI + if (pI830->directRenderingEnabled) { + drmI830Sarea *sPriv = (drmI830Sarea *) DRIGetSAREAPrivate(pScrn->pScreen); + Bool enabled = crtc->enabled && mode != DPMSModeOff; + + I830DRISetVBlankInterrupt (pScrn, TRUE); + + if (!sPriv) + return; + + switch (plane) { + case 0: + sPriv->planeA_w = enabled ? crtc->mode.HDisplay : 0; + sPriv->planeA_h = enabled ? crtc->mode.VDisplay : 0; + break; + case 1: + sPriv->planeB_w = enabled ? crtc->mode.HDisplay : 0; + sPriv->planeB_h = enabled ? crtc->mode.VDisplay : 0; + break; + default: + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Can't update pipe %d in SAREA\n", pipe); + break; + } + } +#endif +} + +static Bool +i830_crtc_lock (xf86CrtcPtr crtc) +{ + /* Sync the engine before mode switch */ + i830WaitSync(crtc->scrn); + +#ifdef XF86DRI + return I830DRILock(crtc->scrn); +#else + return FALSE; +#endif +} + +static void +i830_crtc_unlock (xf86CrtcPtr crtc) +{ +#ifdef XF86DRI + I830DRIUnlock (crtc->scrn); +#endif +} + +static void +i830_crtc_prepare (xf86CrtcPtr crtc) +{ + /* Temporarily turn off FB compression during modeset */ + if (i830_use_fb_compression(crtc)) + i830_disable_fb_compression(crtc); + crtc->funcs->dpms (crtc, DPMSModeOff); +} + +static void +i830_crtc_commit (xf86CrtcPtr crtc) +{ + I830CrtcPrivatePtr intel_crtc = crtc->driver_private; + Bool deactivate = FALSE; + + if (!intel_crtc->enabled && intel_crtc->pipe != 0) + deactivate = i830_pipe_a_require_activate (crtc->scrn); + + intel_crtc->enabled = TRUE; + + crtc->funcs->dpms (crtc, DPMSModeOn); + if (crtc->scrn->pScreen != NULL) + xf86_reload_cursors (crtc->scrn->pScreen); + if (deactivate) + i830_pipe_a_require_deactivate (crtc->scrn); + + /* Reenable FB compression if possible */ + if (i830_use_fb_compression(crtc)) + i830_enable_fb_compression(crtc); +} + +void +i830_output_prepare (xf86OutputPtr output) +{ + output->funcs->dpms (output, DPMSModeOff); +} + +void +i830_output_commit (xf86OutputPtr output) +{ + output->funcs->dpms (output, DPMSModeOn); +} + +static Bool +i830_crtc_mode_fixup(xf86CrtcPtr crtc, DisplayModePtr mode, + DisplayModePtr adjusted_mode) +{ + return TRUE; +} + +/** Returns the core display clock speed for i830 - i945 */ +static int +i830_get_core_clock_speed(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + + /* Core clock values taken from the published datasheets. + * The 830 may go up to 166 Mhz, which we should check. + */ + if (IS_I945G(pI830) || IS_G33CLASS(pI830)) + return 400000; + else if (IS_I915G(pI830)) + return 333000; + else if (IS_I945GM(pI830) || IS_845G(pI830)) + return 200000; + else if (IS_I915GM(pI830)) { + uint16_t gcfgc; + +#if XSERVER_LIBPCIACCESS + pci_device_cfg_read_u16 (pI830->PciInfo, &gcfgc, I915_GCFGC); +#else + gcfgc = pciReadWord(pI830->PciTag, I915_GCFGC); +#endif + if (gcfgc & I915_LOW_FREQUENCY_ENABLE) + return 133000; + else { + switch (gcfgc & I915_DISPLAY_CLOCK_MASK) { + case I915_DISPLAY_CLOCK_333_MHZ: + return 333000; + default: + case I915_DISPLAY_CLOCK_190_200_MHZ: + return 190000; + } + } + } else if (IS_I865G(pI830)) + return 266000; + else if (IS_I855(pI830)) { +#if XSERVER_LIBPCIACCESS + struct pci_device *bridge = intel_host_bridge (); + uint16_t hpllcc; + pci_device_cfg_read_u16 (bridge, &hpllcc, I855_HPLLCC); +#else + PCITAG bridge = pciTag(0, 0, 0); /* This is always the host bridge */ + CARD16 hpllcc = pciReadWord(bridge, I855_HPLLCC); +#endif + + /* Assume that the hardware is in the high speed state. This + * should be the default. + */ + switch (hpllcc & I855_CLOCK_CONTROL_MASK) { + case I855_CLOCK_133_200: + case I855_CLOCK_100_200: + return 200000; + case I855_CLOCK_166_250: + return 250000; + case I855_CLOCK_100_133: + return 133000; + } + } else /* 852, 830 */ + return 133000; + + return 0; /* Silence gcc warning */ +} + +/** + * Return the pipe currently connected to the panel fitter, + * or -1 if the panel fitter is not present or not in use + */ +static int +i830_panel_fitter_pipe(I830Ptr pI830) +{ + CARD32 pfit_control; + + /* i830 doesn't have a panel fitter */ + if (IS_I830(pI830)) + return -1; + + pfit_control = INREG(PFIT_CONTROL); + + /* See if the panel fitter is in use */ + if ((pfit_control & PFIT_ENABLE) == 0) + return -1; + + /* 965 can place panel fitter on either pipe */ + if (IS_I965G(pI830)) + return (pfit_control & PFIT_PIPE_MASK) >> PFIT_PIPE_SHIFT; + + /* older chips can only use pipe 1 */ + return 1; +} + +/** + * Sets up registers for the given mode/adjusted_mode pair. + * + * The clocks, CRTCs and outputs attached to this CRTC must be off. + * + * This shouldn't enable any clocks, CRTCs, or outputs, but they should + * be easily turned on/off after this. + */ +static void +i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode, + DisplayModePtr adjusted_mode, + int x, int y) +{ + ScrnInfoPtr pScrn = crtc->scrn; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + I830Ptr pI830 = I830PTR(pScrn); + I830CrtcPrivatePtr intel_crtc = crtc->driver_private; + int pipe = intel_crtc->pipe; + int plane = intel_crtc->plane; + int fp_reg = (pipe == 0) ? FPA0 : FPB0; + int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B; + int dpll_md_reg = (pipe == 0) ? DPLL_A_MD : DPLL_B_MD; + int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF; + int htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B; + int hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B; + int hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B; + int vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B; + int vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B; + int vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B; + int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC; + int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR; + int dspstride_reg = (plane == 0) ? DSPASTRIDE : DSPBSTRIDE; + int dsppos_reg = (plane == 0) ? DSPAPOS : DSPBPOS; + int dspsize_reg = (plane == 0) ? DSPASIZE : DSPBSIZE; + int i; + int refclk; + intel_clock_t clock; + CARD32 dpll = 0, fp = 0, dspcntr, pipeconf; + Bool ok, is_sdvo = FALSE, is_dvo = FALSE; + Bool is_crt = FALSE, is_lvds = FALSE, is_tv = FALSE; + + /* Set up some convenient bools for what outputs are connected to + * our pipe, used in DPLL setup. + */ + for (i = 0; i < xf86_config->num_output; i++) { + xf86OutputPtr output = xf86_config->output[i]; + I830OutputPrivatePtr intel_output = output->driver_private; + + if (output->crtc != crtc) + continue; + + switch (intel_output->type) { + case I830_OUTPUT_LVDS: + is_lvds = TRUE; + break; + case I830_OUTPUT_SDVO: + is_sdvo = TRUE; + break; + case I830_OUTPUT_DVO_TMDS: + case I830_OUTPUT_DVO_LVDS: + case I830_OUTPUT_DVO_TVOUT: + is_dvo = TRUE; + break; + case I830_OUTPUT_TVOUT: + is_tv = TRUE; + break; + case I830_OUTPUT_ANALOG: + is_crt = TRUE; + break; + } + } + + if (IS_I9XX(pI830)) { + refclk = 96000; + } else { + refclk = 48000; + } + + ok = i830FindBestPLL(crtc, adjusted_mode->Clock, refclk, &clock); + if (!ok) + FatalError("Couldn't find PLL settings for mode!\n"); + + if (fabs(adjusted_mode->Clock - clock.dot) / clock.dot > .02) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Chosen PLL clock of %.1f Mhz more than 2%% away from " + "desired %.1f Mhz\n", + (float)clock.dot / 1000, + (float)adjusted_mode->Clock / 1000); + } + + fp = clock.n << 16 | clock.m1 << 8 | clock.m2; + + dpll = DPLL_VGA_MODE_DIS; + if (IS_I9XX(pI830)) { + if (is_lvds) + dpll |= DPLLB_MODE_LVDS; + else + dpll |= DPLLB_MODE_DAC_SERIAL; + if (is_sdvo) + { + dpll |= DPLL_DVO_HIGH_SPEED; + if (IS_I945G(pI830) || IS_I945GM(pI830) || IS_G33CLASS(pI830)) + { + int sdvo_pixel_multiply = adjusted_mode->Clock / mode->Clock; + dpll |= (sdvo_pixel_multiply - 1) << SDVO_MULTIPLIER_SHIFT_HIRES; + } + } + + /* compute bitmask from p1 value */ + dpll |= (1 << (clock.p1 - 1)) << 16; + switch (clock.p2) { + case 5: + dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5; + break; + case 7: + dpll |= DPLLB_LVDS_P2_CLOCK_DIV_7; + break; + case 10: + dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_10; + break; + case 14: + dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14; + break; + } + if (IS_I965G(pI830)) + dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT); + } else { + if (is_lvds) { + dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT; + } else { + if (clock.p1 == 2) + dpll |= PLL_P1_DIVIDE_BY_TWO; + else + dpll |= (clock.p1 - 2) << DPLL_FPA01_P1_POST_DIV_SHIFT; + if (clock.p2 == 4) + dpll |= PLL_P2_DIVIDE_BY_4; + } + } + + if (is_tv) + { + /* XXX: just matching BIOS for now */ +/* dpll |= PLL_REF_INPUT_TVCLKINBC; */ + dpll |= 3; + } +#if 0 + else if (is_lvds) + dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN; +#endif + else + dpll |= PLL_REF_INPUT_DREFCLK; + + /* Set up the display plane register */ + dspcntr = DISPPLANE_GAMMA_ENABLE; + switch (pScrn->bitsPerPixel) { + case 8: + dspcntr |= DISPPLANE_8BPP; + break; + case 16: + if (pScrn->depth == 15) + dspcntr |= DISPPLANE_15_16BPP; + else + dspcntr |= DISPPLANE_16BPP; + break; + case 32: + dspcntr |= DISPPLANE_32BPP_NO_ALPHA; + break; + default: + FatalError("unknown display bpp\n"); + } + + if (pipe == 0) + dspcntr |= DISPPLANE_SEL_PIPE_A; + else + dspcntr |= DISPPLANE_SEL_PIPE_B; + + if (IS_I965G(pI830) && i830_display_tiled(crtc)) + dspcntr |= DISPLAY_PLANE_TILED; + + pipeconf = INREG(pipeconf_reg); + if (pipe == 0 && !IS_I965G(pI830)) + { + /* Enable pixel doubling when the dot clock is > 90% of the (display) + * core speed. + * + * XXX: No double-wide on 915GM pipe B. Is that the only reason for the + * pipe == 0 check? + */ + if (mode->Clock > i830_get_core_clock_speed(pScrn) * 9 / 10) + pipeconf |= PIPEACONF_DOUBLE_WIDE; + else + pipeconf &= ~PIPEACONF_DOUBLE_WIDE; + } + /* + * This "shouldn't" be needed as the dpms on code + * will be run after the mode is set. On 9xx, it helps. + * On 855, it can lock up the chip (and the entire machine) + */ + if (!IS_I85X (pI830)) + { + dspcntr |= DISPLAY_PLANE_ENABLE; + pipeconf |= PIPEACONF_ENABLE; + dpll |= DPLL_VCO_ENABLE; + } + + /* Disable the panel fitter if it was on our pipe */ + if (i830_panel_fitter_pipe (pI830) == pipe) + OUTREG(PFIT_CONTROL, 0); + + if (pI830->debug_modes) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B'); + xf86PrintModeline(pScrn->scrnIndex, mode); + if (!xf86ModesEqual(mode, adjusted_mode)) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Adjusted mode for pipe %c:\n", pipe == 0 ? 'A' : 'B'); + xf86PrintModeline(pScrn->scrnIndex, mode); + } + i830PrintPll("chosen", &clock); + } + + if (dpll & DPLL_VCO_ENABLE) + { + OUTREG(fp_reg, fp); + OUTREG(dpll_reg, dpll & ~DPLL_VCO_ENABLE); + POSTING_READ(dpll_reg); + usleep(150); + } + + /* The LVDS pin pair needs to be on before the DPLLs are enabled. + * This is an exception to the general rule that mode_set doesn't turn + * things on. + */ + if (is_lvds) + { + CARD32 lvds = INREG(LVDS); + + lvds |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP | LVDS_PIPEB_SELECT; + /* Set the B0-B3 data pairs corresponding to whether we're going to + * set the DPLLs for dual-channel mode or not. + */ + if (clock.p2 == I9XX_P2_LVDS_FAST) + lvds |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP; + else + lvds &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP); + + /* It would be nice to set 24 vs 18-bit mode (LVDS_A3_POWER_UP) + * appropriately here, but we need to look more thoroughly into how + * panels behave in the two modes. + */ + + /* Enable dithering if we're in 18-bit mode. */ + if (IS_I965G(pI830)) + { + if ((lvds & LVDS_A3_POWER_MASK) == LVDS_A3_POWER_UP) + lvds &= ~LVDS_DITHER_ENABLE; + else + lvds |= LVDS_DITHER_ENABLE; + } + + OUTREG(LVDS, lvds); + POSTING_READ(LVDS); + } + + OUTREG(fp_reg, fp); + OUTREG(dpll_reg, dpll); + POSTING_READ(dpll_reg); + /* Wait for the clocks to stabilize. */ + usleep(150); + + if (IS_I965G(pI830)) { + int sdvo_pixel_multiply = adjusted_mode->Clock / mode->Clock; + OUTREG(dpll_md_reg, (0 << DPLL_MD_UDI_DIVIDER_SHIFT) | + ((sdvo_pixel_multiply - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT)); + } else { + /* write it again -- the BIOS does, after all */ + OUTREG(dpll_reg, dpll); + } + POSTING_READ(dpll_reg); + /* Wait for the clocks to stabilize. */ + usleep(150); + + OUTREG(htot_reg, (adjusted_mode->CrtcHDisplay - 1) | + ((adjusted_mode->CrtcHTotal - 1) << 16)); + OUTREG(hblank_reg, (adjusted_mode->CrtcHBlankStart - 1) | + ((adjusted_mode->CrtcHBlankEnd - 1) << 16)); + OUTREG(hsync_reg, (adjusted_mode->CrtcHSyncStart - 1) | + ((adjusted_mode->CrtcHSyncEnd - 1) << 16)); + OUTREG(vtot_reg, (adjusted_mode->CrtcVDisplay - 1) | + ((adjusted_mode->CrtcVTotal - 1) << 16)); + + OUTREG(vblank_reg, (adjusted_mode->CrtcVBlankStart - 1) | + ((adjusted_mode->CrtcVBlankEnd - 1) << 16)); + OUTREG(vsync_reg, (adjusted_mode->CrtcVSyncStart - 1) | + ((adjusted_mode->CrtcVSyncEnd - 1) << 16)); + OUTREG(dspstride_reg, pScrn->displayWidth * pI830->cpp); + /* pipesrc and dspsize control the size that is scaled from, which should + * always be the user's requested size. + */ + OUTREG(dspsize_reg, ((mode->VDisplay - 1) << 16) | (mode->HDisplay - 1)); + OUTREG(dsppos_reg, 0); + OUTREG(pipesrc_reg, ((mode->HDisplay - 1) << 16) | (mode->VDisplay - 1)); + OUTREG(pipeconf_reg, pipeconf); + POSTING_READ(pipeconf_reg); + i830WaitForVblank(pScrn); + + OUTREG(dspcntr_reg, dspcntr); + /* Flush the plane changes */ + i830PipeSetBase(crtc, x, y); +#ifdef XF86DRI + I830DRISetVBlankInterrupt (pScrn, TRUE); +#endif + + i830WaitForVblank(pScrn); +} + + +/** Loads the palette/gamma unit for the CRTC with the prepared values */ +void +i830_crtc_load_lut(xf86CrtcPtr crtc) +{ + ScrnInfoPtr pScrn = crtc->scrn; + I830Ptr pI830 = I830PTR(pScrn); + I830CrtcPrivatePtr intel_crtc = crtc->driver_private; + int palreg = (intel_crtc->pipe == 0) ? PALETTE_A : PALETTE_B; + int i; + + /* The clocks have to be on to load the palette. */ + if (!crtc->enabled) + return; + + for (i = 0; i < 256; i++) { + OUTREG(palreg + 4 * i, + (intel_crtc->lut_r[i] << 16) | + (intel_crtc->lut_g[i] << 8) | + intel_crtc->lut_b[i]); + } +} + +/** Sets the color ramps on behalf of RandR */ +static void +i830_crtc_gamma_set(xf86CrtcPtr crtc, CARD16 *red, CARD16 *green, CARD16 *blue, + int size) +{ + I830CrtcPrivatePtr intel_crtc = crtc->driver_private; + int i; + + assert(size == 256); + + for (i = 0; i < 256; i++) { + intel_crtc->lut_r[i] = red[i] >> 8; + intel_crtc->lut_g[i] = green[i] >> 8; + intel_crtc->lut_b[i] = blue[i] >> 8; + } + + i830_crtc_load_lut(crtc); +} + +/** + * Allocates memory for a locked-in-framebuffer shadow of the given + * width and height for this CRTC's rotated shadow framebuffer. + */ + +static void * +i830_crtc_shadow_allocate (xf86CrtcPtr crtc, int width, int height) +{ + ScrnInfoPtr pScrn = crtc->scrn; + I830Ptr pI830 = I830PTR(pScrn); + I830CrtcPrivatePtr intel_crtc = crtc->driver_private; + unsigned long rotate_pitch; + int align = KB(4), size; + + rotate_pitch = pScrn->displayWidth * pI830->cpp; + size = rotate_pitch * height; + + assert(intel_crtc->rotate_mem == NULL); + intel_crtc->rotate_mem = i830_allocate_memory(pScrn, "rotated crtc", + size, align, 0); + if (intel_crtc->rotate_mem == NULL) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Couldn't allocate shadow memory for rotated CRTC\n"); + return NULL; + } + + return pI830->FbBase + intel_crtc->rotate_mem->offset; +} + +/** + * Creates a pixmap for this CRTC's rotated shadow framebuffer. + */ +static PixmapPtr +i830_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height) +{ + ScrnInfoPtr pScrn = crtc->scrn; + I830Ptr pI830 = I830PTR(pScrn); + unsigned long rotate_pitch; + PixmapPtr rotate_pixmap; + + if (!data) + data = i830_crtc_shadow_allocate (crtc, width, height); + + rotate_pitch = pScrn->displayWidth * pI830->cpp; + + rotate_pixmap = GetScratchPixmapHeader(pScrn->pScreen, + width, height, + pScrn->depth, + pScrn->bitsPerPixel, + rotate_pitch, + data); + + if (rotate_pixmap == NULL) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Couldn't allocate shadow pixmap for rotated CRTC\n"); + } + return rotate_pixmap; +} + +static void +i830_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data) +{ + ScrnInfoPtr pScrn = crtc->scrn; + I830CrtcPrivatePtr intel_crtc = crtc->driver_private; + + if (rotate_pixmap) + FreeScratchPixmapHeader(rotate_pixmap); + + if (data) { + /* Be sure to sync acceleration before the memory gets unbound. */ + I830Sync(pScrn); + i830_free_memory(pScrn, intel_crtc->rotate_mem); + intel_crtc->rotate_mem = NULL; + } +} + + +void +i830DescribeOutputConfiguration(ScrnInfoPtr pScrn) +{ + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + I830Ptr pI830 = I830PTR(pScrn); + int i; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Output configuration:\n"); + + for (i = 0; i < xf86_config->num_crtc; i++) { + xf86CrtcPtr crtc = xf86_config->crtc[i]; + I830CrtcPrivatePtr intel_crtc = crtc ? crtc->driver_private : NULL; + CARD32 dspcntr = intel_crtc->plane == 0 ? INREG(DSPACNTR) : + INREG(DSPBCNTR); + CARD32 pipeconf = i == 0 ? INREG(PIPEACONF) : + INREG(PIPEBCONF); + Bool hw_plane_enable = (dspcntr & DISPLAY_PLANE_ENABLE) != 0; + Bool hw_pipe_enable = (pipeconf & PIPEACONF_ENABLE) != 0; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + " Pipe %c is %s\n", + 'A' + i, crtc->enabled ? "on" : "off"); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + " Display plane %c is now %s and connected to pipe %c.\n", + 'A' + intel_crtc->plane, + hw_plane_enable ? "enabled" : "disabled", + dspcntr & DISPPLANE_SEL_PIPE_MASK ? 'B' : 'A'); + if (hw_pipe_enable != crtc->enabled) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + " Hardware claims pipe %c is %s while software " + "believes it is %s\n", + 'A' + i, hw_pipe_enable ? "on" : "off", + crtc->enabled ? "on" : "off"); + } + if (hw_plane_enable != crtc->enabled) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + " Hardware claims plane %c is %s while software " + "believes it is %s\n", + 'A' + i, hw_plane_enable ? "on" : "off", + crtc->enabled ? "on" : "off"); + } + } + + for (i = 0; i < xf86_config->num_output; i++) { + xf86OutputPtr output = xf86_config->output[i]; + xf86CrtcPtr crtc = output->crtc; + I830CrtcPrivatePtr intel_crtc = crtc ? crtc->driver_private : NULL; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + " Output %s is connected to pipe %s\n", + output->name, intel_crtc == NULL ? "none" : + (intel_crtc->pipe == 0 ? "A" : "B")); + } +} + +/** + * Get a pipe with a simple mode set on it for doing load-based monitor + * detection. + * + * It will be up to the load-detect code to adjust the pipe as appropriate for + * its requirements. The pipe will be connected to no other outputs. + * + * Currently this code will only succeed if there is a pipe with no outputs + * configured for it. In the future, it could choose to temporarily disable + * some outputs to free up a pipe for its use. + * + * \return crtc, or NULL if no pipes are available. + */ + +/* VESA 640x480x72Hz mode to set on the pipe */ +static DisplayModeRec load_detect_mode = { + NULL, NULL, "640x480", MODE_OK, M_T_DEFAULT, + 31500, + 640, 664, 704, 832, 0, + 480, 489, 491, 520, 0, + V_NHSYNC | V_NVSYNC, + 0, 0, + + 640, 640, 664, 704, 832, 832, 0, + 480, 489, 489, 491, 520, 520, + FALSE, FALSE, 0, NULL, 0, 0.0, 0.0 +}; + +xf86CrtcPtr +i830GetLoadDetectPipe(xf86OutputPtr output, DisplayModePtr mode, int *dpms_mode) +{ + ScrnInfoPtr pScrn = output->scrn; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + I830OutputPrivatePtr intel_output = output->driver_private; + I830CrtcPrivatePtr intel_crtc; + xf86CrtcPtr supported_crtc =NULL; + xf86CrtcPtr crtc = NULL; + int i; + + if (output->crtc) + { + crtc = output->crtc; + /* + * Make sure the crtc and output are running + */ + intel_crtc = crtc->driver_private; + *dpms_mode = intel_crtc->dpms_mode; + if (intel_crtc->dpms_mode != DPMSModeOn) + { + crtc->funcs->dpms (crtc, DPMSModeOn); + output->funcs->dpms (output, DPMSModeOn); + } + return crtc; + } + + for (i = 0; i < xf86_config->num_crtc; i++) + { + xf86CrtcPtr possible_crtc; + if (!(output->possible_crtcs & (1 << i))) + continue; + possible_crtc = xf86_config->crtc[i]; + if (!possible_crtc->enabled) + { + crtc = possible_crtc; + break; + } + if (!supported_crtc) + supported_crtc = possible_crtc; + } + if (!crtc) + { + crtc = supported_crtc; + if (!crtc) + return NULL; + } + + output->crtc = crtc; + intel_output->load_detect_temp = TRUE; + + intel_crtc = crtc->driver_private; + *dpms_mode = intel_crtc->dpms_mode; + + if (!crtc->enabled) + { + if (!mode) + mode = &load_detect_mode; + xf86CrtcSetMode (crtc, mode, RR_Rotate_0, 0, 0); + } + else + { + if (intel_crtc->dpms_mode != DPMSModeOn) + crtc->funcs->dpms (crtc, DPMSModeOn); + + /* Add this output to the crtc */ + output->funcs->mode_set (output, &crtc->mode, &crtc->mode); + output->funcs->commit (output); + } + /* let the output get through one full cycle before testing */ + i830WaitForVblank (pScrn); + + return crtc; +} + +void +i830ReleaseLoadDetectPipe(xf86OutputPtr output, int dpms_mode) +{ + ScrnInfoPtr pScrn = output->scrn; + I830OutputPrivatePtr intel_output = output->driver_private; + xf86CrtcPtr crtc = output->crtc; + + if (intel_output->load_detect_temp) + { + output->crtc = NULL; + intel_output->load_detect_temp = FALSE; + crtc->enabled = xf86CrtcInUse (crtc); + xf86DisableUnusedFunctions(pScrn); + } + /* + * Switch crtc and output back off if necessary + */ + if (crtc->enabled && dpms_mode != DPMSModeOn) + { + if (output->crtc == crtc) + output->funcs->dpms (output, dpms_mode); + crtc->funcs->dpms (crtc, dpms_mode); + } +} + +/* Returns the clock of the currently programmed mode of the given pipe. */ +static int +i830_crtc_clock_get(ScrnInfoPtr pScrn, xf86CrtcPtr crtc) +{ + I830Ptr pI830 = I830PTR(pScrn); + I830CrtcPrivatePtr intel_crtc = crtc->driver_private; + int pipe = intel_crtc->pipe; + CARD32 dpll = INREG((pipe == 0) ? DPLL_A : DPLL_B); + CARD32 fp; + intel_clock_t clock; + + if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0) + fp = INREG((pipe == 0) ? FPA0 : FPB0); + else + fp = INREG((pipe == 0) ? FPA1 : FPB1); + + clock.m1 = (fp & FP_M1_DIV_MASK) >> FP_M1_DIV_SHIFT; + clock.m2 = (fp & FP_M2_DIV_MASK) >> FP_M2_DIV_SHIFT; + clock.n = (fp & FP_N_DIV_MASK) >> FP_N_DIV_SHIFT; + if (IS_I9XX(pI830)) { + clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK) >> + DPLL_FPA01_P1_POST_DIV_SHIFT); + + switch (dpll & DPLL_MODE_MASK) { + case DPLLB_MODE_DAC_SERIAL: + clock.p2 = dpll & DPLL_DAC_SERIAL_P2_CLOCK_DIV_5 ? 5 : 10; + break; + case DPLLB_MODE_LVDS: + clock.p2 = dpll & DPLLB_LVDS_P2_CLOCK_DIV_7 ? 7 : 14; + break; + default: + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Unknown DPLL mode %08x in programmed mode\n", + (int)(dpll & DPLL_MODE_MASK)); + return 0; + } + + /* XXX: Handle the 100Mhz refclk */ + i9xx_clock(96000, &clock); + } else { + Bool is_lvds = (pipe == 1) && (INREG(LVDS) & LVDS_PORT_EN); + + if (is_lvds) { + clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS) >> + DPLL_FPA01_P1_POST_DIV_SHIFT); + clock.p2 = 14; + + if ((dpll & PLL_REF_INPUT_MASK) == PLLB_REF_INPUT_SPREADSPECTRUMIN) + i8xx_clock(66000, &clock); /* XXX: might not be 66MHz */ + else + i8xx_clock(48000, &clock); + } else { + if (dpll & PLL_P1_DIVIDE_BY_TWO) { + clock.p1 = 2; + } else { + clock.p1 = ((dpll & DPLL_FPA01_P1_POST_DIV_MASK_I830) >> + DPLL_FPA01_P1_POST_DIV_SHIFT) + 2; + } + if (dpll & PLL_P2_DIVIDE_BY_4) + clock.p2 = 4; + else + clock.p2 = 2; + + i8xx_clock(48000, &clock); + } + } + + /* XXX: It would be nice to validate the clocks, but we can't reuse + * i830PllIsValid() because it relies on the xf86_config output + * configuration being accurate, which it isn't necessarily. + */ + if (0) + i830PrintPll("probed", &clock); + + return clock.dot; +} + +/** Returns the currently programmed mode of the given pipe. */ +DisplayModePtr +i830_crtc_mode_get(ScrnInfoPtr pScrn, xf86CrtcPtr crtc) +{ + I830Ptr pI830 = I830PTR(pScrn); + I830CrtcPrivatePtr intel_crtc = crtc->driver_private; + int pipe = intel_crtc->pipe; + DisplayModePtr mode; + int htot = INREG((pipe == 0) ? HTOTAL_A : HTOTAL_B); + int hsync = INREG((pipe == 0) ? HSYNC_A : HSYNC_B); + int vtot = INREG((pipe == 0) ? VTOTAL_A : VTOTAL_B); + int vsync = INREG((pipe == 0) ? VSYNC_A : VSYNC_B); + + mode = xcalloc(1, sizeof(DisplayModeRec)); + if (mode == NULL) + return NULL; + + mode->Clock = i830_crtc_clock_get(pScrn, crtc); + mode->HDisplay = (htot & 0xffff) + 1; + mode->HTotal = ((htot & 0xffff0000) >> 16) + 1; + mode->HSyncStart = (hsync & 0xffff) + 1; + mode->HSyncEnd = ((hsync & 0xffff0000) >> 16) + 1; + mode->VDisplay = (vtot & 0xffff) + 1; + mode->VTotal = ((vtot & 0xffff0000) >> 16) + 1; + mode->VSyncStart = (vsync & 0xffff) + 1; + mode->VSyncEnd = ((vsync & 0xffff0000) >> 16) + 1; + xf86SetModeDefaultName(mode); + xf86SetModeCrtc(mode, 0); + + return mode; +} + +static const xf86CrtcFuncsRec i830_crtc_funcs = { + .dpms = i830_crtc_dpms, + .save = NULL, /* XXX */ + .restore = NULL, /* XXX */ + .lock = i830_crtc_lock, + .unlock = i830_crtc_unlock, + .mode_fixup = i830_crtc_mode_fixup, + .prepare = i830_crtc_prepare, + .mode_set = i830_crtc_mode_set, + .commit = i830_crtc_commit, + .gamma_set = i830_crtc_gamma_set, + .shadow_create = i830_crtc_shadow_create, + .shadow_allocate = i830_crtc_shadow_allocate, + .shadow_destroy = i830_crtc_shadow_destroy, + .set_cursor_colors = i830_crtc_set_cursor_colors, + .set_cursor_position = i830_crtc_set_cursor_position, + .show_cursor = i830_crtc_show_cursor, + .hide_cursor = i830_crtc_hide_cursor, +/* .load_cursor_image = i830_crtc_load_cursor_image, */ + .load_cursor_argb = i830_crtc_load_cursor_argb, + .destroy = NULL, /* XXX */ +}; + +void +i830_crtc_init(ScrnInfoPtr pScrn, int pipe) +{ + xf86CrtcPtr crtc; + I830CrtcPrivatePtr intel_crtc; + int i; + + crtc = xf86CrtcCreate (pScrn, &i830_crtc_funcs); + if (crtc == NULL) + return; + + intel_crtc = xnfcalloc (sizeof (I830CrtcPrivateRec), 1); + intel_crtc->pipe = pipe; + intel_crtc->dpms_mode = DPMSModeOff; + intel_crtc->plane = pipe; + + /* Initialize the LUTs for when we turn on the CRTC. */ + for (i = 0; i < 256; i++) { + intel_crtc->lut_r[i] = i; + intel_crtc->lut_g[i] = i; + intel_crtc->lut_b[i] = i; + } + crtc->driver_private = intel_crtc; +} + diff --git a/driver/xf86-video-intel/src/i830_display.h b/driver/xf86-video-intel/src/i830_display.h new file mode 100644 index 000000000..1eeb7f15f --- /dev/null +++ b/driver/xf86-video-intel/src/i830_display.h @@ -0,0 +1,42 @@ +/* + * Copyright © 2006 Intel Corporation + * + * 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 + * THE AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +#include "xorgVersion.h" + +/* i830_display.c */ +void i830PipeSetBase(xf86CrtcPtr crtc, int x, int y); +void i830WaitForVblank(ScrnInfoPtr pScrn); +void i830DescribeOutputConfiguration(ScrnInfoPtr pScrn); + +xf86CrtcPtr i830GetLoadDetectPipe(xf86OutputPtr output, DisplayModePtr mode, int *dpms_mode); +void i830ReleaseLoadDetectPipe(xf86OutputPtr output, int dpms_mode); +void i830_crtc_init(ScrnInfoPtr pScrn, int pipe); +void i830_crtc_load_lut(xf86CrtcPtr crtc); +DisplayModePtr i830_crtc_mode_get(ScrnInfoPtr pScrn, xf86CrtcPtr crtc); +void i830_output_prepare (xf86OutputPtr output); +void i830_output_commit (xf86OutputPtr output); + diff --git a/driver/xf86-video-intel/src/i830_dvo.c b/driver/xf86-video-intel/src/i830_dvo.c new file mode 100644 index 000000000..e6ff6af6c --- /dev/null +++ b/driver/xf86-video-intel/src/i830_dvo.c @@ -0,0 +1,524 @@ +/************************************************************************** + +Copyright 2006 Dave Airlie <airlied@linux.ie> + +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. + +****** +********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "xf86.h" +#include "i830.h" +#include "i830_display.h" +#include "i810_reg.h" + +#include "sil164/sil164.h" +#include "ch7xxx/ch7xxx.h" +#include "tfp410/tfp410.h" + +static const char *SIL164Symbols[] = { + "Sil164VidOutput", + NULL +}; +static const char *TFP410Symbols[] = { + "Tfp410VidOutput", + NULL +}; +static const char *CH7xxxSymbols[] = { + "CH7xxxVidOutput", + NULL +}; +static const char *ivch_symbols[] = { + "ivch_methods", + NULL +}; + +static const char *ch7017_symbols[] = { + "ch7017_methods", + NULL +}; + +/* driver list */ +struct _I830DVODriver i830_dvo_drivers[] = +{ + { + .type = I830_OUTPUT_DVO_TMDS, + .modulename = "sil164", + .fntablename = "SIL164VidOutput", + .dvo_reg = DVOC, + .address = (SIL164_ADDR_1<<1), + .symbols = SIL164Symbols + }, + { + .type = I830_OUTPUT_DVO_TMDS, + .modulename = "ch7xxx", + .fntablename = "CH7xxxVidOutput", + .dvo_reg = DVOC, + .address = (CH7xxx_ADDR_1<<1), + .symbols = CH7xxxSymbols + }, + { + .type = I830_OUTPUT_DVO_LVDS, + .modulename = "ivch", + .fntablename = "ivch_methods", + .dvo_reg = DVOA, + .address = 0x04, /* Might also be 0x44, 0x84, 0xc4 */ + .symbols = ivch_symbols + }, + { + .type = I830_OUTPUT_DVO_TMDS, + .modulename = "tfp410", + .fntablename = "TFP410VidOutput", + .dvo_reg = DVOC, + .address = (TFP410_ADDR_1<<1), + .symbols = TFP410Symbols + }, + { + .type = I830_OUTPUT_DVO_LVDS, + .modulename = "ch7017", + .fntablename = "ch7017_methods", + .dvo_reg = DVOC, + .address = 0xea, + .symbols = ch7017_symbols, + .gpio = GPIOE, + } +}; + +#define I830_NUM_DVO_DRIVERS (sizeof(i830_dvo_drivers)/sizeof(struct _I830DVODriver)) + +static void +i830_dvo_dpms(xf86OutputPtr output, int mode) +{ + ScrnInfoPtr pScrn = output->scrn; + I830Ptr pI830 = I830PTR(pScrn); + I830OutputPrivatePtr intel_output = output->driver_private; + struct _I830DVODriver *drv = intel_output->i2c_drv; + void * dev_priv = drv->dev_priv; + unsigned int dvo_reg = drv->dvo_reg; + + if (mode == DPMSModeOn) { + OUTREG(dvo_reg, INREG(dvo_reg) | DVO_ENABLE); + POSTING_READ(dvo_reg); + (*intel_output->i2c_drv->vid_rec->dpms)(dev_priv, mode); + } else { + (*intel_output->i2c_drv->vid_rec->dpms)(dev_priv, mode); + OUTREG(dvo_reg, INREG(dvo_reg) & ~DVO_ENABLE); + POSTING_READ(dvo_reg); + } +} + +static void +i830_dvo_save(xf86OutputPtr output) +{ + ScrnInfoPtr pScrn = output->scrn; + I830Ptr pI830 = I830PTR(pScrn); + I830OutputPrivatePtr intel_output = output->driver_private; + void * dev_priv = intel_output->i2c_drv->dev_priv; + + /* Each output should probably just save the registers it touches, but for + * now, use more overkill. + */ + pI830->saveDVOA = INREG(DVOA); + pI830->saveDVOB = INREG(DVOB); + pI830->saveDVOC = INREG(DVOC); + + (*intel_output->i2c_drv->vid_rec->save)(dev_priv); +} + +static void +i830_dvo_restore(xf86OutputPtr output) +{ + ScrnInfoPtr pScrn = output->scrn; + I830Ptr pI830 = I830PTR(pScrn); + I830OutputPrivatePtr intel_output = output->driver_private; + void * dev_priv = intel_output->i2c_drv->dev_priv; + + (*intel_output->i2c_drv->vid_rec->restore)(dev_priv); + + OUTREG(DVOA, pI830->saveDVOA); + OUTREG(DVOB, pI830->saveDVOB); + OUTREG(DVOC, pI830->saveDVOC); +} + +static int +i830_dvo_mode_valid(xf86OutputPtr output, DisplayModePtr pMode) +{ + I830OutputPrivatePtr intel_output = output->driver_private; + struct _I830DVODriver *drv = intel_output->i2c_drv; + void *dev_priv = intel_output->i2c_drv->dev_priv; + + if (pMode->Flags & V_DBLSCAN) + return MODE_NO_DBLESCAN; + + /* XXX: Validate clock range */ + + if (drv->panel_fixed_mode) { + if (pMode->HDisplay > drv->panel_fixed_mode->HDisplay) + return MODE_PANEL; + if (pMode->VDisplay > drv->panel_fixed_mode->VDisplay) + return MODE_PANEL; + } + + return intel_output->i2c_drv->vid_rec->mode_valid(dev_priv, pMode); +} + +static Bool +i830_dvo_mode_fixup(xf86OutputPtr output, DisplayModePtr mode, + DisplayModePtr adjusted_mode) +{ + I830OutputPrivatePtr intel_output = output->driver_private; + struct _I830DVODriver *drv = intel_output->i2c_drv; + + /* If we have timings from the BIOS for the panel, put them in + * to the adjusted mode. The CRTC will be set up for this mode, + * with the panel scaling set up to source from the H/VDisplay + * of the original mode. + */ + if (drv->panel_fixed_mode != NULL) { + adjusted_mode->HDisplay = drv->panel_fixed_mode->HDisplay; + adjusted_mode->HSyncStart = drv->panel_fixed_mode->HSyncStart; + adjusted_mode->HSyncEnd = drv->panel_fixed_mode->HSyncEnd; + adjusted_mode->HTotal = drv->panel_fixed_mode->HTotal; + adjusted_mode->VDisplay = drv->panel_fixed_mode->VDisplay; + adjusted_mode->VSyncStart = drv->panel_fixed_mode->VSyncStart; + adjusted_mode->VSyncEnd = drv->panel_fixed_mode->VSyncEnd; + adjusted_mode->VTotal = drv->panel_fixed_mode->VTotal; + adjusted_mode->Clock = drv->panel_fixed_mode->Clock; + xf86SetModeCrtc(adjusted_mode, INTERLACE_HALVE_V); + } + + if (intel_output->i2c_drv->vid_rec->mode_fixup) + return intel_output->i2c_drv->vid_rec->mode_fixup (intel_output->i2c_drv->dev_priv, + mode, adjusted_mode); + return TRUE; +} + +static void +i830_dvo_mode_set(xf86OutputPtr output, DisplayModePtr mode, + DisplayModePtr adjusted_mode) +{ + ScrnInfoPtr pScrn = output->scrn; + I830Ptr pI830 = I830PTR(pScrn); + xf86CrtcPtr crtc = output->crtc; + I830CrtcPrivatePtr intel_crtc = crtc->driver_private; + I830OutputPrivatePtr intel_output = output->driver_private; + struct _I830DVODriver *drv = intel_output->i2c_drv; + int pipe = intel_crtc->pipe; + CARD32 dvo; + unsigned int dvo_reg = drv->dvo_reg, dvo_srcdim_reg; + int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B; + + switch (dvo_reg) { + case DVOA: + default: + dvo_srcdim_reg = DVOA_SRCDIM; + break; + case DVOB: + dvo_srcdim_reg = DVOB_SRCDIM; + break; + case DVOC: + dvo_srcdim_reg = DVOC_SRCDIM; + break; + } + + intel_output->i2c_drv->vid_rec->mode_set(intel_output->i2c_drv->dev_priv, + mode, adjusted_mode); + + /* Save the data order, since I don't know what it should be set to. */ + dvo = INREG(dvo_reg) & (DVO_PRESERVE_MASK | DVO_DATA_ORDER_GBRG); + dvo |= DVO_DATA_ORDER_FP | DVO_BORDER_ENABLE | DVO_BLANK_ACTIVE_HIGH; + + if (pipe == 1) + dvo |= DVO_PIPE_B_SELECT; + dvo |= DVO_PIPE_STALL; + if (adjusted_mode->Flags & V_PHSYNC) + dvo |= DVO_HSYNC_ACTIVE_HIGH; + if (adjusted_mode->Flags & V_PVSYNC) + dvo |= DVO_VSYNC_ACTIVE_HIGH; + + OUTREG(dpll_reg, INREG(dpll_reg) | DPLL_DVO_HIGH_SPEED); + + /*OUTREG(DVOB_SRCDIM, + (adjusted_mode->HDisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) | + (adjusted_mode->VDisplay << DVO_SRCDIM_VERTICAL_SHIFT));*/ + OUTREG(dvo_srcdim_reg, + (adjusted_mode->HDisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) | + (adjusted_mode->VDisplay << DVO_SRCDIM_VERTICAL_SHIFT)); + /*OUTREG(DVOB, dvo);*/ + OUTREG(dvo_reg, dvo); +} + +/** + * Detect the output connection on our DVO device. + * + * Unimplemented. + */ +static xf86OutputStatus +i830_dvo_detect(xf86OutputPtr output) +{ + I830OutputPrivatePtr intel_output = output->driver_private; + void *dev_priv = intel_output->i2c_drv->dev_priv; + + return intel_output->i2c_drv->vid_rec->detect(dev_priv); +} + +static DisplayModePtr +i830_dvo_get_modes(xf86OutputPtr output) +{ + I830OutputPrivatePtr intel_output = output->driver_private; + struct _I830DVODriver *drv = intel_output->i2c_drv; + DisplayModePtr modes; + + /* We should probably have an i2c driver get_modes function for those + * devices which will have a fixed set of modes determined by the chip + * (TV-out, for example), but for now with just TMDS and LVDS, that's not + * the case. + */ + modes = i830_ddc_get_modes(output); + if (modes != NULL) + return modes; + + if (intel_output->i2c_drv->vid_rec->get_modes) + { + modes = intel_output->i2c_drv->vid_rec->get_modes (intel_output->i2c_drv->dev_priv); + if (modes != NULL) + return modes; + } + + if (drv->panel_fixed_mode != NULL) + return xf86DuplicateMode(drv->panel_fixed_mode); + + return NULL; +} + +static void +i830_dvo_destroy (xf86OutputPtr output) +{ + I830OutputPrivatePtr intel_output = output->driver_private; + + if (intel_output) + { + if (intel_output->i2c_drv->vid_rec->destroy) + intel_output->i2c_drv->vid_rec->destroy (intel_output->i2c_drv->dev_priv); + if (intel_output->pI2CBus) + xf86DestroyI2CBusRec (intel_output->pI2CBus, TRUE, TRUE); + if (intel_output->pDDCBus) + xf86DestroyI2CBusRec (intel_output->pDDCBus, TRUE, TRUE); + xfree (intel_output); + } +} + +static const xf86OutputFuncsRec i830_dvo_output_funcs = { + .dpms = i830_dvo_dpms, + .save = i830_dvo_save, + .restore = i830_dvo_restore, + .mode_valid = i830_dvo_mode_valid, + .mode_fixup = i830_dvo_mode_fixup, + .prepare = i830_output_prepare, + .mode_set = i830_dvo_mode_set, + .commit = i830_output_commit, + .detect = i830_dvo_detect, + .get_modes = i830_dvo_get_modes, + .destroy = i830_dvo_destroy +}; + +/** + * Attempts to get a fixed panel timing for LVDS (currently only the i830). + * + * Other chips with DVO LVDS will need to extend this to deal with the LVDS + * chip being on DVOB/C and having multiple pipes. + */ +DisplayModePtr +i830_dvo_get_current_mode (xf86OutputPtr output) +{ + ScrnInfoPtr pScrn = output->scrn; + I830OutputPrivatePtr intel_output = output->driver_private; + I830Ptr pI830 = I830PTR(pScrn); + struct _I830DVODriver *drv = intel_output->i2c_drv; + unsigned int dvo_reg = drv->dvo_reg; + CARD32 dvo = INREG(dvo_reg); + DisplayModePtr mode = NULL; + + /* If the DVO port is active, that'll be the LVDS, so we can pull out + * its timings to get how the BIOS set up the panel. + */ + if (dvo & DVO_ENABLE) + { + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + int pipe = (dvo & DVO_PIPE_B_SELECT) ? 1 : 0; + int c; + + for (c = 0; c < xf86_config->num_crtc; c++) + { + xf86CrtcPtr crtc = xf86_config->crtc[c]; + I830CrtcPrivatePtr intel_crtc = crtc->driver_private; + + if (intel_crtc->pipe == pipe) + { + mode = i830_crtc_mode_get(pScrn, crtc); + + if (mode) + { + mode->type |= M_T_PREFERRED; + + if (dvo & DVO_HSYNC_ACTIVE_HIGH) + mode->Flags |= V_PHSYNC; + if (dvo & DVO_VSYNC_ACTIVE_HIGH) + mode->Flags |= V_PVSYNC; + } + break; + } + } + } + return mode; +} + +void +i830_dvo_init(ScrnInfoPtr pScrn) +{ + I830OutputPrivatePtr intel_output; + int ret; + int i; + void *ret_ptr; + struct _I830DVODriver *drv; + int gpio_inited = 0; + I2CBusPtr pI2CBus = NULL; + + intel_output = xnfcalloc (sizeof (I830OutputPrivateRec), 1); + if (!intel_output) + return; + + /* Set up the DDC bus */ + ret = I830I2CInit(pScrn, &intel_output->pDDCBus, GPIOD, "DVODDC_D"); + if (!ret) { + xfree(intel_output); + return; + } + + /* Now, try to find a controller */ + for (i = 0; i < I830_NUM_DVO_DRIVERS; i++) { + int gpio; + + drv = &i830_dvo_drivers[i]; + drv->modhandle = xf86LoadSubModule(pScrn, drv->modulename); + if (drv->modhandle == NULL) + continue; + + xf86LoaderReqSymLists(drv->symbols, NULL); + + ret_ptr = NULL; + drv->vid_rec = LoaderSymbol(drv->fntablename); + + /* Allow the I2C driver info to specify the GPIO to be used in + * special cases, but otherwise default to what's defined in the spec. + */ + if (drv->gpio != 0) + gpio = drv->gpio; + else if (drv->type == I830_OUTPUT_DVO_LVDS) + gpio = GPIOB; + else + gpio = GPIOE; + + /* Set up the I2C bus necessary for the chip we're probing. It appears + * that everything is on GPIOE except for panels on i830 laptops, which + * are on GPIOB (DVOA). + */ + if (gpio_inited != gpio) { + if (pI2CBus != NULL) + xf86DestroyI2CBusRec(pI2CBus, TRUE, TRUE); + if (!I830I2CInit(pScrn, &pI2CBus, gpio, + gpio == GPIOB ? "DVOI2C_B" : "DVOI2C_E")) { + continue; + } + } + + if (drv->vid_rec != NULL) + ret_ptr = drv->vid_rec->init(pI2CBus, drv->address); + + if (ret_ptr != NULL) { + xf86OutputPtr output = NULL; + + intel_output->type = drv->type; + switch (drv->type) { + case I830_OUTPUT_DVO_TMDS: + intel_output->pipe_mask = ((1 << 0) | (1 << 1)); + intel_output->clone_mask = ((1 << I830_OUTPUT_ANALOG) | + (1 << I830_OUTPUT_DVO_TMDS)); + output = xf86OutputCreate(pScrn, &i830_dvo_output_funcs, + "TMDS"); + break; + case I830_OUTPUT_DVO_LVDS: + intel_output->pipe_mask = ((1 << 0) | (1 << 1)); + intel_output->clone_mask = (1 << I830_OUTPUT_DVO_LVDS); + output = xf86OutputCreate(pScrn, &i830_dvo_output_funcs, + "LVDS"); + break; + case I830_OUTPUT_DVO_TVOUT: + intel_output->pipe_mask = ((1 << 0) | (1 << 1)); + intel_output->clone_mask = (1 << I830_OUTPUT_DVO_TVOUT); + output = xf86OutputCreate(pScrn, &i830_dvo_output_funcs, + "TV"); + break; + } + if (output == NULL) { + xf86DestroyI2CBusRec(pI2CBus, TRUE, TRUE); + xf86DestroyI2CBusRec(intel_output->pDDCBus, TRUE, TRUE); + xfree(intel_output); + xf86UnloadSubModule(drv->modhandle); + return; + } + + output->driver_private = intel_output; + output->subpixel_order = SubPixelHorizontalRGB; + output->interlaceAllowed = FALSE; + output->doubleScanAllowed = FALSE; + + drv->dev_priv = ret_ptr; + intel_output->i2c_drv = drv; + intel_output->pI2CBus = pI2CBus; + + if (intel_output->type == I830_OUTPUT_DVO_LVDS) { + /* For our LVDS chipsets, we should hopefully be able to + * dig the fixed panel mode out of the BIOS data. However, + * it's in a different format from the BIOS data on chipsets + * with integrated LVDS (stored in AIM headers, liekly), + * so for now, just get the current mode being output through + * DVO. + */ + drv->panel_fixed_mode = i830_dvo_get_current_mode(output); + drv->panel_wants_dither = TRUE; + } + + return; + } + xf86UnloadSubModule(drv->modhandle); + } + + /* Didn't find a chip, so tear down. */ + if (pI2CBus != NULL) + xf86DestroyI2CBusRec(pI2CBus, TRUE, TRUE); + xf86DestroyI2CBusRec(intel_output->pDDCBus, TRUE, TRUE); + xfree(intel_output); +} diff --git a/driver/xf86-video-intel/src/i830_exa.c b/driver/xf86-video-intel/src/i830_exa.c new file mode 100644 index 000000000..32c55dd0a --- /dev/null +++ b/driver/xf86-video-intel/src/i830_exa.c @@ -0,0 +1,621 @@ +/************************************************************************** + +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +All Rights Reserved. +Copyright (c) 2005 Jesse Barnes <jbarnes@virtuousgeek.org> + Based on code from i830_xaa.c. + +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. + +**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "xf86.h" +#include "xaarop.h" +#include "i830.h" +#include "i810_reg.h" +#include <string.h> + +#ifdef I830DEBUG +#define DEBUG_I830FALLBACK 1 +#endif + +#define ALWAYS_SYNC 0 + +#ifdef DEBUG_I830FALLBACK +#define I830FALLBACK(s, arg...) \ +do { \ + DPRINTF(PFX, "EXA fallback: " s "\n", ##arg); \ + return FALSE; \ +} while(0) +#else +#define I830FALLBACK(s, arg...) \ +do { \ + return FALSE; \ +} while(0) +#endif + +const int I830CopyROP[16] = +{ + ROP_0, /* GXclear */ + ROP_DSa, /* GXand */ + ROP_SDna, /* GXandReverse */ + ROP_S, /* GXcopy */ + ROP_DSna, /* GXandInverted */ + ROP_D, /* GXnoop */ + ROP_DSx, /* GXxor */ + ROP_DSo, /* GXor */ + ROP_DSon, /* GXnor */ + ROP_DSxn, /* GXequiv */ + ROP_Dn, /* GXinvert*/ + ROP_SDno, /* GXorReverse */ + ROP_Sn, /* GXcopyInverted */ + ROP_DSno, /* GXorInverted */ + ROP_DSan, /* GXnand */ + ROP_1 /* GXset */ +}; + +const int I830PatternROP[16] = +{ + ROP_0, + ROP_DPa, + ROP_PDna, + ROP_P, + ROP_DPna, + ROP_D, + ROP_DPx, + ROP_DPo, + ROP_DPon, + ROP_PDxn, + ROP_Dn, + ROP_PDno, + ROP_Pn, + ROP_DPno, + ROP_DPan, + ROP_1 +}; + +/** + * Returns whether a given pixmap is tiled or not. + * + * Currently, we only have one pixmap that might be tiled, which is the front + * buffer. At the point where we are tiling some pixmaps managed by the + * general allocator, we should move this to using pixmap privates. + */ +Bool +i830_pixmap_tiled(PixmapPtr pPixmap) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I830Ptr pI830 = I830PTR(pScrn); + unsigned long offset; + + offset = intel_get_pixmap_offset(pPixmap); + if (offset == pI830->front_buffer->offset && + pI830->front_buffer->tiling != TILE_NONE) + { + return TRUE; + } + + return FALSE; +} + +static Bool +i830_exa_pixmap_is_offscreen(PixmapPtr pPixmap) +{ + ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum]; + I830Ptr pI830 = I830PTR(pScrn); + + if ((void *)pPixmap->devPrivate.ptr >= (void *)pI830->FbBase && + (void *)pPixmap->devPrivate.ptr < + (void *)(pI830->FbBase + pI830->FbMapSize)) + { + return TRUE; + } else { + return FALSE; + } +} + +/** + * I830EXASync - wait for a command to finish + * @pScreen: current screen + * @marker: marker command to wait for + * + * Wait for the command specified by @marker to finish, then return. We don't + * actually do marker waits, though we might in the future. For now, just + * wait for a full idle. + */ +static void +I830EXASync(ScreenPtr pScreen, int marker) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + + I830Sync(pScrn); +} + +/** + * I830EXAPrepareSolid - prepare for a Solid operation, if possible + */ +static Bool +I830EXAPrepareSolid(PixmapPtr pPixmap, int alu, Pixel planemask, Pixel fg) +{ + ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum]; + I830Ptr pI830 = I830PTR(pScrn); + unsigned long offset, pitch; + + if (!EXA_PM_IS_SOLID(&pPixmap->drawable, planemask)) + I830FALLBACK("planemask is not solid"); + + if (pPixmap->drawable.bitsPerPixel == 24) + I830FALLBACK("solid 24bpp unsupported!\n"); + + offset = exaGetPixmapOffset(pPixmap); + pitch = exaGetPixmapPitch(pPixmap); + + if (offset % pI830->EXADriverPtr->pixmapOffsetAlign != 0) + I830FALLBACK("pixmap offset not aligned"); + if (pitch % pI830->EXADriverPtr->pixmapPitchAlign != 0) + I830FALLBACK("pixmap pitch not aligned"); + + pI830->BR[13] = (I830PatternROP[alu] & 0xff) << 16 ; + switch (pPixmap->drawable.bitsPerPixel) { + case 8: + break; + case 16: + /* RGB565 */ + pI830->BR[13] |= (1 << 24); + break; + case 32: + /* RGB8888 */ + pI830->BR[13] |= ((1 << 24) | (1 << 25)); + break; + } + pI830->BR[16] = fg; + return TRUE; +} + +static void +I830EXASolid(PixmapPtr pPixmap, int x1, int y1, int x2, int y2) +{ + ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum]; + I830Ptr pI830 = I830PTR(pScrn); + unsigned long offset, pitch; + uint32_t cmd; + + offset = exaGetPixmapOffset(pPixmap); + pitch = exaGetPixmapPitch(pPixmap); + + { + BEGIN_LP_RING(6); + + cmd = XY_COLOR_BLT_CMD; + + if (pPixmap->drawable.bitsPerPixel == 32) + cmd |= XY_COLOR_BLT_WRITE_ALPHA | XY_COLOR_BLT_WRITE_RGB; + + if (IS_I965G(pI830) && i830_pixmap_tiled(pPixmap)) { + assert((pitch % 512) == 0); + pitch >>= 2; + cmd |= XY_COLOR_BLT_TILED; + } + + OUT_RING(cmd); + + OUT_RING(pI830->BR[13] | pitch); + OUT_RING((y1 << 16) | (x1 & 0xffff)); + OUT_RING((y2 << 16) | (x2 & 0xffff)); + OUT_RING(offset); + OUT_RING(pI830->BR[16]); + ADVANCE_LP_RING(); + } +} + +static void +I830EXADoneSolid(PixmapPtr pPixmap) +{ +#if ALWAYS_SYNC + ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum]; + + I830Sync(pScrn); +#endif +} + +/** + * TODO: + * - support planemask using FULL_BLT_CMD? + */ +static Bool +I830EXAPrepareCopy(PixmapPtr pSrcPixmap, PixmapPtr pDstPixmap, int xdir, + int ydir, int alu, Pixel planemask) +{ + ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum]; + I830Ptr pI830 = I830PTR(pScrn); + + if (!EXA_PM_IS_SOLID(&pSrcPixmap->drawable, planemask)) + I830FALLBACK("planemask is not solid"); + + pI830->pSrcPixmap = pSrcPixmap; + + pI830->BR[13] = I830CopyROP[alu] << 16; + + switch (pSrcPixmap->drawable.bitsPerPixel) { + case 8: + break; + case 16: + pI830->BR[13] |= (1 << 24); + break; + case 32: + pI830->BR[13] |= ((1 << 25) | (1 << 24)); + break; + } + return TRUE; +} + +static void +I830EXACopy(PixmapPtr pDstPixmap, int src_x1, int src_y1, int dst_x1, + int dst_y1, int w, int h) +{ + ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum]; + I830Ptr pI830 = I830PTR(pScrn); + uint32_t cmd; + int dst_x2, dst_y2; + unsigned int dst_off, dst_pitch, src_off, src_pitch; + + dst_x2 = dst_x1 + w; + dst_y2 = dst_y1 + h; + + dst_off = exaGetPixmapOffset(pDstPixmap); + dst_pitch = exaGetPixmapPitch(pDstPixmap); + src_off = exaGetPixmapOffset(pI830->pSrcPixmap); + src_pitch = exaGetPixmapPitch(pI830->pSrcPixmap); + + { + BEGIN_LP_RING(8); + + cmd = XY_SRC_COPY_BLT_CMD; + + if (pDstPixmap->drawable.bitsPerPixel == 32) + cmd |= XY_SRC_COPY_BLT_WRITE_ALPHA | XY_SRC_COPY_BLT_WRITE_RGB; + + if (IS_I965G(pI830)) { + if (i830_pixmap_tiled(pDstPixmap)) { + assert((dst_pitch % 512) == 0); + dst_pitch >>= 2; + cmd |= XY_SRC_COPY_BLT_DST_TILED; + } + + if (i830_pixmap_tiled(pI830->pSrcPixmap)) { + assert((src_pitch % 512) == 0); + src_pitch >>= 2; + cmd |= XY_SRC_COPY_BLT_SRC_TILED; + } + } + + OUT_RING(cmd); + + OUT_RING(pI830->BR[13] | dst_pitch); + OUT_RING((dst_y1 << 16) | (dst_x1 & 0xffff)); + OUT_RING((dst_y2 << 16) | (dst_x2 & 0xffff)); + OUT_RING(dst_off); + OUT_RING((src_y1 << 16) | (src_x1 & 0xffff)); + OUT_RING(src_pitch); + OUT_RING(src_off); + + ADVANCE_LP_RING(); + } +} + +static void +I830EXADoneCopy(PixmapPtr pDstPixmap) +{ +#if ALWAYS_SYNC + ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum]; + + I830Sync(pScrn); +#endif +} + +#define xFixedToFloat(val) \ + ((float)xFixedToInt(val) + ((float)xFixedFrac(val) / 65536.0)) + +/** + * Returns the floating-point coordinates transformed by the given transform. + * + * transform may be null. + */ +void +i830_get_transformed_coordinates(int x, int y, PictTransformPtr transform, + float *x_out, float *y_out) +{ + if (transform == NULL) { + *x_out = x; + *y_out = y; + } else { + PictVector v; + + v.vector[0] = IntToxFixed(x); + v.vector[1] = IntToxFixed(y); + v.vector[2] = xFixed1; + PictureTransformPoint(transform, &v); + *x_out = xFixedToFloat(v.vector[0]); + *y_out = xFixedToFloat(v.vector[1]); + } +} + +/** + * Uploads data from system memory to the framebuffer using a series of + * 8x8 pattern blits. + */ +static Bool +i830_upload_to_screen(PixmapPtr pDst, int x, int y, int w, int h, char *src, + int src_pitch) +{ + ScrnInfoPtr pScrn = xf86Screens[pDst->drawable.pScreen->myNum]; + I830Ptr pI830 = I830PTR(pScrn); + const int uts_width_max = 16, uts_height_max = 16; + int cpp = pDst->drawable.bitsPerPixel / 8; + int sub_x, sub_y; + CARD32 br13; + CARD32 offset; + + if (w > uts_width_max || h > uts_height_max) + I830FALLBACK("too large for upload to screen (%d,%d)", w, h); + + offset = exaGetPixmapOffset(pDst); + + br13 = exaGetPixmapPitch(pDst); + br13 |= ((I830PatternROP[GXcopy] & 0xff) << 16); + switch (pDst->drawable.bitsPerPixel) { + case 16: + br13 |= 1 << 24; + break; + case 32: + br13 |= 3 << 24; + break; + } + + for (sub_y = 0; sub_y < uts_height_max && sub_y < h; sub_y += 8) { + int sub_height; + + if (sub_y + 8 > h) + sub_height = h - sub_y; + else + sub_height = 8; + + for (sub_x = 0; sub_x < uts_width_max && sub_x < w; sub_x += 8) { + int sub_width, line; + char *src_line = src + sub_y * src_pitch + sub_x * cpp; + + if (sub_x + 8 > w) + sub_width = w - sub_x; + else + sub_width = 8; + + BEGIN_LP_RING(6 + (cpp * 8 * 8 / 4)); + + /* XXX We may need a pattern offset here for {x,y} % 8 != 0*/ + OUT_RING(XY_PAT_BLT_IMMEDIATE | + XY_SRC_COPY_BLT_WRITE_ALPHA | + XY_SRC_COPY_BLT_WRITE_RGB | + (3 + cpp * 8 * 8 / 4)); + OUT_RING(br13); + OUT_RING(((y + sub_y) << 16) | (x + sub_x)); + OUT_RING(((y + sub_y + sub_height) << 16) | + (x + sub_x + sub_width)); + OUT_RING(offset); + + /* Write out the lines with valid data, followed by any needed + * padding + */ + for (line = 0; line < sub_height; line++) { + OUT_RING_COPY(sub_width * cpp, src_line); + src_line += src_pitch; + if (sub_width != 8) + OUT_RING_PAD((8 - sub_width) * cpp); + } + /* Write out any full padding lines to follow */ + if (sub_height != 8) + OUT_RING_PAD(8 * cpp * (8 - sub_height)); + + OUT_RING(MI_NOOP); + ADVANCE_LP_RING(); + } + } + + exaMarkSync(pDst->drawable.pScreen); + /* exaWaitSync(pDst->drawable.pScreen); */ + + return TRUE; +} + + +/* + * TODO: + * - Dual head? + */ +Bool +I830EXAInit(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I830Ptr pI830 = I830PTR(pScrn); + + pI830->EXADriverPtr = exaDriverAlloc(); + if (pI830->EXADriverPtr == NULL) { + pI830->noAccel = TRUE; + return FALSE; + } + memset(pI830->EXADriverPtr, 0, sizeof(*pI830->EXADriverPtr)); + + pI830->bufferOffset = 0; + pI830->EXADriverPtr->exa_major = 2; + /* If compiled against EXA 2.2, require 2.2 so we can use the + * PixmapIsOffscreen hook. + */ +#if EXA_VERSION_MINOR >= 2 + pI830->EXADriverPtr->exa_minor = 2; +#else + pI830->EXADriverPtr->exa_minor = 1; + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "EXA compatibility mode. Output rotation rendering " + "performance may suffer\n"); +#endif + pI830->EXADriverPtr->memoryBase = pI830->FbBase; + if (pI830->exa_offscreen) { + pI830->EXADriverPtr->offScreenBase = pI830->exa_offscreen->offset; + pI830->EXADriverPtr->memorySize = pI830->exa_offscreen->offset + + pI830->exa_offscreen->size; + } else { + pI830->EXADriverPtr->offScreenBase = pI830->FbMapSize; + pI830->EXADriverPtr->memorySize = pI830->FbMapSize; + } + pI830->EXADriverPtr->flags = EXA_OFFSCREEN_PIXMAPS; + + DPRINTF(PFX, "EXA Mem: memoryBase 0x%x, end 0x%x, offscreen base 0x%x, " + "memorySize 0x%x\n", + pI830->EXADriverPtr->memoryBase, + pI830->EXADriverPtr->memoryBase + pI830->EXADriverPtr->memorySize, + pI830->EXADriverPtr->offScreenBase, + pI830->EXADriverPtr->memorySize); + + + /* Limits are described in the BLT engine chapter under Graphics Data Size + * Limitations, and the descriptions of SURFACE_STATE, 3DSTATE_BUFFER_INFO, + * 3DSTATE_DRAWING_RECTANGLE, 3DSTATE_MAP_INFO, and 3DSTATE_MAP_INFO. + * + * i845 through i965 limits 2D rendering to 65536 lines and pitch of 32768. + * + * i965 limits 3D surface to (2*element size)-aligned offset if un-tiled. + * i965 limits 3D surface to 4kB-aligned offset if tiled. + * i965 limits 3D surfaces to w,h of ?,8192. + * i965 limits 3D surface to pitch of 1B - 128kB. + * i965 limits 3D surface pitch alignment to 1 or 2 times the element size. + * i965 limits 3D surface pitch alignment to 512B if tiled. + * i965 limits 3D destination drawing rect to w,h of 8192,8192. + * + * i915 limits 3D textures to 4B-aligned offset if un-tiled. + * i915 limits 3D textures to ~4kB-aligned offset if tiled. + * i915 limits 3D textures to width,height of 2048,2048. + * i915 limits 3D textures to pitch of 16B - 8kB, in dwords. + * i915 limits 3D destination to ~4kB-aligned offset if tiled. + * i915 limits 3D destination to pitch of 16B - 8kB, in dwords, if un-tiled. + * i915 limits 3D destination to pitch of 512B - 8kB, in tiles, if tiled. + * i915 limits 3D destination to POT aligned pitch if tiled. + * i915 limits 3D destination drawing rect to w,h of 2048,2048. + * + * i845 limits 3D textures to 4B-aligned offset if un-tiled. + * i845 limits 3D textures to ~4kB-aligned offset if tiled. + * i845 limits 3D textures to width,height of 2048,2048. + * i845 limits 3D textures to pitch of 4B - 8kB, in dwords. + * i845 limits 3D destination to 4B-aligned offset if un-tiled. + * i845 limits 3D destination to ~4kB-aligned offset if tiled. + * i845 limits 3D destination to pitch of 8B - 8kB, in dwords. + * i845 limits 3D destination drawing rect to w,h of 2048,2048. + * + * For the tiled issues, the only tiled buffer we draw to should be + * the front, which will have an appropriate pitch/offset already set up, + * so EXA doesn't need to worry. + */ + if (IS_I965G(pI830)) { + pI830->EXADriverPtr->pixmapOffsetAlign = 4 * 2; + pI830->EXADriverPtr->pixmapPitchAlign = 16; + pI830->EXADriverPtr->maxX = 8192; + pI830->EXADriverPtr->maxY = 8192; + } else { + pI830->EXADriverPtr->pixmapOffsetAlign = 4; + pI830->EXADriverPtr->pixmapPitchAlign = 16; + pI830->EXADriverPtr->maxX = 2048; + pI830->EXADriverPtr->maxY = 2048; + } + + /* Sync */ + pI830->EXADriverPtr->WaitMarker = I830EXASync; + + /* Solid fill */ + pI830->EXADriverPtr->PrepareSolid = I830EXAPrepareSolid; + pI830->EXADriverPtr->Solid = I830EXASolid; + pI830->EXADriverPtr->DoneSolid = I830EXADoneSolid; + + /* Copy */ + pI830->EXADriverPtr->PrepareCopy = I830EXAPrepareCopy; + pI830->EXADriverPtr->Copy = I830EXACopy; + pI830->EXADriverPtr->DoneCopy = I830EXADoneCopy; + + /* Composite */ + if (!IS_I9XX(pI830)) { + pI830->EXADriverPtr->CheckComposite = i830_check_composite; + pI830->EXADriverPtr->PrepareComposite = i830_prepare_composite; + pI830->EXADriverPtr->Composite = i830_composite; + pI830->EXADriverPtr->DoneComposite = i830_done_composite; + } else if (IS_I915G(pI830) || IS_I915GM(pI830) || + IS_I945G(pI830) || IS_I945GM(pI830) || IS_G33CLASS(pI830)) + { + pI830->EXADriverPtr->CheckComposite = i915_check_composite; + pI830->EXADriverPtr->PrepareComposite = i915_prepare_composite; + pI830->EXADriverPtr->Composite = i830_composite; + pI830->EXADriverPtr->DoneComposite = i830_done_composite; + } else { + pI830->EXADriverPtr->CheckComposite = i965_check_composite; + pI830->EXADriverPtr->PrepareComposite = i965_prepare_composite; + pI830->EXADriverPtr->Composite = i965_composite; + pI830->EXADriverPtr->DoneComposite = i830_done_composite; + } +#if EXA_VERSION_MINOR >= 2 + pI830->EXADriverPtr->PixmapIsOffscreen = i830_exa_pixmap_is_offscreen; +#endif + + /* UploadToScreen/DownloadFromScreen */ + if (0) + pI830->EXADriverPtr->UploadToScreen = i830_upload_to_screen; + + if(!exaDriverInit(pScreen, pI830->EXADriverPtr)) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "EXA initialization failed; trying older version\n"); + pI830->EXADriverPtr->exa_minor = 0; + if(!exaDriverInit(pScreen, pI830->EXADriverPtr)) { + xfree(pI830->EXADriverPtr); + pI830->noAccel = TRUE; + return FALSE; + } + } + + I830SelectBuffer(pScrn, I830_SELECT_FRONT); + + return TRUE; +} + +#ifdef XF86DRI + +#ifndef ExaOffscreenMarkUsed +extern void ExaOffscreenMarkUsed(PixmapPtr); +#endif + +unsigned long long +I830TexOffsetStart(PixmapPtr pPix) +{ + exaMoveInPixmap(pPix); + ExaOffscreenMarkUsed(pPix); + + return exaGetPixmapOffset(pPix); +} +#endif diff --git a/driver/xf86-video-intel/src/i830_i2c.c b/driver/xf86-video-intel/src/i830_i2c.c new file mode 100644 index 000000000..da8f38e63 --- /dev/null +++ b/driver/xf86-video-intel/src/i830_i2c.c @@ -0,0 +1,387 @@ +/************************************************************************** + + Copyright 2006 Dave Airlie <airlied@linux.ie> + +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. + +**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "xf86.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 "shadowfb.h" +#include <X11/extensions/randr.h> +#include "fb.h" +#include "miscstruct.h" +#include "xf86xv.h" +#include <X11/extensions/Xv.h> +#include "shadow.h" +#include "i830.h" + +#define AIRLIED_I2C 0 + +#if AIRLIED_I2C + +#define I2C_TIMEOUT(x) /*(x)*/ /* Report timeouts */ +#define I2C_TRACE(x) /*(x)*/ /* Report progress */ + +static void i830_setscl(I2CBusPtr b, int state) +{ + ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex]; + I830Ptr pI830 = I830PTR(pScrn); + CARD32 val; + + OUTREG(b->DriverPrivate.uval, + (state ? GPIO_CLOCK_VAL_OUT : 0) | GPIO_CLOCK_DIR_OUT | + GPIO_CLOCK_DIR_MASK | GPIO_CLOCK_VAL_MASK); + val = INREG(b->DriverPrivate.uval); +} + +static void i830_setsda(I2CBusPtr b, int state) +{ + ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex]; + I830Ptr pI830 = I830PTR(pScrn); + CARD32 val; + + OUTREG(b->DriverPrivate.uval, + (state ? GPIO_DATA_VAL_OUT : 0) | GPIO_DATA_DIR_OUT | + GPIO_DATA_DIR_MASK | GPIO_DATA_VAL_MASK); + val = INREG(b->DriverPrivate.uval); +} + +static void i830_getscl(I2CBusPtr b, int *state) +{ + ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex]; + I830Ptr pI830 = I830PTR(pScrn); + CARD32 val; + + OUTREG(b->DriverPrivate.uval, GPIO_CLOCK_DIR_IN | GPIO_CLOCK_DIR_MASK); + OUTREG(b->DriverPrivate.uval, 0); + val = INREG(b->DriverPrivate.uval); + *state = ((val & GPIO_DATA_VAL_IN) != 0); +} + +static int i830_getsda(I2CBusPtr b) + { + ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex]; + I830Ptr pI830 = I830PTR(pScrn); + CARD32 val; + + OUTREG(b->DriverPrivate.uval, GPIO_DATA_DIR_IN | GPIO_DATA_DIR_MASK); + OUTREG(b->DriverPrivate.uval, 0); + val = INREG(b->DriverPrivate.uval); + return ((val & GPIO_DATA_VAL_IN) != 0); +} + +static inline void sdalo(I2CBusPtr b) +{ + i830_setsda(b, 0); + b->I2CUDelay(b, b->RiseFallTime); +} + +static inline void sdahi(I2CBusPtr b) +{ + i830_setsda(b, 1); + b->I2CUDelay(b, b->RiseFallTime); +} + +static inline void scllo(I2CBusPtr b) +{ + i830_setscl(b, 0); + b->I2CUDelay(b, b->RiseFallTime); +} + +static inline int sclhi(I2CBusPtr b, int timeout) +{ + int scl = 0; + int i; + + i830_setscl(b, 1); + b->I2CUDelay(b, b->RiseFallTime); + + for (i = timeout; i > 0; i -= b->RiseFallTime) { + i830_getscl(b, &scl); + if (scl) break; + b->I2CUDelay(b, b->RiseFallTime); + } + + if (i <= 0) { + I2C_TIMEOUT(ErrorF("[I2CRaiseSCL(<%s>, %d) timeout]", + b->BusName, timeout)); + return FALSE; + } + return TRUE; +} + +static Bool +I830I2CGetByte(I2CDevPtr d, I2CByte *data, Bool last) +{ + I2CBusPtr b = d->pI2CBus; + int i, sda; + unsigned char indata = 0; + + sdahi(b); + + for (i = 0; i < 8; i++) { + if (sclhi(b, d->BitTimeout) == FALSE) { + I2C_TRACE(ErrorF("timeout at bit #%d\n", 7-i)); + return FALSE; + }; + indata *= 2; + if (i830_getsda(b)) + indata |= 0x01; + scllo(b); + } + + if (last) { + sdahi(b); + } else { + sdalo(b); + } + + if (sclhi(b, d->BitTimeout) == FALSE) { + sdahi(b); + return FALSE; + }; + + scllo(b); + sdahi(b); + + *data = indata & 0xff; + I2C_TRACE(ErrorF("R%02x ", (int) *data)); + + return TRUE; +} + +static Bool +I830I2CPutByte(I2CDevPtr d, I2CByte c) +{ + Bool r; + int i, scl, sda; + int sb, ack; + I2CBusPtr b = d->pI2CBus; + + for (i = 7; i >= 0; i--) { + sb = c & (1 << i); + i830_setsda(b, sb); + b->I2CUDelay(b, b->RiseFallTime); + + if (sclhi(b, d->ByteTimeout) == FALSE) { + sdahi(b); + return FALSE; + } + + i830_setscl(b, 0); + b->I2CUDelay(b, b->RiseFallTime); + } + sdahi(b); + if (sclhi(b, d->ByteTimeout) == FALSE) { + I2C_TIMEOUT(ErrorF("[I2CPutByte(<%s>, 0x%02x, %d, %d, %d) timeout]", + b->BusName, c, d->BitTimeout, + d->ByteTimeout, d->AcknTimeout)); + return FALSE; + } + ack = i830_getsda(b); + I2C_TRACE(ErrorF("Put byte 0x%02x , getsda() = %d\n", c & 0xff, ack)); + + scllo(b); + return (0 == ack); +} + +static Bool +I830I2CStart(I2CBusPtr b, int timeout) +{ + if (sclhi(b, timeout) == FALSE) + return FALSE; + + sdalo(b); + scllo(b); + + return TRUE; +} + +static void +I830I2CStop(I2CDevPtr d) +{ + I2CBusPtr b = d->pI2CBus; + + sdalo(b); + sclhi(b, d->ByteTimeout); + sdahi(b); +} + +static Bool +I830I2CAddress(I2CDevPtr d, I2CSlaveAddr addr) +{ + if (I830I2CStart(d->pI2CBus, d->StartTimeout)) { + if (I830I2CPutByte(d, addr & 0xFF)) { + if ((addr & 0xF8) != 0xF0 && + (addr & 0xFE) != 0x00) + return TRUE; + + if (I830I2CPutByte(d, (addr >> 8) & 0xFF)) + return TRUE; + } + + I830I2CStop(d); + } + + return FALSE; +} + +#else + +#define I2C_DEBUG 0 + +#if I2C_DEBUG +static Bool first = TRUE; +#endif + +static void +i830I2CGetBits(I2CBusPtr b, int *clock, int *data) +{ + ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex]; + I830Ptr pI830 = I830PTR(pScrn); + CARD32 val; + + val = INREG(b->DriverPrivate.uval); + + /* + * to read valid data, we must have written a 1 to + * the associated bit. Writing a 1 is done by + * tri-stating the bus in PutBits, so we needn't make + * sure that is true here + */ + *data = (val & GPIO_DATA_VAL_IN) != 0; + *clock = (val & GPIO_CLOCK_VAL_IN) != 0; + +#if I2C_DEBUG + ErrorF("Getting %s: %c %c\n", b->BusName, + *clock ? '^' : 'v', + *data ? '^' : 'v'); +#endif +} + +static void +i830I2CPutBits(I2CBusPtr b, int clock, int data) +{ + CARD32 reserved = 0; + CARD32 data_bits, clock_bits; + +#if I2C_DEBUG + int cur_clock, cur_data; +#endif + + ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex]; + I830Ptr pI830 = I830PTR(pScrn); + +#if I2C_DEBUG + i830I2CGetBits(b, &cur_clock, &cur_data); + + if (first) { + ErrorF("%s Debug: C D C D\n", b->BusName); + first = FALSE; + } + + ErrorF("Setting %s 0x%08x to: %c %c\n", b->BusName, + (int)b->DriverPrivate.uval, + clock ? '^' : 'v', + data ? '^' : 'v'); +#endif + + if (!IS_I830(pI830) && !IS_845G(pI830)) { + /* On most chips, these bits must be preserved in software. */ + reserved = INREG(b->DriverPrivate.uval) & + (GPIO_DATA_PULLUP_DISABLE | GPIO_CLOCK_PULLUP_DISABLE); + } + + /* data or clock == 1 means to tristate the bus. otherwise, drive it low */ + if (data) + data_bits = GPIO_DATA_DIR_IN|GPIO_DATA_DIR_MASK; + else + data_bits = GPIO_DATA_DIR_OUT|GPIO_DATA_DIR_MASK|GPIO_DATA_VAL_MASK; + if (clock) + clock_bits = GPIO_CLOCK_DIR_IN|GPIO_CLOCK_DIR_MASK; + else + clock_bits = GPIO_CLOCK_DIR_OUT|GPIO_CLOCK_DIR_MASK|GPIO_CLOCK_VAL_MASK; + + OUTREG(b->DriverPrivate.uval, reserved | data_bits | clock_bits); + POSTING_READ(b->DriverPrivate.uval); +} + +#endif + +/* the i830 has a number of I2C Buses */ +Bool +I830I2CInit(ScrnInfoPtr pScrn, I2CBusPtr *bus_ptr, int i2c_reg, char *name) +{ + I2CBusPtr pI2CBus; + + pI2CBus = xf86CreateI2CBusRec(); + + if (!pI2CBus) + return FALSE; + + pI2CBus->BusName = name; + pI2CBus->scrnIndex = pScrn->scrnIndex; +#if AIRLIED_I2C + pI2CBus->I2CGetByte = I830I2CGetByte; + pI2CBus->I2CPutByte = I830I2CPutByte; + pI2CBus->I2CStart = I830I2CStart; + pI2CBus->I2CStop = I830I2CStop; + pI2CBus->I2CAddress = I830I2CAddress; +#else + pI2CBus->I2CGetBits = i830I2CGetBits; + pI2CBus->I2CPutBits = i830I2CPutBits; +#endif + pI2CBus->DriverPrivate.uval = i2c_reg; + + /* Assume all busses are used for DDCish stuff */ + + /* + * These were set incorrectly in the server pre-1.3, Having + * duplicate settings is sub-optimal, but this lets the driver + * work with older servers + */ + pI2CBus->ByteTimeout = 2200; /* VESA DDC spec 3 p. 43 (+10 %) */ + pI2CBus->StartTimeout = 550; + pI2CBus->BitTimeout = 40; + pI2CBus->AcknTimeout = 40; + pI2CBus->RiseFallTime = 20; + + if (!xf86I2CBusInit(pI2CBus)) + return FALSE; + + *bus_ptr = pI2CBus; + return TRUE; +} diff --git a/driver/xf86-video-intel/src/i830_lvds.c b/driver/xf86-video-intel/src/i830_lvds.c new file mode 100644 index 000000000..a3a56f7b1 --- /dev/null +++ b/driver/xf86-video-intel/src/i830_lvds.c @@ -0,0 +1,1025 @@ +/* + * Copyright © 2006 Intel Corporation + * + * 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 + * THE AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include "xf86.h" +#include "i830.h" +#include "i830_bios.h" +#include "i830_display.h" +#include "X11/Xatom.h" + +struct i830_lvds_priv { + /* The BIOS's fixed timings for the LVDS */ + DisplayModePtr panel_fixed_mode; + + /* The panel needs dithering enabled */ + Bool panel_wants_dither; + + /* restore backlight to this value */ + int backlight_duty_cycle; + + void (*set_backlight)(xf86OutputPtr output, int level); + int (*get_backlight)(xf86OutputPtr output); + int backlight_max; +}; + +#define BACKLIGHT_CLASS "/sys/class/backlight" + +/* + * List of available kernel interfaces in priority order + */ +static char *backlight_interfaces[] = { + "thinkpad_screen", + "acpi_video1", + "acpi_video0", + NULL, +}; + +/* + * Must be long enough for BACKLIGHT_CLASS + '/' + longest in above table + + * '/' + "max_backlight" + */ +#define BACKLIGHT_PATH_LEN 80 +/* Enough for 8 digits of backlight + '\n' + '\0' */ +#define BACKLIGHT_VALUE_LEN 10 + +static int backlight_index; + +static Bool +i830_kernel_backlight_available(xf86OutputPtr output) +{ + ScrnInfoPtr pScrn = output->scrn; + struct stat buf; + char path[BACKLIGHT_PATH_LEN]; + int i; + + for (i = 0; backlight_interfaces[i] != NULL; i++) { + sprintf(path, "%s/%s", BACKLIGHT_CLASS, backlight_interfaces[i]); + if (!stat(path, &buf)) { + backlight_index = i; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "found backlight control " + "method %s\n", path); + return 1; + } + } + + return 0; +} + +/* Try to figure out which backlight control method to use */ +static void +i830_set_lvds_backlight_method(xf86OutputPtr output) +{ + ScrnInfoPtr pScrn = output->scrn; + I830Ptr pI830 = I830PTR(pScrn); + CARD32 blc_pwm_ctl, blc_pwm_ctl2; + enum backlight_control method = NATIVE; /* Default to native */ + + if (i830_kernel_backlight_available(output)) { + method = KERNEL; + } else if (IS_I965GM(pI830)) { + blc_pwm_ctl2 = INREG(BLC_PWM_CTL2); + if (blc_pwm_ctl2 & BLM_LEGACY_MODE2) + method = COMBO; + } else { + blc_pwm_ctl = INREG(BLC_PWM_CTL); + if (blc_pwm_ctl & BLM_LEGACY_MODE) + method = COMBO; + } + + pI830->backlight_control_method = method; +} + +/* + * Native methods + */ +static void +i830_lvds_set_backlight_native(xf86OutputPtr output, int level) +{ + ScrnInfoPtr pScrn = output->scrn; + I830Ptr pI830 = I830PTR(pScrn); + CARD32 blc_pwm_ctl; + + blc_pwm_ctl = INREG(BLC_PWM_CTL); + blc_pwm_ctl &= ~BACKLIGHT_DUTY_CYCLE_MASK; + OUTREG(BLC_PWM_CTL, blc_pwm_ctl | (level << BACKLIGHT_DUTY_CYCLE_SHIFT)); +} + +static int +i830_lvds_get_backlight_native(xf86OutputPtr output) +{ + ScrnInfoPtr pScrn = output->scrn; + I830Ptr pI830 = I830PTR(pScrn); + CARD32 blc_pwm_ctl; + + blc_pwm_ctl = INREG(BLC_PWM_CTL); + blc_pwm_ctl &= BACKLIGHT_DUTY_CYCLE_MASK; + return blc_pwm_ctl; +} + +static int +i830_lvds_get_backlight_max_native(xf86OutputPtr output) +{ + ScrnInfoPtr pScrn = output->scrn; + I830Ptr pI830 = I830PTR(pScrn); + CARD32 pwm_ctl = INREG(BLC_PWM_CTL); + int val; + + if (IS_I965GM(pI830)) { + val = ((pwm_ctl & BACKLIGHT_MODULATION_FREQ_MASK2) >> + BACKLIGHT_MODULATION_FREQ_SHIFT2); + } else { + val = ((pwm_ctl & BACKLIGHT_MODULATION_FREQ_MASK) >> + BACKLIGHT_MODULATION_FREQ_SHIFT) * 2; + } + + return val; +} + +/* + * Legacy methods + */ +static void +i830_lvds_set_backlight_legacy(xf86OutputPtr output, int level) +{ + ScrnInfoPtr pScrn = output->scrn; + I830Ptr pI830 = I830PTR(pScrn); + +#if XSERVER_LIBPCIACCESS + pci_device_cfg_write_u8(pI830->PciInfo, level, + LEGACY_BACKLIGHT_BRIGHTNESS); +#else + pciWriteByte(pI830->PciTag, LEGACY_BACKLIGHT_BRIGHTNESS, level); +#endif +} + +static int +i830_lvds_get_backlight_legacy(xf86OutputPtr output) +{ + ScrnInfoPtr pScrn = output->scrn; + I830Ptr pI830 = I830PTR(pScrn); + CARD8 lbb; + +#if XSERVER_LIBPCIACCESS + pci_device_cfg_read_u8(pI830->PciInfo, &lbb, LEGACY_BACKLIGHT_BRIGHTNESS); +#else + lbb = pciReadByte(pI830->PciTag, LEGACY_BACKLIGHT_BRIGHTNESS); +#endif + + return lbb; +} + +/* + * Combo methods + */ +static void +i830_lvds_set_backlight_combo(xf86OutputPtr output, int level) +{ + ScrnInfoPtr pScrn = output->scrn; + I830Ptr pI830 = I830PTR(pScrn); + CARD32 blc_pwm_ctl; + CARD8 lbb; + +#if XSERVER_LIBPCIACCESS + pci_device_cfg_read_u8(pI830->PciInfo, &lbb, LEGACY_BACKLIGHT_BRIGHTNESS); +#else + lbb = pciReadByte(pI830->PciTag, LEGACY_BACKLIGHT_BRIGHTNESS); +#endif + /* + * If LBB is zero and we're shooting for a non-zero brightness level, + * we have to increase LBB by at least 1. + */ + if (!lbb && level) { +#if XSERVER_LIBPCIACCESS + pci_device_cfg_write_u8(pI830->PciInfo, 1, + LEGACY_BACKLIGHT_BRIGHTNESS); +#else + pciWriteByte(pI830->PciTag, LEGACY_BACKLIGHT_BRIGHTNESS, 1); +#endif + } + + blc_pwm_ctl = INREG(BLC_PWM_CTL); + blc_pwm_ctl &= ~BACKLIGHT_DUTY_CYCLE_MASK; + OUTREG(BLC_PWM_CTL, blc_pwm_ctl | (level << BACKLIGHT_DUTY_CYCLE_SHIFT)); +} + +static int +i830_lvds_get_backlight_combo(xf86OutputPtr output) +{ + ScrnInfoPtr pScrn = output->scrn; + I830Ptr pI830 = I830PTR(pScrn); + CARD32 blc_pwm_ctl; + + blc_pwm_ctl = INREG(BLC_PWM_CTL); + blc_pwm_ctl &= BACKLIGHT_DUTY_CYCLE_MASK; + return blc_pwm_ctl; +} + +/* + * Kernel methods + */ +static void +i830_lvds_set_backlight_kernel(xf86OutputPtr output, int level) +{ + ScrnInfoPtr pScrn = output->scrn; + char path[BACKLIGHT_PATH_LEN], val[BACKLIGHT_VALUE_LEN]; + int fd, len, ret; + + len = snprintf(val, BACKLIGHT_VALUE_LEN, "%d\n", level); + if (len > BACKLIGHT_VALUE_LEN) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "backlight value too large: %d\n", + level); + return; + } + + sprintf(path, "%s/%s/brightness", BACKLIGHT_CLASS, + backlight_interfaces[backlight_index]); + fd = open(path, O_RDWR); + if (fd == -1) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "failed to open %s for backlight " + "control: %s\n", path, strerror(errno)); + return; + } + + ret = write(fd, val, len); + if (ret == -1) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "write to %s for backlight " + "control failed: %s\n", path, strerror(errno)); + } + + close(fd); +} + +static int +i830_lvds_get_backlight_kernel(xf86OutputPtr output) +{ + ScrnInfoPtr pScrn = output->scrn; + char path[BACKLIGHT_PATH_LEN], val[BACKLIGHT_VALUE_LEN]; + int fd; + + sprintf(path, "%s/%s/actual_brightness", BACKLIGHT_CLASS, + backlight_interfaces[backlight_index]); + fd = open(path, O_RDONLY); + if (fd == -1) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "failed to open %s for backlight " + "control: %s\n", path, strerror(errno)); + return 0; + } + + if (read(fd, val, BACKLIGHT_VALUE_LEN) == -1) + goto out_err; + + close(fd); + return atoi(val); + +out_err: + close(fd); + return 0; +} + +static int +i830_lvds_get_backlight_max_kernel(xf86OutputPtr output) +{ + ScrnInfoPtr pScrn = output->scrn; + char path[BACKLIGHT_PATH_LEN], val[BACKLIGHT_VALUE_LEN]; + int fd, max = 0; + + sprintf(path, "%s/%s/max_brightness", BACKLIGHT_CLASS, + backlight_interfaces[backlight_index]); + fd = open(path, O_RDONLY); + if (fd == -1) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "failed to open %s for backlight " + "control: %s\n", path, strerror(errno)); + return 0; + } + + if (read(fd, val, BACKLIGHT_VALUE_LEN) == -1) + goto out_err; + + close(fd); + + max = atoi(val); + + return max; + +out_err: + close(fd); + return 0; +} + +/** + * Sets the power state for the panel. + */ +static void +i830SetLVDSPanelPower(xf86OutputPtr output, Bool on) +{ + I830OutputPrivatePtr intel_output = output->driver_private; + struct i830_lvds_priv *dev_priv = intel_output->dev_priv; + ScrnInfoPtr pScrn = output->scrn; + I830Ptr pI830 = I830PTR(pScrn); + CARD32 pp_status; + + if (on) { + OUTREG(PP_CONTROL, INREG(PP_CONTROL) | POWER_TARGET_ON); + do { + pp_status = INREG(PP_STATUS); + } while ((pp_status & PP_ON) == 0); + + dev_priv->set_backlight(output, dev_priv->backlight_duty_cycle); + } else { + dev_priv->set_backlight(output, 0); + + OUTREG(PP_CONTROL, INREG(PP_CONTROL) & ~POWER_TARGET_ON); + do { + pp_status = INREG(PP_STATUS); + } while (pp_status & PP_ON); + } +} + +static void +i830_lvds_dpms (xf86OutputPtr output, int mode) +{ + if (mode == DPMSModeOn) + i830SetLVDSPanelPower(output, TRUE); + else + i830SetLVDSPanelPower(output, FALSE); + + /* XXX: We never power down the LVDS pairs. */ +} + +static void +i830_lvds_save (xf86OutputPtr output) +{ + I830OutputPrivatePtr intel_output = output->driver_private; + struct i830_lvds_priv *dev_priv = intel_output->dev_priv; + ScrnInfoPtr pScrn = output->scrn; + I830Ptr pI830 = I830PTR(pScrn); + + if (IS_I965GM(pI830)) + pI830->saveBLC_PWM_CTL2 = INREG(BLC_PWM_CTL2); + pI830->savePP_ON = INREG(LVDSPP_ON); + pI830->savePP_OFF = INREG(LVDSPP_OFF); + pI830->savePP_CONTROL = INREG(PP_CONTROL); + pI830->savePP_CYCLE = INREG(PP_CYCLE); + pI830->saveBLC_PWM_CTL = INREG(BLC_PWM_CTL); + dev_priv->backlight_duty_cycle = dev_priv->get_backlight(output); + + /* + * If the light is off at server startup, just make it full brightness + */ + if (dev_priv->backlight_duty_cycle == 0) + dev_priv->backlight_duty_cycle = dev_priv->backlight_max; +} + +static void +i830_lvds_restore(xf86OutputPtr output) +{ + ScrnInfoPtr pScrn = output->scrn; + I830Ptr pI830 = I830PTR(pScrn); + + if (IS_I965GM(pI830)) + OUTREG(BLC_PWM_CTL2, pI830->saveBLC_PWM_CTL2); + OUTREG(BLC_PWM_CTL, pI830->saveBLC_PWM_CTL); + OUTREG(LVDSPP_ON, pI830->savePP_ON); + OUTREG(LVDSPP_OFF, pI830->savePP_OFF); + OUTREG(PP_CYCLE, pI830->savePP_CYCLE); + OUTREG(PP_CONTROL, pI830->savePP_CONTROL); + if (pI830->savePP_CONTROL & POWER_TARGET_ON) + i830SetLVDSPanelPower(output, TRUE); + else + i830SetLVDSPanelPower(output, FALSE); +} + +static int +i830_lvds_mode_valid(xf86OutputPtr output, DisplayModePtr pMode) +{ + I830OutputPrivatePtr intel_output = output->driver_private; + struct i830_lvds_priv *dev_priv = intel_output->dev_priv; + DisplayModePtr pFixedMode = dev_priv->panel_fixed_mode; + + if (pFixedMode) + { + if (pMode->HDisplay > pFixedMode->HDisplay) + return MODE_PANEL; + if (pMode->VDisplay > pFixedMode->VDisplay) + return MODE_PANEL; + } + + return MODE_OK; +} + +static Bool +i830_lvds_mode_fixup(xf86OutputPtr output, DisplayModePtr mode, + DisplayModePtr adjusted_mode) +{ + I830OutputPrivatePtr intel_output = output->driver_private; + struct i830_lvds_priv *dev_priv = intel_output->dev_priv; + ScrnInfoPtr pScrn = output->scrn; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + I830CrtcPrivatePtr intel_crtc = output->crtc->driver_private; + int i; + + for (i = 0; i < xf86_config->num_output; i++) { + xf86OutputPtr other_output = xf86_config->output[i]; + + if (other_output != output && other_output->crtc == output->crtc) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Can't enable LVDS and another output on the same " + "pipe\n"); + return FALSE; + } + } + + if (intel_crtc->pipe == 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Can't support LVDS on pipe A\n"); + return FALSE; + } + + /* If we have timings from the BIOS for the panel, put them in + * to the adjusted mode. The CRTC will be set up for this mode, + * with the panel scaling set up to source from the H/VDisplay + * of the original mode. + */ + if (dev_priv->panel_fixed_mode != NULL) { + adjusted_mode->HDisplay = dev_priv->panel_fixed_mode->HDisplay; + adjusted_mode->HSyncStart = dev_priv->panel_fixed_mode->HSyncStart; + adjusted_mode->HSyncEnd = dev_priv->panel_fixed_mode->HSyncEnd; + adjusted_mode->HTotal = dev_priv->panel_fixed_mode->HTotal; + adjusted_mode->VDisplay = dev_priv->panel_fixed_mode->VDisplay; + adjusted_mode->VSyncStart = dev_priv->panel_fixed_mode->VSyncStart; + adjusted_mode->VSyncEnd = dev_priv->panel_fixed_mode->VSyncEnd; + adjusted_mode->VTotal = dev_priv->panel_fixed_mode->VTotal; + adjusted_mode->Clock = dev_priv->panel_fixed_mode->Clock; + xf86SetModeCrtc(adjusted_mode, INTERLACE_HALVE_V); + } + + /* XXX: It would be nice to support lower refresh rates on the + * panels to reduce power consumption, and perhaps match the + * user's requested refresh rate. + */ + + return TRUE; +} + +static void +i830_lvds_mode_set(xf86OutputPtr output, DisplayModePtr mode, + DisplayModePtr adjusted_mode) +{ + I830OutputPrivatePtr intel_output = output->driver_private; + struct i830_lvds_priv *dev_priv = intel_output->dev_priv; + ScrnInfoPtr pScrn = output->scrn; + I830Ptr pI830 = I830PTR(pScrn); + I830CrtcPrivatePtr intel_crtc = output->crtc->driver_private; + CARD32 pfit_control; + + /* The LVDS pin pair will already have been turned on in + * i830_crtc_mode_set since it has a large impact on the DPLL settings. + */ + + /* Enable automatic panel scaling for non-native modes so that they fill + * the screen. Should be enabled before the pipe is enabled, according to + * register description and PRM. + */ + if (mode->HDisplay != adjusted_mode->HDisplay || + mode->VDisplay != adjusted_mode->VDisplay) + { + pfit_control = PFIT_ENABLE | + VERT_AUTO_SCALE | HORIZ_AUTO_SCALE | + VERT_INTERP_BILINEAR | HORIZ_INTERP_BILINEAR; + } else { + pfit_control = 0; + } + + if (!IS_I965G(pI830)) { + if (dev_priv->panel_wants_dither) + pfit_control |= PANEL_8TO6_DITHER_ENABLE; + } else { + pfit_control |= intel_crtc->pipe << PFIT_PIPE_SHIFT; + } + + OUTREG(PFIT_CONTROL, pfit_control); +} + +/** + * Detect the LVDS connection. + * + * This always returns OUTPUT_STATUS_CONNECTED. This output should only have + * been set up if the LVDS was actually connected anyway. + */ +static xf86OutputStatus +i830_lvds_detect(xf86OutputPtr output) +{ + return XF86OutputStatusConnected; +} + +/** + * Return the list of DDC modes if available, or the BIOS fixed mode otherwise. + */ +static DisplayModePtr +i830_lvds_get_modes(xf86OutputPtr output) +{ + I830OutputPrivatePtr intel_output = output->driver_private; + struct i830_lvds_priv *dev_priv = intel_output->dev_priv; + xf86MonPtr edid_mon; + DisplayModePtr modes; + + edid_mon = xf86OutputGetEDID (output, intel_output->pDDCBus); + xf86OutputSetEDID (output, edid_mon); + + modes = xf86OutputGetEDIDModes (output); + if (modes != NULL) + return modes; + + if (!output->MonInfo) + { + edid_mon = xcalloc (1, sizeof (xf86Monitor)); + if (edid_mon) + { + /* Set wide sync ranges so we get all modes + * handed to valid_mode for checking + */ + edid_mon->det_mon[0].type = DS_RANGES; + edid_mon->det_mon[0].section.ranges.min_v = 0; + edid_mon->det_mon[0].section.ranges.max_v = 200; + edid_mon->det_mon[0].section.ranges.min_h = 0; + edid_mon->det_mon[0].section.ranges.max_h = 200; + + output->MonInfo = edid_mon; + } + } + + if (dev_priv->panel_fixed_mode != NULL) + return xf86DuplicateMode(dev_priv->panel_fixed_mode); + + return NULL; +} + +static void +i830_lvds_destroy (xf86OutputPtr output) +{ + I830OutputPrivatePtr intel_output = output->driver_private; + + if (intel_output) + { + struct i830_lvds_priv *dev_priv = intel_output->dev_priv; + + xf86DeleteMode (&dev_priv->panel_fixed_mode, dev_priv->panel_fixed_mode); + xfree (intel_output); + } +} + +#ifdef RANDR_12_INTERFACE +#define BACKLIGHT_NAME "BACKLIGHT" +static Atom backlight_atom; + +/* + * Backlight control lets the user select how the driver should manage + * backlight changes: using the legacy interface, the native interface, + * or not at all. + */ +#define BACKLIGHT_CONTROL_NAME "BACKLIGHT_CONTROL" +#define NUM_BACKLIGHT_CONTROL_METHODS 4 +static char *backlight_control_names[] = { + "native", + "legacy", + "combination", + "kernel", +}; +static Atom backlight_control_atom; +static Atom backlight_control_name_atoms[NUM_BACKLIGHT_CONTROL_METHODS]; + +static int +i830_backlight_control_lookup(char *name) +{ + int i; + + for (i = 0; i < NUM_BACKLIGHT_CONTROL_METHODS; i++) + if (!strcmp(name, backlight_control_names[i])) + return i; + + return -1; +} + +static Bool +i830_lvds_set_backlight_control(xf86OutputPtr output) +{ + ScrnInfoPtr pScrn = output->scrn; + I830Ptr pI830 = I830PTR(pScrn); + I830OutputPrivatePtr intel_output = output->driver_private; + struct i830_lvds_priv *dev_priv = intel_output->dev_priv; + + switch (pI830->backlight_control_method) { + case NATIVE: + dev_priv->set_backlight = i830_lvds_set_backlight_native; + dev_priv->get_backlight = i830_lvds_get_backlight_native; + dev_priv->backlight_max = + i830_lvds_get_backlight_max_native(output); + break; + case LEGACY: + dev_priv->set_backlight = i830_lvds_set_backlight_legacy; + dev_priv->get_backlight = i830_lvds_get_backlight_legacy; + dev_priv->backlight_max = 0xff; + break; + case COMBO: + dev_priv->set_backlight = i830_lvds_set_backlight_combo; + dev_priv->get_backlight = i830_lvds_get_backlight_combo; + dev_priv->backlight_max = + i830_lvds_get_backlight_max_native(output); + break; + case KERNEL: + dev_priv->set_backlight = i830_lvds_set_backlight_kernel; + dev_priv->get_backlight = i830_lvds_get_backlight_kernel; + dev_priv->backlight_max = + i830_lvds_get_backlight_max_kernel(output); + break; + default: + /* + * Should be impossible to get here unless the caller set a bogus + * backlight_control_method + */ + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "error: bad backlight control " + "method\n"); + break; + } + + return Success; +} +#endif /* RANDR_12_INTERFACE */ + +static void +i830_lvds_create_resources(xf86OutputPtr output) +{ +#ifdef RANDR_12_INTERFACE + ScrnInfoPtr pScrn = output->scrn; + I830Ptr pI830 = I830PTR(pScrn); + I830OutputPrivatePtr intel_output = output->driver_private; + struct i830_lvds_priv *dev_priv = intel_output->dev_priv; + INT32 backlight_range[2]; + int data, err, i; + + /* Set up the backlight property, which takes effect immediately + * and accepts values only within the backlight_range. + * + * XXX: Currently, RandR doesn't verify that properties set are + * within the backlight_range. + */ + backlight_atom = MakeAtom(BACKLIGHT_NAME, sizeof(BACKLIGHT_NAME) - 1, + TRUE); + + backlight_range[0] = 0; + backlight_range[1] = dev_priv->backlight_max; + err = RRConfigureOutputProperty(output->randr_output, backlight_atom, + FALSE, TRUE, FALSE, 2, backlight_range); + if (err != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "RRConfigureOutputProperty error, %d\n", err); + } + /* Set the current value of the backlight property */ + data = dev_priv->backlight_duty_cycle; + err = RRChangeOutputProperty(output->randr_output, backlight_atom, + XA_INTEGER, 32, PropModeReplace, 1, &data, + FALSE, TRUE); + if (err != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "RRChangeOutputProperty error, %d\n", err); + } + + /* + * Now setup the control selection property + */ + backlight_control_atom = MakeAtom(BACKLIGHT_CONTROL_NAME, + sizeof(BACKLIGHT_CONTROL_NAME) - 1, TRUE); + for (i = 0; i < NUM_BACKLIGHT_CONTROL_METHODS; i++) { + backlight_control_name_atoms[i] = + MakeAtom(backlight_control_names[i], + strlen(backlight_control_names[i]), TRUE); + } + err = RRConfigureOutputProperty(output->randr_output, + backlight_control_atom, TRUE, FALSE, FALSE, + NUM_BACKLIGHT_CONTROL_METHODS, + (INT32 *)backlight_control_name_atoms); + if (err != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "RRConfigureOutputProperty error, %d\n", err); + } + err = RRChangeOutputProperty(output->randr_output, backlight_control_atom, + XA_ATOM, 32, PropModeReplace, 1, + &backlight_control_name_atoms[pI830->backlight_control_method], + FALSE, TRUE); + if (err != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "failed to set backlight control, %d\n", err); + } +#endif /* RANDR_12_INTERFACE */ +} + +#ifdef RANDR_12_INTERFACE +static Bool +i830_lvds_set_property(xf86OutputPtr output, Atom property, + RRPropertyValuePtr value) +{ + ScrnInfoPtr pScrn = output->scrn; + I830Ptr pI830 = I830PTR(pScrn); + I830OutputPrivatePtr intel_output = output->driver_private; + struct i830_lvds_priv *dev_priv = intel_output->dev_priv; + + if (property == backlight_atom) { + INT32 val; + + if (value->type != XA_INTEGER || value->format != 32 || + value->size != 1) + { + return FALSE; + } + + val = *(INT32 *)value->data; + if (val < 0 || val > dev_priv->backlight_max) + return FALSE; + + if (val != dev_priv->backlight_duty_cycle) { + dev_priv->set_backlight(output, val); + dev_priv->backlight_duty_cycle = val; + } + return TRUE; + } else if (property == backlight_control_atom) { + INT32 backlight_range[2]; + Atom atom; + char *name; + int ret, data; + + if (value->type != XA_ATOM || value->format != 32 || value->size != 1) + return FALSE; + + memcpy(&atom, value->data, 4); + name = NameForAtom(atom); + + ret = i830_backlight_control_lookup(name); + if (ret < 0) + return FALSE; + + pI830->backlight_control_method = ret; + i830_lvds_set_backlight_control(output); + + /* + * Update the backlight atom since the range and value may have changed + */ + backlight_range[0] = 0; + backlight_range[1] = dev_priv->backlight_max; + ret = RRConfigureOutputProperty(output->randr_output, backlight_atom, + FALSE, TRUE, FALSE, 2, backlight_range); + if (ret != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "RRConfigureOutputProperty error, %d\n", ret); + } + /* Set the current value of the backlight property */ + data = dev_priv->get_backlight(output); + ret = RRChangeOutputProperty(output->randr_output, backlight_atom, + XA_INTEGER, 32, PropModeReplace, 1, &data, + FALSE, TRUE); + if (ret != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "RRChangeOutputProperty error, %d\n", ret); + } + return TRUE; + } + + return TRUE; +} +#endif /* RANDR_12_INTERFACE */ + +static const xf86OutputFuncsRec i830_lvds_output_funcs = { + .create_resources = i830_lvds_create_resources, + .dpms = i830_lvds_dpms, + .save = i830_lvds_save, + .restore = i830_lvds_restore, + .mode_valid = i830_lvds_mode_valid, + .mode_fixup = i830_lvds_mode_fixup, + .prepare = i830_output_prepare, + .mode_set = i830_lvds_mode_set, + .commit = i830_output_commit, + .detect = i830_lvds_detect, + .get_modes = i830_lvds_get_modes, +#ifdef RANDR_12_INTERFACE + .set_property = i830_lvds_set_property, +#endif + .destroy = i830_lvds_destroy +}; + +void +i830_lvds_init(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + xf86OutputPtr output; + I830OutputPrivatePtr intel_output; + DisplayModePtr modes, scan, bios_mode; + struct i830_lvds_priv *dev_priv; + + if (pI830->quirk_flag & QUIRK_IGNORE_LVDS) + return; + + output = xf86OutputCreate (pScrn, &i830_lvds_output_funcs, "LVDS"); + if (!output) + return; + intel_output = xnfcalloc (sizeof (I830OutputPrivateRec) + + sizeof (struct i830_lvds_priv), 1); + if (!intel_output) + { + xf86OutputDestroy (output); + return; + } + intel_output->type = I830_OUTPUT_LVDS; + intel_output->pipe_mask = (1 << 1); + intel_output->clone_mask = (1 << I830_OUTPUT_LVDS); + + output->driver_private = intel_output; + output->subpixel_order = SubPixelHorizontalRGB; + output->interlaceAllowed = FALSE; + output->doubleScanAllowed = FALSE; + + dev_priv = (struct i830_lvds_priv *) (intel_output + 1); + intel_output->dev_priv = dev_priv; + + /* Set up the LVDS DDC channel. Most panels won't support it, but it can + * be useful if available. + */ + I830I2CInit(pScrn, &intel_output->pDDCBus, GPIOC, "LVDSDDC_C"); + + /* Attempt to get the fixed panel mode from DDC. Assume that the preferred + * mode is the right one. + */ + modes = i830_ddc_get_modes(output); + for (scan = modes; scan != NULL; scan = scan->next) { + if (scan->type & M_T_PREFERRED) + break; + } + if (scan != NULL) { + /* Pull our chosen mode out and make it the fixed mode */ + if (modes == scan) + modes = modes->next; + if (scan->prev != NULL) + scan->prev = scan->next; + if (scan->next != NULL) + scan->next = scan->prev; + dev_priv->panel_fixed_mode = scan; + } + /* Delete the mode list */ + while (modes != NULL) + xf86DeleteMode(&modes, modes); + + /* If we didn't get EDID, try checking if the panel is already turned on. + * If so, assume that whatever is currently programmed is the correct mode. + */ + if (dev_priv->panel_fixed_mode == NULL) { + CARD32 lvds = INREG(LVDS); + int pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + xf86CrtcPtr crtc = xf86_config->crtc[pipe]; + + if (lvds & LVDS_PORT_EN) { + dev_priv->panel_fixed_mode = i830_crtc_mode_get(pScrn, crtc); + if (dev_priv->panel_fixed_mode != NULL) + dev_priv->panel_fixed_mode->type |= M_T_PREFERRED; + } + } + + /* Get the LVDS fixed mode out of the BIOS. We should support LVDS with + * the BIOS being unavailable or broken, but lack the configuration options + * for now. + */ + bios_mode = i830_bios_get_panel_mode(pScrn, &dev_priv->panel_wants_dither); + if (bios_mode != NULL) { + if (dev_priv->panel_fixed_mode != NULL) { + /* Fixup for a 1280x768 panel with the horizontal trimmed + * down to 1024 for text mode. + */ + if (!xf86ModesEqual(dev_priv->panel_fixed_mode, bios_mode) && + dev_priv->panel_fixed_mode->HDisplay == 1024 && + dev_priv->panel_fixed_mode->HSyncStart == 1200 && + dev_priv->panel_fixed_mode->HSyncEnd == 1312 && + dev_priv->panel_fixed_mode->HTotal == 1688 && + dev_priv->panel_fixed_mode->VDisplay == 768) + { + dev_priv->panel_fixed_mode->HDisplay = 1280; + dev_priv->panel_fixed_mode->HSyncStart = 1328; + dev_priv->panel_fixed_mode->HSyncEnd = 1440; + dev_priv->panel_fixed_mode->HTotal = 1688; + } + + if (pI830->debug_modes && + !xf86ModesEqual(dev_priv->panel_fixed_mode, bios_mode)) + { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "BIOS panel mode data doesn't match probed data, " + "continuing with probed.\n"); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "BIOS mode:\n"); + xf86PrintModeline(pScrn->scrnIndex, bios_mode); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "probed mode:\n"); + xf86PrintModeline(pScrn->scrnIndex, dev_priv->panel_fixed_mode); + xfree(bios_mode->name); + xfree(bios_mode); + } + } else { + dev_priv->panel_fixed_mode = bios_mode; + } + } else { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Couldn't detect panel mode. Disabling panel\n"); + goto disable_exit; + } + + /* Blacklist machines with BIOSes that list an LVDS panel without actually + * having one. + */ + if (pI830->quirk_flag & QUIRK_IGNORE_MACMINI_LVDS) { + /* It's a Mac Mini or Macbook Pro. + * + * Apple hardware is out to get us. The macbook pro has a real + * LVDS panel, but the mac mini does not, and they have the same + * device IDs. We'll distinguish by panel size, on the assumption + * that Apple isn't about to make any machines with an 800x600 + * display. + */ + + if (dev_priv->panel_fixed_mode != NULL && + dev_priv->panel_fixed_mode->HDisplay == 800 && + dev_priv->panel_fixed_mode->VDisplay == 600) + { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Suspected Mac Mini, ignoring the LVDS\n"); + goto disable_exit; + } + } + + i830_set_lvds_backlight_method(output); + + switch (pI830->backlight_control_method) { + case NATIVE: + dev_priv->set_backlight = i830_lvds_set_backlight_native; + dev_priv->get_backlight = i830_lvds_get_backlight_native; + dev_priv->backlight_max = i830_lvds_get_backlight_max_native(output); + break; + case LEGACY: + dev_priv->set_backlight = i830_lvds_set_backlight_legacy; + dev_priv->get_backlight = i830_lvds_get_backlight_legacy; + dev_priv->backlight_max = 0xff; + break; + case COMBO: + dev_priv->set_backlight = i830_lvds_set_backlight_combo; + dev_priv->get_backlight = i830_lvds_get_backlight_combo; + dev_priv->backlight_max = i830_lvds_get_backlight_max_native(output); + break; + case KERNEL: + dev_priv->set_backlight = i830_lvds_set_backlight_kernel; + dev_priv->get_backlight = i830_lvds_get_backlight_kernel; + dev_priv->backlight_max = i830_lvds_get_backlight_max_kernel(output); + break; + default: + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "bad backlight control method\n"); + break; + } + + dev_priv->backlight_duty_cycle = dev_priv->backlight_max; + + return; + +disable_exit: + xf86DestroyI2CBusRec(intel_output->pDDCBus, TRUE, TRUE); + xf86OutputDestroy(output); +} diff --git a/driver/xf86-video-intel/src/i830_quirks.c b/driver/xf86-video-intel/src/i830_quirks.c new file mode 100644 index 000000000..1ed6503da --- /dev/null +++ b/driver/xf86-video-intel/src/i830_quirks.c @@ -0,0 +1,104 @@ +/* + * Copyright © 2007 Intel Corporation + * + * 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 + * THE AUTHORS OR COPYRIGHT HOLDERS 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: + * Zhenyu Wang <zhenyu.z.wang@intel.com> + * + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "i830.h" + +#define SUBSYS_ANY (~0) + +typedef struct { + int chipType; + int subsysVendor; + int subsysCard; + void (*hook)(I830Ptr); +} i830_quirk, *i830_quirk_ptr; + +static void quirk_ignore_tv (I830Ptr pI830) +{ + pI830->quirk_flag |= QUIRK_IGNORE_TV; +} + +static void quirk_ignore_lvds (I830Ptr pI830) +{ + pI830->quirk_flag |= QUIRK_IGNORE_LVDS; +} + +static void quirk_mac_mini (I830Ptr pI830) +{ + pI830->quirk_flag |= QUIRK_IGNORE_MACMINI_LVDS; +} + +/* keep this list sorted by OEM, then by chip ID */ +static i830_quirk i830_quirk_list[] = { + /* Aopen mini pc */ + { PCI_CHIP_I945_GM, 0xa0a0, SUBSYS_ANY, quirk_ignore_lvds }, + { PCI_CHIP_I965_GM, 0x8086, 0x1999, quirk_ignore_lvds }, + + /* Apple Mac mini has no lvds, but macbook pro does */ + { PCI_CHIP_I945_GM, 0x8086, 0x7270, quirk_mac_mini }, + + /* Dell Latitude X1 */ + { PCI_CHIP_I945_GM, 0x1028, 0x01a3, quirk_ignore_tv }, + /* Dell XPS 1330 */ + { PCI_CHIP_I965_GM, 0x1028, 0x0209, quirk_ignore_tv }, + + /* Lenovo X60s has no TV output */ + { PCI_CHIP_I945_GM, 0x17aa, 0x201a, quirk_ignore_tv }, + /* Lenovo T61 has no TV output */ + { PCI_CHIP_I965_GM, 0x17aa, 0x20b5, quirk_ignore_tv }, + /* Lenovo 3000 v200 */ + { PCI_CHIP_I965_GM, 0x17aa, 0x3c18, quirk_ignore_tv }, + + /* Panasonic Toughbook CF-Y4 has no TV output */ + { PCI_CHIP_I915_GM, 0x10f7, 0x8338, quirk_ignore_tv }, + /* Panasonic Toughbook CF-Y7 has no TV output */ + { PCI_CHIP_I965_GM, 0x10f7, 0x8338, quirk_ignore_tv }, + + /* Toshiba Satellite U300 has no TV output */ + { PCI_CHIP_I965_GM, 0x1179, 0xff50, quirk_ignore_tv }, + + /* Samsung Q35 has no TV output */ + { PCI_CHIP_I945_GM, 0x144d, 0xc504, quirk_ignore_tv }, + { 0, 0, 0, NULL }, +}; + +void i830_fixup_devices(ScrnInfoPtr scrn) +{ + I830Ptr pI830 = I830PTR(scrn); + i830_quirk_ptr p = i830_quirk_list; + + while (p && p->chipType != 0) { + if (DEVICE_ID(pI830->PciInfo) == p->chipType && + SUBVENDOR_ID(pI830->PciInfo) == p->subsysVendor && + (SUBSYS_ID(pI830->PciInfo) == p->subsysCard || + p->subsysCard == SUBSYS_ANY)) + p->hook(pI830); + ++p; + } +} diff --git a/driver/xf86-video-intel/src/i830_render.c b/driver/xf86-video-intel/src/i830_render.c new file mode 100644 index 000000000..22e09c846 --- /dev/null +++ b/driver/xf86-video-intel/src/i830_render.c @@ -0,0 +1,638 @@ +/* + * Copyright © 2006 Intel Corporation + * + * 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 + * THE AUTHORS OR COPYRIGHT HOLDERS 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: + * Wang Zhenyu <zhenyu.z.wang@intel.com> + * Eric Anholt <eric@anholt.net> + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "xf86.h" +#include "i830.h" +#include "i830_reg.h" + +#ifdef I830DEBUG +#define DEBUG_I830FALLBACK 1 +#endif + +#ifdef DEBUG_I830FALLBACK +#define I830FALLBACK(s, arg...) \ +do { \ + DPRINTF(PFX, "EXA fallback: " s "\n", ##arg); \ + return FALSE; \ +} while(0) +#else +#define I830FALLBACK(s, arg...) \ +do { \ + return FALSE; \ +} while(0) +#endif + +struct blendinfo { + Bool dst_alpha; + Bool src_alpha; + CARD32 src_blend; + CARD32 dst_blend; +}; + +struct formatinfo { + int fmt; + CARD32 card_fmt; +}; + +#define TB0C_LAST_STAGE (1 << 31) +#define TB0C_RESULT_SCALE_1X (0 << 29) +#define TB0C_RESULT_SCALE_2X (1 << 29) +#define TB0C_RESULT_SCALE_4X (2 << 29) +#define TB0C_OP_MODULE (3 << 25) +#define TB0C_OUTPUT_WRITE_CURRENT (0 << 24) +#define TB0C_OUTPUT_WRITE_ACCUM (1 << 24) +#define TB0C_ARG3_REPLICATE_ALPHA (1<<23) +#define TB0C_ARG3_INVERT (1<<22) +#define TB0C_ARG3_SEL_XXX +#define TB0C_ARG2_REPLICATE_ALPHA (1<<17) +#define TB0C_ARG2_INVERT (1<<16) +#define TB0C_ARG2_SEL_ONE (0 << 12) +#define TB0C_ARG2_SEL_FACTOR (1 << 12) +#define TB0C_ARG2_SEL_TEXEL0 (6 << 12) +#define TB0C_ARG2_SEL_TEXEL1 (7 << 12) +#define TB0C_ARG2_SEL_TEXEL2 (8 << 12) +#define TB0C_ARG2_SEL_TEXEL3 (9 << 12) +#define TB0C_ARG1_REPLICATE_ALPHA (1<<11) +#define TB0C_ARG1_INVERT (1<<10) +#define TB0C_ARG1_SEL_ONE (0 << 6) +#define TB0C_ARG1_SEL_TEXEL0 (6 << 6) +#define TB0C_ARG1_SEL_TEXEL1 (7 << 6) +#define TB0C_ARG1_SEL_TEXEL2 (8 << 6) +#define TB0C_ARG1_SEL_TEXEL3 (9 << 6) +#define TB0C_ARG0_REPLICATE_ALPHA (1<<5) +#define TB0C_ARG0_SEL_XXX + +#define TB0A_CTR_STAGE_ENABLE (1<<31) +#define TB0A_RESULT_SCALE_1X (0 << 29) +#define TB0A_RESULT_SCALE_2X (1 << 29) +#define TB0A_RESULT_SCALE_4X (2 << 29) +#define TB0A_OP_MODULE (3 << 25) +#define TB0A_OUTPUT_WRITE_CURRENT (0<<24) +#define TB0A_OUTPUT_WRITE_ACCUM (1<<24) +#define TB0A_CTR_STAGE_SEL_BITS_XXX +#define TB0A_ARG3_SEL_XXX +#define TB0A_ARG3_INVERT (1<<17) +#define TB0A_ARG2_INVERT (1<<16) +#define TB0A_ARG2_SEL_ONE (0 << 12) +#define TB0A_ARG2_SEL_TEXEL0 (6 << 12) +#define TB0A_ARG2_SEL_TEXEL1 (7 << 12) +#define TB0A_ARG2_SEL_TEXEL2 (8 << 12) +#define TB0A_ARG2_SEL_TEXEL3 (9 << 12) +#define TB0A_ARG1_INVERT (1<<10) +#define TB0A_ARG1_SEL_ONE (0 << 6) +#define TB0A_ARG1_SEL_TEXEL0 (6 << 6) +#define TB0A_ARG1_SEL_TEXEL1 (7 << 6) +#define TB0A_ARG1_SEL_TEXEL2 (8 << 6) +#define TB0A_ARG1_SEL_TEXEL3 (9 << 6) + +static struct blendinfo i830_blend_op[] = { + /* Clear */ + {0, 0, BLENDFACTOR_ZERO, BLENDFACTOR_ZERO}, + /* Src */ + {0, 0, BLENDFACTOR_ONE, BLENDFACTOR_ZERO}, + /* Dst */ + {0, 0, BLENDFACTOR_ZERO, BLENDFACTOR_ONE}, + /* Over */ + {0, 1, BLENDFACTOR_ONE, BLENDFACTOR_INV_SRC_ALPHA}, + /* OverReverse */ + {1, 0, BLENDFACTOR_INV_DST_ALPHA, BLENDFACTOR_ONE}, + /* In */ + {1, 0, BLENDFACTOR_DST_ALPHA, BLENDFACTOR_ZERO}, + /* InReverse */ + {0, 1, BLENDFACTOR_ZERO, BLENDFACTOR_SRC_ALPHA}, + /* Out */ + {1, 0, BLENDFACTOR_INV_DST_ALPHA, BLENDFACTOR_ZERO}, + /* OutReverse */ + {0, 1, BLENDFACTOR_ZERO, BLENDFACTOR_INV_SRC_ALPHA}, + /* Atop */ + {1, 1, BLENDFACTOR_DST_ALPHA, BLENDFACTOR_INV_SRC_ALPHA}, + /* AtopReverse */ + {1, 1, BLENDFACTOR_INV_DST_ALPHA, BLENDFACTOR_SRC_ALPHA}, + /* Xor */ + {1, 1, BLENDFACTOR_INV_DST_ALPHA, BLENDFACTOR_INV_SRC_ALPHA}, + /* Add */ + {0, 0, BLENDFACTOR_ONE, BLENDFACTOR_ONE}, +}; + +static struct formatinfo i830_tex_formats[] = { + {PICT_a8r8g8b8, MT_32BIT_ARGB8888 }, + {PICT_x8r8g8b8, MT_32BIT_XRGB8888 }, + {PICT_a8b8g8r8, MT_32BIT_ABGR8888 }, + {PICT_x8b8g8r8, MT_32BIT_XBGR8888 }, + {PICT_r5g6b5, MT_16BIT_RGB565 }, + {PICT_a1r5g5b5, MT_16BIT_ARGB1555 }, + {PICT_x1r5g5b5, MT_16BIT_ARGB1555 }, + {PICT_a8, MT_8BIT_A8 }, +}; + +static Bool i830_get_dest_format(PicturePtr pDstPicture, CARD32 *dst_format) +{ + switch (pDstPicture->format) { + case PICT_a8r8g8b8: + case PICT_x8r8g8b8: + *dst_format = COLR_BUF_ARGB8888; + break; + case PICT_r5g6b5: + *dst_format = COLR_BUF_RGB565; + break; + case PICT_a1r5g5b5: + case PICT_x1r5g5b5: + *dst_format = COLR_BUF_ARGB1555; + break; + /* + case PICT_a8: + *dst_format = COLR_BUF_8BIT; + break; + */ + case PICT_a4r4g4b4: + case PICT_x4r4g4b4: + *dst_format = COLR_BUF_ARGB4444; + break; + default: + I830FALLBACK("Unsupported dest format 0x%x\n", + (int)pDstPicture->format); + } + + return TRUE; +} + + +static CARD32 i830_get_blend_cntl(int op, PicturePtr pMask, CARD32 dst_format) +{ + CARD32 sblend, dblend; + + sblend = i830_blend_op[op].src_blend; + dblend = i830_blend_op[op].dst_blend; + + /* If there's no dst alpha channel, adjust the blend op so that we'll treat + * it as always 1. + */ + if (PICT_FORMAT_A(dst_format) == 0 && i830_blend_op[op].dst_alpha) { + if (sblend == BLENDFACTOR_DST_ALPHA) + sblend = BLENDFACTOR_ONE; + else if (sblend == BLENDFACTOR_INV_DST_ALPHA) + sblend = BLENDFACTOR_ZERO; + } + + /* If the source alpha is being used, then we should only be in a case + * where the source blend factor is 0, and the source blend value is the + * mask channels multiplied by the source picture's alpha. + */ + if (pMask && pMask->componentAlpha && PICT_FORMAT_RGB(pMask->format) + && i830_blend_op[op].src_alpha) { + if (dblend == BLENDFACTOR_SRC_ALPHA) { + dblend = BLENDFACTOR_SRC_COLR; + } else if (dblend == BLENDFACTOR_INV_SRC_ALPHA) { + dblend = BLENDFACTOR_INV_SRC_COLR; + } + } + + return (sblend << S8_SRC_BLEND_FACTOR_SHIFT) | + (dblend << S8_DST_BLEND_FACTOR_SHIFT); +} + +static Bool i830_check_composite_texture(PicturePtr pPict, int unit) +{ + ScrnInfoPtr pScrn = xf86Screens[pPict->pDrawable->pScreen->myNum]; + I830Ptr pI830 = I830PTR(pScrn); + int w = pPict->pDrawable->width; + int h = pPict->pDrawable->height; + int i; + + if ((w > 0x7ff) || (h > 0x7ff)) + I830FALLBACK("Picture w/h too large (%dx%d)\n", w, h); + + for (i = 0; i < sizeof(i830_tex_formats) / sizeof(i830_tex_formats[0]); + i++) + { + if (i830_tex_formats[i].fmt == pPict->format) + break; + } + if (i == sizeof(i830_tex_formats) / sizeof(i830_tex_formats[0])) + I830FALLBACK("Unsupported picture format 0x%x\n", + (int)pPict->format); + + if (IS_I830(pI830) || IS_845G(pI830)) { + if (pPict->format == PICT_x8r8g8b8 || + pPict->format == PICT_x8b8g8r8 || + pPict->format == PICT_a8) + I830FALLBACK("830/845G don't support a8, x8r8g8b8, x8b8g8r8\n"); + } + + if (pPict->repeat && pPict->repeatType != RepeatNormal) + I830FALLBACK("unsupport repeat type\n"); + + if (pPict->filter != PictFilterNearest && + pPict->filter != PictFilterBilinear) + { + I830FALLBACK("Unsupported filter 0x%x\n", pPict->filter); + } + + return TRUE; +} + +static CARD32 +i8xx_get_card_format(PicturePtr pPict) +{ + int i; + for (i = 0; i < sizeof(i830_tex_formats) / sizeof(i830_tex_formats[0]); + i++) + { + if (i830_tex_formats[i].fmt == pPict->format) + break; + } + return i830_tex_formats[i].card_fmt; +} + +static Bool +i830_texture_setup(PicturePtr pPict, PixmapPtr pPix, int unit) +{ + + ScrnInfoPtr pScrn = xf86Screens[pPict->pDrawable->pScreen->myNum]; + I830Ptr pI830 = I830PTR(pScrn); + CARD32 format, offset, pitch, filter; + CARD32 wrap_mode = TEXCOORDMODE_CLAMP_BORDER; + + offset = intel_get_pixmap_offset(pPix); + pitch = intel_get_pixmap_pitch(pPix); + pI830->scale_units[unit][0] = pPix->drawable.width; + pI830->scale_units[unit][1] = pPix->drawable.height; + pI830->transform[unit] = pPict->transform; + + format = i8xx_get_card_format(pPict); + + if (pPict->repeat) + wrap_mode = TEXCOORDMODE_WRAP; + + switch (pPict->filter) { + case PictFilterNearest: + filter = ((FILTER_NEAREST<<TM0S3_MAG_FILTER_SHIFT) | + (FILTER_NEAREST<<TM0S3_MIN_FILTER_SHIFT)); + break; + case PictFilterBilinear: + filter = ((FILTER_LINEAR<<TM0S3_MAG_FILTER_SHIFT) | + (FILTER_LINEAR<<TM0S3_MIN_FILTER_SHIFT)); + break; + default: + filter = 0; + I830FALLBACK("Bad filter 0x%x\n", pPict->filter); + } + filter |= (MIPFILTER_NONE << TM0S3_MIP_FILTER_SHIFT); + + { + if (pPix->drawable.bitsPerPixel == 8) + format |= MAPSURF_8BIT; + else if (pPix->drawable.bitsPerPixel == 16) + format |= MAPSURF_16BIT; + else + format |= MAPSURF_32BIT; + + BEGIN_LP_RING(10); + OUT_RING(_3DSTATE_LOAD_STATE_IMMEDIATE_2 | LOAD_TEXTURE_MAP(unit) | 4); + OUT_RING((offset & TM0S0_ADDRESS_MASK) | TM0S0_USE_FENCE); + OUT_RING(((pPix->drawable.height - 1) << TM0S1_HEIGHT_SHIFT) | + ((pPix->drawable.width - 1) << TM0S1_WIDTH_SHIFT) | format); + OUT_RING((pitch/4 - 1) << TM0S2_PITCH_SHIFT | TM0S2_MAP_2D); + OUT_RING(filter); + OUT_RING(0); /* default color */ + OUT_RING(_3DSTATE_MAP_COORD_SET_CMD | TEXCOORD_SET(unit) | + ENABLE_TEXCOORD_PARAMS | TEXCOORDS_ARE_NORMAL | + TEXCOORDTYPE_CARTESIAN | ENABLE_ADDR_V_CNTL | + TEXCOORD_ADDR_V_MODE(wrap_mode) | + ENABLE_ADDR_U_CNTL | TEXCOORD_ADDR_U_MODE(wrap_mode)); + /* map texel stream */ + OUT_RING(_3DSTATE_MAP_COORD_SETBIND_CMD); + if (unit == 0) + OUT_RING(TEXBIND_SET0(TEXCOORDSRC_VTXSET_0) | + TEXBIND_SET1(TEXCOORDSRC_KEEP) | + TEXBIND_SET2(TEXCOORDSRC_KEEP) | + TEXBIND_SET3(TEXCOORDSRC_KEEP)); + else + OUT_RING(TEXBIND_SET0(TEXCOORDSRC_VTXSET_0) | + TEXBIND_SET1(TEXCOORDSRC_VTXSET_1) | + TEXBIND_SET2(TEXCOORDSRC_KEEP) | + TEXBIND_SET3(TEXCOORDSRC_KEEP)); + OUT_RING(_3DSTATE_MAP_TEX_STREAM_CMD | (unit << 16) | + DISABLE_TEX_STREAM_BUMP | + ENABLE_TEX_STREAM_COORD_SET | + TEX_STREAM_COORD_SET(unit) | + ENABLE_TEX_STREAM_MAP_IDX | + TEX_STREAM_MAP_IDX(unit)); + ADVANCE_LP_RING(); + } + +#ifdef I830DEBUG + ErrorF("try to sync to show any errors..."); + I830Sync(pScrn); +#endif + + return TRUE; +} + +Bool +i830_check_composite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture, + PicturePtr pDstPicture) +{ + CARD32 tmp1; + + /* Check for unsupported compositing operations. */ + if (op >= sizeof(i830_blend_op) / sizeof(i830_blend_op[0])) + I830FALLBACK("Unsupported Composite op 0x%x\n", op); + + if (pMaskPicture != NULL && pMaskPicture->componentAlpha && + PICT_FORMAT_RGB(pMaskPicture->format)) { + /* Check if it's component alpha that relies on a source alpha and on + * the source value. We can only get one of those into the single + * source value that we get to blend with. + */ + if (i830_blend_op[op].src_alpha && + (i830_blend_op[op].src_blend != BLENDFACTOR_ZERO)) + I830FALLBACK("Component alpha not supported with source " + "alpha and source value blending.\n"); + } + + if (!i830_check_composite_texture(pSrcPicture, 0)) + I830FALLBACK("Check Src picture texture\n"); + if (pMaskPicture != NULL && !i830_check_composite_texture(pMaskPicture, 1)) + I830FALLBACK("Check Mask picture texture\n"); + + if (!i830_get_dest_format(pDstPicture, &tmp1)) + I830FALLBACK("Get Color buffer format\n"); + + return TRUE; +} + +Bool +i830_prepare_composite(int op, PicturePtr pSrcPicture, + PicturePtr pMaskPicture, PicturePtr pDstPicture, + PixmapPtr pSrc, PixmapPtr pMask, PixmapPtr pDst) +{ + ScrnInfoPtr pScrn = xf86Screens[pSrcPicture->pDrawable->pScreen->myNum]; + I830Ptr pI830 = I830PTR(pScrn); + CARD32 dst_format, dst_offset, dst_pitch; + + IntelEmitInvarientState(pScrn); + *pI830->last_3d = LAST_3D_RENDER; + + i830_get_dest_format(pDstPicture, &dst_format); + dst_offset = intel_get_pixmap_offset(pDst); + dst_pitch = intel_get_pixmap_pitch(pDst); + + if (!i830_texture_setup(pSrcPicture, pSrc, 0)) + I830FALLBACK("fail to setup src texture\n"); + if (pMask != NULL) { + if (!i830_texture_setup(pMaskPicture, pMask, 1)) + I830FALLBACK("fail to setup mask texture\n"); + } else { + pI830->transform[1] = NULL; + pI830->scale_units[1][0] = -1; + pI830->scale_units[1][1] = -1; + } + + { + CARD32 cblend, ablend, blendctl, vf2; + + BEGIN_LP_RING(30); + + /* color buffer */ + OUT_RING(_3DSTATE_BUF_INFO_CMD); + OUT_RING(BUF_3D_ID_COLOR_BACK| BUF_3D_USE_FENCE | + BUF_3D_PITCH(dst_pitch)); + OUT_RING(BUF_3D_ADDR(dst_offset)); + OUT_RING(MI_NOOP); + + OUT_RING(_3DSTATE_DST_BUF_VARS_CMD); + OUT_RING(dst_format); + + /* defaults */ + OUT_RING(_3DSTATE_DFLT_Z_CMD); + OUT_RING(0); + + OUT_RING(_3DSTATE_DFLT_DIFFUSE_CMD); + OUT_RING(0); + + OUT_RING(_3DSTATE_DFLT_SPEC_CMD); + OUT_RING(0); + + OUT_RING(_3DSTATE_DRAW_RECT_CMD); + OUT_RING(0); + OUT_RING(0); /* ymin, xmin */ + OUT_RING(DRAW_YMAX(pDst->drawable.height - 1) | + DRAW_XMAX(pDst->drawable.width - 1)); + OUT_RING(0); /* yorig, xorig */ + + OUT_RING(_3DSTATE_LOAD_STATE_IMMEDIATE_1 | I1_LOAD_S(2) | + I1_LOAD_S(3) | 1); + if (pMask) + vf2 = 2 << 12; /* 2 texture coord sets */ + else + vf2 = 1 << 12; + OUT_RING(vf2); /* TEXCOORDFMT_2D */ + OUT_RING(S3_CULLMODE_NONE | S3_VERTEXHAS_XY); + + /* We use two pipes for color and alpha, and do (src In mask) + in one stage. Arg1 is from src pict, and arg2 is from mask pict. + Be sure to force 1.0 when src or mask pict has no alpha channel. + */ + cblend = TB0C_LAST_STAGE | TB0C_RESULT_SCALE_1X | TB0C_OP_MODULE | + TB0C_OUTPUT_WRITE_CURRENT; + ablend = TB0A_RESULT_SCALE_1X | TB0A_OP_MODULE | + TB0A_OUTPUT_WRITE_CURRENT; + + if (PICT_FORMAT_A(pSrcPicture->format) != 0) { + ablend |= TB0A_ARG1_SEL_TEXEL0; + cblend |= TB0C_ARG1_SEL_TEXEL0; + } else { + ablend |= TB0A_ARG1_SEL_ONE; + if (pMask && pMaskPicture->componentAlpha + && PICT_FORMAT_RGB(pMaskPicture->format) + && i830_blend_op[op].src_alpha) + cblend |= TB0C_ARG1_SEL_ONE; + else + cblend |= TB0C_ARG1_SEL_TEXEL0; + } + + if (pMask) { + if (pMaskPicture->componentAlpha && + PICT_FORMAT_RGB(pMaskPicture->format)) { + if (i830_blend_op[op].src_alpha) + cblend |= (TB0C_ARG2_SEL_TEXEL1 | + TB0C_ARG1_REPLICATE_ALPHA); + else + cblend |= TB0C_ARG2_SEL_TEXEL1; + } else { + if (PICT_FORMAT_A(pMaskPicture->format) != 0) + cblend |= (TB0C_ARG2_SEL_TEXEL1 | + TB0C_ARG2_REPLICATE_ALPHA); + else + cblend |= TB0C_ARG2_SEL_ONE; + } + if (PICT_FORMAT_A(pMaskPicture->format) != 0) + ablend |= TB0A_ARG2_SEL_TEXEL1; + else + ablend |= TB0A_ARG2_SEL_ONE; + } else { + cblend |= TB0C_ARG2_SEL_ONE; + ablend |= TB0A_ARG2_SEL_ONE; + } + + OUT_RING(_3DSTATE_LOAD_STATE_IMMEDIATE_2 | + LOAD_TEXTURE_BLEND_STAGE(0)|1); + OUT_RING(cblend); + OUT_RING(ablend); + OUT_RING(0); + + blendctl = i830_get_blend_cntl(op, pMaskPicture, pDstPicture->format); + OUT_RING(_3DSTATE_INDPT_ALPHA_BLEND_CMD | DISABLE_INDPT_ALPHA_BLEND); + OUT_RING(MI_NOOP); + OUT_RING(_3DSTATE_LOAD_STATE_IMMEDIATE_1 | I1_LOAD_S(8) | 0); + OUT_RING(S8_ENABLE_COLOR_BLEND | S8_BLENDFUNC_ADD | blendctl | + S8_ENABLE_COLOR_BUFFER_WRITE); + + OUT_RING(_3DSTATE_ENABLES_1_CMD | DISABLE_LOGIC_OP | + DISABLE_STENCIL_TEST | DISABLE_DEPTH_BIAS | + DISABLE_SPEC_ADD | DISABLE_FOG | DISABLE_ALPHA_TEST | + ENABLE_COLOR_BLEND | DISABLE_DEPTH_TEST); + /* We have to explicitly say we don't want write disabled */ + OUT_RING(_3DSTATE_ENABLES_2_CMD | ENABLE_COLOR_MASK | + DISABLE_STENCIL_WRITE | ENABLE_TEX_CACHE | + DISABLE_DITHER | ENABLE_COLOR_WRITE | + DISABLE_DEPTH_WRITE); + ADVANCE_LP_RING(); + } + +#ifdef I830DEBUG + Error("try to sync to show any errors..."); + I830Sync(pScrn); +#endif + + return TRUE; +} + + +/** + * Do a single rectangle composite operation. + * + * This function is shared between i830 and i915 generation code. + */ +void +i830_composite(PixmapPtr pDst, int srcX, int srcY, int maskX, int maskY, + int dstX, int dstY, int w, int h) +{ + ScrnInfoPtr pScrn = xf86Screens[pDst->drawable.pScreen->myNum]; + I830Ptr pI830 = I830PTR(pScrn); + Bool has_mask; + float src_x[3], src_y[3], mask_x[3], mask_y[3]; + + i830_get_transformed_coordinates(srcX, srcY, + pI830->transform[0], + &src_x[0], &src_y[0]); + i830_get_transformed_coordinates(srcX, srcY + h, + pI830->transform[0], + &src_x[1], &src_y[1]); + i830_get_transformed_coordinates(srcX + w, srcY + h, + pI830->transform[0], + &src_x[2], &src_y[2]); + + if (pI830->scale_units[1][0] == -1 || pI830->scale_units[1][1] == -1) { + has_mask = FALSE; + } else { + has_mask = TRUE; + i830_get_transformed_coordinates(maskX, maskY, + pI830->transform[1], + &mask_x[0], &mask_y[0]); + i830_get_transformed_coordinates(maskX, maskY + h, + pI830->transform[1], + &mask_x[1], &mask_y[1]); + i830_get_transformed_coordinates(maskX + w, maskY + h, + pI830->transform[1], + &mask_x[2], &mask_y[2]); + } + + { + int vertex_count; + + if (has_mask) + vertex_count = 3*6; + else + vertex_count = 3*4; + + BEGIN_LP_RING(6+vertex_count); + + OUT_RING(MI_NOOP); + OUT_RING(MI_NOOP); + OUT_RING(MI_NOOP); + OUT_RING(MI_NOOP); + OUT_RING(MI_NOOP); + + OUT_RING(PRIM3D_INLINE | PRIM3D_RECTLIST | (vertex_count-1)); + + OUT_RING_F(-0.125 + dstX + w); + OUT_RING_F(-0.125 + dstY + h); + OUT_RING_F(src_x[2] / pI830->scale_units[0][0]); + OUT_RING_F(src_y[2] / pI830->scale_units[0][1]); + if (has_mask) { + OUT_RING_F(mask_x[2] / pI830->scale_units[1][0]); + OUT_RING_F(mask_y[2] / pI830->scale_units[1][1]); + } + + OUT_RING_F(-0.125 + dstX); + OUT_RING_F(-0.125 + dstY + h); + OUT_RING_F(src_x[1] / pI830->scale_units[0][0]); + OUT_RING_F(src_y[1] / pI830->scale_units[0][1]); + if (has_mask) { + OUT_RING_F(mask_x[1] / pI830->scale_units[1][0]); + OUT_RING_F(mask_y[1] / pI830->scale_units[1][1]); + } + + OUT_RING_F(-0.125 + dstX); + OUT_RING_F(-0.125 + dstY); + OUT_RING_F(src_x[0] / pI830->scale_units[0][0]); + OUT_RING_F(src_y[0] / pI830->scale_units[0][1]); + if (has_mask) { + OUT_RING_F(mask_x[0] / pI830->scale_units[1][0]); + OUT_RING_F(mask_y[0] / pI830->scale_units[1][1]); + } + ADVANCE_LP_RING(); + } +} + +/** + * Do any cleanup from the Composite operation. + * + * This is shared between i830 through i965. + */ +void +i830_done_composite(PixmapPtr pDst) +{ + /* NO-OP */ +} diff --git a/driver/xf86-video-intel/src/i830_sdvo.c b/driver/xf86-video-intel/src/i830_sdvo.c new file mode 100644 index 000000000..27677152e --- /dev/null +++ b/driver/xf86-video-intel/src/i830_sdvo.c @@ -0,0 +1,1335 @@ +/************************************************************************** + + Copyright 2006 Dave Airlie <airlied@linux.ie> + +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. + +**************************************************************************/ + +/** @file + * SDVO support for i915 and newer chipsets. + * + * The SDVO outputs send digital display data out over the PCIE bus to display + * cards implementing a defined interface. These cards may have DVI, TV, CRT, + * or other outputs on them. + * + * The system has two SDVO channels, which may be used for SDVO chips on the + * motherboard, or in the external cards. The two channels may also be used + * in a ganged mode to provide higher bandwidth to a single output. Currently, + * this code doesn't deal with either ganged mode or more than one SDVO output. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <string.h> + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "compiler.h" +#include "i830.h" +#include "i830_display.h" +#include "i810_reg.h" +#include "i830_sdvo_regs.h" + +/** SDVO driver private structure. */ +struct i830_sdvo_priv { + /** SDVO device on SDVO I2C bus. */ + I2CDevRec d; + + /** Register for the SDVO device: SDVOB or SDVOC */ + int output_device; + + /** Active outputs controlled by this SDVO output */ + CARD16 active_outputs; + + /** + * Capabilities of the SDVO device returned by i830_sdvo_get_capabilities() + */ + struct i830_sdvo_caps caps; + + /** Pixel clock limitations reported by the SDVO device, in kHz */ + int pixel_clock_min, pixel_clock_max; + + /** State for save/restore */ + /** @{ */ + int save_sdvo_mult; + CARD16 save_active_outputs; + struct i830_sdvo_dtd save_input_dtd_1, save_input_dtd_2; + struct i830_sdvo_dtd save_output_dtd[16]; + CARD32 save_SDVOX; + /** @} */ +}; + +/** + * Writes the SDVOB or SDVOC with the given value, but always writes both + * SDVOB and SDVOC to work around apparent hardware issues (according to + * comments in the BIOS). + */ +static void i830_sdvo_write_sdvox(xf86OutputPtr output, CARD32 val) +{ + ScrnInfoPtr pScrn = output->scrn; + I830OutputPrivatePtr intel_output = output->driver_private; + struct i830_sdvo_priv *dev_priv = intel_output->dev_priv; + I830Ptr pI830 = I830PTR(pScrn); + CARD32 bval = val, cval = val; + int i; + + if (dev_priv->output_device == SDVOB) + cval = INREG(SDVOC); + else + bval = INREG(SDVOB); + + /* + * Write the registers twice for luck. Sometimes, + * writing them only once doesn't appear to 'stick'. + * The BIOS does this too. Yay, magic + */ + for (i = 0; i < 2; i++) + { + OUTREG(SDVOB, bval); + POSTING_READ(SDVOB); + OUTREG(SDVOC, cval); + POSTING_READ(SDVOC); + } +} + +/** Read a single byte from the given address on the SDVO device. */ +static Bool i830_sdvo_read_byte(xf86OutputPtr output, int addr, + unsigned char *ch) +{ + I830OutputPrivatePtr intel_output = output->driver_private; + struct i830_sdvo_priv *dev_priv = intel_output->dev_priv; + + if (!xf86I2CReadByte(&dev_priv->d, addr, ch)) { + xf86DrvMsg(intel_output->pI2CBus->scrnIndex, X_ERROR, + "Unable to read from %s slave 0x%02x.\n", + intel_output->pI2CBus->BusName, dev_priv->d.SlaveAddr); + return FALSE; + } + return TRUE; +} + +/** Read a single byte from the given address on the SDVO device. */ +static Bool i830_sdvo_read_byte_quiet(xf86OutputPtr output, int addr, + unsigned char *ch) +{ + I830OutputPrivatePtr intel_output = output->driver_private; + struct i830_sdvo_priv *dev_priv = intel_output->dev_priv; + + return xf86I2CReadByte(&dev_priv->d, addr, ch); +} + +/** Write a single byte to the given address on the SDVO device. */ +static Bool i830_sdvo_write_byte(xf86OutputPtr output, + int addr, unsigned char ch) +{ + I830OutputPrivatePtr intel_output = output->driver_private; + struct i830_sdvo_priv *dev_priv = intel_output->dev_priv; + + if (!xf86I2CWriteByte(&dev_priv->d, addr, ch)) { + xf86DrvMsg(intel_output->pI2CBus->scrnIndex, X_ERROR, + "Unable to write to %s Slave 0x%02x.\n", + intel_output->pI2CBus->BusName, dev_priv->d.SlaveAddr); + return FALSE; + } + return TRUE; +} + + +#define SDVO_CMD_NAME_ENTRY(cmd) {cmd, #cmd} +/** Mapping of command numbers to names, for debug output */ +const static struct _sdvo_cmd_name { + CARD8 cmd; + char *name; +} sdvo_cmd_names[] = { + SDVO_CMD_NAME_ENTRY(SDVO_CMD_RESET), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_DEVICE_CAPS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_FIRMWARE_REV), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_TRAINED_INPUTS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ACTIVE_OUTPUTS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_ACTIVE_OUTPUTS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_IN_OUT_MAP), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_IN_OUT_MAP), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ATTACHED_DISPLAYS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HOT_PLUG_SUPPORT), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_ACTIVE_HOT_PLUG), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ACTIVE_HOT_PLUG), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INTERRUPT_EVENT_SOURCE), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TARGET_INPUT), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TARGET_OUTPUT), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INPUT_TIMINGS_PART1), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INPUT_TIMINGS_PART2), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_INPUT_TIMINGS_PART1), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_INPUT_TIMINGS_PART2), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_INPUT_TIMINGS_PART1), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_OUTPUT_TIMINGS_PART1), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_OUTPUT_TIMINGS_PART2), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OUTPUT_TIMINGS_PART1), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OUTPUT_TIMINGS_PART2), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OUTPUT_PIXEL_CLOCK_RANGE), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPPORTED_CLOCK_RATE_MULTS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_CLOCK_RATE_MULT), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_CLOCK_RATE_MULT), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPPORTED_TV_FORMATS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_TV_FORMAT), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TV_FORMAT), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPPORTED_POWER_STATES), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ENCODER_POWER_STATE), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_ENCODER_POWER_STATE), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TV_RESOLUTION_SUPPORT), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_CONTROL_BUS_SWITCH), +}; + +static I2CSlaveAddr slaveAddr; + +#define SDVO_NAME(dev_priv) ((dev_priv)->output_device == SDVOB ? "SDVO" : "SDVO") +#define SDVO_PRIV(output) ((struct i830_sdvo_priv *) (output)->dev_priv) + +/** + * Writes out the data given in args (up to 8 bytes), followed by the opcode. + */ +static void +i830_sdvo_write_cmd(xf86OutputPtr output, CARD8 cmd, void *args, int args_len) +{ + I830Ptr pI830 = I830PTR(output->scrn); + I830OutputPrivatePtr intel_output = output->driver_private; + struct i830_sdvo_priv *dev_priv = intel_output->dev_priv; + int i; + + if (slaveAddr && slaveAddr != dev_priv->d.SlaveAddr) + ErrorF ("Mismatch slave addr %x != %x\n", slaveAddr, dev_priv->d.SlaveAddr); + + /* Write the SDVO command logging */ + if (pI830->debug_modes) { + xf86DrvMsg(intel_output->pI2CBus->scrnIndex, X_INFO, "%s: W: %02X ", + SDVO_NAME(dev_priv), cmd); + for (i = 0; i < args_len; i++) + LogWrite(1, "%02X ", ((CARD8 *)args)[i]); + for (; i < 8; i++) + LogWrite(1, " "); + for (i = 0; i < sizeof(sdvo_cmd_names) / sizeof(sdvo_cmd_names[0]); + i++) + { + if (cmd == sdvo_cmd_names[i].cmd) { + LogWrite(1, "(%s)", sdvo_cmd_names[i].name); + break; + } + } + if (i == sizeof(sdvo_cmd_names) / sizeof(sdvo_cmd_names[0])) + LogWrite(1, "(%02X)", cmd); + LogWrite(1, "\n"); + } + + /* send the output regs */ + for (i = 0; i < args_len; i++) { + i830_sdvo_write_byte(output, SDVO_I2C_ARG_0 - i, ((CARD8 *)args)[i]); + } + /* blast the command reg */ + i830_sdvo_write_byte(output, SDVO_I2C_OPCODE, cmd); +} + +static const char *cmd_status_names[] = { + "Power on", + "Success", + "Not supported", + "Invalid arg", + "Pending", + "Target not specified", + "Scaling not supported" +}; + +/** + * Reads back response_len bytes from the SDVO device, and returns the status. + */ +static CARD8 +i830_sdvo_read_response(xf86OutputPtr output, void *response, int response_len) +{ + I830Ptr pI830 = I830PTR(output->scrn); + I830OutputPrivatePtr intel_output = output->driver_private; + int i; + CARD8 status; + CARD8 retry = 50; + + while (retry--) { + /* Read the command response */ + for (i = 0; i < response_len; i++) { + i830_sdvo_read_byte(output, SDVO_I2C_RETURN_0 + i, + &((CARD8 *)response)[i]); + } + + /* Read the return status */ + i830_sdvo_read_byte(output, SDVO_I2C_CMD_STATUS, &status); + + /* Write the SDVO command logging */ + if (pI830->debug_modes) { + xf86DrvMsg(intel_output->pI2CBus->scrnIndex, X_INFO, + "%s: R: ", SDVO_NAME(SDVO_PRIV(intel_output))); + for (i = 0; i < response_len; i++) + LogWrite(1, "%02X ", ((CARD8 *)response)[i]); + for (; i < 8; i++) + LogWrite(1, " "); + if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP) { + LogWrite(1, "(%s)", cmd_status_names[status]); + } else { + LogWrite(1, "(??? %d)", status); + } + LogWrite(1, "\n"); + } + + if (status != SDVO_CMD_STATUS_PENDING) + return status; + + intel_output->pI2CBus->I2CUDelay(intel_output->pI2CBus, 50); + } + + return status; +} + +int +i830_sdvo_get_pixel_multiplier(DisplayModePtr pMode) +{ + if (pMode->Clock >= 100000) + return 1; + else if (pMode->Clock >= 50000) + return 2; + else + return 4; +} + +/* Sets the control bus switch to either point at one of the DDC buses or the + * PROM. It resets from the DDC bus back to internal registers at the next I2C + * STOP. PROM access is terminated by accessing an internal register. + */ +static void +i830_sdvo_set_control_bus_switch(xf86OutputPtr output, CARD8 target) +{ + i830_sdvo_write_cmd(output, SDVO_CMD_SET_CONTROL_BUS_SWITCH, &target, 1); +} + +static Bool +i830_sdvo_set_target_input(xf86OutputPtr output, Bool target_0, Bool target_1) +{ + struct i830_sdvo_set_target_input_args targets = {0}; + CARD8 status; + + if (target_0 && target_1) + return SDVO_CMD_STATUS_NOTSUPP; + + if (target_1) + targets.target_1 = 1; + + i830_sdvo_write_cmd(output, SDVO_CMD_SET_TARGET_INPUT, &targets, + sizeof(targets)); + + status = i830_sdvo_read_response(output, NULL, 0); + + return (status == SDVO_CMD_STATUS_SUCCESS); +} + +/** + * Return whether each input is trained. + * + * This function is making an assumption about the layout of the response, + * which should be checked against the docs. + */ +static Bool +i830_sdvo_get_trained_inputs(xf86OutputPtr output, Bool *input_1, Bool *input_2) +{ + struct i830_sdvo_get_trained_inputs_response response; + CARD8 status; + + i830_sdvo_write_cmd(output, SDVO_CMD_GET_TRAINED_INPUTS, NULL, 0); + + status = i830_sdvo_read_response(output, &response, sizeof(response)); + if (status != SDVO_CMD_STATUS_SUCCESS) + return FALSE; + + *input_1 = response.input0_trained; + *input_2 = response.input1_trained; + + return TRUE; +} + +static Bool +i830_sdvo_get_active_outputs(xf86OutputPtr output, + CARD16 *outputs) +{ + CARD8 status; + + i830_sdvo_write_cmd(output, SDVO_CMD_GET_ACTIVE_OUTPUTS, NULL, 0); + status = i830_sdvo_read_response(output, outputs, sizeof(*outputs)); + + return (status == SDVO_CMD_STATUS_SUCCESS); +} + +static Bool +i830_sdvo_set_active_outputs(xf86OutputPtr output, + CARD16 outputs) +{ + CARD8 status; + + i830_sdvo_write_cmd(output, SDVO_CMD_SET_ACTIVE_OUTPUTS, &outputs, + sizeof(outputs)); + status = i830_sdvo_read_response(output, NULL, 0); + + return (status == SDVO_CMD_STATUS_SUCCESS); +} + +static Bool +i830_sdvo_set_encoder_power_state(xf86OutputPtr output, int mode) +{ + CARD8 status; + CARD8 state; + + switch (mode) { + case DPMSModeOn: + state = SDVO_ENCODER_STATE_ON; + break; + case DPMSModeStandby: + state = SDVO_ENCODER_STATE_STANDBY; + break; + case DPMSModeSuspend: + state = SDVO_ENCODER_STATE_SUSPEND; + break; + case DPMSModeOff: + state = SDVO_ENCODER_STATE_OFF; + break; + } + + i830_sdvo_write_cmd(output, SDVO_CMD_SET_ENCODER_POWER_STATE, &state, + sizeof(state)); + status = i830_sdvo_read_response(output, NULL, 0); + + return (status == SDVO_CMD_STATUS_SUCCESS); +} + +/** + * Returns the pixel clock range limits of the current target input in kHz. + */ +static Bool +i830_sdvo_get_input_pixel_clock_range(xf86OutputPtr output, int *clock_min, + int *clock_max) +{ + struct i830_sdvo_pixel_clock_range clocks; + CARD8 status; + + i830_sdvo_write_cmd(output, SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE, NULL, 0); + + status = i830_sdvo_read_response(output, &clocks, sizeof(clocks)); + + if (status != SDVO_CMD_STATUS_SUCCESS) + return FALSE; + + /* Convert the values from units of 10 kHz to kHz. */ + *clock_min = clocks.min * 10; + *clock_max = clocks.max * 10; + + return TRUE; +} + +static Bool +i830_sdvo_set_target_output(xf86OutputPtr output, CARD16 outputs) +{ + CARD8 status; + + i830_sdvo_write_cmd(output, SDVO_CMD_SET_TARGET_OUTPUT, &outputs, + sizeof(outputs)); + + status = i830_sdvo_read_response(output, NULL, 0); + + return (status == SDVO_CMD_STATUS_SUCCESS); +} + +/** Fetches either input or output timings to *dtd, depending on cmd. */ +static Bool +i830_sdvo_get_timing(xf86OutputPtr output, CARD8 cmd, struct i830_sdvo_dtd *dtd) +{ + CARD8 status; + + i830_sdvo_write_cmd(output, cmd, NULL, 0); + + status = i830_sdvo_read_response(output, &dtd->part1, sizeof(dtd->part1)); + if (status != SDVO_CMD_STATUS_SUCCESS) + return FALSE; + + i830_sdvo_write_cmd(output, cmd + 1, NULL, 0); + + status = i830_sdvo_read_response(output, &dtd->part2, sizeof(dtd->part2)); + if (status != SDVO_CMD_STATUS_SUCCESS) + return FALSE; + + return TRUE; +} + +static Bool +i830_sdvo_get_input_timing(xf86OutputPtr output, struct i830_sdvo_dtd *dtd) +{ + return i830_sdvo_get_timing(output, SDVO_CMD_GET_INPUT_TIMINGS_PART1, dtd); +} + +static Bool +i830_sdvo_get_output_timing(xf86OutputPtr output, struct i830_sdvo_dtd *dtd) +{ + return i830_sdvo_get_timing(output, SDVO_CMD_GET_OUTPUT_TIMINGS_PART1, dtd); +} + +/** Sets either input or output timings from *dtd, depending on cmd. */ +static Bool +i830_sdvo_set_timing(xf86OutputPtr output, CARD8 cmd, struct i830_sdvo_dtd *dtd) +{ + CARD8 status; + + i830_sdvo_write_cmd(output, cmd, &dtd->part1, sizeof(dtd->part1)); + status = i830_sdvo_read_response(output, NULL, 0); + if (status != SDVO_CMD_STATUS_SUCCESS) + return FALSE; + + i830_sdvo_write_cmd(output, cmd + 1, &dtd->part2, sizeof(dtd->part2)); + status = i830_sdvo_read_response(output, NULL, 0); + if (status != SDVO_CMD_STATUS_SUCCESS) + return FALSE; + + return TRUE; +} + +static Bool +i830_sdvo_set_input_timing(xf86OutputPtr output, struct i830_sdvo_dtd *dtd) +{ + return i830_sdvo_set_timing(output, SDVO_CMD_SET_INPUT_TIMINGS_PART1, dtd); +} + +static Bool +i830_sdvo_set_output_timing(xf86OutputPtr output, struct i830_sdvo_dtd *dtd) +{ + return i830_sdvo_set_timing(output, SDVO_CMD_SET_OUTPUT_TIMINGS_PART1, dtd); +} + +#if 0 +static Bool +i830_sdvo_create_preferred_input_timing(xf86OutputPtr output, CARD16 clock, + CARD16 width, CARD16 height) +{ + struct i830_sdvo_priv *dev_priv = output->dev_priv; + struct i830_sdvo_preferred_input_timing_args args; + + args.clock = clock; + args.width = width; + args.height = height; + i830_sdvo_write_cmd(output, SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING, + &args, sizeof(args)); + status = i830_sdvo_read_response(output, NULL, 0); + if (status != SDVO_CMD_STATUS_SUCCESS) + return FALSE; + + return TRUE; +} + +static Bool +i830_sdvo_get_preferred_input_timing(I830OutputPtr output, + struct i830_sdvo_dtd *dtd) +{ + struct i830_sdvo_priv *dev_priv = output->dev_priv; + + i830_sdvo_write_cmd(output, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1, + NULL, 0); + + status = i830_sdvo_read_response(output, &dtd->part1, sizeof(dtd->part1)); + if (status != SDVO_CMD_STATUS_SUCCESS) + return FALSE; + + i830_sdvo_write_cmd(output, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2, + NULL, 0); + + status = i830_sdvo_read_response(output, &dtd->part2, sizeof(dtd->part2)); + if (status != SDVO_CMD_STATUS_SUCCESS) + return FALSE; + + return TRUE; +} +#endif + +/** Returns the SDVO_CLOCK_RATE_MULT_* for the current clock multiplier */ +static int +i830_sdvo_get_clock_rate_mult(xf86OutputPtr output) +{ + I830OutputPrivatePtr intel_output = output->driver_private; + struct i830_sdvo_priv *dev_priv = intel_output->dev_priv; + CARD8 response; + CARD8 status; + + i830_sdvo_write_cmd(output, SDVO_CMD_GET_CLOCK_RATE_MULT, NULL, 0); + status = i830_sdvo_read_response(output, &response, 1); + + if (status != SDVO_CMD_STATUS_SUCCESS) { + xf86DrvMsg(dev_priv->d.pI2CBus->scrnIndex, X_ERROR, + "Couldn't get SDVO clock rate multiplier\n"); + return SDVO_CLOCK_RATE_MULT_1X; + } else { + xf86DrvMsg(dev_priv->d.pI2CBus->scrnIndex, X_INFO, + "Current clock rate multiplier: %d\n", response); + } + + return response; +} + +/** + * Sets the current clock multiplier. + * + * This has to match with the settings in the DPLL/SDVO reg when the output + * is actually turned on. + */ +static Bool +i830_sdvo_set_clock_rate_mult(xf86OutputPtr output, CARD8 val) +{ + CARD8 status; + + i830_sdvo_write_cmd(output, SDVO_CMD_SET_CLOCK_RATE_MULT, &val, 1); + status = i830_sdvo_read_response(output, NULL, 0); + if (status != SDVO_CMD_STATUS_SUCCESS) + return FALSE; + + return TRUE; +} + +static Bool +i830_sdvo_mode_fixup(xf86OutputPtr output, DisplayModePtr mode, + DisplayModePtr adjusted_mode) +{ + /* Make the CRTC code factor in the SDVO pixel multiplier. The SDVO + * device will be told of the multiplier during mode_set. + */ + adjusted_mode->Clock *= i830_sdvo_get_pixel_multiplier(mode); + + return TRUE; +} + +static void +i830_sdvo_mode_set(xf86OutputPtr output, DisplayModePtr mode, + DisplayModePtr adjusted_mode) +{ + ScrnInfoPtr pScrn = output->scrn; + I830Ptr pI830 = I830PTR(pScrn); + I830OutputPrivatePtr intel_output = output->driver_private; + struct i830_sdvo_priv *dev_priv = intel_output->dev_priv; + xf86CrtcPtr crtc = output->crtc; + I830CrtcPrivatePtr intel_crtc = crtc->driver_private; + CARD32 sdvox; + int sdvo_pixel_multiply; + CARD16 width, height; + CARD16 h_blank_len, h_sync_len, v_blank_len, v_sync_len; + CARD16 h_sync_offset, v_sync_offset; + struct i830_sdvo_dtd output_dtd; + CARD16 no_outputs; + + no_outputs = 0; + + if (!mode) + return; + width = mode->CrtcHDisplay; + height = mode->CrtcVDisplay; + + /* do some mode translations */ + h_blank_len = mode->CrtcHBlankEnd - mode->CrtcHBlankStart; + h_sync_len = mode->CrtcHSyncEnd - mode->CrtcHSyncStart; + + v_blank_len = mode->CrtcVBlankEnd - mode->CrtcVBlankStart; + v_sync_len = mode->CrtcVSyncEnd - mode->CrtcVSyncStart; + + h_sync_offset = mode->CrtcHSyncStart - mode->CrtcHBlankStart; + v_sync_offset = mode->CrtcVSyncStart - mode->CrtcVBlankStart; + + output_dtd.part1.clock = mode->Clock / 10; + output_dtd.part1.h_active = width & 0xff; + output_dtd.part1.h_blank = h_blank_len & 0xff; + output_dtd.part1.h_high = (((width >> 8) & 0xf) << 4) | + ((h_blank_len >> 8) & 0xf); + output_dtd.part1.v_active = height & 0xff; + output_dtd.part1.v_blank = v_blank_len & 0xff; + output_dtd.part1.v_high = (((height >> 8) & 0xf) << 4) | + ((v_blank_len >> 8) & 0xf); + + output_dtd.part2.h_sync_off = h_sync_offset; + output_dtd.part2.h_sync_width = h_sync_len & 0xff; + output_dtd.part2.v_sync_off_width = (v_sync_offset & 0xf) << 4 | + (v_sync_len & 0xf); + output_dtd.part2.sync_off_width_high = ((h_sync_offset & 0x300) >> 2) | + ((h_sync_len & 0x300) >> 4) | ((v_sync_offset & 0x30) >> 2) | + ((v_sync_len & 0x30) >> 4); + + output_dtd.part2.dtd_flags = 0x18; + if (mode->Flags & V_PHSYNC) + output_dtd.part2.dtd_flags |= 0x2; + if (mode->Flags & V_PVSYNC) + output_dtd.part2.dtd_flags |= 0x4; + + output_dtd.part2.sdvo_flags = 0; + output_dtd.part2.v_sync_off_high = v_sync_offset & 0xc0; + output_dtd.part2.reserved = 0; + + /* Set the output timing to the screen */ + i830_sdvo_set_target_output(output, dev_priv->active_outputs); + i830_sdvo_set_output_timing(output, &output_dtd); + + /* Set the input timing to the screen. Assume always input 0. */ + i830_sdvo_set_target_input(output, TRUE, FALSE); + + /* We would like to use i830_sdvo_create_preferred_input_timing() to + * provide the device with a timing it can support, if it supports that + * feature. However, presumably we would need to adjust the CRTC to output + * the preferred timing, and we don't support that currently. + */ +#if 0 + success = i830_sdvo_create_preferred_input_timing(output, clock, + width, height); + if (success) { + struct i830_sdvo_dtd *input_dtd; + + i830_sdvo_get_preferred_input_timing(output, &input_dtd); + i830_sdvo_set_input_timing(output, &input_dtd); + } +#else + i830_sdvo_set_input_timing(output, &output_dtd); +#endif + + switch (i830_sdvo_get_pixel_multiplier(mode)) { + case 1: + i830_sdvo_set_clock_rate_mult(output, SDVO_CLOCK_RATE_MULT_1X); + break; + case 2: + i830_sdvo_set_clock_rate_mult(output, SDVO_CLOCK_RATE_MULT_2X); + break; + case 4: + i830_sdvo_set_clock_rate_mult(output, SDVO_CLOCK_RATE_MULT_4X); + break; + } + + /* Set the SDVO control regs. */ + if (IS_I965GM(pI830)) { + sdvox = SDVO_BORDER_ENABLE; + } else { + sdvox = INREG(dev_priv->output_device); + switch (dev_priv->output_device) { + case SDVOB: + sdvox &= SDVOB_PRESERVE_MASK; + break; + case SDVOC: + sdvox &= SDVOC_PRESERVE_MASK; + break; + } + sdvox |= (9 << 19) | SDVO_BORDER_ENABLE; + } + if (intel_crtc->pipe == 1) + sdvox |= SDVO_PIPE_B_SELECT; + + sdvo_pixel_multiply = i830_sdvo_get_pixel_multiplier(mode); + if (IS_I965G(pI830)) { + /* done in crtc_mode_set as the dpll_md reg must be written early */ + } else if (IS_I945G(pI830) || IS_I945GM(pI830) || IS_G33CLASS(pI830)) { + /* done in crtc_mode_set as it lives inside the dpll register */ + } else { + sdvox |= (sdvo_pixel_multiply - 1) << SDVO_PORT_MULTIPLY_SHIFT; + } + + i830_sdvo_write_sdvox(output, sdvox); +} + +static void +i830_sdvo_dpms(xf86OutputPtr output, int mode) +{ + ScrnInfoPtr pScrn = output->scrn; + I830OutputPrivatePtr intel_output = output->driver_private; + struct i830_sdvo_priv *dev_priv = intel_output->dev_priv; + I830Ptr pI830 = I830PTR(pScrn); + CARD32 temp; + + if (mode != DPMSModeOn) { + i830_sdvo_set_active_outputs(output, 0); + if (0) + i830_sdvo_set_encoder_power_state(output, mode); + + if (mode == DPMSModeOff) { + temp = INREG(dev_priv->output_device); + if ((temp & SDVO_ENABLE) != 0) { + i830_sdvo_write_sdvox(output, temp & ~SDVO_ENABLE); + } + } + } else { + Bool input1, input2; + int i; + CARD8 status; + + temp = INREG(dev_priv->output_device); + if ((temp & SDVO_ENABLE) == 0) + i830_sdvo_write_sdvox(output, temp | SDVO_ENABLE); + for (i = 0; i < 2; i++) + i830WaitForVblank(pScrn); + + status = i830_sdvo_get_trained_inputs(output, &input1, &input2); + + /* Warn if the device reported failure to sync. */ + if (status == SDVO_CMD_STATUS_SUCCESS && !input1) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "First %s output reported failure to sync\n", + SDVO_NAME(dev_priv)); + } + + if (0) + i830_sdvo_set_encoder_power_state(output, mode); + i830_sdvo_set_active_outputs(output, dev_priv->active_outputs); + } +} + +static void +i830_sdvo_save(xf86OutputPtr output) +{ + ScrnInfoPtr pScrn = output->scrn; + I830OutputPrivatePtr intel_output = output->driver_private; + struct i830_sdvo_priv *dev_priv = intel_output->dev_priv; + I830Ptr pI830 = I830PTR(pScrn); + int o; + + /* XXX: We should save the in/out mapping. */ + + dev_priv->save_sdvo_mult = i830_sdvo_get_clock_rate_mult(output); + i830_sdvo_get_active_outputs(output, &dev_priv->save_active_outputs); + + if (dev_priv->caps.sdvo_inputs_mask & 0x1) { + i830_sdvo_set_target_input(output, TRUE, FALSE); + i830_sdvo_get_input_timing(output, &dev_priv->save_input_dtd_1); + } + + if (dev_priv->caps.sdvo_inputs_mask & 0x2) { + i830_sdvo_set_target_input(output, FALSE, TRUE); + i830_sdvo_get_input_timing(output, &dev_priv->save_input_dtd_2); + } + + for (o = SDVO_OUTPUT_FIRST; o <= SDVO_OUTPUT_LAST; o++) + { + CARD16 this_output = (1 << o); + if (dev_priv->caps.output_flags & this_output) + { + i830_sdvo_set_target_output(output, this_output); + i830_sdvo_get_output_timing(output, &dev_priv->save_output_dtd[o]); + } + } + + dev_priv->save_SDVOX = INREG(dev_priv->output_device); +} + +static void +i830_sdvo_restore(xf86OutputPtr output) +{ + ScrnInfoPtr pScrn = output->scrn; + I830OutputPrivatePtr intel_output = output->driver_private; + struct i830_sdvo_priv *dev_priv = intel_output->dev_priv; + int o; + int i; + Bool input1, input2; + CARD8 status; + + i830_sdvo_set_active_outputs(output, 0); + + for (o = SDVO_OUTPUT_FIRST; o <= SDVO_OUTPUT_LAST; o++) + { + CARD16 this_output = (1 << o); + if (dev_priv->caps.output_flags & this_output) + { + i830_sdvo_set_target_output(output, this_output); + i830_sdvo_set_output_timing(output, &dev_priv->save_output_dtd[o]); + } + } + + if (dev_priv->caps.sdvo_inputs_mask & 0x1) { + i830_sdvo_set_target_input(output, TRUE, FALSE); + i830_sdvo_set_input_timing(output, &dev_priv->save_input_dtd_1); + } + + if (dev_priv->caps.sdvo_inputs_mask & 0x2) { + i830_sdvo_set_target_input(output, FALSE, TRUE); + i830_sdvo_set_input_timing(output, &dev_priv->save_input_dtd_2); + } + + i830_sdvo_set_clock_rate_mult(output, dev_priv->save_sdvo_mult); + + i830_sdvo_write_sdvox(output, dev_priv->save_SDVOX); + + if (dev_priv->save_SDVOX & SDVO_ENABLE) + { + for (i = 0; i < 2; i++) + i830WaitForVblank(pScrn); + status = i830_sdvo_get_trained_inputs(output, &input1, &input2); + if (status == SDVO_CMD_STATUS_SUCCESS && !input1) + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "First %s output reported failure to sync\n", + SDVO_NAME(dev_priv)); + } + + i830_sdvo_set_active_outputs(output, dev_priv->save_active_outputs); +} + +static int +i830_sdvo_mode_valid(xf86OutputPtr output, DisplayModePtr pMode) +{ + I830OutputPrivatePtr intel_output = output->driver_private; + struct i830_sdvo_priv *dev_priv = intel_output->dev_priv; + + if (pMode->Flags & V_DBLSCAN) + return MODE_NO_DBLESCAN; + + if (dev_priv->pixel_clock_min > pMode->Clock) + return MODE_CLOCK_HIGH; + + if (dev_priv->pixel_clock_max < pMode->Clock) + return MODE_CLOCK_LOW; + + return MODE_OK; +} + +static Bool +i830_sdvo_get_capabilities(xf86OutputPtr output, struct i830_sdvo_caps *caps) +{ + CARD8 status; + + i830_sdvo_write_cmd(output, SDVO_CMD_GET_DEVICE_CAPS, NULL, 0); + status = i830_sdvo_read_response(output, caps, sizeof(*caps)); + if (status != SDVO_CMD_STATUS_SUCCESS) + return FALSE; + + return TRUE; +} + +/** Forces the device over to the real I2C bus and uses its GetByte */ +static Bool +i830_sdvo_ddc_i2c_get_byte(I2CDevPtr d, I2CByte *data, Bool last) +{ + xf86OutputPtr output = d->pI2CBus->DriverPrivate.ptr; + I830OutputPrivatePtr intel_output = output->driver_private; + I2CBusPtr i2cbus = intel_output->pI2CBus, savebus; + Bool ret; + + savebus = d->pI2CBus; + d->pI2CBus = i2cbus; + ret = i2cbus->I2CGetByte(d, data, last); + d->pI2CBus = savebus; + + return ret; +} + +/** Forces the device over to the real I2C bus and uses its PutByte */ +static Bool +i830_sdvo_ddc_i2c_put_byte(I2CDevPtr d, I2CByte c) +{ + xf86OutputPtr output = d->pI2CBus->DriverPrivate.ptr; + I830OutputPrivatePtr intel_output = output->driver_private; + I2CBusPtr i2cbus = intel_output->pI2CBus, savebus; + Bool ret; + + savebus = d->pI2CBus; + d->pI2CBus = i2cbus; + ret = i2cbus->I2CPutByte(d, c); + d->pI2CBus = savebus; + + return ret; +} + +/** + * Sets the control bus over to DDC before sending the start on the real I2C + * bus. + * + * The control bus will flip back at the stop following the start executed + * here. + */ +static Bool +i830_sdvo_ddc_i2c_start(I2CBusPtr b, int timeout) +{ + xf86OutputPtr output = b->DriverPrivate.ptr; + I830OutputPrivatePtr intel_output = output->driver_private; + I2CBusPtr i2cbus = intel_output->pI2CBus; + + i830_sdvo_set_control_bus_switch(output, SDVO_CONTROL_BUS_DDC2); + return i2cbus->I2CStart(i2cbus, timeout); +} + +/** Forces the device over to the real SDVO bus and sends a stop to it. */ +static void +i830_sdvo_ddc_i2c_stop(I2CDevPtr d) +{ + xf86OutputPtr output = d->pI2CBus->DriverPrivate.ptr; + I830OutputPrivatePtr intel_output = output->driver_private; + I2CBusPtr i2cbus = intel_output->pI2CBus, savebus; + + savebus = d->pI2CBus; + d->pI2CBus = i2cbus; + i2cbus->I2CStop(d); + d->pI2CBus = savebus; +} + +/** + * Mirrors xf86i2c I2CAddress, using the bus's (wrapped) methods rather than + * the default methods. + * + * This ensures that our start commands always get wrapped with control bus + * switches. xf86i2c should probably be fixed to do this. + */ +static Bool +i830_sdvo_ddc_i2c_address(I2CDevPtr d, I2CSlaveAddr addr) +{ + if (d->pI2CBus->I2CStart(d->pI2CBus, d->StartTimeout)) { + if (d->pI2CBus->I2CPutByte(d, addr & 0xFF)) { + if ((addr & 0xF8) != 0xF0 && + (addr & 0xFE) != 0x00) + return TRUE; + + if (d->pI2CBus->I2CPutByte(d, (addr >> 8) & 0xFF)) + return TRUE; + } + + d->pI2CBus->I2CStop(d); + } + + return FALSE; +} + +static void +i830_sdvo_dump_cmd(xf86OutputPtr output, int opcode) +{ + CARD8 response[8]; + + i830_sdvo_write_cmd(output, opcode, NULL, 0); + i830_sdvo_read_response(output, response, 8); +} + +static void +i830_sdvo_dump_device(xf86OutputPtr output) +{ + I830OutputPrivatePtr intel_output = output->driver_private; + struct i830_sdvo_priv *dev_priv = intel_output->dev_priv; + + ErrorF("Dump %s\n", dev_priv->d.DevName); + i830_sdvo_dump_cmd(output, SDVO_CMD_GET_DEVICE_CAPS); + i830_sdvo_dump_cmd(output, SDVO_CMD_GET_FIRMWARE_REV); + i830_sdvo_dump_cmd(output, SDVO_CMD_GET_TRAINED_INPUTS); + i830_sdvo_dump_cmd(output, SDVO_CMD_GET_ACTIVE_OUTPUTS); + i830_sdvo_dump_cmd(output, SDVO_CMD_GET_IN_OUT_MAP); + i830_sdvo_dump_cmd(output, SDVO_CMD_GET_ATTACHED_DISPLAYS); + i830_sdvo_dump_cmd(output, SDVO_CMD_GET_HOT_PLUG_SUPPORT); + i830_sdvo_dump_cmd(output, SDVO_CMD_GET_ACTIVE_HOT_PLUG); + i830_sdvo_dump_cmd(output, SDVO_CMD_GET_INTERRUPT_EVENT_SOURCE); + i830_sdvo_dump_cmd(output, SDVO_CMD_GET_INPUT_TIMINGS_PART1); + i830_sdvo_dump_cmd(output, SDVO_CMD_GET_INPUT_TIMINGS_PART2); + i830_sdvo_dump_cmd(output, SDVO_CMD_GET_OUTPUT_TIMINGS_PART1); + i830_sdvo_dump_cmd(output, SDVO_CMD_GET_OUTPUT_TIMINGS_PART2); + i830_sdvo_dump_cmd(output, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1); + i830_sdvo_dump_cmd(output, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2); + i830_sdvo_dump_cmd(output, SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE); + i830_sdvo_dump_cmd(output, SDVO_CMD_GET_OUTPUT_PIXEL_CLOCK_RANGE); + i830_sdvo_dump_cmd(output, SDVO_CMD_GET_SUPPORTED_CLOCK_RATE_MULTS); + i830_sdvo_dump_cmd(output, SDVO_CMD_GET_CLOCK_RATE_MULT); + i830_sdvo_dump_cmd(output, SDVO_CMD_GET_SUPPORTED_TV_FORMATS); + i830_sdvo_dump_cmd(output, SDVO_CMD_GET_TV_FORMAT); +} + +void +i830_sdvo_dump(ScrnInfoPtr pScrn) +{ + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + int i; + + for (i = 0; i < xf86_config->num_output; i++) + { + xf86OutputPtr output = xf86_config->output[i]; + I830OutputPrivatePtr intel_output = output->driver_private; + + if (intel_output->type == I830_OUTPUT_SDVO) + i830_sdvo_dump_device(output); + } +} + +/** + * Asks the SDVO device if any displays are currently connected. + * + * This interface will need to be augmented, since we could potentially have + * multiple displays connected, and the caller will also probably want to know + * what type of display is connected. But this is enough for the moment. + * + * Takes 14ms on average on my i945G. + */ +static xf86OutputStatus +i830_sdvo_detect(xf86OutputPtr output) +{ + CARD8 response[2]; + CARD8 status; + + i830_sdvo_write_cmd(output, SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0); + status = i830_sdvo_read_response(output, &response, 2); + + if (status != SDVO_CMD_STATUS_SUCCESS) + return XF86OutputStatusUnknown; + + if (response[0] != 0 || response[1] != 0) + return XF86OutputStatusConnected; + else + return XF86OutputStatusDisconnected; +} + +static DisplayModePtr +i830_sdvo_get_modes(xf86OutputPtr output) +{ + ScrnInfoPtr pScrn = output->scrn; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + DisplayModePtr modes; + xf86OutputPtr crt; + + modes = i830_ddc_get_modes(output); + if (modes != NULL) + return modes; + + /* Mac mini hack. On this device, I get DDC through the analog, which + * load-detects as disconnected. I fail to DDC through the SDVO DDC, + * but it does load-detect as connected. So, just steal the DDC bits from + * analog when we fail at finding it the right way. + */ + crt = xf86_config->output[0]; + if (crt->funcs->detect(crt) == XF86OutputStatusDisconnected) { + return crt->funcs->get_modes(crt); + } + + return NULL; +} + +static void +i830_sdvo_destroy (xf86OutputPtr output) +{ + I830OutputPrivatePtr intel_output = output->driver_private; + + if (intel_output) + { + struct i830_sdvo_priv *dev_priv = intel_output->dev_priv; + + xf86DestroyI2CBusRec (intel_output->pDDCBus, FALSE, FALSE); + xf86DestroyI2CDevRec (&dev_priv->d, FALSE); + xf86DestroyI2CBusRec (dev_priv->d.pI2CBus, TRUE, TRUE); + xfree (intel_output); + } +} + +static const xf86OutputFuncsRec i830_sdvo_output_funcs = { + .dpms = i830_sdvo_dpms, + .save = i830_sdvo_save, + .restore = i830_sdvo_restore, + .mode_valid = i830_sdvo_mode_valid, + .mode_fixup = i830_sdvo_mode_fixup, + .prepare = i830_output_prepare, + .mode_set = i830_sdvo_mode_set, + .commit = i830_output_commit, + .detect = i830_sdvo_detect, + .get_modes = i830_sdvo_get_modes, + .destroy = i830_sdvo_destroy +}; + +void +i830_sdvo_init(ScrnInfoPtr pScrn, int output_device) +{ + xf86OutputPtr output; + I830OutputPrivatePtr intel_output; + struct i830_sdvo_priv *dev_priv; + int i; + unsigned char ch[0x40]; + I2CBusPtr i2cbus = NULL, ddcbus; + char name[60]; + char *name_prefix; + char *name_suffix; + + output = xf86OutputCreate (pScrn, &i830_sdvo_output_funcs,NULL); + if (!output) + return; + intel_output = xnfcalloc (sizeof (I830OutputPrivateRec) + + sizeof (struct i830_sdvo_priv), 1); + if (!intel_output) + { + xf86OutputDestroy (output); + return; + } + output->driver_private = intel_output; + output->interlaceAllowed = FALSE; + output->doubleScanAllowed = FALSE; + + dev_priv = (struct i830_sdvo_priv *) (intel_output + 1); + intel_output->type = I830_OUTPUT_SDVO; + intel_output->pipe_mask = ((1 << 0) | (1 << 1)); + intel_output->clone_mask = (1 << I830_OUTPUT_SDVO); + + /* While it's the same bus, we just initialize a new copy to avoid trouble + * with tracking refcounting ourselves, since the XFree86 DDX bits don't. + */ + if (output_device == SDVOB) + I830I2CInit(pScrn, &i2cbus, GPIOE, "SDVOCTRL_E for SDVOB"); + else + I830I2CInit(pScrn, &i2cbus, GPIOE, "SDVOCTRL_E for SDVOC"); + + if (i2cbus == NULL) + { + xf86OutputDestroy (output); + return; + } + + if (output_device == SDVOB) { + dev_priv->d.DevName = "SDVO Controller B"; + dev_priv->d.SlaveAddr = 0x70; + name_suffix="-1"; + } else { + dev_priv->d.DevName = "SDVO Controller C"; + dev_priv->d.SlaveAddr = 0x72; + name_suffix="-2"; + } + dev_priv->d.pI2CBus = i2cbus; + dev_priv->d.DriverPrivate.ptr = output; + dev_priv->output_device = output_device; + + if (!xf86I2CDevInit(&dev_priv->d)) + { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to initialize %s I2C device\n", + SDVO_NAME(dev_priv)); + xf86OutputDestroy (output); + return; + } + + intel_output->pI2CBus = i2cbus; + intel_output->dev_priv = dev_priv; + + /* Read the regs to test if we can talk to the device */ + for (i = 0; i < 0x40; i++) { + if (!i830_sdvo_read_byte_quiet(output, i, &ch[i])) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "No SDVO device found on SDVO%c\n", + output_device == SDVOB ? 'B' : 'C'); + xf86OutputDestroy (output); + return; + } + } + + /* Set up our wrapper I2C bus for DDC. It acts just like the regular I2C + * bus, except that it does the control bus switch to DDC mode before every + * Start. While we only need to do it at Start after every Stop after a + * Start, extra attempts should be harmless. + */ + ddcbus = xf86CreateI2CBusRec(); + if (ddcbus == NULL) + { + xf86OutputDestroy (output); + return; + } + if (output_device == SDVOB) + ddcbus->BusName = "SDVOB DDC Bus"; + else + ddcbus->BusName = "SDVOC DDC Bus"; + ddcbus->scrnIndex = i2cbus->scrnIndex; + ddcbus->I2CGetByte = i830_sdvo_ddc_i2c_get_byte; + ddcbus->I2CPutByte = i830_sdvo_ddc_i2c_put_byte; + ddcbus->I2CStart = i830_sdvo_ddc_i2c_start; + ddcbus->I2CStop = i830_sdvo_ddc_i2c_stop; + ddcbus->I2CAddress = i830_sdvo_ddc_i2c_address; + ddcbus->DriverPrivate.ptr = output; + + if (!xf86I2CBusInit(ddcbus)) + { + xf86OutputDestroy (output); + return; + } + + intel_output->pI2CBus = i2cbus; + intel_output->pDDCBus = ddcbus; + intel_output->dev_priv = dev_priv; + + i830_sdvo_get_capabilities(output, &dev_priv->caps); + + memset(&dev_priv->active_outputs, 0, sizeof(dev_priv->active_outputs)); + if (dev_priv->caps.output_flags & SDVO_OUTPUT_TMDS0) + { + dev_priv->active_outputs = SDVO_OUTPUT_TMDS0; + output->subpixel_order = SubPixelHorizontalRGB; + name_prefix="TMDS"; + } + else if (dev_priv->caps.output_flags & SDVO_OUTPUT_TMDS1) + { + dev_priv->active_outputs = SDVO_OUTPUT_TMDS1; + output->subpixel_order = SubPixelHorizontalRGB; + name_prefix="TMDS"; + } + else if (dev_priv->caps.output_flags & SDVO_OUTPUT_RGB0) + { + dev_priv->active_outputs = SDVO_OUTPUT_RGB0; + output->subpixel_order = SubPixelHorizontalRGB; + name_prefix="VGA"; + } + else if (dev_priv->caps.output_flags & SDVO_OUTPUT_RGB1) + { + dev_priv->active_outputs = SDVO_OUTPUT_RGB1; + output->subpixel_order = SubPixelHorizontalRGB; + name_prefix="VGA"; + } + else + { + unsigned char bytes[2]; + + memcpy (bytes, &dev_priv->caps.output_flags, 2); + xf86DrvMsg(intel_output->pI2CBus->scrnIndex, X_ERROR, + "%s: No active TMDS outputs (0x%02x%02x)\n", + SDVO_NAME(dev_priv), + bytes[0], bytes[1]); + name_prefix="Unknown"; + } + strcpy (name, name_prefix); + strcat (name, name_suffix); + if (!xf86OutputRename (output, name)) + { + xf86OutputDestroy (output); + return; + } + + + /* Set the input timing to the screen. Assume always input 0. */ + i830_sdvo_set_target_input(output, TRUE, FALSE); + + i830_sdvo_get_input_pixel_clock_range(output, &dev_priv->pixel_clock_min, + &dev_priv->pixel_clock_max); + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "%s device VID/DID: %02X:%02X.%02X, " + "clock range %.1fMHz - %.1fMHz, " + "input 1: %c, input 2: %c, " + "output 1: %c, output 2: %c\n", + SDVO_NAME(dev_priv), + dev_priv->caps.vendor_id, dev_priv->caps.device_id, + dev_priv->caps.device_rev_id, + dev_priv->pixel_clock_min / 1000.0, + dev_priv->pixel_clock_max / 1000.0, + (dev_priv->caps.sdvo_inputs_mask & 0x1) ? 'Y' : 'N', + (dev_priv->caps.sdvo_inputs_mask & 0x2) ? 'Y' : 'N', + dev_priv->caps.output_flags & (SDVO_OUTPUT_RGB0 | SDVO_OUTPUT_TMDS0) ? 'Y' : 'N', + dev_priv->caps.output_flags & (SDVO_OUTPUT_RGB1 | SDVO_OUTPUT_TMDS1) ? 'Y' : 'N'); +} diff --git a/driver/xf86-video-intel/src/i830_sdvo.h b/driver/xf86-video-intel/src/i830_sdvo.h new file mode 100644 index 000000000..1368e43b3 --- /dev/null +++ b/driver/xf86-video-intel/src/i830_sdvo.h @@ -0,0 +1,35 @@ +/* + * Copyright © 2006 Intel Corporation + * + * 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 + * THE AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +void +i830_sdvo_init(ScrnInfoPtr pScrn, int output_device); + +int +i830_sdvo_get_pixel_multiplier(DisplayModePtr pMode); + +void +i830_sdvo_dump(ScrnInfoPtr pScrn); diff --git a/driver/xf86-video-intel/src/i830_sdvo_regs.h b/driver/xf86-video-intel/src/i830_sdvo_regs.h new file mode 100644 index 000000000..72e58a00c --- /dev/null +++ b/driver/xf86-video-intel/src/i830_sdvo_regs.h @@ -0,0 +1,329 @@ +/* + * Copyright © 2006 Intel Corporation + * + * 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 + * THE AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +/** + * @file SDVO command definitions and structures. + */ + +#define SDVO_OUTPUT_FIRST (0) +#define SDVO_OUTPUT_TMDS0 (1 << 0) +#define SDVO_OUTPUT_RGB0 (1 << 1) +#define SDVO_OUTPUT_CVBS0 (1 << 2) +#define SDVO_OUTPUT_SVID0 (1 << 3) +#define SDVO_OUTPUT_YPRPB0 (1 << 4) +#define SDVO_OUTPUT_SCART0 (1 << 5) +#define SDVO_OUTPUT_LVDS0 (1 << 6) +#define SDVO_OUTPUT_TMDS1 (1 << 8) +#define SDVO_OUTPUT_RGB1 (1 << 9) +#define SDVO_OUTPUT_CVBS1 (1 << 10) +#define SDVO_OUTPUT_SVID1 (1 << 11) +#define SDVO_OUTPUT_YPRPB1 (1 << 12) +#define SDVO_OUTPUT_SCART1 (1 << 13) +#define SDVO_OUTPUT_LVDS1 (1 << 14) +#define SDVO_OUTPUT_LAST (14) + +struct i830_sdvo_caps { + CARD8 vendor_id; + CARD8 device_id; + CARD8 device_rev_id; + CARD8 sdvo_version_major; + CARD8 sdvo_version_minor; + unsigned int sdvo_inputs_mask:2; + unsigned int smooth_scaling:1; + unsigned int sharp_scaling:1; + unsigned int up_scaling:1; + unsigned int down_scaling:1; + unsigned int stall_support:1; + unsigned int pad:1; + CARD16 output_flags; +} __attribute__((packed)); + +/** This matches the EDID DTD structure, more or less */ +struct i830_sdvo_dtd { + struct { + CARD16 clock; /**< pixel clock, in 10kHz units */ + CARD8 h_active; /**< lower 8 bits (pixels) */ + CARD8 h_blank; /**< lower 8 bits (pixels) */ + CARD8 h_high; /**< upper 4 bits each h_active, h_blank */ + CARD8 v_active; /**< lower 8 bits (lines) */ + CARD8 v_blank; /**< lower 8 bits (lines) */ + CARD8 v_high; /**< upper 4 bits each v_active, v_blank */ + } part1; + + struct { + CARD8 h_sync_off; /**< lower 8 bits, from hblank start */ + CARD8 h_sync_width; /**< lower 8 bits (pixels) */ + /** lower 4 bits each vsync offset, vsync width */ + CARD8 v_sync_off_width; + /** + * 2 high bits of hsync offset, 2 high bits of hsync width, + * bits 4-5 of vsync offset, and 2 high bits of vsync width. + */ + CARD8 sync_off_width_high; + CARD8 dtd_flags; + CARD8 sdvo_flags; + /** bits 6-7 of vsync offset at bits 6-7 */ + CARD8 v_sync_off_high; + CARD8 reserved; + } part2; +} __attribute__((packed)); + +struct i830_sdvo_pixel_clock_range { + CARD16 min; /**< pixel clock, in 10kHz units */ + CARD16 max; /**< pixel clock, in 10kHz units */ +} __attribute__((packed)); + +struct i830_sdvo_preferred_input_timing_args { + CARD16 clock; + CARD16 width; + CARD16 height; +} __attribute__((packed)); + +/* I2C registers for SDVO */ +#define SDVO_I2C_ARG_0 0x07 +#define SDVO_I2C_ARG_1 0x06 +#define SDVO_I2C_ARG_2 0x05 +#define SDVO_I2C_ARG_3 0x04 +#define SDVO_I2C_ARG_4 0x03 +#define SDVO_I2C_ARG_5 0x02 +#define SDVO_I2C_ARG_6 0x01 +#define SDVO_I2C_ARG_7 0x00 +#define SDVO_I2C_OPCODE 0x08 +#define SDVO_I2C_CMD_STATUS 0x09 +#define SDVO_I2C_RETURN_0 0x0a +#define SDVO_I2C_RETURN_1 0x0b +#define SDVO_I2C_RETURN_2 0x0c +#define SDVO_I2C_RETURN_3 0x0d +#define SDVO_I2C_RETURN_4 0x0e +#define SDVO_I2C_RETURN_5 0x0f +#define SDVO_I2C_RETURN_6 0x10 +#define SDVO_I2C_RETURN_7 0x11 +#define SDVO_I2C_VENDOR_BEGIN 0x20 + +/* Status results */ +#define SDVO_CMD_STATUS_POWER_ON 0x0 +#define SDVO_CMD_STATUS_SUCCESS 0x1 +#define SDVO_CMD_STATUS_NOTSUPP 0x2 +#define SDVO_CMD_STATUS_INVALID_ARG 0x3 +#define SDVO_CMD_STATUS_PENDING 0x4 +#define SDVO_CMD_STATUS_TARGET_NOT_SPECIFIED 0x5 +#define SDVO_CMD_STATUS_SCALING_NOT_SUPP 0x6 + +/* SDVO commands, argument/result registers */ + +#define SDVO_CMD_RESET 0x01 + +/** Returns a struct i830_sdvo_caps */ +#define SDVO_CMD_GET_DEVICE_CAPS 0x02 + +#define SDVO_CMD_GET_FIRMWARE_REV 0x86 +# define SDVO_DEVICE_FIRMWARE_MINOR SDVO_I2C_RETURN_0 +# define SDVO_DEVICE_FIRMWARE_MAJOR SDVO_I2C_RETURN_1 +# define SDVO_DEVICE_FIRMWARE_PATCH SDVO_I2C_RETURN_2 + +/** + * Reports which inputs are trained (managed to sync). + * + * Devices must have trained within 2 vsyncs of a mode change. + */ +#define SDVO_CMD_GET_TRAINED_INPUTS 0x03 +struct i830_sdvo_get_trained_inputs_response { + unsigned int input0_trained:1; + unsigned int input1_trained:1; + unsigned int pad:6; +} __attribute__((packed)); + +/** Returns a struct i830_sdvo_output_flags of active outputs. */ +#define SDVO_CMD_GET_ACTIVE_OUTPUTS 0x04 + +/** + * Sets the current set of active outputs. + * + * Takes a struct i830_sdvo_output_flags. Must be preceded by a SET_IN_OUT_MAP + * on multi-output devices. + */ +#define SDVO_CMD_SET_ACTIVE_OUTPUTS 0x05 + +/** + * Returns the current mapping of SDVO inputs to outputs on the device. + * + * Returns two struct i830_sdvo_output_flags structures. + */ +#define SDVO_CMD_GET_IN_OUT_MAP 0x06 + +/** + * Sets the current mapping of SDVO inputs to outputs on the device. + * + * Takes two struct i380_sdvo_output_flags structures. + */ +#define SDVO_CMD_SET_IN_OUT_MAP 0x07 + +/** + * Returns a struct i830_sdvo_output_flags of attached displays. + */ +#define SDVO_CMD_GET_ATTACHED_DISPLAYS 0x0b + +/** + * Returns a struct i830_sdvo_ouptut_flags of displays supporting hot plugging. + */ +#define SDVO_CMD_GET_HOT_PLUG_SUPPORT 0x0c + +/** + * Takes a struct i830_sdvo_output_flags. + */ +#define SDVO_CMD_SET_ACTIVE_HOT_PLUG 0x0d + +/** + * Returns a struct i830_sdvo_output_flags of displays with hot plug + * interrupts enabled. + */ +#define SDVO_CMD_GET_ACTIVE_HOT_PLUG 0x0e + +#define SDVO_CMD_GET_INTERRUPT_EVENT_SOURCE 0x0f +struct i830_sdvo_get_interrupt_event_source_response { + CARD16 interrupt_status; + unsigned int ambient_light_interrupt:1; + unsigned int pad:7; +} __attribute__((packed)); + +/** + * Selects which input is affected by future input commands. + * + * Commands affected include SET_INPUT_TIMINGS_PART[12], + * GET_INPUT_TIMINGS_PART[12], GET_PREFERRED_INPUT_TIMINGS_PART[12], + * GET_INPUT_PIXEL_CLOCK_RANGE, and CREATE_PREFERRED_INPUT_TIMINGS. + */ +#define SDVO_CMD_SET_TARGET_INPUT 0x10 +struct i830_sdvo_set_target_input_args { + unsigned int target_1:1; + unsigned int pad:7; +} __attribute__((packed)); + +/** + * Takes a struct i830_sdvo_output_flags of which outputs are targetted by + * future output commands. + * + * Affected commands inclue SET_OUTPUT_TIMINGS_PART[12], + * GET_OUTPUT_TIMINGS_PART[12], and GET_OUTPUT_PIXEL_CLOCK_RANGE. + */ +#define SDVO_CMD_SET_TARGET_OUTPUT 0x11 + +#define SDVO_CMD_GET_INPUT_TIMINGS_PART1 0x12 +#define SDVO_CMD_GET_INPUT_TIMINGS_PART2 0x13 +#define SDVO_CMD_SET_INPUT_TIMINGS_PART1 0x14 +#define SDVO_CMD_SET_INPUT_TIMINGS_PART2 0x15 +#define SDVO_CMD_SET_OUTPUT_TIMINGS_PART1 0x16 +#define SDVO_CMD_SET_OUTPUT_TIMINGS_PART2 0x17 +#define SDVO_CMD_GET_OUTPUT_TIMINGS_PART1 0x18 +#define SDVO_CMD_GET_OUTPUT_TIMINGS_PART2 0x19 +/* Part 1 */ +# define SDVO_DTD_CLOCK_LOW SDVO_I2C_ARG_0 +# define SDVO_DTD_CLOCK_HIGH SDVO_I2C_ARG_1 +# define SDVO_DTD_H_ACTIVE SDVO_I2C_ARG_2 +# define SDVO_DTD_H_BLANK SDVO_I2C_ARG_3 +# define SDVO_DTD_H_HIGH SDVO_I2C_ARG_4 +# define SDVO_DTD_V_ACTIVE SDVO_I2C_ARG_5 +# define SDVO_DTD_V_BLANK SDVO_I2C_ARG_6 +# define SDVO_DTD_V_HIGH SDVO_I2C_ARG_7 +/* Part 2 */ +# define SDVO_DTD_HSYNC_OFF SDVO_I2C_ARG_0 +# define SDVO_DTD_HSYNC_WIDTH SDVO_I2C_ARG_1 +# define SDVO_DTD_VSYNC_OFF_WIDTH SDVO_I2C_ARG_2 +# define SDVO_DTD_SYNC_OFF_WIDTH_HIGH SDVO_I2C_ARG_3 +# define SDVO_DTD_DTD_FLAGS SDVO_I2C_ARG_4 +# define SDVO_DTD_DTD_FLAG_INTERLACED (1 << 7) +# define SDVO_DTD_DTD_FLAG_STEREO_MASK (3 << 5) +# define SDVO_DTD_DTD_FLAG_INPUT_MASK (3 << 3) +# define SDVO_DTD_DTD_FLAG_SYNC_MASK (3 << 1) +# define SDVO_DTD_SDVO_FLAS SDVO_I2C_ARG_5 +# define SDVO_DTD_SDVO_FLAG_STALL (1 << 7) +# define SDVO_DTD_SDVO_FLAG_CENTERED (0 << 6) +# define SDVO_DTD_SDVO_FLAG_UPPER_LEFT (1 << 6) +# define SDVO_DTD_SDVO_FLAG_SCALING_MASK (3 << 4) +# define SDVO_DTD_SDVO_FLAG_SCALING_NONE (0 << 4) +# define SDVO_DTD_SDVO_FLAG_SCALING_SHARP (1 << 4) +# define SDVO_DTD_SDVO_FLAG_SCALING_SMOOTH (2 << 4) +# define SDVO_DTD_VSYNC_OFF_HIGH SDVO_I2C_ARG_6 + +/** + * Generates a DTD based on the given width, height, and flags. + * + * This will be supported by any device supporting scaling or interlaced + * modes. + */ +#define SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING 0x1a +# define SDVO_PREFERRED_INPUT_TIMING_CLOCK_LOW SDVO_I2C_ARG_0 +# define SDVO_PREFERRED_INPUT_TIMING_CLOCK_HIGH SDVO_I2C_ARG_1 +# define SDVO_PREFERRED_INPUT_TIMING_WIDTH_LOW SDVO_I2C_ARG_2 +# define SDVO_PREFERRED_INPUT_TIMING_WIDTH_HIGH SDVO_I2C_ARG_3 +# define SDVO_PREFERRED_INPUT_TIMING_HEIGHT_LOW SDVO_I2C_ARG_4 +# define SDVO_PREFERRED_INPUT_TIMING_HEIGHT_HIGH SDVO_I2C_ARG_5 +# define SDVO_PREFERRED_INPUT_TIMING_FLAGS SDVO_I2C_ARG_6 +# define SDVO_PREFERRED_INPUT_TIMING_FLAGS_INTERLACED (1 << 0) +# define SDVO_PREFERRED_INPUT_TIMING_FLAGS_SCALED (1 << 1) + +#define SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1 0x1b +#define SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2 0x1c + +/** Returns a struct i830_sdvo_pixel_clock_range */ +#define SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE 0x1d +/** Returns a struct i830_sdvo_pixel_clock_range */ +#define SDVO_CMD_GET_OUTPUT_PIXEL_CLOCK_RANGE 0x1e + +/** Returns a byte bitfield containing SDVO_CLOCK_RATE_MULT_* flags */ +#define SDVO_CMD_GET_SUPPORTED_CLOCK_RATE_MULTS 0x1f + +/** Returns a byte containing a SDVO_CLOCK_RATE_MULT_* flag */ +#define SDVO_CMD_GET_CLOCK_RATE_MULT 0x20 +/** Takes a byte containing a SDVO_CLOCK_RATE_MULT_* flag */ +#define SDVO_CMD_SET_CLOCK_RATE_MULT 0x21 +# define SDVO_CLOCK_RATE_MULT_1X (1 << 0) +# define SDVO_CLOCK_RATE_MULT_2X (1 << 1) +# define SDVO_CLOCK_RATE_MULT_4X (1 << 3) + +#define SDVO_CMD_GET_SUPPORTED_TV_FORMATS 0x27 + +#define SDVO_CMD_GET_TV_FORMAT 0x28 + +#define SDVO_CMD_SET_TV_FORMAT 0x29 + +#define SDVO_CMD_GET_SUPPORTED_POWER_STATES 0x2a +#define SDVO_CMD_GET_ENCODER_POWER_STATE 0x2b +#define SDVO_CMD_SET_ENCODER_POWER_STATE 0x2c +# define SDVO_ENCODER_STATE_ON (1 << 0) +# define SDVO_ENCODER_STATE_STANDBY (1 << 1) +# define SDVO_ENCODER_STATE_SUSPEND (1 << 2) +# define SDVO_ENCODER_STATE_OFF (1 << 3) + +#define SDVO_CMD_SET_TV_RESOLUTION_SUPPORT 0x93 + +#define SDVO_CMD_SET_CONTROL_BUS_SWITCH 0x7a +# define SDVO_CONTROL_BUS_PROM 0x0 +# define SDVO_CONTROL_BUS_DDC1 0x1 +# define SDVO_CONTROL_BUS_DDC2 0x2 +# define SDVO_CONTROL_BUS_DDC3 0x3 + diff --git a/driver/xf86-video-intel/src/i830_tv.c b/driver/xf86-video-intel/src/i830_tv.c new file mode 100644 index 000000000..524a0d3b3 --- /dev/null +++ b/driver/xf86-video-intel/src/i830_tv.c @@ -0,0 +1,1740 @@ +/* + * Copyright © 2006 Intel Corporation + * + * 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 + * THE AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +/** @file + * Integrated TV-out support for the 915GM and 945GM. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "xf86.h" +#include "i830.h" +#include "i830_display.h" +#include "X11/Xatom.h" +#include <string.h> + +enum tv_type { + TV_TYPE_NONE, + TV_TYPE_UNKNOWN, + TV_TYPE_COMPOSITE, + TV_TYPE_SVIDEO, + TV_TYPE_COMPONENT +}; + +enum tv_margin { + TV_MARGIN_LEFT, TV_MARGIN_TOP, + TV_MARGIN_RIGHT, TV_MARGIN_BOTTOM +}; + +/** Private structure for the integrated TV support */ +struct i830_tv_priv { + int type; + char *tv_format; + int margin[4]; + CARD32 save_TV_H_CTL_1; + CARD32 save_TV_H_CTL_2; + CARD32 save_TV_H_CTL_3; + CARD32 save_TV_V_CTL_1; + CARD32 save_TV_V_CTL_2; + CARD32 save_TV_V_CTL_3; + CARD32 save_TV_V_CTL_4; + CARD32 save_TV_V_CTL_5; + CARD32 save_TV_V_CTL_6; + CARD32 save_TV_V_CTL_7; + CARD32 save_TV_SC_CTL_1, save_TV_SC_CTL_2, save_TV_SC_CTL_3; + + CARD32 save_TV_CSC_Y; + CARD32 save_TV_CSC_Y2; + CARD32 save_TV_CSC_U; + CARD32 save_TV_CSC_U2; + CARD32 save_TV_CSC_V; + CARD32 save_TV_CSC_V2; + CARD32 save_TV_CLR_KNOBS; + CARD32 save_TV_CLR_LEVEL; + CARD32 save_TV_WIN_POS; + CARD32 save_TV_WIN_SIZE; + CARD32 save_TV_FILTER_CTL_1; + CARD32 save_TV_FILTER_CTL_2; + CARD32 save_TV_FILTER_CTL_3; + + CARD32 save_TV_H_LUMA[60]; + CARD32 save_TV_H_CHROMA[60]; + CARD32 save_TV_V_LUMA[43]; + CARD32 save_TV_V_CHROMA[43]; + + CARD32 save_TV_DAC; + CARD32 save_TV_CTL; +}; + +typedef struct { + int blank, black, burst; +} video_levels_t; + +typedef struct { + float ry, gy, by, ay; + float ru, gu, bu, au; + float rv, gv, bv, av; +} color_conversion_t; + +static const CARD32 filter_table[] = { + 0xB1403000, 0x2E203500, 0x35002E20, 0x3000B140, + 0x35A0B160, 0x2DC02E80, 0xB1403480, 0xB1603000, + 0x2EA03640, 0x34002D80, 0x3000B120, 0x36E0B160, + 0x2D202EF0, 0xB1203380, 0xB1603000, 0x2F303780, + 0x33002CC0, 0x3000B100, 0x3820B160, 0x2C802F50, + 0xB10032A0, 0xB1603000, 0x2F9038C0, 0x32202C20, + 0x3000B0E0, 0x3980B160, 0x2BC02FC0, 0xB0E031C0, + 0xB1603000, 0x2FF03A20, 0x31602B60, 0xB020B0C0, + 0x3AE0B160, 0x2B001810, 0xB0C03120, 0xB140B020, + 0x18283BA0, 0x30C02A80, 0xB020B0A0, 0x3C60B140, + 0x2A201838, 0xB0A03080, 0xB120B020, 0x18383D20, + 0x304029C0, 0xB040B080, 0x3DE0B100, 0x29601848, + 0xB0803000, 0xB100B040, 0x18483EC0, 0xB0402900, + 0xB040B060, 0x3F80B0C0, 0x28801858, 0xB060B080, + 0xB0A0B060, 0x18602820, 0xB0A02820, 0x0000B060, + 0xB1403000, 0x2E203500, 0x35002E20, 0x3000B140, + 0x35A0B160, 0x2DC02E80, 0xB1403480, 0xB1603000, + 0x2EA03640, 0x34002D80, 0x3000B120, 0x36E0B160, + 0x2D202EF0, 0xB1203380, 0xB1603000, 0x2F303780, + 0x33002CC0, 0x3000B100, 0x3820B160, 0x2C802F50, + 0xB10032A0, 0xB1603000, 0x2F9038C0, 0x32202C20, + 0x3000B0E0, 0x3980B160, 0x2BC02FC0, 0xB0E031C0, + 0xB1603000, 0x2FF03A20, 0x31602B60, 0xB020B0C0, + 0x3AE0B160, 0x2B001810, 0xB0C03120, 0xB140B020, + 0x18283BA0, 0x30C02A80, 0xB020B0A0, 0x3C60B140, + 0x2A201838, 0xB0A03080, 0xB120B020, 0x18383D20, + 0x304029C0, 0xB040B080, 0x3DE0B100, 0x29601848, + 0xB0803000, 0xB100B040, 0x18483EC0, 0xB0402900, + 0xB040B060, 0x3F80B0C0, 0x28801858, 0xB060B080, + 0xB0A0B060, 0x18602820, 0xB0A02820, 0x0000B060, + 0x36403000, 0x2D002CC0, 0x30003640, 0x2D0036C0, + 0x35C02CC0, 0x37403000, 0x2C802D40, 0x30003540, + 0x2D8037C0, 0x34C02C40, 0x38403000, 0x2BC02E00, + 0x30003440, 0x2E2038C0, 0x34002B80, 0x39803000, + 0x2B402E40, 0x30003380, 0x2E603A00, 0x33402B00, + 0x3A803040, 0x2A802EA0, 0x30403300, 0x2EC03B40, + 0x32802A40, 0x3C003040, 0x2A002EC0, 0x30803240, + 0x2EC03C80, 0x320029C0, 0x3D403080, 0x29402F00, + 0x308031C0, 0x2F203DC0, 0x31802900, 0x3E8030C0, + 0x28802F40, 0x30C03140, 0x2F203F40, 0x31402840, + 0x28003100, 0x28002F00, 0x00003100, 0x36403000, + 0x2D002CC0, 0x30003640, 0x2D0036C0, + 0x35C02CC0, 0x37403000, 0x2C802D40, 0x30003540, + 0x2D8037C0, 0x34C02C40, 0x38403000, 0x2BC02E00, + 0x30003440, 0x2E2038C0, 0x34002B80, 0x39803000, + 0x2B402E40, 0x30003380, 0x2E603A00, 0x33402B00, + 0x3A803040, 0x2A802EA0, 0x30403300, 0x2EC03B40, + 0x32802A40, 0x3C003040, 0x2A002EC0, 0x30803240, + 0x2EC03C80, 0x320029C0, 0x3D403080, 0x29402F00, + 0x308031C0, 0x2F203DC0, 0x31802900, 0x3E8030C0, + 0x28802F40, 0x30C03140, 0x2F203F40, 0x31402840, + 0x28003100, 0x28002F00, 0x00003100, +}; + +typedef struct { + char *name; + int clock; + double refresh; + CARD32 oversample; + int hsync_end, hblank_start, hblank_end, htotal; + Bool progressive, trilevel_sync, component_only; + int vsync_start_f1, vsync_start_f2, vsync_len; + Bool veq_ena; + int veq_start_f1, veq_start_f2, veq_len; + int vi_end_f1, vi_end_f2, nbr_end; + Bool burst_ena; + int hburst_start, hburst_len; + int vburst_start_f1, vburst_end_f1; + int vburst_start_f2, vburst_end_f2; + int vburst_start_f3, vburst_end_f3; + int vburst_start_f4, vburst_end_f4; + /* + * subcarrier programming + */ + int dda2_size, dda3_size, dda1_inc, dda2_inc, dda3_inc; + CARD32 sc_reset; + Bool pal_burst; + /* + * blank/black levels + */ + video_levels_t composite_levels, svideo_levels; + color_conversion_t composite_color, svideo_color; + const CARD32 *filter_table; + int max_srcw; +} tv_mode_t; + + +/* + * Sub carrier DDA + * + * I think this works as follows: + * + * subcarrier freq = pixel_clock * (dda1_inc + dda2_inc / dda2_size) / 4096 + * + * Presumably, when dda3 is added in, it gets to adjust the dda2_inc value + * + * So, + * dda1_ideal = subcarrier/pixel * 4096 + * dda1_inc = floor (dda1_ideal) + * dda2 = dda1_ideal - dda1_inc + * + * then pick a ratio for dda2 that gives the closest approximation. If + * you can't get close enough, you can play with dda3 as well. This + * seems likely to happen when dda2 is small as the jumps would be larger + * + * To invert this, + * + * pixel_clock = subcarrier * 4096 / (dda1_inc + dda2_inc / dda2_size) + * + * The constants below were all computed using a 107.520MHz clock + */ + +/** + * Register programming values for TV modes. + * + * These values account for -1s required. + */ + +const static tv_mode_t tv_modes[] = { + { + .name = "NTSC-M", + .clock = 107520, + .refresh = 29.97, + .oversample = TV_OVERSAMPLE_8X, + .component_only = 0, + /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */ + + .hsync_end = 64, .hblank_end = 124, + .hblank_start = 836, .htotal = 857, + + .progressive = FALSE, .trilevel_sync = FALSE, + + .vsync_start_f1 = 6, .vsync_start_f2 = 7, + .vsync_len = 6, + + .veq_ena = TRUE, .veq_start_f1 = 0, + .veq_start_f2 = 1, .veq_len = 18, + + .vi_end_f1 = 20, .vi_end_f2 = 21, + .nbr_end = 240, + + .burst_ena = TRUE, + .hburst_start = 72, .hburst_len = 34, + .vburst_start_f1 = 9, .vburst_end_f1 = 240, + .vburst_start_f2 = 10, .vburst_end_f2 = 240, + .vburst_start_f3 = 9, .vburst_end_f3 = 240, + .vburst_start_f4 = 10, .vburst_end_f4 = 240, + + /* desired 3.5800000 actual 3.5800000 clock 107.52 */ + .dda1_inc = 136, + .dda2_inc = 7624, .dda2_size = 20013, + .dda3_inc = 0, .dda3_size = 0, + .sc_reset = TV_SC_RESET_EVERY_4, + .pal_burst = FALSE, + + .composite_levels = { .blank = 225, .black = 267, .burst = 113 }, + .composite_color = { + .ry = 0.2990, .gy = 0.5870, .by = 0.1140, .ay = 0.5082, + .ru =-0.0749, .gu =-0.1471, .bu = 0.2220, .au = 1.0000, + .rv = 0.3125, .gv =-0.2616, .bv =-0.0508, .av = 1.0000, + }, + + .svideo_levels = { .blank = 266, .black = 316, .burst = 133 }, + .svideo_color = { + .ry = 0.2990, .gy = 0.5870, .by = 0.1140, .ay = 0.6006, + .ru =-0.0885, .gu =-0.1738, .bu = 0.2624, .au = 1.0000, + .rv = 0.3693, .gv =-0.3092, .bv =-0.0601, .av = 1.0000, + }, + .filter_table = filter_table, + }, + { + .name = "NTSC-443", + .clock = 107520, + .refresh = 29.97, + .oversample = TV_OVERSAMPLE_8X, + .component_only = 0, + /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 4.43MHz */ + .hsync_end = 64, .hblank_end = 124, + .hblank_start = 836, .htotal = 857, + + .progressive = FALSE, .trilevel_sync = FALSE, + + .vsync_start_f1 = 6, .vsync_start_f2 = 7, + .vsync_len = 6, + + .veq_ena = TRUE, .veq_start_f1 = 0, + .veq_start_f2 = 1, .veq_len = 18, + + .vi_end_f1 = 20, .vi_end_f2 = 21, + .nbr_end = 240, + + .burst_ena = 8, + .hburst_start = 72, .hburst_len = 34, + .vburst_start_f1 = 9, .vburst_end_f1 = 240, + .vburst_start_f2 = 10, .vburst_end_f2 = 240, + .vburst_start_f3 = 9, .vburst_end_f3 = 240, + .vburst_start_f4 = 10, .vburst_end_f4 = 240, + + /* desired 4.4336180 actual 4.4336180 clock 107.52 */ + .dda1_inc = 168, + .dda2_inc = 18557, .dda2_size = 20625, + .dda3_inc = 0, .dda3_size = 0, + .sc_reset = TV_SC_RESET_EVERY_8, + .pal_burst = TRUE, + + .composite_levels = { .blank = 225, .black = 267, .burst = 113 }, + .composite_color = { + .ry = 0.2990, .gy = 0.5870, .by = 0.1140, .ay = 0.5082, + .ru =-0.0749, .gu =-0.1471, .bu = 0.2220, .au = 1.0000, + .rv = 0.3125, .gv =-0.2616, .bv =-0.0508, .av = 1.0000, + }, + + .svideo_levels = { .blank = 266, .black = 316, .burst = 133 }, + .svideo_color = { + .ry = 0.2990, .gy = 0.5870, .by = 0.1140, .ay = 0.6006, + .ru =-0.0885, .gu =-0.1738, .bu = 0.2624, .au = 1.0000, + .rv = 0.3693, .gv =-0.3092, .bv =-0.0601, .av = 1.0000, + }, + .filter_table = filter_table, + }, + { + .name = "NTSC-J", + .clock = 107520, + .refresh = 29.97, + .oversample = TV_OVERSAMPLE_8X, + .component_only = 0, + + /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */ + .hsync_end = 64, .hblank_end = 124, + .hblank_start = 836, .htotal = 857, + + .progressive = FALSE, .trilevel_sync = FALSE, + + .vsync_start_f1 = 6, .vsync_start_f2 = 7, + .vsync_len = 6, + + .veq_ena = TRUE, .veq_start_f1 = 0, + .veq_start_f2 = 1, .veq_len = 18, + + .vi_end_f1 = 20, .vi_end_f2 = 21, + .nbr_end = 240, + + .burst_ena = TRUE, + .hburst_start = 72, .hburst_len = 34, + .vburst_start_f1 = 9, .vburst_end_f1 = 240, + .vburst_start_f2 = 10, .vburst_end_f2 = 240, + .vburst_start_f3 = 9, .vburst_end_f3 = 240, + .vburst_start_f4 = 10, .vburst_end_f4 = 240, + + /* desired 3.5800000 actual 3.5800000 clock 107.52 */ + .dda1_inc = 136, + .dda2_inc = 7624, .dda2_size = 20013, + .dda3_inc = 0, .dda3_size = 0, + .sc_reset = TV_SC_RESET_EVERY_4, + .pal_burst = FALSE, + + .composite_levels = { .blank = 225, .black = 225, .burst = 113 }, + .composite_color = { + .ry = 0.2990, .gy = 0.5870, .by = 0.1140, .ay = 0.5495, + .ru =-0.0810, .gu =-0.1590, .bu = 0.2400, .au = 1.0000, + .rv = 0.3378, .gv =-0.2829, .bv =-0.0549, .av = 1.0000, + }, + + .svideo_levels = { .blank = 266, .black = 266, .burst = 133 }, + .svideo_color = { + .ry = 0.2990, .gy = 0.5870, .by = 0.1140, .ay = 0.6494, + .ru =-0.0957, .gu =-0.1879, .bu = 0.2836, .au = 1.0000, + .rv = 0.3992, .gv =-0.3343, .bv =-0.0649, .av = 1.0000, + }, + .filter_table = filter_table, + }, + { + .name = "PAL-M", + .clock = 107520, + .refresh = 29.97, + .oversample = TV_OVERSAMPLE_8X, + .component_only = 0, + + /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */ + .hsync_end = 64, .hblank_end = 124, + .hblank_start = 836, .htotal = 857, + + .progressive = FALSE, .trilevel_sync = FALSE, + + .vsync_start_f1 = 6, .vsync_start_f2 = 7, + .vsync_len = 6, + + .veq_ena = TRUE, .veq_start_f1 = 0, + .veq_start_f2 = 1, .veq_len = 18, + + .vi_end_f1 = 20, .vi_end_f2 = 21, + .nbr_end = 240, + + .burst_ena = TRUE, + .hburst_start = 72, .hburst_len = 34, + .vburst_start_f1 = 9, .vburst_end_f1 = 240, + .vburst_start_f2 = 10, .vburst_end_f2 = 240, + .vburst_start_f3 = 9, .vburst_end_f3 = 240, + .vburst_start_f4 = 10, .vburst_end_f4 = 240, + + /* desired 3.5800000 actual 3.5800000 clock 107.52 */ + .dda1_inc = 136, + .dda2_inc = 7624, .dda2_size = 20013, + .dda3_inc = 0, .dda3_size = 0, + .sc_reset = TV_SC_RESET_EVERY_4, + .pal_burst = FALSE, + + .composite_levels = { .blank = 225, .black = 267, .burst = 113 }, + .composite_color = { + .ry = 0.2990, .gy = 0.5870, .by = 0.1140, .ay = 0.5082, + .ru =-0.0749, .gu =-0.1471, .bu = 0.2220, .au = 1.0000, + .rv = 0.3125, .gv =-0.2616, .bv =-0.0508, .av = 1.0000, + }, + + .svideo_levels = { .blank = 266, .black = 316, .burst = 133 }, + .svideo_color = { + .ry = 0.2990, .gy = 0.5870, .by = 0.1140, .ay = 0.6006, + .ru =-0.0885, .gu =-0.1738, .bu = 0.2624, .au = 1.0000, + .rv = 0.3693, .gv =-0.3092, .bv =-0.0601, .av = 1.0000, + }, + .filter_table = filter_table, + }, + { + /* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */ + .name = "PAL-N", + .clock = 107520, + .refresh = 25.0, + .oversample = TV_OVERSAMPLE_8X, + .component_only = 0, + + .hsync_end = 64, .hblank_end = 128, + .hblank_start = 844, .htotal = 863, + + .progressive = FALSE, .trilevel_sync = FALSE, + + + .vsync_start_f1 = 6, .vsync_start_f2 = 7, + .vsync_len = 6, + + .veq_ena = TRUE, .veq_start_f1 = 0, + .veq_start_f2 = 1, .veq_len = 18, + + .vi_end_f1 = 24, .vi_end_f2 = 25, + .nbr_end = 286, + + .burst_ena = TRUE, + .hburst_start = 73, .hburst_len = 34, + .vburst_start_f1 = 8, .vburst_end_f1 = 285, + .vburst_start_f2 = 8, .vburst_end_f2 = 286, + .vburst_start_f3 = 9, .vburst_end_f3 = 286, + .vburst_start_f4 = 9, .vburst_end_f4 = 285, + + + /* desired 4.4336180 actual 4.4336180 clock 107.52 */ + .dda1_inc = 168, + .dda2_inc = 18557, .dda2_size = 20625, + .dda3_inc = 0, .dda3_size = 0, + .sc_reset = TV_SC_RESET_EVERY_8, + .pal_burst = TRUE, + + .composite_levels = { .blank = 225, .black = 267, .burst = 118 }, + .composite_color = { + .ry = 0.2990, .gy = 0.5870, .by = 0.1140, .ay = 0.5082, + .ru =-0.0749, .gu =-0.1471, .bu = 0.2220, .au = 1.0000, + .rv = 0.3125, .gv =-0.2616, .bv =-0.0508, .av = 1.0000, + }, + + .svideo_levels = { .blank = 266, .black = 316, .burst = 139 }, + .svideo_color = { + .ry = 0.2990, .gy = 0.5870, .by = 0.1140, .ay = 0.6006, + .ru =-0.0885, .gu =-0.1738, .bu = 0.2624, .au = 1.0000, + .rv = 0.3693, .gv =-0.3092, .bv =-0.0601, .av = 1.0000, + }, + .filter_table = filter_table, + }, + { + /* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */ + .name = "PAL", + .clock = 107520, + .refresh = 25.0, + .oversample = TV_OVERSAMPLE_8X, + .component_only = 0, + + .hsync_end = 64, .hblank_end = 128, + .hblank_start = 844, .htotal = 863, + + .progressive = FALSE, .trilevel_sync = FALSE, + + .vsync_start_f1 = 5, .vsync_start_f2 = 6, + .vsync_len = 5, + + .veq_ena = TRUE, .veq_start_f1 = 0, + .veq_start_f2 = 1, .veq_len = 15, + + .vi_end_f1 = 24, .vi_end_f2 = 25, + .nbr_end = 286, + + .burst_ena = TRUE, + .hburst_start = 73, .hburst_len = 32, + .vburst_start_f1 = 8, .vburst_end_f1 = 285, + .vburst_start_f2 = 8, .vburst_end_f2 = 286, + .vburst_start_f3 = 9, .vburst_end_f3 = 286, + .vburst_start_f4 = 9, .vburst_end_f4 = 285, + + /* desired 4.4336180 actual 4.4336180 clock 107.52 */ + .dda1_inc = 168, + .dda2_inc = 18557, .dda2_size = 20625, + .dda3_inc = 0, .dda3_size = 0, + .sc_reset = TV_SC_RESET_EVERY_8, + .pal_burst = TRUE, + + .composite_levels = { .blank = 237, .black = 237, .burst = 118 }, + .composite_color = { + .ry = 0.2990, .gy = 0.5870, .by = 0.1140, .ay = 0.5379, + .ru =-0.0793, .gu =-0.1557, .bu = 0.2350, .au = 1.0000, + .rv = 0.3307, .gv =-0.2769, .bv =-0.0538, .av = 1.0000, + }, + + .svideo_levels = { .blank = 280, .black = 280, .burst = 139 }, + .svideo_color = { + .ry = 0.2990, .gy = 0.5870, .by = 0.1140, .ay = 0.6357, + .ru =-0.0937, .gu =-0.1840, .bu = 0.2777, .au = 1.0000, + .rv = 0.3908, .gv =-0.3273, .bv =-0.0636, .av = 1.0000, + }, + .filter_table = filter_table, + }, + { + .name = "480p@59.94Hz", + .clock = 107520, + .refresh = 59.94, + .oversample = TV_OVERSAMPLE_4X, + .component_only = 1, + + .hsync_end = 64, .hblank_end = 122, + .hblank_start = 842, .htotal = 857, + + .progressive = TRUE,.trilevel_sync = FALSE, + + .vsync_start_f1 = 12, .vsync_start_f2 = 12, + .vsync_len = 12, + + .veq_ena = FALSE, + + .vi_end_f1 = 44, .vi_end_f2 = 44, + .nbr_end = 496, + + .burst_ena = FALSE, + + .filter_table = filter_table, + }, + { + .name = "480p@60Hz", + .clock = 107520, + .refresh = 60.0, + .oversample = TV_OVERSAMPLE_4X, + .component_only = 1, + + .hsync_end = 64, .hblank_end = 122, + .hblank_start = 842, .htotal = 856, + + .progressive = TRUE,.trilevel_sync = FALSE, + + .vsync_start_f1 = 12, .vsync_start_f2 = 12, + .vsync_len = 12, + + .veq_ena = FALSE, + + .vi_end_f1 = 44, .vi_end_f2 = 44, + .nbr_end = 496, + + .burst_ena = FALSE, + + .filter_table = filter_table, + }, + { + .name = "576p", + .clock = 107520, + .refresh = 59.94, + .oversample = TV_OVERSAMPLE_4X, + .component_only = 1, + + .hsync_end = 64, .hblank_end = 139, + .hblank_start = 859, .htotal = 863, + + .progressive = TRUE, .trilevel_sync = FALSE, + + .vsync_start_f1 = 10, .vsync_start_f2 = 10, + .vsync_len = 10, + + .veq_ena = FALSE, + + .vi_end_f1 = 48, .vi_end_f2 = 48, + .nbr_end = 575, + + .burst_ena = FALSE, + + .filter_table = filter_table, + }, + { + .name = "720p@60Hz", + .clock = 148800, + .refresh = 60.0, + .oversample = TV_OVERSAMPLE_2X, + .component_only = 1, + + .hsync_end = 80, .hblank_end = 300, + .hblank_start = 1580, .htotal = 1649, + + .progressive = TRUE, .trilevel_sync = TRUE, + + .vsync_start_f1 = 10, .vsync_start_f2 = 10, + .vsync_len = 10, + + .veq_ena = FALSE, + + .vi_end_f1 = 29, .vi_end_f2 = 29, + .nbr_end = 719, + + .burst_ena = FALSE, + + .filter_table = filter_table, + }, + { + .name = "720p@59.94Hz", + .clock = 148800, + .refresh = 59.94, + .oversample = TV_OVERSAMPLE_2X, + .component_only = 1, + + .hsync_end = 80, .hblank_end = 300, + .hblank_start = 1580, .htotal = 1651, + + .progressive = TRUE, .trilevel_sync = TRUE, + + .vsync_start_f1 = 10, .vsync_start_f2 = 10, + .vsync_len = 10, + + .veq_ena = FALSE, + + .vi_end_f1 = 29, .vi_end_f2 = 29, + .nbr_end = 719, + + .burst_ena = FALSE, + + .filter_table = filter_table, + }, + { + .name = "720p@50Hz", + .clock = 148800, + .refresh = 50.0, + .oversample = TV_OVERSAMPLE_2X, + .component_only = 1, + + .hsync_end = 80, .hblank_end = 300, + .hblank_start = 1580, .htotal = 1979, + + .progressive = TRUE, .trilevel_sync = TRUE, + + .vsync_start_f1 = 10, .vsync_start_f2 = 10, + .vsync_len = 10, + + .veq_ena = FALSE, + + .vi_end_f1 = 29, .vi_end_f2 = 29, + .nbr_end = 719, + + .burst_ena = FALSE, + + .filter_table = filter_table, + .max_srcw = 800 + }, + { + .name = "1080i@50Hz", + .clock = 148800, + .refresh = 25.0, + .oversample = TV_OVERSAMPLE_2X, + .component_only = 1, + + .hsync_end = 88, .hblank_end = 235, + .hblank_start = 2155, .htotal = 2639, + + .progressive = FALSE, .trilevel_sync = TRUE, + + .vsync_start_f1 = 4, .vsync_start_f2 = 5, + .vsync_len = 10, + + .veq_ena = TRUE, .veq_start_f1 = 4, + .veq_start_f2 = 4, .veq_len = 10, + + + .vi_end_f1 = 21, .vi_end_f2 = 22, + .nbr_end = 539, + + .burst_ena = FALSE, + + .filter_table = filter_table, + }, + { + .name = "1080i@60Hz", + .clock = 148800, + .refresh = 30.0, + .oversample = TV_OVERSAMPLE_2X, + .component_only = 1, + + .hsync_end = 88, .hblank_end = 235, + .hblank_start = 2155, .htotal = 2199, + + .progressive = FALSE, .trilevel_sync = TRUE, + + .vsync_start_f1 = 4, .vsync_start_f2 = 5, + .vsync_len = 10, + + .veq_ena = TRUE, .veq_start_f1 = 4, + .veq_start_f2 = 4, .veq_len = 10, + + + .vi_end_f1 = 21, .vi_end_f2 = 22, + .nbr_end = 539, + + .burst_ena = FALSE, + + .filter_table = filter_table, + }, + { + .name = "1080i@59.94Hz", + .clock = 148800, + .refresh = 29.97, + .oversample = TV_OVERSAMPLE_2X, + .component_only = 1, + + .hsync_end = 88, .hblank_end = 235, + .hblank_start = 2155, .htotal = 2200, + + .progressive = FALSE, .trilevel_sync = TRUE, + + .vsync_start_f1 = 4, .vsync_start_f2 = 5, + .vsync_len = 10, + + .veq_ena = TRUE, .veq_start_f1 = 4, + .veq_start_f2 = 4, .veq_len = 10, + + + .vi_end_f1 = 21, .vi_end_f2 = 22, + .nbr_end = 539, + + .burst_ena = FALSE, + + .filter_table = filter_table, + }, +}; + +#define NUM_TV_MODES sizeof(tv_modes) / sizeof (tv_modes[0]) + +static const video_levels_t component_level = { + .blank = 279, .black = 279 +}; + +static const color_conversion_t sdtv_component_color = { + .ry = 0.2990, .gy = 0.5870, .by = 0.1140, .ay = 0.6364, + .ru =-0.1687, .gu =-0.3313, .bu = 0.5000, .au = 1.0000, + .rv = 0.5000, .gv =-0.4187, .bv =-0.0813, .av = 1.0000, +}; + +static const color_conversion_t hdtv_component_color = { + .ry = 0.2126, .gy = 0.7152, .by = 0.0722, .ay = 0.6364, + .ru =-0.1146, .gu =-0.3854, .bu = 0.5000, .au = 1.0000, + .rv = 0.5000, .gv =-0.4542, .bv =-0.0458, .av = 1.0000, +}; + +static void +i830_tv_dpms(xf86OutputPtr output, int mode) +{ + ScrnInfoPtr pScrn = output->scrn; + I830Ptr pI830 = I830PTR(pScrn); + + switch(mode) { + case DPMSModeOn: + OUTREG(TV_CTL, INREG(TV_CTL) | TV_ENC_ENABLE); + break; + case DPMSModeStandby: + case DPMSModeSuspend: + case DPMSModeOff: + OUTREG(TV_CTL, INREG(TV_CTL) & ~TV_ENC_ENABLE); + break; + } +} + +static void +i830_tv_save(xf86OutputPtr output) +{ + ScrnInfoPtr pScrn = output->scrn; + I830Ptr pI830 = I830PTR(pScrn); + I830OutputPrivatePtr intel_output = output->driver_private; + struct i830_tv_priv *dev_priv = intel_output->dev_priv; + int i; + + dev_priv->save_TV_H_CTL_1 = INREG(TV_H_CTL_1); + dev_priv->save_TV_H_CTL_2 = INREG(TV_H_CTL_2); + dev_priv->save_TV_H_CTL_3 = INREG(TV_H_CTL_3); + dev_priv->save_TV_V_CTL_1 = INREG(TV_V_CTL_1); + dev_priv->save_TV_V_CTL_2 = INREG(TV_V_CTL_2); + dev_priv->save_TV_V_CTL_3 = INREG(TV_V_CTL_3); + dev_priv->save_TV_V_CTL_4 = INREG(TV_V_CTL_4); + dev_priv->save_TV_V_CTL_5 = INREG(TV_V_CTL_5); + dev_priv->save_TV_V_CTL_6 = INREG(TV_V_CTL_6); + dev_priv->save_TV_V_CTL_7 = INREG(TV_V_CTL_7); + dev_priv->save_TV_SC_CTL_1 = INREG(TV_SC_CTL_1); + dev_priv->save_TV_SC_CTL_2 = INREG(TV_SC_CTL_2); + dev_priv->save_TV_SC_CTL_3 = INREG(TV_SC_CTL_3); + + dev_priv->save_TV_CSC_Y = INREG(TV_CSC_Y); + dev_priv->save_TV_CSC_Y2 = INREG(TV_CSC_Y2); + dev_priv->save_TV_CSC_U = INREG(TV_CSC_U); + dev_priv->save_TV_CSC_U2 = INREG(TV_CSC_U2); + dev_priv->save_TV_CSC_V = INREG(TV_CSC_V); + dev_priv->save_TV_CSC_V2 = INREG(TV_CSC_V2); + dev_priv->save_TV_CLR_KNOBS = INREG(TV_CLR_KNOBS); + dev_priv->save_TV_CLR_LEVEL = INREG(TV_CLR_LEVEL); + dev_priv->save_TV_WIN_POS = INREG(TV_WIN_POS); + dev_priv->save_TV_WIN_SIZE = INREG(TV_WIN_SIZE); + dev_priv->save_TV_FILTER_CTL_1 = INREG(TV_FILTER_CTL_1); + dev_priv->save_TV_FILTER_CTL_2 = INREG(TV_FILTER_CTL_2); + dev_priv->save_TV_FILTER_CTL_3 = INREG(TV_FILTER_CTL_3); + + for (i = 0; i < 60; i++) + dev_priv->save_TV_H_LUMA[i] = INREG(TV_H_LUMA_0 + (i <<2)); + for (i = 0; i < 60; i++) + dev_priv->save_TV_H_CHROMA[i] = INREG(TV_H_CHROMA_0 + (i <<2)); + for (i = 0; i < 43; i++) + dev_priv->save_TV_V_LUMA[i] = INREG(TV_V_LUMA_0 + (i <<2)); + for (i = 0; i < 43; i++) + dev_priv->save_TV_V_CHROMA[i] = INREG(TV_V_CHROMA_0 + (i <<2)); + + dev_priv->save_TV_DAC = INREG(TV_DAC); + dev_priv->save_TV_CTL = INREG(TV_CTL); +} + +static void +i830_tv_restore(xf86OutputPtr output) +{ + ScrnInfoPtr pScrn = output->scrn; + I830Ptr pI830 = I830PTR(pScrn); + I830OutputPrivatePtr intel_output = output->driver_private; + struct i830_tv_priv *dev_priv = intel_output->dev_priv; + int i; + + xf86CrtcPtr crtc = output->crtc; + I830CrtcPrivatePtr intel_crtc; + if (!crtc) + return; + intel_crtc = crtc->driver_private; + OUTREG(TV_H_CTL_1, dev_priv->save_TV_H_CTL_1); + OUTREG(TV_H_CTL_2, dev_priv->save_TV_H_CTL_2); + OUTREG(TV_H_CTL_3, dev_priv->save_TV_H_CTL_3); + OUTREG(TV_V_CTL_1, dev_priv->save_TV_V_CTL_1); + OUTREG(TV_V_CTL_2, dev_priv->save_TV_V_CTL_2); + OUTREG(TV_V_CTL_3, dev_priv->save_TV_V_CTL_3); + OUTREG(TV_V_CTL_4, dev_priv->save_TV_V_CTL_4); + OUTREG(TV_V_CTL_5, dev_priv->save_TV_V_CTL_5); + OUTREG(TV_V_CTL_6, dev_priv->save_TV_V_CTL_6); + OUTREG(TV_V_CTL_7, dev_priv->save_TV_V_CTL_7); + OUTREG(TV_SC_CTL_1, dev_priv->save_TV_SC_CTL_1); + OUTREG(TV_SC_CTL_2, dev_priv->save_TV_SC_CTL_2); + OUTREG(TV_SC_CTL_3, dev_priv->save_TV_SC_CTL_3); + + OUTREG(TV_CSC_Y, dev_priv->save_TV_CSC_Y); + OUTREG(TV_CSC_Y2, dev_priv->save_TV_CSC_Y2); + OUTREG(TV_CSC_U, dev_priv->save_TV_CSC_U); + OUTREG(TV_CSC_U2, dev_priv->save_TV_CSC_U2); + OUTREG(TV_CSC_V, dev_priv->save_TV_CSC_V); + OUTREG(TV_CSC_V2, dev_priv->save_TV_CSC_V2); + OUTREG(TV_CLR_KNOBS, dev_priv->save_TV_CLR_KNOBS); + OUTREG(TV_CLR_LEVEL, dev_priv->save_TV_CLR_LEVEL); + + { + int pipeconf_reg = (intel_crtc->pipe == 0) ? PIPEACONF : PIPEBCONF; + int dspcntr_reg = (intel_crtc->plane == 0) ? DSPACNTR : DSPBCNTR; + int pipeconf = INREG(pipeconf_reg); + int dspcntr = INREG(dspcntr_reg); + int dspbase_reg = (intel_crtc->plane == 0) ? DSPABASE : DSPBBASE; + /* Pipe must be off here */ + OUTREG(dspcntr_reg, dspcntr & ~DISPLAY_PLANE_ENABLE); + /* Flush the plane changes */ + OUTREG(dspbase_reg, INREG(dspbase_reg)); + + if (!IS_I9XX(pI830)) { + /* Wait for vblank for the disable to take effect */ + i830WaitForVblank(pScrn); + } + + OUTREG(pipeconf_reg, pipeconf & ~PIPEACONF_ENABLE); + /* Wait for vblank for the disable to take effect. */ + i830WaitForVblank(pScrn); + + /* Filter ctl must be set before TV_WIN_SIZE */ + OUTREG(TV_FILTER_CTL_1, dev_priv->save_TV_FILTER_CTL_1); + OUTREG(TV_FILTER_CTL_2, dev_priv->save_TV_FILTER_CTL_2); + OUTREG(TV_FILTER_CTL_3, dev_priv->save_TV_FILTER_CTL_3); + OUTREG(TV_WIN_POS, dev_priv->save_TV_WIN_POS); + OUTREG(TV_WIN_SIZE, dev_priv->save_TV_WIN_SIZE); + OUTREG(pipeconf_reg, pipeconf); + OUTREG(dspcntr_reg, dspcntr); + /* Flush the plane changes */ + OUTREG(dspbase_reg, INREG(dspbase_reg)); + } + + for (i = 0; i < 60; i++) + OUTREG(TV_H_LUMA_0 + (i <<2), dev_priv->save_TV_H_LUMA[i]); + for (i = 0; i < 60; i++) + OUTREG(TV_H_CHROMA_0 + (i <<2), dev_priv->save_TV_H_CHROMA[i]); + for (i = 0; i < 43; i++) + OUTREG(TV_V_LUMA_0 + (i <<2), dev_priv->save_TV_V_LUMA[i]); + for (i = 0; i < 43; i++) + OUTREG(TV_V_CHROMA_0 + (i <<2), dev_priv->save_TV_V_CHROMA[i]); + + OUTREG(TV_DAC, dev_priv->save_TV_DAC); + OUTREG(TV_CTL, dev_priv->save_TV_CTL); +} + +static const tv_mode_t * +i830_tv_mode_lookup (char *tv_format) +{ + int i; + + for (i = 0; i < sizeof(tv_modes) / sizeof (tv_modes[0]); i++) + { + const tv_mode_t *tv_mode = &tv_modes[i]; + + if (xf86nameCompare (tv_format, tv_mode->name) == 0) + return tv_mode; + } + return NULL; +} + +static const tv_mode_t * +i830_tv_mode_find (xf86OutputPtr output) +{ + I830OutputPrivatePtr intel_output = output->driver_private; + struct i830_tv_priv *dev_priv = intel_output->dev_priv; + + return i830_tv_mode_lookup (dev_priv->tv_format); +} + +static int +i830_tv_mode_valid(xf86OutputPtr output, DisplayModePtr mode) +{ + const tv_mode_t *tv_mode = i830_tv_mode_find (output); + + if (tv_mode && fabs (tv_mode->refresh - xf86ModeVRefresh (mode)) < 1.0) + return MODE_OK; + return MODE_CLOCK_RANGE; +} + + +static Bool +i830_tv_mode_fixup(xf86OutputPtr output, DisplayModePtr mode, + DisplayModePtr adjusted_mode) +{ + ScrnInfoPtr pScrn = output->scrn; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + int i; + const tv_mode_t *tv_mode = i830_tv_mode_find (output); + + if (!tv_mode) + return FALSE; + + for (i = 0; i < xf86_config->num_output; i++) + { + xf86OutputPtr other_output = xf86_config->output[i]; + + if (other_output != output && other_output->crtc == output->crtc) + return FALSE; + } + + adjusted_mode->Clock = tv_mode->clock; + return TRUE; +} + +static CARD32 +i830_float_to_csc (float fin) +{ + CARD32 exp; + CARD32 mant; + CARD32 ret; + float f = fin; + + /* somehow the color conversion knows the signs of all the values */ + if (f < 0) f = -f; + + if (f >= 1) + { + exp = 0x7; + mant = 1 << 8; + } + else + { + for (exp = 0; exp < 3 && f < 0.5; exp++) + f *= 2.0; + mant = (f * (1 << 9) + 0.5); + if (mant >= (1 << 9)) + mant = (1 << 9) - 1; + } + ret = (exp << 9) | mant; + return ret; +} + +static CARD16 +i830_float_to_luma (float f) +{ + CARD16 ret; + + ret = (f * (1 << 9)); + return ret; +} + +static void +i830_tv_mode_set(xf86OutputPtr output, DisplayModePtr mode, + DisplayModePtr adjusted_mode) +{ + ScrnInfoPtr pScrn = output->scrn; + I830Ptr pI830 = I830PTR(pScrn); + xf86CrtcPtr crtc = output->crtc; + I830OutputPrivatePtr intel_output = output->driver_private; + I830CrtcPrivatePtr intel_crtc = crtc->driver_private; + struct i830_tv_priv *dev_priv = intel_output->dev_priv; + const tv_mode_t *tv_mode = i830_tv_mode_find (output); + CARD32 tv_ctl; + CARD32 hctl1, hctl2, hctl3; + CARD32 vctl1, vctl2, vctl3, vctl4, vctl5, vctl6, vctl7; + CARD32 scctl1, scctl2, scctl3; + int i, j; + const video_levels_t *video_levels; + const color_conversion_t *color_conversion; + Bool burst_ena; + + if (!tv_mode) + return; /* can't happen (mode_prepare prevents this) */ + + tv_ctl = 0; + + switch (dev_priv->type) { + default: + case TV_TYPE_UNKNOWN: + case TV_TYPE_COMPOSITE: + tv_ctl |= TV_ENC_OUTPUT_COMPOSITE; + video_levels = &tv_mode->composite_levels; + color_conversion = &tv_mode->composite_color; + burst_ena = tv_mode->burst_ena; + break; + case TV_TYPE_COMPONENT: + tv_ctl |= TV_ENC_OUTPUT_COMPONENT; + video_levels = &component_level; + if (tv_mode->burst_ena) + color_conversion = &sdtv_component_color; + else + color_conversion = &hdtv_component_color; + burst_ena = FALSE; + break; + case TV_TYPE_SVIDEO: + tv_ctl |= TV_ENC_OUTPUT_SVIDEO; + video_levels = &tv_mode->svideo_levels; + color_conversion = &tv_mode->svideo_color; + burst_ena = tv_mode->burst_ena; + break; + } + hctl1 = (tv_mode->hsync_end << TV_HSYNC_END_SHIFT) | + (tv_mode->htotal << TV_HTOTAL_SHIFT); + + hctl2 = (tv_mode->hburst_start << 16) | + (tv_mode->hburst_len << TV_HBURST_LEN_SHIFT); + + if (burst_ena) + hctl2 |= TV_BURST_ENA; + + hctl3 = (tv_mode->hblank_start << TV_HBLANK_START_SHIFT) | + (tv_mode->hblank_end << TV_HBLANK_END_SHIFT); + + vctl1 = (tv_mode->nbr_end << TV_NBR_END_SHIFT) | + (tv_mode->vi_end_f1 << TV_VI_END_F1_SHIFT) | + (tv_mode->vi_end_f2 << TV_VI_END_F2_SHIFT); + + vctl2 = (tv_mode->vsync_len << TV_VSYNC_LEN_SHIFT) | + (tv_mode->vsync_start_f1 << TV_VSYNC_START_F1_SHIFT) | + (tv_mode->vsync_start_f2 << TV_VSYNC_START_F2_SHIFT); + + vctl3 = (tv_mode->veq_len << TV_VEQ_LEN_SHIFT) | + (tv_mode->veq_start_f1 << TV_VEQ_START_F1_SHIFT) | + (tv_mode->veq_start_f2 << TV_VEQ_START_F2_SHIFT); + + if (tv_mode->veq_ena) + vctl3 |= TV_EQUAL_ENA; + + vctl4 = (tv_mode->vburst_start_f1 << TV_VBURST_START_F1_SHIFT) | + (tv_mode->vburst_end_f1 << TV_VBURST_END_F1_SHIFT); + + vctl5 = (tv_mode->vburst_start_f2 << TV_VBURST_START_F2_SHIFT) | + (tv_mode->vburst_end_f2 << TV_VBURST_END_F2_SHIFT); + + vctl6 = (tv_mode->vburst_start_f3 << TV_VBURST_START_F3_SHIFT) | + (tv_mode->vburst_end_f3 << TV_VBURST_END_F3_SHIFT); + + vctl7 = (tv_mode->vburst_start_f4 << TV_VBURST_START_F4_SHIFT) | + (tv_mode->vburst_end_f4 << TV_VBURST_END_F4_SHIFT); + + if (intel_crtc->pipe == 1) + tv_ctl |= TV_ENC_PIPEB_SELECT; + tv_ctl |= tv_mode->oversample; + + if (tv_mode->progressive) + tv_ctl |= TV_PROGRESSIVE; + if (tv_mode->trilevel_sync) + tv_ctl |= TV_TRILEVEL_SYNC; + if (tv_mode->pal_burst) + tv_ctl |= TV_PAL_BURST; + scctl1 = 0; + if (tv_mode->dda1_inc) + scctl1 |= TV_SC_DDA1_EN; + + if (tv_mode->dda2_inc) + scctl1 |= TV_SC_DDA2_EN; + + if (tv_mode->dda3_inc) + scctl1 |= TV_SC_DDA3_EN; + + scctl1 |= tv_mode->sc_reset; + scctl1 |= video_levels->burst << TV_BURST_LEVEL_SHIFT; + scctl1 |= tv_mode->dda1_inc << TV_SCDDA1_INC_SHIFT; + + scctl2 = tv_mode->dda2_size << TV_SCDDA2_SIZE_SHIFT | + tv_mode->dda2_inc << TV_SCDDA2_INC_SHIFT; + + scctl3 = tv_mode->dda3_size << TV_SCDDA3_SIZE_SHIFT | + tv_mode->dda3_inc << TV_SCDDA3_INC_SHIFT; + + /* Enable two fixes for the chips that need them. */ + if (DEVICE_ID(pI830->PciInfo) < PCI_CHIP_I945_G) + tv_ctl |= TV_ENC_C0_FIX | TV_ENC_SDP_FIX; + + OUTREG(TV_H_CTL_1, hctl1); + OUTREG(TV_H_CTL_2, hctl2); + OUTREG(TV_H_CTL_3, hctl3); + OUTREG(TV_V_CTL_1, vctl1); + OUTREG(TV_V_CTL_2, vctl2); + OUTREG(TV_V_CTL_3, vctl3); + OUTREG(TV_V_CTL_4, vctl4); + OUTREG(TV_V_CTL_5, vctl5); + OUTREG(TV_V_CTL_6, vctl6); + OUTREG(TV_V_CTL_7, vctl7); + OUTREG(TV_SC_CTL_1, scctl1); + OUTREG(TV_SC_CTL_2, scctl2); + OUTREG(TV_SC_CTL_3, scctl3); + + OUTREG(TV_CSC_Y, + (i830_float_to_csc(color_conversion->ry) << 16) | + (i830_float_to_csc(color_conversion->gy))); + OUTREG(TV_CSC_Y2, + (i830_float_to_csc(color_conversion->by) << 16) | + (i830_float_to_luma(color_conversion->ay))); + + OUTREG(TV_CSC_U, + (i830_float_to_csc(color_conversion->ru) << 16) | + (i830_float_to_csc(color_conversion->gu))); + + OUTREG(TV_CSC_U2, + (i830_float_to_csc(color_conversion->bu) << 16) | + (i830_float_to_luma(color_conversion->au))); + + OUTREG(TV_CSC_V, + (i830_float_to_csc(color_conversion->rv) << 16) | + (i830_float_to_csc(color_conversion->gv))); + + OUTREG(TV_CSC_V2, + (i830_float_to_csc(color_conversion->bv) << 16) | + (i830_float_to_luma(color_conversion->av))); + + OUTREG(TV_CLR_KNOBS, 0x00606000); + OUTREG(TV_CLR_LEVEL, ((video_levels->black << TV_BLACK_LEVEL_SHIFT) | + (video_levels->blank << TV_BLANK_LEVEL_SHIFT))); + { + int pipeconf_reg = (intel_crtc->pipe == 0) ? PIPEACONF : PIPEBCONF; + int dspcntr_reg = (intel_crtc->plane == 0) ? DSPACNTR : DSPBCNTR; + int pipeconf = INREG(pipeconf_reg); + int dspcntr = INREG(dspcntr_reg); + int dspbase_reg = (intel_crtc->plane == 0) ? DSPABASE : DSPBBASE; + int xpos = 0x0, ypos = 0x0; + unsigned int xsize, ysize; + /* Pipe must be off here */ + OUTREG(dspcntr_reg, dspcntr & ~DISPLAY_PLANE_ENABLE); + /* Flush the plane changes */ + OUTREG(dspbase_reg, INREG(dspbase_reg)); + + if (!IS_I9XX(pI830)) { + /* Wait for vblank for the disable to take effect */ + i830WaitForVblank(pScrn); + } + + OUTREG(pipeconf_reg, pipeconf & ~PIPEACONF_ENABLE); + /* Wait for vblank for the disable to take effect. */ + i830WaitForVblank(pScrn); + + /* Filter ctl must be set before TV_WIN_SIZE */ + OUTREG(TV_FILTER_CTL_1, TV_AUTO_SCALE); + xsize = tv_mode->hblank_start - tv_mode->hblank_end; + if (tv_mode->progressive) + ysize = tv_mode->nbr_end + 1; + else + ysize = 2*tv_mode->nbr_end + 1; + + xpos += dev_priv->margin[TV_MARGIN_LEFT]; + ypos += dev_priv->margin[TV_MARGIN_TOP]; + xsize -= (dev_priv->margin[TV_MARGIN_LEFT] + + dev_priv->margin[TV_MARGIN_RIGHT]); + ysize -= (dev_priv->margin[TV_MARGIN_TOP] + + dev_priv->margin[TV_MARGIN_BOTTOM]); + OUTREG(TV_WIN_POS, (xpos<<16)|ypos); + OUTREG(TV_WIN_SIZE, (xsize<<16)|ysize); + + OUTREG(pipeconf_reg, pipeconf); + OUTREG(dspcntr_reg, dspcntr); + /* Flush the plane changes */ + OUTREG(dspbase_reg, INREG(dspbase_reg)); + } + + j = 0; + for (i = 0; i < 60; i++) + OUTREG(TV_H_LUMA_0 + (i<<2), tv_mode->filter_table[j++]); + for (i = 0; i < 60; i++) + OUTREG(TV_H_CHROMA_0 + (i<<2), tv_mode->filter_table[j++]); + for (i = 0; i < 43; i++) + OUTREG(TV_V_LUMA_0 + (i<<2), tv_mode->filter_table[j++]); + for (i = 0; i < 43; i++) + OUTREG(TV_V_CHROMA_0 + (i<<2), tv_mode->filter_table[j++]); + OUTREG(TV_DAC, 0); + OUTREG(TV_CTL, tv_ctl); +} + +static const DisplayModeRec reported_modes[] = { + { + .name = "NTSC 480i", + .Clock = 107520, + .HDisplay = 1280, + .HSyncStart = 1368, + .HSyncEnd = 1496, + .HTotal = 1712, + + .VDisplay = 1024, + .VSyncStart = 1027, + .VSyncEnd = 1034, + .VTotal = 1104, + .type = M_T_DRIVER + }, +}; + +/** + * Detects TV presence by checking for load. + * + * Requires that the current pipe's DPLL is active. + + * \return TRUE if TV is connected. + * \return FALSE if TV is disconnected. + */ +static int +i830_tv_detect_type (xf86CrtcPtr crtc, + xf86OutputPtr output) +{ + ScrnInfoPtr pScrn = output->scrn; + I830Ptr pI830 = I830PTR(pScrn); + I830OutputPrivatePtr intel_output = output->driver_private; + CARD32 tv_ctl, save_tv_ctl; + CARD32 tv_dac, save_tv_dac; + int type = TV_TYPE_UNKNOWN; + + tv_dac = INREG(TV_DAC); + /* + * Detect TV by polling) + */ + if (intel_output->load_detect_temp) + { + /* TV not currently running, prod it with destructive detect */ + save_tv_dac = tv_dac; + tv_ctl = INREG(TV_CTL); + save_tv_ctl = tv_ctl; + tv_ctl &= ~TV_ENC_ENABLE; + tv_ctl &= ~TV_TEST_MODE_MASK; + tv_ctl |= TV_TEST_MODE_MONITOR_DETECT; + tv_dac &= ~TVDAC_SENSE_MASK; + tv_dac |= (TVDAC_STATE_CHG_EN | + TVDAC_A_SENSE_CTL | + TVDAC_B_SENSE_CTL | + TVDAC_C_SENSE_CTL | + DAC_CTL_OVERRIDE | + DAC_A_0_7_V | + DAC_B_0_7_V | + DAC_C_0_7_V); + OUTREG(TV_CTL, tv_ctl); + OUTREG(TV_DAC, tv_dac); + i830WaitForVblank(pScrn); + tv_dac = INREG(TV_DAC); + OUTREG(TV_DAC, save_tv_dac); + OUTREG(TV_CTL, save_tv_ctl); + } + /* + * A B C + * 0 1 1 Composite + * 1 0 X svideo + * 0 0 0 Component + */ + if ((tv_dac & TVDAC_SENSE_MASK) == (TVDAC_B_SENSE | TVDAC_C_SENSE)) { + if (pI830->debug_modes) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Detected Composite TV connection\n"); + } + type = TV_TYPE_COMPOSITE; + } else if ((tv_dac & (TVDAC_A_SENSE|TVDAC_B_SENSE)) == TVDAC_A_SENSE) { + if (pI830->debug_modes) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Detected S-Video TV connection\n"); + } + type = TV_TYPE_SVIDEO; + } else if ((tv_dac & TVDAC_SENSE_MASK) == 0) { + if (pI830->debug_modes) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Detected Component TV connection\n"); + } + type = TV_TYPE_COMPONENT; + } else { + if (pI830->debug_modes) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "No TV connection detected\n"); + } + type = TV_TYPE_NONE; + } + + return type; +} + +#ifdef RANDR_12_INTERFACE +static int +i830_tv_format_configure_property (xf86OutputPtr output); +#endif + +/** + * Detect the TV connection. + * + * Currently this always returns OUTPUT_STATUS_UNKNOWN, as we need to be sure + * we have a pipe programmed in order to probe the TV. + */ +static xf86OutputStatus +i830_tv_detect(xf86OutputPtr output) +{ + xf86CrtcPtr crtc; + DisplayModeRec mode; + I830OutputPrivatePtr intel_output = output->driver_private; + struct i830_tv_priv *dev_priv = intel_output->dev_priv; + int dpms_mode; + int type = dev_priv->type; + + mode = reported_modes[0]; + xf86SetModeCrtc (&mode, INTERLACE_HALVE_V); + crtc = i830GetLoadDetectPipe (output, &mode, &dpms_mode); + if (crtc) + { + type = i830_tv_detect_type (crtc, output); + i830ReleaseLoadDetectPipe (output, dpms_mode); + } + + if (type != dev_priv->type) + { + dev_priv->type = type; +#ifdef RANDR_12_INTERFACE + i830_tv_format_configure_property (output); +#endif + } + + switch (type) { + case TV_TYPE_NONE: + return XF86OutputStatusDisconnected; + case TV_TYPE_UNKNOWN: + return XF86OutputStatusUnknown; + default: + return XF86OutputStatusConnected; + } +} + +static struct input_res { + char *name; + int w, h; +} input_res_table[] = +{ + {"640x480", 640, 480}, + {"800x600", 800, 600}, + {"1024x768", 1024, 768}, + {"1280x1024", 1280, 1024}, + {"848x480", 848, 480}, + {"1280x720", 1280, 720}, + {"1920x108", 1920, 1080}, +}; + +/** + * Stub get_modes function. + * + * This should probably return a set of fixed modes, unless we can figure out + * how to probe modes off of TV connections. + */ + +static DisplayModePtr +i830_tv_get_modes(xf86OutputPtr output) +{ + DisplayModePtr ret = NULL, mode_ptr; + int j; + const tv_mode_t *tv_mode = i830_tv_mode_find (output); + + for (j = 0; j < sizeof(input_res_table)/sizeof(input_res_table[0]); j++) + { + struct input_res *input = &input_res_table[j]; + unsigned int hactive_s = input->w; + unsigned int vactive_s = input->h; + + if (tv_mode->max_srcw && input->w > tv_mode->max_srcw) + continue; + + if (input->w > 1024 && (!tv_mode->progressive + && !tv_mode->component_only)) + continue; + + mode_ptr = xnfcalloc(1, sizeof(DisplayModeRec)); + mode_ptr->name = xnfalloc(strlen(input->name) + 1); + strcpy (mode_ptr->name, input->name); + + mode_ptr->HDisplay = hactive_s; + mode_ptr->HSyncStart = hactive_s + 1; + mode_ptr->HSyncEnd = hactive_s + 64; + if ( mode_ptr->HSyncEnd <= mode_ptr->HSyncStart) + mode_ptr->HSyncEnd = mode_ptr->HSyncStart + 1; + mode_ptr->HTotal = hactive_s + 96; + + mode_ptr->VDisplay = vactive_s; + mode_ptr->VSyncStart = vactive_s + 1; + mode_ptr->VSyncEnd = vactive_s + 32; + if ( mode_ptr->VSyncEnd <= mode_ptr->VSyncStart) + mode_ptr->VSyncEnd = mode_ptr->VSyncStart + 1; + mode_ptr->VTotal = vactive_s + 33; + + mode_ptr->Clock = (int) (tv_mode->refresh * + mode_ptr->VTotal * + mode_ptr->HTotal / 1000.0); + + mode_ptr->type = M_T_DRIVER; + mode_ptr->next = ret; + mode_ptr->prev = NULL; + if (ret != NULL) + ret->prev = mode_ptr; + ret = mode_ptr; + } + + return ret; +} + +static void +i830_tv_destroy (xf86OutputPtr output) +{ + if (output->driver_private) + xfree (output->driver_private); +} + +#ifdef RANDR_12_INTERFACE +#define TV_FORMAT_NAME "TV_FORMAT" +static Atom tv_format_atom; +static Atom tv_format_name_atoms[NUM_TV_MODES]; +static Atom margin_atoms[4]; +static char *margin_names[4] = { + "LEFT", "TOP", "RIGHT", "BOTTOM" +}; + +static Bool +i830_tv_format_set_property (xf86OutputPtr output) +{ + I830OutputPrivatePtr intel_output = output->driver_private; + struct i830_tv_priv *dev_priv = intel_output->dev_priv; + const tv_mode_t *tv_mode = i830_tv_mode_lookup (dev_priv->tv_format); + int err; + + if (!tv_mode) + tv_mode = &tv_modes[0]; + err = RRChangeOutputProperty (output->randr_output, tv_format_atom, + XA_ATOM, 32, PropModeReplace, 1, + &tv_format_name_atoms[tv_mode - tv_modes], + FALSE, TRUE); + return err == Success; +} + + +/** + * Configure the TV_FORMAT property to list only supported formats + * + * Unless the connector is component, list only the formats supported by + * svideo and composite + */ + +static int +i830_tv_format_configure_property (xf86OutputPtr output) +{ + I830OutputPrivatePtr intel_output = output->driver_private; + struct i830_tv_priv *dev_priv = intel_output->dev_priv; + Atom current_atoms[NUM_TV_MODES]; + int num_atoms = 0; + int i; + + if (!output->randr_output) + return Success; + + for (i = 0; i < NUM_TV_MODES; i++) + if (!tv_modes[i].component_only || dev_priv->type == TV_TYPE_COMPONENT) + current_atoms[num_atoms++] = tv_format_name_atoms[i]; + + return RRConfigureOutputProperty(output->randr_output, tv_format_atom, + TRUE, FALSE, FALSE, + num_atoms, (INT32 *) current_atoms); +} + +#endif /* RANDR_12_INTERFACE */ + +static void +i830_tv_create_resources(xf86OutputPtr output) +{ +#ifdef RANDR_12_INTERFACE + ScrnInfoPtr pScrn = output->scrn; + I830OutputPrivatePtr intel_output = output->driver_private; + struct i830_tv_priv *dev_priv = intel_output->dev_priv; + int err; + int i; + + /* Set up the tv_format property, which takes effect on mode set + * and accepts strings that match exactly + */ + tv_format_atom = MakeAtom(TV_FORMAT_NAME, sizeof(TV_FORMAT_NAME) - 1, + TRUE); + + for (i = 0; i < NUM_TV_MODES; i++) + tv_format_name_atoms[i] = MakeAtom (tv_modes[i].name, + strlen (tv_modes[i].name), + TRUE); + + err = i830_tv_format_configure_property (output); + + if (err != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "RRConfigureOutputProperty error, %d\n", err); + } + + /* Set the current value of the tv_format property */ + if (!i830_tv_format_set_property (output)) + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "RRChangeOutputProperty error, %d\n", err); + + for (i = 0; i < 4; i++) + { + INT32 range[2]; + margin_atoms[i] = MakeAtom(margin_names[i], strlen (margin_names[i]), + TRUE); + + range[0] = 0; + range[1] = 100; + err = RRConfigureOutputProperty(output->randr_output, margin_atoms[i], + TRUE, TRUE, FALSE, 2, range); + + if (err != 0) + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "RRConfigureOutputProperty error, %d\n", err); + + err = RRChangeOutputProperty(output->randr_output, margin_atoms[i], + XA_INTEGER, 32, PropModeReplace, + 1, &dev_priv->margin[i], + FALSE, TRUE); + if (err != 0) + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "RRChangeOutputProperty error, %d\n", err); + } +#endif /* RANDR_12_INTERFACE */ +} + +#ifdef RANDR_12_INTERFACE +static Bool +i830_tv_set_property(xf86OutputPtr output, Atom property, + RRPropertyValuePtr value) +{ + int i; + + if (property == tv_format_atom) + { + I830OutputPrivatePtr intel_output = output->driver_private; + struct i830_tv_priv *dev_priv = intel_output->dev_priv; + Atom atom; + char *name; + char *val; + + if (value->type != XA_ATOM || value->format != 32 || value->size != 1) + return FALSE; + + memcpy (&atom, value->data, 4); + name = NameForAtom (atom); + + val = xalloc (strlen (name) + 1); + if (!val) + return FALSE; + strcpy (val, name); + if (!i830_tv_mode_lookup (val)) + { + xfree (val); + return FALSE; + } + xfree (dev_priv->tv_format); + dev_priv->tv_format = val; + return TRUE; + } + for (i = 0; i < 4; i++) + { + if (property == margin_atoms[i]) + { + I830OutputPrivatePtr intel_output = output->driver_private; + struct i830_tv_priv *dev_priv = intel_output->dev_priv; + INT32 val; + + if (value->type != XA_INTEGER || value->format != 32 || + value->size != 1) + return FALSE; + + memcpy (&val, value->data, 4); + dev_priv->margin[i] = val; + return TRUE; + } + } + + return TRUE; +} +#endif /* RANDR_12_INTERFACE */ + +static const xf86OutputFuncsRec i830_tv_output_funcs = { + .create_resources = i830_tv_create_resources, + .dpms = i830_tv_dpms, + .save = i830_tv_save, + .restore = i830_tv_restore, + .mode_valid = i830_tv_mode_valid, + .mode_fixup = i830_tv_mode_fixup, + .prepare = i830_output_prepare, + .mode_set = i830_tv_mode_set, + .commit = i830_output_commit, + .detect = i830_tv_detect, + .get_modes = i830_tv_get_modes, + .destroy = i830_tv_destroy, +#ifdef RANDR_12_INTERFACE + .set_property = i830_tv_set_property, +#endif +}; + +void +i830_tv_init(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + xf86OutputPtr output; + I830OutputPrivatePtr intel_output; + struct i830_tv_priv *dev_priv; + CARD32 tv_dac_on, tv_dac_off, save_tv_dac; + + if (pI830->quirk_flag & QUIRK_IGNORE_TV) + return; + + if ((INREG(TV_CTL) & TV_FUSE_STATE_MASK) == TV_FUSE_STATE_DISABLED) + return; + + /* + * Sanity check the TV output by checking to see if the + * DAC register holds a value + */ + save_tv_dac = INREG(TV_DAC); + + OUTREG(TV_DAC, save_tv_dac | TVDAC_STATE_CHG_EN); + tv_dac_on = INREG(TV_DAC); + + OUTREG(TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN); + tv_dac_off = INREG(TV_DAC); + + OUTREG(TV_DAC, save_tv_dac); + + /* + * If the register does not hold the state change enable + * bit, (either as a 0 or a 1), assume it doesn't really + * exist + */ + if ((tv_dac_on & TVDAC_STATE_CHG_EN) == 0 || + (tv_dac_off & TVDAC_STATE_CHG_EN) != 0) + return; + + output = xf86OutputCreate (pScrn, &i830_tv_output_funcs, "TV"); + + if (!output) + return; + + intel_output = xnfcalloc (sizeof (I830OutputPrivateRec) + + sizeof (struct i830_tv_priv), 1); + if (!intel_output) + { + xf86OutputDestroy (output); + return; + } + dev_priv = (struct i830_tv_priv *) (intel_output + 1); + intel_output->type = I830_OUTPUT_TVOUT; + intel_output->pipe_mask = ((1 << 0) | (1 << 1)); + intel_output->clone_mask = (1 << I830_OUTPUT_TVOUT); + intel_output->dev_priv = dev_priv; + dev_priv->type = TV_TYPE_UNKNOWN; + + dev_priv->tv_format = NULL; + + /* BIOS margin values */ + dev_priv->margin[TV_MARGIN_LEFT] = 54; + dev_priv->margin[TV_MARGIN_TOP] = 36; + dev_priv->margin[TV_MARGIN_RIGHT] = 46; + dev_priv->margin[TV_MARGIN_BOTTOM] = 37; + + if (output->conf_monitor) + { + char *tv_format; + + tv_format = xf86findOptionValue (output->conf_monitor->mon_option_lst, "TV Format"); + if (tv_format) + dev_priv->tv_format = xstrdup (tv_format); + } + if (!dev_priv->tv_format) + dev_priv->tv_format = xstrdup (tv_modes[0].name); + + output->driver_private = intel_output; + output->interlaceAllowed = FALSE; + output->doubleScanAllowed = FALSE; +} diff --git a/driver/xf86-video-intel/src/i830_xaa.c b/driver/xf86-video-intel/src/i830_xaa.c new file mode 100644 index 000000000..fabac20e2 --- /dev/null +++ b/driver/xf86-video-intel/src/i830_xaa.c @@ -0,0 +1,888 @@ +/************************************************************************** + +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> + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include "xf86.h" +#include "xaarop.h" +#include "i830.h" +#include "i810_reg.h" +#include "mipict.h" + +#ifndef DO_SCANLINE_IMAGE_WRITE +#define DO_SCANLINE_IMAGE_WRITE 0 +#endif + +/* 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 +static void I830RestoreAccelState(ScrnInfoPtr pScrn); + +void +i830_xaa_composite(CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height); + +Bool +I830XAAInit(ScreenPtr pScreen) +{ + XAAInfoRecPtr infoPtr; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + PictureScreenPtr ps = GetPictureScreenIfSet(pScreen); + I830Ptr pI830 = I830PTR(pScrn); + int i; + int width = 0; + int nr_buffers = 0; + unsigned char *ptr = NULL; + + if (I810_DEBUG & DEBUG_VERBOSE_ACCEL) + ErrorF("I830XAAInit\n"); + + pI830->AccelInfoRec = infoPtr = XAACreateInfoRec(); + if (!infoPtr) + return FALSE; + + 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); + + } + + /* On the primary screen */ + if (pI830->init == 0) { + if (pI830->xaa_scratch->size != 0) { + width = ((pScrn->displayWidth + 31) & ~31) / 8; + nr_buffers = pI830->xaa_scratch->size / width; + ptr = pI830->FbBase + pI830->xaa_scratch->offset; + } + } else { + /* On the secondary screen */ + I830Ptr pI8301 = I830PTR(pI830->entityPrivate->pScrn_1); + if (pI8301->xaa_scratch_2->size != 0) { + width = ((pScrn->displayWidth + 31) & ~31) / 8; + nr_buffers = pI8301->xaa_scratch_2->size / width; + /* We have to use the primary screen's FbBase, as that's where + * we allocated xaa_scratch_2, so we get the correct pointer */ + ptr = pI8301->FbBase + pI8301->xaa_scratch_2->offset; + } + } + + if (nr_buffers) { + 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 + } + + { + Bool shared_accel = FALSE; + + for(i = 0; i < pScrn->numEntities; i++) { + if(xf86IsEntityShared(pScrn->entityList[i])) + shared_accel = TRUE; + } + if(shared_accel == TRUE) + infoPtr->RestoreAccelState = I830RestoreAccelState; + } + + /* Set up pI830->bufferOffset */ + I830SelectBuffer(pScrn, I830_SELECT_FRONT); + + if (!XAAInit(pScreen, infoPtr)) + return FALSE; + + if (ps != NULL) { + if (IS_I865G(pI830) || IS_I855(pI830) || + IS_845G(pI830) || IS_I830(pI830)) + { + pI830->xaa_check_composite = i830_check_composite; + pI830->xaa_prepare_composite = i830_prepare_composite; + pI830->xaa_composite = i830_composite; + pI830->xaa_done_composite = i830_done_composite; + } else if (IS_I915G(pI830) || IS_I915GM(pI830) || + IS_I945G(pI830) || IS_I945GM(pI830) || IS_G33CLASS(pI830)) + { + pI830->xaa_check_composite = i915_check_composite; + pI830->xaa_prepare_composite = i915_prepare_composite; + pI830->xaa_composite = i830_composite; + pI830->xaa_done_composite = i830_done_composite; + } else { + pI830->xaa_check_composite = i965_check_composite; + pI830->xaa_prepare_composite = i965_prepare_composite; + pI830->xaa_composite = i965_composite; + pI830->xaa_done_composite = i830_done_composite; + } + + pI830->saved_composite = ps->Composite; + ps->Composite = i830_xaa_composite; + } + + return TRUE; +} + +static unsigned int +I830CheckTiling(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + + if (pI830->bufferOffset == pI830->front_buffer->offset && + pI830->front_buffer->tiling != TILE_NONE) + { + return TRUE; + } +#ifdef XF86DRI + if (pI830->back_buffer != NULL && + pI830->bufferOffset == pI830->back_buffer->offset && + pI830->back_buffer->tiling != TILE_NONE) + { + return TRUE; + } + if (pI830->depth_buffer != NULL && + pI830->bufferOffset == pI830->depth_buffer->offset && + pI830->depth_buffer->tiling != TILE_NONE) + { + return TRUE; + } + if (pI830->third_buffer != NULL && + pI830->bufferOffset == pI830->third_buffer->offset && + pI830->third_buffer->tiling != TILE_NONE) + { + return TRUE; + } +#endif + + return FALSE; +} + +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); + + if (IS_I965G(pI830) && I830CheckTiling(pScrn)) { + pI830->BR[13] = (pScrn->displayWidth * pI830->cpp) >> 4; + } else { + pI830->BR[13] = (pScrn->displayWidth * pI830->cpp); + } + +#ifdef I830_USE_EXA + /* This function gets used by I830DRIInitBuffers(), and we might not have + * XAAGetPatternROP() available. So just use the ROPs from our EXA code + * if available. + */ + pI830->BR[13] |= (I830PatternROP[rop] << 16); +#else + pI830->BR[13] |= ((XAAGetPatternROP(rop) << 16); +#endif + + 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(); + } + + if (IS_I965G(pI830)) + I830EmitFlush(pScrn); +} + +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); + + if (IS_I965G(pI830) && I830CheckTiling(pScrn)) { + pI830->BR[13] = (pScrn->displayWidth * pI830->cpp) >> 4; + } else { + pI830->BR[13] = (pScrn->displayWidth * pI830->cpp); + } + +#ifdef I830_USE_EXA + /* This function gets used by I830DRIInitBuffers(), and we might not have + * XAAGetCopyROP() available. So just use the ROPs from our EXA code + * if available. + */ + pI830->BR[13] |= I830CopyROP[rop] << 16; +#else + pI830->BR[13] |= XAAGetCopyROP(rop) << 16; +#endif + + 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; + unsigned int tiled = I830CheckTiling(pScrn); + + 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 | tiled << 15 | tiled << 11); + } else { + OUT_RING(XY_SRC_COPY_BLT_CMD | tiled << 15 | tiled << 11); + } + 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(); + } + + if (IS_I965G(pI830)) + I830EmitFlush(pScrn); +} + +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; + + if (IS_I965G(pI830) && I830CheckTiling(pScrn)) { + pI830->BR[13] = (pScrn->displayWidth * pI830->cpp) >> 4; + } else { + pI830->BR[13] = (pScrn->displayWidth * pI830->cpp); + } + pI830->BR[13] |= XAAGetPatternROP(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; + unsigned int tiled = I830CheckTiling(pScrn); + + 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 | tiled << 11 | + ((patty << 8) & XY_MONO_PAT_VERT_SEED) | + ((pattx << 12) & XY_MONO_PAT_HORT_SEED)); + } else { + OUT_RING(XY_MONO_PAT_BLT_CMD | tiled << 11 | + ((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(); + } + + if (IS_I965G(pI830)) + I830EmitFlush(pScrn); +} + +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 */ + if (IS_I965G(pI830) && I830CheckTiling(pScrn)) { + pI830->BR[13] = (pScrn->displayWidth * pI830->cpp) >> 4; + } else { + pI830->BR[13] = (pScrn->displayWidth * pI830->cpp); + } + pI830->BR[13] |= XAAGetCopyROP(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); + unsigned int tiled = I830CheckTiling(pScrn); + + if (pI830->init == 0) { + pI830->BR[12] = (pI830->AccelInfoRec->ScanlineColorExpandBuffers[0] - + pI830->FbBase); + } else { + I830Ptr pI8301 = I830PTR(pI830->entityPrivate->pScrn_1); + + /* We have to use the primary screen's FbBase, as that's where + * we allocated xaa_scratch_2, so we get the correct pointer */ + pI830->BR[12] = (pI830->AccelInfoRec->ScanlineColorExpandBuffers[0] - + pI8301->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 | + tiled << 11 | XY_MONO_SRC_BLT_WRITE_RGB); + } else { + OUT_RING(XY_MONO_SRC_BLT_CMD | tiled << 11); + } + 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 (IS_I965G(pI830)) + I830EmitFlush(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 */ + if (IS_I965G(pI830) && I830CheckTiling(pScrn)) { + pI830->BR[13] = (pScrn->displayWidth * pI830->cpp) >> 4; + } else { + pI830->BR[13] = (pScrn->displayWidth * pI830->cpp); + } + pI830->BR[13] |= XAAGetCopyROP(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); + unsigned int tiled = I830CheckTiling(pScrn); + + if (pI830->init == 0) { + pI830->BR[12] = (pI830->AccelInfoRec->ScanlineColorExpandBuffers[0] - + pI830->FbBase); + } else { + I830Ptr pI8301 = I830PTR(pI830->entityPrivate->pScrn_1); + + /* We have to use the primary screen's FbBase, as that's where + * we allocated xaa_scratch_2, so we get the correct pointer */ + pI830->BR[12] = (pI830->AccelInfoRec->ScanlineColorExpandBuffers[0] - + pI8301->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 | + tiled << 11 | XY_SRC_COPY_BLT_WRITE_RGB); + } else { + OUT_RING(XY_SRC_COPY_BLT_CMD | tiled << 11); + } + 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 /* DO_SCANLINE_IMAGE_WRITE */ +/* Support for multiscreen */ + +/** + * Special case acceleration for Render acceleration of rotation operations + * by xf86Rotate.c + */ +void +i830_xaa_composite(CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + ScreenPtr pScreen = pDst->pDrawable->pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I830Ptr pI830 = I830PTR(pScrn); + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + PictureScreenPtr ps; + PixmapPtr pSrcPixmap, pDstPixmap; + RegionRec region; + BoxPtr pbox; + int nbox; + int i; + + /* Throw out cases that aren't going to be our rotation first */ + if (pMask != NULL || op != PictOpSrc || pSrc->pDrawable == NULL) + goto fallback; + + if (pSrc->pDrawable->type != DRAWABLE_WINDOW || + pDst->pDrawable->type != DRAWABLE_PIXMAP) + { + goto fallback; + } + pSrcPixmap = (*pScreen->GetWindowPixmap) ((WindowPtr) pSrc->pDrawable); + pDstPixmap = (PixmapPtr)pDst->pDrawable; + + /* Check if the dest is one of our shadow pixmaps */ + for (i = 0; i < xf86_config->num_crtc; i++) { + xf86CrtcPtr crtc = xf86_config->crtc[i]; + + if (crtc->rotatedPixmap == pDstPixmap) + break; + } + if (i == xf86_config->num_crtc) + goto fallback; + + if (pSrcPixmap != pScreen->GetScreenPixmap(pScreen)) + goto fallback; + + /* OK, so we've got a Render operation on one of our shadow pixmaps, with + * the source being the real framebuffer. We know that both of these are + * in framebuffer, with no x/y offsets, i.e. normal pixmaps like our EXA- + * based Render acceleration code expects. + */ + assert(pSrcPixmap->drawable.x == 0); + assert(pSrcPixmap->drawable.y == 0); + assert(pDstPixmap->drawable.x == 0); + assert(pDstPixmap->drawable.y == 0); + + if (!miComputeCompositeRegion (®ion, pSrc, NULL, pDst, + xSrc, ySrc, 0, 0, xDst, yDst, + width, height)) + return; + + if (!pI830->xaa_check_composite(op, pSrc, NULL, pDst)) { + REGION_UNINIT(pScreen, ®ion); + goto fallback; + } + + if (!pI830->xaa_prepare_composite(op, pSrc, NULL, pDst, + pSrcPixmap, NULL, pDstPixmap)) + { + REGION_UNINIT(pScreen, ®ion); + goto fallback; + } + + nbox = REGION_NUM_RECTS(®ion); + pbox = REGION_RECTS(®ion); + + xSrc -= xDst; + ySrc -= yDst; + + while (nbox--) + { + pI830->xaa_composite(pDstPixmap, + pbox->x1 + xSrc, + pbox->y1 + ySrc, + 0, 0, + pbox->x1, + pbox->y1, + pbox->x2 - pbox->x1, + pbox->y2 - pbox->y1); + pbox++; + } + + REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); + + pI830->xaa_done_composite(pDstPixmap); + i830MarkSync(pScrn); + + return; + +fallback: + /* Fallback path: Call down to the next level (XAA) */ + ps = GetPictureScreenIfSet(pScreen); + + ps->Composite = pI830->saved_composite; + + ps->Composite(op, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, xDst, yDst, + width, height); + + pI830->saved_composite = ps->Composite; + ps->Composite = i830_xaa_composite; +} + +static void +I830RestoreAccelState(ScrnInfoPtr pScrn) +{ +#if 0 + /* might be needed, but everything is on a ring, so I don't think so */ + I830Sync(pScrn); +#endif +} + diff --git a/driver/xf86-video-intel/src/i915_render.c b/driver/xf86-video-intel/src/i915_render.c new file mode 100644 index 000000000..ca85bf73c --- /dev/null +++ b/driver/xf86-video-intel/src/i915_render.c @@ -0,0 +1,481 @@ +/* + * Copyright © 2006 Intel Corporation + * + * 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 + * THE AUTHORS OR COPYRIGHT HOLDERS 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: + * Wang Zhenyu <zhenyu.z.wang@intel.com> + * Eric Anholt <eric@anholt.net> + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "xf86.h" +#include "i830.h" +#include "i915_reg.h" +#include "i915_3d.h" + +#ifdef I830DEBUG +#define DEBUG_I830FALLBACK 1 +#endif + +#ifdef DEBUG_I830FALLBACK +#define I830FALLBACK(s, arg...) \ +do { \ + DPRINTF(PFX, "EXA fallback: " s "\n", ##arg); \ + return FALSE; \ +} while(0) +#else +#define I830FALLBACK(s, arg...) \ +do { \ + return FALSE; \ +} while(0) +#endif + +struct formatinfo { + int fmt; + CARD32 card_fmt; +}; + +struct blendinfo { + Bool dst_alpha; + Bool src_alpha; + CARD32 src_blend; + CARD32 dst_blend; +}; + +static struct blendinfo i915_blend_op[] = { + /* Clear */ + {0, 0, BLENDFACT_ZERO, BLENDFACT_ZERO}, + /* Src */ + {0, 0, BLENDFACT_ONE, BLENDFACT_ZERO}, + /* Dst */ + {0, 0, BLENDFACT_ZERO, BLENDFACT_ONE}, + /* Over */ + {0, 1, BLENDFACT_ONE, BLENDFACT_INV_SRC_ALPHA}, + /* OverReverse */ + {1, 0, BLENDFACT_INV_DST_ALPHA, BLENDFACT_ONE}, + /* In */ + {1, 0, BLENDFACT_DST_ALPHA, BLENDFACT_ZERO}, + /* InReverse */ + {0, 1, BLENDFACT_ZERO, BLENDFACT_SRC_ALPHA}, + /* Out */ + {1, 0, BLENDFACT_INV_DST_ALPHA, BLENDFACT_ZERO}, + /* OutReverse */ + {0, 1, BLENDFACT_ZERO, BLENDFACT_INV_SRC_ALPHA}, + /* Atop */ + {1, 1, BLENDFACT_DST_ALPHA, BLENDFACT_INV_SRC_ALPHA}, + /* AtopReverse */ + {1, 1, BLENDFACT_INV_DST_ALPHA, BLENDFACT_SRC_ALPHA}, + /* Xor */ + {1, 1, BLENDFACT_INV_DST_ALPHA, BLENDFACT_INV_SRC_ALPHA}, + /* Add */ + {0, 0, BLENDFACT_ONE, BLENDFACT_ONE}, +}; + +static struct formatinfo i915_tex_formats[] = { + {PICT_a8r8g8b8, MAPSURF_32BIT | MT_32BIT_ARGB8888 }, + {PICT_x8r8g8b8, MAPSURF_32BIT | MT_32BIT_XRGB8888 }, + {PICT_a8b8g8r8, MAPSURF_32BIT | MT_32BIT_ABGR8888 }, + {PICT_x8b8g8r8, MAPSURF_32BIT | MT_32BIT_XBGR8888 }, + {PICT_r5g6b5, MAPSURF_16BIT | MT_16BIT_RGB565 }, + {PICT_a1r5g5b5, MAPSURF_16BIT | MT_16BIT_ARGB1555 }, + {PICT_x1r5g5b5, MAPSURF_16BIT | MT_16BIT_ARGB1555 }, + {PICT_a4r4g4b4, MAPSURF_16BIT | MT_16BIT_ARGB4444 }, + {PICT_x4r4g4b4, MAPSURF_16BIT | MT_16BIT_ARGB4444 }, + {PICT_a8, MAPSURF_8BIT | MT_8BIT_A8 }, +}; + +static CARD32 i915_get_blend_cntl(int op, PicturePtr pMask, CARD32 dst_format) +{ + CARD32 sblend, dblend; + + sblend = i915_blend_op[op].src_blend; + dblend = i915_blend_op[op].dst_blend; + + /* If there's no dst alpha channel, adjust the blend op so that we'll treat + * it as always 1. + */ + if (PICT_FORMAT_A(dst_format) == 0 && i915_blend_op[op].dst_alpha) { + if (sblend == BLENDFACT_DST_ALPHA) + sblend = BLENDFACT_ONE; + else if (sblend == BLENDFACT_INV_DST_ALPHA) + sblend = BLENDFACT_ZERO; + } + + /* i915 engine reads 8bit color buffer into green channel in cases + like color buffer blending .etc, and also writes back green channel. + So with dst_alpha blend we should use color factor. See spec on + "8-bit rendering" */ + if ((dst_format == PICT_a8) && i915_blend_op[op].dst_alpha) { + if (sblend == BLENDFACT_DST_ALPHA) + sblend = BLENDFACT_DST_COLR; + else if (sblend == BLENDFACT_INV_DST_ALPHA) + sblend = BLENDFACT_INV_DST_COLR; + } + + /* If the source alpha is being used, then we should only be in a case + * where the source blend factor is 0, and the source blend value is the + * mask channels multiplied by the source picture's alpha. + */ + if (pMask && pMask->componentAlpha && PICT_FORMAT_RGB(pMask->format) && + i915_blend_op[op].src_alpha) + { + if (dblend == BLENDFACT_SRC_ALPHA) { + dblend = BLENDFACT_SRC_COLR; + } else if (dblend == BLENDFACT_INV_SRC_ALPHA) { + dblend = BLENDFACT_INV_SRC_COLR; + } + } + + return (sblend << S6_CBUF_SRC_BLEND_FACT_SHIFT) | + (dblend << S6_CBUF_DST_BLEND_FACT_SHIFT); +} + +static Bool i915_get_dest_format(PicturePtr pDstPicture, CARD32 *dst_format) +{ + switch (pDstPicture->format) { + case PICT_a8r8g8b8: + case PICT_x8r8g8b8: + *dst_format = COLR_BUF_ARGB8888; + break; + case PICT_r5g6b5: + *dst_format = COLR_BUF_RGB565; + break; + case PICT_a1r5g5b5: + case PICT_x1r5g5b5: + *dst_format = COLR_BUF_ARGB1555; + break; + case PICT_a8: + *dst_format = COLR_BUF_8BIT; + break; + case PICT_a4r4g4b4: + case PICT_x4r4g4b4: + *dst_format = COLR_BUF_ARGB4444; + break; + default: + I830FALLBACK("Unsupported dest format 0x%x\n", + (int)pDstPicture->format); + } + + return TRUE; +} + +static Bool i915_check_composite_texture(PicturePtr pPict, int unit) +{ + int w = pPict->pDrawable->width; + int h = pPict->pDrawable->height; + int i; + + if ((w > 0x7ff) || (h > 0x7ff)) + I830FALLBACK("Picture w/h too large (%dx%d)\n", w, h); + + for (i = 0; i < sizeof(i915_tex_formats) / sizeof(i915_tex_formats[0]); + i++) + { + if (i915_tex_formats[i].fmt == pPict->format) + break; + } + if (i == sizeof(i915_tex_formats) / sizeof(i915_tex_formats[0])) + I830FALLBACK("Unsupported picture format 0x%x\n", + (int)pPict->format); + + if (pPict->repeat && pPict->repeatType != RepeatNormal) + I830FALLBACK("extended repeat (%d) not supported\n", + pPict->repeatType); + + if (pPict->filter != PictFilterNearest && + pPict->filter != PictFilterBilinear) + I830FALLBACK("Unsupported filter 0x%x\n", pPict->filter); + + return TRUE; +} + +Bool +i915_check_composite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture, + PicturePtr pDstPicture) +{ + CARD32 tmp1; + + /* Check for unsupported compositing operations. */ + if (op >= sizeof(i915_blend_op) / sizeof(i915_blend_op[0])) + I830FALLBACK("Unsupported Composite op 0x%x\n", op); + if (pMaskPicture != NULL && pMaskPicture->componentAlpha && + PICT_FORMAT_RGB(pMaskPicture->format)) + { + /* Check if it's component alpha that relies on a source alpha and on + * the source value. We can only get one of those into the single + * source value that we get to blend with. + */ + if (i915_blend_op[op].src_alpha && + (i915_blend_op[op].src_blend != BLENDFACT_ZERO)) + I830FALLBACK("Component alpha not supported with source " + "alpha and source value blending.\n"); + } + + if (!i915_check_composite_texture(pSrcPicture, 0)) + I830FALLBACK("Check Src picture texture\n"); + if (pMaskPicture != NULL && !i915_check_composite_texture(pMaskPicture, 1)) + I830FALLBACK("Check Mask picture texture\n"); + + if (!i915_get_dest_format(pDstPicture, &tmp1)) + I830FALLBACK("Get Color buffer format\n"); + + return TRUE; +} + +static Bool +i915_texture_setup(PicturePtr pPict, PixmapPtr pPix, int unit) +{ + ScrnInfoPtr pScrn = xf86Screens[pPict->pDrawable->pScreen->myNum]; + I830Ptr pI830 = I830PTR(pScrn); + CARD32 format, offset, pitch, filter; + int w, h, i; + CARD32 wrap_mode = TEXCOORDMODE_CLAMP_BORDER; + + offset = intel_get_pixmap_offset(pPix); + pitch = intel_get_pixmap_pitch(pPix); + w = pPict->pDrawable->width; + h = pPict->pDrawable->height; + pI830->scale_units[unit][0] = pPix->drawable.width; + pI830->scale_units[unit][1] = pPix->drawable.height; + + for (i = 0; i < sizeof(i915_tex_formats) / sizeof(i915_tex_formats[0]); + i++) + { + if (i915_tex_formats[i].fmt == pPict->format) + break; + } + if (i == sizeof(i915_tex_formats)/ sizeof(i915_tex_formats[0])) + I830FALLBACK("unknown texture format\n"); + format = i915_tex_formats[i].card_fmt; + + if (pPict->repeat) + wrap_mode = TEXCOORDMODE_WRAP; + + switch (pPict->filter) { + case PictFilterNearest: + filter = (FILTER_NEAREST << SS2_MAG_FILTER_SHIFT) | + (FILTER_NEAREST << SS2_MIN_FILTER_SHIFT); + break; + case PictFilterBilinear: + filter = (FILTER_LINEAR << SS2_MAG_FILTER_SHIFT) | + (FILTER_LINEAR << SS2_MIN_FILTER_SHIFT); + break; + default: + filter = 0; + I830FALLBACK("Bad filter 0x%x\n", pPict->filter); + } + + pI830->mapstate[unit * 3 + 0] = offset; + pI830->mapstate[unit * 3 + 1] = format | + MS3_USE_FENCE_REGS | + ((pPix->drawable.height - 1) << MS3_HEIGHT_SHIFT) | + ((pPix->drawable.width - 1) << MS3_WIDTH_SHIFT); + pI830->mapstate[unit * 3 + 2] = ((pitch / 4) - 1) << MS4_PITCH_SHIFT; + + pI830->samplerstate[unit * 3 + 0] = (MIPFILTER_NONE << + SS2_MIP_FILTER_SHIFT); + pI830->samplerstate[unit * 3 + 0] |= filter; + pI830->samplerstate[unit * 3 + 1] = SS3_NORMALIZED_COORDS; + pI830->samplerstate[unit * 3 + 1] |= wrap_mode << SS3_TCX_ADDR_MODE_SHIFT; + pI830->samplerstate[unit * 3 + 1] |= wrap_mode << SS3_TCY_ADDR_MODE_SHIFT; + pI830->samplerstate[unit * 3 + 1] |= unit << SS3_TEXTUREMAP_INDEX_SHIFT; + pI830->samplerstate[unit * 3 + 2] = 0x00000000; /* border color */ + + pI830->transform[unit] = pPict->transform; + + return TRUE; +} + +Bool +i915_prepare_composite(int op, PicturePtr pSrcPicture, + PicturePtr pMaskPicture, PicturePtr pDstPicture, + PixmapPtr pSrc, PixmapPtr pMask, PixmapPtr pDst) +{ + ScrnInfoPtr pScrn = xf86Screens[pSrcPicture->pDrawable->pScreen->myNum]; + I830Ptr pI830 = I830PTR(pScrn); + CARD32 dst_format, dst_offset, dst_pitch; + CARD32 blendctl; + int out_reg = FS_OC; + + IntelEmitInvarientState(pScrn); + *pI830->last_3d = LAST_3D_RENDER; + + i915_get_dest_format(pDstPicture, &dst_format); + dst_offset = intel_get_pixmap_offset(pDst); + dst_pitch = intel_get_pixmap_pitch(pDst); + FS_LOCALS(20); + + if (!i915_texture_setup(pSrcPicture, pSrc, 0)) + I830FALLBACK("fail to setup src texture\n"); + if (pMask != NULL) { + if (!i915_texture_setup(pMaskPicture, pMask, 1)) + I830FALLBACK("fail to setup mask texture\n"); + } else { + pI830->transform[1] = NULL; + pI830->scale_units[1][0] = -1; + pI830->scale_units[1][1] = -1; + } + + if (pMask == NULL) { + BEGIN_LP_RING(10); + OUT_RING(_3DSTATE_MAP_STATE | 3); + OUT_RING(0x00000001); /* map 0 */ + OUT_RING(pI830->mapstate[0]); + OUT_RING(pI830->mapstate[1]); + OUT_RING(pI830->mapstate[2]); + + OUT_RING(_3DSTATE_SAMPLER_STATE | 3); + OUT_RING(0x00000001); /* sampler 0 */ + OUT_RING(pI830->samplerstate[0]); + OUT_RING(pI830->samplerstate[1]); + OUT_RING(pI830->samplerstate[2]); + ADVANCE_LP_RING(); + } else { + BEGIN_LP_RING(16); + OUT_RING(_3DSTATE_MAP_STATE | 6); + OUT_RING(0x00000003); /* map 0,1 */ + OUT_RING(pI830->mapstate[0]); + OUT_RING(pI830->mapstate[1]); + OUT_RING(pI830->mapstate[2]); + OUT_RING(pI830->mapstate[3]); + OUT_RING(pI830->mapstate[4]); + OUT_RING(pI830->mapstate[5]); + + OUT_RING(_3DSTATE_SAMPLER_STATE | 6); + OUT_RING(0x00000003); /* sampler 0,1 */ + OUT_RING(pI830->samplerstate[0]); + OUT_RING(pI830->samplerstate[1]); + OUT_RING(pI830->samplerstate[2]); + OUT_RING(pI830->samplerstate[3]); + OUT_RING(pI830->samplerstate[4]); + OUT_RING(pI830->samplerstate[5]); + ADVANCE_LP_RING(); + } + { + CARD32 ss2; + + BEGIN_LP_RING(16); + OUT_RING(_3DSTATE_BUF_INFO_CMD); + OUT_RING(BUF_3D_ID_COLOR_BACK| BUF_3D_USE_FENCE| + BUF_3D_PITCH(dst_pitch)); + OUT_RING(BUF_3D_ADDR(dst_offset)); + + OUT_RING(_3DSTATE_DST_BUF_VARS_CMD); + OUT_RING(dst_format); + + OUT_RING(_3DSTATE_LOAD_STATE_IMMEDIATE_1 | I1_LOAD_S(2) | + I1_LOAD_S(4) | I1_LOAD_S(5) | I1_LOAD_S(6) | 3); + ss2 = S2_TEXCOORD_FMT(0, TEXCOORDFMT_2D); + if (pMask) + ss2 |= S2_TEXCOORD_FMT(1, TEXCOORDFMT_2D); + else + ss2 |= S2_TEXCOORD_FMT(1, TEXCOORDFMT_NOT_PRESENT); + ss2 |= S2_TEXCOORD_FMT(2, TEXCOORDFMT_NOT_PRESENT); + ss2 |= S2_TEXCOORD_FMT(3, TEXCOORDFMT_NOT_PRESENT); + ss2 |= S2_TEXCOORD_FMT(4, TEXCOORDFMT_NOT_PRESENT); + ss2 |= S2_TEXCOORD_FMT(5, TEXCOORDFMT_NOT_PRESENT); + ss2 |= S2_TEXCOORD_FMT(6, TEXCOORDFMT_NOT_PRESENT); + ss2 |= S2_TEXCOORD_FMT(7, TEXCOORDFMT_NOT_PRESENT); + OUT_RING(ss2); + OUT_RING((1 << S4_POINT_WIDTH_SHIFT) | S4_LINE_WIDTH_ONE | + S4_CULLMODE_NONE| S4_VFMT_XY); + blendctl = i915_get_blend_cntl(op, pMaskPicture, pDstPicture->format); + OUT_RING(0x00000000); /* Disable stencil buffer */ + OUT_RING(S6_CBUF_BLEND_ENABLE | S6_COLOR_WRITE_ENABLE | + (BLENDFUNC_ADD << S6_CBUF_BLEND_FUNC_SHIFT) | blendctl); + + /* draw rect is unconditional */ + OUT_RING(_3DSTATE_DRAW_RECT_CMD); + OUT_RING(0x00000000); + OUT_RING(0x00000000); /* ymin, xmin*/ + OUT_RING(DRAW_YMAX(pDst->drawable.height - 1) | + DRAW_XMAX(pDst->drawable.width - 1)); + OUT_RING(0x00000000); /* yorig, xorig (relate to color buffer?)*/ + OUT_RING(MI_NOOP); + ADVANCE_LP_RING(); + } + + if (dst_format == COLR_BUF_8BIT) + out_reg = FS_U0; + + FS_BEGIN(); + + /* Declare the registers necessary for our program. I don't think the + * S then T ordering is necessary. + */ + i915_fs_dcl(FS_S0); + if (pMask) + i915_fs_dcl(FS_S1); + i915_fs_dcl(FS_T0); + if (pMask) + i915_fs_dcl(FS_T1); + + /* Load the pSrcPicture texel */ + i915_fs_texld(FS_R0, FS_S0, FS_T0); + /* If the texture lacks an alpha channel, force the alpha to 1. */ + if (PICT_FORMAT_A(pSrcPicture->format) == 0) + i915_fs_mov_masked(FS_R0, MASK_W, i915_fs_operand_one()); + + if (!pMask) { + /* No mask, so move to output color */ + i915_fs_mov(out_reg, i915_fs_operand_reg(FS_R0)); + } else { + /* Load the pMaskPicture texel */ + i915_fs_texld(FS_R1, FS_S1, FS_T1); + /* If the texture lacks an alpha channel, force the alpha to 1. */ + if (PICT_FORMAT_A(pMaskPicture->format) == 0) + i915_fs_mov_masked(FS_R1, MASK_W, i915_fs_operand_one()); + + /* If component alpha is active in the mask and the blend operation + * uses the source alpha, then we know we don't need the source + * value (otherwise we would have hit a fallback earlier), so we + * provide the source alpha (src.A * mask.X) as output color. + * Conversely, if CA is set and we don't need the source alpha, then + * we produce the source value (src.X * mask.X) and the source alpha + * is unused.. Otherwise, we provide the non-CA source value + * (src.X * mask.A). + */ + if (pMaskPicture->componentAlpha && + PICT_FORMAT_RGB(pMaskPicture->format)) + { + if (i915_blend_op[op].src_alpha) { + i915_fs_mul(out_reg, i915_fs_operand(FS_R0, W, W, W, W), + i915_fs_operand_reg(FS_R1)); + } else { + i915_fs_mul(out_reg, i915_fs_operand_reg(FS_R0), + i915_fs_operand_reg(FS_R1)); + } + } else { + i915_fs_mul(out_reg, i915_fs_operand_reg(FS_R0), + i915_fs_operand(FS_R1, W, W, W, W)); + } + } + if (dst_format == COLR_BUF_8BIT) + i915_fs_mov(FS_OC, i915_fs_operand(out_reg, W, W, W, W)); + + FS_END(); + + return TRUE; +} diff --git a/driver/xf86-video-intel/src/i965_render.c b/driver/xf86-video-intel/src/i965_render.c new file mode 100644 index 000000000..ad3b53ef5 --- /dev/null +++ b/driver/xf86-video-intel/src/i965_render.c @@ -0,0 +1,1190 @@ +/* + * Copyright © 2006 Intel Corporation + * + * 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 + * THE AUTHORS OR COPYRIGHT HOLDERS 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: + * Wang Zhenyu <zhenyu.z.wang@intel.com> + * Eric Anholt <eric@anholt.net> + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include "xf86.h" +#include "i830.h" +#include "i915_reg.h" + +/* bring in brw structs */ +#include "brw_defines.h" +#include "brw_structs.h" + +#ifdef I830DEBUG +#define DEBUG_I830FALLBACK 1 +#endif + +#ifdef DEBUG_I830FALLBACK +#define I830FALLBACK(s, arg...) \ +do { \ + DPRINTF(PFX, "EXA fallback: " s "\n", ##arg); \ + return FALSE; \ +} while(0) +#else +#define I830FALLBACK(s, arg...) \ +do { \ + return FALSE; \ +} while(0) +#endif + +struct blendinfo { + Bool dst_alpha; + Bool src_alpha; + CARD32 src_blend; + CARD32 dst_blend; +}; + +struct formatinfo { + int fmt; + CARD32 card_fmt; +}; + +// refer vol2, 3d rasterization 3.8.1 + +/* defined in brw_defines.h */ +static struct blendinfo i965_blend_op[] = { + /* Clear */ + {0, 0, BRW_BLENDFACTOR_ZERO, BRW_BLENDFACTOR_ZERO}, + /* Src */ + {0, 0, BRW_BLENDFACTOR_ONE, BRW_BLENDFACTOR_ZERO}, + /* Dst */ + {0, 0, BRW_BLENDFACTOR_ZERO, BRW_BLENDFACTOR_ONE}, + /* Over */ + {0, 1, BRW_BLENDFACTOR_ONE, BRW_BLENDFACTOR_INV_SRC_ALPHA}, + /* OverReverse */ + {1, 0, BRW_BLENDFACTOR_INV_DST_ALPHA, BRW_BLENDFACTOR_ONE}, + /* In */ + {1, 0, BRW_BLENDFACTOR_DST_ALPHA, BRW_BLENDFACTOR_ZERO}, + /* InReverse */ + {0, 1, BRW_BLENDFACTOR_ZERO, BRW_BLENDFACTOR_SRC_ALPHA}, + /* Out */ + {1, 0, BRW_BLENDFACTOR_INV_DST_ALPHA, BRW_BLENDFACTOR_ZERO}, + /* OutReverse */ + {0, 1, BRW_BLENDFACTOR_ZERO, BRW_BLENDFACTOR_INV_SRC_ALPHA}, + /* Atop */ + {1, 1, BRW_BLENDFACTOR_DST_ALPHA, BRW_BLENDFACTOR_INV_SRC_ALPHA}, + /* AtopReverse */ + {1, 1, BRW_BLENDFACTOR_INV_DST_ALPHA, BRW_BLENDFACTOR_SRC_ALPHA}, + /* Xor */ + {1, 1, BRW_BLENDFACTOR_INV_DST_ALPHA, BRW_BLENDFACTOR_INV_SRC_ALPHA}, + /* Add */ + {0, 0, BRW_BLENDFACTOR_ONE, BRW_BLENDFACTOR_ONE}, +}; + +/* FIXME: surface format defined in brw_defines.h, shared Sampling engine + * 1.7.2 + */ +static struct formatinfo i965_tex_formats[] = { + {PICT_a8r8g8b8, BRW_SURFACEFORMAT_B8G8R8A8_UNORM }, + {PICT_x8r8g8b8, BRW_SURFACEFORMAT_B8G8R8X8_UNORM }, + {PICT_a8b8g8r8, BRW_SURFACEFORMAT_R8G8B8A8_UNORM }, + {PICT_x8b8g8r8, BRW_SURFACEFORMAT_R8G8B8X8_UNORM }, + {PICT_r5g6b5, BRW_SURFACEFORMAT_B5G6R5_UNORM }, + {PICT_a1r5g5b5, BRW_SURFACEFORMAT_B5G5R5A1_UNORM }, + {PICT_a8, BRW_SURFACEFORMAT_A8_UNORM }, +}; + +static void i965_get_blend_cntl(int op, PicturePtr pMask, CARD32 dst_format, + CARD32 *sblend, CARD32 *dblend) +{ + + *sblend = i965_blend_op[op].src_blend; + *dblend = i965_blend_op[op].dst_blend; + + /* If there's no dst alpha channel, adjust the blend op so that we'll treat + * it as always 1. + */ + if (PICT_FORMAT_A(dst_format) == 0 && i965_blend_op[op].dst_alpha) { + if (*sblend == BRW_BLENDFACTOR_DST_ALPHA) + *sblend = BRW_BLENDFACTOR_ONE; + else if (*sblend == BRW_BLENDFACTOR_INV_DST_ALPHA) + *sblend = BRW_BLENDFACTOR_ZERO; + } + + /* If the source alpha is being used, then we should only be in a case where + * the source blend factor is 0, and the source blend value is the mask + * channels multiplied by the source picture's alpha. + */ + if (pMask && pMask->componentAlpha && PICT_FORMAT_RGB(pMask->format) + && i965_blend_op[op].src_alpha) { + if (*dblend == BRW_BLENDFACTOR_SRC_ALPHA) { + *dblend = BRW_BLENDFACTOR_SRC_COLOR; + } else if (*dblend == BRW_BLENDFACTOR_INV_SRC_ALPHA) { + *dblend = BRW_BLENDFACTOR_INV_SRC_COLOR; + } + } + +} + +static Bool i965_get_dest_format(PicturePtr pDstPicture, CARD32 *dst_format) +{ + switch (pDstPicture->format) { + case PICT_a8r8g8b8: + case PICT_x8r8g8b8: + *dst_format = BRW_SURFACEFORMAT_B8G8R8A8_UNORM; + break; + case PICT_r5g6b5: + *dst_format = BRW_SURFACEFORMAT_B5G6R5_UNORM; + break; + case PICT_a1r5g5b5: + *dst_format = BRW_SURFACEFORMAT_B5G5R5A1_UNORM; + break; + case PICT_x1r5g5b5: + *dst_format = BRW_SURFACEFORMAT_B5G5R5X1_UNORM; + break; + case PICT_a8: + *dst_format = BRW_SURFACEFORMAT_A8_UNORM; + break; + case PICT_a4r4g4b4: + case PICT_x4r4g4b4: + *dst_format = BRW_SURFACEFORMAT_B4G4R4A4_UNORM; + break; + default: + I830FALLBACK("Unsupported dest format 0x%x\n", + (int)pDstPicture->format); + } + + return TRUE; +} + +static Bool i965_check_composite_texture(PicturePtr pPict, int unit) +{ + int w = pPict->pDrawable->width; + int h = pPict->pDrawable->height; + int i; + + if ((w > 0x7ff) || (h > 0x7ff)) + I830FALLBACK("Picture w/h too large (%dx%d)\n", w, h); + + for (i = 0; i < sizeof(i965_tex_formats) / sizeof(i965_tex_formats[0]); + i++) + { + if (i965_tex_formats[i].fmt == pPict->format) + break; + } + if (i == sizeof(i965_tex_formats) / sizeof(i965_tex_formats[0])) + I830FALLBACK("Unsupported picture format 0x%x\n", + (int)pPict->format); + + if (pPict->repeat && pPict->repeatType != RepeatNormal) + I830FALLBACK("extended repeat (%d) not supported\n", + pPict->repeatType); + + if (pPict->filter != PictFilterNearest && + pPict->filter != PictFilterBilinear) + { + I830FALLBACK("Unsupported filter 0x%x\n", pPict->filter); + } + + return TRUE; +} + +Bool +i965_check_composite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture, + PicturePtr pDstPicture) +{ + CARD32 tmp1; + + /* Check for unsupported compositing operations. */ + if (op >= sizeof(i965_blend_op) / sizeof(i965_blend_op[0])) + I830FALLBACK("Unsupported Composite op 0x%x\n", op); + + if (pMaskPicture && pMaskPicture->componentAlpha && + PICT_FORMAT_RGB(pMaskPicture->format)) { + /* Check if it's component alpha that relies on a source alpha and on + * the source value. We can only get one of those into the single + * source value that we get to blend with. + */ + if (i965_blend_op[op].src_alpha && + (i965_blend_op[op].src_blend != BRW_BLENDFACTOR_ZERO)) + { + I830FALLBACK("Component alpha not supported with source " + "alpha and source value blending.\n"); + } + } + + if (!i965_check_composite_texture(pSrcPicture, 0)) + I830FALLBACK("Check Src picture texture\n"); + if (pMaskPicture != NULL && !i965_check_composite_texture(pMaskPicture, 1)) + I830FALLBACK("Check Mask picture texture\n"); + + if (!i965_get_dest_format(pDstPicture, &tmp1)) + I830FALLBACK("Get Color buffer format\n"); + + return TRUE; + +} + +#define ALIGN(i,m) (((i) + (m) - 1) & ~((m) - 1)) +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#define BRW_GRF_BLOCKS(nreg) ((nreg + 15) / 16 - 1) + +static int urb_vs_start, urb_vs_size; +static int urb_gs_start, urb_gs_size; +static int urb_clip_start, urb_clip_size; +static int urb_sf_start, urb_sf_size; +static int urb_cs_start, urb_cs_size; + +static struct brw_surface_state *dest_surf_state, dest_surf_state_local; +static struct brw_surface_state *src_surf_state, src_surf_state_local; +static struct brw_surface_state *mask_surf_state, mask_surf_state_local; +static struct brw_sampler_state *src_sampler_state, src_sampler_state_local; +static struct brw_sampler_state *mask_sampler_state, mask_sampler_state_local; +static struct brw_sampler_default_color *default_color_state; + +static struct brw_vs_unit_state *vs_state, vs_state_local; +static struct brw_sf_unit_state *sf_state, sf_state_local; +static struct brw_wm_unit_state *wm_state, wm_state_local; +static struct brw_cc_unit_state *cc_state, cc_state_local; +static struct brw_cc_viewport *cc_viewport; + +static struct brw_instruction *sf_kernel; +static struct brw_instruction *ps_kernel; +static struct brw_instruction *sip_kernel; + +static CARD32 *binding_table; +static int binding_table_entries; + +static int dest_surf_offset, src_surf_offset, mask_surf_offset; +static int src_sampler_offset, mask_sampler_offset,vs_offset; +static int sf_offset, wm_offset, cc_offset, vb_offset, cc_viewport_offset; +static int sf_kernel_offset, ps_kernel_offset, sip_kernel_offset; +static int wm_scratch_offset; +static int binding_table_offset; +static int default_color_offset; +static int next_offset, total_state_size; +static char *state_base; +static int state_base_offset; +static float *vb; +static int vb_size = (6 * 4) * 4 ; /* 6 DWORDS per vertex - and mask*/ + +static CARD32 src_blend, dst_blend; + +static const CARD32 sip_kernel_static[][4] = { +/* wait (1) a0<1>UW a145<0,1,0>UW { align1 + } */ + { 0x00000030, 0x20000108, 0x00001220, 0x00000000 }, +/* nop (4) g0<1>UD { align1 + } */ + { 0x0040007e, 0x20000c21, 0x00690000, 0x00000000 }, +/* nop (4) g0<1>UD { align1 + } */ + { 0x0040007e, 0x20000c21, 0x00690000, 0x00000000 }, +/* nop (4) g0<1>UD { align1 + } */ + { 0x0040007e, 0x20000c21, 0x00690000, 0x00000000 }, +/* nop (4) g0<1>UD { align1 + } */ + { 0x0040007e, 0x20000c21, 0x00690000, 0x00000000 }, +/* nop (4) g0<1>UD { align1 + } */ + { 0x0040007e, 0x20000c21, 0x00690000, 0x00000000 }, +/* nop (4) g0<1>UD { align1 + } */ + { 0x0040007e, 0x20000c21, 0x00690000, 0x00000000 }, +/* nop (4) g0<1>UD { align1 + } */ + { 0x0040007e, 0x20000c21, 0x00690000, 0x00000000 }, +/* nop (4) g0<1>UD { align1 + } */ + { 0x0040007e, 0x20000c21, 0x00690000, 0x00000000 }, +/* nop (4) g0<1>UD { align1 + } */ + { 0x0040007e, 0x20000c21, 0x00690000, 0x00000000 }, +}; + +/* + * this program computes dA/dx and dA/dy for the texture coordinates along + * with the base texture coordinate. It was extracted from the Mesa driver + */ + +#define SF_KERNEL_NUM_GRF 16 +#define SF_MAX_THREADS 1 + +static const CARD32 sf_kernel_static[][4] = { +#include "exa_sf_prog.h" +}; + +static const CARD32 sf_kernel_static_mask[][4] = { +#include "exa_sf_mask_prog.h" +}; + +static const CARD32 sf_kernel_static_rotation[][4] = { +#include "exa_sf_rotation_prog.h" +}; + +/* ps kernels */ +#define PS_KERNEL_NUM_GRF 32 +#define PS_MAX_THREADS 32 + +static const CARD32 ps_kernel_static_nomask [][4] = { +#include "exa_wm_nomask_prog.h" +}; + +static const CARD32 ps_kernel_static_maskca [][4] = { +#include "exa_wm_maskca_prog.h" +}; + +static const CARD32 ps_kernel_static_maskca_srcalpha [][4] = { +#include "exa_wm_maskca_srcalpha_prog.h" +}; + +static const CARD32 ps_kernel_static_masknoca [][4] = { +#include "exa_wm_masknoca_prog.h" +}; + +static const CARD32 ps_kernel_static_rotation [][4] = { +#include "exa_wm_rotation_prog.h" +}; + +static CARD32 +i965_get_card_format(PicturePtr pPict) +{ + int i; + + for (i = 0; i < sizeof(i965_tex_formats) / sizeof(i965_tex_formats[0]); + i++) + { + if (i965_tex_formats[i].fmt == pPict->format) + break; + } + return i965_tex_formats[i].card_fmt; +} + +static Bool +i965_check_rotation_transform(PictTransformPtr t) +{ + /* XXX this is arbitrary */ + int a, b; + a = xFixedToInt(t->matrix[0][1]); + b = xFixedToInt(t->matrix[1][0]); + if (a == -1 && b == 1) + return TRUE; + else if (a == 1 && b == -1) + return TRUE; + else + return FALSE; +} + +Bool +i965_prepare_composite(int op, PicturePtr pSrcPicture, + PicturePtr pMaskPicture, PicturePtr pDstPicture, + PixmapPtr pSrc, PixmapPtr pMask, PixmapPtr pDst) +{ + ScrnInfoPtr pScrn = xf86Screens[pSrcPicture->pDrawable->pScreen->myNum]; + I830Ptr pI830 = I830PTR(pScrn); + CARD32 src_offset, src_pitch, src_tile_format = 0, src_tiled = 0; + CARD32 mask_offset = 0, mask_pitch = 0, mask_tile_format = 0, + mask_tiled = 0; + CARD32 dst_format, dst_offset, dst_pitch, dst_tile_format = 0, + dst_tiled = 0; + Bool rotation_program = FALSE; + + IntelEmitInvarientState(pScrn); + *pI830->last_3d = LAST_3D_RENDER; + + src_offset = intel_get_pixmap_offset(pSrc); + src_pitch = intel_get_pixmap_pitch(pSrc); + if (i830_pixmap_tiled(pSrc)) { + src_tiled = 1; + src_tile_format = 0; /* Tiled X */ + } + dst_offset = intel_get_pixmap_offset(pDst); + dst_pitch = intel_get_pixmap_pitch(pDst); + if (i830_pixmap_tiled(pDst)) { + dst_tiled = 1; + dst_tile_format = 0; /* Tiled X */ + } + if (pMask) { + mask_offset = intel_get_pixmap_offset(pMask); + mask_pitch = intel_get_pixmap_pitch(pMask); + if (i830_pixmap_tiled(pMask)) { + mask_tiled = 1; + mask_tile_format = 0; /* Tiled X */ + } + } + pI830->scale_units[0][0] = pSrc->drawable.width; + pI830->scale_units[0][1] = pSrc->drawable.height; + + pI830->transform[0] = pSrcPicture->transform; + + if (!pMask) { + pI830->transform[1] = NULL; + pI830->scale_units[1][0] = -1; + pI830->scale_units[1][1] = -1; + if (pI830->transform[0] && + i965_check_rotation_transform(pI830->transform[0])) + rotation_program = TRUE; + } else { + pI830->transform[1] = pMaskPicture->transform; + if (pI830->transform[1]) + I830FALLBACK("i965 mask transform not implemented!\n"); + pI830->scale_units[1][0] = pMask->drawable.width; + pI830->scale_units[1][1] = pMask->drawable.height; + } + + /* setup 3d pipeline state */ + + binding_table_entries = 2; /* default no mask */ + + /* Set up our layout of state in framebuffer. First the general state: */ + next_offset = 0; + vs_offset = ALIGN(next_offset, 64); + next_offset = vs_offset + sizeof(*vs_state); + + sf_offset = ALIGN(next_offset, 32); + next_offset = sf_offset + sizeof(*sf_state); + + wm_offset = ALIGN(next_offset, 32); + next_offset = wm_offset + sizeof(*wm_state); + + wm_scratch_offset = ALIGN(next_offset, 1024); + next_offset = wm_scratch_offset + 1024 * PS_MAX_THREADS; + + cc_offset = ALIGN(next_offset, 32); + next_offset = cc_offset + sizeof(*cc_state); + + /* keep current sf_kernel, which will send one setup urb entry to + * PS kernel + */ + sf_kernel_offset = ALIGN(next_offset, 64); + if (pMask) + next_offset = sf_kernel_offset + sizeof (sf_kernel_static_mask); + else if (rotation_program) + next_offset = sf_kernel_offset + sizeof (sf_kernel_static_rotation); + else + next_offset = sf_kernel_offset + sizeof (sf_kernel_static); + + ps_kernel_offset = ALIGN(next_offset, 64); + if (pMask) { + if (pMaskPicture->componentAlpha && + PICT_FORMAT_RGB(pMaskPicture->format)) { + if (i965_blend_op[op].src_alpha) { + next_offset = ps_kernel_offset + + sizeof(ps_kernel_static_maskca_srcalpha); + } else { + next_offset = ps_kernel_offset + + sizeof(ps_kernel_static_maskca); + } + } else + next_offset = ps_kernel_offset + + sizeof(ps_kernel_static_masknoca); + } else if (rotation_program) { + next_offset = ps_kernel_offset + sizeof (ps_kernel_static_rotation); + } else { + next_offset = ps_kernel_offset + sizeof (ps_kernel_static_nomask); + } + + sip_kernel_offset = ALIGN(next_offset, 64); + next_offset = sip_kernel_offset + sizeof (sip_kernel_static); + + /* needed? */ + cc_viewport_offset = ALIGN(next_offset, 32); + next_offset = cc_viewport_offset + sizeof(*cc_viewport); + + /* for texture sampler */ + src_sampler_offset = ALIGN(next_offset, 32); + next_offset = src_sampler_offset + sizeof(*src_sampler_state); + + if (pMask) { + mask_sampler_offset = ALIGN(next_offset, 32); + next_offset = mask_sampler_offset + sizeof(*mask_sampler_state); + } + /* Align VB to native size of elements, for safety */ + vb_offset = ALIGN(next_offset, 32); + next_offset = vb_offset + vb_size; + + /* And then the general state: */ + dest_surf_offset = ALIGN(next_offset, 32); + next_offset = dest_surf_offset + sizeof(*dest_surf_state); + + src_surf_offset = ALIGN(next_offset, 32); + next_offset = src_surf_offset + sizeof(*src_surf_state); + + if (pMask) { + mask_surf_offset = ALIGN(next_offset, 32); + next_offset = mask_surf_offset + sizeof(*mask_surf_state); + binding_table_entries = 3; + } + + binding_table_offset = ALIGN(next_offset, 32); + next_offset = binding_table_offset + (binding_table_entries * 4); + + default_color_offset = ALIGN(next_offset, 32); + next_offset = default_color_offset + sizeof(*default_color_state); + + total_state_size = next_offset; + assert(total_state_size < pI830->exa_965_state->size); + + state_base_offset = pI830->exa_965_state->offset; + state_base_offset = ALIGN(state_base_offset, 64); + state_base = (char *)(pI830->FbBase + state_base_offset); + + sf_kernel = (void *)(state_base + sf_kernel_offset); + ps_kernel = (void *)(state_base + ps_kernel_offset); + sip_kernel = (void *)(state_base + sip_kernel_offset); + + cc_viewport = (void *)(state_base + cc_viewport_offset); + + binding_table = (void *)(state_base + binding_table_offset); + + vb = (void *)(state_base + vb_offset); + + default_color_state = (void*)(state_base + default_color_offset); + + /* Set up a default static partitioning of the URB, which is supposed to + * allow anything we would want to do, at potentially lower performance. + */ +#define URB_CS_ENTRY_SIZE 0 +#define URB_CS_ENTRIES 0 + +#define URB_VS_ENTRY_SIZE 1 // each 512-bit row +#define URB_VS_ENTRIES 8 // we needs at least 8 entries + +#define URB_GS_ENTRY_SIZE 0 +#define URB_GS_ENTRIES 0 + +#define URB_CLIP_ENTRY_SIZE 0 +#define URB_CLIP_ENTRIES 0 + +#define URB_SF_ENTRY_SIZE 2 +#define URB_SF_ENTRIES 1 + + urb_vs_start = 0; + urb_vs_size = URB_VS_ENTRIES * URB_VS_ENTRY_SIZE; + urb_gs_start = urb_vs_start + urb_vs_size; + urb_gs_size = URB_GS_ENTRIES * URB_GS_ENTRY_SIZE; + urb_clip_start = urb_gs_start + urb_gs_size; + urb_clip_size = URB_CLIP_ENTRIES * URB_CLIP_ENTRY_SIZE; + urb_sf_start = urb_clip_start + urb_clip_size; + urb_sf_size = URB_SF_ENTRIES * URB_SF_ENTRY_SIZE; + urb_cs_start = urb_sf_start + urb_sf_size; + urb_cs_size = URB_CS_ENTRIES * URB_CS_ENTRY_SIZE; + + /* Because we only have a single static buffer for our state currently, + * we have to sync before updating it every time. + */ + i830WaitSync(pScrn); + + memset (cc_viewport, 0, sizeof (*cc_viewport)); + cc_viewport->min_depth = -1.e35; + cc_viewport->max_depth = 1.e35; + + /* Color calculator state */ + cc_state = &cc_state_local; + memset(cc_state, 0, sizeof(*cc_state)); + cc_state->cc0.stencil_enable = 0; /* disable stencil */ + cc_state->cc2.depth_test = 0; /* disable depth test */ + cc_state->cc2.logicop_enable = 0; /* disable logic op */ + cc_state->cc3.ia_blend_enable = 1; /* blend alpha just like colors */ + cc_state->cc3.blend_enable = 1; /* enable color blend */ + cc_state->cc3.alpha_test = 0; /* disable alpha test */ + cc_state->cc4.cc_viewport_state_offset = (state_base_offset + + cc_viewport_offset) >> 5; + cc_state->cc5.dither_enable = 0; /* disable dither */ + cc_state->cc5.logicop_func = 0xc; /* COPY */ + cc_state->cc5.statistics_enable = 1; + cc_state->cc5.ia_blend_function = BRW_BLENDFUNCTION_ADD; + i965_get_blend_cntl(op, pMaskPicture, pDstPicture->format, + &src_blend, &dst_blend); + /* XXX: alpha blend factor should be same as color, but check + * for CA case in future + */ + cc_state->cc5.ia_src_blend_factor = src_blend; + cc_state->cc5.ia_dest_blend_factor = dst_blend; + cc_state->cc6.blend_function = BRW_BLENDFUNCTION_ADD; + cc_state->cc6.src_blend_factor = src_blend; + cc_state->cc6.dest_blend_factor = dst_blend; + cc_state->cc6.clamp_post_alpha_blend = 1; + cc_state->cc6.clamp_pre_alpha_blend = 1; + cc_state->cc6.clamp_range = 0; /* clamp range [0,1] */ + + cc_state = (void *)(state_base + cc_offset); + memcpy (cc_state, &cc_state_local, sizeof (cc_state_local)); + + /* Upload system kernel */ + memcpy (sip_kernel, sip_kernel_static, sizeof (sip_kernel_static)); + + /* Set up the state buffer for the destination surface */ + dest_surf_state = &dest_surf_state_local; + memset(dest_surf_state, 0, sizeof(*dest_surf_state)); + dest_surf_state->ss0.surface_type = BRW_SURFACE_2D; + dest_surf_state->ss0.data_return_format = BRW_SURFACERETURNFORMAT_FLOAT32; + i965_get_dest_format(pDstPicture, &dst_format); + dest_surf_state->ss0.surface_format = dst_format; + + dest_surf_state->ss0.writedisable_alpha = 0; + dest_surf_state->ss0.writedisable_red = 0; + dest_surf_state->ss0.writedisable_green = 0; + dest_surf_state->ss0.writedisable_blue = 0; + dest_surf_state->ss0.color_blend = 1; + dest_surf_state->ss0.vert_line_stride = 0; + dest_surf_state->ss0.vert_line_stride_ofs = 0; + dest_surf_state->ss0.mipmap_layout_mode = 0; + dest_surf_state->ss0.render_cache_read_mode = 0; + + dest_surf_state->ss1.base_addr = dst_offset; + dest_surf_state->ss2.height = pDst->drawable.height - 1; + dest_surf_state->ss2.width = pDst->drawable.width - 1; + dest_surf_state->ss2.mip_count = 0; + dest_surf_state->ss2.render_target_rotation = 0; + dest_surf_state->ss3.pitch = dst_pitch - 1; + dest_surf_state->ss3.tile_walk = dst_tile_format; + dest_surf_state->ss3.tiled_surface = dst_tiled; + + dest_surf_state = (void *)(state_base + dest_surf_offset); + memcpy (dest_surf_state, &dest_surf_state_local, sizeof (dest_surf_state_local)); + + /* Set up the source surface state buffer */ + src_surf_state = &src_surf_state_local; + memset(src_surf_state, 0, sizeof(*src_surf_state)); + src_surf_state->ss0.surface_type = BRW_SURFACE_2D; + src_surf_state->ss0.surface_format = i965_get_card_format(pSrcPicture); + + src_surf_state->ss0.writedisable_alpha = 0; + src_surf_state->ss0.writedisable_red = 0; + src_surf_state->ss0.writedisable_green = 0; + src_surf_state->ss0.writedisable_blue = 0; + src_surf_state->ss0.color_blend = 1; + src_surf_state->ss0.vert_line_stride = 0; + src_surf_state->ss0.vert_line_stride_ofs = 0; + src_surf_state->ss0.mipmap_layout_mode = 0; + src_surf_state->ss0.render_cache_read_mode = 0; + + src_surf_state->ss1.base_addr = src_offset; + src_surf_state->ss2.width = pSrc->drawable.width - 1; + src_surf_state->ss2.height = pSrc->drawable.height - 1; + src_surf_state->ss2.mip_count = 0; + src_surf_state->ss2.render_target_rotation = 0; + src_surf_state->ss3.pitch = src_pitch - 1; + src_surf_state->ss3.tile_walk = src_tile_format; + src_surf_state->ss3.tiled_surface = src_tiled; + + src_surf_state = (void *)(state_base + src_surf_offset); + memcpy (src_surf_state, &src_surf_state_local, sizeof (src_surf_state_local)); + + /* setup mask surface */ + if (pMask) { + mask_surf_state = &mask_surf_state_local; + memset(mask_surf_state, 0, sizeof(*mask_surf_state)); + mask_surf_state->ss0.surface_type = BRW_SURFACE_2D; + mask_surf_state->ss0.surface_format = + i965_get_card_format(pMaskPicture); + + mask_surf_state->ss0.writedisable_alpha = 0; + mask_surf_state->ss0.writedisable_red = 0; + mask_surf_state->ss0.writedisable_green = 0; + mask_surf_state->ss0.writedisable_blue = 0; + mask_surf_state->ss0.color_blend = 1; + mask_surf_state->ss0.vert_line_stride = 0; + mask_surf_state->ss0.vert_line_stride_ofs = 0; + mask_surf_state->ss0.mipmap_layout_mode = 0; + mask_surf_state->ss0.render_cache_read_mode = 0; + + mask_surf_state->ss1.base_addr = mask_offset; + mask_surf_state->ss2.width = pMask->drawable.width - 1; + mask_surf_state->ss2.height = pMask->drawable.height - 1; + mask_surf_state->ss2.mip_count = 0; + mask_surf_state->ss2.render_target_rotation = 0; + mask_surf_state->ss3.pitch = mask_pitch - 1; + mask_surf_state->ss3.tile_walk = mask_tile_format; + mask_surf_state->ss3.tiled_surface = mask_tiled; + + mask_surf_state = (void *)(state_base + mask_surf_offset); + memcpy (mask_surf_state, &mask_surf_state_local, sizeof (mask_surf_state_local)); + } + + /* Set up a binding table for our surfaces. Only the PS will use it */ + binding_table[0] = state_base_offset + dest_surf_offset; + binding_table[1] = state_base_offset + src_surf_offset; + if (pMask) + binding_table[2] = state_base_offset + mask_surf_offset; + + /* PS kernel use this sampler */ + src_sampler_state = &src_sampler_state_local; + memset(src_sampler_state, 0, sizeof(*src_sampler_state)); + src_sampler_state->ss0.lod_preclamp = 1; /* GL mode */ + switch(pSrcPicture->filter) { + case PictFilterNearest: + src_sampler_state->ss0.min_filter = BRW_MAPFILTER_NEAREST; + src_sampler_state->ss0.mag_filter = BRW_MAPFILTER_NEAREST; + break; + case PictFilterBilinear: + src_sampler_state->ss0.min_filter = BRW_MAPFILTER_LINEAR; + src_sampler_state->ss0.mag_filter = BRW_MAPFILTER_LINEAR; + break; + default: + I830FALLBACK("Bad filter 0x%x\n", pSrcPicture->filter); + } + + memset(default_color_state, 0, sizeof(*default_color_state)); + default_color_state->color[0] = 0.0; /* R */ + default_color_state->color[1] = 0.0; /* G */ + default_color_state->color[2] = 0.0; /* B */ + default_color_state->color[3] = 0.0; /* A */ + + src_sampler_state->ss0.default_color_mode = 0; /* GL mode */ + + if (!pSrcPicture->repeat) { + src_sampler_state->ss1.r_wrap_mode = BRW_TEXCOORDMODE_CLAMP_BORDER; + src_sampler_state->ss1.s_wrap_mode = BRW_TEXCOORDMODE_CLAMP_BORDER; + src_sampler_state->ss1.t_wrap_mode = BRW_TEXCOORDMODE_CLAMP_BORDER; + src_sampler_state->ss2.default_color_pointer = + (state_base_offset + default_color_offset) >> 5; + } else { + src_sampler_state->ss1.r_wrap_mode = BRW_TEXCOORDMODE_WRAP; + src_sampler_state->ss1.s_wrap_mode = BRW_TEXCOORDMODE_WRAP; + src_sampler_state->ss1.t_wrap_mode = BRW_TEXCOORDMODE_WRAP; + } + src_sampler_state->ss3.chroma_key_enable = 0; /* disable chromakey */ + + src_sampler_state = (void *)(state_base + src_sampler_offset); + memcpy (src_sampler_state, &src_sampler_state_local, sizeof (src_sampler_state_local)); + + if (pMask) { + mask_sampler_state = &mask_sampler_state_local; + memset(mask_sampler_state, 0, sizeof(*mask_sampler_state)); + mask_sampler_state->ss0.lod_preclamp = 1; /* GL mode */ + switch(pMaskPicture->filter) { + case PictFilterNearest: + mask_sampler_state->ss0.min_filter = BRW_MAPFILTER_NEAREST; + mask_sampler_state->ss0.mag_filter = BRW_MAPFILTER_NEAREST; + break; + case PictFilterBilinear: + mask_sampler_state->ss0.min_filter = BRW_MAPFILTER_LINEAR; + mask_sampler_state->ss0.mag_filter = BRW_MAPFILTER_LINEAR; + break; + default: + I830FALLBACK("Bad filter 0x%x\n", pMaskPicture->filter); + } + + if (!pMaskPicture->repeat) { + mask_sampler_state->ss1.r_wrap_mode = + BRW_TEXCOORDMODE_CLAMP_BORDER; + mask_sampler_state->ss1.s_wrap_mode = + BRW_TEXCOORDMODE_CLAMP_BORDER; + mask_sampler_state->ss1.t_wrap_mode = + BRW_TEXCOORDMODE_CLAMP_BORDER; + mask_sampler_state->ss2.default_color_pointer = + (state_base_offset + default_color_offset)>>5; + } else { + mask_sampler_state->ss1.r_wrap_mode = BRW_TEXCOORDMODE_WRAP; + mask_sampler_state->ss1.s_wrap_mode = BRW_TEXCOORDMODE_WRAP; + mask_sampler_state->ss1.t_wrap_mode = BRW_TEXCOORDMODE_WRAP; + } + mask_sampler_state->ss3.chroma_key_enable = 0; /* disable chromakey */ + + mask_sampler_state = (void *)(state_base + mask_sampler_offset); + memcpy (mask_sampler_state, &mask_sampler_state_local, sizeof (mask_sampler_state_local)); + } + + /* Set up the vertex shader to be disabled (passthrough) */ + vs_state = &vs_state_local; + memset(vs_state, 0, sizeof(*vs_state)); + vs_state->thread4.nr_urb_entries = URB_VS_ENTRIES; + vs_state->thread4.urb_entry_allocation_size = URB_VS_ENTRY_SIZE - 1; + vs_state->vs6.vs_enable = 0; + vs_state->vs6.vert_cache_disable = 1; + + vs_state = (void *)(state_base + vs_offset); + memcpy (vs_state, &vs_state_local, sizeof (vs_state_local)); + + /* Set up the SF kernel to do coord interp: for each attribute, + * calculate dA/dx and dA/dy. Hand these interpolation coefficients + * back to SF which then hands pixels off to WM. + */ + if (pMask) + memcpy(sf_kernel, sf_kernel_static_mask, + sizeof (sf_kernel_static_mask)); + else if (rotation_program) + memcpy(sf_kernel, sf_kernel_static_rotation, + sizeof (sf_kernel_static_rotation)); + else + memcpy(sf_kernel, sf_kernel_static, sizeof (sf_kernel_static)); + + sf_state = &sf_state_local; + memset(sf_state, 0, sizeof(*sf_state)); + sf_state->thread0.kernel_start_pointer = + (state_base_offset + sf_kernel_offset) >> 6; + sf_state->thread0.grf_reg_count = BRW_GRF_BLOCKS(SF_KERNEL_NUM_GRF); + sf_state->sf1.single_program_flow = 1; + sf_state->sf1.binding_table_entry_count = 0; + sf_state->sf1.thread_priority = 0; + sf_state->sf1.floating_point_mode = 0; /* Mesa does this */ + sf_state->sf1.illegal_op_exception_enable = 1; + sf_state->sf1.mask_stack_exception_enable = 1; + sf_state->sf1.sw_exception_enable = 1; + sf_state->thread2.per_thread_scratch_space = 0; + /* scratch space is not used in our kernel */ + sf_state->thread2.scratch_space_base_pointer = 0; + sf_state->thread3.const_urb_entry_read_length = 0; /* no const URBs */ + sf_state->thread3.const_urb_entry_read_offset = 0; /* no const URBs */ + sf_state->thread3.urb_entry_read_length = 1; /* 1 URB per vertex */ + /* don't smash vertex header, read start from dw8 */ + sf_state->thread3.urb_entry_read_offset = 1; + sf_state->thread3.dispatch_grf_start_reg = 3; + sf_state->thread4.max_threads = SF_MAX_THREADS - 1; + sf_state->thread4.urb_entry_allocation_size = URB_SF_ENTRY_SIZE - 1; + sf_state->thread4.nr_urb_entries = URB_SF_ENTRIES; + sf_state->thread4.stats_enable = 1; + sf_state->sf5.viewport_transform = FALSE; /* skip viewport */ + sf_state->sf6.cull_mode = BRW_CULLMODE_NONE; + sf_state->sf6.scissor = 0; + sf_state->sf7.trifan_pv = 2; + sf_state->sf6.dest_org_vbias = 0x8; + sf_state->sf6.dest_org_hbias = 0x8; + + sf_state = (void *)(state_base + sf_offset); + memcpy (sf_state, &sf_state_local, sizeof (sf_state_local)); + + /* Set up the PS kernel (dispatched by WM) */ + if (pMask) { + if (pMaskPicture->componentAlpha && + PICT_FORMAT_RGB(pMaskPicture->format)) { + if (i965_blend_op[op].src_alpha) + memcpy(ps_kernel, ps_kernel_static_maskca_srcalpha, + sizeof (ps_kernel_static_maskca_srcalpha)); + else + memcpy(ps_kernel, ps_kernel_static_maskca, + sizeof (ps_kernel_static_maskca)); + } else + memcpy(ps_kernel, ps_kernel_static_masknoca, + sizeof (ps_kernel_static_masknoca)); + } else if (rotation_program) { + memcpy(ps_kernel, ps_kernel_static_rotation, + sizeof (ps_kernel_static_rotation)); + } else { + memcpy(ps_kernel, ps_kernel_static_nomask, + sizeof (ps_kernel_static_nomask)); + } + + wm_state = &wm_state_local; + memset(wm_state, 0, sizeof (*wm_state)); + wm_state->thread0.kernel_start_pointer = + (state_base_offset + ps_kernel_offset) >> 6; + wm_state->thread0.grf_reg_count = BRW_GRF_BLOCKS(PS_KERNEL_NUM_GRF); + wm_state->thread1.single_program_flow = 1; + if (!pMask) + wm_state->thread1.binding_table_entry_count = 2; /* 1 tex and fb */ + else + wm_state->thread1.binding_table_entry_count = 3; /* 2 tex and fb */ + + wm_state->thread2.scratch_space_base_pointer = (state_base_offset + + wm_scratch_offset)>>10; + wm_state->thread2.per_thread_scratch_space = 0; + wm_state->thread3.const_urb_entry_read_length = 0; + wm_state->thread3.const_urb_entry_read_offset = 0; + /* Each pair of attributes (src/mask coords) is one URB entry */ + if (pMask) + wm_state->thread3.urb_entry_read_length = 2; + else + wm_state->thread3.urb_entry_read_length = 1; + wm_state->thread3.urb_entry_read_offset = 0; + /* wm kernel use urb from 3, see wm_program in compiler module */ + wm_state->thread3.dispatch_grf_start_reg = 3; /* must match kernel */ + + wm_state->wm4.stats_enable = 1; /* statistic */ + wm_state->wm4.sampler_state_pointer = (state_base_offset + + src_sampler_offset) >> 5; + wm_state->wm4.sampler_count = 1; /* 1-4 samplers used */ + wm_state->wm5.max_threads = PS_MAX_THREADS - 1; + wm_state->wm5.thread_dispatch_enable = 1; + /* just use 16-pixel dispatch (4 subspans), don't need to change kernel + * start point + */ + wm_state->wm5.enable_16_pix = 1; + wm_state->wm5.enable_8_pix = 0; + wm_state->wm5.early_depth_test = 1; + + wm_state = (void *)(state_base + wm_offset); + memcpy (wm_state, &wm_state_local, sizeof (wm_state_local)); + + /* Begin the long sequence of commands needed to set up the 3D + * rendering pipe + */ + { + BEGIN_LP_RING(2); + OUT_RING(MI_FLUSH | + MI_STATE_INSTRUCTION_CACHE_FLUSH | + BRW_MI_GLOBAL_SNAPSHOT_RESET); + OUT_RING(MI_NOOP); + ADVANCE_LP_RING(); + } + { + BEGIN_LP_RING(12); + + /* Match Mesa driver setup */ + OUT_RING(BRW_PIPELINE_SELECT | PIPELINE_SELECT_3D); + + OUT_RING(BRW_CS_URB_STATE | 0); + OUT_RING((0 << 4) | /* URB Entry Allocation Size */ + (0 << 0)); /* Number of URB Entries */ + + /* Zero out the two base address registers so all offsets are + * absolute. + */ + OUT_RING(BRW_STATE_BASE_ADDRESS | 4); + OUT_RING(0 | BASE_ADDRESS_MODIFY); /* Generate state base address */ + OUT_RING(0 | BASE_ADDRESS_MODIFY); /* Surface state base address */ + OUT_RING(0 | BASE_ADDRESS_MODIFY); /* media base addr, don't care */ + /* general state max addr, disabled */ + OUT_RING(0x10000000 | BASE_ADDRESS_MODIFY); + /* media object state max addr, disabled */ + OUT_RING(0x10000000 | BASE_ADDRESS_MODIFY); + + /* Set system instruction pointer */ + OUT_RING(BRW_STATE_SIP | 0); + OUT_RING(state_base_offset + sip_kernel_offset); + OUT_RING(MI_NOOP); + ADVANCE_LP_RING(); + } + { + BEGIN_LP_RING(26); + /* Pipe control */ + OUT_RING(BRW_PIPE_CONTROL | + BRW_PIPE_CONTROL_NOWRITE | + BRW_PIPE_CONTROL_IS_FLUSH | + 2); + OUT_RING(0); /* Destination address */ + OUT_RING(0); /* Immediate data low DW */ + OUT_RING(0); /* Immediate data high DW */ + + /* Binding table pointers */ + OUT_RING(BRW_3DSTATE_BINDING_TABLE_POINTERS | 4); + OUT_RING(0); /* vs */ + OUT_RING(0); /* gs */ + OUT_RING(0); /* clip */ + OUT_RING(0); /* sf */ + /* Only the PS uses the binding table */ + OUT_RING(state_base_offset + binding_table_offset); /* ps */ + + /* The drawing rectangle clipping is always on. Set it to values that + * shouldn't do any clipping. + */ + OUT_RING(BRW_3DSTATE_DRAWING_RECTANGLE | 2); /* XXX 3 for BLC or CTG */ + OUT_RING(0x00000000); /* ymin, xmin */ + OUT_RING(DRAW_YMAX(pDst->drawable.height - 1) | + DRAW_XMAX(pDst->drawable.width - 1)); /* ymax, xmax */ + OUT_RING(0x00000000); /* yorigin, xorigin */ + + /* skip the depth buffer */ + /* skip the polygon stipple */ + /* skip the polygon stipple offset */ + /* skip the line stipple */ + + /* Set the pointers to the 3d pipeline state */ + OUT_RING(BRW_3DSTATE_PIPELINED_POINTERS | 5); + OUT_RING(state_base_offset + vs_offset); /* 32 byte aligned */ + OUT_RING(BRW_GS_DISABLE); /* disable GS, resulting in passthrough */ + OUT_RING(BRW_CLIP_DISABLE); /* disable CLIP, resulting in passthrough */ + OUT_RING(state_base_offset + sf_offset); /* 32 byte aligned */ + OUT_RING(state_base_offset + wm_offset); /* 32 byte aligned */ + OUT_RING(state_base_offset + cc_offset); /* 64 byte aligned */ + + /* URB fence */ + OUT_RING(BRW_URB_FENCE | + UF0_CS_REALLOC | + UF0_SF_REALLOC | + UF0_CLIP_REALLOC | + UF0_GS_REALLOC | + UF0_VS_REALLOC | + 1); + OUT_RING(((urb_clip_start + urb_clip_size) << UF1_CLIP_FENCE_SHIFT) | + ((urb_gs_start + urb_gs_size) << UF1_GS_FENCE_SHIFT) | + ((urb_vs_start + urb_vs_size) << UF1_VS_FENCE_SHIFT)); + OUT_RING(((urb_cs_start + urb_cs_size) << UF2_CS_FENCE_SHIFT) | + ((urb_sf_start + urb_sf_size) << UF2_SF_FENCE_SHIFT)); + + /* Constant buffer state */ + OUT_RING(BRW_CS_URB_STATE | 0); + OUT_RING(((URB_CS_ENTRY_SIZE - 1) << 4) | + (URB_CS_ENTRIES << 0)); + ADVANCE_LP_RING(); + } + { + int nelem = pMask ? 3: 2; + BEGIN_LP_RING(pMask?12:10); + /* Set up the pointer to our vertex buffer */ + OUT_RING(BRW_3DSTATE_VERTEX_BUFFERS | 3); + OUT_RING((0 << VB0_BUFFER_INDEX_SHIFT) | + VB0_VERTEXDATA | + ((4 * 2 * nelem) << VB0_BUFFER_PITCH_SHIFT)); + OUT_RING(state_base_offset + vb_offset); + OUT_RING(3); + OUT_RING(0); // ignore for VERTEXDATA, but still there + + /* Set up our vertex elements, sourced from the single vertex buffer. + */ + OUT_RING(BRW_3DSTATE_VERTEX_ELEMENTS | ((2 * nelem) - 1)); + /* vertex coordinates */ + OUT_RING((0 << VE0_VERTEX_BUFFER_INDEX_SHIFT) | + VE0_VALID | + (BRW_SURFACEFORMAT_R32G32_FLOAT << VE0_FORMAT_SHIFT) | + (0 << VE0_OFFSET_SHIFT)); + OUT_RING((BRW_VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_0_SHIFT) | + (BRW_VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_1_SHIFT) | + (BRW_VFCOMPONENT_STORE_1_FLT << VE1_VFCOMPONENT_2_SHIFT) | + (BRW_VFCOMPONENT_STORE_1_FLT << VE1_VFCOMPONENT_3_SHIFT) | + (4 << VE1_DESTINATION_ELEMENT_OFFSET_SHIFT)); + /* u0, v0 */ + OUT_RING((0 << VE0_VERTEX_BUFFER_INDEX_SHIFT) | + VE0_VALID | + (BRW_SURFACEFORMAT_R32G32_FLOAT << VE0_FORMAT_SHIFT) | + (8 << VE0_OFFSET_SHIFT)); /* offset vb in bytes */ + OUT_RING((BRW_VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_0_SHIFT) | + (BRW_VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_1_SHIFT) | + (BRW_VFCOMPONENT_NOSTORE << VE1_VFCOMPONENT_2_SHIFT) | + (BRW_VFCOMPONENT_NOSTORE << VE1_VFCOMPONENT_3_SHIFT) | + (8 << VE1_DESTINATION_ELEMENT_OFFSET_SHIFT)); /* VUE offset in dwords */ + /* u1, v1 */ + if (pMask) { + OUT_RING((0 << VE0_VERTEX_BUFFER_INDEX_SHIFT) | + VE0_VALID | + (BRW_SURFACEFORMAT_R32G32_FLOAT << VE0_FORMAT_SHIFT) | + (16 << VE0_OFFSET_SHIFT)); + OUT_RING((BRW_VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_0_SHIFT) | + (BRW_VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_1_SHIFT) | + (BRW_VFCOMPONENT_NOSTORE << VE1_VFCOMPONENT_2_SHIFT) | + (BRW_VFCOMPONENT_NOSTORE << VE1_VFCOMPONENT_3_SHIFT) | + (10 << VE1_DESTINATION_ELEMENT_OFFSET_SHIFT)); + } + + ADVANCE_LP_RING(); + } + +#ifdef I830DEBUG + ErrorF("try to sync to show any errors..."); + I830Sync(pScrn); +#endif + return TRUE; +} + +void +i965_composite(PixmapPtr pDst, int srcX, int srcY, int maskX, int maskY, + int dstX, int dstY, int w, int h) +{ + ScrnInfoPtr pScrn = xf86Screens[pDst->drawable.pScreen->myNum]; + I830Ptr pI830 = I830PTR(pScrn); + Bool has_mask; + float src_x[3], src_y[3], mask_x[3], mask_y[3]; + int i; + + i830_get_transformed_coordinates(srcX, srcY, + pI830->transform[0], + &src_x[0], &src_y[0]); + i830_get_transformed_coordinates(srcX, srcY + h, + pI830->transform[0], + &src_x[1], &src_y[1]); + i830_get_transformed_coordinates(srcX + w, srcY + h, + pI830->transform[0], + &src_x[2], &src_y[2]); + + if (pI830->scale_units[1][0] == -1 || pI830->scale_units[1][1] == -1) { + has_mask = FALSE; + } else { + has_mask = TRUE; + i830_get_transformed_coordinates(maskX, maskY, + pI830->transform[1], + &mask_x[0], &mask_y[0]); + i830_get_transformed_coordinates(maskX, maskY + h, + pI830->transform[1], + &mask_x[1], &mask_y[1]); + i830_get_transformed_coordinates(maskX + w, maskY + h, + pI830->transform[1], + &mask_x[2], &mask_y[2]); + } + + /* Wait for any existing composite rectangles to land before we overwrite + * the VB with the next one. + */ + i830WaitSync(pScrn); + + i = 0; + /* rect (x2,y2) */ + vb[i++] = (float)(dstX + w); + vb[i++] = (float)(dstY + h); + vb[i++] = src_x[2] / pI830->scale_units[0][0]; + vb[i++] = src_y[2] / pI830->scale_units[0][1]; + if (has_mask) { + vb[i++] = mask_x[2] / pI830->scale_units[1][0]; + vb[i++] = mask_y[2] / pI830->scale_units[1][1]; + } + + /* rect (x1,y2) */ + vb[i++] = (float)dstX; + vb[i++] = (float)(dstY + h); + vb[i++] = src_x[1] / pI830->scale_units[0][0]; + vb[i++] = src_y[1] / pI830->scale_units[0][1]; + if (has_mask) { + vb[i++] = mask_x[1] / pI830->scale_units[1][0]; + vb[i++] = mask_y[1] / pI830->scale_units[1][1]; + } + + /* rect (x1,y1) */ + vb[i++] = (float)dstX; + vb[i++] = (float)dstY; + vb[i++] = src_x[0] / pI830->scale_units[0][0]; + vb[i++] = src_y[0] / pI830->scale_units[0][1]; + if (has_mask) { + vb[i++] = mask_x[0] / pI830->scale_units[1][0]; + vb[i++] = mask_y[0] / pI830->scale_units[1][1]; + } + + { + BEGIN_LP_RING(6); + OUT_RING(BRW_3DPRIMITIVE | + BRW_3DPRIMITIVE_VERTEX_SEQUENTIAL | + (_3DPRIM_RECTLIST << BRW_3DPRIMITIVE_TOPOLOGY_SHIFT) | + (0 << 9) | /* CTG - indirect vertex count */ + 4); + OUT_RING(3); /* vertex count per instance */ + OUT_RING(0); /* start vertex offset */ + OUT_RING(1); /* single instance */ + OUT_RING(0); /* start instance location */ + OUT_RING(0); /* index buffer offset, ignored */ + ADVANCE_LP_RING(); + } +#ifdef I830DEBUG + ErrorF("sync after 3dprimitive"); + I830Sync(pScrn); +#endif + /* we must be sure that the pipeline is flushed before next exa draw, + because that will be new state, binding state and instructions*/ + { + BEGIN_LP_RING(4); + OUT_RING(BRW_PIPE_CONTROL | + BRW_PIPE_CONTROL_NOWRITE | + BRW_PIPE_CONTROL_WC_FLUSH | + BRW_PIPE_CONTROL_IS_FLUSH | + (1 << 10) | /* XXX texture cache flush for BLC/CTG */ + 2); + OUT_RING(0); /* Destination address */ + OUT_RING(0); /* Immediate data low DW */ + OUT_RING(0); /* Immediate data high DW */ + ADVANCE_LP_RING(); + } + + /* Mark sync so we can wait for it before setting up the VB on the next + * rectangle. + */ + i830MarkSync(pScrn); +} diff --git a/driver/xf86-video-intel/src/i965_video.c b/driver/xf86-video-intel/src/i965_video.c new file mode 100644 index 000000000..035727034 --- /dev/null +++ b/driver/xf86-video-intel/src/i965_video.c @@ -0,0 +1,855 @@ +/* + * Copyright © 2006 Intel Corporation + * + * 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 + * THE AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * Keith Packard <keithp@keithp.com> + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86xv.h" +#include "fourcc.h" + +#include "i830.h" +#include "i830_video.h" +#include "brw_defines.h" +#include "brw_structs.h" +#include <string.h> + +/* Make assert() work. */ +#undef NDEBUG +#include <assert.h> + +static const CARD32 sip_kernel_static[][4] = { +/* wait (1) a0<1>UW a145<0,1,0>UW { align1 + } */ + { 0x00000030, 0x20000108, 0x00001220, 0x00000000 }, +/* nop (4) g0<1>UD { align1 + } */ + { 0x0040007e, 0x20000c21, 0x00690000, 0x00000000 }, +/* nop (4) g0<1>UD { align1 + } */ + { 0x0040007e, 0x20000c21, 0x00690000, 0x00000000 }, +/* nop (4) g0<1>UD { align1 + } */ + { 0x0040007e, 0x20000c21, 0x00690000, 0x00000000 }, +/* nop (4) g0<1>UD { align1 + } */ + { 0x0040007e, 0x20000c21, 0x00690000, 0x00000000 }, +/* nop (4) g0<1>UD { align1 + } */ + { 0x0040007e, 0x20000c21, 0x00690000, 0x00000000 }, +/* nop (4) g0<1>UD { align1 + } */ + { 0x0040007e, 0x20000c21, 0x00690000, 0x00000000 }, +/* nop (4) g0<1>UD { align1 + } */ + { 0x0040007e, 0x20000c21, 0x00690000, 0x00000000 }, +/* nop (4) g0<1>UD { align1 + } */ + { 0x0040007e, 0x20000c21, 0x00690000, 0x00000000 }, +/* nop (4) g0<1>UD { align1 + } */ + { 0x0040007e, 0x20000c21, 0x00690000, 0x00000000 }, +}; + +/* + * this program computes dA/dx and dA/dy for the texture coordinates along + * with the base texture coordinate. It was extracted from the Mesa driver. + * It uses about 10 GRF registers. + */ + +#define SF_KERNEL_NUM_GRF 16 +#define SF_MAX_THREADS 1 + +static const CARD32 sf_kernel_static[][4] = { +#include "sf_prog.h" +}; + +/* + * Ok, this kernel picks up the required data flow values in g0 and g1 + * and passes those along in m0 and m1. In m2-m9, it sticks constant + * values (bright pink). + */ + +/* Our PS kernel uses less than 32 GRF registers (about 20) */ +#define PS_KERNEL_NUM_GRF 32 +#define PS_MAX_THREADS 32 + +#define BRW_GRF_BLOCKS(nreg) ((nreg + 15) / 16 - 1) + +static const CARD32 ps_kernel_static[][4] = { +#include "wm_prog.h" +}; + +#define ALIGN(i,m) (((i) + (m) - 1) & ~((m) - 1)) +#define MIN(a,b) ((a) < (b) ? (a) : (b)) + +#define WM_BINDING_TABLE_ENTRIES 2 + +static CARD32 float_to_uint (float f) { + union {CARD32 i; float f;} x; + x.f = f; + return x.i; +} + +#if 0 +static struct { + CARD32 svg_ctl; + char *name; +} svg_ctl_bits[] = { + { BRW_SVG_CTL_GS_BA, "General State Base Address" }, + { BRW_SVG_CTL_SS_BA, "Surface State Base Address" }, + { BRW_SVG_CTL_IO_BA, "Indirect Object Base Address" }, + { BRW_SVG_CTL_GS_AUB, "Generate State Access Upper Bound" }, + { BRW_SVG_CTL_IO_AUB, "Indirect Object Access Upper Bound" }, + { BRW_SVG_CTL_SIP, "System Instruction Pointer" }, + { 0, 0 }, +}; + +static void +brw_debug (ScrnInfoPtr pScrn, char *when) +{ + I830Ptr pI830 = I830PTR(pScrn); + int i; + CARD32 v; + + I830Sync (pScrn); + ErrorF("brw_debug: %s\n", when); + for (i = 0; svg_ctl_bits[i].name; i++) { + OUTREG(BRW_SVG_CTL, svg_ctl_bits[i].svg_ctl); + v = INREG(BRW_SVG_RDATA); + ErrorF("\t%34.34s: 0x%08x\n", svg_ctl_bits[i].name, v); + } +} +#endif + +#define WATCH_SF 0 +#define WATCH_WIZ 0 +#define WATCH_STATS 0 + +void +I965DisplayVideoTextured(ScrnInfoPtr pScrn, I830PortPrivPtr pPriv, int id, + RegionPtr dstRegion, + short width, short height, int video_pitch, + int x1, int y1, int x2, int y2, + short src_w, short src_h, + short drw_w, short drw_h, + PixmapPtr pPixmap) +{ + I830Ptr pI830 = I830PTR(pScrn); + BoxPtr pbox; + int nbox, dxo, dyo, pix_xoff, pix_yoff; + int urb_vs_start, urb_vs_size; + int urb_gs_start, urb_gs_size; + int urb_clip_start, urb_clip_size; + int urb_sf_start, urb_sf_size; + int urb_cs_start, urb_cs_size; + struct brw_surface_state *dest_surf_state; + struct brw_surface_state *src_surf_state; + struct brw_sampler_state *src_sampler_state; + struct brw_vs_unit_state *vs_state; + struct brw_sf_unit_state *sf_state; + struct brw_wm_unit_state *wm_state; + struct brw_cc_unit_state *cc_state; + struct brw_cc_viewport *cc_viewport; + struct brw_instruction *sf_kernel; + struct brw_instruction *ps_kernel; + struct brw_instruction *sip_kernel; + float *vb; + float src_scale_x, src_scale_y; + CARD32 *binding_table; + Bool first_output = TRUE; + int dest_surf_offset, src_surf_offset, src_sampler_offset, vs_offset; + int sf_offset, wm_offset, cc_offset, vb_offset, cc_viewport_offset; + int wm_scratch_offset; + int sf_kernel_offset, ps_kernel_offset, sip_kernel_offset; + int binding_table_offset; + int next_offset, total_state_size; + int vb_size = (4 * 4) * 4; /* 4 DWORDS per vertex */ + char *state_base; + int state_base_offset; + +#if 0 + ErrorF("BroadwaterDisplayVideoTextured: %dx%d (pitch %d)\n", width, height, + video_pitch); +#endif + + /* enable debug */ + OUTREG (INST_PM, + (1 << (16 + 4)) | + (1 << 4)); +#if 0 + ErrorF ("INST_PM 0x%08x\n", INREG(INST_PM)); +#endif + + assert((id == FOURCC_UYVY) || (id == FOURCC_YUY2)); + + IntelEmitInvarientState(pScrn); + *pI830->last_3d = LAST_3D_VIDEO; + + next_offset = 0; + + /* Set up our layout of state in framebuffer. First the general state: */ + vs_offset = ALIGN(next_offset, 64); + next_offset = vs_offset + sizeof(*vs_state); + sf_offset = ALIGN(next_offset, 32); + next_offset = sf_offset + sizeof(*sf_state); + wm_offset = ALIGN(next_offset, 32); + next_offset = wm_offset + sizeof(*wm_state); + wm_scratch_offset = ALIGN(next_offset, 1024); + next_offset = wm_scratch_offset + 1024 * PS_MAX_THREADS; + cc_offset = ALIGN(next_offset, 32); + next_offset = cc_offset + sizeof(*cc_state); + + sf_kernel_offset = ALIGN(next_offset, 64); + next_offset = sf_kernel_offset + sizeof (sf_kernel_static); + ps_kernel_offset = ALIGN(next_offset, 64); + next_offset = ps_kernel_offset + sizeof (ps_kernel_static); + sip_kernel_offset = ALIGN(next_offset, 64); + next_offset = sip_kernel_offset + sizeof (sip_kernel_static); + cc_viewport_offset = ALIGN(next_offset, 32); + next_offset = cc_viewport_offset + sizeof(*cc_viewport); + + src_sampler_offset = ALIGN(next_offset, 32); + next_offset = src_sampler_offset + sizeof(*src_sampler_state); + + /* Align VB to native size of elements, for safety */ + vb_offset = ALIGN(next_offset, 8); + next_offset = vb_offset + vb_size; + + /* And then the general state: */ + dest_surf_offset = ALIGN(next_offset, 32); + next_offset = dest_surf_offset + sizeof(*dest_surf_state); + src_surf_offset = ALIGN(next_offset, 32); + next_offset = src_surf_offset + sizeof(*src_surf_state); + binding_table_offset = ALIGN(next_offset, 32); + next_offset = binding_table_offset + (WM_BINDING_TABLE_ENTRIES * 4); + + /* Allocate an area in framebuffer for our state layout we just set up */ + total_state_size = next_offset; + assert (total_state_size < BRW_LINEAR_EXTRA); + + /* + * Use the extra space allocated at the end of the Xv buffer + */ + state_base_offset = pPriv->extra_offset; + state_base_offset = ALIGN(state_base_offset, 64); + + state_base = (char *)(pI830->FbBase + state_base_offset); + /* Set up our pointers to state structures in framebuffer. It would + * probably be a good idea to fill these structures out in system memory + * and then dump them there, instead. + */ + vs_state = (void *)(state_base + vs_offset); + sf_state = (void *)(state_base + sf_offset); + wm_state = (void *)(state_base + wm_offset); + cc_state = (void *)(state_base + cc_offset); + sf_kernel = (void *)(state_base + sf_kernel_offset); + ps_kernel = (void *)(state_base + ps_kernel_offset); + sip_kernel = (void *)(state_base + sip_kernel_offset); + + cc_viewport = (void *)(state_base + cc_viewport_offset); + dest_surf_state = (void *)(state_base + dest_surf_offset); + src_surf_state = (void *)(state_base + src_surf_offset); + src_sampler_state = (void *)(state_base + src_sampler_offset); + binding_table = (void *)(state_base + binding_table_offset); + vb = (void *)(state_base + vb_offset); + +#if 0 + ErrorF("vs: 0x%08x\n", state_base_offset + vs_offset); + ErrorF("wm: 0x%08x\n", state_base_offset + wm_offset); + ErrorF("sf: 0x%08x\n", state_base_offset + sf_offset); + ErrorF("cc: 0x%08x\n", state_base_offset + cc_offset); + ErrorF("sf kernel: 0x%08x\n", state_base_offset + sf_kernel_offset); + ErrorF("ps kernel: 0x%08x\n", state_base_offset + ps_kernel_offset); + ErrorF("sip kernel: 0x%08x\n", state_base_offset + sip_kernel_offset); + ErrorF("cc_vp: 0x%08x\n", state_base_offset + cc_viewport_offset); + ErrorF("src sampler: 0x%08x\n", state_base_offset + src_sampler_offset); + ErrorF("vb: 0x%08x\n", state_base_offset + vb_offset); + ErrorF("dst surf: 0x%08x\n", state_base_offset + dest_surf_offset); + ErrorF("src surf: 0x%08x\n", state_base_offset + src_surf_offset); + ErrorF("binding table: 0x%08x\n", state_base_offset + binding_table_offset); +#endif + + /* For 3D, the VS must have 8, 12, 16, 24, or 32 VUEs allocated to it. + * A VUE consists of a 256-bit vertex header followed by the vertex data, + * which in our case is 4 floats (128 bits), thus a single 512-bit URB + * entry. + */ +#define URB_VS_ENTRIES 8 +#define URB_VS_ENTRY_SIZE 1 + +#define URB_GS_ENTRIES 0 +#define URB_GS_ENTRY_SIZE 0 + +#define URB_CLIP_ENTRIES 0 +#define URB_CLIP_ENTRY_SIZE 0 + + /* The SF kernel we use outputs only 4 256-bit registers, leading to an + * entry size of 2 512-bit URBs. We don't need to have many entries to + * output as we're generally working on large rectangles and don't care + * about having WM threads running on different rectangles simultaneously. + */ +#define URB_SF_ENTRIES 1 +#define URB_SF_ENTRY_SIZE 2 + +#define URB_CS_ENTRIES 0 +#define URB_CS_ENTRY_SIZE 0 + + urb_vs_start = 0; + urb_vs_size = URB_VS_ENTRIES * URB_VS_ENTRY_SIZE; + urb_gs_start = urb_vs_start + urb_vs_size; + urb_gs_size = URB_GS_ENTRIES * URB_GS_ENTRY_SIZE; + urb_clip_start = urb_gs_start + urb_gs_size; + urb_clip_size = URB_CLIP_ENTRIES * URB_CLIP_ENTRY_SIZE; + urb_sf_start = urb_clip_start + urb_clip_size; + urb_sf_size = URB_SF_ENTRIES * URB_SF_ENTRY_SIZE; + urb_cs_start = urb_sf_start + urb_sf_size; + urb_cs_size = URB_CS_ENTRIES * URB_CS_ENTRY_SIZE; + + /* We'll be poking the state buffers that could be in use by the 3d + * hardware here, but we should have synced the 3D engine already in + * I830PutImage. + */ + + memset (cc_viewport, 0, sizeof (*cc_viewport)); + cc_viewport->min_depth = -1.e35; + cc_viewport->max_depth = 1.e35; + + /* Color calculator state */ + memset(cc_state, 0, sizeof(*cc_state)); + cc_state->cc0.stencil_enable = 0; /* disable stencil */ + cc_state->cc2.depth_test = 0; /* disable depth test */ + cc_state->cc2.logicop_enable = 1; /* enable logic op */ + cc_state->cc3.ia_blend_enable = 1; /* blend alpha just like colors */ + cc_state->cc3.blend_enable = 0; /* disable color blend */ + cc_state->cc3.alpha_test = 0; /* disable alpha test */ + cc_state->cc4.cc_viewport_state_offset = (state_base_offset + + cc_viewport_offset) >> 5; + cc_state->cc5.dither_enable = 0; /* disable dither */ + cc_state->cc5.logicop_func = 0xc; /* WHITE */ + cc_state->cc5.statistics_enable = 1; + cc_state->cc5.ia_blend_function = BRW_BLENDFUNCTION_ADD; + cc_state->cc5.ia_src_blend_factor = BRW_BLENDFACTOR_ONE; + cc_state->cc5.ia_dest_blend_factor = BRW_BLENDFACTOR_ONE; + + /* Upload system kernel */ + memcpy (sip_kernel, sip_kernel_static, sizeof (sip_kernel_static)); + + /* Set up the state buffer for the destination surface */ + memset(dest_surf_state, 0, sizeof(*dest_surf_state)); + dest_surf_state->ss0.surface_type = BRW_SURFACE_2D; + dest_surf_state->ss0.data_return_format = BRW_SURFACERETURNFORMAT_FLOAT32; + if (pI830->cpp == 2) { + dest_surf_state->ss0.surface_format = BRW_SURFACEFORMAT_B5G6R5_UNORM; + } else { + dest_surf_state->ss0.surface_format = BRW_SURFACEFORMAT_B8G8R8A8_UNORM; + } + dest_surf_state->ss0.writedisable_alpha = 0; + dest_surf_state->ss0.writedisable_red = 0; + dest_surf_state->ss0.writedisable_green = 0; + dest_surf_state->ss0.writedisable_blue = 0; + dest_surf_state->ss0.color_blend = 1; + dest_surf_state->ss0.vert_line_stride = 0; + dest_surf_state->ss0.vert_line_stride_ofs = 0; + dest_surf_state->ss0.mipmap_layout_mode = 0; + dest_surf_state->ss0.render_cache_read_mode = 0; + + dest_surf_state->ss1.base_addr = intel_get_pixmap_offset(pPixmap); + dest_surf_state->ss2.height = pScrn->virtualY - 1; + dest_surf_state->ss2.width = pScrn->virtualX - 1; + dest_surf_state->ss2.mip_count = 0; + dest_surf_state->ss2.render_target_rotation = 0; + dest_surf_state->ss3.pitch = intel_get_pixmap_pitch(pPixmap) - 1; + dest_surf_state->ss3.tiled_surface = i830_pixmap_tiled(pPixmap); + dest_surf_state->ss3.tile_walk = 0; /* TileX */ + + /* Set up the source surface state buffer */ + memset(src_surf_state, 0, sizeof(*src_surf_state)); + src_surf_state->ss0.surface_type = BRW_SURFACE_2D; + /* src_surf_state->ss0.data_return_format = + BRW_SURFACERETURNFORMAT_FLOAT32; */ + switch (id) { + case FOURCC_YUY2: + src_surf_state->ss0.surface_format = BRW_SURFACEFORMAT_YCRCB_NORMAL; + break; + case FOURCC_UYVY: + src_surf_state->ss0.surface_format = BRW_SURFACEFORMAT_YCRCB_SWAPY; + break; + } + src_surf_state->ss0.writedisable_alpha = 0; + src_surf_state->ss0.writedisable_red = 0; + src_surf_state->ss0.writedisable_green = 0; + src_surf_state->ss0.writedisable_blue = 0; + src_surf_state->ss0.color_blend = 1; + src_surf_state->ss0.vert_line_stride = 0; + src_surf_state->ss0.vert_line_stride_ofs = 0; + src_surf_state->ss0.mipmap_layout_mode = 0; + src_surf_state->ss0.render_cache_read_mode = 0; + + src_surf_state->ss1.base_addr = pPriv->YBuf0offset; + src_surf_state->ss2.width = width - 1; + src_surf_state->ss2.height = height - 1; + src_surf_state->ss2.mip_count = 0; + src_surf_state->ss2.render_target_rotation = 0; + src_surf_state->ss3.pitch = video_pitch - 1; + /* FIXME: account for tiling if we ever do it */ + + /* Set up a binding table for our two surfaces. Only the PS will use it */ + /* XXX: are these offset from the right place? */ + binding_table[0] = state_base_offset + dest_surf_offset; + binding_table[1] = state_base_offset + src_surf_offset; + + /* Set up the packed YUV source sampler. Doesn't do colorspace conversion. + */ + memset(src_sampler_state, 0, sizeof(*src_sampler_state)); + src_sampler_state->ss0.min_filter = BRW_MAPFILTER_LINEAR; + src_sampler_state->ss0.mag_filter = BRW_MAPFILTER_LINEAR; + src_sampler_state->ss1.r_wrap_mode = BRW_TEXCOORDMODE_CLAMP; + src_sampler_state->ss1.s_wrap_mode = BRW_TEXCOORDMODE_CLAMP; + src_sampler_state->ss1.t_wrap_mode = BRW_TEXCOORDMODE_CLAMP; + + /* Set up the vertex shader to be disabled (passthrough) */ + memset(vs_state, 0, sizeof(*vs_state)); + vs_state->thread4.nr_urb_entries = URB_VS_ENTRIES; + vs_state->thread4.urb_entry_allocation_size = URB_VS_ENTRY_SIZE - 1; + vs_state->vs6.vs_enable = 0; + vs_state->vs6.vert_cache_disable = 1; + + /* Set up the SF kernel to do coord interp: for each attribute, + * calculate dA/dx and dA/dy. Hand these interpolation coefficients + * back to SF which then hands pixels off to WM. + */ + + memcpy (sf_kernel, sf_kernel_static, sizeof (sf_kernel_static)); + memset(sf_state, 0, sizeof(*sf_state)); + sf_state->thread0.kernel_start_pointer = + (state_base_offset + sf_kernel_offset) >> 6; + sf_state->thread0.grf_reg_count = BRW_GRF_BLOCKS(SF_KERNEL_NUM_GRF); + sf_state->sf1.single_program_flow = 1; /* XXX */ + sf_state->sf1.binding_table_entry_count = 0; + sf_state->sf1.thread_priority = 0; + sf_state->sf1.floating_point_mode = 0; /* Mesa does this */ + sf_state->sf1.illegal_op_exception_enable = 1; + sf_state->sf1.mask_stack_exception_enable = 1; + sf_state->sf1.sw_exception_enable = 1; + sf_state->thread2.per_thread_scratch_space = 0; + /* scratch space is not used in our kernel */ + sf_state->thread2.scratch_space_base_pointer = 0; + sf_state->thread3.const_urb_entry_read_length = 0; /* no const URBs */ + sf_state->thread3.const_urb_entry_read_offset = 0; /* no const URBs */ + sf_state->thread3.urb_entry_read_length = 1; /* 1 URB per vertex */ + sf_state->thread3.urb_entry_read_offset = 0; + sf_state->thread3.dispatch_grf_start_reg = 3; + sf_state->thread4.max_threads = SF_MAX_THREADS - 1; + sf_state->thread4.urb_entry_allocation_size = URB_SF_ENTRY_SIZE - 1; + sf_state->thread4.nr_urb_entries = URB_SF_ENTRIES; + sf_state->thread4.stats_enable = 1; + sf_state->sf5.viewport_transform = FALSE; /* skip viewport */ + sf_state->sf6.cull_mode = BRW_CULLMODE_NONE; + sf_state->sf6.scissor = 0; + sf_state->sf7.trifan_pv = 2; + sf_state->sf6.dest_org_vbias = 0x8; + sf_state->sf6.dest_org_hbias = 0x8; + + memcpy (ps_kernel, ps_kernel_static, sizeof (ps_kernel_static)); + memset (wm_state, 0, sizeof (*wm_state)); + wm_state->thread0.kernel_start_pointer = + (state_base_offset + ps_kernel_offset) >> 6; + wm_state->thread0.grf_reg_count = BRW_GRF_BLOCKS(PS_KERNEL_NUM_GRF); + wm_state->thread1.single_program_flow = 1; /* XXX */ + wm_state->thread1.binding_table_entry_count = 2; + /* Though we never use the scratch space in our WM kernel, it has to be + * set, and the minimum allocation is 1024 bytes. + */ + wm_state->thread2.scratch_space_base_pointer = (state_base_offset + + wm_scratch_offset) >> 10; + wm_state->thread2.per_thread_scratch_space = 0; /* 1024 bytes */ + wm_state->thread3.dispatch_grf_start_reg = 3; /* XXX */ + wm_state->thread3.const_urb_entry_read_length = 0; + wm_state->thread3.const_urb_entry_read_offset = 0; + wm_state->thread3.urb_entry_read_length = 1; /* XXX */ + wm_state->thread3.urb_entry_read_offset = 0; /* XXX */ + wm_state->wm4.stats_enable = 1; + wm_state->wm4.sampler_state_pointer = (state_base_offset + + src_sampler_offset) >> 5; + wm_state->wm4.sampler_count = 1; /* 1-4 samplers used */ + wm_state->wm5.max_threads = PS_MAX_THREADS - 1; + wm_state->wm5.thread_dispatch_enable = 1; + wm_state->wm5.enable_16_pix = 1; + wm_state->wm5.enable_8_pix = 0; + wm_state->wm5.early_depth_test = 1; + + { + BEGIN_LP_RING(2); + OUT_RING(MI_FLUSH | + MI_STATE_INSTRUCTION_CACHE_FLUSH | + BRW_MI_GLOBAL_SNAPSHOT_RESET); + OUT_RING(MI_NOOP); + ADVANCE_LP_RING(); + } + + /* brw_debug (pScrn, "before base address modify"); */ + { + BEGIN_LP_RING(12); + /* Match Mesa driver setup */ + OUT_RING(BRW_PIPELINE_SELECT | PIPELINE_SELECT_3D); + + /* Mesa does this. Who knows... */ + OUT_RING(BRW_CS_URB_STATE | 0); + OUT_RING((0 << 4) | /* URB Entry Allocation Size */ + (0 << 0)); /* Number of URB Entries */ + + /* Zero out the two base address registers so all offsets are + * absolute + */ + OUT_RING(BRW_STATE_BASE_ADDRESS | 4); + OUT_RING(0 | BASE_ADDRESS_MODIFY); /* Generate state base address */ + OUT_RING(0 | BASE_ADDRESS_MODIFY); /* Surface state base address */ + OUT_RING(0 | BASE_ADDRESS_MODIFY); /* media base addr, don't care */ + /* general state max addr, disabled */ + OUT_RING(0x10000000 | BASE_ADDRESS_MODIFY); + /* media object state max addr, disabled */ + OUT_RING(0x10000000 | BASE_ADDRESS_MODIFY); + + /* Set system instruction pointer */ + OUT_RING(BRW_STATE_SIP | 0); + /* system instruction pointer */ + OUT_RING(state_base_offset + sip_kernel_offset); + + OUT_RING(MI_NOOP); + ADVANCE_LP_RING(); + } + + /* brw_debug (pScrn, "after base address modify"); */ + + { + BEGIN_LP_RING(42); + /* Enable VF statistics */ + OUT_RING(BRW_3DSTATE_VF_STATISTICS | 1); + + /* Pipe control */ + OUT_RING(BRW_PIPE_CONTROL | + BRW_PIPE_CONTROL_NOWRITE | + BRW_PIPE_CONTROL_IS_FLUSH | + 2); + OUT_RING(0); /* Destination address */ + OUT_RING(0); /* Immediate data low DW */ + OUT_RING(0); /* Immediate data high DW */ + + /* Binding table pointers */ + OUT_RING(BRW_3DSTATE_BINDING_TABLE_POINTERS | 4); + OUT_RING(0); /* vs */ + OUT_RING(0); /* gs */ + OUT_RING(0); /* clip */ + OUT_RING(0); /* sf */ + /* Only the PS uses the binding table */ + OUT_RING(state_base_offset + binding_table_offset); /* ps */ + + /* Blend constant color (magenta is fun) */ + OUT_RING(BRW_3DSTATE_CONSTANT_COLOR | 3); + OUT_RING(float_to_uint (1.0)); + OUT_RING(float_to_uint (0.0)); + OUT_RING(float_to_uint (1.0)); + OUT_RING(float_to_uint (1.0)); + + /* The drawing rectangle clipping is always on. Set it to values that + * shouldn't do any clipping. + */ + OUT_RING(BRW_3DSTATE_DRAWING_RECTANGLE | 2); /* XXX 3 for BLC or CTG */ + OUT_RING(0x00000000); /* ymin, xmin */ + OUT_RING((pScrn->virtualX - 1) | + (pScrn->virtualY - 1) << 16); /* ymax, xmax */ + OUT_RING(0x00000000); /* yorigin, xorigin */ + + /* skip the depth buffer */ + /* skip the polygon stipple */ + /* skip the polygon stipple offset */ + /* skip the line stipple */ + + /* Set the pointers to the 3d pipeline state */ + OUT_RING(BRW_3DSTATE_PIPELINED_POINTERS | 5); + OUT_RING(state_base_offset + vs_offset); /* 32 byte aligned */ + /* disable GS, resulting in passthrough */ + OUT_RING(BRW_GS_DISABLE); + /* disable CLIP, resulting in passthrough */ + OUT_RING(BRW_CLIP_DISABLE); + OUT_RING(state_base_offset + sf_offset); /* 32 byte aligned */ + OUT_RING(state_base_offset + wm_offset); /* 32 byte aligned */ + OUT_RING(state_base_offset + cc_offset); /* 64 byte aligned */ + + /* URB fence */ + OUT_RING(BRW_URB_FENCE | + UF0_CS_REALLOC | + UF0_SF_REALLOC | + UF0_CLIP_REALLOC | + UF0_GS_REALLOC | + UF0_VS_REALLOC | + 1); + OUT_RING(((urb_clip_start + urb_clip_size) << UF1_CLIP_FENCE_SHIFT) | + ((urb_gs_start + urb_gs_size) << UF1_GS_FENCE_SHIFT) | + ((urb_vs_start + urb_vs_size) << UF1_VS_FENCE_SHIFT)); + OUT_RING(((urb_cs_start + urb_cs_size) << UF2_CS_FENCE_SHIFT) | + ((urb_sf_start + urb_sf_size) << UF2_SF_FENCE_SHIFT)); + + /* Constant buffer state */ + OUT_RING(BRW_CS_URB_STATE | 0); + OUT_RING(((URB_CS_ENTRY_SIZE - 1) << 4) | + (URB_CS_ENTRIES << 0)); + + /* Set up the pointer to our vertex buffer */ + OUT_RING(BRW_3DSTATE_VERTEX_BUFFERS | 2); + /* four 32-bit floats per vertex */ + OUT_RING((0 << VB0_BUFFER_INDEX_SHIFT) | + VB0_VERTEXDATA | + ((4 * 4) << VB0_BUFFER_PITCH_SHIFT)); + OUT_RING(state_base_offset + vb_offset); + OUT_RING(3); /* four corners to our rectangle */ + + /* Set up our vertex elements, sourced from the single vertex buffer. */ + OUT_RING(BRW_3DSTATE_VERTEX_ELEMENTS | 3); + /* offset 0: X,Y -> {X, Y, 1.0, 1.0} */ + OUT_RING((0 << VE0_VERTEX_BUFFER_INDEX_SHIFT) | + VE0_VALID | + (BRW_SURFACEFORMAT_R32G32_FLOAT << VE0_FORMAT_SHIFT) | + (0 << VE0_OFFSET_SHIFT)); + OUT_RING((BRW_VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_0_SHIFT) | + (BRW_VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_1_SHIFT) | + (BRW_VFCOMPONENT_STORE_1_FLT << VE1_VFCOMPONENT_2_SHIFT) | + (BRW_VFCOMPONENT_STORE_1_FLT << VE1_VFCOMPONENT_3_SHIFT) | + (0 << VE1_DESTINATION_ELEMENT_OFFSET_SHIFT)); + /* offset 8: S0, T0 -> {S0, T0, 1.0, 1.0} */ + OUT_RING((0 << VE0_VERTEX_BUFFER_INDEX_SHIFT) | + VE0_VALID | + (BRW_SURFACEFORMAT_R32G32_FLOAT << VE0_FORMAT_SHIFT) | + (8 << VE0_OFFSET_SHIFT)); + OUT_RING((BRW_VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_0_SHIFT) | + (BRW_VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_1_SHIFT) | + (BRW_VFCOMPONENT_STORE_1_FLT << VE1_VFCOMPONENT_2_SHIFT) | + (BRW_VFCOMPONENT_STORE_1_FLT << VE1_VFCOMPONENT_3_SHIFT) | + (4 << VE1_DESTINATION_ELEMENT_OFFSET_SHIFT)); + + OUT_RING(MI_NOOP); /* pad to quadword */ + ADVANCE_LP_RING(); + } + + /* Set up the offset for translating from the given region (in screen + * coordinates) to the backing pixmap. + */ +#ifdef COMPOSITE + pix_xoff = -pPixmap->screen_x + pPixmap->drawable.x; + pix_yoff = -pPixmap->screen_y + pPixmap->drawable.y; +#else + pix_xoff = 0; + pix_yoff = 0; +#endif + + dxo = dstRegion->extents.x1; + dyo = dstRegion->extents.y1; + + /* Use normalized texture coordinates */ + src_scale_x = ((float)src_w / width) / (float)drw_w; + src_scale_y = ((float)src_h / height) / (float)drw_h; + + pbox = REGION_RECTS(dstRegion); + nbox = REGION_NUM_RECTS(dstRegion); + while (nbox--) { + int box_x1 = pbox->x1; + int box_y1 = pbox->y1; + int box_x2 = pbox->x2; + int box_y2 = pbox->y2; + int i; + + if (!first_output) { + /* Since we use the same little vertex buffer over and over, sync + * for subsequent rectangles. + */ + i830WaitSync(pScrn); + } + + pbox++; + + i = 0; + vb[i++] = (box_x2 - dxo) * src_scale_x; + vb[i++] = (box_y2 - dyo) * src_scale_y; + vb[i++] = (float) box_x2 + pix_xoff; + vb[i++] = (float) box_y2 + pix_yoff; + + vb[i++] = (box_x1 - dxo) * src_scale_x; + vb[i++] = (box_y2 - dyo) * src_scale_y; + vb[i++] = (float) box_x1 + pix_xoff; + vb[i++] = (float) box_y2 + pix_yoff; + + vb[i++] = (box_x1 - dxo) * src_scale_x; + vb[i++] = (box_y1 - dyo) * src_scale_y; + vb[i++] = (float) box_x1 + pix_xoff; + vb[i++] = (float) box_y1 + pix_yoff; + +#if 0 + ErrorF ("before EU_ATT 0x%08x%08x EU_ATT_DATA 0x%08x%08x\n", + INREG(BRW_EU_ATT_1), INREG(BRW_EU_ATT_0), + INREG(BRW_EU_ATT_DATA_1), INREG(BRW_EU_ATT_DATA_0)); + + OUTREG(BRW_VF_CTL, + BRW_VF_CTL_SNAPSHOT_MUX_SELECT_THREADID | + BRW_VF_CTL_SNAPSHOT_TYPE_VERTEX_INDEX | + BRW_VF_CTL_SNAPSHOT_ENABLE); + OUTREG(BRW_VF_STRG_VAL, 0); +#endif + +#if 0 + OUTREG(BRW_VS_CTL, + BRW_VS_CTL_SNAPSHOT_ALL_THREADS | + BRW_VS_CTL_SNAPSHOT_MUX_VALID_COUNT | + BRW_VS_CTL_THREAD_SNAPSHOT_ENABLE); + + OUTREG(BRW_VS_STRG_VAL, 0); +#endif + +#if WATCH_SF + OUTREG(BRW_SF_CTL, + BRW_SF_CTL_SNAPSHOT_MUX_VERTEX_COUNT | + BRW_SF_CTL_SNAPSHOT_ALL_THREADS | + BRW_SF_CTL_THREAD_SNAPSHOT_ENABLE); + OUTREG(BRW_SF_STRG_VAL, 0); +#endif + +#if WATCH_WIZ + OUTREG(BRW_WIZ_CTL, + BRW_WIZ_CTL_SNAPSHOT_MUX_SUBSPAN_INSTANCE | + BRW_WIZ_CTL_SNAPSHOT_ALL_THREADS | + BRW_WIZ_CTL_SNAPSHOT_ENABLE); + OUTREG(BRW_WIZ_STRG_VAL, + (box_x1) | (box_y1 << 16)); +#endif + +#if 0 + OUTREG(BRW_TS_CTL, + BRW_TS_CTL_SNAPSHOT_MESSAGE_ERROR | + BRW_TS_CTL_SNAPSHOT_ALL_CHILD_THREADS | + BRW_TS_CTL_SNAPSHOT_ALL_ROOT_THREADS | + BRW_TS_CTL_SNAPSHOT_ENABLE); +#endif + + BEGIN_LP_RING(6); + OUT_RING(BRW_3DPRIMITIVE | + BRW_3DPRIMITIVE_VERTEX_SEQUENTIAL | + (_3DPRIM_RECTLIST << BRW_3DPRIMITIVE_TOPOLOGY_SHIFT) | + (0 << 9) | /* CTG - indirect vertex count */ + 4); + OUT_RING(3); /* vertex count per instance */ + OUT_RING(0); /* start vertex offset */ + OUT_RING(1); /* single instance */ + OUT_RING(0); /* start instance location */ + OUT_RING(0); /* index buffer offset, ignored */ + ADVANCE_LP_RING(); + +#if 0 + for (j = 0; j < 100000; j++) { + ctl = INREG(BRW_VF_CTL); + if (ctl & BRW_VF_CTL_SNAPSHOT_COMPLETE) + break; + } + + rdata = INREG(BRW_VF_RDATA); + OUTREG(BRW_VF_CTL, 0); + ErrorF ("VF_CTL: 0x%08x VF_RDATA: 0x%08x\n", ctl, rdata); +#endif + +#if 0 + for (j = 0; j < 1000000; j++) { + ctl = INREG(BRW_VS_CTL); + if (ctl & BRW_VS_CTL_SNAPSHOT_COMPLETE) + break; + } + + rdata = INREG(BRW_VS_RDATA); + for (k = 0; k <= 3; k++) { + OUTREG(BRW_VS_CTL, + BRW_VS_CTL_SNAPSHOT_COMPLETE | + (k << 8)); + rdata = INREG(BRW_VS_RDATA); + ErrorF ("VS_CTL: 0x%08x VS_RDATA(%d): 0x%08x\n", ctl, k, rdata); + } + + OUTREG(BRW_VS_CTL, 0); +#endif + +#if WATCH_SF + for (j = 0; j < 1000000; j++) { + ctl = INREG(BRW_SF_CTL); + if (ctl & BRW_SF_CTL_SNAPSHOT_COMPLETE) + break; + } + + for (k = 0; k <= 7; k++) { + OUTREG(BRW_SF_CTL, + BRW_SF_CTL_SNAPSHOT_COMPLETE | + (k << 8)); + rdata = INREG(BRW_SF_RDATA); + ErrorF("SF_CTL: 0x%08x SF_RDATA(%d): 0x%08x\n", ctl, k, rdata); + } + + OUTREG(BRW_SF_CTL, 0); +#endif + +#if WATCH_WIZ + for (j = 0; j < 100000; j++) { + ctl = INREG(BRW_WIZ_CTL); + if (ctl & BRW_WIZ_CTL_SNAPSHOT_COMPLETE) + break; + } + + rdata = INREG(BRW_WIZ_RDATA); + OUTREG(BRW_WIZ_CTL, 0); + ErrorF("WIZ_CTL: 0x%08x WIZ_RDATA: 0x%08x\n", ctl, rdata); +#endif + +#if 0 + for (j = 0; j < 100000; j++) { + ctl = INREG(BRW_TS_CTL); + if (ctl & BRW_TS_CTL_SNAPSHOT_COMPLETE) + break; + } + + rdata = INREG(BRW_TS_RDATA); + OUTREG(BRW_TS_CTL, 0); + ErrorF("TS_CTL: 0x%08x TS_RDATA: 0x%08x\n", ctl, rdata); + + ErrorF("after EU_ATT 0x%08x%08x EU_ATT_DATA 0x%08x%08x\n", + INREG(BRW_EU_ATT_1), INREG(BRW_EU_ATT_0), + INREG(BRW_EU_ATT_DATA_1), INREG(BRW_EU_ATT_DATA_0)); +#endif + +#if 0 + for (j = 0; j < 256; j++) { + OUTREG(BRW_TD_CTL, j << BRW_TD_CTL_MUX_SHIFT); + rdata = INREG(BRW_TD_RDATA); + ErrorF ("TD_RDATA(%d): 0x%08x\n", j, rdata); + } +#endif + first_output = FALSE; + i830MarkSync(pScrn); + } + + i830WaitSync(pScrn); +#if WATCH_STATS + i830_dump_error_state(pScrn); +#endif +} diff --git a/driver/xf86-video-intel/src/ivch/Makefile.am b/driver/xf86-video-intel/src/ivch/Makefile.am new file mode 100644 index 000000000..1dc9cb352 --- /dev/null +++ b/driver/xf86-video-intel/src/ivch/Makefile.am @@ -0,0 +1,15 @@ +# this is obnoxious: +# -module lets us name the module exactly how we want +# -avoid-version prevents gratuitous .0.0.0 version numbers on the end +# _ladir passes a dummy rpath to libtool so the thing will actually link +# TODO: -nostdlib/-Bstatic/-lgcc platform magic, not installing the .a, etc. +AM_CFLAGS = @WARN_CFLAGS@ @XMODES_CFLAGS@ @XORG_CFLAGS@ @DRI_CFLAGS@ + +ivch_la_LTLIBRARIES = ivch.la +ivch_la_LDFLAGS = -module -avoid-version +ivch_ladir = @moduledir@/drivers + +ivch_la_SOURCES = \ + ivch.c \ + ivch_module.c \ + ivch_reg.h diff --git a/driver/xf86-video-intel/src/ivch/Makefile.in b/driver/xf86-video-intel/src/ivch/Makefile.in new file mode 100644 index 000000000..231d3d2c3 --- /dev/null +++ b/driver/xf86-video-intel/src/ivch/Makefile.in @@ -0,0 +1,511 @@ +# Makefile.in generated by automake 1.10 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/ivch +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; +am__installdirs = "$(DESTDIR)$(ivch_ladir)" +ivch_laLTLIBRARIES_INSTALL = $(INSTALL) +LTLIBRARIES = $(ivch_la_LTLIBRARIES) +ivch_la_LIBADD = +am_ivch_la_OBJECTS = ivch.lo ivch_module.lo +ivch_la_OBJECTS = $(am_ivch_la_OBJECTS) +ivch_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(ivch_la_LDFLAGS) \ + $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I. -I$(top_builddir)@am__isrc@ +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(ivch_la_SOURCES) +DIST_SOURCES = $(ivch_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ADMIN_MAN_DIR = @ADMIN_MAN_DIR@ +ADMIN_MAN_SUFFIX = @ADMIN_MAN_SUFFIX@ +AMTAR = @AMTAR@ +APP_MAN_DIR = @APP_MAN_DIR@ +APP_MAN_SUFFIX = @APP_MAN_SUFFIX@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DRIVER_MAN_DIR = @DRIVER_MAN_DIR@ +DRIVER_MAN_SUFFIX = @DRIVER_MAN_SUFFIX@ +DRIVER_NAME = @DRIVER_NAME@ +DRI_CFLAGS = @DRI_CFLAGS@ +DRI_LIBS = @DRI_LIBS@ +DRI_MM_CFLAGS = @DRI_MM_CFLAGS@ +DRI_MM_LIBS = @DRI_MM_LIBS@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +FILE_MAN_DIR = @FILE_MAN_DIR@ +FILE_MAN_SUFFIX = @FILE_MAN_SUFFIX@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIB_MAN_DIR = @LIB_MAN_DIR@ +LIB_MAN_SUFFIX = @LIB_MAN_SUFFIX@ +LINUXDOC = @LINUXDOC@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MAKE_HTML = @MAKE_HTML@ +MAKE_PDF = @MAKE_PDF@ +MAKE_PS = @MAKE_PS@ +MAKE_TEXT = @MAKE_TEXT@ +MISC_MAN_DIR = @MISC_MAN_DIR@ +MISC_MAN_SUFFIX = @MISC_MAN_SUFFIX@ +MKDIR_P = @MKDIR_P@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PCIACCESS_CFLAGS = @PCIACCESS_CFLAGS@ +PCIACCESS_LIBS = @PCIACCESS_LIBS@ +PKG_CONFIG = @PKG_CONFIG@ +PS2PDF = @PS2PDF@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +WARN_CFLAGS = @WARN_CFLAGS@ +XMODES_CFLAGS = @XMODES_CFLAGS@ +XORG_CFLAGS = @XORG_CFLAGS@ +XORG_LIBS = @XORG_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +gen4asm = @gen4asm@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +moduledir = @moduledir@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ + +# this is obnoxious: +# -module lets us name the module exactly how we want +# -avoid-version prevents gratuitous .0.0.0 version numbers on the end +# _ladir passes a dummy rpath to libtool so the thing will actually link +# TODO: -nostdlib/-Bstatic/-lgcc platform magic, not installing the .a, etc. +AM_CFLAGS = @WARN_CFLAGS@ @XMODES_CFLAGS@ @XORG_CFLAGS@ @DRI_CFLAGS@ +ivch_la_LTLIBRARIES = ivch.la +ivch_la_LDFLAGS = -module -avoid-version +ivch_ladir = @moduledir@/drivers +ivch_la_SOURCES = \ + ivch.c \ + ivch_module.c \ + ivch_reg.h + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/ivch/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/ivch/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-ivch_laLTLIBRARIES: $(ivch_la_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(ivch_ladir)" || $(MKDIR_P) "$(DESTDIR)$(ivch_ladir)" + @list='$(ivch_la_LTLIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + f=$(am__strip_dir) \ + echo " $(LIBTOOL) --mode=install $(ivch_laLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(ivch_ladir)/$$f'"; \ + $(LIBTOOL) --mode=install $(ivch_laLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(ivch_ladir)/$$f"; \ + else :; fi; \ + done + +uninstall-ivch_laLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(ivch_la_LTLIBRARIES)'; for p in $$list; do \ + p=$(am__strip_dir) \ + echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(ivch_ladir)/$$p'"; \ + $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(ivch_ladir)/$$p"; \ + done + +clean-ivch_laLTLIBRARIES: + -test -z "$(ivch_la_LTLIBRARIES)" || rm -f $(ivch_la_LTLIBRARIES) + @list='$(ivch_la_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +ivch.la: $(ivch_la_OBJECTS) $(ivch_la_DEPENDENCIES) + $(ivch_la_LINK) -rpath $(ivch_ladir) $(ivch_la_OBJECTS) $(ivch_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ivch.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ivch_module.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(ivch_ladir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-ivch_laLTLIBRARIES clean-libtool \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-ivch_laLTLIBRARIES + +install-dvi: install-dvi-am + +install-exec-am: + +install-html: install-html-am + +install-info: install-info-am + +install-man: + +install-pdf: install-pdf-am + +install-ps: install-ps-am + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-ivch_laLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-ivch_laLTLIBRARIES clean-libtool ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am \ + install-ivch_laLTLIBRARIES install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-ivch_laLTLIBRARIES + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/driver/xf86-video-intel/src/ivch/ivch.c b/driver/xf86-video-intel/src/ivch/ivch.c new file mode 100644 index 000000000..ac57ff3af --- /dev/null +++ b/driver/xf86-video-intel/src/ivch/ivch.c @@ -0,0 +1,369 @@ +/* + * Copyright © 2006 Intel Corporation + * + * 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 + * THE AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86Resources.h" +#include "compiler.h" +#include "miscstruct.h" +#include "xf86i2c.h" +#include "xf86Crtc.h" +#define DPMS_SERVER +#include <X11/extensions/dpms.h> +#include <unistd.h> + +#include "../i2c_vid.h" +#include "../i830_bios.h" +#include "ivch_reg.h" + +struct ivch_priv { + I2CDevRec d; + + xf86OutputPtr output; + Bool quiet; + + CARD16 width; + CARD16 height; + + CARD16 save_VR01; + CARD16 save_VR40; +}; + +struct vch_capabilities { + struct aimdb_block aimdb_block; + CARD8 panel_type; + CARD8 set_panel_type; + CARD8 slave_address; + CARD8 capabilities; +#define VCH_PANEL_FITTING_SUPPORT (0x3 << 0) +#define VCH_PANEL_FITTING_TEXT (1 << 2) +#define VCH_PANEL_FITTING_GRAPHICS (1 << 3) +#define VCH_PANEL_FITTING_RATIO (1 << 4) +#define VCH_DITHERING (1 << 5) + CARD8 backlight_gpio; + CARD8 set_panel_type_us_gpios; +} __attribute__ ((packed)); + +static void +ivch_dump_regs(I2CDevPtr d); + +/** + * Reads a register on the ivch. + * + * Each of the 256 registers are 16 bits long. + */ +static Bool +ivch_read(struct ivch_priv *priv, int addr, CARD16 *data) +{ + I2CBusPtr b = priv->d.pI2CBus; + I2CByte *p = (I2CByte *) data; + + if (!b->I2CStart(b, priv->d.StartTimeout)) + goto fail; + + if (!b->I2CPutByte(&priv->d, priv->d.SlaveAddr | 1)) + goto fail; + + if (!b->I2CPutByte(&priv->d, addr)) + goto fail; + + if (!b->I2CGetByte(&priv->d, p++, FALSE)) + goto fail; + + if (!b->I2CGetByte(&priv->d, p++, TRUE)) + goto fail; + + b->I2CStop(&priv->d); + + return TRUE; + + fail: + if (!priv->quiet) { + xf86DrvMsg(priv->d.pI2CBus->scrnIndex, X_ERROR, + "ivch: Unable to read register 0x%02x from %s:%02x.\n", + addr, priv->d.pI2CBus->BusName, priv->d.SlaveAddr); + } + b->I2CStop(&priv->d); + + return FALSE; +} + +/** Writes a 16-bit register on the ivch */ +static Bool +ivch_write(struct ivch_priv *priv, int addr, CARD16 data) +{ + I2CBusPtr b = priv->d.pI2CBus; + + if (!b->I2CStart(b, priv->d.StartTimeout)) + goto fail; + + if (!b->I2CPutByte(&priv->d, priv->d.SlaveAddr)) + goto fail; + + if (!b->I2CPutByte(&priv->d, addr)) + goto fail; + + if (!b->I2CPutByte(&priv->d, data & 0xff)) + goto fail; + + if (!b->I2CPutByte(&priv->d, data >> 8)) + goto fail; + + b->I2CStop(&priv->d); + + return TRUE; + + fail: + b->I2CStop(&priv->d); + + if (!priv->quiet) { + xf86DrvMsg(priv->d.pI2CBus->scrnIndex, X_ERROR, + "Unable to write register 0x%02x to %s:%d.\n", + addr, priv->d.pI2CBus->BusName, priv->d.SlaveAddr); + } + + return FALSE; +} + +/** Probes the given bus and slave address for an ivch */ +static void * +ivch_init(I2CBusPtr b, I2CSlaveAddr addr) +{ + struct ivch_priv *priv; + CARD16 temp; + + priv = xcalloc(1, sizeof(struct ivch_priv)); + if (priv == NULL) + return NULL; + + priv->output = NULL; + priv->d.DevName = "i82807aa \"ivch\" LVDS/CMOS panel controller"; + priv->d.SlaveAddr = addr; + priv->d.pI2CBus = b; + priv->d.StartTimeout = b->StartTimeout; + priv->d.BitTimeout = b->BitTimeout; + priv->d.AcknTimeout = b->AcknTimeout; + priv->d.ByteTimeout = b->ByteTimeout; + priv->d.DriverPrivate.ptr = priv; + priv->quiet = TRUE; + + if (!ivch_read(priv, VR00, &temp)) + goto out; + priv->quiet = FALSE; + + /* Since the identification bits are probably zeroes, which doesn't seem + * very unique, check that the value in the base address field matches + * the address it's responding on. + */ + if ((temp & VR00_BASE_ADDRESS_MASK) != (priv->d.SlaveAddr >> 1)) { + xf86DrvMsg(priv->d.pI2CBus->scrnIndex, X_ERROR, + "ivch detect failed due to address mismatch " + "(%d vs %d)\n", + (temp & VR00_BASE_ADDRESS_MASK), priv->d.SlaveAddr >> 1); + } + + if (!xf86I2CDevInit(&priv->d)) { + goto out; + } + + ivch_read(priv, VR20, &priv->width); + ivch_read(priv, VR21, &priv->height); + + return priv; + +out: + xfree(priv); + return NULL; +} + +static xf86OutputStatus +ivch_detect(I2CDevPtr d) +{ + return XF86OutputStatusConnected; +} + +static ModeStatus +ivch_mode_valid(I2CDevPtr d, DisplayModePtr mode) +{ + if (mode->Clock > 112000) + return MODE_CLOCK_HIGH; + + return MODE_OK; +} + +/** Sets the power state of the panel connected to the ivch */ +static void +ivch_dpms(I2CDevPtr d, int mode) +{ + struct ivch_priv *priv = d->DriverPrivate.ptr; + int i; + CARD16 vr01, vr30, backlight; + + /* Set the new power state of the panel. */ + if (!ivch_read(priv, VR01, &vr01)) + return; + + if (mode == DPMSModeOn) + backlight = 1; + else + backlight = 0; + ivch_write(priv, VR80, backlight); + + if (mode == DPMSModeOn) + vr01 |= VR01_LCD_ENABLE | VR01_DVO_ENABLE; + else + vr01 &= ~(VR01_LCD_ENABLE | VR01_DVO_ENABLE); + + ivch_write(priv, VR01, vr01); + + /* Wait for the panel to make its state transition */ + for (i = 0; i < 100; i++) { + if (!ivch_read(priv, VR30, &vr30)) + break; + + if (((vr30 & VR30_PANEL_ON) != 0) == (mode == DPMSModeOn)) + break; + usleep (1000); + } + /* And wait some more; without this, the vch fails to resync sometimes */ + usleep (16 * 1000); +} + +static void +ivch_mode_set(I2CDevPtr d, DisplayModePtr mode, DisplayModePtr adjusted_mode) +{ + struct ivch_priv *priv = d->DriverPrivate.ptr; + CARD16 vr40 = 0; + CARD16 vr01; + + vr01 = 0; + vr40 = (VR40_STALL_ENABLE | + VR40_VERTICAL_INTERP_ENABLE | + VR40_HORIZONTAL_INTERP_ENABLE); + + if (mode->HDisplay != adjusted_mode->HDisplay || + mode->VDisplay != adjusted_mode->VDisplay) + { + CARD16 x_ratio, y_ratio; + + vr01 |= VR01_PANEL_FIT_ENABLE; + vr40 |= VR40_CLOCK_GATING_ENABLE; + x_ratio = (((mode->HDisplay - 1) << 16) / (adjusted_mode->HDisplay - 1)) >> 2; + y_ratio = (((mode->VDisplay - 1) << 16) / (adjusted_mode->VDisplay - 1)) >> 2; + ivch_write (priv, VR42, x_ratio); + ivch_write (priv, VR41, y_ratio); + } + else + { + vr01 &= ~VR01_PANEL_FIT_ENABLE; + vr40 &= ~VR40_CLOCK_GATING_ENABLE; + } + vr40 &= ~VR40_AUTO_RATIO_ENABLE; + + ivch_write(priv, VR01, vr01); + ivch_write(priv, VR40, vr40); + + ivch_dump_regs(d); +} + +static void +ivch_dump_regs(I2CDevPtr d) +{ + struct ivch_priv *priv = d->DriverPrivate.ptr; + CARD16 val; + + ivch_read(priv, VR00, &val); + xf86DrvMsg(priv->d.pI2CBus->scrnIndex, X_INFO, "VR00: 0x%04x\n", val); + ivch_read(priv, VR01, &val); + xf86DrvMsg(priv->d.pI2CBus->scrnIndex, X_INFO, "VR01: 0x%04x\n", val); + ivch_read(priv, VR30, &val); + xf86DrvMsg(priv->d.pI2CBus->scrnIndex, X_INFO, "VR30: 0x%04x\n", val); + ivch_read(priv, VR40, &val); + xf86DrvMsg(priv->d.pI2CBus->scrnIndex, X_INFO, "VR40: 0x%04x\n", val); + + /* GPIO registers */ + ivch_read(priv, VR80, &val); + xf86DrvMsg(priv->d.pI2CBus->scrnIndex, X_INFO, "VR80: 0x%04x\n", val); + ivch_read(priv, VR81, &val); + xf86DrvMsg(priv->d.pI2CBus->scrnIndex, X_INFO, "VR81: 0x%04x\n", val); + ivch_read(priv, VR82, &val); + xf86DrvMsg(priv->d.pI2CBus->scrnIndex, X_INFO, "VR82: 0x%04x\n", val); + ivch_read(priv, VR83, &val); + xf86DrvMsg(priv->d.pI2CBus->scrnIndex, X_INFO, "VR83: 0x%04x\n", val); + ivch_read(priv, VR84, &val); + xf86DrvMsg(priv->d.pI2CBus->scrnIndex, X_INFO, "VR84: 0x%04x\n", val); + ivch_read(priv, VR85, &val); + xf86DrvMsg(priv->d.pI2CBus->scrnIndex, X_INFO, "VR85: 0x%04x\n", val); + ivch_read(priv, VR86, &val); + xf86DrvMsg(priv->d.pI2CBus->scrnIndex, X_INFO, "VR86: 0x%04x\n", val); + ivch_read(priv, VR87, &val); + xf86DrvMsg(priv->d.pI2CBus->scrnIndex, X_INFO, "VR87: 0x%04x\n", val); + ivch_read(priv, VR88, &val); + xf86DrvMsg(priv->d.pI2CBus->scrnIndex, X_INFO, "VR88: 0x%04x\n", val); + + /* Scratch register 0 - AIM Panel type */ + ivch_read(priv, VR8E, &val); + xf86DrvMsg(priv->d.pI2CBus->scrnIndex, X_INFO, "VR8E: 0x%04x\n", val); + + /* Scratch register 1 - Status register */ + ivch_read(priv, VR8F, &val); + xf86DrvMsg(priv->d.pI2CBus->scrnIndex, X_INFO, "VR8F: 0x%04x\n", val); +} + +static void +ivch_save(I2CDevPtr d) +{ + struct ivch_priv *priv = d->DriverPrivate.ptr; + + ivch_read(priv, VR01, &priv->save_VR01); + ivch_read(priv, VR40, &priv->save_VR40); +} + +static void +ivch_restore(I2CDevPtr d) +{ + struct ivch_priv *priv = d->DriverPrivate.ptr; + + ivch_write(priv, VR01, priv->save_VR01); + ivch_write(priv, VR40, priv->save_VR40); +} + + +I830I2CVidOutputRec ivch_methods = { + .init = ivch_init, + .dpms = ivch_dpms, + .save = ivch_save, + .restore = ivch_restore, + .mode_valid = ivch_mode_valid, + .mode_set = ivch_mode_set, + .detect = ivch_detect, + .dump_regs = ivch_dump_regs, +}; diff --git a/driver/xf86-video-intel/src/ivch/ivch_module.c b/driver/xf86-video-intel/src/ivch/ivch_module.c new file mode 100644 index 000000000..1ed483b12 --- /dev/null +++ b/driver/xf86-video-intel/src/ivch/ivch_module.c @@ -0,0 +1,64 @@ +/* -*- c-basic-offset: 4 -*- */ +/* + * Copyright © 2006 Intel Corporation + * + * 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 + * THE AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "xf86Module.h" + +static MODULESETUPPROTO(ivch_setup); + +static XF86ModuleVersionInfo ivch_version = { + "ivch", + MODULEVENDORSTRING, + MODINFOSTRING1, + MODINFOSTRING2, + XORG_VERSION_CURRENT, + 1, 0, 0, + ABI_CLASS_VIDEODRV, + ABI_VIDEODRV_VERSION, + MOD_CLASS_NONE, + { 0,0,0,0 } +}; + +_X_EXPORT XF86ModuleData ivchModuleData = { + &ivch_version, + ivch_setup, + NULL +}; + +static pointer +ivch_setup(pointer module, pointer opts, int *errmaj, int *errmin) +{ + return (pointer)1; +} diff --git a/driver/xf86-video-intel/src/ivch/ivch_reg.h b/driver/xf86-video-intel/src/ivch/ivch_reg.h new file mode 100644 index 000000000..bcd8c56a3 --- /dev/null +++ b/driver/xf86-video-intel/src/ivch/ivch_reg.h @@ -0,0 +1,291 @@ +/* -*- c-basic-offset: 4 -*- */ +/* + * Copyright © 2006 Intel Corporation + * + * 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 + * THE AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +/** @file + * This file contains the register definitions for the i82807aa. + * + * Documentation on this chipset can be found in datasheet #29069001 at + * intel.com. + */ +#ifndef I82807AA_REG_H +#define I82807AA_REG_H + +/** @defgroup VR00 VCH Revision & GMBus Base Addr + * @{ + */ +#define VR00 0x00 +# define VR00_BASE_ADDRESS_MASK 0x007f +/** @} */ + +/** @defgroup VR01 VCH Functionality Enable + * @{ + */ +#define VR01 0x01 +/** + * Enable the panel fitter + */ +# define VR01_PANEL_FIT_ENABLE (1 << 3) +/** + * Enables the LCD display. + * + * This must not be set while VR01_DVO_BYPASS_ENABLE is set. + */ +# define VR01_LCD_ENABLE (1 << 2) +/** Enables the DVO repeater. */ +# define VR01_DVO_BYPASS_ENABLE (1 << 1) +/** Enables the DVO clock */ +# define VR01_DVO_ENABLE (1 << 0) +/** @} */ + +/** @defgroup VR10 LCD Interface Format + * @{ + */ +#define VR10 0x10 +/** Enables LVDS output instead of CMOS */ +# define VR10_LVDS_ENABLE (1 << 4) +/** Enables 18-bit LVDS output. */ +# define VR10_INTERFACE_1X18 (0 << 2) +/** Enables 24-bit LVDS or CMOS output */ +# define VR10_INTERFACE_1X24 (1 << 2) +/** Enables 2x18-bit LVDS or CMOS output. */ +# define VR10_INTERFACE_2X18 (2 << 2) +/** Enables 2x24-bit LVDS output */ +# define VR10_INTERFACE_2X24 (3 << 2) +/** @} */ + +/** @defgroup VR11 CMOS Output Control + * @{ + */ +/** @} */ + +/** @defgroup VR12 LVDS Output Control + * @{ + */ +/** @} */ + +/** @defgroup VR18 PLL clock select + * @{ + */ +/** @} */ + +/** @defgroup VR19 PLL clock divisor M + * @{ + */ +/** @} */ + +/** @defgroup VR1A PLL clock divisor N + * @{ + */ +/** @} */ + +/** @defgroup VR1F FIFO Pre-load + * @{ + */ +/** @} */ + +/** @defgroup VR20 LCD Horizontal Display Size + * @{ + */ +#define VR20 0x20 +/** @} */ + +/** @defgroup VR21 LCD Vertical Display Size + * @{ + */ +#define VR21 0x20 +/** @} */ + +/** @defgroup VR22 Horizontal TRP to DE Start Delay + * @{ + */ +/** @} */ + +/** @defgroup VR23 Horizontal TRP to DE End Delay + * @{ + */ +/** @} */ + +/** @defgroup VR24 Horizontal TRP To LP Start Delay + * @{ + */ +/** @} */ + +/** @defgroup VR25 Horizontal TRP To LP End Delay + * @{ + */ +/** @} */ + +/** @defgroup VR26 Vertical TRP To FLM Start Delay + * @{ + */ +/** @} */ + +/** @defgroup VR27 Vertical TRP To FLM End Delay + * @{ + */ +/** @} */ + +/** @defgroup VR30 Panel power down status + * @{ + */ +#define VR30 0x30 +/** Read only bit indicating that the panel is not in a safe poweroff state. */ +# define VR30_PANEL_ON (1 << 15) +/** @} */ + +/** @defgroup VR31 Tpon Panel power on sequencing delay + * @{ + */ +/** @} */ + +/** @defgroup VR32 Tpon Panel power off sequencing delay + * @{ + */ +/** @} */ + +/** @defgroup VR33 Tstay Panel power off stay down delay + * @{ + */ +/** @} */ + +/** @defgroup VR34 Maximal FLM Pulse Interval + * @{ + */ +/** @} */ + +/** @defgroup VR35 Maximal LP Pulse Interval + * @{ + */ +/** @} */ + +/** @defgroup VR40 + * @{ + */ +#define VR40 0x40 +# define VR40_STALL_ENABLE (1 << 13) +# define VR40_VERTICAL_INTERP_ENABLE (1 << 12) +# define VR40_ENHANCED_PANEL_FITTING (1 << 11) +# define VR40_HORIZONTAL_INTERP_ENABLE (1 << 10) +# define VR40_AUTO_RATIO_ENABLE (1 << 9) +# define VR40_CLOCK_GATING_ENABLE (1 << 8) +/** @} */ + +/** @defgroup VR41 Panel Fitting Vertical Ratio + * @{ + * + * (((image_height - 1) << 16) / ((panel_height - 1))) >> 2 + */ +/** @} */ +#define VR41 0x41 + +/** @defgroup VR42 Panel Fitting Horizontal Ratio + * @{ + * (((image_width - 1) << 16) / ((panel_width - 1))) >> 2 + */ +/** @} */ +#define VR42 0x42 + +/** @defgroup VR43 Horizontal Image Size + * @{ + */ +/** @} */ +#define VR43 0x43 + +/** @defgroup VR44 Panel Fitting Coefficient 0 + * @{ + */ +/** @} */ + +/** @defgroup VR45 Panel Fitting Coefficient 1 + * @{ + */ +/** @} */ + +/** @defgroup VR46 Panel Fitting Coefficient 2 + * @{ + */ +/** @} */ + +/** @defgroup VR47 Panel Fitting Coefficient 3 + * @{ + */ +/** @} */ + +/** @defgroup VR48 Panel Fitting Coefficient 4 + * @{ + */ +/** @} */ + +/** @defgroup VR49 Panel Fitting Coefficient 5 + * @{ + */ +/** @} */ + +/** @defgroup VR80 GPIO 0 + * @{ + */ +/** @} */ + +#define VR80 0x80 +#define VR81 0x81 +#define VR82 0x82 +#define VR83 0x83 +#define VR84 0x84 +#define VR85 0x85 +#define VR86 0x86 +#define VR87 0x87 + +/** @defgroup VR88 GPIO 8 + * @{ + */ +/** @} */ + +#define VR88 0x88 + +/** @defgroup VR8E Graphics BIOS scratch 0 + * @{ + */ +#define VR8E 0x8E +# define VR8E_PANEL_TYPE_MASK (0xf << 0) +# define VR8E_PANEL_INTERFACE_CMOS (0 << 4) +# define VR8E_PANEL_INTERFACE_LVDS (1 << 4) +# define VR8E_FORCE_DEFAULT_PANEL (1 << 5) +/** @} */ + +/** @defgroup VR8F Graphics BIOS scratch 1 + * @{ + */ +#define VR8F 0x8F +# define VR8F_VCH_PRESENT (1 << 0) +# define VR8F_DISPLAY_CONN (1 << 1) +# define VR8F_POWER_MASK (0x3c) +# define VR8F_POWER_POS (2) +/** @} */ + + +#endif /* I82807AA_REG_H */ diff --git a/driver/xf86-video-intel/src/local_xf86Rename.h b/driver/xf86-video-intel/src/local_xf86Rename.h new file mode 100644 index 000000000..e1e788f30 --- /dev/null +++ b/driver/xf86-video-intel/src/local_xf86Rename.h @@ -0,0 +1,23 @@ +/* + * Copyright © 2006 Keith Packard + * + * 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 the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS 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. + */ + +#define XF86NAME(x) intel_##x diff --git a/driver/xf86-video-intel/src/modes/xf86Crtc.c b/driver/xf86-video-intel/src/modes/xf86Crtc.c new file mode 100644 index 000000000..d375da897 --- /dev/null +++ b/driver/xf86-video-intel/src/modes/xf86Crtc.c @@ -0,0 +1,2264 @@ +/* + * Copyright © 2006 Keith Packard + * + * 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 the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS 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. + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#else +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#endif + +#include <stddef.h> +#include <string.h> +#include <stdio.h> + +#include "xf86.h" +#include "xf86DDC.h" +#include "xf86Crtc.h" +#include "xf86Modes.h" +#include "xf86RandR12.h" +#include "X11/extensions/render.h" +#define DPMS_SERVER +#include "X11/extensions/dpms.h" +#include "X11/Xatom.h" +#ifdef RENDER +#include "picturestr.h" +#endif + +#include "xf86xv.h" + +/* + * Initialize xf86CrtcConfig structure + */ + +int xf86CrtcConfigPrivateIndex = -1; + +_X_EXPORT void +xf86CrtcConfigInit (ScrnInfoPtr scrn, + const xf86CrtcConfigFuncsRec *funcs) +{ + xf86CrtcConfigPtr config; + + if (xf86CrtcConfigPrivateIndex == -1) + xf86CrtcConfigPrivateIndex = xf86AllocateScrnInfoPrivateIndex(); + config = xnfcalloc (1, sizeof (xf86CrtcConfigRec)); + + config->funcs = funcs; + + scrn->privates[xf86CrtcConfigPrivateIndex].ptr = config; +} + +_X_EXPORT void +xf86CrtcSetSizeRange (ScrnInfoPtr scrn, + int minWidth, int minHeight, + int maxWidth, int maxHeight) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + + config->minWidth = minWidth; + config->minHeight = minHeight; + config->maxWidth = maxWidth; + config->maxHeight = maxHeight; +} + +/* + * Crtc functions + */ +_X_EXPORT xf86CrtcPtr +xf86CrtcCreate (ScrnInfoPtr scrn, + const xf86CrtcFuncsRec *funcs) +{ + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + xf86CrtcPtr crtc, *crtcs; + + crtc = xcalloc (sizeof (xf86CrtcRec), 1); + if (!crtc) + return NULL; + crtc->scrn = scrn; + crtc->funcs = funcs; +#ifdef RANDR_12_INTERFACE + crtc->randr_crtc = NULL; +#endif + crtc->rotation = RR_Rotate_0; + crtc->desiredRotation = RR_Rotate_0; + if (xf86_config->crtc) + crtcs = xrealloc (xf86_config->crtc, + (xf86_config->num_crtc + 1) * sizeof (xf86CrtcPtr)); + else + crtcs = xalloc ((xf86_config->num_crtc + 1) * sizeof (xf86CrtcPtr)); + if (!crtcs) + { + xfree (crtc); + return NULL; + } + xf86_config->crtc = crtcs; + xf86_config->crtc[xf86_config->num_crtc++] = crtc; + return crtc; +} + +_X_EXPORT void +xf86CrtcDestroy (xf86CrtcPtr crtc) +{ + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); + int c; + + (*crtc->funcs->destroy) (crtc); + for (c = 0; c < xf86_config->num_crtc; c++) + if (xf86_config->crtc[c] == crtc) + { + memmove (&xf86_config->crtc[c], + &xf86_config->crtc[c+1], + ((xf86_config->num_crtc - (c + 1)) * sizeof(void*))); + xf86_config->num_crtc--; + break; + } + xfree (crtc); +} + + +/** + * Return whether any outputs are connected to the specified pipe + */ + +_X_EXPORT Bool +xf86CrtcInUse (xf86CrtcPtr crtc) +{ + ScrnInfoPtr pScrn = crtc->scrn; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + int o; + + for (o = 0; o < xf86_config->num_output; o++) + if (xf86_config->output[o]->crtc == crtc) + return TRUE; + return FALSE; +} + +_X_EXPORT void +xf86CrtcSetScreenSubpixelOrder (ScreenPtr pScreen) +{ +#ifdef RENDER + int subpixel_order = SubPixelUnknown; + Bool has_none = FALSE; + ScrnInfoPtr scrn = xf86Screens[pScreen->myNum]; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + int c, o; + + for (c = 0; c < xf86_config->num_crtc; c++) + { + xf86CrtcPtr crtc = xf86_config->crtc[c]; + + for (o = 0; o < xf86_config->num_output; o++) + { + xf86OutputPtr output = xf86_config->output[o]; + + if (output->crtc == crtc) + { + switch (output->subpixel_order) { + case SubPixelNone: + has_none = TRUE; + break; + case SubPixelUnknown: + break; + default: + subpixel_order = output->subpixel_order; + break; + } + } + if (subpixel_order != SubPixelUnknown) + break; + } + if (subpixel_order != SubPixelUnknown) + { + static const int circle[4] = { + SubPixelHorizontalRGB, + SubPixelVerticalRGB, + SubPixelHorizontalBGR, + SubPixelVerticalBGR, + }; + int rotate; + int c; + for (rotate = 0; rotate < 4; rotate++) + if (crtc->rotation & (1 << rotate)) + break; + for (c = 0; c < 4; c++) + if (circle[c] == subpixel_order) + break; + c = (c + rotate) & 0x3; + if ((crtc->rotation & RR_Reflect_X) && !(c & 1)) + c ^= 2; + if ((crtc->rotation & RR_Reflect_Y) && (c & 1)) + c ^= 2; + subpixel_order = circle[c]; + break; + } + } + if (subpixel_order == SubPixelUnknown && has_none) + subpixel_order = SubPixelNone; + PictureSetSubpixelOrder (pScreen, subpixel_order); +#endif +} + +/** + * Sets the given video mode on the given crtc + */ +_X_EXPORT Bool +xf86CrtcSetMode (xf86CrtcPtr crtc, DisplayModePtr mode, Rotation rotation, + int x, int y) +{ + ScrnInfoPtr scrn = crtc->scrn; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + int i; + Bool ret = FALSE; + Bool didLock = FALSE; + DisplayModePtr adjusted_mode; + DisplayModeRec saved_mode; + int saved_x, saved_y; + Rotation saved_rotation; + + crtc->enabled = xf86CrtcInUse (crtc); + + if (!crtc->enabled) + { + /* XXX disable crtc? */ + return TRUE; + } + + adjusted_mode = xf86DuplicateMode(mode); + + didLock = crtc->funcs->lock (crtc); + + saved_mode = crtc->mode; + saved_x = crtc->x; + saved_y = crtc->y; + saved_rotation = crtc->rotation; + /* Update crtc values up front so the driver can rely on them for mode + * setting. + */ + crtc->mode = *mode; + crtc->x = x; + crtc->y = y; + crtc->rotation = rotation; + + /* XXX short-circuit changes to base location only */ + + /* Pass our mode to the outputs and the CRTC to give them a chance to + * adjust it according to limitations or output properties, and also + * a chance to reject the mode entirely. + */ + for (i = 0; i < xf86_config->num_output; i++) { + xf86OutputPtr output = xf86_config->output[i]; + + if (output->crtc != crtc) + continue; + + if (!output->funcs->mode_fixup(output, mode, adjusted_mode)) { + goto done; + } + } + + if (!crtc->funcs->mode_fixup(crtc, mode, adjusted_mode)) { + goto done; + } + + if (!xf86CrtcRotate (crtc, mode, rotation)) { + goto done; + } + + /* Prepare the outputs and CRTCs before setting the mode. */ + for (i = 0; i < xf86_config->num_output; i++) { + xf86OutputPtr output = xf86_config->output[i]; + + if (output->crtc != crtc) + continue; + + /* Disable the output as the first thing we do. */ + output->funcs->prepare(output); + } + + crtc->funcs->prepare(crtc); + + /* Set up the DPLL and any output state that needs to adjust or depend + * on the DPLL. + */ + crtc->funcs->mode_set(crtc, mode, adjusted_mode, x, y); + for (i = 0; i < xf86_config->num_output; i++) + { + xf86OutputPtr output = xf86_config->output[i]; + if (output->crtc == crtc) + output->funcs->mode_set(output, mode, adjusted_mode); + } + + /* Now, enable the clocks, plane, pipe, and outputs that we set up. */ + crtc->funcs->commit(crtc); + for (i = 0; i < xf86_config->num_output; i++) + { + xf86OutputPtr output = xf86_config->output[i]; + if (output->crtc == crtc) + { + output->funcs->commit(output); +#ifdef RANDR_12_INTERFACE + if (output->randr_output) + RRPostPendingProperties (output->randr_output); +#endif + } + } + + /* XXX free adjustedmode */ + ret = TRUE; + if (scrn->pScreen) + xf86CrtcSetScreenSubpixelOrder (scrn->pScreen); + +done: + if (!ret) { + crtc->x = saved_x; + crtc->y = saved_y; + crtc->rotation = saved_rotation; + crtc->mode = saved_mode; + } + + if (didLock) + crtc->funcs->unlock (crtc); + + return ret; +} + +/* + * Output functions + */ + +extern XF86ConfigPtr xf86configptr; + +typedef enum { + OPTION_PREFERRED_MODE, + OPTION_POSITION, + OPTION_BELOW, + OPTION_RIGHT_OF, + OPTION_ABOVE, + OPTION_LEFT_OF, + OPTION_ENABLE, + OPTION_DISABLE, + OPTION_MIN_CLOCK, + OPTION_MAX_CLOCK, + OPTION_IGNORE, + OPTION_ROTATE, +} OutputOpts; + +static OptionInfoRec xf86OutputOptions[] = { + {OPTION_PREFERRED_MODE, "PreferredMode", OPTV_STRING, {0}, FALSE }, + {OPTION_POSITION, "Position", OPTV_STRING, {0}, FALSE }, + {OPTION_BELOW, "Below", OPTV_STRING, {0}, FALSE }, + {OPTION_RIGHT_OF, "RightOf", OPTV_STRING, {0}, FALSE }, + {OPTION_ABOVE, "Above", OPTV_STRING, {0}, FALSE }, + {OPTION_LEFT_OF, "LeftOf", OPTV_STRING, {0}, FALSE }, + {OPTION_ENABLE, "Enable", OPTV_BOOLEAN, {0}, FALSE }, + {OPTION_DISABLE, "Disable", OPTV_BOOLEAN, {0}, FALSE }, + {OPTION_MIN_CLOCK, "MinClock", OPTV_FREQ, {0}, FALSE }, + {OPTION_MAX_CLOCK, "MaxClock", OPTV_FREQ, {0}, FALSE }, + {OPTION_IGNORE, "Ignore", OPTV_BOOLEAN, {0}, FALSE }, + {OPTION_ROTATE, "Rotate", OPTV_STRING, {0}, FALSE }, + {-1, NULL, OPTV_NONE, {0}, FALSE }, +}; + +enum { + OPTION_MODEDEBUG, +}; + +static OptionInfoRec xf86DeviceOptions[] = { + {OPTION_MODEDEBUG, "ModeDebug", OPTV_STRING, {0}, FALSE }, + {-1, NULL, OPTV_NONE, {0}, FALSE }, +}; + +static void +xf86OutputSetMonitor (xf86OutputPtr output) +{ + char *option_name; + static const char monitor_prefix[] = "monitor-"; + char *monitor; + + if (!output->name) + return; + + if (output->options) + xfree (output->options); + + output->options = xnfalloc (sizeof (xf86OutputOptions)); + memcpy (output->options, xf86OutputOptions, sizeof (xf86OutputOptions)); + + option_name = xnfalloc (strlen (monitor_prefix) + + strlen (output->name) + 1); + strcpy (option_name, monitor_prefix); + strcat (option_name, output->name); + monitor = xf86findOptionValue (output->scrn->options, option_name); + if (!monitor) + monitor = output->name; + else + xf86MarkOptionUsedByName (output->scrn->options, option_name); + xfree (option_name); + output->conf_monitor = xf86findMonitor (monitor, + xf86configptr->conf_monitor_lst); + /* + * Find the monitor section of the screen and use that + */ + if (!output->conf_monitor && output->use_screen_monitor) + output->conf_monitor = xf86findMonitor (output->scrn->monitor->id, + xf86configptr->conf_monitor_lst); + if (output->conf_monitor) + { + xf86DrvMsg (output->scrn->scrnIndex, X_INFO, + "Output %s using monitor section %s\n", + output->name, output->conf_monitor->mon_identifier); + xf86ProcessOptions (output->scrn->scrnIndex, + output->conf_monitor->mon_option_lst, + output->options); + } + else + xf86DrvMsg (output->scrn->scrnIndex, X_INFO, + "Output %s has no monitor section\n", + output->name); +} + +static Bool +xf86OutputEnabled (xf86OutputPtr output) +{ + Bool enable, disable; + + /* check to see if this output was enabled in the config file */ + if (xf86GetOptValBool (output->options, OPTION_ENABLE, &enable) && enable) + { + xf86DrvMsg (output->scrn->scrnIndex, X_INFO, + "Output %s enabled by config file\n", output->name); + return TRUE; + } + /* or if this output was disabled in the config file */ + if (xf86GetOptValBool (output->options, OPTION_DISABLE, &disable) && disable) + { + xf86DrvMsg (output->scrn->scrnIndex, X_INFO, + "Output %s disabled by config file\n", output->name); + return FALSE; + } + /* otherwise, enable if it is not disconnected */ + enable = output->status != XF86OutputStatusDisconnected; + xf86DrvMsg (output->scrn->scrnIndex, X_INFO, + "Output %s %sconnected\n", output->name, enable ? "" : "dis"); + return enable; +} + +static Bool +xf86OutputIgnored (xf86OutputPtr output) +{ + return xf86ReturnOptValBool (output->options, OPTION_IGNORE, FALSE); +} + +static char *direction[4] = { + "normal", + "left", + "inverted", + "right" +}; + +static Rotation +xf86OutputInitialRotation (xf86OutputPtr output) +{ + char *rotate_name = xf86GetOptValString (output->options, + OPTION_ROTATE); + int i; + + if (!rotate_name) + return RR_Rotate_0; + + for (i = 0; i < 4; i++) + if (xf86nameCompare (direction[i], rotate_name) == 0) + return (1 << i); + return RR_Rotate_0; +} + +_X_EXPORT xf86OutputPtr +xf86OutputCreate (ScrnInfoPtr scrn, + const xf86OutputFuncsRec *funcs, + const char *name) +{ + xf86OutputPtr output, *outputs; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + int len; + + if (name) + len = strlen (name) + 1; + else + len = 0; + + output = xcalloc (sizeof (xf86OutputRec) + len, 1); + if (!output) + return NULL; + output->scrn = scrn; + output->funcs = funcs; + if (name) + { + output->name = (char *) (output + 1); + strcpy (output->name, name); + } + output->subpixel_order = SubPixelUnknown; + /* + * Use the old per-screen monitor section for the first output + */ + output->use_screen_monitor = (xf86_config->num_output == 0); +#ifdef RANDR_12_INTERFACE + output->randr_output = NULL; +#endif + if (name) + { + xf86OutputSetMonitor (output); + if (xf86OutputIgnored (output)) + { + xfree (output); + return FALSE; + } + } + + + if (xf86_config->output) + outputs = xrealloc (xf86_config->output, + (xf86_config->num_output + 1) * sizeof (xf86OutputPtr)); + else + outputs = xalloc ((xf86_config->num_output + 1) * sizeof (xf86OutputPtr)); + if (!outputs) + { + xfree (output); + return NULL; + } + + xf86_config->output = outputs; + xf86_config->output[xf86_config->num_output++] = output; + + return output; +} + +_X_EXPORT Bool +xf86OutputRename (xf86OutputPtr output, const char *name) +{ + int len = strlen(name) + 1; + char *newname = xalloc (len); + + if (!newname) + return FALSE; /* so sorry... */ + + strcpy (newname, name); + if (output->name && output->name != (char *) (output + 1)) + xfree (output->name); + output->name = newname; + xf86OutputSetMonitor (output); + if (xf86OutputIgnored (output)) + return FALSE; + return TRUE; +} + +_X_EXPORT void +xf86OutputUseScreenMonitor (xf86OutputPtr output, Bool use_screen_monitor) +{ + if (use_screen_monitor != output->use_screen_monitor) + { + output->use_screen_monitor = use_screen_monitor; + xf86OutputSetMonitor (output); + } +} + +_X_EXPORT void +xf86OutputDestroy (xf86OutputPtr output) +{ + ScrnInfoPtr scrn = output->scrn; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + int o; + + (*output->funcs->destroy) (output); + while (output->probed_modes) + xf86DeleteMode (&output->probed_modes, output->probed_modes); + for (o = 0; o < xf86_config->num_output; o++) + if (xf86_config->output[o] == output) + { + memmove (&xf86_config->output[o], + &xf86_config->output[o+1], + ((xf86_config->num_output - (o + 1)) * sizeof(void*))); + xf86_config->num_output--; + break; + } + if (output->name && output->name != (char *) (output + 1)) + xfree (output->name); + xfree (output); +} + +/* + * Called during CreateScreenResources to hook up RandR + */ +static Bool +xf86CrtcCreateScreenResources (ScreenPtr screen) +{ + ScrnInfoPtr scrn = xf86Screens[screen->myNum]; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + + screen->CreateScreenResources = config->CreateScreenResources; + + if (!(*screen->CreateScreenResources)(screen)) + return FALSE; + + if (!xf86RandR12CreateScreenResources (screen)) + return FALSE; + + return TRUE; +} + +/* + * Clean up config on server reset + */ +static Bool +xf86CrtcCloseScreen (int index, ScreenPtr screen) +{ + ScrnInfoPtr scrn = xf86Screens[screen->myNum]; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + int o, c; + + screen->CloseScreen = config->CloseScreen; + + xf86RotateCloseScreen (screen); + + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + + output->randr_output = NULL; + } + for (c = 0; c < config->num_crtc; c++) + { + xf86CrtcPtr crtc = config->crtc[c]; + + crtc->randr_crtc = NULL; + } + return screen->CloseScreen (index, screen); +} + +/* + * Called at ScreenInit time to set up + */ +_X_EXPORT Bool +xf86CrtcScreenInit (ScreenPtr screen) +{ + ScrnInfoPtr scrn = xf86Screens[screen->myNum]; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + int c; + + /* Rotation */ + xf86DrvMsg(scrn->scrnIndex, X_INFO, "RandR 1.2 enabled, ignore the following RandR disabled message.\n"); + xf86DisableRandR(); /* Disable old RandR extension support */ + xf86RandR12Init (screen); + + /* support all rotations if every crtc has the shadow alloc funcs */ + for (c = 0; c < config->num_crtc; c++) + { + xf86CrtcPtr crtc = config->crtc[c]; + if (!crtc->funcs->shadow_allocate || !crtc->funcs->shadow_create) + break; + } + if (c == config->num_crtc) + xf86RandR12SetRotations (screen, RR_Rotate_0 | RR_Rotate_90 | + RR_Rotate_180 | RR_Rotate_270 | + RR_Reflect_X | RR_Reflect_Y); + else + xf86RandR12SetRotations (screen, RR_Rotate_0); + + /* Wrap CreateScreenResources so we can initialize the RandR code */ + config->CreateScreenResources = screen->CreateScreenResources; + screen->CreateScreenResources = xf86CrtcCreateScreenResources; + + config->CloseScreen = screen->CloseScreen; + screen->CloseScreen = xf86CrtcCloseScreen; + + return TRUE; +} + +static DisplayModePtr +xf86DefaultMode (xf86OutputPtr output, int width, int height) +{ + DisplayModePtr target_mode = NULL; + DisplayModePtr mode; + int target_diff = 0; + int target_preferred = 0; + int mm_height; + + mm_height = output->mm_height; + if (!mm_height) + mm_height = 203; /* 768 pixels at 96dpi */ + /* + * Pick a mode closest to 96dpi + */ + for (mode = output->probed_modes; mode; mode = mode->next) + { + int dpi; + int preferred = (mode->type & M_T_PREFERRED) != 0; + int diff; + + if (xf86ModeWidth (mode, output->initial_rotation) > width || + xf86ModeHeight (mode, output->initial_rotation) > height) + continue; + + /* yes, use VDisplay here, not xf86ModeHeight */ + dpi = (mode->VDisplay * 254) / (mm_height * 10); + diff = dpi - 96; + diff = diff < 0 ? -diff : diff; + if (target_mode == NULL || (preferred > target_preferred) || + (preferred == target_preferred && diff < target_diff)) + { + target_mode = mode; + target_diff = diff; + target_preferred = preferred; + } + } + return target_mode; +} + +static DisplayModePtr +xf86ClosestMode (xf86OutputPtr output, + DisplayModePtr match, Rotation match_rotation, + int width, int height) +{ + DisplayModePtr target_mode = NULL; + DisplayModePtr mode; + int target_diff = 0; + + /* + * Pick a mode closest to the specified mode + */ + for (mode = output->probed_modes; mode; mode = mode->next) + { + int dx, dy; + int diff; + + if (xf86ModeWidth (mode, output->initial_rotation) > width || + xf86ModeHeight (mode, output->initial_rotation) > height) + continue; + + /* exact matches are preferred */ + if (output->initial_rotation == match_rotation && + xf86ModesEqual (mode, match)) + return mode; + + dx = xf86ModeWidth (match, match_rotation) - xf86ModeWidth (mode, output->initial_rotation); + dy = xf86ModeHeight (match, match_rotation) - xf86ModeHeight (mode, output->initial_rotation); + diff = dx * dx + dy * dy; + if (target_mode == NULL || diff < target_diff) + { + target_mode = mode; + target_diff = diff; + } + } + return target_mode; +} + +static Bool +xf86OutputHasPreferredMode (xf86OutputPtr output, int width, int height) +{ + DisplayModePtr mode; + + for (mode = output->probed_modes; mode; mode = mode->next) + { + if (xf86ModeWidth (mode, output->initial_rotation) > width || + xf86ModeHeight (mode, output->initial_rotation) > height) + continue; + + if (mode->type & M_T_PREFERRED) + return TRUE; + } + return FALSE; +} + +static int +xf86PickCrtcs (ScrnInfoPtr scrn, + xf86CrtcPtr *best_crtcs, + DisplayModePtr *modes, + int n, + int width, + int height) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + int c, o; + xf86OutputPtr output; + xf86CrtcPtr crtc; + xf86CrtcPtr *crtcs; + xf86CrtcPtr best_crtc; + int best_score; + int score; + int my_score; + + if (n == config->num_output) + return 0; + output = config->output[n]; + + /* + * Compute score with this output disabled + */ + best_crtcs[n] = NULL; + best_crtc = NULL; + best_score = xf86PickCrtcs (scrn, best_crtcs, modes, n+1, width, height); + if (modes[n] == NULL) + return best_score; + + crtcs = xalloc (config->num_output * sizeof (xf86CrtcPtr)); + if (!crtcs) + return best_score; + + my_score = 1; + /* Score outputs that are known to be connected higher */ + if (output->status == XF86OutputStatusConnected) + my_score++; + /* Score outputs with preferred modes higher */ + if (xf86OutputHasPreferredMode (output, width, height)) + my_score++; + /* + * Select a crtc for this output and + * then attempt to configure the remaining + * outputs + */ + for (c = 0; c < config->num_crtc; c++) + { + if ((output->possible_crtcs & (1 << c)) == 0) + continue; + + crtc = config->crtc[c]; + /* + * Check to see if some other output is + * using this crtc + */ + for (o = 0; o < n; o++) + if (best_crtcs[o] == crtc) + break; + if (o < n) + { + /* + * If the two outputs desire the same mode, + * see if they can be cloned + */ + if (xf86ModesEqual (modes[o], modes[n]) && + config->output[0]->initial_rotation == config->output[n]->initial_rotation && + config->output[o]->initial_x == config->output[n]->initial_x && + config->output[o]->initial_y == config->output[n]->initial_y) + { + if ((output->possible_clones & (1 << o)) == 0) + continue; /* nope, try next CRTC */ + } + else + continue; /* different modes, can't clone */ + } + crtcs[n] = crtc; + memcpy (crtcs, best_crtcs, n * sizeof (xf86CrtcPtr)); + score = my_score + xf86PickCrtcs (scrn, crtcs, modes, n+1, width, height); + if (score > best_score) + { + best_crtc = crtc; + best_score = score; + memcpy (best_crtcs, crtcs, config->num_output * sizeof (xf86CrtcPtr)); + } + } + xfree (crtcs); + return best_score; +} + + +/* + * Compute the virtual size necessary to place all of the available + * crtcs in the specified configuration. + * + * canGrow indicates that the driver can make the screen larger than its initial + * configuration. If FALSE, this function will enlarge the screen to include + * the largest available mode. + */ + +static void +xf86DefaultScreenLimits (ScrnInfoPtr scrn, int *widthp, int *heightp, + Bool canGrow) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + int width = 0, height = 0; + int o; + int c; + int s; + + for (c = 0; c < config->num_crtc; c++) + { + int crtc_width = 0, crtc_height = 0; + xf86CrtcPtr crtc = config->crtc[c]; + + if (crtc->enabled) + { + crtc_width = crtc->x + xf86ModeWidth (&crtc->desiredMode, crtc->desiredRotation); + crtc_height = crtc->y + xf86ModeHeight (&crtc->desiredMode, crtc->desiredRotation); + } + if (!canGrow) { + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + + for (s = 0; s < config->num_crtc; s++) + if (output->possible_crtcs & (1 << s)) + { + DisplayModePtr mode; + for (mode = output->probed_modes; mode; mode = mode->next) + { + if (mode->HDisplay > crtc_width) + crtc_width = mode->HDisplay; + if (mode->VDisplay > crtc_width) + crtc_width = mode->VDisplay; + if (mode->VDisplay > crtc_height) + crtc_height = mode->VDisplay; + if (mode->HDisplay > crtc_height) + crtc_height = mode->HDisplay; + } + } + } + } + if (crtc_width > width) + width = crtc_width; + if (crtc_height > height) + height = crtc_height; + } + if (config->maxWidth && width > config->maxWidth) width = config->maxWidth; + if (config->maxHeight && height > config->maxHeight) height = config->maxHeight; + if (config->minWidth && width < config->minWidth) width = config->minWidth; + if (config->minHeight && height < config->minHeight) height = config->minHeight; + *widthp = width; + *heightp = height; +} + +#define POSITION_UNSET -100000 + +static Bool +xf86InitialOutputPositions (ScrnInfoPtr scrn, DisplayModePtr *modes) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + int o; + int min_x, min_y; + + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + + output->initial_x = output->initial_y = POSITION_UNSET; + } + + /* + * Loop until all outputs are set + */ + for (;;) + { + Bool any_set = FALSE; + Bool keep_going = FALSE; + + for (o = 0; o < config->num_output; o++) + { + static const OutputOpts relations[] = { + OPTION_BELOW, OPTION_RIGHT_OF, OPTION_ABOVE, OPTION_LEFT_OF + }; + xf86OutputPtr output = config->output[o]; + xf86OutputPtr relative; + char *relative_name; + char *position; + OutputOpts relation; + int r; + + if (output->initial_x != POSITION_UNSET) + continue; + position = xf86GetOptValString (output->options, + OPTION_POSITION); + /* + * Absolute position wins + */ + if (position) + { + int x, y; + if (sscanf (position, "%d %d", &x, &y) == 2) + { + output->initial_x = x; + output->initial_y = y; + } + else + { + xf86DrvMsg (scrn->scrnIndex, X_ERROR, + "Output %s position not of form \"x y\"\n", + output->name); + output->initial_x = output->initial_y = 0; + } + any_set = TRUE; + continue; + } + /* + * Next comes relative positions + */ + relation = 0; + relative_name = NULL; + for (r = 0; r < 4; r++) + { + relation = relations[r]; + relative_name = xf86GetOptValString (output->options, + relation); + if (relative_name) + break; + } + if (relative_name) + { + int or; + relative = NULL; + for (or = 0; or < config->num_output; or++) + { + xf86OutputPtr out_rel = config->output[or]; + XF86ConfMonitorPtr rel_mon = out_rel->conf_monitor; + + if (rel_mon) + { + if (xf86nameCompare (rel_mon->mon_identifier, + relative_name) == 0) + { + relative = config->output[or]; + break; + } + } + if (strcmp (out_rel->name, relative_name) == 0) + { + relative = config->output[or]; + break; + } + } + if (!relative) + { + xf86DrvMsg (scrn->scrnIndex, X_ERROR, + "Cannot position output %s relative to unknown output %s\n", + output->name, relative_name); + output->initial_x = 0; + output->initial_y = 0; + any_set = TRUE; + continue; + } + if (relative->initial_x == POSITION_UNSET) + { + keep_going = TRUE; + continue; + } + output->initial_x = relative->initial_x; + output->initial_y = relative->initial_y; + switch (relation) { + case OPTION_BELOW: + output->initial_y += xf86ModeHeight (modes[or], relative->initial_rotation); + break; + case OPTION_RIGHT_OF: + output->initial_x += xf86ModeWidth (modes[or], relative->initial_rotation); + break; + case OPTION_ABOVE: + output->initial_y -= xf86ModeHeight (modes[or], relative->initial_rotation); + break; + case OPTION_LEFT_OF: + output->initial_x -= xf86ModeWidth (modes[or], relative->initial_rotation); + break; + default: + break; + } + any_set = TRUE; + continue; + } + + /* Nothing set, just stick them at 0,0 */ + output->initial_x = 0; + output->initial_y = 0; + any_set = TRUE; + } + if (!keep_going) + break; + if (!any_set) + { + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + if (output->initial_x == POSITION_UNSET) + { + xf86DrvMsg (scrn->scrnIndex, X_ERROR, + "Output position loop. Moving %s to 0,0\n", + output->name); + output->initial_x = output->initial_y = 0; + break; + } + } + } + } + + /* + * normalize positions + */ + min_x = 1000000; + min_y = 1000000; + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + + if (output->initial_x < min_x) + min_x = output->initial_x; + if (output->initial_y < min_y) + min_y = output->initial_y; + } + + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + + output->initial_x -= min_x; + output->initial_y -= min_y; + } + return TRUE; +} + +/* + * XXX walk the monitor mode list and prune out duplicates that + * are inserted by xf86DDCMonitorSet. In an ideal world, that + * function would do this work by itself. + */ + +static void +xf86PruneDuplicateMonitorModes (MonPtr Monitor) +{ + DisplayModePtr master, clone, next; + + for (master = Monitor->Modes; + master && master != Monitor->Last; + master = master->next) + { + for (clone = master->next; clone && clone != Monitor->Modes; clone = next) + { + next = clone->next; + if (xf86ModesEqual (master, clone)) + { + if (Monitor->Last == clone) + Monitor->Last = clone->prev; + xf86DeleteMode (&Monitor->Modes, clone); + } + } + } +} + +/** Return - 0 + if a should be earlier, same or later than b in list + */ +static int +xf86ModeCompare (DisplayModePtr a, DisplayModePtr b) +{ + int diff; + + diff = ((b->type & M_T_PREFERRED) != 0) - ((a->type & M_T_PREFERRED) != 0); + if (diff) + return diff; + diff = b->HDisplay * b->VDisplay - a->HDisplay * a->VDisplay; + if (diff) + return diff; + diff = b->Clock - a->Clock; + return diff; +} + +/** + * Insertion sort input in-place and return the resulting head + */ +static DisplayModePtr +xf86SortModes (DisplayModePtr input) +{ + DisplayModePtr output = NULL, i, o, n, *op, prev; + + /* sort by preferred status and pixel area */ + while (input) + { + i = input; + input = input->next; + for (op = &output; (o = *op); op = &o->next) + if (xf86ModeCompare (o, i) > 0) + break; + i->next = *op; + *op = i; + } + /* prune identical modes */ + for (o = output; o && (n = o->next); o = n) + { + if (!strcmp (o->name, n->name) && xf86ModesEqual (o, n)) + { + o->next = n->next; + xfree (n->name); + xfree (n); + n = o; + } + } + /* hook up backward links */ + prev = NULL; + for (o = output; o; o = o->next) + { + o->prev = prev; + prev = o; + } + return output; +} + +_X_EXPORT void +xf86ProbeOutputModes (ScrnInfoPtr scrn, int maxX, int maxY) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + int o; + + /* When canGrow was TRUE in the initial configuration we have to + * compare against the maximum values so that we don't drop modes. + * When canGrow was FALSE, the maximum values would have been clamped + * anyway. + */ + if (maxX == 0 || maxY == 0) { + maxX = config->maxWidth; + maxY = config->maxHeight; + } + + /* Elide duplicate modes before defaulting code uses them */ + xf86PruneDuplicateMonitorModes (scrn->monitor); + + /* Probe the list of modes for each output. */ + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + DisplayModePtr mode; + DisplayModePtr config_modes = NULL, output_modes, default_modes; + char *preferred_mode; + xf86MonPtr edid_monitor; + XF86ConfMonitorPtr conf_monitor; + MonRec mon_rec; + int min_clock = 0; + int max_clock = 0; + double clock; + enum { sync_config, sync_edid, sync_default } sync_source = sync_default; + + while (output->probed_modes != NULL) + xf86DeleteMode(&output->probed_modes, output->probed_modes); + + /* + * Check connection status + */ + output->status = (*output->funcs->detect)(output); + + if (output->status == XF86OutputStatusDisconnected) + { + xf86OutputSetEDID (output, NULL); + continue; + } + + memset (&mon_rec, '\0', sizeof (mon_rec)); + + conf_monitor = output->conf_monitor; + + if (conf_monitor) + { + int i; + + for (i = 0; i < conf_monitor->mon_n_hsync; i++) + { + mon_rec.hsync[mon_rec.nHsync].lo = conf_monitor->mon_hsync[i].lo; + mon_rec.hsync[mon_rec.nHsync].hi = conf_monitor->mon_hsync[i].hi; + mon_rec.nHsync++; + sync_source = sync_config; + } + for (i = 0; i < conf_monitor->mon_n_vrefresh; i++) + { + mon_rec.vrefresh[mon_rec.nVrefresh].lo = conf_monitor->mon_vrefresh[i].lo; + mon_rec.vrefresh[mon_rec.nVrefresh].hi = conf_monitor->mon_vrefresh[i].hi; + mon_rec.nVrefresh++; + sync_source = sync_config; + } + config_modes = xf86GetMonitorModes (scrn, conf_monitor); + } + + output_modes = (*output->funcs->get_modes) (output); + + edid_monitor = output->MonInfo; + + if (edid_monitor) + { + int i; + Bool set_hsync = mon_rec.nHsync == 0; + Bool set_vrefresh = mon_rec.nVrefresh == 0; + + for (i = 0; i < sizeof (edid_monitor->det_mon) / sizeof (edid_monitor->det_mon[0]); i++) + { + if (edid_monitor->det_mon[i].type == DS_RANGES) + { + struct monitor_ranges *ranges = &edid_monitor->det_mon[i].section.ranges; + if (set_hsync && ranges->max_h) + { + mon_rec.hsync[mon_rec.nHsync].lo = ranges->min_h; + mon_rec.hsync[mon_rec.nHsync].hi = ranges->max_h; + mon_rec.nHsync++; + if (sync_source == sync_default) + sync_source = sync_edid; + } + if (set_vrefresh && ranges->max_v) + { + mon_rec.vrefresh[mon_rec.nVrefresh].lo = ranges->min_v; + mon_rec.vrefresh[mon_rec.nVrefresh].hi = ranges->max_v; + mon_rec.nVrefresh++; + if (sync_source == sync_default) + sync_source = sync_edid; + } + if (ranges->max_clock > max_clock) + max_clock = ranges->max_clock; + } + } + } + + if (xf86GetOptValFreq (output->options, OPTION_MIN_CLOCK, + OPTUNITS_KHZ, &clock)) + min_clock = (int) clock; + if (xf86GetOptValFreq (output->options, OPTION_MAX_CLOCK, + OPTUNITS_KHZ, &clock)) + max_clock = (int) clock; + + /* + * These limits will end up setting a 1024x768@60Hz mode by default, + * which seems like a fairly good mode to use when nothing else is + * specified + */ + if (mon_rec.nHsync == 0) + { + mon_rec.hsync[0].lo = 31.0; + mon_rec.hsync[0].hi = 55.0; + mon_rec.nHsync = 1; + } + if (mon_rec.nVrefresh == 0) + { + mon_rec.vrefresh[0].lo = 58.0; + mon_rec.vrefresh[0].hi = 62.0; + mon_rec.nVrefresh = 1; + } + default_modes = xf86GetDefaultModes (output->interlaceAllowed, + output->doubleScanAllowed); + + if (sync_source == sync_config) + { + /* + * Check output and config modes against sync range from config file + */ + xf86ValidateModesSync (scrn, output_modes, &mon_rec); + xf86ValidateModesSync (scrn, config_modes, &mon_rec); + } + /* + * Check default modes against sync range + */ + xf86ValidateModesSync (scrn, default_modes, &mon_rec); + /* + * Check default modes against monitor max clock + */ + if (max_clock) + xf86ValidateModesClocks(scrn, default_modes, + &min_clock, &max_clock, 1); + + output->probed_modes = NULL; + output->probed_modes = xf86ModesAdd (output->probed_modes, config_modes); + output->probed_modes = xf86ModesAdd (output->probed_modes, output_modes); + output->probed_modes = xf86ModesAdd (output->probed_modes, default_modes); + + /* + * Check all modes against max size + */ + if (maxX && maxY) + xf86ValidateModesSize (scrn, output->probed_modes, + maxX, maxY, 0); + + /* + * Check all modes against output + */ + for (mode = output->probed_modes; mode != NULL; mode = mode->next) + if (mode->status == MODE_OK) + mode->status = (*output->funcs->mode_valid)(output, mode); + + xf86PruneInvalidModes(scrn, &output->probed_modes, + config->debug_modes); + + output->probed_modes = xf86SortModes (output->probed_modes); + + /* Check for a configured preference for a particular mode */ + preferred_mode = xf86GetOptValString (output->options, + OPTION_PREFERRED_MODE); + + if (preferred_mode) + { + for (mode = output->probed_modes; mode; mode = mode->next) + { + if (!strcmp (preferred_mode, mode->name)) + { + if (mode != output->probed_modes) + { + if (mode->prev) + mode->prev->next = mode->next; + if (mode->next) + mode->next->prev = mode->prev; + mode->next = output->probed_modes; + output->probed_modes->prev = mode; + mode->prev = NULL; + output->probed_modes = mode; + } + mode->type |= M_T_PREFERRED; + } + else + mode->type &= ~M_T_PREFERRED; + } + } + + output->initial_rotation = xf86OutputInitialRotation (output); + + if (config->debug_modes) { + if (output->probed_modes != NULL) { + xf86DrvMsg(scrn->scrnIndex, X_INFO, + "Printing probed modes for output %s\n", + output->name); + } else { + xf86DrvMsg(scrn->scrnIndex, X_INFO, + "No remaining probed modes for output %s\n", + output->name); + } + } + for (mode = output->probed_modes; mode != NULL; mode = mode->next) + { + /* The code to choose the best mode per pipe later on will require + * VRefresh to be set. + */ + mode->VRefresh = xf86ModeVRefresh(mode); + xf86SetModeCrtc(mode, INTERLACE_HALVE_V); + + if (config->debug_modes) + xf86PrintModeline(scrn->scrnIndex, mode); + } + } +} + + +/** + * Copy one of the output mode lists to the ScrnInfo record + */ + +/* XXX where does this function belong? Here? */ +_X_EXPORT void +xf86RandR12GetOriginalVirtualSize(ScrnInfoPtr scrn, int *x, int *y); + +_X_EXPORT void +xf86SetScrnInfoModes (ScrnInfoPtr scrn) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + xf86OutputPtr output; + xf86CrtcPtr crtc; + DisplayModePtr last, mode; + + output = config->output[config->compat_output]; + if (!output->crtc) + { + int o; + + output = NULL; + for (o = 0; o < config->num_output; o++) + if (config->output[o]->crtc) + { + config->compat_output = o; + output = config->output[o]; + break; + } + /* no outputs are active, punt and leave things as they are */ + if (!output) + return; + } + crtc = output->crtc; + + /* Clear any existing modes from scrn->modes */ + while (scrn->modes != NULL) + xf86DeleteMode(&scrn->modes, scrn->modes); + + /* Set scrn->modes to the mode list for the 'compat' output */ + scrn->modes = xf86DuplicateModes(scrn, output->probed_modes); + + for (mode = scrn->modes; mode; mode = mode->next) + if (xf86ModesEqual (mode, &crtc->desiredMode)) + break; + + if (scrn->modes != NULL) { + /* For some reason, scrn->modes is circular, unlike the other mode + * lists. How great is that? + */ + for (last = scrn->modes; last && last->next; last = last->next) + ; + last->next = scrn->modes; + scrn->modes->prev = last; + if (mode) { + while (scrn->modes != mode) + scrn->modes = scrn->modes->next; + } + } + scrn->currentMode = scrn->modes; +} + +/** + * Construct default screen configuration + * + * Given auto-detected (and, eventually, configured) values, + * construct a usable configuration for the system + * + * canGrow indicates that the driver can resize the screen to larger than its + * initially configured size via the config->funcs->resize hook. If TRUE, this + * function will set virtualX and virtualY to match the initial configuration + * and leave config->max{Width,Height} alone. If FALSE, it will bloat + * virtual[XY] to include the largest modes and set config->max{Width,Height} + * accordingly. + */ + +_X_EXPORT Bool +xf86InitialConfiguration (ScrnInfoPtr scrn, Bool canGrow) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + int o, c; + DisplayModePtr target_mode = NULL; + Rotation target_rotation = RR_Rotate_0; + xf86CrtcPtr *crtcs; + DisplayModePtr *modes; + Bool *enabled; + int width; + int height; + + /* Set up the device options */ + config->options = xnfalloc (sizeof (xf86DeviceOptions)); + memcpy (config->options, xf86DeviceOptions, sizeof (xf86DeviceOptions)); + xf86ProcessOptions (scrn->scrnIndex, + scrn->options, + config->options); + config->debug_modes = xf86ReturnOptValBool (config->options, + OPTION_MODEDEBUG, FALSE); + + if (scrn->display->virtualX) + width = scrn->display->virtualX; + else + width = config->maxWidth; + if (scrn->display->virtualY) + height = scrn->display->virtualY; + else + height = config->maxHeight; + + xf86ProbeOutputModes (scrn, width, height); + + crtcs = xnfcalloc (config->num_output, sizeof (xf86CrtcPtr)); + modes = xnfcalloc (config->num_output, sizeof (DisplayModePtr)); + enabled = xnfcalloc (config->num_output, sizeof (Bool)); + + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + + modes[o] = NULL; + enabled[o] = xf86OutputEnabled (output); + } + + /* + * Let outputs with preferred modes drive screen size + */ + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + + if (enabled[o] && + xf86OutputHasPreferredMode (output, width, height)) + { + target_mode = xf86DefaultMode (output, width, height); + target_rotation = output->initial_rotation; + if (target_mode) + { + modes[o] = target_mode; + config->compat_output = o; + break; + } + } + } + if (!target_mode) + { + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + if (enabled[o]) + { + target_mode = xf86DefaultMode (output, width, height); + target_rotation = output->initial_rotation; + if (target_mode) + { + modes[o] = target_mode; + config->compat_output = o; + break; + } + } + } + } + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + + if (enabled[o]) + { + if (!modes[o]) + modes[o] = xf86ClosestMode (output, target_mode, + target_rotation, width, height); + if (!modes[o]) + xf86DrvMsg (scrn->scrnIndex, X_ERROR, + "Output %s enabled but has no modes\n", + output->name); + else + xf86DrvMsg (scrn->scrnIndex, X_INFO, + "Output %s using initial mode %s\n", + output->name, modes[o]->name); + } + } + + /* + * Set the position of each output + */ + if (!xf86InitialOutputPositions (scrn, modes)) + { + xfree (crtcs); + xfree (modes); + return FALSE; + } + + /* + * Assign CRTCs to fit output configuration + */ + if (!xf86PickCrtcs (scrn, crtcs, modes, 0, width, height)) + { + xfree (crtcs); + xfree (modes); + return FALSE; + } + + /* XXX override xf86 common frame computation code */ + + scrn->display->frameX0 = 0; + scrn->display->frameY0 = 0; + + for (c = 0; c < config->num_crtc; c++) + { + xf86CrtcPtr crtc = config->crtc[c]; + + crtc->enabled = FALSE; + memset (&crtc->desiredMode, '\0', sizeof (crtc->desiredMode)); + } + + /* + * Set initial configuration + */ + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + DisplayModePtr mode = modes[o]; + xf86CrtcPtr crtc = crtcs[o]; + + if (mode && crtc) + { + crtc->desiredMode = *mode; + crtc->desiredRotation = output->initial_rotation; + crtc->desiredX = output->initial_x; + crtc->desiredY = output->initial_y; + crtc->enabled = TRUE; + crtc->x = output->initial_x; + crtc->y = output->initial_y; + output->crtc = crtc; + } + } + + if (scrn->display->virtualX == 0) + { + /* + * Expand virtual size to cover the current config and potential mode + * switches, if the driver can't enlarge the screen later. + */ + xf86DefaultScreenLimits (scrn, &width, &height, canGrow); + + scrn->display->virtualX = width; + scrn->display->virtualY = height; + } + + if (width > scrn->virtualX) + scrn->virtualX = width; + if (height > scrn->virtualY) + scrn->virtualY = height; + + /* + * Make sure the configuration isn't too small. + */ + if (width < config->minWidth || height < config->minHeight) + return FALSE; + + /* + * Limit the crtc config to virtual[XY] if the driver can't grow the + * desktop. + */ + if (!canGrow) + { + xf86CrtcSetSizeRange (scrn, config->minWidth, config->minHeight, + width, height); + } + + /* Mirror output modes to scrn mode list */ + xf86SetScrnInfoModes (scrn); + + xfree (crtcs); + xfree (modes); + return TRUE; +} + +/* + * Using the desired mode information in each crtc, set + * modes (used in EnterVT functions, or at server startup) + */ + +_X_EXPORT Bool +xf86SetDesiredModes (ScrnInfoPtr scrn) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + int c, o; + + /* + * Turn off everything so mode setting is done + * with hardware in a consistent state + */ + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + (*output->funcs->dpms)(output, DPMSModeOff); + } + + for (c = 0; c < config->num_crtc; c++) + { + xf86CrtcPtr crtc = config->crtc[c]; + + crtc->funcs->dpms(crtc, DPMSModeOff); + memset(&crtc->mode, 0, sizeof(crtc->mode)); + } + + for (c = 0; c < config->num_crtc; c++) + { + xf86CrtcPtr crtc = config->crtc[c]; + xf86OutputPtr output = NULL; + int o; + + if (config->output[config->compat_output]->crtc == crtc) + output = config->output[config->compat_output]; + else + { + for (o = 0; o < config->num_output; o++) + if (config->output[o]->crtc == crtc) + { + output = config->output[o]; + break; + } + } + /* + * Skip disabled crtcs + */ + if (!output) + continue; + + /* Mark that we'll need to re-set the mode for sure */ + memset(&crtc->mode, 0, sizeof(crtc->mode)); + if (!crtc->desiredMode.CrtcHDisplay) + { + DisplayModePtr mode = xf86OutputFindClosestMode (output, scrn->currentMode); + + if (!mode) + return FALSE; + crtc->desiredMode = *mode; + crtc->desiredRotation = RR_Rotate_0; + crtc->desiredX = 0; + crtc->desiredY = 0; + } + + if (!xf86CrtcSetMode (crtc, &crtc->desiredMode, crtc->desiredRotation, + crtc->desiredX, crtc->desiredY)) + return FALSE; + } + + xf86DisableUnusedFunctions(scrn); + return TRUE; +} + +/** + * In the current world order, there are lists of modes per output, which may + * or may not include the mode that was asked to be set by XFree86's mode + * selection. Find the closest one, in the following preference order: + * + * - Equality + * - Closer in size to the requested mode, but no larger + * - Closer in refresh rate to the requested mode. + */ + +_X_EXPORT DisplayModePtr +xf86OutputFindClosestMode (xf86OutputPtr output, DisplayModePtr desired) +{ + DisplayModePtr best = NULL, scan = NULL; + + for (scan = output->probed_modes; scan != NULL; scan = scan->next) + { + /* If there's an exact match, we're done. */ + if (xf86ModesEqual(scan, desired)) { + best = desired; + break; + } + + /* Reject if it's larger than the desired mode. */ + if (scan->HDisplay > desired->HDisplay || + scan->VDisplay > desired->VDisplay) + { + continue; + } + + /* + * If we haven't picked a best mode yet, use the first + * one in the size range + */ + if (best == NULL) + { + best = scan; + continue; + } + + /* Find if it's closer to the right size than the current best + * option. + */ + if ((scan->HDisplay > best->HDisplay && + scan->VDisplay >= best->VDisplay) || + (scan->HDisplay >= best->HDisplay && + scan->VDisplay > best->VDisplay)) + { + best = scan; + continue; + } + + /* Find if it's still closer to the right refresh than the current + * best resolution. + */ + if (scan->HDisplay == best->HDisplay && + scan->VDisplay == best->VDisplay && + (fabs(scan->VRefresh - desired->VRefresh) < + fabs(best->VRefresh - desired->VRefresh))) { + best = scan; + } + } + return best; +} + +/** + * When setting a mode through XFree86-VidModeExtension or XFree86-DGA, + * take the specified mode and apply it to the crtc connected to the compat + * output. Then, find similar modes for the other outputs, as with the + * InitialConfiguration code above. The goal is to clone the desired + * mode across all outputs that are currently active. + */ + +_X_EXPORT Bool +xf86SetSingleMode (ScrnInfoPtr pScrn, DisplayModePtr desired, Rotation rotation) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + Bool ok = TRUE; + xf86OutputPtr compat_output = config->output[config->compat_output]; + DisplayModePtr compat_mode; + int c; + + /* + * Let the compat output drive the final mode selection + */ + compat_mode = xf86OutputFindClosestMode (compat_output, desired); + if (compat_mode) + desired = compat_mode; + + for (c = 0; c < config->num_crtc; c++) + { + xf86CrtcPtr crtc = config->crtc[c]; + DisplayModePtr crtc_mode = NULL; + int o; + + if (!crtc->enabled) + continue; + + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + DisplayModePtr output_mode; + + /* skip outputs not on this crtc */ + if (output->crtc != crtc) + continue; + + if (crtc_mode) + { + output_mode = xf86OutputFindClosestMode (output, crtc_mode); + if (output_mode != crtc_mode) + output->crtc = NULL; + } + else + crtc_mode = xf86OutputFindClosestMode (output, desired); + } + if (!crtc_mode) + { + crtc->enabled = FALSE; + continue; + } + if (!xf86CrtcSetMode (crtc, crtc_mode, rotation, 0, 0)) + ok = FALSE; + else + { + crtc->desiredMode = *crtc_mode; + crtc->desiredRotation = rotation; + crtc->desiredX = 0; + crtc->desiredY = 0; + } + } + xf86DisableUnusedFunctions(pScrn); +#if RANDR_12_INTERFACE + xf86RandR12TellChanged (pScrn->pScreen); +#endif + return ok; +} + + +/** + * Set the DPMS power mode of all outputs and CRTCs. + * + * If the new mode is off, it will turn off outputs and then CRTCs. + * Otherwise, it will affect CRTCs before outputs. + */ +_X_EXPORT void +xf86DPMSSet(ScrnInfoPtr scrn, int mode, int flags) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + int i; + + if (!scrn->vtSema) + return; + + if (mode == DPMSModeOff) { + for (i = 0; i < config->num_output; i++) { + xf86OutputPtr output = config->output[i]; + if (output->crtc != NULL) + (*output->funcs->dpms) (output, mode); + } + } + + for (i = 0; i < config->num_crtc; i++) { + xf86CrtcPtr crtc = config->crtc[i]; + if (crtc->enabled) + (*crtc->funcs->dpms) (crtc, mode); + } + + if (mode != DPMSModeOff) { + for (i = 0; i < config->num_output; i++) { + xf86OutputPtr output = config->output[i]; + if (output->crtc != NULL) + (*output->funcs->dpms) (output, mode); + } + } +} + +/** + * Implement the screensaver by just calling down into the driver DPMS hooks. + * + * Even for monitors with no DPMS support, by the definition of our DPMS hooks, + * the outputs will still get disabled (blanked). + */ +_X_EXPORT Bool +xf86SaveScreen(ScreenPtr pScreen, int mode) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + + if (xf86IsUnblank(mode)) + xf86DPMSSet(pScrn, DPMSModeOn, 0); + else + xf86DPMSSet(pScrn, DPMSModeOff, 0); + + return TRUE; +} + +/** + * Disable all inactive crtcs and outputs + */ +_X_EXPORT void +xf86DisableUnusedFunctions(ScrnInfoPtr pScrn) +{ + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + int o, c; + + for (o = 0; o < xf86_config->num_output; o++) + { + xf86OutputPtr output = xf86_config->output[o]; + if (!output->crtc) + (*output->funcs->dpms)(output, DPMSModeOff); + } + + for (c = 0; c < xf86_config->num_crtc; c++) + { + xf86CrtcPtr crtc = xf86_config->crtc[c]; + + if (!crtc->enabled) + { + crtc->funcs->dpms(crtc, DPMSModeOff); + memset(&crtc->mode, 0, sizeof(crtc->mode)); + } + } +} + +#ifdef RANDR_12_INTERFACE + +#define EDID_ATOM_NAME "EDID_DATA" + +/** + * Set the RandR EDID property + */ +static void +xf86OutputSetEDIDProperty (xf86OutputPtr output, void *data, int data_len) +{ + Atom edid_atom = MakeAtom(EDID_ATOM_NAME, sizeof(EDID_ATOM_NAME) - 1, TRUE); + + /* This may get called before the RandR resources have been created */ + if (output->randr_output == NULL) + return; + + if (data_len != 0) { + RRChangeOutputProperty(output->randr_output, edid_atom, XA_INTEGER, 8, + PropModeReplace, data_len, data, FALSE, TRUE); + } else { + RRDeleteOutputProperty(output->randr_output, edid_atom); + } +} + +#endif + +/** + * Set the EDID information for the specified output + */ +_X_EXPORT void +xf86OutputSetEDID (xf86OutputPtr output, xf86MonPtr edid_mon) +{ + ScrnInfoPtr scrn = output->scrn; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + int i; +#ifdef RANDR_12_INTERFACE + int size; +#endif + + if (output->MonInfo != NULL) + xfree(output->MonInfo); + + output->MonInfo = edid_mon; + + if (config->debug_modes) { + xf86DrvMsg(scrn->scrnIndex, X_INFO, "EDID for output %s\n", + output->name); + xf86PrintEDID(edid_mon); + } + + /* Set the DDC properties for the 'compat' output */ + if (output == config->output[config->compat_output]) + xf86SetDDCproperties(scrn, edid_mon); + +#ifdef RANDR_12_INTERFACE + /* Set the RandR output properties */ + size = 0; + if (edid_mon) + { + if (edid_mon->ver.version == 1) + size = 128; + else if (edid_mon->ver.version == 2) + size = 256; + } + xf86OutputSetEDIDProperty (output, edid_mon ? edid_mon->rawData : NULL, size); +#endif + + if (edid_mon) + { + /* Pull out a phyiscal size from a detailed timing if available. */ + for (i = 0; i < 4; i++) { + if (edid_mon->det_mon[i].type == DT && + edid_mon->det_mon[i].section.d_timings.h_size != 0 && + edid_mon->det_mon[i].section.d_timings.v_size != 0) + { + output->mm_width = edid_mon->det_mon[i].section.d_timings.h_size; + output->mm_height = edid_mon->det_mon[i].section.d_timings.v_size; + break; + } + } + + /* if no mm size is available from a detailed timing, check the max size field */ + if ((!output->mm_width || !output->mm_height) && + (edid_mon->features.hsize && edid_mon->features.vsize)) + { + output->mm_width = edid_mon->features.hsize * 10; + output->mm_height = edid_mon->features.vsize * 10; + } + } +} + +/** + * Return the list of modes supported by the EDID information + * stored in 'output' + */ +_X_EXPORT DisplayModePtr +xf86OutputGetEDIDModes (xf86OutputPtr output) +{ + ScrnInfoPtr scrn = output->scrn; + xf86MonPtr edid_mon = output->MonInfo; + + if (!edid_mon) + return NULL; + return xf86DDCGetModes(scrn->scrnIndex, edid_mon); +} + +_X_EXPORT xf86MonPtr +xf86OutputGetEDID (xf86OutputPtr output, I2CBusPtr pDDCBus) +{ + ScrnInfoPtr scrn = output->scrn; + + return xf86DoEDID_DDC2 (scrn->scrnIndex, pDDCBus); +} + +static char *_xf86ConnectorNames[] = { "None", "VGA", "DVI-I", "DVI-D", + "DVI-A", "Composite", "S-Video", + "Component", "LFP", "Proprietary" }; +_X_EXPORT char * +xf86ConnectorGetName(xf86ConnectorType connector) +{ + return _xf86ConnectorNames[connector]; +} + +static void +x86_crtc_box_intersect(BoxPtr dest, BoxPtr a, BoxPtr b) +{ + dest->x1 = a->x1 > b->x1 ? a->x1 : b->x1; + dest->x2 = a->x2 < b->x2 ? a->x2 : b->x2; + dest->y1 = a->y1 > b->y1 ? a->y1 : b->y1; + dest->y2 = a->y2 < b->y2 ? a->y2 : b->y2; + + if (dest->x1 >= dest->x2 || dest->y1 >= dest->y2) + dest->x1 = dest->x2 = dest->y1 = dest->y2 = 0; +} + +static void +x86_crtc_box(xf86CrtcPtr crtc, BoxPtr crtc_box) +{ + if (crtc->enabled) { + crtc_box->x1 = crtc->x; + crtc_box->x2 = crtc->x + xf86ModeWidth(&crtc->mode, crtc->rotation); + crtc_box->y1 = crtc->y; + crtc_box->y2 = crtc->y + xf86ModeHeight(&crtc->mode, crtc->rotation); + } else + crtc_box->x1 = crtc_box->x2 = crtc_box->y1 = crtc_box->y2 = 0; +} + +static int +xf86_crtc_box_area(BoxPtr box) +{ + return (int) (box->x2 - box->x1) * (int) (box->y2 - box->y1); +} + +/* + * Return the crtc covering 'box'. If two crtcs cover a portion of + * 'box', then prefer 'desired'. If 'desired' is NULL, then prefer the crtc + * with greater coverage + */ + +static xf86CrtcPtr +xf86_covering_crtc(ScrnInfoPtr pScrn, + BoxPtr box, + xf86CrtcPtr desired, + BoxPtr crtc_box_ret) +{ + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + xf86CrtcPtr crtc, best_crtc; + int coverage, best_coverage; + int c; + BoxRec crtc_box, cover_box; + + best_crtc = NULL; + best_coverage = 0; + crtc_box_ret->x1 = 0; + crtc_box_ret->x2 = 0; + crtc_box_ret->y1 = 0; + crtc_box_ret->y2 = 0; + for (c = 0; c < xf86_config->num_crtc; c++) { + crtc = xf86_config->crtc[c]; + x86_crtc_box(crtc, &crtc_box); + x86_crtc_box_intersect(&cover_box, &crtc_box, box); + coverage = xf86_crtc_box_area(&cover_box); + if (coverage && crtc == desired) { + *crtc_box_ret = crtc_box; + return crtc; + } else if (coverage > best_coverage) { + *crtc_box_ret = crtc_box; + best_crtc = crtc; + best_coverage = coverage; + } + } + return best_crtc; +} + +/* + * For overlay video, compute the relevant CRTC and + * clip video to that + */ + +_X_EXPORT Bool +xf86_crtc_clip_video_helper(ScrnInfoPtr pScrn, + xf86CrtcPtr *crtc_ret, + xf86CrtcPtr desired_crtc, + BoxPtr dst, + INT32 *xa, + INT32 *xb, + INT32 *ya, + INT32 *yb, + RegionPtr reg, + INT32 width, + INT32 height) +{ + Bool ret; + RegionRec crtc_region_local; + RegionPtr crtc_region = reg; + + if (crtc_ret) { + BoxRec crtc_box; + xf86CrtcPtr crtc = xf86_covering_crtc(pScrn, dst, + desired_crtc, + &crtc_box); + + if (crtc) { + REGION_INIT (pScreen, &crtc_region_local, &crtc_box, 1); + crtc_region = &crtc_region_local; + REGION_INTERSECT (pScreen, crtc_region, crtc_region, reg); + } + *crtc_ret = crtc; + } + + ret = xf86XVClipVideoHelper(dst, xa, xb, ya, yb, + crtc_region, width, height); + + if (crtc_region != reg) + REGION_UNINIT (pScreen, &crtc_region_local); + + return ret; +} diff --git a/driver/xf86-video-intel/src/modes/xf86Crtc.h b/driver/xf86-video-intel/src/modes/xf86Crtc.h new file mode 100644 index 000000000..9693e12bb --- /dev/null +++ b/driver/xf86-video-intel/src/modes/xf86Crtc.h @@ -0,0 +1,788 @@ +/* + * Copyright © 2006 Keith Packard + * + * 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 the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS 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. + */ +#ifndef _XF86CRTC_H_ +#define _XF86CRTC_H_ + +#include <edid.h> +#include "randrstr.h" +#if XF86_MODES_RENAME +#include "xf86Rename.h" +#endif +#include "xf86Modes.h" +#include "xf86Cursor.h" +#include "damage.h" +#include "picturestr.h" + +/* Compat definitions for older X Servers. */ +#ifndef M_T_PREFERRED +#define M_T_PREFERRED 0x08 +#endif +#ifndef M_T_DRIVER +#define M_T_DRIVER 0x40 +#endif +#ifndef HARDWARE_CURSOR_ARGB +#define HARDWARE_CURSOR_ARGB 0x00004000 +#endif + +typedef struct _xf86Crtc xf86CrtcRec, *xf86CrtcPtr; +typedef struct _xf86Output xf86OutputRec, *xf86OutputPtr; + +/* define a standard for connector types */ +typedef enum _xf86ConnectorType { + XF86ConnectorNone, + XF86ConnectorVGA, + XF86ConnectorDVI_I, + XF86ConnectorDVI_D, + XF86ConnectorDVI_A, + XF86ConnectorComposite, + XF86ConnectorSvideo, + XF86ConnectorComponent, + XF86ConnectorLFP, + XF86ConnectorProprietary, +} xf86ConnectorType; + +typedef enum _xf86OutputStatus { + XF86OutputStatusConnected, + XF86OutputStatusDisconnected, + XF86OutputStatusUnknown, +} xf86OutputStatus; + +typedef struct _xf86CrtcFuncs { + /** + * Turns the crtc on/off, or sets intermediate power levels if available. + * + * Unsupported intermediate modes drop to the lower power setting. If the + * mode is DPMSModeOff, the crtc must be disabled sufficiently for it to + * be safe to call mode_set. + */ + void + (*dpms)(xf86CrtcPtr crtc, + int mode); + + /** + * Saves the crtc's state for restoration on VT switch. + */ + void + (*save)(xf86CrtcPtr crtc); + + /** + * Restore's the crtc's state at VT switch. + */ + void + (*restore)(xf86CrtcPtr crtc); + + /** + * Lock CRTC prior to mode setting, mostly for DRI. + * Returns whether unlock is needed + */ + Bool + (*lock) (xf86CrtcPtr crtc); + + /** + * Unlock CRTC after mode setting, mostly for DRI + */ + void + (*unlock) (xf86CrtcPtr crtc); + + /** + * Callback to adjust the mode to be set in the CRTC. + * + * This allows a CRTC to adjust the clock or even the entire set of + * timings, which is used for panels with fixed timings or for + * buses with clock limitations. + */ + Bool + (*mode_fixup)(xf86CrtcPtr crtc, + DisplayModePtr mode, + DisplayModePtr adjusted_mode); + + /** + * Prepare CRTC for an upcoming mode set. + */ + void + (*prepare)(xf86CrtcPtr crtc); + + /** + * Callback for setting up a video mode after fixups have been made. + */ + void + (*mode_set)(xf86CrtcPtr crtc, + DisplayModePtr mode, + DisplayModePtr adjusted_mode, + int x, int y); + + /** + * Commit mode changes to a CRTC + */ + void + (*commit)(xf86CrtcPtr crtc); + + /* Set the color ramps for the CRTC to the given values. */ + void + (*gamma_set)(xf86CrtcPtr crtc, CARD16 *red, CARD16 *green, CARD16 *blue, + int size); + + /** + * Allocate the shadow area, delay the pixmap creation until needed + */ + void * + (*shadow_allocate) (xf86CrtcPtr crtc, int width, int height); + + /** + * Create shadow pixmap for rotation support + */ + PixmapPtr + (*shadow_create) (xf86CrtcPtr crtc, void *data, int width, int height); + + /** + * Destroy shadow pixmap + */ + void + (*shadow_destroy) (xf86CrtcPtr crtc, PixmapPtr pPixmap, void *data); + + /** + * Set cursor colors + */ + void + (*set_cursor_colors) (xf86CrtcPtr crtc, int bg, int fg); + + /** + * Set cursor position + */ + void + (*set_cursor_position) (xf86CrtcPtr crtc, int x, int y); + + /** + * Show cursor + */ + void + (*show_cursor) (xf86CrtcPtr crtc); + + /** + * Hide cursor + */ + void + (*hide_cursor) (xf86CrtcPtr crtc); + + /** + * Load monochrome image + */ + void + (*load_cursor_image) (xf86CrtcPtr crtc, CARD8 *image); + + /** + * Load ARGB image + */ + void + (*load_cursor_argb) (xf86CrtcPtr crtc, CARD32 *image); + + /** + * Clean up driver-specific bits of the crtc + */ + void + (*destroy) (xf86CrtcPtr crtc); +} xf86CrtcFuncsRec, *xf86CrtcFuncsPtr; + +struct _xf86Crtc { + /** + * Associated ScrnInfo + */ + ScrnInfoPtr scrn; + + /** + * Active state of this CRTC + * + * Set when this CRTC is driving one or more outputs + */ + Bool enabled; + + /** + * Active mode + * + * This reflects the mode as set in the CRTC currently + * It will be cleared when the VT is not active or + * during server startup + */ + DisplayModeRec mode; + Rotation rotation; + PixmapPtr rotatedPixmap; + void *rotatedData; + + /** + * Position on screen + * + * Locates this CRTC within the frame buffer + */ + int x, y; + + /** + * Desired mode + * + * This is set to the requested mode, independent of + * whether the VT is active. In particular, it receives + * the startup configured mode and saves the active mode + * on VT switch. + */ + DisplayModeRec desiredMode; + Rotation desiredRotation; + int desiredX, desiredY; + + /** crtc-specific functions */ + const xf86CrtcFuncsRec *funcs; + + /** + * Driver private + * + * Holds driver-private information + */ + void *driver_private; + +#ifdef RANDR_12_INTERFACE + /** + * RandR crtc + * + * When RandR 1.2 is available, this + * points at the associated crtc object + */ + RRCrtcPtr randr_crtc; +#else + void *randr_crtc; +#endif + + /** + * Current cursor is ARGB + */ + Bool cursor_argb; + /** + * Track whether cursor is within CRTC range + */ + Bool cursor_in_range; + /** + * Track state of cursor associated with this CRTC + */ + Bool cursor_shown; + + /** + * Current transformation matrix + */ + PictTransform crtc_to_framebuffer; + PictTransform framebuffer_to_crtc; + Bool transform_in_use; + /** + * Bounding box in screen space + */ + BoxRec bounds; +}; + +typedef struct _xf86OutputFuncs { + /** + * Called to allow the output a chance to create properties after the + * RandR objects have been created. + */ + void + (*create_resources)(xf86OutputPtr output); + + /** + * Turns the output on/off, or sets intermediate power levels if available. + * + * Unsupported intermediate modes drop to the lower power setting. If the + * mode is DPMSModeOff, the output must be disabled, as the DPLL may be + * disabled afterwards. + */ + void + (*dpms)(xf86OutputPtr output, + int mode); + + /** + * Saves the output's state for restoration on VT switch. + */ + void + (*save)(xf86OutputPtr output); + + /** + * Restore's the output's state at VT switch. + */ + void + (*restore)(xf86OutputPtr output); + + /** + * Callback for testing a video mode for a given output. + * + * This function should only check for cases where a mode can't be supported + * on the output specifically, and not represent generic CRTC limitations. + * + * \return MODE_OK if the mode is valid, or another MODE_* otherwise. + */ + int + (*mode_valid)(xf86OutputPtr output, + DisplayModePtr pMode); + + /** + * Callback to adjust the mode to be set in the CRTC. + * + * This allows an output to adjust the clock or even the entire set of + * timings, which is used for panels with fixed timings or for + * buses with clock limitations. + */ + Bool + (*mode_fixup)(xf86OutputPtr output, + DisplayModePtr mode, + DisplayModePtr adjusted_mode); + + /** + * Callback for preparing mode changes on an output + */ + void + (*prepare)(xf86OutputPtr output); + + /** + * Callback for committing mode changes on an output + */ + void + (*commit)(xf86OutputPtr output); + + /** + * Callback for setting up a video mode after fixups have been made. + * + * This is only called while the output is disabled. The dpms callback + * must be all that's necessary for the output, to turn the output on + * after this function is called. + */ + void + (*mode_set)(xf86OutputPtr output, + DisplayModePtr mode, + DisplayModePtr adjusted_mode); + + /** + * Probe for a connected output, and return detect_status. + */ + xf86OutputStatus + (*detect)(xf86OutputPtr output); + + /** + * Query the device for the modes it provides. + * + * This function may also update MonInfo, mm_width, and mm_height. + * + * \return singly-linked list of modes or NULL if no modes found. + */ + DisplayModePtr + (*get_modes)(xf86OutputPtr output); + +#ifdef RANDR_12_INTERFACE + /** + * Callback when an output's property has changed. + */ + Bool + (*set_property)(xf86OutputPtr output, + Atom property, + RRPropertyValuePtr value); +#endif + /** + * Clean up driver-specific bits of the output + */ + void + (*destroy) (xf86OutputPtr output); +} xf86OutputFuncsRec, *xf86OutputFuncsPtr; + +struct _xf86Output { + /** + * Associated ScrnInfo + */ + ScrnInfoPtr scrn; + + /** + * Currently connected crtc (if any) + * + * If this output is not in use, this field will be NULL. + */ + xf86CrtcPtr crtc; + + /** + * Possible CRTCs for this output as a mask of crtc indices + */ + CARD32 possible_crtcs; + + /** + * Possible outputs to share the same CRTC as a mask of output indices + */ + CARD32 possible_clones; + + /** + * Whether this output can support interlaced modes + */ + Bool interlaceAllowed; + + /** + * Whether this output can support double scan modes + */ + Bool doubleScanAllowed; + + /** + * List of available modes on this output. + * + * This should be the list from get_modes(), plus perhaps additional + * compatible modes added later. + */ + DisplayModePtr probed_modes; + + /** + * Options parsed from the related monitor section + */ + OptionInfoPtr options; + + /** + * Configured monitor section + */ + XF86ConfMonitorPtr conf_monitor; + + /** + * Desired initial position + */ + int initial_x, initial_y; + + /** + * Desired initial rotation + */ + Rotation initial_rotation; + + /** + * Current connection status + * + * This indicates whether a monitor is known to be connected + * to this output or not, or whether there is no way to tell + */ + xf86OutputStatus status; + + /** EDID monitor information */ + xf86MonPtr MonInfo; + + /** subpixel order */ + int subpixel_order; + + /** Physical size of the currently attached output device. */ + int mm_width, mm_height; + + /** Output name */ + char *name; + + /** output-specific functions */ + const xf86OutputFuncsRec *funcs; + + /** driver private information */ + void *driver_private; + + /** Whether to use the old per-screen Monitor config section */ + Bool use_screen_monitor; + +#ifdef RANDR_12_INTERFACE + /** + * RandR 1.2 output structure. + * + * When RandR 1.2 is available, this points at the associated + * RandR output structure and is created when this output is created + */ + RROutputPtr randr_output; +#else + void *randr_output; +#endif +}; + +typedef struct _xf86CrtcConfigFuncs { + /** + * Requests that the driver resize the screen. + * + * The driver is responsible for updating scrn->virtualX and scrn->virtualY. + * If the requested size cannot be set, the driver should leave those values + * alone and return FALSE. + * + * A naive driver that cannot reallocate the screen may simply change + * virtual[XY]. A more advanced driver will want to also change the + * devPrivate.ptr and devKind of the screen pixmap, update any offscreen + * pixmaps it may have moved, and change pScrn->displayWidth. + */ + Bool + (*resize)(ScrnInfoPtr scrn, + int width, + int height); +} xf86CrtcConfigFuncsRec, *xf86CrtcConfigFuncsPtr; + +typedef struct _xf86CrtcConfig { + int num_output; + xf86OutputPtr *output; + /** + * compat_output is used whenever we deal + * with legacy code that only understands a single + * output. pScrn->modes will be loaded from this output, + * adjust frame will whack this output, etc. + */ + int compat_output; + + int num_crtc; + xf86CrtcPtr *crtc; + + int minWidth, minHeight; + int maxWidth, maxHeight; + + /* For crtc-based rotation */ + DamagePtr rotation_damage; + Bool rotation_damage_registered; + + /* DGA */ + unsigned int dga_flags; + unsigned long dga_address; + DGAModePtr dga_modes; + int dga_nmode; + int dga_width, dga_height, dga_stride; + DisplayModePtr dga_save_mode; + + const xf86CrtcConfigFuncsRec *funcs; + + CreateScreenResourcesProcPtr CreateScreenResources; + + CloseScreenProcPtr CloseScreen; + + /* Cursor information */ + xf86CursorInfoPtr cursor_info; + CursorPtr cursor; + CARD8 *cursor_image; + Bool cursor_on; + CARD32 cursor_fg, cursor_bg; + + /** + * Options parsed from the related device section + */ + OptionInfoPtr options; + + Bool debug_modes; + + /* wrap screen BlockHandler for rotation */ + ScreenBlockHandlerProcPtr BlockHandler; + +} xf86CrtcConfigRec, *xf86CrtcConfigPtr; + +extern int xf86CrtcConfigPrivateIndex; + +#define XF86_CRTC_CONFIG_PTR(p) ((xf86CrtcConfigPtr) ((p)->privates[xf86CrtcConfigPrivateIndex].ptr)) + +/* + * Initialize xf86CrtcConfig structure + */ + +void +xf86CrtcConfigInit (ScrnInfoPtr scrn, + const xf86CrtcConfigFuncsRec *funcs); + +void +xf86CrtcSetSizeRange (ScrnInfoPtr scrn, + int minWidth, int minHeight, + int maxWidth, int maxHeight); + +/* + * Crtc functions + */ +xf86CrtcPtr +xf86CrtcCreate (ScrnInfoPtr scrn, + const xf86CrtcFuncsRec *funcs); + +void +xf86CrtcDestroy (xf86CrtcPtr crtc); + + +/** + * Sets the given video mode on the given crtc + */ +Bool +xf86CrtcSetMode (xf86CrtcPtr crtc, DisplayModePtr mode, Rotation rotation, + int x, int y); + +/* + * Assign crtc rotation during mode set + */ +Bool +xf86CrtcRotate (xf86CrtcPtr crtc, DisplayModePtr mode, Rotation rotation); + +/* + * Clean up rotation during CloseScreen + */ +void +xf86RotateCloseScreen (ScreenPtr pScreen); + +/** + * Return whether any output is assigned to the crtc + */ +Bool +xf86CrtcInUse (xf86CrtcPtr crtc); + +/* + * Output functions + */ +xf86OutputPtr +xf86OutputCreate (ScrnInfoPtr scrn, + const xf86OutputFuncsRec *funcs, + const char *name); + +void +xf86OutputUseScreenMonitor (xf86OutputPtr output, Bool use_screen_monitor); + +Bool +xf86OutputRename (xf86OutputPtr output, const char *name); + +void +xf86OutputDestroy (xf86OutputPtr output); + +void +xf86ProbeOutputModes (ScrnInfoPtr pScrn, int maxX, int maxY); + +void +xf86SetScrnInfoModes (ScrnInfoPtr pScrn); + +Bool +xf86CrtcScreenInit (ScreenPtr pScreen); + +Bool +xf86InitialConfiguration (ScrnInfoPtr pScrn, Bool canGrow); + +void +xf86DPMSSet(ScrnInfoPtr pScrn, int PowerManagementMode, int flags); + +Bool +xf86SaveScreen(ScreenPtr pScreen, int mode); + +void +xf86DisableUnusedFunctions(ScrnInfoPtr pScrn); + +DisplayModePtr +xf86OutputFindClosestMode (xf86OutputPtr output, DisplayModePtr desired); + +Bool +xf86SetSingleMode (ScrnInfoPtr pScrn, DisplayModePtr desired, Rotation rotation); + +/** + * Set the EDID information for the specified output + */ +void +xf86OutputSetEDID (xf86OutputPtr output, xf86MonPtr edid_mon); + +/** + * Return the list of modes supported by the EDID information + * stored in 'output' + */ +DisplayModePtr +xf86OutputGetEDIDModes (xf86OutputPtr output); + +xf86MonPtr +xf86OutputGetEDID (xf86OutputPtr output, I2CBusPtr pDDCBus); + +/** + * Initialize dga for this screen + */ + +Bool +xf86DiDGAInit (ScreenPtr pScreen, unsigned long dga_address); + +/** + * Re-initialize dga for this screen (as when the set of modes changes) + */ + +Bool +xf86DiDGAReInit (ScreenPtr pScreen); + +/* + * Set the subpixel order reported for the screen using + * the information from the outputs + */ + +void +xf86CrtcSetScreenSubpixelOrder (ScreenPtr pScreen); + +/* + * Get a standard string name for a connector type + */ +char * +xf86ConnectorGetName(xf86ConnectorType connector); + +/* + * Using the desired mode information in each crtc, set + * modes (used in EnterVT functions, or at server startup) + */ + +Bool +xf86SetDesiredModes (ScrnInfoPtr pScrn); + +/** + * Initialize the CRTC-based cursor code. CRTC function vectors must + * contain relevant cursor setting functions. + * + * Driver should call this from ScreenInit function + */ +Bool +xf86_cursors_init (ScreenPtr screen, int max_width, int max_height, int flags); + +/** + * Called when anything on the screen is reconfigured. + * + * Reloads cursor images as needed, then adjusts cursor positions. + * + * Driver should call this from crtc commit function. + */ +void +xf86_reload_cursors (ScreenPtr screen); + +/** + * Called from EnterVT to turn the cursors back on + */ +void +xf86_show_cursors (ScrnInfoPtr scrn); + +/** + * Called by the driver to turn cursors off + */ +void +xf86_hide_cursors (ScrnInfoPtr scrn); + +/** + * Clean up CRTC-based cursor code. Driver must call this at CloseScreen time. + */ +void +xf86_cursors_fini (ScreenPtr screen); + +/* + * For overlay video, compute the relevant CRTC and + * clip video to that. + * wraps xf86XVClipVideoHelper() + */ + +Bool +xf86_crtc_clip_video_helper(ScrnInfoPtr pScrn, + xf86CrtcPtr *crtc_ret, + xf86CrtcPtr desired_crtc, + BoxPtr dst, + INT32 *xa, + INT32 *xb, + INT32 *ya, + INT32 *yb, + RegionPtr reg, + INT32 width, + INT32 height); + +#endif /* _XF86CRTC_H_ */ diff --git a/driver/xf86-video-intel/src/modes/xf86Cursors.c b/driver/xf86-video-intel/src/modes/xf86Cursors.c new file mode 100644 index 000000000..b5101642b --- /dev/null +++ b/driver/xf86-video-intel/src/modes/xf86Cursors.c @@ -0,0 +1,646 @@ +/* + * Copyright © 2007 Keith Packard + * + * 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 the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS 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. + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#else +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#endif + +#include <stddef.h> +#include <string.h> +#include <stdio.h> + +#include "xf86.h" +#include "xf86DDC.h" +#include "xf86Crtc.h" +#include "xf86Modes.h" +#include "xf86RandR12.h" +#include "X11/extensions/render.h" +#define DPMS_SERVER +#include "X11/extensions/dpms.h" +#include "X11/Xatom.h" +#ifdef RENDER +#include "picturestr.h" +#endif +#include "cursorstr.h" + +/* + * Given a screen coordinate, rotate back to a cursor source coordinate + */ +static void +xf86_crtc_rotate_coord (Rotation rotation, + int width, + int height, + int x_dst, + int y_dst, + int *x_src, + int *y_src) +{ + int t; + + switch (rotation & 0xf) { + case RR_Rotate_0: + break; + case RR_Rotate_90: + t = x_dst; + x_dst = height - y_dst - 1; + y_dst = t; + break; + case RR_Rotate_180: + x_dst = width - x_dst - 1; + y_dst = height - y_dst - 1; + break; + case RR_Rotate_270: + t = x_dst; + x_dst = y_dst; + y_dst = width - t - 1; + break; + } + if (rotation & RR_Reflect_X) + x_dst = width - x_dst - 1; + if (rotation & RR_Reflect_Y) + y_dst = height - y_dst - 1; + *x_src = x_dst; + *y_src = y_dst; +} + +/* + * Given a cursor source coordinate, rotate to a screen coordinate + */ +static void +xf86_crtc_rotate_coord_back (Rotation rotation, + int width, + int height, + int x_dst, + int y_dst, + int *x_src, + int *y_src) +{ + int t; + + if (rotation & RR_Reflect_X) + x_dst = width - x_dst - 1; + if (rotation & RR_Reflect_Y) + y_dst = height - y_dst - 1; + + switch (rotation & 0xf) { + case RR_Rotate_0: + break; + case RR_Rotate_90: + t = x_dst; + x_dst = y_dst; + y_dst = width - t - 1; + break; + case RR_Rotate_180: + x_dst = width - x_dst - 1; + y_dst = height - y_dst - 1; + break; + case RR_Rotate_270: + t = x_dst; + x_dst = height - y_dst - 1; + y_dst = t; + break; + } + *x_src = x_dst; + *y_src = y_dst; +} + +/* + * Convert an x coordinate to a position within the cursor bitmap + */ +static int +cursor_bitpos (int flags, int x, Bool mask) +{ + if (flags & HARDWARE_CURSOR_SWAP_SOURCE_AND_MASK) + mask = !mask; + if (flags & HARDWARE_CURSOR_NIBBLE_SWAPPED) + x = (x & ~3) | (3 - (x & 3)); + if (flags & HARDWARE_CURSOR_BIT_ORDER_MSBFIRST) + x = (x & ~7) | (7 - (x & 7)); + if (flags & HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1) + x = (x << 1) + mask; + else if (flags & HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_8) + x = ((x & ~7) << 1) | (mask << 3) | (x & 7); + else if (flags & HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_16) + x = ((x & ~15) << 1) | (mask << 4) | (x & 15); + else if (flags & HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_32) + x = ((x & ~31) << 1) | (mask << 5) | (x & 31); + else if (flags & HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64) + x = ((x & ~63) << 1) | (mask << 6) | (x & 63); + return x; +} + +/* + * Fetch one bit from a cursor bitmap + */ +static CARD8 +get_bit (CARD8 *image, int stride, int flags, int x, int y, Bool mask) +{ + x = cursor_bitpos (flags, x, mask); + image += y * stride; + return (image[(x >> 3)] >> (x & 7)) & 1; +} + +/* + * Set one bit in a cursor bitmap + */ +static void +set_bit (CARD8 *image, int stride, int flags, int x, int y, Bool mask) +{ + x = cursor_bitpos (flags, x, mask); + image += y * stride; + image[(x >> 3)] |= 1 << (x & 7); +} + +/* + * Load a two color cursor into a driver that supports only ARGB cursors + */ +static void +xf86_crtc_convert_cursor_to_argb (xf86CrtcPtr crtc, unsigned char *src) +{ + ScrnInfoPtr scrn = crtc->scrn; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + xf86CursorInfoPtr cursor_info = xf86_config->cursor_info; + CARD32 *cursor_image = (CARD32 *) xf86_config->cursor_image; + int x, y; + int xin, yin; + int stride = cursor_info->MaxWidth >> 2; + int flags = cursor_info->Flags; + CARD32 bits; + +#ifdef ARGB_CURSOR + crtc->cursor_argb = FALSE; +#endif + + for (y = 0; y < cursor_info->MaxHeight; y++) + for (x = 0; x < cursor_info->MaxWidth; x++) + { + xf86_crtc_rotate_coord (crtc->rotation, + cursor_info->MaxWidth, + cursor_info->MaxHeight, + x, y, &xin, &yin); + if (get_bit (src, stride, flags, xin, yin, TRUE) == + ((flags & HARDWARE_CURSOR_INVERT_MASK) == 0)) + { + if (get_bit (src, stride, flags, xin, yin, FALSE)) + bits = xf86_config->cursor_fg; + else + bits = xf86_config->cursor_bg; + } + else + bits = 0; + cursor_image[y * cursor_info->MaxWidth + x] = bits; + } + crtc->funcs->load_cursor_argb (crtc, cursor_image); +} + +/* + * Set the colors for a two-color cursor (ignore for ARGB cursors) + */ +static void +xf86_set_cursor_colors (ScrnInfoPtr scrn, int bg, int fg) +{ + ScreenPtr screen = scrn->pScreen; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + CursorPtr cursor = xf86_config->cursor; + int c; + CARD8 *bits = cursor ? cursor->devPriv[screen->myNum] : NULL; + + /* Save ARGB versions of these colors */ + xf86_config->cursor_fg = (CARD32) fg | 0xff000000; + xf86_config->cursor_bg = (CARD32) bg | 0xff000000; + + for (c = 0; c < xf86_config->num_crtc; c++) + { + xf86CrtcPtr crtc = xf86_config->crtc[c]; + + if (crtc->enabled && !crtc->cursor_argb) + { + if (crtc->funcs->load_cursor_image) + crtc->funcs->set_cursor_colors (crtc, bg, fg); + else if (bits) + xf86_crtc_convert_cursor_to_argb (crtc, bits); + } + } +} + +static void +xf86_crtc_hide_cursor (xf86CrtcPtr crtc) +{ + if (crtc->cursor_shown) + { + crtc->funcs->hide_cursor (crtc); + crtc->cursor_shown = FALSE; + } +} + +_X_EXPORT void +xf86_hide_cursors (ScrnInfoPtr scrn) +{ + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + int c; + + xf86_config->cursor_on = FALSE; + for (c = 0; c < xf86_config->num_crtc; c++) + { + xf86CrtcPtr crtc = xf86_config->crtc[c]; + + if (crtc->enabled) + xf86_crtc_hide_cursor (crtc); + } +} + +static void +xf86_crtc_show_cursor (xf86CrtcPtr crtc) +{ + if (!crtc->cursor_shown && crtc->cursor_in_range) + { + crtc->funcs->show_cursor (crtc); + crtc->cursor_shown = TRUE; + } +} + +_X_EXPORT void +xf86_show_cursors (ScrnInfoPtr scrn) +{ + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + int c; + + xf86_config->cursor_on = TRUE; + for (c = 0; c < xf86_config->num_crtc; c++) + { + xf86CrtcPtr crtc = xf86_config->crtc[c]; + + if (crtc->enabled) + xf86_crtc_show_cursor (crtc); + } +} + +static void +xf86_crtc_set_cursor_position (xf86CrtcPtr crtc, int x, int y) +{ + ScrnInfoPtr scrn = crtc->scrn; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + xf86CursorInfoPtr cursor_info = xf86_config->cursor_info; + DisplayModePtr mode = &crtc->mode; + Bool in_range; + int dx, dy; + + /* + * Transform position of cursor on screen + */ + if (crtc->transform_in_use) + { + PictVector v; + v.vector[0] = IntToxFixed (x); v.vector[1] = IntToxFixed (y); v.vector[2] = IntToxFixed(1); + PictureTransformPoint (&crtc->framebuffer_to_crtc, &v); + x = xFixedToInt (v.vector[0]); y = xFixedToInt (v.vector[1]); + } + else + { + x -= crtc->x; + y -= crtc->y; + } + /* + * Transform position of cursor upper left corner + */ + xf86_crtc_rotate_coord_back (crtc->rotation, + cursor_info->MaxWidth, + cursor_info->MaxHeight, + 0, 0, &dx, &dy); + x -= dx; + y -= dy; + + /* + * Disable the cursor when it is outside the viewport + */ + in_range = TRUE; + if (x >= mode->HDisplay || y >= mode->VDisplay || + x <= -cursor_info->MaxWidth || y <= -cursor_info->MaxHeight) + { + in_range = FALSE; + x = 0; + y = 0; + } + + crtc->cursor_in_range = in_range; + + if (in_range) + { + crtc->funcs->set_cursor_position (crtc, x, y); + xf86_crtc_show_cursor (crtc); + } + else + xf86_crtc_hide_cursor (crtc); +} + +static void +xf86_set_cursor_position (ScrnInfoPtr scrn, int x, int y) +{ + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + int c; + + /* undo what xf86HWCurs did to the coordinates */ + x += scrn->frameX0; + y += scrn->frameY0; + for (c = 0; c < xf86_config->num_crtc; c++) + { + xf86CrtcPtr crtc = xf86_config->crtc[c]; + + if (crtc->enabled) + xf86_crtc_set_cursor_position (crtc, x, y); + } +} + +/* + * Load a two-color cursor into a crtc, performing rotation as needed + */ +static void +xf86_crtc_load_cursor_image (xf86CrtcPtr crtc, CARD8 *src) +{ + ScrnInfoPtr scrn = crtc->scrn; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + xf86CursorInfoPtr cursor_info = xf86_config->cursor_info; + CARD8 *cursor_image; + +#ifdef ARGB_CURSOR + crtc->cursor_argb = FALSE; +#endif + + if (crtc->rotation == RR_Rotate_0) + cursor_image = src; + else + { + int x, y; + int xin, yin; + int stride = cursor_info->MaxWidth >> 2; + int flags = cursor_info->Flags; + + cursor_image = xf86_config->cursor_image; + memset(cursor_image, 0, cursor_info->MaxWidth * stride); + + for (y = 0; y < cursor_info->MaxHeight; y++) + for (x = 0; x < cursor_info->MaxWidth; x++) + { + xf86_crtc_rotate_coord (crtc->rotation, + cursor_info->MaxWidth, + cursor_info->MaxHeight, + x, y, &xin, &yin); + if (get_bit(src, stride, flags, xin, yin, FALSE)) + set_bit(cursor_image, stride, flags, x, y, FALSE); + if (get_bit(src, stride, flags, xin, yin, TRUE)) + set_bit(cursor_image, stride, flags, x, y, TRUE); + } + } + crtc->funcs->load_cursor_image (crtc, cursor_image); +} + +/* + * Load a cursor image into all active CRTCs + */ +static void +xf86_load_cursor_image (ScrnInfoPtr scrn, unsigned char *src) +{ + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + int c; + + for (c = 0; c < xf86_config->num_crtc; c++) + { + xf86CrtcPtr crtc = xf86_config->crtc[c]; + + if (crtc->enabled) + { + if (crtc->funcs->load_cursor_image) + xf86_crtc_load_cursor_image (crtc, src); + else if (crtc->funcs->load_cursor_argb) + xf86_crtc_convert_cursor_to_argb (crtc, src); + } + } +} + +static Bool +xf86_use_hw_cursor (ScreenPtr screen, CursorPtr cursor) +{ + ScrnInfoPtr scrn = xf86Screens[screen->myNum]; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + xf86CursorInfoPtr cursor_info = xf86_config->cursor_info; + + if (xf86_config->cursor) + FreeCursor (xf86_config->cursor, None); + xf86_config->cursor = cursor; + ++cursor->refcnt; + + if (cursor->bits->width > cursor_info->MaxWidth || + cursor->bits->height> cursor_info->MaxHeight) + return FALSE; + + return TRUE; +} + +static Bool +xf86_use_hw_cursor_argb (ScreenPtr screen, CursorPtr cursor) +{ + ScrnInfoPtr scrn = xf86Screens[screen->myNum]; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + xf86CursorInfoPtr cursor_info = xf86_config->cursor_info; + + if (xf86_config->cursor) + FreeCursor (xf86_config->cursor, None); + xf86_config->cursor = cursor; + ++cursor->refcnt; + + /* Make sure ARGB support is available */ + if ((cursor_info->Flags & HARDWARE_CURSOR_ARGB) == 0) + return FALSE; + + if (cursor->bits->width > cursor_info->MaxWidth || + cursor->bits->height> cursor_info->MaxHeight) + return FALSE; + + return TRUE; +} + +static void +xf86_crtc_load_cursor_argb (xf86CrtcPtr crtc, CursorPtr cursor) +{ + ScrnInfoPtr scrn = crtc->scrn; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + xf86CursorInfoPtr cursor_info = xf86_config->cursor_info; + CARD32 *cursor_image = (CARD32 *) xf86_config->cursor_image; + CARD32 *cursor_source = (CARD32 *) cursor->bits->argb; + int x, y; + int xin, yin; + CARD32 bits; + int source_width = cursor->bits->width; + int source_height = cursor->bits->height; + int image_width = cursor_info->MaxWidth; + int image_height = cursor_info->MaxHeight; + + for (y = 0; y < image_height; y++) + for (x = 0; x < image_width; x++) + { + xf86_crtc_rotate_coord (crtc->rotation, image_width, image_height, + x, y, &xin, &yin); + if (xin < source_width && yin < source_height) + bits = cursor_source[yin * source_width + xin]; + else + bits = 0; + cursor_image[y * image_width + x] = bits; + } + + crtc->funcs->load_cursor_argb (crtc, cursor_image); +} + +static void +xf86_load_cursor_argb (ScrnInfoPtr scrn, CursorPtr cursor) +{ + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + int c; + + for (c = 0; c < xf86_config->num_crtc; c++) + { + xf86CrtcPtr crtc = xf86_config->crtc[c]; + + if (crtc->enabled) + xf86_crtc_load_cursor_argb (crtc, cursor); + } +} + +_X_EXPORT Bool +xf86_cursors_init (ScreenPtr screen, int max_width, int max_height, int flags) +{ + ScrnInfoPtr scrn = xf86Screens[screen->myNum]; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + xf86CursorInfoPtr cursor_info; + + cursor_info = xf86CreateCursorInfoRec(); + if (!cursor_info) + return FALSE; + + xf86_config->cursor_image = xalloc (max_width * max_height * 4); + + if (!xf86_config->cursor_image) + { + xf86DestroyCursorInfoRec (cursor_info); + return FALSE; + } + + xf86_config->cursor_info = cursor_info; + + cursor_info->MaxWidth = max_width; + cursor_info->MaxHeight = max_height; + cursor_info->Flags = flags; + + cursor_info->SetCursorColors = xf86_set_cursor_colors; + cursor_info->SetCursorPosition = xf86_set_cursor_position; + cursor_info->LoadCursorImage = xf86_load_cursor_image; + cursor_info->HideCursor = xf86_hide_cursors; + cursor_info->ShowCursor = xf86_show_cursors; + cursor_info->UseHWCursor = xf86_use_hw_cursor; +#ifdef ARGB_CURSOR + if (flags & HARDWARE_CURSOR_ARGB) + { + cursor_info->UseHWCursorARGB = xf86_use_hw_cursor_argb; + cursor_info->LoadCursorARGB = xf86_load_cursor_argb; + } +#endif + + xf86_config->cursor = NULL; + xf86_hide_cursors (scrn); + + return xf86InitCursor (screen, cursor_info); +} + +/** + * Called when anything on the screen is reconfigured. + * + * Reloads cursor images as needed, then adjusts cursor positions + */ + +_X_EXPORT void +xf86_reload_cursors (ScreenPtr screen) +{ + ScrnInfoPtr scrn; + xf86CrtcConfigPtr xf86_config; + xf86CursorInfoPtr cursor_info; + CursorPtr cursor; + int x, y; + + /* initial mode setting will not have set a screen yet */ + if (!screen) + return; + scrn = xf86Screens[screen->myNum]; + xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + + /* make sure the cursor code has been initialized */ + cursor_info = xf86_config->cursor_info; + if (!cursor_info) + return; + + cursor = xf86_config->cursor; + GetSpritePosition (&x, &y); + if (!(cursor_info->Flags & HARDWARE_CURSOR_UPDATE_UNHIDDEN)) + (*cursor_info->HideCursor)(scrn); + + if (cursor) + { +#ifdef ARGB_CURSOR + if (cursor->bits->argb && cursor_info->LoadCursorARGB) + (*cursor_info->LoadCursorARGB) (scrn, cursor); + else +#endif + (*cursor_info->LoadCursorImage)(cursor_info->pScrn, + cursor->devPriv[screen->myNum]); + + (*cursor_info->SetCursorPosition)(cursor_info->pScrn, x, y); + (*cursor_info->ShowCursor)(cursor_info->pScrn); + } +} + +/** + * Clean up CRTC-based cursor code + */ +_X_EXPORT void +xf86_cursors_fini (ScreenPtr screen) +{ + ScrnInfoPtr scrn = xf86Screens[screen->myNum]; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + + if (xf86_config->cursor_info) + { + xf86DestroyCursorInfoRec (xf86_config->cursor_info); + xf86_config->cursor_info = NULL; + } + if (xf86_config->cursor_image) + { + xfree (xf86_config->cursor_image); + xf86_config->cursor_image = NULL; + } + if (xf86_config->cursor) + { + FreeCursor (xf86_config->cursor, None); + xf86_config->cursor = NULL; + } +} diff --git a/driver/xf86-video-intel/src/modes/xf86DiDGA.c b/driver/xf86-video-intel/src/modes/xf86DiDGA.c new file mode 100644 index 000000000..f40d0abef --- /dev/null +++ b/driver/xf86-video-intel/src/modes/xf86DiDGA.c @@ -0,0 +1,286 @@ +/* + * Copyright © 2006 Keith Packard + * + * 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 the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS 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. + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#else +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#endif + +#include "xf86.h" +#include "xf86DDC.h" +#include "xf86_OSproc.h" +#include "dgaproc.h" +#include "xf86Crtc.h" +#include "xf86Modes.h" +#include "gcstruct.h" +#include "scrnintstr.h" +#include "windowstr.h" + +static Bool +xf86_dga_get_modes (ScreenPtr pScreen) +{ + ScrnInfoPtr scrn = xf86Screens[pScreen->myNum]; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + DGAModePtr modes, mode; + DisplayModePtr display_mode; + int bpp = scrn->bitsPerPixel >> 3; + int num; + + num = 0; + display_mode = scrn->modes; + while (display_mode) + { + num++; + display_mode = display_mode->next; + if (display_mode == scrn->modes) + break; + } + + if (!num) + return FALSE; + + modes = xalloc(num * sizeof(DGAModeRec)); + if (!modes) + return FALSE; + + num = 0; + display_mode = scrn->modes; + while (display_mode) + { + mode = modes + num++; + + mode->mode = display_mode; + mode->flags = DGA_CONCURRENT_ACCESS | DGA_PIXMAP_AVAILABLE; + mode->flags |= DGA_FILL_RECT | DGA_BLIT_RECT; + if (display_mode->Flags & V_DBLSCAN) + mode->flags |= DGA_DOUBLESCAN; + if (display_mode->Flags & V_INTERLACE) + mode->flags |= DGA_INTERLACED; + mode->byteOrder = scrn->imageByteOrder; + mode->depth = scrn->depth; + mode->bitsPerPixel = scrn->bitsPerPixel; + mode->red_mask = scrn->mask.red; + mode->green_mask = scrn->mask.green; + mode->blue_mask = scrn->mask.blue; + mode->visualClass = (bpp == 1) ? PseudoColor : TrueColor; + mode->viewportWidth = display_mode->HDisplay; + mode->viewportHeight = display_mode->VDisplay; + mode->xViewportStep = (bpp == 3) ? 2 : 1; + mode->yViewportStep = 1; + mode->viewportFlags = DGA_FLIP_RETRACE; + mode->offset = 0; + mode->address = (unsigned char *) xf86_config->dga_address; + mode->bytesPerScanline = xf86_config->dga_stride; + mode->imageWidth = xf86_config->dga_width; + mode->imageHeight = xf86_config->dga_height; + mode->pixmapWidth = mode->imageWidth; + mode->pixmapHeight = mode->imageHeight; + mode->maxViewportX = mode->imageWidth - mode->viewportWidth; + mode->maxViewportY = mode->imageHeight - mode->viewportHeight; + + display_mode = display_mode->next; + if (display_mode == scrn->modes) + break; + } + if (xf86_config->dga_modes) + xfree (xf86_config->dga_modes); + xf86_config->dga_nmode = num; + xf86_config->dga_modes = modes; + return TRUE; +} + +static Bool +xf86_dga_set_mode(ScrnInfoPtr scrn, DGAModePtr display_mode) +{ + ScreenPtr pScreen = scrn->pScreen; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + + if (!display_mode) + { + if (xf86_config->dga_save_mode) + { + xf86SwitchMode(pScreen, xf86_config->dga_save_mode); + xf86_config->dga_save_mode = NULL; + } + } + else + { + if (!xf86_config->dga_save_mode) + { + xf86_config->dga_save_mode = scrn->currentMode; + xf86SwitchMode(pScreen, display_mode->mode); + } + } + return TRUE; +} + +static int +xf86_dga_get_viewport(ScrnInfoPtr scrn) +{ + return 0; +} + +static void +xf86_dga_set_viewport(ScrnInfoPtr scrn, int x, int y, int flags) +{ + scrn->AdjustFrame(scrn->pScreen->myNum, x, y, flags); +} + +static Bool +xf86_dga_get_drawable_and_gc (ScrnInfoPtr scrn, DrawablePtr *ppDrawable, GCPtr *ppGC) +{ + ScreenPtr pScreen = scrn->pScreen; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + PixmapPtr pPixmap; + GCPtr pGC; + + pPixmap = GetScratchPixmapHeader (pScreen, xf86_config->dga_width, xf86_config->dga_height, + scrn->depth, scrn->bitsPerPixel, xf86_config->dga_stride, + (char *) scrn->memPhysBase + scrn->fbOffset); + if (!pPixmap) + return FALSE; + pGC = GetScratchGC (scrn->depth, pScreen); + if (!pGC) + { + FreeScratchPixmapHeader (pPixmap); + return FALSE; + } + *ppDrawable = &pPixmap->drawable; + *ppGC = pGC; + return TRUE; +} + +static void +xf86_dga_release_drawable_and_gc (ScrnInfoPtr scrn, DrawablePtr pDrawable, GCPtr pGC) +{ + FreeScratchGC (pGC); + FreeScratchPixmapHeader ((PixmapPtr) pDrawable); +} + +static void +xf86_dga_fill_rect(ScrnInfoPtr scrn, int x, int y, int w, int h, unsigned long color) +{ + GCPtr pGC; + DrawablePtr pDrawable; + XID vals[1]; + xRectangle r; + + if (!xf86_dga_get_drawable_and_gc (scrn, &pDrawable, &pGC)) + return; + vals[0] = color; + ChangeGC (pGC, GCForeground, vals); + ValidateGC (pDrawable, pGC); + r.x = x; + r.y = y; + r.width = w; + r.height = h; + pGC->ops->PolyFillRect (pDrawable, pGC, 1, &r); + xf86_dga_release_drawable_and_gc (scrn, pDrawable, pGC); +} + +static void +xf86_dga_sync(ScrnInfoPtr scrn) +{ + ScreenPtr pScreen = scrn->pScreen; + WindowPtr pRoot = WindowTable [pScreen->myNum]; + char buffer[4]; + + pScreen->GetImage (&pRoot->drawable, 0, 0, 1, 1, ZPixmap, ~0L, buffer); +} + +static void +xf86_dga_blit_rect(ScrnInfoPtr scrn, int srcx, int srcy, int w, int h, int dstx, int dsty) +{ + DrawablePtr pDrawable; + GCPtr pGC; + + if (!xf86_dga_get_drawable_and_gc (scrn, &pDrawable, &pGC)) + return; + ValidateGC (pDrawable, pGC); + pGC->ops->CopyArea (pDrawable, pDrawable, pGC, srcx, srcy, w, h, dstx, dsty); + xf86_dga_release_drawable_and_gc (scrn, pDrawable, pGC); +} + +static Bool +xf86_dga_open_framebuffer(ScrnInfoPtr scrn, + char **name, + unsigned char **mem, int *size, int *offset, int *flags) +{ + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + + *size = xf86_config->dga_stride * xf86_config->dga_height; + *mem = (unsigned char *) (xf86_config->dga_address); + *offset = 0; + *flags = DGA_NEED_ROOT; + + return TRUE; +} + +static void +xf86_dga_close_framebuffer(ScrnInfoPtr scrn) +{ +} + +static DGAFunctionRec xf86_dga_funcs = { + xf86_dga_open_framebuffer, + xf86_dga_close_framebuffer, + xf86_dga_set_mode, + xf86_dga_set_viewport, + xf86_dga_get_viewport, + xf86_dga_sync, + xf86_dga_fill_rect, + xf86_dga_blit_rect, + NULL +}; + +_X_EXPORT Bool +xf86DiDGAReInit (ScreenPtr pScreen) +{ + ScrnInfoPtr scrn = xf86Screens[pScreen->myNum]; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + + if (!xf86_dga_get_modes (pScreen)) + return FALSE; + + return DGAReInitModes (pScreen, xf86_config->dga_modes, xf86_config->dga_nmode); +} + +_X_EXPORT Bool +xf86DiDGAInit (ScreenPtr pScreen, unsigned long dga_address) +{ + ScrnInfoPtr scrn = xf86Screens[pScreen->myNum]; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + + xf86_config->dga_flags = 0; + xf86_config->dga_address = dga_address; + xf86_config->dga_width = scrn->virtualX; + xf86_config->dga_height = scrn->virtualY; + xf86_config->dga_stride = scrn->displayWidth * scrn->bitsPerPixel >> 3; + + if (!xf86_dga_get_modes (pScreen)) + return FALSE; + + return DGAInit(pScreen, &xf86_dga_funcs, xf86_config->dga_modes, xf86_config->dga_nmode); +} diff --git a/driver/xf86-video-intel/src/modes/xf86EdidModes.c b/driver/xf86-video-intel/src/modes/xf86EdidModes.c new file mode 100644 index 000000000..8b5e69d9a --- /dev/null +++ b/driver/xf86-video-intel/src/modes/xf86EdidModes.c @@ -0,0 +1,491 @@ +/* + * Copyright 2006 Luc Verhaegen. + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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 This file covers code to convert a xf86MonPtr containing EDID-probed + * information into a list of modes, including applying monitor-specific + * quirks to fix broken EDID data. + */ +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#else +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#endif + +#include "xf86.h" +#include "xf86DDC.h" +#include <X11/Xatom.h> +#include "property.h" +#include "propertyst.h" +#include "xf86DDC.h" +#include "xf86Crtc.h" +#include <string.h> +#include <math.h> + +/* + * Quirks to work around broken EDID data from various monitors. + */ + +typedef enum { + DDC_QUIRK_NONE = 0, + /* First detailed mode is bogus, prefer largest mode at 60hz */ + DDC_QUIRK_PREFER_LARGE_60 = 1 << 0, + /* 135MHz clock is too high, drop a bit */ + DDC_QUIRK_135_CLOCK_TOO_HIGH = 1 << 1, +} ddc_quirk_t; + +static Bool quirk_prefer_large_60 (int scrnIndex, xf86MonPtr DDC) +{ + /* Belinea 10 15 55 */ + if (memcmp (DDC->vendor.name, "MAX", 4) == 0 && + DDC->vendor.prod_id == 1516) + return TRUE; + + /* Acer AL1706 */ + if (memcmp (DDC->vendor.name, "ACR", 4) == 0 && + DDC->vendor.prod_id == 44358) + return TRUE; + + /* Bug #10814: Samsung SyncMaster 225BW */ + if (memcmp (DDC->vendor.name, "SAM", 4) == 0 && + DDC->vendor.prod_id == 596) + return TRUE; + + /* Bug #10545: Samsung SyncMaster 226BW */ + if (memcmp (DDC->vendor.name, "SAM", 4) == 0 && + DDC->vendor.prod_id == 638) + return TRUE; + + return FALSE; +} + +static Bool quirk_135_clock_too_high (int scrnIndex, xf86MonPtr DDC) +{ + /* Envision Peripherals, Inc. EN-7100e. See bug #9550. */ + if (memcmp (DDC->vendor.name, "EPI", 4) == 0 && + DDC->vendor.prod_id == 59264) + return TRUE; + + return FALSE; +} + +typedef struct { + Bool (*detect) (int scrnIndex, xf86MonPtr DDC); + ddc_quirk_t quirk; + char *description; +} ddc_quirk_map_t; + +static const ddc_quirk_map_t ddc_quirks[] = { + { + quirk_prefer_large_60, DDC_QUIRK_PREFER_LARGE_60, + "Detailed timing is not preferred, use largest mode at 60Hz" + }, + { + quirk_135_clock_too_high, DDC_QUIRK_135_CLOCK_TOO_HIGH, + "Recommended 135MHz pixel clock is too high" + }, + { + NULL, DDC_QUIRK_NONE, + "No known quirks" + }, +}; + +/* + * TODO: + * - for those with access to the VESA DMT standard; review please. + */ +#define MODEPREFIX(name) NULL, NULL, name, 0,M_T_DRIVER +#define MODESUFFIX 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,FALSE,FALSE,0,NULL,0,0.0,0.0 + +static DisplayModeRec DDCEstablishedModes[17] = { + { MODEPREFIX("800x600"), 40000, 800, 840, 968, 1056, 0, 600, 601, 605, 628, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@60Hz */ + { MODEPREFIX("800x600"), 36000, 800, 824, 896, 1024, 0, 600, 601, 603, 625, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@56Hz */ + { MODEPREFIX("640x480"), 31500, 640, 656, 720, 840, 0, 480, 481, 484, 500, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@75Hz */ + { MODEPREFIX("640x480"), 31500, 640, 664, 704, 832, 0, 480, 489, 491, 520, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@72Hz */ + { MODEPREFIX("640x480"), 30240, 640, 704, 768, 864, 0, 480, 483, 486, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@67Hz */ + { MODEPREFIX("640x480"), 25200, 640, 656, 752, 800, 0, 480, 490, 492, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@60Hz */ + { MODEPREFIX("720x400"), 35500, 720, 738, 846, 900, 0, 400, 421, 423, 449, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 720x400@88Hz */ + { MODEPREFIX("720x400"), 28320, 720, 738, 846, 900, 0, 400, 412, 414, 449, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 720x400@70Hz */ + { MODEPREFIX("1280x1024"), 135000, 1280, 1296, 1440, 1688, 0, 1024, 1025, 1028, 1066, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x1024@75Hz */ + { MODEPREFIX("1024x768"), 78800, 1024, 1040, 1136, 1312, 0, 768, 769, 772, 800, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1024x768@75Hz */ + { MODEPREFIX("1024x768"), 75000, 1024, 1048, 1184, 1328, 0, 768, 771, 777, 806, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 1024x768@70Hz */ + { MODEPREFIX("1024x768"), 65000, 1024, 1048, 1184, 1344, 0, 768, 771, 777, 806, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 1024x768@60Hz */ + { MODEPREFIX("1024x768"), 44900, 1024, 1032, 1208, 1264, 0, 768, 768, 776, 817, 0, V_PHSYNC | V_PVSYNC | V_INTERLACE, MODESUFFIX }, /* 1024x768@43Hz */ + { MODEPREFIX("832x624"), 57284, 832, 864, 928, 1152, 0, 624, 625, 628, 667, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 832x624@75Hz */ + { MODEPREFIX("800x600"), 49500, 800, 816, 896, 1056, 0, 600, 601, 604, 625, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@75Hz */ + { MODEPREFIX("800x600"), 50000, 800, 856, 976, 1040, 0, 600, 637, 643, 666, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@72Hz */ + { MODEPREFIX("1152x864"), 108000, 1152, 1216, 1344, 1600, 0, 864, 865, 868, 900, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1152x864@75Hz */ +}; + +static DisplayModePtr +DDCModesFromEstablished(int scrnIndex, struct established_timings *timing, + ddc_quirk_t quirks) +{ + DisplayModePtr Modes = NULL, Mode = NULL; + CARD32 bits = (timing->t1) | (timing->t2 << 8) | + ((timing->t_manu & 0x80) << 9); + int i; + + for (i = 0; i < 17; i++) { + if (bits & (0x01 << i)) { + Mode = xf86DuplicateMode(&DDCEstablishedModes[i]); + Modes = xf86ModesAdd(Modes, Mode); + } + } + + return Modes; +} + +/* + * + */ +static DisplayModePtr +DDCModesFromStandardTiming(int scrnIndex, struct std_timings *timing, + ddc_quirk_t quirks) +{ + DisplayModePtr Modes = NULL, Mode = NULL; + int i; + + for (i = 0; i < STD_TIMINGS; i++) { + if (timing[i].hsize && timing[i].vsize && timing[i].refresh) { + Mode = xf86CVTMode(timing[i].hsize, timing[i].vsize, + timing[i].refresh, FALSE, FALSE); + Mode->type = M_T_DRIVER; + Modes = xf86ModesAdd(Modes, Mode); + } + } + + return Modes; +} + +/* + * + */ +static DisplayModePtr +DDCModeFromDetailedTiming(int scrnIndex, struct detailed_timings *timing, + int preferred, ddc_quirk_t quirks) +{ + DisplayModePtr Mode; + + /* + * Refuse to create modes that are insufficiently large. 64 is a random + * number, maybe the spec says something about what the minimum is. In + * particular I see this frequently with _old_ EDID, 1.0 or so, so maybe + * our parser is just being too aggresive there. + */ + if (timing->h_active < 64 || timing->v_active < 64) { + xf86DrvMsg(scrnIndex, X_INFO, + "%s: Ignoring tiny %dx%d mode\n", __func__, + timing->h_active, timing->v_active); + return NULL; + } + + /* We don't do stereo */ + if (timing->stereo) { + xf86DrvMsg(scrnIndex, X_INFO, + "%s: Ignoring: We don't handle stereo.\n", __func__); + return NULL; + } + + /* We only do seperate sync currently */ + if (timing->sync != 0x03) { + xf86DrvMsg(scrnIndex, X_INFO, + "%s: %dx%d Warning: We only handle seperate" + " sync.\n", __func__, timing->h_active, timing->v_active); + } + + Mode = xnfalloc(sizeof(DisplayModeRec)); + memset(Mode, 0, sizeof(DisplayModeRec)); + + Mode->type = M_T_DRIVER; + if (preferred) + Mode->type |= M_T_PREFERRED; + + if( ( quirks & DDC_QUIRK_135_CLOCK_TOO_HIGH ) && + timing->clock == 135000000 ) + Mode->Clock = 108880; + else + Mode->Clock = timing->clock / 1000.0; + + Mode->HDisplay = timing->h_active; + Mode->HSyncStart = timing->h_active + timing->h_sync_off; + Mode->HSyncEnd = Mode->HSyncStart + timing->h_sync_width; + Mode->HTotal = timing->h_active + timing->h_blanking; + + Mode->VDisplay = timing->v_active; + Mode->VSyncStart = timing->v_active + timing->v_sync_off; + Mode->VSyncEnd = Mode->VSyncStart + timing->v_sync_width; + Mode->VTotal = timing->v_active + timing->v_blanking; + + xf86SetModeDefaultName(Mode); + + /* We ignore h/v_size and h/v_border for now. */ + + if (timing->interlaced) + Mode->Flags |= V_INTERLACE; + + if (timing->misc & 0x02) + Mode->Flags |= V_PVSYNC; + else + Mode->Flags |= V_NVSYNC; + + if (timing->misc & 0x01) + Mode->Flags |= V_PHSYNC; + else + Mode->Flags |= V_NHSYNC; + + return Mode; +} + +/* + * + */ +static void +DDCGuessRangesFromModes(int scrnIndex, MonPtr Monitor, DisplayModePtr Modes) +{ + DisplayModePtr Mode = Modes; + + if (!Monitor || !Modes) + return; + + /* set up the ranges for scanning through the modes */ + Monitor->nHsync = 1; + Monitor->hsync[0].lo = 1024.0; + Monitor->hsync[0].hi = 0.0; + + Monitor->nVrefresh = 1; + Monitor->vrefresh[0].lo = 1024.0; + Monitor->vrefresh[0].hi = 0.0; + + while (Mode) { + if (!Mode->HSync) + Mode->HSync = ((float) Mode->Clock ) / ((float) Mode->HTotal); + + if (!Mode->VRefresh) + Mode->VRefresh = (1000.0 * ((float) Mode->Clock)) / + ((float) (Mode->HTotal * Mode->VTotal)); + + if (Mode->HSync < Monitor->hsync[0].lo) + Monitor->hsync[0].lo = Mode->HSync; + + if (Mode->HSync > Monitor->hsync[0].hi) + Monitor->hsync[0].hi = Mode->HSync; + + if (Mode->VRefresh < Monitor->vrefresh[0].lo) + Monitor->vrefresh[0].lo = Mode->VRefresh; + + if (Mode->VRefresh > Monitor->vrefresh[0].hi) + Monitor->vrefresh[0].hi = Mode->VRefresh; + + Mode = Mode->next; + } +} + +_X_EXPORT DisplayModePtr +xf86DDCGetModes(int scrnIndex, xf86MonPtr DDC) +{ + int preferred, i; + DisplayModePtr Modes = NULL, Mode; + ddc_quirk_t quirks; + + xf86DrvMsg (scrnIndex, X_INFO, "EDID vendor \"%s\", prod id %d\n", + DDC->vendor.name, DDC->vendor.prod_id); + quirks = DDC_QUIRK_NONE; + for (i = 0; ddc_quirks[i].detect; i++) + if (ddc_quirks[i].detect (scrnIndex, DDC)) + { + xf86DrvMsg (scrnIndex, X_INFO, " EDID quirk: %s\n", + ddc_quirks[i].description); + quirks |= ddc_quirks[i].quirk; + } + + preferred = PREFERRED_TIMING_MODE(DDC->features.msc); + if (quirks & DDC_QUIRK_PREFER_LARGE_60) + preferred = 0; + + for (i = 0; i < DET_TIMINGS; i++) { + struct detailed_monitor_section *det_mon = &DDC->det_mon[i]; + + switch (det_mon->type) { + case DT: + Mode = DDCModeFromDetailedTiming(scrnIndex, + &det_mon->section.d_timings, + preferred, + quirks); + preferred = 0; + Modes = xf86ModesAdd(Modes, Mode); + break; + case DS_STD_TIMINGS: + Mode = DDCModesFromStandardTiming(scrnIndex, + det_mon->section.std_t, + quirks); + Modes = xf86ModesAdd(Modes, Mode); + break; + default: + break; + } + } + + /* Add established timings */ + Mode = DDCModesFromEstablished(scrnIndex, &DDC->timings1, quirks); + Modes = xf86ModesAdd(Modes, Mode); + + /* Add standard timings */ + Mode = DDCModesFromStandardTiming(scrnIndex, DDC->timings2, quirks); + Modes = xf86ModesAdd(Modes, Mode); + + if (quirks & DDC_QUIRK_PREFER_LARGE_60) + { + DisplayModePtr best = Modes; + for (Mode = Modes; Mode; Mode = Mode->next) + { + if (Mode == best) continue; + if (Mode->HDisplay * Mode->VDisplay > best->HDisplay * best->VDisplay) + { + best = Mode; + continue; + } + if (Mode->HDisplay * Mode->VDisplay == best->HDisplay * best->VDisplay) + { + double mode_refresh = xf86ModeVRefresh (Mode); + double best_refresh = xf86ModeVRefresh (best); + double mode_dist = fabs(mode_refresh - 60.0); + double best_dist = fabs(best_refresh - 60.0); + if (mode_dist < best_dist) + { + best = Mode; + continue; + } + } + } + if (best) + best->type |= M_T_PREFERRED; + } + return Modes; +} + +/* + * Fill out MonPtr with xf86MonPtr information. + */ +_X_EXPORT void +xf86DDCMonitorSet(int scrnIndex, MonPtr Monitor, xf86MonPtr DDC) +{ + DisplayModePtr Modes = NULL, Mode; + int i, clock; + Bool have_hsync = FALSE, have_vrefresh = FALSE, have_maxpixclock = FALSE; + + if (!Monitor || !DDC) + return; + + Monitor->DDC = DDC; + + Monitor->widthmm = 10 * DDC->features.hsize; + Monitor->heightmm = 10 * DDC->features.vsize; + + /* If this is a digital display, then we can use reduced blanking */ + if (DDC->features.input_type) + Monitor->reducedblanking = TRUE; + /* Allow the user to also enable this through config */ + + Modes = xf86DDCGetModes(scrnIndex, DDC); + + /* Skip EDID ranges if they were specified in the config file */ + have_hsync = (Monitor->nHsync != 0); + have_vrefresh = (Monitor->nVrefresh != 0); + have_maxpixclock = (Monitor->maxPixClock != 0); + + /* Go through the detailed monitor sections */ + for (i = 0; i < DET_TIMINGS; i++) { + switch (DDC->det_mon[i].type) { + case DS_RANGES: + if (!have_hsync) { + if (!Monitor->nHsync) + xf86DrvMsg(scrnIndex, X_INFO, + "Using EDID range info for horizontal sync\n"); + Monitor->hsync[Monitor->nHsync].lo = + DDC->det_mon[i].section.ranges.min_h; + Monitor->hsync[Monitor->nHsync].hi = + DDC->det_mon[i].section.ranges.max_h; + Monitor->nHsync++; + } else { + xf86DrvMsg(scrnIndex, X_INFO, + "Using hsync ranges from config file\n"); + } + + if (!have_vrefresh) { + if (!Monitor->nVrefresh) + xf86DrvMsg(scrnIndex, X_INFO, + "Using EDID range info for vertical refresh\n"); + Monitor->vrefresh[Monitor->nVrefresh].lo = + DDC->det_mon[i].section.ranges.min_v; + Monitor->vrefresh[Monitor->nVrefresh].hi = + DDC->det_mon[i].section.ranges.max_v; + Monitor->nVrefresh++; + } else { + xf86DrvMsg(scrnIndex, X_INFO, + "Using vrefresh ranges from config file\n"); + } + + clock = DDC->det_mon[i].section.ranges.max_clock * 1000; + if (!have_maxpixclock && clock > Monitor->maxPixClock) + Monitor->maxPixClock = clock; + + break; + default: + break; + } + } + + if (Modes) { + /* Print Modes */ + xf86DrvMsg(scrnIndex, X_INFO, "Printing DDC gathered Modelines:\n"); + + Mode = Modes; + while (Mode) { + xf86PrintModeline(scrnIndex, Mode); + Mode = Mode->next; + } + + /* Do we still need ranges to be filled in? */ + if (!Monitor->nHsync || !Monitor->nVrefresh) + DDCGuessRangesFromModes(scrnIndex, Monitor, Modes); + + /* look for last Mode */ + Mode = Modes; + + while (Mode->next) + Mode = Mode->next; + + /* add to MonPtr */ + if (Monitor->Modes) { + Monitor->Last->next = Modes; + Modes->prev = Monitor->Last; + Monitor->Last = Mode; + } else { + Monitor->Modes = Modes; + Monitor->Last = Mode; + } + } +} diff --git a/driver/xf86-video-intel/src/modes/xf86Modes.c b/driver/xf86-video-intel/src/modes/xf86Modes.c new file mode 100644 index 000000000..f49c2921c --- /dev/null +++ b/driver/xf86-video-intel/src/modes/xf86Modes.c @@ -0,0 +1,661 @@ +/* + * Copyright (c) 1997-2003 by The XFree86 Project, Inc. + * + * 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 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 + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + * + * Except as contained in this notice, the name of the copyright holder(s) + * and author(s) shall not be used in advertising or otherwise to promote + * the sale, use or other dealings in this Software without prior written + * authorization from the copyright holder(s) and author(s). + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#else +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#endif + +#include "xf86Modes.h" +#include "xf86Priv.h" + +extern XF86ConfigPtr xf86configptr; + +/** + * @file this file contains symbols from xf86Mode.c and friends that are static + * there but we still want to use. We need to come up with better API here. + */ + +#if XORG_VERSION_CURRENT <= XORG_VERSION_NUMERIC(7,2,99,2,0) +/** + * Calculates the horizontal sync rate of a mode. + * + * Exact copy of xf86Mode.c's. + */ +_X_EXPORT double +xf86ModeHSync(DisplayModePtr mode) +{ + double hsync = 0.0; + + if (mode->HSync > 0.0) + hsync = mode->HSync; + else if (mode->HTotal > 0) + hsync = (float)mode->Clock / (float)mode->HTotal; + + return hsync; +} + +/** + * Calculates the vertical refresh rate of a mode. + * + * Exact copy of xf86Mode.c's. + */ +_X_EXPORT double +xf86ModeVRefresh(DisplayModePtr mode) +{ + double refresh = 0.0; + + if (mode->VRefresh > 0.0) + refresh = mode->VRefresh; + else if (mode->HTotal > 0 && mode->VTotal > 0) { + refresh = mode->Clock * 1000.0 / mode->HTotal / mode->VTotal; + if (mode->Flags & V_INTERLACE) + refresh *= 2.0; + if (mode->Flags & V_DBLSCAN) + refresh /= 2.0; + if (mode->VScan > 1) + refresh /= (float)(mode->VScan); + } + return refresh; +} + +_X_EXPORT int +xf86ModeWidth (DisplayModePtr mode, Rotation rotation) +{ + switch (rotation & 0xf) { + case RR_Rotate_0: + case RR_Rotate_180: + return mode->HDisplay; + case RR_Rotate_90: + case RR_Rotate_270: + return mode->VDisplay; + default: + return 0; + } +} + +_X_EXPORT int +xf86ModeHeight (DisplayModePtr mode, Rotation rotation) +{ + switch (rotation & 0xf) { + case RR_Rotate_0: + case RR_Rotate_180: + return mode->VDisplay; + case RR_Rotate_90: + case RR_Rotate_270: + return mode->HDisplay; + default: + return 0; + } +} + +/** Sets a default mode name of <width>x<height> on a mode. */ +_X_EXPORT void +xf86SetModeDefaultName(DisplayModePtr mode) +{ + if (mode->name != NULL) + xfree(mode->name); + + mode->name = XNFprintf("%dx%d", mode->HDisplay, mode->VDisplay); +} + +/* + * xf86SetModeCrtc + * + * Initialises the Crtc parameters for a mode. The initialisation includes + * adjustments for interlaced and double scan modes. + * + * Exact copy of xf86Mode.c's. + */ +_X_EXPORT void +xf86SetModeCrtc(DisplayModePtr p, int adjustFlags) +{ + if ((p == NULL) || ((p->type & M_T_CRTC_C) == M_T_BUILTIN)) + return; + + p->CrtcHDisplay = p->HDisplay; + p->CrtcHSyncStart = p->HSyncStart; + p->CrtcHSyncEnd = p->HSyncEnd; + p->CrtcHTotal = p->HTotal; + p->CrtcHSkew = p->HSkew; + p->CrtcVDisplay = p->VDisplay; + p->CrtcVSyncStart = p->VSyncStart; + p->CrtcVSyncEnd = p->VSyncEnd; + p->CrtcVTotal = p->VTotal; + if (p->Flags & V_INTERLACE) { + if (adjustFlags & INTERLACE_HALVE_V) { + p->CrtcVDisplay /= 2; + p->CrtcVSyncStart /= 2; + p->CrtcVSyncEnd /= 2; + p->CrtcVTotal /= 2; + } + /* Force interlaced modes to have an odd VTotal */ + /* maybe we should only do this when INTERLACE_HALVE_V is set? */ + p->CrtcVTotal |= 1; + } + + if (p->Flags & V_DBLSCAN) { + p->CrtcVDisplay *= 2; + p->CrtcVSyncStart *= 2; + p->CrtcVSyncEnd *= 2; + p->CrtcVTotal *= 2; + } + if (p->VScan > 1) { + p->CrtcVDisplay *= p->VScan; + p->CrtcVSyncStart *= p->VScan; + p->CrtcVSyncEnd *= p->VScan; + p->CrtcVTotal *= p->VScan; + } + p->CrtcVBlankStart = min(p->CrtcVSyncStart, p->CrtcVDisplay); + p->CrtcVBlankEnd = max(p->CrtcVSyncEnd, p->CrtcVTotal); + p->CrtcHBlankStart = min(p->CrtcHSyncStart, p->CrtcHDisplay); + p->CrtcHBlankEnd = max(p->CrtcHSyncEnd, p->CrtcHTotal); + + p->CrtcHAdjusted = FALSE; + p->CrtcVAdjusted = FALSE; +} + +/** + * Allocates and returns a copy of pMode, including pointers within pMode. + */ +_X_EXPORT DisplayModePtr +xf86DuplicateMode(DisplayModePtr pMode) +{ + DisplayModePtr pNew; + + pNew = xnfalloc(sizeof(DisplayModeRec)); + *pNew = *pMode; + pNew->next = NULL; + pNew->prev = NULL; + if (pNew->name == NULL) { + xf86SetModeDefaultName(pMode); + } else { + pNew->name = xnfstrdup(pMode->name); + } + + return pNew; +} + +/** + * Duplicates every mode in the given list and returns a pointer to the first + * mode. + * + * \param modeList doubly-linked mode list + */ +_X_EXPORT DisplayModePtr +xf86DuplicateModes(ScrnInfoPtr pScrn, DisplayModePtr modeList) +{ + DisplayModePtr first = NULL, last = NULL; + DisplayModePtr mode; + + for (mode = modeList; mode != NULL; mode = mode->next) { + DisplayModePtr new; + + new = xf86DuplicateMode(mode); + + /* Insert pNew into modeList */ + if (last) { + last->next = new; + new->prev = last; + } else { + first = new; + new->prev = NULL; + } + new->next = NULL; + last = new; + } + + return first; +} + +/** + * Returns true if the given modes should program to the same timings. + * + * This doesn't use Crtc values, as it might be used on ModeRecs without the + * Crtc values set. So, it's assumed that the other numbers are enough. + * + * This isn't in xf86Modes.c, but it might deserve to be there. + */ +_X_EXPORT Bool +xf86ModesEqual(DisplayModePtr pMode1, DisplayModePtr pMode2) +{ + if (pMode1->Clock == pMode2->Clock && + pMode1->HDisplay == pMode2->HDisplay && + pMode1->HSyncStart == pMode2->HSyncStart && + pMode1->HSyncEnd == pMode2->HSyncEnd && + pMode1->HTotal == pMode2->HTotal && + pMode1->HSkew == pMode2->HSkew && + pMode1->VDisplay == pMode2->VDisplay && + pMode1->VSyncStart == pMode2->VSyncStart && + pMode1->VSyncEnd == pMode2->VSyncEnd && + pMode1->VTotal == pMode2->VTotal && + pMode1->VScan == pMode2->VScan && + pMode1->Flags == pMode2->Flags) + { + return TRUE; + } else { + return FALSE; + } +} + +/* exact copy of xf86Mode.c */ +static void +add(char **p, char *new) +{ + *p = xnfrealloc(*p, strlen(*p) + strlen(new) + 2); + strcat(*p, " "); + strcat(*p, new); +} + +/** + * Print out a modeline. + * + * Convenient VRefresh printing was added, though, compared to xf86Mode.c + */ +_X_EXPORT void +xf86PrintModeline(int scrnIndex,DisplayModePtr mode) +{ + char tmp[256]; + char *flags = xnfcalloc(1, 1); + + if (mode->HSkew) { + snprintf(tmp, 256, "hskew %i", mode->HSkew); + add(&flags, tmp); + } + if (mode->VScan) { + snprintf(tmp, 256, "vscan %i", mode->VScan); + add(&flags, tmp); + } + if (mode->Flags & V_INTERLACE) add(&flags, "interlace"); + if (mode->Flags & V_CSYNC) add(&flags, "composite"); + if (mode->Flags & V_DBLSCAN) add(&flags, "doublescan"); + if (mode->Flags & V_BCAST) add(&flags, "bcast"); + if (mode->Flags & V_PHSYNC) add(&flags, "+hsync"); + if (mode->Flags & V_NHSYNC) add(&flags, "-hsync"); + if (mode->Flags & V_PVSYNC) add(&flags, "+vsync"); + if (mode->Flags & V_NVSYNC) add(&flags, "-vsync"); + if (mode->Flags & V_PCSYNC) add(&flags, "+csync"); + if (mode->Flags & V_NCSYNC) add(&flags, "-csync"); +#if 0 + if (mode->Flags & V_CLKDIV2) add(&flags, "vclk/2"); +#endif + xf86DrvMsg(scrnIndex, X_INFO, + "Modeline \"%s\"x%.01f %6.2f %i %i %i %i %i %i %i %i%s " + "(%.01f kHz)\n", + mode->name, mode->VRefresh, mode->Clock/1000., mode->HDisplay, + mode->HSyncStart, mode->HSyncEnd, mode->HTotal, + mode->VDisplay, mode->VSyncStart, mode->VSyncEnd, + mode->VTotal, flags, xf86ModeHSync(mode)); + xfree(flags); +} +#endif /* XORG_VERSION_CURRENT <= 7.2.99.2 */ + +/** + * Marks as bad any modes with unsupported flags. + * + * \param modeList doubly-linked or circular list of modes. + * \param flags flags supported by the driver. + * + * \bug only V_INTERLACE and V_DBLSCAN are supported. Is that enough? + * + * This is not in xf86Modes.c, but would be part of the proposed new API. + */ +_X_EXPORT void +xf86ValidateModesFlags(ScrnInfoPtr pScrn, DisplayModePtr modeList, + int flags) +{ + DisplayModePtr mode; + + for (mode = modeList; mode != NULL; mode = mode->next) { + if (mode->Flags & V_INTERLACE && !(flags & V_INTERLACE)) + mode->status = MODE_NO_INTERLACE; + if (mode->Flags & V_DBLSCAN && !(flags & V_DBLSCAN)) + mode->status = MODE_NO_DBLESCAN; + } +} + +/** + * Marks as bad any modes extending beyond the given max X, Y, or pitch. + * + * \param modeList doubly-linked or circular list of modes. + * + * This is not in xf86Modes.c, but would be part of the proposed new API. + */ +_X_EXPORT void +xf86ValidateModesSize(ScrnInfoPtr pScrn, DisplayModePtr modeList, + int maxX, int maxY, int maxPitch) +{ + DisplayModePtr mode; + + for (mode = modeList; mode != NULL; mode = mode->next) { + if (maxPitch > 0 && mode->HDisplay > maxPitch) + mode->status = MODE_BAD_WIDTH; + + if (maxX > 0 && mode->HDisplay > maxX) + mode->status = MODE_VIRTUAL_X; + + if (maxY > 0 && mode->VDisplay > maxY) + mode->status = MODE_VIRTUAL_Y; + + if (mode->next == modeList) + break; + } +} + +/** + * Marks as bad any modes that aren't supported by the given monitor's + * hsync and vrefresh ranges. + * + * \param modeList doubly-linked or circular list of modes. + * + * This is not in xf86Modes.c, but would be part of the proposed new API. + */ +_X_EXPORT void +xf86ValidateModesSync(ScrnInfoPtr pScrn, DisplayModePtr modeList, + MonPtr mon) +{ + DisplayModePtr mode; + + for (mode = modeList; mode != NULL; mode = mode->next) { + Bool bad; + int i; + + bad = TRUE; + for (i = 0; i < mon->nHsync; i++) { + if (xf86ModeHSync(mode) >= mon->hsync[i].lo && + xf86ModeHSync(mode) <= mon->hsync[i].hi) + { + bad = FALSE; + } + } + if (bad) + mode->status = MODE_HSYNC; + + bad = TRUE; + for (i = 0; i < mon->nVrefresh; i++) { + if (xf86ModeVRefresh(mode) >= mon->vrefresh[i].lo && + xf86ModeVRefresh(mode) <= mon->vrefresh[i].hi) + { + bad = FALSE; + } + } + if (bad) + mode->status = MODE_VSYNC; + + if (mode->next == modeList) + break; + } +} + +/** + * Marks as bad any modes extending beyond outside of the given clock ranges. + * + * \param modeList doubly-linked or circular list of modes. + * \param min pointer to minimums of clock ranges + * \param max pointer to maximums of clock ranges + * \param n_ranges number of ranges. + * + * This is not in xf86Modes.c, but would be part of the proposed new API. + */ +_X_EXPORT void +xf86ValidateModesClocks(ScrnInfoPtr pScrn, DisplayModePtr modeList, + int *min, int *max, int n_ranges) +{ + DisplayModePtr mode; + int i; + + for (mode = modeList; mode != NULL; mode = mode->next) { + Bool good = FALSE; + for (i = 0; i < n_ranges; i++) { + if (mode->Clock >= min[i] && mode->Clock <= max[i]) { + good = TRUE; + break; + } + } + if (!good) + mode->status = MODE_CLOCK_RANGE; + } +} + +/** + * If the user has specified a set of mode names to use, mark as bad any modes + * not listed. + * + * The user mode names specified are prefixes to names of modes, so "1024x768" + * will match modes named "1024x768", "1024x768x75", "1024x768-good", but + * "1024x768x75" would only match "1024x768x75" from that list. + * + * MODE_BAD is used as the rejection flag, for lack of a better flag. + * + * \param modeList doubly-linked or circular list of modes. + * + * This is not in xf86Modes.c, but would be part of the proposed new API. + */ +_X_EXPORT void +xf86ValidateModesUserConfig(ScrnInfoPtr pScrn, DisplayModePtr modeList) +{ + DisplayModePtr mode; + + if (pScrn->display->modes[0] == NULL) + return; + + for (mode = modeList; mode != NULL; mode = mode->next) { + int i; + Bool good = FALSE; + + for (i = 0; pScrn->display->modes[i] != NULL; i++) { + if (strncmp(pScrn->display->modes[i], mode->name, + strlen(pScrn->display->modes[i])) == 0) { + good = TRUE; + break; + } + } + if (!good) + mode->status = MODE_BAD; + } +} + + +/** + * Frees any modes from the list with a status other than MODE_OK. + * + * \param modeList pointer to a doubly-linked or circular list of modes. + * \param verbose determines whether the reason for mode invalidation is + * printed. + * + * This is not in xf86Modes.c, but would be part of the proposed new API. + */ +_X_EXPORT void +xf86PruneInvalidModes(ScrnInfoPtr pScrn, DisplayModePtr *modeList, + Bool verbose) +{ + DisplayModePtr mode; + + for (mode = *modeList; mode != NULL;) { + DisplayModePtr next = mode->next, first = *modeList; + + if (mode->status != MODE_OK) { + if (verbose) { + char *type = ""; + if (mode->type & M_T_BUILTIN) + type = "built-in "; + else if (mode->type & M_T_DEFAULT) + type = "default "; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Not using %smode \"%s\" (%s)\n", type, mode->name, + xf86ModeStatusToString(mode->status)); + } + xf86DeleteMode(modeList, mode); + } + + if (next == first) + break; + mode = next; + } +} + +/** + * Adds the new mode into the mode list, and returns the new list + * + * \param modes doubly-linked mode list. + */ +_X_EXPORT DisplayModePtr +xf86ModesAdd(DisplayModePtr modes, DisplayModePtr new) +{ + if (modes == NULL) + return new; + + if (new) { + DisplayModePtr mode = modes; + + while (mode->next) + mode = mode->next; + + mode->next = new; + new->prev = mode; + } + + return modes; +} + +/** + * Build a mode list from a list of config file modes + */ +static DisplayModePtr +xf86GetConfigModes (XF86ConfModeLinePtr conf_mode) +{ + DisplayModePtr head = NULL, prev = NULL, mode; + + for (; conf_mode; conf_mode = (XF86ConfModeLinePtr) conf_mode->list.next) + { + mode = xcalloc(1, sizeof(DisplayModeRec)); + if (!mode) + continue; + mode->name = xstrdup(conf_mode->ml_identifier); + if (!mode->name) + { + xfree (mode); + continue; + } + mode->type = 0; + mode->Clock = conf_mode->ml_clock; + mode->HDisplay = conf_mode->ml_hdisplay; + mode->HSyncStart = conf_mode->ml_hsyncstart; + mode->HSyncEnd = conf_mode->ml_hsyncend; + mode->HTotal = conf_mode->ml_htotal; + mode->VDisplay = conf_mode->ml_vdisplay; + mode->VSyncStart = conf_mode->ml_vsyncstart; + mode->VSyncEnd = conf_mode->ml_vsyncend; + mode->VTotal = conf_mode->ml_vtotal; + mode->Flags = conf_mode->ml_flags; + mode->HSkew = conf_mode->ml_hskew; + mode->VScan = conf_mode->ml_vscan; + + mode->prev = prev; + mode->next = NULL; + if (prev) + prev->next = mode; + else + head = mode; + prev = mode; + } + return head; +} + +/** + * Build a mode list from a monitor configuration + */ +_X_EXPORT DisplayModePtr +xf86GetMonitorModes (ScrnInfoPtr pScrn, XF86ConfMonitorPtr conf_monitor) +{ + DisplayModePtr modes = NULL; + XF86ConfModesLinkPtr modes_link; + + if (!conf_monitor) + return NULL; + + /* + * first we collect the mode lines from the UseModes directive + */ + for (modes_link = conf_monitor->mon_modes_sect_lst; + modes_link; + modes_link = modes_link->list.next) + { + /* If this modes link hasn't been resolved, go look it up now */ + if (!modes_link->ml_modes) + modes_link->ml_modes = xf86findModes (modes_link->ml_modes_str, + xf86configptr->conf_modes_lst); + if (modes_link->ml_modes) + modes = xf86ModesAdd (modes, + xf86GetConfigModes (modes_link->ml_modes->mon_modeline_lst)); + } + + return xf86ModesAdd (modes, + xf86GetConfigModes (conf_monitor->mon_modeline_lst)); +} + +/** + * Build a mode list containing all of the default modes + */ +_X_EXPORT DisplayModePtr +xf86GetDefaultModes (Bool interlaceAllowed, Bool doubleScanAllowed) +{ + DisplayModePtr head = NULL, prev = NULL, mode; + int i; + + for (i = 0; xf86DefaultModes[i].name != NULL; i++) + { + DisplayModePtr defMode = &xf86DefaultModes[i]; + + if (!interlaceAllowed && (defMode->Flags & V_INTERLACE)) + continue; + if (!doubleScanAllowed && (defMode->Flags & V_DBLSCAN)) + continue; + + mode = xalloc(sizeof(DisplayModeRec)); + if (!mode) + continue; + memcpy(mode,&xf86DefaultModes[i],sizeof(DisplayModeRec)); + mode->name = xstrdup(xf86DefaultModes[i].name); + if (!mode->name) + { + xfree (mode); + continue; + } + mode->prev = prev; + mode->next = NULL; + if (prev) + prev->next = mode; + else + head = mode; + prev = mode; + } + return head; +} diff --git a/driver/xf86-video-intel/src/modes/xf86Modes.h b/driver/xf86-video-intel/src/modes/xf86Modes.h new file mode 100644 index 000000000..2bd4edeba --- /dev/null +++ b/driver/xf86-video-intel/src/modes/xf86Modes.h @@ -0,0 +1,98 @@ +/* + * Copyright © 2006 Intel Corporation + * + * 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 + * THE AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +#ifndef _XF86MODES_H_ +#define _XF86MODES_H_ + +#include <stddef.h> +#include <string.h> +#include <stdio.h> + +#include "xf86.h" +#include "xorgVersion.h" +#include "edid.h" +#include "xf86Parser.h" +#if XF86_MODES_RENAME +#include "xf86Rename.h" +#endif + +double xf86ModeHSync(DisplayModePtr mode); +double xf86ModeVRefresh(DisplayModePtr mode); + +int +xf86ModeWidth (DisplayModePtr mode, Rotation rotation); + +int +xf86ModeHeight (DisplayModePtr mode, Rotation rotation); + +DisplayModePtr xf86DuplicateMode(DisplayModePtr pMode); +DisplayModePtr xf86DuplicateModes(ScrnInfoPtr pScrn, + DisplayModePtr modeList); +void xf86SetModeDefaultName(DisplayModePtr mode); +void xf86SetModeCrtc(DisplayModePtr p, int adjustFlags); +Bool xf86ModesEqual(DisplayModePtr pMode1, DisplayModePtr pMode2); +void xf86PrintModeline(int scrnIndex,DisplayModePtr mode); +DisplayModePtr xf86ModesAdd(DisplayModePtr modes, DisplayModePtr new); + +DisplayModePtr xf86DDCGetModes(int scrnIndex, xf86MonPtr DDC); +DisplayModePtr xf86CVTMode(int HDisplay, int VDisplay, float VRefresh, + Bool Reduced, Bool Interlaced); + +void +xf86ValidateModesFlags(ScrnInfoPtr pScrn, DisplayModePtr modeList, + int flags); + +void +xf86ValidateModesClocks(ScrnInfoPtr pScrn, DisplayModePtr modeList, + int *min, int *max, int n_ranges); + +void +xf86ValidateModesSize(ScrnInfoPtr pScrn, DisplayModePtr modeList, + int maxX, int maxY, int maxPitch); + +void +xf86ValidateModesSync(ScrnInfoPtr pScrn, DisplayModePtr modeList, + MonPtr mon); + +void +xf86PruneInvalidModes(ScrnInfoPtr pScrn, DisplayModePtr *modeList, + Bool verbose); + +void +xf86ValidateModesFlags(ScrnInfoPtr pScrn, DisplayModePtr modeList, + int flags); + +void +xf86ValidateModesUserConfig(ScrnInfoPtr pScrn, DisplayModePtr modeList); + +DisplayModePtr +xf86GetMonitorModes (ScrnInfoPtr pScrn, XF86ConfMonitorPtr conf_monitor); + +DisplayModePtr +xf86GetDefaultModes (Bool interlaceAllowed, Bool doubleScanAllowed); + +#endif /* _XF86MODES_H_ */ diff --git a/driver/xf86-video-intel/src/modes/xf86RandR12.c b/driver/xf86-video-intel/src/modes/xf86RandR12.c new file mode 100644 index 000000000..7169f74c8 --- /dev/null +++ b/driver/xf86-video-intel/src/modes/xf86RandR12.c @@ -0,0 +1,1139 @@ +/* + * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS 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. + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#else +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#endif + +#include "xf86.h" +#include "os.h" +#include "mibank.h" +#include "globals.h" +#include "xf86.h" +#include "xf86Priv.h" +#include "xf86DDC.h" +#include "mipointer.h" +#include "windowstr.h" +#include <randrstr.h> +#include <X11/extensions/render.h> + +#include "xf86Crtc.h" +#include "xf86RandR12.h" + +typedef struct _xf86RandR12Info { + int virtualX; + int virtualY; + int mmWidth; + int mmHeight; + int maxX; + int maxY; + Rotation rotation; /* current mode */ + Rotation supported_rotations; /* driver supported */ +} XF86RandRInfoRec, *XF86RandRInfoPtr; + +#ifdef RANDR_12_INTERFACE +static Bool xf86RandR12Init12 (ScreenPtr pScreen); +static Bool xf86RandR12CreateScreenResources12 (ScreenPtr pScreen); +#endif + +static int xf86RandR12Index; +static int xf86RandR12Generation; + +#define XF86RANDRINFO(p) \ + ((XF86RandRInfoPtr)(p)->devPrivates[xf86RandR12Index].ptr) + +static int +xf86RandR12ModeRefresh (DisplayModePtr mode) +{ + if (mode->VRefresh) + return (int) (mode->VRefresh + 0.5); + else + return (int) (mode->Clock * 1000.0 / mode->HTotal / mode->VTotal + 0.5); +} + +static Bool +xf86RandR12GetInfo (ScreenPtr pScreen, Rotation *rotations) +{ + RRScreenSizePtr pSize; + ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); + XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); + DisplayModePtr mode; + int refresh0 = 60; + int maxX = 0, maxY = 0; + + *rotations = randrp->supported_rotations; + + if (randrp->virtualX == -1 || randrp->virtualY == -1) + { + randrp->virtualX = scrp->virtualX; + randrp->virtualY = scrp->virtualY; + } + + /* Re-probe the outputs for new monitors or modes */ + if (scrp->vtSema) + { + xf86ProbeOutputModes (scrp, 0, 0); + xf86SetScrnInfoModes (scrp); + xf86DiDGAReInit (pScreen); + } + + for (mode = scrp->modes; ; mode = mode->next) + { + int refresh = xf86RandR12ModeRefresh (mode); + if (randrp->maxX == 0 || randrp->maxY == 0) + { + if (maxX < mode->HDisplay) + maxX = mode->HDisplay; + if (maxY < mode->VDisplay) + maxY = mode->VDisplay; + } + if (mode == scrp->modes) + refresh0 = refresh; + pSize = RRRegisterSize (pScreen, + mode->HDisplay, mode->VDisplay, + randrp->mmWidth, randrp->mmHeight); + if (!pSize) + return FALSE; + RRRegisterRate (pScreen, pSize, refresh); + + if (xf86ModesEqual(mode, scrp->currentMode) && + mode->HDisplay == scrp->virtualX && + mode->VDisplay == scrp->virtualY) + { + RRSetCurrentConfig (pScreen, randrp->rotation, refresh, pSize); + } + if (mode->next == scrp->modes) + break; + } + + if (randrp->maxX == 0 || randrp->maxY == 0) + { + randrp->maxX = maxX; + randrp->maxY = maxY; + } + + if (scrp->currentMode->HDisplay != randrp->virtualX || + scrp->currentMode->VDisplay != randrp->virtualY) + { + pSize = RRRegisterSize (pScreen, + randrp->virtualX, randrp->virtualY, + randrp->mmWidth, + randrp->mmHeight); + if (!pSize) + return FALSE; + RRRegisterRate (pScreen, pSize, refresh0); + if (scrp->virtualX == randrp->virtualX && + scrp->virtualY == randrp->virtualY) + { + RRSetCurrentConfig (pScreen, randrp->rotation, refresh0, pSize); + } + } + + return TRUE; +} + +static Bool +xf86RandR12SetMode (ScreenPtr pScreen, + DisplayModePtr mode, + Bool useVirtual, + int mmWidth, + int mmHeight) +{ + ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); + XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); + int oldWidth = pScreen->width; + int oldHeight = pScreen->height; + int oldmmWidth = pScreen->mmWidth; + int oldmmHeight = pScreen->mmHeight; + WindowPtr pRoot = WindowTable[pScreen->myNum]; + DisplayModePtr currentMode = NULL; + Bool ret = TRUE; + PixmapPtr pspix = NULL; + + if (pRoot) + (*scrp->EnableDisableFBAccess) (pScreen->myNum, FALSE); + if (useVirtual) + { + scrp->virtualX = randrp->virtualX; + scrp->virtualY = randrp->virtualY; + } + else + { + scrp->virtualX = mode->HDisplay; + scrp->virtualY = mode->VDisplay; + } + + if(randrp->rotation & (RR_Rotate_90 | RR_Rotate_270)) + { + /* If the screen is rotated 90 or 270 degrees, swap the sizes. */ + pScreen->width = scrp->virtualY; + pScreen->height = scrp->virtualX; + pScreen->mmWidth = mmHeight; + pScreen->mmHeight = mmWidth; + } + else + { + pScreen->width = scrp->virtualX; + pScreen->height = scrp->virtualY; + pScreen->mmWidth = mmWidth; + pScreen->mmHeight = mmHeight; + } + if (scrp->currentMode == mode) { + /* Save current mode */ + currentMode = scrp->currentMode; + /* Reset, just so we ensure the drivers SwitchMode is called */ + scrp->currentMode = NULL; + } + /* + * We know that if the driver failed to SwitchMode to the rotated + * version, then it should revert back to it's prior mode. + */ + if (!xf86SwitchMode (pScreen, mode)) + { + ret = FALSE; + scrp->virtualX = pScreen->width = oldWidth; + scrp->virtualY = pScreen->height = oldHeight; + pScreen->mmWidth = oldmmWidth; + pScreen->mmHeight = oldmmHeight; + scrp->currentMode = currentMode; + } + /* + * Get the new Screen pixmap ptr as SwitchMode might have called + * ModifyPixmapHeader and xf86EnableDisableFBAccess will put it back... + * Unfortunately. + */ + pspix = (*pScreen->GetScreenPixmap) (pScreen); + if (pspix->devPrivate.ptr) + scrp->pixmapPrivate = pspix->devPrivate; + + /* + * Make sure the layout is correct + */ + xf86ReconfigureLayout(); + + /* + * Make sure the whole screen is visible + */ + xf86SetViewport (pScreen, pScreen->width, pScreen->height); + xf86SetViewport (pScreen, 0, 0); + if (pRoot) + (*scrp->EnableDisableFBAccess) (pScreen->myNum, TRUE); + return ret; +} + +_X_EXPORT Bool +xf86RandR12SetConfig (ScreenPtr pScreen, + Rotation rotation, + int rate, + RRScreenSizePtr pSize) +{ + ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); + XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); + DisplayModePtr mode; + int px, py; + Bool useVirtual = FALSE; + int maxX = 0, maxY = 0; + Rotation oldRotation = randrp->rotation; + + randrp->rotation = rotation; + + if (randrp->virtualX == -1 || randrp->virtualY == -1) + { + randrp->virtualX = scrp->virtualX; + randrp->virtualY = scrp->virtualY; + } + + miPointerPosition (&px, &py); + for (mode = scrp->modes; ; mode = mode->next) + { + if (randrp->maxX == 0 || randrp->maxY == 0) + { + if (maxX < mode->HDisplay) + maxX = mode->HDisplay; + if (maxY < mode->VDisplay) + maxY = mode->VDisplay; + } + if (mode->HDisplay == pSize->width && + mode->VDisplay == pSize->height && + (rate == 0 || xf86RandR12ModeRefresh (mode) == rate)) + break; + if (mode->next == scrp->modes) + { + if (pSize->width == randrp->virtualX && + pSize->height == randrp->virtualY) + { + mode = scrp->modes; + useVirtual = TRUE; + break; + } + if (randrp->maxX == 0 || randrp->maxY == 0) + { + randrp->maxX = maxX; + randrp->maxY = maxY; + } + return FALSE; + } + } + + if (randrp->maxX == 0 || randrp->maxY == 0) + { + randrp->maxX = maxX; + randrp->maxY = maxY; + } + + if (!xf86RandR12SetMode (pScreen, mode, useVirtual, pSize->mmWidth, + pSize->mmHeight)) { + randrp->rotation = oldRotation; + return FALSE; + } + + /* + * Move the cursor back where it belongs; SwitchMode repositions it + */ + if (pScreen == miPointerCurrentScreen ()) + { + px = (px >= pScreen->width ? (pScreen->width - 1) : px); + py = (py >= pScreen->height ? (pScreen->height - 1) : py); + + xf86SetViewport(pScreen, px, py); + + (*pScreen->SetCursorPosition) (pScreen, px, py, FALSE); + } + + return TRUE; +} + +static Bool +xf86RandR12ScreenSetSize (ScreenPtr pScreen, + CARD16 width, + CARD16 height, + CARD32 mmWidth, + CARD32 mmHeight) +{ + XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); + ScrnInfoPtr pScrn = XF86SCRNINFO(pScreen); + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + WindowPtr pRoot = WindowTable[pScreen->myNum]; + PixmapPtr pScrnPix = (*pScreen->GetScreenPixmap)(pScreen); + Bool ret = FALSE; + + if (randrp->virtualX == -1 || randrp->virtualY == -1) + { + randrp->virtualX = pScrn->virtualX; + randrp->virtualY = pScrn->virtualY; + } + if (pRoot && pScrn->vtSema) + (*pScrn->EnableDisableFBAccess) (pScreen->myNum, FALSE); + + /* Let the driver update virtualX and virtualY */ + if (!(*config->funcs->resize)(pScrn, width, height)) + goto finish; + + ret = TRUE; + + pScreen->width = pScrnPix->drawable.width = width; + pScreen->height = pScrnPix->drawable.height = height; + pScreen->mmWidth = mmWidth; + pScreen->mmHeight = mmHeight; + + xf86SetViewport (pScreen, pScreen->width-1, pScreen->height-1); + xf86SetViewport (pScreen, 0, 0); + +finish: + if (pRoot && pScrn->vtSema) + (*pScrn->EnableDisableFBAccess) (pScreen->myNum, TRUE); +#if RANDR_12_INTERFACE + if (WindowTable[pScreen->myNum] && ret) + RRScreenSizeNotify (pScreen); +#endif + return ret; +} + +_X_EXPORT Rotation +xf86RandR12GetRotation(ScreenPtr pScreen) +{ + XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); + + return randrp->rotation; +} + +_X_EXPORT Bool +xf86RandR12CreateScreenResources (ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); + int c; + int width, height; + int mmWidth, mmHeight; +#ifdef PANORAMIX + /* XXX disable RandR when using Xinerama */ + if (!noPanoramiXExtension) + return TRUE; +#endif + + /* + * Compute size of screen + */ + width = 0; height = 0; + for (c = 0; c < config->num_crtc; c++) + { + xf86CrtcPtr crtc = config->crtc[c]; + int crtc_width = crtc->x + xf86ModeWidth (&crtc->mode, crtc->rotation); + int crtc_height = crtc->y + xf86ModeHeight (&crtc->mode, crtc->rotation); + + if (crtc->enabled && crtc_width > width) + width = crtc_width; + if (crtc->enabled && crtc_height > height) + height = crtc_height; + } + + if (width && height) + { + /* + * Compute physical size of screen + */ + if (monitorResolution) + { + mmWidth = width * 25.4 / monitorResolution; + mmHeight = height * 25.4 / monitorResolution; + } + else + { + xf86OutputPtr output = config->output[config->compat_output]; + xf86CrtcPtr crtc = output->crtc; + + if (output->conf_monitor && + (output->conf_monitor->mon_width > 0 && + output->conf_monitor->mon_height > 0)) + { + /* + * Prefer user configured DisplaySize + */ + mmWidth = output->conf_monitor->mon_width; + mmHeight = output->conf_monitor->mon_height; + } + else if (crtc && crtc->mode.HDisplay && + output->mm_width && output->mm_height) + { + /* + * If the output has a mode and a declared size, use that + * to scale the screen size + */ + DisplayModePtr mode = &crtc->mode; + mmWidth = output->mm_width * width / mode->HDisplay; + mmHeight = output->mm_height * height / mode->VDisplay; + } + else + { + /* + * Otherwise, just set the screen to 96dpi + */ + mmWidth = width * 25.4 / 96; + mmHeight = height * 25.4 / 96; + } + } + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Setting screen physical size to %d x %d\n", + mmWidth, mmHeight); + xf86RandR12ScreenSetSize (pScreen, + width, + height, + mmWidth, + mmHeight); + } + + if (randrp->virtualX == -1 || randrp->virtualY == -1) + { + randrp->virtualX = pScrn->virtualX; + randrp->virtualY = pScrn->virtualY; + } + xf86CrtcSetScreenSubpixelOrder (pScreen); +#if RANDR_12_INTERFACE + if (xf86RandR12CreateScreenResources12 (pScreen)) + return TRUE; +#endif + return TRUE; +} + + +_X_EXPORT Bool +xf86RandR12Init (ScreenPtr pScreen) +{ + rrScrPrivPtr rp; + XF86RandRInfoPtr randrp; + +#ifdef PANORAMIX + /* XXX disable RandR when using Xinerama */ + if (!noPanoramiXExtension) + return TRUE; +#endif + if (xf86RandR12Generation != serverGeneration) + { + xf86RandR12Index = AllocateScreenPrivateIndex(); + xf86RandR12Generation = serverGeneration; + } + + randrp = xalloc (sizeof (XF86RandRInfoRec)); + if (!randrp) + return FALSE; + + if (!RRScreenInit(pScreen)) + { + xfree (randrp); + return FALSE; + } + rp = rrGetScrPriv(pScreen); + rp->rrGetInfo = xf86RandR12GetInfo; + rp->rrSetConfig = xf86RandR12SetConfig; + + randrp->virtualX = -1; + randrp->virtualY = -1; + randrp->mmWidth = pScreen->mmWidth; + randrp->mmHeight = pScreen->mmHeight; + + randrp->rotation = RR_Rotate_0; /* initial rotated mode */ + + randrp->supported_rotations = RR_Rotate_0; + + randrp->maxX = randrp->maxY = 0; + + pScreen->devPrivates[xf86RandR12Index].ptr = randrp; + +#if RANDR_12_INTERFACE + if (!xf86RandR12Init12 (pScreen)) + return FALSE; +#endif + return TRUE; +} + +_X_EXPORT void +xf86RandR12SetRotations (ScreenPtr pScreen, Rotation rotations) +{ + XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); +#if RANDR_12_INTERFACE + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + int c; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + + for (c = 0; c < config->num_crtc; c++) { + xf86CrtcPtr crtc = config->crtc[c]; + + RRCrtcSetRotations (crtc->randr_crtc, rotations); + } +#endif + randrp->supported_rotations = rotations; +} + +_X_EXPORT void +xf86RandR12GetOriginalVirtualSize(ScrnInfoPtr pScrn, int *x, int *y) +{ + ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex]; + + if (xf86RandR12Generation != serverGeneration || + XF86RANDRINFO(pScreen)->virtualX == -1) + { + *x = pScrn->virtualX; + *y = pScrn->virtualY; + } else { + XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); + + *x = randrp->virtualX; + *y = randrp->virtualY; + } +} + +#if RANDR_12_INTERFACE + +#define FLAG_BITS (RR_HSyncPositive | \ + RR_HSyncNegative | \ + RR_VSyncPositive | \ + RR_VSyncNegative | \ + RR_Interlace | \ + RR_DoubleScan | \ + RR_CSync | \ + RR_CSyncPositive | \ + RR_CSyncNegative | \ + RR_HSkewPresent | \ + RR_BCast | \ + RR_PixelMultiplex | \ + RR_DoubleClock | \ + RR_ClockDivideBy2) + +static Bool +xf86RandRModeMatches (RRModePtr randr_mode, + DisplayModePtr mode) +{ +#if 0 + if (match_name) + { + /* check for same name */ + int len = strlen (mode->name); + if (randr_mode->mode.nameLength != len) return FALSE; + if (memcmp (randr_mode->name, mode->name, len) != 0) return FALSE; + } +#endif + + /* check for same timings */ + if (randr_mode->mode.dotClock / 1000 != mode->Clock) return FALSE; + if (randr_mode->mode.width != mode->HDisplay) return FALSE; + if (randr_mode->mode.hSyncStart != mode->HSyncStart) return FALSE; + if (randr_mode->mode.hSyncEnd != mode->HSyncEnd) return FALSE; + if (randr_mode->mode.hTotal != mode->HTotal) return FALSE; + if (randr_mode->mode.hSkew != mode->HSkew) return FALSE; + if (randr_mode->mode.height != mode->VDisplay) return FALSE; + if (randr_mode->mode.vSyncStart != mode->VSyncStart) return FALSE; + if (randr_mode->mode.vSyncEnd != mode->VSyncEnd) return FALSE; + if (randr_mode->mode.vTotal != mode->VTotal) return FALSE; + + /* check for same flags (using only the XF86 valid flag bits) */ + if ((randr_mode->mode.modeFlags & FLAG_BITS) != (mode->Flags & FLAG_BITS)) + return FALSE; + + /* everything matches */ + return TRUE; +} + +static Bool +xf86RandR12CrtcNotify (RRCrtcPtr randr_crtc) +{ + ScreenPtr pScreen = randr_crtc->pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + RRModePtr randr_mode = NULL; + int x; + int y; + Rotation rotation; + int numOutputs; + RROutputPtr *randr_outputs; + RROutputPtr randr_output; + xf86CrtcPtr crtc = randr_crtc->devPrivate; + xf86OutputPtr output; + int i, j; + DisplayModePtr mode = &crtc->mode; + Bool ret; + + randr_outputs = ALLOCATE_LOCAL(config->num_output * sizeof (RROutputPtr)); + if (!randr_outputs) + return FALSE; + x = crtc->x; + y = crtc->y; + rotation = crtc->rotation; + numOutputs = 0; + randr_mode = NULL; + for (i = 0; i < config->num_output; i++) + { + output = config->output[i]; + if (output->crtc == crtc) + { + randr_output = output->randr_output; + randr_outputs[numOutputs++] = randr_output; + /* + * We make copies of modes, so pointer equality + * isn't sufficient + */ + for (j = 0; j < randr_output->numModes + randr_output->numUserModes; j++) + { + RRModePtr m = (j < randr_output->numModes ? + randr_output->modes[j] : + randr_output->userModes[j-randr_output->numModes]); + + if (xf86RandRModeMatches (m, mode)) + { + randr_mode = m; + break; + } + } + } + } + ret = RRCrtcNotify (randr_crtc, randr_mode, x, y, + rotation, numOutputs, randr_outputs); + DEALLOCATE_LOCAL(randr_outputs); + return ret; +} + +/* + * Convert a RandR mode to a DisplayMode + */ +static void +xf86RandRModeConvert (ScrnInfoPtr scrn, + RRModePtr randr_mode, + DisplayModePtr mode) +{ + mode->prev = NULL; + mode->next = NULL; + mode->name = NULL; + mode->status = MODE_OK; + mode->type = 0; + + mode->Clock = randr_mode->mode.dotClock / 1000; + + mode->HDisplay = randr_mode->mode.width; + mode->HSyncStart = randr_mode->mode.hSyncStart; + mode->HSyncEnd = randr_mode->mode.hSyncEnd; + mode->HTotal = randr_mode->mode.hTotal; + mode->HSkew = randr_mode->mode.hSkew; + + mode->VDisplay = randr_mode->mode.height; + mode->VSyncStart = randr_mode->mode.vSyncStart; + mode->VSyncEnd = randr_mode->mode.vSyncEnd; + mode->VTotal = randr_mode->mode.vTotal; + mode->VScan = 0; + + mode->Flags = randr_mode->mode.modeFlags & FLAG_BITS; + + xf86SetModeCrtc (mode, scrn->adjustFlags); +} + +static Bool +xf86RandR12CrtcSet (ScreenPtr pScreen, + RRCrtcPtr randr_crtc, + RRModePtr randr_mode, + int x, + int y, + Rotation rotation, + int num_randr_outputs, + RROutputPtr *randr_outputs) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + xf86CrtcPtr crtc = randr_crtc->devPrivate; + Bool changed = FALSE; + int o, ro; + xf86CrtcPtr *save_crtcs; + Bool save_enabled = crtc->enabled; + + save_crtcs = ALLOCATE_LOCAL(config->num_output * sizeof (xf86CrtcPtr)); + if ((randr_mode != NULL) != crtc->enabled) + changed = TRUE; + else if (randr_mode && !xf86RandRModeMatches (randr_mode, &crtc->mode)) + changed = TRUE; + + if (rotation != crtc->rotation) + changed = TRUE; + + if (x != crtc->x || y != crtc->y) + changed = TRUE; + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + xf86CrtcPtr new_crtc; + + save_crtcs[o] = output->crtc; + + if (output->crtc == crtc) + new_crtc = NULL; + else + new_crtc = output->crtc; + for (ro = 0; ro < num_randr_outputs; ro++) + if (output->randr_output == randr_outputs[ro]) + { + new_crtc = crtc; + break; + } + if (new_crtc != output->crtc) + { + changed = TRUE; + output->crtc = new_crtc; + } + } + for (ro = 0; ro < num_randr_outputs; ro++) + if (randr_outputs[ro]->pendingProperties) + changed = TRUE; + + /* XXX need device-independent mode setting code through an API */ + if (changed) + { + crtc->enabled = randr_mode != NULL; + + if (randr_mode) + { + DisplayModeRec mode; + + xf86RandRModeConvert (pScrn, randr_mode, &mode); + if (!xf86CrtcSetMode (crtc, &mode, rotation, x, y)) + { + crtc->enabled = save_enabled; + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + output->crtc = save_crtcs[o]; + } + DEALLOCATE_LOCAL(save_crtcs); + return FALSE; + } + /* + * Save the last successful setting for EnterVT + */ + crtc->desiredMode = mode; + crtc->desiredRotation = rotation; + crtc->desiredX = x; + crtc->desiredY = y; + } + xf86DisableUnusedFunctions (pScrn); + } + DEALLOCATE_LOCAL(save_crtcs); + return xf86RandR12CrtcNotify (randr_crtc); +} + +static Bool +xf86RandR12CrtcSetGamma (ScreenPtr pScreen, + RRCrtcPtr randr_crtc) +{ + xf86CrtcPtr crtc = randr_crtc->devPrivate; + + if (crtc->funcs->gamma_set == NULL) + return FALSE; + + if (!crtc->scrn->vtSema) + return TRUE; + + crtc->funcs->gamma_set(crtc, randr_crtc->gammaRed, randr_crtc->gammaGreen, + randr_crtc->gammaBlue, randr_crtc->gammaSize); + + return TRUE; +} + +static Bool +xf86RandR12OutputSetProperty (ScreenPtr pScreen, + RROutputPtr randr_output, + Atom property, + RRPropertyValuePtr value) +{ + xf86OutputPtr output = randr_output->devPrivate; + + /* If we don't have any property handler, then we don't care what the + * user is setting properties to. + */ + if (output->funcs->set_property == NULL) + return TRUE; + + /* + * This function gets called even when vtSema is FALSE, as + * drivers will need to remember the correct value to apply + * when the VT switch occurs + */ + return output->funcs->set_property(output, property, value); +} + +static Bool +xf86RandR12OutputValidateMode (ScreenPtr pScreen, + RROutputPtr randr_output, + RRModePtr randr_mode) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + xf86OutputPtr output = randr_output->devPrivate; + DisplayModeRec mode; + + xf86RandRModeConvert (pScrn, randr_mode, &mode); + /* + * This function may be called when vtSema is FALSE, so + * the underlying function must either avoid touching the hardware + * or return FALSE when vtSema is FALSE + */ + if (output->funcs->mode_valid (output, &mode) != MODE_OK) + return FALSE; + return TRUE; +} + +static void +xf86RandR12ModeDestroy (ScreenPtr pScreen, RRModePtr randr_mode) +{ +} + +/** + * Given a list of xf86 modes and a RandR Output object, construct + * RandR modes and assign them to the output + */ +static Bool +xf86RROutputSetModes (RROutputPtr randr_output, DisplayModePtr modes) +{ + DisplayModePtr mode; + RRModePtr *rrmodes = NULL; + int nmode = 0; + int npreferred = 0; + Bool ret = TRUE; + int pref; + + for (mode = modes; mode; mode = mode->next) + nmode++; + + if (nmode) { + rrmodes = xalloc (nmode * sizeof (RRModePtr)); + + if (!rrmodes) + return FALSE; + nmode = 0; + + for (pref = 1; pref >= 0; pref--) { + for (mode = modes; mode; mode = mode->next) { + if ((pref != 0) == ((mode->type & M_T_PREFERRED) != 0)) { + xRRModeInfo modeInfo; + RRModePtr rrmode; + + modeInfo.nameLength = strlen (mode->name); + modeInfo.width = mode->HDisplay; + modeInfo.dotClock = mode->Clock * 1000; + modeInfo.hSyncStart = mode->HSyncStart; + modeInfo.hSyncEnd = mode->HSyncEnd; + modeInfo.hTotal = mode->HTotal; + modeInfo.hSkew = mode->HSkew; + + modeInfo.height = mode->VDisplay; + modeInfo.vSyncStart = mode->VSyncStart; + modeInfo.vSyncEnd = mode->VSyncEnd; + modeInfo.vTotal = mode->VTotal; + modeInfo.modeFlags = mode->Flags; + + rrmode = RRModeGet (&modeInfo, mode->name); + if (rrmode) { + rrmodes[nmode++] = rrmode; + npreferred += pref; + } + } + } + } + } + + ret = RROutputSetModes (randr_output, rrmodes, nmode, npreferred); + xfree (rrmodes); + return ret; +} + +/* + * Mirror the current mode configuration to RandR + */ +static Bool +xf86RandR12SetInfo12 (ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + RROutputPtr *clones; + RRCrtcPtr *crtcs; + int ncrtc; + int o, c, l; + RRCrtcPtr randr_crtc; + int nclone; + + clones = ALLOCATE_LOCAL(config->num_output * sizeof (RROutputPtr)); + crtcs = ALLOCATE_LOCAL (config->num_crtc * sizeof (RRCrtcPtr)); + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + + ncrtc = 0; + for (c = 0; c < config->num_crtc; c++) + if (output->possible_crtcs & (1 << c)) + crtcs[ncrtc++] = config->crtc[c]->randr_crtc; + + if (output->crtc) + randr_crtc = output->crtc->randr_crtc; + else + randr_crtc = NULL; + + if (!RROutputSetCrtcs (output->randr_output, crtcs, ncrtc)) + { + DEALLOCATE_LOCAL (crtcs); + DEALLOCATE_LOCAL (clones); + return FALSE; + } + + RROutputSetPhysicalSize(output->randr_output, + output->mm_width, + output->mm_height); + xf86RROutputSetModes (output->randr_output, output->probed_modes); + + switch (output->status) { + case XF86OutputStatusConnected: + RROutputSetConnection (output->randr_output, RR_Connected); + break; + case XF86OutputStatusDisconnected: + RROutputSetConnection (output->randr_output, RR_Disconnected); + break; + case XF86OutputStatusUnknown: + RROutputSetConnection (output->randr_output, RR_UnknownConnection); + break; + } + + RROutputSetSubpixelOrder (output->randr_output, output->subpixel_order); + + /* + * Valid clones + */ + nclone = 0; + for (l = 0; l < config->num_output; l++) + { + xf86OutputPtr clone = config->output[l]; + + if (l != o && (output->possible_clones & (1 << l))) + clones[nclone++] = clone->randr_output; + } + if (!RROutputSetClones (output->randr_output, clones, nclone)) + { + DEALLOCATE_LOCAL (crtcs); + DEALLOCATE_LOCAL (clones); + return FALSE; + } + } + DEALLOCATE_LOCAL (crtcs); + DEALLOCATE_LOCAL (clones); + return TRUE; +} + + + +/* + * Query the hardware for the current state, then mirror + * that to RandR + */ +static Bool +xf86RandR12GetInfo12 (ScreenPtr pScreen, Rotation *rotations) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + + if (!pScrn->vtSema) + return TRUE; + xf86ProbeOutputModes (pScrn, 0, 0); + xf86SetScrnInfoModes (pScrn); + xf86DiDGAReInit (pScreen); + return xf86RandR12SetInfo12 (pScreen); +} + +static Bool +xf86RandR12CreateObjects12 (ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + int c; + int o; + + if (!RRInit ()) + return FALSE; + + /* + * Configure crtcs + */ + for (c = 0; c < config->num_crtc; c++) + { + xf86CrtcPtr crtc = config->crtc[c]; + + crtc->randr_crtc = RRCrtcCreate (pScreen, crtc); + RRCrtcGammaSetSize (crtc->randr_crtc, 256); + } + /* + * Configure outputs + */ + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + + output->randr_output = RROutputCreate (pScreen, output->name, + strlen (output->name), + output); + + if (output->funcs->create_resources != NULL) + output->funcs->create_resources(output); + RRPostPendingProperties (output->randr_output); + } + return TRUE; +} + +static Bool +xf86RandR12CreateScreenResources12 (ScreenPtr pScreen) +{ + int c; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + + for (c = 0; c < config->num_crtc; c++) + xf86RandR12CrtcNotify (config->crtc[c]->randr_crtc); + + + RRScreenSetSizeRange (pScreen, config->minWidth, config->minHeight, + config->maxWidth, config->maxHeight); + return TRUE; +} + +/* + * Something happened within the screen configuration due + * to DGA, VidMode or hot key. Tell RandR + */ + +_X_EXPORT void +xf86RandR12TellChanged (ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); + int c; + + if (!randrp) + return; + xf86RandR12SetInfo12 (pScreen); + for (c = 0; c < config->num_crtc; c++) + xf86RandR12CrtcNotify (config->crtc[c]->randr_crtc); + + RRTellChanged (pScreen); +} + +static void +xf86RandR12PointerMoved (int scrnIndex, int x, int y) +{ +} + +static Bool +xf86RandR12Init12 (ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + rrScrPrivPtr rp = rrGetScrPriv(pScreen); + + rp->rrGetInfo = xf86RandR12GetInfo12; + rp->rrScreenSetSize = xf86RandR12ScreenSetSize; + rp->rrCrtcSet = xf86RandR12CrtcSet; + rp->rrCrtcSetGamma = xf86RandR12CrtcSetGamma; + rp->rrOutputSetProperty = xf86RandR12OutputSetProperty; + rp->rrOutputValidateMode = xf86RandR12OutputValidateMode; + rp->rrModeDestroy = xf86RandR12ModeDestroy; + rp->rrSetConfig = NULL; + pScrn->PointerMoved = xf86RandR12PointerMoved; + if (!xf86RandR12CreateObjects12 (pScreen)) + return FALSE; + + /* + * Configure output modes + */ + if (!xf86RandR12SetInfo12 (pScreen)) + return FALSE; + return TRUE; +} + +#endif + +_X_EXPORT Bool +xf86RandR12PreInit (ScrnInfoPtr pScrn) +{ + return TRUE; +} diff --git a/driver/xf86-video-intel/src/modes/xf86RandR12.h b/driver/xf86-video-intel/src/modes/xf86RandR12.h new file mode 100644 index 000000000..4fd855cf5 --- /dev/null +++ b/driver/xf86-video-intel/src/modes/xf86RandR12.h @@ -0,0 +1,41 @@ +/* + * Copyright © 2006 Keith Packard + * + * 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 the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS 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. + */ + +#ifndef _XF86_RANDR_H_ +#define _XF86_RANDR_H_ +#include <randrstr.h> +#include <X11/extensions/render.h> +#if XF86_MODES_RENAME +#include "xf86Rename.h" +#endif + +Bool xf86RandR12CreateScreenResources (ScreenPtr pScreen); +Bool xf86RandR12Init(ScreenPtr pScreen); +void xf86RandR12SetRotations (ScreenPtr pScreen, Rotation rotation); +Bool xf86RandR12SetConfig(ScreenPtr pScreen, Rotation rotation, int rate, + RRScreenSizePtr pSize); +Rotation xf86RandR12GetRotation(ScreenPtr pScreen); +void xf86RandR12GetOriginalVirtualSize(ScrnInfoPtr pScrn, int *x, int *y); +Bool xf86RandR12PreInit (ScrnInfoPtr pScrn); +void xf86RandR12TellChanged (ScreenPtr pScreen); + +#endif /* _XF86_RANDR_H_ */ diff --git a/driver/xf86-video-intel/src/modes/xf86Rename.h b/driver/xf86-video-intel/src/modes/xf86Rename.h new file mode 100644 index 000000000..b8c1d70ef --- /dev/null +++ b/driver/xf86-video-intel/src/modes/xf86Rename.h @@ -0,0 +1,93 @@ +/* + * Copyright © 2006 Keith Packard + * + * 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 the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS 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. + */ + +#ifndef _XF86RENAME_H_ +#define _XF86RENAME_H_ + +#include "local_xf86Rename.h" + +#define xf86_cursors_fini XF86NAME(xf86_cursors_fini) +#define xf86_cursors_init XF86NAME(xf86_cursors_init) +#define xf86_hide_cursors XF86NAME(xf86_hide_cursors) +#define xf86_reload_cursors XF86NAME(xf86_reload_cursors) +#define xf86_show_cursors XF86NAME(xf86_show_cursors) +#define xf86ConnectorGetName XF86NAME(xf86ConnectorGetName) +#define xf86CrtcConfigInit XF86NAME(xf86CrtcConfigInit) +#define xf86CrtcConfigPrivateIndex XF86NAME(xf86CrtcConfigPrivateIndex) +#define xf86CrtcCreate XF86NAME(xf86CrtcCreate) +#define xf86CrtcDestroy XF86NAME(xf86CrtcDestroy) +#define xf86CrtcInUse XF86NAME(xf86CrtcInUse) +#define xf86CrtcRotate XF86NAME(xf86CrtcRotate) +#define xf86CrtcScreenInit XF86NAME(xf86CrtcScreenInit) +#define xf86CrtcSetMode XF86NAME(xf86CrtcSetMode) +#define xf86CrtcSetSizeRange XF86NAME(xf86CrtcSetSizeRange) +#define xf86CVTMode XF86NAME(xf86CVTMode) +#define xf86DDCMonitorSet XF86NAME(xf86DDCMonitorSet) +#define xf86DisableUnusedFunctions XF86NAME(xf86DisableUnusedFunctions) +#define xf86DPMSSet XF86NAME(xf86DPMSSet) +#define xf86DuplicateMode XF86NAME(xf86DuplicateMode) +#define xf86DuplicateModes XF86NAME(xf86DuplicateModes) +#define xf86GetDefaultModes XF86NAME(xf86GetDefaultModes) +#define xf86GetMonitorModes XF86NAME(xf86GetMonitorModes) +#define xf86InitialConfiguration XF86NAME(xf86InitialConfiguration) +#define xf86ModeHSync XF86NAME(xf86ModeHSync) +#define xf86ModesAdd XF86NAME(xf86ModesAdd) +#define xf86ModesEqual XF86NAME(xf86ModesEqual) +#define xf86ModeVRefresh XF86NAME(xf86ModeVRefresh) +#define xf86OutputCreate XF86NAME(xf86OutputCreate) +#define xf86OutputDestroy XF86NAME(xf86OutputDestroy) +#define xf86OutputGetEDID XF86NAME(xf86OutputGetEDID) +#define xf86OutputGetEDIDModes XF86NAME(xf86OutputGetEDIDModes) +#define xf86OutputRename XF86NAME(xf86OutputRename) +#define xf86OutputSetEDID XF86NAME(xf86OutputSetEDID) +#define xf86OutputUseScreenMonitor XF86NAME(xf86OutputUseScreenMonitor) +#define xf86PrintModeline XF86NAME(xf86PrintModeline) +#define xf86ProbeOutputModes XF86NAME(xf86ProbeOutputModes) +#define xf86PruneInvalidModes XF86NAME(xf86PruneInvalidModes) +#define xf86RotateCloseScreen XF86NAME(xf86RotateCloseScreen) +#define xf86SetModeCrtc XF86NAME(xf86SetModeCrtc) +#define xf86SetModeDefaultName XF86NAME(xf86SetModeDefaultName) +#define xf86SetScrnInfoModes XF86NAME(xf86SetScrnInfoModes) +#define xf86ValidateModesClocks XF86NAME(xf86ValidateModesClocks) +#define xf86ValidateModesFlags XF86NAME(xf86ValidateModesFlags) +#define xf86ValidateModesSize XF86NAME(xf86ValidateModesSize) +#define xf86ValidateModesSync XF86NAME(xf86ValidateModesSync) +#define xf86ValidateModesUserConfig XF86NAME(xf86ValidateModesUserConfig) +#define xf86DiDGAInit XF86NAME(xf86DiDGAInit) +#define xf86DiDGAReInit XF86NAME(xf86DiDGAReInit) +#define xf86DDCGetModes XF86NAME(xf86DDCGetModes) +#define xf86RandR12CreateScreenResources XF86NAME(xf86RandR12CreateScreenResources) +#define xf86RandR12GetOriginalVirtualSize XF86NAME(xf86RandR12GetOriginalVirtualSize) +#define xf86RandR12GetRotation XF86NAME(xf86RandR12GetRotation) +#define xf86RandR12Init XF86NAME(xf86RandR12Init) +#define xf86RandR12PreInit XF86NAME(xf86RandR12PreInit) +#define xf86RandR12SetConfig XF86NAME(xf86RandR12SetConfig) +#define xf86RandR12SetRotations XF86NAME(xf86RandR12SetRotations) +#define xf86SaveScreen XF86NAME(xf86SaveScreen) +#define xf86CrtcSetScreenSubpixelOrder XF86NAME(xf86CrtcSetScreenSubpixelOrder) +#define xf86ModeWidth XF86NAME(xf86ModeWidth) +#define xf86ModeHeight XF86NAME(xf86ModeHeight) +#define xf86OutputFindClosestMode XF86NAME(xf86OutputFindClosestMode) +#define xf86SetSingleMode XF86NAME(xf86SetSingleMode) +#define xf86SetDesiredModes XF86NAME(xf86SetDesiredModes) + +#endif /* _XF86RENAME_H_ */ diff --git a/driver/xf86-video-intel/src/modes/xf86Rotate.c b/driver/xf86-video-intel/src/modes/xf86Rotate.c new file mode 100644 index 000000000..380478f7f --- /dev/null +++ b/driver/xf86-video-intel/src/modes/xf86Rotate.c @@ -0,0 +1,660 @@ +/* + * Copyright © 2006 Keith Packard + * + * 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 the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS 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. + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#else +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#endif + +#include <stddef.h> +#include <string.h> +#include <stdio.h> + +#include "xf86.h" +#include "xf86DDC.h" +#include "fb.h" +#include "windowstr.h" +#include "xf86Crtc.h" +#include "xf86Modes.h" +#include "xf86RandR12.h" +#include "X11/extensions/render.h" +#define DPMS_SERVER +#include "X11/extensions/dpms.h" +#include "X11/Xatom.h" + +/* borrowed from composite extension, move to Render and publish? */ + +static VisualPtr +compGetWindowVisual (WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + VisualID vid = wVisual (pWin); + int i; + + for (i = 0; i < pScreen->numVisuals; i++) + if (pScreen->visuals[i].vid == vid) + return &pScreen->visuals[i]; + return 0; +} + +static PictFormatPtr +compWindowFormat (WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + + return PictureMatchVisual (pScreen, pWin->drawable.depth, + compGetWindowVisual (pWin)); +} + +#define F(x) IntToxFixed(x) + +static void +PictureTransformIdentity (PictTransformPtr matrix) +{ + int i; + memset (matrix, '\0', sizeof (PictTransform)); + for (i = 0; i < 3; i++) + matrix->matrix[i][i] = F(1); +} + +static Bool +PictureTransformMultiply (PictTransformPtr dst, PictTransformPtr l, PictTransformPtr r) +{ + PictTransform d; + int dx, dy; + int o; + + for (dy = 0; dy < 3; dy++) + for (dx = 0; dx < 3; dx++) + { + xFixed_48_16 v; + xFixed_32_32 partial; + v = 0; + for (o = 0; o < 3; o++) + { + partial = (xFixed_32_32) l->matrix[dy][o] * (xFixed_32_32) r->matrix[o][dx]; + v += partial >> 16; + } + if (v > MAX_FIXED_48_16 || v < MIN_FIXED_48_16) + return FALSE; + d.matrix[dy][dx] = (xFixed) v; + } + *dst = d; + return TRUE; +} + +static void +PictureTransformInitScale (PictTransformPtr t, xFixed sx, xFixed sy) +{ + memset (t, '\0', sizeof (PictTransform)); + t->matrix[0][0] = sx; + t->matrix[1][1] = sy; + t->matrix[2][2] = F (1); +} + +static xFixed +fixed_inverse (xFixed x) +{ + return (xFixed) ((((xFixed_48_16) F(1)) * F(1)) / x); +} + +static Bool +PictureTransformScale (PictTransformPtr forward, + PictTransformPtr reverse, + xFixed sx, xFixed sy) +{ + PictTransform t; + + PictureTransformInitScale (&t, sx, sy); + if (!PictureTransformMultiply (forward, &t, forward)) + return FALSE; + PictureTransformInitScale (&t, fixed_inverse (sx), fixed_inverse (sy)); + if (!PictureTransformMultiply (reverse, reverse, &t)) + return FALSE; + return TRUE; +} + +static void +PictureTransformInitRotate (PictTransformPtr t, xFixed c, xFixed s) +{ + memset (t, '\0', sizeof (PictTransform)); + t->matrix[0][0] = c; + t->matrix[0][1] = -s; + t->matrix[1][0] = s; + t->matrix[1][1] = c; + t->matrix[2][2] = F (1); +} + +static Bool +PictureTransformRotate (PictTransformPtr forward, + PictTransformPtr reverse, + xFixed c, xFixed s) +{ + PictTransform t; + PictureTransformInitRotate (&t, c, s); + if (!PictureTransformMultiply (forward, &t, forward)) + return FALSE; + + PictureTransformInitRotate (&t, c, -s); + if (!PictureTransformMultiply (reverse, reverse, &t)) + return FALSE; + return TRUE; +} + +static void +PictureTransformInitTranslate (PictTransformPtr t, xFixed tx, xFixed ty) +{ + memset (t, '\0', sizeof (PictTransform)); + t->matrix[0][0] = F (1); + t->matrix[0][2] = tx; + t->matrix[1][1] = F (1); + t->matrix[1][2] = ty; + t->matrix[2][2] = F (1); +} + +static Bool +PictureTransformTranslate (PictTransformPtr forward, + PictTransformPtr reverse, + xFixed tx, xFixed ty) +{ + PictTransform t; + PictureTransformInitTranslate (&t, tx, ty); + if (!PictureTransformMultiply (forward, &t, forward)) + return FALSE; + + PictureTransformInitTranslate (&t, -tx, -ty); + if (!PictureTransformMultiply (reverse, reverse, &t)) + return FALSE; + return TRUE; +} + +static void +PictureTransformBounds (BoxPtr b, PictTransformPtr matrix) +{ + PictVector v[4]; + int i; + int x1, y1, x2, y2; + + v[0].vector[0] = F (b->x1); v[0].vector[1] = F (b->y1); v[0].vector[2] = F(1); + v[1].vector[0] = F (b->x2); v[1].vector[1] = F (b->y1); v[1].vector[2] = F(1); + v[2].vector[0] = F (b->x2); v[2].vector[1] = F (b->y2); v[2].vector[2] = F(1); + v[3].vector[0] = F (b->x1); v[3].vector[1] = F (b->y2); v[3].vector[2] = F(1); + for (i = 0; i < 4; i++) + { + PictureTransformPoint (matrix, &v[i]); + x1 = xFixedToInt (v[i].vector[0]); + y1 = xFixedToInt (v[i].vector[1]); + x2 = xFixedToInt (xFixedCeil (v[i].vector[0])); + y2 = xFixedToInt (xFixedCeil (v[i].vector[1])); + if (i == 0) + { + b->x1 = x1; b->y1 = y1; + b->x2 = x2; b->y2 = y2; + } + else + { + if (x1 < b->x1) b->x1 = x1; + if (y1 < b->y1) b->y1 = y1; + if (x2 > b->x2) b->x2 = x2; + if (y2 > b->y2) b->y2 = y2; + } + } +} + +static Bool +PictureTransformIsIdentity(PictTransform *t) +{ + return ((t->matrix[0][0] == t->matrix[1][1]) && + (t->matrix[0][0] == t->matrix[2][2]) && + (t->matrix[0][0] != 0) && + (t->matrix[0][1] == 0) && + (t->matrix[0][2] == 0) && + (t->matrix[1][0] == 0) && + (t->matrix[1][2] == 0) && + (t->matrix[2][0] == 0) && + (t->matrix[2][1] == 0)); +} + +#define toF(x) ((float) (x) / 65536.0f) + +static void +PictureTransformErrorF (PictTransform *t) +{ + ErrorF ("{ { %f %f %f } { %f %f %f } { %f %f %f } }", + toF(t->matrix[0][0]), toF(t->matrix[0][1]), toF(t->matrix[0][2]), + toF(t->matrix[1][0]), toF(t->matrix[1][1]), toF(t->matrix[1][2]), + toF(t->matrix[2][0]), toF(t->matrix[2][1]), toF(t->matrix[2][2])); +} + +static Bool +PictureTransformIsInverse (char *where, PictTransform *a, PictTransform *b) +{ + PictTransform t; + + PictureTransformMultiply (&t, a, b); + if (!PictureTransformIsIdentity (&t)) + { + ErrorF ("%s: ", where); + PictureTransformErrorF (a); + ErrorF (" * "); + PictureTransformErrorF (b); + ErrorF (" = "); + PictureTransformErrorF (a); + ErrorF ("\n"); + return FALSE; + } + return TRUE; +} + +static void +xf86RotateCrtcRedisplay (xf86CrtcPtr crtc, RegionPtr region) +{ + ScrnInfoPtr scrn = crtc->scrn; + ScreenPtr screen = scrn->pScreen; + WindowPtr root = WindowTable[screen->myNum]; + PixmapPtr dst_pixmap = crtc->rotatedPixmap; + PictFormatPtr format = compWindowFormat (WindowTable[screen->myNum]); + int error; + PicturePtr src, dst; + int n = REGION_NUM_RECTS(region); + BoxPtr b = REGION_RECTS(region); + XID include_inferiors = IncludeInferiors; + + src = CreatePicture (None, + &root->drawable, + format, + CPSubwindowMode, + &include_inferiors, + serverClient, + &error); + if (!src) + return; + + dst = CreatePicture (None, + &dst_pixmap->drawable, + format, + 0L, + NULL, + serverClient, + &error); + if (!dst) + return; + + error = SetPictureTransform (src, &crtc->crtc_to_framebuffer); + if (error) + return; + + while (n--) + { + BoxRec dst_box; + + dst_box = *b; + PictureTransformBounds (&dst_box, &crtc->framebuffer_to_crtc); + CompositePicture (PictOpSrc, + src, NULL, dst, + dst_box.x1, dst_box.y1, 0, 0, dst_box.x1, dst_box.y1, + dst_box.x2 - dst_box.x1, + dst_box.y2 - dst_box.y1); + b++; + } + FreePicture (src, None); + FreePicture (dst, None); +} + +static void +xf86CrtcDamageShadow (xf86CrtcPtr crtc) +{ + ScrnInfoPtr pScrn = crtc->scrn; + BoxRec damage_box; + RegionRec damage_region; + ScreenPtr pScreen = pScrn->pScreen; + + damage_box.x1 = crtc->x; + damage_box.x2 = crtc->x + xf86ModeWidth (&crtc->mode, crtc->rotation); + damage_box.y1 = crtc->y; + damage_box.y2 = crtc->y + xf86ModeHeight (&crtc->mode, crtc->rotation); + REGION_INIT (pScreen, &damage_region, &damage_box, 1); + DamageDamageRegion (&(*pScreen->GetScreenPixmap)(pScreen)->drawable, + &damage_region); + REGION_UNINIT (pScreen, &damage_region); +} + +static void +xf86RotatePrepare (ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + int c; + + for (c = 0; c < xf86_config->num_crtc; c++) + { + xf86CrtcPtr crtc = xf86_config->crtc[c]; + + if (crtc->rotatedData && !crtc->rotatedPixmap) + { + crtc->rotatedPixmap = crtc->funcs->shadow_create (crtc, + crtc->rotatedData, + crtc->mode.HDisplay, + crtc->mode.VDisplay); + if (!xf86_config->rotation_damage_registered) + { + /* Hook damage to screen pixmap */ + DamageRegister (&(*pScreen->GetScreenPixmap)(pScreen)->drawable, + xf86_config->rotation_damage); + xf86_config->rotation_damage_registered = TRUE; + } + + xf86CrtcDamageShadow (crtc); + } + } +} + +static Bool +xf86RotateRedisplay(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + DamagePtr damage = xf86_config->rotation_damage; + RegionPtr region; + + if (!damage) + return FALSE; + xf86RotatePrepare (pScreen); + region = DamageRegion(damage); + if (REGION_NOTEMPTY(pScreen, region)) + { + int c; + SourceValidateProcPtr SourceValidate; + + /* + * SourceValidate is used by the software cursor code + * to pull the cursor off of the screen when reading + * bits from the frame buffer. Bypassing this function + * leaves the software cursor in place + */ + SourceValidate = pScreen->SourceValidate; + pScreen->SourceValidate = NULL; + + for (c = 0; c < xf86_config->num_crtc; c++) + { + xf86CrtcPtr crtc = xf86_config->crtc[c]; + + if (crtc->rotation != RR_Rotate_0 && crtc->enabled) + { + RegionRec crtc_damage; + + /* compute portion of damage that overlaps crtc */ + REGION_INIT(pScreen, &crtc_damage, &crtc->bounds, 1); + REGION_INTERSECT (pScreen, &crtc_damage, &crtc_damage, region); + + /* update damaged region */ + if (REGION_NOTEMPTY(pScreen, &crtc_damage)) + xf86RotateCrtcRedisplay (crtc, &crtc_damage); + + REGION_UNINIT (pScreen, &crtc_damage); + } + } + pScreen->SourceValidate = SourceValidate; + DamageEmpty(damage); + } + return TRUE; +} + +static void +xf86RotateBlockHandler(int screenNum, pointer blockData, + pointer pTimeout, pointer pReadmask) +{ + ScreenPtr pScreen = screenInfo.screens[screenNum]; + ScrnInfoPtr pScrn = xf86Screens[screenNum]; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + + pScreen->BlockHandler = xf86_config->BlockHandler; + (*pScreen->BlockHandler) (screenNum, blockData, pTimeout, pReadmask); + if (xf86RotateRedisplay(pScreen)) + { + /* Re-wrap if rotation is still happening */ + xf86_config->BlockHandler = pScreen->BlockHandler; + pScreen->BlockHandler = xf86RotateBlockHandler; + } +} + +static void +xf86RotateDestroy (xf86CrtcPtr crtc) +{ + ScrnInfoPtr pScrn = crtc->scrn; + ScreenPtr pScreen = pScrn->pScreen; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + int c; + + /* Free memory from rotation */ + if (crtc->rotatedPixmap || crtc->rotatedData) + { + crtc->funcs->shadow_destroy (crtc, crtc->rotatedPixmap, crtc->rotatedData); + crtc->rotatedPixmap = NULL; + crtc->rotatedData = NULL; + } + + for (c = 0; c < xf86_config->num_crtc; c++) + if (xf86_config->crtc[c]->rotatedPixmap || + xf86_config->crtc[c]->rotatedData) + return; + + /* + * Clean up damage structures when no crtcs are rotated + */ + if (xf86_config->rotation_damage) + { + /* Free damage structure */ + if (xf86_config->rotation_damage_registered) + { + DamageUnregister (&(*pScreen->GetScreenPixmap)(pScreen)->drawable, + xf86_config->rotation_damage); + xf86_config->rotation_damage_registered = FALSE; + } + DamageDestroy (xf86_config->rotation_damage); + xf86_config->rotation_damage = NULL; + } +} + +_X_EXPORT void +xf86RotateCloseScreen (ScreenPtr screen) +{ + ScrnInfoPtr scrn = xf86Screens[screen->myNum]; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + int c; + + for (c = 0; c < xf86_config->num_crtc; c++) + xf86RotateDestroy (xf86_config->crtc[c]); +} + +_X_EXPORT Bool +xf86CrtcRotate (xf86CrtcPtr crtc, DisplayModePtr mode, Rotation rotation) +{ + ScrnInfoPtr pScrn = crtc->scrn; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + ScreenPtr pScreen = pScrn->pScreen; + PictTransform crtc_to_fb, fb_to_crtc; + + PictureTransformIdentity (&crtc_to_fb); + PictureTransformIdentity (&fb_to_crtc); + PictureTransformIsInverse ("identity", &crtc_to_fb, &fb_to_crtc); + if (rotation != RR_Rotate_0) + { + xFixed rot_cos, rot_sin, rot_dx, rot_dy; + xFixed scale_x, scale_y, scale_dx, scale_dy; + int mode_w = crtc->mode.HDisplay; + int mode_h = crtc->mode.VDisplay; + + /* rotation */ + switch (rotation & 0xf) { + default: + case RR_Rotate_0: + rot_cos = F ( 1); rot_sin = F ( 0); + rot_dx = F ( 0); rot_dy = F ( 0); + break; + case RR_Rotate_90: + rot_cos = F ( 0); rot_sin = F ( 1); + rot_dx = F ( mode_h); rot_dy = F (0); + break; + case RR_Rotate_180: + rot_cos = F (-1); rot_sin = F ( 0); + rot_dx = F (mode_w); rot_dy = F ( mode_h); + break; + case RR_Rotate_270: + rot_cos = F ( 0); rot_sin = F (-1); + rot_dx = F ( 0); rot_dy = F ( mode_w); + break; + } + + PictureTransformRotate (&crtc_to_fb, &fb_to_crtc, rot_cos, rot_sin); + PictureTransformIsInverse ("rotate", &crtc_to_fb, &fb_to_crtc); + + PictureTransformTranslate (&crtc_to_fb, &fb_to_crtc, rot_dx, rot_dy); + PictureTransformIsInverse ("rotate translate", &crtc_to_fb, &fb_to_crtc); + + /* reflection */ + scale_x = F (1); + scale_dx = 0; + scale_y = F (1); + scale_dy = 0; + if (rotation & RR_Reflect_X) + { + scale_x = F(-1); + if (rotation & (RR_Rotate_0|RR_Rotate_180)) + scale_dx = F(mode_w); + else + scale_dx = F(mode_h); + } + if (rotation & RR_Reflect_Y) + { + scale_y = F(-1); + if (rotation & (RR_Rotate_0|RR_Rotate_180)) + scale_dy = F(mode_h); + else + scale_dy = F(mode_w); + } + + PictureTransformScale (&crtc_to_fb, &fb_to_crtc, scale_x, scale_y); + PictureTransformIsInverse ("scale", &crtc_to_fb, &fb_to_crtc); + + PictureTransformTranslate (&crtc_to_fb, &fb_to_crtc, scale_dx, scale_dy); + PictureTransformIsInverse ("scale translate", &crtc_to_fb, &fb_to_crtc); + + } + + /* + * If the untranslated transformation is the identity, + * disable the shadow buffer + */ + if (PictureTransformIsIdentity (&crtc_to_fb)) + { + crtc->transform_in_use = FALSE; + PictureTransformInitTranslate (&crtc->crtc_to_framebuffer, + F (-crtc->x), F (-crtc->y)); + PictureTransformInitTranslate (&crtc->framebuffer_to_crtc, + F ( crtc->x), F ( crtc->y)); + xf86RotateDestroy (crtc); + } + else + { + PictureTransformTranslate (&crtc_to_fb, &fb_to_crtc, crtc->x, crtc->y); + PictureTransformIsInverse ("offset", &crtc_to_fb, &fb_to_crtc); + + /* + * these are the size of the shadow pixmap, which + * matches the mode, not the pre-rotated copy in the + * frame buffer + */ + int width = mode->HDisplay; + int height = mode->VDisplay; + void *shadowData = crtc->rotatedData; + PixmapPtr shadow = crtc->rotatedPixmap; + int old_width = shadow ? shadow->drawable.width : 0; + int old_height = shadow ? shadow->drawable.height : 0; + + /* Allocate memory for rotation */ + if (old_width != width || old_height != height) + { + if (shadow || shadowData) + { + crtc->funcs->shadow_destroy (crtc, shadow, shadowData); + crtc->rotatedPixmap = NULL; + crtc->rotatedData = NULL; + } + shadowData = crtc->funcs->shadow_allocate (crtc, width, height); + if (!shadowData) + goto bail1; + crtc->rotatedData = shadowData; + /* shadow will be damaged in xf86RotatePrepare */ + } + else + { + /* mark shadowed area as damaged so it will be repainted */ + xf86CrtcDamageShadow (crtc); + } + + if (!xf86_config->rotation_damage) + { + /* Create damage structure */ + xf86_config->rotation_damage = DamageCreate (NULL, NULL, + DamageReportNone, + TRUE, pScreen, pScreen); + if (!xf86_config->rotation_damage) + goto bail2; + + /* Wrap block handler */ + xf86_config->BlockHandler = pScreen->BlockHandler; + pScreen->BlockHandler = xf86RotateBlockHandler; + } + if (0) + { + bail2: + if (shadow || shadowData) + { + crtc->funcs->shadow_destroy (crtc, shadow, shadowData); + crtc->rotatedPixmap = NULL; + crtc->rotatedData = NULL; + } + bail1: + if (old_width && old_height) + crtc->rotatedPixmap = crtc->funcs->shadow_create (crtc, + NULL, + old_width, + old_height); + return FALSE; + } + crtc->transform_in_use = TRUE; + crtc->crtc_to_framebuffer = crtc_to_fb; + crtc->framebuffer_to_crtc = fb_to_crtc; + crtc->bounds.x1 = 0; + crtc->bounds.x2 = crtc->mode.HDisplay; + crtc->bounds.y1 = 0; + crtc->bounds.y2 = crtc->mode.VDisplay; + PictureTransformBounds (&crtc->bounds, &crtc_to_fb); + } + + /* All done */ + return TRUE; +} diff --git a/driver/xf86-video-intel/src/modes/xf86cvt.c b/driver/xf86-video-intel/src/modes/xf86cvt.c new file mode 100644 index 000000000..69ccc4259 --- /dev/null +++ b/driver/xf86-video-intel/src/modes/xf86cvt.c @@ -0,0 +1,308 @@ +/* + * Copyright 2005-2006 Luc Verhaegen. + * + * 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 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 + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 This is a copy of xf86cvt.c from the X Server, for compatibility with + * old servers (pre-1.2). + */ + +/* + * The reason for having this function in a file of its own is + * so that ../utils/cvt/cvt can link to it, and that xf86CVTMode + * code is shared directly. + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#else +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#endif + +#include "xf86.h" +#include "xf86Modes.h" + +#include <string.h> + +/* + * Generate a CVT standard mode from HDisplay, VDisplay and VRefresh. + * + * These calculations are stolen from the CVT calculation spreadsheet written + * by Graham Loveridge. He seems to be claiming no copyright and there seems to + * be no license attached to this. He apparently just wants to see his name + * mentioned. + * + * This file can be found at http://www.vesa.org/Public/CVT/CVTd6r1.xls + * + * Comments and structure corresponds to the comments and structure of the xls. + * This should ease importing of future changes to the standard (not very + * likely though). + * + * About margins; i'm sure that they are to be the bit between HDisplay and + * HBlankStart, HBlankEnd and HTotal, VDisplay and VBlankStart, VBlankEnd and + * VTotal, where the overscan colour is shown. FB seems to call _all_ blanking + * outside sync "margin" for some reason. Since we prefer seeing proper + * blanking instead of the overscan colour, and since the Crtc* values will + * probably get altered after us, we will disable margins altogether. With + * these calculations, Margins will plainly expand H/VDisplay, and we don't + * want that. -- libv + * + */ +_X_EXPORT DisplayModePtr +xf86CVTMode(int HDisplay, int VDisplay, float VRefresh, Bool Reduced, + Bool Interlaced) +{ + DisplayModeRec *Mode = xnfalloc(sizeof(DisplayModeRec)); + + /* 1) top/bottom margin size (% of height) - default: 1.8 */ +#define CVT_MARGIN_PERCENTAGE 1.8 + + /* 2) character cell horizontal granularity (pixels) - default 8 */ +#define CVT_H_GRANULARITY 8 + + /* 4) Minimum vertical porch (lines) - default 3 */ +#define CVT_MIN_V_PORCH 3 + + /* 4) Minimum number of vertical back porch lines - default 6 */ +#define CVT_MIN_V_BPORCH 6 + + /* Pixel Clock step (kHz) */ +#define CVT_CLOCK_STEP 250 + + Bool Margins = FALSE; + float VFieldRate, HPeriod; + int HDisplayRnd, HMargin; + int VDisplayRnd, VMargin, VSync; + float Interlace; /* Please rename this */ + + memset(Mode, 0, sizeof(DisplayModeRec)); + + /* CVT default is 60.0Hz */ + if (!VRefresh) + VRefresh = 60.0; + + /* 1. Required field rate */ + if (Interlaced) + VFieldRate = VRefresh * 2; + else + VFieldRate = VRefresh; + + /* 2. Horizontal pixels */ + HDisplayRnd = HDisplay - (HDisplay % CVT_H_GRANULARITY); + + /* 3. Determine left and right borders */ + if (Margins) { + /* right margin is actually exactly the same as left */ + HMargin = (((float) HDisplayRnd) * CVT_MARGIN_PERCENTAGE / 100.0); + HMargin -= HMargin % CVT_H_GRANULARITY; + } else + HMargin = 0; + + /* 4. Find total active pixels */ + Mode->HDisplay = HDisplayRnd + 2*HMargin; + + /* 5. Find number of lines per field */ + if (Interlaced) + VDisplayRnd = VDisplay / 2; + else + VDisplayRnd = VDisplay; + + /* 6. Find top and bottom margins */ + /* nope. */ + if (Margins) + /* top and bottom margins are equal again. */ + VMargin = (((float) VDisplayRnd) * CVT_MARGIN_PERCENTAGE / 100.0); + else + VMargin = 0; + + Mode->VDisplay = VDisplay + 2*VMargin; + + /* 7. Interlace */ + if (Interlaced) + Interlace = 0.5; + else + Interlace = 0.0; + + /* Determine VSync Width from aspect ratio */ + if (!(VDisplay % 3) && ((VDisplay * 4 / 3) == HDisplay)) + VSync = 4; + else if (!(VDisplay % 9) && ((VDisplay * 16 / 9) == HDisplay)) + VSync = 5; + else if (!(VDisplay % 10) && ((VDisplay * 16 / 10) == HDisplay)) + VSync = 6; + else if (!(VDisplay % 4) && ((VDisplay * 5 / 4) == HDisplay)) + VSync = 7; + else if (!(VDisplay % 9) && ((VDisplay * 15 / 9) == HDisplay)) + VSync = 7; + else /* Custom */ + VSync = 10; + + if (!Reduced) { /* simplified GTF calculation */ + + /* 4) Minimum time of vertical sync + back porch interval (µs) + * default 550.0 */ +#define CVT_MIN_VSYNC_BP 550.0 + + /* 3) Nominal HSync width (% of line period) - default 8 */ +#define CVT_HSYNC_PERCENTAGE 8 + + float HBlankPercentage; + int VSyncAndBackPorch, VBackPorch; + int HBlank; + + /* 8. Estimated Horizontal period */ + HPeriod = ((float) (1000000.0 / VFieldRate - CVT_MIN_VSYNC_BP)) / + (VDisplayRnd + 2 * VMargin + CVT_MIN_V_PORCH + Interlace); + + /* 9. Find number of lines in sync + backporch */ + if (((int)(CVT_MIN_VSYNC_BP / HPeriod) + 1) < (VSync + CVT_MIN_V_PORCH)) + VSyncAndBackPorch = VSync + CVT_MIN_V_PORCH; + else + VSyncAndBackPorch = (int)(CVT_MIN_VSYNC_BP / HPeriod) + 1; + + /* 10. Find number of lines in back porch */ + VBackPorch = VSyncAndBackPorch - VSync; + + /* 11. Find total number of lines in vertical field */ + Mode->VTotal = VDisplayRnd + 2 * VMargin + VSyncAndBackPorch + Interlace + + CVT_MIN_V_PORCH; + + /* 5) Definition of Horizontal blanking time limitation */ + /* Gradient (%/kHz) - default 600 */ +#define CVT_M_FACTOR 600 + + /* Offset (%) - default 40 */ +#define CVT_C_FACTOR 40 + + /* Blanking time scaling factor - default 128 */ +#define CVT_K_FACTOR 128 + + /* Scaling factor weighting - default 20 */ +#define CVT_J_FACTOR 20 + +#define CVT_M_PRIME CVT_M_FACTOR * CVT_K_FACTOR / 256 +#define CVT_C_PRIME (CVT_C_FACTOR - CVT_J_FACTOR) * CVT_K_FACTOR / 256 + \ + CVT_J_FACTOR + + /* 12. Find ideal blanking duty cycle from formula */ + HBlankPercentage = CVT_C_PRIME - CVT_M_PRIME * HPeriod/1000.0; + + /* 13. Blanking time */ + if (HBlankPercentage < 20) + HBlankPercentage = 20; + + HBlank = Mode->HDisplay * HBlankPercentage/(100.0 - HBlankPercentage); + HBlank -= HBlank % (2*CVT_H_GRANULARITY); + + /* 14. Find total number of pixels in a line. */ + Mode->HTotal = Mode->HDisplay + HBlank; + + /* Fill in HSync values */ + Mode->HSyncEnd = Mode->HDisplay + HBlank / 2; + + Mode->HSyncStart = Mode->HSyncEnd - + (Mode->HTotal * CVT_HSYNC_PERCENTAGE) / 100; + Mode->HSyncStart += CVT_H_GRANULARITY - + Mode->HSyncStart % CVT_H_GRANULARITY; + + /* Fill in VSync values */ + Mode->VSyncStart = Mode->VDisplay + CVT_MIN_V_PORCH; + Mode->VSyncEnd = Mode->VSyncStart + VSync; + + } else { /* Reduced blanking */ + /* Minimum vertical blanking interval time (µs) - default 460 */ +#define CVT_RB_MIN_VBLANK 460.0 + + /* Fixed number of clocks for horizontal sync */ +#define CVT_RB_H_SYNC 32.0 + + /* Fixed number of clocks for horizontal blanking */ +#define CVT_RB_H_BLANK 160.0 + + /* Fixed number of lines for vertical front porch - default 3 */ +#define CVT_RB_VFPORCH 3 + + int VBILines; + + /* 8. Estimate Horizontal period. */ + HPeriod = ((float) (1000000.0 / VFieldRate - CVT_RB_MIN_VBLANK)) / + (VDisplayRnd + 2*VMargin); + + /* 9. Find number of lines in vertical blanking */ + VBILines = ((float) CVT_RB_MIN_VBLANK) / HPeriod + 1; + + /* 10. Check if vertical blanking is sufficient */ + if (VBILines < (CVT_RB_VFPORCH + VSync + CVT_MIN_V_BPORCH)) + VBILines = CVT_RB_VFPORCH + VSync + CVT_MIN_V_BPORCH; + + /* 11. Find total number of lines in vertical field */ + Mode->VTotal = VDisplayRnd + 2 * VMargin + Interlace + VBILines; + + /* 12. Find total number of pixels in a line */ + Mode->HTotal = Mode->HDisplay + CVT_RB_H_BLANK; + + /* Fill in HSync values */ + Mode->HSyncEnd = Mode->HDisplay + CVT_RB_H_BLANK / 2; + Mode->HSyncStart = Mode->HSyncEnd - CVT_RB_H_SYNC; + + /* Fill in VSync values */ + Mode->VSyncStart = Mode->VDisplay + CVT_RB_VFPORCH; + Mode->VSyncEnd = Mode->VSyncStart + VSync; + } + + /* 15/13. Find pixel clock frequency (kHz for xf86) */ + Mode->Clock = Mode->HTotal * 1000.0 / HPeriod; + Mode->Clock -= Mode->Clock % CVT_CLOCK_STEP; + + /* 16/14. Find actual Horizontal Frequency (kHz) */ + Mode->HSync = ((float) Mode->Clock) / ((float) Mode->HTotal); + + /* 17/15. Find actual Field rate */ + Mode->VRefresh = (1000.0 * ((float) Mode->Clock)) / + ((float) (Mode->HTotal * Mode->VTotal)); + + /* 18/16. Find actual vertical frame frequency */ + /* ignore - just set the mode flag for interlaced */ + if (Interlaced) + Mode->VTotal *= 2; + + { + char Name[256]; + Name[0] = 0; + + snprintf(Name, 256, "%dx%d", HDisplay, VDisplay); + + Mode->name = xnfalloc(strlen(Name) + 1); + memcpy(Mode->name, Name, strlen(Name) + 1); + } + + if (Reduced) + Mode->Flags |= V_PHSYNC | V_NVSYNC; + else + Mode->Flags |= V_NHSYNC | V_PVSYNC; + + if (Interlaced) + Mode->Flags |= V_INTERLACE; + + return Mode; +} diff --git a/driver/xf86-video-intel/src/parser/xf86Optrec.h b/driver/xf86-video-intel/src/parser/xf86Optrec.h new file mode 100644 index 000000000..183b85720 --- /dev/null +++ b/driver/xf86-video-intel/src/parser/xf86Optrec.h @@ -0,0 +1,112 @@ +/* + * + * Copyright (c) 1997 Metro Link Incorporated + * + * 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 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 + * THE X CONSORTIUM 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. + * + * Except as contained in this notice, the name of the Metro Link shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from Metro Link. + * + */ +/* + * Copyright (c) 1997-2001 by The XFree86 Project, Inc. + * + * 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 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 + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + * + * Except as contained in this notice, the name of the copyright holder(s) + * and author(s) shall not be used in advertising or otherwise to promote + * the sale, use or other dealings in this Software without prior written + * authorization from the copyright holder(s) and author(s). + */ + + +/* + * This file contains the Option Record that is passed between the Parser, + * and Module setup procs. + */ +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#ifndef _xf86Optrec_h_ +#define _xf86Optrec_h_ +#include <stdio.h> + +/* + * all records that need to be linked lists should contain a GenericList as + * their first field. + */ +typedef struct generic_list_rec +{ + void *next; +} +GenericListRec, *GenericListPtr, *glp; + +/* + * All options are stored using this data type. + */ +typedef struct +{ + GenericListRec list; + char *opt_name; + char *opt_val; + int opt_used; + char *opt_comment; +} +XF86OptionRec, *XF86OptionPtr; + + +XF86OptionPtr xf86addNewOption(XF86OptionPtr head, char *name, char *val); +XF86OptionPtr xf86optionListDup(XF86OptionPtr opt); +void xf86optionListFree(XF86OptionPtr opt); +char *xf86optionName(XF86OptionPtr opt); +char *xf86optionValue(XF86OptionPtr opt); +XF86OptionPtr xf86newOption(char *name, char *value); +XF86OptionPtr xf86nextOption(XF86OptionPtr list); +XF86OptionPtr xf86findOption(XF86OptionPtr list, const char *name); +char *xf86findOptionValue(XF86OptionPtr list, const char *name); +int xf86findOptionBoolean (XF86OptionPtr, const char *, int); +XF86OptionPtr xf86optionListCreate(const char **options, int count, int used); +XF86OptionPtr xf86optionListMerge(XF86OptionPtr head, XF86OptionPtr tail); +char *xf86configStrdup (const char *s); +int xf86nameCompare (const char *s1, const char *s2); +char *xf86uLongToString(unsigned long i); +void xf86debugListOptions(XF86OptionPtr); +XF86OptionPtr xf86parseOption(XF86OptionPtr head); +void xf86printOptionList(FILE *fp, XF86OptionPtr list, int tabs); + + +#endif /* _xf86Optrec_h_ */ diff --git a/driver/xf86-video-intel/src/parser/xf86Parser.h b/driver/xf86-video-intel/src/parser/xf86Parser.h new file mode 100644 index 000000000..dc30823cc --- /dev/null +++ b/driver/xf86-video-intel/src/parser/xf86Parser.h @@ -0,0 +1,484 @@ +/* + * + * Copyright (c) 1997 Metro Link Incorporated + * + * 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 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 + * THE X CONSORTIUM 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. + * + * Except as contained in this notice, the name of the Metro Link shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from Metro Link. + * + */ +/* + * Copyright (c) 1997-2003 by The XFree86 Project, Inc. + * + * 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 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 + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + * + * Except as contained in this notice, the name of the copyright holder(s) + * and author(s) shall not be used in advertising or otherwise to promote + * the sale, use or other dealings in this Software without prior written + * authorization from the copyright holder(s) and author(s). + */ + + +/* + * This file contains the external interfaces for the XFree86 configuration + * file parser. + */ +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#ifndef _xf86Parser_h_ +#define _xf86Parser_h_ + +#include "xf86Optrec.h" + +#define HAVE_PARSER_DECLS + +typedef struct +{ + char *file_logfile; + char *file_rgbpath; + char *file_modulepath; + char *file_inputdevs; + char *file_fontpath; + char *file_comment; +} +XF86ConfFilesRec, *XF86ConfFilesPtr; + +/* Values for load_type */ +#define XF86_LOAD_MODULE 0 +#define XF86_LOAD_DRIVER 1 +#define XF86_DISABLE_MODULE 2 + +typedef struct +{ + GenericListRec list; + int load_type; + char *load_name; + XF86OptionPtr load_opt; + char *load_comment; + int ignore; +} +XF86LoadRec, *XF86LoadPtr; + +typedef struct +{ + XF86LoadPtr mod_load_lst; + XF86LoadPtr mod_disable_lst; + char *mod_comment; +} +XF86ConfModuleRec, *XF86ConfModulePtr; + +#define CONF_IMPLICIT_KEYBOARD "Implicit Core Keyboard" + +#define CONF_IMPLICIT_POINTER "Implicit Core Pointer" + +#define XF86CONF_PHSYNC 0x0001 +#define XF86CONF_NHSYNC 0x0002 +#define XF86CONF_PVSYNC 0x0004 +#define XF86CONF_NVSYNC 0x0008 +#define XF86CONF_INTERLACE 0x0010 +#define XF86CONF_DBLSCAN 0x0020 +#define XF86CONF_CSYNC 0x0040 +#define XF86CONF_PCSYNC 0x0080 +#define XF86CONF_NCSYNC 0x0100 +#define XF86CONF_HSKEW 0x0200 /* hskew provided */ +#define XF86CONF_BCAST 0x0400 +#define XF86CONF_CUSTOM 0x0800 /* timing numbers customized by editor */ +#define XF86CONF_VSCAN 0x1000 + +typedef struct +{ + GenericListRec list; + char *ml_identifier; + int ml_clock; + int ml_hdisplay; + int ml_hsyncstart; + int ml_hsyncend; + int ml_htotal; + int ml_vdisplay; + int ml_vsyncstart; + int ml_vsyncend; + int ml_vtotal; + int ml_vscan; + int ml_flags; + int ml_hskew; + char *ml_comment; +} +XF86ConfModeLineRec, *XF86ConfModeLinePtr; + +typedef struct +{ + GenericListRec list; + char *vp_identifier; + XF86OptionPtr vp_option_lst; + char *vp_comment; +} +XF86ConfVideoPortRec, *XF86ConfVideoPortPtr; + +typedef struct +{ + GenericListRec list; + char *va_identifier; + char *va_vendor; + char *va_board; + char *va_busid; + char *va_driver; + XF86OptionPtr va_option_lst; + XF86ConfVideoPortPtr va_port_lst; + char *va_fwdref; + char *va_comment; +} +XF86ConfVideoAdaptorRec, *XF86ConfVideoAdaptorPtr; + +#define CONF_MAX_HSYNC 8 +#define CONF_MAX_VREFRESH 8 + +typedef struct +{ + float hi, lo; +} +parser_range; + +typedef struct +{ + int red, green, blue; +} +parser_rgb; + +typedef struct +{ + GenericListRec list; + char *modes_identifier; + XF86ConfModeLinePtr mon_modeline_lst; + char *modes_comment; +} +XF86ConfModesRec, *XF86ConfModesPtr; + +typedef struct +{ + GenericListRec list; + char *ml_modes_str; + XF86ConfModesPtr ml_modes; +} +XF86ConfModesLinkRec, *XF86ConfModesLinkPtr; + +typedef struct +{ + GenericListRec list; + char *mon_identifier; + char *mon_vendor; + char *mon_modelname; + int mon_width; /* in mm */ + int mon_height; /* in mm */ + XF86ConfModeLinePtr mon_modeline_lst; + int mon_n_hsync; + parser_range mon_hsync[CONF_MAX_HSYNC]; + int mon_n_vrefresh; + parser_range mon_vrefresh[CONF_MAX_VREFRESH]; + float mon_gamma_red; + float mon_gamma_green; + float mon_gamma_blue; + XF86OptionPtr mon_option_lst; + XF86ConfModesLinkPtr mon_modes_sect_lst; + char *mon_comment; +} +XF86ConfMonitorRec, *XF86ConfMonitorPtr; + +#define CONF_MAXDACSPEEDS 4 +#define CONF_MAXCLOCKS 128 + +typedef struct +{ + GenericListRec list; + char *dev_identifier; + char *dev_vendor; + char *dev_board; + char *dev_chipset; + char *dev_busid; + char *dev_card; + char *dev_driver; + char *dev_ramdac; + int dev_dacSpeeds[CONF_MAXDACSPEEDS]; + int dev_videoram; + int dev_textclockfreq; + unsigned long dev_bios_base; + unsigned long dev_mem_base; + unsigned long dev_io_base; + char *dev_clockchip; + int dev_clocks; + int dev_clock[CONF_MAXCLOCKS]; + int dev_chipid; + int dev_chiprev; + int dev_irq; + int dev_screen; + XF86OptionPtr dev_option_lst; + char *dev_comment; +} +XF86ConfDeviceRec, *XF86ConfDevicePtr; + +typedef struct +{ + GenericListRec list; + char *mode_name; +} +XF86ModeRec, *XF86ModePtr; + +typedef struct +{ + GenericListRec list; + int disp_frameX0; + int disp_frameY0; + int disp_virtualX; + int disp_virtualY; + int disp_depth; + int disp_bpp; + char *disp_visual; + parser_rgb disp_weight; + parser_rgb disp_black; + parser_rgb disp_white; + XF86ModePtr disp_mode_lst; + XF86OptionPtr disp_option_lst; + char *disp_comment; +} +XF86ConfDisplayRec, *XF86ConfDisplayPtr; + +typedef struct +{ + XF86OptionPtr flg_option_lst; + char *flg_comment; +} +XF86ConfFlagsRec, *XF86ConfFlagsPtr; + +typedef struct +{ + GenericListRec list; + char *al_adaptor_str; + XF86ConfVideoAdaptorPtr al_adaptor; +} +XF86ConfAdaptorLinkRec, *XF86ConfAdaptorLinkPtr; + +typedef struct +{ + GenericListRec list; + char *scrn_identifier; + char *scrn_obso_driver; + int scrn_defaultdepth; + int scrn_defaultbpp; + int scrn_defaultfbbpp; + char *scrn_monitor_str; + XF86ConfMonitorPtr scrn_monitor; + char *scrn_device_str; + XF86ConfDevicePtr scrn_device; + XF86ConfAdaptorLinkPtr scrn_adaptor_lst; + XF86ConfDisplayPtr scrn_display_lst; + XF86OptionPtr scrn_option_lst; + char *scrn_comment; +} +XF86ConfScreenRec, *XF86ConfScreenPtr; + +typedef struct +{ + GenericListRec list; + char *inp_identifier; + char *inp_driver; + XF86OptionPtr inp_option_lst; + char *inp_comment; +} +XF86ConfInputRec, *XF86ConfInputPtr; + +typedef struct +{ + GenericListRec list; + XF86ConfInputPtr iref_inputdev; + char *iref_inputdev_str; + XF86OptionPtr iref_option_lst; +} +XF86ConfInputrefRec, *XF86ConfInputrefPtr; + +/* Values for adj_where */ +#define CONF_ADJ_OBSOLETE -1 +#define CONF_ADJ_ABSOLUTE 0 +#define CONF_ADJ_RIGHTOF 1 +#define CONF_ADJ_LEFTOF 2 +#define CONF_ADJ_ABOVE 3 +#define CONF_ADJ_BELOW 4 +#define CONF_ADJ_RELATIVE 5 + +typedef struct +{ + GenericListRec list; + int adj_scrnum; + XF86ConfScreenPtr adj_screen; + char *adj_screen_str; + XF86ConfScreenPtr adj_top; + char *adj_top_str; + XF86ConfScreenPtr adj_bottom; + char *adj_bottom_str; + XF86ConfScreenPtr adj_left; + char *adj_left_str; + XF86ConfScreenPtr adj_right; + char *adj_right_str; + int adj_where; + int adj_x; + int adj_y; + char *adj_refscreen; +} +XF86ConfAdjacencyRec, *XF86ConfAdjacencyPtr; + +typedef struct +{ + GenericListRec list; + char *inactive_device_str; + XF86ConfDevicePtr inactive_device; +} +XF86ConfInactiveRec, *XF86ConfInactivePtr; + +typedef struct +{ + GenericListRec list; + char *lay_identifier; + XF86ConfAdjacencyPtr lay_adjacency_lst; + XF86ConfInactivePtr lay_inactive_lst; + XF86ConfInputrefPtr lay_input_lst; + XF86OptionPtr lay_option_lst; + char *lay_comment; +} +XF86ConfLayoutRec, *XF86ConfLayoutPtr; + +typedef struct +{ + GenericListRec list; + char *vs_name; + char *vs_identifier; + XF86OptionPtr vs_option_lst; + char *vs_comment; +} +XF86ConfVendSubRec, *XF86ConfVendSubPtr; + +typedef struct +{ + GenericListRec list; + char *vnd_identifier; + XF86OptionPtr vnd_option_lst; + XF86ConfVendSubPtr vnd_sub_lst; + char *vnd_comment; +} +XF86ConfVendorRec, *XF86ConfVendorPtr; + +typedef struct +{ + GenericListRec list; + int buf_count; + int buf_size; + char *buf_flags; + char *buf_comment; +} +XF86ConfBuffersRec, *XF86ConfBuffersPtr; + +typedef struct +{ + char *dri_group_name; + int dri_group; + int dri_mode; + XF86ConfBuffersPtr dri_buffers_lst; + char *dri_comment; +} +XF86ConfDRIRec, *XF86ConfDRIPtr; + +typedef struct +{ + XF86OptionPtr ext_option_lst; + char *extensions_comment; +} +XF86ConfExtensionsRec, *XF86ConfExtensionsPtr; + +typedef struct +{ + XF86ConfFilesPtr conf_files; + XF86ConfModulePtr conf_modules; + XF86ConfFlagsPtr conf_flags; + XF86ConfVideoAdaptorPtr conf_videoadaptor_lst; + XF86ConfModesPtr conf_modes_lst; + XF86ConfMonitorPtr conf_monitor_lst; + XF86ConfDevicePtr conf_device_lst; + XF86ConfScreenPtr conf_screen_lst; + XF86ConfInputPtr conf_input_lst; + XF86ConfLayoutPtr conf_layout_lst; + XF86ConfVendorPtr conf_vendor_lst; + XF86ConfDRIPtr conf_dri; + XF86ConfExtensionsPtr conf_extensions; + char *conf_comment; +} +XF86ConfigRec, *XF86ConfigPtr; + +typedef struct +{ + int token; /* id of the token */ + char *name; /* pointer to the LOWERCASED name */ +} +xf86ConfigSymTabRec, *xf86ConfigSymTabPtr; + +/* + * prototypes for public functions + */ +extern const char *xf86openConfigFile (const char *, const char *, + const char *); +extern void xf86setBuiltinConfig(const char *config[]); +extern XF86ConfigPtr xf86readConfigFile (void); +extern void xf86closeConfigFile (void); +extern void xf86freeConfig (XF86ConfigPtr p); +extern int xf86writeConfigFile (const char *, XF86ConfigPtr); +XF86ConfDevicePtr xf86findDevice(const char *ident, XF86ConfDevicePtr p); +XF86ConfLayoutPtr xf86findLayout(const char *name, XF86ConfLayoutPtr list); +XF86ConfMonitorPtr xf86findMonitor(const char *ident, XF86ConfMonitorPtr p); +XF86ConfModesPtr xf86findModes(const char *ident, XF86ConfModesPtr p); +XF86ConfModeLinePtr xf86findModeLine(const char *ident, XF86ConfModeLinePtr p); +XF86ConfScreenPtr xf86findScreen(const char *ident, XF86ConfScreenPtr p); +XF86ConfInputPtr xf86findInput(const char *ident, XF86ConfInputPtr p); +XF86ConfInputPtr xf86findInputByDriver(const char *driver, XF86ConfInputPtr p); +XF86ConfVideoAdaptorPtr xf86findVideoAdaptor(const char *ident, + XF86ConfVideoAdaptorPtr p); + +GenericListPtr xf86addListItem(GenericListPtr head, GenericListPtr c_new); +int xf86itemNotSublist(GenericListPtr list_1, GenericListPtr list_2); + +int xf86pathIsAbsolute(const char *path); +int xf86pathIsSafe(const char *path); +char *xf86addComment(char *cur, char *add); + +#endif /* _xf86Parser_h_ */ diff --git a/driver/xf86-video-intel/src/reg_dumper/Makefile.am b/driver/xf86-video-intel/src/reg_dumper/Makefile.am new file mode 100644 index 000000000..aee26d0ed --- /dev/null +++ b/driver/xf86-video-intel/src/reg_dumper/Makefile.am @@ -0,0 +1,12 @@ +noinst_PROGRAMS = intel_reg_dumper + +intel_reg_dumper_SOURCES = \ + main.c \ + reg_dumper.h \ + xprintf.c \ + ../i830_debug.c + +intel_reg_dumper_LDADD = $(PCIACCESS_LIBS) + +intel_reg_dumper_CFLAGS = $(PCIACCESS_CFLAGS) $(WARN_CFLAGS) \ + -I$(srcdir)/.. -DREG_DUMPER diff --git a/driver/xf86-video-intel/src/reg_dumper/Makefile.in b/driver/xf86-video-intel/src/reg_dumper/Makefile.in new file mode 100644 index 000000000..28cb5a31e --- /dev/null +++ b/driver/xf86-video-intel/src/reg_dumper/Makefile.in @@ -0,0 +1,522 @@ +# Makefile.in generated by automake 1.10 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +noinst_PROGRAMS = intel_reg_dumper$(EXEEXT) +subdir = src/reg_dumper +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +PROGRAMS = $(noinst_PROGRAMS) +am_intel_reg_dumper_OBJECTS = intel_reg_dumper-main.$(OBJEXT) \ + intel_reg_dumper-xprintf.$(OBJEXT) \ + intel_reg_dumper-i830_debug.$(OBJEXT) +intel_reg_dumper_OBJECTS = $(am_intel_reg_dumper_OBJECTS) +am__DEPENDENCIES_1 = +intel_reg_dumper_DEPENDENCIES = $(am__DEPENDENCIES_1) +intel_reg_dumper_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(intel_reg_dumper_CFLAGS) \ + $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I. -I$(top_builddir)@am__isrc@ +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(intel_reg_dumper_SOURCES) +DIST_SOURCES = $(intel_reg_dumper_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ADMIN_MAN_DIR = @ADMIN_MAN_DIR@ +ADMIN_MAN_SUFFIX = @ADMIN_MAN_SUFFIX@ +AMTAR = @AMTAR@ +APP_MAN_DIR = @APP_MAN_DIR@ +APP_MAN_SUFFIX = @APP_MAN_SUFFIX@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DRIVER_MAN_DIR = @DRIVER_MAN_DIR@ +DRIVER_MAN_SUFFIX = @DRIVER_MAN_SUFFIX@ +DRIVER_NAME = @DRIVER_NAME@ +DRI_CFLAGS = @DRI_CFLAGS@ +DRI_LIBS = @DRI_LIBS@ +DRI_MM_CFLAGS = @DRI_MM_CFLAGS@ +DRI_MM_LIBS = @DRI_MM_LIBS@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +FILE_MAN_DIR = @FILE_MAN_DIR@ +FILE_MAN_SUFFIX = @FILE_MAN_SUFFIX@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIB_MAN_DIR = @LIB_MAN_DIR@ +LIB_MAN_SUFFIX = @LIB_MAN_SUFFIX@ +LINUXDOC = @LINUXDOC@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MAKE_HTML = @MAKE_HTML@ +MAKE_PDF = @MAKE_PDF@ +MAKE_PS = @MAKE_PS@ +MAKE_TEXT = @MAKE_TEXT@ +MISC_MAN_DIR = @MISC_MAN_DIR@ +MISC_MAN_SUFFIX = @MISC_MAN_SUFFIX@ +MKDIR_P = @MKDIR_P@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PCIACCESS_CFLAGS = @PCIACCESS_CFLAGS@ +PCIACCESS_LIBS = @PCIACCESS_LIBS@ +PKG_CONFIG = @PKG_CONFIG@ +PS2PDF = @PS2PDF@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +WARN_CFLAGS = @WARN_CFLAGS@ +XMODES_CFLAGS = @XMODES_CFLAGS@ +XORG_CFLAGS = @XORG_CFLAGS@ +XORG_LIBS = @XORG_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +gen4asm = @gen4asm@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +moduledir = @moduledir@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +intel_reg_dumper_SOURCES = \ + main.c \ + reg_dumper.h \ + xprintf.c \ + ../i830_debug.c + +intel_reg_dumper_LDADD = $(PCIACCESS_LIBS) +intel_reg_dumper_CFLAGS = $(PCIACCESS_CFLAGS) $(WARN_CFLAGS) \ + -I$(srcdir)/.. -DREG_DUMPER + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/reg_dumper/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/reg_dumper/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstPROGRAMS: + @list='$(noinst_PROGRAMS)'; for p in $$list; do \ + f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f $$p $$f"; \ + rm -f $$p $$f ; \ + done +intel_reg_dumper$(EXEEXT): $(intel_reg_dumper_OBJECTS) $(intel_reg_dumper_DEPENDENCIES) + @rm -f intel_reg_dumper$(EXEEXT) + $(intel_reg_dumper_LINK) $(intel_reg_dumper_OBJECTS) $(intel_reg_dumper_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/intel_reg_dumper-i830_debug.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/intel_reg_dumper-main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/intel_reg_dumper-xprintf.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +intel_reg_dumper-main.o: main.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(intel_reg_dumper_CFLAGS) $(CFLAGS) -MT intel_reg_dumper-main.o -MD -MP -MF $(DEPDIR)/intel_reg_dumper-main.Tpo -c -o intel_reg_dumper-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/intel_reg_dumper-main.Tpo $(DEPDIR)/intel_reg_dumper-main.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='main.c' object='intel_reg_dumper-main.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(intel_reg_dumper_CFLAGS) $(CFLAGS) -c -o intel_reg_dumper-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c + +intel_reg_dumper-main.obj: main.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(intel_reg_dumper_CFLAGS) $(CFLAGS) -MT intel_reg_dumper-main.obj -MD -MP -MF $(DEPDIR)/intel_reg_dumper-main.Tpo -c -o intel_reg_dumper-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/intel_reg_dumper-main.Tpo $(DEPDIR)/intel_reg_dumper-main.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='main.c' object='intel_reg_dumper-main.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(intel_reg_dumper_CFLAGS) $(CFLAGS) -c -o intel_reg_dumper-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi` + +intel_reg_dumper-xprintf.o: xprintf.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(intel_reg_dumper_CFLAGS) $(CFLAGS) -MT intel_reg_dumper-xprintf.o -MD -MP -MF $(DEPDIR)/intel_reg_dumper-xprintf.Tpo -c -o intel_reg_dumper-xprintf.o `test -f 'xprintf.c' || echo '$(srcdir)/'`xprintf.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/intel_reg_dumper-xprintf.Tpo $(DEPDIR)/intel_reg_dumper-xprintf.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='xprintf.c' object='intel_reg_dumper-xprintf.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(intel_reg_dumper_CFLAGS) $(CFLAGS) -c -o intel_reg_dumper-xprintf.o `test -f 'xprintf.c' || echo '$(srcdir)/'`xprintf.c + +intel_reg_dumper-xprintf.obj: xprintf.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(intel_reg_dumper_CFLAGS) $(CFLAGS) -MT intel_reg_dumper-xprintf.obj -MD -MP -MF $(DEPDIR)/intel_reg_dumper-xprintf.Tpo -c -o intel_reg_dumper-xprintf.obj `if test -f 'xprintf.c'; then $(CYGPATH_W) 'xprintf.c'; else $(CYGPATH_W) '$(srcdir)/xprintf.c'; fi` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/intel_reg_dumper-xprintf.Tpo $(DEPDIR)/intel_reg_dumper-xprintf.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='xprintf.c' object='intel_reg_dumper-xprintf.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(intel_reg_dumper_CFLAGS) $(CFLAGS) -c -o intel_reg_dumper-xprintf.obj `if test -f 'xprintf.c'; then $(CYGPATH_W) 'xprintf.c'; else $(CYGPATH_W) '$(srcdir)/xprintf.c'; fi` + +intel_reg_dumper-i830_debug.o: ../i830_debug.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(intel_reg_dumper_CFLAGS) $(CFLAGS) -MT intel_reg_dumper-i830_debug.o -MD -MP -MF $(DEPDIR)/intel_reg_dumper-i830_debug.Tpo -c -o intel_reg_dumper-i830_debug.o `test -f '../i830_debug.c' || echo '$(srcdir)/'`../i830_debug.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/intel_reg_dumper-i830_debug.Tpo $(DEPDIR)/intel_reg_dumper-i830_debug.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../i830_debug.c' object='intel_reg_dumper-i830_debug.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(intel_reg_dumper_CFLAGS) $(CFLAGS) -c -o intel_reg_dumper-i830_debug.o `test -f '../i830_debug.c' || echo '$(srcdir)/'`../i830_debug.c + +intel_reg_dumper-i830_debug.obj: ../i830_debug.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(intel_reg_dumper_CFLAGS) $(CFLAGS) -MT intel_reg_dumper-i830_debug.obj -MD -MP -MF $(DEPDIR)/intel_reg_dumper-i830_debug.Tpo -c -o intel_reg_dumper-i830_debug.obj `if test -f '../i830_debug.c'; then $(CYGPATH_W) '../i830_debug.c'; else $(CYGPATH_W) '$(srcdir)/../i830_debug.c'; fi` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/intel_reg_dumper-i830_debug.Tpo $(DEPDIR)/intel_reg_dumper-i830_debug.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../i830_debug.c' object='intel_reg_dumper-i830_debug.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(intel_reg_dumper_CFLAGS) $(CFLAGS) -c -o intel_reg_dumper-i830_debug.obj `if test -f '../i830_debug.c'; then $(CYGPATH_W) '../i830_debug.c'; else $(CYGPATH_W) '$(srcdir)/../i830_debug.c'; fi` + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-exec-am: + +install-html: install-html-am + +install-info: install-info-am + +install-man: + +install-pdf: install-pdf-am + +install-ps: install-ps-am + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstPROGRAMS ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/driver/xf86-video-intel/src/reg_dumper/main.c b/driver/xf86-video-intel/src/reg_dumper/main.c new file mode 100644 index 000000000..5c8ef9ede --- /dev/null +++ b/driver/xf86-video-intel/src/reg_dumper/main.c @@ -0,0 +1,111 @@ +/* + * Copyright © 2007 Intel Corporation + * + * 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 + * THE AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <pciaccess.h> +#include <err.h> + +#include "reg_dumper.h" + +int main(int argc, char **argv) +{ + struct pci_device *dev; + I830Rec i830; + ScrnInfoRec scrn; + int err, mmio_bar; + void *mmio; + + err = pci_system_init(); + if (err != 0) { + fprintf(stderr, "Couldn't initialize PCI system: %s\n", strerror(err)); + exit(1); + } + + /* Grab the graphics card */ + dev = pci_device_find_by_slot(0, 0, 2, 0); + if (dev == NULL) + errx(1, "Couldn't find graphics card"); + + err = pci_device_probe(dev); + if (err != 0) { + fprintf(stderr, "Couldn't probe graphics card: %s\n", strerror(err)); + exit(1); + } + + if (dev->vendor_id != 0x8086) + errx(1, "Graphics card is non-intel"); + + i830.PciInfo = &i830.pci_info_rec; + i830.PciInfo->chipType = dev->device_id; + + i830.pci_dev = dev; + + mmio_bar = IS_I9XX((&i830)) ? 0 : 1; + + err = pci_device_map_range (dev, + dev->regions[mmio_bar].base_addr, + dev->regions[mmio_bar].size, + PCI_DEV_MAP_FLAG_WRITABLE, + &mmio); + + if (err != 0) { + fprintf(stderr, "Couldn't map MMIO region: %s\n", strerror(err)); + exit(1); + } + i830.mmio = mmio; + + scrn.scrnIndex = 0; + scrn.pI830 = &i830; + + i830DumpRegs(&scrn); + + return 0; +} + +void xf86DrvMsg(int scrnIndex, int severity, const char *format, ...) +{ + va_list va; + + switch (severity) { + case X_INFO: + printf("(II): "); + break; + case X_WARNING: + printf("(WW): "); + break; + case X_ERROR: + printf("(EE): "); + break; + } + + va_start(va, format); + vprintf(format, va); + va_end(va); +} diff --git a/driver/xf86-video-intel/src/reg_dumper/reg_dumper.h b/driver/xf86-video-intel/src/reg_dumper/reg_dumper.h new file mode 100644 index 000000000..07ddf6fd1 --- /dev/null +++ b/driver/xf86-video-intel/src/reg_dumper/reg_dumper.h @@ -0,0 +1,89 @@ +/* + * Copyright © 2007 Intel Corporation + * + * 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 + * THE AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt <eric@anholt.net> + * + */ + +#include <inttypes.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include "common.h" + +/** @file + * This file defines the typedefs and stub structures necessary for us to + * use i830_debug.c mostly unmodified. + */ + +typedef uint32_t CARD32; +typedef char Bool; + +#define FALSE 0 +#define TRUE 1 + +#define X_INFO 0 +#define X_WARNING 1 +#define X_ERROR 2 + +struct pci_info_rec { + uint16_t chipType; +}; + +typedef struct _i830 { + /* Fields in common with the real pI830 */ + struct pci_info_rec *PciInfo; + + /* Fields used for setting up reg_dumper */ + struct pci_device *pci_dev; + struct pci_info_rec pci_info_rec; + volatile unsigned char *mmio; +} I830Rec, *I830Ptr; + +typedef struct _scrn { + /* Fields in common with the real pScrn */ + int scrnIndex; + + /* Fields used for setting up reg_dumper */ + I830Ptr pI830; +} ScrnInfoRec, *ScrnInfoPtr; + +#define I830PTR(pScrn) (pScrn->pI830) + +#define INREG8(reg) (*(volatile uint8_t *)((pI830)->mmio + (reg))) +#define INREG16(reg) (*(volatile uint16_t *)((pI830)->mmio + (reg))) +#define INREG(reg) (*(volatile uint32_t *)((pI830)->mmio + (reg))) +#define OUTREG8(reg, val) \ + *(volatile uint8_t *)((pI830)->mmio + (reg)) = (val) +#define OUTREG16(reg, val) \ + *(volatile uint16_t *)((pI830)->mmio + (reg)) = (val) +#define OUTREG(reg, val) \ + *(volatile uint32_t *)((pI830)->mmio + (reg)) = (val) + +#define xalloc malloc +#define xfree free +#define ErrorF printf + +char *XNFprintf(const char *format, ...); +void xf86DrvMsg(int scrnIndex, int severity, const char *format, ...); +void i830DumpRegs(ScrnInfoPtr pScrn); diff --git a/driver/xf86-video-intel/src/reg_dumper/xprintf.c b/driver/xf86-video-intel/src/reg_dumper/xprintf.c new file mode 100644 index 000000000..125ae8704 --- /dev/null +++ b/driver/xf86-video-intel/src/reg_dumper/xprintf.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2004 Alexander Gottwald + * + * 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 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 + * THE ABOVE LISTED COPYRIGHT HOLDER(S) 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. + * + * Except as contained in this notice, the name(s) of the above copyright + * holders shall not be used in advertising or otherwise to promote the sale, + * use or other dealings in this Software without prior written authorization. + */ + +#include <string.h> +#include <stdarg.h> +#include "reg_dumper.h" + +static char * +XNFvprintf(const char *format, va_list va) +{ + char *ret; + int size; + va_list va2; + + va_copy(va2, va); + size = vsnprintf(NULL, 0, format, va2); + va_end(va2); + + ret = (char *)malloc(size + 1); + if (ret == NULL) + return NULL; + + vsnprintf(ret, size + 1, format, va); + ret[size] = 0; + return ret; +} + +char * +XNFprintf(const char *format, ...) +{ + char *ret; + va_list va; + va_start(va, format); + ret = XNFvprintf(format, va); + va_end(va); + return ret; +} diff --git a/driver/xf86-video-intel/src/sil164/Makefile.am b/driver/xf86-video-intel/src/sil164/Makefile.am new file mode 100644 index 000000000..497ee9f7b --- /dev/null +++ b/driver/xf86-video-intel/src/sil164/Makefile.am @@ -0,0 +1,16 @@ +# this is obnoxious: +# -module lets us name the module exactly how we want +# -avoid-version prevents gratuitous .0.0.0 version numbers on the end +# _ladir passes a dummy rpath to libtool so the thing will actually link +# TODO: -nostdlib/-Bstatic/-lgcc platform magic, not installing the .a, etc. +AM_CFLAGS = @WARN_CFLAGS@ @XMODES_CFLAGS@ @XORG_CFLAGS@ @DRI_CFLAGS@ + +sil164_la_LTLIBRARIES = sil164.la +sil164_la_LDFLAGS = -module -avoid-version +sil164_ladir = @moduledir@/drivers + +sil164_la_SOURCES = \ + sil164.c \ + sil164_module.c \ + sil164.h \ + sil164_reg.h diff --git a/driver/xf86-video-intel/src/sil164/Makefile.in b/driver/xf86-video-intel/src/sil164/Makefile.in new file mode 100644 index 000000000..2ebdc98ce --- /dev/null +++ b/driver/xf86-video-intel/src/sil164/Makefile.in @@ -0,0 +1,512 @@ +# Makefile.in generated by automake 1.10 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/sil164 +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; +am__installdirs = "$(DESTDIR)$(sil164_ladir)" +sil164_laLTLIBRARIES_INSTALL = $(INSTALL) +LTLIBRARIES = $(sil164_la_LTLIBRARIES) +sil164_la_LIBADD = +am_sil164_la_OBJECTS = sil164.lo sil164_module.lo +sil164_la_OBJECTS = $(am_sil164_la_OBJECTS) +sil164_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(sil164_la_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I. -I$(top_builddir)@am__isrc@ +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(sil164_la_SOURCES) +DIST_SOURCES = $(sil164_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ADMIN_MAN_DIR = @ADMIN_MAN_DIR@ +ADMIN_MAN_SUFFIX = @ADMIN_MAN_SUFFIX@ +AMTAR = @AMTAR@ +APP_MAN_DIR = @APP_MAN_DIR@ +APP_MAN_SUFFIX = @APP_MAN_SUFFIX@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DRIVER_MAN_DIR = @DRIVER_MAN_DIR@ +DRIVER_MAN_SUFFIX = @DRIVER_MAN_SUFFIX@ +DRIVER_NAME = @DRIVER_NAME@ +DRI_CFLAGS = @DRI_CFLAGS@ +DRI_LIBS = @DRI_LIBS@ +DRI_MM_CFLAGS = @DRI_MM_CFLAGS@ +DRI_MM_LIBS = @DRI_MM_LIBS@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +FILE_MAN_DIR = @FILE_MAN_DIR@ +FILE_MAN_SUFFIX = @FILE_MAN_SUFFIX@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIB_MAN_DIR = @LIB_MAN_DIR@ +LIB_MAN_SUFFIX = @LIB_MAN_SUFFIX@ +LINUXDOC = @LINUXDOC@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MAKE_HTML = @MAKE_HTML@ +MAKE_PDF = @MAKE_PDF@ +MAKE_PS = @MAKE_PS@ +MAKE_TEXT = @MAKE_TEXT@ +MISC_MAN_DIR = @MISC_MAN_DIR@ +MISC_MAN_SUFFIX = @MISC_MAN_SUFFIX@ +MKDIR_P = @MKDIR_P@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PCIACCESS_CFLAGS = @PCIACCESS_CFLAGS@ +PCIACCESS_LIBS = @PCIACCESS_LIBS@ +PKG_CONFIG = @PKG_CONFIG@ +PS2PDF = @PS2PDF@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +WARN_CFLAGS = @WARN_CFLAGS@ +XMODES_CFLAGS = @XMODES_CFLAGS@ +XORG_CFLAGS = @XORG_CFLAGS@ +XORG_LIBS = @XORG_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +gen4asm = @gen4asm@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +moduledir = @moduledir@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ + +# this is obnoxious: +# -module lets us name the module exactly how we want +# -avoid-version prevents gratuitous .0.0.0 version numbers on the end +# _ladir passes a dummy rpath to libtool so the thing will actually link +# TODO: -nostdlib/-Bstatic/-lgcc platform magic, not installing the .a, etc. +AM_CFLAGS = @WARN_CFLAGS@ @XMODES_CFLAGS@ @XORG_CFLAGS@ @DRI_CFLAGS@ +sil164_la_LTLIBRARIES = sil164.la +sil164_la_LDFLAGS = -module -avoid-version +sil164_ladir = @moduledir@/drivers +sil164_la_SOURCES = \ + sil164.c \ + sil164_module.c \ + sil164.h \ + sil164_reg.h + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/sil164/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/sil164/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-sil164_laLTLIBRARIES: $(sil164_la_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(sil164_ladir)" || $(MKDIR_P) "$(DESTDIR)$(sil164_ladir)" + @list='$(sil164_la_LTLIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + f=$(am__strip_dir) \ + echo " $(LIBTOOL) --mode=install $(sil164_laLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(sil164_ladir)/$$f'"; \ + $(LIBTOOL) --mode=install $(sil164_laLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(sil164_ladir)/$$f"; \ + else :; fi; \ + done + +uninstall-sil164_laLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(sil164_la_LTLIBRARIES)'; for p in $$list; do \ + p=$(am__strip_dir) \ + echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(sil164_ladir)/$$p'"; \ + $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(sil164_ladir)/$$p"; \ + done + +clean-sil164_laLTLIBRARIES: + -test -z "$(sil164_la_LTLIBRARIES)" || rm -f $(sil164_la_LTLIBRARIES) + @list='$(sil164_la_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +sil164.la: $(sil164_la_OBJECTS) $(sil164_la_DEPENDENCIES) + $(sil164_la_LINK) -rpath $(sil164_ladir) $(sil164_la_OBJECTS) $(sil164_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sil164.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sil164_module.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(sil164_ladir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-sil164_laLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-sil164_laLTLIBRARIES + +install-dvi: install-dvi-am + +install-exec-am: + +install-html: install-html-am + +install-info: install-info-am + +install-man: + +install-pdf: install-pdf-am + +install-ps: install-ps-am + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-sil164_laLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-sil164_laLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-sil164_laLTLIBRARIES install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-sil164_laLTLIBRARIES + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/driver/xf86-video-intel/src/sil164/sil164.c b/driver/xf86-video-intel/src/sil164/sil164.c new file mode 100644 index 000000000..12fe8e2e5 --- /dev/null +++ b/driver/xf86-video-intel/src/sil164/sil164.c @@ -0,0 +1,249 @@ +/* -*- c-basic-offset: 4 -*- */ +/************************************************************************** + +Copyright © 2006 Dave Airlie + +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 AUTHOR 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. + +**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86Resources.h" +#include "compiler.h" +#include "miscstruct.h" +#include "xf86i2c.h" +#include "xf86Crtc.h" +#define DPMS_SERVER +#include <X11/extensions/dpms.h> + +#include "../i2c_vid.h" +#include "sil164.h" +#include "sil164_reg.h" + +static Bool +sil164ReadByte(SIL164Ptr sil, int addr, CARD8 *ch) +{ + if (!xf86I2CReadByte(&(sil->d), addr, ch)) { + if (!sil->quiet) { + xf86DrvMsg(sil->d.pI2CBus->scrnIndex, X_ERROR, + "Unable to read from %s Slave %d.\n", + sil->d.pI2CBus->BusName, sil->d.SlaveAddr); + } + return FALSE; + } + return TRUE; +} + +static Bool +sil164WriteByte(SIL164Ptr sil, int addr, CARD8 ch) +{ + if (!xf86I2CWriteByte(&(sil->d), addr, ch)) { + if (!sil->quiet) { + xf86DrvMsg(sil->d.pI2CBus->scrnIndex, X_ERROR, + "Unable to write to %s Slave %d.\n", + sil->d.pI2CBus->BusName, sil->d.SlaveAddr); + } + return FALSE; + } + return TRUE; +} + +/* Silicon Image 164 driver for chip on i2c bus */ +static void * +sil164_init(I2CBusPtr b, I2CSlaveAddr addr) +{ + /* this will detect the SIL164 chip on the specified i2c bus */ + SIL164Ptr sil; + unsigned char ch; + + sil = xcalloc(1, sizeof(SIL164Rec)); + if (sil == NULL) + return NULL; + + sil->d.DevName = "SIL164 TMDS Controller"; + sil->d.SlaveAddr = addr; + sil->d.pI2CBus = b; + sil->d.StartTimeout = b->StartTimeout; + sil->d.BitTimeout = b->BitTimeout; + sil->d.AcknTimeout = b->AcknTimeout; + sil->d.ByteTimeout = b->ByteTimeout; + sil->d.DriverPrivate.ptr = sil; + sil->quiet = TRUE; + + if (!sil164ReadByte(sil, SIL164_VID_LO, &ch)) + goto out; + + if (ch!=(SIL164_VID & 0xFF)) { + xf86DrvMsg(sil->d.pI2CBus->scrnIndex, X_ERROR, + "sil164 not detected got %d: from %s Slave %d.\n", + ch, sil->d.pI2CBus->BusName, sil->d.SlaveAddr); + goto out; + } + + if (!sil164ReadByte(sil, SIL164_DID_LO, &ch)) + goto out; + + if (ch!=(SIL164_DID & 0xFF)) { + xf86DrvMsg(sil->d.pI2CBus->scrnIndex, X_ERROR, + "sil164 not detected got %d: from %s Slave %d.\n", + ch, sil->d.pI2CBus->BusName, sil->d.SlaveAddr); + goto out; + } + sil->quiet = FALSE; + + if (!xf86I2CDevInit(&(sil->d))) { + goto out; + } + + return sil; + +out: + xfree(sil); + return NULL; +} + +static xf86OutputStatus +sil164_detect(I2CDevPtr d) +{ + SIL164Ptr sil = SILPTR(d); + CARD8 reg9; + + sil164ReadByte(sil, SIL164_REG9, ®9); + + if (reg9 & SIL164_9_HTPLG) + return XF86OutputStatusConnected; + else + return XF86OutputStatusDisconnected; +} + +static ModeStatus +sil164_mode_valid(I2CDevPtr d, DisplayModePtr mode) +{ + return MODE_OK; +} + +static void +sil164_mode_set(I2CDevPtr d, DisplayModePtr mode, DisplayModePtr adjusted_mode) +{ + /* As long as the basics are set up, since we don't have clock dependencies + * in the mode setup, we can just leave the registers alone and everything + * will work fine. + */ + /* recommended programming sequence from doc */ + /*sil164WriteByte(sil, 0x08, 0x30); + sil164WriteByte(sil, 0x09, 0x00); + sil164WriteByte(sil, 0x0a, 0x90); + sil164WriteByte(sil, 0x0c, 0x89); + sil164WriteByte(sil, 0x08, 0x31);*/ + /* don't do much */ + return; +} + +/* set the SIL164 power state */ +static void +sil164_dpms(I2CDevPtr d, int mode) +{ + SIL164Ptr sil = SILPTR(d); + int ret; + unsigned char ch; + + ret = sil164ReadByte(sil, SIL164_REG8, &ch); + if (ret == FALSE) + return; + + if (mode == DPMSModeOn) + ch |= SIL164_8_PD; + else + ch &= ~SIL164_8_PD; + + sil164WriteByte(sil, SIL164_REG8, ch); + + return; +} + +static void +sil164_dump_regs(I2CDevPtr d) +{ + SIL164Ptr sil = SILPTR(d); + CARD8 val; + + sil164ReadByte(sil, SIL164_FREQ_LO, &val); + xf86DrvMsg(sil->d.pI2CBus->scrnIndex, X_INFO, "SIL164_FREQ_LO: 0x%02x\n", + val); + sil164ReadByte(sil, SIL164_FREQ_HI, &val); + xf86DrvMsg(sil->d.pI2CBus->scrnIndex, X_INFO, "SIL164_FREQ_HI: 0x%02x\n", + val); + sil164ReadByte(sil, SIL164_REG8, &val); + xf86DrvMsg(sil->d.pI2CBus->scrnIndex, X_INFO, "SIL164_REG8: 0x%02x\n", val); + sil164ReadByte(sil, SIL164_REG9, &val); + xf86DrvMsg(sil->d.pI2CBus->scrnIndex, X_INFO, "SIL164_REG9: 0x%02x\n", val); + sil164ReadByte(sil, SIL164_REGC, &val); + xf86DrvMsg(sil->d.pI2CBus->scrnIndex, X_INFO, "SIL164_REGC: 0x%02x\n", val); +} + +static void +sil164_save(I2CDevPtr d) +{ + SIL164Ptr sil = SILPTR(d); + + if (!sil164ReadByte(sil, SIL164_REG8, &sil->SavedReg.reg8)) + return; + + if (!sil164ReadByte(sil, SIL164_REG9, &sil->SavedReg.reg9)) + return; + + if (!sil164ReadByte(sil, SIL164_REGC, &sil->SavedReg.regc)) + return; + + return; +} + +static void +sil164_restore(I2CDevPtr d) +{ + SIL164Ptr sil = SILPTR(d); + + /* Restore it powered down initially */ + sil164WriteByte(sil, SIL164_REG8, sil->SavedReg.reg8 & ~0x1); + + sil164WriteByte(sil, SIL164_REG9, sil->SavedReg.reg9); + sil164WriteByte(sil, SIL164_REGC, sil->SavedReg.regc); + sil164WriteByte(sil, SIL164_REG8, sil->SavedReg.reg8); +} + + +I830I2CVidOutputRec SIL164VidOutput = { + .init = sil164_init, + .detect = sil164_detect, + .mode_valid = sil164_mode_valid, + .mode_set = sil164_mode_set, + .dpms = sil164_dpms, + .dump_regs = sil164_dump_regs, + .save = sil164_save, + .restore = sil164_restore, +}; diff --git a/driver/xf86-video-intel/src/sil164/sil164.h b/driver/xf86-video-intel/src/sil164/sil164.h new file mode 100644 index 000000000..9f823d6b1 --- /dev/null +++ b/driver/xf86-video-intel/src/sil164/sil164.h @@ -0,0 +1,31 @@ +/************************************************************************** + + Copyright 2006 Dave Airlie <airlied@linux.ie> + +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. + +**************************************************************************/ + +#ifndef SIL164_H +#define SIL164_H + +#define SIL164_ADDR_1 0x38 + +#endif diff --git a/driver/xf86-video-intel/src/sil164/sil164_module.c b/driver/xf86-video-intel/src/sil164/sil164_module.c new file mode 100644 index 000000000..d3bda8196 --- /dev/null +++ b/driver/xf86-video-intel/src/sil164/sil164_module.c @@ -0,0 +1,38 @@ +/* -*- c-basic-offset: 4 -*- */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "xf86Module.h" + +static MODULESETUPPROTO(sil164Setup); + +static XF86ModuleVersionInfo sil164VersRec = { + "sil164", + MODULEVENDORSTRING, + MODINFOSTRING1, + MODINFOSTRING2, + XORG_VERSION_CURRENT, + 1, 0, 0, + ABI_CLASS_VIDEODRV, + ABI_VIDEODRV_VERSION, + MOD_CLASS_NONE, + { 0,0,0,0 } +}; + +_X_EXPORT XF86ModuleData sil164ModuleData = { + &sil164VersRec, + sil164Setup, + NULL +}; + +static pointer +sil164Setup(pointer module, pointer opts, int *errmaj, int *errmin) +{ + return (pointer)1; +} diff --git a/driver/xf86-video-intel/src/sil164/sil164_reg.h b/driver/xf86-video-intel/src/sil164/sil164_reg.h new file mode 100644 index 000000000..734e55dd1 --- /dev/null +++ b/driver/xf86-video-intel/src/sil164/sil164_reg.h @@ -0,0 +1,75 @@ +/* -*- c-basic-offset: 4 -*- */ +/************************************************************************** + + Copyright 2006 Dave Airlie <airlied@linux.ie> + +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. + +**************************************************************************/ + +#ifndef SIL164_REG_H +#define SIL164_REG_H + +#define SIL164_VID 0x0001 +#define SIL164_DID 0x0006 + +#define SIL164_VID_LO 0x00 +#define SIL164_VID_HI 0x01 +#define SIL164_DID_LO 0x02 +#define SIL164_DID_HI 0x03 +#define SIL164_REV 0x04 +#define SIL164_RSVD 0x05 +#define SIL164_FREQ_LO 0x06 +#define SIL164_FREQ_HI 0x07 + +#define SIL164_REG8 0x08 +#define SIL164_8_VEN (1<<5) +#define SIL164_8_HEN (1<<4) +#define SIL164_8_DSEL (1<<3) +#define SIL164_8_BSEL (1<<2) +#define SIL164_8_EDGE (1<<1) +#define SIL164_8_PD (1<<0) + +#define SIL164_REG9 0x09 +#define SIL164_9_VLOW (1<<7) +#define SIL164_9_MSEL_MASK (0x7<<4) +#define SIL164_9_TSEL (1<<3) +#define SIL164_9_RSEN (1<<2) +#define SIL164_9_HTPLG (1<<1) +#define SIL164_9_MDI (1<<0) + +#define SIL164_REGC 0x0c + +typedef struct _Sil164SaveRec { + CARD8 reg8; + CARD8 reg9; + CARD8 regc; +} SIL164SaveRec; + +typedef struct { + I2CDevRec d; + Bool quiet; + SIL164SaveRec SavedReg; + SIL164SaveRec ModeReg; +} SIL164Rec, *SIL164Ptr; + +#define SILPTR(d) ((SIL164Ptr)(d->DriverPrivate.ptr)) + +#endif diff --git a/driver/xf86-video-intel/src/tfp410/Makefile.am b/driver/xf86-video-intel/src/tfp410/Makefile.am new file mode 100644 index 000000000..89a27d034 --- /dev/null +++ b/driver/xf86-video-intel/src/tfp410/Makefile.am @@ -0,0 +1,16 @@ +# this is obnoxious: +# -module lets us name the module exactly how we want +# -avoid-version prevents gratuitous .0.0.0 version numbers on the end +# _ladir passes a dummy rpath to libtool so the thing will actually link +# TODO: -nostdlib/-Bstatic/-lgcc platform magic, not installing the .a, etc. +AM_CFLAGS = @WARN_CFLAGS@ @XMODES_CFLAGS@ @XORG_CFLAGS@ @DRI_CFLAGS@ + +tfp410_la_LTLIBRARIES = tfp410.la +tfp410_la_LDFLAGS = -module -avoid-version +tfp410_ladir = @moduledir@/drivers + +tfp410_la_SOURCES = \ + tfp410.c \ + tfp410_module.c \ + tfp410.h \ + tfp410_reg.h diff --git a/driver/xf86-video-intel/src/tfp410/Makefile.in b/driver/xf86-video-intel/src/tfp410/Makefile.in new file mode 100644 index 000000000..92b935a4c --- /dev/null +++ b/driver/xf86-video-intel/src/tfp410/Makefile.in @@ -0,0 +1,512 @@ +# Makefile.in generated by automake 1.10 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/tfp410 +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; +am__installdirs = "$(DESTDIR)$(tfp410_ladir)" +tfp410_laLTLIBRARIES_INSTALL = $(INSTALL) +LTLIBRARIES = $(tfp410_la_LTLIBRARIES) +tfp410_la_LIBADD = +am_tfp410_la_OBJECTS = tfp410.lo tfp410_module.lo +tfp410_la_OBJECTS = $(am_tfp410_la_OBJECTS) +tfp410_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(tfp410_la_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I. -I$(top_builddir)@am__isrc@ +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(tfp410_la_SOURCES) +DIST_SOURCES = $(tfp410_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ADMIN_MAN_DIR = @ADMIN_MAN_DIR@ +ADMIN_MAN_SUFFIX = @ADMIN_MAN_SUFFIX@ +AMTAR = @AMTAR@ +APP_MAN_DIR = @APP_MAN_DIR@ +APP_MAN_SUFFIX = @APP_MAN_SUFFIX@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DRIVER_MAN_DIR = @DRIVER_MAN_DIR@ +DRIVER_MAN_SUFFIX = @DRIVER_MAN_SUFFIX@ +DRIVER_NAME = @DRIVER_NAME@ +DRI_CFLAGS = @DRI_CFLAGS@ +DRI_LIBS = @DRI_LIBS@ +DRI_MM_CFLAGS = @DRI_MM_CFLAGS@ +DRI_MM_LIBS = @DRI_MM_LIBS@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +FILE_MAN_DIR = @FILE_MAN_DIR@ +FILE_MAN_SUFFIX = @FILE_MAN_SUFFIX@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIB_MAN_DIR = @LIB_MAN_DIR@ +LIB_MAN_SUFFIX = @LIB_MAN_SUFFIX@ +LINUXDOC = @LINUXDOC@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MAKE_HTML = @MAKE_HTML@ +MAKE_PDF = @MAKE_PDF@ +MAKE_PS = @MAKE_PS@ +MAKE_TEXT = @MAKE_TEXT@ +MISC_MAN_DIR = @MISC_MAN_DIR@ +MISC_MAN_SUFFIX = @MISC_MAN_SUFFIX@ +MKDIR_P = @MKDIR_P@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PCIACCESS_CFLAGS = @PCIACCESS_CFLAGS@ +PCIACCESS_LIBS = @PCIACCESS_LIBS@ +PKG_CONFIG = @PKG_CONFIG@ +PS2PDF = @PS2PDF@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +WARN_CFLAGS = @WARN_CFLAGS@ +XMODES_CFLAGS = @XMODES_CFLAGS@ +XORG_CFLAGS = @XORG_CFLAGS@ +XORG_LIBS = @XORG_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +gen4asm = @gen4asm@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +moduledir = @moduledir@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ + +# this is obnoxious: +# -module lets us name the module exactly how we want +# -avoid-version prevents gratuitous .0.0.0 version numbers on the end +# _ladir passes a dummy rpath to libtool so the thing will actually link +# TODO: -nostdlib/-Bstatic/-lgcc platform magic, not installing the .a, etc. +AM_CFLAGS = @WARN_CFLAGS@ @XMODES_CFLAGS@ @XORG_CFLAGS@ @DRI_CFLAGS@ +tfp410_la_LTLIBRARIES = tfp410.la +tfp410_la_LDFLAGS = -module -avoid-version +tfp410_ladir = @moduledir@/drivers +tfp410_la_SOURCES = \ + tfp410.c \ + tfp410_module.c \ + tfp410.h \ + tfp410_reg.h + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/tfp410/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/tfp410/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-tfp410_laLTLIBRARIES: $(tfp410_la_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(tfp410_ladir)" || $(MKDIR_P) "$(DESTDIR)$(tfp410_ladir)" + @list='$(tfp410_la_LTLIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + f=$(am__strip_dir) \ + echo " $(LIBTOOL) --mode=install $(tfp410_laLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(tfp410_ladir)/$$f'"; \ + $(LIBTOOL) --mode=install $(tfp410_laLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(tfp410_ladir)/$$f"; \ + else :; fi; \ + done + +uninstall-tfp410_laLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(tfp410_la_LTLIBRARIES)'; for p in $$list; do \ + p=$(am__strip_dir) \ + echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(tfp410_ladir)/$$p'"; \ + $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(tfp410_ladir)/$$p"; \ + done + +clean-tfp410_laLTLIBRARIES: + -test -z "$(tfp410_la_LTLIBRARIES)" || rm -f $(tfp410_la_LTLIBRARIES) + @list='$(tfp410_la_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +tfp410.la: $(tfp410_la_OBJECTS) $(tfp410_la_DEPENDENCIES) + $(tfp410_la_LINK) -rpath $(tfp410_ladir) $(tfp410_la_OBJECTS) $(tfp410_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tfp410.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tfp410_module.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(tfp410_ladir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-tfp410_laLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-tfp410_laLTLIBRARIES + +install-dvi: install-dvi-am + +install-exec-am: + +install-html: install-html-am + +install-info: install-info-am + +install-man: + +install-pdf: install-pdf-am + +install-ps: install-ps-am + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-tfp410_laLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-tfp410_laLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip install-tfp410_laLTLIBRARIES installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-tfp410_laLTLIBRARIES + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/driver/xf86-video-intel/src/tfp410/tfp410.c b/driver/xf86-video-intel/src/tfp410/tfp410.c new file mode 100644 index 000000000..b79fd2a87 --- /dev/null +++ b/driver/xf86-video-intel/src/tfp410/tfp410.c @@ -0,0 +1,271 @@ +/* -*- c-basic-offset: 4 -*- */ +/* + * Copyright © 2007 Dave Mueller + * + * 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 + * THE AUTHORS OR COPYRIGHT HOLDERS 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: + * Dave Mueller <dave.mueller@gmx.ch> + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86Resources.h" +#include "compiler.h" +#include "miscstruct.h" +#include "xf86i2c.h" +#include "xf86Crtc.h" +#define DPMS_SERVER +#include <X11/extensions/dpms.h> + +#include "../i2c_vid.h" +#include "tfp410.h" +#include "tfp410_reg.h" + +static Bool +tfp410ReadByte(TFP410Ptr tfp, int addr, CARD8 *ch) +{ + if (!xf86I2CReadByte(&(tfp->d), addr, ch)) { + if (!tfp->quiet) { + xf86DrvMsg(tfp->d.pI2CBus->scrnIndex, X_ERROR, + "Unable to read from %s Slave %d.\n", + tfp->d.pI2CBus->BusName, tfp->d.SlaveAddr); + } + return FALSE; + } + return TRUE; +} + +static Bool +tfp410WriteByte(TFP410Ptr tfp, int addr, CARD8 ch) +{ + if (!xf86I2CWriteByte(&(tfp->d), addr, ch)) { + if (!tfp->quiet) { + xf86DrvMsg(tfp->d.pI2CBus->scrnIndex, X_ERROR, + "Unable to write to %s Slave %d.\n", + tfp->d.pI2CBus->BusName, tfp->d.SlaveAddr); + } + return FALSE; + } + return TRUE; +} + +static int +tfp410GetID(TFP410Ptr tfp, int addr) +{ + unsigned char ch1, ch2; + + if (tfp410ReadByte(tfp, addr+0, &ch1) && + tfp410ReadByte(tfp, addr+1, &ch2)) { + + return ((ch2<<8) & 0xFF00) | (ch1 & 0x00FF); + } + return -1; +} + +/* Ti TFP410 driver for chip on i2c bus */ +static void * +tfp410_init(I2CBusPtr b, I2CSlaveAddr addr) +{ + /* this will detect the tfp410 chip on the specified i2c bus */ + TFP410Ptr tfp; + int id; + + tfp = xcalloc(1, sizeof(TFP410Rec)); + if (tfp == NULL) + return NULL; + + tfp->d.DevName = "TFP410 TMDS Controller"; + tfp->d.SlaveAddr = addr; + tfp->d.pI2CBus = b; + tfp->d.StartTimeout = b->StartTimeout; + tfp->d.BitTimeout = b->BitTimeout; + tfp->d.AcknTimeout = b->AcknTimeout; + tfp->d.ByteTimeout = b->ByteTimeout; + tfp->d.DriverPrivate.ptr = tfp; + tfp->quiet = TRUE; + + if ((id = tfp410GetID(tfp, TFP410_VID_LO)) != TFP410_VID) { + if (id != 0xffffffff) { + xf86DrvMsg(tfp->d.pI2CBus->scrnIndex, X_ERROR, + "tfp410 not detected got VID %X: from %s Slave %d.\n", + id, tfp->d.pI2CBus->BusName, tfp->d.SlaveAddr); + } + goto out; + } + + if ((id = tfp410GetID(tfp, TFP410_DID_LO)) != TFP410_DID) { + xf86DrvMsg(tfp->d.pI2CBus->scrnIndex, X_ERROR, + "tfp410 not detected got DID %X: from %s Slave %d.\n", + id, tfp->d.pI2CBus->BusName, tfp->d.SlaveAddr); + goto out; + } + tfp->quiet = FALSE; + + if (!xf86I2CDevInit(&(tfp->d))) { + goto out; + } + + return tfp; + +out: + xfree(tfp); + return NULL; +} + +static xf86OutputStatus +tfp410_detect(I2CDevPtr d) +{ + TFP410Ptr tfp = TFPPTR(d); + xf86OutputStatus ret = XF86OutputStatusDisconnected; + unsigned char ctl2; + + if (tfp410ReadByte(tfp, TFP410_CTL_2, &ctl2)) { + if (ctl2 & TFP410_CTL_2_HTPLG) + ret = XF86OutputStatusConnected; + else + ret = XF86OutputStatusDisconnected; + } + + return ret; +} + +static ModeStatus +tfp410_mode_valid(I2CDevPtr d, DisplayModePtr mode) +{ + return MODE_OK; +} + +static void +tfp410_mode_set(I2CDevPtr d, DisplayModePtr mode, DisplayModePtr adjusted_mode) +{ + /* As long as the basics are set up, since we don't have clock dependencies + * in the mode setup, we can just leave the registers alone and everything + * will work fine. + */ + /* don't do much */ + return; +} + +/* set the tfp410 power state */ +static void +tfp410_dpms(I2CDevPtr d, int mode) +{ + TFP410Ptr tfp = TFPPTR(d); + unsigned char ctl1; + + if (!tfp410ReadByte(tfp, TFP410_CTL_1, &ctl1)) + return; + + if (mode == DPMSModeOn) + ctl1 |= TFP410_CTL_1_PD; + else + ctl1 &= ~TFP410_CTL_1_PD; + + tfp410WriteByte(tfp, TFP410_CTL_1, ctl1); +} + +static void +tfp410_dump_regs(I2CDevPtr d) +{ + TFP410Ptr tfp = TFPPTR(d); + CARD8 val, val2; + + tfp410ReadByte(tfp, TFP410_REV, &val); + xf86DrvMsg(tfp->d.pI2CBus->scrnIndex, X_INFO, + "TFP410_REV: 0x%02X\n", val); + tfp410ReadByte(tfp, TFP410_CTL_1, &val); + xf86DrvMsg(tfp->d.pI2CBus->scrnIndex, X_INFO, + "TFP410_CTL1: 0x%02X\n", val); + tfp410ReadByte(tfp, TFP410_CTL_2, &val); + xf86DrvMsg(tfp->d.pI2CBus->scrnIndex, X_INFO, + "TFP410_CTL2: 0x%02X\n", val); + tfp410ReadByte(tfp, TFP410_CTL_3, &val); + xf86DrvMsg(tfp->d.pI2CBus->scrnIndex, X_INFO, + "TFP410_CTL3: 0x%02X\n", val); + tfp410ReadByte(tfp, TFP410_USERCFG, &val); + xf86DrvMsg(tfp->d.pI2CBus->scrnIndex, X_INFO, + "TFP410_USERCFG: 0x%02X\n", val); + tfp410ReadByte(tfp, TFP410_DE_DLY, &val); + xf86DrvMsg(tfp->d.pI2CBus->scrnIndex, X_INFO, + "TFP410_DE_DLY: 0x%02X\n", val); + tfp410ReadByte(tfp, TFP410_DE_CTL, &val); + xf86DrvMsg(tfp->d.pI2CBus->scrnIndex, X_INFO, + "TFP410_DE_CTL: 0x%02X\n", val); + tfp410ReadByte(tfp, TFP410_DE_TOP, &val); + xf86DrvMsg(tfp->d.pI2CBus->scrnIndex, X_INFO, + "TFP410_DE_TOP: 0x%02X\n", val); + tfp410ReadByte(tfp, TFP410_DE_CNT_LO, &val); + tfp410ReadByte(tfp, TFP410_DE_CNT_HI, &val2); + xf86DrvMsg(tfp->d.pI2CBus->scrnIndex, X_INFO, + "TFP410_DE_CNT: 0x%02X%02X\n", val2, val); + tfp410ReadByte(tfp, TFP410_DE_LIN_LO, &val); + tfp410ReadByte(tfp, TFP410_DE_LIN_HI, &val2); + xf86DrvMsg(tfp->d.pI2CBus->scrnIndex, X_INFO, + "TFP410_DE_LIN: 0x%02X%02X\n", val2, val); + tfp410ReadByte(tfp, TFP410_H_RES_LO, &val); + tfp410ReadByte(tfp, TFP410_H_RES_HI, &val2); + xf86DrvMsg(tfp->d.pI2CBus->scrnIndex, X_INFO, + "TFP410_H_RES: 0x%02X%02X\n", val2, val); + tfp410ReadByte(tfp, TFP410_V_RES_LO, &val); + tfp410ReadByte(tfp, TFP410_V_RES_HI, &val2); + xf86DrvMsg(tfp->d.pI2CBus->scrnIndex, X_INFO, + "TFP410_V_RES: 0x%02X%02X\n", val2, val); +} + +static void +tfp410_save(I2CDevPtr d) +{ + TFP410Ptr tfp = TFPPTR(d); + + if (!tfp410ReadByte(tfp, TFP410_CTL_1, &tfp->SavedReg.ctl1)) + return; + + if (!tfp410ReadByte(tfp, TFP410_CTL_2, &tfp->SavedReg.ctl2)) + return; +} + +static void +tfp410_restore(I2CDevPtr d) +{ + TFP410Ptr tfp = TFPPTR(d); + + /* Restore it powered down initially */ + tfp410WriteByte(tfp, TFP410_CTL_1, tfp->SavedReg.ctl1 & ~0x1); + + tfp410WriteByte(tfp, TFP410_CTL_2, tfp->SavedReg.ctl2); + tfp410WriteByte(tfp, TFP410_CTL_1, tfp->SavedReg.ctl1); +} + +I830I2CVidOutputRec TFP410VidOutput = { + .init = tfp410_init, + .detect = tfp410_detect, + .mode_valid = tfp410_mode_valid, + .mode_set = tfp410_mode_set, + .dpms = tfp410_dpms, + .dump_regs = tfp410_dump_regs, + .save = tfp410_save, + .restore = tfp410_restore, +}; diff --git a/driver/xf86-video-intel/src/tfp410/tfp410.h b/driver/xf86-video-intel/src/tfp410/tfp410.h new file mode 100644 index 000000000..fb3f45244 --- /dev/null +++ b/driver/xf86-video-intel/src/tfp410/tfp410.h @@ -0,0 +1,33 @@ +/* + * Copyright © 2007 Dave Mueller + * + * 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 + * THE AUTHORS OR COPYRIGHT HOLDERS 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: + * Dave Mueller <dave.mueller@gmx.ch> + * + */ + +#ifndef TFP410_H +#define TFP410_H + +#define TFP410_ADDR_1 0x38 + +#endif diff --git a/driver/xf86-video-intel/src/tfp410/tfp410_module.c b/driver/xf86-video-intel/src/tfp410/tfp410_module.c new file mode 100644 index 000000000..c05b21a68 --- /dev/null +++ b/driver/xf86-video-intel/src/tfp410/tfp410_module.c @@ -0,0 +1,38 @@ +/* -*- c-basic-offset: 4 -*- */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "xf86Module.h" + +static MODULESETUPPROTO(tfp410Setup); + +static XF86ModuleVersionInfo tfp410VersRec = { + "tfp410", + MODULEVENDORSTRING, + MODINFOSTRING1, + MODINFOSTRING2, + XORG_VERSION_CURRENT, + 1, 0, 0, + ABI_CLASS_VIDEODRV, + ABI_VIDEODRV_VERSION, + MOD_CLASS_NONE, + { 0,0,0,0 } +}; + +_X_EXPORT XF86ModuleData tfp410ModuleData = { + &tfp410VersRec, + tfp410Setup, + NULL +}; + +static pointer +tfp410Setup(pointer module, pointer opts, int *errmaj, int *errmin) +{ + return (pointer)1; +} diff --git a/driver/xf86-video-intel/src/tfp410/tfp410_reg.h b/driver/xf86-video-intel/src/tfp410/tfp410_reg.h new file mode 100644 index 000000000..c555b9779 --- /dev/null +++ b/driver/xf86-video-intel/src/tfp410/tfp410_reg.h @@ -0,0 +1,106 @@ +/* -*- c-basic-offset: 4 -*- */ +/* + * Copyright © 2007 Dave Mueller + * + * 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 + * THE AUTHORS OR COPYRIGHT HOLDERS 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: + * Dave Mueller <dave.mueller@gmx.ch> + * + */ + +#ifndef TFP410_REG_H +#define TFP410_REG_H + +/* register definitions according to the TFP410 data sheet */ +#define TFP410_VID 0x014C +#define TFP410_DID 0x0410 + +#define TFP410_VID_LO 0x00 +#define TFP410_VID_HI 0x01 +#define TFP410_DID_LO 0x02 +#define TFP410_DID_HI 0x03 +#define TFP410_REV 0x04 + +#define TFP410_CTL_1 0x08 +#define TFP410_CTL_1_TDIS (1<<6) +#define TFP410_CTL_1_VEN (1<<5) +#define TFP410_CTL_1_HEN (1<<4) +#define TFP410_CTL_1_DSEL (1<<3) +#define TFP410_CTL_1_BSEL (1<<2) +#define TFP410_CTL_1_EDGE (1<<1) +#define TFP410_CTL_1_PD (1<<0) + +#define TFP410_CTL_2 0x09 +#define TFP410_CTL_2_VLOW (1<<7) +#define TFP410_CTL_2_MSEL_MASK (0x7<<4) +#define TFP410_CTL_2_MSEL (1<<4) +#define TFP410_CTL_2_TSEL (1<<3) +#define TFP410_CTL_2_RSEN (1<<2) +#define TFP410_CTL_2_HTPLG (1<<1) +#define TFP410_CTL_2_MDI (1<<0) + +#define TFP410_CTL_3 0x0A +#define TFP410_CTL_3_DK_MASK (0x7<<5) +#define TFP410_CTL_3_DK (1<<5) +#define TFP410_CTL_3_DKEN (1<<4) +#define TFP410_CTL_3_CTL_MASK (0x7<<1) +#define TFP410_CTL_3_CTL (1<<1) + +#define TFP410_USERCFG 0x0B + +#define TFP410_DE_DLY 0x32 + +#define TFP410_DE_CTL 0x33 +#define TFP410_DE_CTL_DEGEN (1<<6) +#define TFP410_DE_CTL_VSPOL (1<<5) +#define TFP410_DE_CTL_HSPOL (1<<4) +#define TFP410_DE_CTL_DEDLY8 (1<<0) + +#define TFP410_DE_TOP 0x34 + +#define TFP410_DE_CNT_LO 0x36 +#define TFP410_DE_CNT_HI 0x37 + +#define TFP410_DE_LIN_LO 0x38 +#define TFP410_DE_LIN_HI 0x39 + +#define TFP410_H_RES_LO 0x3A +#define TFP410_H_RES_HI 0x3B + +#define TFP410_V_RES_LO 0x3C +#define TFP410_V_RES_HI 0x3D + +typedef struct _TFP410SaveRec { + CARD8 ctl1; + CARD8 ctl2; +} TFP410SaveRec; + +typedef struct { + I2CDevRec d; + Bool quiet; + + TFP410SaveRec SavedReg; + TFP410SaveRec ModeReg; +} TFP410Rec, *TFP410Ptr; + +#define TFPPTR(d) ((TFP410Ptr)(d->DriverPrivate.ptr)) + +#endif |