diff options
Diffstat (limited to 'sgx/services4/3rdparty/dc_omap_linux')
-rwxr-xr-x | sgx/services4/3rdparty/dc_omap_linux/3rdparty_dc_drm_shared.h | 45 | ||||
-rwxr-xr-x | sgx/services4/3rdparty/dc_omap_linux/Kbuild.mk | 33 | ||||
-rwxr-xr-x | sgx/services4/3rdparty/dc_omap_linux/Linux.mk | 30 | ||||
-rwxr-xr-x | sgx/services4/3rdparty/dc_omap_linux/omaplfb.h | 253 | ||||
-rwxr-xr-x | sgx/services4/3rdparty/dc_omap_linux/omaplfb_displayclass.c | 1969 | ||||
-rwxr-xr-x | sgx/services4/3rdparty/dc_omap_linux/omaplfb_linux.c | 520 |
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 |