]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
ENGR00176504 - EPDC fb: Reduce number of PxP output buffers to 2
authorDanny Nold <dannynold@freescale.com>
Thu, 8 Mar 2012 21:12:43 +0000 (15:12 -0600)
committerLothar Waßmann <LW@KARO-electronics.de>
Fri, 24 May 2013 06:34:12 +0000 (08:34 +0200)
- 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>
drivers/video/mxc/mxc_epdc_fb.c

index 36bb84dc15114fd433c5c499313bae5de5609093..3d81e915159667662d2ed231187ad8c04ba8fc35 100644 (file)
@@ -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: