pax_global_header00006660000000000000000000000064127575433500014525gustar00rootroot0000000000000052 comment=8bbdb2ae3bb8ef649999a8da33ddbe11a04763b8 xf86-video-armsoc-1.4.1/000077500000000000000000000000001275754335000147115ustar00rootroot00000000000000xf86-video-armsoc-1.4.1/.gitignore000066400000000000000000000004111275754335000166750ustar00rootroot00000000000000aclocal.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-1.4.1/COPYING000066400000000000000000000021111275754335000157370ustar00rootroot00000000000000Copyright © 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-1.4.1/Makefile.am000066400000000000000000000024701275754335000167500ustar00rootroot00000000000000# 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-1.4.1/NEWS000066400000000000000000000000041275754335000154020ustar00rootroot00000000000000TBD xf86-video-armsoc-1.4.1/README000066400000000000000000000041751275754335000156000ustar00rootroot00000000000000xf86-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 should choose a particular DRM driver dynamically according to the current environment. The currently supported DRM drivers are: - pl111 - exynos - kirin - sti For other drivers, you will need to implement this support yourself. A template implementation is provided in src/drmmode_template. 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_, modify the driver_name to match with the name used in the kernel drm driver. Summary of bo reference counting -------------------------------- The Screen takes a ref on the scanout bo in InitScreen and drops it in ScreenClose. When the scanout bo changes (due to a flip or a modeset) the ref is moved from the old bo to the new one by set_scanout_bo. Pixmaps take a ref on their bo(s) when created in ARMSOCCreatePixmap2 and drop it in ARMSOCDestroyPixmap. If ARMSOCModifyPixmapHeader points a pixmap at anything other than the scanout bo then the ref to the existing bo (if any) is dropped. If ARMSOCModifyPixmapHeader points a pixmap at the scanout bo the ref is moved from the old bo to the new If ARMSOCModifyPixmapHeader changes the size of the pixmap's bo the ref is dropped, a new bo created and a ref taken on that. resize_scanout_bo creates and takes a ref on the new bo and drops its ref when the new bo becomes the scanout bo and the Screen has taken a ref. The swap chain takes a ref on the src and dst bos when a swap is scheduled in ARMSOCDRI2ScheduleSwap and drops them in ARMSOCDRI2SwapComplete after the src becomes pARMSOC->scanout and the screen takes a ref. The cursor takes a ref on its bo in drmmode_cursor_init and drops it in drmmode_cursor_fini xf86-video-armsoc-1.4.1/autogen.sh000077500000000000000000000014671275754335000167220ustar00rootroot00000000000000#! /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-1.4.1/configure.ac000066400000000000000000000056441275754335000172100ustar00rootroot00000000000000# -*- 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], [1.4.1], [], [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 foreign]) 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"]) # 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 pixman-1 $REQUIRED_MODULES) PKG_CHECK_MODULES(XEXT, [xextproto >= 7.0.99.1], HAVE_XEXTPROTO_71="yes"; AC_DEFINE(HAVE_XEXTPROTO_71, 1, [xextproto 7.1 available]), HAVE_XEXTPROTO_71="no") AM_CONDITIONAL(HAVE_XEXTPROTO_71, [ test "$HAVE_XEXTPROTO_71" = "yes"]) # Checks for 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-1.4.1/man/000077500000000000000000000000001275754335000154645ustar00rootroot00000000000000xf86-video-armsoc-1.4.1/man/Makefile.am000066400000000000000000000027351275754335000175270ustar00rootroot00000000000000# # 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-1.4.1/man/armsoc.man000066400000000000000000000113371275754335000174520ustar00rootroot00000000000000.\" 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 .TP .BI "Option \*qInitFromFBDev\*q \*q" string \*q Specifies an fbdev device node (such as "/dev/fb0") to use to initialize the DRM scanout buffer. Specifying this option only makes sense (and is required) when X is started with the parameter "-background none". The InitFromFBDev functionality is limited to when the fbdev device pixel format matches the format of the X screen. This includes bits-per-pixel and RGB ordering and size. If the driver is unable to copy from the fbdev device then an error will be logged, and the -background none functionality will be disabled. .IP Default: NULL .TP .BI "Option \*qUMP_LOCK\*q \*q" boolean \*q Use the umplock module for cross-process access synchronization. It should be only enabled for Mali400 .IP Default: Umplock is Disabled .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-1.4.1/src/000077500000000000000000000000001275754335000155005ustar00rootroot00000000000000xf86-video-armsoc-1.4.1/src/Makefile.am000066400000000000000000000046641275754335000175460ustar00rootroot00000000000000# 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_exynos/drmmode_exynos.c \ drmmode_pl111/drmmode_pl111.c \ drmmode_kirin/drmmode_kirin.c \ drmmode_sti/drmmode_sti.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-1.4.1/src/armsoc_dri2.c000077500000000000000000001004271275754335000200570ustar00rootroot00000000000000/* -*- 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 < 5 # error "Requires newer DRI2" #endif #include "drmmode_driver.h" struct ARMSOCDRI2BufferRec { DRI2BufferRec base; /** * Pixmap(s) that are backing the buffer * * We assume that a window's front buffer pixmap is never reallocated, * and therefore that it is safe to use the pointer to it stored here. */ 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. * * If canflip() returns something different to what is stored here, * the DRI2 buffers should be 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 = xf86ScreenToScrn(pScreen); 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); } static inline Bool canexchange(DrawablePtr pDraw, struct armsoc_bo *src_bo, struct armsoc_bo *dst_bo) { Bool ret = FALSE; ScreenPtr pScreen = pDraw->pScreen; PixmapPtr pRootPixmap, pWindowPixmap; int src_fb_id, dst_fb_id; pRootPixmap = pScreen->GetWindowPixmap(pScreen->root); pWindowPixmap = pDraw->type == DRAWABLE_PIXMAP ? (PixmapPtr)pDraw : pScreen->GetWindowPixmap((WindowPtr)pDraw); src_fb_id = armsoc_bo_get_fb(src_bo); dst_fb_id = armsoc_bo_get_fb(dst_bo); if (pRootPixmap != pWindowPixmap && armsoc_bo_width(src_bo) == armsoc_bo_width(dst_bo) && armsoc_bo_height(src_bo) == armsoc_bo_height(dst_bo) && armsoc_bo_bpp(src_bo) == armsoc_bo_bpp(dst_bo) && armsoc_bo_width(src_bo) == pDraw->width && armsoc_bo_height(src_bo) == pDraw->height && armsoc_bo_bpp(src_bo) == pDraw->bitsPerPixel && src_fb_id == 0 && dst_fb_id == 0) { ret = TRUE; } return ret; } static Bool create_buffer(DrawablePtr pDraw, struct ARMSOCDRI2BufferRec *buf) { ScreenPtr pScreen = pDraw->pScreen; ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); DRI2BufferPtr buffer = DRIBUF(buf); PixmapPtr pPixmap = NULL; struct armsoc_bo *bo; int ret; if (buffer->attachment == DRI2BufferFrontLeft) { pPixmap = draw2pix(pDraw); pPixmap->refcnt++; } else { pPixmap = createpix(pDraw); } if (!pPixmap) { assert(buffer->attachment != DRI2BufferFrontLeft); ERROR_MSG("Failed to create back buffer for window"); goto fail; } if (buffer->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)->pitch = exaGetPixmapPitch(pPixmap); DRIBUF(buf)->cpp = pPixmap->drawable.bitsPerPixel / 8; DRIBUF(buf)->flags = 0; buf->refcnt = 1; buf->previous_canflip = canflip(pDraw); 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) && buffer->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"); } #if DRI2INFOREC_VERSION >= 6 else if (FALSE == DRI2SwapLimit(pDraw, pARMSOC->swap_chain_size)) { WARNING_MSG( "Failed to set DRI2SwapLimit(%p,%d)", pDraw, pARMSOC->swap_chain_size); } #endif /* DRI2INFOREC_VERSION >= 6 */ } DRI2_BUFFER_SET_FB(DRIBUF(buf)->flags, armsoc_bo_get_fb(bo) > 0 ? 1 : 0); DRI2_BUFFER_SET_REUSED(DRIBUF(buf)->flags, 0); /* Register Pixmap as having a buffer that can be accessed externally, * so needs synchronised access */ ARMSOCRegisterExternalAccess(pPixmap); return TRUE; fail: if (pPixmap != NULL) { if (buffer->attachment != DRI2BufferFrontLeft) pScreen->DestroyPixmap(pPixmap); else pPixmap->refcnt--; } return FALSE; } static Bool destroy_buffer(DrawablePtr pDraw, struct ARMSOCDRI2BufferRec *buf) { ScreenPtr pScreen = buf->pPixmaps[0]->drawable.pScreen; ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); DRI2BufferPtr buffer = DRIBUF(buf); int numBuffers, i; if (--buf->refcnt > 0) return FALSE; 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]); } return TRUE; } /** * 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 = xf86ScreenToScrn(pScreen); struct ARMSOCDRI2BufferRec *buf; DEBUG_MSG("pDraw=%p, attachment=%d, format=%08x", pDraw, attachment, format); buf = calloc(1, sizeof *buf); if (!buf) { ERROR_MSG("Couldn't allocate internal buffer structure"); return NULL; } DRIBUF(buf)->attachment = attachment; DRIBUF(buf)->format = format; if (!create_buffer(pDraw, buf)) { free(buf); return NULL; } return DRIBUF(buf); } /** * Destroy Buffer */ static void ARMSOCDRI2DestroyBuffer(DrawablePtr pDraw, DRI2BufferPtr buffer) { struct ARMSOCDRI2BufferRec *buf = ARMSOCBUF(buffer); ScreenPtr pScreen; ScrnInfoPtr pScrn; /* Note: pDraw may already be deleted, so use the pPixmap here * instead (since it is at least refcntd) */ if (NULL == buf->pPixmaps || NULL == buf->pPixmaps[0]) { if (--buf->refcnt == 0) free(buf); return; } pScreen = buf->pPixmaps[0]->drawable.pScreen; pScrn = xf86ScreenToScrn(pScreen); DEBUG_MSG("pDraw=%p, DRIbuffer=%p", pDraw, buffer); if (destroy_buffer(pDraw, buf)) { 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 = xf86ScreenToScrn(pScreen); 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 = xf86ScreenToScrn(pScreen); 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; } #if DRI2INFOREC_VERSION >= 6 /** * Called by DRI2 to validate that any new swap limit being set by * DRI2 is in range. In our case the range is 1 to the DRI2MaxBuffers * option, plus one in the case of early display usage. */ static Bool ARMSOCDRI2SwapLimitValidate(DrawablePtr pDraw, int swap_limit) { ScreenPtr pScreen = pDraw->pScreen; ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); int32_t lower_limit, upper_limit; lower_limit = 1; upper_limit = pARMSOC->driNumBufs-1; if (pARMSOC->drmmode_interface->use_early_display) upper_limit += 1; return ((swap_limit >= lower_limit) && (swap_limit <= upper_limit)) ? TRUE : FALSE; } #endif /* DRI2INFOREC_VERSION >= 6 */ #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; /* number of crtcs with flips in flight for this swap */ int flags; void *data; struct armsoc_bo *old_src_bo; /* Swap chain holds ref on src bo */ struct armsoc_bo *old_dst_bo; /* Swap chain holds ref on dst bo */ struct armsoc_bo *new_scanout; /* scanout to be used after swap */ unsigned int swap_id; }; static const char * const swap_names[] = { [DRI2_EXCHANGE_COMPLETE] = "exchange", [DRI2_BLIT_COMPLETE] = "blit", [DRI2_FLIP_COMPLETE] = "flip," }; struct ARMSOCDRIVBlankCmd { int type; ClientPtr client; DrawablePtr pDraw; }; static Bool allocNextBuffer(DrawablePtr pDraw, PixmapPtr *ppPixmap, uint32_t *name) { ScreenPtr pScreen = pDraw->pScreen; ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 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 (canflip(pDraw) && !armsoc_bo_get_fb(bo)) { ret = armsoc_bo_add_fb(bo); 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 = xf86ScreenToScrn(pScreen); 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; } static void updateResizedBuffer(ScrnInfoPtr pScrn, void *buffer, struct armsoc_bo *old_bo, struct armsoc_bo *resized_bo) { DRI2BufferPtr dri2buf = (DRI2BufferPtr)buffer; struct ARMSOCDRI2BufferRec *buf = ARMSOCBUF(dri2buf); int i; for (i = 0; i < buf->numPixmaps; i++) { if (buf->pPixmaps[i] != NULL) { struct ARMSOCPixmapPrivRec *priv = exaGetPixmapDriverPrivate(buf->pPixmaps[i]); if (old_bo == priv->bo) { int ret; /* Update the buffer name if this pixmap is current */ if (i == buf->currentPixmap) { ret = armsoc_bo_get_name(resized_bo, &dri2buf->name); assert(!ret); } /* pixmap takes ref on resized bo */ armsoc_bo_reference(resized_bo); /* replace the old_bo with the resized_bo */ priv->bo = resized_bo; /* pixmap drops ref on old bo */ armsoc_bo_unreference(old_bo); } } } } void ARMSOCDRI2ResizeSwapChain(ScrnInfoPtr pScrn, struct armsoc_bo *old_bo, struct armsoc_bo *resized_bo) { struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); struct ARMSOCDRISwapCmd *cmd = NULL; int i; int back = pARMSOC->swap_chain_count - 1; /* The last swap scheduled */ /* Update the bos for each scheduled swap in the swap chain */ for (i = 0; i < pARMSOC->swap_chain_size && back >= 0; i++) { unsigned int idx = back % pARMSOC->swap_chain_size; cmd = pARMSOC->swap_chain[idx]; back--; if (!cmd) continue; updateResizedBuffer(pScrn, cmd->pSrcBuffer, old_bo, resized_bo); updateResizedBuffer(pScrn, cmd->pDstBuffer, old_bo, resized_bo); } } void ARMSOCDRI2SwapComplete(struct ARMSOCDRISwapCmd *cmd) { ScreenPtr pScreen = cmd->pScreen; ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); DrawablePtr pDraw = NULL; unsigned int idx; int status; if (--cmd->swapCount > 0) /* wait for all crtcs to flip */ return; if ((cmd->flags & ARMSOC_SWAP_FAIL) == 0) { DEBUG_MSG("swap %d %s complete: %d -> %d", cmd->swap_id, swap_names[cmd->type], cmd->pSrcBuffer->attachment, cmd->pDstBuffer->attachment); status = dixLookupDrawable(&pDraw, cmd->draw_id, serverClient, M_ANY, DixWriteAccess); if (status == Success) { DRI2SwapComplete(cmd->client, pDraw, 0, 0, 0, cmd->type, cmd->func, cmd->data); if (cmd->type != DRI2_BLIT_COMPLETE && cmd->type != DRI2_EXCHANGE_COMPLETE && (cmd->flags & ARMSOC_SWAP_FAKE_FLIP) == 0) { assert(cmd->type == DRI2_FLIP_COMPLETE); set_scanout_bo(pScrn, cmd->new_scanout); } } else { ERROR_MSG("dixLookupDrawable fail on swap complete"); } } else { ERROR_MSG("swap %d ARMSOC_SWAP_FAIL on swap complete", cmd->swap_id); } /* drop extra refcnt we obtained prior to swap: */ ARMSOCDRI2DestroyBuffer(pDraw, cmd->pSrcBuffer); ARMSOCDRI2DestroyBuffer(pDraw, cmd->pDstBuffer); /* swap chain drops ref on original src bo */ armsoc_bo_unreference(cmd->old_src_bo); /* swap chain drops ref on original dst bo */ armsoc_bo_unreference(cmd->old_dst_bo); if (cmd->type == DRI2_FLIP_COMPLETE) { pARMSOC->pending_flips--; /* Free the swap cmd and remove it from the swap chain. */ idx = cmd->swap_id % pARMSOC->swap_chain_size; if (pARMSOC->swap_chain[idx] != cmd) WARNING_MSG("Flip isn't in order\n"); pARMSOC->swap_chain[idx] = NULL; } 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 = xf86ScreenToScrn(pScreen); struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); struct ARMSOCDRI2BufferRec *src = ARMSOCBUF(pSrcBuffer); struct ARMSOCDRI2BufferRec *dst = ARMSOCBUF(pDstBuffer); #if DRI2INFOREC_VERSION < 6 int new_canflip; #endif struct ARMSOCDRISwapCmd *cmd; struct armsoc_bo *src_bo, *dst_bo; int src_fb_id, dst_fb_id; int ret, do_flip; unsigned int idx; RegionRec region; PixmapPtr pDstPixmap = NULL; if (NULL == src->pPixmaps || NULL == src->pPixmaps[src->currentPixmap] || NULL == dst->pPixmaps || NULL == dst->pPixmaps[dst->currentPixmap]) { return FALSE; } pDstPixmap = draw2pix(dri2draw(pDraw, pDstBuffer)); cmd = calloc(1, sizeof(*cmd)); 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; /* obtain extra ref on DRI buffers to avoid them going * away while we await the page flip event. */ ARMSOCDRI2ReferenceBuffer(pSrcBuffer); ARMSOCDRI2ReferenceBuffer(pDstBuffer); 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); /* Store and reference actual buffer-objects used in case * the pixmaps disappear. */ cmd->old_src_bo = src_bo; cmd->old_dst_bo = dst_bo; /* Swap chain takes a ref on original src bo */ armsoc_bo_reference(cmd->old_src_bo); /* Swap chain takes a ref on original dst bo */ armsoc_bo_reference(cmd->old_dst_bo); DEBUG_MSG("SWAP %d SCHEDULED : %d -> %d ", cmd->swap_id, pSrcBuffer->attachment, pDstBuffer->attachment); #if DRI2INFOREC_VERSION < 6 new_canflip = canflip(pDraw); if ((src->previous_canflip != new_canflip) || (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; #endif 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("FLIPPING: FB%d -> FB%d", src_fb_id, dst_fb_id); cmd->type = DRI2_FLIP_COMPLETE; /* Add swap operation to the swap chain */ cmd->swap_id = pARMSOC->swap_chain_count++; idx = cmd->swap_id % pARMSOC->swap_chain_size; if (NULL != pARMSOC->swap_chain[idx]) WARNING_MSG("Flip is called too fast\n"); pARMSOC->swap_chain[idx] = cmd; /* TODO: MIDEGL-1461: Handle rollback if multiple CRTC flip is * only partially successful */ pARMSOC->pending_flips++; 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; cmd->new_scanout = boFromBuffer(pDstBuffer); 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; /* Flip successfully scheduled. * Now exchange bos between src and dst pixmaps * and select the next bo for the back buffer. */ if (ret) { assert(cmd->type == DRI2_FLIP_COMPLETE); exchangebufs(pDraw, pSrcBuffer, pDstBuffer); if (pSrcBuffer->attachment == DRI2BufferBackLeft) nextBuffer(pDraw, ARMSOCBUF(pSrcBuffer)); } /* Store the new scanout bo now as the destination * buffer bo might be exchanged if another swap is * scheduled before this swap completes */ cmd->new_scanout = boFromBuffer(pDstBuffer); if (cmd->swapCount == 0) ARMSOCDRI2SwapComplete(cmd); } } else if (canexchange(pDraw, src_bo, dst_bo)) { exchangebufs(pDraw, pSrcBuffer, pDstBuffer); if (pSrcBuffer->attachment == DRI2BufferBackLeft) nextBuffer(pDraw, ARMSOCBUF(pSrcBuffer)); region.extents.x1 = region.extents.y1 = 0; region.extents.x2 = pDstPixmap->drawable.width; region.extents.y2 = pDstPixmap->drawable.height; region.data = NULL; DamageRegionAppend(&pDstPixmap->drawable, ®ion); DamageRegionProcessPending(&pDstPixmap->drawable); cmd->type = DRI2_EXCHANGE_COMPLETE; ARMSOCDRI2SwapComplete(cmd); } else { /* fallback to blit: */ BoxRec box = { .x1 = 0, .y1 = 0, .x2 = pDraw->width, .y2 = pDraw->height, }; RegionRec region; DEBUG_MSG("BLITTING"); RegionInit(®ion, &box, 0); ARMSOCDRI2CopyRegion(pDraw, ®ion, pDstBuffer, pSrcBuffer); cmd->type = DRI2_BLIT_COMPLETE; cmd->new_scanout = boFromBuffer(pDstBuffer); ARMSOCDRI2SwapComplete(cmd); } return TRUE; } void ARMSOCDRI2VBlankHandler(unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec, void *user_data) { struct ARMSOCDRIVBlankCmd *cmd = (struct ARMSOCDRIVBlankCmd *)user_data; DRI2WaitMSCComplete(cmd->client, cmd->pDraw, sequence, tv_sec, tv_usec); free(cmd); } /** * 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 = xf86ScreenToScrn(pScreen); struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); struct ARMSOCDRIVBlankCmd *cmd = NULL; drmVBlank vbl = { .request = { .type = DRM_VBLANK_RELATIVE, .sequence = 0, } }; int ret; CARD64 current_msc; 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; } current_msc = vbl.reply.sequence; if (current_msc >= target_msc) { DRI2WaitMSCComplete(client, pDraw, current_msc, 0, 0); return TRUE; } cmd = calloc(1, sizeof(*cmd)); if (!cmd) return FALSE; cmd->type = 0; cmd->client = client; cmd->pDraw = pDraw; vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT; vbl.request.sequence = target_msc; vbl.request.signal = (unsigned long)cmd; ret = drmWaitVBlank(pARMSOC->drmFD, &vbl); if (ret) { ERROR_MSG("get vblank counter failed: %s", strerror(errno)); return FALSE; } DRI2BlockClient(client, pDraw); return TRUE; } #if DRI2INFOREC_VERSION >= 6 /** * Called by DRI2 to reuse a buffer which is created earlier. */ static void ARMSOCDRI2ReuseBufferNotify(DrawablePtr pDraw, DRI2BufferPtr buffer) { int new_canflip, ret, fb_id; struct armsoc_bo *bo; struct ARMSOCDRI2BufferRec *buf = ARMSOCBUF(buffer); ScreenPtr pScreen = pDraw->pScreen; ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); DRI2_BUFFER_SET_REUSED(buffer->flags, 1); if (DRI2BufferBackLeft != buffer->attachment) { return; } bo = boFromBuffer(buffer); new_canflip = canflip(pDraw); if (buf->previous_canflip == new_canflip && armsoc_bo_width(bo) == pDraw->width && armsoc_bo_height(bo) == pDraw->height) { return; } if (destroy_buffer(pDraw, buf)) { free(buf->pPixmaps); buf->pPixmaps = NULL; if (!create_buffer(pDraw, buf)) { ERROR_MSG("Failed to create buffer"); } } else { fb_id = armsoc_bo_get_fb(bo); if (buf->previous_canflip == FALSE && new_canflip == TRUE && fb_id == 0) { ret = armsoc_bo_add_fb(bo); if (ret) { WARNING_MSG("Falling back to blitting a flippable window"); } else { DRI2_BUFFER_SET_FB(buffer->flags, 1); } buf->previous_canflip = new_canflip; } else if (buf->previous_canflip == TRUE && new_canflip == FALSE && fb_id) { ret = armsoc_bo_rm_fb(bo); if (ret) { ERROR_MSG("Could not remove fb for a flippable to non-flippable window"); } else { DRI2_BUFFER_SET_FB(buffer->flags, 0); } buf->previous_canflip = new_canflip; } } } #endif /** * The DRI2 ScreenInit() function.. register our handler fxns w/ DRI2 core */ Bool ARMSOCDRI2ScreenInit(ScreenPtr pScreen) { ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); drmVBlank vbl = { .request = { .type = DRM_VBLANK_RELATIVE, .sequence = 0, } }; int ret; DRI2InfoRec info = { #if DRI2INFOREC_VERSION >= 6 .version = 6, #else .version = 5, #endif .fd = pARMSOC->drmFD, .driverName = "armsoc", .deviceName = pARMSOC->deviceName, .CreateBuffer = ARMSOCDRI2CreateBuffer, .DestroyBuffer = ARMSOCDRI2DestroyBuffer, .CopyRegion = ARMSOCDRI2CopyRegion, .ScheduleSwap = ARMSOCDRI2ScheduleSwap, .ScheduleWaitMSC = ARMSOCDRI2ScheduleWaitMSC, .GetMSC = ARMSOCDRI2GetMSC, .AuthMagic = drmAuthMagic, #if DRI2INFOREC_VERSION >= 6 .ReuseBufferNotify = ARMSOCDRI2ReuseBufferNotify, .SwapLimitValidate = ARMSOCDRI2SwapLimitValidate, #endif }; 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; } /* There is a one-to-one mapping with the DRI2SwapLimit * feature and the swap chain size. If DRI2SwapLimit is * not supported swap-chain will be of size 1. */ pARMSOC->swap_chain_size = 1; pARMSOC->swap_chain_count = 0; if (FALSE == pARMSOC->NoFlip && pARMSOC->drmmode_interface->use_page_flip_events) { #if DRI2INFOREC_VERSION < 6 if (pARMSOC->drmmode_interface->use_early_display || pARMSOC->driNumBufs > 2) ERROR_MSG("DRI2SwapLimit not supported, but buffers requested are > 2"); else WARNING_MSG("DRI2SwapLimit not supported."); #else /* Swap chain size or the swap limit must be set to one * less than the number of buffers available unless we * have early display enabled which uses one extra flip. */ if (pARMSOC->drmmode_interface->use_early_display) pARMSOC->swap_chain_size = pARMSOC->driNumBufs; else pARMSOC->swap_chain_size = pARMSOC->driNumBufs-1; #endif } pARMSOC->swap_chain = calloc(pARMSOC->swap_chain_size, sizeof(*pARMSOC->swap_chain)); INFO_MSG("Setting swap chain size: %d ", pARMSOC->swap_chain_size); ret = drmWaitVBlank(pARMSOC->drmFD, &vbl); if (ret) pARMSOC->drmmode_interface->vblank_query_supported = 0; else pARMSOC->drmmode_interface->vblank_query_supported = 1; return DRI2ScreenInit(pScreen, &info); } /** * The DRI2 CloseScreen() function.. unregister ourself w/ DRI2 core. */ void ARMSOCDRI2CloseScreen(ScreenPtr pScreen) { ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); while (pARMSOC->pending_flips > 0) { DEBUG_MSG("waiting.."); drmmode_wait_for_event(pScrn); } DRI2CloseScreen(pScreen); if (pARMSOC->swap_chain) { unsigned int idx = pARMSOC->swap_chain_count % pARMSOC->swap_chain_size; assert(!pARMSOC->swap_chain[idx]); free(pARMSOC->swap_chain); pARMSOC->swap_chain = NULL; } } xf86-video-armsoc-1.4.1/src/armsoc_driver.c000066400000000000000000001117051275754335000205100ustar00rootroot00000000000000/* -*- 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 */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #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 }; /** Supported "chipsets." */ #define ARMSOC_CHIPSET_NAME "Mali" /** Supported options, as enum values. */ enum { OPTION_DEBUG, OPTION_NO_FLIP, OPTION_CARD_NUM, OPTION_BUSID, OPTION_DRIVERNAME, OPTION_DRI_NUM_BUF, OPTION_INIT_FROM_FBDEV, OPTION_UMP_LOCK, }; /** 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 }, { OPTION_INIT_FROM_FBDEV, "InitFromFBDev", OPTV_STRING, {0}, FALSE }, { OPTION_UMP_LOCK, "UMP_LOCK", OPTV_BOOLEAN, {0}, 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; } 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); drmClose(pARMSOC->drmFD); connection.fd = -1; } pARMSOC->drmFD = -1; } } static Bool ARMSOCCopyFB(ScrnInfoPtr pScrn, const char *fb_dev) { struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); int src_cpp; uint32_t src_pitch; int src_pixman_stride; int dst_pixman_stride; int dst_width, dst_height, dst_bpp, dst_pitch; unsigned int src_size = 0; unsigned char *src = NULL, *dst = NULL; struct fb_var_screeninfo vinfo; int fd = -1; int width, height; pixman_bool_t pixman_ret; Bool ret = FALSE; dst = armsoc_bo_map(pARMSOC->scanout); if (!dst) { ERROR_MSG("Couldn't map scanout bo"); goto exit; } fd = open(fb_dev, O_RDONLY | O_SYNC); if (fd == -1) { ERROR_MSG("Couldn't open %s", fb_dev); goto exit; } if (ioctl(fd, FBIOGET_VSCREENINFO, &vinfo) < 0) { ERROR_MSG("Vscreeninfo ioctl failed"); goto exit; } src_cpp = (vinfo.bits_per_pixel + 7) / 8; src_pitch = vinfo.xres_virtual * src_cpp; src_size = vinfo.yres_virtual * src_pitch; src = mmap(NULL, src_size, PROT_READ, MAP_SHARED, fd, 0); if (src == MAP_FAILED) { ERROR_MSG("Couldn't mmap %s", fb_dev); goto exit; } dst_width = armsoc_bo_width(pARMSOC->scanout); dst_height = armsoc_bo_height(pARMSOC->scanout); dst_bpp = armsoc_bo_bpp(pARMSOC->scanout); dst_pitch = armsoc_bo_pitch(pARMSOC->scanout); width = min(vinfo.xres, dst_width); height = min(vinfo.yres, dst_height); /* The stride parameters pixman takes are in multiples of uint32_t, * which is the data type of the pointer passed */ src_pixman_stride = src_pitch/sizeof(uint32_t); dst_pixman_stride = dst_pitch/sizeof(uint32_t); /* We could handle the cases where stride is not a multiple of uint32_t, * but they will be rare so not currently worth the added complexity */ if (src_pitch%sizeof(uint32_t) || dst_pitch%sizeof(uint32_t)) { ERROR_MSG( "Buffer strides need to be a multiple of 4 bytes to initialize from fbdev device"); goto exit; } /* similarly using pixman_blt doesn't allow for format conversion, so * check if they don't match and print a message */ if (vinfo.bits_per_pixel != dst_bpp || vinfo.grayscale != 0 || vinfo.nonstd != 0 || vinfo.red.offset != pScrn->offset.red || vinfo.red.length != pScrn->weight.red || vinfo.red.msb_right != 0 || vinfo.green.offset != pScrn->offset.green || vinfo.green.length != pScrn->weight.green || vinfo.green.msb_right != 0 || vinfo.blue.offset != pScrn->offset.blue || vinfo.blue.length != pScrn->weight.blue || vinfo.blue.msb_right != 0) { ERROR_MSG("Format of %s does not match scanout buffer", fb_dev); goto exit; } armsoc_bo_cpu_prep(pARMSOC->scanout, ARMSOC_GEM_WRITE); /* NB: We have to call pixman direct instead of wrapping the buffers as * Pixmaps as this function is called from ScreenInit. Pixmaps cannot be * created until X calls CreateScratchPixmapsForScreen(), and the screen * pixmap is not initialized until X calls CreateScreenResources */ pixman_ret = pixman_blt((uint32_t *)src, (uint32_t *)dst, src_pixman_stride, dst_pixman_stride, vinfo.bits_per_pixel, dst_bpp, vinfo.xoffset, vinfo.yoffset, 0, 0, width, height); if (!pixman_ret) { armsoc_bo_cpu_fini(pARMSOC->scanout, 0); ERROR_MSG("Pixman failed to blit from %s to scanout buffer", fb_dev); goto exit; } /* fill any area not covered by the blit */ if (width < dst_width) { pixman_ret = pixman_fill((uint32_t *)dst, dst_pixman_stride, dst_bpp, width, 0, dst_width-width, dst_height, 0); if (!pixman_ret) { armsoc_bo_cpu_fini(pARMSOC->scanout, 0); ERROR_MSG( "Pixman failed to fill margin of scanout buffer"); goto exit; } } if (height < dst_height) { pixman_ret = pixman_fill((uint32_t *)dst, dst_pixman_stride, dst_bpp, 0, height, width, dst_height-height, 0); if (!pixman_ret) { armsoc_bo_cpu_fini(pARMSOC->scanout, 0); ERROR_MSG( "Pixman failed to fill margin of scanout buffer"); goto exit; } } armsoc_bo_cpu_fini(pARMSOC->scanout, 0); ret = TRUE; exit: if (src) munmap(src, src_size); if (fd >= 0) close(fd); return ret; } /** 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. */ static void ARMSOCIdentify(int flags) { xf86Msg(X_INFO, "%s: Driver for ARM Mali compatible chipsets\n", ARMSOC_NAME); } /** * 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 { goto out; } } 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"); drmClose(fd); goto free_sections; } /* Allocate the driver's Screen-specific, "private" * data structure and hook it into the ScrnInfoRec's * driverPrivate field. */ pScrn->driverPrivate = calloc(1, sizeof(*pARMSOC)); 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_sections: free(devSections); out: return foundScreen; } /** * Find a drmmode driver with the same name as the underlying * drm kernel driver */ static struct drmmode_interface *get_drmmode_implementation(int drm_fd) { drmVersionPtr version; struct drmmode_interface *ret = NULL; struct drmmode_interface *ifaces[] = { &exynos_interface, &pl111_interface, &kirin_interface, &sti_interface, }; int i; version = drmGetVersion(drm_fd); if (!version) return NULL; for (i = 0; i < ARRAY_SIZE(ifaces); i++) { struct drmmode_interface *iface = ifaces[i]; if (strcmp(version->name, iface->driver_name) == 0) { ret = iface; break; } } drmFreeVersion(version); return ret; } /** * 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 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 color depth & bpp, 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 = get_drmmode_implementation(pARMSOC->drmFD); if (!pARMSOC->drmmode_interface) goto fail2; /* create DRM device instance: */ pARMSOC->dev = armsoc_device_new(pARMSOC->drmFD, pARMSOC->drmmode_interface->create_custom_gem); /* set chipset name: */ pScrn->chipset = (char *)ARMSOC_CHIPSET_NAME; INFO_MSG("Chipset: %s", pScrn->chipset); /* * Process the "xorg.conf" file options: */ xf86CollectOptions(pScrn, NULL); pARMSOC->pOptionInfo = malloc(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"); pARMSOC->useUmplock = xf86ReturnOptValBool(pARMSOC->pOptionInfo, OPTION_UMP_LOCK, FALSE); INFO_MSG("umplock is %s", pARMSOC->useUmplock ? "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 bitsPerPixel: */ 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 = xf86ScreenToScrn(pScreen); 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 = xf86ScreenToScrn(pScreen); #ifndef XF86_SCRN_INTERFACE int scrnIndex = pScrn->scrnIndex; #endif struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); VisualPtr visual; xf86CrtcConfigPtr xf86_config; int j; const char *fbdev; int depth; TRACE_ENTER(); /* set drm master before allocating scanout buffer */ if (ARMSOCSetDRMMaster()) { ERROR_MSG("Cannot get DRM master: %s", strerror(errno)); goto fail; } /* We create a single visual with the depth set to the * screen's bpp as otherwise XComposite will add an alternate * visual and ARGB8888 windows will be implicitly redirected. * The initial scanout buffer is created with the same depth * to match the visual. */ depth = pScrn->bitsPerPixel; /* Allocate initial scanout buffer.*/ DEBUG_MSG("allocating new scanout buffer: %dx%d %d %d", pScrn->virtualX, pScrn->virtualY, depth, pScrn->bitsPerPixel); assert(!pARMSOC->scanout); /* Screen creates and takes a ref on the scanout bo */ pARMSOC->scanout = armsoc_bo_new_with_dim(pARMSOC->dev, pScrn->virtualX, pScrn->virtualY, 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(depth, miGetDefaultVisualMask(depth), pScrn->rgbBits, pScrn->defaultVisual)) { ERROR_MSG( "Cannot initialize the visual type for %d depth, %d bits per pixel!", depth, pScrn->bitsPerPixel); goto fail2; } 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); fbdev = xf86GetOptValString(pARMSOC->pOptionInfo, OPTION_INIT_FROM_FBDEV); if (fbdev && *fbdev != '\0') { if (ARMSOCCopyFB(pScrn, fbdev)) { /* Only allow None BG root if we initialized the scanout * buffer */ pScreen->canDoBGNoneRoot = TRUE; } } /* 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); if (pARMSOC->useUmplock) { pARMSOC->lockFD = open("/dev/umplock", O_RDWR); if (-1 == pARMSOC->lockFD) ERROR_MSG("Failed to open umplock device!"); } else { pARMSOC->lockFD = -1; } 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: /* Screen drops its ref on scanout bo on failure exit */ 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); Bool ret; TRACE_ENTER(); drmmode_screen_fini(pScrn); drmmode_cursor_fini(pScreen); /* pScreen->devPrivate holds the root pixmap created around our bo by miCreateResources which is installed * by fbScreenInit() when called from ARMSOCScreenInit(). * This pixmap should be destroyed in miScreenClose() but this isn't wrapped by fbScreenInit() so to prevent a leak * we do it here, before calling the CloseScreen chain which would just free pScreen->devPrivate in fbCloseScreen() */ if (pScreen->devPrivate) { (void) (*pScreen->DestroyPixmap)(pScreen->devPrivate); pScreen->devPrivate = NULL; } unwrap(pARMSOC, pScreen, CloseScreen); unwrap(pARMSOC, pScreen, BlockHandler); unwrap(pARMSOC, pScreen, CreateScreenResources); ret = (*pScreen->CloseScreen)(CLOSE_SCREEN_ARGS); if (pARMSOC->dri) ARMSOCDRI2CloseScreen(pScreen); if (pARMSOC->pARMSOCEXA) if (pARMSOC->pARMSOCEXA->CloseScreen) pARMSOC->pARMSOCEXA->CloseScreen(CLOSE_SCREEN_ARGS); assert(pARMSOC->scanout); /* Screen drops its ref on 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; if (-1 != pARMSOC->lockFD) { close(pARMSOC->lockFD); pARMSOC->lockFD = -1; } TRACE_EXIT(); return ret; } /** * 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 = xf86ScreenToScrn(pScreen); 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] && !clients[i]->clientGone) 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] && !clients[i]->clientGone) 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-1.4.1/src/armsoc_driver.h000066400000000000000000000174561275754335000205250ustar00rootroot00000000000000/* -*- 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) #define DRI2_BUFFER_FB_MASK 0x02 /* FB: 1, non-FB: 0 */ #define DRI2_BUFFER_MAPPED_MASK 0x04 /* mapped: 1, not-mapped: 0 */ #define DRI2_BUFFER_REUSED_MASK 0x08 /* re-used: 1, re-created: 0 */ #define DRI2_BUFFER_AGE_MASK 0x70 /* buffer age */ #define DRI2_BUFFER_FLAG_MASK 0x7f /* dri2 buffer flag mask */ #define DRI2_BUFFER_GET_FB(flag) ((flag) & DRI2_BUFFER_FB_MASK) ? 1 : 0 #define DRI2_BUFFER_SET_FB(flag, fb) (flag) |= (((fb) << 1) & DRI2_BUFFER_FB_MASK); #define DRI2_BUFFER_GET_MAPPED(flag) ((flag) & DRI2_BUFFER_MAPPED_MASK) ? 1 : 0 #define DRI2_BUFFER_SET_MAPPED(flag, mapped) (flag) |= (((mapped) << 2) & DRI2_BUFFER_MAPPED_MASK); #define DRI2_BUFFER_GET_REUSED(flag) ((flag) & DRI2_BUFFER_REUSED_MASK) ? 1 : 0 #define DRI2_BUFFER_SET_REUSED(flag, reused) (flag) |= (((reused) << 3) & DRI2_BUFFER_REUSED_MASK); #define DRI2_BUFFER_GET_AGE(flag) ((flag) & DRI2_BUFFER_AGE_MASK) >> 4 #define DRI2_BUFFER_SET_AGE(flag, age) (flag) |= (((age) << 4) & DRI2_BUFFER_AGE_MASK); /** 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; Bool useUmplock; /* File descriptor of the umplock*/ int lockFD; /* The Swap Chain stores the pending swap operations */ struct ARMSOCDRISwapCmd **swap_chain; /* Count of swaps scheduled since startup. * Used as swap_id of the next swap cmd */ unsigned int swap_chain_count; /* Size of the swap chain. Set to 1 if DRI2SwapLimit unsupported, * driNumBufs if early display enabled, otherwise driNumBufs-1 */ unsigned int swap_chain_size; }; /* * 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 *)(xf86ScreenToScrn(pScreen))->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(struct ARMSOCRec *pARMSOC); void drmmode_fini_wakeup_handler(struct ARMSOCRec *pARMSOC); /** * DRI2 functions.. */ struct ARMSOCDRISwapCmd; Bool ARMSOCDRI2ScreenInit(ScreenPtr pScreen); void ARMSOCDRI2CloseScreen(ScreenPtr pScreen); void ARMSOCDRI2SwapComplete(struct ARMSOCDRISwapCmd *cmd); void ARMSOCDRI2ResizeSwapChain(ScrnInfoPtr pScrn, struct armsoc_bo *old_bo, struct armsoc_bo *resized_bo); void ARMSOCDRI2VBlankHandler(unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec, void *user_data); /** * DRI2 util functions.. */ void set_scanout_bo(ScrnInfoPtr pScrn, struct armsoc_bo *bo); #endif /* __ARMSOC_DRV_H__ */ xf86-video-armsoc-1.4.1/src/armsoc_dumb.c000066400000000000000000000243021275754335000201400ustar00rootroot00000000000000/* * 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. * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #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; int (*create_custom_gem)(int fd, struct armsoc_create_gem *create_gem); Bool alpha_supported; }; 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, int (*create_custom_gem)(int fd, struct armsoc_create_gem *create_gem)) { struct armsoc_device *new_dev = calloc(1, sizeof(*new_dev)); if (!new_dev) return NULL; new_dev->fd = fd; new_dev->create_custom_gem = create_custom_gem; new_dev->alpha_supported = TRUE; 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 armsoc_create_gem create_gem; struct armsoc_bo *new_buf; int res; new_buf = malloc(sizeof(*new_buf)); if (!new_buf) return NULL; create_gem.buf_type = buf_type; create_gem.height = height; create_gem.width = width; create_gem.bpp = bpp; res = dev->create_custom_gem(dev->fd, &create_gem); if (res) { free(new_buf); xf86DrvMsg(-1, X_ERROR, "_CREATE_GEM({height: %d, width: %d, bpp: %d buf_type: 0x%X}) failed. errno: %d - %s\n", height, width, bpp, buf_type, errno, strerror(errno)); return NULL; } new_buf->dev = dev; new_buf->handle = create_gem.handle; new_buf->size = create_gem.size; new_buf->map_addr = NULL; new_buf->fb_id = 0; new_buf->pitch = create_gem.pitch; new_buf->width = create_gem.width; new_buf->height = create_gem.height; new_buf->original_size = create_gem.size; new_buf->depth = depth; new_buf->bpp = create_gem.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; } uint8_t armsoc_bo_depth(struct armsoc_bo *bo) { assert(bo->refcnt > 0); return bo->depth; } 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, depth = bo->depth; assert(bo->refcnt > 0); assert(bo->fb_id == 0); if (bo->bpp == 32 && bo->depth == 32 && !bo->dev->alpha_supported) depth = 24; ret = drmModeAddFB(bo->dev->fd, bo->width, bo->height, depth, bo->bpp, bo->pitch, bo->handle, &bo->fb_id); if (ret < 0 && bo->bpp == 32 && bo->depth == 32 && bo->dev->alpha_supported) { /* The DRM driver may not support an alpha channel but * it is possible to continue by ignoring the alpha, so * if an attempt to create a depth 32, bpp 32 framebuffer * fails we retry with depth 24, bpp 32 */ xf86DrvMsg(-1, X_WARNING, "depth 32 FB unsupported : falling back to depth 24\n"); bo->dev->alpha_supported = FALSE; ret = drmModeAddFB(bo->dev->fd, bo->width, bo->height, 24, 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-1.4.1/src/armsoc_dumb.h000066400000000000000000000065501275754335000201520ustar00rootroot00000000000000/* * 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 }; /* * Generic GEM object information used to abstract custom GEM creation * for every DRM driver. */ struct armsoc_create_gem { /* parameters that will be provided */ uint32_t height; uint32_t width; uint32_t bpp; enum armsoc_buf_type buf_type; /* handle, pitch, size will be returned */ uint32_t handle; uint32_t pitch; uint64_t size; }; struct armsoc_device *armsoc_device_new(int fd, int (*create_custom_gem)(int fd, struct armsoc_create_gem *create_gem)); 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); uint8_t armsoc_bo_depth(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-1.4.1/src/armsoc_exa.c000066400000000000000000000356301275754335000177740ustar00rootroot00000000000000 /* * 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" #include "umplock/umplock_ioctl.h" #include #include /* 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(1, sizeof(*priv)); ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 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) { /* Pixmap creates and takes a ref on its bo */ 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; /* Pixmap creates and takes a ref on its bo */ 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)); /* pixmap drops ref on its 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! * Pixmap drops ref on its old bo */ armsoc_bo_unreference(priv->bo); priv->bo = NULL; /* Returning FALSE calls miModifyPixmapHeader */ return FALSE; } /* Replacing the pixmap's current bo with the scanout bo */ if (pPixData == armsoc_bo_map(pARMSOC->scanout) && priv->bo != pARMSOC->scanout) { struct armsoc_bo *old_bo = priv->bo; priv->bo = pARMSOC->scanout; /* pixmap takes a ref on its new bo */ armsoc_bo_reference(priv->bo); if (old_bo) { /* We are detaching the old_bo so clear it now. */ if (armsoc_bo_has_dmabuf(old_bo)) armsoc_bo_clear_dmabuf(old_bo); /* pixmap drops ref on previous bo */ armsoc_bo_unreference(old_bo); } } 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; assert(priv->bo); if (armsoc_bo_width(priv->bo) != pPixmap->drawable.width || armsoc_bo_height(priv->bo) != pPixmap->drawable.height || armsoc_bo_bpp(priv->bo) != pPixmap->drawable.bitsPerPixel) { /* pixmap drops ref on its old bo */ armsoc_bo_unreference(priv->bo); /* pixmap creates new bo and takes ref on it */ 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; /* pixmap creates new bo and takes ref on it */ 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) { ScreenPtr pScreen = pPixmap->drawable.pScreen; ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); uint32_t dmabuf_name = 0; _lock_item_s item; int ret; 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 (-1 != pARMSOC->lockFD) { ret = armsoc_bo_get_name(priv->bo, &dmabuf_name); if (ret) { ERROR_MSG("could not get buffer name"); return FALSE; } item.secure_id = dmabuf_name; item.usage = _LOCK_ACCESS_CPU_WRITE; if (ioctl(pARMSOC->lockFD, LOCK_IOCTL_CREATE, &item) < 0) { ERROR_MSG("Unable to create lock item\n"); return FALSE; } if (ioctl(pARMSOC->lockFD, LOCK_IOCTL_PROCESS, &item) < 0) { int max_retries = 5; ERROR_MSG("Unable to process lock item with ID 0x%x - throttling\n", item.secure_id); while ((ioctl(pARMSOC->lockFD, LOCK_IOCTL_PROCESS, &item) < 0) && max_retries) { usleep(2000); max_retries--; } if (max_retries == 0) ERROR_MSG("Warning: Max retries == 0\n"); } } else { 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) { ScreenPtr pScreen = pPixmap->drawable.pScreen; ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; struct ARMSOCPixmapPrivRec *priv = exaGetPixmapDriverPrivate(pPixmap); struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); if (-1 != pARMSOC->lockFD){ uint32_t dmabuf_name = 0; _lock_item_s item; int ret; pPixmap->devPrivate.ptr = NULL; ret = armsoc_bo_get_name(priv->bo, &dmabuf_name); if (ret) { ERROR_MSG("could not get buffer name"); return ; } item.secure_id = dmabuf_name; item.usage = _LOCK_ACCESS_CPU_WRITE; ioctl(pARMSOC->lockFD, LOCK_IOCTL_RELEASE, &item); }else{ /* 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.. */ pPixmap->devPrivate.ptr = NULL; 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-1.4.1/src/armsoc_exa.h000066400000000000000000000106211275754335000177720ustar00rootroot00000000000000/* -*- 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) { ScreenPtr pScreen = (pPixmap)->drawable.pScreen; return xf86ScreenToScrn(pScreen); } 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-1.4.1/src/armsoc_exa_null.c000066400000000000000000000107141275754335000210220ustar00rootroot00000000000000/* -*- 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; struct ARMSOCEXARec *armsoc_exa; ExaDriverPtr exa; INFO_MSG("Soft EXA mode"); null_exa = calloc(1, sizeof(*null_exa)); if (!null_exa) goto out; armsoc_exa = (struct ARMSOCEXARec *)null_exa; exa = exaDriverAlloc(); if (!exa) goto free_null_exa; 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 free_exa; } armsoc_exa->CloseScreen = CloseScreen; armsoc_exa->FreeScreen = FreeScreen; return armsoc_exa; free_exa: free(exa); free_null_exa: free(null_exa); out: return NULL; } xf86-video-armsoc-1.4.1/src/compat-api.h000066400000000000000000000076021275754335000177100ustar00rootroot00000000000000/* * 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 #if ABI_VIDEODRV_VERSION >= SET_ABI_VERSION(22,0) #define HAVE_NOTIFY_FD 1 #endif #if ABI_VIDEODRV_VERSION >= SET_ABI_VERSION(23, 0) #define RELOAD_CURSORS_DEPRECATED 1 #define BLOCKHANDLER_ARGS_DECL \ ScreenPtr arg, pointer pTimeout #define BLOCKHANDLER_ARGS arg, pTimeout #else #define BLOCKHANDLER_ARGS_DECL \ ScreenPtr arg, pointer pTimeout, pointer pReadmask #define BLOCKHANDLER_ARGS arg, pTimeout, pReadmask #endif #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-1.4.1/src/drmmode_display.c000066400000000000000000001463201275754335000210260ustar00rootroot00000000000000/* * 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 #include #include #include "xf86DDC.h" #include "xf86RandR12.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: */ struct armsoc_bo *bo; int x, y; /* These are used for HWCURSOR_API_PLANE */ drmModePlane *ovr; uint32_t fb_id; /* This is used for HWCURSOR_API_STANDARD */ uint32_t handle; }; 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; uint32_t crtc_id; int cursor_visible; /* settings retained on last good modeset */ int last_good_x; int last_good_y; Rotation last_good_rotation; DisplayModePtr last_good_mode; }; 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 connector; drmModeEncoderPtr *encoders; drmModePropertyBlobPtr edid_blob; int num_props; struct drmmode_prop_rec *props; int enc_mask; /* encoders present (mask of encoder indices) */ int enc_clones; /* encoder clones possible (mask of encoder indices) */ }; static void drmmode_output_dpms(xf86OutputPtr output, int mode); static Bool resize_scanout_bo(ScrnInfoPtr pScrn, int width, int height); static Bool drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, Rotation rotation, int x, int y); 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 crtc, int mode) { struct drmmode_crtc_private_rec *drmmode_crtc = crtc->driver_private; struct drmmode_rec *drmmode = drmmode_crtc->drmmode; ScrnInfoPtr pScrn = crtc->scrn; DEBUG_MSG("Setting dpms mode %d on crtc %d", mode, drmmode_crtc->crtc_id); switch (mode) { case DPMSModeOn: drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, crtc->x, crtc->y); break; /* unimplemented modes fall through to the next lowest mode */ case DPMSModeStandby: case DPMSModeSuspend: case DPMSModeOff: if (drmModeSetCrtc(drmmode->fd, drmmode_crtc->crtc_id, 0, 0, 0, 0, 0, NULL)) { ERROR_MSG("drm failed to disable crtc %d", drmmode_crtc->crtc_id); } else { int i; xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); /* set dpms off for all outputs for this crtc */ for (i = 0; i < xf86_config->num_output; i++) { xf86OutputPtr output = xf86_config->output[i]; if (output->crtc != crtc) continue; drmmode_output_dpms(output, mode); } } break; default: ERROR_MSG("bad dpms mode %d for crtc %d", mode, drmmode_crtc->crtc_id); return; } } static int drmmode_revert_mode(xf86CrtcPtr crtc, uint32_t *output_ids, int output_count) { ScrnInfoPtr pScrn = crtc->scrn; struct drmmode_crtc_private_rec *drmmode_crtc = crtc->driver_private; uint32_t fb_id; struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); drmModeModeInfo kmode; if (!drmmode_crtc->last_good_mode) { DEBUG_MSG("No last good values to use"); return FALSE; } /* revert to last good settings */ DEBUG_MSG("Reverting to last_good values"); if (!resize_scanout_bo(pScrn, drmmode_crtc->last_good_mode->HDisplay, drmmode_crtc->last_good_mode->VDisplay)) { ERROR_MSG("Could not revert to last good mode"); return FALSE; } fb_id = armsoc_bo_get_fb(pARMSOC->scanout); drmmode_ConvertToKMode(crtc->scrn, &kmode, drmmode_crtc->last_good_mode); drmModeSetCrtc(drmmode_crtc->drmmode->fd, drmmode_crtc->crtc_id, fb_id, drmmode_crtc->last_good_x, drmmode_crtc->last_good_y, output_ids, output_count, &kmode); /* let RandR know we changed things */ xf86RandR12TellChanged(pScrn->pScreen); return TRUE; } 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; uint32_t *output_ids = NULL; int output_count = 0; int ret = TRUE; int err; int i; uint32_t fb_id; drmModeModeInfo kmode; drmModeCrtcPtr newcrtc = NULL; TRACE_ENTER(); fb_id = armsoc_bo_get_fb(pARMSOC->scanout); if (fb_id == 0) { DEBUG_MSG("create framebuffer: %dx%d", pScrn->virtualX, pScrn->virtualY); err = armsoc_bo_add_fb(pARMSOC->scanout); if (err) { 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; } /* Set the new mode: */ crtc->mode = *mode; crtc->x = x; crtc->y = y; crtc->rotation = rotation; output_ids = calloc(xf86_config->num_output, sizeof *output_ids); if (!output_ids) { ERROR_MSG( "memory allocation failed in drmmode_set_mode_major()"); ret = FALSE; goto cleanup; } 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->connector->connector_id; output_count++; } if (!xf86CrtcRotate(crtc)) { ERROR_MSG( "failed to assign rotation in drmmode_set_mode_major()"); ret = FALSE; goto cleanup; } 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); err = drmModeSetCrtc(drmmode->fd, drmmode_crtc->crtc_id, fb_id, x, y, output_ids, output_count, &kmode); if (err) { ERROR_MSG( "drm failed to set mode: %s", strerror(-err)); ret = FALSE; if (!drmmode_revert_mode(crtc, output_ids, output_count)) goto cleanup; else goto done_setting; } /* get the actual crtc info */ newcrtc = drmModeGetCrtc(drmmode->fd, drmmode_crtc->crtc_id); if (!newcrtc) { ERROR_MSG("couldn't get actual mode back"); ret = FALSE; if (!drmmode_revert_mode(crtc, output_ids, output_count)) goto cleanup; else goto done_setting; } if (kmode.hdisplay != newcrtc->mode.hdisplay || kmode.vdisplay != newcrtc->mode.vdisplay) { ERROR_MSG( "drm did not set requested mode! (requested %dx%d, actual %dx%d)", kmode.hdisplay, kmode.vdisplay, newcrtc->mode.hdisplay, newcrtc->mode.vdisplay); ret = FALSE; if (!drmmode_revert_mode(crtc, output_ids, output_count)) goto cleanup; else goto done_setting; } /* When called on a resize, crtc->mode already contains the * resized values so we can't use this for recovery. * We can't read it out of the crtc either as mode_valid is 0. * Instead we save the last good mode set here & fallback to * that on failure. */ DEBUG_MSG("Saving last good values"); drmmode_crtc->last_good_x = crtc->x; drmmode_crtc->last_good_y = crtc->y; drmmode_crtc->last_good_rotation = crtc->rotation; if (drmmode_crtc->last_good_mode) { if (drmmode_crtc->last_good_mode->name) free((void *)drmmode_crtc->last_good_mode->name); free(drmmode_crtc->last_good_mode); } drmmode_crtc->last_good_mode = xf86DuplicateMode(&crtc->mode); ret = TRUE; done_setting: /* 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 !RELOAD_CURSORS_DEPRECATED /* if hw cursor is initialized, reload it */ if (drmmode->cursor) xf86_reload_cursors(pScrn->pScreen); #endif cleanup: if (newcrtc) drmModeFreeCrtc(newcrtc); if (output_ids) free(output_ids); if (!ret && drmmode_crtc->last_good_mode) { /* If there was a problem, restore the last good mode: */ crtc->x = drmmode_crtc->last_good_x; crtc->y = drmmode_crtc->last_good_y; crtc->rotation = drmmode_crtc->last_good_rotation; crtc->mode = *drmmode_crtc->last_good_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; ScrnInfoPtr pScrn = crtc->scrn; struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); if (!cursor) return; drmmode_crtc->cursor_visible = FALSE; if (pARMSOC->drmmode_interface->cursor_api == HWCURSOR_API_PLANE) { /* set plane's fb_id to 0 to disable it */ drmModeSetPlane(drmmode->fd, cursor->ovr->plane_id, drmmode_crtc->crtc_id, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); } else { /* HWCURSOR_API_STANDARD */ /* set handle to 0 to disable the cursor */ drmModeSetCursor(drmmode->fd, drmmode_crtc->crtc_id, 0, 0, 0); } } /* * The argument "update_image" controls whether the cursor image needs * to be updated by the HW or not. This is ignored by HWCURSOR_API_PLANE * which doesn't allow changing the cursor position without updating * the image too. */ static void drmmode_show_cursor_image(xf86CrtcPtr crtc, Bool update_image) { 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; if (pARMSOC->drmmode_interface->cursor_api == HWCURSOR_API_PLANE) { 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->crtc_id, cursor->fb_id, 0, crtc_x, crtc_y, w, h, src_x<<16, src_y<<16, w<<16, h<<16); } else { if (update_image) drmModeSetCursor(drmmode->fd, drmmode_crtc->crtc_id, cursor->handle, w, h); drmModeMoveCursor(drmmode->fd, drmmode_crtc->crtc_id, crtc_x, crtc_y); } } static void drmmode_show_cursor(xf86CrtcPtr crtc) { drmmode_show_cursor_image(crtc, TRUE); } 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; /* * Show the cursor at a different position without updating the image * when possible (HWCURSOR_API_PLANE doesn't have a way to update * cursor position without updating the image too). */ drmmode_show_cursor_image(crtc, FALSE); } /* * 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 in some DRM * drivers. */ static void set_cursor_image(xf86CrtcPtr crtc, uint32_t *d, CARD32 *s) { ScrnInfoPtr pScrn = crtc->scrn; struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); int row; void *dst; const char *src_row; char *dst_row; uint32_t cursorh = pARMSOC->drmmode_interface->cursor_height; uint32_t cursorw = pARMSOC->drmmode_interface->cursor_width; uint32_t cursorpad = pARMSOC->drmmode_interface->cursor_padding; 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)); } } 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; 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_image(crtc, TRUE); return; } set_cursor_image(crtc, d, image); if (visible) drmmode_show_cursor_image(crtc, TRUE); } static Bool drmmode_cursor_init_plane(ScreenPtr pScreen) { ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 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; } static Bool drmmode_cursor_init_standard(ScreenPtr pScreen) { ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); struct drmmode_rec *drmmode = drmmode_from_scrn(pScrn); struct drmmode_cursor_rec *cursor; int w, h, pad; if (drmmode->cursor) { INFO_MSG("cursor already initialized"); return TRUE; } if (!xf86LoaderCheckSymbol("drmModeSetCursor") || !xf86LoaderCheckSymbol("drmModeMoveCursor")) { ERROR_MSG( "Standard HW cursor not supported (needs libdrm 2.4.3 or higher)"); return FALSE; } cursor = calloc(1, sizeof(struct drmmode_cursor_rec)); if (!cursor) { ERROR_MSG("HW cursor (standard): calloc failed"); return FALSE; } 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 (standard): buffer allocation failed"); free(cursor); return FALSE; } cursor->handle = armsoc_bo_handle(cursor->bo); 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); return FALSE; } INFO_MSG("HW cursor initialized"); drmmode->cursor = cursor; return TRUE; } Bool drmmode_cursor_init(ScreenPtr pScreen) { ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); INFO_MSG("HW cursor init()"); switch (pARMSOC->drmmode_interface->cursor_api) { case HWCURSOR_API_PLANE: return drmmode_cursor_init_plane(pScreen); case HWCURSOR_API_STANDARD: return drmmode_cursor_init_standard(pScreen); case HWCURSOR_API_NONE: return FALSE; default: assert(0); } } void drmmode_cursor_fini(ScreenPtr pScreen) { ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); struct drmmode_rec *drmmode = drmmode_from_scrn(pScrn); struct drmmode_cursor_rec *cursor = drmmode->cursor; struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); if (!cursor) return; drmmode->cursor = NULL; xf86_cursors_fini(pScreen); if (pARMSOC->drmmode_interface->cursor_api == HWCURSOR_API_PLANE) drmModeRmFB(drmmode->fd, cursor->fb_id); armsoc_bo_unreference(cursor->bo); if (pARMSOC->drmmode_interface->cursor_api == HWCURSOR_API_PLANE) 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->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(1, sizeof *drmmode_crtc); drmmode_crtc->crtc_id = drmmode->mode_res->crtcs[num]; drmmode_crtc->drmmode = drmmode; drmmode_crtc->last_good_mode = NULL; INFO_MSG("Got CRTC: %d (id: %d)", num, drmmode_crtc->crtc_id); 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->connector); drmmode_output->connector = drmModeGetConnector(drmmode->fd, drmmode_output->output_id); switch (drmmode_output->connector->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 connector = drmmode_output->connector; 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 < connector->count_props; i++) { prop = drmModeGetProperty(drmmode->fd, connector->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, connector->prop_values[i]); } drmModeFreeProperty(prop); } if (drmmode_output->edid_blob) ddc_mon = xf86InterpretEDID(pScrn->scrnIndex, drmmode_output->edid_blob->data); if (ddc_mon) { if (drmmode_output->edid_blob->length > 128) ddc_mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA; xf86OutputSetEDID(output, ddc_mon); xf86SetDDCproperties(pScrn, ddc_mon); } DEBUG_MSG("count_modes: %d", connector->count_modes); /* modes should already be available */ for (i = 0; i < connector->count_modes; i++) { DisplayModePtr mode = xnfalloc(sizeof(DisplayModeRec)); drmmode_ConvertFromKMode(pScrn, &connector->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); for (i = 0; i < drmmode_output->connector->count_encoders; i++) drmModeFreeEncoder(drmmode_output->encoders[i]); free(drmmode_output->encoders); drmModeFreeConnector(drmmode_output->connector); 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 connector = drmmode_output->connector; drmModePropertyPtr prop; struct drmmode_rec *drmmode = drmmode_output->drmmode; int mode_id = -1, i; for (i = 0; i < connector->count_props; i++) { prop = drmModeGetProperty(drmmode->fd, connector->props[i]); if (!prop) continue; if ((prop->flags & DRM_MODE_PROP_ENUM) && !strcmp(prop->name, "DPMS")) { mode_id = connector->props[i]; drmModeFreeProperty(prop); break; } drmModeFreeProperty(prop); } if (mode_id < 0) return; drmModeConnectorSetProperty(drmmode->fd, connector->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 connector = drmmode_output->connector; struct drmmode_rec *drmmode = drmmode_output->drmmode; drmModePropertyPtr drmmode_prop; uint32_t value; int i, j, err; drmmode_output->props = calloc(connector->count_props, sizeof(*drmmode_output->props)); if (!drmmode_output->props) return; drmmode_output->num_props = 0; for (i = 0; i < connector->count_props; i++) { drmmode_prop = drmModeGetProperty(drmmode->fd, connector->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->connector->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 *p->atoms); 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 *p->atoms); 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); if (name == NULL) return FALSE; /* 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->connector); drmmode_output->connector = 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->connector->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 connector; drmModeEncoderPtr *encoders = NULL; struct drmmode_output_priv *drmmode_output; char name[32]; int i; TRACE_ENTER(); connector = drmModeGetConnector(drmmode->fd, drmmode->mode_res->connectors[num]); if (!connector) goto exit; encoders = calloc(sizeof(drmModeEncoderPtr), connector->count_encoders); if (!encoders) goto free_connector_exit; for (i = 0; i < connector->count_encoders; i++) { encoders[i] = drmModeGetEncoder(drmmode->fd, connector->encoders[i]); if (!encoders[i]) goto free_encoders_exit; } if (connector->connector_type >= NUM_OUTPUT_NAMES) snprintf(name, 32, "Unknown%d-%d", connector->connector_type, connector->connector_type_id); else snprintf(name, 32, "%s-%d", output_names[connector->connector_type], connector->connector_type_id); output = xf86OutputCreate(pScrn, &drmmode_output_funcs, name); if (!output) goto free_encoders_exit; drmmode_output = calloc(1, sizeof *drmmode_output); if (!drmmode_output) { xf86OutputDestroy(output); goto free_encoders_exit; } drmmode_output->output_id = drmmode->mode_res->connectors[num]; drmmode_output->connector = connector; drmmode_output->encoders = encoders; drmmode_output->drmmode = drmmode; output->mm_width = connector->mmWidth; output->mm_height = connector->mmHeight; output->driver_private = drmmode_output; /* * Determine which crtcs are supported by all the encoders which * are valid for the connector of this output. */ output->possible_crtcs = 0xffffffff; for (i = 0; i < connector->count_encoders; i++) output->possible_crtcs &= encoders[i]->possible_crtcs; /* * output->possible_crtcs is a bitmask arranged by index of crtcs for this screen while * encoders->possible_crtcs covers all crtcs supported by the drm. If we have selected * one crtc per screen, it must be at index 0. */ if (ARMSOCPTR(pScrn)->crtcNum >= 0) output->possible_crtcs = (output->possible_crtcs >> (ARMSOCPTR(pScrn)->crtcNum)) & 1; output->possible_clones = 0; /* set after all outputs initialized */ output->interlaceAllowed = TRUE; goto exit; free_encoders_exit: for (i = 0; i < connector->count_encoders; i++) drmModeFreeEncoder(encoders[i]); free_connector_exit: drmModeFreeConnector(connector); exit: TRACE_EXIT(); return; } static void drmmode_clones_init(ScrnInfoPtr pScrn, struct drmmode_rec *drmmode) { int i; xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); /* For each output generate enc_mask, a mask of encoders present, * and enc_clones, a mask of possible clone encoders */ for (i = 0; i < xf86_config->num_output; i++) { xf86OutputPtr output = xf86_config->output[i]; struct drmmode_output_priv *drmmode_output = output->driver_private; int j; drmmode_output->enc_clones = 0xffffffff; drmmode_output->enc_mask = 0; for (j = 0; j < drmmode_output->connector->count_encoders; j++) { int k; /* set index ordered mask of encoders on this output */ for (k = 0; k < drmmode->mode_res->count_encoders; k++) { if (drmmode->mode_res->encoders[k] == drmmode_output->encoders[j]->encoder_id) drmmode_output->enc_mask |= (1 << k); } /* set mask for encoder clones possible with all encoders on this output */ drmmode_output->enc_clones &= drmmode_output->encoders[j]->possible_clones; } } /* Output j is a possible clone of output i if the enc_mask for j matches the enc_clones for i */ for (i = 0; i < xf86_config->num_output; i++) { xf86OutputPtr output = xf86_config->output[i]; struct drmmode_output_priv *drmmode_output = output->driver_private; int j; output->possible_clones = 0; if (drmmode_output->enc_clones == 0) continue; for (j = 0; j < xf86_config->num_output; j++) { struct drmmode_output_priv *clone = xf86_config->output[j]->driver_private; if ((i != j) && (clone->enc_mask != 0) && (drmmode_output->enc_clones == clone->enc_mask)) output->possible_clones |= (1 << j); } } } void set_scanout_bo(ScrnInfoPtr pScrn, struct armsoc_bo *bo) { struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); struct armsoc_bo *old_scanout; old_scanout = pARMSOC->scanout; /* It had better have a framebuffer if we're scanning it out */ assert(armsoc_bo_get_fb(bo)); armsoc_bo_reference(bo); /* Screen takes ref on new scanout bo */ pARMSOC->scanout = bo; if (old_scanout) armsoc_bo_unreference(old_scanout); /* Screen drops ref on old scanout bo */ } static Bool resize_scanout_bo(ScrnInfoPtr pScrn, int width, int height) { struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); ScreenPtr pScreen = pScrn->pScreen; uint32_t pitch; uint8_t depth, bpp; TRACE_ENTER(); depth = armsoc_bo_depth(pARMSOC->scanout); bpp = armsoc_bo_bpp(pARMSOC->scanout); DEBUG_MSG("Resize: %dx%d %d,%d", width, height, depth, bpp); /* We don't expect the depth and bpp to change for the screen * assert this here as a check */ assert(depth == pScrn->bitsPerPixel); assert(bpp == pScrn->bitsPerPixel); pScrn->virtualX = width; pScrn->virtualY = height; if ((width != armsoc_bo_width(pARMSOC->scanout)) || (height != armsoc_bo_height(pARMSOC->scanout))) { struct armsoc_bo *new_scanout; /* resize_scanout_bo creates and takes ref on new scanout bo */ new_scanout = armsoc_bo_new_with_dim(pARMSOC->dev, width, height, depth, bpp, 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 { struct armsoc_bo *old_scanout = pARMSOC->scanout; 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)) { /* resize_scanout_bo drops ref on new scanout on failure exit */ 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"); /* resize_scanout_bo drops ref on new scanout on failure exit */ armsoc_bo_unreference(new_scanout); return FALSE; } /* Handle dma_buf fd that may be attached to old bo */ if (armsoc_bo_has_dmabuf(old_scanout)) { int res; armsoc_bo_clear_dmabuf(old_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); /* resize_scanout_bo drops ref on new scanout on failure exit */ return FALSE; } } /* use new scanout buffer */ set_scanout_bo(pScrn, new_scanout); armsoc_bo_unreference(new_scanout); /* Screen has now taken ref on new_scanout so resize_scanout_bo drops it */ ARMSOCDRI2ResizeSwapChain(pScrn, old_scanout, 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); /* Wrap the screen pixmap around the new scanout bo. * If we are n-buffering and the scanout bo is behind the * screen pixmap by a few flips, the bo which is being resized * may not belong to the screen pixmap. However we need to * resize the screen pixmap in order to continue flipping. * For now we let this happen and the swap chain reference * on the screen pixmap's existing bo will prevent it being * deleted here. Things may look odd until the swap chain * works through. This needs improvement. */ pScreen->ModifyPixmapHeader(rootPixmap, pScrn->virtualX, pScrn->virtualY, depth, bpp, 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; } TRACE_EXIT(); return TRUE; } static Bool drmmode_xf86crtc_resize(ScrnInfoPtr pScrn, int width, int height) { int i; xf86CrtcConfigPtr xf86_config; TRACE_ENTER(); if (!resize_scanout_bo(pScrn, width, height)) goto fail; /* 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; fail: TRACE_EXIT(); return FALSE; } static const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = { .resize = 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); } drmmode_clones_init(pScrn, drmmode); 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 void vblank_handler(int fd, unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec, void *user_data) { ARMSOCDRI2VBlankHandler(sequence, tv_sec, tv_usec, user_data); } static drmEventContext event_context = { .version = DRM_EVENT_CONTEXT_VERSION, .page_flip_handler = page_flip_handler, .vblank_handler = vblank_handler, }; int drmmode_page_flip(DrawablePtr draw, uint32_t fb_id, void *priv) { ScreenPtr pScreen = draw->pScreen; ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 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->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: * TODO: MIDEGL-1441: Do we need to keep this handler, which * Rob originally wrote? */ 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; /* * 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); if (fstat(pARMSOC->drmFD, &s)) { ERROR_MSG("fstat failed: %s", strerror(errno)); udev_device_unref(dev); return; } 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(xf86ScrnToScreen(pScrn), 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(); } #if HAVE_NOTIFY_FD static void drmmode_notify_fd(int fd, int notify, void *data) { drmHandleEvent(fd, &event_context); } #else static void drmmode_wakeup_handler(pointer data, int err, pointer p) { struct ARMSOCRec *pARMSOC = (struct ARMSOCRec *)data; int fd = pARMSOC->drmFD; fd_set *read_mask = p; if (err < 0) return; if (FD_ISSET(fd, read_mask)) drmHandleEvent(fd, &event_context); } #endif void drmmode_init_wakeup_handler(struct ARMSOCRec *pARMSOC) { #if HAVE_NOTIFY_FD SetNotifyFd(pARMSOC->drmFD, drmmode_notify_fd, X_NOTIFY_READ, pARMSOC); #else AddGeneralSocket(pARMSOC->drmFD); RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA, drmmode_wakeup_handler, pARMSOC); #endif } void drmmode_fini_wakeup_handler(struct ARMSOCRec *pARMSOC) { #if HAVE_NOTIFY_FD RemoveNotifyFd(pARMSOC->drmFD); #else RemoveBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA, drmmode_wakeup_handler, pARMSOC); RemoveGeneralSocket(pARMSOC->drmFD); #endif } 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) { struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); drmmode_uevent_init(pScrn); drmmode_init_wakeup_handler(pARMSOC); } void drmmode_screen_fini(ScrnInfoPtr pScrn) { struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn); drmmode_uevent_fini(pScrn); drmmode_fini_wakeup_handler(pARMSOC); } xf86-video-armsoc-1.4.1/src/drmmode_driver.h000066400000000000000000000072161275754335000206610ustar00rootroot00000000000000/* * 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" #include "armsoc_dumb.h" enum hwcursor_api { HWCURSOR_API_PLANE = 0, HWCURSOR_API_STANDARD = 1, HWCURSOR_API_NONE = 2 }; struct drmmode_interface { /* Must match name used in the kernel driver */ const char *driver_name; /* 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; /* Boolean value indicating whether to support early display * feature. This allows the next back buffer to be obtained while * the previous is being flipped. */ int use_early_display; /* 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; /* Specifies the hardware cursor api used by the DRM : * HWCURSOR_API_PLANE - Use planes. * HWCURSOR_API_STANDARD - Use the standard API : drmModeSetCursor() & drmModeMoveCursor(). * HWCURSOR_API_NONE - No hardware cursor - use a software cursor. */ enum hwcursor_api cursor_api; /* (Optional) Initialize the hardware cursor plane. * * When cursor_api is HWCURSOR_API_PLANE, this function should do any * plane initialization necessary, for example setting the z-order on the * plane to appear above all other layers. If this function fails the driver * falls back to using a software cursor. * * If cursor_api is not HWCURSOR_API_PLANE this function should be omitted. * * @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); /* Boolean value indicating whether the DRM supports * vblank timestamp query */ int vblank_query_supported; /* (Mandatory) Create new gem object * * A driver specific ioctl() is usually needed to create GEM objects * with particular features such as contiguous memory, uncached, etc... * * @param fd DRM device file descriptor * @param create_gem generic GEM description * @return 0 on success, non-zero on failure */ int (*create_custom_gem)(int fd, struct armsoc_create_gem *create_gem); }; extern struct drmmode_interface exynos_interface; extern struct drmmode_interface pl111_interface; extern struct drmmode_interface kirin_interface; extern struct drmmode_interface sti_interface; #endif xf86-video-armsoc-1.4.1/src/drmmode_exynos/000077500000000000000000000000001275754335000205345ustar00rootroot00000000000000xf86-video-armsoc-1.4.1/src/drmmode_exynos/drmmode_exynos.c000066400000000000000000000115631275754335000237420ustar00rootroot00000000000000/* * 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 #include /* Following ioctls should be included from libdrm exynos_drm.h but * libdrm doesn't install this correctly so for now they are here. */ struct drm_exynos_plane_set_zpos { __u32 plane_id; __s32 zpos; }; #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) #define EXYNOS_BO_CONTIG 0 #define EXYNOS_BO_NONCONTIG 1 struct drm_exynos_gem_create { uint64_t size; unsigned int flags; unsigned int handle; }; #define DRM_EXYNOS_GEM_CREATE 0x00 #define DRM_IOCTL_EXYNOS_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + \ DRM_EXYNOS_GEM_CREATE, struct drm_exynos_gem_create) /* 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. This is a workaround for a bug * causing corruption when the cursor reaches the screen edges. */ #define CURSORPAD (16) #define ALIGN(val, align) (((val) + (align) - 1) & ~((align) - 1)) 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; } static int create_custom_gem(int fd, struct armsoc_create_gem *create_gem) { struct drm_exynos_gem_create create_exynos; int ret; unsigned int pitch; /* make pitch a multiple of 64 bytes for best performance */ pitch = ALIGN(create_gem->width * ((create_gem->bpp + 7) / 8), 64); memset(&create_exynos, 0, sizeof(create_exynos)); create_exynos.size = create_gem->height * pitch; assert((create_gem->buf_type == ARMSOC_BO_SCANOUT) || (create_gem->buf_type == ARMSOC_BO_NON_SCANOUT)); /* Contiguous allocations are not supported in some exynos drm versions. * When they are supported all allocations are effectively contiguous * anyway, so for simplicity we always request non contiguous buffers. */ create_exynos.flags = EXYNOS_BO_NONCONTIG; ret = drmIoctl(fd, DRM_IOCTL_EXYNOS_GEM_CREATE, &create_exynos); if (ret) return ret; /* Convert custom create_exynos to generic create_gem */ create_gem->handle = create_exynos.handle; create_gem->pitch = pitch; create_gem->size = create_exynos.size; return 0; } struct drmmode_interface exynos_interface = { "exynos" /* name of drm driver */, 1 /* use_page_flip_events */, 1 /* use_early_display */, CURSORW /* cursor width */, CURSORH /* cursor_height */, CURSORPAD /* cursor padding */, HWCURSOR_API_PLANE /* cursor_api */, init_plane_for_cursor /* init_plane_for_cursor */, 0 /* vblank_query_supported */, create_custom_gem /* create_custom_gem */, }; xf86-video-armsoc-1.4.1/src/drmmode_kirin/000077500000000000000000000000001275754335000203235ustar00rootroot00000000000000xf86-video-armsoc-1.4.1/src/drmmode_kirin/drmmode_kirin.c000066400000000000000000000054771275754335000233270ustar00rootroot00000000000000/* * Copyright © 2016 Linaro Limited. * Copyright © 2016 Hisilicon 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 "../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) #define ALIGN(val, align) (((val) + (align) - 1) & ~((align) - 1)) static int create_custom_gem(int fd, struct armsoc_create_gem *create_gem) { struct drm_mode_create_dumb arg; unsigned int pitch; int ret; /* For 32bpp mali 450GPU needs pitch 8 bytes alignment */ pitch = ALIGN(create_gem->width * ((create_gem->bpp + 7) / 8), 8); memset(&arg, 0, sizeof(arg)); arg.width = create_gem->width; arg.height = create_gem->height; arg.bpp = create_gem->bpp; arg.pitch = pitch; arg.size = pitch * create_gem->height; ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &arg); if (ret) return ret; create_gem->handle = arg.handle; create_gem->pitch = arg.pitch; create_gem->size = arg.size; return 0; } struct drmmode_interface kirin_interface = { "kirin" /* name of drm driver */, 1 /* use_page_flip_events */, 1 /* use_early_display */, CURSORW /* cursor width */, CURSORH /* cursor_height */, CURSORPAD /* cursor padding */, HWCURSOR_API_NONE /* software cursor */, NULL /* no plane for cursor */, 0 /* vblank_query_supported */, create_custom_gem /* create_custom_gem */, }; xf86-video-armsoc-1.4.1/src/drmmode_pl111/000077500000000000000000000000001275754335000200455ustar00rootroot00000000000000xf86-video-armsoc-1.4.1/src/drmmode_pl111/drmmode_pl111.c000066400000000000000000000076721275754335000225720ustar00rootroot00000000000000/* * 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 /* 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) /* * Parameters for different buffer objects: * bit [0]: backing storage * (0 -> DMA) * (1 -> SHM) * bit [2:1]: kind of mapping * (0x0 -> uncached) * (0x1 -> write combine) * (0x2 -> cached) */ #define PL111_BOT_MASK (0x7) #define PL111_BOT_SHM (0x0 << 0) #define PL111_BOT_DMA (0x1 << 0) #define PL111_BOT_UNCACHED (0x0 << 1) #define PL111_BOT_WC (0x1 << 1) #define PL111_BOT_CACHED (0x2 << 1) /* TODO MIDEGL-1718: this should be included * from libdrm headers when pl111 is mainline */ struct drm_pl111_gem_create { uint32_t height; uint32_t width; uint32_t bpp; uint32_t flags; /* handle, pitch, size will be returned */ uint32_t handle; uint32_t pitch; uint64_t size; }; #define DRM_PL111_GEM_CREATE 0x00 #define DRM_IOCTL_PL111_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + \ DRM_PL111_GEM_CREATE, struct drm_pl111_gem_create) /***************************************************************************/ static int create_custom_gem(int fd, struct armsoc_create_gem *create_gem) { struct drm_pl111_gem_create create_pl111; int ret; memset(&create_pl111, 0, sizeof(create_pl111)); create_pl111.height = create_gem->height; create_pl111.width = create_gem->width; create_pl111.bpp = create_gem->bpp; assert((create_gem->buf_type == ARMSOC_BO_SCANOUT) || (create_gem->buf_type == ARMSOC_BO_NON_SCANOUT)); if (create_gem->buf_type == ARMSOC_BO_SCANOUT) create_pl111.flags = PL111_BOT_DMA | PL111_BOT_UNCACHED; else create_pl111.flags = PL111_BOT_SHM | PL111_BOT_UNCACHED; ret = drmIoctl(fd, DRM_IOCTL_PL111_GEM_CREATE, &create_pl111); if (ret) return ret; /* Convert custom create_pl111 to generic create_gem */ create_gem->height = create_pl111.height; create_gem->width = create_pl111.width; create_gem->bpp = create_pl111.bpp; create_gem->handle = create_pl111.handle; create_gem->pitch = create_pl111.pitch; create_gem->size = create_pl111.size; return 0; } struct drmmode_interface pl111_interface = { "pl111_drm" /* name of drm driver */, 1 /* use_page_flip_events */, 1 /* use_early_display */, CURSORW /* cursor width */, CURSORH /* cursor_height */, CURSORPAD /* cursor padding */, HWCURSOR_API_STANDARD /* cursor_api */, NULL /* init_plane_for_cursor */, 0 /* vblank_query_supported */, create_custom_gem /* create_custom_gem */, }; xf86-video-armsoc-1.4.1/src/drmmode_sti/000077500000000000000000000000001275754335000200065ustar00rootroot00000000000000xf86-video-armsoc-1.4.1/src/drmmode_sti/drmmode_sti.c000066400000000000000000000056051275754335000224660ustar00rootroot00000000000000/* * 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 #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. This is a workaround for a bug * causing corruption when the cursor reaches the screen edges. */ #define CURSORPAD (16) /* Optional function */ static int init_plane_for_cursor(int drm_fd, uint32_t plane_id) { return 0; } static int create_custom_gem(int fd, struct armsoc_create_gem *create_gem) { struct drm_mode_create_dumb create_arg; int ret; memset (&create_arg, 0, sizeof (create_arg)); create_arg.bpp = create_gem->bpp; create_arg.width = create_gem->width; create_arg.height = create_gem->height; ret = ioctl (fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg); if (ret) return ret; /* Convert custom create_exynos to generic create_gem */ create_gem->handle = create_arg.handle; create_gem->pitch = create_arg.pitch; create_gem->size = create_gem->height * create_arg.pitch; return 0; } struct drmmode_interface sti_interface = { "sti" /* name of drm driver */, 1 /* use_page_flip_events */, 1 /* use_early_display */, CURSORW /* cursor width */, CURSORH /* cursor_height */, CURSORPAD /* cursor padding */, HWCURSOR_API_STANDARD /* cursor_api */, init_plane_for_cursor /* init_plane_for_cursor */, 0 /* vblank_query_supported */, create_custom_gem /* create_custom_gem */, }; xf86-video-armsoc-1.4.1/src/drmmode_template/000077500000000000000000000000001275754335000210225ustar00rootroot00000000000000xf86-video-armsoc-1.4.1/src/drmmode_template/drmmode_template.c000066400000000000000000000046501275754335000245150ustar00rootroot00000000000000/* * 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 only for HWCURSOR_API_PLANE interface */ static int init_plane_for_cursor(int drm_fd, uint32_t plane_id) { return 0; } static int create_custom_gem(int fd, struct armsoc_create_gem *create_gem) { /* * provide a method of creating both scanout and non-scanout GEM * objects here. This method is usually a custom ioctl() call to * the DRM driver. */ } struct drmmode_interface template_interface = { "template" /* name of drm driver*/ 1 /* use_page_flip_events */, 1 /* use_early_display */, CURSORW /* cursor width */, CURSORH /* cursor_height */, CURSORPAD /* cursor padding */, HWCURSOR_API_STANDARD /* cursor_api */, init_plane_for_cursor /* init_plane_for_cursor */, 0 /* vblank_query_supported */, create_custom_gem /* create_custom_gem */, }; xf86-video-armsoc-1.4.1/src/umplock/000077500000000000000000000000001275754335000171525ustar00rootroot00000000000000xf86-video-armsoc-1.4.1/src/umplock/umplock_ioctl.h000066400000000000000000000051271275754335000221740ustar00rootroot00000000000000/* * 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 __UMPLOCK_IOCTL_H__ #define __UMPLOCK_IOCTL_H__ #ifdef __cplusplus extern "C" { #endif #include #include #ifndef __user #define __user #endif /** * @file umplock_ioctl.h * This file describes the interface needed to use the Linux device driver. * The interface is used by the userpace Mali DDK. */ typedef enum { _LOCK_ACCESS_RENDERABLE = 1, _LOCK_ACCESS_TEXTURE, _LOCK_ACCESS_CPU_WRITE, _LOCK_ACCESS_CPU_READ, } _lock_access_usage; typedef struct _lock_item_s { unsigned int secure_id; _lock_access_usage usage; } _lock_item_s; #define LOCK_IOCTL_GROUP 0x91 #define _LOCK_IOCTL_CREATE_CMD 0 /* create kernel lock item */ #define _LOCK_IOCTL_PROCESS_CMD 1 /* process kernel lock item */ #define _LOCK_IOCTL_RELEASE_CMD 2 /* release kernel lock item */ #define _LOCK_IOCTL_ZAP_CMD 3 /* clean up all kernel lock items */ #define _LOCK_IOCTL_DUMP_CMD 4 /* dump all the items */ #define LOCK_IOCTL_MAX_CMDS 5 #define LOCK_IOCTL_CREATE _IOW( LOCK_IOCTL_GROUP, _LOCK_IOCTL_CREATE_CMD, _lock_item_s ) #define LOCK_IOCTL_PROCESS _IOW( LOCK_IOCTL_GROUP, _LOCK_IOCTL_PROCESS_CMD, _lock_item_s ) #define LOCK_IOCTL_RELEASE _IOW( LOCK_IOCTL_GROUP, _LOCK_IOCTL_RELEASE_CMD, _lock_item_s ) #define LOCK_IOCTL_ZAP _IO ( LOCK_IOCTL_GROUP, _LOCK_IOCTL_ZAP_CMD ) #define LOCK_IOCTL_DUMP _IO ( LOCK_IOCTL_GROUP, _LOCK_IOCTL_DUMP_CMD ) #ifdef __cplusplus } #endif #endif /* __UMPLOCK_IOCTL_H__ */