summaryrefslogtreecommitdiffstats
path: root/pvr-source/services4/3rdparty/dc_omapfb3_linux
diff options
context:
space:
mode:
Diffstat (limited to 'pvr-source/services4/3rdparty/dc_omapfb3_linux')
-rw-r--r--pvr-source/services4/3rdparty/dc_omapfb3_linux/Kbuild.mk48
-rw-r--r--pvr-source/services4/3rdparty/dc_omapfb3_linux/Linux.mk45
-rw-r--r--pvr-source/services4/3rdparty/dc_omapfb3_linux/omaplfb.h323
-rw-r--r--pvr-source/services4/3rdparty/dc_omapfb3_linux/omaplfb_displayclass.c1722
-rw-r--r--pvr-source/services4/3rdparty/dc_omapfb3_linux/omaplfb_linux.c1165
5 files changed, 3303 insertions, 0 deletions
diff --git a/pvr-source/services4/3rdparty/dc_omapfb3_linux/Kbuild.mk b/pvr-source/services4/3rdparty/dc_omapfb3_linux/Kbuild.mk
new file mode 100644
index 0000000..7f4fd99
--- /dev/null
+++ b/pvr-source/services4/3rdparty/dc_omapfb3_linux/Kbuild.mk
@@ -0,0 +1,48 @@
+########################################################################### ###
+#@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
+#@License Dual MIT/GPLv2
+#
+# The contents of this file are subject to the MIT license as set out below.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# Alternatively, the contents of this file may be used under the terms of
+# the GNU General Public License Version 2 ("GPL") in which case the provisions
+# of GPL are applicable instead of those above.
+#
+# If you wish to allow use of your version of this file only under the terms of
+# GPL, and not to allow others to use your version of this file under the terms
+# of the MIT license, indicate your decision by deleting the provisions above
+# and replace them with the notice and other provisions required by GPL as set
+# out in the file called "GPL-COPYING" included in this distribution. If you do
+# not delete the provisions above, a recipient may use your version of this file
+# under the terms of either the MIT license or GPL.
+#
+# This License is also included in this distribution in the file called
+# "MIT-COPYING".
+#
+# EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) 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; AND (B) 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.
+### ###########################################################################
+
+ccflags-y += \
+ -I$(TOP)/services4/3rdparty/dc_omapfb3_linux \
+ -I$(KERNELDIR)/drivers/video/omap2 \
+ -I$(KERNELDIR)/arch/arm/plat-omap/include
+
+omaplfb-y += \
+ services4/3rdparty/dc_omapfb3_linux/omaplfb_displayclass.o \
+ services4/3rdparty/dc_omapfb3_linux/omaplfb_linux.o
diff --git a/pvr-source/services4/3rdparty/dc_omapfb3_linux/Linux.mk b/pvr-source/services4/3rdparty/dc_omapfb3_linux/Linux.mk
new file mode 100644
index 0000000..75d11a9
--- /dev/null
+++ b/pvr-source/services4/3rdparty/dc_omapfb3_linux/Linux.mk
@@ -0,0 +1,45 @@
+########################################################################### ###
+#@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
+#@License Dual MIT/GPLv2
+#
+# The contents of this file are subject to the MIT license as set out below.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# Alternatively, the contents of this file may be used under the terms of
+# the GNU General Public License Version 2 ("GPL") in which case the provisions
+# of GPL are applicable instead of those above.
+#
+# If you wish to allow use of your version of this file only under the terms of
+# GPL, and not to allow others to use your version of this file under the terms
+# of the MIT license, indicate your decision by deleting the provisions above
+# and replace them with the notice and other provisions required by GPL as set
+# out in the file called "GPL-COPYING" included in this distribution. If you do
+# not delete the provisions above, a recipient may use your version of this file
+# under the terms of either the MIT license or GPL.
+#
+# This License is also included in this distribution in the file called
+# "MIT-COPYING".
+#
+# EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) 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; AND (B) 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.
+### ###########################################################################
+
+modules := dc_omapfb3_linux
+
+dc_omapfb3_linux_type := kernel_module
+dc_omapfb3_linux_target := omaplfb.ko
+dc_omapfb3_linux_makefile := $(THIS_DIR)/Kbuild.mk
diff --git a/pvr-source/services4/3rdparty/dc_omapfb3_linux/omaplfb.h b/pvr-source/services4/3rdparty/dc_omapfb3_linux/omaplfb.h
new file mode 100644
index 0000000..804695b
--- /dev/null
+++ b/pvr-source/services4/3rdparty/dc_omapfb3_linux/omaplfb.h
@@ -0,0 +1,323 @@
+/*************************************************************************/ /*!
+@Title OMAP Linux display driver structures and prototypes
+@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
+@License Dual MIT/GPLv2
+
+The contents of this file are subject to the MIT license as set out below.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+Alternatively, the contents of this file may be used under the terms of
+the GNU General Public License Version 2 ("GPL") in which case the provisions
+of GPL are applicable instead of those above.
+
+If you wish to allow use of your version of this file only under the terms of
+GPL, and not to allow others to use your version of this file under the terms
+of the MIT license, indicate your decision by deleting the provisions above
+and replace them with the notice and other provisions required by GPL as set
+out in the file called "GPL-COPYING" included in this distribution. If you do
+not delete the provisions above, a recipient may use your version of this file
+under the terms of either the MIT license or GPL.
+
+This License is also included in this distribution in the file called
+"MIT-COPYING".
+
+EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) 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; AND (B) 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 __OMAPLFB_H__
+#define __OMAPLFB_H__
+
+#include <linux/version.h>
+
+#include <asm/atomic.h>
+
+#include <linux/kernel.h>
+#include <linux/console.h>
+#include <linux/fb.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/notifier.h>
+#include <linux/mutex.h>
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
+#define OMAPLFB_CONSOLE_LOCK() console_lock()
+#define OMAPLFB_CONSOLE_UNLOCK() console_unlock()
+#else
+#define OMAPLFB_CONSOLE_LOCK() acquire_console_sem()
+#define OMAPLFB_CONSOLE_UNLOCK() release_console_sem()
+#endif
+
+#define unref__ __attribute__ ((unused))
+
+typedef void * OMAPLFB_HANDLE;
+
+typedef bool OMAPLFB_BOOL, *OMAPLFB_PBOOL;
+#define OMAPLFB_FALSE false
+#define OMAPLFB_TRUE true
+
+typedef atomic_t OMAPLFB_ATOMIC_BOOL;
+
+typedef atomic_t OMAPLFB_ATOMIC_INT;
+
+/* OMAPLFB buffer structure */
+typedef struct OMAPLFB_BUFFER_TAG
+{
+ struct OMAPLFB_BUFFER_TAG *psNext;
+ struct OMAPLFB_DEVINFO_TAG *psDevInfo;
+
+ struct work_struct sWork;
+
+ /* Position of this buffer in the virtual framebuffer */
+ unsigned long ulYOffset;
+
+ /* IMG structures used, to minimise API function code */
+ /* replace with own structures where necessary */
+ IMG_SYS_PHYADDR sSysAddr;
+ IMG_CPU_VIRTADDR sCPUVAddr;
+ PVRSRV_SYNC_DATA *psSyncData;
+
+ OMAPLFB_HANDLE hCmdComplete;
+ unsigned long ulSwapInterval;
+} OMAPLFB_BUFFER;
+
+/* OMAPLFB swapchain structure */
+typedef struct OMAPLFB_SWAPCHAIN_TAG
+{
+ /* Swap chain ID */
+ unsigned int uiSwapChainID;
+
+ /* number of buffers in swapchain */
+ unsigned long ulBufferCount;
+
+ /* list of buffers in the swapchain */
+ OMAPLFB_BUFFER *psBuffer;
+
+ /* Swap chain work queue */
+ struct workqueue_struct *psWorkQueue;
+
+ /*
+ * Set if we didn't manage to wait for VSync on last swap,
+ * or if we think we need to wait for VSync on the next flip.
+ * The flag helps to avoid jitter when the screen is
+ * unblanked, by forcing an extended wait for VSync before
+ * attempting the next flip.
+ */
+ OMAPLFB_BOOL bNotVSynced;
+
+ /* Previous number of blank events */
+ int iBlankEvents;
+
+ /* Framebuffer Device ID for messages (e.g. printk) */
+ unsigned int uiFBDevID;
+} OMAPLFB_SWAPCHAIN;
+
+typedef struct OMAPLFB_FBINFO_TAG
+{
+ unsigned long ulFBSize;
+ unsigned long ulBufferSize;
+ unsigned long ulRoundedBufferSize;
+ unsigned long ulWidth;
+ unsigned long ulHeight;
+ unsigned long ulByteStride;
+ unsigned long ulPhysicalWidthmm;
+ unsigned long ulPhysicalHeightmm;
+
+ /* IMG structures used, to minimise API function code */
+ /* replace with own structures where necessary */
+ IMG_SYS_PHYADDR sSysAddr;//system physical address
+ IMG_CPU_VIRTADDR sCPUVAddr;
+
+ /* pixelformat of system/primary surface */
+ PVRSRV_PIXEL_FORMAT ePixelFormat;
+
+#if defined(CONFIG_DSSCOMP)
+ OMAPLFB_BOOL bIs2D;
+ IMG_SYS_PHYADDR *psPageList;
+ struct ion_handle *psIONHandle;
+ IMG_UINT32 uiBytesPerPixel;
+#endif
+} OMAPLFB_FBINFO;
+
+/* kernel device information structure */
+typedef struct OMAPLFB_DEVINFO_TAG
+{
+ /* Framebuffer Device ID */
+ unsigned int uiFBDevID;
+
+ /* PVR Device ID */
+ unsigned int uiPVRDevID;
+
+ /* Swapchain create/destroy mutex */
+ struct mutex sCreateSwapChainMutex;
+
+ /* system surface info */
+ OMAPLFB_BUFFER sSystemBuffer;
+
+ /* jump table into PVR services */
+ PVRSRV_DC_DISP2SRV_KMJTABLE sPVRJTable;
+
+ /* jump table into DC */
+ PVRSRV_DC_SRV2DISP_KMJTABLE sDCJTable;
+
+ /* fb info structure */
+ OMAPLFB_FBINFO sFBInfo;
+
+ /* Only one swapchain supported by this device so hang it here */
+ OMAPLFB_SWAPCHAIN *psSwapChain;
+
+ /* Swap chain ID */
+ unsigned int uiSwapChainID;
+
+ /* True if PVR Services is flushing its command queues */
+ OMAPLFB_ATOMIC_BOOL sFlushCommands;
+
+ /* pointer to linux frame buffer information structure */
+ struct fb_info *psLINFBInfo;
+
+ /* Linux Framebuffer event notification block */
+ struct notifier_block sLINNotifBlock;
+
+ /* IMG structures used, to minimise API function code */
+ /* replace with own structures where necessary */
+
+ /* Address of the surface being displayed */
+ IMG_DEV_VIRTADDR sDisplayDevVAddr;
+
+ DISPLAY_INFO sDisplayInfo;
+
+ /* Display format */
+ DISPLAY_FORMAT sDisplayFormat;
+
+ /* Display dimensions */
+ DISPLAY_DIMS sDisplayDim;
+
+ /* True if screen is blanked */
+ OMAPLFB_ATOMIC_BOOL sBlanked;
+
+ /* Number of blank/unblank events */
+ OMAPLFB_ATOMIC_INT sBlankEvents;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ /* Set by early suspend */
+ OMAPLFB_ATOMIC_BOOL sEarlySuspendFlag;
+
+ struct early_suspend sEarlySuspend;
+#endif
+
+#if defined(SUPPORT_DRI_DRM)
+ OMAPLFB_ATOMIC_BOOL sLeaveVT;
+#endif
+
+} OMAPLFB_DEVINFO;
+
+#define OMAPLFB_PAGE_SIZE 4096
+
+/* DEBUG only printk */
+#ifdef DEBUG
+#define DEBUG_PRINTK(x) printk x
+#else
+#define DEBUG_PRINTK(x)
+#endif
+
+#define DISPLAY_DEVICE_NAME "PowerVR OMAP Linux Display Driver"
+#define DRVNAME "omaplfb"
+#define DEVNAME DRVNAME
+#define DRIVER_PREFIX DRVNAME
+
+/*!
+ *****************************************************************************
+ * Error values
+ *****************************************************************************/
+typedef enum _OMAPLFB_ERROR_
+{
+ OMAPLFB_OK = 0,
+ OMAPLFB_ERROR_GENERIC = 1,
+ OMAPLFB_ERROR_OUT_OF_MEMORY = 2,
+ OMAPLFB_ERROR_TOO_FEW_BUFFERS = 3,
+ OMAPLFB_ERROR_INVALID_PARAMS = 4,
+ OMAPLFB_ERROR_INIT_FAILURE = 5,
+ OMAPLFB_ERROR_CANT_REGISTER_CALLBACK = 6,
+ OMAPLFB_ERROR_INVALID_DEVICE = 7,
+ OMAPLFB_ERROR_DEVICE_REGISTER_FAILED = 8,
+ OMAPLFB_ERROR_SET_UPDATE_MODE_FAILED = 9
+} OMAPLFB_ERROR;
+
+typedef enum _OMAPLFB_UPDATE_MODE_
+{
+ OMAPLFB_UPDATE_MODE_UNDEFINED = 0,
+ OMAPLFB_UPDATE_MODE_MANUAL = 1,
+ OMAPLFB_UPDATE_MODE_AUTO = 2,
+ OMAPLFB_UPDATE_MODE_DISABLED = 3
+} OMAPLFB_UPDATE_MODE;
+
+#ifndef UNREFERENCED_PARAMETER
+#define UNREFERENCED_PARAMETER(param) (param) = (param)
+#endif
+
+OMAPLFB_ERROR OMAPLFBInit(void);
+OMAPLFB_ERROR OMAPLFBDeInit(void);
+
+/* OS Specific APIs */
+OMAPLFB_DEVINFO *OMAPLFBGetDevInfoPtr(unsigned uiFBDevID);
+unsigned OMAPLFBMaxFBDevIDPlusOne(void);
+void *OMAPLFBAllocKernelMem(unsigned long ulSize);
+void OMAPLFBFreeKernelMem(void *pvMem);
+OMAPLFB_ERROR OMAPLFBGetLibFuncAddr(char *szFunctionName, PFN_DC_GET_PVRJTABLE *ppfnFuncTable);
+OMAPLFB_ERROR OMAPLFBCreateSwapQueue (OMAPLFB_SWAPCHAIN *psSwapChain);
+void OMAPLFBDestroySwapQueue(OMAPLFB_SWAPCHAIN *psSwapChain);
+void OMAPLFBInitBufferForSwap(OMAPLFB_BUFFER *psBuffer);
+void OMAPLFBSwapHandler(OMAPLFB_BUFFER *psBuffer);
+void OMAPLFBQueueBufferForSwap(OMAPLFB_SWAPCHAIN *psSwapChain, OMAPLFB_BUFFER *psBuffer);
+void OMAPLFBFlip(OMAPLFB_DEVINFO *psDevInfo, OMAPLFB_BUFFER *psBuffer);
+OMAPLFB_UPDATE_MODE OMAPLFBGetUpdateMode(OMAPLFB_DEVINFO *psDevInfo);
+OMAPLFB_BOOL OMAPLFBSetUpdateMode(OMAPLFB_DEVINFO *psDevInfo, OMAPLFB_UPDATE_MODE eMode);
+OMAPLFB_BOOL OMAPLFBWaitForVSync(OMAPLFB_DEVINFO *psDevInfo);
+OMAPLFB_BOOL OMAPLFBManualSync(OMAPLFB_DEVINFO *psDevInfo);
+OMAPLFB_BOOL OMAPLFBCheckModeAndSync(OMAPLFB_DEVINFO *psDevInfo);
+OMAPLFB_ERROR OMAPLFBUnblankDisplay(OMAPLFB_DEVINFO *psDevInfo);
+OMAPLFB_ERROR OMAPLFBEnableLFBEventNotification(OMAPLFB_DEVINFO *psDevInfo);
+OMAPLFB_ERROR OMAPLFBDisableLFBEventNotification(OMAPLFB_DEVINFO *psDevInfo);
+void OMAPLFBCreateSwapChainLockInit(OMAPLFB_DEVINFO *psDevInfo);
+void OMAPLFBCreateSwapChainLockDeInit(OMAPLFB_DEVINFO *psDevInfo);
+void OMAPLFBCreateSwapChainLock(OMAPLFB_DEVINFO *psDevInfo);
+void OMAPLFBCreateSwapChainUnLock(OMAPLFB_DEVINFO *psDevInfo);
+void OMAPLFBAtomicBoolInit(OMAPLFB_ATOMIC_BOOL *psAtomic, OMAPLFB_BOOL bVal);
+void OMAPLFBAtomicBoolDeInit(OMAPLFB_ATOMIC_BOOL *psAtomic);
+void OMAPLFBAtomicBoolSet(OMAPLFB_ATOMIC_BOOL *psAtomic, OMAPLFB_BOOL bVal);
+OMAPLFB_BOOL OMAPLFBAtomicBoolRead(OMAPLFB_ATOMIC_BOOL *psAtomic);
+void OMAPLFBAtomicIntInit(OMAPLFB_ATOMIC_INT *psAtomic, int iVal);
+void OMAPLFBAtomicIntDeInit(OMAPLFB_ATOMIC_INT *psAtomic);
+void OMAPLFBAtomicIntSet(OMAPLFB_ATOMIC_INT *psAtomic, int iVal);
+int OMAPLFBAtomicIntRead(OMAPLFB_ATOMIC_INT *psAtomic);
+void OMAPLFBAtomicIntInc(OMAPLFB_ATOMIC_INT *psAtomic);
+
+#if defined(DEBUG)
+void OMAPLFBPrintInfo(OMAPLFB_DEVINFO *psDevInfo);
+#else
+#define OMAPLFBPrintInfo(psDevInfo)
+#endif
+
+#endif /* __OMAPLFB_H__ */
+
+/******************************************************************************
+ End of file (omaplfb.h)
+******************************************************************************/
+
diff --git a/pvr-source/services4/3rdparty/dc_omapfb3_linux/omaplfb_displayclass.c b/pvr-source/services4/3rdparty/dc_omapfb3_linux/omaplfb_displayclass.c
new file mode 100644
index 0000000..ebca814
--- /dev/null
+++ b/pvr-source/services4/3rdparty/dc_omapfb3_linux/omaplfb_displayclass.c
@@ -0,0 +1,1722 @@
+/*************************************************************************/ /*!
+@Title OMAP common display driver components
+@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
+@License Dual MIT/GPLv2
+
+The contents of this file are subject to the MIT license as set out below.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+Alternatively, the contents of this file may be used under the terms of
+the GNU General Public License Version 2 ("GPL") in which case the provisions
+of GPL are applicable instead of those above.
+
+If you wish to allow use of your version of this file only under the terms of
+GPL, and not to allow others to use your version of this file under the terms
+of the MIT license, indicate your decision by deleting the provisions above
+and replace them with the notice and other provisions required by GPL as set
+out in the file called "GPL-COPYING" included in this distribution. If you do
+not delete the provisions above, a recipient may use your version of this file
+under the terms of either the MIT license or GPL.
+
+This License is also included in this distribution in the file called
+"MIT-COPYING".
+
+EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) 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; AND (B) 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.
+*/ /**************************************************************************/
+
+/**************************************************************************
+ The 3rd party driver is a specification of an API to integrate the IMG POWERVR
+ Services driver with 3rd Party display hardware. It is NOT a specification for
+ a display controller driver, rather a specification to extend the API for a
+ pre-existing driver for the display hardware.
+
+ The 3rd party driver interface provides IMG POWERVR client drivers (e.g. PVR2D)
+ with an API abstraction of the system's underlying display hardware, allowing
+ the client drivers to indirectly control the display hardware and access its
+ associated memory.
+
+ Functions of the API include
+ - query primary surface attributes (width, height, stride, pixel format, CPU
+ physical and virtual address)
+ - swap/flip chain creation and subsequent query of surface attributes
+ - asynchronous display surface flipping, taking account of asynchronous read
+ (flip) and write (render) operations to the display surface
+
+ Note: having queried surface attributes the client drivers are able to map the
+ display memory to any IMG POWERVR Services device by calling
+ PVRSRVMapDeviceClassMemory with the display surface handle.
+
+ This code is intended to be an example of how a pre-existing display driver may
+ be extended to support the 3rd Party Display interface to POWERVR Services
+ - IMG is not providing a display driver implementation.
+ **************************************************************************/
+
+/*
+ * OMAP Linux 3rd party display driver.
+ * This is based on the Generic PVR Linux Framebuffer 3rd party display
+ * driver, with OMAP specific extensions to support flipping.
+ */
+
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/console.h>
+#include <linux/fb.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/notifier.h>
+
+/* IMG services headers */
+#include "img_defs.h"
+#include "servicesext.h"
+#include "kerneldisplay.h"
+#include "omaplfb.h"
+
+#if defined(CONFIG_DSSCOMP)
+
+#if !defined(CONFIG_ION_OMAP)
+#error CONFIG_DSSCOMP support requires CONFIG_ION_OMAP
+#endif
+
+#include <linux/ion.h>
+#include <linux/omap_ion.h>
+
+extern struct ion_client *gpsIONClient;
+
+#include <mach/tiler.h>
+#include <video/dsscomp.h>
+#include <plat/dsscomp.h>
+
+#endif /* defined(CONFIG_DSSCOMP) */
+
+#define OMAPLFB_COMMAND_COUNT 1
+
+#define OMAPLFB_VSYNC_SETTLE_COUNT 5
+
+#define OMAPLFB_MAX_NUM_DEVICES FB_MAX
+#if (OMAPLFB_MAX_NUM_DEVICES > FB_MAX)
+#error "OMAPLFB_MAX_NUM_DEVICES must not be greater than FB_MAX"
+#endif
+
+static OMAPLFB_DEVINFO *gapsDevInfo[OMAPLFB_MAX_NUM_DEVICES];
+
+/* Top level 'hook ptr' */
+static PFN_DC_GET_PVRJTABLE gpfnGetPVRJTable = NULL;
+
+/* Round x up to a multiple of y */
+static inline unsigned long RoundUpToMultiple(unsigned long x, unsigned long y)
+{
+ unsigned long div = x / y;
+ unsigned long rem = x % y;
+
+ return (div + ((rem == 0) ? 0 : 1)) * y;
+}
+
+/* Greatest common divisor of x and y */
+static unsigned long GCD(unsigned long x, unsigned long y)
+{
+ while (y != 0)
+ {
+ unsigned long r = x % y;
+ x = y;
+ y = r;
+ }
+
+ return x;
+}
+
+/* Least common multiple of x and y */
+static unsigned long LCM(unsigned long x, unsigned long y)
+{
+ unsigned long gcd = GCD(x, y);
+
+ return (gcd == 0) ? 0 : ((x / gcd) * y);
+}
+
+unsigned OMAPLFBMaxFBDevIDPlusOne(void)
+{
+ return OMAPLFB_MAX_NUM_DEVICES;
+}
+
+/* Returns DevInfo pointer for a given device */
+OMAPLFB_DEVINFO *OMAPLFBGetDevInfoPtr(unsigned uiFBDevID)
+{
+ WARN_ON(uiFBDevID >= OMAPLFBMaxFBDevIDPlusOne());
+
+ if (uiFBDevID >= OMAPLFB_MAX_NUM_DEVICES)
+ {
+ return NULL;
+ }
+
+ return gapsDevInfo[uiFBDevID];
+}
+
+/* Sets the DevInfo pointer for a given device */
+static inline void OMAPLFBSetDevInfoPtr(unsigned uiFBDevID, OMAPLFB_DEVINFO *psDevInfo)
+{
+ WARN_ON(uiFBDevID >= OMAPLFB_MAX_NUM_DEVICES);
+
+ if (uiFBDevID < OMAPLFB_MAX_NUM_DEVICES)
+ {
+ gapsDevInfo[uiFBDevID] = psDevInfo;
+ }
+}
+
+static inline OMAPLFB_BOOL SwapChainHasChanged(OMAPLFB_DEVINFO *psDevInfo, OMAPLFB_SWAPCHAIN *psSwapChain)
+{
+ return (psDevInfo->psSwapChain != psSwapChain) ||
+ (psDevInfo->uiSwapChainID != psSwapChain->uiSwapChainID);
+}
+
+/* Don't wait for vertical sync */
+static inline OMAPLFB_BOOL DontWaitForVSync(OMAPLFB_DEVINFO *psDevInfo)
+{
+ OMAPLFB_BOOL bDontWait;
+
+ bDontWait = OMAPLFBAtomicBoolRead(&psDevInfo->sBlanked) ||
+ OMAPLFBAtomicBoolRead(&psDevInfo->sFlushCommands);
+
+#if defined(CONFIG_HAS_EARLYSUSPEND)
+ bDontWait = bDontWait || OMAPLFBAtomicBoolRead(&psDevInfo->sEarlySuspendFlag);
+#endif
+#if defined(SUPPORT_DRI_DRM)
+ bDontWait = bDontWait || OMAPLFBAtomicBoolRead(&psDevInfo->sLeaveVT);
+#endif
+ return bDontWait;
+}
+
+/*
+ * SetDCState
+ * Called from services.
+ */
+static IMG_VOID SetDCState(IMG_HANDLE hDevice, IMG_UINT32 ui32State)
+{
+ OMAPLFB_DEVINFO *psDevInfo = (OMAPLFB_DEVINFO *)hDevice;
+
+ switch (ui32State)
+ {
+ case DC_STATE_FLUSH_COMMANDS:
+ OMAPLFBAtomicBoolSet(&psDevInfo->sFlushCommands, OMAPLFB_TRUE);
+ break;
+ case DC_STATE_NO_FLUSH_COMMANDS:
+ OMAPLFBAtomicBoolSet(&psDevInfo->sFlushCommands, OMAPLFB_FALSE);
+ break;
+ case DC_STATE_FORCE_SWAP_TO_SYSTEM:
+ OMAPLFBFlip(psDevInfo, &psDevInfo->sSystemBuffer);
+ break;
+ default:
+ break;
+ }
+}
+
+/*
+ * OpenDCDevice
+ * Called from services.
+ */
+static PVRSRV_ERROR OpenDCDevice(IMG_UINT32 uiPVRDevID,
+ IMG_HANDLE *phDevice,
+ PVRSRV_SYNC_DATA* psSystemBufferSyncData)
+{
+ OMAPLFB_DEVINFO *psDevInfo;
+ OMAPLFB_ERROR eError;
+ unsigned uiMaxFBDevIDPlusOne = OMAPLFBMaxFBDevIDPlusOne();
+ unsigned i;
+
+ for (i = 0; i < uiMaxFBDevIDPlusOne; i++)
+ {
+ psDevInfo = OMAPLFBGetDevInfoPtr(i);
+ if (psDevInfo != NULL && psDevInfo->uiPVRDevID == uiPVRDevID)
+ {
+ break;
+ }
+ }
+ if (i == uiMaxFBDevIDPlusOne)
+ {
+ DEBUG_PRINTK((KERN_WARNING DRIVER_PREFIX
+ ": %s: PVR Device %u not found\n", __FUNCTION__, uiPVRDevID));
+ return PVRSRV_ERROR_INVALID_DEVICE;
+ }
+
+ /* store the system surface sync data */
+ psDevInfo->sSystemBuffer.psSyncData = psSystemBufferSyncData;
+
+ eError = OMAPLFBUnblankDisplay(psDevInfo);
+ if (eError != OMAPLFB_OK)
+ {
+ DEBUG_PRINTK((KERN_WARNING DRIVER_PREFIX
+ ": %s: Device %u: OMAPLFBUnblankDisplay failed (%d)\n", __FUNCTION__, psDevInfo->uiFBDevID, eError));
+ return PVRSRV_ERROR_UNBLANK_DISPLAY_FAILED;
+ }
+
+ /* return handle to the devinfo */
+ *phDevice = (IMG_HANDLE)psDevInfo;
+
+ return PVRSRV_OK;
+}
+
+/*
+ * CloseDCDevice
+ * Called from services.
+ */
+static PVRSRV_ERROR CloseDCDevice(IMG_HANDLE hDevice)
+{
+#if defined(SUPPORT_DRI_DRM)
+ OMAPLFB_DEVINFO *psDevInfo = (OMAPLFB_DEVINFO *)hDevice;
+
+ OMAPLFBAtomicBoolSet(&psDevInfo->sLeaveVT, OMAPLFB_FALSE);
+ (void) OMAPLFBUnblankDisplay(psDevInfo);
+#else
+ UNREFERENCED_PARAMETER(hDevice);
+#endif
+ return PVRSRV_OK;
+}
+
+/*
+ * EnumDCFormats
+ * Called from services.
+ */
+static PVRSRV_ERROR EnumDCFormats(IMG_HANDLE hDevice,
+ IMG_UINT32 *pui32NumFormats,
+ DISPLAY_FORMAT *psFormat)
+{
+ OMAPLFB_DEVINFO *psDevInfo;
+
+ if(!hDevice || !pui32NumFormats)
+ {
+ return PVRSRV_ERROR_INVALID_PARAMS;
+ }
+
+ psDevInfo = (OMAPLFB_DEVINFO*)hDevice;
+
+ *pui32NumFormats = 1;
+
+ if(psFormat)
+ {
+ psFormat[0] = psDevInfo->sDisplayFormat;
+ }
+
+ return PVRSRV_OK;
+}
+
+/*
+ * EnumDCDims
+ * Called from services.
+ */
+static PVRSRV_ERROR EnumDCDims(IMG_HANDLE hDevice,
+ DISPLAY_FORMAT *psFormat,
+ IMG_UINT32 *pui32NumDims,
+ DISPLAY_DIMS *psDim)
+{
+ OMAPLFB_DEVINFO *psDevInfo;
+
+ if(!hDevice || !psFormat || !pui32NumDims)
+ {
+ return PVRSRV_ERROR_INVALID_PARAMS;
+ }
+
+ psDevInfo = (OMAPLFB_DEVINFO*)hDevice;
+
+ *pui32NumDims = 1;
+
+ /* No need to look at psFormat; there is only one */
+ if(psDim)
+ {
+ psDim[0] = psDevInfo->sDisplayDim;
+ }
+
+ return PVRSRV_OK;
+}
+
+
+/*
+ * GetDCSystemBuffer
+ * Called from services.
+ */
+static PVRSRV_ERROR GetDCSystemBuffer(IMG_HANDLE hDevice, IMG_HANDLE *phBuffer)
+{
+ OMAPLFB_DEVINFO *psDevInfo;
+
+ if(!hDevice || !phBuffer)
+ {
+ return PVRSRV_ERROR_INVALID_PARAMS;
+ }
+
+ psDevInfo = (OMAPLFB_DEVINFO*)hDevice;
+
+ *phBuffer = (IMG_HANDLE)&psDevInfo->sSystemBuffer;
+
+ return PVRSRV_OK;
+}
+
+
+/*
+ * GetDCInfo
+ * Called from services.
+ */
+static PVRSRV_ERROR GetDCInfo(IMG_HANDLE hDevice, DISPLAY_INFO *psDCInfo)
+{
+ OMAPLFB_DEVINFO *psDevInfo;
+
+ if(!hDevice || !psDCInfo)
+ {
+ return PVRSRV_ERROR_INVALID_PARAMS;
+ }
+
+ psDevInfo = (OMAPLFB_DEVINFO*)hDevice;
+
+ *psDCInfo = psDevInfo->sDisplayInfo;
+
+ return PVRSRV_OK;
+}
+
+/*
+ * GetDCBufferAddr
+ * Called from services.
+ */
+static PVRSRV_ERROR GetDCBufferAddr(IMG_HANDLE hDevice,
+ IMG_HANDLE hBuffer,
+ IMG_SYS_PHYADDR **ppsSysAddr,
+ IMG_UINT32 *pui32ByteSize,
+ IMG_VOID **ppvCpuVAddr,
+ IMG_HANDLE *phOSMapInfo,
+ IMG_BOOL *pbIsContiguous,
+ IMG_UINT32 *pui32TilingStride)
+{
+ OMAPLFB_DEVINFO *psDevInfo;
+ OMAPLFB_BUFFER *psSystemBuffer;
+
+ UNREFERENCED_PARAMETER(pui32TilingStride);
+
+ if(!hDevice)
+ {
+ return PVRSRV_ERROR_INVALID_PARAMS;
+ }
+
+ if(!hBuffer)
+ {
+ return PVRSRV_ERROR_INVALID_PARAMS;
+ }
+
+ if (!ppsSysAddr)
+ {
+ return PVRSRV_ERROR_INVALID_PARAMS;
+ }
+
+ if (!pui32ByteSize)
+ {
+ return PVRSRV_ERROR_INVALID_PARAMS;
+ }
+
+ psDevInfo = (OMAPLFB_DEVINFO*)hDevice;
+
+ psSystemBuffer = (OMAPLFB_BUFFER *)hBuffer;
+
+ *ppsSysAddr = &psSystemBuffer->sSysAddr;
+
+ *pui32ByteSize = (IMG_UINT32)psDevInfo->sFBInfo.ulBufferSize;
+
+ if (ppvCpuVAddr)
+ {
+#if defined(CONFIG_DSSCOMP)
+ *ppvCpuVAddr = psDevInfo->sFBInfo.bIs2D ? NULL : psSystemBuffer->sCPUVAddr;
+#else
+ *ppvCpuVAddr = psSystemBuffer->sCPUVAddr;
+#endif
+ }
+
+ if (phOSMapInfo)
+ {
+ *phOSMapInfo = (IMG_HANDLE)0;
+ }
+
+ if (pbIsContiguous)
+ {
+#if defined(CONFIG_DSSCOMP)
+ *pbIsContiguous = !psDevInfo->sFBInfo.bIs2D;
+#else
+ *pbIsContiguous = IMG_TRUE;
+#endif
+ }
+
+#if defined(CONFIG_DSSCOMP)
+ if (psDevInfo->sFBInfo.bIs2D)
+ {
+ int i = (psSystemBuffer->sSysAddr.uiAddr - psDevInfo->sFBInfo.psPageList->uiAddr) >> PAGE_SHIFT;
+ *ppsSysAddr = psDevInfo->sFBInfo.psPageList + psDevInfo->sFBInfo.ulHeight * i;
+ }
+#endif
+
+ return PVRSRV_OK;
+}
+
+/*
+ * CreateDCSwapChain
+ * Called from services.
+ */
+static PVRSRV_ERROR CreateDCSwapChain(IMG_HANDLE hDevice,
+ IMG_UINT32 ui32Flags,
+ DISPLAY_SURF_ATTRIBUTES *psDstSurfAttrib,
+ DISPLAY_SURF_ATTRIBUTES *psSrcSurfAttrib,
+ IMG_UINT32 ui32BufferCount,
+ PVRSRV_SYNC_DATA **ppsSyncData,
+ IMG_UINT32 ui32OEMFlags,
+ IMG_HANDLE *phSwapChain,
+ IMG_UINT32 *pui32SwapChainID)
+{
+ OMAPLFB_DEVINFO *psDevInfo;
+ OMAPLFB_SWAPCHAIN *psSwapChain;
+ OMAPLFB_BUFFER *psBuffer;
+ IMG_UINT32 i;
+ PVRSRV_ERROR eError;
+ IMG_UINT32 ui32BuffersToSkip;
+
+ UNREFERENCED_PARAMETER(ui32OEMFlags);
+
+ /* Check parameters */
+ if(!hDevice
+ || !psDstSurfAttrib
+ || !psSrcSurfAttrib
+ || !ppsSyncData
+ || !phSwapChain)
+ {
+ return PVRSRV_ERROR_INVALID_PARAMS;
+ }
+
+ psDevInfo = (OMAPLFB_DEVINFO*)hDevice;
+
+ /* Do we support swap chains? */
+ if (psDevInfo->sDisplayInfo.ui32MaxSwapChains == 0)
+ {
+ return PVRSRV_ERROR_NOT_SUPPORTED;
+ }
+
+ OMAPLFBCreateSwapChainLock(psDevInfo);
+
+ /* The driver only supports a single swapchain */
+ if(psDevInfo->psSwapChain != NULL)
+ {
+ eError = PVRSRV_ERROR_FLIP_CHAIN_EXISTS;
+ goto ExitUnLock;
+ }
+
+ /* Check the buffer count */
+ if(ui32BufferCount > psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers)
+ {
+ eError = PVRSRV_ERROR_TOOMANYBUFFERS;
+ goto ExitUnLock;
+ }
+
+ if ((psDevInfo->sFBInfo.ulRoundedBufferSize * (unsigned long)ui32BufferCount) > psDevInfo->sFBInfo.ulFBSize)
+ {
+ eError = PVRSRV_ERROR_TOOMANYBUFFERS;
+ goto ExitUnLock;
+ }
+
+ /*
+ * We will allocate the swap chain buffers at the back of the frame
+ * buffer area. This preserves the front portion, which may be being
+ * used by other Linux Framebuffer based applications.
+ */
+ ui32BuffersToSkip = psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers - ui32BufferCount;
+
+ /*
+ * Verify the DST/SRC attributes,
+ * SRC/DST must match the current display mode config
+ */
+ if(psDstSurfAttrib->pixelformat != psDevInfo->sDisplayFormat.pixelformat
+ || psDstSurfAttrib->sDims.ui32ByteStride != psDevInfo->sDisplayDim.ui32ByteStride
+ || psDstSurfAttrib->sDims.ui32Width != psDevInfo->sDisplayDim.ui32Width
+ || psDstSurfAttrib->sDims.ui32Height != psDevInfo->sDisplayDim.ui32Height)
+ {
+ /* DST doesn't match the current mode */
+ eError = PVRSRV_ERROR_INVALID_PARAMS;
+ goto ExitUnLock;
+ }
+
+ if(psDstSurfAttrib->pixelformat != psSrcSurfAttrib->pixelformat
+ || psDstSurfAttrib->sDims.ui32ByteStride != psSrcSurfAttrib->sDims.ui32ByteStride
+ || psDstSurfAttrib->sDims.ui32Width != psSrcSurfAttrib->sDims.ui32Width
+ || psDstSurfAttrib->sDims.ui32Height != psSrcSurfAttrib->sDims.ui32Height)
+ {
+ /* DST doesn't match the SRC */
+ eError = PVRSRV_ERROR_INVALID_PARAMS;
+ goto ExitUnLock;
+ }
+
+ /* check flags if implementation requires them */
+ UNREFERENCED_PARAMETER(ui32Flags);
+
+#if defined(PVR_OMAPFB3_UPDATE_MODE)
+ if (!OMAPLFBSetUpdateMode(psDevInfo, PVR_OMAPFB3_UPDATE_MODE))
+ {
+ printk(KERN_WARNING DRIVER_PREFIX ": %s: Device %u: Couldn't set frame buffer update mode %d\n", __FUNCTION__, psDevInfo->uiFBDevID, PVR_OMAPFB3_UPDATE_MODE);
+ }
+#endif
+ /* create a swapchain structure */
+ psSwapChain = (OMAPLFB_SWAPCHAIN*)OMAPLFBAllocKernelMem(sizeof(OMAPLFB_SWAPCHAIN));
+ if(!psSwapChain)
+ {
+ eError = PVRSRV_ERROR_OUT_OF_MEMORY;
+ goto ExitUnLock;
+ }
+
+ psBuffer = (OMAPLFB_BUFFER*)OMAPLFBAllocKernelMem(sizeof(OMAPLFB_BUFFER) * ui32BufferCount);
+ if(!psBuffer)
+ {
+ eError = PVRSRV_ERROR_OUT_OF_MEMORY;
+ goto ErrorFreeSwapChain;
+ }
+
+ psSwapChain->ulBufferCount = (unsigned long)ui32BufferCount;
+ psSwapChain->psBuffer = psBuffer;
+ psSwapChain->bNotVSynced = OMAPLFB_TRUE;
+ psSwapChain->uiFBDevID = psDevInfo->uiFBDevID;
+
+ /* Link the buffers */
+ for(i=0; i<ui32BufferCount-1; i++)
+ {
+ psBuffer[i].psNext = &psBuffer[i+1];
+ }
+ /* and link last to first */
+ psBuffer[i].psNext = &psBuffer[0];
+
+ /* Configure the swapchain buffers */
+ for(i=0; i<ui32BufferCount; i++)
+ {
+ IMG_UINT32 ui32SwapBuffer = i + ui32BuffersToSkip;
+ IMG_UINT32 ui32BufferOffset = ui32SwapBuffer * (IMG_UINT32)psDevInfo->sFBInfo.ulRoundedBufferSize;
+
+#if defined(CONFIG_DSSCOMP)
+ if (psDevInfo->sFBInfo.bIs2D)
+ {
+ ui32BufferOffset = 0;
+ }
+#endif /* defined(CONFIG_DSSCOMP) */
+
+ psBuffer[i].psSyncData = ppsSyncData[i];
+
+ psBuffer[i].sSysAddr.uiAddr = psDevInfo->sFBInfo.sSysAddr.uiAddr + ui32BufferOffset;
+ psBuffer[i].sCPUVAddr = psDevInfo->sFBInfo.sCPUVAddr + ui32BufferOffset;
+ psBuffer[i].ulYOffset = ui32BufferOffset / psDevInfo->sFBInfo.ulByteStride;
+ psBuffer[i].psDevInfo = psDevInfo;
+
+#if defined(CONFIG_DSSCOMP)
+ if (psDevInfo->sFBInfo.bIs2D)
+ {
+ psBuffer[i].sSysAddr.uiAddr += ui32SwapBuffer *
+ ALIGN((IMG_UINT32)psDevInfo->sFBInfo.ulWidth * psDevInfo->sFBInfo.uiBytesPerPixel, PAGE_SIZE);
+ }
+#endif /* defined(CONFIG_DSSCOMP) */
+
+ OMAPLFBInitBufferForSwap(&psBuffer[i]);
+ }
+
+ if (OMAPLFBCreateSwapQueue(psSwapChain) != OMAPLFB_OK)
+ {
+ printk(KERN_WARNING DRIVER_PREFIX ": %s: Device %u: Failed to create workqueue\n", __FUNCTION__, psDevInfo->uiFBDevID);
+ eError = PVRSRV_ERROR_UNABLE_TO_INSTALL_ISR;
+ goto ErrorFreeBuffers;
+ }
+
+ if (OMAPLFBEnableLFBEventNotification(psDevInfo)!= OMAPLFB_OK)
+ {
+ eError = PVRSRV_ERROR_UNABLE_TO_ENABLE_EVENT;
+ printk(KERN_WARNING DRIVER_PREFIX ": %s: Device %u: Couldn't enable framebuffer event notification\n", __FUNCTION__, psDevInfo->uiFBDevID);
+ goto ErrorDestroySwapQueue;
+ }
+
+ psDevInfo->uiSwapChainID++;
+ if (psDevInfo->uiSwapChainID == 0)
+ {
+ psDevInfo->uiSwapChainID++;
+ }
+
+ psSwapChain->uiSwapChainID = psDevInfo->uiSwapChainID;
+
+ psDevInfo->psSwapChain = psSwapChain;
+
+ *pui32SwapChainID = psDevInfo->uiSwapChainID;
+
+ *phSwapChain = (IMG_HANDLE)psSwapChain;
+
+ eError = PVRSRV_OK;
+ goto ExitUnLock;
+
+ErrorDestroySwapQueue:
+ OMAPLFBDestroySwapQueue(psSwapChain);
+ErrorFreeBuffers:
+ OMAPLFBFreeKernelMem(psBuffer);
+ErrorFreeSwapChain:
+ OMAPLFBFreeKernelMem(psSwapChain);
+ExitUnLock:
+ OMAPLFBCreateSwapChainUnLock(psDevInfo);
+ return eError;
+}
+
+/*
+ * DestroyDCSwapChain
+ * Called from services.
+ */
+static PVRSRV_ERROR DestroyDCSwapChain(IMG_HANDLE hDevice,
+ IMG_HANDLE hSwapChain)
+{
+ OMAPLFB_DEVINFO *psDevInfo;
+ OMAPLFB_SWAPCHAIN *psSwapChain;
+ OMAPLFB_ERROR eError;
+
+ /* Check parameters */
+ if(!hDevice || !hSwapChain)
+ {
+ return PVRSRV_ERROR_INVALID_PARAMS;
+ }
+
+ psDevInfo = (OMAPLFB_DEVINFO*)hDevice;
+ psSwapChain = (OMAPLFB_SWAPCHAIN*)hSwapChain;
+
+ OMAPLFBCreateSwapChainLock(psDevInfo);
+
+ if (SwapChainHasChanged(psDevInfo, psSwapChain))
+ {
+ printk(KERN_WARNING DRIVER_PREFIX
+ ": %s: Device %u: Swap chain mismatch\n", __FUNCTION__, psDevInfo->uiFBDevID);
+
+ eError = PVRSRV_ERROR_INVALID_PARAMS;
+ goto ExitUnLock;
+ }
+
+ /* The swap queue is flushed before being destroyed */
+ OMAPLFBDestroySwapQueue(psSwapChain);
+
+ eError = OMAPLFBDisableLFBEventNotification(psDevInfo);
+ if (eError != OMAPLFB_OK)
+ {
+ printk(KERN_WARNING DRIVER_PREFIX ": %s: Device %u: Couldn't disable framebuffer event notification\n", __FUNCTION__, psDevInfo->uiFBDevID);
+ }
+
+ /* Free resources */
+ OMAPLFBFreeKernelMem(psSwapChain->psBuffer);
+ OMAPLFBFreeKernelMem(psSwapChain);
+
+ psDevInfo->psSwapChain = NULL;
+
+ OMAPLFBFlip(psDevInfo, &psDevInfo->sSystemBuffer);
+ (void) OMAPLFBCheckModeAndSync(psDevInfo);
+
+ eError = PVRSRV_OK;
+
+ExitUnLock:
+ OMAPLFBCreateSwapChainUnLock(psDevInfo);
+
+ return eError;
+}
+
+/*
+ * SetDCDstRect
+ * Called from services.
+ */
+static PVRSRV_ERROR SetDCDstRect(IMG_HANDLE hDevice,
+ IMG_HANDLE hSwapChain,
+ IMG_RECT *psRect)
+{
+ UNREFERENCED_PARAMETER(hDevice);
+ UNREFERENCED_PARAMETER(hSwapChain);
+ UNREFERENCED_PARAMETER(psRect);
+
+ /* Only full display swapchains on this device */
+
+ return PVRSRV_ERROR_NOT_SUPPORTED;
+}
+
+/*
+ * SetDCSrcRect
+ * Called from services.
+ */
+static PVRSRV_ERROR SetDCSrcRect(IMG_HANDLE hDevice,
+ IMG_HANDLE hSwapChain,
+ IMG_RECT *psRect)
+{
+ UNREFERENCED_PARAMETER(hDevice);
+ UNREFERENCED_PARAMETER(hSwapChain);
+ UNREFERENCED_PARAMETER(psRect);
+
+ /* Only full display swapchains on this device */
+
+ return PVRSRV_ERROR_NOT_SUPPORTED;
+}
+
+/*
+ * SetDCDstColourKey
+ * Called from services.
+ */
+static PVRSRV_ERROR SetDCDstColourKey(IMG_HANDLE hDevice,
+ IMG_HANDLE hSwapChain,
+ IMG_UINT32 ui32CKColour)
+{
+ UNREFERENCED_PARAMETER(hDevice);
+ UNREFERENCED_PARAMETER(hSwapChain);
+ UNREFERENCED_PARAMETER(ui32CKColour);
+
+ /* Don't support DST CK on this device */
+
+ return PVRSRV_ERROR_NOT_SUPPORTED;
+}
+
+/*
+ * SetDCSrcColourKey
+ * Called from services.
+ */
+static PVRSRV_ERROR SetDCSrcColourKey(IMG_HANDLE hDevice,
+ IMG_HANDLE hSwapChain,
+ IMG_UINT32 ui32CKColour)
+{
+ UNREFERENCED_PARAMETER(hDevice);
+ UNREFERENCED_PARAMETER(hSwapChain);
+ UNREFERENCED_PARAMETER(ui32CKColour);
+
+ /* Don't support SRC CK on this device */
+
+ return PVRSRV_ERROR_NOT_SUPPORTED;
+}
+
+/*
+ * GetDCBuffers
+ * Called from services.
+ */
+static PVRSRV_ERROR GetDCBuffers(IMG_HANDLE hDevice,
+ IMG_HANDLE hSwapChain,
+ IMG_UINT32 *pui32BufferCount,
+ IMG_HANDLE *phBuffer)
+{
+ OMAPLFB_DEVINFO *psDevInfo;
+ OMAPLFB_SWAPCHAIN *psSwapChain;
+ PVRSRV_ERROR eError;
+ unsigned i;
+
+ /* Check parameters */
+ if(!hDevice
+ || !hSwapChain
+ || !pui32BufferCount
+ || !phBuffer)
+ {
+ return PVRSRV_ERROR_INVALID_PARAMS;
+ }
+
+ psDevInfo = (OMAPLFB_DEVINFO*)hDevice;
+ psSwapChain = (OMAPLFB_SWAPCHAIN*)hSwapChain;
+
+ OMAPLFBCreateSwapChainLock(psDevInfo);
+
+ if (SwapChainHasChanged(psDevInfo, psSwapChain))
+ {
+ printk(KERN_WARNING DRIVER_PREFIX
+ ": %s: Device %u: Swap chain mismatch\n", __FUNCTION__, psDevInfo->uiFBDevID);
+
+ eError = PVRSRV_ERROR_INVALID_PARAMS;
+ goto Exit;
+ }
+
+ /* Return the buffer count */
+ *pui32BufferCount = (IMG_UINT32)psSwapChain->ulBufferCount;
+
+ /* Return the buffers */
+ for(i=0; i<psSwapChain->ulBufferCount; i++)
+ {
+ phBuffer[i] = (IMG_HANDLE)&psSwapChain->psBuffer[i];
+ }
+
+ eError = PVRSRV_OK;
+
+Exit:
+ OMAPLFBCreateSwapChainUnLock(psDevInfo);
+
+ return eError;
+}
+
+/*
+ * SwapToDCBuffer
+ * Called from services.
+ */
+static PVRSRV_ERROR SwapToDCBuffer(IMG_HANDLE hDevice,
+ IMG_HANDLE hBuffer,
+ IMG_UINT32 ui32SwapInterval,
+ IMG_HANDLE hPrivateTag,
+ IMG_UINT32 ui32ClipRectCount,
+ IMG_RECT *psClipRect)
+{
+ UNREFERENCED_PARAMETER(hDevice);
+ UNREFERENCED_PARAMETER(hBuffer);
+ UNREFERENCED_PARAMETER(ui32SwapInterval);
+ UNREFERENCED_PARAMETER(hPrivateTag);
+ UNREFERENCED_PARAMETER(ui32ClipRectCount);
+ UNREFERENCED_PARAMETER(psClipRect);
+
+ /* * Nothing to do since Services common code does the work */
+
+ return PVRSRV_OK;
+}
+
+/*
+ * Called after the screen has unblanked, or after any other occasion
+ * when we didn't wait for vsync, but now need to. Not doing this after
+ * unblank leads to screen jitter on some screens.
+ * Returns true if the screen has been deemed to have settled.
+ */
+static OMAPLFB_BOOL WaitForVSyncSettle(OMAPLFB_DEVINFO *psDevInfo)
+{
+ unsigned i;
+ for(i = 0; i < OMAPLFB_VSYNC_SETTLE_COUNT; i++)
+ {
+ if (DontWaitForVSync(psDevInfo) || !OMAPLFBWaitForVSync(psDevInfo))
+ {
+ return OMAPLFB_FALSE;
+ }
+ }
+
+ return OMAPLFB_TRUE;
+}
+
+/*
+ * Swap handler.
+ * Called from the swap chain work queue handler.
+ * There is no need to take the swap chain creation lock in here, or use
+ * some other method of stopping the swap chain from being destroyed.
+ * This is because the swap chain creation lock is taken when queueing work,
+ * and the work queue is flushed before the swap chain is destroyed.
+ */
+void OMAPLFBSwapHandler(OMAPLFB_BUFFER *psBuffer)
+{
+ OMAPLFB_DEVINFO *psDevInfo = psBuffer->psDevInfo;
+ OMAPLFB_SWAPCHAIN *psSwapChain = psDevInfo->psSwapChain;
+ OMAPLFB_BOOL bPreviouslyNotVSynced;
+
+#if defined(SUPPORT_DRI_DRM)
+ if (!OMAPLFBAtomicBoolRead(&psDevInfo->sLeaveVT))
+#endif
+ {
+ OMAPLFBFlip(psDevInfo, psBuffer);
+ }
+
+ bPreviouslyNotVSynced = psSwapChain->bNotVSynced;
+ psSwapChain->bNotVSynced = OMAPLFB_TRUE;
+
+
+ if (!DontWaitForVSync(psDevInfo))
+ {
+ OMAPLFB_UPDATE_MODE eMode = OMAPLFBGetUpdateMode(psDevInfo);
+ int iBlankEvents = OMAPLFBAtomicIntRead(&psDevInfo->sBlankEvents);
+
+ switch(eMode)
+ {
+ case OMAPLFB_UPDATE_MODE_AUTO:
+ psSwapChain->bNotVSynced = OMAPLFB_FALSE;
+
+ if (bPreviouslyNotVSynced || psSwapChain->iBlankEvents != iBlankEvents)
+ {
+ psSwapChain->iBlankEvents = iBlankEvents;
+ psSwapChain->bNotVSynced = !WaitForVSyncSettle(psDevInfo);
+ } else if (psBuffer->ulSwapInterval != 0)
+ {
+ psSwapChain->bNotVSynced = !OMAPLFBWaitForVSync(psDevInfo);
+ }
+ break;
+#if defined(PVR_OMAPFB3_MANUAL_UPDATE_SYNC_IN_SWAP)
+ case OMAPLFB_UPDATE_MODE_MANUAL:
+ if (psBuffer->ulSwapInterval != 0)
+ {
+ (void) OMAPLFBManualSync(psDevInfo);
+ }
+ break;
+#endif
+ default:
+ break;
+ }
+ }
+
+ psDevInfo->sPVRJTable.pfnPVRSRVCmdComplete((IMG_HANDLE)psBuffer->hCmdComplete, IMG_TRUE);
+}
+
+/* Triggered by PVRSRVSwapToDCBuffer */
+static IMG_BOOL ProcessFlipV1(IMG_HANDLE hCmdCookie,
+ OMAPLFB_DEVINFO *psDevInfo,
+ OMAPLFB_SWAPCHAIN *psSwapChain,
+ OMAPLFB_BUFFER *psBuffer,
+ unsigned long ulSwapInterval)
+{
+ OMAPLFBCreateSwapChainLock(psDevInfo);
+
+ /* The swap chain has been destroyed */
+ if (SwapChainHasChanged(psDevInfo, psSwapChain))
+ {
+ DEBUG_PRINTK((KERN_WARNING DRIVER_PREFIX
+ ": %s: Device %u (PVR Device ID %u): The swap chain has been destroyed\n",
+ __FUNCTION__, psDevInfo->uiFBDevID, psDevInfo->uiPVRDevID));
+ }
+ else
+ {
+ psBuffer->hCmdComplete = (OMAPLFB_HANDLE)hCmdCookie;
+ psBuffer->ulSwapInterval = ulSwapInterval;
+#if defined(CONFIG_DSSCOMP)
+ if (is_tiler_addr(psBuffer->sSysAddr.uiAddr))
+ {
+ IMG_UINT32 w = psBuffer->psDevInfo->sDisplayDim.ui32Width;
+ IMG_UINT32 h = psBuffer->psDevInfo->sDisplayDim.ui32Height;
+ struct dsscomp_setup_dispc_data comp = {
+ .num_mgrs = 1,
+ .mgrs[0].alpha_blending = 1,
+ .num_ovls = 1,
+ .ovls[0].cfg =
+ {
+ .width = w,
+ .win.w = w,
+ .crop.w = w,
+ .height = h,
+ .win.h = h,
+ .crop.h = h,
+ .stride = psBuffer->psDevInfo->sDisplayDim.ui32ByteStride,
+ .color_mode = OMAP_DSS_COLOR_ARGB32,
+ .enabled = 1,
+ .global_alpha = 255,
+ },
+ .mode = DSSCOMP_SETUP_DISPLAY,
+ };
+ struct tiler_pa_info *pas[1] = { NULL };
+ comp.ovls[0].ba = (u32) psBuffer->sSysAddr.uiAddr;
+ dsscomp_gralloc_queue(&comp, pas, true,
+ (void *) psDevInfo->sPVRJTable.pfnPVRSRVCmdComplete,
+ (void *) psBuffer->hCmdComplete);
+ }
+ else
+#endif /* defined(CONFIG_DSSCOMP) */
+ {
+ OMAPLFBQueueBufferForSwap(psSwapChain, psBuffer);
+ }
+ }
+
+ OMAPLFBCreateSwapChainUnLock(psDevInfo);
+
+ return IMG_TRUE;
+}
+
+#if defined(CONFIG_DSSCOMP)
+
+/* Triggered by PVRSRVSwapToDCBuffer2 */
+static IMG_BOOL ProcessFlipV2(IMG_HANDLE hCmdCookie,
+ OMAPLFB_DEVINFO *psDevInfo,
+ PDC_MEM_INFO *ppsMemInfos,
+ IMG_UINT32 ui32NumMemInfos,
+ struct dsscomp_setup_dispc_data *psDssData,
+ IMG_UINT32 ui32DssDataLength)
+{
+ struct tiler_pa_info *apsTilerPAs[5];
+ IMG_UINT32 i, k;
+
+ if(ui32DssDataLength != sizeof(*psDssData))
+ {
+ WARN(1, "invalid size of private data (%d vs %d)",
+ ui32DssDataLength, sizeof(*psDssData));
+ return IMG_FALSE;
+ }
+
+ if(psDssData->num_ovls == 0 || ui32NumMemInfos == 0)
+ {
+ WARN(1, "must have at least one layer");
+ return IMG_FALSE;
+ }
+
+ for(i = k = 0; i < ui32NumMemInfos && k < ARRAY_SIZE(apsTilerPAs); i++, k++)
+ {
+ struct tiler_pa_info *psTilerInfo;
+ IMG_CPU_VIRTADDR virtAddr;
+ IMG_CPU_PHYADDR phyAddr;
+ IMG_UINT32 ui32NumPages;
+ IMG_SIZE_T uByteSize;
+ int j;
+
+ psDevInfo->sPVRJTable.pfnPVRSRVDCMemInfoGetByteSize(ppsMemInfos[i], &uByteSize);
+ ui32NumPages = (uByteSize + PAGE_SIZE - 1) >> PAGE_SHIFT;
+
+ apsTilerPAs[k] = NULL;
+
+ psDevInfo->sPVRJTable.pfnPVRSRVDCMemInfoGetCpuPAddr(ppsMemInfos[i], 0, &phyAddr);
+
+ /* NV12 buffers are already mapped to tiler */
+ if(psDssData->ovls[k].cfg.color_mode == OMAP_DSS_COLOR_NV12)
+ {
+ psDssData->ovls[k].ba = (u32)phyAddr.uiAddr;
+
+ psDevInfo->sPVRJTable.pfnPVRSRVDCMemInfoGetCpuPAddr(ppsMemInfos[i], (uByteSize * 2) / 3, &phyAddr);
+ psDssData->ovls[k].uv = (u32)phyAddr.uiAddr;
+ continue;
+ }
+
+ /* Other kinds of buffer may also already be mapped to tiler */
+ if(is_tiler_addr((u32)phyAddr.uiAddr))
+ {
+ psDssData->ovls[k].ba = (u32)phyAddr.uiAddr;
+ continue;
+ }
+
+ psTilerInfo = kzalloc(sizeof(*psTilerInfo), GFP_KERNEL);
+ if(!psTilerInfo)
+ {
+ continue;
+ }
+
+ psTilerInfo->mem = kzalloc(sizeof(*psTilerInfo->mem) * ui32NumPages, GFP_KERNEL);
+ if(!psTilerInfo->mem)
+ {
+ kfree(psTilerInfo);
+ continue;
+ }
+
+ psTilerInfo->num_pg = ui32NumPages;
+ psTilerInfo->memtype = TILER_MEM_USING;
+
+ for(j = 0; j < ui32NumPages; j++)
+ {
+ psDevInfo->sPVRJTable.pfnPVRSRVDCMemInfoGetCpuPAddr(ppsMemInfos[i], j << PAGE_SHIFT, &phyAddr);
+ psTilerInfo->mem[j] = (u32)phyAddr.uiAddr;
+ }
+
+ /* Need base address for in-page offset */
+ psDevInfo->sPVRJTable.pfnPVRSRVDCMemInfoGetCpuVAddr(ppsMemInfos[i], &virtAddr);
+ psDssData->ovls[k].ba = (u32)virtAddr;
+ apsTilerPAs[k] = psTilerInfo;
+ }
+
+ /* Set up cloned layer addresses (but don't duplicate tiler_pas) */
+ for(i = k; i < psDssData->num_ovls && i < ARRAY_SIZE(apsTilerPAs); i++)
+ {
+ unsigned int ix = psDssData->ovls[i].ba;
+ if(ix >= ARRAY_SIZE(apsTilerPAs))
+ {
+ WARN(1, "Invalid clone layer (%u); skipping all cloned layers", ix);
+ psDssData->num_ovls = k;
+ break;
+ }
+ apsTilerPAs[i] = apsTilerPAs[ix];
+ psDssData->ovls[i].ba = psDssData->ovls[ix].ba;
+ psDssData->ovls[i].uv = psDssData->ovls[ix].uv;
+ }
+
+ dsscomp_gralloc_queue(psDssData, apsTilerPAs, false,
+ (void *)psDevInfo->sPVRJTable.pfnPVRSRVCmdComplete,
+ (void *)hCmdCookie);
+
+ for(i = 0; i < k; i++)
+ {
+ tiler_pa_free(apsTilerPAs[i]);
+ }
+
+ return IMG_TRUE;
+}
+
+#endif /* defined(CONFIG_DSSCOMP) */
+
+/* Command processing flip handler function. Called from services. */
+static IMG_BOOL ProcessFlip(IMG_HANDLE hCmdCookie,
+ IMG_UINT32 ui32DataSize,
+ IMG_VOID *pvData)
+{
+ DISPLAYCLASS_FLIP_COMMAND *psFlipCmd;
+ OMAPLFB_DEVINFO *psDevInfo;
+
+ /* Check parameters */
+ if(!hCmdCookie || !pvData)
+ {
+ return IMG_FALSE;
+ }
+
+ /* Validate data packet */
+ psFlipCmd = (DISPLAYCLASS_FLIP_COMMAND*)pvData;
+
+ if (psFlipCmd == IMG_NULL)
+ {
+ return IMG_FALSE;
+ }
+
+ psDevInfo = (OMAPLFB_DEVINFO*)psFlipCmd->hExtDevice;
+
+ if(psFlipCmd->hExtBuffer)
+ {
+ return ProcessFlipV1(hCmdCookie,
+ psDevInfo,
+ psFlipCmd->hExtSwapChain,
+ psFlipCmd->hExtBuffer,
+ psFlipCmd->ui32SwapInterval);
+ }
+ else
+ {
+#if defined(CONFIG_DSSCOMP)
+ DISPLAYCLASS_FLIP_COMMAND2 *psFlipCmd2;
+ psFlipCmd2 = (DISPLAYCLASS_FLIP_COMMAND2 *)pvData;
+ return ProcessFlipV2(hCmdCookie,
+ psDevInfo,
+ psFlipCmd2->ppsMemInfos,
+ psFlipCmd2->ui32NumMemInfos,
+ psFlipCmd2->pvPrivData,
+ psFlipCmd2->ui32PrivDataLength);
+#else
+ BUG();
+#endif
+ }
+}
+
+/*!
+******************************************************************************
+
+ @Function OMAPLFBInitFBDev
+
+ @Description specifies devices in the systems memory map
+
+ @Input psSysData - sys data
+
+ @Return OMAPLFB_ERROR :
+
+******************************************************************************/
+static OMAPLFB_ERROR OMAPLFBInitFBDev(OMAPLFB_DEVINFO *psDevInfo)
+{
+ struct fb_info *psLINFBInfo;
+ struct module *psLINFBOwner;
+ OMAPLFB_FBINFO *psPVRFBInfo = &psDevInfo->sFBInfo;
+ OMAPLFB_ERROR eError = OMAPLFB_ERROR_GENERIC;
+ unsigned long FBSize;
+ unsigned long ulLCM;
+ unsigned uiFBDevID = psDevInfo->uiFBDevID;
+
+ OMAPLFB_CONSOLE_LOCK();
+
+ psLINFBInfo = registered_fb[uiFBDevID];
+ if (psLINFBInfo == NULL)
+ {
+ eError = OMAPLFB_ERROR_INVALID_DEVICE;
+ goto ErrorRelSem;
+ }
+
+ FBSize = (psLINFBInfo->screen_size) != 0 ?
+ psLINFBInfo->screen_size :
+ psLINFBInfo->fix.smem_len;
+
+ /*
+ * Try and filter out invalid FB info structures (a problem
+ * seen on some OMAP3 systems).
+ */
+ if (FBSize == 0 || psLINFBInfo->fix.line_length == 0)
+ {
+ eError = OMAPLFB_ERROR_INVALID_DEVICE;
+ goto ErrorRelSem;
+ }
+
+ psLINFBOwner = psLINFBInfo->fbops->owner;
+ if (!try_module_get(psLINFBOwner))
+ {
+ printk(KERN_INFO DRIVER_PREFIX
+ ": %s: Device %u: Couldn't get framebuffer module\n", __FUNCTION__, uiFBDevID);
+
+ goto ErrorRelSem;
+ }
+
+ if (psLINFBInfo->fbops->fb_open != NULL)
+ {
+ int res;
+
+ res = psLINFBInfo->fbops->fb_open(psLINFBInfo, 0);
+ if (res != 0)
+ {
+ printk(KERN_INFO DRIVER_PREFIX
+ " %s: Device %u: Couldn't open framebuffer(%d)\n", __FUNCTION__, uiFBDevID, res);
+
+ goto ErrorModPut;
+ }
+ }
+
+ psDevInfo->psLINFBInfo = psLINFBInfo;
+
+ ulLCM = LCM(psLINFBInfo->fix.line_length, OMAPLFB_PAGE_SIZE);
+
+ DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX
+ ": Device %u: Framebuffer physical address: 0x%lx\n",
+ psDevInfo->uiFBDevID, psLINFBInfo->fix.smem_start));
+ DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX
+ ": Device %u: Framebuffer virtual address: 0x%lx\n",
+ psDevInfo->uiFBDevID, (unsigned long)psLINFBInfo->screen_base));
+ DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX
+ ": Device %u: Framebuffer size: %lu\n",
+ psDevInfo->uiFBDevID, FBSize));
+ DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX
+ ": Device %u: Framebuffer virtual width: %u\n",
+ psDevInfo->uiFBDevID, psLINFBInfo->var.xres_virtual));
+ DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX
+ ": Device %u: Framebuffer virtual height: %u\n",
+ psDevInfo->uiFBDevID, psLINFBInfo->var.yres_virtual));
+ DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX
+ ": Device %u: Framebuffer width: %u\n",
+ psDevInfo->uiFBDevID, psLINFBInfo->var.xres));
+ DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX
+ ": Device %u: Framebuffer height: %u\n",
+ psDevInfo->uiFBDevID, psLINFBInfo->var.yres));
+ DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX
+ ": Device %u: Framebuffer stride: %u\n",
+ psDevInfo->uiFBDevID, psLINFBInfo->fix.line_length));
+ DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX
+ ": Device %u: LCM of stride and page size: %lu\n",
+ psDevInfo->uiFBDevID, ulLCM));
+
+ /* Additional implementation specific information */
+ OMAPLFBPrintInfo(psDevInfo);
+
+#if defined(CONFIG_DSSCOMP)
+ {
+ /* for some reason we need at least 3 buffers in the swap chain */
+ int n = FBSize / RoundUpToMultiple(psLINFBInfo->fix.line_length * psLINFBInfo->var.yres, ulLCM);
+ int res;
+ int i, x, y, w;
+ ion_phys_addr_t phys;
+ size_t size;
+ struct tiler_view_t view;
+
+ struct omap_ion_tiler_alloc_data sAllocData =
+ {
+ /* TILER will align width to 128-bytes */
+ /* however, SGX must have full page width */
+ .w = ALIGN(psLINFBInfo->var.xres, PAGE_SIZE / (psLINFBInfo->var.bits_per_pixel / 8)),
+ .h = psLINFBInfo->var.yres,
+ .fmt = psLINFBInfo->var.bits_per_pixel == 16 ? TILER_PIXEL_FMT_16BIT : TILER_PIXEL_FMT_32BIT,
+ .flags = 0,
+ };
+
+ printk(KERN_DEBUG DRIVER_PREFIX
+ " %s: Device %u: Requesting %d TILER 2D framebuffers\n",
+ __FUNCTION__, uiFBDevID, n);
+
+ /* INTEGRATION_POINT: limit to MAX 3 FBs to save TILER container space */
+ if (n != 3)
+ n = 3;
+
+ sAllocData.w *= n;
+
+ psPVRFBInfo->uiBytesPerPixel = psLINFBInfo->var.bits_per_pixel >> 3;
+ psPVRFBInfo->bIs2D = OMAPLFB_TRUE;
+
+ res = omap_ion_tiler_alloc(gpsIONClient, &sAllocData);
+ psPVRFBInfo->psIONHandle = sAllocData.handle;
+ if (res < 0)
+ {
+ printk(KERN_ERR DRIVER_PREFIX
+ " %s: Device %u: Could not allocate 2D framebuffer(%d)\n",
+ __FUNCTION__, uiFBDevID, res);
+ goto ErrorModPut;
+ }
+
+ psLINFBInfo->fix.smem_start = ion_phys(gpsIONClient, sAllocData.handle, &phys, &size);
+
+ psPVRFBInfo->sSysAddr.uiAddr = phys;
+ psPVRFBInfo->sCPUVAddr = 0;
+ psPVRFBInfo->ulWidth = psLINFBInfo->var.xres;
+ psPVRFBInfo->ulHeight = psLINFBInfo->var.yres;
+
+ psPVRFBInfo->ulByteStride = PAGE_ALIGN(psPVRFBInfo->ulWidth * psPVRFBInfo->uiBytesPerPixel);
+ w = psPVRFBInfo->ulByteStride >> PAGE_SHIFT;
+
+ /* this is an "effective" FB size to get correct number of buffers */
+ psPVRFBInfo->ulFBSize = sAllocData.h * n * psPVRFBInfo->ulByteStride;
+ psPVRFBInfo->psPageList = kzalloc(w * n * psPVRFBInfo->ulHeight * sizeof(*psPVRFBInfo->psPageList), GFP_KERNEL);
+ if (!psPVRFBInfo->psPageList)
+ {
+ printk(KERN_WARNING DRIVER_PREFIX ": %s: Device %u: Could not allocate page list\n", __FUNCTION__, psDevInfo->uiFBDevID);
+ ion_free(gpsIONClient, sAllocData.handle);
+ goto ErrorModPut;
+ }
+
+ tilview_create(&view, phys, psDevInfo->sFBInfo.ulWidth, psDevInfo->sFBInfo.ulHeight);
+ for(i = 0; i < n; i++)
+ {
+ for(y = 0; y < psDevInfo->sFBInfo.ulHeight; y++)
+ {
+ for(x = 0; x < w; x++)
+ {
+ psPVRFBInfo->psPageList[i * psDevInfo->sFBInfo.ulHeight * w + y * w + x].uiAddr =
+ phys + view.v_inc * y + ((x + i * w) << PAGE_SHIFT);
+ }
+ }
+ }
+ }
+#else /* defined(CONFIG_DSSCOMP) */
+ /* System Surface */
+ psPVRFBInfo->sSysAddr.uiAddr = psLINFBInfo->fix.smem_start;
+ psPVRFBInfo->sCPUVAddr = psLINFBInfo->screen_base;
+
+ psPVRFBInfo->ulWidth = psLINFBInfo->var.xres;
+ psPVRFBInfo->ulHeight = psLINFBInfo->var.yres;
+ psPVRFBInfo->ulByteStride = psLINFBInfo->fix.line_length;
+ psPVRFBInfo->ulFBSize = FBSize;
+#endif /* defined(CONFIG_DSSCOMP) */
+
+ psPVRFBInfo->ulBufferSize = psPVRFBInfo->ulHeight * psPVRFBInfo->ulByteStride;
+
+ /* Round the buffer size up to a multiple of the number of pages
+ * and the byte stride.
+ * This is used internally, to ensure buffers start on page
+ * boundaries, for the benefit of PVR Services.
+ */
+ psPVRFBInfo->ulRoundedBufferSize = RoundUpToMultiple(psPVRFBInfo->ulBufferSize, ulLCM);
+
+ if(psLINFBInfo->var.bits_per_pixel == 16)
+ {
+ if((psLINFBInfo->var.red.length == 5) &&
+ (psLINFBInfo->var.green.length == 6) &&
+ (psLINFBInfo->var.blue.length == 5) &&
+ (psLINFBInfo->var.red.offset == 11) &&
+ (psLINFBInfo->var.green.offset == 5) &&
+ (psLINFBInfo->var.blue.offset == 0) &&
+ (psLINFBInfo->var.red.msb_right == 0))
+ {
+ psPVRFBInfo->ePixelFormat = PVRSRV_PIXEL_FORMAT_RGB565;
+ }
+ else
+ {
+ printk(KERN_INFO DRIVER_PREFIX ": %s: Device %u: Unknown FB format\n", __FUNCTION__, uiFBDevID);
+ }
+ }
+ else if(psLINFBInfo->var.bits_per_pixel == 32)
+ {
+ if((psLINFBInfo->var.red.length == 8) &&
+ (psLINFBInfo->var.green.length == 8) &&
+ (psLINFBInfo->var.blue.length == 8) &&
+ (psLINFBInfo->var.red.offset == 16) &&
+ (psLINFBInfo->var.green.offset == 8) &&
+ (psLINFBInfo->var.blue.offset == 0) &&
+ (psLINFBInfo->var.red.msb_right == 0))
+ {
+ psPVRFBInfo->ePixelFormat = PVRSRV_PIXEL_FORMAT_ARGB8888;
+ }
+ else
+ {
+ printk(KERN_INFO DRIVER_PREFIX ": %s: Device %u: Unknown FB format\n", __FUNCTION__, uiFBDevID);
+ }
+ }
+ else
+ {
+ printk(KERN_INFO DRIVER_PREFIX ": %s: Device %u: Unknown FB format\n", __FUNCTION__, uiFBDevID);
+ }
+
+ psDevInfo->sFBInfo.ulPhysicalWidthmm =
+ ((int)psLINFBInfo->var.width > 0) ? psLINFBInfo->var.width : 90;
+
+ psDevInfo->sFBInfo.ulPhysicalHeightmm =
+ ((int)psLINFBInfo->var.height > 0) ? psLINFBInfo->var.height : 54;
+
+ /* System Surface */
+ psDevInfo->sFBInfo.sSysAddr.uiAddr = psPVRFBInfo->sSysAddr.uiAddr;
+ psDevInfo->sFBInfo.sCPUVAddr = psPVRFBInfo->sCPUVAddr;
+
+ eError = OMAPLFB_OK;
+ goto ErrorRelSem;
+
+ErrorModPut:
+ module_put(psLINFBOwner);
+ErrorRelSem:
+ OMAPLFB_CONSOLE_UNLOCK();
+
+ return eError;
+}
+
+static void OMAPLFBDeInitFBDev(OMAPLFB_DEVINFO *psDevInfo)
+{
+ struct fb_info *psLINFBInfo = psDevInfo->psLINFBInfo;
+ struct module *psLINFBOwner;
+
+ OMAPLFB_CONSOLE_LOCK();
+
+#if defined(CONFIG_DSSCOMP)
+ {
+ OMAPLFB_FBINFO *psPVRFBInfo = &psDevInfo->sFBInfo;
+ kfree(psPVRFBInfo->psPageList);
+ if (psPVRFBInfo->psIONHandle)
+ {
+ ion_free(gpsIONClient, psPVRFBInfo->psIONHandle);
+ }
+ }
+#endif /* defined(CONFIG_DSSCOMP) */
+
+ psLINFBOwner = psLINFBInfo->fbops->owner;
+
+ if (psLINFBInfo->fbops->fb_release != NULL)
+ {
+ (void) psLINFBInfo->fbops->fb_release(psLINFBInfo, 0);
+ }
+
+ module_put(psLINFBOwner);
+
+ OMAPLFB_CONSOLE_UNLOCK();
+}
+
+static OMAPLFB_DEVINFO *OMAPLFBInitDev(unsigned uiFBDevID)
+{
+ PFN_CMD_PROC pfnCmdProcList[OMAPLFB_COMMAND_COUNT];
+ IMG_UINT32 aui32SyncCountList[OMAPLFB_COMMAND_COUNT][2];
+ OMAPLFB_DEVINFO *psDevInfo = NULL;
+
+ /* Allocate device info. structure */
+ psDevInfo = (OMAPLFB_DEVINFO *)OMAPLFBAllocKernelMem(sizeof(OMAPLFB_DEVINFO));
+
+ if(psDevInfo == NULL)
+ {
+ printk(KERN_ERR DRIVER_PREFIX
+ ": %s: Device %u: Couldn't allocate device information structure\n", __FUNCTION__, uiFBDevID);
+
+ goto ErrorExit;
+ }
+
+ /* Any fields not set will be zero */
+ memset(psDevInfo, 0, sizeof(OMAPLFB_DEVINFO));
+
+ psDevInfo->uiFBDevID = uiFBDevID;
+
+ /* Get the kernel services function table */
+ if(!(*gpfnGetPVRJTable)(&psDevInfo->sPVRJTable))
+ {
+ goto ErrorFreeDevInfo;
+ }
+
+ /* Save private fbdev information structure in the dev. info. */
+ if(OMAPLFBInitFBDev(psDevInfo) != OMAPLFB_OK)
+ {
+ /*
+ * Leave it to OMAPLFBInitFBDev to print an error message, if
+ * required. The function may have failed because
+ * there is no Linux framebuffer device corresponding
+ * to the device ID.
+ */
+ goto ErrorFreeDevInfo;
+ }
+
+ psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers = (IMG_UINT32)(psDevInfo->sFBInfo.ulFBSize / psDevInfo->sFBInfo.ulRoundedBufferSize);
+ if (psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers != 0)
+ {
+ psDevInfo->sDisplayInfo.ui32MaxSwapChains = 1;
+ psDevInfo->sDisplayInfo.ui32MaxSwapInterval = 1;
+ }
+
+ psDevInfo->sDisplayInfo.ui32PhysicalWidthmm = psDevInfo->sFBInfo.ulPhysicalWidthmm;
+ psDevInfo->sDisplayInfo.ui32PhysicalHeightmm = psDevInfo->sFBInfo.ulPhysicalHeightmm;
+
+ strncpy(psDevInfo->sDisplayInfo.szDisplayName, DISPLAY_DEVICE_NAME, MAX_DISPLAY_NAME_SIZE);
+
+ psDevInfo->sDisplayFormat.pixelformat = psDevInfo->sFBInfo.ePixelFormat;
+ psDevInfo->sDisplayDim.ui32Width = (IMG_UINT32)psDevInfo->sFBInfo.ulWidth;
+ psDevInfo->sDisplayDim.ui32Height = (IMG_UINT32)psDevInfo->sFBInfo.ulHeight;
+ psDevInfo->sDisplayDim.ui32ByteStride = (IMG_UINT32)psDevInfo->sFBInfo.ulByteStride;
+
+ DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX
+ ": Device %u: Maximum number of swap chain buffers: %u\n",
+ psDevInfo->uiFBDevID, psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers));
+
+ /* Setup system buffer */
+ psDevInfo->sSystemBuffer.sSysAddr = psDevInfo->sFBInfo.sSysAddr;
+ psDevInfo->sSystemBuffer.sCPUVAddr = psDevInfo->sFBInfo.sCPUVAddr;
+ psDevInfo->sSystemBuffer.psDevInfo = psDevInfo;
+
+ OMAPLFBInitBufferForSwap(&psDevInfo->sSystemBuffer);
+
+ /*
+ Setup the DC Jtable so SRVKM can call into this driver
+ */
+ psDevInfo->sDCJTable.ui32TableSize = sizeof(PVRSRV_DC_SRV2DISP_KMJTABLE);
+ psDevInfo->sDCJTable.pfnOpenDCDevice = OpenDCDevice;
+ psDevInfo->sDCJTable.pfnCloseDCDevice = CloseDCDevice;
+ psDevInfo->sDCJTable.pfnEnumDCFormats = EnumDCFormats;
+ psDevInfo->sDCJTable.pfnEnumDCDims = EnumDCDims;
+ psDevInfo->sDCJTable.pfnGetDCSystemBuffer = GetDCSystemBuffer;
+ psDevInfo->sDCJTable.pfnGetDCInfo = GetDCInfo;
+ psDevInfo->sDCJTable.pfnGetBufferAddr = GetDCBufferAddr;
+ psDevInfo->sDCJTable.pfnCreateDCSwapChain = CreateDCSwapChain;
+ psDevInfo->sDCJTable.pfnDestroyDCSwapChain = DestroyDCSwapChain;
+ psDevInfo->sDCJTable.pfnSetDCDstRect = SetDCDstRect;
+ psDevInfo->sDCJTable.pfnSetDCSrcRect = SetDCSrcRect;
+ psDevInfo->sDCJTable.pfnSetDCDstColourKey = SetDCDstColourKey;
+ psDevInfo->sDCJTable.pfnSetDCSrcColourKey = SetDCSrcColourKey;
+ psDevInfo->sDCJTable.pfnGetDCBuffers = GetDCBuffers;
+ psDevInfo->sDCJTable.pfnSwapToDCBuffer = SwapToDCBuffer;
+ psDevInfo->sDCJTable.pfnSetDCState = SetDCState;
+
+ /* Register device with services and retrieve device index */
+ if(psDevInfo->sPVRJTable.pfnPVRSRVRegisterDCDevice(
+ &psDevInfo->sDCJTable,
+ &psDevInfo->uiPVRDevID) != PVRSRV_OK)
+ {
+ printk(KERN_ERR DRIVER_PREFIX
+ ": %s: Device %u: PVR Services device registration failed\n", __FUNCTION__, uiFBDevID);
+
+ goto ErrorDeInitFBDev;
+ }
+ DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX
+ ": Device %u: PVR Device ID: %u\n",
+ psDevInfo->uiFBDevID, psDevInfo->uiPVRDevID));
+
+ /* Setup private command processing function table ... */
+ pfnCmdProcList[DC_FLIP_COMMAND] = ProcessFlip;
+
+ /* ... and associated sync count(s) */
+ aui32SyncCountList[DC_FLIP_COMMAND][0] = 0; /* writes */
+ aui32SyncCountList[DC_FLIP_COMMAND][1] = 10; /* reads */
+
+ /*
+ Register private command processing functions with
+ the Command Queue Manager and setup the general
+ command complete function in the devinfo.
+ */
+ if (psDevInfo->sPVRJTable.pfnPVRSRVRegisterCmdProcList(psDevInfo->uiPVRDevID,
+ &pfnCmdProcList[0],
+ aui32SyncCountList,
+ OMAPLFB_COMMAND_COUNT) != PVRSRV_OK)
+ {
+ printk(KERN_ERR DRIVER_PREFIX
+ ": %s: Device %u: Couldn't register command processing functions with PVR Services\n", __FUNCTION__, uiFBDevID);
+ goto ErrorUnregisterDevice;
+ }
+
+ OMAPLFBCreateSwapChainLockInit(psDevInfo);
+
+ OMAPLFBAtomicBoolInit(&psDevInfo->sBlanked, OMAPLFB_FALSE);
+ OMAPLFBAtomicIntInit(&psDevInfo->sBlankEvents, 0);
+ OMAPLFBAtomicBoolInit(&psDevInfo->sFlushCommands, OMAPLFB_FALSE);
+#if defined(CONFIG_HAS_EARLYSUSPEND)
+ OMAPLFBAtomicBoolInit(&psDevInfo->sEarlySuspendFlag, OMAPLFB_FALSE);
+#endif
+#if defined(SUPPORT_DRI_DRM)
+ OMAPLFBAtomicBoolInit(&psDevInfo->sLeaveVT, OMAPLFB_FALSE);
+#endif
+ return psDevInfo;
+
+ErrorUnregisterDevice:
+ (void)psDevInfo->sPVRJTable.pfnPVRSRVRemoveDCDevice(psDevInfo->uiPVRDevID);
+ErrorDeInitFBDev:
+ OMAPLFBDeInitFBDev(psDevInfo);
+ErrorFreeDevInfo:
+ OMAPLFBFreeKernelMem(psDevInfo);
+ErrorExit:
+ return NULL;
+}
+
+OMAPLFB_ERROR OMAPLFBInit(void)
+{
+ unsigned uiMaxFBDevIDPlusOne = OMAPLFBMaxFBDevIDPlusOne();
+ unsigned i;
+ unsigned uiDevicesFound = 0;
+
+ if(OMAPLFBGetLibFuncAddr ("PVRGetDisplayClassJTable", &gpfnGetPVRJTable) != OMAPLFB_OK)
+ {
+ return OMAPLFB_ERROR_INIT_FAILURE;
+ }
+
+ /*
+ * We search for frame buffer devices backwards, as the last device
+ * registered with PVR Services will be the first device enumerated
+ * by PVR Services.
+ */
+ for(i = uiMaxFBDevIDPlusOne; i-- != 0;)
+ {
+ OMAPLFB_DEVINFO *psDevInfo = OMAPLFBInitDev(i);
+
+ if (psDevInfo != NULL)
+ {
+ /* Set the top-level anchor */
+ OMAPLFBSetDevInfoPtr(psDevInfo->uiFBDevID, psDevInfo);
+ uiDevicesFound++;
+ }
+ }
+
+ return (uiDevicesFound != 0) ? OMAPLFB_OK : OMAPLFB_ERROR_INIT_FAILURE;
+}
+
+/*
+ * OMAPLFBDeInitDev
+ * DeInitialises one device
+ */
+static OMAPLFB_BOOL OMAPLFBDeInitDev(OMAPLFB_DEVINFO *psDevInfo)
+{
+ PVRSRV_DC_DISP2SRV_KMJTABLE *psPVRJTable = &psDevInfo->sPVRJTable;
+
+ OMAPLFBCreateSwapChainLockDeInit(psDevInfo);
+
+ OMAPLFBAtomicBoolDeInit(&psDevInfo->sBlanked);
+ OMAPLFBAtomicIntDeInit(&psDevInfo->sBlankEvents);
+ OMAPLFBAtomicBoolDeInit(&psDevInfo->sFlushCommands);
+#if defined(CONFIG_HAS_EARLYSUSPEND)
+ OMAPLFBAtomicBoolDeInit(&psDevInfo->sEarlySuspendFlag);
+#endif
+#if defined(SUPPORT_DRI_DRM)
+ OMAPLFBAtomicBoolDeInit(&psDevInfo->sLeaveVT);
+#endif
+ psPVRJTable = &psDevInfo->sPVRJTable;
+
+ if (psPVRJTable->pfnPVRSRVRemoveCmdProcList (psDevInfo->uiPVRDevID, OMAPLFB_COMMAND_COUNT) != PVRSRV_OK)
+ {
+ printk(KERN_ERR DRIVER_PREFIX
+ ": %s: Device %u: PVR Device %u: Couldn't unregister command processing functions\n", __FUNCTION__, psDevInfo->uiFBDevID, psDevInfo->uiPVRDevID);
+ return OMAPLFB_FALSE;
+ }
+
+ /*
+ * Remove display class device from kernel services device
+ * register.
+ */
+ if (psPVRJTable->pfnPVRSRVRemoveDCDevice(psDevInfo->uiPVRDevID) != PVRSRV_OK)
+ {
+ printk(KERN_ERR DRIVER_PREFIX
+ ": %s: Device %u: PVR Device %u: Couldn't remove device from PVR Services\n", __FUNCTION__, psDevInfo->uiFBDevID, psDevInfo->uiPVRDevID);
+ return OMAPLFB_FALSE;
+ }
+
+ OMAPLFBDeInitFBDev(psDevInfo);
+
+ OMAPLFBSetDevInfoPtr(psDevInfo->uiFBDevID, NULL);
+
+ /* De-allocate data structure */
+ OMAPLFBFreeKernelMem(psDevInfo);
+
+ return OMAPLFB_TRUE;
+}
+
+/*
+ * OMAPLFBDeInit
+ * Deinitialises the display class device component of the FBDev
+ */
+OMAPLFB_ERROR OMAPLFBDeInit(void)
+{
+ unsigned uiMaxFBDevIDPlusOne = OMAPLFBMaxFBDevIDPlusOne();
+ unsigned i;
+ OMAPLFB_BOOL bError = OMAPLFB_FALSE;
+
+ for(i = 0; i < uiMaxFBDevIDPlusOne; i++)
+ {
+ OMAPLFB_DEVINFO *psDevInfo = OMAPLFBGetDevInfoPtr(i);
+
+ if (psDevInfo != NULL)
+ {
+ bError |= !OMAPLFBDeInitDev(psDevInfo);
+ }
+ }
+
+ return (bError) ? OMAPLFB_ERROR_INIT_FAILURE : OMAPLFB_OK;
+}
+
+/******************************************************************************
+ End of file (omaplfb_displayclass.c)
+******************************************************************************/
+
diff --git a/pvr-source/services4/3rdparty/dc_omapfb3_linux/omaplfb_linux.c b/pvr-source/services4/3rdparty/dc_omapfb3_linux/omaplfb_linux.c
new file mode 100644
index 0000000..82c7fce
--- /dev/null
+++ b/pvr-source/services4/3rdparty/dc_omapfb3_linux/omaplfb_linux.c
@@ -0,0 +1,1165 @@
+/*************************************************************************/ /*!
+@Title OMAP linux display driver components
+@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
+@License Dual MIT/GPLv2
+
+The contents of this file are subject to the MIT license as set out below.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+Alternatively, the contents of this file may be used under the terms of
+the GNU General Public License Version 2 ("GPL") in which case the provisions
+of GPL are applicable instead of those above.
+
+If you wish to allow use of your version of this file only under the terms of
+GPL, and not to allow others to use your version of this file under the terms
+of the MIT license, indicate your decision by deleting the provisions above
+and replace them with the notice and other provisions required by GPL as set
+out in the file called "GPL-COPYING" included in this distribution. If you do
+not delete the provisions above, a recipient may use your version of this file
+under the terms of either the MIT license or GPL.
+
+This License is also included in this distribution in the file called
+"MIT-COPYING".
+
+EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) 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; AND (B) 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.
+*/ /**************************************************************************/
+
+/**************************************************************************
+ The 3rd party driver is a specification of an API to integrate the IMG POWERVR
+ Services driver with 3rd Party display hardware. It is NOT a specification for
+ a display controller driver, rather a specification to extend the API for a
+ pre-existing driver for the display hardware.
+
+ The 3rd party driver interface provides IMG POWERVR client drivers (e.g. PVR2D)
+ with an API abstraction of the system's underlying display hardware, allowing
+ the client drivers to indirectly control the display hardware and access its
+ associated memory.
+
+ Functions of the API include
+ - query primary surface attributes (width, height, stride, pixel format, CPU
+ physical and virtual address)
+ - swap/flip chain creation and subsequent query of surface attributes
+ - asynchronous display surface flipping, taking account of asynchronous read
+ (flip) and write (render) operations to the display surface
+
+ Note: having queried surface attributes the client drivers are able to map the
+ display memory to any IMG POWERVR Services device by calling
+ PVRSRVMapDeviceClassMemory with the display surface handle.
+
+ This code is intended to be an example of how a pre-existing display driver may
+ be extended to support the 3rd Party Display interface to POWERVR Services
+ - IMG is not providing a display driver implementation.
+ **************************************************************************/
+
+#include <linux/version.h>
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38))
+#ifndef AUTOCONF_INCLUDED
+#include <linux/config.h>
+#endif
+#endif
+
+#include <asm/atomic.h>
+
+#if defined(SUPPORT_DRI_DRM)
+#include <drm/drmP.h>
+#else
+#include <linux/module.h>
+#endif
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/hardirq.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/fb.h>
+#include <linux/console.h>
+#include <linux/omapfb.h>
+#include <linux/mutex.h>
+
+#if defined(PVR_OMAPLFB_DRM_FB)
+#include <plat/display.h>
+#include <linux/omap_gpu.h>
+#else /* defined(PVR_OMAPLFB_DRM_FB) */
+/* OmapZoom.org OMAP3 2.6.29 kernel tree - Needs mach/vrfb.h
+ * OmapZoom.org OMAP3 2.6.32 kernel tree - No additional header required
+ * OmapZoom.org OMAP4 2.6.33 kernel tree - No additional header required
+ * OmapZoom.org OMAP4 2.6.34 kernel tree - Needs plat/vrfb.h
+ * Sholes 2.6.32 kernel tree - Needs plat/vrfb.h
+ */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34))
+#define PVR_OMAPFB3_NEEDS_PLAT_VRFB_H
+#endif
+
+#if defined(PVR_OMAPFB3_NEEDS_PLAT_VRFB_H)
+#include <plat/vrfb.h>
+#else
+#if defined(PVR_OMAPFB3_NEEDS_MACH_VRFB_H)
+#include <mach/vrfb.h>
+#endif
+#endif
+
+#if defined(DEBUG)
+#define PVR_DEBUG DEBUG
+#undef DEBUG
+#endif
+#include <omapfb/omapfb.h>
+#if defined(DEBUG)
+#undef DEBUG
+#endif
+#if defined(PVR_DEBUG)
+#define DEBUG PVR_DEBUG
+#undef PVR_DEBUG
+#endif
+#endif /* defined(PVR_OMAPLFB_DRM_FB) */
+
+#if defined(CONFIG_DSSCOMP)
+#include <mach/tiler.h>
+#include <video/dsscomp.h>
+#include <plat/dsscomp.h>
+#endif /* defined(CONFIG_DSSCOMP) */
+
+#include "img_defs.h"
+#include "servicesext.h"
+#include "kerneldisplay.h"
+#include "omaplfb.h"
+#include "pvrmodule.h"
+#if defined(SUPPORT_DRI_DRM)
+#include "pvr_drm.h"
+#include "3rdparty_dc_drm_shared.h"
+#endif
+
+#if !defined(PVR_LINUX_USING_WORKQUEUES)
+#error "PVR_LINUX_USING_WORKQUEUES must be defined"
+#endif
+
+MODULE_SUPPORTED_DEVICE(DEVNAME);
+
+#if !defined(PVR_OMAPLFB_DRM_FB)
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34))
+#define OMAP_DSS_DRIVER(drv, dev) struct omap_dss_driver *drv = (dev) != NULL ? (dev)->driver : NULL
+#define OMAP_DSS_MANAGER(man, dev) struct omap_overlay_manager *man = (dev) != NULL ? (dev)->manager : NULL
+#define WAIT_FOR_VSYNC(man) ((man)->wait_for_vsync)
+#else
+#define OMAP_DSS_DRIVER(drv, dev) struct omap_dss_device *drv = (dev)
+#define OMAP_DSS_MANAGER(man, dev) struct omap_dss_device *man = (dev)
+#define WAIT_FOR_VSYNC(man) ((man)->wait_vsync)
+#endif
+#endif /* !defined(PVR_OMAPLFB_DRM_FB) */
+
+void *OMAPLFBAllocKernelMem(unsigned long ulSize)
+{
+ return kmalloc(ulSize, GFP_KERNEL);
+}
+
+void OMAPLFBFreeKernelMem(void *pvMem)
+{
+ kfree(pvMem);
+}
+
+void OMAPLFBCreateSwapChainLockInit(OMAPLFB_DEVINFO *psDevInfo)
+{
+ mutex_init(&psDevInfo->sCreateSwapChainMutex);
+}
+
+void OMAPLFBCreateSwapChainLockDeInit(OMAPLFB_DEVINFO *psDevInfo)
+{
+ mutex_destroy(&psDevInfo->sCreateSwapChainMutex);
+}
+
+void OMAPLFBCreateSwapChainLock(OMAPLFB_DEVINFO *psDevInfo)
+{
+ mutex_lock(&psDevInfo->sCreateSwapChainMutex);
+}
+
+void OMAPLFBCreateSwapChainUnLock(OMAPLFB_DEVINFO *psDevInfo)
+{
+ mutex_unlock(&psDevInfo->sCreateSwapChainMutex);
+}
+
+void OMAPLFBAtomicBoolInit(OMAPLFB_ATOMIC_BOOL *psAtomic, OMAPLFB_BOOL bVal)
+{
+ atomic_set(psAtomic, (int)bVal);
+}
+
+void OMAPLFBAtomicBoolDeInit(OMAPLFB_ATOMIC_BOOL *psAtomic)
+{
+}
+
+void OMAPLFBAtomicBoolSet(OMAPLFB_ATOMIC_BOOL *psAtomic, OMAPLFB_BOOL bVal)
+{
+ atomic_set(psAtomic, (int)bVal);
+}
+
+OMAPLFB_BOOL OMAPLFBAtomicBoolRead(OMAPLFB_ATOMIC_BOOL *psAtomic)
+{
+ return (OMAPLFB_BOOL)atomic_read(psAtomic);
+}
+
+void OMAPLFBAtomicIntInit(OMAPLFB_ATOMIC_INT *psAtomic, int iVal)
+{
+ atomic_set(psAtomic, iVal);
+}
+
+void OMAPLFBAtomicIntDeInit(OMAPLFB_ATOMIC_INT *psAtomic)
+{
+}
+
+void OMAPLFBAtomicIntSet(OMAPLFB_ATOMIC_INT *psAtomic, int iVal)
+{
+ atomic_set(psAtomic, iVal);
+}
+
+int OMAPLFBAtomicIntRead(OMAPLFB_ATOMIC_INT *psAtomic)
+{
+ return atomic_read(psAtomic);
+}
+
+void OMAPLFBAtomicIntInc(OMAPLFB_ATOMIC_INT *psAtomic)
+{
+ atomic_inc(psAtomic);
+}
+
+OMAPLFB_ERROR OMAPLFBGetLibFuncAddr (char *szFunctionName, PFN_DC_GET_PVRJTABLE *ppfnFuncTable)
+{
+ if(strcmp("PVRGetDisplayClassJTable", szFunctionName) != 0)
+ {
+ return (OMAPLFB_ERROR_INVALID_PARAMS);
+ }
+
+ /* Nothing to do - should be exported from pvrsrv.ko */
+ *ppfnFuncTable = PVRGetDisplayClassJTable;
+
+ return (OMAPLFB_OK);
+}
+
+/* Inset a swap buffer into the swap chain work queue */
+void OMAPLFBQueueBufferForSwap(OMAPLFB_SWAPCHAIN *psSwapChain, OMAPLFB_BUFFER *psBuffer)
+{
+ int res = queue_work(psSwapChain->psWorkQueue, &psBuffer->sWork);
+
+ if (res == 0)
+ {
+ printk(KERN_WARNING DRIVER_PREFIX ": %s: Device %u: Buffer already on work queue\n", __FUNCTION__, psSwapChain->uiFBDevID);
+ }
+}
+
+/* Process an item on a swap chain work queue */
+static void WorkQueueHandler(struct work_struct *psWork)
+{
+ OMAPLFB_BUFFER *psBuffer = container_of(psWork, OMAPLFB_BUFFER, sWork);
+
+ OMAPLFBSwapHandler(psBuffer);
+}
+
+/* Create a swap chain work queue */
+OMAPLFB_ERROR OMAPLFBCreateSwapQueue(OMAPLFB_SWAPCHAIN *psSwapChain)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37))
+#if (LINUX_VERSION_CODE == KERNEL_VERSION(2,6,37))
+#define WQ_FREEZABLE WQ_FREEZEABLE
+#endif
+ /*
+ * Calling alloc_ordered_workqueue with the WQ_FREEZABLE and
+ * WQ_MEM_RECLAIM flags set, (currently) has the same effect as
+ * calling create_freezable_workqueue. None of the other WQ
+ * flags are valid. Setting WQ_MEM_RECLAIM should allow the
+ * workqueue to continue to service the swap chain in low memory
+ * conditions, preventing the driver from holding on to
+ * resources longer than it needs to.
+ */
+ psSwapChain->psWorkQueue = alloc_ordered_workqueue(DEVNAME, WQ_FREEZABLE | WQ_MEM_RECLAIM);
+#else
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
+ psSwapChain->psWorkQueue = create_freezable_workqueue(DEVNAME);
+#else
+ /*
+ * Create a single-threaded, freezable, rt-prio workqueue.
+ * Such workqueues are frozen with user threads when a system
+ * suspends, before driver suspend entry points are called.
+ * This ensures this driver will not call into the Linux
+ * framebuffer driver after the latter is suspended.
+ */
+ psSwapChain->psWorkQueue = __create_workqueue(DEVNAME, 1, 1, 1);
+#endif
+#endif
+ if (psSwapChain->psWorkQueue == NULL)
+ {
+ printk(KERN_ERR DRIVER_PREFIX ": %s: Device %u: Couldn't create workqueue\n", __FUNCTION__, psSwapChain->uiFBDevID);
+
+ return (OMAPLFB_ERROR_INIT_FAILURE);
+ }
+
+ return (OMAPLFB_OK);
+}
+
+/* Prepare buffer for insertion into a swap chain work queue */
+void OMAPLFBInitBufferForSwap(OMAPLFB_BUFFER *psBuffer)
+{
+ INIT_WORK(&psBuffer->sWork, WorkQueueHandler);
+}
+
+/* Destroy a swap chain work queue */
+void OMAPLFBDestroySwapQueue(OMAPLFB_SWAPCHAIN *psSwapChain)
+{
+ destroy_workqueue(psSwapChain->psWorkQueue);
+}
+
+/* Flip display to given buffer */
+void OMAPLFBFlip(OMAPLFB_DEVINFO *psDevInfo, OMAPLFB_BUFFER *psBuffer)
+{
+ struct fb_var_screeninfo sFBVar;
+ int res;
+ unsigned long ulYResVirtual;
+
+ OMAPLFB_CONSOLE_LOCK();
+
+ sFBVar = psDevInfo->psLINFBInfo->var;
+
+ sFBVar.xoffset = 0;
+ sFBVar.yoffset = psBuffer->ulYOffset;
+
+ ulYResVirtual = psBuffer->ulYOffset + sFBVar.yres;
+
+#if defined(CONFIG_DSSCOMP)
+ {
+ /*
+ * If using DSSCOMP, we need to use dsscomp queuing for normal
+ * framebuffer updates, so that previously used overlays get
+ * automatically disabled, and manager gets dirtied. We can
+ * do that because DSSCOMP takes ownership of all pipelines on
+ * a manager.
+ */
+ struct fb_fix_screeninfo sFBFix = psDevInfo->psLINFBInfo->fix;
+ struct dsscomp_setup_dispc_data d =
+ {
+ .num_ovls = 1,
+ .num_mgrs = 1,
+ .mgrs[0].alpha_blending = 1,
+ .ovls[0] =
+ {
+ .cfg =
+ {
+ .win.w = sFBVar.xres,
+ .win.h = sFBVar.yres,
+ .crop.x = sFBVar.xoffset,
+ .crop.y = sFBVar.yoffset,
+ .crop.w = sFBVar.xres,
+ .crop.h = sFBVar.yres,
+ .width = sFBVar.xres_virtual,
+ .height = sFBVar.yres_virtual,
+ .stride = sFBFix.line_length,
+ .enabled = 1,
+ .global_alpha = 255,
+ },
+ },
+ };
+
+ /* do not map buffer into TILER1D as it is contiguous */
+ struct tiler_pa_info *pas[] = { NULL };
+
+ d.ovls[0].ba = sFBFix.smem_start;
+ omapfb_mode_to_dss_mode(&sFBVar, &d.ovls[0].cfg.color_mode);
+
+ res = dsscomp_gralloc_queue(&d, pas, true, NULL, NULL);
+ }
+#else /* defined(CONFIG_DSSCOMP) */
+ /*
+ * PVR_OMAPLFB_DONT_USE_FB_PAN_DISPLAY should be defined to work
+ * around flipping problems seen with the Taal LCDs on Blaze.
+ * The work around is safe to use with other types of screen on Blaze
+ * (e.g. HDMI) and on other platforms (e.g. Panda board).
+ */
+#if !defined(PVR_OMAPLFB_DONT_USE_FB_PAN_DISPLAY)
+ /*
+ * Attempt to change the virtual screen resolution if it is too
+ * small. Note that fb_set_var also pans the display.
+ */
+ if (sFBVar.xres_virtual != sFBVar.xres || sFBVar.yres_virtual < ulYResVirtual)
+#endif /* !defined(PVR_OMAPLFB_DONT_USE_FB_PAN_DISPLAY) */
+ {
+ sFBVar.xres_virtual = sFBVar.xres;
+ sFBVar.yres_virtual = ulYResVirtual;
+
+ sFBVar.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE;
+
+ res = fb_set_var(psDevInfo->psLINFBInfo, &sFBVar);
+ if (res != 0)
+ {
+ printk(KERN_ERR DRIVER_PREFIX ": %s: Device %u: fb_set_var failed (Y Offset: %lu, Error: %d)\n", __FUNCTION__, psDevInfo->uiFBDevID, psBuffer->ulYOffset, res);
+ }
+ }
+#if !defined(PVR_OMAPLFB_DONT_USE_FB_PAN_DISPLAY)
+ else
+ {
+ res = fb_pan_display(psDevInfo->psLINFBInfo, &sFBVar);
+ if (res != 0)
+ {
+ printk(KERN_ERR DRIVER_PREFIX ": %s: Device %u: fb_pan_display failed (Y Offset: %lu, Error: %d)\n", __FUNCTION__, psDevInfo->uiFBDevID, psBuffer->ulYOffset, res);
+ }
+ }
+#endif /* !defined(PVR_OMAPLFB_DONT_USE_FB_PAN_DISPLAY) */
+#endif /* defined(CONFIG_DSSCOMP) */
+
+ OMAPLFB_CONSOLE_UNLOCK();
+}
+
+#if !defined(PVR_OMAPLFB_DRM_FB) || defined(DEBUG)
+static OMAPLFB_BOOL OMAPLFBValidateDSSUpdateMode(enum omap_dss_update_mode eMode)
+{
+ switch (eMode)
+ {
+ case OMAP_DSS_UPDATE_AUTO:
+ case OMAP_DSS_UPDATE_MANUAL:
+ case OMAP_DSS_UPDATE_DISABLED:
+ return OMAPLFB_TRUE;
+ default:
+ break;
+ }
+
+ return OMAPLFB_FALSE;
+}
+
+static OMAPLFB_UPDATE_MODE OMAPLFBFromDSSUpdateMode(enum omap_dss_update_mode eMode)
+{
+ switch (eMode)
+ {
+ case OMAP_DSS_UPDATE_AUTO:
+ return OMAPLFB_UPDATE_MODE_AUTO;
+ case OMAP_DSS_UPDATE_MANUAL:
+ return OMAPLFB_UPDATE_MODE_MANUAL;
+ case OMAP_DSS_UPDATE_DISABLED:
+ return OMAPLFB_UPDATE_MODE_DISABLED;
+ default:
+ break;
+ }
+
+ return OMAPLFB_UPDATE_MODE_UNDEFINED;
+}
+#endif
+
+static OMAPLFB_BOOL OMAPLFBValidateUpdateMode(OMAPLFB_UPDATE_MODE eMode)
+{
+ switch(eMode)
+ {
+ case OMAPLFB_UPDATE_MODE_AUTO:
+ case OMAPLFB_UPDATE_MODE_MANUAL:
+ case OMAPLFB_UPDATE_MODE_DISABLED:
+ return OMAPLFB_TRUE;
+ default:
+ break;
+ }
+
+ return OMAPLFB_FALSE;
+}
+
+static enum omap_dss_update_mode OMAPLFBToDSSUpdateMode(OMAPLFB_UPDATE_MODE eMode)
+{
+ switch(eMode)
+ {
+ case OMAPLFB_UPDATE_MODE_AUTO:
+ return OMAP_DSS_UPDATE_AUTO;
+ case OMAPLFB_UPDATE_MODE_MANUAL:
+ return OMAP_DSS_UPDATE_MANUAL;
+ case OMAPLFB_UPDATE_MODE_DISABLED:
+ return OMAP_DSS_UPDATE_DISABLED;
+ default:
+ break;
+ }
+
+ return -1;
+}
+
+#if defined(DEBUG)
+static const char *OMAPLFBUpdateModeToString(OMAPLFB_UPDATE_MODE eMode)
+{
+ switch(eMode)
+ {
+ case OMAPLFB_UPDATE_MODE_AUTO:
+ return "Auto Update Mode";
+ case OMAPLFB_UPDATE_MODE_MANUAL:
+ return "Manual Update Mode";
+ case OMAPLFB_UPDATE_MODE_DISABLED:
+ return "Update Mode Disabled";
+ case OMAPLFB_UPDATE_MODE_UNDEFINED:
+ return "Update Mode Undefined";
+ default:
+ break;
+ }
+
+ return "Unknown Update Mode";
+}
+
+static const char *OMAPLFBDSSUpdateModeToString(enum omap_dss_update_mode eMode)
+{
+ if (!OMAPLFBValidateDSSUpdateMode(eMode))
+ {
+ return "Unknown Update Mode";
+ }
+
+ return OMAPLFBUpdateModeToString(OMAPLFBFromDSSUpdateMode(eMode));
+}
+
+void OMAPLFBPrintInfo(OMAPLFB_DEVINFO *psDevInfo)
+{
+#if defined(PVR_OMAPLFB_DRM_FB)
+ struct drm_connector *psConnector;
+ unsigned uConnectors;
+ unsigned uConnector;
+
+ DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX ": Device %u: DRM framebuffer\n", psDevInfo->uiFBDevID));
+
+ for (psConnector = NULL, uConnectors = 0;
+ (psConnector = omap_fbdev_get_next_connector(psDevInfo->psLINFBInfo, psConnector)) != NULL;)
+ {
+ uConnectors++;
+ }
+
+ DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX ": Device %u: Number of screens (DRM connectors): %u\n", psDevInfo->uiFBDevID, uConnectors));
+
+ if (uConnectors == 0)
+ {
+ return;
+ }
+
+ for (psConnector = NULL, uConnector = 0;
+ (psConnector = omap_fbdev_get_next_connector(psDevInfo->psLINFBInfo, psConnector)) != NULL; uConnector++)
+ {
+ enum omap_dss_update_mode eMode = omap_connector_get_update_mode(psConnector);
+
+ DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX ": Device %u: Screen %u: %s (%d)\n", psDevInfo->uiFBDevID, uConnector, OMAPLFBDSSUpdateModeToString(eMode), (int)eMode));
+
+ }
+#else /* defined(PVR_OMAPLFB_DRM_FB) */
+ OMAPLFB_UPDATE_MODE eMode = OMAPLFBGetUpdateMode(psDevInfo);
+
+ DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX ": Device %u: non-DRM framebuffer\n", psDevInfo->uiFBDevID));
+
+ DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX ": Device %u: %s\n", psDevInfo->uiFBDevID, OMAPLFBUpdateModeToString(eMode)));
+#endif /* defined(PVR_OMAPLFB_DRM_FB) */
+}
+#endif /* defined(DEBUG) */
+
+/*
+ * Get display update mode.
+ * If the mode is AUTO, we can wait for VSync, if desired.
+ */
+OMAPLFB_UPDATE_MODE OMAPLFBGetUpdateMode(OMAPLFB_DEVINFO *psDevInfo)
+{
+#if defined(PVR_OMAPLFB_DRM_FB)
+ struct drm_connector *psConnector;
+ OMAPLFB_UPDATE_MODE eMode = OMAPLFB_UPDATE_MODE_UNDEFINED;
+
+ /*
+ * There may be multiple displays connected. If at least one
+ * display is manual update mode, report all screens as being
+ * in that mode.
+ */
+ for (psConnector = NULL;
+ (psConnector = omap_fbdev_get_next_connector(psDevInfo->psLINFBInfo, psConnector)) != NULL;)
+ {
+ switch(omap_connector_get_update_mode(psConnector))
+ {
+ case OMAP_DSS_UPDATE_MANUAL:
+ eMode = OMAPLFB_UPDATE_MODE_MANUAL;
+ break;
+ case OMAP_DSS_UPDATE_DISABLED:
+ if (eMode == OMAPLFB_UPDATE_MODE_UNDEFINED)
+ {
+ eMode = OMAPLFB_UPDATE_MODE_DISABLED;
+ }
+ break;
+ case OMAP_DSS_UPDATE_AUTO:
+ /* Fall through to default case */
+ default:
+ /* Asssume auto update is possible */
+ if (eMode != OMAPLFB_UPDATE_MODE_MANUAL)
+ {
+ eMode = OMAPLFB_UPDATE_MODE_AUTO;
+ }
+ break;
+ }
+ }
+
+ return eMode;
+#else /* defined(PVR_OMAPLFB_DRM_FB) */
+ struct omap_dss_device *psDSSDev = fb2display(psDevInfo->psLINFBInfo);
+ OMAP_DSS_DRIVER(psDSSDrv, psDSSDev);
+
+ enum omap_dss_update_mode eMode;
+
+ if (psDSSDrv == NULL)
+ {
+ DEBUG_PRINTK((KERN_WARNING DRIVER_PREFIX ": %s: Device %u: No DSS device\n", __FUNCTION__, psDevInfo->uiFBDevID));
+ return OMAPLFB_UPDATE_MODE_UNDEFINED;
+ }
+
+ if (psDSSDrv->get_update_mode == NULL)
+ {
+ if (strcmp(psDSSDev->name, "hdmi") == 0)
+ {
+ return OMAPLFB_UPDATE_MODE_AUTO;
+ }
+ DEBUG_PRINTK((KERN_WARNING DRIVER_PREFIX ": %s: Device %u: No get_update_mode function\n", __FUNCTION__, psDevInfo->uiFBDevID));
+ return OMAPLFB_UPDATE_MODE_UNDEFINED;
+ }
+
+ eMode = psDSSDrv->get_update_mode(psDSSDev);
+ if (!OMAPLFBValidateDSSUpdateMode(eMode))
+ {
+ DEBUG_PRINTK((KERN_WARNING DRIVER_PREFIX ": %s: Device %u: Unknown update mode (%d)\n", __FUNCTION__, psDevInfo->uiFBDevID, (int)eMode));
+ }
+
+ return OMAPLFBFromDSSUpdateMode(eMode);
+#endif /* defined(PVR_OMAPLFB_DRM_FB) */
+}
+
+/* Set display update mode */
+OMAPLFB_BOOL OMAPLFBSetUpdateMode(OMAPLFB_DEVINFO *psDevInfo, OMAPLFB_UPDATE_MODE eMode)
+{
+#if defined(PVR_OMAPLFB_DRM_FB)
+ struct drm_connector *psConnector;
+ enum omap_dss_update_mode eDSSMode;
+ OMAPLFB_BOOL bSuccess = OMAPLFB_FALSE;
+ OMAPLFB_BOOL bFailure = OMAPLFB_FALSE;
+
+ if (!OMAPLFBValidateUpdateMode(eMode))
+ {
+ DEBUG_PRINTK((KERN_WARNING DRIVER_PREFIX ": %s: Device %u: Unknown update mode (%d)\n", __FUNCTION__, psDevInfo->uiFBDevID, (int)eMode));
+ return OMAPLFB_FALSE;
+ }
+ eDSSMode = OMAPLFBToDSSUpdateMode(eMode);
+
+ for (psConnector = NULL;
+ (psConnector = omap_fbdev_get_next_connector(psDevInfo->psLINFBInfo, psConnector)) != NULL;)
+ {
+ int iRes = omap_connector_set_update_mode(psConnector, eDSSMode);
+ OMAPLFB_BOOL bRes = (iRes == 0);
+
+
+ bSuccess |= bRes;
+ bFailure |= !bRes;
+ }
+
+ if (!bFailure)
+ {
+ if (!bSuccess)
+ {
+ DEBUG_PRINTK((KERN_WARNING DRIVER_PREFIX ": %s: Device %u: No screens\n", __FUNCTION__, psDevInfo->uiFBDevID));
+ }
+
+ return OMAPLFB_TRUE;
+ }
+
+ if (!bSuccess)
+ {
+ DEBUG_PRINTK((KERN_WARNING DRIVER_PREFIX ": %s: Device %u: Couldn't set %s for any screen\n", __FUNCTION__, psDevInfo->uiFBDevID, OMAPLFBUpdateModeToString(eMode)));
+ return OMAPLFB_FALSE;
+ }
+
+ if (eMode == OMAPLFB_UPDATE_MODE_AUTO)
+ {
+ DEBUG_PRINTK((KERN_WARNING DRIVER_PREFIX ": %s: Device %u: Couldn't set %s for all screens\n", __FUNCTION__, psDevInfo->uiFBDevID, OMAPLFBUpdateModeToString(eMode)));
+ return OMAPLFB_FALSE;
+ }
+
+ DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX ": %s: Device %u: %s set for some screens\n", __FUNCTION__, psDevInfo->uiFBDevID, OMAPLFBUpdateModeToString(eMode)));
+
+ return OMAPLFB_TRUE;
+#else /* defined(PVR_OMAPLFB_DRM_FB) */
+ struct omap_dss_device *psDSSDev = fb2display(psDevInfo->psLINFBInfo);
+ OMAP_DSS_DRIVER(psDSSDrv, psDSSDev);
+ enum omap_dss_update_mode eDSSMode;
+ int res;
+
+ if (psDSSDrv == NULL || psDSSDrv->set_update_mode == NULL)
+ {
+ DEBUG_PRINTK((KERN_WARNING DRIVER_PREFIX ": %s: Device %u: Can't set update mode\n", __FUNCTION__, psDevInfo->uiFBDevID));
+ return OMAPLFB_FALSE;
+ }
+
+ if (!OMAPLFBValidateUpdateMode(eMode))
+ {
+ DEBUG_PRINTK((KERN_WARNING DRIVER_PREFIX ": %s: Device %u: Unknown update mode (%d)\n", __FUNCTION__, psDevInfo->uiFBDevID, (int)eMode));
+ return OMAPLFB_FALSE;
+ }
+ eDSSMode = OMAPLFBToDSSUpdateMode(eMode);
+
+ res = psDSSDrv->set_update_mode(psDSSDev, eDSSMode);
+ if (res != 0)
+ {
+ DEBUG_PRINTK((KERN_WARNING DRIVER_PREFIX ": %s: Device %u: set_update_mode (%s) failed (%d)\n", __FUNCTION__, psDevInfo->uiFBDevID, OMAPLFBDSSUpdateModeToString(eDSSMode), res));
+ }
+
+ return (res == 0);
+#endif /* defined(PVR_OMAPLFB_DRM_FB) */
+}
+
+/* Wait for VSync */
+OMAPLFB_BOOL OMAPLFBWaitForVSync(OMAPLFB_DEVINFO *psDevInfo)
+{
+#if defined(PVR_OMAPLFB_DRM_FB)
+ struct drm_connector *psConnector;
+
+ for (psConnector = NULL;
+ (psConnector = omap_fbdev_get_next_connector(psDevInfo->psLINFBInfo, psConnector)) != NULL;)
+ {
+ (void) omap_encoder_wait_for_vsync(psConnector->encoder);
+ }
+
+ return OMAPLFB_TRUE;
+#else /* defined(PVR_OMAPLFB_DRM_FB) */
+ struct omap_dss_device *psDSSDev = fb2display(psDevInfo->psLINFBInfo);
+ OMAP_DSS_MANAGER(psDSSMan, psDSSDev);
+
+ if (psDSSMan != NULL && WAIT_FOR_VSYNC(psDSSMan) != NULL)
+ {
+ int res = WAIT_FOR_VSYNC(psDSSMan)(psDSSMan);
+ if (res != 0)
+ {
+ DEBUG_PRINTK((KERN_WARNING DRIVER_PREFIX ": %s: Device %u: Wait for vsync failed (%d)\n", __FUNCTION__, psDevInfo->uiFBDevID, res));
+ return OMAPLFB_FALSE;
+ }
+ }
+
+ return OMAPLFB_TRUE;
+#endif /* defined(PVR_OMAPLFB_DRM_FB) */
+}
+
+/*
+ * Wait for screen to update. If the screen is in manual or auto update
+ * mode, we can call this function to wait for the screen to update.
+ */
+OMAPLFB_BOOL OMAPLFBManualSync(OMAPLFB_DEVINFO *psDevInfo)
+{
+#if defined(PVR_OMAPLFB_DRM_FB)
+ struct drm_connector *psConnector;
+
+ for (psConnector = NULL;
+ (psConnector = omap_fbdev_get_next_connector(psDevInfo->psLINFBInfo, psConnector)) != NULL; )
+ {
+ /* Try manual sync first, then try wait for vsync */
+ if (omap_connector_sync(psConnector) != 0)
+ {
+ (void) omap_encoder_wait_for_vsync(psConnector->encoder);
+ }
+ }
+
+ return OMAPLFB_TRUE;
+#else /* defined(PVR_OMAPLFB_DRM_FB) */
+ struct omap_dss_device *psDSSDev = fb2display(psDevInfo->psLINFBInfo);
+ OMAP_DSS_DRIVER(psDSSDrv, psDSSDev);
+
+ if (psDSSDrv != NULL && psDSSDrv->sync != NULL)
+ {
+ int res = psDSSDrv->sync(psDSSDev);
+ if (res != 0)
+ {
+ printk(KERN_ERR DRIVER_PREFIX ": %s: Device %u: Sync failed (%d)\n", __FUNCTION__, psDevInfo->uiFBDevID, res);
+ return OMAPLFB_FALSE;
+ }
+ }
+
+ return OMAPLFB_TRUE;
+#endif /* defined(PVR_OMAPLFB_DRM_FB) */
+}
+
+/*
+ * If the screen is manual or auto update mode, wait for the screen to
+ * update.
+ */
+OMAPLFB_BOOL OMAPLFBCheckModeAndSync(OMAPLFB_DEVINFO *psDevInfo)
+{
+ OMAPLFB_UPDATE_MODE eMode = OMAPLFBGetUpdateMode(psDevInfo);
+
+ switch(eMode)
+ {
+ case OMAPLFB_UPDATE_MODE_AUTO:
+ case OMAPLFB_UPDATE_MODE_MANUAL:
+ return OMAPLFBManualSync(psDevInfo);
+ default:
+ break;
+ }
+
+ return OMAPLFB_TRUE;
+}
+
+/* Linux Framebuffer event notification handler */
+static int OMAPLFBFrameBufferEvents(struct notifier_block *psNotif,
+ unsigned long event, void *data)
+{
+ OMAPLFB_DEVINFO *psDevInfo;
+ struct fb_event *psFBEvent = (struct fb_event *)data;
+ struct fb_info *psFBInfo = psFBEvent->info;
+ OMAPLFB_BOOL bBlanked;
+
+ /* Only interested in blanking events */
+ if (event != FB_EVENT_BLANK)
+ {
+ return 0;
+ }
+
+ bBlanked = (*(IMG_INT *)psFBEvent->data != 0) ? OMAPLFB_TRUE: OMAPLFB_FALSE;
+
+ psDevInfo = OMAPLFBGetDevInfoPtr(psFBInfo->node);
+
+#if 0
+ if (psDevInfo != NULL)
+ {
+ if (bBlanked)
+ {
+ DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX ": %s: Device %u: Blank event received\n", __FUNCTION__, psDevInfo->uiFBDevID));
+ }
+ else
+ {
+ DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX ": %s: Device %u: Unblank event received\n", __FUNCTION__, psDevInfo->uiFBDevID));
+ }
+ }
+ else
+ {
+ DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX ": %s: Device %u: Blank/Unblank event for unknown framebuffer\n", __FUNCTION__, psFBInfo->node));
+ }
+#endif
+
+ if (psDevInfo != NULL)
+ {
+ OMAPLFBAtomicBoolSet(&psDevInfo->sBlanked, bBlanked);
+ OMAPLFBAtomicIntInc(&psDevInfo->sBlankEvents);
+ }
+
+ return 0;
+}
+
+/* Unblank the screen */
+OMAPLFB_ERROR OMAPLFBUnblankDisplay(OMAPLFB_DEVINFO *psDevInfo)
+{
+ int res;
+
+ OMAPLFB_CONSOLE_LOCK();
+ res = fb_blank(psDevInfo->psLINFBInfo, 0);
+ OMAPLFB_CONSOLE_UNLOCK();
+ if (res != 0 && res != -EINVAL)
+ {
+ printk(KERN_ERR DRIVER_PREFIX
+ ": %s: Device %u: fb_blank failed (%d)\n", __FUNCTION__, psDevInfo->uiFBDevID, res);
+ return (OMAPLFB_ERROR_GENERIC);
+ }
+
+ return (OMAPLFB_OK);
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+
+/* Blank the screen */
+static void OMAPLFBBlankDisplay(OMAPLFB_DEVINFO *psDevInfo)
+{
+ OMAPLFB_CONSOLE_LOCK();
+ fb_blank(psDevInfo->psLINFBInfo, 1);
+ OMAPLFB_CONSOLE_UNLOCK();
+}
+
+static void OMAPLFBEarlySuspendHandler(struct early_suspend *h)
+{
+ unsigned uiMaxFBDevIDPlusOne = OMAPLFBMaxFBDevIDPlusOne();
+ unsigned i;
+
+ for (i=0; i < uiMaxFBDevIDPlusOne; i++)
+ {
+ OMAPLFB_DEVINFO *psDevInfo = OMAPLFBGetDevInfoPtr(i);
+
+ if (psDevInfo != NULL)
+ {
+ OMAPLFBAtomicBoolSet(&psDevInfo->sEarlySuspendFlag, OMAPLFB_TRUE);
+ OMAPLFBBlankDisplay(psDevInfo);
+ }
+ }
+}
+
+static void OMAPLFBEarlyResumeHandler(struct early_suspend *h)
+{
+ unsigned uiMaxFBDevIDPlusOne = OMAPLFBMaxFBDevIDPlusOne();
+ unsigned i;
+
+ for (i=0; i < uiMaxFBDevIDPlusOne; i++)
+ {
+ OMAPLFB_DEVINFO *psDevInfo = OMAPLFBGetDevInfoPtr(i);
+
+ if (psDevInfo != NULL)
+ {
+ OMAPLFBUnblankDisplay(psDevInfo);
+ OMAPLFBAtomicBoolSet(&psDevInfo->sEarlySuspendFlag, OMAPLFB_FALSE);
+ }
+ }
+}
+
+#endif /* CONFIG_HAS_EARLYSUSPEND */
+
+/* Set up Linux Framebuffer event notification */
+OMAPLFB_ERROR OMAPLFBEnableLFBEventNotification(OMAPLFB_DEVINFO *psDevInfo)
+{
+ int res;
+ OMAPLFB_ERROR eError;
+
+ /* Set up Linux Framebuffer event notification */
+ memset(&psDevInfo->sLINNotifBlock, 0, sizeof(psDevInfo->sLINNotifBlock));
+
+ psDevInfo->sLINNotifBlock.notifier_call = OMAPLFBFrameBufferEvents;
+
+ OMAPLFBAtomicBoolSet(&psDevInfo->sBlanked, OMAPLFB_FALSE);
+ OMAPLFBAtomicIntSet(&psDevInfo->sBlankEvents, 0);
+
+ res = fb_register_client(&psDevInfo->sLINNotifBlock);
+ if (res != 0)
+ {
+ printk(KERN_ERR DRIVER_PREFIX
+ ": %s: Device %u: fb_register_client failed (%d)\n", __FUNCTION__, psDevInfo->uiFBDevID, res);
+
+ return (OMAPLFB_ERROR_GENERIC);
+ }
+
+ eError = OMAPLFBUnblankDisplay(psDevInfo);
+ if (eError != OMAPLFB_OK)
+ {
+ printk(KERN_ERR DRIVER_PREFIX
+ ": %s: Device %u: UnblankDisplay failed (%d)\n", __FUNCTION__, psDevInfo->uiFBDevID, eError);
+ return eError;
+ }
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ psDevInfo->sEarlySuspend.suspend = OMAPLFBEarlySuspendHandler;
+ psDevInfo->sEarlySuspend.resume = OMAPLFBEarlyResumeHandler;
+ psDevInfo->sEarlySuspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB + 1;
+ register_early_suspend(&psDevInfo->sEarlySuspend);
+#endif
+
+ return (OMAPLFB_OK);
+}
+
+/* Disable Linux Framebuffer event notification */
+OMAPLFB_ERROR OMAPLFBDisableLFBEventNotification(OMAPLFB_DEVINFO *psDevInfo)
+{
+ int res;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ unregister_early_suspend(&psDevInfo->sEarlySuspend);
+#endif
+
+ /* Unregister for Framebuffer events */
+ res = fb_unregister_client(&psDevInfo->sLINNotifBlock);
+ if (res != 0)
+ {
+ printk(KERN_ERR DRIVER_PREFIX
+ ": %s: Device %u: fb_unregister_client failed (%d)\n", __FUNCTION__, psDevInfo->uiFBDevID, res);
+ return (OMAPLFB_ERROR_GENERIC);
+ }
+
+ OMAPLFBAtomicBoolSet(&psDevInfo->sBlanked, OMAPLFB_FALSE);
+
+ return (OMAPLFB_OK);
+}
+
+#if defined(SUPPORT_DRI_DRM) && defined(PVR_DISPLAY_CONTROLLER_DRM_IOCTL)
+static OMAPLFB_DEVINFO *OMAPLFBPVRDevIDToDevInfo(unsigned uiPVRDevID)
+{
+ unsigned uiMaxFBDevIDPlusOne = OMAPLFBMaxFBDevIDPlusOne();
+ unsigned i;
+
+ for (i=0; i < uiMaxFBDevIDPlusOne; i++)
+ {
+ OMAPLFB_DEVINFO *psDevInfo = OMAPLFBGetDevInfoPtr(i);
+
+ if (psDevInfo->uiPVRDevID == uiPVRDevID)
+ {
+ return psDevInfo;
+ }
+ }
+
+ printk(KERN_ERR DRIVER_PREFIX
+ ": %s: PVR Device %u: Couldn't find device\n", __FUNCTION__, uiPVRDevID);
+
+ return NULL;
+}
+
+int PVR_DRM_MAKENAME(DISPLAY_CONTROLLER, _Ioctl)(struct drm_device unref__ *dev, void *arg, struct drm_file unref__ *pFile)
+{
+ uint32_t *puiArgs;
+ uint32_t uiCmd;
+ unsigned uiPVRDevID;
+ int ret = 0;
+ OMAPLFB_DEVINFO *psDevInfo;
+
+ if (arg == NULL)
+ {
+ return -EFAULT;
+ }
+
+ puiArgs = (uint32_t *)arg;
+ uiCmd = puiArgs[PVR_DRM_DISP_ARG_CMD];
+ uiPVRDevID = puiArgs[PVR_DRM_DISP_ARG_DEV];
+
+ psDevInfo = OMAPLFBPVRDevIDToDevInfo(uiPVRDevID);
+ if (psDevInfo == NULL)
+ {
+ return -EINVAL;
+ }
+
+
+ switch (uiCmd)
+ {
+ case PVR_DRM_DISP_CMD_LEAVE_VT:
+ case PVR_DRM_DISP_CMD_ENTER_VT:
+ {
+ OMAPLFB_BOOL bLeaveVT = (uiCmd == PVR_DRM_DISP_CMD_LEAVE_VT);
+ DEBUG_PRINTK((KERN_WARNING DRIVER_PREFIX ": %s: PVR Device %u: %s\n",
+ __FUNCTION__, uiPVRDevID,
+ bLeaveVT ? "Leave VT" : "Enter VT"));
+
+ OMAPLFBCreateSwapChainLock(psDevInfo);
+
+ OMAPLFBAtomicBoolSet(&psDevInfo->sLeaveVT, bLeaveVT);
+ if (psDevInfo->psSwapChain != NULL)
+ {
+ flush_workqueue(psDevInfo->psSwapChain->psWorkQueue);
+
+ if (bLeaveVT)
+ {
+ OMAPLFBFlip(psDevInfo, &psDevInfo->sSystemBuffer);
+ (void) OMAPLFBCheckModeAndSync(psDevInfo);
+ }
+ }
+
+ OMAPLFBCreateSwapChainUnLock(psDevInfo);
+ (void) OMAPLFBUnblankDisplay(psDevInfo);
+ break;
+ }
+ case PVR_DRM_DISP_CMD_ON:
+ case PVR_DRM_DISP_CMD_STANDBY:
+ case PVR_DRM_DISP_CMD_SUSPEND:
+ case PVR_DRM_DISP_CMD_OFF:
+ {
+ int iFBMode;
+#if defined(DEBUG)
+ {
+ const char *pszMode;
+ switch(uiCmd)
+ {
+ case PVR_DRM_DISP_CMD_ON:
+ pszMode = "On";
+ break;
+ case PVR_DRM_DISP_CMD_STANDBY:
+ pszMode = "Standby";
+ break;
+ case PVR_DRM_DISP_CMD_SUSPEND:
+ pszMode = "Suspend";
+ break;
+ case PVR_DRM_DISP_CMD_OFF:
+ pszMode = "Off";
+ break;
+ default:
+ pszMode = "(Unknown Mode)";
+ break;
+ }
+ printk(KERN_WARNING DRIVER_PREFIX ": %s: PVR Device %u: Display %s\n",
+ __FUNCTION__, uiPVRDevID, pszMode);
+ }
+#endif
+ switch(uiCmd)
+ {
+ case PVR_DRM_DISP_CMD_ON:
+ iFBMode = FB_BLANK_UNBLANK;
+ break;
+ case PVR_DRM_DISP_CMD_STANDBY:
+ iFBMode = FB_BLANK_HSYNC_SUSPEND;
+ break;
+ case PVR_DRM_DISP_CMD_SUSPEND:
+ iFBMode = FB_BLANK_VSYNC_SUSPEND;
+ break;
+ case PVR_DRM_DISP_CMD_OFF:
+ iFBMode = FB_BLANK_POWERDOWN;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ OMAPLFBCreateSwapChainLock(psDevInfo);
+
+ if (psDevInfo->psSwapChain != NULL)
+ {
+ flush_workqueue(psDevInfo->psSwapChain->psWorkQueue);
+ }
+
+ OMAPLFB_CONSOLE_LOCK();
+ ret = fb_blank(psDevInfo->psLINFBInfo, iFBMode);
+ OMAPLFB_CONSOLE_UNLOCK();
+
+ OMAPLFBCreateSwapChainUnLock(psDevInfo);
+
+ break;
+ }
+ default:
+ {
+ ret = -EINVAL;
+ break;
+ }
+ }
+
+ return ret;
+}
+#endif
+
+/* Insert the driver into the kernel */
+#if defined(SUPPORT_DRI_DRM)
+int PVR_DRM_MAKENAME(DISPLAY_CONTROLLER, _Init)(struct drm_device unref__ *dev)
+#else
+static int __init OMAPLFB_Init(void)
+#endif
+{
+
+ if(OMAPLFBInit() != OMAPLFB_OK)
+ {
+ printk(KERN_ERR DRIVER_PREFIX ": %s: OMAPLFBInit failed\n", __FUNCTION__);
+ return -ENODEV;
+ }
+
+ return 0;
+
+}
+
+/* Remove the driver from the kernel */
+#if defined(SUPPORT_DRI_DRM)
+void PVR_DRM_MAKENAME(DISPLAY_CONTROLLER, _Cleanup)(struct drm_device unref__ *dev)
+#else
+static void __exit OMAPLFB_Cleanup(void)
+#endif
+{
+ if(OMAPLFBDeInit() != OMAPLFB_OK)
+ {
+ printk(KERN_ERR DRIVER_PREFIX ": %s: OMAPLFBDeInit failed\n", __FUNCTION__);
+ }
+}
+
+#if !defined(SUPPORT_DRI_DRM)
+/*
+ These macro calls define the initialisation and removal functions of the
+ driver. Although they are prefixed `module_', they apply when compiling
+ statically as well; in both cases they define the function the kernel will
+ run to start/stop the driver.
+*/
+late_initcall(OMAPLFB_Init);
+module_exit(OMAPLFB_Cleanup);
+#endif