diff options
Diffstat (limited to 'drivers/staging/cdv/pvr/services4/3rdparty/linux_framebuffer_mrst/mrstlfb_displayclass.c')
-rw-r--r-- | drivers/staging/cdv/pvr/services4/3rdparty/linux_framebuffer_mrst/mrstlfb_displayclass.c | 1652 |
1 files changed, 1652 insertions, 0 deletions
diff --git a/drivers/staging/cdv/pvr/services4/3rdparty/linux_framebuffer_mrst/mrstlfb_displayclass.c b/drivers/staging/cdv/pvr/services4/3rdparty/linux_framebuffer_mrst/mrstlfb_displayclass.c new file mode 100644 index 000000000000..7d937d75318c --- /dev/null +++ b/drivers/staging/cdv/pvr/services4/3rdparty/linux_framebuffer_mrst/mrstlfb_displayclass.c @@ -0,0 +1,1652 @@ +/********************************************************************** + * + * 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> +#include <linux/module.h> +#include <linux/string.h> +#include <linux/notifier.h> +#include <linux/spinlock.h> +#include <asm/intel_scu_ipc.h> + +#include "img_defs.h" +#include "servicesext.h" +#include "kerneldisplay.h" +#include "mrstlfb.h" + +#include "psb_fb.h" +#include "psb_drv.h" +#include "psb_powermgmt.h" + +IMG_UINT32 gui32MRSTDisplayDeviceID; + +PVRSRV_ERROR MRSTLFBPrePowerState(IMG_HANDLE hDevHandle, + PVRSRV_DEV_POWER_STATE eNewPowerState, + PVRSRV_DEV_POWER_STATE eCurrentPowerState); + +PVRSRV_ERROR MRSTLFBPostPowerState(IMG_HANDLE hDevHandle, + PVRSRV_DEV_POWER_STATE eNewPowerState, + PVRSRV_DEV_POWER_STATE eCurrentPowerState); + +#ifdef MODESET_640x480 +extern int psb_to_640 (struct fb_info* info); +#endif + +extern void mrst_init_LGE_MIPI(struct drm_device *dev); +extern void mrst_init_NSC_MIPI_bridge(struct drm_device *dev); + +struct psbfb_par { + struct drm_device *dev; + void *psbfb; + + int dpms_state; + + int crtc_count; + + uint32_t crtc_ids[2]; +}; + +extern void* psbfb_vdc_reg(struct drm_device* dev); + +static void *gpvAnchor; + + +#define MRSTLFB_COMMAND_COUNT 1 + +static PFN_DC_GET_PVRJTABLE pfnGetPVRJTable = 0; + +static MRSTLFB_DEVINFO * GetAnchorPtr(void) +{ + return (MRSTLFB_DEVINFO *)gpvAnchor; +} + +static void SetAnchorPtr(MRSTLFB_DEVINFO *psDevInfo) +{ + gpvAnchor = (void*)psDevInfo; +} + +static int MRSTLFB_dimension_match(MRSTLFB_DEVINFO *psDevInfo, MRSTLFB_SWAPCHAIN *psSwapChain) +{ + int dimension_match = 1; + + /* When the psSwapchain is NULL, it means that it will explicitly switch + * to the system buffer. So it is considered as match. + */ + if (!psSwapChain) + return dimension_match; + + if ((psSwapChain->ui32Height != psDevInfo->sDisplayDim.ui32Height) || + (psSwapChain->ui32ByteStride != psDevInfo->sDisplayDim.ui32ByteStride) || + (psSwapChain->ui32Width != psDevInfo->sDisplayDim.ui32Width)) + dimension_match = 0; + + return dimension_match; +} + +static void MRSTLFBFlip(MRSTLFB_DEVINFO *psDevInfo, MRSTLFB_BUFFER *psBuffer, int dim_match) +{ + unsigned long ulAddr = (unsigned long)psBuffer->sDevVAddr.uiAddr; + + if (!psDevInfo->bSuspended && !psDevInfo->bLeaveVT && dim_match) + { + MRSTLFBFlipToSurface(psDevInfo, ulAddr); + } + + psDevInfo->ulLastFlipAddr = ulAddr; + psDevInfo->bLastFlipAddrValid = MRST_TRUE; +} + +static void MRSTLFBRestoreLastFlip(MRSTLFB_DEVINFO *psDevInfo) +{ + if (!psDevInfo->bSuspended && !psDevInfo->bLeaveVT) + { + if (psDevInfo->bLastFlipAddrValid) + { + MRSTLFBFlipToSurface(psDevInfo, psDevInfo->ulLastFlipAddr); + } + } +} + +static void MRSTLFBClearSavedFlip(MRSTLFB_DEVINFO *psDevInfo) +{ + psDevInfo->bLastFlipAddrValid = MRST_FALSE; +} + +static void FlushInternalVSyncQueue(MRSTLFB_SWAPCHAIN *psSwapChain, MRST_BOOL bFlip, int dim_match) +{ + MRSTLFB_VSYNC_FLIP_ITEM *psFlipItem; + unsigned long ulMaxIndex; + unsigned long i; + + psFlipItem = &psSwapChain->psVSyncFlips[psSwapChain->ulRemoveIndex]; + ulMaxIndex = psSwapChain->ulSwapChainLength - 1; + + for(i = 0; i < psSwapChain->ulSwapChainLength; i++) + { + if (psFlipItem->bValid == MRST_FALSE) + { + continue; + } + + DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX ": FlushInternalVSyncQueue: Flushing swap buffer (index %lu)\n", psSwapChain->ulRemoveIndex)); + + if(psFlipItem->bFlipped == MRST_FALSE) + { + if (bFlip) + { + + MRSTLFBFlip(psSwapChain->psDevInfo, psFlipItem->psBuffer, dim_match); + } + } + + if(psFlipItem->bCmdCompleted == MRST_FALSE) + { + DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX ": FlushInternalVSyncQueue: Calling command complete for swap buffer (index %lu)\n", psSwapChain->ulRemoveIndex)); + + psSwapChain->psPVRJTable->pfnPVRSRVCmdComplete((IMG_HANDLE)psFlipItem->hCmdComplete, MRST_TRUE); + } + + + psSwapChain->ulRemoveIndex++; + + if(psSwapChain->ulRemoveIndex > ulMaxIndex) + { + psSwapChain->ulRemoveIndex = 0; + } + + + psFlipItem->bFlipped = MRST_FALSE; + psFlipItem->bCmdCompleted = MRST_FALSE; + psFlipItem->bValid = MRST_FALSE; + + + psFlipItem = &psSwapChain->psVSyncFlips[psSwapChain->ulRemoveIndex]; + } + + psSwapChain->ulInsertIndex = 0; + psSwapChain->ulRemoveIndex = 0; +} + +static void DRMLFBFlipBuffer(MRSTLFB_DEVINFO *psDevInfo, MRSTLFB_SWAPCHAIN *psSwapChain, MRSTLFB_BUFFER *psBuffer) +{ + int dim_match = MRSTLFB_dimension_match(psDevInfo, psSwapChain); + if(psSwapChain != NULL) + { + if(psDevInfo->psCurrentSwapChain != NULL) + { + + if(psDevInfo->psCurrentSwapChain != psSwapChain) + FlushInternalVSyncQueue(psDevInfo->psCurrentSwapChain, MRST_FALSE, dim_match); + } + psDevInfo->psCurrentSwapChain = psSwapChain; + } + + MRSTLFBFlip(psDevInfo, psBuffer, dim_match); +} + +static void SetFlushStateNoLock(MRSTLFB_DEVINFO* psDevInfo, + MRST_BOOL bFlushState) +{ + if (bFlushState) + { + if (psDevInfo->ulSetFlushStateRefCount == 0) + { + psDevInfo->bFlushCommands = MRST_TRUE; + if (psDevInfo->psCurrentSwapChain != NULL) + { + int dim_match = MRSTLFB_dimension_match(psDevInfo, + psDevInfo->psCurrentSwapChain); + FlushInternalVSyncQueue(psDevInfo->psCurrentSwapChain, MRST_TRUE, dim_match); + } + } + psDevInfo->ulSetFlushStateRefCount++; + } + else + { + if (psDevInfo->ulSetFlushStateRefCount != 0) + { + psDevInfo->ulSetFlushStateRefCount--; + if (psDevInfo->ulSetFlushStateRefCount == 0) + { + psDevInfo->bFlushCommands = MRST_FALSE; + } + } + } +} + +static IMG_VOID SetFlushState(MRSTLFB_DEVINFO* psDevInfo, + MRST_BOOL bFlushState) +{ + unsigned long ulLockFlags; + + spin_lock_irqsave(&psDevInfo->sSwapChainLock, ulLockFlags); + + SetFlushStateNoLock(psDevInfo, bFlushState); + + spin_unlock_irqrestore(&psDevInfo->sSwapChainLock, ulLockFlags); +} + +static IMG_VOID SetDCState(IMG_HANDLE hDevice, IMG_UINT32 ui32State) +{ + MRSTLFB_DEVINFO *psDevInfo = (MRSTLFB_DEVINFO *)hDevice; + + switch (ui32State) + { + case DC_STATE_FLUSH_COMMANDS: + SetFlushState(psDevInfo, MRST_TRUE); + break; + case DC_STATE_NO_FLUSH_COMMANDS: + SetFlushState(psDevInfo, MRST_FALSE); + break; + default: + break; + } + + return; +} + +static int FrameBufferEvents(struct notifier_block *psNotif, + unsigned long event, void *data) +{ + MRSTLFB_DEVINFO *psDevInfo; + struct fb_event *psFBEvent = (struct fb_event *)data; + MRST_BOOL bBlanked; + + + if (event != FB_EVENT_BLANK) + { + return 0; + } + + psDevInfo = GetAnchorPtr(); + + bBlanked = (*(IMG_INT *)psFBEvent->data != 0) ? MRST_TRUE: MRST_FALSE; + + if (bBlanked != psDevInfo->bBlanked) + { + psDevInfo->bBlanked = bBlanked; + + SetFlushState(psDevInfo, bBlanked); + } + + return 0; +} + + +static MRST_ERROR UnblankDisplay(MRSTLFB_DEVINFO *psDevInfo) +{ + int res; + + console_lock(); + res = fb_blank(psDevInfo->psLINFBInfo, 0); + console_unlock(); + if (res != 0) + { + printk(KERN_WARNING DRIVER_PREFIX + ": fb_blank failed (%d)", res); + return (MRST_ERROR_GENERIC); + } + + return (MRST_OK); +} + +static MRST_ERROR EnableLFBEventNotification(MRSTLFB_DEVINFO *psDevInfo) +{ + int res; + MRST_ERROR eError; + + + memset(&psDevInfo->sLINNotifBlock, 0, sizeof(psDevInfo->sLINNotifBlock)); + + psDevInfo->sLINNotifBlock.notifier_call = FrameBufferEvents; + psDevInfo->bBlanked = MRST_FALSE; + + res = fb_register_client(&psDevInfo->sLINNotifBlock); + if (res != 0) + { + printk(KERN_WARNING DRIVER_PREFIX + ": fb_register_client failed (%d)", res); + + return (MRST_ERROR_GENERIC); + } + + eError = UnblankDisplay(psDevInfo); + if (eError != MRST_OK) + { + DEBUG_PRINTK((KERN_WARNING DRIVER_PREFIX + ": UnblankDisplay failed (%d)", eError)); + return eError; + } + + return (MRST_OK); +} + +static MRST_ERROR DisableLFBEventNotification(MRSTLFB_DEVINFO *psDevInfo) +{ + int res; + + + res = fb_unregister_client(&psDevInfo->sLINNotifBlock); + if (res != 0) + { + printk(KERN_WARNING DRIVER_PREFIX + ": fb_unregister_client failed (%d)", res); + return (MRST_ERROR_GENERIC); + } + + return (MRST_OK); +} + +static PVRSRV_ERROR OpenDCDevice(IMG_UINT32 ui32DeviceID, + IMG_HANDLE *phDevice, + PVRSRV_SYNC_DATA* psSystemBufferSyncData) +{ + MRSTLFB_DEVINFO *psDevInfo; + MRST_ERROR eError; + + UNREFERENCED_PARAMETER(ui32DeviceID); + + psDevInfo = GetAnchorPtr(); + + + psDevInfo->sSystemBuffer.psSyncData = psSystemBufferSyncData; + + psDevInfo->ulSetFlushStateRefCount = 0; + psDevInfo->bFlushCommands = MRST_FALSE; + + eError = EnableLFBEventNotification(psDevInfo); + if (eError != MRST_OK) + { + printk(KERN_WARNING DRIVER_PREFIX ": Couldn't enable framebuffer event notification\n"); + return PVRSRV_ERROR_UNABLE_TO_OPEN_DC_DEVICE; + } + + + *phDevice = (IMG_HANDLE)psDevInfo; + + return (PVRSRV_OK); +} + +static PVRSRV_ERROR CloseDCDevice(IMG_HANDLE hDevice) +{ + MRSTLFB_DEVINFO *psDevInfo = (MRSTLFB_DEVINFO *)hDevice; + MRST_ERROR eError; + + eError = DisableLFBEventNotification(psDevInfo); + if (eError != MRST_OK) + { + printk(KERN_WARNING DRIVER_PREFIX ": Couldn't disable framebuffer event notification\n"); + return PVRSRV_ERROR_UNABLE_TO_REMOVE_DEVICE; + } + + return (PVRSRV_OK); +} + +static PVRSRV_ERROR EnumDCFormats(IMG_HANDLE hDevice, + IMG_UINT32 *pui32NumFormats, + DISPLAY_FORMAT *psFormat) +{ + MRSTLFB_DEVINFO *psDevInfo; + + if(!hDevice || !pui32NumFormats) + { + return (PVRSRV_ERROR_INVALID_PARAMS); + } + + psDevInfo = (MRSTLFB_DEVINFO*)hDevice; + + *pui32NumFormats = 1; + + if(psFormat) + { + psFormat[0] = psDevInfo->sDisplayFormat; + } + + return (PVRSRV_OK); +} + +static PVRSRV_ERROR EnumDCDims(IMG_HANDLE hDevice, + DISPLAY_FORMAT *psFormat, + IMG_UINT32 *pui32NumDims, + DISPLAY_DIMS *psDim) +{ + MRSTLFB_DEVINFO *psDevInfo; + + if(!hDevice || !psFormat || !pui32NumDims) + { + return (PVRSRV_ERROR_INVALID_PARAMS); + } + + psDevInfo = (MRSTLFB_DEVINFO*)hDevice; + + *pui32NumDims = 1; + + + if(psDim) + { + psDim[0] = psDevInfo->sDisplayDim; + } + + return (PVRSRV_OK); +} + + +static PVRSRV_ERROR GetDCSystemBuffer(IMG_HANDLE hDevice, IMG_HANDLE *phBuffer) +{ + MRSTLFB_DEVINFO *psDevInfo; + + if(!hDevice || !phBuffer) + { + return (PVRSRV_ERROR_INVALID_PARAMS); + } + + psDevInfo = (MRSTLFB_DEVINFO*)hDevice; + + + + *phBuffer = (IMG_HANDLE)&psDevInfo->sSystemBuffer; + + return (PVRSRV_OK); +} + + +static PVRSRV_ERROR GetDCInfo(IMG_HANDLE hDevice, DISPLAY_INFO *psDCInfo) +{ + MRSTLFB_DEVINFO *psDevInfo; + + if(!hDevice || !psDCInfo) + { + return (PVRSRV_ERROR_INVALID_PARAMS); + } + + psDevInfo = (MRSTLFB_DEVINFO*)hDevice; + + *psDCInfo = psDevInfo->sDisplayInfo; + + return (PVRSRV_OK); +} + +static PVRSRV_ERROR GetDCBufferAddr(IMG_HANDLE hDevice, + IMG_HANDLE hBuffer, + IMG_SYS_PHYADDR **ppsSysAddr, + IMG_SIZE_T *pui32ByteSize, + IMG_VOID **ppvCpuVAddr, + IMG_HANDLE *phOSMapInfo, + IMG_BOOL *pbIsContiguous, + IMG_UINT32 *pui32TilingStride) +{ + MRSTLFB_BUFFER *psSystemBuffer; + + UNREFERENCED_PARAMETER(pui32TilingStride); + + if(!hDevice) + { + return (PVRSRV_ERROR_INVALID_PARAMS); + } + + if(!hBuffer) + { + return (PVRSRV_ERROR_INVALID_PARAMS); + } + psSystemBuffer = (MRSTLFB_BUFFER *)hBuffer; + + if (!ppsSysAddr) + { + return (PVRSRV_ERROR_INVALID_PARAMS); + } + + if( psSystemBuffer->bIsContiguous ) + *ppsSysAddr = &psSystemBuffer->uSysAddr.sCont; + else + *ppsSysAddr = psSystemBuffer->uSysAddr.psNonCont; + + if (!pui32ByteSize) + { + return (PVRSRV_ERROR_INVALID_PARAMS); + } + *pui32ByteSize = psSystemBuffer->ui32BufferSize; + + if (ppvCpuVAddr) + { + *ppvCpuVAddr = psSystemBuffer->sCPUVAddr; + } + + if (phOSMapInfo) + { + *phOSMapInfo = (IMG_HANDLE)0; + } + + if (pbIsContiguous) + { + *pbIsContiguous = psSystemBuffer->bIsContiguous; + } + + return (PVRSRV_OK); +} + + + +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) +{ + MRSTLFB_DEVINFO *psDevInfo; + MRSTLFB_SWAPCHAIN *psSwapChain; + MRSTLFB_BUFFER **ppsBuffer; + MRSTLFB_VSYNC_FLIP_ITEM *psVSyncFlips; + IMG_UINT32 i; + IMG_UINT32 iSCId = MAX_SWAPCHAINS; + PVRSRV_ERROR eError = PVRSRV_ERROR_NOT_SUPPORTED; + unsigned long ulLockFlags; + struct drm_device* psDrmDev; + unsigned long ulSwapChainLength; + + UNREFERENCED_PARAMETER(ui32OEMFlags); + + + if(!hDevice + || !psDstSurfAttrib + || !psSrcSurfAttrib + || !ppsSyncData + || !phSwapChain) + { + return (PVRSRV_ERROR_INVALID_PARAMS); + } + + psDevInfo = (MRSTLFB_DEVINFO*)hDevice; + + + if(ui32BufferCount > psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers) + { + return (PVRSRV_ERROR_TOOMANYBUFFERS); + } + + + ulSwapChainLength = ui32BufferCount + 1; + + + + if(psDstSurfAttrib->pixelformat != psDevInfo->sDisplayFormat.pixelformat + || psDstSurfAttrib->sDims.ui32ByteStride != psDevInfo->sDisplayDim.ui32ByteStride + || psDstSurfAttrib->sDims.ui32Width != psDevInfo->sDisplayDim.ui32Width + || psDstSurfAttrib->sDims.ui32Height != psDevInfo->sDisplayDim.ui32Height) + { + + 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) + { + + return (PVRSRV_ERROR_INVALID_PARAMS); + } + + + UNREFERENCED_PARAMETER(ui32Flags); + + /* If we can't enable the vblank on the corresponding pipe, + * don't create the DC swap chain + */ + if (psb_enable_vblank(psDevInfo->psDrmDevice, psDevInfo->ui32MainPipe)) + return (PVRSRV_ERROR_NOT_SUPPORTED); + + + psSwapChain = (MRSTLFB_SWAPCHAIN*)MRSTLFBAllocKernelMem(sizeof(MRSTLFB_SWAPCHAIN)); + if(!psSwapChain) + { + return (PVRSRV_ERROR_OUT_OF_MEMORY); + } + + for(iSCId = 0;iSCId < MAX_SWAPCHAINS;++iSCId) + { + if( psDevInfo->apsSwapChains[iSCId] == NULL ) + { + psDevInfo->apsSwapChains[iSCId] = psSwapChain; + break; + } + } + + if(iSCId == MAX_SWAPCHAINS) + { + eError = PVRSRV_ERROR_OUT_OF_MEMORY; + goto ErrorFreeSwapChain; + } + + ppsBuffer = (MRSTLFB_BUFFER**)MRSTLFBAllocKernelMem(sizeof(MRSTLFB_BUFFER*) * ui32BufferCount); + if(!ppsBuffer) + { + eError = PVRSRV_ERROR_OUT_OF_MEMORY; + goto ErrorFreeSwapChain; + } + + psVSyncFlips = (MRSTLFB_VSYNC_FLIP_ITEM *)MRSTLFBAllocKernelMem(sizeof(MRSTLFB_VSYNC_FLIP_ITEM) * ulSwapChainLength); + if (!psVSyncFlips) + { + eError = PVRSRV_ERROR_OUT_OF_MEMORY; + goto ErrorFreeBuffers; + } + + psSwapChain->ulSwapChainLength = ulSwapChainLength; + psSwapChain->ulBufferCount = (unsigned long)ui32BufferCount; + psSwapChain->ppsBuffer = ppsBuffer; + psSwapChain->psVSyncFlips = psVSyncFlips; + psSwapChain->ulInsertIndex = 0; + psSwapChain->ulRemoveIndex = 0; + psSwapChain->psPVRJTable = &psDevInfo->sPVRJTable; + /* save the dimension info of system buffer for the new swapchain*/ + psSwapChain->ui32Height = psDevInfo->sDisplayDim.ui32Height; + psSwapChain->ui32ByteStride = psDevInfo->sDisplayDim.ui32ByteStride; + psSwapChain->ui32Width = psDevInfo->sDisplayDim.ui32Width; + + memset(ppsBuffer, 0, sizeof(MRSTLFB_BUFFER *) * ui32BufferCount); + for (i = 0; i < ui32BufferCount; i++) + { + unsigned long bufSize = psDevInfo->sDisplayDim.ui32ByteStride * psDevInfo->sDisplayDim.ui32Height; + if (MRSTLFBAllocBuffer(psDevInfo->psDrmDevice, bufSize, &ppsBuffer[i]) != MRST_OK) { + eError = PVRSRV_ERROR_OUT_OF_MEMORY; + goto ErrorFreeVSyncFlips; + } + ppsBuffer[i]->psSyncData = ppsSyncData[i]; + } + + + for (i = 0; i < ulSwapChainLength; i++) + { + psVSyncFlips[i].bValid = MRST_FALSE; + psVSyncFlips[i].bFlipped = MRST_FALSE; + psVSyncFlips[i].bCmdCompleted = MRST_FALSE; + } + + + psDrmDev = psDevInfo->psDrmDevice; + + psSwapChain->psDevInfo = psDevInfo; + psSwapChain->psDrmDev = psDrmDev; + psSwapChain->psDrmDriver = psDrmDev->driver; + + spin_lock_irqsave(&psDevInfo->sSwapChainLock, ulLockFlags); + + psSwapChain->ui32SwapChainID = *pui32SwapChainID = iSCId+1; + + if(psDevInfo->psCurrentSwapChain == NULL) + psDevInfo->psCurrentSwapChain = psSwapChain; + + psDevInfo->ui32SwapChainNum++; + if(psDevInfo->ui32SwapChainNum == 1) + { + MRSTLFBEnableVSyncInterrupt(psDevInfo); + } + + spin_unlock_irqrestore(&psDevInfo->sSwapChainLock, ulLockFlags); + + + *phSwapChain = (IMG_HANDLE)psSwapChain; + + return (PVRSRV_OK); + +ErrorFreeVSyncFlips: + for (i = 0; i < ui32BufferCount; i++) { + MRSTLFBFreeBuffer(psDevInfo->psDrmDevice, &ppsBuffer[i]); + } + MRSTLFBFreeKernelMem(psVSyncFlips); +ErrorFreeBuffers: + MRSTLFBFreeKernelMem(ppsBuffer); +ErrorFreeSwapChain: + if(iSCId != MAX_SWAPCHAINS && psDevInfo->apsSwapChains[iSCId] == psSwapChain ) + psDevInfo->apsSwapChains[iSCId] = NULL; + MRSTLFBFreeKernelMem(psSwapChain); + + return eError; +} + +static PVRSRV_ERROR DestroyDCSwapChain(IMG_HANDLE hDevice, + IMG_HANDLE hSwapChain) +{ + MRSTLFB_DEVINFO *psDevInfo; + MRSTLFB_SWAPCHAIN *psSwapChain; + unsigned long ulLockFlags; + int i; + int dimension_match; + + + if(!hDevice || !hSwapChain) + { + return (PVRSRV_ERROR_INVALID_PARAMS); + } + + psDevInfo = (MRSTLFB_DEVINFO*)hDevice; + psSwapChain = (MRSTLFB_SWAPCHAIN*)hSwapChain; + + spin_lock_irqsave(&psDevInfo->sSwapChainLock, ulLockFlags); + dimension_match = MRSTLFB_dimension_match(psDevInfo, psSwapChain); + + psDevInfo->ui32SwapChainNum--; + + if(psDevInfo->ui32SwapChainNum == 0) + { + MRSTLFBDisableVSyncInterrupt(psDevInfo); + psDevInfo->psCurrentSwapChain = NULL; + } + + psDevInfo->apsSwapChains[ psSwapChain->ui32SwapChainID -1] = NULL; + + + FlushInternalVSyncQueue(psSwapChain, (psDevInfo->ui32SwapChainNum == 0), dimension_match); + + if (psDevInfo->ui32SwapChainNum == 0) + { + + DRMLFBFlipBuffer(psDevInfo, NULL, &psDevInfo->sSystemBuffer); + MRSTLFBClearSavedFlip(psDevInfo); + } + + if(psDevInfo->psCurrentSwapChain == psSwapChain) + psDevInfo->psCurrentSwapChain = NULL; + + spin_unlock_irqrestore(&psDevInfo->sSwapChainLock, ulLockFlags); + + + for (i = 0; i < psSwapChain->ulBufferCount; i++) + { + MRSTLFBFreeBuffer(psDevInfo->psDrmDevice, &psSwapChain->ppsBuffer[i] ); + } + MRSTLFBFreeKernelMem(psSwapChain->psVSyncFlips); + MRSTLFBFreeKernelMem(psSwapChain->ppsBuffer); + MRSTLFBFreeKernelMem(psSwapChain); + + return (PVRSRV_OK); +} + +static PVRSRV_ERROR SetDCDstRect(IMG_HANDLE hDevice, + IMG_HANDLE hSwapChain, + IMG_RECT *psRect) +{ + UNREFERENCED_PARAMETER(hDevice); + UNREFERENCED_PARAMETER(hSwapChain); + UNREFERENCED_PARAMETER(psRect); + + + + return (PVRSRV_ERROR_NOT_SUPPORTED); +} + +static PVRSRV_ERROR SetDCSrcRect(IMG_HANDLE hDevice, + IMG_HANDLE hSwapChain, + IMG_RECT *psRect) +{ + UNREFERENCED_PARAMETER(hDevice); + UNREFERENCED_PARAMETER(hSwapChain); + UNREFERENCED_PARAMETER(psRect); + + + + return (PVRSRV_ERROR_NOT_SUPPORTED); +} + +static PVRSRV_ERROR SetDCDstColourKey(IMG_HANDLE hDevice, + IMG_HANDLE hSwapChain, + IMG_UINT32 ui32CKColour) +{ + UNREFERENCED_PARAMETER(hDevice); + UNREFERENCED_PARAMETER(hSwapChain); + UNREFERENCED_PARAMETER(ui32CKColour); + + + + return (PVRSRV_ERROR_NOT_SUPPORTED); +} + +static PVRSRV_ERROR SetDCSrcColourKey(IMG_HANDLE hDevice, + IMG_HANDLE hSwapChain, + IMG_UINT32 ui32CKColour) +{ + UNREFERENCED_PARAMETER(hDevice); + UNREFERENCED_PARAMETER(hSwapChain); + UNREFERENCED_PARAMETER(ui32CKColour); + + + + return (PVRSRV_ERROR_NOT_SUPPORTED); +} + +static PVRSRV_ERROR GetDCBuffers(IMG_HANDLE hDevice, + IMG_HANDLE hSwapChain, + IMG_UINT32 *pui32BufferCount, + IMG_HANDLE *phBuffer) +{ + MRSTLFB_SWAPCHAIN *psSwapChain; + unsigned long i; + + + if(!hDevice + || !hSwapChain + || !pui32BufferCount + || !phBuffer) + { + return (PVRSRV_ERROR_INVALID_PARAMS); + } + + psSwapChain = (MRSTLFB_SWAPCHAIN*)hSwapChain; + + + *pui32BufferCount = (IMG_UINT32)psSwapChain->ulBufferCount; + + + for(i=0; i<psSwapChain->ulBufferCount; i++) + { + phBuffer[i] = (IMG_HANDLE)psSwapChain->ppsBuffer[i]; + } + + return (PVRSRV_OK); +} + +static PVRSRV_ERROR SwapToDCBuffer(IMG_HANDLE hDevice, + IMG_HANDLE hBuffer, + IMG_UINT32 ui32SwapInterval, + IMG_HANDLE hPrivateTag, + IMG_UINT32 ui32ClipRectCount, + IMG_RECT *psClipRect) +{ + UNREFERENCED_PARAMETER(ui32SwapInterval); + UNREFERENCED_PARAMETER(hPrivateTag); + UNREFERENCED_PARAMETER(psClipRect); + + if(!hDevice + || !hBuffer + || (ui32ClipRectCount != 0)) + { + return (PVRSRV_ERROR_INVALID_PARAMS); + } + + return (PVRSRV_OK); +} + +static PVRSRV_ERROR SwapToDCSystem(IMG_HANDLE hDevice, + IMG_HANDLE hSwapChain) +{ + if(!hDevice || !hSwapChain) + { + return (PVRSRV_ERROR_INVALID_PARAMS); + } + + + return (PVRSRV_OK); +} + +static MRST_BOOL MRSTLFBVSyncIHandler(MRSTLFB_DEVINFO *psDevInfo) +{ + MRST_BOOL bStatus = MRST_TRUE; + MRSTLFB_VSYNC_FLIP_ITEM *psFlipItem; + unsigned long ulMaxIndex; + unsigned long ulLockFlags; + MRSTLFB_SWAPCHAIN *psSwapChain; + + spin_lock_irqsave(&psDevInfo->sSwapChainLock, ulLockFlags); + + + psSwapChain = psDevInfo->psCurrentSwapChain; + if (psSwapChain == NULL) + { + goto ExitUnlock; + } + + + if (psDevInfo->bFlushCommands || psDevInfo->bSuspended || psDevInfo->bLeaveVT) + { + goto ExitUnlock; + } + + psFlipItem = &psSwapChain->psVSyncFlips[psSwapChain->ulRemoveIndex]; + ulMaxIndex = psSwapChain->ulSwapChainLength - 1; + + while(psFlipItem->bValid) + { + + if(psFlipItem->bFlipped) + { + + if(!psFlipItem->bCmdCompleted) + { + + MRST_BOOL bScheduleMISR; + + bScheduleMISR = MRST_TRUE; + + + psSwapChain->psPVRJTable->pfnPVRSRVCmdComplete((IMG_HANDLE)psFlipItem->hCmdComplete, bScheduleMISR); + + + psFlipItem->bCmdCompleted = MRST_TRUE; + } + + + psFlipItem->ulSwapInterval--; + + + if(psFlipItem->ulSwapInterval == 0) + { + + psSwapChain->ulRemoveIndex++; + + if(psSwapChain->ulRemoveIndex > ulMaxIndex) + { + psSwapChain->ulRemoveIndex = 0; + } + + + psFlipItem->bCmdCompleted = MRST_FALSE; + psFlipItem->bFlipped = MRST_FALSE; + + + psFlipItem->bValid = MRST_FALSE; + } + else + { + + break; + } + } + else + { + + DRMLFBFlipBuffer(psDevInfo, psSwapChain, psFlipItem->psBuffer); + + + psFlipItem->bFlipped = MRST_TRUE; + + + break; + } + + + psFlipItem = &psSwapChain->psVSyncFlips[psSwapChain->ulRemoveIndex]; + } + +ExitUnlock: + spin_unlock_irqrestore(&psDevInfo->sSwapChainLock, ulLockFlags); + + return bStatus; +} + +#if defined(MRST_USING_INTERRUPTS) +static int +MRSTLFBVSyncISR(struct drm_device *psDrmDevice, int iPipe) +{ + MRSTLFB_DEVINFO *psDevInfo = GetAnchorPtr(); + + if (iPipe == psDevInfo->ui32MainPipe) + MRSTLFBVSyncIHandler(psDevInfo); + + return 0; +} +#endif + + +static IMG_BOOL ProcessFlip(IMG_HANDLE hCmdCookie, + IMG_UINT32 ui32DataSize, + IMG_VOID *pvData) +{ + DISPLAYCLASS_FLIP_COMMAND *psFlipCmd; + MRSTLFB_DEVINFO *psDevInfo; + MRSTLFB_BUFFER *psBuffer; + MRSTLFB_SWAPCHAIN *psSwapChain; +#if defined(MRST_USING_INTERRUPTS) + MRSTLFB_VSYNC_FLIP_ITEM* psFlipItem; +#endif + unsigned long ulLockFlags; + + + if(!hCmdCookie || !pvData) + { + return IMG_FALSE; + } + + + psFlipCmd = (DISPLAYCLASS_FLIP_COMMAND*)pvData; + + if (psFlipCmd == IMG_NULL || sizeof(DISPLAYCLASS_FLIP_COMMAND) != ui32DataSize) + { + return IMG_FALSE; + } + + + psDevInfo = (MRSTLFB_DEVINFO*)psFlipCmd->hExtDevice; + + psBuffer = (MRSTLFB_BUFFER*)psFlipCmd->hExtBuffer; + psSwapChain = (MRSTLFB_SWAPCHAIN*) psFlipCmd->hExtSwapChain; + + spin_lock_irqsave(&psDevInfo->sSwapChainLock, ulLockFlags); + +#if defined(MRST_USING_INTERRUPTS) + + if(psFlipCmd->ui32SwapInterval == 0 || psDevInfo->bFlushCommands) + { +#endif + DRMLFBFlipBuffer(psDevInfo, psSwapChain, psBuffer); + + + + psSwapChain->psPVRJTable->pfnPVRSRVCmdComplete(hCmdCookie, IMG_TRUE); + +#if defined(MRST_USING_INTERRUPTS) + goto ExitTrueUnlock; + } + + psFlipItem = &psSwapChain->psVSyncFlips[psSwapChain->ulInsertIndex]; + + + if(psFlipItem->bValid == MRST_FALSE) + { + unsigned long ulMaxIndex = psSwapChain->ulSwapChainLength - 1; + + if(psSwapChain->ulInsertIndex == psSwapChain->ulRemoveIndex) + { + + DRMLFBFlipBuffer(psDevInfo, psSwapChain, psBuffer); + + psFlipItem->bFlipped = MRST_TRUE; + } + else + { + psFlipItem->bFlipped = MRST_FALSE; + } + + psFlipItem->hCmdComplete = (MRST_HANDLE)hCmdCookie; + psFlipItem->ulSwapInterval = (unsigned long)psFlipCmd->ui32SwapInterval; + psFlipItem->psBuffer = psBuffer; + psFlipItem->bValid = MRST_TRUE; + + psSwapChain->ulInsertIndex++; + if(psSwapChain->ulInsertIndex > ulMaxIndex) + { + psSwapChain->ulInsertIndex = 0; + } + + goto ExitTrueUnlock; + } + + spin_unlock_irqrestore(&psDevInfo->sSwapChainLock, ulLockFlags); + return IMG_FALSE; + +ExitTrueUnlock: +#endif + spin_unlock_irqrestore(&psDevInfo->sSwapChainLock, ulLockFlags); + return IMG_TRUE; +} + + +#if defined(PVR_MRST_FB_SET_PAR_ON_INIT) +static void MRSTFBSetPar(struct fb_info *psLINFBInfo) +{ + console_lock(); + + if (psLINFBInfo->fbops->fb_set_par != NULL) + { + int res; + + res = psLINFBInfo->fbops->fb_set_par(psLINFBInfo); + if (res != 0) + { + printk(KERN_WARNING DRIVER_PREFIX + ": fb_set_par failed: %d\n", res); + + } + } + else + { + printk(KERN_WARNING DRIVER_PREFIX + ": fb_set_par not set - HW cursor may not work\n"); + } + + console_unlock(); +} +#endif + +void MRSTLFBSuspend(void) +{ + MRSTLFB_DEVINFO *psDevInfo = GetAnchorPtr(); + unsigned long ulLockFlags; + + spin_lock_irqsave(&psDevInfo->sSwapChainLock, ulLockFlags); + + if (!psDevInfo->bSuspended) + { +#if !defined(PVR_MRST_STYLE_PM) + if(psDevInfo->ui32SwapChainNum != 0) + { + MRSTLFBDisableVSyncInterrupt(psDevInfo); + } +#endif + psDevInfo->bSuspended = MRST_TRUE; + } + + spin_unlock_irqrestore(&psDevInfo->sSwapChainLock, ulLockFlags); +} + +void MRSTLFBResume(void) +{ + MRSTLFB_DEVINFO *psDevInfo = GetAnchorPtr(); + unsigned long ulLockFlags; + + spin_lock_irqsave(&psDevInfo->sSwapChainLock, ulLockFlags); + + if (psDevInfo->bSuspended) + { +#if !defined(PVR_MRST_STYLE_PM) + if(psDevInfo->ui32SwapChainNum != 0) + { + MRSTLFBEnableVSyncInterrupt(psDevInfo); + } +#endif + psDevInfo->bSuspended = MRST_FALSE; + + MRSTLFBRestoreLastFlip(psDevInfo); + } + + spin_unlock_irqrestore(&psDevInfo->sSwapChainLock, ulLockFlags); + +#if !defined(PVR_MRST_STYLE_PM) + (void) UnblankDisplay(psDevInfo); +#endif +} + +#ifdef DRM_PVR_USE_INTEL_FB +#include "mm.h" +int MRSTLFBHandleChangeFB(struct drm_device* dev, struct psb_framebuffer *psbfb) +{ + MRSTLFB_DEVINFO *psDevInfo = GetAnchorPtr(); + int i; + struct drm_psb_private * dev_priv = (struct drm_psb_private *)dev->dev_private; + struct psb_gtt * pg = dev_priv->pg; + LinuxMemArea *psLinuxMemArea = NULL; + MRSTLFB_BUFFER *pBuffer; + + if (!psDevInfo->sSystemBuffer.bIsContiguous) { + MRSTLFBFreeKernelMem( psDevInfo->sSystemBuffer.uSysAddr.psNonCont ); + psDevInfo->sSystemBuffer.uSysAddr.psNonCont = NULL; + } + psDevInfo->sDisplayFormat.pixelformat = (psbfb->base.depth == 16) ? PVRSRV_PIXEL_FORMAT_RGB565 : PVRSRV_PIXEL_FORMAT_ARGB8888; + + psDevInfo->sDisplayDim.ui32ByteStride = psbfb->base.pitch; + psDevInfo->sDisplayDim.ui32Width = psbfb->base.width; + psDevInfo->sDisplayDim.ui32Height = psbfb->base.height; + + psDevInfo->sSystemBuffer.ui32BufferSize = psbfb->size; + + if (psbfb->pvrBO != NULL) + { + psDevInfo->sSystemBuffer.sCPUVAddr = psbfb->fbdev->screen_base; + psDevInfo->sSystemBuffer.sDevVAddr.uiAddr = psbfb->offset; + } + else + { + if (dev_priv->fb_reloc) { + /* + * the frame buffer has been relocated + * because the stolen memory isn't large enough + */ + pBuffer = (MRSTLFB_BUFFER *)dev_priv->fb_reloc; + psDevInfo->sSystemBuffer.sCPUVAddr = pBuffer->sCPUVAddr; + psDevInfo->sSystemBuffer.sDevVAddr.uiAddr = pBuffer->sDevVAddr.uiAddr; + } else { + psDevInfo->sSystemBuffer.sCPUVAddr = pg->vram_addr; + psDevInfo->sSystemBuffer.sDevVAddr.uiAddr = 0; + } + } + + psDevInfo->sSystemBuffer.bIsAllocated = MRST_FALSE; + + if (psbfb->pvrBO != NULL) + { + psLinuxMemArea = (LinuxMemArea *)psbfb->pvrBO->sMemBlk.hOSMemHandle; + } + + if ((dev_priv->fb_reloc == NULL) && + ((psbfb->pvrBO == NULL) || (psLinuxMemArea->eAreaType != LINUX_MEM_AREA_ALLOC_PAGES))) + { + psDevInfo->sSystemBuffer.bIsContiguous = MRST_TRUE; + psDevInfo->sSystemBuffer.uSysAddr.sCont.uiAddr = pg->stolen_base; + } else { + psDevInfo->sSystemBuffer.bIsContiguous = MRST_FALSE; + psDevInfo->sSystemBuffer.uSysAddr.psNonCont = MRSTLFBAllocKernelMem( sizeof( IMG_SYS_PHYADDR ) * (psbfb->size >> PAGE_SHIFT)); + if (psDevInfo->sSystemBuffer.uSysAddr.psNonCont == NULL) { + WARN_ON_ONCE(1); + printk(KERN_ERR "Out of Memory in HandleChangeFB\n"); + return -ENOMEM; + } + if (dev_priv->fb_reloc) { + pBuffer = (MRSTLFB_BUFFER *)dev_priv->fb_reloc; + for (i = 0; i < psbfb->size >> PAGE_SHIFT; i++) + psDevInfo->sSystemBuffer.uSysAddr.psNonCont[i].uiAddr = + pBuffer->uSysAddr.psNonCont[i].uiAddr; + } else { + struct page **page_list = psLinuxMemArea->uData.sPageList.pvPageList; + for (i = 0; i < psbfb->size >> PAGE_SHIFT; i++) + psDevInfo->sSystemBuffer.uSysAddr.psNonCont[i].uiAddr = + page_to_pfn(page_list[i]) << PAGE_SHIFT; + } + } + + return 0; +} + + +uint32_t MRSTLFBGetSize(MRSTLFB_BUFFER *pBuffer) +{ + return pBuffer->ui32BufferSize; +} + +void* MRSTLFBGetCPUVAddr(MRSTLFB_BUFFER *pBuffer) +{ + return pBuffer->sCPUVAddr; +} + +uint32_t MRSTLFBGetDevVAddr(MRSTLFB_BUFFER *pBuffer) +{ + return pBuffer->sDevVAddr.uiAddr; +} + +#endif + +static int MRSTLFBFindMainPipe(struct drm_device *dev) +{ + struct drm_crtc *crtc; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) + { + if ( drm_helper_crtc_in_use(crtc) ) + { + struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); + return psb_intel_crtc->pipe; + } + } + + return 0; +} + + +static MRST_ERROR InitDev(MRSTLFB_DEVINFO *psDevInfo) +{ + MRST_ERROR eError = MRST_ERROR_GENERIC; + struct fb_info *psLINFBInfo; + struct drm_device * psDrmDevice = psDevInfo->psDrmDevice; + struct drm_psb_private * psDrmPrivate = (struct drm_psb_private *)psDrmDevice->dev_private; + struct psb_fbdev * psPsbFBDev = (struct psb_fbdev *)psDrmPrivate->fbdev; + struct drm_framebuffer * psDrmFB; + struct psb_framebuffer *psbfb; + int i; + + psDrmFB = psPsbFBDev->psb_fb_helper.fb; + if(!psDrmFB) { + printk(KERN_INFO"%s:Cannot find drm FB", __FUNCTION__); + return eError; + } + psbfb = to_psb_fb(psDrmFB); + + psLINFBInfo = (struct fb_info*)psPsbFBDev->psb_fb_helper.fbdev; + +#if defined(PVR_MRST_FB_SET_PAR_ON_INIT) + MRSTFBSetPar(psLINFBInfo); +#endif + + + psDevInfo->sSystemBuffer.bIsContiguous = MRST_TRUE; + psDevInfo->sSystemBuffer.bIsAllocated = MRST_FALSE; + + MRSTLFBHandleChangeFB(psDrmDevice, psbfb); + + + psDevInfo->sDisplayFormat.pixelformat = PVRSRV_PIXEL_FORMAT_ARGB8888; + psDevInfo->psLINFBInfo = psLINFBInfo; + + /* + * Ugly. This will always select the pipe B as the main pipe on CDV. + * If the external monitor is connected during loading the gfx kernel driver, + * it will select the pipe A as the main pipe. Then maybe the wrong main pipe + * is selected when the external monitor is explicitly turned off. + * To be simple, currently we only choose the LVDS pipe as the main pipe. + * Otherwise we will have to handle the scenario when the main pipe is switched. + */ + psDevInfo->ui32MainPipe = MRSTLFBFindMainPipe(psDevInfo->psDrmDevice); + psDevInfo->ui32MainPipe = 1; + + for(i = 0;i < MAX_SWAPCHAINS;++i) + { + psDevInfo->apsSwapChains[i] = NULL; + } + + + + + psDevInfo->pvRegs = psbfb_vdc_reg(psDevInfo->psDrmDevice); + + if (psDevInfo->pvRegs == NULL) + { + eError = PVRSRV_ERROR_BAD_MAPPING; + printk(KERN_WARNING DRIVER_PREFIX ": Couldn't map registers needed for flipping\n"); + return eError; + } + + return MRST_OK; +} + +static void DeInitDev(MRSTLFB_DEVINFO *psDevInfo) +{ + +} + +MRST_ERROR MRSTLFBInit(struct drm_device * dev) +{ + MRSTLFB_DEVINFO *psDevInfo; + //struct drm_psb_private *psDrmPriv = (struct drm_psb_private *)dev->dev_private; + + psDevInfo = GetAnchorPtr(); + + if (psDevInfo == NULL) + { + PFN_CMD_PROC pfnCmdProcList[MRSTLFB_COMMAND_COUNT]; + IMG_UINT32 aui32SyncCountList[MRSTLFB_COMMAND_COUNT][2]; + + psDevInfo = (MRSTLFB_DEVINFO *)MRSTLFBAllocKernelMem(sizeof(MRSTLFB_DEVINFO)); + + if(!psDevInfo) + { + return (MRST_ERROR_OUT_OF_MEMORY); + } + + + memset(psDevInfo, 0, sizeof(MRSTLFB_DEVINFO)); + + + SetAnchorPtr((void*)psDevInfo); + + psDevInfo->psDrmDevice = dev; + psDevInfo->ulRefCount = 0; + + + if(InitDev(psDevInfo) != MRST_OK) + { + return (MRST_ERROR_INIT_FAILURE); + } + + if(MRSTLFBGetLibFuncAddr ("PVRGetDisplayClassJTable", &pfnGetPVRJTable) != MRST_OK) + { + return (MRST_ERROR_INIT_FAILURE); + } + + + if(!(*pfnGetPVRJTable)(&psDevInfo->sPVRJTable)) + { + return (MRST_ERROR_INIT_FAILURE); + } + + + spin_lock_init(&psDevInfo->sSwapChainLock); + + psDevInfo->psCurrentSwapChain = NULL; + psDevInfo->bFlushCommands = MRST_FALSE; + + psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers = MAX_FLIPBUFFERS; + psDevInfo->sDisplayInfo.ui32MaxSwapChains = MAX_SWAPCHAINS; + psDevInfo->sDisplayInfo.ui32MaxSwapInterval = 3; + psDevInfo->sDisplayInfo.ui32MinSwapInterval = 0; + + strncpy(psDevInfo->sDisplayInfo.szDisplayName, DISPLAY_DEVICE_NAME, MAX_DISPLAY_NAME_SIZE); + + + DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX + ": Maximum number of swap chain buffers: %u\n", + psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers)); + + + + + 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; + + + if(psDevInfo->sPVRJTable.pfnPVRSRVRegisterDCDevice ( + &psDevInfo->sDCJTable, + &psDevInfo->uiDeviceID ) != PVRSRV_OK) + { + return (MRST_ERROR_DEVICE_REGISTER_FAILED); + } + + printk("Device ID: %d\n", (int)psDevInfo->uiDeviceID); + + +#if defined (MRST_USING_INTERRUPTS) + + if(MRSTLFBInstallVSyncISR(psDevInfo,MRSTLFBVSyncISR) != MRST_OK) + { + DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX "ISR Installation failed\n")); + return (MRST_ERROR_INIT_FAILURE); + } +#endif + + + pfnCmdProcList[DC_FLIP_COMMAND] = ProcessFlip; + + + aui32SyncCountList[DC_FLIP_COMMAND][0] = 0; + aui32SyncCountList[DC_FLIP_COMMAND][1] = 2; + + + if (psDevInfo->sPVRJTable.pfnPVRSRVRegisterCmdProcList (psDevInfo->uiDeviceID, + &pfnCmdProcList[0], + aui32SyncCountList, + MRSTLFB_COMMAND_COUNT) != PVRSRV_OK) + { + printk(KERN_WARNING DRIVER_PREFIX ": Can't register callback\n"); + return (MRST_ERROR_CANT_REGISTER_CALLBACK); + } + + + } + + + //psDrmPriv->psb_change_fb_handler = MRSTLFBHandleChangeFB; + + //psDrmPriv->psb_leave_vt_handler = DRMLFBLeaveVTHandler; + //psDrmPriv->psb_enter_vt_handler = DRMLFBEnterVTHandler; + + psDevInfo->ulRefCount++; + + + return (MRST_OK); +} + +MRST_ERROR MRSTLFBDeinit(void) +{ + MRSTLFB_DEVINFO *psDevInfo, *psDevFirst; + + psDevFirst = GetAnchorPtr(); + psDevInfo = psDevFirst; + + + if (psDevInfo == NULL) + { + return (MRST_ERROR_GENERIC); + } + + + psDevInfo->ulRefCount--; + + psDevInfo->psDrmDevice = NULL; + if (psDevInfo->ulRefCount == 0) + { + + PVRSRV_DC_DISP2SRV_KMJTABLE *psJTable = &psDevInfo->sPVRJTable; + + if (psDevInfo->sPVRJTable.pfnPVRSRVRemoveCmdProcList (psDevInfo->uiDeviceID, MRSTLFB_COMMAND_COUNT) != PVRSRV_OK) + { + return (MRST_ERROR_GENERIC); + } + + if (psDevInfo->sPVRJTable.pfnPVRSRVRegisterPowerDevice((IMG_UINT32)psDevInfo->uiDeviceID, + IMG_NULL, IMG_NULL, + IMG_NULL, IMG_NULL, IMG_NULL, + PVRSRV_DEV_POWER_STATE_ON, + PVRSRV_DEV_POWER_STATE_ON) != PVRSRV_OK) + { + return (MRST_ERROR_GENERIC); + } + + +#if defined (MRST_USING_INTERRUPTS) + + if(MRSTLFBUninstallVSyncISR(psDevInfo) != MRST_OK) + { + return (MRST_ERROR_GENERIC); + } +#endif + + if (psJTable->pfnPVRSRVRemoveDCDevice(psDevInfo->uiDeviceID) != PVRSRV_OK) + { + return (MRST_ERROR_GENERIC); + } + + DeInitDev(psDevInfo); + + + MRSTLFBFreeKernelMem(psDevInfo); + } + + + SetAnchorPtr(NULL); + + + return (MRST_OK); +} + +int MRSTLFBAllocBuffer(struct drm_device *dev, IMG_UINT32 ui32Size, MRSTLFB_BUFFER **ppBuffer) + +{ + IMG_VOID *pvBuf; + IMG_UINT32 ulPagesNumber; + IMG_UINT32 ulCounter; + int i, ret; + + pvBuf = __vmalloc( ui32Size, GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO, __pgprot((pgprot_val(PAGE_KERNEL ) & ~_PAGE_CACHE_MASK) | _PAGE_CACHE_WC) ); + if( pvBuf == NULL ) + { + return MRST_ERROR_OUT_OF_MEMORY; + } + + ulPagesNumber = (ui32Size + PAGE_SIZE -1) / PAGE_SIZE; + + *ppBuffer = MRSTLFBAllocKernelMem( sizeof( MRSTLFB_BUFFER ) ); + if (*ppBuffer == NULL) { + /* Free the allocated memory */ + vfree(pvBuf); + return MRST_ERROR_OUT_OF_MEMORY; + } + + (*ppBuffer)->sCPUVAddr = pvBuf; + (*ppBuffer)->ui32BufferSize = ui32Size; + (*ppBuffer)->uSysAddr.psNonCont = MRSTLFBAllocKernelMem( sizeof( IMG_SYS_PHYADDR ) * ulPagesNumber); + + if ((*ppBuffer)->uSysAddr.psNonCont == NULL) { + /* Free the allocated memory */ + vfree(pvBuf); + MRSTLFBFreeKernelMem(*ppBuffer); + *ppBuffer = NULL; + return MRST_ERROR_OUT_OF_MEMORY; + } + + (*ppBuffer)->bIsAllocated = MRST_TRUE; + (*ppBuffer)->bIsContiguous = MRST_FALSE; + (*ppBuffer)->ui32OwnerTaskID = task_tgid_nr(current); + + i = 0; + for(ulCounter = 0; ulCounter < ui32Size; ulCounter += PAGE_SIZE) + { + (*ppBuffer)->uSysAddr.psNonCont[i++].uiAddr = vmalloc_to_pfn( pvBuf + ulCounter ) << PAGE_SHIFT; + } + + ret = psb_gtt_map_pvr_memory(dev, (unsigned int)*ppBuffer, + (*ppBuffer)->ui32OwnerTaskID, + (IMG_CPU_PHYADDR*) (*ppBuffer)->uSysAddr.psNonCont, + ulPagesNumber, &(*ppBuffer)->sDevVAddr.uiAddr ); + if (ret == 0) { + (*ppBuffer)->sDevVAddr.uiAddr <<= PAGE_SHIFT; + + return MRST_OK; + } else { + vfree(pvBuf); + MRSTLFBFreeKernelMem((*ppBuffer)->uSysAddr.psNonCont); + MRSTLFBFreeKernelMem(*ppBuffer); + *ppBuffer = NULL; + return MRST_ERROR_OUT_OF_MEMORY; + } +} + +int MRSTLFBFreeBuffer(struct drm_device *dev, MRSTLFB_BUFFER **ppBuffer) +{ + if((*ppBuffer == NULL) || !(*ppBuffer)->bIsAllocated ) + return MRST_ERROR_INVALID_PARAMS; + + psb_gtt_unmap_pvr_memory(dev, (unsigned int)*ppBuffer, + (*ppBuffer)->ui32OwnerTaskID); + + vfree( (*ppBuffer)->sCPUVAddr ); + + MRSTLFBFreeKernelMem( (*ppBuffer)->uSysAddr.psNonCont ); + + MRSTLFBFreeKernelMem( *ppBuffer); + + *ppBuffer = NULL; + + return MRST_OK; +} + |