diff options
author | Rob Clark <rob@ti.com> | 2011-07-17 17:29:02 -0500 |
---|---|---|
committer | Rob Clark <rob@ti.com> | 2011-07-19 20:38:19 -0500 |
commit | 487687ecc36e158a41378eb48f6ea26332c877d8 (patch) | |
tree | 1c9a5d353048e08212635e5b8a735a14f0cf94e4 |
initial commit
-rw-r--r-- | AUTHORS | 2 | ||||
-rw-r--r-- | COPYING | 20 | ||||
-rw-r--r-- | Makefile.am | 34 | ||||
-rw-r--r-- | NEWS | 1 | ||||
-rw-r--r-- | README | 19 | ||||
-rwxr-xr-x | autogen.sh | 33 | ||||
-rw-r--r-- | configure.ac | 97 | ||||
-rw-r--r-- | man/Makefile.am | 37 | ||||
-rw-r--r-- | man/omap.man | 114 | ||||
-rw-r--r-- | src/Makefile.am | 48 | ||||
-rw-r--r-- | src/drmmode_display.c | 1180 | ||||
-rw-r--r-- | src/omap_driver.c | 989 | ||||
-rw-r--r-- | src/omap_driver.h | 239 | ||||
-rw-r--r-- | src/omap_drm.c | 172 | ||||
-rw-r--r-- | src/omap_drm.h | 99 | ||||
-rw-r--r-- | src/omap_exa_common.c | 231 | ||||
-rw-r--r-- | src/omap_exa_common.h | 57 | ||||
-rw-r--r-- | src/omap_exa_null.c | 153 |
18 files changed, 3525 insertions, 0 deletions
@@ -0,0 +1,2 @@ +Ian Elliott <ianelliottus@yahoo.com> +Rob Clark <rob@ti.com> @@ -0,0 +1,20 @@ +Copyright © 2011 Texas Instruments, 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 (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. diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..7c0a6a9 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,34 @@ +# Copyright 2005 Adam Jackson. +# +# 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 +# ADAM JACKSON 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. + +ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS} + +SUBDIRS = src man +MAINTAINERCLEANFILES = ChangeLog INSTALL + +.PHONY: ChangeLog INSTALL + +INSTALL: + $(INSTALL_CMD) + +ChangeLog: + $(CHANGELOG_CMD) + +dist-hook: ChangeLog INSTALL @@ -0,0 +1 @@ +TBD @@ -0,0 +1,19 @@ +xf86-video-omap +Open-source X.org graphics driver for TI OMAP graphics + +Currently relies on a closed-source submodule for EXA acceleration on +the following chipsets: + + OMAP3430 + + OMAP3630 + + OMAP4430 + + OMAP4460 + + +NOTE: this driver is work in progress.. you probably don't want to try +and use it yet. The API/ABI between driver and kernel, and driver and +acceleration submodules is not stable yet. This driver requires the +omapdrm kernel driver w/ GEM support. + +EXA vs UXA? This is an open question.. + + diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..d1885dc --- /dev/null +++ b/autogen.sh @@ -0,0 +1,33 @@ +#! /bin/sh + +cd `dirname $0` + +# on some platforms, you have "g" versions of some of these tools instead, +# ie glibtoolize instead of libtoolize.. +find_tool() { + which $1 2> /dev/null || which g$1 2> /dev/null +} + +aclocal=`find_tool aclocal` +libtoolize=`find_tool libtoolize` +automake=`find_tool automake` +autoconf=`find_tool autoconf` +autoheader=`find_tool autoheader` + +mkdir -p config && $aclocal && $libtoolize --copy --force && $automake --copy --add-missing --foreign && $autoheader && $autoconf + +test -n "$NOCONFIGURE" && { + echo "skipping configure stage as requested." + echo "autogen.sh done." + exit 0 +} + +CONFIGURE_DEF_OPT="--enable-maintainer-mode" +echo ./configure $CONFIGURE_DEF_OPT $* +./configure $CONFIGURE_DEF_OPT $* || { + echo " configure failed" + exit 1 +} + +echo "Now type 'make' to compile" + diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..58516ab --- /dev/null +++ b/configure.ac @@ -0,0 +1,97 @@ +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + +AC_PREREQ(2.60) +# XXX bug URL should be https://bugs.freedesktop.org/enter_bug.cgi?product=xorg +# but this makes autoheader choke.. +AC_INIT([xf86-video-omap], + [0.0.1], + [https://bugs.freedesktop.org/enter_bug.cgi], + [xf86-video-omap]) +AC_CONFIG_SRCDIR([Makefile.am]) +AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_AUX_DIR(.) + +AM_INIT_AUTOMAKE([dist-bzip2]) + +AM_MAINTAINER_MODE + +# Require xorg-macros: XORG_DEFAULT_OPTIONS +m4_ifndef([XORG_MACROS_VERSION], + [m4_fatal([must install xorg-macros 1.4 or later before running autoconf/autogen])]) +XORG_MACROS_VERSION(1.4) +XORG_DEFAULT_OPTIONS + +# Checks for programs. +AC_DISABLE_STATIC +AC_PROG_LIBTOOL +AC_PROG_CC + +AC_CHECK_HEADERS([sys/ioctl.h]) + +AH_TOP([#include "xorg-server.h"]) + +AC_ARG_WITH(xorg-module-dir, + AC_HELP_STRING([--with-xorg-module-dir=DIR], + [Default xorg module directory [[default=$libdir/xorg/modules]]]), + [moduledir="$withval"], + [moduledir="$libdir/xorg/modules"]) + +# Checks for extensions +XORG_DRIVER_CHECK_EXT(RANDR, randrproto) +XORG_DRIVER_CHECK_EXT(RENDER, renderproto) +XORG_DRIVER_CHECK_EXT(XV, videoproto) +XORG_DRIVER_CHECK_EXT(DPMSExtension, xextproto) + +# Checks for pkg-config packages +PKG_CHECK_MODULES(XORG, [xorg-server >= 1.3] xproto fontsproto libdrm xf86driproto $REQUIRED_MODULES) +sdkdir=$(pkg-config --variable=sdkdir xorg-server) + +# Checks for header files. +AC_HEADER_STDC + +save_CFLAGS="$CFLAGS" +CFLAGS="$XORG_CFLAGS $DRI_CFLAGS $DRM_CFLAGS" +CPPFLAGS="$XORG_CFLAGS $DRI_CFLAGS $DRM_CFLAGS" +AC_MSG_CHECKING([whether to include DRI support]) +if test x$DRI != xno; then + AC_CHECK_FILE([${sdkdir}/dri.h], + [have_dri_h="yes"], [have_dri_h="no"]) + AC_CHECK_FILE([${sdkdir}/dristruct.h], + [have_dristruct_h="yes"], [have_dristruct_h="no"]) +fi +AC_MSG_CHECKING([whether to include DRI support]) +if test x$DRI = xauto; then + if test "$have_dri_h" = yes -a \ + "$have_dristruct_h" = yes; then + DRI="yes" + else + DRI="no" + fi +fi +AC_MSG_RESULT([$DRI]) +CFLAGS="$save_CFLAGS $DEBUGFLAGS" + +AM_CONDITIONAL(DRI, test x$DRI = xyes) +if test "$DRI" = yes; then + PKG_CHECK_MODULES(DRI, [xf86driproto glproto]) + AC_DEFINE(XF86DRI,1,[Enable DRI driver support]) + AC_DEFINE(XF86DRI_DEVEL,1,[Enable developmental DRI driver support]) +fi + +AM_CONDITIONAL(VIDEO_DEBUG, test x$VIDEO_DEBUG = xyes) +if test "$VIDEO_DEBUG" = yes; then + AC_DEFINE(VIDEO_DEBUG,1,[Enable debug support]) +fi + +AC_SUBST([DRI_CFLAGS]) + +DRIVER_NAME=omap +AC_SUBST([DRIVER_NAME]) +AC_SUBST([moduledir]) + +AC_OUTPUT([ + Makefile + src/Makefile + man/Makefile +]) diff --git a/man/Makefile.am b/man/Makefile.am new file mode 100644 index 0000000..9ca5ff6 --- /dev/null +++ b/man/Makefile.am @@ -0,0 +1,37 @@ +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice (including the next +# paragraph) shall be included in all copies or substantial portions of the +# Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# 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. +# + +drivermandir = $(DRIVER_MAN_DIR) +driverman_DATA = $(DRIVER_NAME).$(DRIVER_MAN_SUFFIX) + +EXTRA_DIST = $(DRIVER_NAME).man + +CLEANFILES = $(driverman_DATA) + +# String replacements in MAN_SUBSTS now come from xorg-macros.m4 via configure + + +SUFFIXES = .$(DRIVER_MAN_SUFFIX) .man + +.man.$(DRIVER_MAN_SUFFIX): + $(AM_V_GEN)$(SED) $(MAN_SUBSTS) < $< > $@ diff --git a/man/omap.man b/man/omap.man new file mode 100644 index 0000000..21567ab --- /dev/null +++ b/man/omap.man @@ -0,0 +1,114 @@ +.\" shorthand for double quote that works everywhere. +.ds q \N'34' +.TH omap __drivermansuffix__ __vendorversion__ +.SH NAME +omap \- OMAP SoC graphics +.SH SYNOPSIS +.nf +.B "Section \*qDevice\*q" +.BI " Identifier \*q" devname \*q +.B " Driver \*qomap\*q" +\ \ ... +.B EndSection +.fi +.SH DESCRIPTION +.B omap +is an __xservername__ driver for OMAP SoCs. +.SH SUPPORTED HARDWARE +.B omap +supports the OMAP3430, OMAP3630, OMAP4430, OMAP4460 + +.SH CONFIGURATION DETAILS +Please refer to __xconfigfile__(__filemansuffix__) for general configuration +details. This section only covers configuration details specific to this +driver. +.PP +TODO +.PP +The following driver +.B Options +are supported +.TP +.BI "Option \*qDebug\*q \*q" boolean \*q +Enable debug logging. +.IP +Default: Disabled +.TP +.BI "Option \*qNoAccel\*q \*q" boolean \*q +Disable hw acceleration. +.IP +Default: Disabled + +.SH OUTPUT CONFIGURATION +The driver supports runtime configuration of detected outputs. You can use the +.B xrandr +tool to control outputs on the command line as follows: + +.RS +.B xrandr \-\-output +.I output +.B \-\-set +.I property value +.RE + +Note that you may need to quote property and value arguments that contain spaces. +Each output listed below may have one or more properties associated +with it (like a binary EDID block if one is found). Some outputs have +unique properties which are described below. See the "MULTIHEAD +CONFIGURATIONS" section below for additional information. + +TODO + +.PP +See __xconfigfile__(__filemansuffix__) for information on associating Monitor +sections with these outputs for configuration. Associating Monitor sections +with each output can be helpful if you need to ignore a specific output, for +example, or statically configure an extended desktop monitor layout. + +.SH MULTIHEAD CONFIGURATIONS + +The number of independent outputs is dictated by the number of CRTCs +(in X parlance) a given chip supports. OMAP3xxx supports up to two, +while OMAP4xxx supports up to three displays. The actual number of +displays supported will depend on the board. But a built-in LCD and +external HDMI are a common configuration. + +You can use the "xrandr" tool, or various desktop utilities, to change +your output configuration at runtime. To statically configure your +outputs, you can use the "Monitor-<type>" options along with +additional monitor sections in your xorg.conf to create your screen +topology. The example below puts the VGA output to the right of the +builtin laptop screen, both running at 1024x768. + +.nf +.B "Section \*qMonitor\*q" +.BI " Identifier \*qLaptop FooBar Internal Display\*q" +.BI " Option \*qPosition\*q \*q0 0\*q" +.B "EndSection" + +.B "Section \*qMonitor\*q" +.BI " Identifier \*qSome Random CRT\*q" +.BI " Option \*qPosition\*q \*q1024 0\*q" +.BI " Option \*qRightOf\*q \*qLaptop FoodBar Internal Display\*q" +.B "EndSection" + +.B "Section \*qDevice\*q" +.BI " Driver \*qomap\*q" +.BI " Option \*qmonitor-LVDS\*q \*qLaptop FooBar Internal Display\*q" +.BI " Option \*qmonitor-VGA\*q \*qSome Random CRT\*q" +.B "EndSection" + +.SH REPORTING BUGS + +The xf86-video-omap driver is part of the X.Org and Freedesktop.org +umbrella projects. Report bugs at +https://bugs.freedesktop.org/enter_bug.cgi?product=xorg. Mailing +lists are also commonly used to report experiences and ask questions +about configuration and other topics. See lists.freedesktop.org for +more information (the xorg@lists.freedesktop.org mailing list is the +most appropriate place to ask X.Org and driver related questions). + +.SH "SEE ALSO" +__xservername__(__appmansuffix__), __xconfigfile__(__filemansuffix__), Xserver(__appmansuffix__), X(__miscmansuffix__) +.SH AUTHORS +Authors include: Ian Elliott, Rob Clark. diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..86209ef --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,48 @@ +# Copyright © 2011 Texas Instruments 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 +# 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 +# ADAM JACKSON 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: +# Ian Elliott <ianelliottus@yahoo.com> +# Rob Clark <rob@ti.com> + +# 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. + +# TODO: probably should have configure script check for what is supported.. +ERROR_CFLAGS = -Werror -Wall -Wdeclaration-after-statement -Wvla \ + -Wpointer-arith -Wmissing-declarations -Wmissing-prototypes \ + -Wwrite-strings -Wformat-nonliteral -Wformat-security \ + -Wold-style-definition -Winit-self -Wmissing-include-dirs \ + -Waddress -Waggregate-return -Wno-multichar -Wnested-externs + +AM_CFLAGS = @XORG_CFLAGS@ $(ERROR_CFLAGS) +omap_drv_la_LTLIBRARIES = omap_drv.la +omap_drv_la_LDFLAGS = -module -avoid-version -no-undefined +omap_drv_ladir = @moduledir@/drivers + +omap_drv_la_SOURCES = \ + drmmode_display.c \ + omap_exa_common.c \ + omap_exa_null.c \ + omap_drm.c \ + omap_driver.c diff --git a/src/drmmode_display.c b/src/drmmode_display.c new file mode 100644 index 0000000..c1e79ad --- /dev/null +++ b/src/drmmode_display.c @@ -0,0 +1,1180 @@ +/* + * Copyright © 2007 Red Hat, Inc. + * Copyright © 2008 Maarten Maathuis + * Copyright © 2011 Texas Instruments, 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 (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 Airlie <airlied@redhat.com> + * Ian Elliott <ianelliottus@yahoo.com> + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "xorgVersion.h" + + + +#include <sys/stat.h> + + + + +// START: THE FOLLOWING #include STATEMENTS WERE COPIED FROM "nv_include.h"; + // FIXME - DETERMINE WHICH OF THESE ARE REALLY/STILL NEEDED FOR THE TI DRIVER: +#include <string.h> +#include <math.h> +#include <errno.h> +#include <unistd.h> +#include <stdlib.h> + +/* All drivers should typically include these */ +#include "xf86.h" +#include "xf86_OSproc.h" +#define PPC_MMIO_IS_BE +#include "compiler.h" + +/* Drivers for PCI hardware need this */ +#include "xf86PciInfo.h" + +/* Drivers that need to access the PCI config space directly need this */ +#include "xf86Pci.h" + +/* All drivers initialising the SW cursor need this */ +#include "mipointer.h" + +/* All drivers implementing backing store need this */ +#include "mibstore.h" + +#include "micmap.h" + +#include "xf86DDC.h" + +#include "vbe.h" + +#include "xf86RandR12.h" + +//#include "nv_const.h" + +#include "dixstruct.h" +#include "scrnintstr.h" + +#include "fb.h" + +#include "xf86cmap.h" +#include "shadowfb.h" + +#include "xf86xv.h" +#include <X11/extensions/Xv.h> + +#include "xf86Cursor.h" +#include "xf86DDC.h" + +#include "region.h" + +#include <X11/extensions/randr.h> + +#ifdef HAVE_XEXTPROTO_71 +#include <X11/extensions/dpmsconst.h> +#else +#define DPMS_SERVER +#include <X11/extensions/dpms.h> +#endif + +// END: THE PREVIOUS #include STATEMENTS WERE COPIED FROM "nv_include.h"; + + + + +#include "omap_driver.h" + +// START: SOME OTHER #include STATEMENTS THAT I NEEDED TO COMPILE. + // FIXME - DETERMINE WHICH OF THESE ARE REALLY/STILL NEEDED, AND HOW TO + // COALESCE THEM WITH THE OTHER #include STATEMENTS: +#include "xf86Crtc.h" +// END: SOME OTHER #include STATEMENTS THAT I NEEDED TO COMPILE. + + + + +#include "xf86drmMode.h" +#include "X11/Xatom.h" + +#include <sys/ioctl.h> +#include <libudev.h> + +typedef struct { + int fd; + uint32_t fb_id; + drmModeResPtr mode_res; + int cpp; + struct udev_monitor *uevent_monitor; + InputHandlerProc uevent_handler; +} drmmode_rec, *drmmode_ptr; + +typedef struct { + drmmode_ptr drmmode; + drmModeCrtcPtr mode_crtc; +#if 0 + // Fixme - We need different code to deal with a cursor on OMAP4: + struct nouveau_bo *cursor; + struct nouveau_bo *rotate_bo; +#endif + uint32_t rotate_pitch; + PixmapPtr rotate_pixmap; + uint32_t rotate_fb_id; + Bool cursor_visible; +} drmmode_crtc_private_rec, *drmmode_crtc_private_ptr; + +typedef struct { + drmModePropertyPtr mode_prop; + int index; /* Index within the kernel-side property arrays for + * this connector. */ + int num_atoms; /* if range prop, num_atoms == 1; if enum prop, + * num_atoms == num_enums + 1 */ + Atom *atoms; +} drmmode_prop_rec, *drmmode_prop_ptr; + +typedef struct { + drmmode_ptr drmmode; + int output_id; + drmModeConnectorPtr mode_output; + drmModeEncoderPtr mode_encoder; + drmModePropertyBlobPtr edid_blob; + int num_props; + drmmode_prop_ptr props; +} drmmode_output_private_rec, *drmmode_output_private_ptr; + +static void drmmode_output_dpms(xf86OutputPtr output, int mode); +void drmmode_remove_fb(ScrnInfoPtr pScrn); + +#if 0 +static PixmapPtr +drmmode_pixmap_wrap(ScreenPtr pScreen, int width, int height, int depth, + int bpp, int pitch, struct nouveau_bo *bo) +{ + PixmapPtr ppix; + + ppix = pScreen->CreatePixmap(pScreen, 0, 0, depth, 0); + if (!ppix) + return NULL; + + pScreen->ModifyPixmapHeader(ppix, width, height, depth, bpp, + pitch, NULL); + nouveau_bo_ref(bo, &nouveau_pixmap(ppix)->bo); + + return ppix; +} +#endif + +static void +drmmode_ConvertFromKMode(ScrnInfoPtr pScrn, drmModeModeInfo *kmode, + DisplayModePtr mode) +{ + memset(mode, 0, sizeof(DisplayModeRec)); + mode->status = MODE_OK; + + mode->Clock = kmode->clock; + + mode->HDisplay = kmode->hdisplay; + mode->HSyncStart = kmode->hsync_start; + mode->HSyncEnd = kmode->hsync_end; + mode->HTotal = kmode->htotal; + mode->HSkew = kmode->hskew; + + mode->VDisplay = kmode->vdisplay; + mode->VSyncStart = kmode->vsync_start; + mode->VSyncEnd = kmode->vsync_end; + mode->VTotal = kmode->vtotal; + mode->VScan = kmode->vscan; + + mode->Flags = kmode->flags; //& FLAG_BITS; + mode->name = strdup(kmode->name); + + DEBUG_MSG("copy mode %s (%p %p)", kmode->name, mode->name, mode); + + if (kmode->type & DRM_MODE_TYPE_DRIVER) + mode->type = M_T_DRIVER; + if (kmode->type & DRM_MODE_TYPE_PREFERRED) + mode->type |= M_T_PREFERRED; + + xf86SetModeCrtc (mode, pScrn->adjustFlags); +} /* drmmode_ConvertFromKMode() */ + +static void +drmmode_ConvertToKMode(ScrnInfoPtr pScrn, drmModeModeInfo *kmode, + DisplayModePtr mode) +{ + memset(kmode, 0, sizeof(*kmode)); + + kmode->clock = mode->Clock; + kmode->hdisplay = mode->HDisplay; + kmode->hsync_start = mode->HSyncStart; + kmode->hsync_end = mode->HSyncEnd; + kmode->htotal = mode->HTotal; + kmode->hskew = mode->HSkew; + + kmode->vdisplay = mode->VDisplay; + kmode->vsync_start = mode->VSyncStart; + kmode->vsync_end = mode->VSyncEnd; + kmode->vtotal = mode->VTotal; + kmode->vscan = mode->VScan; + + kmode->flags = mode->Flags; //& FLAG_BITS; + if (mode->name) + strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN); + kmode->name[DRM_DISPLAY_MODE_LEN-1] = 0; +} /* drmmode_ConvertToKMode() */ + +static void +drmmode_crtc_dpms(xf86CrtcPtr drmmode_crtc, int mode) +{ + // FIXME - Implement this function +} /* drmmode_crtc_dpms() */ + +static Bool +drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, + Rotation rotation, int x, int y) +{ + ScrnInfoPtr pScrn = crtc->scrn; + OMAPPtr pOMAP = OMAPPTR(pScrn); + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + drmmode_ptr drmmode = drmmode_crtc->drmmode; + int saved_x, saved_y; + Rotation saved_rotation; + DisplayModeRec saved_mode; + uint32_t *output_ids = NULL; + int output_count = 0; + int ret = TRUE; + int i; + int fb_id; + drmModeModeInfo kmode; + + TRACE_ENTER(); + + /* remove old fb if it exists */ + drmmode_remove_fb(pScrn); + + if (drmmode->fb_id == 0) { + unsigned int pitch = + OMAPCalculateStride(pScrn->virtualX, pScrn->bitsPerPixel); + + DEBUG_MSG("create framebuffer: %dx%d", + pScrn->virtualX, pScrn->virtualY); + + ret = drmModeAddFB(drmmode->fd, + pScrn->virtualX, pScrn->virtualY, + pScrn->depth, pScrn->bitsPerPixel, + pitch, omap_bo_handle(pOMAP->scanout), + &drmmode->fb_id); + if (ret < 0) { + // Fixme - improve this error message: + ErrorF("failed to add fb\n"); + return FALSE; + } + } + + /* Save the current mode in case there's a problem: */ + saved_mode = crtc->mode; + saved_x = crtc->x; + saved_y = crtc->y; + saved_rotation = crtc->rotation; + + /* Set the new mode: */ + crtc->mode = *mode; + crtc->x = x; + crtc->y = y; + crtc->rotation = rotation; + + output_ids = calloc(sizeof(uint32_t), xf86_config->num_output); + if (!output_ids) { + // Fixme - have an error message? + ret = FALSE; + goto done; + } + + for (i = 0; i < xf86_config->num_output; i++) { + xf86OutputPtr output = xf86_config->output[i]; + drmmode_output_private_ptr drmmode_output; + + if (output->crtc != crtc) + continue; + + drmmode_output = output->driver_private; + output_ids[output_count] = + drmmode_output->mode_output->connector_id; + output_count++; + } + + if (!xf86CrtcRotate(crtc)) + goto done; + + // Fixme - Intel puts this function here, and Nouveau puts it at the end + // of this function -> determine what's best for TI'S OMAP4: + crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green, + crtc->gamma_blue, crtc->gamma_size); + + drmmode_ConvertToKMode(crtc->scrn, &kmode, mode); + + fb_id = drmmode->fb_id; + if (drmmode_crtc->rotate_fb_id) { + fb_id = drmmode_crtc->rotate_fb_id; + x = 0; + y = 0; + } + ret = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, + fb_id, x, y, output_ids, output_count, &kmode); + if (ret) { + xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, + "failed to set mode: %s\n", strerror(-ret)); + } else { + ret = TRUE; + } + + // FIXME - DO WE NEED TO CALL TO THE PVR EXA/DRI2 CODE TO UPDATE THEM??? + + /* Turn on any outputs on this crtc that may have been disabled: */ + for (i = 0; i < xf86_config->num_output; i++) { + xf86OutputPtr output = xf86_config->output[i]; + + if (output->crtc != crtc) + continue; + + drmmode_output_dpms(output, DPMSModeOn); + } + + // Fixme - Intel puts a call to set GEM sizes here; do we need to do + // something like that? + + if (pScrn->pScreen) + xf86_reload_cursors(pScrn->pScreen); + +done: + if (output_ids) { + free(output_ids); + } + if (!ret) { + /* If there was a problem, resture the old mode: */ + crtc->x = saved_x; + crtc->y = saved_y; + crtc->rotation = saved_rotation; + crtc->mode = saved_mode; + } + + TRACE_EXIT(); + return ret; +} /* drmmode_set_mode_major() */ + +static void +drmmode_set_cursor_position (xf86CrtcPtr crtc, int x, int y) +{ +#if 0 // Fixme - address this function when we address HW cursor functionality + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + drmmode_ptr drmmode = drmmode_crtc->drmmode; + + drmModeMoveCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, x, y); +#endif +} /* drmmode_set_cursor_position() */ + +static void +drmmode_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *image) +{ +#if 0 // Fixme - address this function when we address HW cursor functionality +#endif +} /* drmmode_load_cursor_argb() */ + +static void +drmmode_hide_cursor(xf86CrtcPtr crtc) +{ +#if 0 // Fixme - address this function when we address HW cursor functionality + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + drmmode_ptr drmmode = drmmode_crtc->drmmode; + + drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, + 0, 64, 64); + drmmode_crtc->cursor_visible = FALSE; +#endif +} /* drmmode_hide_cursor() */ + +static void +drmmode_show_cursor(xf86CrtcPtr crtc) +{ +#if 0 // Fixme - address this function when we address HW cursor functionality + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + drmmode_ptr drmmode = drmmode_crtc->drmmode; + + // Fixme - Do we may need a different data structure for the cursor handle?: + drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, + drmmode_crtc->cursor->handle, 64, 64); + + drmmode_crtc->cursor_visible = TRUE; +#endif +} /* drmmode_show_cursor() */ + +static void +drmmode_gamma_set(xf86CrtcPtr crtc, CARD16 *red, CARD16 *green, CARD16 *blue, + int size) +{ + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + drmmode_ptr drmmode = drmmode_crtc->drmmode; + int ret; + + ret = drmModeCrtcSetGamma(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, + size, red, green, blue); + if (ret != 0) { + xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, + "failed to set gamma: %s\n", strerror(-ret)); + } +} + +static const xf86CrtcFuncsRec drmmode_crtc_funcs = { + .dpms = drmmode_crtc_dpms, + .set_mode_major = drmmode_set_mode_major, + .set_cursor_position = drmmode_set_cursor_position, + .show_cursor = drmmode_show_cursor, + .hide_cursor = drmmode_hide_cursor, + .load_cursor_argb = drmmode_load_cursor_argb, + .gamma_set = drmmode_gamma_set, +}; + + +static void +drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num) +{ + xf86CrtcPtr crtc; + drmmode_crtc_private_ptr drmmode_crtc; + + TRACE_ENTER(); + + crtc = xf86CrtcCreate(pScrn, &drmmode_crtc_funcs); + if (crtc == NULL) + return; + + drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1); + drmmode_crtc->mode_crtc = drmModeGetCrtc(drmmode->fd, + drmmode->mode_res->crtcs[num]); + drmmode_crtc->drmmode = drmmode; + +// FIXME - potentially add code to allocate a HW cursor here. + + crtc->driver_private = drmmode_crtc; + + TRACE_EXIT(); + return; +} /* drmmode_crtc_init() */ + +static xf86OutputStatus +drmmode_output_detect(xf86OutputPtr output) +{ + /* go to the hw and retrieve a new output struct */ + drmmode_output_private_ptr drmmode_output = output->driver_private; + drmmode_ptr drmmode = drmmode_output->drmmode; + xf86OutputStatus status; + drmModeFreeConnector(drmmode_output->mode_output); + + drmmode_output->mode_output = + drmModeGetConnector(drmmode->fd, drmmode_output->output_id); + + switch (drmmode_output->mode_output->connection) { + case DRM_MODE_CONNECTED: + status = XF86OutputStatusConnected; + break; + case DRM_MODE_DISCONNECTED: + status = XF86OutputStatusDisconnected; + break; + default: + case DRM_MODE_UNKNOWNCONNECTION: + status = XF86OutputStatusUnknown; + break; + } + return status; +} + +static Bool +drmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr mode) +{ + if (mode->type & M_T_DEFAULT) + /* Default modes are harmful here. */ + return MODE_BAD; + + return MODE_OK; +} + +static DisplayModePtr +drmmode_output_get_modes(xf86OutputPtr output) +{ + ScrnInfoPtr pScrn = output->scrn; + drmmode_output_private_ptr drmmode_output = output->driver_private; + drmModeConnectorPtr koutput = drmmode_output->mode_output; + drmmode_ptr drmmode = drmmode_output->drmmode; + DisplayModePtr Modes = NULL, Mode; + drmModePropertyPtr props; + xf86MonPtr ddc_mon = NULL; + int i; + + /* look for an EDID property */ + for (i = 0; i < koutput->count_props; i++) { + props = drmModeGetProperty(drmmode->fd, koutput->props[i]); + if (!props || !(props->flags & DRM_MODE_PROP_BLOB)) + continue; + + if (!strcmp(props->name, "EDID")) { + if (drmmode_output->edid_blob) + drmModeFreePropertyBlob(drmmode_output->edid_blob); + drmmode_output->edid_blob = + drmModeGetPropertyBlob(drmmode->fd, + koutput->prop_values[i]); + } + drmModeFreeProperty(props); + } + + if (drmmode_output->edid_blob) + ddc_mon = xf86InterpretEDID(pScrn->scrnIndex, + drmmode_output->edid_blob->data); + + if (ddc_mon) { + XF86_CRTC_CONFIG_PTR(pScrn)->debug_modes = TRUE; + xf86PrintEDID(ddc_mon); + xf86OutputSetEDID(output, ddc_mon); + xf86SetDDCproperties(pScrn, ddc_mon); + } + + DEBUG_MSG("count_modes: %d", koutput->count_modes); + + /* modes should already be available */ + for (i = 0; i < koutput->count_modes; i++) { + Mode = xnfalloc(sizeof(DisplayModeRec)); + + drmmode_ConvertFromKMode(pScrn, &koutput->modes[i], + Mode); + Modes = xf86ModesAdd(Modes, Mode); + + } + return Modes; +} + +static void +drmmode_output_destroy(xf86OutputPtr output) +{ + drmmode_output_private_ptr drmmode_output = output->driver_private; + int i; + + if (drmmode_output->edid_blob) + drmModeFreePropertyBlob(drmmode_output->edid_blob); + for (i = 0; i < drmmode_output->num_props; i++) { + drmModeFreeProperty(drmmode_output->props[i].mode_prop); + free(drmmode_output->props[i].atoms); + } + drmModeFreeConnector(drmmode_output->mode_output); + free(drmmode_output); + output->driver_private = NULL; +} + +static void +drmmode_output_dpms(xf86OutputPtr output, int mode) +{ + drmmode_output_private_ptr drmmode_output = output->driver_private; + drmModeConnectorPtr koutput = drmmode_output->mode_output; + drmModePropertyPtr props; + drmmode_ptr drmmode = drmmode_output->drmmode; + int mode_id = -1, i; + + for (i = 0; i < koutput->count_props; i++) { + props = drmModeGetProperty(drmmode->fd, koutput->props[i]); + if (props && (props->flags && DRM_MODE_PROP_ENUM)) { + if (!strcmp(props->name, "DPMS")) { + mode_id = koutput->props[i]; + drmModeFreeProperty(props); + break; + } + drmModeFreeProperty(props); + } + } + + if (mode_id < 0) + return; + + drmModeConnectorSetProperty(drmmode->fd, koutput->connector_id, + mode_id, mode); +} + +static Bool +drmmode_property_ignore(drmModePropertyPtr prop) +{ + if (!prop) + return TRUE; + /* ignore blob prop */ + if (prop->flags & DRM_MODE_PROP_BLOB) + return TRUE; + /* ignore standard property */ + if (!strcmp(prop->name, "EDID") || + !strcmp(prop->name, "DPMS")) + return TRUE; + + return FALSE; +} + +static void +drmmode_output_create_resources(xf86OutputPtr output) +{ + drmmode_output_private_ptr drmmode_output = output->driver_private; + drmModeConnectorPtr mode_output = drmmode_output->mode_output; + drmmode_ptr drmmode = drmmode_output->drmmode; + drmModePropertyPtr drmmode_prop; + uint32_t value; + int i, j, err; + + drmmode_output->props = calloc(mode_output->count_props, sizeof(drmmode_prop_rec)); + if (!drmmode_output->props) + return; + + drmmode_output->num_props = 0; + for (i = 0, j = 0; i < mode_output->count_props; i++) { + drmmode_prop = drmModeGetProperty(drmmode->fd, mode_output->props[i]); + if (drmmode_property_ignore(drmmode_prop)) { + drmModeFreeProperty(drmmode_prop); + continue; + } + drmmode_output->props[j].mode_prop = drmmode_prop; + drmmode_output->props[j].index = i; + drmmode_output->num_props++; + j++; + } + + for (i = 0; i < drmmode_output->num_props; i++) { + drmmode_prop_ptr p = &drmmode_output->props[i]; + drmmode_prop = p->mode_prop; + + value = drmmode_output->mode_output->prop_values[p->index]; + + if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) { + INT32 range[2]; + + p->num_atoms = 1; + p->atoms = calloc(p->num_atoms, sizeof(Atom)); + if (!p->atoms) + continue; + p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE); + range[0] = drmmode_prop->values[0]; + range[1] = drmmode_prop->values[1]; + err = RRConfigureOutputProperty(output->randr_output, p->atoms[0], + FALSE, TRUE, + drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE, + 2, range); + if (err != 0) { + xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, + "RRConfigureOutputProperty error, %d\n", err); + } + err = RRChangeOutputProperty(output->randr_output, p->atoms[0], + XA_INTEGER, 32, PropModeReplace, 1, + &value, FALSE, FALSE); + if (err != 0) { + xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, + "RRChangeOutputProperty error, %d\n", err); + } + } else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) { + p->num_atoms = drmmode_prop->count_enums + 1; + p->atoms = calloc(p->num_atoms, sizeof(Atom)); + if (!p->atoms) + continue; + p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE); + for (j = 1; j <= drmmode_prop->count_enums; j++) { + struct drm_mode_property_enum *e = &drmmode_prop->enums[j-1]; + p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE); + } + err = RRConfigureOutputProperty(output->randr_output, p->atoms[0], + FALSE, FALSE, + drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE, + p->num_atoms - 1, (INT32 *)&p->atoms[1]); + if (err != 0) { + xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, + "RRConfigureOutputProperty error, %d\n", err); + } + for (j = 0; j < drmmode_prop->count_enums; j++) + if (drmmode_prop->enums[j].value == value) + break; + /* there's always a matching value */ + err = RRChangeOutputProperty(output->randr_output, p->atoms[0], + XA_ATOM, 32, PropModeReplace, 1, &p->atoms[j+1], FALSE, FALSE); + if (err != 0) { + xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, + "RRChangeOutputProperty error, %d\n", err); + } + } + } +} + +static Bool +drmmode_output_set_property(xf86OutputPtr output, Atom property, + RRPropertyValuePtr value) +{ + drmmode_output_private_ptr drmmode_output = output->driver_private; + drmmode_ptr drmmode = drmmode_output->drmmode; + int i, ret; + + for (i = 0; i < drmmode_output->num_props; i++) { + drmmode_prop_ptr p = &drmmode_output->props[i]; + + if (p->atoms[0] != property) + continue; + + if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) { + uint32_t val; + + if (value->type != XA_INTEGER || value->format != 32 || + value->size != 1) + return FALSE; + val = *(uint32_t *)value->data; + + ret = drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id, + p->mode_prop->prop_id, (uint64_t)val); + + if (ret) + return FALSE; + + return TRUE; + + } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) { + Atom atom; + const char *name; + int j; + + if (value->type != XA_ATOM || value->format != 32 || value->size != 1) + return FALSE; + memcpy(&atom, value->data, 4); + name = NameForAtom(atom); + + /* search for matching name string, then set its value down */ + for (j = 0; j < p->mode_prop->count_enums; j++) { + if (!strcmp(p->mode_prop->enums[j].name, name)) { + ret = drmModeConnectorSetProperty(drmmode->fd, + drmmode_output->output_id, + p->mode_prop->prop_id, + p->mode_prop->enums[j].value); + + if (ret) + return FALSE; + + return TRUE; + } + } + + return FALSE; + } + } + + return TRUE; +} + +static Bool +drmmode_output_get_property(xf86OutputPtr output, Atom property) +{ + + drmmode_output_private_ptr drmmode_output = output->driver_private; + drmmode_ptr drmmode = drmmode_output->drmmode; + uint32_t value; + int err, i; + + if (output->scrn->vtSema) { + drmModeFreeConnector(drmmode_output->mode_output); + drmmode_output->mode_output = + drmModeGetConnector(drmmode->fd, drmmode_output->output_id); + } + + for (i = 0; i < drmmode_output->num_props; i++) { + drmmode_prop_ptr p = &drmmode_output->props[i]; + if (p->atoms[0] != property) + continue; + + value = drmmode_output->mode_output->prop_values[p->index]; + + if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) { + err = RRChangeOutputProperty(output->randr_output, + property, XA_INTEGER, 32, + PropModeReplace, 1, &value, + FALSE, FALSE); + + return !err; + } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) { + int j; + + /* search for matching name string, then set its value down */ + for (j = 0; j < p->mode_prop->count_enums; j++) { + if (p->mode_prop->enums[j].value == value) + break; + } + + err = RRChangeOutputProperty(output->randr_output, property, + XA_ATOM, 32, PropModeReplace, 1, + &p->atoms[j+1], FALSE, FALSE); + + return !err; + } + } + + return FALSE; +} + +static const xf86OutputFuncsRec drmmode_output_funcs = { + .create_resources = drmmode_output_create_resources, + .dpms = drmmode_output_dpms, + .detect = drmmode_output_detect, + .mode_valid = drmmode_output_mode_valid, + .get_modes = drmmode_output_get_modes, + .set_property = drmmode_output_set_property, + .get_property = drmmode_output_get_property, + .destroy = drmmode_output_destroy +}; + +// FIXME - Eliminate the following values that aren't accurate for OMAP4: +const char *output_names[] = { "None", + "VGA", + "DVI-I", + "DVI-D", + "DVI-A", + "Composite", + "SVIDEO", + "LVDS", + "CTV", + "DIN", + "DP", + "HDMI", + "HDMI", + "TV", + "eDP", +}; +#define NUM_OUTPUT_NAMES (sizeof(output_names) / sizeof(output_names[0])) + +static void +drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num) +{ + xf86OutputPtr output; + drmModeConnectorPtr koutput; + drmModeEncoderPtr kencoder; + drmmode_output_private_ptr drmmode_output; + char name[32]; + + TRACE_ENTER(); + + koutput = drmModeGetConnector(drmmode->fd, + drmmode->mode_res->connectors[num]); + if (!koutput) + return; + + kencoder = drmModeGetEncoder(drmmode->fd, koutput->encoders[0]); + if (!kencoder) { + drmModeFreeConnector(koutput); + return; + } + + if (koutput->connector_type >= NUM_OUTPUT_NAMES) + snprintf(name, 32, "Unknown%d-%d", koutput->connector_type, + koutput->connector_type_id); + else + snprintf(name, 32, "%s-%d", + output_names[koutput->connector_type], + koutput->connector_type_id); + + output = xf86OutputCreate(pScrn, &drmmode_output_funcs, name); + if (!output) { + drmModeFreeEncoder(kencoder); + drmModeFreeConnector(koutput); + return; + } + + drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1); + if (!drmmode_output) { + xf86OutputDestroy(output); + drmModeFreeConnector(koutput); + drmModeFreeEncoder(kencoder); + return; + } + + drmmode_output->output_id = drmmode->mode_res->connectors[num]; + drmmode_output->mode_output = koutput; + drmmode_output->mode_encoder = kencoder; + drmmode_output->drmmode = drmmode; + + output->mm_width = koutput->mmWidth; + output->mm_height = koutput->mmHeight; + output->driver_private = drmmode_output; + + output->possible_crtcs = kencoder->possible_crtcs; + output->possible_clones = kencoder->possible_clones; + output->interlaceAllowed = TRUE; +#if 0 +// FIXME - check with Rob whether this is supported for OMAP4: + output->doubleScanAllowed = TRUE; +#endif + + TRACE_EXIT(); + return; +} /* drmmode_output_init() */ + +static Bool +drmmode_xf86crtc_resize(ScrnInfoPtr pScrn, int width, int height) +{ + OMAPPtr pOMAP = OMAPPTR(pScrn); + ScreenPtr pScreen = pScrn->pScreen; + unsigned int pitch; + + TRACE_ENTER(); + + /* if fb required size has changed, realloc! */ + + DEBUG_MSG("Resize! %dx%d", width, height); + + pScrn->virtualX = width; + pScrn->virtualY = height; + + pitch = OMAPCalculateStride(width, pScrn->bitsPerPixel); + + if ((pitch * height) != omap_bo_size(pOMAP->scanout)) { + /* hmm, should we remove fb here.. we don't want to keep + * scanning out a deallocated buffer.. + */ + drmmode_remove_fb(pScrn); + + /* delete old scanout buffer */ + omap_bo_del(pOMAP->scanout); + + DEBUG_MSG("allocating new scanout buffer: %dx%d (%d)", + width, height, pitch); + + /* allocate new scanout buffer */ + pOMAP->scanout = omap_bo_new(pOMAP->dev, height * pitch, + OMAP_BO_SCANOUT | OMAP_BO_WC); + if (!pOMAP->scanout) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Error reallocating scanout buffer\n"); + return FALSE; + } + } + + if (pScreen && pScreen->ModifyPixmapHeader) { + PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen); + pScreen->ModifyPixmapHeader(rootPixmap, + pScrn->virtualX, pScrn->virtualY, + pScrn->depth, pScrn->bitsPerPixel, pitch, + omap_bo_map(pOMAP->scanout)); + } + + TRACE_EXIT(); + return TRUE; +} /* drmmode_xf86crtc_resize() */ + + +static const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = { + drmmode_xf86crtc_resize +}; + + +Bool drmmode_pre_init(ScrnInfoPtr pScrn, int fd, int cpp) +{ + xf86CrtcConfigPtr xf86_config; + drmmode_ptr drmmode; + int i; + + TRACE_ENTER(); + + drmmode = malloc(sizeof *drmmode); + drmmode->fd = fd; + drmmode->fb_id = 0; + + xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs); + xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + + + drmmode->cpp = cpp; + drmmode->mode_res = drmModeGetResources(drmmode->fd); + if (!drmmode->mode_res) { + return FALSE; + } else { + DEBUG_MSG("Got KMS resources"); + DEBUG_MSG(" %d connectors, %d encoders", + drmmode->mode_res->count_connectors, + drmmode->mode_res->count_encoders); + DEBUG_MSG(" %d crtcs, %d fbs", + drmmode->mode_res->count_crtcs, drmmode->mode_res->count_fbs); + DEBUG_MSG(" %dx%d minimum resolution", + drmmode->mode_res->min_width, drmmode->mode_res->min_height); + DEBUG_MSG(" %dx%d maximum resolution", + drmmode->mode_res->max_width, drmmode->mode_res->max_height); + } + xf86CrtcSetSizeRange(pScrn, 320, 200, drmmode->mode_res->max_width, + drmmode->mode_res->max_height); + for (i = 0; i < drmmode->mode_res->count_crtcs; i++) + drmmode_crtc_init(pScrn, drmmode, i); + + for (i = 0; i < drmmode->mode_res->count_connectors; i++) + drmmode_output_init(pScrn, drmmode, i); + + xf86InitialConfiguration(pScrn, TRUE); + + TRACE_EXIT(); + + return TRUE; +} /* drmmode_pre_init() */ + +void +drmmode_adjust_frame(ScrnInfoPtr pScrn, int x, int y, int flags) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + xf86OutputPtr output = config->output[config->compat_output]; + xf86CrtcPtr crtc = output->crtc; + + if (!crtc || !crtc->enabled) + return; + + drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, x, y); +} + +void +drmmode_remove_fb(ScrnInfoPtr pScrn) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + xf86CrtcPtr crtc = NULL; + drmmode_crtc_private_ptr drmmode_crtc; + drmmode_ptr drmmode; + + if (config) + crtc = config->crtc[0]; + if (!crtc) + return; + + drmmode_crtc = crtc->driver_private; + drmmode = drmmode_crtc->drmmode; + + if (drmmode->fb_id) + drmModeRmFB(drmmode->fd, drmmode->fb_id); + drmmode->fb_id = 0; +} + + +/* + * Hot Plug Event handling: + */ + +static drmmode_ptr +drmmode_from_scrn(ScrnInfoPtr pScrn) +{ + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + drmmode_crtc_private_ptr drmmode_crtc; + + drmmode_crtc = xf86_config->crtc[0]->driver_private; + return drmmode_crtc->drmmode; +} /* drmmode_from_scrn() */ + +static void +drmmode_handle_uevents(int fd, void *closure) +{ + ScrnInfoPtr pScrn = closure; + OMAPPtr pOMAP = OMAPPTR(pScrn); + drmmode_ptr drmmode = drmmode_from_scrn(pScrn); + struct udev_device *dev; + const char *hotplug; + struct stat s; + dev_t udev_devnum; + + dev = udev_monitor_receive_device(drmmode->uevent_monitor); + if (!dev) + return; + +// FIXME - Do we need to keep this code, which Rob originally wrote +// (i.e. up thru the "if" statement)?: + + /* + * Check to make sure this event is directed at our + * device (by comparing dev_t values), then make + * sure it's a hotplug event (HOTPLUG=1) + */ + udev_devnum = udev_device_get_devnum(dev); + fstat(pOMAP->drmFD, &s); + + hotplug = udev_device_get_property_value(dev, "HOTPLUG"); + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "hotplug=%s, match=%d\n", hotplug, + memcmp(&s.st_rdev, &udev_devnum, sizeof (dev_t))); + + if (memcmp(&s.st_rdev, &udev_devnum, sizeof (dev_t)) == 0 && + hotplug && atoi(hotplug) == 1) { + RRGetInfo(screenInfo.screens[pScrn->scrnIndex], TRUE); + } + udev_device_unref(dev); +} /* drmmode_handle_uevents() */ + +void +drmmode_uevent_init(ScrnInfoPtr pScrn) +{ + drmmode_ptr drmmode = drmmode_from_scrn(pScrn); + struct udev *u; + struct udev_monitor *mon; + + TRACE_ENTER(); + + u = udev_new(); + if (!u) + return; + mon = udev_monitor_new_from_netlink(u, "udev"); + if (!mon) { + udev_unref(u); + return; + } + + if (udev_monitor_filter_add_match_subsystem_devtype(mon, + "drm", + "drm_minor") < 0 || + udev_monitor_enable_receiving(mon) < 0) { + udev_monitor_unref(mon); + udev_unref(u); + return; + } + + drmmode->uevent_handler = + xf86AddGeneralHandler(udev_monitor_get_fd(mon), + drmmode_handle_uevents, pScrn); + + drmmode->uevent_monitor = mon; + + TRACE_EXIT(); +} /* drmmode_uevent_init() */ + +void +drmmode_uevent_fini(ScrnInfoPtr pScrn) +{ + drmmode_ptr drmmode = drmmode_from_scrn(pScrn); + + TRACE_ENTER(); + + if (drmmode->uevent_handler) { + struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor); + xf86RemoveGeneralHandler(drmmode->uevent_handler); + + udev_monitor_unref(drmmode->uevent_monitor); + udev_unref(u); + } + + TRACE_EXIT(); +} /* drmmode_uevent_fini() */ diff --git a/src/omap_driver.c b/src/omap_driver.c new file mode 100644 index 0000000..a68602c --- /dev/null +++ b/src/omap_driver.c @@ -0,0 +1,989 @@ +/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ + +/* + * Copyright © 2011 Texas Instruments, 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 (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: + * Ian Elliott <ianelliottus@yahoo.com> + * Rob Clark <rob@ti.com> + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "omap_driver.h" + + +Bool omapDebug = 0; + +/* + * Forward declarations: + */ +static const OptionInfoRec *OMAPAvailableOptions(int chipid, int busid); +static void OMAPIdentify(int flags); +static Bool OMAPProbe(DriverPtr drv, int flags); +static Bool OMAPPreInit(ScrnInfoPtr pScrn, int flags); +static Bool OMAPScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, + char **argv); +static void OMAPLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, + LOCO * colors, VisualPtr pVisual); +static Bool OMAPCloseScreen(int scrnIndex, ScreenPtr pScreen); +static Bool OMAPCreateScreenResources(ScreenPtr pScreen); +static void OMAPBlockHandler(int i, pointer blockData, pointer pTimeout, + pointer pReadmask); +static Bool OMAPSwitchMode(int scrnIndex, DisplayModePtr mode, int flags); +static void OMAPAdjustFrame(int scrnIndex, int x, int y, int flags); +static Bool OMAPEnterVT(int scrnIndex, int flags); +static void OMAPLeaveVT(int scrnIndex, int flags); +static void OMAPFreeScreen(int scrnIndex, int flags); + + + +/** + * A structure used by the XFree86 code when loading this driver, so that it + * can access the Probe() function, and other functions/info that it uses + * before it calls the Probe() function. The name of this structure must be + * the all-upper-case version of the driver name. + */ +_X_EXPORT DriverRec OMAP = { + OMAP_VERSION, + (char *)OMAP_DRIVER_NAME, + OMAPIdentify, + OMAPProbe, + OMAPAvailableOptions, + NULL, + 0, + NULL, +#ifdef XSERVER_LIBPCIACCESS + NULL, + NULL +#endif +}; + +/** Supported "chipsets." */ +static SymTabRec OMAPChipsets[] = { + /* OMAP2 and earlier not supported */ + { 0x3430, "OMAP3430 with PowerVR SGX530" }, + { 0x3630, "OMAP3630 with PowerVR SGX530" }, + { 0x4430, "OMAP4430 with PowerVR SGX540" }, + { 0x4460, "OMAP4460 with PowerVR SGX540" }, + /* { 4470, "OMAP4470 with <redacted> ;-)" }, */ + {-1, NULL } +}; + +/** Supported options, as enum values. */ +typedef enum { + OPTION_DEBUG, + OPTION_NO_ACCEL, + /* TODO: probably need to add an option to let user specify bus-id */ +} OMAPOpts; + +/** Supported options. */ +static const OptionInfoRec OMAPOptions[] = { + { OPTION_DEBUG, "Debug", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_NO_ACCEL, "NoAccel", OPTV_BOOLEAN, {0}, FALSE }, + { -1, NULL, OPTV_NONE, {0}, FALSE } +}; + +/** + * Helper function for opening a connection to the DRM. + */ + +static int +OMAPOpenDRM(int n) +{ + char bus_id[32]; + snprintf(bus_id, sizeof(bus_id), "platform:omapdrm:%02d", n); + return drmOpen("omapdrm", bus_id); +} + +static Bool +OMAPOpenDRMMaster(ScrnInfoPtr pScrn, int n) +{ + OMAPPtr pOMAP = OMAPPTR(pScrn); + drmSetVersion sv; + int err; + + pOMAP->drmFD = OMAPOpenDRM(n); + if (pOMAP->drmFD == -1) { + ERROR_MSG("Cannot open a connection with the DRM."); + return FALSE; + } + + /* Check that what we opened was a master or a master-capable FD, + * by setting the version of the interface we'll use to talk to it. + * (see DRIOpenDRMMaster() in DRI1) + */ + sv.drm_di_major = 1; + sv.drm_di_minor = 1; + sv.drm_dd_major = -1; + sv.drm_dd_minor = -1; + err = drmSetInterfaceVersion(pOMAP->drmFD, &sv); + if (err != 0) { + ERROR_MSG("Cannot set the DRM interface version."); + drmClose(pOMAP->drmFD); + pOMAP->drmFD = -1; + return FALSE; + } + + return TRUE; +} + + + +/** + * Helper function for closing a connection to the DRM. + */ +static void +OMAPCloseDRMMaster(ScrnInfoPtr pScrn) +{ + OMAPPtr pOMAP = OMAPPTR(pScrn); + + if (pOMAP && (pOMAP->drmFD > 0)) { + drmClose(pOMAP->drmFD); + pOMAP->drmFD = -1; + } +} + + + +/** + * Helper function for calculating the stride of pixmaps. + * TODO get stride requirements from kernel driver, or from EXA module, + * rather than hard-coding.. + */ +#define STRIDE_BOUNDARY 32 +unsigned int +OMAPCalculateStride(unsigned int width, unsigned int bitsPerPixel) +{ + unsigned int alignedWidth; + + alignedWidth = (width + (STRIDE_BOUNDARY - 1)) & ~(STRIDE_BOUNDARY - 1); + return ((alignedWidth * bitsPerPixel) + 7) / 8; +} + + +static Bool +OMAPMapMem(ScrnInfoPtr pScrn) +{ + OMAPPtr pOMAP = OMAPPTR(pScrn); + int pitch; + + pitch = OMAPCalculateStride(pScrn->virtualX, pScrn->bitsPerPixel); + + DEBUG_MSG("allocating new scanout buffer: %dx%d (%d)", + pScrn->virtualX, pScrn->virtualY, pitch); + + pOMAP->scanout = omap_bo_new(pOMAP->dev, pScrn->virtualY * pitch, + OMAP_BO_SCANOUT | OMAP_BO_WC); + if (!pOMAP->scanout) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Error allocating scanout buffer\n"); + return FALSE; + } + + pScrn->displayWidth = pitch / (pScrn->bitsPerPixel / 8); + + return TRUE; +} + + +static Bool +OMAPUnmapMem(ScrnInfoPtr pScrn) +{ + OMAPPtr pOMAP = OMAPPTR(pScrn); + drmmode_remove_fb(pScrn); + omap_bo_del(pOMAP->scanout); + pOMAP->scanout = NULL; + return TRUE; +} + + + +/** Let the XFree86 code know the Setup() function. */ +static MODULESETUPPROTO(OMAPSetup); + +/** Provide basic version information to the XFree86 code. */ +static XF86ModuleVersionInfo OMAPVersRec = +{ + OMAP_DRIVER_NAME, + MODULEVENDORSTRING, + MODINFOSTRING1, + MODINFOSTRING2, + XORG_VERSION_CURRENT, + OMAP_MAJOR_VERSION, OMAP_MINOR_VERSION, OMAP_PATCHLEVEL, + ABI_CLASS_VIDEODRV, + ABI_VIDEODRV_VERSION, + MOD_CLASS_VIDEODRV, + {0, 0, 0, 0} +}; + +/** Let the XFree86 code know about the VersRec and Setup() function. */ +_X_EXPORT XF86ModuleData omapModuleData = { &OMAPVersRec, OMAPSetup, NULL }; + + +/** + * The first function that the XFree86 code calls, after loading this module. + */ +static pointer +OMAPSetup(pointer module, pointer opts, int *errmaj, int *errmin) +{ + static Bool setupDone = FALSE; + + /* This module should be loaded only once, but check to be sure: */ + if (!setupDone) { + setupDone = TRUE; + xf86AddDriver(&OMAP, module, 0); + + /* The return value must be non-NULL on success even though there is no + * TearDownProc. + */ + return (pointer) 1; + } else { + if (errmaj) + *errmaj = LDR_ONCEONLY; + return NULL; + } +} + + +/** + * Allocate the driver's Screen-specific, "private" data structure and hook it + * into the ScrnInfoRec's driverPrivate field. + */ +static Bool +OMAPGetRec(ScrnInfoPtr pScrn) +{ + if (pScrn->driverPrivate != NULL) + return TRUE; + + pScrn->driverPrivate = calloc(1, sizeof(OMAPRec)); + if (pScrn->driverPrivate == NULL) + return FALSE; + + return TRUE; +} + + +/** + * Free the driver's Screen-specific, "private" data structure and NULL-out the + * ScrnInfoRec's driverPrivate field. + */ +static void +OMAPFreeRec(ScrnInfoPtr pScrn) +{ + if (pScrn->driverPrivate == NULL) + return; + free(pScrn->driverPrivate); + pScrn->driverPrivate = NULL; +} + + +/** + * The mandatory AvailableOptions() function. It returns the available driver + * options to the "-configure" option, so that an xorg.conf file can be built + * and the user can see which options are available for them to use. + */ +static const OptionInfoRec * +OMAPAvailableOptions(int chipid, int busid) +{ + return OMAPOptions; +} + + + +/** + * The mandatory Identify() function. It is run before Probe(), and prints out + * an identifying message, which includes the chipset(s) the driver supports. + */ +static void +OMAPIdentify(int flags) +{ + xf86PrintChipsets(OMAP_NAME, "Driver for TI OMAP", OMAPChipsets); +} + + + +/** + * The driver's Probe() function. This function finds all instances of the + * TI OMAP hardware that the driver supports (from within the "xorg.conf" + * device sections), and for instances not already claimed by another driver, + * claim the instances, and allocate a ScrnInfoRec. Only minimal hardware + * probing is allowed here. + */ +static Bool +OMAPProbe(DriverPtr drv, int flags) +{ + int i; + ScrnInfoPtr pScrn; + GDevPtr *devSections; + int numDevSections; + Bool foundScreen = FALSE; + + if (flags & PROBE_DETECT) { + EARLY_ERROR_MSG("The %s driver does not support the \"-configure\" or " + "\"-probe\" command line arguments.", OMAP_NAME); + return FALSE; + } + + /* Get the "xorg.conf" file device sections that match this driver, and + * return (error out) if there are none: + */ + numDevSections = xf86MatchDevice(OMAP_DRIVER_NAME, &devSections); + if (numDevSections <= 0) { + EARLY_ERROR_MSG("Did not find any matching device section in " + "configuration file"); + return FALSE; + } + + for (i = 0; i < numDevSections; i++) { + int fd = OMAPOpenDRM(i); + if (fd != -1) { + int entity = xf86ClaimNoSlot(drv, 0, devSections[i], TRUE); + + pScrn = xf86AllocateScreen(drv, 0); + if (!pScrn) { + EARLY_ERROR_MSG("Cannot allocate a ScrnInfoPtr"); + return FALSE; + } + xf86AddEntityToScreen(pScrn, entity); + + foundScreen = TRUE; + + pScrn->driverVersion = OMAP_VERSION; + pScrn->driverName = (char *)OMAP_DRIVER_NAME; + pScrn->name = (char *)OMAP_NAME; + pScrn->Probe = OMAPProbe; + pScrn->PreInit = OMAPPreInit; + pScrn->ScreenInit = OMAPScreenInit; + pScrn->SwitchMode = OMAPSwitchMode; + pScrn->AdjustFrame = OMAPAdjustFrame; + pScrn->EnterVT = OMAPEnterVT; + pScrn->LeaveVT = OMAPLeaveVT; + pScrn->FreeScreen = OMAPFreeScreen; + + /* would be nice to be able to keep the connection open.. but + * currently we don't allocate the private until PreInit + */ + drmClose(fd); + } + } + free(devSections); + return foundScreen; +} + + + +/** + * The driver's PreInit() function. Additional hardware probing is allowed + * now, including display configuration. + */ +static Bool +OMAPPreInit(ScrnInfoPtr pScrn, int flags) +{ + OMAPPtr pOMAP; + int default_depth, fbbpp; + rgb defaultWeight = { 0, 0, 0 }; + rgb defaultMask = { 0, 0, 0 }; + Gamma defaultGamma = { 0.0, 0.0, 0.0 }; + uint64_t value; + int i; + + TRACE_ENTER(); + + if (flags & PROBE_DETECT) { + ERROR_MSG("The %s driver does not support the \"-configure\" or " + "\"-probe\" command line arguments.", OMAP_NAME); + return FALSE; + } + + /* Check the number of entities, and fail if it isn't one. */ + if (pScrn->numEntities != 1) { + ERROR_MSG("Driver expected 1 entity, but found %d for screen %d", + pScrn->numEntities, pScrn->scrnIndex); + return FALSE; + } + + /* Allocate the driver's Screen-specific, "private" data structure: */ + OMAPGetRec(pScrn); + pOMAP = OMAPPTR(pScrn); + + pOMAP->pEntityInfo = xf86GetEntityInfo(pScrn->entityList[0]); + + pScrn->monitor = pScrn->confScreen->monitor; + + /* Get the current depth, and set it for XFree86: */ + default_depth = 24; /* TODO: get from kernel */ + fbbpp = 32; /* TODO: get from kernel */ + + if (!xf86SetDepthBpp(pScrn, default_depth, 0, fbbpp, Support32bppFb)) { + /* The above function prints an error message. */ + goto fail; + } + xf86PrintDepthBpp(pScrn); + + /* Set the color weight: */ + if (!xf86SetWeight(pScrn, defaultWeight, defaultMask)) { + /* The above function prints an error message. */ + goto fail; + } + + /* Set the gamma: */ + if (!xf86SetGamma(pScrn, defaultGamma)) { + /* The above function prints an error message. */ + goto fail; + } + + /* Visual init: */ + if (!xf86SetDefaultVisual(pScrn, -1)) { + /* The above function prints an error message. */ + goto fail; + } + + /* We don't support 8-bit depths: */ + if (pScrn->depth < 16) { + ERROR_MSG("The requested default visual (%s) has an unsupported " + "depth (%d).", + xf86GetVisualName(pScrn->defaultVisual), pScrn->depth); + goto fail; + } + + /* Using a programmable clock: */ + pScrn->progClock = TRUE; + + /* Open a connection to the DRM, so we can communicate with the KMS code: */ + if (!OMAPOpenDRMMaster(pScrn, 0)) { + goto fail; + } + DEBUG_MSG("Became DRM master."); + + /* create DRM device instance: */ + pOMAP->dev = omap_device_new(pOMAP->drmFD); + + /* query chip-id: */ + if (omap_get_param(pOMAP->dev, OMAP_PARAM_CHIPSET_ID, &value)) { + ERROR_MSG("Could not read chipset"); + goto fail; + } + pOMAP->chipset = value; + + /* find matching chipset name: */ + for (i = 0; OMAPChipsets[i].name; i++) { + if (OMAPChipsets[i].token == pOMAP->chipset) { + pScrn->chipset = (char *)OMAPChipsets[i].name; + break; + } + } + + if (!pScrn->chipset) { + ERROR_MSG("Unknown chipset: %s", pScrn->chipset); + goto fail; + } + + INFO_MSG("Found chipset: %s", pScrn->chipset); + + /* + * Process the "xorg.conf" file options: + */ + xf86CollectOptions(pScrn, NULL); + if (!(pOMAP->pOptionInfo = calloc(1, sizeof(OMAPOptions)))) + return FALSE; + memcpy(pOMAP->pOptionInfo, OMAPOptions, sizeof(OMAPOptions)); + xf86ProcessOptions(pScrn->scrnIndex, pOMAP->pEntityInfo->device->options, + pOMAP->pOptionInfo); + + /* Determine if the user wants debug messages turned on: */ + omapDebug = xf86ReturnOptValBool(pOMAP->pOptionInfo, OPTION_DEBUG, FALSE); + + /* Determine if the user wants to disable acceleration: */ + pOMAP->NoAccel = + xf86ReturnOptValBool(pOMAP->pOptionInfo, OPTION_NO_ACCEL, FALSE); + + /* + * Select the video modes: + */ + INFO_MSG("Setting the video modes ..."); + + /* Don't call drmCheckModesettingSupported() as its written only for + * PCI devices. + */ + + /* Do initial KMS setup: */ + if (!drmmode_pre_init(pScrn, pOMAP->drmFD, (pScrn->bitsPerPixel >> 3))) { + ERROR_MSG("Cannot get KMS resources"); + } else { + INFO_MSG("Got KMS resources"); + } + + xf86RandR12PreInit(pScrn); + + /* Let XFree86 calculate or get (from command line) the display DPI: */ + xf86SetDpi(pScrn, 0, 0); + + /* Ensure we have a supported depth: */ + switch (pScrn->bitsPerPixel) { + case 16: + case 24: + case 32: + break; + default: + ERROR_MSG("The requested number of bits per pixel (%d) is unsupported.", + pScrn->bitsPerPixel); + goto fail; + } + + + /* Load external sub-modules now: */ + + if (!(xf86LoadSubModule(pScrn, "dri2") && + xf86LoadSubModule(pScrn, "exa") && + xf86LoadSubModule(pScrn, "fb"))) { + goto fail; + } + + switch (pOMAP->chipset) { + case 0x3430: + case 0x3630: + case 0x4430: + case 0x4460: + if (xf86LoadSubModule(pScrn, SUB_MODULE_PVR)) { + INFO_MSG("Loaded the %s sub-module", SUB_MODULE_PVR); + } else { + INFO_MSG("Cannot load the %s sub-module", SUB_MODULE_PVR); + /* note that this is not fatal.. since IMG/PVR EXA module + * is closed source, it is only optional. + */ + pOMAP->NoAccel = TRUE; /* don't call InitPowerVREXA() */ + } + break; + /* case 0x4470: ..; break; */ + default: + ERROR_MSG("Unsupported chipset: %d", pOMAP->chipset); + goto fail; + } + + TRACE_EXIT(); + return TRUE; + +fail: + TRACE_EXIT(); + OMAPFreeRec(pScrn); + return FALSE; +} + + + +/** + * The driver's ScreenInit() function. Fill in pScreen, map the frame buffer, + * save state, initialize the mode, etc. + */ +static Bool +OMAPScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + OMAPPtr pOMAP = OMAPPTR(pScrn); + VisualPtr visual; + xf86CrtcConfigPtr xf86_config; + int i; + + TRACE_ENTER(); + +#if 0 + if (!pOMAP->NoAccel) + OMAPDRI2Init(pScreen); +#endif + + /* Allocate and map memory areas we need */ + if (!OMAPMapMem(pScrn)) + return FALSE; + + xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + + /* need to point to new screen on server regeneration */ + for (i = 0; i < xf86_config->num_crtc; i++) + xf86_config->crtc[i]->scrn = pScrn; + for (i = 0; i < xf86_config->num_output; i++) + xf86_config->output[i]->scrn = pScrn; + + /* + * The next step is to setup the screen's visuals, and initialize the + * framebuffer code. In cases where the framebuffer's default + * choices for things like visual layouts and bits per RGB are OK, + * this may be as simple as calling the framebuffer's ScreenInit() + * function. If not, the visuals will need to be setup before calling + * a fb ScreenInit() function and fixed up after. + * + * For most PC hardware at depths >= 8, the defaults that fb uses + * are not appropriate. In this driver, we fixup the visuals after. + */ + + /* + * Reset the visual list. + */ + + miClearVisualTypes(); + if (!miSetVisualTypes(pScrn->depth, miGetDefaultVisualMask(pScrn->depth), + pScrn->rgbBits, pScrn->defaultVisual)) { + ERROR_MSG("Cannot initialize the visual type for %d bits per pixel!", + pScrn->bitsPerPixel); + goto fail; + } + + if (!miSetPixmapDepths()) { + ERROR_MSG("Cannot initialize the pixmap depth!"); + goto fail; + } + + /* Initialize some generic 2D drawing functions: */ + if (!fbScreenInit(pScreen, omap_bo_map(pOMAP->scanout), + pScrn->virtualX, pScrn->virtualY, + pScrn->xDpi, pScrn->yDpi, pScrn->displayWidth, + pScrn->bitsPerPixel)) { + ERROR_MSG("fbScreenInit() failed!"); + goto fail; + } + + /* Fixup RGB ordering: */ + visual = pScreen->visuals + pScreen->numVisuals; + while (--visual >= pScreen->visuals) { + if ((visual->class | DynamicClass) == DirectColor) { + visual->offsetRed = pScrn->offset.red; + visual->offsetGreen = pScrn->offset.green; + visual->offsetBlue = pScrn->offset.blue; + visual->redMask = pScrn->mask.red; + visual->greenMask = pScrn->mask.green; + visual->blueMask = pScrn->mask.blue; + } + } + + /* Continue initializing the generic 2D drawing functions after fixing the + * RGB ordering: + */ + if (!fbPictureInit(pScreen, NULL, 0)) { + ERROR_MSG("fbPictureInit() failed!"); + goto fail; + } + + /* Set the initial black & white colormap indices: */ + xf86SetBlackWhitePixels(pScreen); + + /* Initialize backing store: */ + miInitializeBackingStore(pScreen); + xf86SetBackingStore(pScreen); + + /* Initialize the cursor: */ + miDCInitialize(pScreen, xf86GetPointerScreenFuncs()); + + /* Cause the cursor position to be updated by the mouse signal handler: */ + xf86SetSilkenMouse(pScreen); + + /* XXX -- Is this the right place for this? The Intel i830 driver says: + * "Must force it before EnterVT, so we are in control of VT..." + */ + pScrn->vtSema = TRUE; + + /* Take over the virtual terminal from the console, set the desired mode, + * etc.: + */ + OMAPEnterVT(scrnIndex, 0); + + /* Set the desired mode(s): */ + if (!xf86SetDesiredModes(pScrn)) { + ERROR_MSG("xf86SetDesiredModes() failed!"); + goto fail; + } + + /* Do some XRandR initialization: */ + if (!xf86CrtcScreenInit(pScreen)) { + ERROR_MSG("xf86CrtcScreenInit() failed!"); + goto fail; + } + + if (!miCreateDefColormap(pScreen)) { + ERROR_MSG("Cannot create colormap!"); + goto fail; + } + + if (!xf86HandleColormaps(pScreen, 256, 8, OMAPLoadPalette, NULL, + CMAP_PALETTED_TRUECOLOR)) { + ERROR_MSG("xf86HandleColormaps() failed!"); + goto fail; + } + + /* Setup power management: */ + xf86DPMSInit(pScreen, xf86DPMSSet, 0); + + pScreen->SaveScreen = xf86SaveScreen; + + /* Wrap some screen functions: */ + wrap(pOMAP, pScreen, CloseScreen, OMAPCloseScreen); + wrap(pOMAP, pScreen, CreateScreenResources, OMAPCreateScreenResources); + wrap(pOMAP, pScreen, BlockHandler, OMAPBlockHandler); + + /* + * Initialize external sub-modules for EXA now: + */ + + if (!pOMAP->NoAccel) { + switch (pOMAP->chipset) { + case 0x3430: + case 0x3630: + case 0x4430: + case 0x4460: + INFO_MSG("Initializing the \"%s\" sub-module ...", SUB_MODULE_PVR); + pOMAP->pOMAPEXA = InitPowerVREXA(pScreen, pScrn); + if (pOMAP->pOMAPEXA) { + INFO_MSG("Successfully initialized the \"%s\" sub-module", + SUB_MODULE_PVR); + } else { + INFO_MSG("Could not initialize the \"%s\" sub-module", + SUB_MODULE_PVR); + pOMAP->NoAccel = TRUE; + } + break; + /* case 4470: ..; break; */ + default: + ERROR_MSG("Unsupported chipset: %d", pOMAP->chipset); + pOMAP->NoAccel = TRUE; + break; + } + } + + if (!pOMAP->pOMAPEXA) { + pOMAP->pOMAPEXA = InitNullEXA(pScreen, pScrn); + } + + drmmode_uevent_init(pScrn); + + TRACE_EXIT(); + return TRUE; + +fail: + TRACE_EXIT(); + return FALSE; +} + + +static void +OMAPLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, + LOCO * colors, VisualPtr pVisual) +{ + TRACE_ENTER(); + TRACE_EXIT(); +} + + +/** + * The driver's CloseScreen() function. This is called at the end of each + * server generation. Restore state, unmap the frame buffer (and any other + * mapped memory regions), and free per-Screen data structures (except those + * held by pScrn). + */ +static Bool +OMAPCloseScreen(int scrnIndex, ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + OMAPPtr pOMAP = OMAPPTR(pScrn); + + TRACE_ENTER(); + + drmmode_uevent_fini(pScrn); + + if (pScrn->vtSema == TRUE) { + OMAPLeaveVT(scrnIndex, 0); + } + + if (pOMAP->pOMAPEXA) { + if (pOMAP->pOMAPEXA->CloseScreen) { + pOMAP->pOMAPEXA->CloseScreen(scrnIndex, pScreen); + } + } + + OMAPUnmapMem(pScrn); + + pScrn->vtSema = FALSE; + + unwrap(pOMAP, pScreen, CloseScreen); + unwrap(pOMAP, pScreen, BlockHandler); + unwrap(pOMAP, pScreen, CreateScreenResources); + + TRACE_EXIT(); + + return (*pScreen->CloseScreen)(scrnIndex, pScreen); +} + + + +/** + * Adjust the screen pixmap for the current location of the front buffer. + * This is done at EnterVT when buffers are bound as long as the resources + * have already been created, but the first EnterVT happens before + * CreateScreenResources. + */ +static Bool +OMAPCreateScreenResources(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + OMAPPtr pOMAP = OMAPPTR(pScrn); + + swap(pOMAP, pScreen, CreateScreenResources); + if (!(*pScreen->CreateScreenResources) (pScreen)) + return FALSE; + swap(pOMAP, pScreen, CreateScreenResources); + + return TRUE; +} + + +static void +OMAPBlockHandler(int i, pointer blockData, pointer pTimeout, pointer pReadmask) +{ + ScreenPtr pScreen = screenInfo.screens[i]; + ScrnInfoPtr pScrn = xf86Screens[i]; + OMAPPtr pOMAP = OMAPPTR(pScrn); + + swap(pOMAP, pScreen, BlockHandler); + (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask); + swap(pOMAP, pScreen, BlockHandler); + + /* TODO OMAPVideoBlockHandler(), etc.. */ +} + + + +/** + * The driver's SwitchMode() function. Initialize the new mode for the + * Screen. + */ +static Bool +OMAPSwitchMode(int scrnIndex, DisplayModePtr mode, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + return xf86SetSingleMode(pScrn, mode, RR_Rotate_0); +} + + + +/** + * The driver's AdjustFrame() function. For cases where the frame buffer is + * larger than the monitor resolution, this function can pan around the frame + * buffer within the "viewport" of the monitor. + */ +static void +OMAPAdjustFrame(int scrnIndex, int x, int y, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + drmmode_adjust_frame(pScrn, x, y, flags); +} + + + +/** + * The driver's EnterVT() function. This is called at server startup time, and + * when the X server takes over the virtual terminal from the console. As + * such, it may need to save the current (i.e. console) HW state, and set the + * HW state as needed by the X server. + */ +static Bool +OMAPEnterVT(int scrnIndex, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + OMAPPtr pOMAP = OMAPPTR(pScrn); + int ret; + + TRACE_ENTER(); + + ret = drmSetMaster(pOMAP->drmFD); + if (ret) { + ERROR_MSG("Cannot get DRM master: %s\n", strerror(ret)); + } + + if (!xf86SetDesiredModes(pScrn)) { + ERROR_MSG("xf86SetDesiredModes() failed!"); + return FALSE; + } + + TRACE_EXIT(); + return TRUE; +} + + + +/** + * The driver's LeaveVT() function. This is called when the X server + * temporarily gives up the virtual terminal to the console. As such, it may + * need to restore the console's HW state. + */ +static void +OMAPLeaveVT(int scrnIndex, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + OMAPPtr pOMAP = OMAPPTR(pScrn); + int ret; + + TRACE_ENTER(); + + ret = drmDropMaster(pOMAP->drmFD); + if (ret) { + WARNING_MSG("drmDropMaster failed: %s\n", strerror(errno)); + } + + TRACE_EXIT(); +} + + + +/** + * The driver's FreeScreen() function. This is called at the server's end of + * life. This should free any driver-allocated data that was allocated + * up-to-and-including an unsuccessful ScreenInit() call. + */ +static void +OMAPFreeScreen(int scrnIndex, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + OMAPPtr pOMAP = OMAPPTR(pScrn); + + TRACE_ENTER(); + + if (!pOMAP) { + /* This can happen if a Screen is deleted after Probe(): */ + return; + } + + if (pOMAP->pOMAPEXA) { + if (pOMAP->pOMAPEXA->FreeScreen) { + pOMAP->pOMAPEXA->FreeScreen(scrnIndex, flags); + } + free(pOMAP->pOMAPEXA); + } + + omap_device_del(pOMAP->dev); + + OMAPCloseDRMMaster(pScrn); + + OMAPFreeRec(pScrn); + + TRACE_EXIT(); +} + diff --git a/src/omap_driver.h b/src/omap_driver.h new file mode 100644 index 0000000..57f809e --- /dev/null +++ b/src/omap_driver.h @@ -0,0 +1,239 @@ +/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ + +/* + * Copyright © 2011 Texas Instruments, 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 (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: + * Ian Elliott <ianelliottus@yahoo.com> + * Rob Clark <rob@ti.com> + */ + +#ifndef OMAP_DRV_H_ +#define OMAP_DRV_H_ + +/* All drivers need the following headers: */ +#include "xf86.h" +#include "xf86_OSproc.h" + +/* XXX - Perhaps, the following header files will only be used temporarily + * (i.e. so we can use fbdevHW, SW cursor, etc): + * XXX - figure out what can be removed.. + */ +#include "mipointer.h" +#include "mibstore.h" +#include "micmap.h" +#include "colormapst.h" +#include "xf86cmap.h" +#include "shadow.h" +/* for visuals */ +#include "fb.h" +#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 6 +#include "xf86Resources.h" +#include "xf86RAC.h" +#endif +#include "xf86xv.h" +#include "xf86Crtc.h" +#include "xf86RandR12.h" +#include "xf86drm.h" +#ifdef XF86DRI +#define _XF86DRI_SERVER_ +#include "dri2.h" +#endif + +#include "omap_drm.h" + +#include <errno.h> + + + + +#define OMAP_VERSION 1000 /* Apparently not used by X server */ +#define OMAP_NAME "OMAP" /* Name used to prefix messages */ +#define OMAP_DRIVER_NAME "omap" /* Driver name as used in config file */ +#define OMAP_MAJOR_VERSION 0 +#define OMAP_MINOR_VERSION 83 +#define OMAP_PATCHLEVEL 0 + + +/** + * This controls whether debug statements (and function "trace" enter/exit) + * messages are sent to the log file (TRUE) or are ignored (FALSE). + */ +extern _X_EXPORT Bool omapDebug; + + +/* Various logging/debug macros for use in the X driver and the external + * sub-modules: + */ +#define TRACE_ENTER() \ + do { if (omapDebug) xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s:%d: Entering\n",\ + __FUNCTION__, __LINE__); } while (0) +#define TRACE_EXIT() \ + do { if (omapDebug) xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s:%d: Exiting\n",\ + __FUNCTION__, __LINE__); } while (0) +#define DEBUG_MSG(fmt, ...) \ + do { if (omapDebug) xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s:%d " fmt "\n",\ + __FUNCTION__, __LINE__, ##__VA_ARGS__); } while (0) +#define INFO_MSG(fmt, ...) \ + do { xf86DrvMsg(pScrn->scrnIndex, X_INFO, fmt "\n",\ + ##__VA_ARGS__); } while (0) +#define CONFIG_MSG(fmt, ...) \ + do { xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, fmt "\n",\ + ##__VA_ARGS__); } while (0) +#define WARNING_MSG(fmt, ...) \ + do { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "WARNING: " fmt "\n",\ + ##__VA_ARGS__); } while (0) +#define ERROR_MSG(fmt, ...) \ + do { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "ERROR: " fmt "\n",\ + ##__VA_ARGS__); } while (0) +#define EARLY_ERROR_MSG(fmt, ...) \ + do { xf86Msg(X_ERROR, "ERROR: " fmt "\n",\ + ##__VA_ARGS__); } while (0) + + +/* Forward declarations: */ +struct _OMAPRec; + +extern unsigned int +OMAPCalculateStride(unsigned int fbWidth, unsigned int bitsPerPixel); + + +/** + * A per-Screen structure used to communicate and coordinate between the OMAP X + * driver and an external EXA sub-module (if loaded). + */ +typedef struct _OMAPEXARec +{ + union { struct { + + /** + * Called by X driver's CloseScreen() function at the end of each server + * generation to free per-Screen data structures (except those held by + * pScrn). + */ + Bool (*CloseScreen)(int scrnIndex, ScreenPtr pScreen); + + /** + * Called by X driver's FreeScreen() function at the end of each server + * lifetime to free per-ScrnInfoRec data structures, to close any external + * connections (e.g. with PVR2D, DRM), etc. + */ + void (*FreeScreen)(int scrnIndex, int flags); + + /* add new fields here at end, to preserve ABI */ + + }; + + /* padding to keep ABI stable, so an existing EXA submodule + * doesn't need to be recompiled when new fields are added + */ + void *pad[64]; + }; + +} OMAPEXARec, *OMAPEXAPtr; + + + +/** The driver's Screen-specific, "private" data structure. */ +typedef struct _OMAPRec +{ + /** Chipset id */ + int chipset; + + /** + * Pointer to a structure used to communicate and coordinate with an + * external EXA library (if loaded). + */ + OMAPEXAPtr pOMAPEXA; + + Bool NoAccel; + + /** File descriptor of the connection with the DRM. */ + int drmFD; + + /** DRM device instance */ + struct omap_device *dev; + + /** Scan-out buffer. */ + struct omap_bo *scanout; + + /** Pointer to the options for this screen. */ + OptionInfoPtr pOptionInfo; + + /** Save (wrap) the original pScreen functions. */ + CloseScreenProcPtr SavedCloseScreen; + CreateScreenResourcesProcPtr SavedCreateScreenResources; + ScreenBlockHandlerProcPtr SavedBlockHandler; + + /** Pointer to the entity structure for this screen. */ + EntityInfoPtr pEntityInfo; + +} OMAPRec, *OMAPPtr; + +/* + * Misc utility macros: + */ + +/** Return a pointer to the driver's private structure. */ +#define OMAPPTR(p) ((OMAPPtr)((p)->driverPrivate)) +#define OMAPPTR_FROM_SCREEN(pScreen) \ + ((OMAPPtr)(xf86Screens[(pScreen)->myNum])->driverPrivate); + +#define wrap(priv, real, mem, func) {\ + priv->Saved##mem = real->mem; \ + real->mem = func; \ +} + +#define unwrap(priv, real, mem) {\ + real->mem = priv->Saved##mem; \ +} + +#define swap(priv, real, mem) {\ + void *tmp = priv->Saved##mem; \ + priv->Saved##mem = real->mem; \ + real->mem = tmp; \ +} + + +/** + * Canonical name of an external sub-module providing support for EXA + * acceleration, that utiltizes the OMAP's PowerVR accelerator and uses closed + * source from Imaginations Technology Limited. + */ +#define SUB_MODULE_PVR "omap_pvr" +OMAPEXAPtr InitPowerVREXA(ScreenPtr pScreen, ScrnInfoPtr pScrn); + +/** + * Fallback EXA implementation + */ +OMAPEXAPtr InitNullEXA(ScreenPtr pScreen, ScrnInfoPtr pScrn); + +/** + * drmmode functions.. + */ +Bool drmmode_pre_init(ScrnInfoPtr pScrn, int fd, int cpp); +void drmmode_uevent_init(ScrnInfoPtr pScrn); +void drmmode_uevent_fini(ScrnInfoPtr pScrn); +void drmmode_adjust_frame(ScrnInfoPtr pScrn, int x, int y, int flags); +void drmmode_remove_fb(ScrnInfoPtr pScrn); + +#endif /* OMAP_DRV_H_ */ diff --git a/src/omap_drm.c b/src/omap_drm.c new file mode 100644 index 0000000..003a758 --- /dev/null +++ b/src/omap_drm.c @@ -0,0 +1,172 @@ +/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ + +/* + * Copyright © 2011 Texas Instruments, 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 (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: + * Rob Clark <rob@ti.com> + */ + +/* This file is a staging area for OMAP DRM ioctl wrapper stuff that should + * eventually become part of libdrm.. for now, I'm still sorting the API out + * so it remains here until things stabilize. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdlib.h> +#include <sys/mman.h> + +#include "omap_drm.h" + +struct omap_device { + int fd; +}; + +/* a GEM buffer object allocated from the DRM device */ +struct omap_bo { + struct omap_device *dev; + void *map; /* userspace mmap'ing (if there is one) */ + uint32_t size; + uint32_t handle; + uint64_t offset; /* offset to mmap() */ +}; + +struct omap_device * omap_device_new(int fd) +{ + struct omap_device *dev = calloc(sizeof(*dev), 1); + dev->fd = fd; + return dev; +} + +void omap_device_del(struct omap_device *dev) +{ + free(dev); +} + +int omap_get_param(struct omap_device *dev, uint64_t param, uint64_t *value) +{ + struct drm_omap_param req = { + .param = param, + }; + int ret; + + ret = drmCommandWriteRead(dev->fd, DRM_OMAP_GET_PARAM, &req, sizeof(req)); + if (ret) { + return ret; + } + + *value = req.value; + + return 0; +} + +int omap_set_param(struct omap_device *dev, uint64_t param, uint64_t value) +{ + struct drm_omap_param req = { + .param = param, + .value = value, + }; + return drmCommandWrite(dev->fd, DRM_OMAP_GET_PARAM, &req, sizeof(req)); +} + +/* allocate a new (un-tiled) buffer object */ +struct omap_bo * omap_bo_new(struct omap_device *dev, + uint32_t size, uint32_t flags) +{ + struct omap_bo *bo = calloc(sizeof(*bo), 1); + struct drm_omap_gem_new req = { + .size = size, + .flags = flags, + }; + + if (size == 0) { + goto fail; + } + + if (!bo) { + goto fail; + } + + bo->dev = dev; + bo->size = size; + + if (drmCommandWriteRead(dev->fd, DRM_OMAP_GEM_NEW, + &req, sizeof(req))) { + goto fail; + } + + bo->handle = req.handle; + bo->offset = req.offset; + + return bo; + +fail: + free(bo); + return NULL; +} + +/* destroy a buffer object */ +void omap_bo_del(struct omap_bo *bo) +{ + if (!bo) { + return; + } + + if (bo->map) { + munmap(bo->map, bo->size); + } + + if (bo->handle) { + struct drm_gem_close req = { + .handle = bo->handle, + }; + + drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_CLOSE, &req); + } + + free(bo); +} + +uint32_t omap_bo_handle(struct omap_bo *bo) +{ + return bo->handle; +} + +uint32_t omap_bo_size(struct omap_bo *bo) +{ + return bo->size; +} + +void * omap_bo_map(struct omap_bo *bo) +{ + if (!bo->map) { + bo->map = mmap(0, bo->size, PROT_READ | PROT_WRITE, + MAP_SHARED, bo->dev->fd, bo->offset); + if (bo->map == MAP_FAILED) { + bo->map = NULL; + } + } + return bo->map; +} diff --git a/src/omap_drm.h b/src/omap_drm.h new file mode 100644 index 0000000..f15c527 --- /dev/null +++ b/src/omap_drm.h @@ -0,0 +1,99 @@ +/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ + +/* + * Copyright © 2011 Texas Instruments, 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 (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: + * Rob Clark <rob@ti.com> + */ + +#ifndef OMAP_DRM_H_ +#define OMAP_DRM_H_ + +#include <xf86drm.h> +#include <stdint.h> + +/* This file is a staging area for OMAP DRM ioctl wrapper stuff that should + * eventually become part of libdrm.. for now, I'm still sorting the API out + * so it remains here until things stabilize. + */ + + +/**************************/ +/**************************/ +/**************************/ +/* these should be in kernel header.. */ +#define OMAP_PARAM_CHIPSET_ID 1 /* ie. 0x3430, 0x4430, etc */ + +struct drm_omap_param { + uint64_t param; /* in */ + uint64_t value; /* in (set_param), out (get_param) */ +}; + +struct drm_omap_get_base { + char plugin_name[64]; /* in */ + uint32_t ioctl_base; /* out */ +}; + +#define OMAP_BO_SCANOUT 0x00000001 /* scanout capable (phys contiguous) */ +#define OMAP_BO_WC 0x00000002 /* map write-combine (default cached) */ + +struct drm_omap_gem_new { + uint32_t size; /* in */ + uint32_t flags; /* in */ + uint32_t handle; /* out */ + uint64_t offset; /* out */ +}; + +#define DRM_OMAP_GET_PARAM 0x00 +#define DRM_OMAP_SET_PARAM 0x01 +#define DRM_OMAP_GET_BASE 0x02 +#define DRM_OMAP_GEM_NEW 0x03 +#define DRM_OMAP_NUM_IOCTLS 0x04 +/**************************/ +/**************************/ +/**************************/ + + +struct omap_bo; +struct omap_device; + +/* device related functions: + */ + +struct omap_device * omap_device_new(int fd); +void omap_device_del(struct omap_device *dev); +int omap_get_param(struct omap_device *dev, uint64_t param, uint64_t *value); +int omap_set_param(struct omap_device *dev, uint64_t param, uint64_t value); + +/* buffer-object related functions: + */ + +struct omap_bo * omap_bo_new(struct omap_device *dev, + uint32_t size, uint32_t flags); +void omap_bo_del(struct omap_bo *bo); +uint32_t omap_bo_handle(struct omap_bo *bo); +uint32_t omap_bo_size(struct omap_bo *bo); +void * omap_bo_map(struct omap_bo *bo); + + +#endif /* OMAP_DRM_H_ */ diff --git a/src/omap_exa_common.c b/src/omap_exa_common.c new file mode 100644 index 0000000..13585e0 --- /dev/null +++ b/src/omap_exa_common.c @@ -0,0 +1,231 @@ +/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ + +/* + * Copyright © 2011 Texas Instruments, 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 (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: + * Rob Clark <rob@ti.com> + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "omap_exa_common.h" + +#include "exa.h" + + +#define pix2scrn(pPixmap) \ + xf86Screens[(pPixmap)->drawable.pScreen->myNum] + + +/* Common OMAP EXA functions, mostly related to pixmap/buffer allocation. + * Individual driver submodules can use these directly, or wrap them with + * there own functions if anything additional is required. Submodules + * can use OMAPPrixmapPrivPtr#priv for their own private data. + */ + +void * +OMAPCreatePixmap (ScreenPtr pScreen, int width, int height, + int depth, int usage_hint, int bitsPerPixel, + int *new_fb_pitch) +{ + OMAPPixmapPrivPtr priv = calloc(sizeof(OMAPPixmapPrivRec), 1); + + /* actual allocation of buffer is in OMAPModifyPixmapHeader */ + + return priv; +} + +void +OMAPDestroyPixmap(ScreenPtr pScreen, void *driverPriv) +{ + OMAPPixmapPrivPtr priv = driverPriv; + + if (priv->bo) { + omap_bo_del(priv->bo); + } + + free(priv); +} + +Bool +OMAPModifyPixmapHeader(PixmapPtr pPixmap, int width, int height, + int depth, int bitsPerPixel, int devKind, + pointer pPixData) +{ + OMAPPixmapPrivPtr priv = exaGetPixmapDriverPrivate(pPixmap); + ScrnInfoPtr pScrn = pix2scrn(pPixmap); + OMAPPtr pOMAP = OMAPPTR(pScrn); + uint32_t size; + Bool ret; + + ret = miModifyPixmapHeader(pPixmap, width, height, depth, + bitsPerPixel, devKind, pPixData); + if (!ret) { + return ret; + } + + if (pPixData == omap_bo_map(pOMAP->scanout)) { + DEBUG_MSG("wrapping scanout buffer"); + if (priv->bo != pOMAP->scanout) { + omap_bo_del(priv->bo); + priv->bo = pOMAP->scanout; + } + return TRUE; + } else if (pPixData) { + /* we can't accelerate this pixmap, and don't ever want to + * see it again.. + */ + pPixmap->devPrivate.ptr = pPixData; + pPixmap->devKind = devKind; + + /* scratch-pixmap (see GetScratchPixmapHeader()) gets recycled, + * so could have a previous bo! + */ + omap_bo_del(priv->bo); + priv->bo = NULL; + + return FALSE; + } + + /* passed in values could be zero, indicating that existing values + * should be kept.. miModifyPixmapHeader() will deal with that, but + * we need to resync to ensure we have the right values in the rest + * of this function + */ + width = pPixmap->drawable.width; + height = pPixmap->drawable.height; + depth = pPixmap->drawable.depth; + bitsPerPixel = pPixmap->drawable.bitsPerPixel; + + + pPixmap->devKind = OMAPCalculateStride(width, bitsPerPixel); + size = pPixmap->devKind * height; + + if ((!priv->bo) || (omap_bo_size(priv->bo) != size)) { + /* re-allocate buffer! */ + omap_bo_del(priv->bo); + priv->bo = omap_bo_new(pOMAP->dev, size, 0); + } + + return TRUE; +} + +/** + * WaitMarker is a required EXA callback but synchronization is + * performed during OMAPPrepareAccess so this function does not + * have anything to do at present + */ +void +OMAPWaitMarker(ScreenPtr pScreen, int marker) +{ + /* no-op */ +} + +/** + * PrepareAccess() is called before CPU access to an offscreen pixmap. + * + * @param pPix the pixmap being accessed + * @param index the index of the pixmap being accessed. + * + * PrepareAccess() will be called before CPU access to an offscreen pixmap. + * This can be used to set up hardware surfaces for byteswapping or + * untiling, or to adjust the pixmap's devPrivate.ptr for the purpose of + * making CPU access use a different aperture. + * + * The index is one of #EXA_PREPARE_DEST, #EXA_PREPARE_SRC, + * #EXA_PREPARE_MASK, #EXA_PREPARE_AUX_DEST, #EXA_PREPARE_AUX_SRC, or + * #EXA_PREPARE_AUX_MASK. Since only up to #EXA_NUM_PREPARE_INDICES pixmaps + * will have PrepareAccess() called on them per operation, drivers can have + * a small, statically-allocated space to maintain state for PrepareAccess() + * and FinishAccess() in. Note that PrepareAccess() is only called once per + * pixmap and operation, regardless of whether the pixmap is used as a + * destination and/or source, and the index may not reflect the usage. + * + * PrepareAccess() may fail. An example might be the case of hardware that + * can set up 1 or 2 surfaces for CPU access, but not 3. If PrepareAccess() + * fails, EXA will migrate the pixmap to system memory. + * DownloadFromScreen() must be implemented and must not fail if a driver + * wishes to fail in PrepareAccess(). PrepareAccess() must not fail when + * pPix is the visible screen, because the visible screen can not be + * migrated. + * + * @return TRUE if PrepareAccess() successfully prepared the pixmap for CPU + * drawing. + * @return FALSE if PrepareAccess() is unsuccessful and EXA should use + * DownloadFromScreen() to migate the pixmap out. + */ +Bool +OMAPPrepareAccess(PixmapPtr pPixmap, int index) +{ + OMAPPixmapPrivPtr priv = exaGetPixmapDriverPrivate(pPixmap); + + /* TODO: wait for blits complete on priv->bo.. */ + + pPixmap->devPrivate.ptr = omap_bo_map(priv->bo); + + return TRUE; +} + +/** + * FinishAccess() is called after CPU access to an offscreen pixmap. + * + * @param pPix the pixmap being accessed + * @param index the index of the pixmap being accessed. + * + * FinishAccess() will be called after finishing CPU access of an offscreen + * pixmap set up by PrepareAccess(). Note that the FinishAccess() will not be + * called if PrepareAccess() failed and the pixmap was migrated out. + */ +void +OMAPFinishAccess(PixmapPtr pPixmap, int index) +{ + pPixmap->devPrivate.ptr = NULL; +} + +/** + * PixmapIsOffscreen() is an optional driver replacement to + * exaPixmapHasGpuCopy(). Set to NULL if you want the standard behaviour + * of exaPixmapHasGpuCopy(). + * + * @param pPix the pixmap + * @return TRUE if the given drawable is in framebuffer memory. + * + * exaPixmapHasGpuCopy() is used to determine if a pixmap is in offscreen + * memory, meaning that acceleration could probably be done to it, and that it + * will need to be wrapped by PrepareAccess()/FinishAccess() when accessing it + * with the CPU. + */ +Bool +OMAPPixmapIsOffscreen(PixmapPtr pPixmap) +{ + /* offscreen means in 'gpu accessible memory', not that it's off the + * visible screen. We currently have no special constraints, since + * OMAP has a flat memory model (no separate GPU memory). If + * individual EXA implementation has additional constraints, like + * buffer size or mapping in GPU MMU, it should wrap this function. + */ + OMAPPixmapPrivPtr priv = exaGetPixmapDriverPrivate(pPixmap); + return priv && priv->bo; +} diff --git a/src/omap_exa_common.h b/src/omap_exa_common.h new file mode 100644 index 0000000..a1bd955 --- /dev/null +++ b/src/omap_exa_common.h @@ -0,0 +1,57 @@ +/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ + +/* + * Copyright © 2011 Texas Instruments, 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 (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: + * Rob Clark <rob@ti.com> + */ + +#ifndef OMAP_EXA_COMMON_H_ +#define OMAP_EXA_COMMON_H_ + +#include "omap_driver.h" + +/* Common OMAP EXA functions, mostly related to pixmap/buffer allocation. + * Individual driver submodules can use these directly, or wrap them with + * there own functions if anything additional is required. Submodules + * can use OMAPPrixmapPrivPtr#priv for their own private data. + */ + +typedef struct { + void *priv; /* EXA submodule private data */ + struct omap_bo *bo; +} OMAPPixmapPrivRec, *OMAPPixmapPrivPtr; + +void * OMAPCreatePixmap (ScreenPtr pScreen, int width, int height, + int depth, int usage_hint, int bitsPerPixel, + int *new_fb_pitch); +void OMAPDestroyPixmap(ScreenPtr pScreen, void *driverPriv); +Bool OMAPModifyPixmapHeader(PixmapPtr pPixmap, int width, int height, + int depth, int bitsPerPixel, int devKind, + pointer pPixData); +void OMAPWaitMarker(ScreenPtr pScreen, int marker); +Bool OMAPPrepareAccess(PixmapPtr pPix, int index); +void OMAPFinishAccess(PixmapPtr pPix, int index); +Bool OMAPPixmapIsOffscreen(PixmapPtr pPix); + +#endif /* OMAP_EXA_COMMON_H_ */ diff --git a/src/omap_exa_null.c b/src/omap_exa_null.c new file mode 100644 index 0000000..524045b --- /dev/null +++ b/src/omap_exa_null.c @@ -0,0 +1,153 @@ +/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ + +/* + * Copyright © 2011 Texas Instruments, 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 (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: + * Rob Clark <rob@ti.com> + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "omap_driver.h" +#include "omap_exa_common.h" + +#include "exa.h" + +/* This file has a trivial EXA implementation which accelerates nothing. It + * is used as the fall-back in case the EXA implementation for the current + * chipset is not available. (For example, on chipsets which used the closed + * source IMG PowerVR EXA implementation, if the closed-source submodule is + * not installed. + */ + +typedef struct { + OMAPEXARec base; + ExaDriverPtr exa; + /* add any other driver private data here.. */ +} OMAPNullEXARec, *OMAPNullEXAPtr; + + +static Bool +PrepareSolidFail(PixmapPtr pPixmap, int alu, Pixel planemask, Pixel fill_colour) +{ + return FALSE; +} + +static Bool +PrepareCopyFail(PixmapPtr pSrc, PixmapPtr pDst, int xdir, int ydir, + int alu, Pixel planemask) +{ + return FALSE; +} + +static Bool +CheckCompositeFail(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture, + PicturePtr pDstPicture) +{ + return FALSE; +} + +static Bool +PrepareCompositeFail(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture, + PicturePtr pDstPicture, PixmapPtr pSrc, PixmapPtr pMask, PixmapPtr pDst) +{ + return FALSE; +} + +static Bool +CloseScreen(int scrnIndex, ScreenPtr pScreen) +{ +#if 0 // TODO need to change CloseScreen/FreeScreen .. + exaDriverFini(pScreen); + free(pNv->EXADriverPtr); +#endif + return TRUE; +} + +static void +FreeScreen(int scrnIndex, int flags) +{ +} + + +OMAPEXAPtr +InitNullEXA(ScreenPtr pScreen, ScrnInfoPtr pScrn) +{ + OMAPNullEXAPtr null_exa = calloc(sizeof (*null_exa), 1); + OMAPEXAPtr omap_exa = (OMAPEXAPtr)null_exa; + ExaDriverPtr exa; + + INFO_MSG("Soft EXA mode"); + + exa = exaDriverAlloc(); + if (!exa) { + goto fail; + } + + null_exa->exa = exa; + + exa->exa_major = EXA_VERSION_MAJOR; + exa->exa_minor = EXA_VERSION_MINOR; + + exa->pixmapOffsetAlign = 0; + exa->pixmapPitchAlign = 32 * 4; // see OMAPCalculateStride() + exa->flags = EXA_OFFSCREEN_PIXMAPS | + EXA_HANDLES_PIXMAPS | EXA_SUPPORTS_PREPARE_AUX; + exa->maxX = 4096; + exa->maxY = 4096; + + /* Required EXA functions: */ + exa->WaitMarker = OMAPWaitMarker; + exa->CreatePixmap2 = OMAPCreatePixmap; + exa->DestroyPixmap = OMAPDestroyPixmap; + exa->ModifyPixmapHeader = OMAPModifyPixmapHeader; + + exa->PrepareAccess = OMAPPrepareAccess; + exa->FinishAccess = OMAPFinishAccess; + exa->PixmapIsOffscreen = OMAPPixmapIsOffscreen; + + // Always fallback for software operations + exa->PrepareCopy = PrepareCopyFail; + exa->PrepareSolid = PrepareSolidFail; + exa->CheckComposite = CheckCompositeFail; + exa->PrepareComposite = PrepareCompositeFail; + + if (! exaDriverInit(pScreen, exa)) { + ERROR_MSG("exaDriverInit failed"); + goto fail; + } + + omap_exa->CloseScreen = CloseScreen; + omap_exa->FreeScreen = FreeScreen; + + return omap_exa; + +fail: + if (null_exa) { + free(null_exa); + } + return NULL; +} + |