static PVRSRV_ERROR SwapToDCSystem(IMG_HANDLE hDevice, IMG_HANDLE hSwapChain) { OMAPLFB_DEVINFO *psDevInfo; OMAPLFB_SWAPCHAIN *psSwapChain; unsigned long ulLockFlags; if(!hDevice || !hSwapChain) { return (PVRSRV_ERROR_INVALID_PARAMS); } psDevInfo = (OMAPLFB_DEVINFO*)hDevice; psSwapChain = (OMAPLFB_SWAPCHAIN*)hSwapChain; if (psSwapChain != psDevInfo->psSwapChain) { return (PVRSRV_ERROR_INVALID_PARAMS); } spin_lock_irqsave(&psDevInfo->sSwapChainLock, ulLockFlags); FlushInternalVSyncQueue(psSwapChain); OMAPLFBFlip(psSwapChain, (unsigned long)psDevInfo->sFBInfo.sSysAddr.uiAddr); spin_unlock_irqrestore(&psDevInfo->sSwapChainLock, ulLockFlags); return (PVRSRV_OK); }
static void active_worker(struct work_struct *work) { OMAPLFB_DEVINFO *psDevInfo = container_of(work, OMAPLFB_DEVINFO, active_work); OMAPLFB_SWAPCHAIN *psSwapChain = psDevInfo->psSwapChain; OMAPLFB_BUFFER *psBuffer; OMAPLFBSync(); mutex_lock(&psDevInfo->active_list_lock); if (list_empty(&psDevInfo->active_list)) { pr_warning("omaplfb: syncing with no active buffer\n"); mutex_unlock(&psDevInfo->active_list_lock); return; } psBuffer = list_first_entry(&psDevInfo->active_list, OMAPLFB_BUFFER, list); list_del_init(&psBuffer->list); if (!list_empty(&psDevInfo->active_list)) { psBuffer = list_first_entry(&psDevInfo->active_list, OMAPLFB_BUFFER, list); OMAPLFBFlip(psSwapChain, (unsigned long)psBuffer->sSysAddr.uiAddr); psSwapChain->psPVRJTable-> pfnPVRSRVCmdComplete(psBuffer->hCmdCookie, IMG_TRUE); queue_work(psDevInfo->workq, &psDevInfo->active_work); } mutex_unlock(&psDevInfo->active_list_lock); }
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(!hCmdCookie || !pvData) { return IMG_FALSE; } psFlipCmd = (DISPLAYCLASS_FLIP_COMMAND*)pvData; if (psFlipCmd == IMG_NULL || sizeof(DISPLAYCLASS_FLIP_COMMAND) != ui32DataSize) { return IMG_FALSE; } psDevInfo = (OMAPLFB_DEVINFO*)psFlipCmd->hExtDevice; psBuffer = (OMAPLFB_BUFFER*)psFlipCmd->hExtBuffer; psSwapChain = (OMAPLFB_SWAPCHAIN*) psFlipCmd->hExtSwapChain; if (psDevInfo->bDeviceSuspended) { psSwapChain->psPVRJTable->pfnPVRSRVCmdComplete(hCmdCookie, IMG_TRUE); return IMG_TRUE; } mutex_lock(&psDevInfo->active_list_lock); if (!list_empty(&psBuffer->list)) { pr_warning("omaplfb: this buffer's already on the list\n"); psSwapChain->psPVRJTable->\ pfnPVRSRVCmdComplete(hCmdCookie, IMG_TRUE); } else { if (list_empty(&psDevInfo->active_list)) { OMAPLFBFlip(psSwapChain, (unsigned long)psBuffer->sSysAddr.uiAddr); psSwapChain->psPVRJTable->\ pfnPVRSRVCmdComplete(hCmdCookie, IMG_TRUE); } psBuffer->hCmdCookie = hCmdCookie; list_add_tail(&psBuffer->list, &psDevInfo->active_list); queue_work(psDevInfo->workq, &psDevInfo->active_work); } mutex_unlock(&psDevInfo->active_list_lock); return IMG_TRUE; }
static PVRSRV_ERROR DestroyDCSwapChain(IMG_HANDLE hDevice, IMG_HANDLE hSwapChain) { OMAPLFB_DEVINFO *psDevInfo; OMAPLFB_SWAPCHAIN *psSwapChain; OMAPLFB_ERROR eError; if(!hDevice || !hSwapChain) { return PVRSRV_ERROR_INVALID_PARAMS; } psDevInfo = (OMAPLFB_DEVINFO*)hDevice; psSwapChain = (OMAPLFB_SWAPCHAIN*)hSwapChain; OMAPLFBCreateSwapChainLock(psDevInfo); if (SwapChainHasChanged(psDevInfo, psSwapChain)) { printk(KERN_WARNING DRIVER_PREFIX ": %s: Device %u: Swap chain mismatch\n", __FUNCTION__, psDevInfo->uiFBDevID); eError = PVRSRV_ERROR_INVALID_PARAMS; goto ExitUnLock; } OMAPLFBDestroySwapQueue(psSwapChain); eError = OMAPLFBDisableLFBEventNotification(psDevInfo); if (eError != OMAPLFB_OK) { printk(KERN_WARNING DRIVER_PREFIX ": %s: Device %u: Couldn't disable framebuffer event notification\n", __FUNCTION__, psDevInfo->uiFBDevID); } OMAPLFBFreeKernelMem(psSwapChain->psBuffer); OMAPLFBFreeKernelMem(psSwapChain); psDevInfo->psSwapChain = NULL; OMAPLFBFlip(psDevInfo, &psDevInfo->sSystemBuffer); (void) OMAPLFBCheckModeAndSync(psDevInfo); eError = PVRSRV_OK; ExitUnLock: OMAPLFBCreateSwapChainUnLock(psDevInfo); return eError; }
static void FlushInternalVSyncQueue(OMAPLFB_SWAPCHAIN *psSwapChain) { OMAPLFB_VSYNC_FLIP_ITEM *psFlipItem; unsigned long ulMaxIndex; unsigned long i; psFlipItem = &psSwapChain->psVSyncFlips[psSwapChain->ulRemoveIndex]; ulMaxIndex = psSwapChain->ulBufferCount - 1; for(i = 0; i < psSwapChain->ulBufferCount; i++) { if (psFlipItem->bValid == OMAP_FALSE) { continue; } DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX ": FlushInternalVSyncQueue: Flushing swap buffer (index %lu)\n", psSwapChain->ulRemoveIndex)); if(psFlipItem->bFlipped == OMAP_FALSE) { OMAPLFBFlip(psSwapChain, (unsigned long)psFlipItem->sSysAddr); } if(psFlipItem->bCmdCompleted == OMAP_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, IMG_TRUE); } psSwapChain->ulRemoveIndex++; if(psSwapChain->ulRemoveIndex > ulMaxIndex) { psSwapChain->ulRemoveIndex = 0; } psFlipItem->bFlipped = OMAP_FALSE; psFlipItem->bCmdCompleted = OMAP_FALSE; psFlipItem->bValid = OMAP_FALSE; psFlipItem = &psSwapChain->psVSyncFlips[psSwapChain->ulRemoveIndex]; } psSwapChain->ulInsertIndex = 0; psSwapChain->ulRemoveIndex = 0; }
void OMAPLFBSwapHandler(OMAPLFB_BUFFER *psBuffer) { OMAPLFB_DEVINFO *psDevInfo = psBuffer->psDevInfo; OMAPLFB_SWAPCHAIN *psSwapChain = psDevInfo->psSwapChain; OMAPLFB_BOOL bPreviouslyNotVSynced; #if defined(SUPPORT_DRI_DRM) if (!OMAPLFBAtomicBoolRead(&psDevInfo->sLeaveVT)) #endif { OMAPLFBFlip(psDevInfo, psBuffer); } bPreviouslyNotVSynced = psSwapChain->bNotVSynced; psSwapChain->bNotVSynced = OMAPLFB_TRUE; if (!DontWaitForVSync(psDevInfo)) { OMAPLFB_UPDATE_MODE eMode = OMAPLFBGetUpdateMode(psDevInfo); int iBlankEvents = OMAPLFBAtomicIntRead(&psDevInfo->sBlankEvents); switch(eMode) { case OMAPLFB_UPDATE_MODE_AUTO: psSwapChain->bNotVSynced = OMAPLFB_FALSE; if (bPreviouslyNotVSynced || psSwapChain->iBlankEvents != iBlankEvents) { psSwapChain->iBlankEvents = iBlankEvents; psSwapChain->bNotVSynced = !WaitForVSyncSettle(psDevInfo); } else if (psBuffer->ulSwapInterval != 0) { psSwapChain->bNotVSynced = !OMAPLFBWaitForVSync(psDevInfo); } break; #if defined(PVR_OMAPFB3_MANUAL_UPDATE_SYNC_IN_SWAP) case OMAPLFB_UPDATE_MODE_MANUAL: if (psBuffer->ulSwapInterval != 0) { (void) OMAPLFBManualSync(psDevInfo); } break; #endif default: break; } } psDevInfo->sPVRJTable.pfnPVRSRVCmdComplete((IMG_HANDLE)psBuffer->hCmdComplete, IMG_TRUE); }
static PVRSRV_ERROR DestroyDCSwapChain(IMG_HANDLE hDevice, IMG_HANDLE hSwapChain) { OMAPLFB_DEVINFO *psDevInfo; OMAPLFB_SWAPCHAIN *psSwapChain; unsigned long ulLockFlags; OMAP_ERROR eError; if(!hDevice || !hSwapChain) { return (PVRSRV_ERROR_INVALID_PARAMS); } psDevInfo = (OMAPLFB_DEVINFO*)hDevice; psSwapChain = (OMAPLFB_SWAPCHAIN*)hSwapChain; if (psSwapChain != psDevInfo->psSwapChain) { return (PVRSRV_ERROR_INVALID_PARAMS); } eError = DisableLFBEventNotification(psDevInfo); if (eError != OMAP_OK) { printk(KERN_WARNING DRIVER_PREFIX ": Couldn't disable framebuffer event notification\n"); } OMAPLFBFlip(psSwapChain, (unsigned long)psDevInfo->sFBInfo.sSysAddr.uiAddr); cancel_work_sync(&psDevInfo->active_work); INIT_LIST_HEAD(&psDevInfo->active_list); spin_lock_irqsave(&psDevInfo->sSwapChainLock, ulLockFlags); FlushInternalVSyncQueue(psSwapChain); psDevInfo->psSwapChain = NULL; spin_unlock_irqrestore(&psDevInfo->sSwapChainLock, ulLockFlags); OMAPLFBFreeKernelMem(psSwapChain->psVSyncFlips); OMAPLFBFreeKernelMem(psSwapChain->psBuffer); OMAPLFBFreeKernelMem(psSwapChain); return (PVRSRV_OK); }
/* * SetDCState * Called from services. */ static IMG_VOID SetDCState(IMG_HANDLE hDevice, IMG_UINT32 ui32State) { OMAPLFB_DEVINFO *psDevInfo = (OMAPLFB_DEVINFO *)hDevice; switch (ui32State) { case DC_STATE_FLUSH_COMMANDS: OMAPLFBAtomicBoolSet(&psDevInfo->sFlushCommands, OMAPLFB_TRUE); break; case DC_STATE_NO_FLUSH_COMMANDS: OMAPLFBAtomicBoolSet(&psDevInfo->sFlushCommands, OMAPLFB_FALSE); break; case DC_STATE_FORCE_SWAP_TO_SYSTEM: OMAPLFBFlip(psDevInfo, &psDevInfo->sSystemBuffer); break; default: break; } }
static void active_worker(struct work_struct *work) { OMAPLFB_DEVINFO *psDevInfo = container_of(work, OMAPLFB_DEVINFO, active_work); OMAPLFB_SWAPCHAIN *psSwapChain = psDevInfo->psSwapChain; OMAPLFB_BUFFER *psBuffer; mutex_lock(&psDevInfo->active_list_lock); while (!list_empty(&psDevInfo->active_list)) { psBuffer = list_first_entry(&psDevInfo->active_list, OMAPLFB_BUFFER, list); mutex_unlock(&psDevInfo->active_list_lock); OMAPLFBFlip(psSwapChain, (unsigned long)psBuffer->sSysAddr.uiAddr); psSwapChain->psPVRJTable-> pfnPVRSRVCmdComplete(psBuffer->hCmdCookie, IMG_TRUE); list_del_init(&psBuffer->list); mutex_lock(&psDevInfo->active_list_lock); } mutex_unlock(&psDevInfo->active_list_lock); }
int PVR_DRM_MAKENAME(DISPLAY_CONTROLLER, _Ioctl)(struct drm_device unref__ *dev, void *arg, struct drm_file unref__ *pFile) { uint32_t *puiArgs; uint32_t uiCmd; unsigned uiPVRDevID; int ret = 0; OMAPLFB_DEVINFO *psDevInfo; if (arg == NULL) { return -EFAULT; } puiArgs = (uint32_t *)arg; uiCmd = puiArgs[PVR_DRM_DISP_ARG_CMD]; uiPVRDevID = puiArgs[PVR_DRM_DISP_ARG_DEV]; psDevInfo = OMAPLFBPVRDevIDToDevInfo(uiPVRDevID); if (psDevInfo == NULL) { return -EINVAL; } switch (uiCmd) { case PVR_DRM_DISP_CMD_LEAVE_VT: case PVR_DRM_DISP_CMD_ENTER_VT: { OMAPLFB_BOOL bLeaveVT = (uiCmd == PVR_DRM_DISP_CMD_LEAVE_VT); DEBUG_PRINTK((KERN_WARNING DRIVER_PREFIX ": %s: PVR Device %u: %s\n", __FUNCTION__, uiPVRDevID, bLeaveVT ? "Leave VT" : "Enter VT")); OMAPLFBCreateSwapChainLock(psDevInfo); OMAPLFBAtomicBoolSet(&psDevInfo->sLeaveVT, bLeaveVT); if (psDevInfo->psSwapChain != NULL) { flush_workqueue(psDevInfo->psSwapChain->psWorkQueue); if (bLeaveVT) { OMAPLFBFlip(psDevInfo, &psDevInfo->sSystemBuffer); (void) OMAPLFBCheckModeAndSync(psDevInfo); } } OMAPLFBCreateSwapChainUnLock(psDevInfo); (void) OMAPLFBUnblankDisplay(psDevInfo); break; } case PVR_DRM_DISP_CMD_ON: case PVR_DRM_DISP_CMD_STANDBY: case PVR_DRM_DISP_CMD_SUSPEND: case PVR_DRM_DISP_CMD_OFF: { int iFBMode; #if defined(DEBUG) { const char *pszMode; switch(uiCmd) { case PVR_DRM_DISP_CMD_ON: pszMode = "On"; break; case PVR_DRM_DISP_CMD_STANDBY: pszMode = "Standby"; break; case PVR_DRM_DISP_CMD_SUSPEND: pszMode = "Suspend"; break; case PVR_DRM_DISP_CMD_OFF: pszMode = "Off"; break; default: pszMode = "(Unknown Mode)"; break; } printk(KERN_WARNING DRIVER_PREFIX ": %s: PVR Device %u: Display %s\n", __FUNCTION__, uiPVRDevID, pszMode); } #endif switch(uiCmd) { case PVR_DRM_DISP_CMD_ON: iFBMode = FB_BLANK_UNBLANK; break; case PVR_DRM_DISP_CMD_STANDBY: iFBMode = FB_BLANK_HSYNC_SUSPEND; break; case PVR_DRM_DISP_CMD_SUSPEND: iFBMode = FB_BLANK_VSYNC_SUSPEND; break; case PVR_DRM_DISP_CMD_OFF: iFBMode = FB_BLANK_POWERDOWN; break; default: return -EINVAL; } OMAPLFBCreateSwapChainLock(psDevInfo); if (psDevInfo->psSwapChain != NULL) { flush_workqueue(psDevInfo->psSwapChain->psWorkQueue); } OMAPLFB_CONSOLE_LOCK(); ret = fb_blank(psDevInfo->psLINFBInfo, iFBMode); OMAPLFB_CONSOLE_UNLOCK(); OMAPLFBCreateSwapChainUnLock(psDevInfo); break; } default: { ret = -EINVAL; break; } } return ret; }
OMAP_BOOL OMAPLFBVSyncIHandler(OMAPLFB_SWAPCHAIN *psSwapChain) { OMAP_BOOL bStatus = OMAP_FALSE; OMAPLFB_VSYNC_FLIP_ITEM *psFlipItem; unsigned long ulMaxIndex; unsigned long ulLockFlags; spin_lock_irqsave(psSwapChain->psSwapChainLock, ulLockFlags); psFlipItem = &psSwapChain->psVSyncFlips[psSwapChain->ulRemoveIndex]; ulMaxIndex = psSwapChain->ulBufferCount - 1; if (psSwapChain->bFlushCommands) { goto ExitUnlock; } while(psFlipItem->bValid) { if(psFlipItem->bFlipped) { if(!psFlipItem->bCmdCompleted) { psSwapChain->psPVRJTable->pfnPVRSRVCmdComplete((IMG_HANDLE)psFlipItem->hCmdComplete, IMG_TRUE); psFlipItem->bCmdCompleted = OMAP_TRUE; } psFlipItem->ulSwapInterval--; if(psFlipItem->ulSwapInterval == 0) { psSwapChain->ulRemoveIndex++; if(psSwapChain->ulRemoveIndex > ulMaxIndex) { psSwapChain->ulRemoveIndex = 0; } psFlipItem->bCmdCompleted = OMAP_FALSE; psFlipItem->bFlipped = OMAP_FALSE; psFlipItem->bValid = OMAP_FALSE; } else { break; } } else { OMAPLFBFlip(psSwapChain, (unsigned long)psFlipItem->sSysAddr); psFlipItem->bFlipped = OMAP_TRUE; break; } psFlipItem = &psSwapChain->psVSyncFlips[psSwapChain->ulRemoveIndex]; } ExitUnlock: spin_unlock_irqrestore(psSwapChain->psSwapChainLock, ulLockFlags); return bStatus; }