/* * Driver init function */ static int __init OMAPLFB_Init(void) { #if defined(LDM_PLATFORM) DEBUG_PRINTK("Registering platform driver"); if (platform_driver_register(&omaplfb_driver)) return -ENODEV; #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) register_early_suspend(&omaplfb_early_suspend); DEBUG_PRINTK("Registered early suspend support"); #endif #endif return 0; }
/* * Driver init function */ static int __init omap_sgx_dc_init(void) { if(create_display_devices() != OMAP_OK) { WARNING_PRINTK("Driver init failed"); return -ENODEV; } #if defined(LDM_PLATFORM) DEBUG_PRINTK("Registering platform driver"); if (platform_driver_register(&omap_sgx_dc_driver)) { WARNING_PRINTK("Unable to register platform driver"); if(destroy_display_devices() != OMAP_OK) WARNING_PRINTK("Driver cleanup failed\n"); return -ENODEV; } #if defined(SGX_EARLYSUSPEND) driver_early_suspend.suspend = DriverSuspend_Entry; driver_early_suspend.resume = DriverResume_Entry; driver_early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB; register_early_suspend(&driver_early_suspend); DEBUG_PRINTK("Registered early suspend support"); #endif #endif return 0; }
/* * Driver init function */ static int __init OMAPLFB_Init(void) { int Major; if(OMAPLFBInit() != OMAP_OK) { WARNING_PRINTK("Driver init failed"); return -ENODEV; } #if defined(LDM_PLATFORM) DEBUG_PRINTK("Registering platform driver"); 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; } Major = register_chrdev(OMAPLFB_MAJOR,"omaplfb",&omaplfb_fops); if (Major < 0) printk("unable to get major %d for fb devs!!!!\n", Major); #if defined(SGX_EARLYSUSPEND) omaplfb_early_suspend.suspend = OMAPLFBDriverSuspend_Entry; omaplfb_early_suspend.resume = OMAPLFBDriverResume_Entry; //omaplfb_early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN; omaplfb_early_suspend.level = EARLY_SUSPEND_LEVEL_STOP_DRAWING; register_early_suspend(&omaplfb_early_suspend); DEBUG_PRINTK("Registered early suspend support"); #endif #endif return 0; }
/* * Driver exit function */ static IMG_VOID __exit omap_sgx_dc_deinit(IMG_VOID) { #if defined(LDM_PLATFORM) DEBUG_PRINTK("Removing platform driver"); platform_driver_unregister(&omap_sgx_dc_driver); #if defined(SGX_EARLYSUSPEND) unregister_early_suspend(&driver_early_suspend); #endif #endif if(destroy_display_devices() != OMAP_OK) WARNING_PRINTK("Driver cleanup failed"); }
/* * Closes the display. * in: hDevice */ static PVRSRV_ERROR CloseDCDevice(IMG_HANDLE hDevice) { struct OMAP_DISP_DEVINFO *psDevInfo = (struct OMAP_DISP_DEVINFO*) hDevice; struct omap_display_device *display = psDevInfo->display; if(display->close(display)) WARNING_PRINTK("Unable to close properly display '%s'", display->name); return PVRSRV_OK; }
/* * 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 OMAPLFBPresentSync(OMAPLFB_DEVINFO *psDevInfo, OMAPLFB_FLIP_ITEM *psFlipItem) { struct fb_info *framebuffer = psDevInfo->psLINFBInfo; struct omapfb_info *ofbi = FB2OFB(framebuffer); struct omap_dss_device *display; struct omapfb2_device *fbdev = ofbi->fbdev; struct omap_dss_driver *driver; struct omap_overlay_manager *manager; int err = 1; omapfb_lock(fbdev); // [email protected] Backup the Display device for using later [START] #if defined(CONFIG_MACH_LGE_OMAP3) Prev_disp = display = fb2display(framebuffer); #else display = fb2display(framebuffer); #endif // [email protected] Backup the Display device for using later [END] /* The framebuffer doesn't have a display attached, just bail out */ if (!display) { omapfb_unlock(fbdev); return; } driver = display->driver; manager = display->manager; if (driver && driver->sync && driver->get_update_mode(display) == OMAP_DSS_UPDATE_MANUAL) { /* Wait first for the DSI bus to be released then update */ err = driver->sync(display); OMAPLFBFlipNoLock(psDevInfo->psSwapChain, (unsigned long)psFlipItem->sSysAddr->uiAddr); } else if (manager && manager->wait_for_vsync) { /* * Update the video pipelines registers then wait until the * frame is shown with a VSYNC */ OMAPLFBFlipNoLock(psDevInfo->psSwapChain, (unsigned long)psFlipItem->sSysAddr->uiAddr); err = manager->wait_for_vsync(manager); } if (err) WARNING_PRINTK("Unable to sync with display %u!", psDevInfo->uDeviceID); omapfb_unlock(fbdev); }
/* * Driver exit function */ static IMG_VOID __exit OMAPLFB_Cleanup(IMG_VOID) { /* Unregister the device */ unregister_chrdev(OMAPLFB_MAJOR, "omaplfb"); #if defined(LDM_PLATFORM) DEBUG_PRINTK("Removing platform driver"); platform_driver_unregister(&omaplfb_driver); #if defined(SGX_EARLYSUSPEND) unregister_early_suspend(&omaplfb_early_suspend); #endif #endif if(OMAPLFBDeinit() != OMAP_OK) WARNING_PRINTK("Driver cleanup failed"); }
static int omaplfb_remove(struct platform_device *pdev) { struct omaplfb_device *odev; odev = platform_get_drvdata(pdev); omaplfb_remove_sysfs(odev); if (OMAPLFBDeinit() != OMAP_OK) WARNING_PRINTK("Driver cleanup failed"); kfree(odev); return 0; }
/* * Opens the display. * in: ui32DeviceID, phDevice * out: psSystemBufferSyncData */ static PVRSRV_ERROR OpenDCDevice(IMG_UINT32 ui32DeviceID, IMG_HANDLE *phDevice, PVRSRV_SYNC_DATA* psSystemBufferSyncData) { struct OMAP_DISP_DEVINFO *psDevInfo; struct omap_display_device *display; int i; psDevInfo = 0; for(i = 0; i < display_devices_count; i++) { if(ui32DeviceID == (&pDisplayDevices[i])->ulDeviceID) { psDevInfo = &pDisplayDevices[i]; break; } } if(!psDevInfo) { WARNING_PRINTK("Unable to identify display device with id %i", (int)ui32DeviceID); return OMAP_ERROR_INVALID_DEVICE; } psDevInfo->sSystemBuffer.psSyncData = psSystemBufferSyncData; display = psDevInfo->display; DEBUG_PRINTK("Opening display %lu '%s'",psDevInfo->ulDeviceID, display->name); /* TODO: Explain here why ORIENTATION_VERTICAL is used*/ if(display->open(display, ORIENTATION_VERTICAL | ORIENTATION_INVERT)) ERROR_PRINTK("Unable to open properly display '%s'", psDevInfo->display->name); display->present_buffer(display->main_buffer); /* TODO: Turn on display here? */ *phDevice = (IMG_HANDLE)psDevInfo; return PVRSRV_OK; }
/* * Synchronize with the display to prevent tearing * On DSI panels the display->sync function is used to handle FRAMEDONE IRQ * On DPI panels the display->wait_vsync is used to handle VSYNC IRQ * in: psDevInfo */ void OMAPLFBPresentSync(OMAPLFB_DEVINFO *psDevInfo, OMAPLFB_FLIP_ITEM *psFlipItem) { struct fb_info * framebuffer = psDevInfo->psLINFBInfo; struct omapfb_info *ofbi = FB2OFB(framebuffer); struct omapfb2_device *fbdev = ofbi->fbdev; struct omap_dss_device *display; int err = 1; omapfb_lock(fbdev); display = fb2display(framebuffer); /* The framebuffer doesn't have a display attached, just bail out */ if (!display) { omapfb_unlock(fbdev); return; } if (display->sync && display->get_update_mode(display) == OMAP_DSS_UPDATE_MANUAL) { /* Wait first for the DSI bus to be released then update */ err = display->sync(display); OMAPLFBFlipNoLock(psDevInfo->psSwapChain, (unsigned long)psFlipItem->sSysAddr->uiAddr); } else if (display->wait_vsync) { /* * Update the video pipelines registers then wait until the * frame is shown with a VSYNC */ OMAPLFBFlipNoLock(psDevInfo->psSwapChain, (unsigned long)psFlipItem->sSysAddr->uiAddr); err = display->wait_vsync(display); } if (err) WARNING_PRINTK("Unable to sync with display %u!", psDevInfo->uDeviceID); omapfb_unlock(fbdev); }
/* * 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) { struct OMAP_DISP_DEVINFO *psDevInfo; if(!hDevice || !pui32NumFormats) { ERROR_PRINTK("Invalid parameters"); return PVRSRV_ERROR_INVALID_PARAMS; } psDevInfo = (struct OMAP_DISP_DEVINFO*)hDevice; *pui32NumFormats = 1; if(psFormat) psFormat[0] = psDevInfo->sDisplayFormat; else WARNING_PRINTK("Display format is null for" " display %lu", psDevInfo->ulDeviceID); 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) { struct OMAP_DISP_DEVINFO *psDevInfo; if(!hDevice || !psFormat || !pui32NumDims) { ERROR_PRINTK("Invalid parameters"); return PVRSRV_ERROR_INVALID_PARAMS; } psDevInfo = (struct OMAP_DISP_DEVINFO*)hDevice; *pui32NumDims = 1; if(psDim) psDim[0] = psDevInfo->sDisplayDim; else WARNING_PRINTK("Display dimensions are null for" " display %lu", psDevInfo->ulDeviceID); return PVRSRV_OK; }
/* * Sets the display state. * in: ui32State, hDevice */ static IMG_VOID SetDCState(IMG_HANDLE hDevice, IMG_UINT32 ui32State) { struct OMAP_DISP_DEVINFO *psDevInfo = (struct OMAP_DISP_DEVINFO*) hDevice; switch (ui32State) { case DC_STATE_FLUSH_COMMANDS: DEBUG_PRINTK("Setting state to flush commands for" " display %lu", psDevInfo->ulDeviceID); SetFlushStateExternal(psDevInfo, OMAP_TRUE); break; case DC_STATE_NO_FLUSH_COMMANDS: DEBUG_PRINTK("Setting state to not flush commands for" " display %lu", psDevInfo->ulDeviceID); SetFlushStateExternal(psDevInfo, OMAP_FALSE); break; default: WARNING_PRINTK("Unknown command state %u for display" " %lu", (unsigned int)ui32State, psDevInfo->ulDeviceID); break; } }
/* * 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; struct OMAP_DISP_DEVINFO *psDevInfo; struct OMAP_DISP_BUFFER *psBuffer; struct OMAP_DISP_SWAPCHAIN *psSwapChain; struct omap_display_device *display; #if defined(SYS_USING_INTERRUPTS) struct OMAP_DISP_FLIP_ITEM* psFlipItem; #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 = (struct OMAP_DISP_DEVINFO*)psFlipCmd->hExtDevice; psBuffer = (struct OMAP_DISP_BUFFER*)psFlipCmd->hExtBuffer; psSwapChain = (struct OMAP_DISP_SWAPCHAIN*) psFlipCmd->hExtSwapChain; display = psDevInfo->display; mutex_lock(&psDevInfo->sSwapChainLockMutex); if (psDevInfo->bDeviceSuspended) { /* 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 display->present_buffer(psBuffer->display_buffer); psSwapChain->psPVRJTable->pfnPVRSRVCmdComplete( hCmdCookie, IMG_TRUE); #if defined(SYS_USING_INTERRUPTS) goto ExitTrueUnlock; } psFlipItem = &psSwapChain->psFlipItems[psSwapChain->ulInsertIndex]; if(psFlipItem->bValid == OMAP_FALSE) { unsigned long 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; psFlipItem->display_buffer = psBuffer->display_buffer; 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; } mutex_unlock(&psDevInfo->sSwapChainLockMutex); return IMG_FALSE; #endif ExitTrueUnlock: mutex_unlock(&psDevInfo->sSwapChainLockMutex); return IMG_TRUE; }
/* * Extracts the framebuffer data from the kernel driver * in: psDevInfo */ static enum OMAP_ERROR init_display_device(struct OMAP_DISP_DEVINFO *psDevInfo, struct omap_display_device *display) { int buffers_available = display->buffers_available; /* Extract the needed data from the display struct */ DEBUG_PRINTK("Display '%s' id %i information:", display->name, display->id); DEBUG_PRINTK("*Width, height: %u,%u", display->width, display->height); DEBUG_PRINTK("*Rotation: %u", display->rotation); DEBUG_PRINTK("*Stride: %u bytes", display->byte_stride); DEBUG_PRINTK("*Buffers available: %u", buffers_available); DEBUG_PRINTK("*Bytes per pixel: %u (%u bpp)", display->bytes_per_pixel, display->bits_per_pixel); if(display->bits_per_pixel == 16) { if(display->pixel_format == RGB_565) { DEBUG_PRINTK("*Format: RGB565"); psDevInfo->sDisplayFormat.pixelformat = PVRSRV_PIXEL_FORMAT_RGB565; } else WARNING_PRINTK("*Format: Unknown framebuffer" "format"); } else if(display->bits_per_pixel == 24 || display->bits_per_pixel == 32) { if(display->pixel_format == ARGB_8888) { DEBUG_PRINTK("*Format: ARGB8888"); psDevInfo->sDisplayFormat.pixelformat = PVRSRV_PIXEL_FORMAT_ARGB8888; } else WARNING_PRINTK("*Format: Unknown framebuffer" "format"); } else WARNING_PRINTK("*Format: Unknown framebuffer format"); if(display->main_buffer) { DEBUG_PRINTK("*Bytes per buffer: %lu", display->main_buffer->size); DEBUG_PRINTK("*Main buffer physical address: 0x%lx", display->main_buffer->physical_addr); DEBUG_PRINTK("*Main buffer virtual address: 0x%lx", display->main_buffer->virtual_addr); DEBUG_PRINTK("*Main buffer size: %lu bytes", display->main_buffer->size); } else { psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers = 0; ERROR_PRINTK("*No main buffer found for display '%s'", display->name); return OMAP_ERROR_INIT_FAILURE; } psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers = buffers_available; mutex_init(&psDevInfo->sSwapChainLockMutex); psDevInfo->psSwapChain = 0; psDevInfo->bFlushCommands = OMAP_FALSE; psDevInfo->bDeviceSuspended = OMAP_FALSE; if(psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers > 1) { if(MAX_BUFFERS_FLIPPING == 1) { DEBUG_PRINTK("Flipping support is possible" " but you decided not to use it"); } DEBUG_PRINTK("*Flipping support"); if(psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers > MAX_BUFFERS_FLIPPING) psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers = MAX_BUFFERS_FLIPPING; } else { DEBUG_PRINTK("*Flipping not supported"); } 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->sDisplayDim.ui32Width = display->width; psDevInfo->sDisplayDim.ui32Height = display->height; psDevInfo->sDisplayDim.ui32ByteStride = display->byte_stride; psDevInfo->sSystemBuffer.sSysAddr.uiAddr = display->main_buffer->physical_addr; psDevInfo->sSystemBuffer.sCPUVAddr = (IMG_CPU_VIRTADDR) display->main_buffer->virtual_addr; psDevInfo->sSystemBuffer.ulBufferSize = display->main_buffer->size; psDevInfo->display = display; return OMAP_OK; }