pax_global_header00006660000000000000000000000064122073542560014520gustar00rootroot0000000000000052 comment=9983d3d8d0d55f9e97decb39121193adf56e7e5f xf86-video-armsoc-0.6.0/000077500000000000000000000000001220735425600147045ustar00rootroot00000000000000xf86-video-armsoc-0.6.0/.gitignore000066400000000000000000000004111220735425600166700ustar00rootroot00000000000000aclocal.m4 autom4te.cache Makefile.in Makefile .deps .libs *.o *.lo *.la libtool *.pc config.log config.status config.guess config.h config.h.in config.sub config configure install-sh ltmain.sh missing stamp-h1 depcomp .cproject .project .settings man/armsoc.4 /m4 xf86-video-armsoc-0.6.0/COPYING000066400000000000000000000021111220735425600157320ustar00rootroot00000000000000Copyright © 2011 Texas Instruments, Inc Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. xf86-video-armsoc-0.6.0/Makefile.am000066400000000000000000000024701220735425600167430ustar00rootroot00000000000000# Copyright 2005 Adam Jackson. # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # on the rights to use, copy, modify, merge, publish, distribute, sub # license, and/or sell copies of the Software, and to permit persons to whom # the Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice (including the next # paragraph) shall be included in all copies or substantial portions of the # Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL # ADAM JACKSON BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS} SUBDIRS = src man MAINTAINERCLEANFILES = ChangeLog INSTALL .PHONY: ChangeLog INSTALL INSTALL: $(INSTALL_CMD) ChangeLog: $(CHANGELOG_CMD) dist-hook: ChangeLog INSTALL xf86-video-armsoc-0.6.0/NEWS000066400000000000000000000000041220735425600153750ustar00rootroot00000000000000TBD xf86-video-armsoc-0.6.0/README000066400000000000000000000021231220735425600155620ustar00rootroot00000000000000xf86-video-armsoc Open-source X.org graphics driver for ARM graphics DRM driver selection -------------------- While most operations use only the standard DRM modesetting interfaces, certain operations unavoidably rely on specific driver behaviour (including dumb buffer allocation flags and cursor plane z-ordering). As such, the armsoc driver must be configured for a particular DRM driver. The currently supported DRM drivers are: - pl111 - exynos To configure armsoc for one of these, pass the --with-drmmode option to ./configure. For example: $ ./configure --with-drmmode=pl111 For other drivers, you will need to implement this support yourself. A template implementation is provided in src/drmmode_template which can be built by passing --with-drmmode=template to ./configure. The interface is defined and documented in src/drmmode_driver.h, and you should refer to this while modifying the template to set up your DRM driver's abstraction appropriately. You can also copy src/drmmode_template into src/drmmode_ and build with: $ ./configure --with-drmmode= xf86-video-armsoc-0.6.0/autogen.sh000077500000000000000000000014671220735425600167150ustar00rootroot00000000000000#! /bin/sh cd `dirname $0` # on some platforms, you have "g" versions of some of these tools instead, # ie glibtoolize instead of libtoolize.. find_tool() { which $1 2> /dev/null || which g$1 2> /dev/null } aclocal=`find_tool aclocal` libtoolize=`find_tool libtoolize` automake=`find_tool automake` autoconf=`find_tool autoconf` autoheader=`find_tool autoheader` mkdir -p config && $aclocal && $autoheader && $libtoolize --copy --force && $automake --copy --add-missing --foreign && $autoconf test -n "$NOCONFIGURE" && { echo "skipping configure stage as requested." echo "autogen.sh done." exit 0 } CONFIGURE_DEF_OPT="--enable-maintainer-mode" echo ./configure $CONFIGURE_DEF_OPT $* ./configure $CONFIGURE_DEF_OPT $* || { echo " configure failed" exit 1 } echo "Now type 'make' to compile" xf86-video-armsoc-0.6.0/configure.ac000066400000000000000000000056051220735425600172000ustar00rootroot00000000000000# -*- Autoconf -*- # # Copyright 2013 ARM # # 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 # ARM 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.60) AC_INIT([xf86-video-armsoc], [0.6.0], [], [xf86-video-armsoc]) AC_CONFIG_SRCDIR([Makefile.am]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_AUX_DIR(.) AC_CONFIG_MACRO_DIR([m4]) 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 # Initialize libtool LT_INIT([disable-static]) # Checks for programs. AC_PROG_CC AC_CHECK_HEADERS([sys/ioctl.h]) AC_CHECK_HEADERS([stdint.h]) AH_TOP([#include "xorg-server.h"]) AC_ARG_WITH(xorg-module-dir, AS_HELP_STRING([--with-xorg-module-dir=DIR], [Default xorg module directory [[default=$libdir/xorg/modules]]]), [moduledir="$withval"], [moduledir="$libdir/xorg/modules"]) AC_MSG_CHECKING([which DRM driver to use]) AC_ARG_WITH(drmmode, AS_HELP_STRING([--with-drmmode], [Which DRM driver to use (see README)]), [drmmode=$withval], AC_MSG_FAILURE([You must specify which DRM driver to build for - see README])) AC_MSG_RESULT([$drmmode]) AC_SUBST(drmmode) # Checks for extensions XORG_DRIVER_CHECK_EXT(RANDR, randrproto) XORG_DRIVER_CHECK_EXT(RENDER, renderproto) XORG_DRIVER_CHECK_EXT(DPMSExtension, xextproto) # Checks for pkg-config packages PKG_CHECK_MODULES(XORG, [xorg-server >= 1.10] xproto fontsproto libdrm dri2proto $REQUIRED_MODULES) # Checks for header files. AC_HEADER_STDC DRIVER_NAME=armsoc AC_SUBST([DRIVER_NAME]) AC_SUBST([moduledir]) AC_OUTPUT([ Makefile src/Makefile man/Makefile ]) xf86-video-armsoc-0.6.0/man/000077500000000000000000000000001220735425600154575ustar00rootroot00000000000000xf86-video-armsoc-0.6.0/man/Makefile.am000066400000000000000000000027351220735425600175220ustar00rootroot00000000000000# # Copyright 2005 Sun Microsystems, Inc. All rights reserved. # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice (including the next # paragraph) shall be included in all copies or substantial portions of the # Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. # drivermandir = $(DRIVER_MAN_DIR) driverman_DATA = $(DRIVER_NAME).$(DRIVER_MAN_SUFFIX) EXTRA_DIST = $(DRIVER_NAME).man CLEANFILES = $(driverman_DATA) # String replacements in MAN_SUBSTS now come from xorg-macros.m4 via configure SUFFIXES = .$(DRIVER_MAN_SUFFIX) .man .man.$(DRIVER_MAN_SUFFIX): $(AM_V_GEN)$(SED) $(MAN_SUBSTS) < $< > $@ xf86-video-armsoc-0.6.0/man/armsoc.man000066400000000000000000000077221220735425600174500ustar00rootroot00000000000000.\" shorthand for double quote that works everywhere. .ds q \N'34' .TH armsoc __drivermansuffix__ __vendorversion__ .SH NAME armsoc \- Arm SoC graphics .SH SYNOPSIS .nf .B "Section \*qDevice\*q" .BI " Identifier \*q" devname \*q .B " Driver \*qarmsoc\*q" \ \ ... .B EndSection .fi .SH DESCRIPTION .B armsoc is an __xservername__ driver for Arm Mali SoCs. .SH SUPPORTED HARDWARE .B armsoc supports the Mali-T400 & Mali-T60x .SH CONFIGURATION DETAILS Please refer to __xconfigfile__(__filemansuffix__) for general configuration details. This section only covers configuration details specific to this driver. .PP The following driver .B Options are supported .TP .BI "Option \*qDebug\*q \*q" boolean \*q Enable debug logging. .IP Default: Debug logging is Disabled .TP .BI "Option \*qNoFlip\*q \*q" boolean \*q Disable buffer flipping. .IP Default: Flipping is Enabled .TP .BI "Option \*qDriverName\*q \*q" string \*q The name of the drm driver to use. .IP Default: NULL .TP .BI "Option \*qBusID\*q \*q" string \*q The Bus ID of the drm device to use. .IP Default: NULL .TP .BI "Option \*qDRICard\*q \*q" integer \*q Select which dri card to use. .IP Default: 0 .SH DRM DEVICE SELECTION Either the DRM driver name or bus ID can be specified using e.g. .nf .B "Section \*qDevice\*q" .BI " Driver \*qarmsoc\*q" .BI " Option \*qDriverName\*q \*qpl111_drm\*q" .B "EndSection" or .B "Section \*qDevice\*q" .BI " Driver \*qarmsoc\*q" .BI " Option \*qBusID\*q \*qplatform:pl111_drm:00\*q" .B "EndSection" If neither of these are set then /dev/dri/card0 is used. In this case the card number can be set using the \*qDRICard\*q option. .B "Section \*qDevice\*q" .BI " Driver \*qarmsoc\*q" .BI " Option \*qDRICard\*q \*q1\*q" .B "EndSection" .SH OUTPUT CONFIGURATION The driver supports runtime configuration of detected outputs. You can use the .B xrandr tool to control outputs on the command line as follows: .RS .B xrandr \-\-output .I output .B \-\-set .I property value .RE Note that you may need to quote property and value arguments that contain spaces. Each output listed below may have one or more properties associated with it (like a binary EDID block if one is found). Some outputs have unique properties which are described below. See the "MULTIHEAD CONFIGURATIONS" section below for additional information. TODO .PP See __xconfigfile__(__filemansuffix__) for information on associating Monitor sections with these outputs for configuration. Associating Monitor sections with each output can be helpful if you need to ignore a specific output, for example, or statically configure an extended desktop monitor layout. .SH MULTIHEAD CONFIGURATIONS The number of independent outputs is dictated by the number of CRTCs (in X parlance) a given chip supports. The actual number of displays supported will depend on the board. But a built-in LCD and external HDMI are a common configuration. You can use the "xrandr" tool, or various desktop utilities, to change your output configuration at runtime. To statically configure your outputs, you can use the "Monitor-" options along with additional monitor sections in your xorg.conf to create your screen topology. The example below puts the VGA output to the right of the builtin laptop screen, both running at 1024x768. .nf .B "Section \*qMonitor\*q" .BI " Identifier \*qLaptop FooBar Internal Display\*q" .BI " Option \*qPosition\*q \*q0 0\*q" .B "EndSection" .B "Section \*qMonitor\*q" .BI " Identifier \*qSome Random CRT\*q" .BI " Option \*qPosition\*q \*q1024 0\*q" .BI " Option \*qRightOf\*q \*qLaptop FoodBar Internal Display\*q" .B "EndSection" .B "Section \*qDevice\*q" .BI " Driver \*qarmsoc\*q" .BI " Option \*qmonitor-LVDS\*q \*qLaptop FooBar Internal Display\*q" .BI " Option \*qmonitor-VGA\*q \*qSome Random CRT\*q" .B "EndSection" .SH "SEE ALSO" __xservername__(__appmansuffix__), __xconfigfile__(__filemansuffix__), Xserver(__appmansuffix__), X(__miscmansuffix__) .SH AUTHORS Authors include: Ian Elliott, Rob Clark. xf86-video-armsoc-0.6.0/src/000077500000000000000000000000001220735425600154735ustar00rootroot00000000000000xf86-video-armsoc-0.6.0/src/Makefile.am000066400000000000000000000045321220735425600175330ustar00rootroot00000000000000# Copyright © 2011 Texas Instruments Incorporated # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # on the rights to use, copy, modify, merge, publish, distribute, sub # license, and/or sell copies of the Software, and to permit persons to whom # the Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice (including the next # paragraph) shall be included in all copies or substantial portions of the # Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL # ADAM JACKSON BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Authors: # Ian Elliott # Rob Clark # this is obnoxious: # -module lets us name the module exactly how we want # -avoid-version prevents gratuitous .0.0.0 version numbers on the end # _ladir passes a dummy rpath to libtool so the thing will actually link # TODO: -nostdlib/-Bstatic/-lgcc platform magic, not installing the .a, etc. # TODO: probably should have configure script check for what is supported.. ERROR_CFLAGS = -Werror -Wall -Wdeclaration-after-statement -Wvla \ -Wpointer-arith -Wmissing-declarations -Wmissing-prototypes \ -Wwrite-strings -Wformat-nonliteral -Wformat-security \ -Wold-style-definition -Winit-self -Wmissing-include-dirs \ -Waddress -Waggregate-return -Wno-multichar -Wnested-externs AM_CFLAGS = @XORG_CFLAGS@ $(ERROR_CFLAGS) armsoc_drv_la_LTLIBRARIES = armsoc_drv.la armsoc_drv_la_LDFLAGS = -module -avoid-version -no-undefined armsoc_drv_la_LIBADD = @XORG_LIBS@ armsoc_drv_ladir = @moduledir@/drivers DRMMODE_SRCS = drmmode_@drmmode@/drmmode_@drmmode@.c armsoc_drv_la_SOURCES = \ drmmode_display.c \ armsoc_exa.c \ armsoc_exa_null.c \ armsoc_dri2.c \ armsoc_driver.c \ armsoc_dumb.c \ $(DRMMODE_SRCS) xf86-video-armsoc-0.6.0/src/armsoc_dri2.c000066400000000000000000000525751220735425600200610ustar00rootroot00000000000000/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ /* * Copyright © 2011 Texas Instruments, Inc * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Rob Clark */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "armsoc_driver.h" #include "armsoc_exa.h" #include "dri2.h" /* any point to support earlier? */ #if DRI2INFOREC_VERSION < 4 # error "Requires newer DRI2" #endif #include "drmmode_driver.h" struct ARMSOCDRI2BufferRec { DRI2BufferRec base; /** * Pixmap(s) that are backing the buffer * * NOTE: don't track the pixmap ptr for the front buffer if it is * a window.. this could get reallocated from beneath us, so we should * always use draw2pix to be sure to have the correct one */ PixmapPtr *pPixmaps; /** * Pixmap that corresponds to the DRI2BufferRec.name, so wraps * the buffer that will be used for DRI2GetBuffers calls and the * next DRI2SwapBuffers call. * * When using more than double buffering this (and the name) are updated * after a swap, before the next DRI2GetBuffers call. */ unsigned currentPixmap; /** * Number of Pixmaps to use. * * This allows the number of back buffers used to be reduced, for * example when allocation fails. It cannot be changed to increase the * number of buffers as we would overflow the pPixmaps array. */ unsigned numPixmaps; /** * The DRI2 buffers are reference counted to avoid crashyness when the * client detaches a dri2 drawable while we are still waiting for a * page_flip event. */ int refcnt; /** * The value of canflip() for the previous frame. Used so that we can * tell whether the buffer should be re-allocated, e.g into scanout-able * memory if the buffer can now be flipped. * * We don't want to re-allocate every frame because it is unnecessary * overhead most of the time apart from when we switch from flipping * to blitting or vice versa. * * We should bump the serial number of the drawable if canflip() returns * something different to what is stored here, so that the DRI2 buffers * will get re-allocated. */ int previous_canflip; }; #define ARMSOCBUF(p) ((struct ARMSOCDRI2BufferRec *)(p)) #define DRIBUF(p) ((DRI2BufferPtr)(&(p)->base)) static inline DrawablePtr dri2draw(DrawablePtr pDraw, DRI2BufferPtr buf) { if (buf->attachment == DRI2BufferFrontLeft) return pDraw; else { const unsigned curPix = ARMSOCBUF(buf)->currentPixmap; return &(ARMSOCBUF(buf)->pPixmaps[curPix]->drawable); } } static Bool canflip(DrawablePtr pDraw) { ScreenPtr pScreen = pDraw->pScreen; ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); if (pARMSOC->NoFlip) { /* flipping is disabled by user option */ return FALSE; } else { return (pDraw->type == DRAWABLE_WINDOW) && DRI2CanFlip(pDraw); } } static inline Bool exchangebufs(DrawablePtr pDraw, DRI2BufferPtr a, DRI2BufferPtr b) { PixmapPtr aPix = draw2pix(dri2draw(pDraw, a)); PixmapPtr bPix = draw2pix(dri2draw(pDraw, b)); ARMSOCPixmapExchange(aPix, bPix); exchange(a->name, b->name); return TRUE; } static PixmapPtr createpix(DrawablePtr pDraw) { ScreenPtr pScreen = pDraw->pScreen; int flags = canflip(pDraw) ? ARMSOC_CREATE_PIXMAP_SCANOUT : 0; return pScreen->CreatePixmap(pScreen, pDraw->width, pDraw->height, pDraw->depth, flags); } /** * Create Buffer. * * Note that 'format' is used from the client side to specify the DRI buffer * format, which could differ from the drawable format. For example, the * drawable could be 32b RGB, but the DRI buffer some YUV format (video) or * perhaps lower bit depth RGB (GL). The color conversion is handled when * blitting to front buffer, and page-flipping (overlay or flipchain) can * only be used if the display supports. */ static DRI2BufferPtr ARMSOCDRI2CreateBuffer(DrawablePtr pDraw, unsigned int attachment, unsigned int format) { ScreenPtr pScreen = pDraw->pScreen; ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; struct ARMSOCDRI2BufferRec *buf = calloc(1, sizeof(*buf)); struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); PixmapPtr pPixmap = NULL; struct armsoc_bo *bo; int ret; DEBUG_MSG("pDraw=%p, attachment=%d, format=%08x", pDraw, attachment, format); if (!buf) { ERROR_MSG("Couldn't allocate internal buffer structure"); return NULL; } if (attachment == DRI2BufferFrontLeft) { pPixmap = draw2pix(pDraw); pPixmap->refcnt++; } else { pPixmap = createpix(pDraw); } if (!pPixmap) { assert(attachment != DRI2BufferFrontLeft); ERROR_MSG("Failed to create back buffer for window"); goto fail; } if (attachment == DRI2BufferBackLeft && pARMSOC->driNumBufs > 2) { buf->pPixmaps = calloc(pARMSOC->driNumBufs-1, sizeof(PixmapPtr)); buf->numPixmaps = pARMSOC->driNumBufs-1; } else { buf->pPixmaps = malloc(sizeof(PixmapPtr)); buf->numPixmaps = 1; } if (!buf->pPixmaps) { ERROR_MSG("Failed to allocate PixmapPtr array for DRI2Buffer"); goto fail; } buf->pPixmaps[0] = pPixmap; assert(buf->currentPixmap == 0); bo = ARMSOCPixmapBo(pPixmap); if (!bo) { ERROR_MSG( "Attempting to DRI2 wrap a pixmap with no DRM buffer object backing"); goto fail; } DRIBUF(buf)->attachment = attachment; DRIBUF(buf)->pitch = exaGetPixmapPitch(pPixmap); DRIBUF(buf)->cpp = pPixmap->drawable.bitsPerPixel / 8; DRIBUF(buf)->format = format; DRIBUF(buf)->flags = 0; buf->refcnt = 1; buf->previous_canflip = -1; ret = armsoc_bo_get_name(bo, &DRIBUF(buf)->name); if (ret) { ERROR_MSG("could not get buffer name: %d", ret); goto fail; } if (canflip(pDraw) && attachment != DRI2BufferFrontLeft) { /* Create an fb around this buffer. This will fail and we will * fall back to blitting if the display controller hardware * cannot scan out this buffer (for example, if it doesn't * support the format or there was insufficient scanout memory * at buffer creation time). */ int ret = armsoc_bo_add_fb(bo); if (ret) { WARNING_MSG( "Falling back to blitting a flippable window"); } } /* Register Pixmap as having a buffer that can be accessed externally, * so needs synchronised access */ ARMSOCRegisterExternalAccess(pPixmap); return DRIBUF(buf); fail: if (pPixmap != NULL) { if (attachment != DRI2BufferFrontLeft) pScreen->DestroyPixmap(pPixmap); else pPixmap->refcnt--; } free(buf->pPixmaps); free(buf); return NULL; } /** * Destroy Buffer */ static void ARMSOCDRI2DestroyBuffer(DrawablePtr pDraw, DRI2BufferPtr buffer) { struct ARMSOCDRI2BufferRec *buf = ARMSOCBUF(buffer); /* Note: pDraw may already be deleted, so use the pPixmap here * instead (since it is at least refcntd) */ ScreenPtr pScreen = buf->pPixmaps[0]->drawable.pScreen; ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); int numBuffers, i; if (--buf->refcnt > 0) return; DEBUG_MSG("pDraw=%p, buffer=%p", pDraw, buffer); if (buffer->attachment == DRI2BufferBackLeft) { assert(pARMSOC->driNumBufs > 1); numBuffers = pARMSOC->driNumBufs-1; } else numBuffers = 1; for (i = 0; i < numBuffers && buf->pPixmaps[i] != NULL; i++) { ARMSOCDeregisterExternalAccess(buf->pPixmaps[i]); pScreen->DestroyPixmap(buf->pPixmaps[i]); } free(buf->pPixmaps); free(buf); } static void ARMSOCDRI2ReferenceBuffer(DRI2BufferPtr buffer) { struct ARMSOCDRI2BufferRec *buf = ARMSOCBUF(buffer); buf->refcnt++; } /** * */ static void ARMSOCDRI2CopyRegion(DrawablePtr pDraw, RegionPtr pRegion, DRI2BufferPtr pDstBuffer, DRI2BufferPtr pSrcBuffer) { ScreenPtr pScreen = pDraw->pScreen; ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; DrawablePtr pSrcDraw = dri2draw(pDraw, pSrcBuffer); DrawablePtr pDstDraw = dri2draw(pDraw, pDstBuffer); RegionPtr pCopyClip; GCPtr pGC; DEBUG_MSG("pDraw=%p, pDstBuffer=%p (%p), pSrcBuffer=%p (%p)", pDraw, pDstBuffer, pSrcDraw, pSrcBuffer, pDstDraw); pGC = GetScratchGC(pDstDraw->depth, pScreen); if (!pGC) return; pCopyClip = REGION_CREATE(pScreen, NULL, 0); RegionCopy(pCopyClip, pRegion); (*pGC->funcs->ChangeClip) (pGC, CT_REGION, pCopyClip, 0); ValidateGC(pDstDraw, pGC); /* If the dst is the framebuffer, and we had a way to * schedule a deferred blit synchronized w/ vsync, that * would be a nice thing to do utilize here to avoid * tearing.. when we have sync object support for GEM * buffers, I think we could do something more clever * here. */ pGC->ops->CopyArea(pSrcDraw, pDstDraw, pGC, 0, 0, pDraw->width, pDraw->height, 0, 0); FreeScratchGC(pGC); } /** * Get current frame count and frame count timestamp, based on drawable's * crtc. */ static int ARMSOCDRI2GetMSC(DrawablePtr pDraw, CARD64 *ust, CARD64 *msc) { ScreenPtr pScreen = pDraw->pScreen; ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); drmVBlank vbl = { .request = { .type = DRM_VBLANK_RELATIVE, .sequence = 0, } }; int ret; if (!pARMSOC->drmmode_interface->vblank_query_supported) return FALSE; ret = drmWaitVBlank(pARMSOC->drmFD, &vbl); if (ret) { ERROR_MSG("get vblank counter failed: %s", strerror(errno)); return FALSE; } if (ust) *ust = ((CARD64)vbl.reply.tval_sec * 1000000) + vbl.reply.tval_usec; if (msc) *msc = vbl.reply.sequence; return TRUE; } #define ARMSOC_SWAP_FAKE_FLIP (1 << 0) #define ARMSOC_SWAP_FAIL (1 << 1) struct ARMSOCDRISwapCmd { int type; ClientPtr client; ScreenPtr pScreen; /* Note: store drawable ID, rather than drawable. It's possible that * the drawable can be destroyed while we wait for page flip event: */ XID draw_id; DRI2BufferPtr pDstBuffer; DRI2BufferPtr pSrcBuffer; DRI2SwapEventPtr func; int swapCount; int flags; void *data; }; static const char * const swap_names[] = { [DRI2_EXCHANGE_COMPLETE] = "exchange", [DRI2_BLIT_COMPLETE] = "blit", [DRI2_FLIP_COMPLETE] = "flip," }; static Bool allocNextBuffer(DrawablePtr pDraw, PixmapPtr *ppPixmap, uint32_t *name) { ScreenPtr pScreen = pDraw->pScreen; ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; struct armsoc_bo *bo; PixmapPtr pPixmap; int ret; uint32_t new_name; Bool extRegistered = FALSE; pPixmap = createpix(pDraw); if (!pPixmap) goto error; bo = ARMSOCPixmapBo(pPixmap); if (!bo) { WARNING_MSG( "Attempting to DRI2 wrap a pixmap with no DRM buffer object backing"); goto error; } ARMSOCRegisterExternalAccess(pPixmap); extRegistered = TRUE; ret = armsoc_bo_get_name(bo, &new_name); if (ret) { ERROR_MSG("Could not get buffer name: %d", ret); goto error; } if (!armsoc_bo_get_fb(bo)) { ret = armsoc_bo_add_fb(bo); /* Should always be able to add fb, as we only add more buffers * when flipping*/ if (ret) { ERROR_MSG( "Could not add framebuffer to additional back buffer"); goto error; } } /* No errors, update pixmap and name */ *ppPixmap = pPixmap; *name = new_name; return TRUE; error: /* revert to existing pixmap */ if (pPixmap) { if (extRegistered) ARMSOCDeregisterExternalAccess(pPixmap); pScreen->DestroyPixmap(pPixmap); } return FALSE; } static void nextBuffer(DrawablePtr pDraw, struct ARMSOCDRI2BufferRec *backBuf) { ScreenPtr pScreen = pDraw->pScreen; ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); if (pARMSOC->driNumBufs <= 2) { /*Only using double buffering, leave the pixmap as-is */ return; } backBuf->currentPixmap++; backBuf->currentPixmap %= backBuf->numPixmaps; if (backBuf->pPixmaps[backBuf->currentPixmap]) { /* Already allocated the next buffer - get the name and * early-out */ struct armsoc_bo *bo; int ret; bo = ARMSOCPixmapBo(backBuf->pPixmaps[backBuf->currentPixmap]); assert(bo); ret = armsoc_bo_get_name(bo, &DRIBUF(backBuf)->name); assert(!ret); } else { Bool ret; PixmapPtr * const curBackPix = &backBuf->pPixmaps[backBuf->currentPixmap]; ret = allocNextBuffer(pDraw, curBackPix, &DRIBUF(backBuf)->name); if (!ret) { /* can't have failed on the first buffer */ assert(backBuf->currentPixmap > 0); /* Fall back to last buffer */ backBuf->currentPixmap--; WARNING_MSG( "Failed to use the requested %d-buffering due to an allocation failure.\n" "Falling back to %d-buffering for this DRI2Drawable", backBuf->numPixmaps+1, backBuf->currentPixmap+2); backBuf->numPixmaps = backBuf->currentPixmap+1; } } } static struct armsoc_bo *boFromBuffer(DRI2BufferPtr buf) { PixmapPtr pPixmap; struct ARMSOCPixmapPrivRec *priv; pPixmap = ARMSOCBUF(buf)->pPixmaps[ARMSOCBUF(buf)->currentPixmap]; priv = exaGetPixmapDriverPrivate(pPixmap); return priv->bo; } void ARMSOCDRI2SwapComplete(struct ARMSOCDRISwapCmd *cmd) { ScreenPtr pScreen = cmd->pScreen; ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); DrawablePtr pDraw = NULL; int status; struct armsoc_bo *old_src_bo, *old_dst_bo; if (--cmd->swapCount > 0) return; /* Save the old source bo for unreference below */ old_src_bo = boFromBuffer(cmd->pSrcBuffer); old_dst_bo = boFromBuffer(cmd->pDstBuffer); if ((cmd->flags & ARMSOC_SWAP_FAIL) == 0) { DEBUG_MSG("%s complete: %d -> %d", swap_names[cmd->type], cmd->pSrcBuffer->attachment, cmd->pDstBuffer->attachment); status = dixLookupDrawable(&pDraw, cmd->draw_id, serverClient, M_ANY, DixWriteAccess); if (status == Success) { if (cmd->type != DRI2_BLIT_COMPLETE && (cmd->flags & ARMSOC_SWAP_FAKE_FLIP) == 0) { assert(cmd->type == DRI2_FLIP_COMPLETE); exchangebufs(pDraw, cmd->pSrcBuffer, cmd->pDstBuffer); if (cmd->pSrcBuffer->attachment == DRI2BufferBackLeft) nextBuffer(pDraw, ARMSOCBUF(cmd->pSrcBuffer)); } DRI2SwapComplete(cmd->client, pDraw, 0, 0, 0, cmd->type, cmd->func, cmd->data); if (cmd->type != DRI2_BLIT_COMPLETE && (cmd->flags & ARMSOC_SWAP_FAKE_FLIP) == 0) { assert(cmd->type == DRI2_FLIP_COMPLETE); set_scanout_bo(pScrn, boFromBuffer(cmd->pDstBuffer)); } } } /* drop extra refcnt we obtained prior to swap: */ ARMSOCDRI2DestroyBuffer(pDraw, cmd->pSrcBuffer); ARMSOCDRI2DestroyBuffer(pDraw, cmd->pDstBuffer); armsoc_bo_unreference(old_src_bo); armsoc_bo_unreference(old_dst_bo); pARMSOC->pending_flips--; free(cmd); } /** * ScheduleSwap is responsible for requesting a DRM vblank event for the * appropriate frame. * * In the case of a blit (e.g. for a windowed swap) or buffer exchange, * the vblank requested can simply be the last queued swap frame + the swap * interval for the drawable. * * In the case of a page flip, we request an event for the last queued swap * frame + swap interval - 1, since we'll need to queue the flip for the frame * immediately following the received event. */ static int ARMSOCDRI2ScheduleSwap(ClientPtr client, DrawablePtr pDraw, DRI2BufferPtr pDstBuffer, DRI2BufferPtr pSrcBuffer, CARD64 *target_msc, CARD64 divisor, CARD64 remainder, DRI2SwapEventPtr func, void *data) { ScreenPtr pScreen = pDraw->pScreen; ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); struct ARMSOCDRI2BufferRec *src = ARMSOCBUF(pSrcBuffer); struct ARMSOCDRI2BufferRec *dst = ARMSOCBUF(pDstBuffer); struct ARMSOCDRISwapCmd *cmd = calloc(1, sizeof(*cmd)); struct armsoc_bo *src_bo, *dst_bo; int src_fb_id, dst_fb_id; int new_canflip, ret, do_flip; if (!cmd) return FALSE; cmd->client = client; cmd->pScreen = pScreen; cmd->draw_id = pDraw->id; cmd->pSrcBuffer = pSrcBuffer; cmd->pDstBuffer = pDstBuffer; cmd->swapCount = 0; cmd->flags = 0; cmd->func = func; cmd->data = data; DEBUG_MSG("%d -> %d", pSrcBuffer->attachment, pDstBuffer->attachment); /* obtain extra ref on buffers to avoid them going away while we await * the page flip event: */ ARMSOCDRI2ReferenceBuffer(pSrcBuffer); ARMSOCDRI2ReferenceBuffer(pDstBuffer); pARMSOC->pending_flips++; src_bo = boFromBuffer(pSrcBuffer); dst_bo = boFromBuffer(pDstBuffer); src_fb_id = armsoc_bo_get_fb(src_bo); dst_fb_id = armsoc_bo_get_fb(dst_bo); new_canflip = canflip(pDraw); if ((src->previous_canflip != -1 && src->previous_canflip != new_canflip) || (dst->previous_canflip != -1 && dst->previous_canflip != new_canflip)) { /* The drawable has transitioned between being flippable and * non-flippable or vice versa. Bump the serial number to force * the DRI2 buffers to be re-allocated during the next frame so * that: * - It is able to be scanned out * (if drawable is now flippable), or * - It is not taking up possibly scarce scanout-able memory * (if drawable is now not flippable) */ PixmapPtr pPix = pScreen->GetWindowPixmap((WindowPtr)pDraw); pPix->drawable.serialNumber = NEXT_SERIAL_NUMBER; } src->previous_canflip = new_canflip; dst->previous_canflip = new_canflip; armsoc_bo_reference(src_bo); armsoc_bo_reference(dst_bo); do_flip = src_fb_id && dst_fb_id && canflip(pDraw); /* After a resolution change the back buffer (src) will still be * of the original size. We can't sensibly flip to a framebuffer of * a different size to the current resolution (it will look corrupted) * so we must do a copy for this frame (which will clip the contents * as expected). * * Once the client calls DRI2GetBuffers again, it will receive a new * back buffer of the same size as the new resolution, and subsequent * DRI2SwapBuffers will result in a flip. */ do_flip = do_flip && (armsoc_bo_width(src_bo) == armsoc_bo_width(dst_bo)); do_flip = do_flip && (armsoc_bo_height(src_bo) == armsoc_bo_height(dst_bo)); if (do_flip) { DEBUG_MSG("can flip: %d -> %d", src_fb_id, dst_fb_id); cmd->type = DRI2_FLIP_COMPLETE; /* TODO: MIDEGL-1461: Handle rollback if multiple CRTC flip is * only partially successful */ ret = drmmode_page_flip(pDraw, src_fb_id, cmd); /* If using page flip events, we'll trigger an immediate * completion in the case that no CRTCs were enabled to be * flipped. If not using page flip events, trigger immediate * completion unconditionally. */ if (ret < 0) { /* * Error while flipping; bail. */ cmd->flags |= ARMSOC_SWAP_FAIL; if (pARMSOC->drmmode_interface->use_page_flip_events) cmd->swapCount = -(ret + 1); else cmd->swapCount = 0; if (cmd->swapCount == 0) ARMSOCDRI2SwapComplete(cmd); return FALSE; } else { if (ret == 0) cmd->flags |= ARMSOC_SWAP_FAKE_FLIP; if (pARMSOC->drmmode_interface->use_page_flip_events) cmd->swapCount = ret; else cmd->swapCount = 0; if (cmd->swapCount == 0) ARMSOCDRI2SwapComplete(cmd); } } else { /* fallback to blit: */ BoxRec box = { .x1 = 0, .y1 = 0, .x2 = pDraw->width, .y2 = pDraw->height, }; RegionRec region; RegionInit(®ion, &box, 0); ARMSOCDRI2CopyRegion(pDraw, ®ion, pDstBuffer, pSrcBuffer); cmd->type = DRI2_BLIT_COMPLETE; ARMSOCDRI2SwapComplete(cmd); } return TRUE; } /** * Request a DRM event when the requested conditions will be satisfied. * * We need to handle the event and ask the server to wake up the client when * we receive it. */ static int ARMSOCDRI2ScheduleWaitMSC(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc, CARD64 divisor, CARD64 remainder) { ScreenPtr pScreen = pDraw->pScreen; ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; ERROR_MSG("not implemented"); return FALSE; } /** * The DRI2 ScreenInit() function.. register our handler fxns w/ DRI2 core */ Bool ARMSOCDRI2ScreenInit(ScreenPtr pScreen) { ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); DRI2InfoRec info = { .version = 5, .fd = pARMSOC->drmFD, .driverName = "armsoc", .deviceName = pARMSOC->deviceName, .CreateBuffer = ARMSOCDRI2CreateBuffer, .DestroyBuffer = ARMSOCDRI2DestroyBuffer, .CopyRegion = ARMSOCDRI2CopyRegion, .ScheduleSwap = ARMSOCDRI2ScheduleSwap, .ScheduleWaitMSC = ARMSOCDRI2ScheduleWaitMSC, .GetMSC = ARMSOCDRI2GetMSC, .AuthMagic = drmAuthMagic, }; int minor = 1, major = 0; if (xf86LoaderCheckSymbol("DRI2Version")) DRI2Version(&major, &minor); if (minor < 1) { WARNING_MSG("DRI2 requires DRI2 module version 1.1.0 or later"); return FALSE; } return DRI2ScreenInit(pScreen, &info); } /** * The DRI2 CloseScreen() function.. unregister ourself w/ DRI2 core. */ void ARMSOCDRI2CloseScreen(ScreenPtr pScreen) { ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); while (pARMSOC->pending_flips > 0) { DEBUG_MSG("waiting.."); drmmode_wait_for_event(pScrn); } DRI2CloseScreen(pScreen); } xf86-video-armsoc-0.6.0/src/armsoc_driver.c000066400000000000000000000762501220735425600205100ustar00rootroot00000000000000/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ /* * Copyright © 2011 Texas Instruments, Inc * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Ian Elliott * Rob Clark */ #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "armsoc_driver.h" #include "micmap.h" #include "xf86cmap.h" #include "xf86RandR12.h" #include "compat-api.h" #include "drmmode_driver.h" #define DRM_DEVICE "/dev/dri/card%d" Bool armsocDebug; /* * Forward declarations: */ static const OptionInfoRec *ARMSOCAvailableOptions(int chipid, int busid); static void ARMSOCIdentify(int flags); static Bool ARMSOCProbe(DriverPtr drv, int flags); static Bool ARMSOCPreInit(ScrnInfoPtr pScrn, int flags); static Bool ARMSOCScreenInit(SCREEN_INIT_ARGS_DECL); static void ARMSOCLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, LOCO *colors, VisualPtr pVisual); static Bool ARMSOCCloseScreen(CLOSE_SCREEN_ARGS_DECL); static Bool ARMSOCCreateScreenResources(ScreenPtr pScreen); static void ARMSOCBlockHandler(BLOCKHANDLER_ARGS_DECL); static Bool ARMSOCSwitchMode(SWITCH_MODE_ARGS_DECL); static void ARMSOCAdjustFrame(ADJUST_FRAME_ARGS_DECL); static Bool ARMSOCEnterVT(VT_FUNC_ARGS_DECL); static void ARMSOCLeaveVT(VT_FUNC_ARGS_DECL); static void ARMSOCFreeScreen(FREE_SCREEN_ARGS_DECL); /** * A structure used by the XFree86 code when loading this driver, so that it * can access the Probe() function, and other functions/info that it uses * before it calls the Probe() function. The name of this structure must be * the all-upper-case version of the driver name. */ _X_EXPORT DriverRec ARMSOC = { ARMSOC_VERSION, (char *)ARMSOC_DRIVER_NAME, ARMSOCIdentify, ARMSOCProbe, ARMSOCAvailableOptions, NULL, 0, NULL, #ifdef XSERVER_LIBPCIACCESS NULL, NULL #endif }; #define MALI_4XX_CHIPSET_ID (0x0400) #define MALI_T6XX_CHIPSET_ID (0x0600) /** Supported "chipsets." */ static SymTabRec ARMSOCChipsets[] = { { MALI_4XX_CHIPSET_ID, "Mali-4XX" }, { MALI_T6XX_CHIPSET_ID, "Mali-T6XX" }, {-1, NULL } }; /** Supported options, as enum values. */ enum { OPTION_DEBUG, OPTION_NO_FLIP, OPTION_CARD_NUM, OPTION_BUSID, OPTION_DRIVERNAME, OPTION_DRI_NUM_BUF, }; /** Supported options. */ static const OptionInfoRec ARMSOCOptions[] = { { OPTION_DEBUG, "Debug", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_NO_FLIP, "NoFlip", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_CARD_NUM, "DRICard", OPTV_INTEGER, {0}, FALSE }, { OPTION_BUSID, "BusID", OPTV_STRING, {0}, FALSE }, { OPTION_DRIVERNAME, "DriverName", OPTV_STRING, {0}, FALSE }, { OPTION_DRI_NUM_BUF, "DRI2MaxBuffers", OPTV_INTEGER, {-1}, FALSE }, { -1, NULL, OPTV_NONE, {0}, FALSE } }; /** * Helper functions for sharing a DRM connection across screens. */ static struct ARMSOCConnection { const char *driver_name; const char *bus_id; unsigned int card_num; int fd; int open_count; int master_count; } connection = {NULL, NULL, 0, -1, 0, 0}; static int ARMSOCSetDRMMaster(void) { int ret = 0; assert(connection.fd >= 0); if (!connection.master_count) ret = drmSetMaster(connection.fd); if (!ret) connection.master_count++; return ret; } static int ARMSOCDropDRMMaster(void) { int ret = 0; assert(connection.fd >= 0); assert(connection.master_count > 0); if (1 == connection.master_count) ret = drmDropMaster(connection.fd); if (!ret) connection.master_count--; return ret; } static void ARMSOCShowDriverInfo(int fd) { char *bus_id; drmVersionPtr version; char *deviceName; EARLY_INFO_MSG("Opened DRM"); deviceName = drmGetDeviceNameFromFd(fd); EARLY_INFO_MSG(" DeviceName is [%s]", deviceName ? deviceName : "NULL"); drmFree(deviceName); bus_id = drmGetBusid(fd); EARLY_INFO_MSG(" bus_id is [%s]", bus_id ? bus_id : "NULL"); drmFreeBusid(bus_id); version = drmGetVersion(fd); if (version) { EARLY_INFO_MSG(" DriverName is [%s]", version->name); EARLY_INFO_MSG(" version is [%d.%d.%d]", version->version_major, version->version_minor, version->version_patchlevel); drmFreeVersion(version); } else { EARLY_INFO_MSG(" version is [NULL]"); } return; } static int ARMSOCOpenDRMCard(void) { int fd; if ((connection.bus_id) || (connection.driver_name)) { /* user specified bus ID or driver name - pass to drmOpen */ EARLY_INFO_MSG("Opening driver [%s], bus_id [%s]", connection.driver_name ? connection.driver_name : "NULL", connection.bus_id ? connection.bus_id : "NULL"); fd = drmOpen(connection.driver_name, connection.bus_id); if (fd < 0) goto fail2; } else { char filename[32]; int err; drmSetVersion sv; char *bus_id, *bus_id_copy; /* open with card_num */ snprintf(filename, sizeof(filename), DRM_DEVICE, connection.card_num); EARLY_INFO_MSG( "No BusID or DriverName specified - opening %s", filename); fd = open(filename, O_RDWR, 0); if (-1 == fd) goto fail2; /* Set interface version to initialise bus id */ sv.drm_di_major = 1; sv.drm_di_minor = 1; sv.drm_dd_major = -1; sv.drm_dd_minor = -1; err = drmSetInterfaceVersion(fd, &sv); if (err) { EARLY_ERROR_MSG( "Cannot set the DRM interface version."); goto fail1; } /* get the bus id */ bus_id = drmGetBusid(fd); if (!bus_id) { EARLY_ERROR_MSG("Couldn't get BusID from %s", filename); goto fail1; } EARLY_INFO_MSG("Got BusID %s", bus_id); bus_id_copy = malloc(strlen(bus_id)+1); if (!bus_id_copy) { EARLY_ERROR_MSG("Memory alloc failed"); goto fail1; } strcpy(bus_id_copy, bus_id); drmFreeBusid(bus_id); err = close(fd); if (err) { free(bus_id_copy); EARLY_ERROR_MSG("Couldn't close %s", filename); goto fail2; } /* use bus_id to open driver */ fd = drmOpen(NULL, bus_id_copy); free(bus_id_copy); if (fd < 0) goto fail2; } ARMSOCShowDriverInfo(fd); return fd; fail1: close(fd); fail2: EARLY_ERROR_MSG( "Cannot open a connection with the DRM - %s", strerror(errno)); return -1; } static Bool ARMSOCOpenDRM(ScrnInfoPtr pScrn) { struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); drmSetVersion sv; int err; if (connection.fd < 0) { assert(!connection.open_count); assert(!connection.master_count); pARMSOC->drmFD = ARMSOCOpenDRMCard(); if (pARMSOC->drmFD < 0) return FALSE; /* Check that what we are or can become drm master by * attempting a drmSetInterfaceVersion(). If successful * this leaves us as master. * (see DRIOpenDRMMaster() in DRI1) */ sv.drm_di_major = 1; sv.drm_di_minor = 1; sv.drm_dd_major = -1; sv.drm_dd_minor = -1; err = drmSetInterfaceVersion(pARMSOC->drmFD, &sv); if (err != 0) { ERROR_MSG("Cannot set the DRM interface version."); drmClose(pARMSOC->drmFD); pARMSOC->drmFD = -1; return FALSE; } connection.fd = pARMSOC->drmFD; connection.open_count = 1; connection.master_count = 1; drmmode_init_wakeup_handler(connection.fd); } else { assert(connection.open_count); connection.open_count++; connection.master_count++; pARMSOC->drmFD = connection.fd; } pARMSOC->deviceName = drmGetDeviceNameFromFd(pARMSOC->drmFD); return TRUE; } /** * Helper function for closing a connection to the DRM. */ static void ARMSOCCloseDRM(ScrnInfoPtr pScrn) { struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); if (pARMSOC && (pARMSOC->drmFD >= 0)) { drmFree(pARMSOC->deviceName); connection.open_count--; if (!connection.open_count) { assert(!connection.master_count); drmmode_fini_wakeup_handler(connection.fd); drmClose(pARMSOC->drmFD); connection.fd = -1; } pARMSOC->drmFD = -1; } } /** Let the XFree86 code know the Setup() function. */ static MODULESETUPPROTO(ARMSOCSetup); /** Provide basic version information to the XFree86 code. */ static XF86ModuleVersionInfo ARMSOCVersRec = { ARMSOC_DRIVER_NAME, MODULEVENDORSTRING, MODINFOSTRING1, MODINFOSTRING2, XORG_VERSION_CURRENT, PACKAGE_VERSION_MAJOR, PACKAGE_VERSION_MINOR, PACKAGE_VERSION_PATCHLEVEL, ABI_CLASS_VIDEODRV, ABI_VIDEODRV_VERSION, MOD_CLASS_VIDEODRV, {0, 0, 0, 0} }; /** Let the XFree86 code know about the VersRec and Setup() function. */ _X_EXPORT XF86ModuleData armsocModuleData = { &ARMSOCVersRec, ARMSOCSetup, NULL }; /** * The first function that the XFree86 code calls, after loading this module. */ static pointer ARMSOCSetup(pointer module, pointer opts, int *errmaj, int *errmin) { static Bool setupDone = FALSE; /* This module should be loaded only once, but check to be sure: */ if (!setupDone) { setupDone = TRUE; xf86AddDriver(&ARMSOC, module, 0); /* The return value must be non-NULL on success even * though there is no TearDownProc. */ return (pointer) 1; } else { if (errmaj) *errmaj = LDR_ONCEONLY; return NULL; } } /** * The mandatory AvailableOptions() function. It returns the available driver * options to the "-configure" option, so that an xorg.conf file can be built * and the user can see which options are available for them to use. */ static const OptionInfoRec * ARMSOCAvailableOptions(int chipid, int busid) { return ARMSOCOptions; } /** * The mandatory Identify() function. It is run before Probe(), and prints out * an identifying message, which includes the chipset(s) the driver supports. */ static void ARMSOCIdentify(int flags) { xf86PrintChipsets(ARMSOC_NAME, "Driver for ARM compatible chipsets", ARMSOCChipsets); } /** * The driver's Probe() function. This function finds all instances of * ARM hardware that the driver supports (from within the "xorg.conf" * device sections), and for instances not already claimed by another driver, * claim the instances, and allocate a ScrnInfoRec. Only minimal hardware * probing is allowed here. */ static Bool ARMSOCProbe(DriverPtr drv, int flags) { int i; ScrnInfoPtr pScrn; GDevPtr *devSections = NULL; int numDevSections; Bool foundScreen = FALSE; /* Get the "xorg.conf" file device sections that match this driver, and * return (error out) if there are none: */ numDevSections = xf86MatchDevice(ARMSOC_DRIVER_NAME, &devSections); if (numDevSections <= 0) { EARLY_ERROR_MSG( "Did not find any matching device section in configuration file"); if (flags & PROBE_DETECT) { /* if we are probing, assume one and lets see if we can * open the device to confirm it is there: */ numDevSections = 1; } else { return FALSE; } } for (i = 0; i < numDevSections; i++) { int fd; if (devSections) { const char *busIdStr; const char *driverNameStr; const char *cardNumStr; /* get the Bus ID */ busIdStr = xf86FindOptionValue( devSections[i]->options, "BusID"); /* get the DriverName */ driverNameStr = xf86FindOptionValue( devSections[i]->options, "DriverName"); /* get the card_num from xorg.conf if present */ cardNumStr = xf86FindOptionValue( devSections[i]->options, "DRICard"); if (busIdStr && driverNameStr) { EARLY_WARNING_MSG( "Option DriverName ignored (BusID is specified)"); } if (busIdStr || driverNameStr) { if (cardNumStr) { EARLY_WARNING_MSG( "Option DRICard ignored (BusID or DriverName are specified)"); } } if (busIdStr) { if (0 == strlen(busIdStr)) { EARLY_ERROR_MSG( "Missing value for Option BusID"); return FALSE; } connection.bus_id = busIdStr; } else if (driverNameStr) { if (0 == strlen(driverNameStr)) { EARLY_ERROR_MSG( "Missing value for Option DriverName"); return FALSE; } connection.driver_name = driverNameStr; } else if (cardNumStr) { char *endptr; errno = 0; connection.card_num = strtol(cardNumStr, &endptr, 10); if (('\0' == *cardNumStr) || ('\0' != *endptr) || (errno != 0)) { EARLY_ERROR_MSG( "Bad Option DRICard value : %s", cardNumStr); return FALSE; } } } fd = ARMSOCOpenDRMCard(); if (fd >= 0) { struct ARMSOCRec *pARMSOC; /* Allocate the ScrnInfoRec */ pScrn = xf86AllocateScreen(drv, 0); if (!pScrn) { EARLY_ERROR_MSG( "Cannot allocate a ScrnInfoPtr"); return FALSE; } /* Allocate the driver's Screen-specific, "private" * data structure and hook it into the ScrnInfoRec's * driverPrivate field. */ pScrn->driverPrivate = calloc(1, sizeof(struct ARMSOCRec)); if (!pScrn->driverPrivate) return FALSE; pARMSOC = ARMSOCPTR(pScrn); /* initially mark to use all DRM crtcs */ pARMSOC->crtcNum = -1; if (flags & PROBE_DETECT) { /* just add the device.. we aren't a PCI device, * so call xf86AddBusDeviceToConfigure() * directly */ xf86AddBusDeviceToConfigure(ARMSOC_DRIVER_NAME, BUS_NONE, NULL, i); foundScreen = TRUE; drmClose(fd); continue; } if (devSections) { int entity = xf86ClaimNoSlot(drv, 0, devSections[i], TRUE); xf86AddEntityToScreen(pScrn, entity); } /* if there are multiple screens, use a separate * crtc for each one */ if (numDevSections > 1) pARMSOC->crtcNum = i; xf86Msg(X_INFO, "Screen:%d, CRTC:%d\n", pScrn->scrnIndex, pARMSOC->crtcNum); foundScreen = TRUE; pScrn->driverVersion = ARMSOC_VERSION; pScrn->driverName = (char *)ARMSOC_DRIVER_NAME; pScrn->name = (char *)ARMSOC_NAME; pScrn->Probe = ARMSOCProbe; pScrn->PreInit = ARMSOCPreInit; pScrn->ScreenInit = ARMSOCScreenInit; pScrn->SwitchMode = ARMSOCSwitchMode; pScrn->AdjustFrame = ARMSOCAdjustFrame; pScrn->EnterVT = ARMSOCEnterVT; pScrn->LeaveVT = ARMSOCLeaveVT; pScrn->FreeScreen = ARMSOCFreeScreen; /* would be nice to keep the connection open */ drmClose(fd); } } free(devSections); return foundScreen; } /** * The driver's PreInit() function. Additional hardware probing is allowed * now, including display configuration. */ static Bool ARMSOCPreInit(ScrnInfoPtr pScrn, int flags) { struct ARMSOCRec *pARMSOC; int default_depth, fbbpp; rgb defaultWeight = { 0, 0, 0 }; rgb defaultMask = { 0, 0, 0 }; Gamma defaultGamma = { 0.0, 0.0, 0.0 }; int i; int driNumBufs; TRACE_ENTER(); if (flags & PROBE_DETECT) { ERROR_MSG( "The %s driver does not support the \"-configure\" or \"-probe\" command line arguments.", ARMSOC_NAME); return FALSE; } /* Check the number of entities, and fail if it isn't one. */ if (pScrn->numEntities != 1) { ERROR_MSG( "Driver expected 1 entity, but found %d for screen %d", pScrn->numEntities, pScrn->scrnIndex); return FALSE; } pARMSOC = ARMSOCPTR(pScrn); pARMSOC->pEntityInfo = xf86GetEntityInfo(pScrn->entityList[0]); pScrn->monitor = pScrn->confScreen->monitor; /* Get the current depth, and set it for XFree86: */ default_depth = 24; /* TODO: MIDEGL-1445: get from kernel */ fbbpp = 32; /* TODO: MIDEGL-1445: get from kernel */ if (!xf86SetDepthBpp(pScrn, default_depth, 0, fbbpp, Support32bppFb)) { /* The above function prints an error message. */ goto fail; } xf86PrintDepthBpp(pScrn); /* Set the color weight: */ if (!xf86SetWeight(pScrn, defaultWeight, defaultMask)) { /* The above function prints an error message. */ goto fail; } /* Set the gamma: */ if (!xf86SetGamma(pScrn, defaultGamma)) { /* The above function prints an error message. */ goto fail; } /* Visual init: */ if (!xf86SetDefaultVisual(pScrn, -1)) { /* The above function prints an error message. */ goto fail; } /* We don't support 8-bit depths: */ if (pScrn->depth < 16) { ERROR_MSG( "The requested default visual (%s) has an unsupported depth (%d).", xf86GetVisualName(pScrn->defaultVisual), pScrn->depth); goto fail; } /* Using a programmable clock: */ pScrn->progClock = TRUE; /* Open a connection to the DRM, so we can communicate * with the KMS code: */ if (!ARMSOCOpenDRM(pScrn)) goto fail; pARMSOC->drmmode_interface = drmmode_interface_get_implementation(pARMSOC->drmFD); if (!pARMSOC->drmmode_interface) goto fail2; /* create DRM device instance: */ pARMSOC->dev = armsoc_device_new(pARMSOC->drmFD, pARMSOC->drmmode_interface->dumb_scanout_flags, pARMSOC->drmmode_interface->dumb_no_scanout_flags); /* find matching chipset name: */ for (i = 0; ARMSOCChipsets[i].name; i++) { if (ARMSOCChipsets[i].token == MALI_T6XX_CHIPSET_ID) { pScrn->chipset = (char *)ARMSOCChipsets[i].name; break; } } INFO_MSG("Chipset: %s", pScrn->chipset); /* * Process the "xorg.conf" file options: */ xf86CollectOptions(pScrn, NULL); pARMSOC->pOptionInfo = calloc(1, sizeof(ARMSOCOptions)); if (!pARMSOC->pOptionInfo) goto fail2; memcpy(pARMSOC->pOptionInfo, ARMSOCOptions, sizeof(ARMSOCOptions)); xf86ProcessOptions(pScrn->scrnIndex, pARMSOC->pEntityInfo->device->options, pARMSOC->pOptionInfo); /* Determine if the user wants debug messages turned on: */ armsocDebug = xf86ReturnOptValBool(pARMSOC->pOptionInfo, OPTION_DEBUG, FALSE); if (!xf86GetOptValInteger(pARMSOC->pOptionInfo, OPTION_DRI_NUM_BUF, &driNumBufs)) { /* Default to double buffering */ driNumBufs = 2; } if (driNumBufs < 2) { ERROR_MSG( "Invalid option for %s: %d. Must be greater than or equal to 2", xf86TokenToOptName(pARMSOC->pOptionInfo, OPTION_DRI_NUM_BUF), driNumBufs); return FALSE; } pARMSOC->driNumBufs = driNumBufs; /* Determine if user wants to disable buffer flipping: */ pARMSOC->NoFlip = xf86ReturnOptValBool(pARMSOC->pOptionInfo, OPTION_NO_FLIP, FALSE); INFO_MSG("Buffer Flipping is %s", pARMSOC->NoFlip ? "Disabled" : "Enabled"); /* * Select the video modes: */ INFO_MSG("Setting the video modes ..."); /* Don't call drmCheckModesettingSupported() as its written only for * PCI devices. */ /* Do initial KMS setup: */ if (!drmmode_pre_init(pScrn, pARMSOC->drmFD, (pScrn->bitsPerPixel >> 3))) { ERROR_MSG("Cannot get KMS resources"); goto fail2; } else { INFO_MSG("Got KMS resources"); } xf86RandR12PreInit(pScrn); /* Let XFree86 calculate or get (from command line) the display DPI: */ xf86SetDpi(pScrn, 0, 0); /* Ensure we have a supported depth: */ switch (pScrn->bitsPerPixel) { case 16: case 24: case 32: break; default: ERROR_MSG( "The requested number of bits per pixel (%d) is unsupported.", pScrn->bitsPerPixel); goto fail2; } /* Load external sub-modules now: */ if (!(xf86LoadSubModule(pScrn, "dri2") && xf86LoadSubModule(pScrn, "exa") && xf86LoadSubModule(pScrn, "fb"))) { goto fail2; } TRACE_EXIT(); return TRUE; fail2: /* Cleanup here where we know whether we took a connection * instead of in FreeScreen where we don't */ ARMSOCDropDRMMaster(); ARMSOCCloseDRM(pScrn); fail: TRACE_EXIT(); return FALSE; } /** * Initialize EXA and DRI2 */ static void ARMSOCAccelInit(ScreenPtr pScreen) { ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); if (!pARMSOC->pARMSOCEXA) pARMSOC->pARMSOCEXA = InitNullEXA(pScreen, pScrn, pARMSOC->drmFD); if (pARMSOC->pARMSOCEXA) pARMSOC->dri = ARMSOCDRI2ScreenInit(pScreen); else pARMSOC->dri = FALSE; } /** * The driver's ScreenInit() function, called at the start of each server * generation. Fill in pScreen, map the frame buffer, save state, * initialize the mode, etc. */ static Bool ARMSOCScreenInit(SCREEN_INIT_ARGS_DECL) { ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; #ifndef XF86_SCRN_INTERFACE int scrnIndex = pScrn->scrnIndex; #endif struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); VisualPtr visual; xf86CrtcConfigPtr xf86_config; int j; TRACE_ENTER(); /* set drm master before allocating scanout buffer */ if (ARMSOCSetDRMMaster()) { ERROR_MSG("Cannot get DRM master: %s", strerror(errno)); goto fail; } /* Allocate initial scanout buffer */ DEBUG_MSG("allocating new scanout buffer: %dx%d", pScrn->virtualX, pScrn->virtualY); assert(!pARMSOC->scanout); pARMSOC->scanout = armsoc_bo_new_with_dim(pARMSOC->dev, pScrn->virtualX, pScrn->virtualY, pScrn->depth, pScrn->bitsPerPixel, ARMSOC_BO_SCANOUT); if (!pARMSOC->scanout) { ERROR_MSG("Cannot allocate scanout buffer\n"); goto fail1; } pScrn->displayWidth = armsoc_bo_pitch(pARMSOC->scanout) / ((pScrn->bitsPerPixel+7) / 8); xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); /* need to point to new screen on server regeneration */ for (j = 0; j < xf86_config->num_crtc; j++) xf86_config->crtc[j]->scrn = pScrn; for (j = 0; j < xf86_config->num_output; j++) xf86_config->output[j]->scrn = pScrn; /* * The next step is to setup the screen's visuals, and initialize the * framebuffer code. In cases where the framebuffer's default * choices for things like visual layouts and bits per RGB are OK, * this may be as simple as calling the framebuffer's ScreenInit() * function. If not, the visuals will need to be setup before calling * a fb ScreenInit() function and fixed up after. * * For most PC hardware at depths >= 8, the defaults that fb uses * are not appropriate. In this driver, we fixup the visuals after. */ /* Reset the visual list. */ miClearVisualTypes(); if (!miSetVisualTypes(pScrn->bitsPerPixel, miGetDefaultVisualMask(pScrn->depth), pScrn->rgbBits, pScrn->defaultVisual)) { ERROR_MSG( "Cannot initialize the visual type for %d bits per pixel!", pScrn->bitsPerPixel); goto fail2; } if (pScrn->bitsPerPixel == 32 && pScrn->depth == 24) { /* Also add a 24 bit depth visual */ if (!miSetVisualTypes(24, miGetDefaultVisualMask(pScrn->depth), pScrn->rgbBits, pScrn->defaultVisual)) { WARNING_MSG( "Cannot initialize a 24 depth visual for 32bpp"); } else { INFO_MSG("Initialized a 24 depth visual for 32bpp"); } } if (!miSetPixmapDepths()) { ERROR_MSG("Cannot initialize the pixmap depth!"); goto fail3; } /* Initialize some generic 2D drawing functions: */ if (!fbScreenInit(pScreen, armsoc_bo_map(pARMSOC->scanout), pScrn->virtualX, pScrn->virtualY, pScrn->xDpi, pScrn->yDpi, pScrn->displayWidth, pScrn->bitsPerPixel)) { ERROR_MSG("fbScreenInit() failed!"); goto fail3; } /* Fixup RGB ordering: */ visual = pScreen->visuals + pScreen->numVisuals; while (--visual >= pScreen->visuals) { if ((visual->class | DynamicClass) == DirectColor) { visual->offsetRed = pScrn->offset.red; visual->offsetGreen = pScrn->offset.green; visual->offsetBlue = pScrn->offset.blue; visual->redMask = pScrn->mask.red; visual->greenMask = pScrn->mask.green; visual->blueMask = pScrn->mask.blue; visual->bitsPerRGBValue = pScrn->rgbBits; visual->ColormapEntries = 1 << pScrn->rgbBits; } } /* Continue initializing the generic 2D drawing functions after * fixing the RGB ordering: */ if (!fbPictureInit(pScreen, NULL, 0)) { ERROR_MSG("fbPictureInit() failed!"); goto fail4; } /* Set the initial black & white colormap indices: */ xf86SetBlackWhitePixels(pScreen); /* Initialize external sub-modules for EXA now, this has to be before * miDCInitialize() otherwise stacking order for wrapped ScreenPtr fxns * ends up in the wrong order. */ ARMSOCAccelInit(pScreen); /* Initialize backing store: */ xf86SetBackingStore(pScreen); /* Enable cursor position updates by mouse signal handler: */ xf86SetSilkenMouse(pScreen); /* Initialize the cursor: */ if (!miDCInitialize(pScreen, xf86GetPointerScreenFuncs())) { ERROR_MSG("miDCInitialize() failed!"); goto fail5; } /* ignore failures here as we will fall back to software cursor */ (void)drmmode_cursor_init(pScreen); /* TODO: MIDEGL-1458: Is this the right place for this? * The Intel i830 driver says: * "Must force it before EnterVT, so we are in control of VT..." */ pScrn->vtSema = TRUE; /* Take over the virtual terminal from the console, set the * desired mode, etc.: */ if (!ARMSOCEnterVT(VT_FUNC_ARGS(0))) { ERROR_MSG("ARMSOCEnterVT() failed!"); goto fail6; } /* Do some XRandR initialization. Return value is not useful */ (void)xf86CrtcScreenInit(pScreen); if (!miCreateDefColormap(pScreen)) { ERROR_MSG("Cannot create colormap!"); goto fail7; } if (!xf86HandleColormaps(pScreen, 1 << pScrn->rgbBits, pScrn->rgbBits, ARMSOCLoadPalette, NULL, CMAP_PALETTED_TRUECOLOR)) { ERROR_MSG("xf86HandleColormaps() failed!"); goto fail8; } /* Setup power management: */ xf86DPMSInit(pScreen, xf86DPMSSet, 0); pScreen->SaveScreen = xf86SaveScreen; /* Wrap some screen functions: */ wrap(pARMSOC, pScreen, CloseScreen, ARMSOCCloseScreen); wrap(pARMSOC, pScreen, CreateScreenResources, ARMSOCCreateScreenResources); wrap(pARMSOC, pScreen, BlockHandler, ARMSOCBlockHandler); drmmode_screen_init(pScrn); TRACE_EXIT(); return TRUE; /* cleanup on failures */ fail8: /* uninstall the default colormap */ miUninstallColormap(GetInstalledmiColormap(pScreen)); fail7: ARMSOCLeaveVT(VT_FUNC_ARGS(0)); pScrn->vtSema = FALSE; fail6: drmmode_cursor_fini(pScreen); fail5: if (pARMSOC->dri) ARMSOCDRI2CloseScreen(pScreen); if (pARMSOC->pARMSOCEXA) if (pARMSOC->pARMSOCEXA->CloseScreen) pARMSOC->pARMSOCEXA->CloseScreen(CLOSE_SCREEN_ARGS); fail4: /* Call the CloseScreen functions for fbInitScreen, miDCInitialize, * exaDriverInit & xf86CrtcScreenInit as appropriate via their * wrapped pointers. * exaDDXCloseScreen uses the XF86SCRNINFO macro so we must * set up the key for this before it gets called. */ dixSetPrivate(&pScreen->devPrivates, xf86ScreenKey, pScrn); (*pScreen->CloseScreen)(CLOSE_SCREEN_ARGS); fail3: /* reset the visual list */ miClearVisualTypes(); fail2: /* release the scanout buffer */ armsoc_bo_unreference(pARMSOC->scanout); pARMSOC->scanout = NULL; pScrn->displayWidth = 0; fail1: /* drop drm master */ (void)drmDropMaster(pARMSOC->drmFD); fail: TRACE_EXIT(); return FALSE; } static void ARMSOCLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, LOCO *colors, VisualPtr pVisual) { TRACE_ENTER(); TRACE_EXIT(); } /** * The driver's CloseScreen() function. This is called at the end of each * server generation. Restore state, unmap the frame buffer (and any other * mapped memory regions), and free per-Screen data structures (except those * held by pScrn). */ static Bool ARMSOCCloseScreen(CLOSE_SCREEN_ARGS_DECL) { ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); TRACE_ENTER(); drmmode_screen_fini(pScrn); if (pARMSOC->dri) ARMSOCDRI2CloseScreen(pScreen); if (pARMSOC->pARMSOCEXA) if (pARMSOC->pARMSOCEXA->CloseScreen) pARMSOC->pARMSOCEXA->CloseScreen(CLOSE_SCREEN_ARGS); /* release the scanout buffer */ armsoc_bo_unreference(pARMSOC->scanout); pARMSOC->scanout = NULL; pScrn->displayWidth = 0; if (pScrn->vtSema == TRUE) ARMSOCLeaveVT(VT_FUNC_ARGS(0)); pScrn->vtSema = FALSE; unwrap(pARMSOC, pScreen, CloseScreen); unwrap(pARMSOC, pScreen, BlockHandler); unwrap(pARMSOC, pScreen, CreateScreenResources); TRACE_EXIT(); return (*pScreen->CloseScreen)(CLOSE_SCREEN_ARGS); } /** * Adjust the screen pixmap for the current location of the front buffer. * This is done at EnterVT when buffers are bound as long as the resources * have already been created, but the first EnterVT happens before * CreateScreenResources. */ static Bool ARMSOCCreateScreenResources(ScreenPtr pScreen) { ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); swap(pARMSOC, pScreen, CreateScreenResources); if (!(*pScreen->CreateScreenResources) (pScreen)) return FALSE; swap(pARMSOC, pScreen, CreateScreenResources); return TRUE; } static void ARMSOCBlockHandler(BLOCKHANDLER_ARGS_DECL) { SCREEN_PTR(arg); ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); swap(pARMSOC, pScreen, BlockHandler); (*pScreen->BlockHandler) (BLOCKHANDLER_ARGS); swap(pARMSOC, pScreen, BlockHandler); } /** * The driver's SwitchMode() function. Initialize the new mode for the * Screen. */ static Bool ARMSOCSwitchMode(SWITCH_MODE_ARGS_DECL) { SCRN_INFO_PTR(arg); return xf86SetSingleMode(pScrn, mode, RR_Rotate_0); } /** * The driver's AdjustFrame() function. For cases where the frame buffer is * larger than the monitor resolution, this function can pan around the frame * buffer within the "viewport" of the monitor. */ static void ARMSOCAdjustFrame(ADJUST_FRAME_ARGS_DECL) { SCRN_INFO_PTR(arg); drmmode_adjust_frame(pScrn, x, y); } /** * The driver's EnterVT() function. This is called at server startup time, and * when the X server takes over the virtual terminal from the console. As * such, it may need to save the current (i.e. console) HW state, and set the * HW state as needed by the X server. */ static Bool ARMSOCEnterVT(VT_FUNC_ARGS_DECL) { SCRN_INFO_PTR(arg); int i, ret; TRACE_ENTER(); for (i = 1; i < currentMaxClients; i++) { if (clients[i]) AttendClient(clients[i]); } ret = ARMSOCSetDRMMaster(); if (ret) { ERROR_MSG("Cannot get DRM master: %s", strerror(errno)); return FALSE; } if (!xf86SetDesiredModes(pScrn)) { ERROR_MSG("xf86SetDesiredModes() failed!"); return FALSE; } TRACE_EXIT(); return TRUE; } /** * The driver's LeaveVT() function. This is called when the X server * temporarily gives up the virtual terminal to the console. As such, it may * need to restore the console's HW state. */ static void ARMSOCLeaveVT(VT_FUNC_ARGS_DECL) { SCRN_INFO_PTR(arg); int i, ret; TRACE_ENTER(); for (i = 1; i < currentMaxClients; i++) { if (clients[i]) IgnoreClient(clients[i]); } ret = ARMSOCDropDRMMaster(); if (ret) WARNING_MSG("drmDropMaster failed: %s", strerror(errno)); TRACE_EXIT(); } /** * The driver's FreeScreen() function. * Frees the ScrnInfoRec driverPrivate field when a screen is * deleted by the common layer. * This function is not used in normal (error free) operation. */ static void ARMSOCFreeScreen(FREE_SCREEN_ARGS_DECL) { SCRN_INFO_PTR(arg); struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); TRACE_ENTER(); if (!pARMSOC) { /* This can happen if a Screen is deleted after Probe(): */ return; } if (pARMSOC->pARMSOCEXA) { if (pARMSOC->pARMSOCEXA->FreeScreen) pARMSOC->pARMSOCEXA->FreeScreen( FREE_SCREEN_ARGS(pScrn)); } armsoc_device_del(pARMSOC->dev); /* Free the driver's Screen-specific, "private" data structure and * NULL-out the ScrnInfoRec's driverPrivate field. */ if (pScrn->driverPrivate) { free(pScrn->driverPrivate); pScrn->driverPrivate = NULL; } TRACE_EXIT(); } xf86-video-armsoc-0.6.0/src/armsoc_driver.h000066400000000000000000000141011220735425600205000ustar00rootroot00000000000000/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ /* * Copyright © 2011 Texas Instruments, Inc * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Ian Elliott * Rob Clark */ #ifndef __ARMSOC_DRV_H__ #define __ARMSOC_DRV_H__ #include "xf86.h" #if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 6 #include "xf86Resources.h" #include "xf86RAC.h" #endif #include "xf86drm.h" #include #include "armsoc_exa.h" /* Apparently not used by X server */ #define ARMSOC_VERSION 1000 /* Name used to prefix messages */ #define ARMSOC_NAME "ARMSOC" /* Driver name as used in config file */ #define ARMSOC_DRIVER_NAME "armsoc" #define ARMSOC_SUPPORT_GAMMA 0 /** * This controls whether debug statements (and function "trace" enter/exit) * messages are sent to the log file (TRUE) or are ignored (FALSE). */ extern _X_EXPORT Bool armsocDebug; /* Various logging/debug macros for use in the X driver and the external * sub-modules: */ #define TRACE_ENTER() \ do { if (armsocDebug) \ xf86DrvMsg(pScrn->scrnIndex, \ X_INFO, "%s:%d: Entering\n",\ __func__, __LINE__);\ } while (0) #define TRACE_EXIT() \ do { if (armsocDebug) \ xf86DrvMsg(pScrn->scrnIndex, \ X_INFO, "%s:%d: Exiting\n",\ __func__, __LINE__); \ } while (0) #define DEBUG_MSG(fmt, ...) \ do { if (armsocDebug) \ xf86DrvMsg(pScrn->scrnIndex, \ X_INFO, "%s:%d " fmt "\n",\ __func__, __LINE__, ##__VA_ARGS__); \ } while (0) #define INFO_MSG(fmt, ...) \ do { xf86DrvMsg(pScrn->scrnIndex, X_INFO, fmt "\n",\ ##__VA_ARGS__); } while (0) #define EARLY_INFO_MSG(fmt, ...) \ do { xf86Msg(X_INFO, fmt "\n",\ ##__VA_ARGS__); } while (0) #define CONFIG_MSG(fmt, ...) \ do { xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, fmt "\n",\ ##__VA_ARGS__); } while (0) #define WARNING_MSG(fmt, ...) \ do { xf86DrvMsg(pScrn->scrnIndex, \ X_WARNING, "WARNING: " fmt "\n",\ ##__VA_ARGS__); \ } while (0) #define EARLY_WARNING_MSG(fmt, ...) \ do { xf86Msg(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) /** The driver's Screen-specific, "private" data structure. */ struct ARMSOCRec { /** * Pointer to a structure used to communicate and coordinate with an * external EXA library (if loaded). */ struct ARMSOCEXARec *pARMSOCEXA; /** record if ARMSOCDRI2ScreenInit() was successful */ Bool dri; /** user-configurable option: */ Bool NoFlip; unsigned driNumBufs; /** File descriptor of the connection with the DRM. */ int drmFD; char *deviceName; /** interface to hardware specific functionality */ struct drmmode_interface *drmmode_interface; /** DRM device instance */ struct armsoc_device *dev; /** Scan-out buffer. */ struct armsoc_bo *scanout; /** Pointer to the options for this screen. */ OptionInfoPtr pOptionInfo; /** Save (wrap) the original pScreen functions. */ CloseScreenProcPtr SavedCloseScreen; CreateScreenResourcesProcPtr SavedCreateScreenResources; ScreenBlockHandlerProcPtr SavedBlockHandler; /** Pointer to the entity structure for this screen. */ EntityInfoPtr pEntityInfo; /** Flips we are waiting for: */ int pending_flips; /* Identify which CRTC to use. -1 uses all CRTCs */ int crtcNum; }; /* * Misc utility macros: */ /** Return a pointer to the driver's private structure. */ #define ARMSOCPTR(p) ((struct ARMSOCRec *)((p)->driverPrivate)) #define ARMSOCPTR_FROM_SCREEN(pScreen) \ ((struct ARMSOCRec *)(xf86Screens[(pScreen)->myNum])->driverPrivate) #define wrap(priv, real, mem, func) {\ priv->Saved##mem = real->mem; \ real->mem = func; \ } #define unwrap(priv, real, mem) {\ real->mem = priv->Saved##mem; \ } #define swap(priv, real, mem) {\ void *tmp = priv->Saved##mem; \ priv->Saved##mem = real->mem; \ real->mem = tmp; \ } #define exchange(a, b) {\ typeof(a) tmp = a; \ a = b; \ b = tmp; \ } #ifndef ARRAY_SIZE # define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) #endif /** * drmmode functions.. */ Bool drmmode_pre_init(ScrnInfoPtr pScrn, int fd, int cpp); void drmmode_screen_init(ScrnInfoPtr pScrn); void drmmode_screen_fini(ScrnInfoPtr pScrn); void drmmode_adjust_frame(ScrnInfoPtr pScrn, int x, int y); Bool drmmode_page_flip(DrawablePtr draw, uint32_t fb_id, void *priv); void drmmode_wait_for_event(ScrnInfoPtr pScrn); Bool drmmode_cursor_init(ScreenPtr pScreen); void drmmode_cursor_fini(ScreenPtr pScreen); void drmmode_init_wakeup_handler(int fd); void drmmode_fini_wakeup_handler(int fd); /** * DRI2 functions.. */ struct ARMSOCDRISwapCmd; Bool ARMSOCDRI2ScreenInit(ScreenPtr pScreen); void ARMSOCDRI2CloseScreen(ScreenPtr pScreen); void ARMSOCDRI2SwapComplete(struct ARMSOCDRISwapCmd *cmd); /** * DRI2 util functions.. */ void set_scanout_bo(ScrnInfoPtr pScrn, struct armsoc_bo *bo); #endif /* __ARMSOC_DRV_H__ */ xf86-video-armsoc-0.6.0/src/armsoc_dumb.c000066400000000000000000000231161220735425600201350ustar00rootroot00000000000000/* * Copyright © 2012 ARM Limited * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * */ #include #include #include #include #include #include #include #include #include "armsoc_dumb.h" #include "drmmode_driver.h" #define ALIGN(val, align) (((val) + (align) - 1) & ~((align) - 1)) struct armsoc_device { int fd; uint32_t dumb_scanout_flags; uint32_t dumb_no_scanout_flags; }; struct armsoc_bo { struct armsoc_device *dev; uint32_t handle; uint32_t size; void *map_addr; uint32_t fb_id; uint32_t width; uint32_t height; uint8_t depth; uint8_t bpp; uint32_t pitch; int refcnt; int dmabuf; /* initial size of backing memory. Used on resize to * check if the new size will fit */ uint32_t original_size; uint32_t name; }; /* device related functions: */ struct armsoc_device *armsoc_device_new(int fd, uint32_t dumb_scanout_flags, uint32_t dumb_no_scanout_flags) { struct armsoc_device *new_dev = malloc(sizeof(*new_dev)); if (!new_dev) return NULL; new_dev->fd = fd; new_dev->dumb_scanout_flags = dumb_scanout_flags; new_dev->dumb_no_scanout_flags = dumb_no_scanout_flags; return new_dev; } void armsoc_device_del(struct armsoc_device *dev) { free(dev); } /* buffer-object related functions: */ int armsoc_bo_set_dmabuf(struct armsoc_bo *bo) { int res; struct drm_prime_handle prime_handle; assert(bo->refcnt > 0); assert(!armsoc_bo_has_dmabuf(bo)); /* Try to get dma_buf fd */ prime_handle.handle = bo->handle; prime_handle.flags = 0; res = drmIoctl(bo->dev->fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &prime_handle); if (res) res = errno; else bo->dmabuf = prime_handle.fd; return res; } void armsoc_bo_clear_dmabuf(struct armsoc_bo *bo) { assert(bo->refcnt > 0); assert(armsoc_bo_has_dmabuf(bo)); close(bo->dmabuf); bo->dmabuf = -1; } int armsoc_bo_has_dmabuf(struct armsoc_bo *bo) { assert(bo->refcnt > 0); return bo->dmabuf >= 0; } struct armsoc_bo *armsoc_bo_new_with_dim(struct armsoc_device *dev, uint32_t width, uint32_t height, uint8_t depth, uint8_t bpp, enum armsoc_buf_type buf_type) { struct drm_mode_create_dumb create_dumb; struct armsoc_bo *new_buf; int res; new_buf = malloc(sizeof(*new_buf)); if (!new_buf) return NULL; create_dumb.height = height; create_dumb.width = width; create_dumb.bpp = bpp; assert((ARMSOC_BO_SCANOUT == buf_type) || (ARMSOC_BO_NON_SCANOUT == buf_type)); if (ARMSOC_BO_SCANOUT == buf_type) create_dumb.flags = dev->dumb_scanout_flags; else create_dumb.flags = dev->dumb_no_scanout_flags; res = drmIoctl(dev->fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_dumb); if (res) { free(new_buf); xf86DrvMsg(-1, X_ERROR, "_CREATE_DUMB({height: 0x%X, width: 0x%X, bpp: 0x%X, flags: 0x%X}) failed. errno:0x%X\n", height, width, bpp, create_dumb.flags, errno); return NULL; } new_buf->dev = dev; new_buf->handle = create_dumb.handle; new_buf->size = create_dumb.size; new_buf->map_addr = NULL; new_buf->fb_id = 0; new_buf->pitch = create_dumb.pitch; new_buf->width = create_dumb.width; new_buf->height = create_dumb.height; new_buf->original_size = create_dumb.size; new_buf->depth = depth; new_buf->bpp = create_dumb.bpp; new_buf->refcnt = 1; new_buf->dmabuf = -1; new_buf->name = 0; return new_buf; } static void armsoc_bo_del(struct armsoc_bo *bo) { int res; struct drm_mode_destroy_dumb destroy_dumb; if (!bo) return; /* NB: name doesn't need cleanup */ assert(bo->refcnt == 0); assert(bo->dmabuf < 0); if (bo->map_addr) { /* always map/unmap the full buffer for consistency */ munmap(bo->map_addr, bo->original_size); } if (bo->fb_id) { res = drmModeRmFB(bo->dev->fd, bo->fb_id); if (res) xf86DrvMsg(-1, X_ERROR, "drmModeRmFb failed %d : %s\n", res, strerror(errno)); } destroy_dumb.handle = bo->handle; res = drmIoctl(bo->dev->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_dumb); if (res) xf86DrvMsg(-1, X_ERROR, "destroy dumb failed %d : %s\n", res, strerror(errno)); free(bo); } void armsoc_bo_unreference(struct armsoc_bo *bo) { if (!bo) return; assert(bo->refcnt > 0); if (--bo->refcnt == 0) armsoc_bo_del(bo); } void armsoc_bo_reference(struct armsoc_bo *bo) { assert(bo->refcnt > 0); bo->refcnt++; } int armsoc_bo_get_name(struct armsoc_bo *bo, uint32_t *name) { if (bo->name == 0) { int ret; struct drm_gem_flink flink; assert(bo->refcnt > 0); flink.handle = bo->handle; ret = drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_FLINK, &flink); if (ret) { xf86DrvMsg(-1, X_ERROR, "_GEM_FLINK(handle:0x%X)failed. errno:0x%X\n", flink.handle, errno); return ret; } bo->name = flink.name; } *name = bo->name; return 0; } uint32_t armsoc_bo_handle(struct armsoc_bo *bo) { assert(bo->refcnt > 0); return bo->handle; } uint32_t armsoc_bo_size(struct armsoc_bo *bo) { assert(bo->refcnt > 0); return bo->size; } uint32_t armsoc_bo_width(struct armsoc_bo *bo) { assert(bo->refcnt > 0); return bo->width; } uint32_t armsoc_bo_height(struct armsoc_bo *bo) { assert(bo->refcnt > 0); return bo->height; } uint32_t armsoc_bo_bpp(struct armsoc_bo *bo) { assert(bo->refcnt > 0); return bo->bpp; } uint32_t armsoc_bo_pitch(struct armsoc_bo *bo) { assert(bo->refcnt > 0); return bo->pitch; } void *armsoc_bo_map(struct armsoc_bo *bo) { assert(bo->refcnt > 0); if (!bo->map_addr) { struct drm_mode_map_dumb map_dumb; int res; map_dumb.handle = bo->handle; res = drmIoctl(bo->dev->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_dumb); if (res) return NULL; /* always map/unmap the full buffer for consistency */ bo->map_addr = mmap(NULL, bo->original_size, PROT_READ | PROT_WRITE, MAP_SHARED, bo->dev->fd, map_dumb.offset); if (bo->map_addr == MAP_FAILED) bo->map_addr = NULL; } return bo->map_addr; } int armsoc_bo_cpu_prep(struct armsoc_bo *bo, enum armsoc_gem_op op) { int ret = 0; assert(bo->refcnt > 0); if (armsoc_bo_has_dmabuf(bo)) { fd_set fds; /* 10s before printing a msg */ const struct timeval timeout = {10, 0}; struct timeval t; FD_ZERO(&fds); FD_SET(bo->dmabuf, &fds); do { t = timeout; ret = select(bo->dmabuf+1, &fds, NULL, NULL, &t); if (ret == 0) xf86DrvMsg(-1, X_ERROR, "select() on dma_buf fd has timed-out\n"); } while ((ret == -1 && errno == EINTR) || ret == 0); if (ret > 0) ret = 0; } return ret; } int armsoc_bo_cpu_fini(struct armsoc_bo *bo, enum armsoc_gem_op op) { assert(bo->refcnt > 0); return msync(bo->map_addr, bo->size, MS_SYNC | MS_INVALIDATE); } int armsoc_bo_add_fb(struct armsoc_bo *bo) { int ret; assert(bo->refcnt > 0); assert(bo->fb_id == 0); ret = drmModeAddFB(bo->dev->fd, bo->width, bo->height, bo->depth, bo->bpp, bo->pitch, bo->handle, &bo->fb_id); if (ret < 0) { bo->fb_id = 0; return ret; } return 0; } int armsoc_bo_rm_fb(struct armsoc_bo *bo) { int ret; assert(bo->refcnt > 0); assert(bo->fb_id != 0); ret = drmModeRmFB(bo->dev->fd, bo->fb_id); if (ret < 0) { xf86DrvMsg(-1, X_ERROR, "Could not remove fb from bo %d\n", ret); return ret; } bo->fb_id = 0; return 0; } uint32_t armsoc_bo_get_fb(struct armsoc_bo *bo) { assert(bo->refcnt > 0); return bo->fb_id; } int armsoc_bo_clear(struct armsoc_bo *bo) { unsigned char *dst; assert(bo->refcnt > 0); dst = armsoc_bo_map(bo); if (!dst) { xf86DrvMsg(-1, X_ERROR, "Couldn't map scanout bo\n"); return -1; } if (armsoc_bo_cpu_prep(bo, ARMSOC_GEM_WRITE)) { xf86DrvMsg(-1, X_ERROR, " %s: armsoc_bo_cpu_prep failed - unable to synchronise access.\n", __func__); return -1; } memset(dst, 0x0, bo->size); (void)armsoc_bo_cpu_fini(bo, ARMSOC_GEM_WRITE); return 0; } int armsoc_bo_resize(struct armsoc_bo *bo, uint32_t new_width, uint32_t new_height) { uint32_t new_size; uint32_t new_pitch; assert(bo != NULL); assert(new_width > 0); assert(new_height > 0); /* The caller must remove the fb object before * attempting to resize. */ assert(bo->fb_id == 0); assert(bo->refcnt > 0); xf86DrvMsg(-1, X_INFO, "Resizing bo from %dx%d to %dx%d\n", bo->width, bo->height, new_width, new_height); /* TODO: MIDEGL-1563: Get pitch from DRM as * only DRM knows the ideal pitch and alignment * requirements * */ new_pitch = new_width * ((armsoc_bo_bpp(bo)+7)/8); /* Align pitch to 64 byte */ new_pitch = ALIGN(new_pitch, 64); new_size = (((new_height-1) * new_pitch) + (new_width * ((armsoc_bo_bpp(bo)+7)/8))); if (new_size <= bo->original_size) { bo->width = new_width; bo->height = new_height; bo->pitch = new_pitch; bo->size = new_size; return 0; } xf86DrvMsg(-1, X_ERROR, "Failed to resize buffer\n"); return -1; } xf86-video-armsoc-0.6.0/src/armsoc_dumb.h000066400000000000000000000057201220735425600201430ustar00rootroot00000000000000/* * Copyright (C) 2012 ARM Limited * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #ifndef ARMSOC_DUMB_H_ #define ARMSOC_DUMB_H_ #include struct armsoc_bo; struct armsoc_device; enum armsoc_gem_op { ARMSOC_GEM_READ = 0x01, ARMSOC_GEM_WRITE = 0x02, ARMSOC_GEM_READ_WRITE = 0x03, }; enum armsoc_buf_type { ARMSOC_BO_SCANOUT, ARMSOC_BO_NON_SCANOUT }; struct armsoc_device *armsoc_device_new(int fd, uint32_t dumb_scanout_flags, uint32_t dumb_no_scanout_flags); void armsoc_device_del(struct armsoc_device *dev); int armsoc_bo_get_name(struct armsoc_bo *bo, uint32_t *name); uint32_t armsoc_bo_handle(struct armsoc_bo *bo); void *armsoc_bo_map(struct armsoc_bo *bo); int armsoc_get_param(struct armsoc_device *dev, uint64_t param, uint64_t *value); int armsoc_bo_add_fb(struct armsoc_bo *bo); uint32_t armsoc_bo_get_fb(struct armsoc_bo *bo); int armsoc_bo_cpu_prep(struct armsoc_bo *bo, enum armsoc_gem_op op); int armsoc_bo_cpu_fini(struct armsoc_bo *bo, enum armsoc_gem_op op); uint32_t armsoc_bo_size(struct armsoc_bo *bo); struct armsoc_bo *armsoc_bo_new_with_dim(struct armsoc_device *dev, uint32_t width, uint32_t height, uint8_t depth, uint8_t bpp, enum armsoc_buf_type buf_type); uint32_t armsoc_bo_width(struct armsoc_bo *bo); uint32_t armsoc_bo_height(struct armsoc_bo *bo); uint32_t armsoc_bo_bpp(struct armsoc_bo *bo); uint32_t armsoc_bo_pitch(struct armsoc_bo *bo); void armsoc_bo_reference(struct armsoc_bo *bo); void armsoc_bo_unreference(struct armsoc_bo *bo); /* When dmabuf is set on a bo, armsoc_bo_cpu_prep() * waits for KDS shared access */ int armsoc_bo_set_dmabuf(struct armsoc_bo *bo); void armsoc_bo_clear_dmabuf(struct armsoc_bo *bo); int armsoc_bo_has_dmabuf(struct armsoc_bo *bo); int armsoc_bo_clear(struct armsoc_bo *bo); int armsoc_bo_rm_fb(struct armsoc_bo *bo); int armsoc_bo_resize(struct armsoc_bo *bo, uint32_t new_width, uint32_t new_height); #endif /* ARMSOC_DUMB_H_ */ xf86-video-armsoc-0.6.0/src/armsoc_exa.c000066400000000000000000000314261220735425600177660ustar00rootroot00000000000000/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ /* * Copyright © 2011 Texas Instruments, Inc * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Rob Clark */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "armsoc_exa.h" #include "armsoc_driver.h" /* keep this here, instead of static-inline so submodule doesn't * need to know layout of ARMSOCRec. */ _X_EXPORT struct ARMSOCEXARec * ARMSOCEXAPTR(ScrnInfoPtr pScrn) { struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); return pARMSOC->pARMSOCEXA; } /* Common ARMSOC EXA functions, mostly related to pixmap/buffer allocation. * Individual driver submodules can use these directly, or wrap them with * there own functions if anything additional is required. Submodules * can use ARMSOCPrixmapPrivPtr#priv for their own private data. */ /* used by DRI2 code to play buffer switcharoo */ void ARMSOCPixmapExchange(PixmapPtr a, PixmapPtr b) { struct ARMSOCPixmapPrivRec *apriv = exaGetPixmapDriverPrivate(a); struct ARMSOCPixmapPrivRec *bpriv = exaGetPixmapDriverPrivate(b); exchange(apriv->priv, bpriv->priv); exchange(apriv->bo, bpriv->bo); /* Ensure neither pixmap has a dmabuf fd attached to the bo if the * ext_access_cnt refcount is 0, as it will never be cleared. */ if (armsoc_bo_has_dmabuf(apriv->bo) && !apriv->ext_access_cnt) { armsoc_bo_clear_dmabuf(apriv->bo); /* Should only have to clear one dmabuf fd, otherwise the * refcount is wrong */ assert(!armsoc_bo_has_dmabuf(bpriv->bo)); } else if (armsoc_bo_has_dmabuf(bpriv->bo) && !bpriv->ext_access_cnt) { armsoc_bo_clear_dmabuf(bpriv->bo); assert(!armsoc_bo_has_dmabuf(apriv->bo)); } } _X_EXPORT void * ARMSOCCreatePixmap2(ScreenPtr pScreen, int width, int height, int depth, int usage_hint, int bitsPerPixel, int *new_fb_pitch) { struct ARMSOCPixmapPrivRec *priv = calloc(sizeof(struct ARMSOCPixmapPrivRec), 1); ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); enum armsoc_buf_type buf_type = ARMSOC_BO_NON_SCANOUT; if (!priv) return NULL; if (usage_hint & ARMSOC_CREATE_PIXMAP_SCANOUT) buf_type = ARMSOC_BO_SCANOUT; if (width > 0 && height > 0 && depth > 0 && bitsPerPixel > 0) { priv->bo = armsoc_bo_new_with_dim(pARMSOC->dev, width, height, depth, bitsPerPixel, buf_type); if ((!priv->bo) && ARMSOC_BO_SCANOUT == buf_type) { /* Tried to create a scanout but failed. Attempt to * fall back to non-scanout instead. */ WARNING_MSG( "Scanout buffer allocation failed, falling back to non-scanout"); buf_type = ARMSOC_BO_NON_SCANOUT; priv->bo = armsoc_bo_new_with_dim(pARMSOC->dev, width, height, depth, bitsPerPixel, buf_type); } if (!priv->bo) { ERROR_MSG("failed to allocate %dx%d bo, buf_type = %d", width, height, buf_type); free(priv); return NULL; } *new_fb_pitch = armsoc_bo_pitch(priv->bo); } /* The usage_hint field of the Pixmap passed to ModifyPixmapHeader is * not set to the usage_hint parameter passed to CreatePixmap. * It does appear to be set here so we stash it in the private * structure. However as we do not fully understand the uses of this * parameter, beware of any unexpected values! */ priv->usage_hint = usage_hint; return priv; } _X_EXPORT void ARMSOCDestroyPixmap(ScreenPtr pScreen, void *driverPriv) { struct ARMSOCPixmapPrivRec *priv = driverPriv; assert(!priv->ext_access_cnt); /* If ModifyPixmapHeader failed, it's possible we don't have a bo * backing this pixmap. */ if (priv->bo) { assert(!armsoc_bo_has_dmabuf(priv->bo)); armsoc_bo_unreference(priv->bo); } free(priv); } _X_EXPORT Bool ARMSOCModifyPixmapHeader(PixmapPtr pPixmap, int width, int height, int depth, int bitsPerPixel, int devKind, pointer pPixData) { struct ARMSOCPixmapPrivRec *priv = exaGetPixmapDriverPrivate(pPixmap); ScrnInfoPtr pScrn = pix2scrn(pPixmap); struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); enum armsoc_buf_type buf_type = ARMSOC_BO_NON_SCANOUT; /* Only modify specified fields, keeping all others intact. */ if (pPixData) pPixmap->devPrivate.ptr = pPixData; if (devKind > 0) pPixmap->devKind = devKind; /* * We can't accelerate this pixmap, and don't ever want to * see it again.. */ if (pPixData && pPixData != armsoc_bo_map(pARMSOC->scanout)) { /* scratch-pixmap (see GetScratchPixmapHeader()) gets recycled, * so could have a previous bo! */ armsoc_bo_unreference(priv->bo); priv->bo = NULL; /* Returning FALSE calls miModifyPixmapHeader */ return FALSE; } if (pPixData == armsoc_bo_map(pARMSOC->scanout)) priv->bo = pARMSOC->scanout; if (priv->usage_hint & ARMSOC_CREATE_PIXMAP_SCANOUT) buf_type = ARMSOC_BO_SCANOUT; if (depth > 0) pPixmap->drawable.depth = depth; if (bitsPerPixel > 0) pPixmap->drawable.bitsPerPixel = bitsPerPixel; if (width > 0) pPixmap->drawable.width = width; if (height > 0) pPixmap->drawable.height = height; /* * X will sometimes create an empty pixmap (width/height == 0) and then * use ModifyPixmapHeader to point it at PixData. We'll hit this path * during the CreatePixmap call. Just return true and skip the allocate * in this case. */ if (!pPixmap->drawable.width || !pPixmap->drawable.height) return TRUE; if (!priv->bo || armsoc_bo_width(priv->bo) != pPixmap->drawable.width || armsoc_bo_height(priv->bo) != pPixmap->drawable.height || armsoc_bo_bpp(priv->bo) != pPixmap->drawable.bitsPerPixel) { /* re-allocate buffer! */ armsoc_bo_unreference(priv->bo); priv->bo = armsoc_bo_new_with_dim(pARMSOC->dev, pPixmap->drawable.width, pPixmap->drawable.height, pPixmap->drawable.depth, pPixmap->drawable.bitsPerPixel, buf_type); if ((!priv->bo) && ARMSOC_BO_SCANOUT == buf_type) { /* Tried to create a scanout but failed. Attempt to * fall back to non-scanout instead. */ WARNING_MSG( "Scanout buffer allocation failed, falling back to non-scanout"); buf_type = ARMSOC_BO_NON_SCANOUT; priv->bo = armsoc_bo_new_with_dim(pARMSOC->dev, pPixmap->drawable.width, pPixmap->drawable.height, pPixmap->drawable.depth, pPixmap->drawable.bitsPerPixel, buf_type); } if (!priv->bo) { ERROR_MSG("failed to allocate %dx%d bo, buf_type = %d", pPixmap->drawable.width, pPixmap->drawable.height, buf_type); return FALSE; } pPixmap->devKind = armsoc_bo_pitch(priv->bo); } return TRUE; } /** * WaitMarker is a required EXA callback but synchronization is * performed during ARMSOCPrepareAccess so this function does not * have anything to do at present */ _X_EXPORT void ARMSOCWaitMarker(ScreenPtr pScreen, int marker) { /* no-op */ } static inline enum armsoc_gem_op idx2op(int index) { switch (index) { case EXA_PREPARE_SRC: case EXA_PREPARE_MASK: case EXA_PREPARE_AUX_SRC: case EXA_PREPARE_AUX_MASK: return ARMSOC_GEM_READ; case EXA_PREPARE_AUX_DEST: case EXA_PREPARE_DEST: default: return ARMSOC_GEM_READ_WRITE; } } /** * PrepareAccess() is called before CPU access to an offscreen pixmap. * * @param pPix the pixmap being accessed * @param index the index of the pixmap being accessed. * * PrepareAccess() will be called before CPU access to an offscreen pixmap. * This can be used to set up hardware surfaces for byteswapping or * untiling, or to adjust the pixmap's devPrivate.ptr for the purpose of * making CPU access use a different aperture. * * The index is one of #EXA_PREPARE_DEST, #EXA_PREPARE_SRC, * #EXA_PREPARE_MASK, #EXA_PREPARE_AUX_DEST, #EXA_PREPARE_AUX_SRC, or * #EXA_PREPARE_AUX_MASK. Since only up to #EXA_NUM_PREPARE_INDICES pixmaps * will have PrepareAccess() called on them per operation, drivers can have * a small, statically-allocated space to maintain state for PrepareAccess() * and FinishAccess() in. Note that PrepareAccess() is only called once per * pixmap and operation, regardless of whether the pixmap is used as a * destination and/or source, and the index may not reflect the usage. * * PrepareAccess() may fail. An example might be the case of hardware that * can set up 1 or 2 surfaces for CPU access, but not 3. If PrepareAccess() * fails, EXA will migrate the pixmap to system memory. * DownloadFromScreen() must be implemented and must not fail if a driver * wishes to fail in PrepareAccess(). PrepareAccess() must not fail when * pPix is the visible screen, because the visible screen can not be * migrated. * * @return TRUE if PrepareAccess() successfully prepared the pixmap for CPU * drawing. * @return FALSE if PrepareAccess() is unsuccessful and EXA should use * DownloadFromScreen() to migate the pixmap out. */ _X_EXPORT Bool ARMSOCPrepareAccess(PixmapPtr pPixmap, int index) { struct ARMSOCPixmapPrivRec *priv = exaGetPixmapDriverPrivate(pPixmap); pPixmap->devPrivate.ptr = armsoc_bo_map(priv->bo); if (!pPixmap->devPrivate.ptr) { xf86DrvMsg(-1, X_ERROR, "%s: Failed to map buffer\n", __func__); return FALSE; } /* Attach dmabuf fd to bo to synchronise access if * pixmap wrapped by DRI2 */ if (priv->ext_access_cnt && !armsoc_bo_has_dmabuf(priv->bo)) { if (armsoc_bo_set_dmabuf(priv->bo)) { xf86DrvMsg(-1, X_ERROR, "%s: Unable to get dma_buf fd for bo, to enable synchronised CPU access.\n", __func__); return FALSE; } } if (armsoc_bo_cpu_prep(priv->bo, idx2op(index))) { xf86DrvMsg(-1, X_ERROR, "%s: armsoc_bo_cpu_prep failed - unable to synchronise access.\n", __func__); return FALSE; } return TRUE; } /** * FinishAccess() is called after CPU access to an offscreen pixmap. * * @param pPix the pixmap being accessed * @param index the index of the pixmap being accessed. * * FinishAccess() will be called after finishing CPU access of an offscreen * pixmap set up by PrepareAccess(). Note that the FinishAccess() will not be * called if PrepareAccess() failed and the pixmap was migrated out. */ _X_EXPORT void ARMSOCFinishAccess(PixmapPtr pPixmap, int index) { struct ARMSOCPixmapPrivRec *priv = exaGetPixmapDriverPrivate(pPixmap); pPixmap->devPrivate.ptr = NULL; /* NOTE: can we use EXA migration module to track which parts of the * buffer was accessed by sw, and pass that info down to kernel to * do a more precise cache flush.. */ armsoc_bo_cpu_fini(priv->bo, idx2op(index)); } /** * PixmapIsOffscreen() is an optional driver replacement to * exaPixmapHasGpuCopy(). Set to NULL if you want the standard behaviour * of exaPixmapHasGpuCopy(). * * @param pPix the pixmap * @return TRUE if the given drawable is in framebuffer memory. * * exaPixmapHasGpuCopy() is used to determine if a pixmap is in * offscreen memory, meaning that acceleration could probably be done * to it, and that it will need to be wrapped by PrepareAccess()/ * FinishAccess() when accessing it from the CPU. */ _X_EXPORT Bool ARMSOCPixmapIsOffscreen(PixmapPtr pPixmap) { /* offscreen means in 'gpu accessible memory', not that it's off * the visible screen. We currently have no special constraints, * since compatible ARM CPUS have a flat memory model (no separate * GPU memory). If an individual EXA implementation has additional * constraints, like buffer size or mapping in GPU MMU, it should * wrap this function. */ struct ARMSOCPixmapPrivRec *priv = exaGetPixmapDriverPrivate(pPixmap); return priv && priv->bo; } void ARMSOCRegisterExternalAccess(PixmapPtr pPixmap) { struct ARMSOCPixmapPrivRec *priv = exaGetPixmapDriverPrivate(pPixmap); priv->ext_access_cnt++; } void ARMSOCDeregisterExternalAccess(PixmapPtr pPixmap) { struct ARMSOCPixmapPrivRec *priv = exaGetPixmapDriverPrivate(pPixmap); assert(priv->ext_access_cnt > 0); priv->ext_access_cnt--; if (priv->ext_access_cnt == 0) { /* No DRI2 buffers wrapping the pixmap, so no * need for synchronisation with dma_buf */ if (armsoc_bo_has_dmabuf(priv->bo)) armsoc_bo_clear_dmabuf(priv->bo); } } xf86-video-armsoc-0.6.0/src/armsoc_exa.h000066400000000000000000000105651220735425600177740ustar00rootroot00000000000000/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ /* * Copyright © 2011 Texas Instruments, Inc * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Rob Clark */ #ifndef ARMSOC_EXA_COMMON_H_ #define ARMSOC_EXA_COMMON_H_ /* note: don't include "armsoc_driver.h" here.. we want to keep some * isolation between structs shared with submodules and stuff internal * to core driver.. */ #include "armsoc_dumb.h" #include "xf86.h" #include "xf86_OSproc.h" #include "exa.h" #include "compat-api.h" /** * A per-Screen structure used to communicate and coordinate between the * ARMSOC X driver and an external EXA sub-module (if loaded). */ struct ARMSOCEXARec { /** * Called by X driver's CloseScreen() function at the end of each server * generation to free per-Screen data structures (except those held by * pScrn). */ Bool (*CloseScreen)(CLOSE_SCREEN_ARGS_DECL); /** * Called by X driver's FreeScreen() function at the end of each * server lifetime to free per-ScrnInfoRec data structures, to close * any external connections (e.g. with PVR2D, DRM), etc. */ void (*FreeScreen)(FREE_SCREEN_ARGS_DECL); /* add new fields here at end, to preserve ABI */ }; /** * Fallback EXA implementation */ struct ARMSOCEXARec *InitNullEXA(ScreenPtr pScreen, ScrnInfoPtr pScrn, int fd); struct ARMSOCEXARec *ARMSOCEXAPTR(ScrnInfoPtr pScrn); static inline ScrnInfoPtr pix2scrn(PixmapPtr pPixmap) { return xf86Screens[(pPixmap)->drawable.pScreen->myNum]; } static inline PixmapPtr draw2pix(DrawablePtr pDraw) { if (!pDraw) return NULL; else if (pDraw->type == DRAWABLE_WINDOW) return pDraw->pScreen->GetWindowPixmap((WindowPtr)pDraw); else return (PixmapPtr)pDraw; } /* Common ARMSOC EXA functions, mostly related to pixmap/buffer allocation. * Individual driver submodules can use these directly, or wrap them with * there own functions if anything additional is required. Submodules * can use ARMSOCPrixmapPrivPtr#priv for their own private data. */ struct ARMSOCPixmapPrivRec { /* EXA submodule private data */ void *priv; /* Ref-count of DRI2Buffers that wrap the Pixmap, * that allow external access to the underlying * buffer. When >0 CPU access must be synchronised. */ int ext_access_cnt; struct armsoc_bo *bo; int usage_hint; }; #define ARMSOC_CREATE_PIXMAP_SCANOUT 0x80000000 void *ARMSOCCreatePixmap2(ScreenPtr pScreen, int width, int height, int depth, int usage_hint, int bitsPerPixel, int *new_fb_pitch); void ARMSOCDestroyPixmap(ScreenPtr pScreen, void *driverPriv); Bool ARMSOCModifyPixmapHeader(PixmapPtr pPixmap, int width, int height, int depth, int bitsPerPixel, int devKind, pointer pPixData); void ARMSOCWaitMarker(ScreenPtr pScreen, int marker); Bool ARMSOCPrepareAccess(PixmapPtr pPixmap, int index); void ARMSOCFinishAccess(PixmapPtr pPixmap, int index); Bool ARMSOCPixmapIsOffscreen(PixmapPtr pPixmap); static inline struct armsoc_bo * ARMSOCPixmapBo(PixmapPtr pPixmap) { struct ARMSOCPixmapPrivRec *priv = exaGetPixmapDriverPrivate(pPixmap); return priv->bo; } void ARMSOCPixmapExchange(PixmapPtr a, PixmapPtr b); /* Register that the pixmap can be accessed externally, so * CPU access must be synchronised. */ void ARMSOCRegisterExternalAccess(PixmapPtr pPixmap); void ARMSOCDeregisterExternalAccess(PixmapPtr pPixmap); #endif /* ARMSOC_EXA_COMMON_H_ */ xf86-video-armsoc-0.6.0/src/armsoc_exa_null.c000066400000000000000000000106741220735425600210220ustar00rootroot00000000000000/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ /* * Copyright © 2011 Texas Instruments, Inc * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Rob Clark */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "armsoc_driver.h" #include "armsoc_exa.h" #include "exa.h" /* This file has a trivial EXA implementation which accelerates nothing. It * is used as the fall-back in case the EXA implementation for the current * chipset is not available. (For example, on chipsets which used the closed * source IMG PowerVR EXA implementation, if the closed-source submodule is * not installed. */ struct ARMSOCNullEXARec { struct ARMSOCEXARec base; ExaDriverPtr exa; /* add any other driver private data here.. */ }; static Bool PrepareSolidFail(PixmapPtr pPixmap, int alu, Pixel planemask, Pixel fill_colour) { return FALSE; } static Bool PrepareCopyFail(PixmapPtr pSrc, PixmapPtr pDst, int xdir, int ydir, int alu, Pixel planemask) { return FALSE; } static Bool CheckCompositeFail(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture, PicturePtr pDstPicture) { return FALSE; } static Bool PrepareCompositeFail(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture, PicturePtr pDstPicture, PixmapPtr pSrc, PixmapPtr pMask, PixmapPtr pDst) { return FALSE; } /** * CloseScreen() is called at the end of each server generation and * cleans up everything initialised in InitNullEXA() */ static Bool CloseScreen(CLOSE_SCREEN_ARGS_DECL) { ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); exaDriverFini(pScreen); free(((struct ARMSOCNullEXARec *)pARMSOC->pARMSOCEXA)->exa); free(pARMSOC->pARMSOCEXA); pARMSOC->pARMSOCEXA = NULL; return TRUE; } /* FreeScreen() is called on an error during PreInit and * should clean up anything initialised before InitNullEXA() * (which currently is nothing) * */ static void FreeScreen(FREE_SCREEN_ARGS_DECL) { } struct ARMSOCEXARec * InitNullEXA(ScreenPtr pScreen, ScrnInfoPtr pScrn, int fd) { struct ARMSOCNullEXARec *null_exa = calloc(sizeof(*null_exa), 1); struct ARMSOCEXARec *armsoc_exa; ExaDriverPtr exa; INFO_MSG("Soft EXA mode"); if (!null_exa) return NULL; armsoc_exa = (struct ARMSOCEXARec *)null_exa; exa = exaDriverAlloc(); if (!exa) goto fail; null_exa->exa = exa; exa->exa_major = EXA_VERSION_MAJOR; exa->exa_minor = EXA_VERSION_MINOR; exa->pixmapOffsetAlign = 0; exa->pixmapPitchAlign = 32; exa->flags = EXA_OFFSCREEN_PIXMAPS | EXA_HANDLES_PIXMAPS | EXA_SUPPORTS_PREPARE_AUX; exa->maxX = 4096; exa->maxY = 4096; /* Required EXA functions: */ exa->WaitMarker = ARMSOCWaitMarker; exa->CreatePixmap2 = ARMSOCCreatePixmap2; exa->DestroyPixmap = ARMSOCDestroyPixmap; exa->ModifyPixmapHeader = ARMSOCModifyPixmapHeader; exa->PrepareAccess = ARMSOCPrepareAccess; exa->FinishAccess = ARMSOCFinishAccess; exa->PixmapIsOffscreen = ARMSOCPixmapIsOffscreen; /* Always fallback for software operations */ exa->PrepareCopy = PrepareCopyFail; exa->PrepareSolid = PrepareSolidFail; exa->CheckComposite = CheckCompositeFail; exa->PrepareComposite = PrepareCompositeFail; if (!exaDriverInit(pScreen, exa)) { ERROR_MSG("exaDriverInit failed"); goto fail; } armsoc_exa->CloseScreen = CloseScreen; armsoc_exa->FreeScreen = FreeScreen; return armsoc_exa; fail: if (exa) free(exa); if (null_exa) free(null_exa); return NULL; } xf86-video-armsoc-0.6.0/src/compat-api.h000066400000000000000000000071411220735425600177010ustar00rootroot00000000000000/* * Copyright 2012 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * * Author: Dave Airlie */ /* this file provides API compat between server post 1.13 and pre it, it should be reused inside as many drivers as possible */ #ifndef COMPAT_API_H #define COMPAT_API_H #ifndef GLYPH_HAS_GLYPH_PICTURE_ACCESSOR #define GetGlyphPicture(g, s) GlyphPicture((g))[(s)->myNum] #define SetGlyphPicture(g, s, p) GlyphPicture((g))[(s)->myNum] = p #endif #ifndef XF86_HAS_SCRN_CONV #define xf86ScreenToScrn(s) xf86Screens[(s)->myNum] #define xf86ScrnToScreen(s) screenInfo.screens[(s)->scrnIndex] #endif #ifndef XF86_SCRN_INTERFACE #define SCRN_ARG_TYPE int #define SCRN_INFO_PTR(arg1) ScrnInfoPtr pScrn = xf86Screens[(arg1)] #define SCREEN_ARG_TYPE int #define SCREEN_PTR(arg1) ScreenPtr pScreen = screenInfo.screens[(arg1)] #define SCREEN_INIT_ARGS_DECL int i, ScreenPtr pScreen, int argc, char **argv #define BLOCKHANDLER_ARGS_DECL \ int arg, pointer blockData, pointer pTimeout, pointer pReadmask #define BLOCKHANDLER_ARGS arg, blockData, pTimeout, pReadmask #define CLOSE_SCREEN_ARGS_DECL int scrnIndex, ScreenPtr pScreen #define CLOSE_SCREEN_ARGS scrnIndex, pScreen #define ADJUST_FRAME_ARGS_DECL int arg, int x, int y, int flags #define ADJUST_FRAME_ARGS(arg, x, y) (arg)->scrnIndex, x, y, 0 #define SWITCH_MODE_ARGS_DECL int arg, DisplayModePtr mode, int flags #define SWITCH_MODE_ARGS(arg, m) (arg)->scrnIndex, m, 0 #define FREE_SCREEN_ARGS_DECL int arg, int flags #define FREE_SCREEN_ARGS(x) (x)->scrnIndex, 0 #define VT_FUNC_ARGS_DECL int arg, int flags #define VT_FUNC_ARGS(flags) pScrn->scrnIndex, (flags) #define XF86_ENABLEDISABLEFB_ARG(x) ((x)->scrnIndex) #else #define SCRN_ARG_TYPE ScrnInfoPtr #define SCRN_INFO_PTR(arg1) ScrnInfoPtr pScrn = (arg1) #define SCREEN_ARG_TYPE ScreenPtr #define SCREEN_PTR(arg1) ScreenPtr pScreen = (arg1) #define SCREEN_INIT_ARGS_DECL ScreenPtr pScreen, int argc, char **argv #define BLOCKHANDLER_ARGS_DECL \ ScreenPtr arg, pointer pTimeout, pointer pReadmask #define BLOCKHANDLER_ARGS arg, pTimeout, pReadmask #define CLOSE_SCREEN_ARGS_DECL ScreenPtr pScreen #define CLOSE_SCREEN_ARGS pScreen #define ADJUST_FRAME_ARGS_DECL ScrnInfoPtr arg, int x, int y #define ADJUST_FRAME_ARGS(arg, x, y) arg, x, y #define SWITCH_MODE_ARGS_DECL ScrnInfoPtr arg, DisplayModePtr mode #define SWITCH_MODE_ARGS(arg, m) arg, m #define FREE_SCREEN_ARGS_DECL ScrnInfoPtr arg #define FREE_SCREEN_ARGS(x) (x) #define VT_FUNC_ARGS_DECL ScrnInfoPtr arg #define VT_FUNC_ARGS(flags) pScrn #define XF86_ENABLEDISABLEFB_ARG(x) (x) #endif #endif xf86-video-armsoc-0.6.0/src/drmmode_display.c000066400000000000000000001141071220735425600210170ustar00rootroot00000000000000/* * Copyright © 2007 Red Hat, Inc. * Copyright © 2008 Maarten Maathuis * Copyright © 2011 Texas Instruments, Inc * * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Dave Airlie * Ian Elliott */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "xf86DDC.h" #ifdef HAVE_XEXTPROTO_71 #include #else #define DPMS_SERVER #include #endif #include "armsoc_driver.h" #include "xf86drmMode.h" #include "drm_fourcc.h" #include "X11/Xatom.h" #include #include "drmmode_driver.h" struct drmmode_cursor_rec { /* hardware cursor: */ drmModePlane *ovr; struct armsoc_bo *bo; uint32_t fb_id; int x, y; }; struct drmmode_rec { int fd; drmModeResPtr mode_res; int cpp; struct udev_monitor *uevent_monitor; InputHandlerProc uevent_handler; struct drmmode_cursor_rec *cursor; }; struct drmmode_crtc_private_rec { struct drmmode_rec *drmmode; drmModeCrtcPtr mode_crtc; int cursor_visible; }; struct drmmode_prop_rec { drmModePropertyPtr mode_prop; /* Index within the kernel-side property arrays for this connector. */ int index; /* if range prop, num_atoms == 1; * if enum prop, num_atoms == num_enums + 1 */ int num_atoms; Atom *atoms; }; struct drmmode_output_priv { struct drmmode_rec *drmmode; int output_id; drmModeConnectorPtr mode_output; drmModeEncoderPtr mode_encoder; drmModePropertyBlobPtr edid_blob; int num_props; struct drmmode_prop_rec *props; }; static void drmmode_output_dpms(xf86OutputPtr output, int mode); static struct drmmode_rec * drmmode_from_scrn(ScrnInfoPtr pScrn) { xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); struct drmmode_crtc_private_rec *drmmode_crtc; drmmode_crtc = xf86_config->crtc[0]->driver_private; return drmmode_crtc->drmmode; } static void drmmode_ConvertFromKMode(ScrnInfoPtr pScrn, drmModeModeInfo *kmode, DisplayModePtr mode) { memset(mode, 0, sizeof(DisplayModeRec)); mode->status = MODE_OK; mode->Clock = kmode->clock; mode->HDisplay = kmode->hdisplay; mode->HSyncStart = kmode->hsync_start; mode->HSyncEnd = kmode->hsync_end; mode->HTotal = kmode->htotal; mode->HSkew = kmode->hskew; mode->VDisplay = kmode->vdisplay; mode->VSyncStart = kmode->vsync_start; mode->VSyncEnd = kmode->vsync_end; mode->VTotal = kmode->vtotal; mode->VScan = kmode->vscan; mode->Flags = kmode->flags; mode->name = strdup(kmode->name); DEBUG_MSG("copy mode %s (%p %p)", kmode->name, mode->name, mode); if (kmode->type & DRM_MODE_TYPE_DRIVER) mode->type = M_T_DRIVER; if (kmode->type & DRM_MODE_TYPE_PREFERRED) mode->type |= M_T_PREFERRED; xf86SetModeCrtc(mode, pScrn->adjustFlags); } static void drmmode_ConvertToKMode(ScrnInfoPtr pScrn, drmModeModeInfo *kmode, DisplayModePtr mode) { memset(kmode, 0, sizeof(*kmode)); kmode->clock = mode->Clock; kmode->hdisplay = mode->HDisplay; kmode->hsync_start = mode->HSyncStart; kmode->hsync_end = mode->HSyncEnd; kmode->htotal = mode->HTotal; kmode->hskew = mode->HSkew; kmode->vdisplay = mode->VDisplay; kmode->vsync_start = mode->VSyncStart; kmode->vsync_end = mode->VSyncEnd; kmode->vtotal = mode->VTotal; kmode->vscan = mode->VScan; kmode->flags = mode->Flags; if (mode->name) strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN); kmode->name[DRM_DISPLAY_MODE_LEN-1] = 0; } static void drmmode_crtc_dpms(xf86CrtcPtr drmmode_crtc, int mode) { /* TODO: MIDEGL-1431: Implement this function */ } static Bool drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, Rotation rotation, int x, int y) { ScrnInfoPtr pScrn = crtc->scrn; struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); struct drmmode_crtc_private_rec *drmmode_crtc = crtc->driver_private; struct drmmode_rec *drmmode = drmmode_crtc->drmmode; int saved_x, saved_y; Rotation saved_rotation; DisplayModeRec saved_mode; uint32_t *output_ids = NULL; int output_count = 0; int ret = TRUE; int i; uint32_t fb_id; drmModeModeInfo kmode; TRACE_ENTER(); fb_id = armsoc_bo_get_fb(pARMSOC->scanout); if (fb_id == 0) { DEBUG_MSG("create framebuffer: %dx%d", pScrn->virtualX, pScrn->virtualY); ret = armsoc_bo_add_fb(pARMSOC->scanout); if (ret) { ERROR_MSG( "Failed to add framebuffer to the scanout buffer"); return FALSE; } fb_id = armsoc_bo_get_fb(pARMSOC->scanout); if (0 == fb_id) return FALSE; } /* Save the current mode in case there's a problem: */ saved_mode = crtc->mode; saved_x = crtc->x; saved_y = crtc->y; saved_rotation = crtc->rotation; /* Set the new mode: */ crtc->mode = *mode; crtc->x = x; crtc->y = y; crtc->rotation = rotation; output_ids = calloc(sizeof(uint32_t), xf86_config->num_output); if (!output_ids) { xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, "memory allocation failed in drmmode_set_mode_major()\n"); ret = FALSE; goto done; } for (i = 0; i < xf86_config->num_output; i++) { xf86OutputPtr output = xf86_config->output[i]; struct drmmode_output_priv *drmmode_output; if (output->crtc != crtc) continue; drmmode_output = output->driver_private; output_ids[output_count] = drmmode_output->mode_output->connector_id; output_count++; } if (!xf86CrtcRotate(crtc)) { xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, "failed to assign rotation in drmmode_set_mode_major()\n"); ret = FALSE; goto done; } if (crtc->funcs->gamma_set) crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green, crtc->gamma_blue, crtc->gamma_size); drmmode_ConvertToKMode(crtc->scrn, &kmode, mode); ret = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, fb_id, x, y, output_ids, output_count, &kmode); if (ret) { xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, "failed to set mode: %s\n", strerror(-ret)); ret = FALSE; goto done; } else { ret = TRUE; } /* Turn on any outputs on this crtc that may have been disabled: */ for (i = 0; i < xf86_config->num_output; i++) { xf86OutputPtr output = xf86_config->output[i]; if (output->crtc != crtc) continue; drmmode_output_dpms(output, DPMSModeOn); } /* if hw cursor is initialized, reload it */ if (drmmode->cursor) xf86_reload_cursors(pScrn->pScreen); done: if (output_ids) free(output_ids); if (!ret) { /* If there was a problem, restore the old mode: */ crtc->x = saved_x; crtc->y = saved_y; crtc->rotation = saved_rotation; crtc->mode = saved_mode; } TRACE_EXIT(); return ret; } static void drmmode_hide_cursor(xf86CrtcPtr crtc) { struct drmmode_crtc_private_rec *drmmode_crtc = crtc->driver_private; struct drmmode_rec *drmmode = drmmode_crtc->drmmode; struct drmmode_cursor_rec *cursor = drmmode->cursor; if (!cursor) return; drmmode_crtc->cursor_visible = FALSE; /* set plane's fb_id to 0 to disable it */ drmModeSetPlane(drmmode->fd, cursor->ovr->plane_id, drmmode_crtc->mode_crtc->crtc_id, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); } static void drmmode_show_cursor(xf86CrtcPtr crtc) { struct drmmode_crtc_private_rec *drmmode_crtc = crtc->driver_private; struct drmmode_rec *drmmode = drmmode_crtc->drmmode; struct drmmode_cursor_rec *cursor = drmmode->cursor; int crtc_x, crtc_y, src_x, src_y; int w, h, pad; ScrnInfoPtr pScrn = crtc->scrn; struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); if (!cursor) return; drmmode_crtc->cursor_visible = TRUE; w = pARMSOC->drmmode_interface->cursor_width; h = pARMSOC->drmmode_interface->cursor_height; pad = pARMSOC->drmmode_interface->cursor_padding; /* get padded width */ w = w + 2 * pad; /* get x of padded cursor */ crtc_x = cursor->x - pad; crtc_y = cursor->y; src_x = 0; src_y = 0; /* calculate clipped x, y, w & h if cursor is off edges */ if (crtc_x < 0) { src_x += -crtc_x; w -= -crtc_x; crtc_x = 0; } if (crtc_y < 0) { src_y += -crtc_y; h -= -crtc_y; crtc_y = 0; } if ((crtc_x + w) > crtc->mode.HDisplay) w = crtc->mode.HDisplay - crtc_x; if ((crtc_y + h) > crtc->mode.VDisplay) h = crtc->mode.VDisplay - crtc_y; /* note src coords (last 4 args) are in Q16 format */ drmModeSetPlane(drmmode->fd, cursor->ovr->plane_id, drmmode_crtc->mode_crtc->crtc_id, cursor->fb_id, 0, crtc_x, crtc_y, w, h, src_x<<16, src_y<<16, w<<16, h<<16); } static void drmmode_set_cursor_position(xf86CrtcPtr crtc, int x, int y) { struct drmmode_crtc_private_rec *drmmode_crtc = crtc->driver_private; struct drmmode_rec *drmmode = drmmode_crtc->drmmode; struct drmmode_cursor_rec *cursor = drmmode->cursor; if (!cursor) return; cursor->x = x; cursor->y = y; if (drmmode_crtc->cursor_visible) drmmode_show_cursor(crtc); } static void drmmode_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *image) { uint32_t *d; struct drmmode_crtc_private_rec *drmmode_crtc = crtc->driver_private; struct drmmode_rec *drmmode = drmmode_crtc->drmmode; struct drmmode_cursor_rec *cursor = drmmode->cursor; int visible; ScrnInfoPtr pScrn = crtc->scrn; struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); if (!cursor) return; visible = drmmode_crtc->cursor_visible; if (visible) drmmode_hide_cursor(crtc); d = armsoc_bo_map(cursor->bo); if (!d) { xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, "load_cursor_argb map failure\n"); if (visible) drmmode_show_cursor(crtc); return; } /* set_cursor_image is a mandatory function */ assert(pARMSOC->drmmode_interface->set_cursor_image); pARMSOC->drmmode_interface->set_cursor_image(crtc, d, image); if (visible) drmmode_show_cursor(crtc); } Bool drmmode_cursor_init(ScreenPtr pScreen) { ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); struct drmmode_rec *drmmode = drmmode_from_scrn(pScrn); struct drmmode_cursor_rec *cursor; drmModePlaneRes *plane_resources; drmModePlane *ovr; int w, h, pad; uint32_t handles[4], pitches[4], offsets[4]; /* we only use [0] */ if (drmmode->cursor) { INFO_MSG("cursor already initialized"); return TRUE; } if (!xf86LoaderCheckSymbol("drmModeGetPlaneResources")) { ERROR_MSG( "HW cursor not supported (needs libdrm 2.4.30 or higher)"); return FALSE; } /* find an unused plane which can be used as a mouse cursor. Note * that we cheat a bit, in order to not burn one overlay per crtc, * and only show the mouse cursor on one crtc at a time */ plane_resources = drmModeGetPlaneResources(drmmode->fd); if (!plane_resources) { ERROR_MSG("HW cursor: drmModeGetPlaneResources failed: %s", strerror(errno)); return FALSE; } if (plane_resources->count_planes < 1) { ERROR_MSG("not enough planes for HW cursor"); drmModeFreePlaneResources(plane_resources); return FALSE; } ovr = drmModeGetPlane(drmmode->fd, plane_resources->planes[0]); if (!ovr) { ERROR_MSG("HW cursor: drmModeGetPlane failed: %s", strerror(errno)); drmModeFreePlaneResources(plane_resources); return FALSE; } if (pARMSOC->drmmode_interface->init_plane_for_cursor && pARMSOC->drmmode_interface->init_plane_for_cursor( drmmode->fd, ovr->plane_id)) { ERROR_MSG("Failed driver-specific cursor initialization"); drmModeFreePlaneResources(plane_resources); return FALSE; } cursor = calloc(1, sizeof(struct drmmode_cursor_rec)); if (!cursor) { ERROR_MSG("HW cursor: calloc failed"); drmModeFreePlane(ovr); drmModeFreePlaneResources(plane_resources); return FALSE; } cursor->ovr = ovr; w = pARMSOC->drmmode_interface->cursor_width; h = pARMSOC->drmmode_interface->cursor_height; pad = pARMSOC->drmmode_interface->cursor_padding; /* allow for cursor padding in the bo */ cursor->bo = armsoc_bo_new_with_dim(pARMSOC->dev, w + 2 * pad, h, 0, 32, ARMSOC_BO_SCANOUT); if (!cursor->bo) { ERROR_MSG("HW cursor: buffer allocation failed"); free(cursor); drmModeFreePlane(ovr); drmModeFreePlaneResources(plane_resources); return FALSE; } handles[0] = armsoc_bo_handle(cursor->bo); pitches[0] = armsoc_bo_pitch(cursor->bo); offsets[0] = 0; /* allow for cursor padding in the fb */ if (drmModeAddFB2(drmmode->fd, w + 2 * pad, h, DRM_FORMAT_ARGB8888, handles, pitches, offsets, &cursor->fb_id, 0)) { ERROR_MSG("HW cursor: drmModeAddFB2 failed: %s", strerror(errno)); armsoc_bo_unreference(cursor->bo); free(cursor); drmModeFreePlane(ovr); drmModeFreePlaneResources(plane_resources); return FALSE; } if (!xf86_cursors_init(pScreen, w, h, HARDWARE_CURSOR_ARGB)) { ERROR_MSG("xf86_cursors_init() failed"); if (drmModeRmFB(drmmode->fd, cursor->fb_id)) ERROR_MSG("drmModeRmFB() failed"); armsoc_bo_unreference(cursor->bo); free(cursor); drmModeFreePlane(ovr); drmModeFreePlaneResources(plane_resources); return FALSE; } INFO_MSG("HW cursor initialized"); drmmode->cursor = cursor; drmModeFreePlaneResources(plane_resources); return TRUE; } void drmmode_cursor_fini(ScreenPtr pScreen) { ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; struct drmmode_rec *drmmode = drmmode_from_scrn(pScrn); struct drmmode_cursor_rec *cursor = drmmode->cursor; if (!cursor) return; drmmode->cursor = NULL; xf86_cursors_fini(pScreen); drmModeRmFB(drmmode->fd, cursor->fb_id); armsoc_bo_unreference(cursor->bo); drmModeFreePlane(cursor->ovr); free(cursor); } #if 1 == ARMSOC_SUPPORT_GAMMA static void drmmode_gamma_set(xf86CrtcPtr crtc, CARD16 *red, CARD16 *green, CARD16 *blue, int size) { struct drmmode_crtc_private_rec *drmmode_crtc = crtc->driver_private; struct drmmode_rec *drmmode = drmmode_crtc->drmmode; int ret; ret = drmModeCrtcSetGamma(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, size, red, green, blue); if (ret != 0) { xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, "failed to set gamma: %s\n", strerror(-ret)); } } #endif static const xf86CrtcFuncsRec drmmode_crtc_funcs = { .dpms = drmmode_crtc_dpms, .set_mode_major = drmmode_set_mode_major, .set_cursor_position = drmmode_set_cursor_position, .show_cursor = drmmode_show_cursor, .hide_cursor = drmmode_hide_cursor, .load_cursor_argb = drmmode_load_cursor_argb, #if 1 == ARMSOC_SUPPORT_GAMMA .gamma_set = drmmode_gamma_set, #endif }; static void drmmode_crtc_init(ScrnInfoPtr pScrn, struct drmmode_rec *drmmode, int num) { xf86CrtcPtr crtc; struct drmmode_crtc_private_rec *drmmode_crtc; TRACE_ENTER(); crtc = xf86CrtcCreate(pScrn, &drmmode_crtc_funcs); if (crtc == NULL) return; drmmode_crtc = xnfcalloc(sizeof(struct drmmode_crtc_private_rec), 1); drmmode_crtc->mode_crtc = drmModeGetCrtc(drmmode->fd, drmmode->mode_res->crtcs[num]); drmmode_crtc->drmmode = drmmode; INFO_MSG("Got CRTC: %d", num); crtc->driver_private = drmmode_crtc; TRACE_EXIT(); return; } static xf86OutputStatus drmmode_output_detect(xf86OutputPtr output) { /* go to the hw and retrieve a new output struct */ struct drmmode_output_priv *drmmode_output = output->driver_private; struct drmmode_rec *drmmode = drmmode_output->drmmode; xf86OutputStatus status; drmModeFreeConnector(drmmode_output->mode_output); drmmode_output->mode_output = drmModeGetConnector(drmmode->fd, drmmode_output->output_id); switch (drmmode_output->mode_output->connection) { case DRM_MODE_CONNECTED: status = XF86OutputStatusConnected; break; case DRM_MODE_DISCONNECTED: status = XF86OutputStatusDisconnected; break; default: case DRM_MODE_UNKNOWNCONNECTION: status = XF86OutputStatusUnknown; break; } return status; } static Bool drmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr mode) { if (mode->type & M_T_DEFAULT) /* Default modes are harmful here. */ return MODE_BAD; return MODE_OK; } static DisplayModePtr drmmode_output_get_modes(xf86OutputPtr output) { ScrnInfoPtr pScrn = output->scrn; struct drmmode_output_priv *drmmode_output = output->driver_private; drmModeConnectorPtr koutput = drmmode_output->mode_output; struct drmmode_rec *drmmode = drmmode_output->drmmode; DisplayModePtr modes = NULL; drmModePropertyPtr prop; xf86MonPtr ddc_mon = NULL; int i; /* look for an EDID property */ for (i = 0; i < koutput->count_props; i++) { prop = drmModeGetProperty(drmmode->fd, koutput->props[i]); if (!prop) continue; if ((prop->flags & DRM_MODE_PROP_BLOB) && !strcmp(prop->name, "EDID")) { if (drmmode_output->edid_blob) drmModeFreePropertyBlob( drmmode_output->edid_blob); drmmode_output->edid_blob = drmModeGetPropertyBlob(drmmode->fd, koutput->prop_values[i]); } drmModeFreeProperty(prop); } if (drmmode_output->edid_blob) ddc_mon = xf86InterpretEDID(pScrn->scrnIndex, drmmode_output->edid_blob->data); if (ddc_mon) { xf86OutputSetEDID(output, ddc_mon); xf86SetDDCproperties(pScrn, ddc_mon); } DEBUG_MSG("count_modes: %d", koutput->count_modes); /* modes should already be available */ for (i = 0; i < koutput->count_modes; i++) { DisplayModePtr mode = xnfalloc(sizeof(DisplayModeRec)); drmmode_ConvertFromKMode(pScrn, &koutput->modes[i], mode); modes = xf86ModesAdd(modes, mode); } return modes; } static void drmmode_output_destroy(xf86OutputPtr output) { struct drmmode_output_priv *drmmode_output = output->driver_private; int i; if (drmmode_output->edid_blob) drmModeFreePropertyBlob(drmmode_output->edid_blob); for (i = 0; i < drmmode_output->num_props; i++) { drmModeFreeProperty(drmmode_output->props[i].mode_prop); free(drmmode_output->props[i].atoms); } free(drmmode_output->props); drmModeFreeConnector(drmmode_output->mode_output); free(drmmode_output); output->driver_private = NULL; } static void drmmode_output_dpms(xf86OutputPtr output, int mode) { struct drmmode_output_priv *drmmode_output = output->driver_private; drmModeConnectorPtr koutput = drmmode_output->mode_output; drmModePropertyPtr prop; struct drmmode_rec *drmmode = drmmode_output->drmmode; int mode_id = -1, i; for (i = 0; i < koutput->count_props; i++) { prop = drmModeGetProperty(drmmode->fd, koutput->props[i]); if (!prop) continue; if ((prop->flags & DRM_MODE_PROP_ENUM) && !strcmp(prop->name, "DPMS")) { mode_id = koutput->props[i]; drmModeFreeProperty(prop); break; } drmModeFreeProperty(prop); } if (mode_id < 0) return; drmModeConnectorSetProperty(drmmode->fd, koutput->connector_id, mode_id, mode); } static Bool drmmode_property_ignore(drmModePropertyPtr prop) { if (!prop) return TRUE; /* ignore blob prop */ if (prop->flags & DRM_MODE_PROP_BLOB) return TRUE; /* ignore standard property */ if (!strcmp(prop->name, "EDID") || !strcmp(prop->name, "DPMS")) return TRUE; return FALSE; } static void drmmode_output_create_resources(xf86OutputPtr output) { struct drmmode_output_priv *drmmode_output = output->driver_private; drmModeConnectorPtr mode_output = drmmode_output->mode_output; struct drmmode_rec *drmmode = drmmode_output->drmmode; drmModePropertyPtr drmmode_prop; uint32_t value; int i, j, err; drmmode_output->props = calloc(mode_output->count_props, sizeof(struct drmmode_prop_rec)); if (!drmmode_output->props) return; drmmode_output->num_props = 0; for (i = 0; i < mode_output->count_props; i++) { drmmode_prop = drmModeGetProperty(drmmode->fd, mode_output->props[i]); if (drmmode_property_ignore(drmmode_prop)) { drmModeFreeProperty(drmmode_prop); continue; } drmmode_output->props[drmmode_output->num_props].mode_prop = drmmode_prop; drmmode_output->props[drmmode_output->num_props].index = i; drmmode_output->num_props++; } for (i = 0; i < drmmode_output->num_props; i++) { struct drmmode_prop_rec *p = &drmmode_output->props[i]; drmmode_prop = p->mode_prop; value = drmmode_output->mode_output->prop_values[p->index]; if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) { INT32 range[2]; p->num_atoms = 1; p->atoms = calloc(p->num_atoms, sizeof(Atom)); if (!p->atoms) continue; p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE); range[0] = drmmode_prop->values[0]; range[1] = drmmode_prop->values[1]; err = RRConfigureOutputProperty(output->randr_output, p->atoms[0], FALSE, TRUE, drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE, 2, range); if (err != 0) xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, "RRConfigureOutputProperty error, %d\n", err); err = RRChangeOutputProperty(output->randr_output, p->atoms[0], XA_INTEGER, 32, PropModeReplace, 1, &value, FALSE, FALSE); if (err != 0) xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, "RRChangeOutputProperty error, %d\n", err); } else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) { p->num_atoms = drmmode_prop->count_enums + 1; p->atoms = calloc(p->num_atoms, sizeof(Atom)); if (!p->atoms) continue; p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE); for (j = 1; j <= drmmode_prop->count_enums; j++) { struct drm_mode_property_enum *e = &drmmode_prop->enums[j-1]; p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE); } err = RRConfigureOutputProperty(output->randr_output, p->atoms[0], FALSE, FALSE, drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE, p->num_atoms - 1, (INT32 *)&p->atoms[1]); if (err != 0) xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, "RRConfigureOutputProperty error, %d\n", err); for (j = 0; j < drmmode_prop->count_enums; j++) if (drmmode_prop->enums[j].value == value) break; /* there's always a matching value */ err = RRChangeOutputProperty(output->randr_output, p->atoms[0], XA_ATOM, 32, PropModeReplace, 1, &p->atoms[j+1], FALSE, FALSE); if (err != 0) xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, "RRChangeOutputProperty error, %d\n", err); } } } static Bool drmmode_output_set_property(xf86OutputPtr output, Atom property, RRPropertyValuePtr value) { struct drmmode_output_priv *drmmode_output = output->driver_private; struct drmmode_rec *drmmode = drmmode_output->drmmode; int i, ret; for (i = 0; i < drmmode_output->num_props; i++) { struct drmmode_prop_rec *p = &drmmode_output->props[i]; if (p->atoms[0] != property) continue; if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) { uint32_t val; if (value->type != XA_INTEGER || value->format != 32 || value->size != 1) return FALSE; val = *(uint32_t *)value->data; ret = drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id, p->mode_prop->prop_id, (uint64_t)val); if (ret) return FALSE; return TRUE; } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) { Atom atom; const char *name; int j; if (value->type != XA_ATOM || value->format != 32 || value->size != 1) return FALSE; memcpy(&atom, value->data, 4); name = NameForAtom(atom); /* search for matching name string, then * set its value down */ for (j = 0; j < p->mode_prop->count_enums; j++) { if (!strcmp(p->mode_prop->enums[j].name, name)) { ret = drmModeConnectorSetProperty( drmmode->fd, drmmode_output->output_id, p->mode_prop->prop_id, p->mode_prop->enums[j].value); if (ret) return FALSE; return TRUE; } } return FALSE; } } return TRUE; } static Bool drmmode_output_get_property(xf86OutputPtr output, Atom property) { struct drmmode_output_priv *drmmode_output = output->driver_private; struct drmmode_rec *drmmode = drmmode_output->drmmode; uint32_t value; int err, i; if (output->scrn->vtSema) { drmModeFreeConnector(drmmode_output->mode_output); drmmode_output->mode_output = drmModeGetConnector(drmmode->fd, drmmode_output->output_id); } for (i = 0; i < drmmode_output->num_props; i++) { struct drmmode_prop_rec *p = &drmmode_output->props[i]; if (p->atoms[0] != property) continue; value = drmmode_output->mode_output->prop_values[p->index]; if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) { err = RRChangeOutputProperty(output->randr_output, property, XA_INTEGER, 32, PropModeReplace, 1, &value, FALSE, FALSE); return !err; } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) { int j; /* search for matching name string, then set * its value down */ for (j = 0; j < p->mode_prop->count_enums; j++) { if (p->mode_prop->enums[j].value == value) break; } err = RRChangeOutputProperty(output->randr_output, property, XA_ATOM, 32, PropModeReplace, 1, &p->atoms[j+1], FALSE, FALSE); return !err; } } return FALSE; } static const xf86OutputFuncsRec drmmode_output_funcs = { .create_resources = drmmode_output_create_resources, .dpms = drmmode_output_dpms, .detect = drmmode_output_detect, .mode_valid = drmmode_output_mode_valid, .get_modes = drmmode_output_get_modes, .set_property = drmmode_output_set_property, .get_property = drmmode_output_get_property, .destroy = drmmode_output_destroy }; const char *output_names[] = { "None", "VGA", "DVI-I", "DVI-D", "DVI-A", "Composite", "SVIDEO", "LVDS", "CTV", "DIN", "DP", "HDMI", "HDMI", "TV", "eDP", }; #define NUM_OUTPUT_NAMES (sizeof(output_names) / sizeof(output_names[0])) static void drmmode_output_init(ScrnInfoPtr pScrn, struct drmmode_rec *drmmode, int num) { xf86OutputPtr output; drmModeConnectorPtr koutput; drmModeEncoderPtr kencoder; struct drmmode_output_priv *drmmode_output; char name[32]; TRACE_ENTER(); koutput = drmModeGetConnector(drmmode->fd, drmmode->mode_res->connectors[num]); if (!koutput) return; kencoder = drmModeGetEncoder(drmmode->fd, koutput->encoders[0]); if (!kencoder) { drmModeFreeConnector(koutput); return; } if (koutput->connector_type >= NUM_OUTPUT_NAMES) snprintf(name, 32, "Unknown%d-%d", koutput->connector_type, koutput->connector_type_id); else snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id); output = xf86OutputCreate(pScrn, &drmmode_output_funcs, name); if (!output) { drmModeFreeEncoder(kencoder); drmModeFreeConnector(koutput); return; } drmmode_output = calloc(sizeof(struct drmmode_output_priv), 1); if (!drmmode_output) { xf86OutputDestroy(output); drmModeFreeConnector(koutput); drmModeFreeEncoder(kencoder); return; } drmmode_output->output_id = drmmode->mode_res->connectors[num]; drmmode_output->mode_output = koutput; drmmode_output->mode_encoder = kencoder; drmmode_output->drmmode = drmmode; output->mm_width = koutput->mmWidth; output->mm_height = koutput->mmHeight; output->driver_private = drmmode_output; if (ARMSOCPTR(pScrn)->crtcNum >= 0) { /* Only single crtc per screen - see if this output can use it*/ output->possible_crtcs = (kencoder->possible_crtcs >> (ARMSOCPTR(pScrn)->crtcNum) )&1; } else output->possible_crtcs = kencoder->possible_crtcs; output->possible_clones = kencoder->possible_clones; output->interlaceAllowed = TRUE; TRACE_EXIT(); return; } void set_scanout_bo(ScrnInfoPtr pScrn, struct armsoc_bo *bo) { struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); /* It had better have a framebuffer if we're scanning it out */ assert(armsoc_bo_get_fb(bo)); pARMSOC->scanout = bo; } static Bool drmmode_xf86crtc_resize(ScrnInfoPtr pScrn, int width, int height) { struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); ScreenPtr pScreen = pScrn->pScreen; uint32_t pitch; int i; xf86CrtcConfigPtr xf86_config; TRACE_ENTER(); DEBUG_MSG("Resize: %dx%d", width, height); pScrn->virtualX = width; pScrn->virtualY = height; if ((width != armsoc_bo_width(pARMSOC->scanout)) || (height != armsoc_bo_height(pARMSOC->scanout)) || (pScrn->bitsPerPixel != armsoc_bo_bpp(pARMSOC->scanout))) { struct armsoc_bo *new_scanout; /* allocate new scanout buffer */ new_scanout = armsoc_bo_new_with_dim(pARMSOC->dev, width, height, pScrn->depth, pScrn->bitsPerPixel, ARMSOC_BO_SCANOUT); if (!new_scanout) { /* Try to use the previous buffer if the new resolution * is smaller than the one on buffer creation */ DEBUG_MSG( "allocate new scanout buffer failed - resizing existing bo"); /* Remove the old fb from the bo */ if (armsoc_bo_rm_fb(pARMSOC->scanout)) return FALSE; /* Resize the bo */ if (armsoc_bo_resize(pARMSOC->scanout, width, height)) { armsoc_bo_clear(pARMSOC->scanout); if (armsoc_bo_add_fb(pARMSOC->scanout)) ERROR_MSG( "Failed to add framebuffer to the existing scanout buffer"); return FALSE; } /* Add new fb to the bo */ if (armsoc_bo_clear(pARMSOC->scanout)) return FALSE; if (armsoc_bo_add_fb(pARMSOC->scanout)) { ERROR_MSG( "Failed to add framebuffer to the existing scanout buffer"); return FALSE; } pitch = armsoc_bo_pitch(pARMSOC->scanout); } else { DEBUG_MSG("allocated new scanout buffer okay"); pitch = armsoc_bo_pitch(new_scanout); /* clear new BO and add FB */ if (armsoc_bo_clear(new_scanout)) { armsoc_bo_unreference(new_scanout); return FALSE; } if (armsoc_bo_add_fb(new_scanout)) { ERROR_MSG( "Failed to add framebuffer to the new scanout buffer"); armsoc_bo_unreference(new_scanout); return FALSE; } /* Handle dma_buf fd that may be attached to old bo */ if (armsoc_bo_has_dmabuf(pARMSOC->scanout)) { int res; armsoc_bo_clear_dmabuf(pARMSOC->scanout); res = armsoc_bo_set_dmabuf(new_scanout); if (res) { ERROR_MSG( "Unable to attach dma_buf fd to new scanout buffer - %d (%s)\n", res, strerror(res)); armsoc_bo_unreference(new_scanout); return FALSE; } } /* delete old scanout buffer */ armsoc_bo_unreference(pARMSOC->scanout); /* use new scanout buffer */ set_scanout_bo(pScrn, new_scanout); } pScrn->displayWidth = pitch / ((pScrn->bitsPerPixel + 7) / 8); } else pitch = armsoc_bo_pitch(pARMSOC->scanout); if (pScreen && pScreen->ModifyPixmapHeader) { PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen); pScreen->ModifyPixmapHeader(rootPixmap, pScrn->virtualX, pScrn->virtualY, pScrn->depth, pScrn->bitsPerPixel, pitch, armsoc_bo_map(pARMSOC->scanout)); /* Bump the serial number to ensure that all existing DRI2 * buffers are invalidated. * * This is particularly required for when the resolution is * changed and then reverted to the original size without a * DRI2 client/s getting a new buffer. Without this, the * drawable is the same size and serial number so the old * DRI2Buffer will be returned, even though the backing buffer * has been deleted. */ rootPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; } /* Framebuffer needs to be reset on all CRTCs, not just * those that have repositioned */ xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); for (i = 0; i < xf86_config->num_crtc; i++) { xf86CrtcPtr crtc = xf86_config->crtc[i]; if (!crtc->enabled) continue; drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, crtc->x, crtc->y); } TRACE_EXIT(); return TRUE; } static const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = { drmmode_xf86crtc_resize }; Bool drmmode_pre_init(ScrnInfoPtr pScrn, int fd, int cpp) { struct drmmode_rec *drmmode; int i; TRACE_ENTER(); drmmode = calloc(1, sizeof *drmmode); if (!drmmode) return FALSE; drmmode->fd = fd; xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs); drmmode->cpp = cpp; drmmode->mode_res = drmModeGetResources(drmmode->fd); if (!drmmode->mode_res) { free(drmmode); return FALSE; } else { DEBUG_MSG("Got KMS resources"); DEBUG_MSG(" %d connectors, %d encoders", drmmode->mode_res->count_connectors, drmmode->mode_res->count_encoders); DEBUG_MSG(" %d crtcs, %d fbs", drmmode->mode_res->count_crtcs, drmmode->mode_res->count_fbs); DEBUG_MSG(" %dx%d minimum resolution", drmmode->mode_res->min_width, drmmode->mode_res->min_height); DEBUG_MSG(" %dx%d maximum resolution", drmmode->mode_res->max_width, drmmode->mode_res->max_height); } xf86CrtcSetSizeRange(pScrn, 320, 200, drmmode->mode_res->max_width, drmmode->mode_res->max_height); if (ARMSOCPTR(pScrn)->crtcNum == -1) { INFO_MSG("Adding all CRTCs"); for (i = 0; i < drmmode->mode_res->count_crtcs; i++) drmmode_crtc_init(pScrn, drmmode, i); } else if (ARMSOCPTR(pScrn)->crtcNum < drmmode->mode_res->count_crtcs) { drmmode_crtc_init(pScrn, drmmode, ARMSOCPTR(pScrn)->crtcNum); } else { ERROR_MSG( "Specified more Screens in xorg.conf than there are DRM CRTCs"); return FALSE; } if (ARMSOCPTR(pScrn)->crtcNum != -1) { if (ARMSOCPTR(pScrn)->crtcNum < drmmode->mode_res->count_connectors) drmmode_output_init(pScrn, drmmode, ARMSOCPTR(pScrn)->crtcNum); else return FALSE; } else { for (i = 0; i < drmmode->mode_res->count_connectors; i++) drmmode_output_init(pScrn, drmmode, i); } xf86InitialConfiguration(pScrn, TRUE); TRACE_EXIT(); return TRUE; } void drmmode_adjust_frame(ScrnInfoPtr pScrn, int x, int y) { xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); xf86OutputPtr output = config->output[config->compat_output]; xf86CrtcPtr crtc = output->crtc; if (!crtc || !crtc->enabled) return; drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, x, y); } /* * Page Flipping */ static void page_flip_handler(int fd, unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec, void *user_data) { ARMSOCDRI2SwapComplete(user_data); } static drmEventContext event_context = { .version = DRM_EVENT_CONTEXT_VERSION, .page_flip_handler = page_flip_handler, }; int drmmode_page_flip(DrawablePtr draw, uint32_t fb_id, void *priv) { ScrnInfoPtr pScrn = xf86Screens[draw->pScreen->myNum]; struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); struct drmmode_crtc_private_rec *crtc = config->crtc[0]->driver_private; struct drmmode_rec *mode = crtc->drmmode; int ret, i, failed = 0, num_flipped = 0; unsigned int flags = 0; if (pARMSOC->drmmode_interface->use_page_flip_events) flags |= DRM_MODE_PAGE_FLIP_EVENT; /* if we can flip, we must be fullscreen.. so flip all CRTC's.. */ for (i = 0; i < config->num_crtc; i++) { crtc = config->crtc[i]->driver_private; if (!config->crtc[i]->enabled) continue; ret = drmModePageFlip(mode->fd, crtc->mode_crtc->crtc_id, fb_id, flags, priv); if (ret) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "flip queue failed: %s\n", strerror(errno)); failed = 1; } else num_flipped += 1; } if (failed) return -(num_flipped + 1); else return num_flipped; } /* * Hot Plug Event handling: */ static void drmmode_handle_uevents(int fd, void *closure) { ScrnInfoPtr pScrn = closure; struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); struct drmmode_rec *drmmode = drmmode_from_scrn(pScrn); struct udev_device *dev; const char *hotplug; struct stat s; dev_t udev_devnum; dev = udev_monitor_receive_device(drmmode->uevent_monitor); if (!dev) return; /* TODO: MIDEGL-1441: Do we need to keep this code, which * Rob originally wrote? (i.e. up thru the "if" statement)? */ /* * Check to make sure this event is directed at our * device (by comparing dev_t values), then make * sure it's a hotplug event (HOTPLUG=1) */ udev_devnum = udev_device_get_devnum(dev); fstat(pARMSOC->drmFD, &s); hotplug = udev_device_get_property_value(dev, "HOTPLUG"); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "hotplug=%s, match=%d\n", hotplug, !memcmp(&s.st_rdev, &udev_devnum, sizeof(dev_t))); if (memcmp(&s.st_rdev, &udev_devnum, sizeof(dev_t)) == 0 && hotplug && atoi(hotplug) == 1) { RRGetInfo(screenInfo.screens[pScrn->scrnIndex], TRUE); } udev_device_unref(dev); } static void drmmode_uevent_init(ScrnInfoPtr pScrn) { struct drmmode_rec *drmmode = drmmode_from_scrn(pScrn); struct udev *u; struct udev_monitor *mon; TRACE_ENTER(); u = udev_new(); if (!u) return; mon = udev_monitor_new_from_netlink(u, "udev"); if (!mon) { udev_unref(u); return; } if (udev_monitor_filter_add_match_subsystem_devtype(mon, "drm", "drm_minor") < 0 || udev_monitor_enable_receiving(mon) < 0) { udev_monitor_unref(mon); udev_unref(u); return; } drmmode->uevent_handler = xf86AddGeneralHandler(udev_monitor_get_fd(mon), drmmode_handle_uevents, pScrn); drmmode->uevent_monitor = mon; TRACE_EXIT(); } static void drmmode_uevent_fini(ScrnInfoPtr pScrn) { struct drmmode_rec *drmmode = drmmode_from_scrn(pScrn); TRACE_ENTER(); if (drmmode->uevent_handler) { struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor); xf86RemoveGeneralHandler(drmmode->uevent_handler); udev_monitor_unref(drmmode->uevent_monitor); udev_unref(u); } TRACE_EXIT(); } static void drmmode_wakeup_handler(pointer data, int err, pointer p) { int fd = (int)data; fd_set *read_mask = p; if (err < 0) return; if (FD_ISSET(fd, read_mask)) drmHandleEvent(fd, &event_context); } void drmmode_init_wakeup_handler(int fd) { AddGeneralSocket(fd); RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA, drmmode_wakeup_handler, (pointer)fd); } void drmmode_fini_wakeup_handler(int fd) { RemoveBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA, drmmode_wakeup_handler, (pointer)fd); RemoveGeneralSocket(fd); } void drmmode_wait_for_event(ScrnInfoPtr pScrn) { struct drmmode_rec *drmmode = drmmode_from_scrn(pScrn); drmHandleEvent(drmmode->fd, &event_context); } void drmmode_screen_init(ScrnInfoPtr pScrn) { drmmode_uevent_init(pScrn); } void drmmode_screen_fini(ScrnInfoPtr pScrn) { drmmode_uevent_fini(pScrn); } xf86-video-armsoc-0.6.0/src/drmmode_driver.h000066400000000000000000000064371220735425600206600ustar00rootroot00000000000000/* * Copyright © 2013 ARM Limited. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * */ #ifndef DRMMODE_DRIVER_H #define DRMMODE_DRIVER_H #include #include "xorg-server.h" #include "xf86Crtc.h" struct drmmode_interface { /* Flags value to pass to DRM_IOCTL_MODE_CREATE_DUMB to allocate * a scanout-capable buffer. A buffer allocated with these flags * must be able to be wrapped in a DRM framebuffer (via * DRM_IOCTL_MODE_ADDFB or DRM_IOCTL_MODE_ADDFB2). */ uint32_t dumb_scanout_flags; /* Flags value to pass to DRM_IOCTL_MODE_CREATE_DUMB to allocate a * non-scanout-capable buffer. It is acceptable for the driver to * create a scanout-capable buffer when given this flag, this flag * is used to give the option of preserving scarce scanout-capable * memory if applicable. */ uint32_t dumb_no_scanout_flags; /* Boolean value indicating whether DRM page flip events should * be requested and waited for during DRM_IOCTL_MODE_PAGE_FLIP. */ int use_page_flip_events; /* The cursor width */ int cursor_width; /* The cursor height */ int cursor_height; /* A padding column of pixels of this width is added to either * side of the image */ int cursor_padding; /* (Optional) Initialize the given plane for use as a hardware cursor. * * This function should do any initialization necessary, for example * setting the z-order on the plane to appear above all other layers. * * @param drm_fd The DRM device file * @param plane_id The plane to initialize * @return 0 on success, non-zero on failure */ int (*init_plane_for_cursor)(int drm_fd, uint32_t plane_id); /* (Mandatory) Set the cursor image from an ARGB image * * If the cursor image is ARGB this is a straight copy, otherwise * it must perform any necessary conversion from ARGB to the * cursor format. * * @param crtc The CRTC in use * @param [out] d Pointer to the destination cursor image * @param [in] s Pointer to the source for the cursor image */ void (*set_cursor_image)(xf86CrtcPtr crtc, uint32_t *d, CARD32 *s); /* Boolean value indicating whether the DRM supports * vblank timestamp query */ int vblank_query_supported; }; struct drmmode_interface *drmmode_interface_get_implementation(int drm_fd); #endif xf86-video-armsoc-0.6.0/src/drmmode_exynos/000077500000000000000000000000001220735425600205275ustar00rootroot00000000000000xf86-video-armsoc-0.6.0/src/drmmode_exynos/drmmode_exynos.c000066400000000000000000000103341220735425600237300ustar00rootroot00000000000000/* * Copyright © 2013 ARM Limited. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * */ #include "../drmmode_driver.h" #include #include #include struct drm_exynos_plane_set_zpos { __u32 plane_id; __s32 zpos; }; /* Cursor dimensions * Technically we probably don't have any size limit.. since we * are just using an overlay... but xserver will always create * cursor images in the max size, so don't use width/height values * that are too big */ #define CURSORW (64) #define CURSORH (64) #define CURSORPAD (16) /* Padding added down each side of cursor image */ #define DRM_EXYNOS_PLANE_SET_ZPOS 0x06 #define DRM_IOCTL_EXYNOS_PLANE_SET_ZPOS DRM_IOWR(DRM_COMMAND_BASE + \ DRM_EXYNOS_PLANE_SET_ZPOS, struct drm_exynos_plane_set_zpos) static int init_plane_for_cursor(int drm_fd, uint32_t plane_id) { int res = -1; drmModeObjectPropertiesPtr props; props = drmModeObjectGetProperties(drm_fd, plane_id, DRM_MODE_OBJECT_PLANE); if (props) { int i; for (i = 0; i < props->count_props; i++) { drmModePropertyPtr this_prop; this_prop = drmModeGetProperty(drm_fd, props->props[i]); if (this_prop) { if (!strncmp(this_prop->name, "zpos", DRM_PROP_NAME_LEN)) { res = drmModeObjectSetProperty(drm_fd, plane_id, DRM_MODE_OBJECT_PLANE, this_prop->prop_id, 1); drmModeFreeProperty(this_prop); break; } drmModeFreeProperty(this_prop); } } drmModeFreeObjectProperties(props); } if (res) { /* Try the old method */ struct drm_exynos_plane_set_zpos data; data.plane_id = plane_id; data.zpos = 1; res = ioctl(drm_fd, DRM_IOCTL_EXYNOS_PLANE_SET_ZPOS, &data); } return res; } /* The cursor format is ARGB so the image can be copied straight over. * Columns of CURSORPAD blank pixels are maintained down either side * of the destination image. This is a workaround for a bug causing * corruption when the cursor reaches the screen edges. */ static void set_cursor_image(xf86CrtcPtr crtc, uint32_t *d, CARD32 *s) { int row; void *dst; const char *src_row; char *dst_row; dst = d; for (row = 0; row < CURSORH; row += 1) { /* we're operating with ARGB data (4 bytes per pixel) */ src_row = (const char *)s + row * 4 * CURSORW; dst_row = (char *)dst + row * 4 * (CURSORW + 2 * CURSORPAD); /* set first CURSORPAD pixels in row to 0 */ memset(dst_row, 0, (4 * CURSORPAD)); /* copy cursor image pixel row across */ memcpy(dst_row + (4 * CURSORPAD), src_row, 4 * CURSORW); /* set last CURSORPAD pixels in row to 0 */ memset(dst_row + 4 * (CURSORPAD + CURSORW), 0, (4 * CURSORPAD)); } } struct drmmode_interface exynos_interface = { 0x00000000 /* dumb_scanout_flags */, 0x00000001 /* dumb_no_scanout_flags */, 1 /* use_page_flip_events */, CURSORW /* cursor width */, CURSORH /* cursor_height */, CURSORPAD /* cursor padding */, init_plane_for_cursor /* init_plane_for_cursor */, set_cursor_image /* set cursor image */, 0 /* vblank_query_supported */, }; struct drmmode_interface *drmmode_interface_get_implementation(int drm_fd) { return &exynos_interface; } xf86-video-armsoc-0.6.0/src/drmmode_pl111/000077500000000000000000000000001220735425600200405ustar00rootroot00000000000000xf86-video-armsoc-0.6.0/src/drmmode_pl111/drmmode_pl111.c000066400000000000000000000116111220735425600225510ustar00rootroot00000000000000/* * Copyright © 2013 ARM Limited. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * */ #include "../drmmode_driver.h" #include /* Cursor dimensions * Technically we probably don't have any size limit.. since we * are just using an overlay... but xserver will always create * cursor images in the max size, so don't use width/height values * that are too big */ #define CURSORW (64) #define CURSORH (64) /* Padding added down each side of cursor image */ #define CURSORPAD (0) /* un-comment to enable cursor format conversion debugging.*/ /* #define ARGB_LBBP_CONVERSION_DEBUG */ #define LBBP_BACKGROUND (0x0) #define LBBP_FOREGROUND (0x1) #define LBBP_TRANSPARENT (0x2) #define LBBP_INVERSE (0x3) #define ARGB_ALPHA (0xff000000) #define ARGB_RGB (~ARGB_ALPHA) #define LBBP_WORDS_PER_LINE (4) #define LBBP_PIXELS_PER_WORD (16) /* shift required to locate pixel into the correct position in * a cursor LBBP word, indexed by x mod 16. */ const unsigned char x_mod_16_to_value_shift[LBBP_PIXELS_PER_WORD] = { 6, 4, 2, 0, 14, 12, 10, 8, 22, 20, 18, 16, 30, 28, 26, 24 }; /* Pack the pixel value into its correct position in the buffer as specified * for LBBP */ static inline void set_lbbp_pixel(uint32_t *buffer, unsigned int x, unsigned int y, uint32_t value) { uint32_t *p; uint32_t shift; assert((x < CURSORW) && (y < CURSORH)); shift = x_mod_16_to_value_shift[x % LBBP_PIXELS_PER_WORD]; /* Get the word containing this pixel */ p = buffer + (x >> LBBP_WORDS_PER_LINE) + (y << 2); /* Clear data for this pixel in the buffer and apply the new data */ *p &= ~(LBBP_INVERSE << shift); *p |= value << shift; } /* * The PL111 hardware cursor supports only LBBP which is a 2bpp format but * there are no drm fourcc formats that are compatible with this so instead * the PL111 DRM reports (to DRM core) that it supports only * DRM_FORMAT_ARGB8888 and expects the DDX to supply an LBPP image in the * first 1/16th of the buffer, the rest being unused. * Ideally we would want to receive the image in this format from X, but * currently the X cursor image is 32bpp ARGB so we need to convert * to LBBP here. */ static void set_cursor_image(xf86CrtcPtr crtc, uint32_t *d, CARD32 *s) { #ifdef ARGB_LBBP_CONVERSION_DEBUG /* Add 1 on width to insert trailing NULL */ char string_cursor[CURSORW+1]; #endif /* ARGB_LBBP_CONVERSION_DEBUG */ unsigned int x; unsigned int y; for (y = 0; y < CURSORH ; y++) { for (x = 0; x < CURSORW ; x++) { uint32_t value = LBBP_TRANSPARENT; /* If pixel visible foreground/background */ if ((*s & ARGB_ALPHA) != 0) { /* Any color set then just convert to * foreground for now */ if ((*s & ARGB_RGB) != 0) value = LBBP_FOREGROUND; else value = LBBP_BACKGROUND; } #ifdef ARGB_LBBP_CONVERSION_DEBUG if (value == LBBP_TRANSPARENT) string_cursor[x] = 'T'; else if (value == LBBP_FOREGROUND) string_cursor[x] = 'F'; else if (value == LBBP_INVERSE) string_cursor[x] = 'I'; else string_cursor[x] = 'B'; #endif /* ARGB_LBBP_CONVERSION_DEBUG */ set_lbbp_pixel(d, x, y, value); ++s; } #ifdef ARGB_LBBP_CONVERSION_DEBUG string_cursor[CURSORW] = '\0'; xf86DrvMsg(crtc->scrn->scrnIndex, X_INFO, "%s\n", string_cursor); #endif /* ARGB_LBBP_CONVERSION_DEBUG */ } } struct drmmode_interface pl111_interface = { 0x00000001 /* dumb_scanout_flags */, 0x00000000 /* dumb_no_scanout_flags */, 0 /* use_page_flip_events */, CURSORW /* cursor width */, CURSORH /* cursor_height */, CURSORPAD /* cursor padding */, NULL /* init_plane_for_cursor */, set_cursor_image /* set cursor image */, 0 /* vblank_query_supported */, }; struct drmmode_interface *drmmode_interface_get_implementation(int drm_fd) { return &pl111_interface; } xf86-video-armsoc-0.6.0/src/drmmode_template/000077500000000000000000000000001220735425600210155ustar00rootroot00000000000000xf86-video-armsoc-0.6.0/src/drmmode_template/drmmode_template.c000066400000000000000000000045451220735425600245130ustar00rootroot00000000000000/* * Copyright © 2013 ARM Limited. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * */ #include "../drmmode_driver.h" /* Cursor dimensions * Technically we probably don't have any size limit.. since we * are just using an overlay... but xserver will always create * cursor images in the max size, so don't use width/height values * that are too big */ /* width */ #define CURSORW (64) /* height */ #define CURSORH (64) /* Padding added down each side of cursor image */ #define CURSORPAD (0) /* Optional function */ static int init_plane_for_cursor(int drm_fd, uint32_t plane_id) { return 0; } static void set_cursor_image(xf86CrtcPtr crtc, uint32_t *d, CARD32 *s) { /* provide a method of setting the cursor image here */ } struct drmmode_interface template_interface = { 0x00000000 /* dumb_scanout_flags */, 0x00000000 /* dumb_no_scanout_flags */, 1 /* use_page_flip_events */, CURSORW /* cursor width */, CURSORH /* cursor_height */, CURSORPAD /* cursor padding */, init_plane_for_cursor /* init_plane_for_cursor */, set_cursor_image /* set cursor image */, 0 /* vblank_query_supported */, }; struct drmmode_interface *drmmode_interface_get_implementation(int drm_fd) { return &template_interface; }