commit 085d5e28c8febf48bfa0c4a6471b69e929780ed9 Author: Rob Clark Date: Sat Mar 31 12:30:18 2012 -0500 Initial commit based on a stripped down xf86-video-msm.. the goal is to get something with just EXA and remove the unneeded bits (like xv and dri2) for now. They can be re-added later with removal of dependency on c2d2 if needed. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..87bc9d2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,25 @@ +.deps +.libs +Makefile +*.la +*.lo +*.o +*~ +aclocal.m4 +autom4te.cache +compile +config.h +config.h.in +config.log +config.status +depcomp +stamp-h1 +Makefile.in +configure +libtool +ltmain.sh +config.guess +config.sub +install-sh +missing + diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..16f4412 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,22 @@ +# 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. + +AUTOMAKE_OPTIONS = foreign +SUBDIRS = src diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..904cd67 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,12 @@ +#! /bin/sh + +srcdir=`dirname $0` +test -z "$srcdir" && srcdir=. + +ORIGDIR=`pwd` +cd $srcdir + +autoreconf -v --install || exit 1 +cd $ORIGDIR || exit $? + +$srcdir/configure --enable-maintainer-mode "$@" diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..f9bf4aa --- /dev/null +++ b/configure.ac @@ -0,0 +1,89 @@ +# 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. +# +# Process this file with autoconf to produce a configure script + +AC_PREREQ(2.57) +AC_INIT([xf86-video-freedreno], + 0.0.1, + [], + xf86-video-freedreno) + +AC_CONFIG_SRCDIR([Makefile.am]) +AM_CONFIG_HEADER([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 +AM_PROG_AS + +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) + +# Checks for pkg-config packages +PKG_CHECK_MODULES(XORG, [libdrm xorg-server xproto $REQUIRED_MODULES]) +sdkdir=$(pkg-config --variable=sdkdir xorg-server) +PKG_CHECK_MODULES(XEXT, [xextproto >= 7.0.99.1], +HAVE_XEXTPROTO_71="yes"; AC_DEFINE(HAVE_XEXTPROTO_71, 1, [xextproto 7.1 available]), +HAVE_XEXTPROTO_71="no") +AM_CONDITIONAL(HAVE_XEXTPROTO_71, [ test "$HAVE_XEXTPROTO_71" = "yes" ]) + +# Checks for libraries. + +# Checks for header files. +AC_HEADER_STDC + +AC_SUBST([XORG_CFLAGS]) +AC_SUBST([moduledir]) +AC_SUBST([CFLAGS]) +AC_SUBST([CCASFLAGS]) + +DRIVER_NAME=freedreno +AC_SUBST([DRIVER_NAME]) + +#XORG_MANPAGE_SECTIONS +XORG_RELEASE_VERSION + +AC_OUTPUT([ + Makefile + src/Makefile +]) diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..868ca28 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,20 @@ +freedreno_drv_la_LIBADD = + +AM_CFLAGS = @XORG_CFLAGS@ -Wall -Werror -I$(top_srcdir)/system-includes/ + +freedreno_drv_la_LTLIBRARIES = freedreno_drv.la +freedreno_drv_la_LDFLAGS = -module -avoid-version +freedreno_drv_ladir = @moduledir@/drivers + +freedreno_drv_la_SOURCES = \ + msm-drm.c \ + msm-driver.c \ + msm-exa.c \ + msm-output.c \ + msm-display.c \ + msm-cursor.c \ + msm-pixmap.c + +EXTRA_DIST = \ + msm.h \ + msm-drm.h diff --git a/src/msm-cursor.c b/src/msm-cursor.c new file mode 100644 index 0000000..f7dd8d1 --- /dev/null +++ b/src/msm-cursor.c @@ -0,0 +1,176 @@ +/* msm-cursor.c + * + * Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "xf86.h" +#include "xf86Crtc.h" +#include "xf86Cursor.h" + +#include +#include + +#include "msm.h" + +#define MSM_CURSOR_WIDTH 64 +#define MSM_CURSOR_HEIGHT 64 + +#ifdef MSMFB_CURSOR + +static void +_init_cursor(MSMPtr pMsm, struct fb_cursor *cursor) +{ + memset(cursor, 0, sizeof(*cursor)); + + /* This is a workaround for a buggy kernel */ + + cursor->image.width = MSM_CURSOR_WIDTH; + cursor->image.height = MSM_CURSOR_HEIGHT; + cursor->image.depth = 32; + + cursor->enable = pMsm->HWCursorState; +} + +void +MSMSetCursorPosition(MSMPtr pMsm, int x, int y) +{ + struct fb_cursor cursor; + + _init_cursor(pMsm, &cursor); + + if (x < 0) + x = 0; + + if (y < 0) + y = 0; + + cursor.set |= FB_CUR_SETPOS; + cursor.image.dx = x; + cursor.image.dy = y; + + if (ioctl(pMsm->fd, MSMFB_CURSOR, &cursor)) + ErrorF("%s: Error calling MSMBF_CURSOR\n", __FUNCTION__); +} + +void +MSMCursorEnable(MSMPtr pMsm, Bool enable) +{ + struct fb_cursor cursor; + + _init_cursor(pMsm, &cursor); + + pMsm->HWCursorState = cursor.enable = (enable == TRUE) ? 1 : 0; + + if (ioctl(pMsm->fd, MSMFB_CURSOR, &cursor)) + ErrorF("%s: Error calling MSMBF_CURSOR\n", __FUNCTION__); +} + +void +MSMCursorLoadARGB(MSMPtr pMsm, CARD32 * image) +{ + struct fb_cursor cursor; + + _init_cursor(pMsm, &cursor); + + cursor.set |= FB_CUR_SETIMAGE; + cursor.image.data = (char *)image; + + /* BLEND_TRANSP_EN off */ + cursor.image.bg_color = 0xFFFFFFFF; + + /* Per pixel alpha on */ + cursor.image.fg_color = 0; + + if (ioctl(pMsm->fd, MSMFB_CURSOR, &cursor)) + ErrorF("%s: Error calling MSMBF_CURSOR\n", __FUNCTION__); +} + +Bool +MSMCursorInit(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + + MSMPtr pMsm = MSMPTR(pScrn); + + struct fb_cursor cursor; + + _init_cursor(pMsm, &cursor); + + /* Try to turn off the cursor - if this fails then we don't have + * HW cursor support */ + + cursor.enable = 0; + + if (ioctl(pMsm->fd, MSMFB_CURSOR, &cursor)) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "Unable to enable the HW cursor: %s\n", strerror(errno)); + + return FALSE; + } + + /* HWCursor is on the air, but not visible (yet) */ + pMsm->HWCursorState = 0; + + return xf86_cursors_init(pScreen, MSM_CURSOR_WIDTH, MSM_CURSOR_HEIGHT, + HARDWARE_CURSOR_TRUECOLOR_AT_8BPP | + HARDWARE_CURSOR_INVERT_MASK | + HARDWARE_CURSOR_AND_SOURCE_WITH_MASK | + HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_32 | + HARDWARE_CURSOR_ARGB); +} + +#else + +/* if MSMFB_CURSOR isn't defined, then this is an older version of the kernel + that doesn't support it - so just provide some dummy stuff here */ + +void +MSMCrtcSetCursorPosition(MSMPtr pMsm, int x, int y) +{ +} + +void +MSMCursorEnable(MSMPtr pMsm, Bool enable) +{ +} + +void +MSMCursorLoadARGB(MSMPtr pMsm, CARD32 * image) +{ +} + +Bool +MSMCursorInit(ScreenPtr pScreen) +{ + return FALSE; +} + +#endif diff --git a/src/msm-display.c b/src/msm-display.c new file mode 100644 index 0000000..083b34e --- /dev/null +++ b/src/msm-display.c @@ -0,0 +1,254 @@ +/* msm-output.c +k * + * Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_XEXTPROTO_71 +#include +#else +#define DPMS_SERVER +#include +#endif + +#include +#include "xf86.h" +#include "xf86Crtc.h" +#include "xf86_OSlib.h" +#include "msm.h" +#include "msm-drm.h" + + +static void +MSMCrtcGammaSet(xf86CrtcPtr crtc, + CARD16 *red, CARD16 *green, CARD16 *blue, int size) +{ + /* This is a new function that gets called by the DI code */ + +} + +static void +MSMCrtcDPMS(xf86CrtcPtr crtc, int mode) +{ + /* TODO: Implement DPMS */ +} + +static Bool +MSMCrtcLock(xf86CrtcPtr crtc) +{ + return TRUE; +} + +static void +MSMCrtcUnlock(xf86CrtcPtr crtc) +{ +} + +static void +MSMCrtcPrepare(xf86CrtcPtr crtc) +{ + /* Blank the display before we change modes? */ +} + +static Bool +MSMCrtcModeFixup(xf86CrtcPtr crtc, DisplayModePtr mode, + DisplayModePtr adjmode) +{ + ScrnInfoPtr pScrn = crtc->scrn; + + MSMPtr pMsm = MSMPTR(pScrn); + + if (mode->HDisplay > pMsm->mode_info.xres_virtual || + mode->VDisplay > pMsm->mode_info.yres_virtual) + return FALSE; + + return TRUE; +} + +static void +MSMCrtcModeSet(xf86CrtcPtr crtc, DisplayModePtr mode, + DisplayModePtr adjmode, int x, int y) +{ + int ret; + ScrnInfoPtr pScrn = crtc->scrn; + MSMPtr pMsm = MSMPTR(pScrn); + struct fb_var_screeninfo var; + int htotal, vtotal; + + memcpy(&var, &pMsm->mode_info, sizeof(var)); + + htotal = var.xres + var.right_margin + var.hsync_len + var.left_margin; + + var.xres = adjmode->HDisplay; + var.right_margin = adjmode->HSyncStart - adjmode->HDisplay; + var.hsync_len = adjmode->HSyncEnd - adjmode->HSyncStart; + var.left_margin = adjmode->HTotal - adjmode->HSyncEnd; + + vtotal = var.yres + var.lower_margin + var.vsync_len + var.upper_margin; + + var.yres = adjmode->VDisplay; + var.lower_margin = adjmode->VSyncStart - adjmode->VDisplay; + var.vsync_len = adjmode->VSyncEnd - adjmode->VSyncStart; + var.upper_margin = adjmode->VTotal - adjmode->VSyncEnd; + + if (vtotal != adjmode->VTotal || htotal != adjmode->HTotal) + var.pixclock = pMsm->defaultVsync * adjmode->HTotal * adjmode->VTotal; + /*crtc->rotatedData!= NULL indicates that rotation has been requested + and shadow framebuffer has been allocated, so change the yoffset to make + the shadow framebuffer as visible screen. */ + var.yoffset = (crtc->rotatedData && crtc->rotation != 1) ? var.yres : 0; + + ret = ioctl(pMsm->fd, FBIOPUT_VSCREENINFO, &var); + + if (ret) + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Unable to change the mode: %m\n"); + else { + /* Refresh the changed settings from the driver */ + if (crtc->scrn->pScreen) + xf86_reload_cursors(crtc->scrn->pScreen); + ioctl(pMsm->fd, FBIOGET_VSCREENINFO, &pMsm->mode_info); + } +} + +static void +MSMCrtcCommit(xf86CrtcPtr crtc) +{ +} + +static void * +MSMCrtcShadowAllocate(xf86CrtcPtr crtc, int width, int height) +{ + ScrnInfoPtr pScrn = crtc->scrn; + MSMPtr pMsm = MSMPTR(pScrn); + /* (pMsm->fixed_info.line_length * pMsm->mode_info.yres) is the size of + original framebuufer. As buffer is already preallocated by kernel, so just + return the memory address after the end of original framebuffer as the + starting address of the shadow framebuffer.*/ + memset((char*)(pMsm->fbmem + pMsm->mode_info.yres * + pMsm->fixed_info.line_length), 0, pMsm->mode_info.yres * + pMsm->fixed_info.line_length ); + return (pMsm->fbmem + pMsm->mode_info.yres * pMsm->fixed_info.line_length); +} + +static PixmapPtr +MSMCrtcShadowCreate(xf86CrtcPtr crtc, void *data, int width, int height) +{ + ScrnInfoPtr pScrn = crtc->scrn; + PixmapPtr pNewPixmap = NULL; + MSMPtr pMsm = MSMPTR(pScrn); + if (!data) + data = MSMCrtcShadowAllocate(crtc, width, height); + /*The pitch, width and size of the rotated pixmap has to be the same as + those of the display framebuffer*/ + pNewPixmap = GetScratchPixmapHeader(pScrn->pScreen,pMsm->mode_info.xres, + pMsm->mode_info.yres,pScrn->depth, pScrn->bitsPerPixel, + pMsm->fixed_info.line_length, data); + if (!pNewPixmap) + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Unable to allocate shadow pixmap for rotation\n"); + pMsm->rotatedPixmap = pNewPixmap; + return pNewPixmap; +} + +static void +MSMCrtcShadowDestroy(xf86CrtcPtr crtc, PixmapPtr pPixmap, void *data) +{ + ScrnInfoPtr pScrn = crtc->scrn; + MSMPtr pMsm = MSMPTR(pScrn); + pMsm->rotatedPixmap = NULL; + if (pPixmap) + FreeScratchPixmapHeader(pPixmap); +} + +static void +MSMCrtcSetCursorPosition(xf86CrtcPtr crtc, int x, int y) +{ + ScrnInfoPtr pScrn = crtc->scrn; + + MSMPtr pMsm = MSMPTR(pScrn); + + MSMSetCursorPosition(pMsm, x, y); +} + +static void +MSMCrtcShowCursor(xf86CrtcPtr crtc) +{ + ScrnInfoPtr pScrn = crtc->scrn; + + MSMPtr pMsm = MSMPTR(pScrn); + + MSMCursorEnable(pMsm, TRUE); +} + +static void +MSMCrtcHideCursor(xf86CrtcPtr crtc) +{ + ScrnInfoPtr pScrn = crtc->scrn; + + MSMPtr pMsm = MSMPTR(pScrn); + + MSMCursorEnable(pMsm, FALSE); +} + +static void +MSMCrtcLoadCursorARGB(xf86CrtcPtr crtc, CARD32 * image) +{ + ScrnInfoPtr pScrn = crtc->scrn; + + MSMPtr pMsm = MSMPTR(pScrn); + + MSMCursorLoadARGB(pMsm, image); +} + +static const xf86CrtcFuncsRec MSMCrtcFuncs = { + .dpms = MSMCrtcDPMS, + .lock = MSMCrtcLock, + .unlock = MSMCrtcUnlock, + .mode_fixup = MSMCrtcModeFixup, + .prepare = MSMCrtcPrepare, + .mode_set = MSMCrtcModeSet, + .commit = MSMCrtcCommit, + .shadow_create = MSMCrtcShadowCreate, + .shadow_allocate = MSMCrtcShadowAllocate, + .shadow_destroy = MSMCrtcShadowDestroy, + .set_cursor_position = MSMCrtcSetCursorPosition, + .show_cursor = MSMCrtcShowCursor, + .hide_cursor = MSMCrtcHideCursor, + .load_cursor_argb = MSMCrtcLoadCursorARGB, + .gamma_set = MSMCrtcGammaSet, + .destroy = NULL, /* XXX */ +}; + +void +MSMCrtcSetup(ScrnInfoPtr pScrn) +{ + xf86CrtcPtr crtc = xf86CrtcCreate(pScrn, &MSMCrtcFuncs); + crtc->driver_private = NULL; +} diff --git a/src/msm-driver.c b/src/msm-driver.c new file mode 100644 index 0000000..a224157 --- /dev/null +++ b/src/msm-driver.c @@ -0,0 +1,1062 @@ +/* msm-driver.c + * + * Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include + +#include "xf86.h" +#include "damage.h" +#include "xf86_OSlib.h" +#include "xf86Crtc.h" + +#include "mipointer.h" +#include "mibstore.h" +#include "micmap.h" +#include "fb.h" +#include "dixstruct.h" + +#include "msm.h" +#include "msm-drm.h" + +#include +#include "xf86drm.h" + +#define MSM_NAME "freedreno" +#define MSM_DRIVER_NAME "freedreno" + +#define MSM_VERSION_MAJOR PACKAGE_VERSION_MAJOR +#define MSM_VERSION_MINOR PACKAGE_VERSION_MINOR +#define MSM_VERSION_PATCH PACKAGE_VERSION_PATCHLEVEL + +#define MSM_VERSION_CURRENT \ + ((MSM_VERSION_MAJOR << 20) |\ + (MSM_VERSION_MINOR << 10) | \ + (MSM_VERSION_PATCH)) + +/* List of available strings for fbCache support */ + + +static const char *fbCacheStrings[] = { +#ifdef MSMFB_GET_PAGE_PROTECTION + [MDP_FB_PAGE_PROTECTION_NONCACHED] = "Noncached", + [MDP_FB_PAGE_PROTECTION_WRITECOMBINE] = "WriteCombine", + [MDP_FB_PAGE_PROTECTION_WRITETHROUGHCACHE] = "WriteThroughCache", + [MDP_FB_PAGE_PROTECTION_WRITEBACKCACHE] = "WriteBackCache", + [MDP_FB_PAGE_PROTECTION_WRITEBACKWACACHE] = "WriteBackWACache", +#endif + NULL +}; + +/* An aray containing the options that the user can + configure in xorg.conf + */ + +static const OptionInfoRec MSMOptions[] = { + {OPTION_FB, "fb", OPTV_STRING, {0}, FALSE}, + {OPTION_NOACCEL, "NoAccel", OPTV_BOOLEAN, {0}, FALSE}, + {OPTION_SWCURSOR, "SWCursor", OPTV_BOOLEAN, {0}, FALSE}, + {OPTION_VSYNC, "DefaultVsync", OPTV_INTEGER, {0}, FALSE}, + {OPTION_FBCACHE, "FBCache", OPTV_STRING, {0}, FALSE}, + {OPTION_PIXMAP_MEMTYPE, "PixmapMemtype", OPTV_STRING, {0}, FALSE}, + {OPTION_PAGEFLIP, "PageFlip", OPTV_BOOLEAN, {0}, FALSE}, + {OPTION_DRIMEMTYPE, "DRIMemtype", OPTV_STRING, {0}, FALSE }, + {OPTION_DEBUG, "Debug", OPTV_BOOLEAN, {0}, FALSE}, + {-1, NULL, OPTV_NONE, {0}, FALSE} +}; + +// TODO make this a config option +Bool msmDebug = TRUE; + +static Bool +MSMInitDRM(ScrnInfoPtr pScrn) +{ + MSMPtr pMsm = MSMPTR(pScrn); int i, fd; + drmVersionPtr version; + drmSetVersion sv; + int ret; + + /* Ugly, huh? */ + + pMsm->drmFD = 0; + pMsm->drmDevName[0] = '\0'; + + for(i = 0; i < DRM_MAX_MINOR; i++) { + int ret = -1; + + snprintf(pMsm->drmDevName, sizeof(pMsm->drmDevName), + DRM_DEV_NAME, DRM_DIR_NAME, i); + fd = open(pMsm->drmDevName, O_RDWR); + if (fd < 0) + continue; + + version = drmGetVersion(fd); + if (version) + ret = strcmp(version->name, "kgsl"); + + drmFreeVersion(version); + + if (!ret) + break; + + close(fd); + } + + if (i ==DRM_MAX_MINOR) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Unable to open a DRM device\n"); + close(fd); + return FALSE; + } + + + sv.drm_di_major = 1; + sv.drm_di_minor = 1; + sv.drm_dd_major = -1; + sv.drm_dd_minor = -1; + + ret = drmSetInterfaceVersion(fd, &sv); + if (ret != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Unable to set the DRM version: %d\n", ret); + close(fd); + return FALSE; + } + + pMsm->drmFD = fd; + return TRUE; +} + +/* Get the current mode from the framebuffer mode and + * convert it into xfree86 timings + */ + +static void +MSMGetDefaultMode(MSMPtr pMsm) +{ + char name[32]; + sprintf(name, "%dx%d", pMsm->mode_info.xres, pMsm->mode_info.yres); + + pMsm->default_mode.name = strdup(name); + + if (pMsm->default_mode.name == NULL) + pMsm->default_mode.name = ""; + + pMsm->default_mode.next = &pMsm->default_mode; + pMsm->default_mode.prev = &pMsm->default_mode; + pMsm->default_mode.type |= M_T_BUILTIN | M_T_PREFERRED; + + pMsm->default_mode.HDisplay = pMsm->mode_info.xres; + pMsm->default_mode.HSyncStart = + pMsm->default_mode.HDisplay + pMsm->mode_info.right_margin; + pMsm->default_mode.HSyncEnd = + pMsm->default_mode.HSyncStart + pMsm->mode_info.hsync_len; + pMsm->default_mode.HTotal = + pMsm->default_mode.HSyncEnd + pMsm->mode_info.left_margin; + + pMsm->default_mode.VDisplay = pMsm->mode_info.yres; + pMsm->default_mode.VSyncStart = + pMsm->default_mode.VDisplay + pMsm->mode_info.lower_margin; + pMsm->default_mode.VSyncEnd = + pMsm->default_mode.VSyncStart + pMsm->mode_info.vsync_len; + pMsm->default_mode.VTotal = + pMsm->default_mode.VSyncEnd + pMsm->mode_info.upper_margin; + + /* The clock number we get is not the actual pixclock for the display, + * which automagically updates at a fixed rate. There is no good way + * to automatically figure out the fixed rate, so we use a config + * value */ + + pMsm->default_mode.Clock = (pMsm->defaultVsync * + pMsm->default_mode.HTotal * + pMsm->default_mode.VTotal) / 1000; + + pMsm->default_mode.CrtcHDisplay = pMsm->default_mode.HDisplay; + pMsm->default_mode.CrtcHSyncStart = pMsm->default_mode.HSyncStart; + pMsm->default_mode.CrtcHSyncEnd = pMsm->default_mode.HSyncEnd; + pMsm->default_mode.CrtcHTotal = pMsm->default_mode.HTotal; + + pMsm->default_mode.CrtcVDisplay = pMsm->default_mode.VDisplay; + pMsm->default_mode.CrtcVSyncStart = pMsm->default_mode.VSyncStart; + pMsm->default_mode.CrtcVSyncEnd = pMsm->default_mode.VSyncEnd; + pMsm->default_mode.CrtcVTotal = pMsm->default_mode.VTotal; + + pMsm->default_mode.CrtcHAdjusted = FALSE; + pMsm->default_mode.CrtcVAdjusted = FALSE; +} + +static Bool +MSMCrtcResize(ScrnInfoPtr pScrn, int width, int height) +{ + MSMPtr pMsm = MSMPTR(pScrn); + int oldx = pScrn->virtualX; + int oldy = pScrn->virtualY; + ScreenPtr screen = screenInfo.screens[pScrn->scrnIndex]; + if (oldx == width && oldy == height) + return TRUE; + pScrn->virtualX = width; + pScrn->virtualY = height; + pScrn->displayWidth = width; + (*screen->ModifyPixmapHeader)((*screen->GetScreenPixmap)(screen), + width, height, pScrn->depth, pScrn->bitsPerPixel, pScrn->displayWidth + * (pScrn->bitsPerPixel / 8), NULL); + pMsm->isFBSurfaceStale = TRUE; + return TRUE; +} + +static const xf86CrtcConfigFuncsRec MSMCrtcConfigFuncs = { + MSMCrtcResize, +}; + +/* A simple case-insenstive string comparison function. */ + +static int stricmp(const char *left, const char *right) +{ + const int MAXSTRINGLEN = 100; + char leftCopy[MAXSTRINGLEN], + rightCopy[MAXSTRINGLEN]; + int i; + + // Make temporary copies of comparison strings. + strncpy(leftCopy,left, MAXSTRINGLEN); + strncpy(rightCopy,right, MAXSTRINGLEN); + + // Convert English upper-case characters to lower-case. + i = 0; + while (leftCopy[i] != '\0') + { + if (leftCopy[i] >= 'A' && leftCopy[i] <= 'Z') + leftCopy[i] += 'a' - 'A'; + i++; + } + i = 0; + while (rightCopy[i] != '\0') + { + if (rightCopy[i] >= 'A' && rightCopy[i] <= 'Z') + rightCopy[i] += 'a' - 'A'; + i++; + } + + return strcmp(leftCopy, rightCopy); +} + +/* This is the main initialization function for the screen */ + +static Bool +MSMPreInit(ScrnInfoPtr pScrn, int flags) +{ + MSMPtr pMsm; + EntityInfoPtr pEnt; + char *dev, *str; + int mdpver, panelid; + int depth, fbbpp; + rgb defaultWeight = { 0, 0, 0 }; + int vsync; + + DEBUG_MSG("pre-init"); + + /* Omit ourselves from auto-probing (which is bound to + * fail on our hardware anyway) + */ + + if (flags & PROBE_DETECT) { + DEBUG_MSG("probe not supported"); + return FALSE; + } + + if (pScrn->numEntities != 1) { + DEBUG_MSG("numEntities=%d", pScrn->numEntities); + return FALSE; + } + + /* Just use the current monitor specified in the + * xorg.conf. This really means little to us since + * we have no choice over which monitor is used, + * but X needs this to be set + */ + + pScrn->monitor = pScrn->confScreen->monitor; + + /* Allocate room for our private data */ + if (pScrn->driverPrivate == NULL) + pScrn->driverPrivate = xnfcalloc(sizeof(MSMRec), 1); + + pMsm = MSMPTR(pScrn); + + if (pMsm == NULL) { + ERROR_MSG("Unable to allocate memory"); + return FALSE; + } + + pEnt = xf86GetEntityInfo(pScrn->entityList[0]); + + /* Open the FB device specified by the user */ + dev = xf86FindOptionValue(pEnt->device->options, "fb"); + + pMsm->fd = open(dev, O_RDWR, 0); + + if (pMsm->fd < 0) { + ERROR_MSG("Opening '%s' failed: %s", dev, strerror(errno)); + free(pMsm); + return FALSE; + } + + /* Unblank the screen if it was previously blanked */ + ioctl(pMsm->fd, FBIOBLANK, FB_BLANK_UNBLANK); + + /* Make sure the software refresher is on */ + ioctl(pMsm->fd, MSMFB_RESUME_SW_REFRESHER, 0); + + /* Get the fixed info (par) structure */ + + if (ioctl(pMsm->fd, FBIOGET_FSCREENINFO, &pMsm->fixed_info)) { + ERROR_MSG("Unable to read hardware info from %s: %s", + dev, strerror(errno)); + free(pMsm); + return FALSE; + } + + /* Parse the ID and figure out what version of the MDP and what + * panel ID we have - default to the MDP3 */ + + pMsm->chipID = MSM_MDP_VERSION_31; + + if (sscanf(pMsm->fixed_info.id, "msmfb%d_%x", &mdpver, &panelid) < 2) { + WARNING_MSG("Unable to determine the MDP version - assume 3.1"); + } + else { + switch (mdpver) { + case 22: + pMsm->chipID = MSM_MDP_VERSION_22; + break; + case 31: + pMsm->chipID = MSM_MDP_VERSION_31; + break; + case 40: + pMsm->chipID = MSM_MDP_VERSION_40; + break; + default: + WARNING_MSG("Unable to determine the MDP version - assume 3.1"); + break; + } + } + + /* FIXME: If we want to parse the panel type, it happens here */ + + /* Setup memory */ + + /* FIXME: This is where we will be in close communication with + * the fbdev driver to allocate memory. In the mean time, we + * just reuse the framebuffer memory */ + + pScrn->videoRam = pMsm->fixed_info.smem_len; + + /* Get the current screen setting */ + if (ioctl(pMsm->fd, FBIOGET_VSCREENINFO, &pMsm->mode_info)) { + ERROR_MSG("Unable to read the current mode from %s: %s", + dev, strerror(errno)); + + free(pMsm); + return FALSE; + } + + switch(pMsm->mode_info.bits_per_pixel) { + case 16: + depth = 16; + fbbpp = 16; + break; + case 24: + case 32: + depth = 24; + fbbpp = 32; + break; + default: + ERROR_MSG("The driver can only support 16bpp and 24bpp output"); + free(pMsm); + return FALSE; + } + + if (!xf86SetDepthBpp(pScrn, depth, 0, fbbpp, + Support24bppFb | Support32bppFb | + SupportConvert32to24 | SupportConvert24to32)) { + ERROR_MSG("Unable to set bitdepth"); + free(pMsm); + return FALSE; + } + + /* Set the color information in the mode structure to be set when the + screen initializes. This might seem like a redundant step, but + at least on the 8650A, the default color setting is RGBA, not ARGB, + so setting the color information here insures that the framebuffer + mode is what we expect */ + + switch(pScrn->depth) { + case 16: + pMsm->mode_info.bits_per_pixel = 16; + pMsm->mode_info.red.offset = 11; + pMsm->mode_info.green.offset = 5; + pMsm->mode_info.blue.offset = 0; + pMsm->mode_info.red.length = 5; + pMsm->mode_info.green.length = 6; + pMsm->mode_info.blue.length = 5; + pMsm->mode_info.red.msb_right = 0; + pMsm->mode_info.green.msb_right = 0; + pMsm->mode_info.blue.msb_right = 0; + pMsm->mode_info.transp.offset = 0; + pMsm->mode_info.transp.length = 0; + break; + case 24: + case 32: + pMsm->mode_info.bits_per_pixel = 32; + pMsm->mode_info.red.offset = 16; + pMsm->mode_info.green.offset = 8; + pMsm->mode_info.blue.offset = 0; + pMsm->mode_info.blue.length = 8; + pMsm->mode_info.green.length = 8; + pMsm->mode_info.red.length = 8; + pMsm->mode_info.blue.msb_right = 0; + pMsm->mode_info.green.msb_right = 0; + pMsm->mode_info.red.msb_right = 0; + pMsm->mode_info.transp.offset = 24; + pMsm->mode_info.transp.length = 8; + break; + default: + ERROR_MSG("The driver can only support 16bpp and 24bpp output"); + free(pMsm); + return FALSE; + } + + xf86PrintDepthBpp(pScrn); + pScrn->rgbBits = 8; + + if (!xf86SetWeight(pScrn, defaultWeight, defaultWeight)) { + free(pMsm); + return FALSE; + } + + /* Initialize default visual */ + if (!xf86SetDefaultVisual(pScrn, -1)) { + free(pMsm); + return FALSE; + } + + { + Gamma zeros = { 0.0, 0.0, 0.0 }; + + if (!xf86SetGamma(pScrn, zeros)) { + free(pMsm); + return FALSE; + } + } + + pScrn->progClock = TRUE; + pScrn->chipset = MSM_DRIVER_NAME; + + INFO_MSG("MSM/Qualcomm processor (video memory: %dkB)", pScrn->videoRam / 1024); + + xf86CollectOptions(pScrn, NULL); + + pMsm->options = malloc(sizeof(MSMOptions)); + + if (pMsm->options == NULL) { + free(pMsm); + return FALSE; + } + + memcpy(pMsm->options, MSMOptions, sizeof(MSMOptions)); + + xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, pMsm->options); + + /* Determine if the user wants debug messages turned on: */ + msmDebug = xf86ReturnOptValBool(pMsm->options, OPTION_DEBUG, FALSE); + + /* SWCursor - default FALSE */ + pMsm->HWCursor = !xf86ReturnOptValBool(pMsm->options, OPTION_SWCURSOR, FALSE); + + /* DefaultVsync - default 60 */ + pMsm->defaultVsync = 60; + + if (xf86GetOptValInteger(pMsm->options, OPTION_VSYNC, &vsync)) { + if (vsync > 0 && vsync < 120) + pMsm->defaultVsync = vsync; + } + + /* FBCache - default WriteThroughCache */ + pMsm->FBCache = MDP_FB_PAGE_PROTECTION_WRITETHROUGHCACHE; + + str = xf86GetOptValString(pMsm->options, OPTION_FBCACHE); + + if (str) { + int i; + + for(i = 0; fbCacheStrings[i] != NULL; i++) { + if (!stricmp(str, fbCacheStrings[i])) { + pMsm->FBCache = i; + break; + } + } + + if (fbCacheStrings[i] == NULL) + ERROR_MSG("Invalid FBCache '%s'", str); + } + + /* PixmapMemtype - default KMEM */ + pMsm->pixmapMemtype = MSM_DRM_MEMTYPE_KMEM; + + str = xf86GetOptValString(pMsm->options, OPTION_PIXMAP_MEMTYPE); + + if (str) { + /* No for loop here because the memory types are masks, not indexes */ + + if (!stricmp(str, "KMEM")) + pMsm->pixmapMemtype = MSM_DRM_MEMTYPE_KMEM; + else if (!stricmp(str, "UncachedKMEM")) + pMsm->pixmapMemtype = MSM_DRM_MEMTYPE_KMEM_NOCACHE; + else if (!stricmp(str, "EBI")) + pMsm->pixmapMemtype = MSM_DRM_MEMTYPE_EBI; + else if (!stricmp(str, "SMI")) + pMsm->pixmapMemtype = MSM_DRM_MEMTYPE_SMI; + else + ERROR_MSG("Invalid pixmap memory type %s", str); + } + + /* DRI Memtype - default EBI */ + pMsm->DRIMemtype = MSM_DRM_MEMTYPE_EBI; + + str = xf86GetOptValString(pMsm->options, OPTION_DRIMEMTYPE); + + if (str) { + /* No for loop here because the memory types are masks, not indexes */ + + if (!stricmp(str, "EBI")) + pMsm->DRIMemtype = MSM_DRM_MEMTYPE_EBI; + else if (!stricmp(str, "SMI")) + pMsm->DRIMemtype = MSM_DRM_MEMTYPE_SMI; + else + ERROR_MSG("Invalid DRI memory type %s", str); + } + + if (!MSMInitDRM(pScrn)) { + ERROR_MSG("Unable to open DRM"); + return FALSE; + } + + /* Set up the virtual size */ + + pScrn->virtualX = pScrn->display->virtualX > pMsm->mode_info.xres ? + pScrn->display->virtualX : pMsm->mode_info.xres; + + pScrn->virtualY = pScrn->display->virtualY > pMsm->mode_info.yres ? + pScrn->display->virtualY : pMsm->mode_info.yres; + + if (pScrn->virtualX > pMsm->mode_info.xres_virtual) + pScrn->virtualX = pMsm->mode_info.xres_virtual; + + if (pScrn->virtualY > pMsm->mode_info.yres_virtual) + pScrn->virtualY = pMsm->mode_info.yres_virtual; + + /* displayWidth is the width of the line in pixels */ + + /* The framebuffer driver should always report the line length, + * but in case it doesn't, we can calculate it ourselves */ + + if (pMsm->fixed_info.line_length) { + pScrn->displayWidth = pMsm->fixed_info.line_length; + } else { + pScrn->displayWidth = pMsm->mode_info.xres_virtual * + pMsm->mode_info.bits_per_pixel / 8; + } + + pScrn->displayWidth /= (pScrn->bitsPerPixel / 8); + + /* Set up the view port */ + pScrn->frameX0 = 0; + pScrn->frameY0 = 0; + pScrn->frameX1 = pMsm->mode_info.xres; + pScrn->frameY1 = pMsm->mode_info.yres; + + MSMGetDefaultMode(pMsm); + + /* Make a copy of the mode - this is important, because some + * where in the RandR setup, these modes get deleted */ + + pScrn->modes = xf86DuplicateMode(&pMsm->default_mode); + pScrn->currentMode = pScrn->modes; + + /* Set up the colors - this is from fbdevhw, which implies + * that it is important for TrueColor and DirectColor modes + */ + + pScrn->offset.red = pMsm->mode_info.red.offset; + pScrn->offset.green = pMsm->mode_info.green.offset; + pScrn->offset.blue = pMsm->mode_info.blue.offset; + + pScrn->mask.red = ((1 << pMsm->mode_info.red.length) - 1) + << pMsm->mode_info.red.offset; + + pScrn->mask.green = ((1 << pMsm->mode_info.green.length) - 1) + << pMsm->mode_info.green.offset; + + pScrn->mask.blue = ((1 << pMsm->mode_info.blue.length) - 1) + << pMsm->mode_info.blue.offset; + + xf86CrtcConfigInit(pScrn, &MSMCrtcConfigFuncs); + MSMCrtcSetup(pScrn); + + xf86CrtcSetSizeRange(pScrn,200,200,2048,2048); + + /* Setup the output */ + MSMOutputSetup(pScrn); + + if (!xf86InitialConfiguration(pScrn, FALSE)) { + ERROR_MSG("configuration failed"); + free(pMsm); + return FALSE; + } + + xf86PrintModes(pScrn); + + /* FIXME: We will probably need to be more exact when setting + * the DPI. For now, we just use the default (96,96 I think) */ + + xf86SetDpi(pScrn, 0, 0); + + INFO_MSG("MSM Options:"); + INFO_MSG(" HW Cursor: %s", pMsm->HWCursor ? "Enabled" : "Disabled"); + INFO_MSG(" Default Vsync: %d", pMsm->defaultVsync); + INFO_MSG(" FBCache: %s", fbCacheStrings[pMsm->FBCache]); + + // TODO table of mem type names + switch(pMsm->pixmapMemtype) { + case MSM_DRM_MEMTYPE_KMEM: + INFO_MSG(" Pixmap: KMEM"); + break; + case MSM_DRM_MEMTYPE_KMEM_NOCACHE: + INFO_MSG(" Pixmap: Uncached KMEM"); + break; + case MSM_DRM_MEMTYPE_EBI: + INFO_MSG(" Pixmap: EBI"); + break; + case MSM_DRM_MEMTYPE_SMI: + INFO_MSG(" Pixmap: SMI"); + break; + } + + return TRUE; +} + +static Bool +MSMSaveScreen(ScreenPtr pScreen, int mode) +{ + /* Nothing to do here, yet */ + return TRUE; +} + +static Bool +MSMCloseScreen(int scrnIndex, ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + + MSMPtr pMsm = MSMPTR(pScrn); + + DEBUG_MSG("close screen"); + + /* Close EXA */ + if (pMsm->pExa) { + exaDriverFini(pScreen); + free(pMsm->pExa); + pMsm->pExa = NULL; + } + + /* Unmap the framebuffer memory */ + munmap(pMsm->fbmem, pMsm->fixed_info.smem_len); + + pScreen->CloseScreen = pMsm->CloseScreen; + + return (*pScreen->CloseScreen) (scrnIndex, pScreen); +} + +static Bool +MSMScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + + MSMPtr pMsm = MSMPTR(pScrn); + + DEBUG_MSG("screen-init"); + +#if 0 +#if defined (MSMFB_GET_PAGE_PROTECTION) && defined (MSMFB_SET_PAGE_PROTECTION) + /* If the frame buffer can be cached, do so. */ + /* CAUTION: This needs to be done *BEFORE* the mmap() call, or it has no effect. */ + /* FIXME: The current page protection should ideally be saved here and restored */ + /* when exiting the driver, but there may be little point in doing this */ + /* since the XServer typically won't exit for most applications. */ + { + const int desired_fb_page_protection = pMsm->FBCache; + struct mdp_page_protection fb_page_protection; + + // If the kernel supports the FB Caching settings infrastructure, + // then set the frame buffer cache settings. + // Otherwise, issue a warning and continue. + if (ioctl(pMsm->fd, MSMFB_GET_PAGE_PROTECTION, &fb_page_protection)) { + xf86DrvMsg(scrnIndex, X_WARNING, + "MSMFB_GET_PAGE_PROTECTION IOCTL: Unable to get current FB cache settings.\n"); + } + else { + if (fb_page_protection.page_protection != desired_fb_page_protection) { + fb_page_protection.page_protection = desired_fb_page_protection; + if (ioctl(pMsm->fd, MSMFB_SET_PAGE_PROTECTION, &fb_page_protection)) { + xf86DrvMsg(scrnIndex, X_WARNING, + "MSMFB_SET_PAGE_PROTECTION IOCTL: Unable to set requested FB cache settings: %s.\n", + fbCacheStrings[desired_fb_page_protection]); + } + } + } + } +#endif // defined (MSMFB_GET_PAGE_PROTECTION) && defined (MSMFB_SET_PAGE_PROTECTION) +#endif + + /* Map the framebuffer memory */ + pMsm->fbmem = mmap(NULL, pMsm->fixed_info.smem_len, + PROT_READ | PROT_WRITE, MAP_SHARED, pMsm->fd, 0); + + /* If we can't map the memory, then this is a short trip */ + + if (pMsm->fbmem == MAP_FAILED) { + ERROR_MSG("Unable to map the framebuffer memory: %s", strerror(errno)); + return FALSE; + } + + pMsm->curVisiblePtr = pMsm->fbmem; + + /* Make a buffer object for the framebuffer so that the GPU MMU + * can use it + */ + pMsm->fbBo = msm_drm_bo_create_fb(pMsm, pMsm->drmFD, pMsm->fd, + pMsm->fixed_info.smem_len); + + /* Set up the mode - this doesn't actually touch the hardware, + * but it makes RandR all happy */ + + if (!xf86SetDesiredModes(pScrn)) { + ERROR_MSG("Unable to set the mode"); + return FALSE; + } + + /* Set up the X visuals */ + miClearVisualTypes(); + + /* We only support TrueColor at the moment, and I suspect that is all + * we will ever support */ + + if (!miSetVisualTypes(pScrn->depth, TrueColorMask, + pScrn->rgbBits, TrueColor)) { + ERROR_MSG("Unable to set up the visual for %d BPP", pScrn->bitsPerPixel); + return FALSE; + } + + if (!miSetPixmapDepths()) { + ERROR_MSG("Unable to set the pixmap depth"); + return FALSE; + } + + /* Set up the X drawing area */ + + xf86LoadSubModule(pScrn, "fb"); + + if (!fbScreenInit(pScreen, pMsm->fbmem, + pScrn->virtualX, pScrn->virtualY, + pScrn->xDpi, pScrn->yDpi, + pScrn->displayWidth, pScrn->bitsPerPixel)) { + ERROR_MSG("fbScreenInit failed"); + return FALSE; + } + + /* Set up the color information for the visual(s) */ + + if (pScrn->bitsPerPixel > 8) { + VisualPtr 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; + } + } + } + + /* Set up the Render fallbacks */ + if (!fbPictureInit(pScreen, NULL, 0)) { + ERROR_MSG("fbPictureInit failed"); + return FALSE; + } + + /* Set default colors */ + xf86SetBlackWhitePixels(pScreen); + + /* Set up the backing store */ + miInitializeBackingStore(pScreen); + xf86SetBackingStore(pScreen); + + /* Set up EXA */ + xf86LoadSubModule(pScrn, "exa"); + + if (!MSMSetupExa(pScreen)) + ERROR_MSG("Unable to setup EXA"); + + /* Set up the software cursor */ + miDCInitialize(pScreen, xf86GetPointerScreenFuncs()); + + /* Try to set up the HW cursor */ + + if (pMsm->HWCursor == TRUE) + pMsm->HWCursor = MSMCursorInit(pScreen); + + /* Set up the default colormap */ + + if (!miCreateDefColormap(pScreen)) { + ERROR_MSG("miCreateDefColormap failed"); + return FALSE; + } + + /* FIXME: Set up DPMS here */ + + pScreen->SaveScreen = MSMSaveScreen; + + /*Set up our own CloseScreen function */ + + pMsm->CloseScreen = pScreen->CloseScreen; + pScreen->CloseScreen = MSMCloseScreen; + + if (!xf86CrtcScreenInit(pScreen)) { + ERROR_MSG("CRTCScreenInit failed"); + return FALSE; + } + + return TRUE; +} + +static Bool +MSMSwitchMode(int scrnIndex, DisplayModePtr mode, int flags) +{ + /* FIXME: We should only have the one mode, so we shouldn't ever call + * this function - regardless, it needs to be stubbed - so what + * do we return, TRUE or FALSE? */ + + return TRUE; +} + +static Bool +MSMEnterVT(int ScrnIndex, int flags) +{ + /* Nothing to do here yet - there might be some triggers that we need + * to throw at the framebuffer */ + return TRUE; +} + +static void +MSMLeaveVT(int ScrnIndex, int flags) +{ +} + +/* ------------------------------------------------------------ */ +/* Following is the standard driver setup that probes for the */ +/* hardware and sets up the structures. */ + +static const OptionInfoRec * +MSMAvailableOptions(int chipid, int busid) +{ + return MSMOptions; +} + +static void +MSMIdentify(int flags) +{ + xf86Msg(X_INFO, "%s: Video driver for Qualcomm processors\n", MSM_NAME); +} + +static Bool +MSMProbe(DriverPtr drv, int flags) +{ + GDevPtr *sections; + int nsects; + char *dev; + + Bool foundScreen = FALSE; + + ScrnInfoPtr pScrn = NULL; + + int fd, i; + + /* For now, just return false during a probe */ + + if (flags & PROBE_DETECT) { + ErrorF("probe not supported\n"); + return FALSE; + } + + /* Find all of the device sections in the config */ + + nsects = xf86MatchDevice(MSM_NAME, §ions); + if (nsects <= 0) { + ErrorF("nsects=%d\n", nsects); + return FALSE; + } + + /* We know that we will only have at most 4 possible outputs */ + + for (i = 0; i < (nsects > 4 ? 4 : nsects); i++) { + + dev = xf86FindOptionValue(sections[i]->options, "fb"); + + xf86Msg(X_WARNING, "Section %d - looking for %s\n", i, dev); + + /* FIXME: There should be some discussion about how we + * refer to devices - blindly matching to /dev/fbX files + * seems like it could backfire on us. For now, force + * the user to set the backing FB in the xorg.conf */ + + if (dev == NULL) { + xf86Msg(X_WARNING, "no device specified in section %d\n", i); + continue; + } + + fd = open(dev, O_RDWR, 0); + + if (fd <= 0) { + xf86Msg(X_WARNING, "Could not open '%s': %s\n", + dev, strerror(errno)); + continue; + } else { + struct fb_fix_screeninfo info; + + int entity; + + if (ioctl(fd, FBIOGET_FSCREENINFO, &info)) { + xf86Msg(X_WARNING, + "Unable to read hardware info " + "from %s: %s\n", dev, strerror(errno)); + close(fd); + continue; + } + + close(fd); + + /* Make sure that this is a MSM driver */ + if (strncmp(info.id, "msmfb", 5)) { + xf86Msg(X_WARNING, "%s is not a MSM device: %s\n", dev, info.id); + continue; + } + + foundScreen = TRUE; + + entity = xf86ClaimFbSlot(drv, 0, sections[i], TRUE); + pScrn = xf86ConfigFbEntity(NULL, 0, entity, NULL, NULL, NULL, NULL); + + xf86Msg(X_WARNING, "Add screen %p\n", pScrn); + + /* Set up the hooks for the screen */ + + pScrn->driverVersion = MSM_VERSION_CURRENT; + pScrn->driverName = MSM_NAME; + pScrn->name = MSM_NAME; + pScrn->Probe = MSMProbe; + pScrn->PreInit = MSMPreInit; + pScrn->ScreenInit = MSMScreenInit; + pScrn->SwitchMode = MSMSwitchMode; + pScrn->EnterVT = MSMEnterVT; + pScrn->LeaveVT = MSMLeaveVT; + } + } + + free(sections); + return foundScreen; +} + +_X_EXPORT DriverRec freedrenoDriver = { + MSM_VERSION_CURRENT, + MSM_DRIVER_NAME, + MSMIdentify, + MSMProbe, + MSMAvailableOptions, + NULL, + 0, + NULL +}; + +MODULESETUPPROTO(freedrenoSetup); + +/* Versioning information for the module - most of these variables will + come from config.h generated by ./configure + */ + +static XF86ModuleVersionInfo freedrenoVersRec = { + MSM_DRIVER_NAME, + MODULEVENDORSTRING, + MODINFOSTRING1, + MODINFOSTRING2, + XORG_VERSION_CURRENT, + MSM_VERSION_MAJOR, MSM_VERSION_MINOR, MSM_VERSION_PATCH, + ABI_CLASS_VIDEODRV, + ABI_VIDEODRV_VERSION, + NULL, + {0, 0, 0, 0}, +}; + +_X_EXPORT XF86ModuleData freedrenoModuleData = { &freedrenoVersRec, freedrenoSetup, NULL }; + +pointer +freedrenoSetup(pointer module, pointer ops, int *errmaj, int *errmin) +{ + static Bool initDone = FALSE; + + if (initDone == FALSE) { + initDone = TRUE; + xf86AddDriver(&freedrenoDriver, module, HaveDriverFuncs); + + /* FIXME: Load symbol references here */ + return (pointer) 1; + } else { + if (errmaj) + *errmaj = LDR_ONCEONLY; + return NULL; + } +} diff --git a/src/msm-drm.c b/src/msm-drm.c new file mode 100644 index 0000000..579e58f --- /dev/null +++ b/src/msm-drm.c @@ -0,0 +1,532 @@ +/* msm-drm.c + * + * Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include + +#include +#include + +#include "msm.h" +#include "msm-drm.h" + +static int drm_version; + +static int +msm_drm_get_version(int fd) +{ + struct drm_version version; + memset(&version, 0, sizeof(version)); + + if (ioctl(fd, DRM_IOCTL_VERSION, &version)) { + ErrorF("%s: Unable to get the DRM version\n", __FUNCTION__); + return -1; + } + + drm_version = (version.version_major << 16); + drm_version |= version.version_minor & 0xFFFF; + + return 0; +} + +int +msm_drm_bo_set_memtype(struct msm_drm_bo *bo, int type) +{ + static int ebionly = 0; + int ret; + struct drm_kgsl_gem_memtype mtype; + + if (bo == NULL || bo->handle == 0) + return -1; + + /* Only fail the ioctl() once - the other times just quietly + * force the mode to EBI - see below */ + + if (ebionly) { + bo->memtype = DRM_KGSL_GEM_TYPE_EBI; + return 0; + } + + switch(type) { + case MSM_DRM_MEMTYPE_KMEM: + bo->memtype = DRM_KGSL_GEM_TYPE_KMEM; + break; + case MSM_DRM_MEMTYPE_EBI: + bo->memtype = DRM_KGSL_GEM_TYPE_EBI; + break; + case MSM_DRM_MEMTYPE_SMI: + bo->memtype = DRM_KGSL_GEM_TYPE_SMI; + break; + case MSM_DRM_MEMTYPE_KMEM_NOCACHE: + bo->memtype = DRM_KGSL_GEM_TYPE_KMEM_NOCACHE; + break; + default: + return -1; + } + + memset(&mtype, 0, sizeof(mtype)); + mtype.handle = bo->handle; + mtype.type = bo->memtype; + + ret = ioctl(bo->fd, DRM_IOCTL_KGSL_GEM_SETMEMTYPE, &mtype); + + if (ret) { + /* If the ioctl() isn't supported, then the legacy behavior + * is to put everything is in EBI */ + + if (errno == EINVAL) { + ErrorF("DRM: DRM_IOCTL_KGSL_GEM_SETMEMTYPE is not supported.\n"); + ErrorF(" All offscreen memory will be in EBI\n"); + + bo->memtype = DRM_KGSL_GEM_TYPE_EBI; + + /* Set a flag so we don't come in here and fail for every + * allocation */ + + ebionly = 1; + return 0; + } + } + + return ret; +} + +int +msm_drm_bo_get_memtype(struct msm_drm_bo *bo) +{ + struct drm_kgsl_gem_memtype mtype; + int ret; + + if (bo == NULL || bo->handle == 0) + return -1; + + if (bo->memtype < 0) { + memset(&mtype, 0, sizeof(mtype)); + mtype.handle = bo->handle; + + ret = ioctl(bo->fd, DRM_IOCTL_KGSL_GEM_SETMEMTYPE, &mtype); + + if (ret) + return ret; + } + + switch(bo->memtype) { + case DRM_KGSL_GEM_TYPE_KMEM: + return MSM_DRM_MEMTYPE_KMEM; + case DRM_KGSL_GEM_TYPE_KMEM_NOCACHE: + return MSM_DRM_MEMTYPE_KMEM_NOCACHE; + case DRM_KGSL_GEM_TYPE_EBI: + return MSM_DRM_MEMTYPE_EBI; + case DRM_KGSL_GEM_TYPE_SMI: + return MSM_DRM_MEMTYPE_SMI; + } + + return -1; +} + +void +_msm_drm_bo_free(struct msm_drm_bo *bo) +{ + struct drm_gem_close close; + + if (bo == NULL || bo->handle == 0) + return; + + if (bo->hostptr) + munmap((void *) bo->hostptr, bo->size * bo->count); + + memset(&close, 0, sizeof(close)); + close.handle = bo->handle; + ioctl(bo->fd, DRM_IOCTL_GEM_CLOSE, &close); + + free(bo); +} + +struct msm_drm_bo * +msm_drm_bo_create(MSMPtr pMsm, int fd, int size, int type) +{ + struct drm_kgsl_gem_create create; + struct msm_drm_bo *bo; + int ret; + + size = (size + (getpagesize() - 1)) & ~(getpagesize() - 1); + + if (size == 0) + return NULL; + + /* We only cache the default pixmap type */ + if (pMsm->cachedBo && type == pMsm->pixmapMemtype) { + if (pMsm->cachedBo->size == size) { + bo = pMsm->cachedBo; + pMsm->cachedBo = NULL; + return bo; + } + + _msm_drm_bo_free(pMsm->cachedBo); + pMsm->cachedBo = NULL; + } + + memset(&create, 0, sizeof(create)); + create.size = size; + + ret = ioctl(fd, DRM_IOCTL_KGSL_GEM_CREATE, &create); + + if (ret) + return NULL; + + bo = calloc(1, sizeof(*bo)); + + if (bo == NULL) + return NULL; + + bo->size = size; + bo->handle = create.handle; + bo->fd = fd; + bo->active = 0; + bo->count = 1; + + /* All memory defaults to EBI */ + bo->memtype = DRM_KGSL_GEM_TYPE_EBI; + + if (msm_drm_bo_set_memtype(bo, type)) { + ErrorF("Unable to set the memory type\n"); + _msm_drm_bo_free(bo); + return NULL; + } + + return bo; +} + +int +msm_drm_bo_flink(struct msm_drm_bo *bo, unsigned int *name) +{ + struct drm_gem_flink flink; + int ret; + + memset(&flink, 0, sizeof(flink)); + + if (bo == NULL) + return -1; + + flink.handle = bo->handle; + ret = ioctl(bo->fd, DRM_IOCTL_GEM_FLINK, &flink); + + if (ret) + return -1; + + bo->name = flink.name; + + if (name) + *name = flink.name; + + return 0; +} + +int +msm_drm_bo_alloc(struct msm_drm_bo *bo) +{ + struct drm_kgsl_gem_alloc alloc; + int ret; + + if (bo == NULL) + return -1; + + /* If the offset is set, then assume it has been allocated */ + if (bo->offset != 0) + return 0; + + memset(&alloc, 0, sizeof(alloc)); + alloc.handle = bo->handle; + + ret = ioctl(bo->fd, DRM_IOCTL_KGSL_GEM_ALLOC, &alloc); + + if (ret) { + /* if the ioctl isn't supported, then use the legacy PREP ioctl */ + + if (errno == EINVAL) { + struct drm_kgsl_gem_prep prep; + + ErrorF("DRM: DRM_IOCTL_KGSL_GEM_ALLOC is not supported.\n"); + + memset(&prep, 0, sizeof(prep)); + prep.handle = bo->handle; + ret = ioctl(bo->fd, DRM_IOCTL_KGSL_GEM_PREP, &prep); + + if (ret) + return -1; + + bo->offset = prep.offset; + bo->gpuaddr[0] = prep.phys; + + return 0; + } + + return ret; + } + + bo->offset = alloc.offset; + return 0; +} + +int +msm_drm_bo_bind_gpu(struct msm_drm_bo *bo) +{ + struct drm_kgsl_gem_bind_gpu bind; + int ret; + + if (bo->gpuaddr[0]) + return 0; + + if (bo == NULL) + return -1; + + bind.handle = bo->handle; + + ret = ioctl(bo->fd, DRM_IOCTL_KGSL_GEM_BIND_GPU, &bind); + + if (ret) + return ret; + + bo->gpuaddr[0] = bind.gpuptr; + + /* If the ioctls are in place, then get the buffer info to get the GPU + addresses directly */ + +#ifdef DRM_IOCTL_KGSL_GEM_GET_BUFINFO + { + int i; + struct drm_kgsl_gem_bufinfo bufinfo; + bufinfo.handle = bo->handle; + + ret = ioctl(bo->fd, DRM_IOCTL_KGSL_GEM_GET_BUFINFO, &bufinfo); + + for(i = 0; !ret && i < bufinfo.count; i++) + bo->gpuaddr[i] = bufinfo.gpuaddr[i]; + } +#endif + + return 0; +} + +int +msm_drm_bo_map(struct msm_drm_bo *bo) +{ + int ret, i; + unsigned int mapsize; + + if (bo == NULL) + return -1; + + /* Already mapped */ + + if (bo->hostptr != NULL) + return 0; + + if (!bo->offset) { + ret = msm_drm_bo_alloc(bo); + + if (ret) { + ErrorF("DRM: Unable to allocate: %m\n"); + return ret; + } + } + + mapsize = bo->size; + bo->offsets[0] = 0; + +#ifdef DRM_IOCTL_KGSL_GEM_GET_BUFINFO + { + struct drm_kgsl_gem_bufinfo bufinfo; + bufinfo.handle = bo->handle; + + ret = ioctl(bo->fd, DRM_IOCTL_KGSL_GEM_GET_BUFINFO, &bufinfo); + + if (ret == 0) { + for(i = 0; i < bufinfo.count; i++) { + bo->offsets[i] = bufinfo.offset[i]; + bo->gpuaddr[i] = bufinfo.gpuaddr[i]; + } + + bo->count = bufinfo.count; + bo->active = bufinfo.active; + + mapsize = bo->size * bo->count; + } + } +#endif + + bo->hostptr = mmap(0, mapsize, PROT_READ | PROT_WRITE, MAP_SHARED, + bo->fd, bo->offset); + + if (bo->hostptr == MAP_FAILED) { + ErrorF("DRM: Unable to map: %m\n"); + return -1; + } + + for(i = 0; i < bo->count; i++) + bo->virtaddr[i] = (void *) bo->hostptr + bo->offsets[i]; + + return 0; +} + +void +msm_drm_bo_unmap(struct msm_drm_bo *bo) +{ + if (bo == NULL) + return; + + /* For the moment, always leave buffers mapped */ + +#if 0 + if (bo->hostptr) + munmap((void *) bo->hostptr, bo->size); + + bo->hostptr = 0; +#endif +} + +void +msm_drm_bo_free(MSMPtr pMsm, struct msm_drm_bo *bo) +{ + if (bo == NULL || bo->handle == 0) + return; + + if (bo->memtype == pMsm->pixmapMemtype && + bo->count == 1 && + bo->name == 0) { + if (pMsm->cachedBo) + _msm_drm_bo_free(pMsm->cachedBo); + pMsm->cachedBo = bo; + } + else + _msm_drm_bo_free(bo); +} + +/* Set the next buffer in the list as active */ + +#ifdef DRM_IOCTL_KGSL_GEM_SET_ACTIVE + +int msm_drm_bo_swap_buffers(struct msm_drm_bo *bo) +{ + struct drm_kgsl_gem_active active; + int ret = 0; + + if (drm_version < 0x00020001) + return -1; + + active.active = bo->active + 1; + + if (active.active == bo->count) + active.active = 0; + + active.handle = bo->handle; + + ret= ioctl(bo->fd, DRM_IOCTL_KGSL_GEM_SET_ACTIVE, &active); + + if (!ret) + bo->active = active.active; + + return ret; +} +#else +int msm_drm_bo_swap_buffers(struct msm_drm_bo *bo) +{ + return -1; +} +#endif + +#ifdef DRM_IOCTL_KGSL_GEM_SET_BUFCOUNT +int msm_drm_bo_set_bufcount(struct msm_drm_bo *bo, int count) +{ + struct drm_kgsl_gem_bufcount bcount; + int ret; + + if (drm_version < 0x00020001) + return -1; + + bcount.bufcount = count; + bcount.handle = bo->handle; + + ret = ioctl(bo->fd, DRM_IOCTL_KGSL_GEM_SET_BUFCOUNT, &bcount); + + if (!ret) + bo->count = count; + + return ret; +} + +#endif + +int msm_drm_bo_support_swap(int fd) +{ + if (!drm_version) + msm_drm_get_version(fd); + + return (drm_version >= 0x00020001) ? 1 : 0; +} + +/* Create a buffer object for the framebuffer */ + +struct msm_drm_bo * +msm_drm_bo_create_fb(MSMPtr pMsm, int drmfd, int fbfd, int size) +{ + struct drm_kgsl_gem_create_fd createfd; + struct msm_drm_bo *bo; + int ret; + + memset(&createfd, 0, sizeof(createfd)); + createfd.fd = fbfd; + + ret = ioctl(drmfd, DRM_IOCTL_KGSL_GEM_CREATE_FD, &createfd); + + if (ret) + return NULL; + + bo = calloc(1, sizeof(*bo)); + + if (bo == NULL) + return NULL; + + bo->size = size; + bo->handle = createfd.handle; + bo->fd =drmfd; + bo->active = 0; + bo->count = 1; + + bo->memtype = DRM_KGSL_GEM_TYPE_FD_FBMEM; + + return bo; +} diff --git a/src/msm-drm.h b/src/msm-drm.h new file mode 100644 index 0000000..b9bb96b --- /dev/null +++ b/src/msm-drm.h @@ -0,0 +1,75 @@ +/* msm-drm.h + * + * Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef MSM_DRM_H_ +#define MSM_DRM_H_ + +#include +#include + +#define MSM_DRM_MEMTYPE_EBI 0 +#define MSM_DRM_MEMTYPE_SMI 1 +#define MSM_DRM_MEMTYPE_KMEM 2 +#define MSM_DRM_MEMTYPE_KMEM_NOCACHE 3 + +struct msm_drm_bo { + int fd; + unsigned int name; + int memtype; + unsigned int size; + unsigned int handle; + int count; + void *hostptr; + void *virtaddr[3]; + unsigned int offsets[3]; + unsigned int gpuaddr[3]; + int ref; + int active; + unsigned long long offset; +}; + +int msm_drm_init(int fd); +struct msm_drm_bo *msm_drm_bo_create(MSMPtr pMsm, int fd, int size, int type); +int msm_drm_bo_flink(struct msm_drm_bo *bo, unsigned int *name); +void msm_drm_bo_free(MSMPtr pMsm, struct msm_drm_bo *bo); +void msm_drm_bo_unmap(struct msm_drm_bo *bo); +int msm_drm_bo_map(struct msm_drm_bo *bo); +int msm_drm_bo_bind_gpu(struct msm_drm_bo *bo); +int msm_drm_bo_alloc(struct msm_drm_bo *bo); +int msm_drm_bo_set_memtype(struct msm_drm_bo *bo, int type); +int msm_drm_bo_get_memtype(struct msm_drm_bo *bo); + + +int msm_drm_bo_set_bufcount(struct msm_drm_bo *bo, int count); +int msm_drm_bo_swap_buffers(struct msm_drm_bo *bo); + +int msm_drm_bo_support_swap(int fd); +struct msm_drm_bo *msm_drm_bo_create_fb(MSMPtr pMsm, int drmfd, int fbfd, + int size); +#endif diff --git a/src/msm-exa.c b/src/msm-exa.c new file mode 100644 index 0000000..d00fd78 --- /dev/null +++ b/src/msm-exa.c @@ -0,0 +1,689 @@ +/* msm-exa.c + * + * Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "xf86.h" +#include "exa.h" + +#include "msm.h" +#include "msm-drm.h" + +#define xFixedtoDouble(_f) (double) ((_f)/(double) xFixed1) + +#define ENABLE_EXA_TRACE 1 +#define ENABLE_SW_FALLBACK_REPORTS 1 + +#define SCREEN(pDraw) \ + ScrnInfoPtr pScrn = xf86Screens[((DrawablePtr)(pDraw))->pScreen->myNum]; + +#define TRACE_EXA(fmt, ...) do { \ + if (ENABLE_EXA_TRACE) \ + DEBUG_MSG(fmt, ##__VA_ARGS__); \ + } while (0) + +#define EXA_FAIL_IF(cond) do { \ + if (cond) { \ + if (ENABLE_SW_FALLBACK_REPORTS) { \ + DEBUG_MSG("fallback: " #cond); \ + } \ + return FALSE; \ + } \ + } while (0) + + +#if 0 +/* Get the length of the vector represented by (x,y) */ +static inline double +vector_length(double x, double y) +{ + return sqrt((x*x) + (y*y)); +} + +static inline void +vector_normalize(double *x, double *y) +{ + double len = vector_length(*x, *y); + if (len != 0.0) { + *x /= len; + *y /= len; + } +} + +static void +transform_get_translate(PictTransform *t, double *x, double *y) +{ + double scale = xFixedtoDouble(t->matrix[2][2]); + + if (scale == 0) + return; + + *x = xFixedtoDouble(t->matrix[0][2]) / scale; + *y = xFixedtoDouble(t->matrix[1][2]) / scale; +} + +static void +transform_get_scale(PictTransform *t, double *xscale, double *yscale) +{ + double scale = xFixedtoDouble(t->matrix[2][2]); + double xs, ys; + + if (scale == 0) + return; + + xs = (vector_length(xFixedtoDouble(t->matrix[0][0]) / scale, + xFixedtoDouble(t->matrix[0][1]) / scale)); + + ys = (vector_length(xFixedtoDouble(t->matrix[1][0]) / scale, + xFixedtoDouble(t->matrix[1][1]) / scale)); + + /* The returned value is the inverse of what we calculate, because + the matrix is mapping the transformed surface back to the source + surface */ + + if (xs) + xs = 1/xs; + + if (ys) + ys = 1/ys; + + *xscale = xs; + *yscale = ys; +} + +static void +transform_get_rotate(PictTransform *t, double *d) +{ + double row[2][2]; + double ret; + double scale = xFixedtoDouble(t->matrix[2][2]); + + if (scale == 0) + return; + + row[0][0] = xFixedtoDouble(t->matrix[0][0]) / scale; + row[0][1] = xFixedtoDouble(t->matrix[0][1]) / scale; + row[1][0] = xFixedtoDouble(t->matrix[1][0]) / scale; + row[1][1] = xFixedtoDouble(t->matrix[1][1]) / scale; + + vector_normalize(&row[0][0], &row[0][1]); + vector_normalize(&row[1][0], &row[1][1]); + + ret = atan2(row[0][1], row[0][0]) - atan2(0, 1); + + *d = ret >= 0 ? ret : (2 * M_PI) + ret; +} +#endif + +/** + * PrepareSolid() sets up the driver for doing a solid fill. + * @param pPixmap Destination pixmap + * @param alu raster operation + * @param planemask write mask for the fill + * @param fg "foreground" color for the fill + * + * This call should set up the driver for doing a series of solid fills + * through the Solid() call. The alu raster op is one of the GX* + * graphics functions listed in X.h, and typically maps to a similar + * single-byte "ROP" setting in all hardware. The planemask controls + * which bits of the destination should be affected, and will only represent + * the bits up to the depth of pPixmap. The fg is the pixel value of the + * foreground color referred to in ROP descriptions. + * + * Note that many drivers will need to store some of the data in the driver + * private record, for sending to the hardware with each drawing command. + * + * The PrepareSolid() call is required of all drivers, but it may fail for any + * reason. Failure results in a fallback to software rendering. + */ +static Bool +MSMPrepareSolid(PixmapPtr pPixmap, int alu, Pixel planemask, Pixel fg) +{ + SCREEN(pPixmap); + + TRACE_EXA("%p <- alu=%x, planemask=%08x, fg=%08x", + pPixmap, alu, (unsigned int)planemask, (unsigned int)fg); + + EXA_FAIL_IF(planemask != FB_ALLONES); + EXA_FAIL_IF(alu != GXcopy); + + EXA_FAIL_IF(TRUE); + + return TRUE; +} + +/** + * Solid() performs a solid fill set up in the last PrepareSolid() call. + * + * @param pPixmap destination pixmap + * @param x1 left coordinate + * @param y1 top coordinate + * @param x2 right coordinate + * @param y2 bottom coordinate + * + * Performs the fill set up by the last PrepareSolid() call, covering the + * area from (x1,y1) to (x2,y2) in pPixmap. Note that the coordinates are + * in the coordinate space of the destination pixmap, so the driver will + * need to set up the hardware's offset and pitch for the destination + * coordinates according to the pixmap's offset and pitch within + * framebuffer. This likely means using exaGetPixmapOffset() and + * exaGetPixmapPitch(). + * + * This call is required if PrepareSolid() ever succeeds. + */ +static void +MSMSolid(PixmapPtr pPixmap, int x1, int y1, int x2, int y2) +{ + SCREEN(pPixmap); + TRACE_EXA("x1=%d\ty1=%d\tx2=%d\ty2=%d", x1, y1, x2, y2); +} + +/** + * DoneSolid() finishes a set of solid fills. + * + * @param pPixmap destination pixmap. + * + * The DoneSolid() call is called at the end of a series of consecutive + * Solid() calls following a successful PrepareSolid(). This allows drivers + * to finish up emitting drawing commands that were buffered, or clean up + * state from PrepareSolid(). + * + * This call is required if PrepareSolid() ever succeeds. + */ +static void +MSMDoneSolid(PixmapPtr pPixmap) +{ + +} + +/** + * PrepareCopy() sets up the driver for doing a copy within video + * memory. + * + * @param pSrcPixmap source pixmap + * @param pDstPixmap destination pixmap + * @param dx X copy direction + * @param dy Y copy direction + * @param alu raster operation + * @param planemask write mask for the fill + * + * This call should set up the driver for doing a series of copies from the + * the pSrcPixmap to the pDstPixmap. The dx flag will be positive if the + * hardware should do the copy from the left to the right, and dy will be + * positive if the copy should be done from the top to the bottom. This + * is to deal with self-overlapping copies when pSrcPixmap == pDstPixmap. + * If your hardware can only support blits that are (left to right, top to + * bottom) or (right to left, bottom to top), then you should set + * #EXA_TWO_BITBLT_DIRECTIONS, and EXA will break down Copy operations to + * ones that meet those requirements. The alu raster op is one of the GX* + * graphics functions listed in X.h, and typically maps to a similar + * single-byte "ROP" setting in all hardware. The planemask controls which + * bits of the destination should be affected, and will only represent the + * bits up to the depth of pPixmap. + * + * Note that many drivers will need to store some of the data in the driver + * private record, for sending to the hardware with each drawing command. + * + * The PrepareCopy() call is required of all drivers, but it may fail for any + * reason. Failure results in a fallback to software rendering. + */ +static Bool +MSMPrepareCopy(PixmapPtr pSrcPixmap, PixmapPtr pDstPixmap, int dx, int dy, + int alu, Pixel planemask) +{ + SCREEN(pDstPixmap); + + TRACE_EXA("%p <- %p", pDstPixmap, pSrcPixmap); + + EXA_FAIL_IF(planemask != FB_ALLONES); + EXA_FAIL_IF(alu != GXcopy); + + EXA_FAIL_IF(TRUE); + + return TRUE; +} + +/** + * Copy() performs a copy set up in the last PrepareCopy call. + * + * @param pDstPixmap destination pixmap + * @param srcX source X coordinate + * @param srcY source Y coordinate + * @param dstX destination X coordinate + * @param dstY destination Y coordinate + * @param width width of the rectangle to be copied + * @param height height of the rectangle to be copied. + * + * Performs the copy set up by the last PrepareCopy() call, copying the + * rectangle from (srcX, srcY) to (srcX + width, srcY + width) in the source + * pixmap to the same-sized rectangle at (dstX, dstY) in the destination + * pixmap. Those rectangles may overlap in memory, if + * pSrcPixmap == pDstPixmap. Note that this call does not receive the + * pSrcPixmap as an argument -- if it's needed in this function, it should + * be stored in the driver private during PrepareCopy(). As with Solid(), + * the coordinates are in the coordinate space of each pixmap, so the driver + * will need to set up source and destination pitches and offsets from those + * pixmaps, probably using exaGetPixmapOffset() and exaGetPixmapPitch(). + * + * This call is required if PrepareCopy ever succeeds. + */ +static void +MSMCopy(PixmapPtr pDstPixmap, int srcX, int srcY, int dstX, int dstY, + int width, int height) +{ + SCREEN(pDstPixmap); + + TRACE_EXA("srcX=%d\tsrcY=%d\tdstX=%d\tdstY=%d\twidth=%d\theight=%d", + srcX, srcY, dstX, dstY, width, height); +} + +/** + * DoneCopy() finishes a set of copies. + * + * @param pPixmap destination pixmap. + * + * The DoneCopy() call is called at the end of a series of consecutive + * Copy() calls following a successful PrepareCopy(). This allows drivers + * to finish up emitting drawing commands that were buffered, or clean up + * state from PrepareCopy(). + * + * This call is required if PrepareCopy() ever succeeds. + */ +static void +MSMDoneCopy(PixmapPtr pDstPixmap) +{ + +} + +/** + * CheckComposite() checks to see if a composite operation could be + * accelerated. + * + * @param op Render operation + * @param pSrcPicture source Picture + * @param pMaskPicture mask picture + * @param pDstPicture destination Picture + * + * The CheckComposite() call checks if the driver could handle acceleration + * of op with the given source, mask, and destination pictures. This allows + * drivers to check source and destination formats, supported operations, + * transformations, and component alpha state, and send operations it can't + * support to software rendering early on. This avoids costly pixmap + * migration to the wrong places when the driver can't accelerate + * operations. Note that because migration hasn't happened, the driver + * can't know during CheckComposite() what the offsets and pitches of the + * pixmaps are going to be. + * + * See PrepareComposite() for more details on likely issues that drivers + * will have in accelerating Composite operations. + * + * The CheckComposite() call is recommended if PrepareComposite() is + * implemented, but is not required. + */ +static Bool +MSMCheckComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture, + PicturePtr pDstPicture) +{ + SCREEN(pDstPicture->pDrawable); + TRACE_EXA("%p <- %p (%p)", pDstPicture, pSrcPicture, pMaskPicture); + EXA_FAIL_IF(TRUE); + return TRUE; +} + +/** + * PrepareComposite() sets up the driver for doing a Composite operation + * described in the Render extension protocol spec. + * + * @param op Render operation + * @param pSrcPicture source Picture + * @param pMaskPicture mask picture + * @param pDstPicture destination Picture + * @param pSrc source pixmap + * @param pMask mask pixmap + * @param pDst destination pixmap + * + * This call should set up the driver for doing a series of Composite + * operations, as described in the Render protocol spec, with the given + * pSrcPicture, pMaskPicture, and pDstPicture. The pSrc, pMask, and + * pDst are the pixmaps containing the pixel data, and should be used for + * setting the offset and pitch used for the coordinate spaces for each of + * the Pictures. + * + * Notes on interpreting Picture structures: + * - The Picture structures will always have a valid pDrawable. + * - The Picture structures will never have alphaMap set. + * - The mask Picture (and therefore pMask) may be NULL, in which case the + * operation is simply src OP dst instead of src IN mask OP dst, and + * mask coordinates should be ignored. + * - pMarkPicture may have componentAlpha set, which greatly changes + * the behavior of the Composite operation. componentAlpha has no effect + * when set on pSrcPicture or pDstPicture. + * - The source and mask Pictures may have a transformation set + * (Picture->transform != NULL), which means that the source coordinates + * should be transformed by that transformation, resulting in scaling, + * rotation, etc. The PictureTransformPoint() call can transform + * coordinates for you. Transforms have no effect on Pictures when used + * as a destination. + * - The source and mask pictures may have a filter set. PictFilterNearest + * and PictFilterBilinear are defined in the Render protocol, but others + * may be encountered, and must be handled correctly (usually by + * PrepareComposite failing, and falling back to software). Filters have + * no effect on Pictures when used as a destination. + * - The source and mask Pictures may have repeating set, which must be + * respected. Many chipsets will be unable to support repeating on + * pixmaps that have a width or height that is not a power of two. + * + * If your hardware can't support source pictures (textures) with + * non-power-of-two pitches, you should set #EXA_OFFSCREEN_ALIGN_POT. + * + * Note that many drivers will need to store some of the data in the driver + * private record, for sending to the hardware with each drawing command. + * + * The PrepareComposite() call is not required. However, it is highly + * recommended for performance of antialiased font rendering and performance + * of cairo applications. Failure results in a fallback to software + * rendering. + */ +static Bool +MSMPrepareComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture, + PicturePtr pDstPicture, PixmapPtr pSrc, PixmapPtr pMask, PixmapPtr pDst) +{ + SCREEN(pDst); + TRACE_EXA("%p <- %p (%p)", pDst, pSrc, pMask); + EXA_FAIL_IF(TRUE); + return TRUE; +} + +/** + * Composite() performs a Composite operation set up in the last + * PrepareComposite() call. + * + * @param pDstPixmap destination pixmap + * @param srcX source X coordinate + * @param srcY source Y coordinate + * @param maskX source X coordinate + * @param maskY source Y coordinate + * @param dstX destination X coordinate + * @param dstY destination Y coordinate + * @param width destination rectangle width + * @param height destination rectangle height + * + * Performs the Composite operation set up by the last PrepareComposite() + * call, to the rectangle from (dstX, dstY) to (dstX + width, dstY + height) + * in the destination Pixmap. Note that if a transformation was set on + * the source or mask Pictures, the source rectangles may not be the same + * size as the destination rectangles and filtering. Getting the coordinate + * transformation right at the subpixel level can be tricky, and rendercheck + * can test this for you. + * + * This call is required if PrepareComposite() ever succeeds. + */ +static void +MSMComposite(PixmapPtr pDst, int srcX, int srcY, int maskX, int maskY, + int dstX, int dstY, int width, int height) +{ + SCREEN(pDst); + TRACE_EXA("srcX=%d\tsrcY=%d\tmaskX=%d\tmaskY=%d\tdstX=%d\tdstY=%d\twidth=%d\theight=%d", + srcX, srcY, maskX, maskY, dstX, dstY, width, height); +} + +/** + * DoneComposite() finishes a set of Composite operations. + * + * @param pPixmap destination pixmap. + * + * The DoneComposite() call is called at the end of a series of consecutive + * Composite() calls following a successful PrepareComposite(). This allows + * drivers to finish up emitting drawing commands that were buffered, or + * clean up state from PrepareComposite(). + * + * This call is required if PrepareComposite() ever succeeds. + */ +static void +MSMDoneComposite(PixmapPtr pDst) +{ + +} + +/** + * MarkSync() requests that the driver mark a synchronization point, + * returning an driver-defined integer marker which could be requested for + * synchronization to later in WaitMarker(). This might be used in the + * future to avoid waiting for full hardware stalls before accessing pixmap + * data with the CPU, but is not important in the current incarnation of + * EXA. + * + * Note that drivers should call exaMarkSync() when they have done some + * acceleration, rather than their own MarkSync() handler, as otherwise EXA + * will be unaware of the driver's acceleration and not sync to it during + * fallbacks. + * + * MarkSync() is optional. + */ +static int +MSMMarkSync(ScreenPtr pScreen) +{ + return 0; +} + + +/** + * WaitMarker() waits for all rendering before the given marker to have + * completed. If the driver does not implement MarkSync(), marker is + * meaningless, and all rendering by the hardware should be completed before + * WaitMarker() returns. + * + * Note that drivers should call exaWaitSync() to wait for all acceleration + * to finish, as otherwise EXA will be unaware of the driver having + * synchronized, resulting in excessive WaitMarker() calls. + * + * WaitMarker() is required of all drivers. + */ +static void +MSMWaitMarker(ScreenPtr pScreen, int marker) +{ + +} + +static Bool +MSMPixmapIsOffscreen(PixmapPtr pPixmap) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + MSMPtr pMsm = MSMPTR_FROM_PIXMAP(pPixmap); + + struct msm_pixmap_priv *priv; + if ((pScreen->GetScreenPixmap(pScreen) == pPixmap) || + (pMsm->rotatedPixmap == pPixmap)){ + return TRUE; + } + + priv = exaGetPixmapDriverPrivate(pPixmap); + + if (priv && priv->bo) + return TRUE; + + return FALSE; +} + +static Bool +MSMPrepareAccess(PixmapPtr pPixmap, int index) +{ + struct msm_pixmap_priv *priv; + + priv = exaGetPixmapDriverPrivate(pPixmap); + + if (!priv) + return FALSE; + + if (!priv->bo) + return TRUE; + + if (msm_drm_bo_map(priv->bo)) + return FALSE; + + if (pPixmap->devPrivate.ptr == NULL) + pPixmap->devPrivate.ptr = (void *) priv->bo->hostptr; + + if (pPixmap->drawable.bitsPerPixel == 16 || + pPixmap->drawable.bitsPerPixel == 32) { + priv->SavedPitch = pPixmap->devKind; + + pPixmap->devKind = ((pPixmap->drawable.width + 31) & ~31) * + (pPixmap->drawable.bitsPerPixel >> 3); + } + + return TRUE; +} + +static void +MSMFinishAccess(PixmapPtr pPixmap, int index) +{ + struct msm_pixmap_priv *priv; + priv = exaGetPixmapDriverPrivate(pPixmap); + + if (!priv || !priv->bo) + return; + + if (priv->SavedPitch) { + pPixmap->devKind = priv->SavedPitch; + priv->SavedPitch = 0; + } + + pPixmap->devPrivate.ptr = NULL; +} + +static void * +MSMCreatePixmap(ScreenPtr pScreen, int size, int align) +{ + struct msm_pixmap_priv *priv; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + MSMPtr pMsm = MSMPTR(pScrn); + + priv = calloc(1, sizeof(struct msm_pixmap_priv)); + + if (priv == NULL) + return NULL; + + if (!size) + return priv; + + priv->bo = msm_drm_bo_create(pMsm, pMsm->drmFD, size, + pMsm->pixmapMemtype); + + if (priv->bo) + return priv; + + free(priv); + return NULL; +} + +static void +MSMDestroyPixmap(ScreenPtr pScreen, void *dpriv) +{ + struct msm_pixmap_priv *priv = dpriv; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + MSMPtr pMsm = MSMPTR(pScrn); + + if (!dpriv) + return; + + if (priv->bo) + msm_drm_bo_free(pMsm, priv->bo); + + free(dpriv); +} + +Bool +MSMSetupExa(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + + MSMPtr pMsm = MSMPTR(pScrn); + + ExaDriverPtr pExa; + + if (pMsm->pExa == NULL) + pMsm->pExa = exaDriverAlloc(); + + if (pMsm->pExa == NULL) + return FALSE; + + pExa = pMsm->pExa; + + /* This is the current major/minor that we support */ + + pExa->exa_major = 2; + pExa->exa_minor = 2; + + pExa->memoryBase = pMsm->fbmem; + + /* Max blit extents that hw supports */ + pExa->maxX = 2048; + pExa->maxY = 2048; + + pExa->flags = EXA_OFFSCREEN_PIXMAPS | EXA_HANDLES_PIXMAPS | EXA_SUPPORTS_PREPARE_AUX; + + pExa->offScreenBase = + (pMsm->fixed_info.line_length * pMsm->mode_info.yres); + pExa->memorySize = pMsm->fixed_info.smem_len; + + /* Align pixmap offsets along page boundaries */ + pExa->pixmapOffsetAlign = 4096; + + /* Align pixmap pitches to the maximum needed aligment for the + GPU - this ensures that we have enough room, and we adjust the + pitches down to the depth later */ + + pExa->pixmapPitchAlign = 128; + + /* The maximum acceleratable pitch is 2048 pixels */ + pExa->maxPitchPixels = 2048; + + pExa->PrepareSolid = MSMPrepareSolid; + pExa->Solid = MSMSolid; + pExa->DoneSolid = MSMDoneSolid; + pExa->PrepareCopy = MSMPrepareCopy; + pExa->Copy = MSMCopy; + pExa->DoneCopy = MSMDoneCopy; + pExa->CheckComposite = MSMCheckComposite; + pExa->PrepareComposite = MSMPrepareComposite; + pExa->Composite = MSMComposite; + pExa->DoneComposite = MSMDoneComposite; + pExa->MarkSync = MSMMarkSync; + pExa->WaitMarker = MSMWaitMarker; + pExa->PixmapIsOffscreen = MSMPixmapIsOffscreen; + pExa->CreatePixmap = MSMCreatePixmap; + pExa->DestroyPixmap = MSMDestroyPixmap; + pExa->PrepareAccess = MSMPrepareAccess; + pExa->FinishAccess = MSMFinishAccess; + + return exaDriverInit(pScreen, pMsm->pExa); +} diff --git a/src/msm-output.c b/src/msm-output.c new file mode 100644 index 0000000..8d0860b --- /dev/null +++ b/src/msm-output.c @@ -0,0 +1,165 @@ +/* msm-output.c + * + * Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "xf86.h" +#include "xf86i2c.h" +#include "xf86Crtc.h" +#include "xf86_OSlib.h" +#include "X11/Xatom.h" +#include "randrstr.h" + +#ifdef HAVE_XEXTPROTO_71 +#include +#else +#define DPMS_SERVER +#include +#endif +#include "msm.h" + +static void +MSMOutputCreateResources(xf86OutputPtr output) +{ + /* No custom properties are supported */ +} + +static Bool +MSMOutputSetProperty(xf86OutputPtr output, Atom property, + RRPropertyValuePtr value) +{ + /* No custom properties are supported */ + return TRUE; +} + +static void +MSMOutputDPMS(xf86OutputPtr output, int mode) +{ + /* DPMS is handled at the CRTC */ +} + +static void +MSMOutputPrepare(xf86OutputPtr output) +{ +} + +static void +MSMOutputCommit(xf86OutputPtr output) +{ +} + +static void +MSMOutputSave(xf86OutputPtr output) +{ +} + +static void +MSMOutputRestore(xf86OutputPtr output) +{ +} + +static int +MSMOutputModeValid(xf86OutputPtr output, DisplayModePtr pMode) +{ + return MODE_OK; +} + +static Bool +MSMOutputModeFixup(xf86OutputPtr output, DisplayModePtr mode, + DisplayModePtr adjmode) +{ + return TRUE; +} + +static void +MSMOutputModeSet(xf86OutputPtr output, DisplayModePtr mode, + DisplayModePtr adjmode) +{ + /* Nothing to do on the output side */ +} + +static xf86OutputStatus +MSMOutputDetect(xf86OutputPtr output) +{ + return XF86OutputStatusConnected; +} + +static DisplayModePtr +MSMOutputGetModes(xf86OutputPtr output) +{ + ScrnInfoPtr pScrn = output->scrn; + + MSMPtr pMsm = MSMPTR(pScrn); + + DisplayModePtr modes = NULL; + + modes = xf86DuplicateMode(&pMsm->default_mode); + return modes; +} + +static void +MSMOutputDestroy(xf86OutputPtr output) +{ +} + +static const xf86OutputFuncsRec MSMOutputFuncs = { + .create_resources = MSMOutputCreateResources, + .dpms = MSMOutputDPMS, + .save = MSMOutputSave, + .restore = MSMOutputRestore, + .mode_valid = MSMOutputModeValid, + .mode_fixup = MSMOutputModeFixup, + .prepare = MSMOutputPrepare, + .mode_set = MSMOutputModeSet, + .commit = MSMOutputCommit, + .detect = MSMOutputDetect, + .get_modes = MSMOutputGetModes, + .set_property = MSMOutputSetProperty, + .destroy = MSMOutputDestroy +}; + +void +MSMOutputSetup(ScrnInfoPtr pScrn) +{ + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + xf86OutputPtr output; + + /*For primary display*/ + output = xf86OutputCreate(pScrn, &MSMOutputFuncs, "default"); + + output->interlaceAllowed = FALSE; + output->doubleScanAllowed = FALSE; + + /* FIXME: Set monitor size here? */ + output->possible_crtcs = 1; + output->driver_private = NULL; + output->crtc = xf86_config->crtc[0]; +} diff --git a/src/msm-pixmap.c b/src/msm-pixmap.c new file mode 100644 index 0000000..1eb176f --- /dev/null +++ b/src/msm-pixmap.c @@ -0,0 +1,135 @@ +/* msm-pixmap.c + * + * Copyright (c) 2009 - 2010 Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "msm.h" +#include "msm-drm.h" + +unsigned int +msm_pixmap_gpuptr(PixmapPtr pixmap) +{ + ScreenPtr pScreen = pixmap->drawable.pScreen; + MSMPtr pMsm = MSMPTR_FROM_PIXMAP(pixmap); + + if (msm_pixmap_in_gem(pixmap)) { + struct msm_drm_bo *bo = msm_get_pixmap_bo(pixmap); + if (!msm_drm_bo_bind_gpu(bo)) { + return (unsigned int) bo->gpuaddr[bo->active]; + } + } + + /* Return the physical address of the framebuffer */ + /* If we have a BO for the framebuffer, then bind it + and return the adress, otherwise revert back to the + physical address */ + + if ((pScreen->GetScreenPixmap(pScreen) == pixmap) || + (pMsm->rotatedPixmap == pixmap)) { + unsigned int offset = 0; + if(pMsm->rotatedPixmap == pixmap) + offset = pMsm->mode_info.yres * pMsm->fixed_info.line_length; + if (pMsm->fbBo && !msm_drm_bo_bind_gpu(pMsm->fbBo)) + return (unsigned int) (pMsm->fbBo->gpuaddr[0] + offset); + + return ((unsigned int)pMsm->fixed_info.smem_start + offset); + } + + return 0; +} + +void * +msm_pixmap_hostptr(PixmapPtr pixmap) +{ + ScreenPtr pScreen = pixmap->drawable.pScreen; + MSMPtr pMsm = MSMPTR_FROM_PIXMAP(pixmap); + + if (msm_pixmap_in_gem(pixmap)) { + struct msm_drm_bo *bo = msm_get_pixmap_bo(pixmap); + return (void *) bo->virtaddr[bo->active]; + } + + /* Return virtual address of the framebuffer */ + + if (pScreen->GetScreenPixmap(pScreen) == pixmap) + return pMsm->curVisiblePtr; + + return (void *) pixmap->devPrivate.ptr; +} + +int +msm_pixmap_offset(PixmapPtr pixmap) +{ + return 0; +} + +int +msm_pixmap_get_pitch(PixmapPtr pix) +{ + struct msm_pixmap_priv *priv = exaGetPixmapDriverPrivate(pix); + + /* We only modify the pitch for 16bpp operations */ + + if (priv && priv->bo && pix->drawable.bitsPerPixel == 16) { + return ((pix->drawable.width + 31) & ~31) * + (pix->drawable.bitsPerPixel >> 3); + } + + return exaGetPixmapPitch(pix); +} + +Bool +msm_pixmap_in_gem(PixmapPtr pix) +{ + struct msm_pixmap_priv *priv = exaGetPixmapDriverPrivate(pix); + + if (priv && priv->bo) + return TRUE; + + return FALSE; +} + +struct msm_drm_bo * +msm_get_pixmap_bo(PixmapPtr pix) +{ + struct msm_pixmap_priv *priv = exaGetPixmapDriverPrivate(pix); + + if (priv && priv->bo) { + /* When this fucntion is called then ensure it gets + allocated - if this function ever gets used outside of + EXA this could cause problems */ + + msm_drm_bo_alloc(priv->bo); + return priv->bo; + } + + return NULL; +} diff --git a/src/msm.h b/src/msm.h new file mode 100644 index 0000000..2454887 --- /dev/null +++ b/src/msm.h @@ -0,0 +1,169 @@ +/* msm.h + * + * Copyright (c) 2009-2010 Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _MSM_H_ +#define _MSM_H_ + +#include "xf86.h" +#include "damage.h" +#include "exa.h" + +#include +#include +#include + +#define ARRAY_SIZE(a) (sizeof((a)) / (sizeof(*(a)))) + +/* This enumerates all of the available options */ + +typedef enum +{ + OPTION_FB, + OPTION_NOACCEL, + OPTION_SWCURSOR, + OPTION_VSYNC, + OPTION_FBCACHE, + OPTION_PIXMAP_MEMTYPE, + OPTION_PAGEFLIP, + OPTION_DRIMEMTYPE, + OPTION_DEBUG, +} MSMOpts; + +typedef enum +{ + MSM_MDP_VERSION_22, + MSM_MDP_VERSION_31, + MSM_MDP_VERSION_40, +} MSMChipType; + +typedef struct _MSMRec +{ + /* File descriptor for the framebuffer device */ + int fd; + + /* Fixed and var strutures from the framebuffer */ + struct fb_fix_screeninfo fixed_info; + struct fb_var_screeninfo mode_info; + + /* Pointer to the mapped framebuffer memory */ + void *fbmem; + + /* Processor identifier */ + MSMChipType chipID; + + /* Default mode for X */ + DisplayModeRec default_mode; + + /* EXA driver structure */ + ExaDriverPtr pExa; + + /* Place holder for the standard close screen function */ + CloseScreenProcPtr CloseScreen; + + Bool HWCursor; + int HWCursorState; + int defaultVsync; + int FBCache; + + int drmFD; + char drmDevName[64]; + + int pixmapMemtype; + int DRIMemtype; + struct msm_drm_bo *cachedBo; + + struct msm_drm_bo *fbBo; + void *curVisiblePtr; + + OptionInfoPtr options; + PixmapPtr rotatedPixmap; + Bool isFBSurfaceStale; + PictTransform *currentTransform; +} MSMRec, *MSMPtr; + +struct msm_pixmap_priv { + struct msm_drm_bo *bo; + int SavedPitch; + unsigned int c2dsurface; +}; + +/* Macro to get the private record from the ScreenInfo structure */ +#define MSMPTR(p) ((MSMPtr) ((p)->driverPrivate)) + +#define MSMPTR_FROM_PIXMAP(_x) \ + MSMPTR(xf86Screens[(_x)->drawable.pScreen->myNum]) + +Bool MSMSetupExa(ScreenPtr); +void MSMSetCursorPosition(MSMPtr pMsm, int x, int y); +void MSMCursorEnable(MSMPtr pMsm, Bool enable); +void MSMCursorLoadARGB(MSMPtr pMsm, CARD32 * image); +Bool MSMCursorInit(ScreenPtr pScreen); +void MSMOutputSetup(ScrnInfoPtr pScrn); +void MSMCrtcSetup(ScrnInfoPtr pScrn); + +#define MSM_OFFSCREEN_GEM 0x01 + + +#define xFixedtoDouble(_f) (double) ((_f)/(double) xFixed1) + +unsigned int msm_pixmap_gpuptr(PixmapPtr); +void *msm_pixmap_hostptr(PixmapPtr); +int msm_pixmap_offset(PixmapPtr); +int msm_pixmap_get_pitch(PixmapPtr pix); +Bool msm_pixmap_in_gem(PixmapPtr); +struct msm_drm_bo *msm_get_pixmap_bo(PixmapPtr); + + +/** + * This controls whether debug statements (and function "trace" enter/exit) + * messages are sent to the log file (TRUE) or are ignored (FALSE). + */ +extern Bool msmDebug; + + +/* Various logging/debug macros for use in the X driver and the external + * sub-modules: + */ +#define DEBUG_MSG(fmt, ...) \ + do { if (msmDebug) 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 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) + +#endif diff --git a/system-includes/drm/kgsl_drm.h b/system-includes/drm/kgsl_drm.h new file mode 100644 index 0000000..f1c7f4e --- /dev/null +++ b/system-includes/drm/kgsl_drm.h @@ -0,0 +1,192 @@ +#ifndef _KGSL_DRM_H_ +#define _KGSL_DRM_H_ + +#include "drm.h" + +#define DRM_KGSL_GEM_CREATE 0x00 +#define DRM_KGSL_GEM_PREP 0x01 +#define DRM_KGSL_GEM_SETMEMTYPE 0x02 +#define DRM_KGSL_GEM_GETMEMTYPE 0x03 +#define DRM_KGSL_GEM_MMAP 0x04 +#define DRM_KGSL_GEM_ALLOC 0x05 +#define DRM_KGSL_GEM_BIND_GPU 0x06 +#define DRM_KGSL_GEM_UNBIND_GPU 0x07 + +#define DRM_KGSL_GEM_GET_BUFINFO 0x08 +#define DRM_KGSL_GEM_SET_BUFCOUNT 0x09 +#define DRM_KGSL_GEM_SET_ACTIVE 0x0A +#define DRM_KGSL_GEM_LOCK_HANDLE 0x0B +#define DRM_KGSL_GEM_UNLOCK_HANDLE 0x0C +#define DRM_KGSL_GEM_UNLOCK_ON_TS 0x0D +#define DRM_KGSL_GEM_CREATE_FD 0x0E + +#define DRM_IOCTL_KGSL_GEM_CREATE \ +DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_CREATE, struct drm_kgsl_gem_create) + +#define DRM_IOCTL_KGSL_GEM_PREP \ +DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_PREP, struct drm_kgsl_gem_prep) + +#define DRM_IOCTL_KGSL_GEM_SETMEMTYPE \ +DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_SETMEMTYPE, \ +struct drm_kgsl_gem_memtype) + +#define DRM_IOCTL_KGSL_GEM_GETMEMTYPE \ +DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_GETMEMTYPE, \ +struct drm_kgsl_gem_memtype) + +#define DRM_IOCTL_KGSL_GEM_MMAP \ +DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_MMAP, struct drm_kgsl_gem_mmap) + +#define DRM_IOCTL_KGSL_GEM_ALLOC \ +DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_ALLOC, struct drm_kgsl_gem_alloc) + +#define DRM_IOCTL_KGSL_GEM_BIND_GPU \ +DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_BIND_GPU, struct drm_kgsl_gem_bind_gpu) + +#define DRM_IOCTL_KGSL_GEM_UNBIND_GPU \ +DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_UNBIND_GPU, \ +struct drm_kgsl_gem_bind_gpu) + +#define DRM_IOCTL_KGSL_GEM_GET_BUFINFO \ +DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_GET_BUFINFO, \ + struct drm_kgsl_gem_bufinfo) + +#define DRM_IOCTL_KGSL_GEM_SET_BUFCOUNT \ +DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_SET_BUFCOUNT, \ + struct drm_kgsl_gem_bufcount) + +#define DRM_IOCTL_KGSL_GEM_SET_ACTIVE \ +DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_SET_ACTIVE, \ + struct drm_kgsl_gem_active) + +#define DRM_IOCTL_KGSL_GEM_LOCK_HANDLE \ +DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_LOCK_HANDLE, \ +struct drm_kgsl_gem_lock_handles) + +#define DRM_IOCTL_KGSL_GEM_UNLOCK_HANDLE \ +DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_UNLOCK_HANDLE, \ +struct drm_kgsl_gem_unlock_handles) + +#define DRM_IOCTL_KGSL_GEM_UNLOCK_ON_TS \ +DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_UNLOCK_ON_TS, \ +struct drm_kgsl_gem_unlock_on_ts) + +#define DRM_IOCTL_KGSL_GEM_CREATE_FD \ +DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_CREATE_FD, \ +struct drm_kgsl_gem_create_fd) + +/* Maximum number of sub buffers per GEM object */ +#define DRM_KGSL_GEM_MAX_BUFFERS 2 + +/* Memory types - these define the source and caching policies + of the GEM memory chunk */ + +/* Legacy definitions left for compatability */ + +#define DRM_KGSL_GEM_TYPE_EBI 0 +#define DRM_KGSL_GEM_TYPE_SMI 1 +#define DRM_KGSL_GEM_TYPE_KMEM 2 +#define DRM_KGSL_GEM_TYPE_KMEM_NOCACHE 3 +#define DRM_KGSL_GEM_TYPE_MEM_MASK 0xF + +/* Contiguous memory (PMEM) */ +#define DRM_KGSL_GEM_TYPE_PMEM 0x000100 + +/* PMEM memory types */ +#define DRM_KGSL_GEM_PMEM_EBI 0x001000 +#define DRM_KGSL_GEM_PMEM_SMI 0x002000 + +/* Standard paged memory */ +#define DRM_KGSL_GEM_TYPE_MEM 0x010000 + +/* Caching controls */ +#define DRM_KGSL_GEM_CACHE_NONE 0x000000 +#define DRM_KGSL_GEM_CACHE_WCOMBINE 0x100000 +#define DRM_KGSL_GEM_CACHE_WTHROUGH 0x200000 +#define DRM_KGSL_GEM_CACHE_WBACK 0x400000 +#define DRM_KGSL_GEM_CACHE_WBACKWA 0x800000 +#define DRM_KGSL_GEM_CACHE_MASK 0xF00000 + +/* FD based objects */ +#define DRM_KGSL_GEM_TYPE_FD_FBMEM 0x1000000 +#define DRM_KGSL_GEM_TYPE_FD_MASK 0xF000000 + +/* Timestamp types */ +#define DRM_KGSL_GEM_TS_3D 0x00000430 +#define DRM_KGSL_GEM_TS_2D 0x00000180 + + +struct drm_kgsl_gem_create { + uint32_t size; + uint32_t handle; +}; + +struct drm_kgsl_gem_prep { + uint32_t handle; + uint32_t phys; + uint64_t offset; +}; + +struct drm_kgsl_gem_memtype { + uint32_t handle; + uint32_t type; +}; + +struct drm_kgsl_gem_mmap { + uint32_t handle; + uint32_t size; + uint32_t hostptr; + uint64_t offset; +}; + +struct drm_kgsl_gem_alloc { + uint32_t handle; + uint64_t offset; +}; + +struct drm_kgsl_gem_bind_gpu { + uint32_t handle; + uint32_t gpuptr; +}; + +struct drm_kgsl_gem_bufinfo { + uint32_t handle; + uint32_t count; + uint32_t active; + uint32_t offset[DRM_KGSL_GEM_MAX_BUFFERS]; + uint32_t gpuaddr[DRM_KGSL_GEM_MAX_BUFFERS]; +}; + +struct drm_kgsl_gem_bufcount { + uint32_t handle; + uint32_t bufcount; +}; + +struct drm_kgsl_gem_active { + uint32_t handle; + uint32_t active; +}; + +struct drm_kgsl_gem_lock_handles { + uint32_t num_handles; + uint32_t *handle_list; + uint32_t pid; + uint32_t lock_id; /* Returned lock id used for unlocking */ +}; + +struct drm_kgsl_gem_unlock_handles { + uint32_t lock_id; +}; + +struct drm_kgsl_gem_unlock_on_ts { + uint32_t lock_id; + uint32_t timestamp; /* This field is a hw generated ts */ + uint32_t type; /* Which pipe to check for ts generation */ +}; + +struct drm_kgsl_gem_create_fd { + uint32_t fd; + uint32_t handle; +}; + +#endif diff --git a/system-includes/linux/msm_kgsl.h b/system-includes/linux/msm_kgsl.h new file mode 100644 index 0000000..69ff05b --- /dev/null +++ b/system-includes/linux/msm_kgsl.h @@ -0,0 +1,476 @@ +#ifndef _MSM_KGSL_H +#define _MSM_KGSL_H + +#define KGSL_VERSION_MAJOR 3 +#define KGSL_VERSION_MINOR 8 + +/*context flags */ +#define KGSL_CONTEXT_SAVE_GMEM 1 +#define KGSL_CONTEXT_NO_GMEM_ALLOC 2 +#define KGSL_CONTEXT_SUBMIT_IB_LIST 4 +#define KGSL_CONTEXT_CTX_SWITCH 8 +#define KGSL_CONTEXT_PREAMBLE 16 + +/* Memory allocayion flags */ +#define KGSL_MEMFLAGS_GPUREADONLY 0x01000000 + +/* generic flag values */ +#define KGSL_FLAGS_NORMALMODE 0x00000000 +#define KGSL_FLAGS_SAFEMODE 0x00000001 +#define KGSL_FLAGS_INITIALIZED0 0x00000002 +#define KGSL_FLAGS_INITIALIZED 0x00000004 +#define KGSL_FLAGS_STARTED 0x00000008 +#define KGSL_FLAGS_ACTIVE 0x00000010 +#define KGSL_FLAGS_RESERVED0 0x00000020 +#define KGSL_FLAGS_RESERVED1 0x00000040 +#define KGSL_FLAGS_RESERVED2 0x00000080 +#define KGSL_FLAGS_SOFT_RESET 0x00000100 + +/* Clock flags to show which clocks should be controled by a given platform */ +#define KGSL_CLK_SRC 0x00000001 +#define KGSL_CLK_CORE 0x00000002 +#define KGSL_CLK_IFACE 0x00000004 +#define KGSL_CLK_MEM 0x00000008 +#define KGSL_CLK_MEM_IFACE 0x00000010 +#define KGSL_CLK_AXI 0x00000020 + +/* + * Reset status values for context + */ +enum kgsl_ctx_reset_stat { + KGSL_CTX_STAT_NO_ERROR = 0x00000000, + KGSL_CTX_STAT_GUILTY_CONTEXT_RESET_EXT = 0x00000001, + KGSL_CTX_STAT_INNOCENT_CONTEXT_RESET_EXT = 0x00000002, + KGSL_CTX_STAT_UNKNOWN_CONTEXT_RESET_EXT = 0x00000003 +}; + +#define KGSL_MAX_PWRLEVELS 5 + +#define KGSL_CONVERT_TO_MBPS(val) \ + (val*1000*1000U) + +/* device id */ +enum kgsl_deviceid { + KGSL_DEVICE_3D0 = 0x00000000, + KGSL_DEVICE_2D0 = 0x00000001, + KGSL_DEVICE_2D1 = 0x00000002, + KGSL_DEVICE_MAX = 0x00000003 +}; + +enum kgsl_user_mem_type { + KGSL_USER_MEM_TYPE_PMEM = 0x00000000, + KGSL_USER_MEM_TYPE_ASHMEM = 0x00000001, + KGSL_USER_MEM_TYPE_ADDR = 0x00000002, + KGSL_USER_MEM_TYPE_ION = 0x00000003, + KGSL_USER_MEM_TYPE_MAX = 0x00000004, +}; + +struct kgsl_devinfo { + + unsigned int device_id; + /* chip revision id + * coreid:8 majorrev:8 minorrev:8 patch:8 + */ + unsigned int chip_id; + unsigned int mmu_enabled; + unsigned int gmem_gpubaseaddr; + /* + * This field contains the adreno revision + * number 200, 205, 220, etc... + */ + unsigned int gpu_id; + unsigned int gmem_sizebytes; +}; + +/* this structure defines the region of memory that can be mmap()ed from this + driver. The timestamp fields are volatile because they are written by the + GPU +*/ +struct kgsl_devmemstore { + volatile unsigned int soptimestamp; + unsigned int sbz; + volatile unsigned int eoptimestamp; + unsigned int sbz2; + volatile unsigned int ts_cmp_enable; + unsigned int sbz3; + volatile unsigned int ref_wait_ts; + unsigned int sbz4; + unsigned int current_context; + unsigned int sbz5; +}; + +#define KGSL_DEVICE_MEMSTORE_OFFSET(field) \ + offsetof(struct kgsl_devmemstore, field) + + +/* timestamp id*/ +enum kgsl_timestamp_type { + KGSL_TIMESTAMP_CONSUMED = 0x00000001, /* start-of-pipeline timestamp */ + KGSL_TIMESTAMP_RETIRED = 0x00000002, /* end-of-pipeline timestamp*/ + KGSL_TIMESTAMP_MAX = 0x00000002, +}; + +/* property types - used with kgsl_device_getproperty */ +enum kgsl_property_type { + KGSL_PROP_DEVICE_INFO = 0x00000001, + KGSL_PROP_DEVICE_SHADOW = 0x00000002, + KGSL_PROP_DEVICE_POWER = 0x00000003, + KGSL_PROP_SHMEM = 0x00000004, + KGSL_PROP_SHMEM_APERTURES = 0x00000005, + KGSL_PROP_MMU_ENABLE = 0x00000006, + KGSL_PROP_INTERRUPT_WAITS = 0x00000007, + KGSL_PROP_VERSION = 0x00000008, + KGSL_PROP_GPU_RESET_STAT = 0x00000009 +}; + +struct kgsl_shadowprop { + unsigned int gpuaddr; + unsigned int size; + unsigned int flags; /* contains KGSL_FLAGS_ values */ +}; + +struct kgsl_pwrlevel { + unsigned int gpu_freq; + unsigned int bus_freq; + unsigned int io_fraction; +}; + +struct kgsl_version { + unsigned int drv_major; + unsigned int drv_minor; + unsigned int dev_major; + unsigned int dev_minor; +}; + +#ifdef __KERNEL__ + +#define KGSL_3D0_REG_MEMORY "kgsl_3d0_reg_memory" +#define KGSL_3D0_IRQ "kgsl_3d0_irq" +#define KGSL_2D0_REG_MEMORY "kgsl_2d0_reg_memory" +#define KGSL_2D0_IRQ "kgsl_2d0_irq" +#define KGSL_2D1_REG_MEMORY "kgsl_2d1_reg_memory" +#define KGSL_2D1_IRQ "kgsl_2d1_irq" + +struct kgsl_device_iommu_data { + const char **iommu_ctx_names; + int iommu_ctx_count; + unsigned int physstart; + unsigned int physend; +}; + +struct kgsl_device_platform_data { + struct kgsl_pwrlevel pwrlevel[KGSL_MAX_PWRLEVELS]; + int init_level; + int num_levels; + int (*set_grp_async)(void); + unsigned int idle_timeout; + unsigned int nap_allowed; + unsigned int clk_map; + unsigned int idle_needed; + struct msm_bus_scale_pdata *bus_scale_table; + struct kgsl_device_iommu_data *iommu_data; + int iommu_count; +}; + +#endif + +/* structure holds list of ibs */ +struct kgsl_ibdesc { + unsigned int gpuaddr; + void *hostptr; + unsigned int sizedwords; + unsigned int ctrl; +}; + +/* ioctls */ +#define KGSL_IOC_TYPE 0x09 + +/* get misc info about the GPU + type should be a value from enum kgsl_property_type + value points to a structure that varies based on type + sizebytes is sizeof() that structure + for KGSL_PROP_DEVICE_INFO, use struct kgsl_devinfo + this structure contaings hardware versioning info. + for KGSL_PROP_DEVICE_SHADOW, use struct kgsl_shadowprop + this is used to find mmap() offset and sizes for mapping + struct kgsl_memstore into userspace. +*/ +struct kgsl_device_getproperty { + unsigned int type; + void *value; + unsigned int sizebytes; +}; + +#define IOCTL_KGSL_DEVICE_GETPROPERTY \ + _IOWR(KGSL_IOC_TYPE, 0x2, struct kgsl_device_getproperty) + + +/* read a GPU register. + offsetwords it the 32 bit word offset from the beginning of the + GPU register space. + */ +struct kgsl_device_regread { + unsigned int offsetwords; + unsigned int value; /* output param */ +}; + +#define IOCTL_KGSL_DEVICE_REGREAD \ + _IOWR(KGSL_IOC_TYPE, 0x3, struct kgsl_device_regread) + + +/* block until the GPU has executed past a given timestamp + * timeout is in milliseconds. + */ +struct kgsl_device_waittimestamp { + unsigned int timestamp; + unsigned int timeout; +}; + +#define IOCTL_KGSL_DEVICE_WAITTIMESTAMP \ + _IOW(KGSL_IOC_TYPE, 0x6, struct kgsl_device_waittimestamp) + + +/* issue indirect commands to the GPU. + * drawctxt_id must have been created with IOCTL_KGSL_DRAWCTXT_CREATE + * ibaddr and sizedwords must specify a subset of a buffer created + * with IOCTL_KGSL_SHAREDMEM_FROM_PMEM + * flags may be a mask of KGSL_CONTEXT_ values + * timestamp is a returned counter value which can be passed to + * other ioctls to determine when the commands have been executed by + * the GPU. + */ +struct kgsl_ringbuffer_issueibcmds { + unsigned int drawctxt_id; + unsigned int ibdesc_addr; + unsigned int numibs; + unsigned int timestamp; /*output param */ + unsigned int flags; +}; + +#define IOCTL_KGSL_RINGBUFFER_ISSUEIBCMDS \ + _IOWR(KGSL_IOC_TYPE, 0x10, struct kgsl_ringbuffer_issueibcmds) + +/* read the most recently executed timestamp value + * type should be a value from enum kgsl_timestamp_type + */ +struct kgsl_cmdstream_readtimestamp { + unsigned int type; + unsigned int timestamp; /*output param */ +}; + +#define IOCTL_KGSL_CMDSTREAM_READTIMESTAMP_OLD \ + _IOR(KGSL_IOC_TYPE, 0x11, struct kgsl_cmdstream_readtimestamp) + +#define IOCTL_KGSL_CMDSTREAM_READTIMESTAMP \ + _IOWR(KGSL_IOC_TYPE, 0x11, struct kgsl_cmdstream_readtimestamp) + +/* free memory when the GPU reaches a given timestamp. + * gpuaddr specify a memory region created by a + * IOCTL_KGSL_SHAREDMEM_FROM_PMEM call + * type should be a value from enum kgsl_timestamp_type + */ +struct kgsl_cmdstream_freememontimestamp { + unsigned int gpuaddr; + unsigned int type; + unsigned int timestamp; +}; + +#define IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP \ + _IOW(KGSL_IOC_TYPE, 0x12, struct kgsl_cmdstream_freememontimestamp) + +/* Previous versions of this header had incorrectly defined + IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP as a read-only ioctl instead + of a write only ioctl. To ensure binary compatability, the following + #define will be used to intercept the incorrect ioctl +*/ + +#define IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP_OLD \ + _IOR(KGSL_IOC_TYPE, 0x12, struct kgsl_cmdstream_freememontimestamp) + +/* create a draw context, which is used to preserve GPU state. + * The flags field may contain a mask KGSL_CONTEXT_* values + */ +struct kgsl_drawctxt_create { + unsigned int flags; + unsigned int drawctxt_id; /*output param */ +}; + +#define IOCTL_KGSL_DRAWCTXT_CREATE \ + _IOWR(KGSL_IOC_TYPE, 0x13, struct kgsl_drawctxt_create) + +/* destroy a draw context */ +struct kgsl_drawctxt_destroy { + unsigned int drawctxt_id; +}; + +#define IOCTL_KGSL_DRAWCTXT_DESTROY \ + _IOW(KGSL_IOC_TYPE, 0x14, struct kgsl_drawctxt_destroy) + +/* add a block of pmem, fb, ashmem or user allocated address + * into the GPU address space */ +struct kgsl_map_user_mem { + int fd; + unsigned int gpuaddr; /*output param */ + unsigned int len; + unsigned int offset; + unsigned int hostptr; /*input param */ + enum kgsl_user_mem_type memtype; + unsigned int reserved; /* May be required to add + params for another mem type */ +}; + +#define IOCTL_KGSL_MAP_USER_MEM \ + _IOWR(KGSL_IOC_TYPE, 0x15, struct kgsl_map_user_mem) + +/* add a block of pmem or fb into the GPU address space */ +struct kgsl_sharedmem_from_pmem { + int pmem_fd; + unsigned int gpuaddr; /*output param */ + unsigned int len; + unsigned int offset; +}; + +#define IOCTL_KGSL_SHAREDMEM_FROM_PMEM \ + _IOWR(KGSL_IOC_TYPE, 0x20, struct kgsl_sharedmem_from_pmem) + +/* remove memory from the GPU's address space */ +struct kgsl_sharedmem_free { + unsigned int gpuaddr; +}; + +#define IOCTL_KGSL_SHAREDMEM_FREE \ + _IOW(KGSL_IOC_TYPE, 0x21, struct kgsl_sharedmem_free) + +struct kgsl_cff_user_event { + unsigned char cff_opcode; + unsigned int op1; + unsigned int op2; + unsigned int op3; + unsigned int op4; + unsigned int op5; + unsigned int __pad[2]; +}; + +#define IOCTL_KGSL_CFF_USER_EVENT \ + _IOW(KGSL_IOC_TYPE, 0x31, struct kgsl_cff_user_event) + +struct kgsl_gmem_desc { + unsigned int x; + unsigned int y; + unsigned int width; + unsigned int height; + unsigned int pitch; +}; + +struct kgsl_buffer_desc { + void *hostptr; + unsigned int gpuaddr; + int size; + unsigned int format; + unsigned int pitch; + unsigned int enabled; +}; + +struct kgsl_bind_gmem_shadow { + unsigned int drawctxt_id; + struct kgsl_gmem_desc gmem_desc; + unsigned int shadow_x; + unsigned int shadow_y; + struct kgsl_buffer_desc shadow_buffer; + unsigned int buffer_id; +}; + +#define IOCTL_KGSL_DRAWCTXT_BIND_GMEM_SHADOW \ + _IOW(KGSL_IOC_TYPE, 0x22, struct kgsl_bind_gmem_shadow) + +/* add a block of memory into the GPU address space */ +struct kgsl_sharedmem_from_vmalloc { + unsigned int gpuaddr; /*output param */ + unsigned int hostptr; + unsigned int flags; +}; + +#define IOCTL_KGSL_SHAREDMEM_FROM_VMALLOC \ + _IOWR(KGSL_IOC_TYPE, 0x23, struct kgsl_sharedmem_from_vmalloc) + +#define IOCTL_KGSL_SHAREDMEM_FLUSH_CACHE \ + _IOW(KGSL_IOC_TYPE, 0x24, struct kgsl_sharedmem_free) + +struct kgsl_drawctxt_set_bin_base_offset { + unsigned int drawctxt_id; + unsigned int offset; +}; + +#define IOCTL_KGSL_DRAWCTXT_SET_BIN_BASE_OFFSET \ + _IOW(KGSL_IOC_TYPE, 0x25, struct kgsl_drawctxt_set_bin_base_offset) + +enum kgsl_cmdwindow_type { + KGSL_CMDWINDOW_MIN = 0x00000000, + KGSL_CMDWINDOW_2D = 0x00000000, + KGSL_CMDWINDOW_3D = 0x00000001, /* legacy */ + KGSL_CMDWINDOW_MMU = 0x00000002, + KGSL_CMDWINDOW_ARBITER = 0x000000FF, + KGSL_CMDWINDOW_MAX = 0x000000FF, +}; + +/* write to the command window */ +struct kgsl_cmdwindow_write { + enum kgsl_cmdwindow_type target; + unsigned int addr; + unsigned int data; +}; + +#define IOCTL_KGSL_CMDWINDOW_WRITE \ + _IOW(KGSL_IOC_TYPE, 0x2e, struct kgsl_cmdwindow_write) + +struct kgsl_gpumem_alloc { + unsigned long gpuaddr; + size_t size; + unsigned int flags; +}; + +#define IOCTL_KGSL_GPUMEM_ALLOC \ + _IOWR(KGSL_IOC_TYPE, 0x2f, struct kgsl_gpumem_alloc) + +struct kgsl_cff_syncmem { + unsigned int gpuaddr; + unsigned int len; + unsigned int __pad[2]; /* For future binary compatibility */ +}; + +#define IOCTL_KGSL_CFF_SYNCMEM \ + _IOW(KGSL_IOC_TYPE, 0x30, struct kgsl_cff_syncmem) + +/* + * A timestamp event allows the user space to register an action following an + * expired timestamp. + */ + +struct kgsl_timestamp_event { + int type; /* Type of event (see list below) */ + unsigned int timestamp; /* Timestamp to trigger event on */ + unsigned int context_id; /* Context for the timestamp */ + void *priv; /* Pointer to the event specific blob */ + size_t len; /* Size of the event specific blob */ +}; + +#define IOCTL_KGSL_TIMESTAMP_EVENT \ + _IOW(KGSL_IOC_TYPE, 0x31, struct kgsl_timestamp_event) + +/* A genlock timestamp event releases an existing lock on timestamp expire */ + +#define KGSL_TIMESTAMP_EVENT_GENLOCK 1 + +struct kgsl_timestamp_event_genlock { + int handle; /* Handle of the genlock lock to release */ +}; + +#ifdef __KERNEL__ +#ifdef CONFIG_MSM_KGSL_DRM +int kgsl_gem_obj_addr(int drm_fd, int handle, unsigned long *start, + unsigned long *len); +#else +#define kgsl_gem_obj_addr(...) 0 +#endif +#endif +#endif /* _MSM_KGSL_H */ diff --git a/system-includes/linux/msm_mdp.h b/system-includes/linux/msm_mdp.h new file mode 100644 index 0000000..6442faa --- /dev/null +++ b/system-includes/linux/msm_mdp.h @@ -0,0 +1,464 @@ +/* include/linux/msm_mdp.h + * + * Copyright (C) 2007 Google Incorporated + * Copyright (c) 2012 Code Aurora Forum. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef _MSM_MDP_H_ +#define _MSM_MDP_H_ + +#include +#include + +#define MSMFB_IOCTL_MAGIC 'm' +#define MSMFB_GRP_DISP _IOW(MSMFB_IOCTL_MAGIC, 1, unsigned int) +#define MSMFB_BLIT _IOW(MSMFB_IOCTL_MAGIC, 2, unsigned int) +#define MSMFB_SUSPEND_SW_REFRESHER _IOW(MSMFB_IOCTL_MAGIC, 128, unsigned int) +#define MSMFB_RESUME_SW_REFRESHER _IOW(MSMFB_IOCTL_MAGIC, 129, unsigned int) +#define MSMFB_CURSOR _IOW(MSMFB_IOCTL_MAGIC, 130, struct fb_cursor) +#define MSMFB_SET_LUT _IOW(MSMFB_IOCTL_MAGIC, 131, struct fb_cmap) +#define MSMFB_HISTOGRAM _IOWR(MSMFB_IOCTL_MAGIC, 132, struct mdp_histogram) +/* new ioctls's for set/get ccs matrix */ +#define MSMFB_GET_CCS_MATRIX _IOWR(MSMFB_IOCTL_MAGIC, 133, struct mdp_ccs) +#define MSMFB_SET_CCS_MATRIX _IOW(MSMFB_IOCTL_MAGIC, 134, struct mdp_ccs) +#define MSMFB_OVERLAY_SET _IOWR(MSMFB_IOCTL_MAGIC, 135, \ + struct mdp_overlay) +#define MSMFB_OVERLAY_UNSET _IOW(MSMFB_IOCTL_MAGIC, 136, unsigned int) +#define MSMFB_OVERLAY_PLAY _IOW(MSMFB_IOCTL_MAGIC, 137, \ + struct msmfb_overlay_data) +#define MSMFB_GET_PAGE_PROTECTION _IOR(MSMFB_IOCTL_MAGIC, 138, \ + struct mdp_page_protection) +#define MSMFB_SET_PAGE_PROTECTION _IOW(MSMFB_IOCTL_MAGIC, 139, \ + struct mdp_page_protection) +#define MSMFB_OVERLAY_GET _IOR(MSMFB_IOCTL_MAGIC, 140, \ + struct mdp_overlay) +#define MSMFB_OVERLAY_PLAY_ENABLE _IOW(MSMFB_IOCTL_MAGIC, 141, unsigned int) +#define MSMFB_OVERLAY_BLT _IOWR(MSMFB_IOCTL_MAGIC, 142, \ + struct msmfb_overlay_blt) +#define MSMFB_OVERLAY_BLT_OFFSET _IOW(MSMFB_IOCTL_MAGIC, 143, unsigned int) +#define MSMFB_HISTOGRAM_START _IO(MSMFB_IOCTL_MAGIC, 144) +#define MSMFB_HISTOGRAM_STOP _IO(MSMFB_IOCTL_MAGIC, 145) +#define MSMFB_NOTIFY_UPDATE _IOW(MSMFB_IOCTL_MAGIC, 146, unsigned int) + +#define MSMFB_OVERLAY_3D _IOWR(MSMFB_IOCTL_MAGIC, 147, \ + struct msmfb_overlay_3d) + +#define MSMFB_MIXER_INFO _IOWR(MSMFB_IOCTL_MAGIC, 148, \ + struct msmfb_mixer_info_req) +#define MSMFB_OVERLAY_PLAY_WAIT _IOWR(MSMFB_IOCTL_MAGIC, 149, \ + struct msmfb_overlay_data) +#define MSMFB_WRITEBACK_INIT _IO(MSMFB_IOCTL_MAGIC, 150) +#define MSMFB_WRITEBACK_START _IO(MSMFB_IOCTL_MAGIC, 151) +#define MSMFB_WRITEBACK_STOP _IO(MSMFB_IOCTL_MAGIC, 152) +#define MSMFB_WRITEBACK_QUEUE_BUFFER _IOW(MSMFB_IOCTL_MAGIC, 153, \ + struct msmfb_data) +#define MSMFB_WRITEBACK_DEQUEUE_BUFFER _IOW(MSMFB_IOCTL_MAGIC, 154, \ + struct msmfb_data) +#define MSMFB_WRITEBACK_TERMINATE _IO(MSMFB_IOCTL_MAGIC, 155) +#define MSMFB_MDP_PP _IOWR(MSMFB_IOCTL_MAGIC, 156, struct msmfb_mdp_pp) + +#define FB_TYPE_3D_PANEL 0x10101010 +#define MDP_IMGTYPE2_START 0x10000 +#define MSMFB_DRIVER_VERSION 0xF9E8D701 + +enum { + NOTIFY_UPDATE_START, + NOTIFY_UPDATE_STOP, +}; + +enum { + MDP_RGB_565, /* RGB 565 planer */ + MDP_XRGB_8888, /* RGB 888 padded */ + MDP_Y_CBCR_H2V2, /* Y and CbCr, pseudo planer w/ Cb is in MSB */ + MDP_Y_CBCR_H2V2_ADRENO, + MDP_ARGB_8888, /* ARGB 888 */ + MDP_RGB_888, /* RGB 888 planer */ + MDP_Y_CRCB_H2V2, /* Y and CrCb, pseudo planer w/ Cr is in MSB */ + MDP_YCRYCB_H2V1, /* YCrYCb interleave */ + MDP_Y_CRCB_H2V1, /* Y and CrCb, pseduo planer w/ Cr is in MSB */ + MDP_Y_CBCR_H2V1, /* Y and CrCb, pseduo planer w/ Cr is in MSB */ + MDP_RGBA_8888, /* ARGB 888 */ + MDP_BGRA_8888, /* ABGR 888 */ + MDP_RGBX_8888, /* RGBX 888 */ + MDP_Y_CRCB_H2V2_TILE, /* Y and CrCb, pseudo planer tile */ + MDP_Y_CBCR_H2V2_TILE, /* Y and CbCr, pseudo planer tile */ + MDP_Y_CR_CB_H2V2, /* Y, Cr and Cb, planar */ + MDP_Y_CR_CB_GH2V2, /* Y, Cr and Cb, planar aligned to Android YV12 */ + MDP_Y_CB_CR_H2V2, /* Y, Cb and Cr, planar */ + MDP_Y_CRCB_H1V1, /* Y and CrCb, pseduo planer w/ Cr is in MSB */ + MDP_Y_CBCR_H1V1, /* Y and CbCr, pseduo planer w/ Cb is in MSB */ + MDP_IMGTYPE_LIMIT, + MDP_BGR_565 = MDP_IMGTYPE2_START, /* BGR 565 planer */ + MDP_FB_FORMAT, /* framebuffer format */ + MDP_IMGTYPE_LIMIT2 /* Non valid image type after this enum */ +}; + +enum { + PMEM_IMG, + FB_IMG, +}; + +enum { + HSIC_HUE = 0, + HSIC_SAT, + HSIC_INT, + HSIC_CON, + NUM_HSIC_PARAM, +}; + +/* mdp_blit_req flag values */ +#define MDP_ROT_NOP 0 +#define MDP_FLIP_LR 0x1 +#define MDP_FLIP_UD 0x2 +#define MDP_ROT_90 0x4 +#define MDP_ROT_180 (MDP_FLIP_UD|MDP_FLIP_LR) +#define MDP_ROT_270 (MDP_ROT_90|MDP_FLIP_UD|MDP_FLIP_LR) +#define MDP_DITHER 0x8 +#define MDP_BLUR 0x10 +#define MDP_BLEND_FG_PREMULT 0x20000 +#define MDP_DEINTERLACE 0x80000000 +#define MDP_SHARPENING 0x40000000 +#define MDP_NO_DMA_BARRIER_START 0x20000000 +#define MDP_NO_DMA_BARRIER_END 0x10000000 +#define MDP_NO_BLIT 0x08000000 +#define MDP_BLIT_WITH_DMA_BARRIERS 0x000 +#define MDP_BLIT_WITH_NO_DMA_BARRIERS \ + (MDP_NO_DMA_BARRIER_START | MDP_NO_DMA_BARRIER_END) +#define MDP_BLIT_SRC_GEM 0x04000000 +#define MDP_BLIT_DST_GEM 0x02000000 +#define MDP_BLIT_NON_CACHED 0x01000000 +#define MDP_OV_PIPE_SHARE 0x00800000 +#define MDP_DEINTERLACE_ODD 0x00400000 +#define MDP_OV_PLAY_NOWAIT 0x00200000 +#define MDP_SOURCE_ROTATED_90 0x00100000 +#define MDP_DPP_HSIC 0x00080000 +#define MDP_BACKEND_COMPOSITION 0x00040000 +#define MDP_BORDERFILL_SUPPORTED 0x00010000 +#define MDP_SECURE_OVERLAY_SESSION 0x00008000 +#define MDP_MEMORY_ID_TYPE_FB 0x00001000 + +#define MDP_TRANSP_NOP 0xffffffff +#define MDP_ALPHA_NOP 0xff + +#define MDP_FB_PAGE_PROTECTION_NONCACHED (0) +#define MDP_FB_PAGE_PROTECTION_WRITECOMBINE (1) +#define MDP_FB_PAGE_PROTECTION_WRITETHROUGHCACHE (2) +#define MDP_FB_PAGE_PROTECTION_WRITEBACKCACHE (3) +#define MDP_FB_PAGE_PROTECTION_WRITEBACKWACACHE (4) +/* Sentinel: Don't use! */ +#define MDP_FB_PAGE_PROTECTION_INVALID (5) +/* Count of the number of MDP_FB_PAGE_PROTECTION_... values. */ +#define MDP_NUM_FB_PAGE_PROTECTION_VALUES (5) + +struct mdp_rect { + uint32_t x; + uint32_t y; + uint32_t w; + uint32_t h; +}; + +struct mdp_img { + uint32_t width; + uint32_t height; + uint32_t format; + uint32_t offset; + int memory_id; /* the file descriptor */ + uint32_t priv; +}; + +/* + * {3x3} + {3} ccs matrix + */ + +#define MDP_CCS_RGB2YUV 0 +#define MDP_CCS_YUV2RGB 1 + +#define MDP_CCS_SIZE 9 +#define MDP_BV_SIZE 3 + +struct mdp_ccs { + int direction; /* MDP_CCS_RGB2YUV or YUV2RGB */ + uint16_t ccs[MDP_CCS_SIZE]; /* 3x3 color coefficients */ + uint16_t bv[MDP_BV_SIZE]; /* 1x3 bias vector */ +}; + +struct mdp_csc { + int id; + uint32_t csc_mv[9]; + uint32_t csc_pre_bv[3]; + uint32_t csc_post_bv[3]; + uint32_t csc_pre_lv[6]; + uint32_t csc_post_lv[6]; +}; + +/* The version of the mdp_blit_req structure so that + * user applications can selectively decide which functionality + * to include + */ + +#define MDP_BLIT_REQ_VERSION 2 + +struct mdp_blit_req { + struct mdp_img src; + struct mdp_img dst; + struct mdp_rect src_rect; + struct mdp_rect dst_rect; + uint32_t alpha; + uint32_t transp_mask; + uint32_t flags; + int sharpening_strength; /* -127 <--> 127, default 64 */ +}; + +struct mdp_blit_req_list { + uint32_t count; + struct mdp_blit_req req[]; +}; + +#define MSMFB_DATA_VERSION 2 + +struct msmfb_data { + uint32_t offset; + int memory_id; + int id; + uint32_t flags; + uint32_t priv; + uint32_t iova; +}; + +#define MSMFB_NEW_REQUEST -1 + +struct msmfb_overlay_data { + uint32_t id; + struct msmfb_data data; + uint32_t version_key; + struct msmfb_data plane1_data; + struct msmfb_data plane2_data; +}; + +struct msmfb_img { + uint32_t width; + uint32_t height; + uint32_t format; +}; + +#define MSMFB_WRITEBACK_DEQUEUE_BLOCKING 0x1 +struct msmfb_writeback_data { + struct msmfb_data buf_info; + struct msmfb_img img; +}; + +struct dpp_ctrl { + /* + *'sharp_strength' has inputs = -128 <-> 127 + * Increasingly positive values correlate with increasingly sharper + * picture. Increasingly negative values correlate with increasingly + * smoothed picture. + */ + int8_t sharp_strength; + int8_t hsic_params[NUM_HSIC_PARAM]; +}; + +struct mdp_overlay { + struct msmfb_img src; + struct mdp_rect src_rect; + struct mdp_rect dst_rect; + uint32_t z_order; /* stage number */ + uint32_t is_fg; /* control alpha & transp */ + uint32_t alpha; + uint32_t transp_mask; + uint32_t flags; + uint32_t id; + uint32_t user_data[8]; + struct dpp_ctrl dpp; +}; + +struct msmfb_overlay_3d { + uint32_t is_3d; + uint32_t width; + uint32_t height; +}; + + +struct msmfb_overlay_blt { + uint32_t enable; + uint32_t offset; + uint32_t width; + uint32_t height; + uint32_t bpp; +}; + +struct mdp_histogram { + uint32_t frame_cnt; + uint32_t bin_cnt; + uint32_t *r; + uint32_t *g; + uint32_t *b; +}; + + +/* + + mdp_block_type defines the identifiers for each of pipes in MDP 4.3 + + MDP_BLOCK_RESERVED is provided for backward compatibility and is + deprecated. It corresponds to DMA_P. So MDP_BLOCK_DMA_P should be used + instead. + +*/ + +enum { + MDP_BLOCK_RESERVED = 0, + MDP_BLOCK_OVERLAY_0, + MDP_BLOCK_OVERLAY_1, + MDP_BLOCK_VG_1, + MDP_BLOCK_VG_2, + MDP_BLOCK_RGB_1, + MDP_BLOCK_RGB_2, + MDP_BLOCK_DMA_P, + MDP_BLOCK_DMA_S, + MDP_BLOCK_DMA_E, + MDP_BLOCK_MAX, +}; + +struct mdp_pcc_coeff { + uint32_t c, r, g, b, rr, gg, bb, rg, gb, rb, rgb_0, rgb_1; +}; + +struct mdp_pcc_cfg_data { + uint32_t block; + uint32_t ops; + struct mdp_pcc_coeff r, g, b; +}; + +#define MDP_CSC_FLAG_ENABLE 0x1 +#define MDP_CSC_FLAG_YUV_IN 0x2 +#define MDP_CSC_FLAG_YUV_OUT 0x4 + +struct mdp_csc_cfg { + /* flags for enable CSC, toggling RGB,YUV input/output */ + uint32_t flags; + uint32_t csc_mv[9]; + uint32_t csc_pre_bv[3]; + uint32_t csc_post_bv[3]; + uint32_t csc_pre_lv[6]; + uint32_t csc_post_lv[6]; +}; + +struct mdp_csc_cfg_data { + uint32_t block; + struct mdp_csc_cfg csc_data; +}; + +enum { + mdp_lut_igc, + mdp_lut_pgc, + mdp_lut_hist, + mdp_lut_max, +}; + + +struct mdp_igc_lut_data { + uint32_t block; + uint32_t len, ops; + uint32_t *c0_c1_data; + uint32_t *c2_data; +}; + +struct mdp_ar_gc_lut_data { + uint32_t x_start; + uint32_t slope; + uint32_t offset; +}; + +struct mdp_pgc_lut_data { + uint32_t block; + uint32_t flags; + uint8_t num_r_stages; + uint8_t num_g_stages; + uint8_t num_b_stages; + struct mdp_ar_gc_lut_data *r_data; + struct mdp_ar_gc_lut_data *g_data; + struct mdp_ar_gc_lut_data *b_data; +}; + + +struct mdp_hist_lut_data { + uint32_t block; + uint32_t ops; + uint32_t len; + uint32_t *data; +}; + + +struct mdp_lut_cfg_data { + uint32_t lut_type; + union { + struct mdp_igc_lut_data igc_lut_data; + struct mdp_pgc_lut_data pgc_lut_data; + struct mdp_hist_lut_data hist_lut_data; + } data; +}; + +enum { + mdp_op_pcc_cfg, + mdp_op_csc_cfg, + mdp_op_lut_cfg, + mdp_op_max, +}; + +struct msmfb_mdp_pp { + uint32_t op; + union { + struct mdp_pcc_cfg_data pcc_cfg_data; + struct mdp_csc_cfg_data csc_cfg_data; + struct mdp_lut_cfg_data lut_cfg_data; + } data; +}; + + +struct mdp_page_protection { + uint32_t page_protection; +}; + + +struct mdp_mixer_info { + int pndx; + int pnum; + int ptype; + int mixer_num; + int z_order; +}; + +#define MAX_PIPE_PER_MIXER 4 + +struct msmfb_mixer_info_req { + int mixer_num; + int cnt; + struct mdp_mixer_info info[MAX_PIPE_PER_MIXER]; +}; + + +#ifdef __KERNEL__ + +/* get the framebuffer physical address information */ +int get_fb_phys_info(unsigned long *start, unsigned long *len, int fb_num); +struct fb_info *msm_fb_get_writeback_fb(void); +int msm_fb_writeback_init(struct fb_info *info); +int msm_fb_writeback_start(struct fb_info *info); +int msm_fb_writeback_queue_buffer(struct fb_info *info, + struct msmfb_data *data); +int msm_fb_writeback_dequeue_buffer(struct fb_info *info, + struct msmfb_data *data); +int msm_fb_writeback_stop(struct fb_info *info); +int msm_fb_writeback_terminate(struct fb_info *info); +#endif + +#endif /*_MSM_MDP_H_*/