/********************************************************************** * * 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. * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK * ******************************************************************************/ #include #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38)) #ifndef AUTOCONF_INCLUDED #include #endif #endif #include #if defined(SUPPORT_DRI_DRM) #include #else #include #endif #include #include #include #include #include #include #include #include #include #include #if defined(PVR_OMAPLFB_DRM_FB) #include #include #else #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)) #define PVR_OMAPFB3_NEEDS_PLAT_VRFB_H #endif #if defined(PVR_OMAPFB3_NEEDS_PLAT_VRFB_H) #include #else #if defined(PVR_OMAPFB3_NEEDS_MACH_VRFB_H) #include #endif #endif #if defined(DEBUG) #define PVR_DEBUG DEBUG #undef DEBUG #endif #include "../omapfb/omapfb.h" #if defined(DEBUG) #undef DEBUG #endif #if defined(PVR_DEBUG) #define DEBUG PVR_DEBUG #undef PVR_DEBUG #endif #endif #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 MODULE_SUPPORTED_DEVICE(DEVNAME); #if !defined(PVR_OMAPLFB_DRM_FB) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)) #define OMAP_DSS_DRIVER(drv, dev) struct omap_dss_driver *drv = (dev) != NULL ? (dev)->driver : NULL #define OMAP_DSS_MANAGER(man, dev) struct omap_overlay_manager *man = (dev) != NULL ? (dev)->manager : NULL #define WAIT_FOR_VSYNC(man) ((man)->wait_for_vsync) #else #define OMAP_DSS_DRIVER(drv, dev) struct omap_dss_device *drv = (dev) #define OMAP_DSS_MANAGER(man, dev) struct omap_dss_device *man = (dev) #define WAIT_FOR_VSYNC(man) ((man)->wait_vsync) #endif #endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,1,0)) #define OMAP_FB_UPDATE_MODE #define OMAP_UPDATE_MODE omapfb_update_mode #define OMAP_UPDATE_MODE_AUTO OMAPFB_AUTO_UPDATE #define OMAP_UPDATE_MODE_MANUAL OMAPFB_MANUAL_UPDATE #define OMAP_UPDATE_MODE_DISABLED OMAPFB_UPDATE_DISABLED #else #define OMAP_UPDATE_MODE omap_dss_update_mode #define OMAP_UPDATE_MODE_AUTO OMAP_DSS_UPDATE_AUTO #define OMAP_UPDATE_MODE_MANUAL OMAP_DSS_UPDATE_MANUAL #define OMAP_UPDATE_MODE_DISABLED OMAP_DSS_UPDATE_DISABLED #endif static int debug; module_param(debug, int, 0644); /* For future use */ static struct sgx_omaplfb_platform_data *gplatdata; void *OMAPLFBAllocKernelMem(unsigned long ulSize) { return kmalloc(ulSize, GFP_KERNEL); } void OMAPLFBFreeKernelMem(void *pvMem) { kfree(pvMem); } void OMAPLFBCreateSwapChainLockInit(OMAPLFB_DEVINFO *psDevInfo) { mutex_init(&psDevInfo->sCreateSwapChainMutex); } void OMAPLFBCreateSwapChainLockDeInit(OMAPLFB_DEVINFO *psDevInfo) { mutex_destroy(&psDevInfo->sCreateSwapChainMutex); } void OMAPLFBCreateSwapChainLock(OMAPLFB_DEVINFO *psDevInfo) { mutex_lock(&psDevInfo->sCreateSwapChainMutex); } void OMAPLFBCreateSwapChainUnLock(OMAPLFB_DEVINFO *psDevInfo) { mutex_unlock(&psDevInfo->sCreateSwapChainMutex); } void OMAPLFBAtomicBoolInit(OMAPLFB_ATOMIC_BOOL *psAtomic, OMAPLFB_BOOL bVal) { atomic_set(psAtomic, (int)bVal); } void OMAPLFBAtomicBoolDeInit(OMAPLFB_ATOMIC_BOOL *psAtomic) { } void OMAPLFBAtomicBoolSet(OMAPLFB_ATOMIC_BOOL *psAtomic, OMAPLFB_BOOL bVal) { atomic_set(psAtomic, (int)bVal); } OMAPLFB_BOOL OMAPLFBAtomicBoolRead(OMAPLFB_ATOMIC_BOOL *psAtomic) { return (OMAPLFB_BOOL)atomic_read(psAtomic); } void OMAPLFBAtomicIntInit(OMAPLFB_ATOMIC_INT *psAtomic, int iVal) { atomic_set(psAtomic, iVal); } void OMAPLFBAtomicIntDeInit(OMAPLFB_ATOMIC_INT *psAtomic) { } void OMAPLFBAtomicIntSet(OMAPLFB_ATOMIC_INT *psAtomic, int iVal) { atomic_set(psAtomic, iVal); } int OMAPLFBAtomicIntRead(OMAPLFB_ATOMIC_INT *psAtomic) { return atomic_read(psAtomic); } void OMAPLFBAtomicIntInc(OMAPLFB_ATOMIC_INT *psAtomic) { atomic_inc(psAtomic); } #if !defined(CONFIG_OMAPLFB) OMAPLFB_ERROR OMAPLFBGetLibFuncAddr (char *szFunctionName, PFN_DC_GET_PVRJTABLE *ppfnFuncTable) { if(strcmp("PVRGetDisplayClassJTable", szFunctionName) != 0) { return (OMAPLFB_ERROR_INVALID_PARAMS); } *ppfnFuncTable = PVRGetDisplayClassJTable; return (OMAPLFB_OK); } #endif void OMAPLFBQueueBufferForSwap(OMAPLFB_SWAPCHAIN *psSwapChain, OMAPLFB_BUFFER *psBuffer) { int res = queue_work(psSwapChain->psWorkQueue, &psBuffer->sWork); if (res == 0) { printk(KERN_WARNING DRIVER_PREFIX ": %s: Device %u: Buffer already on work queue\n", __FUNCTION__, psSwapChain->uiFBDevID); } } static void WorkQueueHandler(struct work_struct *psWork) { OMAPLFB_BUFFER *psBuffer = container_of(psWork, OMAPLFB_BUFFER, sWork); OMAPLFBSwapHandler(psBuffer); } OMAPLFB_ERROR OMAPLFBCreateSwapQueue(OMAPLFB_SWAPCHAIN *psSwapChain) { #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) psSwapChain->psWorkQueue = alloc_ordered_workqueue(DEVNAME, WQ_FREEZABLE | WQ_MEM_RECLAIM); #else #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)) psSwapChain->psWorkQueue = create_freezable_workqueue(DEVNAME); #else psSwapChain->psWorkQueue = __create_workqueue(DEVNAME, 1, 1, 1); #endif #endif if (psSwapChain->psWorkQueue == NULL) { printk(KERN_ERR DRIVER_PREFIX ": %s: Device %u: Couldn't create workqueue\n", __FUNCTION__, psSwapChain->uiFBDevID); return (OMAPLFB_ERROR_INIT_FAILURE); } return (OMAPLFB_OK); } void OMAPLFBInitBufferForSwap(OMAPLFB_BUFFER *psBuffer) { INIT_WORK(&psBuffer->sWork, WorkQueueHandler); } void OMAPLFBDestroySwapQueue(OMAPLFB_SWAPCHAIN *psSwapChain) { destroy_workqueue(psSwapChain->psWorkQueue); } #if defined(CONFIG_DSSCOMP) #include