diff options
author | Danny Nold <dannynold@freescale.com> | 2012-03-08 15:12:43 -0600 |
---|---|---|
committer | Danny Nold <dannynold@freescale.com> | 2012-03-09 09:47:40 -0600 |
commit | 442ddf797f97599dab273a6b4cc915848f2c14bb (patch) | |
tree | c472b4ebd47d72076bb9e6dfaaafdd138d20c109 /drivers | |
parent | e1be4924ca2868b773fb0a5b15b28c56d6f4a0e3 (diff) |
ENGR00176504 - EPDC fb: Reduce number of PxP output buffers to 2
- Changed from one-buffer-per-LUT (up to 16 for EPDCv1.0 and 64 for EPDCv2.0)
to using 2 static buffers for PxP output. This is facilitated by the switch
to using a single-threaded workqueue to process each update, which
guarantees that we can use just 2 buffers without clobbering concurrent
updates.
- One known limitation: This restricts the SNAPSHOT update scheme to only 2
concurrent updates. So if a user intends to use SNAPSHOT scheme, the
EPDC_MAX_NUM_BUFFERS #define should be increased based on the desired number
of allowable concurrent updates (with a corresponding penalty in static
memory allocation).
Signed-off-by: Danny Nold <dannynold@freescale.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/video/mxc/mxc_epdc_fb.c | 77 |
1 files changed, 59 insertions, 18 deletions
diff --git a/drivers/video/mxc/mxc_epdc_fb.c b/drivers/video/mxc/mxc_epdc_fb.c index 36bb84dc1511..3d81e9151596 100644 --- a/drivers/video/mxc/mxc_epdc_fb.c +++ b/drivers/video/mxc/mxc_epdc_fb.c @@ -65,6 +65,7 @@ #define EPDC_V1_MAX_NUM_UPDATES 20 #define EPDC_V2_NUM_LUTS 64 #define EPDC_V2_MAX_NUM_UPDATES 64 +#define EPDC_MAX_NUM_BUFFERS 2 #define INVALID_LUT (-1) #define DRY_RUN_NO_LUT 100 @@ -172,6 +173,10 @@ struct mxc_epdc_fb_data { u32 *working_buffer_virt; u32 working_buffer_phys; u32 working_buffer_size; + dma_addr_t *phys_addr_updbuf; + void **virt_addr_updbuf; + u32 upd_buffer_num; + u32 max_num_buffers; dma_addr_t phys_addr_copybuf; /* Phys address of copied update data */ void *virt_addr_copybuf; /* Used for PxP SW workaround */ u32 order_cnt; @@ -2381,6 +2386,15 @@ static void epdc_submit_work_func(struct work_struct *work) fb_data->info.var.xres_virtual * fb_data->info.var.bits_per_pixel/8; } else { + /* Select from PxP output buffers */ + upd_data_list->phys_addr = + fb_data->phys_addr_updbuf[fb_data->upd_buffer_num]; + upd_data_list->virt_addr = + fb_data->virt_addr_updbuf[fb_data->upd_buffer_num]; + fb_data->upd_buffer_num++; + if (fb_data->upd_buffer_num > fb_data->max_num_buffers-1) + fb_data->upd_buffer_num = 0; + /* Release buffer queues */ mutex_unlock(&fb_data->queue_mutex); @@ -2630,6 +2644,9 @@ int mxc_epdc_fb_send_update(struct mxcfb_update_data *upd_data, } if (fb_data->upd_scheme == UPDATE_SCHEME_SNAPSHOT) { + int count = 0; + struct update_data_list *plist; + /* * If next update is a FULL mode update, then we must * ensure that all pending & active updates are complete @@ -2643,11 +2660,14 @@ int mxc_epdc_fb_send_update(struct mxcfb_update_data *upd_data, mutex_lock(&fb_data->queue_mutex); } - /* - * Get available intermediate (PxP output) buffer to hold - * processed update region - */ - if (list_empty(&fb_data->upd_buf_free_list)) { + /* Count buffers in free buffer list */ + list_for_each_entry(plist, &fb_data->upd_buf_free_list, list) + count++; + + /* Use count to determine if we have enough + * free buffers to handle this update request */ + if (count + fb_data->max_num_buffers + <= fb_data->max_num_updates) { dev_err(fb_data->dev, "No free intermediate buffers available.\n"); mutex_unlock(&fb_data->queue_mutex); @@ -2732,6 +2752,15 @@ int mxc_epdc_fb_send_update(struct mxcfb_update_data *upd_data, */ screen_upd_region = &upd_desc->upd_data.update_region; + /* Select from PxP output buffers */ + upd_data_list->phys_addr = + fb_data->phys_addr_updbuf[fb_data->upd_buffer_num]; + upd_data_list->virt_addr = + fb_data->virt_addr_updbuf[fb_data->upd_buffer_num]; + fb_data->upd_buffer_num++; + if (fb_data->upd_buffer_num > fb_data->max_num_buffers-1) + fb_data->upd_buffer_num = 0; + ret = epdc_process_update(upd_data_list, fb_data); if (ret) { mutex_unlock(&fb_data->pxp_mutex); @@ -4378,11 +4407,12 @@ int __devinit mxc_epdc_fb_probe(struct platform_device *pdev) fb_data->num_luts = EPDC_V2_NUM_LUTS; fb_data->max_num_updates = EPDC_V2_MAX_NUM_UPDATES; } + fb_data->max_num_buffers = EPDC_MAX_NUM_BUFFERS; /* * Initialize lists for pending updates, * active update requests, update collisions, - * and available update (PxP output) buffers + * and freely available updates. */ INIT_LIST_HEAD(&fb_data->upd_pending_list); INIT_LIST_HEAD(&fb_data->upd_buf_queue); @@ -4394,30 +4424,39 @@ int __devinit mxc_epdc_fb_probe(struct platform_device *pdev) upd_list = kzalloc(sizeof(*upd_list), GFP_KERNEL); if (upd_list == NULL) { ret = -ENOMEM; - goto out_upd_buffers; + goto out_upd_lists; } + /* Add newly allocated buffer to free list */ + list_add(&upd_list->list, &fb_data->upd_buf_free_list); + } + + fb_data->virt_addr_updbuf = + kzalloc(sizeof(void *) * fb_data->max_num_buffers, GFP_KERNEL); + fb_data->phys_addr_updbuf = + kzalloc(sizeof(dma_addr_t) * fb_data->max_num_buffers, + GFP_KERNEL); + for (i = 0; i < fb_data->max_num_buffers; i++) { /* * Allocate memory for PxP output buffer. * Each update buffer is 1 byte per pixel, and can * be as big as the full-screen frame buffer */ - upd_list->virt_addr = + fb_data->virt_addr_updbuf[i] = dma_alloc_coherent(fb_data->info.device, fb_data->max_pix_size, - &upd_list->phys_addr, GFP_DMA); - if (upd_list->virt_addr == NULL) { - kfree(upd_list); + &fb_data->phys_addr_updbuf[i], GFP_DMA); + if (fb_data->virt_addr_updbuf[i] == NULL) { ret = -ENOMEM; goto out_upd_buffers; } - /* Add newly allocated buffer to free list */ - list_add(&upd_list->list, &fb_data->upd_buf_free_list); - dev_dbg(fb_data->info.device, "allocated %d bytes @ 0x%08X\n", - fb_data->max_pix_size, upd_list->phys_addr); + fb_data->max_pix_size, fb_data->phys_addr_updbuf[i]); } + /* Counter indicating which update buffer should be used next. */ + fb_data->upd_buffer_num = 0; + /* * Allocate memory for PxP SW workaround buffer * These buffers are used to hold copy of the update region, @@ -4683,12 +4722,14 @@ out_copybuffer: fb_data->virt_addr_copybuf, fb_data->phys_addr_copybuf); out_upd_buffers: + for (i = 0; i < fb_data->max_num_buffers; i++) + dma_free_writecombine(&pdev->dev, fb_data->max_pix_size, + fb_data->virt_addr_updbuf[i], + fb_data->phys_addr_updbuf[i]); +out_upd_lists: list_for_each_entry_safe(plist, temp_list, &fb_data->upd_buf_free_list, list) { list_del(&plist->list); - dma_free_writecombine(&pdev->dev, fb_data->max_pix_size, - plist->virt_addr, - plist->phys_addr); kfree(plist); } out_dma_fb: |