summaryrefslogtreecommitdiff
path: root/sgx/services4/3rdparty/dc_omap_linux
diff options
context:
space:
mode:
Diffstat (limited to 'sgx/services4/3rdparty/dc_omap_linux')
-rwxr-xr-xsgx/services4/3rdparty/dc_omap_linux/3rdparty_dc_drm_shared.h45
-rwxr-xr-xsgx/services4/3rdparty/dc_omap_linux/Kbuild.mk33
-rwxr-xr-xsgx/services4/3rdparty/dc_omap_linux/Linux.mk30
-rwxr-xr-xsgx/services4/3rdparty/dc_omap_linux/omaplfb.h253
-rwxr-xr-xsgx/services4/3rdparty/dc_omap_linux/omaplfb_displayclass.c1969
-rwxr-xr-xsgx/services4/3rdparty/dc_omap_linux/omaplfb_linux.c520
6 files changed, 2850 insertions, 0 deletions
diff --git a/sgx/services4/3rdparty/dc_omap_linux/3rdparty_dc_drm_shared.h b/sgx/services4/3rdparty/dc_omap_linux/3rdparty_dc_drm_shared.h
new file mode 100755
index 0000000..5ba3e7b
--- /dev/null
+++ b/sgx/services4/3rdparty/dc_omap_linux/3rdparty_dc_drm_shared.h
@@ -0,0 +1,45 @@
+/**********************************************************************
+ *
+ * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful but, except
+ * as otherwise stated in writing, without any warranty; without even the
+ * implied warranty of merchantability or fitness for a particular purpose.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Imagination Technologies Ltd. <gpl-support@imgtec.com>
+ * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
+ *
+ ******************************************************************************/
+
+#ifndef __3RDPARTY_DC_DRM_SHARED_H__
+#define __3RDPARTY_DC_DRM_SHARED_H__
+#if defined(SUPPORT_DRI_DRM)
+
+#define PVR_DRM_DISP_CMD_ENTER_VT 1
+#define PVR_DRM_DISP_CMD_LEAVE_VT 2
+
+#define PVR_DRM_DISP_CMD_ON 3
+#define PVR_DRM_DISP_CMD_STANDBY 4
+#define PVR_DRM_DISP_CMD_SUSPEND 5
+#define PVR_DRM_DISP_CMD_OFF 6
+#define PVR_DRM_DISP_CMD_RESYNC 7
+
+#define PVR_DRM_DISP_ARG_CMD 0
+#define PVR_DRM_DISP_ARG_DEV 1
+#define PVR_DRM_DISP_NUM_ARGS 2
+
+#endif
+#endif
diff --git a/sgx/services4/3rdparty/dc_omap_linux/Kbuild.mk b/sgx/services4/3rdparty/dc_omap_linux/Kbuild.mk
new file mode 100755
index 0000000..0abcaff
--- /dev/null
+++ b/sgx/services4/3rdparty/dc_omap_linux/Kbuild.mk
@@ -0,0 +1,33 @@
+#
+# Copyright (C) Imagination Technologies Ltd. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms and conditions of the GNU General Public License,
+# version 2, as published by the Free Software Foundation.
+#
+# This program is distributed in the hope it will be useful but, except
+# as otherwise stated in writing, without any warranty; without even the
+# implied warranty of merchantability or fitness for a particular purpose.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# The full GNU General Public License is included in this distribution in
+# the file called "COPYING".
+#
+# Contact Information:
+# Imagination Technologies Ltd. <gpl-support@imgtec.com>
+# Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
+#
+#
+
+ccflags-y += \
+ -I$(TOP)/services4/3rdparty/dc_omap_linux \
+ -I$(KERNELDIR)/drivers/video/omap2 \
+ -I$(KERNELDIR)/arch/arm/plat-omap/include
+
+omaplfb-y += \
+ services4/3rdparty/dc_omap_linux/omaplfb_displayclass.o \
+ services4/3rdparty/dc_omap_linux/omaplfb_linux.o
diff --git a/sgx/services4/3rdparty/dc_omap_linux/Linux.mk b/sgx/services4/3rdparty/dc_omap_linux/Linux.mk
new file mode 100755
index 0000000..a3d619d
--- /dev/null
+++ b/sgx/services4/3rdparty/dc_omap_linux/Linux.mk
@@ -0,0 +1,30 @@
+#
+# Copyright (C) Imagination Technologies Ltd. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms and conditions of the GNU General Public License,
+# version 2, as published by the Free Software Foundation.
+#
+# This program is distributed in the hope it will be useful but, except
+# as otherwise stated in writing, without any warranty; without even the
+# implied warranty of merchantability or fitness for a particular purpose.
+# See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# The full GNU General Public License is included in this distribution in
+# the file called "COPYING".
+#
+# Contact Information:
+# Imagination Technologies Ltd. <gpl-support@imgtec.com>
+# Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
+#
+#
+
+modules := dc_omap_linux
+
+dc_omap_linux_type := kernel_module
+dc_omap_linux_target := omaplfb.ko
+dc_omap_linux_makefile := $(THIS_DIR)/Kbuild.mk
diff --git a/sgx/services4/3rdparty/dc_omap_linux/omaplfb.h b/sgx/services4/3rdparty/dc_omap_linux/omaplfb.h
new file mode 100755
index 0000000..06bccee
--- /dev/null
+++ b/sgx/services4/3rdparty/dc_omap_linux/omaplfb.h
@@ -0,0 +1,253 @@
+/**********************************************************************
+ *
+ * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful but, except
+ * as otherwise stated in writing, without any warranty; without even the
+ * implied warranty of merchantability or fitness for a particular purpose.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Imagination Technologies Ltd. <gpl-support@imgtec.com>
+ * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
+ *
+ ******************************************************************************/
+
+#ifndef __OMAPLFB_H__
+#define __OMAPLFB_H__
+
+/* max number of overlays to which a framebuffer data can be direct */
+#define OMAPFB_MAX_OVL_PER_FB 3
+
+extern IMG_BOOL PVRGetDisplayClassJTable(PVRSRV_DC_DISP2SRV_KMJTABLE *psJTable);
+
+typedef void * OMAP_HANDLE;
+
+typedef enum tag_omap_bool
+{
+ OMAP_FALSE = 0,
+ OMAP_TRUE = 1,
+} OMAP_BOOL, *OMAP_PBOOL;
+
+typedef struct OMAPLFB_BUFFER_TAG
+{
+ unsigned long ulBufferSize;
+ IMG_SYS_PHYADDR sSysAddr;
+ IMG_CPU_VIRTADDR sCPUVAddr;
+ PVRSRV_SYNC_DATA* psSyncData;
+ struct OMAPLFB_BUFFER_TAG* psNext;
+
+} OMAPLFB_BUFFER;
+
+typedef struct OMAPLFB_FLIP_ITEM_TAG
+{
+ OMAP_HANDLE hCmdComplete;
+ unsigned long ulSwapInterval;
+ OMAP_BOOL bValid;
+ OMAP_BOOL bFlipped;
+ OMAP_BOOL bCmdCompleted;
+ IMG_SYS_PHYADDR* sSysAddr;
+
+} OMAPLFB_FLIP_ITEM;
+
+typedef struct PVRPDP_SWAPCHAIN_TAG
+{
+ unsigned int uiSwapChainID;
+ unsigned long ulBufferCount;
+ OMAPLFB_BUFFER* psBuffer;
+ OMAPLFB_FLIP_ITEM* psFlipItems;
+ unsigned long ulInsertIndex;
+ unsigned long ulRemoveIndex;
+ PVRSRV_DC_DISP2SRV_KMJTABLE* psPVRJTable;
+ OMAP_BOOL bFlushCommands;
+ unsigned long ulSetFlushStateRefCount;
+ OMAP_BOOL bBlanked;
+ spinlock_t* psSwapChainLock;
+ void* pvDevInfo;
+
+} 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;
+ IMG_SYS_PHYADDR sSysAddr;
+ IMG_CPU_VIRTADDR sCPUVAddr;
+ PVRSRV_PIXEL_FORMAT ePixelFormat;
+ int iFBId;
+}OMAPLFB_FBINFO;
+
+typedef struct OMAPLFB_DEVINFO_TAG
+{
+ unsigned int uiSwapChainID;
+ IMG_UINT32 uDeviceID;
+ OMAPLFB_BUFFER sSystemBuffer;
+ PVRSRV_DC_DISP2SRV_KMJTABLE sPVRJTable;
+ PVRSRV_DC_SRV2DISP_KMJTABLE sDCJTable;
+ OMAPLFB_FBINFO sFBInfo;
+ OMAPLFB_SWAPCHAIN* psSwapChain;
+ OMAP_BOOL bFlushCommands;
+ struct fb_info* psLINFBInfo;
+ struct notifier_block sLINNotifBlock;
+ OMAP_BOOL bDeviceSuspended;
+ struct mutex sSwapChainLockMutex;
+ IMG_DEV_VIRTADDR sDisplayDevVAddr;
+ DISPLAY_INFO sDisplayInfo;
+ DISPLAY_FORMAT sDisplayFormat;
+ DISPLAY_DIMS sDisplayDim;
+ struct workqueue_struct* sync_display_wq;
+ struct work_struct sync_display_work;
+#if defined(SUPPORT_DRI_DRM)
+ OMAP_BOOL bLeaveVT;
+#endif
+} OMAPLFB_DEVINFO;
+
+typedef enum _OMAP_ERROR_
+{
+ OMAP_OK = 0,
+ OMAP_ERROR_GENERIC = 1,
+ OMAP_ERROR_OUT_OF_MEMORY = 2,
+ OMAP_ERROR_TOO_FEW_BUFFERS = 3,
+ OMAP_ERROR_INVALID_PARAMS = 4,
+ OMAP_ERROR_INIT_FAILURE = 5,
+ OMAP_ERROR_CANT_REGISTER_CALLBACK = 6,
+ OMAP_ERROR_INVALID_DEVICE = 7,
+ OMAP_ERROR_DEVICE_REGISTER_FAILED = 8
+
+} OMAP_ERROR;
+
+struct omapfb2_mem_region {
+ int id;
+ u32 paddr;
+ void __iomem *vaddr;
+ struct vrfb vrfb;
+ unsigned long size;
+ u8 type; /* OMAPFB_PLANE_MEM_* */
+ bool alloc; /* allocated by the driver */
+ bool map; /* kernel mapped by the driver */
+ atomic_t map_count;
+ struct rw_semaphore lock;
+ atomic_t lock_count;
+};
+
+struct omapfb_info {
+ int id;
+ struct omapfb2_mem_region *region;
+ int num_overlays;
+ struct omap_overlay *overlays[OMAPFB_MAX_OVL_PER_FB];
+ struct omapfb2_device *fbdev;
+ enum omap_dss_rotation_type rotation_type;
+ u8 rotation[OMAPFB_MAX_OVL_PER_FB];
+ bool mirror;
+};
+
+struct omapfb2_device {
+ struct device *dev;
+ struct mutex mtx;
+
+ u32 pseudo_palette[17];
+
+ int state;
+
+ unsigned num_fbs;
+ struct fb_info *fbs[10];
+ struct omapfb2_mem_region regions[10];
+
+ unsigned num_displays;
+ struct omap_dss_device *displays[10];
+ unsigned num_overlays;
+ struct omap_overlay *overlays[10];
+ unsigned num_managers;
+ struct omap_overlay_manager *managers[10];
+
+ unsigned num_bpp_overrides;
+ struct {
+ struct omap_dss_device *dssdev;
+ u8 bpp;
+ } bpp_overrides[10];
+};
+
+#define OMAPLFB_PAGE_SIZE 4096
+#define OMAPLFB_PAGE_MASK (OMAPLFB_PAGE_SIZE - 1)
+#define OMAPLFB_PAGE_TRUNC (~OMAPLFB_PAGE_MASK)
+
+#define OMAPLFB_PAGE_ROUNDUP(x) (((x)+OMAPLFB_PAGE_MASK) & OMAPLFB_PAGE_TRUNC)
+
+#define DISPLAY_DEVICE_NAME "PowerVR OMAP Linux Display Driver"
+#define DRVNAME "omaplfb"
+#define DEVNAME DRVNAME
+#define DRIVER_PREFIX DRVNAME
+
+#define FRAMEBUFFER_COUNT num_registered_fb
+
+#define DEBUG
+#ifdef DEBUG
+#define DEBUG_PRINTK(format, ...) printk(KERN_DEBUG DRIVER_PREFIX \
+ " (%s %i): " format "\n", __func__, __LINE__, ## __VA_ARGS__)
+#else
+#define DEBUG_PRINTK(format,...)
+#endif
+
+#define WARNING_PRINTK(format, ...) printk(KERN_WARNING DRIVER_PREFIX \
+ " (%s %i): " format "\n", __func__, __LINE__, ## __VA_ARGS__)
+#define ERROR_PRINTK(format, ...) printk(KERN_ERR DRIVER_PREFIX \
+ " (%s %i): " format "\n", __func__, __LINE__, ## __VA_ARGS__)
+
+#define FB2OFB(fb_info) ((struct omapfb_info *)(fb_info->par))
+
+static inline void omapfb_lock(struct omapfb2_device *fbdev)
+{
+ mutex_lock(&fbdev->mtx);
+}
+
+static inline void omapfb_unlock(struct omapfb2_device *fbdev)
+{
+ mutex_unlock(&fbdev->mtx);
+}
+
+/* find the display connected to this fb, if any */
+static inline struct omap_dss_device *fb2display(struct fb_info *fbi)
+{
+ struct omapfb_info *ofbi = FB2OFB(fbi);
+ int i;
+
+ /* XXX: returns the display connected to first attached overlay */
+ for (i = 0; i < ofbi->num_overlays; i++) {
+ if (ofbi->overlays[i]->manager)
+ return ofbi->overlays[i]->manager->device;
+ }
+ return NULL;
+}
+
+OMAP_ERROR OMAPLFBInit(void);
+OMAP_ERROR OMAPLFBDeinit(void);
+OMAP_ERROR UnBlankDisplay(OMAPLFB_DEVINFO *psDevInfo);
+void *OMAPLFBAllocKernelMem(unsigned long ulSize);
+void OMAPLFBFreeKernelMem(void *pvMem);
+void OMAPLFBPresentSync(OMAPLFB_DEVINFO *psDevInfo,
+ OMAPLFB_FLIP_ITEM *psFlipItem);
+void OMAPLFBPresentSyncAddr(OMAPLFB_DEVINFO *psDevInfo, unsigned long aPhyAddr);
+OMAP_ERROR OMAPLFBGetLibFuncAddr(char *szFunctionName,
+ PFN_DC_GET_PVRJTABLE *ppfnFuncTable);
+void OMAPLFBFlip(OMAPLFB_SWAPCHAIN *psSwapChain, unsigned long aPhyAddr);
+#ifdef LDM_PLATFORM
+void OMAPLFBDriverSuspend(void);
+void OMAPLFBDriverResume(void);
+#endif
+
+#endif
diff --git a/sgx/services4/3rdparty/dc_omap_linux/omaplfb_displayclass.c b/sgx/services4/3rdparty/dc_omap_linux/omaplfb_displayclass.c
new file mode 100755
index 0000000..0d62c14
--- /dev/null
+++ b/sgx/services4/3rdparty/dc_omap_linux/omaplfb_displayclass.c
@@ -0,0 +1,1969 @@
+/**********************************************************************
+ *
+ * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful but, except
+ * as otherwise stated in writing, without any warranty; without even the
+ * implied warranty of merchantability or fitness for a particular purpose.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Imagination Technologies Ltd. <gpl-support@imgtec.com>
+ * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
+ *
+ ******************************************************************************/
+
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/console.h>
+#include <linux/fb.h>
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32))
+#include <plat/vrfb.h>
+#include <plat/display.h>
+#else
+#include <mach/vrfb.h>
+#include <mach/display.h>
+#endif
+
+#if defined(SUPPORT_DRI_DRM)
+#include <drm/drmP.h>
+#include <linux/omap_gpu.h>
+#else
+#include <linux/module.h>
+#endif
+
+#include <linux/string.h>
+#include <linux/notifier.h>
+
+#include "img_defs.h"
+#include "servicesext.h"
+#include "kerneldisplay.h"
+#include "omaplfb.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
+
+#define OMAPLFB_COMMAND_COUNT 1
+#define MAX_BUFFERS_FLIPPING 3
+/* Put 0 as desired bpp to use the default in the framebuffer */
+#define DESIRED_BPP 0 /* Possible values 32,16,0 */
+
+/* Pointer Display->Services */
+static PFN_DC_GET_PVRJTABLE pfnGetPVRJTable = NULL;
+
+/* Pointer to the display devices */
+static OMAPLFB_DEVINFO *pDisplayDevices = NULL;
+
+static void OMAPLFBSyncIHandler(struct work_struct*);
+
+static OMAP_ERROR ReInitDev(OMAPLFB_DEVINFO *psDevInfo);
+
+/*
+ * Swap to display buffer. This buffer refers to one inside the
+ * framebuffer memory.
+ * in: hDevice, hBuffer, ui32SwapInterval, hPrivateTag, ui32ClipRectCount,
+ * psClipRect
+ */
+static PVRSRV_ERROR SwapToDCBuffer(IMG_HANDLE hDevice,
+ IMG_HANDLE hBuffer,
+ IMG_UINT32 ui32SwapInterval,
+ IMG_HANDLE hPrivateTag,
+ IMG_UINT32 ui32ClipRectCount,
+ IMG_RECT *psClipRect)
+{
+ /* Nothing to do */
+ return PVRSRV_OK;
+}
+
+/*
+ * Set display destination rectangle.
+ * in: hDevice, hSwapChain, psRect
+ */
+static PVRSRV_ERROR SetDCDstRect(IMG_HANDLE hDevice,
+ IMG_HANDLE hSwapChain,
+ IMG_RECT *psRect)
+{
+ /* Nothing to do */
+ return PVRSRV_ERROR_NOT_SUPPORTED;
+}
+
+/*
+ * Set display source rectangle.
+ * in: hDevice, hSwapChain, psRect
+ */
+static PVRSRV_ERROR SetDCSrcRect(IMG_HANDLE hDevice,
+ IMG_HANDLE hSwapChain,
+ IMG_RECT *psRect)
+{
+ /* Nothing to do */
+ return PVRSRV_ERROR_NOT_SUPPORTED;
+}
+
+/*
+ * Set display destination colour key.
+ * in: hDevice, hSwapChain, ui32CKColour
+ */
+static PVRSRV_ERROR SetDCDstColourKey(IMG_HANDLE hDevice,
+ IMG_HANDLE hSwapChain,
+ IMG_UINT32 ui32CKColour)
+{
+ /* Nothing to do */
+ return PVRSRV_ERROR_NOT_SUPPORTED;
+}
+
+/*
+ * Set display source colour key.
+ * in: hDevice, hSwapChain, ui32CKColour
+ */
+static PVRSRV_ERROR SetDCSrcColourKey(IMG_HANDLE hDevice,
+ IMG_HANDLE hSwapChain,
+ IMG_UINT32 ui32CKColour)
+{
+ /* Nothing to do */
+ return PVRSRV_ERROR_NOT_SUPPORTED;
+}
+
+/*
+ * Closes the display.
+ * in: hDevice
+ */
+static PVRSRV_ERROR CloseDCDevice(IMG_HANDLE hDevice)
+{
+#if defined(SUPPORT_DRI_DRM)
+ OMAPLFB_DEVINFO *psDevInfo = (OMAPLFB_DEVINFO *)hDevice;
+
+ psDevInfo->bLeaveVT = OMAP_FALSE;
+ UnBlankDisplay(psDevInfo);
+#endif
+ /* Nothing to do */
+ return PVRSRV_OK;
+}
+
+/*
+ * Flushes the sync queue present in the specified swap chain.
+ * in: psSwapChain
+ */
+static void FlushInternalSyncQueue(OMAPLFB_SWAPCHAIN *psSwapChain)
+{
+#ifdef DEBUG
+ OMAPLFB_DEVINFO *psDevInfo = (OMAPLFB_DEVINFO *) psSwapChain->pvDevInfo;
+#endif
+ OMAPLFB_FLIP_ITEM *psFlipItem;
+ unsigned long ulMaxIndex;
+ unsigned long i;
+
+ psFlipItem = &psSwapChain->psFlipItems[psSwapChain->ulRemoveIndex];
+ ulMaxIndex = psSwapChain->ulBufferCount - 1;
+
+#ifdef DEBUG
+ DEBUG_PRINTK("Flushing sync queue on display %u",
+ psDevInfo->uDeviceID);
+#endif
+ for(i = 0; i < psSwapChain->ulBufferCount; i++)
+ {
+ if (psFlipItem->bValid == OMAP_FALSE)
+ continue;
+
+ DEBUG_PRINTK("Flushing swap buffer index %lu",
+ psSwapChain->ulRemoveIndex);
+
+ /* Flip the buffer if it hasn't been flipped */
+ if(psFlipItem->bFlipped == OMAP_FALSE)
+ {
+ OMAPLFBFlip(psSwapChain,
+ (unsigned long)psFlipItem->sSysAddr);
+ }
+
+ /* If the command didn't complete, assume it did */
+ if(psFlipItem->bCmdCompleted == OMAP_FALSE)
+ {
+ DEBUG_PRINTK("Calling command complete for swap "
+ "buffer index %lu",
+ psSwapChain->ulRemoveIndex);
+ psSwapChain->psPVRJTable->pfnPVRSRVCmdComplete(
+ (IMG_HANDLE)psFlipItem->hCmdComplete,
+ IMG_TRUE);
+ }
+
+ psSwapChain->ulRemoveIndex++;
+ if(psSwapChain->ulRemoveIndex > ulMaxIndex)
+ psSwapChain->ulRemoveIndex = 0;
+
+ /* Put the state of the buffer to be used again later */
+ psFlipItem->bFlipped = OMAP_FALSE;
+ psFlipItem->bCmdCompleted = OMAP_FALSE;
+ psFlipItem->bValid = OMAP_FALSE;
+ psFlipItem =
+ &psSwapChain->psFlipItems[psSwapChain->ulRemoveIndex];
+ }
+
+ psSwapChain->ulInsertIndex = 0;
+ psSwapChain->ulRemoveIndex = 0;
+}
+
+/*
+ * Sets the flush state of the specified display device
+ * at the swap chain level without blocking the call.
+ * in: psDevInfo, bFlushState
+ */
+static void SetFlushStateInternalNoLock(OMAPLFB_DEVINFO* psDevInfo,
+ OMAP_BOOL bFlushState)
+{
+ OMAPLFB_SWAPCHAIN *psSwapChain = psDevInfo->psSwapChain;
+
+ /* Nothing to do if there is no swap chain */
+ if (psSwapChain == NULL){
+ DEBUG_PRINTK("Swap chain is null, nothing to do for"
+ " display %u", psDevInfo->uDeviceID);
+ return;
+ }
+
+ if (bFlushState)
+ {
+ DEBUG_PRINTK("Desired flushState is true for display %u",
+ psDevInfo->uDeviceID);
+ if (psSwapChain->ulSetFlushStateRefCount == 0)
+ {
+ psSwapChain->bFlushCommands = OMAP_TRUE;
+ FlushInternalSyncQueue(psSwapChain);
+ }
+ psSwapChain->ulSetFlushStateRefCount++;
+ }
+ else
+ {
+ DEBUG_PRINTK("Desired flushState is false for display %u",
+ psDevInfo->uDeviceID);
+ if (psSwapChain->ulSetFlushStateRefCount != 0)
+ {
+ psSwapChain->ulSetFlushStateRefCount--;
+ if (psSwapChain->ulSetFlushStateRefCount == 0)
+ {
+ psSwapChain->bFlushCommands = OMAP_FALSE;
+ }
+ }
+ }
+}
+
+/*
+ * Sets the flush state of the specified display device
+ * at the swap chain level blocking the call if needed.
+ * in: psDevInfo, bFlushState
+ */
+static IMG_VOID SetFlushStateInternal(OMAPLFB_DEVINFO* psDevInfo,
+ OMAP_BOOL bFlushState)
+{
+ DEBUG_PRINTK("Executing for display %u",
+ psDevInfo->uDeviceID);
+ mutex_lock(&psDevInfo->sSwapChainLockMutex);
+ SetFlushStateInternalNoLock(psDevInfo, bFlushState);
+ mutex_unlock(&psDevInfo->sSwapChainLockMutex);
+}
+
+/*
+ * Sets the flush state of the specified display device
+ * at device level blocking the call if needed.
+ * in: psDevInfo, bFlushState
+ */
+static void SetFlushStateExternal(OMAPLFB_DEVINFO* psDevInfo,
+ OMAP_BOOL bFlushState)
+{
+ DEBUG_PRINTK("Executing for display %u",
+ psDevInfo->uDeviceID);
+ mutex_lock(&psDevInfo->sSwapChainLockMutex);
+ if (psDevInfo->bFlushCommands != bFlushState)
+ {
+ psDevInfo->bFlushCommands = bFlushState;
+ SetFlushStateInternalNoLock(psDevInfo, bFlushState);
+ }
+ mutex_unlock(&psDevInfo->sSwapChainLockMutex);
+}
+
+/*
+ * Unblank the framebuffer display
+ * in: psDevInfo
+ */
+OMAP_ERROR UnBlankDisplay(OMAPLFB_DEVINFO *psDevInfo)
+{
+ DEBUG_PRINTK("Executing for display %u",
+ psDevInfo->uDeviceID);
+
+ acquire_console_sem();
+ if (fb_blank(psDevInfo->psLINFBInfo, FB_BLANK_UNBLANK))
+ {
+ release_console_sem();
+ WARNING_PRINTK("fb_blank FB_BLANK_UNBLANK failed");
+ return OMAP_ERROR_GENERIC;
+ }
+ release_console_sem();
+
+ return OMAP_OK;
+}
+
+/*
+ * Blank the framebuffer display
+ * in: psDevInfo
+ */
+#if defined(SUPPORT_DRI_DRM) && defined(PVR_DISPLAY_CONTROLLER_DRM_IOCTL)
+static OMAP_ERROR BlankDisplay(OMAPLFB_DEVINFO *psDevInfo, int blank_cmd)
+{
+ DEBUG_PRINTK("Executing for display %u",
+ psDevInfo->uDeviceID);
+
+ acquire_console_sem();
+ if (fb_blank(psDevInfo->psLINFBInfo, blank_cmd)) {
+ release_console_sem();
+ WARNING_PRINTK("fb_blank %i failed", blank_cmd);
+ return OMAP_ERROR_GENERIC;
+ }
+ release_console_sem();
+
+ return OMAP_OK;
+}
+#endif
+
+/*
+ * Framebuffer listener
+ * in: psNotif, event, data
+ */
+static int FrameBufferEvents(struct notifier_block *psNotif,
+ unsigned long event, void *data)
+{
+ OMAPLFB_DEVINFO *psDevInfo;
+ OMAPLFB_SWAPCHAIN *psSwapChain;
+ struct fb_event *psFBEvent = (struct fb_event *)data;
+ OMAP_BOOL bBlanked;
+ int i;
+
+ DEBUG_PRINTK("Framebuffer event (%lu) happened", event);
+ if (event != FB_EVENT_BLANK){
+ DEBUG_PRINTK("Ignoring");
+ return 0;
+ }
+
+ DEBUG_PRINTK("Event is FB_EVENT_BLANK");
+
+ psDevInfo = 0;
+ for(i = 0; i < FRAMEBUFFER_COUNT; i++)
+ {
+ if(psFBEvent->info == (&pDisplayDevices[i])->psLINFBInfo)
+ {
+ psDevInfo = &pDisplayDevices[i];
+ break;
+ }
+ }
+
+ if(!psDevInfo)
+ {
+ WARNING_PRINTK("Unable to find the display related to "
+ " the framebuffer event");
+ return 1;
+ }
+
+ psSwapChain = psDevInfo->psSwapChain;
+
+ if(!psSwapChain)
+ {
+ DEBUG_PRINTK("No swapchain associated with this display");
+ return 0;
+ }
+
+ bBlanked = (*(IMG_INT *)psFBEvent->data != 0) ?
+ OMAP_TRUE: OMAP_FALSE;
+
+ /* Check if the blank state is the same as the swap chain */
+ if (bBlanked != psSwapChain->bBlanked)
+ {
+ DEBUG_PRINTK("Executing for display %u",
+ psDevInfo->uDeviceID);
+
+ /* Set the new blank state in the swap chain */
+ psSwapChain->bBlanked = bBlanked;
+
+ if (bBlanked)
+ {
+ DEBUG_PRINTK("Requesting flush state true for"
+ " display %u", psDevInfo->uDeviceID);
+ SetFlushStateInternal(psDevInfo, OMAP_TRUE);
+ }
+ else
+ {
+ DEBUG_PRINTK("Requesting flush state false for"
+ " display %u", psDevInfo->uDeviceID);
+ SetFlushStateInternal(psDevInfo, OMAP_FALSE);
+ }
+ }
+ else
+ {
+ DEBUG_PRINTK("Ignoring event for display %u",
+ psDevInfo->uDeviceID);
+ }
+
+ return 0;
+}
+
+/*
+ * Registers a listener for changes in the framebuffer
+ * in: psDevInfo
+ */
+static OMAP_ERROR EnableLFBEventNotification(OMAPLFB_DEVINFO *psDevInfo)
+{
+ OMAPLFB_SWAPCHAIN *psSwapChain = psDevInfo->psSwapChain;
+ OMAP_ERROR eError;
+
+ memset(&psDevInfo->sLINNotifBlock, 0,
+ sizeof(psDevInfo->sLINNotifBlock));
+
+ /* Register the function to listen the changes */
+ psDevInfo->sLINNotifBlock.notifier_call = FrameBufferEvents;
+ psSwapChain->bBlanked = OMAP_FALSE;
+
+ DEBUG_PRINTK("Registering framebuffer event listener for"
+ " display %u", psDevInfo->uDeviceID);
+
+ if (fb_register_client(&psDevInfo->sLINNotifBlock))
+ {
+ WARNING_PRINTK("fb_register_client failed for"
+ " display %u", psDevInfo->uDeviceID);
+ return OMAP_ERROR_GENERIC;
+ }
+
+ eError = UnBlankDisplay(psDevInfo);
+ if (eError != OMAP_OK)
+ {
+ WARNING_PRINTK("UnBlankDisplay failed for"
+ " display %u", psDevInfo->uDeviceID);
+ return eError;
+ }
+
+ return OMAP_OK;
+}
+
+/*
+ * Unregister a listener from the framebuffer
+ * in: psDevInfo
+ */
+static OMAP_ERROR DisableLFBEventNotification(OMAPLFB_DEVINFO *psDevInfo)
+{
+ DEBUG_PRINTK("Removing framebuffer event listener for"
+ " display %u", psDevInfo->uDeviceID);
+
+ if (fb_unregister_client(&psDevInfo->sLINNotifBlock))
+ {
+ WARNING_PRINTK("fb_unregister_client failed for"
+ " display %u", psDevInfo->uDeviceID);
+ return OMAP_ERROR_GENERIC;
+ }
+
+ return OMAP_OK;
+}
+
+/*
+ * Opens the display.
+ * in: ui32DeviceID, phDevice
+ * out: psSystemBufferSyncData
+ */
+static PVRSRV_ERROR OpenDCDevice(IMG_UINT32 ui32DeviceID,
+ IMG_HANDLE *phDevice,
+ PVRSRV_SYNC_DATA* psSystemBufferSyncData)
+{
+ OMAPLFB_DEVINFO *psDevInfo;
+ int i;
+
+ psDevInfo = 0;
+ for(i = 0; i < FRAMEBUFFER_COUNT; i++)
+ {
+ if (ui32DeviceID == (&pDisplayDevices[i])->uDeviceID)
+ {
+ psDevInfo = &pDisplayDevices[i];
+ break;
+ }
+ }
+
+ if(!psDevInfo)
+ {
+ WARNING_PRINTK("Unable to identify display device with id %i",
+ (int)ui32DeviceID);
+ return 1;
+ }
+
+ ReInitDev(psDevInfo);
+
+ psDevInfo->sSystemBuffer.psSyncData = psSystemBufferSyncData;
+ if ( UnBlankDisplay(psDevInfo) != OMAP_OK)
+ {
+ WARNING_PRINTK("UnBlankDisplay failed for"
+ " display %u", psDevInfo->uDeviceID);
+ return PVRSRV_ERROR_UNBLANK_DISPLAY_FAILED;
+ }
+ *phDevice = (IMG_HANDLE)psDevInfo;
+
+ return PVRSRV_OK;
+}
+
+/*
+ * Gets the available formats for the display.
+ * in: hDevice
+ * out: pui32NumFormats, psFormat
+ */
+static PVRSRV_ERROR EnumDCFormats(IMG_HANDLE hDevice,
+ IMG_UINT32 *pui32NumFormats,
+ DISPLAY_FORMAT *psFormat)
+{
+ OMAPLFB_DEVINFO *psDevInfo;
+ if(!hDevice || !pui32NumFormats)
+ {
+ ERROR_PRINTK("Invalid parameters");
+ return PVRSRV_ERROR_INVALID_PARAMS;
+ }
+
+ psDevInfo = (OMAPLFB_DEVINFO*)hDevice;
+ *pui32NumFormats = 1;
+
+ if(psFormat)
+ psFormat[0] = psDevInfo->sDisplayFormat;
+ else
+ WARNING_PRINTK("Display format is null for"
+ " display %u", psDevInfo->uDeviceID);
+
+ return PVRSRV_OK;
+}
+
+/*
+ * Gets the available dimensions for the display.
+ * in: hDevice, psFormat
+ * out: pui32NumDims, psDim
+ */
+static PVRSRV_ERROR EnumDCDims(IMG_HANDLE hDevice,
+ DISPLAY_FORMAT *psFormat,
+ IMG_UINT32 *pui32NumDims,
+ DISPLAY_DIMS *psDim)
+{
+ OMAPLFB_DEVINFO *psDevInfo;
+ if(!hDevice || !psFormat || !pui32NumDims)
+ {
+ ERROR_PRINTK("Invalid parameters");
+ return PVRSRV_ERROR_INVALID_PARAMS;
+ }
+
+ psDevInfo = (OMAPLFB_DEVINFO*)hDevice;
+ *pui32NumDims = 1;
+
+ if(psDim)
+ psDim[0] = psDevInfo->sDisplayDim;
+ else
+ WARNING_PRINTK("Display dimensions are null for"
+ " display %u", psDevInfo->uDeviceID);
+
+ return PVRSRV_OK;
+}
+
+/*
+ * Gets the display framebuffer physical address.
+ * in: hDevice
+ * out: phBuffer
+ */
+static PVRSRV_ERROR GetDCSystemBuffer(IMG_HANDLE hDevice, IMG_HANDLE *phBuffer)
+{
+ OMAPLFB_DEVINFO *psDevInfo;
+
+ if(!hDevice || !phBuffer)
+ {
+ ERROR_PRINTK("Invalid parameters");
+ return PVRSRV_ERROR_INVALID_PARAMS;
+ }
+
+ psDevInfo = (OMAPLFB_DEVINFO*)hDevice;
+ *phBuffer = (IMG_HANDLE)&psDevInfo->sSystemBuffer;
+
+ return PVRSRV_OK;
+}
+
+/*
+ * Gets the display general information.
+ * in: hDevice
+ * out: psDCInfo
+ */
+static PVRSRV_ERROR GetDCInfo(IMG_HANDLE hDevice, DISPLAY_INFO *psDCInfo)
+{
+ OMAPLFB_DEVINFO *psDevInfo;
+
+ if(!hDevice || !psDCInfo)
+ {
+ ERROR_PRINTK("Invalid parameters");
+ return PVRSRV_ERROR_INVALID_PARAMS;
+ }
+
+ psDevInfo = (OMAPLFB_DEVINFO*)hDevice;
+ *psDCInfo = psDevInfo->sDisplayInfo;
+
+ return PVRSRV_OK;
+}
+
+/*
+ * Gets the display framebuffer virtual address.
+ * in: hDevice
+ * out: ppsSysAddr, pui32ByteSize, ppvCpuVAddr, phOSMapInfo, pbIsContiguous
+ */
+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;
+
+ if(!hDevice || !hBuffer || !ppsSysAddr || !pui32ByteSize )
+ {
+ ERROR_PRINTK("Invalid parameters");
+ return PVRSRV_ERROR_INVALID_PARAMS;
+ }
+
+ psDevInfo = (OMAPLFB_DEVINFO*)hDevice;
+ psSystemBuffer = (OMAPLFB_BUFFER *)hBuffer;
+ *ppsSysAddr = &psSystemBuffer->sSysAddr;
+ *pui32ByteSize = (IMG_UINT32)psDevInfo->sFBInfo.ulBufferSize;
+
+ if (ppvCpuVAddr)
+ *ppvCpuVAddr = psSystemBuffer->sCPUVAddr;
+
+ if (phOSMapInfo)
+ *phOSMapInfo = (IMG_HANDLE)0;
+
+ if (pbIsContiguous)
+ *pbIsContiguous = IMG_TRUE;
+
+ return PVRSRV_OK;
+}
+
+/*
+ * Creates a swap chain. Called when a 3D application begins.
+ * in: hDevice, ui32Flags, ui32BufferCount, psDstSurfAttrib, psSrcSurfAttrib
+ * ui32OEMFlags
+ * out: phSwapChain, ppsSyncData, pui32SwapChainID
+ */
+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;
+ OMAPLFB_FLIP_ITEM *psFlipItems;
+ IMG_UINT32 i;
+ PVRSRV_ERROR eError = PVRSRV_OK;
+ IMG_UINT32 ui32BuffersToSkip;
+
+ if(!hDevice || !psDstSurfAttrib || !psSrcSurfAttrib ||
+ !ppsSyncData || !phSwapChain)
+ {
+ ERROR_PRINTK("Invalid parameters");
+ return PVRSRV_ERROR_INVALID_PARAMS;
+ }
+ psDevInfo = (OMAPLFB_DEVINFO*)hDevice;
+
+ if (psDevInfo->sDisplayInfo.ui32MaxSwapChains == 0)
+ {
+ ERROR_PRINTK("Unable to operate with 0 MaxSwapChains for"
+ " display %u", psDevInfo->uDeviceID);
+ return PVRSRV_ERROR_NOT_SUPPORTED;
+ }
+
+ if(psDevInfo->psSwapChain != NULL)
+ {
+ ERROR_PRINTK("Swap chain already exists for"
+ " display %u", psDevInfo->uDeviceID);
+ return PVRSRV_ERROR_FLIP_CHAIN_EXISTS;
+ }
+
+ if(ui32BufferCount > psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers)
+ {
+ ERROR_PRINTK("Too many buffers. Trying to use %u buffers while"
+ " there is only %u available for display %u",
+ (unsigned int)ui32BufferCount,
+ (unsigned int)psDevInfo->
+ sDisplayInfo.ui32MaxSwapChainBuffers,
+ psDevInfo->uDeviceID);
+ return PVRSRV_ERROR_TOOMANYBUFFERS;
+ }
+
+
+ if ((psDevInfo->sFBInfo.ulRoundedBufferSize *
+ (unsigned long)ui32BufferCount) > psDevInfo->sFBInfo.ulFBSize)
+ {
+ ERROR_PRINTK("Too many buffers. Trying to use %u buffers "
+ "(%lu bytes each) while there is only %lu memory for"
+ " display %u",
+ (unsigned int)ui32BufferCount,
+ psDevInfo->sFBInfo.ulRoundedBufferSize,
+ psDevInfo->sFBInfo.ulFBSize,
+ psDevInfo->uDeviceID);
+ return PVRSRV_ERROR_TOOMANYBUFFERS;
+ }
+
+ ui32BuffersToSkip = psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers -
+ ui32BufferCount;
+
+ if((psDstSurfAttrib->pixelformat !=
+ psDevInfo->sDisplayFormat.pixelformat) ||
+ (psDstSurfAttrib->sDims.ui32ByteStride !=
+ psDevInfo->sDisplayDim.ui32ByteStride) ||
+ (psDstSurfAttrib->sDims.ui32Width !=
+ psDevInfo->sDisplayDim.ui32Width) ||
+ (psDstSurfAttrib->sDims.ui32Height !=
+ psDevInfo->sDisplayDim.ui32Height))
+ {
+ ERROR_PRINTK("Destination surface attributes differ from the"
+ " current framebuffer for display %u",
+ psDevInfo->uDeviceID);
+ return PVRSRV_ERROR_INVALID_PARAMS;
+ }
+
+ if((psDstSurfAttrib->pixelformat !=
+ psSrcSurfAttrib->pixelformat) ||
+ (psDstSurfAttrib->sDims.ui32ByteStride !=
+ psSrcSurfAttrib->sDims.ui32ByteStride) ||
+ (psDstSurfAttrib->sDims.ui32Width !=
+ psSrcSurfAttrib->sDims.ui32Width) ||
+ (psDstSurfAttrib->sDims.ui32Height !=
+ psSrcSurfAttrib->sDims.ui32Height))
+ {
+ ERROR_PRINTK("Destination surface attributes differ from the"
+ " target destination surface for display %u",
+ psDevInfo->uDeviceID);
+ return PVRSRV_ERROR_INVALID_PARAMS;
+ }
+
+ /* Allocate memory needed for the swap chain */
+ psSwapChain = (OMAPLFB_SWAPCHAIN*)OMAPLFBAllocKernelMem(
+ sizeof(OMAPLFB_SWAPCHAIN));
+ if(!psSwapChain)
+ {
+ ERROR_PRINTK("Out of memory to allocate swap chain for"
+ " display %u", psDevInfo->uDeviceID);
+ return PVRSRV_ERROR_OUT_OF_MEMORY;
+ }
+
+ DEBUG_PRINTK("Creating swap chain 0x%lx for display %u",
+ (unsigned long)psSwapChain, psDevInfo->uDeviceID);
+
+ /* Allocate memory for the buffer abstraction structures */
+ psBuffer = (OMAPLFB_BUFFER*)OMAPLFBAllocKernelMem(
+ sizeof(OMAPLFB_BUFFER) * ui32BufferCount);
+ if(!psBuffer)
+ {
+ ERROR_PRINTK("Out of memory to allocate the buffer"
+ " abstraction structures for display %u",
+ psDevInfo->uDeviceID);
+ eError = PVRSRV_ERROR_OUT_OF_MEMORY;
+ goto ErrorFreeSwapChain;
+ }
+
+ /* Allocate memory for the flip item abstraction structures */
+ psFlipItems = (OMAPLFB_FLIP_ITEM *)OMAPLFBAllocKernelMem(
+ sizeof(OMAPLFB_FLIP_ITEM) * ui32BufferCount);
+ if (!psFlipItems)
+ {
+ ERROR_PRINTK("Out of memory to allocate the flip item"
+ " abstraction structures for display %u",
+ psDevInfo->uDeviceID);
+ eError = PVRSRV_ERROR_OUT_OF_MEMORY;
+ goto ErrorFreeBuffers;
+ }
+
+ /* Assign to the swap chain structure the initial data */
+ psSwapChain->ulBufferCount = (unsigned long)ui32BufferCount;
+ psSwapChain->psBuffer = psBuffer;
+ psSwapChain->psFlipItems = psFlipItems;
+ psSwapChain->ulInsertIndex = 0;
+ psSwapChain->ulRemoveIndex = 0;
+ psSwapChain->psPVRJTable = &psDevInfo->sPVRJTable;
+ psSwapChain->pvDevInfo = (void*)psDevInfo;
+
+ /*
+ * Init the workqueue (single thread, freezable and real time)
+ * and its own work for this display
+ */
+ INIT_WORK(&psDevInfo->sync_display_work, OMAPLFBSyncIHandler);
+ psDevInfo->sync_display_wq =
+ __create_workqueue("pvr_display_sync_wq", 1, 1, 1);
+
+ DEBUG_PRINTK("Swap chain will have %u buffers for display %u",
+ (unsigned int)ui32BufferCount, psDevInfo->uDeviceID);
+ /* Link the buffers available like a circular list */
+ for(i=0; i<ui32BufferCount-1; i++)
+ {
+ psBuffer[i].psNext = &psBuffer[i+1];
+ }
+ psBuffer[i].psNext = &psBuffer[0];
+
+ /* Initialize each buffer abstraction structure */
+ for(i=0; i<ui32BufferCount; i++)
+ {
+ IMG_UINT32 ui32SwapBuffer = i + ui32BuffersToSkip;
+ IMG_UINT32 ui32BufferOffset = ui32SwapBuffer *
+ (IMG_UINT32)psDevInfo->sFBInfo.ulRoundedBufferSize;
+ psBuffer[i].psSyncData = ppsSyncData[i];
+ psBuffer[i].sSysAddr.uiAddr =
+ psDevInfo->sFBInfo.sSysAddr.uiAddr +
+ ui32BufferOffset;
+ psBuffer[i].sCPUVAddr = psDevInfo->sFBInfo.sCPUVAddr +
+ ui32BufferOffset;
+ DEBUG_PRINTK("Display %u buffer index %u has physical "
+ "address 0x%x and virtual address 0x%x",
+ psDevInfo->uDeviceID,
+ (unsigned int)i,
+ (unsigned int)psBuffer[i].sSysAddr.uiAddr,
+ (unsigned int)psBuffer[i].sCPUVAddr);
+ }
+
+ /* Initialize each flip item abstraction structure */
+ for(i=0; i<ui32BufferCount; i++)
+ {
+ psFlipItems[i].bValid = OMAP_FALSE;
+ psFlipItems[i].bFlipped = OMAP_FALSE;
+ psFlipItems[i].bCmdCompleted = OMAP_FALSE;
+ }
+
+ mutex_lock(&psDevInfo->sSwapChainLockMutex);
+
+ psDevInfo->psSwapChain = psSwapChain;
+ psSwapChain->bFlushCommands = psDevInfo->bFlushCommands;
+ if (psSwapChain->bFlushCommands)
+ psSwapChain->ulSetFlushStateRefCount = 1;
+ else
+ psSwapChain->ulSetFlushStateRefCount = 0;
+
+ mutex_unlock(&psDevInfo->sSwapChainLockMutex);
+
+ if (EnableLFBEventNotification(psDevInfo)!= OMAP_OK)
+ {
+ WARNING_PRINTK("Couldn't enable framebuffer event"
+ " notification for display %u",
+ psDevInfo->uDeviceID);
+ goto ErrorUnRegisterDisplayClient;
+ }
+
+ psDevInfo->uiSwapChainID++;
+ if (psDevInfo->uiSwapChainID == 0)
+ psDevInfo->uiSwapChainID++;
+ psSwapChain->uiSwapChainID = psDevInfo->uiSwapChainID;
+ *pui32SwapChainID = psDevInfo->uiSwapChainID;
+
+ *phSwapChain = (IMG_HANDLE)psSwapChain;
+
+ return PVRSRV_OK;
+
+ErrorUnRegisterDisplayClient:
+ OMAPLFBFreeKernelMem(psFlipItems);
+ErrorFreeBuffers:
+ OMAPLFBFreeKernelMem(psBuffer);
+ErrorFreeSwapChain:
+ OMAPLFBFreeKernelMem(psSwapChain);
+
+ return eError;
+}
+
+/*
+ * Destroy a swap chain. Called when a 3D application ends.
+ * in: hDevice, hSwapChain
+ */
+static PVRSRV_ERROR DestroyDCSwapChain(IMG_HANDLE hDevice,
+ IMG_HANDLE hSwapChain)
+{
+ OMAPLFB_DEVINFO *psDevInfo;
+ OMAPLFB_SWAPCHAIN *psSwapChain;
+ OMAP_ERROR eError;
+
+ if(!hDevice || !hSwapChain)
+ {
+ ERROR_PRINTK("Invalid parameters");
+ return PVRSRV_ERROR_INVALID_PARAMS;
+ }
+
+ psDevInfo = (OMAPLFB_DEVINFO*)hDevice;
+ psSwapChain = (OMAPLFB_SWAPCHAIN*)hSwapChain;
+
+ if (psSwapChain != psDevInfo->psSwapChain)
+ {
+ ERROR_PRINTK("Swap chain handler differs from the one "
+ "present in the display device pointer");
+ return PVRSRV_ERROR_INVALID_PARAMS;
+ }
+
+ DEBUG_PRINTK("Destroying swap chain for display %u",
+ psDevInfo->uDeviceID);
+
+ eError = DisableLFBEventNotification(psDevInfo);
+ if (eError != OMAP_OK)
+ {
+ WARNING_PRINTK("Couldn't disable framebuffer event "
+ "notification");
+ }
+
+ mutex_lock(&psDevInfo->sSwapChainLockMutex);
+
+ FlushInternalSyncQueue(psSwapChain);
+
+ /*
+ * Present the buffer which is at the base of address of
+ * the framebuffer
+ */
+ OMAPLFBFlip(psSwapChain,
+ (unsigned long)psDevInfo->sFBInfo.sSysAddr.uiAddr);
+ psDevInfo->psSwapChain = NULL;
+
+ mutex_unlock(&psDevInfo->sSwapChainLockMutex);
+
+ /* Destroy the workqueue */
+ flush_workqueue(psDevInfo->sync_display_wq);
+ destroy_workqueue(psDevInfo->sync_display_wq);
+
+ OMAPLFBFreeKernelMem(psSwapChain->psFlipItems);
+ OMAPLFBFreeKernelMem(psSwapChain->psBuffer);
+ OMAPLFBFreeKernelMem(psSwapChain);
+
+ return PVRSRV_OK;
+}
+
+
+/*
+ * Get display buffers. These are the buffers that can be allocated
+ * inside the framebuffer memory.
+ * in: hDevice, hSwapChain
+ * out: pui32BufferCount, phBuffer
+ */
+static PVRSRV_ERROR GetDCBuffers(IMG_HANDLE hDevice,
+ IMG_HANDLE hSwapChain,
+ IMG_UINT32 *pui32BufferCount,
+ IMG_HANDLE *phBuffer)
+{
+ OMAPLFB_DEVINFO *psDevInfo;
+ OMAPLFB_SWAPCHAIN *psSwapChain;
+ unsigned long i;
+
+ if(!hDevice || !hSwapChain || !pui32BufferCount || !phBuffer)
+ {
+ ERROR_PRINTK("Invalid parameters");
+ return PVRSRV_ERROR_INVALID_PARAMS;
+ }
+
+ psDevInfo = (OMAPLFB_DEVINFO*)hDevice;
+ psSwapChain = (OMAPLFB_SWAPCHAIN*)hSwapChain;
+ if (psSwapChain != psDevInfo->psSwapChain)
+ {
+ ERROR_PRINTK("Swap chain handler differs from the one "
+ "present in the display device %u pointer",
+ psDevInfo->uDeviceID);
+ return PVRSRV_ERROR_INVALID_PARAMS;
+ }
+ *pui32BufferCount = (IMG_UINT32)psSwapChain->ulBufferCount;
+
+ for(i=0; i<psSwapChain->ulBufferCount; i++)
+ phBuffer[i] = (IMG_HANDLE)&psSwapChain->psBuffer[i];
+
+ return PVRSRV_OK;
+}
+
+/*
+ * Sets the display state.
+ * in: ui32State, hDevice
+ */
+static IMG_VOID SetDCState(IMG_HANDLE hDevice, IMG_UINT32 ui32State)
+{
+ OMAPLFB_DEVINFO *psDevInfo = (OMAPLFB_DEVINFO *)hDevice;
+
+ switch (ui32State)
+ {
+ case DC_STATE_FLUSH_COMMANDS:
+ DEBUG_PRINTK("Setting state to flush commands for"
+ " display %u", psDevInfo->uDeviceID);
+ SetFlushStateExternal(psDevInfo, OMAP_TRUE);
+ break;
+ case DC_STATE_NO_FLUSH_COMMANDS:
+ DEBUG_PRINTK("Setting state to not flush commands for"
+ " display %u", psDevInfo->uDeviceID);
+ SetFlushStateExternal(psDevInfo, OMAP_FALSE);
+ break;
+ default:
+ WARNING_PRINTK("Unknown command state %u for display"
+ " %u", (unsigned int)ui32State,
+ psDevInfo->uDeviceID);
+ break;
+ }
+}
+
+/*
+ * Swap to display system buffer. This buffer refers to the one which
+ * is that fits in the framebuffer memory.
+ * in: hDevice, hSwapChain
+ */
+static PVRSRV_ERROR SwapToDCSystem(IMG_HANDLE hDevice,
+ IMG_HANDLE hSwapChain)
+{
+ OMAPLFB_DEVINFO *psDevInfo;
+ OMAPLFB_SWAPCHAIN *psSwapChain;
+
+ if(!hDevice || !hSwapChain)
+ {
+ ERROR_PRINTK("Invalid parameters");
+ return PVRSRV_ERROR_INVALID_PARAMS;
+ }
+
+ psDevInfo = (OMAPLFB_DEVINFO*)hDevice;
+ psSwapChain = (OMAPLFB_SWAPCHAIN*)hSwapChain;
+
+ DEBUG_PRINTK("Executing for display %u",
+ psDevInfo->uDeviceID);
+
+ if (psSwapChain != psDevInfo->psSwapChain)
+ {
+ ERROR_PRINTK("Swap chain handler differs from the one "
+ "present in the display device %u pointer",
+ psDevInfo->uDeviceID);
+ return PVRSRV_ERROR_INVALID_PARAMS;
+ }
+
+ mutex_lock(&psDevInfo->sSwapChainLockMutex);
+
+ FlushInternalSyncQueue(psSwapChain);
+ OMAPLFBFlip(psSwapChain,
+ (unsigned long)psDevInfo->sFBInfo.sSysAddr.uiAddr);
+
+ mutex_unlock(&psDevInfo->sSwapChainLockMutex);
+
+ return PVRSRV_OK;
+}
+
+/*
+ * Handles the synchronization with the display
+ * in: work
+ */
+static void OMAPLFBSyncIHandler(struct work_struct *work)
+{
+ OMAPLFB_DEVINFO *psDevInfo = container_of(work, OMAPLFB_DEVINFO,
+ sync_display_work);
+ OMAPLFB_FLIP_ITEM *psFlipItem;
+ OMAPLFB_SWAPCHAIN *psSwapChain;
+ unsigned long ulMaxIndex;
+
+ mutex_lock(&psDevInfo->sSwapChainLockMutex);
+
+ psSwapChain = psDevInfo->psSwapChain;
+ if (!psSwapChain || psSwapChain->bFlushCommands
+#if defined(SUPPORT_DRI_DRM)
+ || psDevInfo->bLeaveVT
+#endif
+ )
+ goto ExitUnlock;
+
+ psFlipItem = &psSwapChain->psFlipItems[psSwapChain->ulRemoveIndex];
+ ulMaxIndex = psSwapChain->ulBufferCount - 1;
+
+ /* Iterate through the flip items and flip them if necessary */
+ while (psFlipItem->bValid) {
+ /* Update display */
+ OMAPLFBPresentSync(psDevInfo, psFlipItem);
+
+ psFlipItem->ulSwapInterval--;
+ psFlipItem->bFlipped = OMAP_TRUE;
+
+ if (psFlipItem->ulSwapInterval == 0) {
+
+ /* Mark the flip item as completed to reuse it */
+ psSwapChain->ulRemoveIndex++;
+ if (psSwapChain->ulRemoveIndex > ulMaxIndex)
+ psSwapChain->ulRemoveIndex = 0;
+ psFlipItem->bCmdCompleted = OMAP_FALSE;
+ psFlipItem->bFlipped = OMAP_FALSE;
+ psFlipItem->bValid = OMAP_FALSE;
+
+ psSwapChain->psPVRJTable->pfnPVRSRVCmdComplete(
+ (IMG_HANDLE)psFlipItem->hCmdComplete,
+ IMG_TRUE);
+ psFlipItem->bCmdCompleted = OMAP_TRUE;
+ } else {
+ /*
+ * Here the swap interval is not zero yet
+ * we need to schedule another work until
+ * it reaches zero
+ */
+ queue_work(psDevInfo->sync_display_wq,
+ &psDevInfo->sync_display_work);
+ break;
+ }
+
+ psFlipItem =
+ &psSwapChain->psFlipItems[psSwapChain->ulRemoveIndex];
+ }
+
+ExitUnlock:
+ mutex_unlock(&psDevInfo->sSwapChainLockMutex);
+}
+
+/*
+ * Performs a flip. This function takes the necessary steps to present
+ * the buffer to be flipped in the display.
+ * in: hCmdCookie, ui32DataSize, pvData
+ */
+static IMG_BOOL ProcessFlip(IMG_HANDLE hCmdCookie,
+ IMG_UINT32 ui32DataSize,
+ IMG_VOID *pvData)
+{
+ DISPLAYCLASS_FLIP_COMMAND *psFlipCmd;
+ OMAPLFB_DEVINFO *psDevInfo;
+ OMAPLFB_BUFFER *psBuffer;
+ OMAPLFB_SWAPCHAIN *psSwapChain;
+#if defined(SYS_USING_INTERRUPTS)
+ OMAPLFB_FLIP_ITEM* psFlipItem;
+ unsigned long ulMaxIndex;
+#endif
+
+ if(!hCmdCookie || !pvData)
+ {
+ WARNING_PRINTK("Ignoring call with NULL parameters");
+ return IMG_FALSE;
+ }
+
+ psFlipCmd = (DISPLAYCLASS_FLIP_COMMAND*)pvData;
+
+ if (psFlipCmd == IMG_NULL ||
+ sizeof(DISPLAYCLASS_FLIP_COMMAND) != ui32DataSize)
+ {
+ WARNING_PRINTK("NULL command or command data size is wrong");
+ return IMG_FALSE;
+ }
+
+ psDevInfo = (OMAPLFB_DEVINFO*)psFlipCmd->hExtDevice;
+ psBuffer = (OMAPLFB_BUFFER*)psFlipCmd->hExtBuffer;
+ psSwapChain = (OMAPLFB_SWAPCHAIN*) psFlipCmd->hExtSwapChain;
+
+ mutex_lock(&psDevInfo->sSwapChainLockMutex);
+
+ if (psDevInfo->bDeviceSuspended
+#if defined(SUPPORT_DRI_DRM)
+ || psDevInfo->bLeaveVT == OMAP_TRUE
+#endif
+ )
+ {
+ /* If is suspended then assume the commands are completed */
+ psSwapChain->psPVRJTable->pfnPVRSRVCmdComplete(
+ hCmdCookie, IMG_TRUE);
+ goto ExitTrueUnlock;
+ }
+
+#if defined(SYS_USING_INTERRUPTS)
+
+ if( psFlipCmd->ui32SwapInterval == 0 ||
+
+ psSwapChain->bFlushCommands == OMAP_TRUE)
+ {
+#endif
+ OMAPLFBFlip(psSwapChain,
+ (unsigned long)psBuffer->sSysAddr.uiAddr);
+ psSwapChain->psPVRJTable->pfnPVRSRVCmdComplete(
+ hCmdCookie, IMG_TRUE);
+
+#if defined(SYS_USING_INTERRUPTS)
+ goto ExitTrueUnlock;
+ }
+
+ psFlipItem = &psSwapChain->psFlipItems[psSwapChain->ulInsertIndex];
+
+ if(psFlipItem->bValid == OMAP_FALSE)
+ {
+ /* Mark the flip item as not flipped */
+ ulMaxIndex = psSwapChain->ulBufferCount - 1;
+ psFlipItem->bFlipped = OMAP_FALSE;
+
+ /*
+ * The buffer is queued here, must be consumed by the workqueue
+ */
+ psFlipItem->hCmdComplete = (OMAP_HANDLE)hCmdCookie;
+ psFlipItem->ulSwapInterval =
+ (unsigned long)psFlipCmd->ui32SwapInterval;
+ psFlipItem->sSysAddr = &psBuffer->sSysAddr;
+ psFlipItem->bValid = OMAP_TRUE;
+
+ psSwapChain->ulInsertIndex++;
+ if(psSwapChain->ulInsertIndex > ulMaxIndex)
+ psSwapChain->ulInsertIndex = 0;
+
+ /* Give work to the workqueue to sync with the display */
+ queue_work(psDevInfo->sync_display_wq, &psDevInfo->sync_display_work);
+
+ goto ExitTrueUnlock;
+ } else
+ WARNING_PRINTK("Dropping frame! %p index %lu is the flip "
+ "queue full?", psFlipItem, psSwapChain->ulInsertIndex);
+
+ mutex_unlock(&psDevInfo->sSwapChainLockMutex);
+ return IMG_FALSE;
+#endif
+
+ExitTrueUnlock:
+ mutex_unlock(&psDevInfo->sSwapChainLockMutex);
+ return IMG_TRUE;
+}
+
+#if defined(LDM_PLATFORM)
+
+/*
+ * Function called when the driver must suspend
+ */
+void OMAPLFBDriverSuspend(void)
+{
+ OMAPLFB_DEVINFO *psDevInfo;
+ int i;
+
+ if(!pDisplayDevices)
+ return;
+
+ for(i = 0; i < FRAMEBUFFER_COUNT; i++)
+ {
+ psDevInfo = &pDisplayDevices[i];
+
+ mutex_lock(&psDevInfo->sSwapChainLockMutex);
+
+ if (psDevInfo->bDeviceSuspended)
+ {
+ mutex_unlock(&psDevInfo->sSwapChainLockMutex);
+ continue;
+ }
+
+ psDevInfo->bDeviceSuspended = OMAP_TRUE;
+ SetFlushStateInternalNoLock(psDevInfo, OMAP_TRUE);
+
+ mutex_unlock(&psDevInfo->sSwapChainLockMutex);
+ }
+}
+
+/*
+ * Function called when the driver must resume
+ */
+void OMAPLFBDriverResume(void)
+{
+ OMAPLFB_DEVINFO *psDevInfo;
+ int i;
+
+ if(!pDisplayDevices)
+ return;
+
+ for(i = 0; i < FRAMEBUFFER_COUNT; i++)
+ {
+ psDevInfo = &pDisplayDevices[i];
+
+ mutex_lock(&psDevInfo->sSwapChainLockMutex);
+
+ if (!psDevInfo->bDeviceSuspended)
+ {
+ mutex_unlock(&psDevInfo->sSwapChainLockMutex);
+ continue;
+ }
+
+ SetFlushStateInternalNoLock(psDevInfo, OMAP_FALSE);
+ psDevInfo->bDeviceSuspended = OMAP_FALSE;
+
+ mutex_unlock(&psDevInfo->sSwapChainLockMutex);
+ }
+}
+#endif /* defined(LDM_PLATFORM) */
+
+#if defined(SUPPORT_DRI_DRM) && defined(PVR_DISPLAY_CONTROLLER_DRM_IOCTL)
+static OMAPLFB_DEVINFO *OMAPLFBPVRDevIDToDevInfo(unsigned uiPVRDevID)
+{
+ int i;
+
+ for (i = 0; i < FRAMEBUFFER_COUNT; i++) {
+ if (uiPVRDevID == (&pDisplayDevices[i])->uDeviceID)
+ return &pDisplayDevices[i];
+ }
+
+ WARNING_PRINTK("Couldn't find device %u\n", 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:
+ {
+ OMAP_BOOL bLeaveVT = (uiCmd == PVR_DRM_DISP_CMD_LEAVE_VT);
+ DEBUG_PRINTK("PVR Device %u: %s\n", uiPVRDevID,
+ bLeaveVT ? "Leave VT" : "Enter VT");
+
+ mutex_lock(&psDevInfo->sSwapChainLockMutex);
+ psDevInfo->bLeaveVT = bLeaveVT;
+
+ if (psDevInfo->psSwapChain != NULL) {
+ FlushInternalSyncQueue(psDevInfo->psSwapChain);
+ if (bLeaveVT) {
+ OMAPLFBPresentSyncAddr(psDevInfo,
+ (unsigned long) psDevInfo->sSystemBuffer.sSysAddr.uiAddr);
+ }
+ }
+
+ mutex_unlock(&psDevInfo->sSwapChainLockMutex);
+ UnBlankDisplay(psDevInfo);
+ break;
+ }
+ case PVR_DRM_DISP_CMD_RESYNC:
+ if (ReInitDev(psDevInfo) != OMAP_OK)
+ {
+ printk(KERN_WARNING DRIVER_PREFIX ": %s: ReInitDev failed\n", __FUNCTION__);
+ ret = -EINVAL;
+ break;
+ }
+
+ 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;
+ }
+ DEBUG_PRINTK("PVR Device %u: Display %s\n",
+ 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;
+ }
+
+ mutex_lock(&psDevInfo->sSwapChainLockMutex);
+
+ if (psDevInfo->psSwapChain != NULL)
+ FlushInternalSyncQueue(psDevInfo->psSwapChain);
+
+ mutex_unlock(&psDevInfo->sSwapChainLockMutex);
+ /* XXX: Internally all the previous ioctl commands are
+ * implemented the same in omapfb
+ */
+ BlankDisplay(psDevInfo, iFBMode);
+
+ break;
+ }
+ default:
+ {
+ ret = -EINVAL;
+ break;
+ }
+ }
+
+ return ret;
+}
+#endif
+
+/*
+ * Frees the kernel framebuffer
+ * in: psDevInfo
+ */
+static void DeInitDev(OMAPLFB_DEVINFO *psDevInfo)
+{
+ struct fb_info *psLINFBInfo = psDevInfo->psLINFBInfo;
+ struct module *psLINFBOwner;
+
+ acquire_console_sem();
+ psLINFBOwner = psLINFBInfo->fbops->owner;
+
+ if (psLINFBInfo->fbops->fb_release != NULL)
+ (void) psLINFBInfo->fbops->fb_release(psLINFBInfo, 0);
+
+ module_put(psLINFBOwner);
+
+ release_console_sem();
+}
+
+#if defined(SUPPORT_DRI_DRM)
+/* drm driver case.. because of virtual displays, the width/height coming
+ * from framebuffer->var are meaningless so we need to iterate the connectors
+ */
+static void OMAPLFBGetDisplaySize(OMAPLFB_DEVINFO *psDevInfo)
+{
+ struct fb_info *framebuffer = psDevInfo->psLINFBInfo;
+ struct drm_connector *connector = NULL;
+
+ psDevInfo->sDisplayInfo.ui32PhysicalWidthmm = 0;
+ psDevInfo->sDisplayInfo.ui32PhysicalHeightmm = 0;
+
+ while ((connector = omap_fbdev_get_next_connector(framebuffer, connector)))
+ {
+ u32 width = 0, height = 0;
+ if (omap_connector_get_dimension(connector, &width, &height)) {
+ /* if there are multiple displays, we really need to know how they
+ * are arranged in relation to each other to know how to calculate
+ * the combined width/height.. but width/height really don't make
+ * sense for virtual displays anyways..
+ */
+ psDevInfo->sDisplayInfo.ui32PhysicalWidthmm += width;
+ psDevInfo->sDisplayInfo.ui32PhysicalHeightmm += height;
+ }
+ }
+}
+#else
+/* non-drm driver case.. not sure we have a #define for that */
+static void OMAPLFBGetDisplaySize(OMAPLFB_DEVINFO *psDevInfo)
+{
+ struct fb_info *psLINFBInfo = psDevInfo->psLINFBInfo;
+ if (psLINFBInfo->var.width < 0 || psLINFBInfo->var.height < 0) {
+ psDevInfo->sDisplayInfo.ui32PhysicalWidthmm = 0;
+ psDevInfo->sDisplayInfo.ui32PhysicalHeightmm = 0;
+ } else {
+ psDevInfo->sDisplayInfo.ui32PhysicalWidthmm =
+ psLINFBInfo->var.width;
+ psDevInfo->sDisplayInfo.ui32PhysicalHeightmm =
+ psLINFBInfo->var.height;
+ }
+}
+#endif
+
+/*
+ * Deinitialization routine for the 3rd party display driver
+ */
+OMAP_ERROR OMAPLFBDeinit(void)
+{
+ OMAPLFB_DEVINFO *psDevInfo;
+ PVRSRV_DC_DISP2SRV_KMJTABLE *psJTable;
+ int i;
+
+ DEBUG_PRINTK("Deinitializing 3rd party display driver");
+
+ if(!pDisplayDevices)
+ return OMAP_OK;
+
+ for(i = 0; i < FRAMEBUFFER_COUNT; i++)
+ {
+ psDevInfo = &pDisplayDevices[i];
+
+ /* Remove the ProcessFlip command callback */
+ psJTable = &psDevInfo->sPVRJTable;
+ if (psDevInfo->sPVRJTable.pfnPVRSRVRemoveCmdProcList(
+ psDevInfo->uDeviceID,
+ OMAPLFB_COMMAND_COUNT) != PVRSRV_OK)
+ {
+ ERROR_PRINTK("Unable to remove callback for "
+ "ProcessFlip command for display %u",
+ psDevInfo->uDeviceID);
+ return OMAP_ERROR_GENERIC;
+ }
+
+ /* Remove the display device from services */
+ if (psJTable->pfnPVRSRVRemoveDCDevice(
+ psDevInfo->uDeviceID) != PVRSRV_OK)
+ {
+ ERROR_PRINTK("Unable to remove the display %u "
+ "from services", psDevInfo->uDeviceID);
+ return OMAP_ERROR_GENERIC;
+ }
+
+ DeInitDev(psDevInfo);
+ }
+
+ OMAPLFBFreeKernelMem(pDisplayDevices);
+
+ return OMAP_OK;
+}
+
+/*
+ * Extracts the framebuffer data from the kernel driver
+ * in: psDevInfo
+ */
+static OMAP_ERROR InitDev(OMAPLFB_DEVINFO *psDevInfo)
+{
+ struct fb_info *psLINFBInfo = psDevInfo->psLINFBInfo;
+ struct module *psLINFBOwner;
+ OMAPLFB_FBINFO *psPVRFBInfo = &psDevInfo->sFBInfo;
+ unsigned long FBSize;
+ int buffers_available;
+
+ /* Check the framebuffer width and height are valid */
+ if(psLINFBInfo->var.xres <= 0 || psLINFBInfo->var.yres <= 0)
+ {
+ ERROR_PRINTK("Framebuffer %p has an invalid state, "
+ "width and height are %u,%u", psLINFBInfo,
+ psLINFBInfo->var.xres, psLINFBInfo->var.yres);
+ return OMAP_ERROR_INVALID_DEVICE;
+ }
+
+ if(DESIRED_BPP != 0){
+ psLINFBInfo->var.bits_per_pixel = DESIRED_BPP;
+ if(DESIRED_BPP == 16){
+ psLINFBInfo->var.red.offset = 11;
+ psLINFBInfo->var.red.length = 5;
+ psLINFBInfo->var.green.offset = 5;
+ psLINFBInfo->var.green.length = 6;
+ psLINFBInfo->var.blue.offset = 0;
+ psLINFBInfo->var.blue.length = 5;
+ psLINFBInfo->var.transp.offset = 0;
+ psLINFBInfo->var.transp.length = 0;
+ }
+ else if(DESIRED_BPP == 32)
+ {
+ psLINFBInfo->var.red.offset = 16;
+ psLINFBInfo->var.red.length = 8;
+ psLINFBInfo->var.green.offset = 8;
+ psLINFBInfo->var.green.length = 8;
+ psLINFBInfo->var.blue.offset = 0;
+ psLINFBInfo->var.blue.length = 8;
+ psLINFBInfo->var.transp.offset = 0;
+ psLINFBInfo->var.transp.length = 0;
+ }
+ else
+ WARNING_PRINTK("Unknown bits per pixel format %i",
+ DESIRED_BPP);
+ }
+ acquire_console_sem();
+ FBSize = (psLINFBInfo->screen_size) != 0 ?
+ psLINFBInfo->screen_size : psLINFBInfo->fix.smem_len;
+ 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;
+ psPVRFBInfo->ulBufferSize =
+ psPVRFBInfo->ulHeight * psPVRFBInfo->ulByteStride;
+ psLINFBInfo->var.activate = FB_ACTIVATE_FORCE;
+ fb_set_var(psLINFBInfo, &psLINFBInfo->var);
+ /* note: calculate by fb size, not yres_virtual, as drm will set
+ * yres_virtual back to yres
+ */
+ buffers_available =
+ psLINFBInfo->fix.smem_len / psPVRFBInfo->ulBufferSize;
+
+ if(buffers_available <= 1)
+ {
+ /*
+ * Flipping is not supported, return the framebuffer to
+ * its original state
+ */
+ psLINFBInfo->var.activate = FB_ACTIVATE_FORCE;
+ fb_set_var(psLINFBInfo, &psLINFBInfo->var);
+ buffers_available = 1;
+ }
+ psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers = buffers_available;
+
+ psLINFBOwner = psLINFBInfo->fbops->owner;
+ if (!try_module_get(psLINFBOwner))
+ {
+ ERROR_PRINTK("Couldn't get framebuffer module");
+ release_console_sem();
+ return OMAP_ERROR_GENERIC;
+ }
+
+ if (psLINFBInfo->fbops->fb_open != NULL)
+ {
+ if (psLINFBInfo->fbops->fb_open(psLINFBInfo, 0))
+ {
+ ERROR_PRINTK("Couldn't open framebuffer %p", psLINFBInfo);
+ module_put(psLINFBOwner);
+ release_console_sem();
+ return OMAP_ERROR_GENERIC;
+ }
+ }
+ psDevInfo->psLINFBInfo = psLINFBInfo;
+
+ /* Extract the needed data from the framebuffer structures */
+ FBSize = (psLINFBInfo->screen_size) != 0 ?
+ psLINFBInfo->screen_size : psLINFBInfo->fix.smem_len;
+ DEBUG_PRINTK("Framebuffer %p information:", psLINFBInfo);
+ DEBUG_PRINTK("*Physical address: 0x%lx",
+ psLINFBInfo->fix.smem_start);
+ DEBUG_PRINTK("*Virtual address: 0x%lx",
+ (unsigned long)psLINFBInfo->screen_base);
+ DEBUG_PRINTK("*Size (bytes): %lu",FBSize);
+ DEBUG_PRINTK("*Width, height: %u,%u",
+ psLINFBInfo->var.xres, psLINFBInfo->var.yres);
+ DEBUG_PRINTK("*Virtual width, height: %u,%u",
+ psLINFBInfo->var.xres_virtual, psLINFBInfo->var.yres_virtual);
+ DEBUG_PRINTK("*Rotation: %u", psLINFBInfo->var.rotate);
+ DEBUG_PRINTK("*Buffers available: %d", buffers_available);
+ DEBUG_PRINTK("*Stride (bytes): %u",
+ (unsigned int)psLINFBInfo->fix.line_length);
+
+ 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;
+
+ psPVRFBInfo->ulBufferSize =
+ psPVRFBInfo->ulHeight * psPVRFBInfo->ulByteStride;
+ /* Get physical display size for DPI calculation */
+ OMAPLFBGetDisplaySize(psDevInfo);
+
+ DEBUG_PRINTK("*Buffer size: %lu", psPVRFBInfo->ulBufferSize);
+ /* XXX: Page aligning with 16bpp causes the
+ * position of framebuffer address to look in the wrong place.
+ */
+ psPVRFBInfo->ulRoundedBufferSize =
+ OMAPLFB_PAGE_ROUNDUP(psPVRFBInfo->ulBufferSize);
+
+ psDevInfo->sFBInfo.sSysAddr.uiAddr = psPVRFBInfo->sSysAddr.uiAddr;
+ psDevInfo->sFBInfo.sCPUVAddr = psPVRFBInfo->sCPUVAddr;
+
+ /* Get the current bits per pixel configured in the framebuffer */
+ DEBUG_PRINTK("*Bits per pixel: %d", psLINFBInfo->var.bits_per_pixel);
+ 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))
+ {
+ DEBUG_PRINTK("*Format: RGB565");
+ psPVRFBInfo->ePixelFormat = PVRSRV_PIXEL_FORMAT_RGB565;
+ }
+ else
+ WARNING_PRINTK("*Format: Unknown framebuffer"
+ " format");
+ }
+ 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;
+ DEBUG_PRINTK("*Format: ARGB8888");
+ }
+ else
+ WARNING_PRINTK("*Format: Unknown framebuffer"
+ "format");
+ }
+ else
+ WARNING_PRINTK("*Format: Unknown framebuffer format");
+
+ release_console_sem();
+ return OMAP_OK;
+}
+
+/*
+ * Reinitialize our state after screen dimension change
+*/
+
+static OMAP_ERROR ReInitDev(OMAPLFB_DEVINFO *psDevInfo)
+{
+ OMAP_ERROR err = InitDev(psDevInfo);
+ if (err) {
+ return err;
+ }
+
+ 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;
+ psDevInfo->sSystemBuffer.sSysAddr =
+ psDevInfo->sFBInfo.sSysAddr;
+ psDevInfo->sSystemBuffer.sCPUVAddr =
+ psDevInfo->sFBInfo.sCPUVAddr;
+ psDevInfo->sSystemBuffer.ulBufferSize =
+ psDevInfo->sFBInfo.ulRoundedBufferSize;
+ DEBUG_PRINTK("Buffers available: %u (%lu bytes per buffer)",
+ psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers,
+ psDevInfo->sFBInfo.ulBufferSize);
+
+ return OMAP_OK;
+}
+
+
+/*
+ * Initialization routine for the 3rd party display driver
+ */
+OMAP_ERROR OMAPLFBInit(void)
+{
+ OMAPLFB_DEVINFO *psDevInfo;
+ PFN_CMD_PROC pfnCmdProcList[OMAPLFB_COMMAND_COUNT];
+ IMG_UINT32 aui32SyncCountList[OMAPLFB_COMMAND_COUNT][2];
+ int i;
+
+ DEBUG_PRINTK("Initializing 3rd party display driver");
+ DEBUG_PRINTK("Found %u framebuffers", FRAMEBUFFER_COUNT);
+
+ /*
+ * Obtain the function pointer for the jump table from
+ * services to fill it with the function pointers that we want
+ */
+ if(OMAPLFBGetLibFuncAddr ("PVRGetDisplayClassJTable",
+ &pfnGetPVRJTable) != OMAP_OK)
+ {
+ ERROR_PRINTK("Unable to get the function to get the"
+ " jump table display->services");
+ return OMAP_ERROR_INIT_FAILURE;
+ }
+
+ /*
+ * Allocate the display device structures, one per framebuffer
+ */
+ pDisplayDevices = (OMAPLFB_DEVINFO *)OMAPLFBAllocKernelMem(
+ sizeof(OMAPLFB_DEVINFO) * FRAMEBUFFER_COUNT);
+ if(!pDisplayDevices)
+ {
+ pDisplayDevices = NULL;
+ ERROR_PRINTK("Out of memory");
+ return OMAP_ERROR_OUT_OF_MEMORY;
+ }
+ memset(pDisplayDevices, 0, sizeof(OMAPLFB_DEVINFO) *
+ FRAMEBUFFER_COUNT);
+
+ /*
+ * Initialize each display device
+ */
+ for (i = 0; i < FRAMEBUFFER_COUNT; i++)
+ {
+ DEBUG_PRINTK("-> Initializing display device %i", i);
+
+ /* Check if the framebuffer index to use is valid */
+ if (i < 0 || i >= num_registered_fb)
+ {
+ ERROR_PRINTK("Framebuffer index %i out of range, "
+ "only %i available", i, num_registered_fb);
+ return OMAP_ERROR_INVALID_DEVICE;
+ }
+
+ /* Get the framebuffer from the kernel */
+ if (!registered_fb[i])
+ {
+ ERROR_PRINTK("Framebuffer index %i is null", i);
+ return OMAP_ERROR_INVALID_DEVICE;
+ }
+
+ pDisplayDevices[i].psLINFBInfo = registered_fb[i];
+
+ /*
+ * Here we get the framebuffer data for each display device
+ * and check for error
+ */
+ if(InitDev(&pDisplayDevices[i]) != OMAP_OK)
+ {
+ ERROR_PRINTK("Unable to initialize display "
+ "device %i",i);
+ OMAPLFBFreeKernelMem(pDisplayDevices);
+ pDisplayDevices = NULL;
+ return OMAP_ERROR_INIT_FAILURE;
+ }
+
+ /*
+ * Populate each display device structure
+ */
+ DEBUG_PRINTK("-> Populating display device %i", i);
+ psDevInfo = &pDisplayDevices[i];
+
+ if(!(*pfnGetPVRJTable)(&psDevInfo->sPVRJTable))
+ {
+ ERROR_PRINTK("Unable to get the jump table"
+ " display->services");
+ return OMAP_ERROR_INIT_FAILURE;
+ }
+
+ mutex_init(&psDevInfo->sSwapChainLockMutex);
+
+ psDevInfo->psSwapChain = 0;
+ psDevInfo->bFlushCommands = OMAP_FALSE;
+ psDevInfo->bDeviceSuspended = OMAP_FALSE;
+#if defined(SUPPORT_DRI_DRM)
+ psDevInfo->bLeaveVT = OMAP_FALSE;
+#endif
+
+ if(psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers > 1)
+ {
+ if(MAX_BUFFERS_FLIPPING == 1)
+ {
+ DEBUG_PRINTK("Flipping support is possible"
+ " but you decided not to use it, "
+ "no swap chain will be created");
+ }
+
+ DEBUG_PRINTK("Flipping support");
+ if(psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers >
+ MAX_BUFFERS_FLIPPING)
+ psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers =
+ MAX_BUFFERS_FLIPPING;
+ }
+ else
+ {
+ DEBUG_PRINTK("Flipping not supported, no swap chain"
+ " will be created");
+ }
+
+ if (psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers == 0)
+ {
+ psDevInfo->sDisplayInfo.ui32MaxSwapChains = 0;
+ psDevInfo->sDisplayInfo.ui32MaxSwapInterval = 0;
+ }
+ else
+ {
+ psDevInfo->sDisplayInfo.ui32MaxSwapChains = 1;
+ psDevInfo->sDisplayInfo.ui32MaxSwapInterval = 3;
+ }
+ psDevInfo->sDisplayInfo.ui32MinSwapInterval = 0;
+
+ /* Get the display and framebuffer needed info */
+ 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;
+ psDevInfo->sSystemBuffer.sSysAddr =
+ psDevInfo->sFBInfo.sSysAddr;
+ psDevInfo->sSystemBuffer.sCPUVAddr =
+ psDevInfo->sFBInfo.sCPUVAddr;
+ psDevInfo->sSystemBuffer.ulBufferSize =
+ psDevInfo->sFBInfo.ulRoundedBufferSize;
+ DEBUG_PRINTK("Buffers available: %u (%lu bytes per buffer)",
+ psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers,
+ psDevInfo->sFBInfo.ulBufferSize);
+
+ /* Populate the function table that services will use */
+ 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.pfnSwapToDCSystem = SwapToDCSystem;
+ psDevInfo->sDCJTable.pfnSetDCState = SetDCState;
+
+ /* Register the display device */
+ if(psDevInfo->sPVRJTable.pfnPVRSRVRegisterDCDevice(
+ &psDevInfo->sDCJTable,
+ &psDevInfo->uDeviceID,
+ psDevInfo->psLINFBInfo) != PVRSRV_OK)
+ {
+ ERROR_PRINTK("Unable to register the jump table"
+ " services->display");
+ return OMAP_ERROR_DEVICE_REGISTER_FAILED;
+ }
+
+ DEBUG_PRINTK("Framebuffer fb%i registered with id %u",
+ i, psDevInfo->uDeviceID);
+
+ /*
+ * Register the ProcessFlip function to notify when a frame is
+ * ready to be flipped
+ */
+ pfnCmdProcList[DC_FLIP_COMMAND] = ProcessFlip;
+ aui32SyncCountList[DC_FLIP_COMMAND][0] = 0;
+ aui32SyncCountList[DC_FLIP_COMMAND][1] = 2;
+ if (psDevInfo->sPVRJTable.pfnPVRSRVRegisterCmdProcList(
+ psDevInfo->uDeviceID, &pfnCmdProcList[0],
+ aui32SyncCountList, OMAPLFB_COMMAND_COUNT) != PVRSRV_OK)
+ {
+ ERROR_PRINTK("Unable to register callback for "
+ "ProcessFlip command");
+ return OMAP_ERROR_CANT_REGISTER_CALLBACK;
+ }
+
+ }
+ return OMAP_OK;
+}
diff --git a/sgx/services4/3rdparty/dc_omap_linux/omaplfb_linux.c b/sgx/services4/3rdparty/dc_omap_linux/omaplfb_linux.c
new file mode 100755
index 0000000..55eaa74
--- /dev/null
+++ b/sgx/services4/3rdparty/dc_omap_linux/omaplfb_linux.c
@@ -0,0 +1,520 @@
+/**********************************************************************
+ *
+ * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful but, except
+ * as otherwise stated in writing, without any warranty; without even the
+ * implied warranty of merchantability or fitness for a particular purpose.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Imagination Technologies Ltd. <gpl-support@imgtec.com>
+ * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
+ *
+ ******************************************************************************/
+
+#ifndef AUTOCONF_INCLUDED
+#include <linux/config.h>
+#endif
+
+#if defined(SUPPORT_DRI_DRM)
+#include <drm/drmP.h>
+#include <linux/omap_gpu.h>
+#else
+#include <linux/module.h>
+#endif
+
+#include <linux/version.h>
+#include <linux/fb.h>
+#include <asm/io.h>
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32))
+#include <plat/vrfb.h>
+#include <plat/display.h>
+#else
+#include <mach/vrfb.h>
+#include <mach/display.h>
+#endif
+
+#if defined(CONFIG_OUTER_CACHE) /* Kernel config option */
+#include <asm/cacheflush.h>
+#define HOST_PAGESIZE (4096)
+#define HOST_PAGEMASK (~(HOST_PAGESIZE-1))
+#define HOST_PAGEALIGN(addr) (((addr)+HOST_PAGESIZE-1)&HOST_PAGEMASK)
+#endif
+
+#if defined(LDM_PLATFORM)
+#include <linux/platform_device.h>
+#if defined(SGX_EARLYSUSPEND)
+#include <linux/earlysuspend.h>
+#endif
+#endif
+
+#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(CONFIG_OUTER_CACHE) /* Kernel config option */
+#if defined(__arm__)
+static void per_cpu_cache_flush_arm(void *arg)
+{
+ PVR_UNREFERENCED_PARAMETER(arg);
+ flush_cache_all();
+}
+#endif
+#endif
+
+/*
+ * Kernel malloc
+ * in: ui32ByteSize
+ */
+void *OMAPLFBAllocKernelMem(unsigned long ui32ByteSize)
+{
+ void *p;
+
+#if defined(CONFIG_OUTER_CACHE) /* Kernel config option */
+ IMG_VOID *pvPageAlignedCPUPAddr;
+ IMG_VOID *pvPageAlignedCPUVAddr;
+ IMG_UINT32 ui32PageOffset;
+ IMG_UINT32 ui32PageCount;
+#endif
+ p = kmalloc(ui32ByteSize, GFP_KERNEL);
+
+ if(!p)
+ return 0;
+
+#if defined(CONFIG_OUTER_CACHE) /* Kernel config option */
+ ui32PageOffset = (IMG_UINT32) p & (HOST_PAGESIZE - 1);
+ ui32PageCount = HOST_PAGEALIGN(ui32ByteSize + ui32PageOffset) / HOST_PAGESIZE;
+
+ pvPageAlignedCPUVAddr = (IMG_VOID *)((IMG_UINT8 *)p - ui32PageOffset);
+ pvPageAlignedCPUPAddr = (IMG_VOID*) __pa(pvPageAlignedCPUVAddr);
+
+#if defined(__arm__)
+ on_each_cpu(per_cpu_cache_flush_arm, NULL, 1);
+#endif
+ outer_cache.flush_range((unsigned long) pvPageAlignedCPUPAddr, (unsigned long) ((pvPageAlignedCPUPAddr + HOST_PAGESIZE*ui32PageCount) - 1));
+#endif
+ return p;
+}
+
+/*
+ * Kernel free
+ * in: pvMem
+ */
+void OMAPLFBFreeKernelMem(void *pvMem)
+{
+ kfree(pvMem);
+}
+
+/*
+ * Here we get the function pointer to get jump table from
+ * services using an external function.
+ * in: szFunctionName
+ * out: ppfnFuncTable
+ */
+OMAP_ERROR OMAPLFBGetLibFuncAddr (char *szFunctionName,
+ PFN_DC_GET_PVRJTABLE *ppfnFuncTable)
+{
+ if(strcmp("PVRGetDisplayClassJTable", szFunctionName) != 0)
+ {
+ ERROR_PRINTK("Unable to get function pointer for %s"
+ " from services", szFunctionName);
+ return OMAP_ERROR_INVALID_PARAMS;
+ }
+ *ppfnFuncTable = PVRGetDisplayClassJTable;
+
+ return OMAP_OK;
+}
+
+#if defined(FLIP_TECHNIQUE_FRAMEBUFFER)
+/*
+ * Presents the flip in the display with the framebuffer API
+ * in: psSwapChain, aPhyAddr
+ */
+static void OMAPLFBFlipNoLock(OMAPLFB_SWAPCHAIN *psSwapChain,
+ unsigned long aPhyAddr)
+{
+ OMAPLFB_DEVINFO *psDevInfo = (OMAPLFB_DEVINFO *)psSwapChain->pvDevInfo;
+ struct fb_info *framebuffer = psDevInfo->psLINFBInfo;
+ /* note: make a copy of the current var, to modify.. otherwise we
+ * fool fbdev into thinking that nothing has changed!
+ */
+ struct fb_var_screeninfo var = framebuffer->var;
+
+ /* TODO: we really should create a separate fb for each buffer in
+ * the flip chain.. then flipping could be done either from kernel
+ * or userspace via crtc->funcs->page_flip().. this will be easier
+ * when we can more easily allocate framebuffer memory dynamically
+ * (ie. something like CMA.. http://lwn.net/Articles/416303/ ..
+ * Nicolas Pitre had some idea that highmem could make this easier
+ * because highmem pages could be more easily relocated to make
+ * contiguous memory available.. see
+ * http://lists.linaro.org/pipermail/linaro-dev/2011-February/002854.html
+ */
+
+ /* Get the framebuffer physical address base */
+ unsigned long fb_base_phyaddr =
+ psDevInfo->sSystemBuffer.sSysAddr.uiAddr;
+
+ /* Calculate the virtual Y to move in the framebuffer */
+ var.yoffset = (aPhyAddr - fb_base_phyaddr) / framebuffer->fix.line_length;
+ var.activate = FB_ACTIVATE_FORCE;
+
+ /* hack.. normally virtual height would be same as actual height of the
+ * virtual framebuffer (ie. the bounding box around all sub-rects of
+ * the fb that are being scanned out to some display.. but that would
+ * cause fb_pan_display to fail.. this hack can go away once we start
+ * using crtc->funcs->page_flip()
+ */
+ framebuffer->var.yres_virtual = var.yoffset + var.yres;
+
+ fb_pan_display(framebuffer, &var);
+}
+
+void OMAPLFBFlip(OMAPLFB_SWAPCHAIN *psSwapChain, unsigned long aPhyAddr)
+{
+ OMAPLFBFlipNoLock(psSwapChain, aPhyAddr);
+}
+
+#elif defined(FLIP_TECHNIQUE_OVERLAY)
+/*
+ * Presents the flip in the display with the DSS2 overlay API
+ * in: psSwapChain, aPhyAddr
+ */
+static void OMAPLFBFlipNoLock(OMAPLFB_SWAPCHAIN *psSwapChain,
+ unsigned long aPhyAddr)
+{
+ OMAPLFB_DEVINFO *psDevInfo = (OMAPLFB_DEVINFO *)psSwapChain->pvDevInfo;
+ struct fb_info * framebuffer = psDevInfo->psLINFBInfo;
+ struct omapfb_info *ofbi = FB2OFB(framebuffer);
+ unsigned long fb_offset;
+ int i;
+
+ fb_offset = aPhyAddr - psDevInfo->sSystemBuffer.sSysAddr.uiAddr;
+
+ for(i = 0; i < ofbi->num_overlays ; i++)
+ {
+ struct omap_dss_device *display = NULL;
+ struct omap_dss_driver *driver = NULL;
+ struct omap_overlay_manager *manager;
+ struct omap_overlay *overlay;
+ struct omap_overlay_info overlay_info;
+
+ overlay = ofbi->overlays[i];
+ manager = overlay->manager;
+ overlay->get_overlay_info( overlay, &overlay_info );
+
+ overlay_info.paddr = framebuffer->fix.smem_start + fb_offset;
+ overlay_info.vaddr = framebuffer->screen_base + fb_offset;
+ overlay->set_overlay_info(overlay, &overlay_info);
+
+ if (manager) {
+ display = manager->device;
+ /* No display attached to this overlay, don't update */
+ if (!display)
+ continue;
+ driver = display->driver;
+ manager->apply(manager);
+ }
+
+ if (dss_ovl_manually_updated(overlay)) {
+ if (driver->sched_update)
+ driver->sched_update(display, 0, 0,
+ overlay_info.width,
+ overlay_info.height);
+ else if (driver->update)
+ driver->update(display, 0, 0,
+ overlay_info.width,
+ overlay_info.height);
+
+ }
+
+ }
+}
+
+void OMAPLFBFlip(OMAPLFB_SWAPCHAIN *psSwapChain, unsigned long aPhyAddr)
+{
+ OMAPLFB_DEVINFO *psDevInfo = (OMAPLFB_DEVINFO *)psSwapChain->pvDevInfo;
+ struct fb_info *framebuffer = psDevInfo->psLINFBInfo;
+ struct omapfb_info *ofbi = FB2OFB(framebuffer);
+ struct omapfb2_device *fbdev = ofbi->fbdev;
+
+ omapfb_lock(fbdev);
+ OMAPLFBFlipNoLock(psSwapChain, aPhyAddr);
+ omapfb_unlock(fbdev);
+}
+
+#else
+#error No flipping technique selected, please define \
+ FLIP_TECHNIQUE_FRAMEBUFFER or FLIP_TECHNIQUE_OVERLAY
+#endif
+
+void OMAPLFBPresentSync(OMAPLFB_DEVINFO *psDevInfo,
+ OMAPLFB_FLIP_ITEM *psFlipItem)
+{
+ OMAPLFBPresentSyncAddr(psDevInfo,
+ (unsigned long)psFlipItem->sSysAddr->uiAddr);
+}
+
+/*
+ * Present frame and synchronize with the display to prevent tearing
+ * On DSI panels the sync function is used to handle FRAMEDONE IRQ
+ * On DPI panels the wait_for_vsync is used to handle VSYNC IRQ
+ * in: psDevInfo
+ */
+void OMAPLFBPresentSyncAddr(OMAPLFB_DEVINFO *psDevInfo,
+ unsigned long paddr)
+{
+ struct fb_info *framebuffer = psDevInfo->psLINFBInfo;
+ struct drm_connector *connector = NULL;
+ int err = 0;
+
+ while ((connector = omap_fbdev_get_next_connector(framebuffer, connector)))
+ {
+ err |= omap_connector_sync(connector);
+ }
+
+ OMAPLFBFlipNoLock(psDevInfo->psSwapChain, paddr);
+
+ connector = NULL;
+ while ((connector = omap_fbdev_get_next_connector(framebuffer, connector)))
+ {
+ if (err && connector->encoder)
+ {
+ /* if the panel didn't support sync(), then try wait_for_vsync() */
+ err = omap_encoder_wait_for_vsync(connector->encoder);
+ }
+ }
+}
+
+#if defined(LDM_PLATFORM)
+
+static volatile OMAP_BOOL bDeviceSuspended;
+
+#if !defined(SUPPORT_DRI_DRM)
+/*
+ * Common suspend driver function
+ * in: psSwapChain, aPhyAddr
+ */
+static void OMAPLFBCommonSuspend(void)
+{
+ if (bDeviceSuspended)
+ {
+ DEBUG_PRINTK("Driver is already suspended");
+ return;
+ }
+
+ OMAPLFBDriverSuspend();
+ bDeviceSuspended = OMAP_TRUE;
+}
+#endif
+
+#if 0
+/*
+ * Function called when the driver is requested to release
+ * in: pDevice
+ */
+static void OMAPLFBDeviceRelease_Entry(struct device unref__ *pDevice)
+{
+ DEBUG_PRINTK("Requested driver release");
+ OMAPLFBCommonSuspend();
+}
+
+static struct platform_device omaplfb_device = {
+ .name = DEVNAME,
+ .id = -1,
+ .dev = {
+ .release = OMAPLFBDeviceRelease_Entry
+ }
+};
+#endif
+
+#if defined(SGX_EARLYSUSPEND) && defined(CONFIG_HAS_EARLYSUSPEND)
+
+static struct early_suspend omaplfb_early_suspend;
+
+/*
+ * Android specific, driver is requested to be suspended
+ * in: ea_event
+ */
+static void OMAPLFBDriverSuspend_Entry(struct early_suspend *ea_event)
+{
+ DEBUG_PRINTK("Requested driver suspend");
+ OMAPLFBCommonSuspend();
+}
+
+/*
+ * Android specific, driver is requested to be suspended
+ * in: ea_event
+ */
+static void OMAPLFBDriverResume_Entry(struct early_suspend *ea_event)
+{
+ DEBUG_PRINTK("Requested driver resume");
+ OMAPLFBDriverResume();
+ bDeviceSuspended = OMAP_FALSE;
+}
+
+static struct platform_driver omaplfb_driver = {
+ .driver = {
+ .name = DRVNAME,
+ }
+};
+
+#else /* defined(SGX_EARLYSUSPEND) && defined(CONFIG_HAS_EARLYSUSPEND) */
+
+#if !defined(SUPPORT_DRI_DRM)
+/*
+ * Function called when the driver is requested to be suspended
+ * in: pDevice, state
+ */
+static int OMAPLFBDriverSuspend_Entry(struct platform_device unref__ *pDevice,
+ pm_message_t unref__ state)
+{
+ DEBUG_PRINTK("Requested driver suspend");
+ OMAPLFBCommonSuspend();
+ return 0;
+}
+
+/*
+ * Function called when the driver is requested to resume
+ * in: pDevice
+ */
+static int OMAPLFBDriverResume_Entry(struct platform_device unref__ *pDevice)
+{
+ DEBUG_PRINTK("Requested driver resume");
+ OMAPLFBDriverResume();
+ bDeviceSuspended = OMAP_FALSE;
+ return 0;
+}
+
+/*
+ * Function called when the driver is requested to shutdown
+ * in: pDevice
+ */
+static IMG_VOID OMAPLFBDriverShutdown_Entry(
+ struct platform_device unref__ *pDevice)
+{
+ DEBUG_PRINTK("Requested driver shutdown");
+ OMAPLFBCommonSuspend();
+}
+
+static struct platform_driver omaplfb_driver = {
+ .driver = {
+ .name = DRVNAME,
+ },
+ .suspend = OMAPLFBDriverSuspend_Entry,
+ .resume = OMAPLFBDriverResume_Entry,
+ .shutdown = OMAPLFBDriverShutdown_Entry,
+};
+#endif /* !defined (SUPPORT_DRI_DRM)*/
+
+#endif /* defined(SGX_EARLYSUSPEND) && defined(CONFIG_HAS_EARLYSUSPEND) */
+
+#endif /* defined(LDM_PLATFORM) */
+
+/*
+ * Driver init function
+ */
+#if defined(SUPPORT_DRI_DRM)
+int PVR_DRM_MAKENAME(DISPLAY_CONTROLLER, _Init)(struct drm_device *dev)
+#else
+static int __init OMAPLFB_Init(void)
+#endif
+{
+ if(OMAPLFBInit() != OMAP_OK)
+ {
+ WARNING_PRINTK("Driver init failed");
+ return -ENODEV;
+ }
+
+#if defined(LDM_PLATFORM)
+ DEBUG_PRINTK("Registering platform driver");
+#if !defined(SUPPORT_DRI_DRM)
+ if (platform_driver_register(&omaplfb_driver))
+ {
+ WARNING_PRINTK("Unable to register platform driver");
+ if(OMAPLFBDeinit() != OMAP_OK)
+ WARNING_PRINTK("Driver cleanup failed\n");
+ return -ENODEV;
+ }
+#endif
+#if 0
+ DEBUG_PRINTK("Registering device driver");
+ if (platform_device_register(&omaplfb_device))
+ {
+ WARNING_PRINTK("Unable to register platform device");
+ platform_driver_unregister(&omaplfb_driver);
+ if(OMAPLFBDeinit() != OMAP_OK)
+ WARNING_PRINTK("Driver cleanup failed\n");
+ return -ENODEV;
+ }
+#endif
+
+#if defined(SGX_EARLYSUSPEND) && defined(CONFIG_HAS_EARLYSUSPEND)
+ omaplfb_early_suspend.suspend = OMAPLFBDriverSuspend_Entry;
+ omaplfb_early_suspend.resume = OMAPLFBDriverResume_Entry;
+ omaplfb_early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
+ register_early_suspend(&omaplfb_early_suspend);
+ DEBUG_PRINTK("Registered early suspend support");
+#endif
+
+#endif
+ return 0;
+}
+
+/*
+ * Driver exit function
+ */
+#if defined(SUPPORT_DRI_DRM)
+void PVR_DRM_MAKENAME(DISPLAY_CONTROLLER, _Cleanup)
+ (struct drm_device unref__ *dev)
+#else
+static IMG_VOID __exit OMAPLFB_Cleanup(IMG_VOID)
+#endif
+{
+#if defined(LDM_PLATFORM)
+#if 0
+ DEBUG_PRINTK(format, ...)("Removing platform device");
+ platform_device_unregister(&omaplfb_device);
+#endif
+#if !defined(SUPPORT_DRI_DRM)
+ DEBUG_PRINTK("Removing platform driver");
+ platform_driver_unregister(&omaplfb_driver);
+#endif
+#if defined(SGX_EARLYSUSPEND) && defined(CONFIG_HAS_EARLYSUSPEND)
+ unregister_early_suspend(&omaplfb_early_suspend);
+#endif
+#endif
+ if(OMAPLFBDeinit() != OMAP_OK)
+ WARNING_PRINTK("Driver cleanup failed");
+}
+
+#if !defined(SUPPORT_DRI_DRM)
+late_initcall(OMAPLFB_Init);
+module_exit(OMAPLFB_Cleanup);
+#endif