static int present_buffer_virtual(struct omap_display_buffer *buffer) { /* * TODO: Support for ORIENTATION_VERTICAL is in place, * ORIENTATION_HORIZONTAL is missing */ struct omap_display_device *display_virtual = buffer->display; struct omap_display_device *display_primary; struct omap_display_device *display_secondary; struct omap_display_buffer temp_buffer; unsigned int buffer_offset; if (display_virtual->id != OMAP_DISPID_VIRTUAL) { ERR_PRINT("Not a virtual display"); BUG(); } display_primary = omap_display_get(OMAP_DISPID_PRIMARY); display_secondary = omap_display_get(OMAP_DISPID_SECONDARY); /* * Calculate offset without page alignment round up otherwise second * display may see incorrect data */ buffer_offset = display_primary->height * display_virtual->byte_stride; /* The first buffer will be the base */ temp_buffer.physical_addr = buffer->physical_addr; temp_buffer.virtual_addr = buffer->virtual_addr; temp_buffer.size = buffer->size >> 1; if (display_virtual->features & ORIENTATION_INVERT) { /* Secondary display has the base */ temp_buffer.display = display_secondary; display_secondary->present_buffer(&temp_buffer); } else { /* Primary display has the base */ temp_buffer.display = display_primary; display_primary->present_buffer(&temp_buffer); } /* Remaining display will show the rest */ temp_buffer.physical_addr = buffer->physical_addr + buffer_offset; temp_buffer.virtual_addr = buffer->virtual_addr + buffer_offset; if (display_virtual->features & ORIENTATION_INVERT) { temp_buffer.display = display_primary; display_primary->present_buffer(&temp_buffer); } else { temp_buffer.display = display_secondary; display_secondary->present_buffer(&temp_buffer); } return 0; }
static int display_sync_virtual(struct omap_display_device *display_virtual) { /* * XXX: This function only waits for the primary display it should * be adapted to the customer needs since waiting for the primary * AND the secondary display may take too long for a single sync. */ struct omap_display_device *display_primary; if (display_virtual->id != OMAP_DISPID_VIRTUAL) { ERR_PRINT("Not a virtual display"); BUG(); } display_primary = omap_display_get(OMAP_DISPID_PRIMARY); return display_primary->sync(display_primary); }
/* * Initialization routine for the 3rd party display driver */ static enum OMAP_ERROR create_display_devices(void) { PFN_CMD_PROC pfnCmdProcList[OMAP_DC_CMD_COUNT]; IMG_UINT32 aui32SyncCountList[OMAP_DC_CMD_COUNT][2]; int i; unsigned int bytes_to_alloc; DEBUG_PRINTK("Initializing 3rd party display driver"); /* Ask for the number of displays available */ omap_display_init(); /* TODO: allow more displays */ display_devices_count = 1; // omap_display_count(); DEBUG_PRINTK("Found %i displays", display_devices_count); /* * Obtain the function pointer for the jump table from kernel * services to fill it with the function pointers that we want */ if(get_pvr_dc_jtable ("PVRGetDisplayClassJTable", &pfnGetPVRJTable) != OMAP_OK) { ERROR_PRINTK("Unable to get the function to get the" " jump table display->services"); return OMAP_ERROR_INIT_FAILURE; } /* * Allocate the display device structures, one per display available */ bytes_to_alloc = sizeof(struct OMAP_DISP_DEVINFO) * display_devices_count; pDisplayDevices = (struct OMAP_DISP_DEVINFO *) kmalloc( bytes_to_alloc, GFP_KERNEL); if(!pDisplayDevices) { pDisplayDevices = NULL; ERROR_PRINTK("Out of memory"); return OMAP_ERROR_OUT_OF_MEMORY; } memset(pDisplayDevices, 0, bytes_to_alloc); /* * Initialize each display device */ for(i = 0; i < display_devices_count; i++) { struct omap_display_device *display; struct OMAP_DISP_DEVINFO * psDevInfo; enum omap_display_id id; psDevInfo = &pDisplayDevices[i]; psDevInfo->display = 0; id = OMAP_DISPID_VIRTUAL; /* * TODO: Modify this to allow primary, secondary, * not only virtual */ #if 0 switch(i) { case 0: id = OMAP_DISPID_PRIMARY; break; case 1: id = OMAP_DISPID_SECONDARY; break; case 2: id = OMAP_DISPID_TERTIARY; break; case 3: id = OMAP_DISPID_VIRTUAL; break; default: ERROR_PRINTK("Invalid display type %i", i); BUG(); } #endif display = omap_display_get(id); if(!display) continue; if(init_display_device(psDevInfo, display) != OMAP_OK) { ERROR_PRINTK("Unable to initialize display '%s' type" " %u", display->name, display->id); continue; #if 0 kfree(pDisplayDevices); pDisplayDevices = NULL; return OMAP_ERROR_INIT_FAILURE; #endif } /* * Populate each display device structure */ if(!(*pfnGetPVRJTable)(&psDevInfo->sPVRJTable)) { ERROR_PRINTK("Unable to get the jump table" " display->services for display '%s'", display->name); return OMAP_ERROR_INIT_FAILURE; } /* Populate the function table that services will use */ 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; /* Register the display device */ if(psDevInfo->sPVRJTable.pfnPVRSRVRegisterDCDevice( &psDevInfo->sDCJTable, (IMG_UINT32*) &psDevInfo->ulDeviceID) != PVRSRV_OK) { ERROR_PRINTK("Unable to register the jump table" " services->display"); return OMAP_ERROR_DEVICE_REGISTER_FAILED; } DEBUG_PRINTK("Display '%s' registered with the GPU with" " id %lu", display->name, psDevInfo->ulDeviceID); /* * Register the ProcessFlip function to notify when a frame is * ready to be flipped */ pfnCmdProcList[DC_FLIP_COMMAND] = ProcessFlip; aui32SyncCountList[DC_FLIP_COMMAND][0] = 0; aui32SyncCountList[DC_FLIP_COMMAND][1] = 2; if (psDevInfo->sPVRJTable.pfnPVRSRVRegisterCmdProcList( psDevInfo->ulDeviceID, &pfnCmdProcList[0], aui32SyncCountList, OMAP_DC_CMD_COUNT) != PVRSRV_OK) { ERROR_PRINTK("Unable to register callback for " "ProcessFlip command"); return OMAP_ERROR_CANT_REGISTER_CALLBACK; } } return OMAP_OK; }
static int populate_virtual_display_info(struct omap_display_device *display) { struct omap_display_device *display_primary ; struct omap_display_device *display_secondary; int i; display->id = OMAP_DISPID_VIRTUAL; display->name = "virtual"; display_primary = omap_display_get(OMAP_DISPID_PRIMARY); display_secondary = omap_display_get(OMAP_DISPID_SECONDARY); if (!display_primary) { ERR_PRINT("Primary display doesn't exist"); return 1; } else if (!display_secondary) { ERR_PRINT("Secondary display doesn't exist"); return 1; } /* Combine primary and secondary display resolutions */ if (display_primary->width != display_secondary->width || display_primary->height != display_secondary->height) { ERR_PRINT("Primary and seconday displays resolution are not" " the same"); return 1; } /* * TODO: Here it is hardcoded the resolution asumming a vertical * virtual config, what about horizontal? */ display->width = display_primary->width; display->height = display_primary->height * 2; if (display_primary->bits_per_pixel != display_secondary->bits_per_pixel) { ERR_PRINT("Primary and seconday displays format are" " not the same"); return 1; } display->bits_per_pixel = display_primary->bits_per_pixel; switch (display->bits_per_pixel) { case 16: /* * TODO: Asume RGB_565, maybe need to double check in * the DSS if this is true */ display->pixel_format = RGB_565; display->bytes_per_pixel = 2; break; case 24: /* 24 bits are encapsulated with 32 bits */ case 32: /* * TODO: Asume ARGB_8888, maybe need to double check in * the DSS if this is true */ display->pixel_format = ARGB_8888; display->bytes_per_pixel = 4; break; default: ERR_PRINT("Unable to handle %i bpp", display->bits_per_pixel); return 1; } /* TODO: Asumming a vertical virtual config too for stride */ display->byte_stride = display->bytes_per_pixel * display->width; display->rotation = OMAP_DSS_ROT_0; /* Asume rotation 0 degrees */ display->main_buffer = 0; display->flip_chain = 0; /* Add the primary and secondary overlay managers */ for (i = 0; i < OMAP_DISP_MAX_MANAGERS; i++) display->overlay_managers[i] = 0; display->overlay_managers[0] = display_primary->overlay_managers[0]; display->overlay_managers[1] = display_secondary->overlay_managers[0]; display->overlay_managers_count = 2; /* Assign function pointers for display operations */ display->open = open_display; display->close = close_display; display->create_flip_chain = create_flip_chain; display->destroy_flip_chain = destroy_flip_chain; display->rotate = rotate_display; display->present_buffer = present_buffer_virtual; display->sync = display_sync_virtual; display->present_buffer_sync = present_buffer_sync_virtual; display->main_buffer = create_main_buffer(display); if (!display->main_buffer) WRN_PRINT("Failed to create main buffer for '%s'", display->name); display->buffers_available = get_max_buffers(display); /* Just print some display info */ DBG_PRINT("Found display '%s' (%i,%i) %i bpp (%i bytes per pixel)" " rotation %i", display->name, display->width, display->height, display->bits_per_pixel, display->bytes_per_pixel, display->rotation); return 0; }
static int present_buffer_sync_virtual(struct omap_display_buffer *buffer) { /* * TODO: Support for ORIENTATION_VERTICAL is in place, * ORIENTATION_HORIZONTAL is missing. Some code can be reduced here, * it will be simplified in the future. */ struct omap_display_device *display_virtual = buffer->display; struct omap_display_device *display_primary; struct omap_display_device *display_secondary; struct omap_display_buffer temp_buffer_top; struct omap_display_buffer temp_buffer_bottom; unsigned int buffer_offset; if (display_virtual->id != OMAP_DISPID_VIRTUAL) { ERR_PRINT("Not a virtual display"); BUG(); } display_primary = omap_display_get(OMAP_DISPID_PRIMARY); display_secondary = omap_display_get(OMAP_DISPID_SECONDARY); /* * Calculate offset without page alignment round up otherwise second * display may see incorrect data */ buffer_offset = display_primary->height * display_virtual->byte_stride; /* The first buffer will be the top */ temp_buffer_top.physical_addr = buffer->physical_addr; temp_buffer_top.virtual_addr = buffer->virtual_addr; temp_buffer_top.size = buffer->size >> 1; /* Then the bottom */ temp_buffer_bottom.physical_addr = buffer->physical_addr + buffer_offset; temp_buffer_bottom.virtual_addr = buffer->virtual_addr + buffer_offset; temp_buffer_bottom.size = buffer->size >> 1; if (display_virtual->features & ORIENTATION_INVERT) { /* Secondary display has the base */ temp_buffer_top.display = display_secondary; temp_buffer_bottom.display = display_primary; vdisp_sync_primary.buffer = &temp_buffer_bottom; vdisp_sync_secondary.buffer = &temp_buffer_top; } else { /* Primary display has the base */ temp_buffer_top.display = display_primary; temp_buffer_bottom.display = display_secondary; vdisp_sync_primary.buffer = &temp_buffer_top; vdisp_sync_secondary.buffer = &temp_buffer_bottom; } /* Launch the workqueues for each display to present independently */ queue_work(vdisp_wq_primary, (struct work_struct *)&vdisp_sync_primary); queue_work(vdisp_wq_secondary, (struct work_struct *)&vdisp_sync_secondary); /* Wait until each display sync and present */ flush_workqueue(vdisp_wq_primary); flush_workqueue(vdisp_wq_secondary); return 0; }