int omap_display_initialize(void) { /* * TODO: Is there a better way to check if list is already created? */ if (!omap_display_list) { DBG_PRINT("Initializing driver"); if (create_display_list()) { ERR_PRINT("Error loading driver"); return 1; } } vdisp_wq_primary = __create_workqueue("vdisp_wq_primary", 1, 1, 1); vdisp_wq_secondary = __create_workqueue("vdisp_wq_secondary", 1, 1, 1); INIT_WORK((struct work_struct *)&vdisp_sync_primary, vdisp_sync_handler); INIT_WORK((struct work_struct *)&vdisp_sync_secondary, vdisp_sync_handler); return 0; }
MTKLFB_ERROR MTKLFBCreateSwapQueue(MTKLFB_SWAPCHAIN *psSwapChain) { psSwapChain->psWorkQueue = __create_workqueue(DEVNAME, 1, 1, 1); if (psSwapChain->psWorkQueue == NULL) { printk(KERN_WARNING DRIVER_PREFIX ": %s: Device %u: create_singlethreaded_workqueue failed\n", __FUNCTION__, psSwapChain->uiFBDevID); return (MTKLFB_ERROR_INIT_FAILURE); } return (MTKLFB_OK); }
OMAPLFB_ERROR OMAPLFBCreateSwapQueue(OMAPLFB_SWAPCHAIN *psSwapChain) { #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,34)) psSwapChain->psWorkQueue = __create_workqueue(DEVNAME, 1, 1, 1); #else psSwapChain->psWorkQueue = create_workqueue(DEVNAME); #endif if (psSwapChain->psWorkQueue == NULL) { printk(KERN_WARNING DRIVER_PREFIX ": %s: Device %u: create_singlethreaded_workqueue failed\n", __FUNCTION__, psSwapChain->uiFBDevID); return (OMAPLFB_ERROR_INIT_FAILURE); } return (OMAPLFB_OK); }
/* Create a swap chain work queue */ OMAPLFB_ERROR OMAPLFBCreateSwapQueue(OMAPLFB_SWAPCHAIN *psSwapChain) { #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) /* * Calling alloc_ordered_workqueue with the WQ_FREEZABLE and * WQ_MEM_RECLAIM flags set, (currently) has the same effect as * calling create_freezable_workqueue. None of the other WQ * flags are valid. Setting WQ_MEM_RECLAIM should allow the * workqueue to continue to service the swap chain in low memory * conditions, preventing the driver from holding on to * resources longer than it needs to. */ #if (LINUX_VERSION_CODE == KERNEL_VERSION(2,6,37)) psSwapChain->psWorkQueue = alloc_ordered_workqueue(DEVNAME, WQ_FREEZEABLE | WQ_MEM_RECLAIM); #else psSwapChain->psWorkQueue = alloc_ordered_workqueue(DEVNAME, WQ_FREEZABLE | WQ_MEM_RECLAIM); #endif #else #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)) psSwapChain->psWorkQueue = create_freezable_workqueue(DEVNAME); #else /* * Create a single-threaded, freezable, rt-prio workqueue. * Such workqueues are frozen with user threads when a system * suspends, before driver suspend entry points are called. * This ensures this driver will not call into the Linux * framebuffer driver after the latter is suspended. */ 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); }
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); }
/* * 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) { struct OMAP_DISP_DEVINFO *psDevInfo; struct OMAP_DISP_SWAPCHAIN *psSwapChain; struct OMAP_DISP_BUFFER *psBuffer; struct OMAP_DISP_FLIP_ITEM *psFlipItems; IMG_UINT32 i; PVRSRV_ERROR eError; IMG_UINT32 ui32BuffersToSkip; struct omap_display_device *display; int err; if(!hDevice || !psDstSurfAttrib || !psSrcSurfAttrib || !ppsSyncData || !phSwapChain) { ERROR_PRINTK("Invalid parameters"); return PVRSRV_ERROR_INVALID_PARAMS; } psDevInfo = (struct OMAP_DISP_DEVINFO*)hDevice; if (psDevInfo->sDisplayInfo.ui32MaxSwapChains == 0) { ERROR_PRINTK("Unable to operate with 0 MaxSwapChains for" " display %lu", psDevInfo->ulDeviceID); return PVRSRV_ERROR_NOT_SUPPORTED; } if(psDevInfo->psSwapChain != NULL) { ERROR_PRINTK("Swap chain already exists for" " display %lu", psDevInfo->ulDeviceID); 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 %lu", (unsigned int)ui32BufferCount, (unsigned int)psDevInfo-> sDisplayInfo.ui32MaxSwapChainBuffers, psDevInfo->ulDeviceID); 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 %lu", psDevInfo->ulDeviceID); 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 %lu", psDevInfo->ulDeviceID); return PVRSRV_ERROR_INVALID_PARAMS; } /* Create the flip chain in display side */ display = psDevInfo->display; /* TODO: What about TILER buffers? */ /* * Creating the flip chain with the maximum number of buffers * we will decide which ones will be used later */ err = display->create_flip_chain( display, psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers); if(err) { ERROR_PRINTK("Unable to create the flip chain for '%s' display" " id %lu", display->name, psDevInfo->ulDeviceID); return PVRSRV_ERROR_INVALID_PARAMS; } /* Allocate memory needed for the swap chain */ psSwapChain = (struct OMAP_DISP_SWAPCHAIN*) kmalloc( sizeof(struct OMAP_DISP_SWAPCHAIN), GFP_KERNEL); if(!psSwapChain) { ERROR_PRINTK("Out of memory to allocate swap chain for" " display %lu", psDevInfo->ulDeviceID); return PVRSRV_ERROR_OUT_OF_MEMORY; } DEBUG_PRINTK("Creating swap chain for display %lu", psDevInfo->ulDeviceID ); /* Allocate memory for the buffer abstraction structures */ psBuffer = (struct OMAP_DISP_BUFFER*) kmalloc( sizeof(struct OMAP_DISP_BUFFER) * ui32BufferCount, GFP_KERNEL); if(!psBuffer) { ERROR_PRINTK("Out of memory to allocate the buffer" " abstraction structures for display %lu", psDevInfo->ulDeviceID); eError = PVRSRV_ERROR_OUT_OF_MEMORY; goto ErrorFreeSwapChain; } /* Allocate memory for the flip item abstraction structures */ psFlipItems = (struct OMAP_DISP_FLIP_ITEM *) kmalloc ( sizeof(struct OMAP_DISP_FLIP_ITEM) * ui32BufferCount, GFP_KERNEL); if (!psFlipItems) { ERROR_PRINTK("Out of memory to allocate the flip item" " abstraction structures for display %lu", psDevInfo->ulDeviceID); 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, display_sync_handler); psDevInfo->sync_display_wq = __create_workqueue("pvr_display_sync_wq", 1, 1, 1); DEBUG_PRINTK("Swap chain will have %u buffers for display %lu", (unsigned int)ui32BufferCount, psDevInfo->ulDeviceID); /* 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++) { /* Get the needed buffers from the display flip chain */ IMG_UINT32 ui32SwapBuffer = i + ui32BuffersToSkip; struct omap_display_buffer * flip_buffer = display->flip_chain->buffers[ui32SwapBuffer]; psBuffer[i].display_buffer = flip_buffer; psBuffer[i].psSyncData = ppsSyncData[i]; psBuffer[i].sSysAddr.uiAddr = flip_buffer->physical_addr; psBuffer[i].sCPUVAddr = (IMG_CPU_VIRTADDR) flip_buffer->virtual_addr; DEBUG_PRINTK("Display %lu buffer index %u has physical " "address 0x%x", psDevInfo->ulDeviceID, (unsigned int)i, (unsigned int)psBuffer[i].sSysAddr.uiAddr); } /* 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; psFlipItems[i].display_buffer = 0; } 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); *phSwapChain = (IMG_HANDLE)psSwapChain; return PVRSRV_OK; ErrorFreeBuffers: kfree(psBuffer); ErrorFreeSwapChain: kfree(psSwapChain); return eError; }