video: tegra: clean up fb flipping code
authorErik Gilling <konkers@android.com>
Mon, 11 Oct 2010 22:35:41 +0000 (15:35 -0700)
committerErik Gilling <konkers@android.com>
Wed, 13 Oct 2010 01:07:15 +0000 (18:07 -0700)
Signed-off-by: Erik Gilling <konkers@android.com>
Change-Id: I1c1f5aea92c1b062c8ccf2f2f6116c399d847262

arch/arm/mach-tegra/include/mach/dc.h
drivers/video/tegra/fb.c

index 49c09a177d00bf3702644181b9bdbb7af60c3950..9a66c252e76abba906dcb31698f1660dd8526154 100644 (file)
@@ -110,9 +110,10 @@ struct tegra_dc_win {
        int                     dirty;
        struct tegra_dc         *dc;
 
-       struct nvmap_handle_ref *surface;
+       struct nvmap_handle_ref *cur_handle;
 };
 
+
 #define TEGRA_WIN_FLAG_ENABLED         (1 << 0)
 #define TEGRA_WIN_FLAG_BLEND_PREMULT   (1 << 1)
 #define TEGRA_WIN_FLAG_BLEND_COVERAGE  (1 << 2)
index 1656a6e492795a280a5c5567ab6aa2143cff2e6e..9e5bb1639554edbf7772b56cd6a474eaab3e4eec 100644 (file)
@@ -59,17 +59,16 @@ struct tegra_fb_info {
 };
 
 struct tegra_fb_flip_win {
-       struct tegra_dc_win     win_data;
-       struct tegra_dc_win     *dc_win;
-       s32                     pre_syncpt_id;
-       u32                     pre_syncpt_val;
+       struct tegra_fb_windowattr      attr;
+       struct nvmap_handle_ref         *handle;
+       dma_addr_t                      phys_addr;
 };
 
 struct tegra_fb_flip_data {
-       struct work_struct      work;
-       struct tegra_fb_info    *fb;
-       struct tegra_fb_flip_win windows[TEGRA_FB_FLIP_N_WINDOWS];
-       u32                     syncpt_max;
+       struct work_struct              work;
+       struct tegra_fb_info            *fb;
+       struct tegra_fb_flip_win        win[TEGRA_FB_FLIP_N_WINDOWS];
+       u32                             syncpt_max;
 };
 
 /* palette array used by the fbcon */
@@ -251,10 +250,10 @@ static int tegra_fb_pan_display(struct fb_var_screeninfo *var,
        tegra_dc_update_windows(&tegra_fb->win, 1);
        tegra_dc_sync_windows(&tegra_fb->win, 1);
 
-       if (WARN_ON(tegra_fb->win->surface)) {
-               nvmap_unpin(tegra_fb->fb_nvmap, tegra_fb->win->surface);
-               nvmap_free(tegra_fb->fb_nvmap, tegra_fb->win->surface);
-               tegra_fb->win->surface = NULL;
+       if (WARN_ON(tegra_fb->win->cur_handle)) {
+               nvmap_unpin(tegra_fb->fb_nvmap, tegra_fb->win->cur_handle);
+               nvmap_free(tegra_fb->fb_nvmap, tegra_fb->win->cur_handle);
+               tegra_fb->win->cur_handle = NULL;
        }
 
        return 0;
@@ -299,131 +298,140 @@ static int tegra_fb_set_nvmap_fd(struct tegra_fb_info *tegra_fb, int fd)
        return 0;
 }
 
-static int tegra_fb_set_windowattr(struct tegra_fb_info *tegra_fb,
-                                  struct tegra_dc_win *win,
-                                  const struct tegra_fb_windowattr *attr)
+static int tegra_fb_pin_window(struct tegra_fb_info *tegra_fb,
+                              struct tegra_fb_flip_win *flip_win)
 {
-       struct nvmap_handle_ref *r_dupe;
-       struct nvmap_handle *h_win;
+       struct nvmap_handle_ref *win_dupe;
+       struct nvmap_handle *win_handle;
+       unsigned long buff_id = flip_win->attr.buff_id;
 
-       if (!attr->buff_id) {
-               win->flags = 0;
-               win->surface = NULL;
+       if (!buff_id)
                return 0;
-       }
 
-       h_win = nvmap_get_handle_id(tegra_fb->user_nvmap, attr->buff_id);
-       if (h_win == NULL) {
+       win_handle = nvmap_get_handle_id(tegra_fb->user_nvmap, buff_id);
+       if (win_handle == NULL) {
                dev_err(&tegra_fb->ndev->dev, "%s: flip invalid "
-                       "handle %08x\n", current->comm, attr->buff_id);
+                       "handle %08lx\n", current->comm, buff_id);
                return -EPERM;
        }
 
        /* duplicate the new framebuffer's handle into the fb driver's
         * nvmap context, to ensure that the handle won't be freed as
         * long as it is in-use by the fb driver */
-       r_dupe = nvmap_duplicate_handle_id(tegra_fb->fb_nvmap, attr->buff_id);
-       nvmap_handle_put(h_win);
+       win_dupe = nvmap_duplicate_handle_id(tegra_fb->fb_nvmap, buff_id);
+       nvmap_handle_put(win_handle);
 
-       if (IS_ERR(r_dupe)) {
+       if (IS_ERR(win_dupe)) {
                dev_err(&tegra_fb->ndev->dev, "couldn't duplicate handle\n");
-               return PTR_ERR(r_dupe);
+               return PTR_ERR(win_dupe);
+       }
+
+       flip_win->handle = win_dupe;
+
+       flip_win->phys_addr = nvmap_pin(tegra_fb->fb_nvmap, win_dupe);
+       if (IS_ERR((void *)flip_win->phys_addr)) {
+               dev_err(&tegra_fb->ndev->dev, "couldn't pin handle\n");
+               nvmap_free(tegra_fb->fb_nvmap, win_dupe);
+               return PTR_ERR((void *)flip_win->phys_addr);
        }
 
-       win->surface = r_dupe;
+       return 0;
+}
+
+static int tegra_fb_set_windowattr(struct tegra_fb_info *tegra_fb,
+                                  struct tegra_dc_win *win,
+                                  const struct tegra_fb_flip_win *flip_win)
+{
+       if (flip_win->handle == NULL) {
+               win->flags = 0;
+               return 0;
+       }
 
        win->flags = TEGRA_WIN_FLAG_ENABLED;
-       if (attr->blend == TEGRA_FB_WIN_BLEND_PREMULT)
+       if (flip_win->attr.blend == TEGRA_FB_WIN_BLEND_PREMULT)
                win->flags |= TEGRA_WIN_FLAG_BLEND_PREMULT;
-       else if (attr->blend == TEGRA_FB_WIN_BLEND_COVERAGE)
+       else if (flip_win->attr.blend == TEGRA_FB_WIN_BLEND_COVERAGE)
                win->flags |= TEGRA_WIN_FLAG_BLEND_COVERAGE;
-       win->fmt = attr->pixformat;
-       win->x = attr->x;
-       win->y = attr->y;
-       win->w = attr->w;
-       win->h = attr->h;
-       win->out_x = attr->out_x;
-       win->out_y = attr->out_y;
-       win->out_w = attr->out_w;
-       win->out_h = attr->out_h;
-       win->z = attr->z;
-
-       win->phys_addr = nvmap_pin(tegra_fb->fb_nvmap, r_dupe);
-       if (IS_ERR((void *)win->phys_addr)) {
-               dev_err(&tegra_fb->ndev->dev, "couldn't pin handle\n");
-               nvmap_free(tegra_fb->fb_nvmap, r_dupe);
-               return (int)win->phys_addr;
-       }
+       win->fmt = flip_win->attr.pixformat;
+       win->x = flip_win->attr.x;
+       win->y = flip_win->attr.y;
+       win->w = flip_win->attr.w;
+       win->h = flip_win->attr.h;
+       win->out_x = flip_win->attr.out_x;
+       win->out_y = flip_win->attr.out_y;
+       win->out_w = flip_win->attr.out_w;
+       win->out_h = flip_win->attr.out_h;
+       win->z = flip_win->attr.z;
+       win->cur_handle = flip_win->handle;
+
        /* STOPSHIP verify that this won't read outside of the surface */
-       win->phys_addr += attr->offset;
-       win->stride = attr->stride;
+       win->phys_addr = flip_win->phys_addr + flip_win->attr.offset;
+       win->stride = flip_win->attr.stride;
+
+       if ((s32)flip_win->attr.pre_syncpt_id >= 0) {
+               nvhost_syncpt_wait_timeout(&tegra_fb->ndev->host->syncpt,
+                                          flip_win->attr.pre_syncpt_id,
+                                          flip_win->attr.pre_syncpt_val,
+                                          msecs_to_jiffies(500));
+       }
+
 
        return 0;
 }
 
-static void tegra_fb_flip_work(struct work_struct *work)
+static void tegra_fb_flip_worker(struct work_struct *work)
 {
-       struct tegra_fb_flip_data *data;
+       struct tegra_fb_flip_data *data =
+               container_of(work, struct tegra_fb_flip_data, work);
+       struct tegra_fb_info *tegra_fb = data->fb;
+       struct tegra_dc_win *win;
        struct tegra_dc_win *wins[TEGRA_FB_FLIP_N_WINDOWS];
-       struct nvmap_handle_ref *surfs[TEGRA_FB_FLIP_N_WINDOWS];
+       struct nvmap_handle_ref *unpin_handles[TEGRA_FB_FLIP_N_WINDOWS];
        int i, nr_win = 0, nr_unpin = 0;
 
        data = container_of(work, struct tegra_fb_flip_data, work);
 
        for (i = 0; i < TEGRA_FB_FLIP_N_WINDOWS; i++) {
-               struct tegra_fb_flip_win *flip_win = &data->windows[i];
+               struct tegra_fb_flip_win *flip_win = &data->win[i];
+               int idx = flip_win->attr.index;
+               win = tegra_dc_get_window(tegra_fb->win->dc, idx);
 
-               if (!flip_win->dc_win)
+               if (!win)
                        continue;
 
-               if (flip_win->dc_win->flags && flip_win->dc_win->surface)
-                       surfs[nr_unpin++] = flip_win->dc_win->surface;
+               if (win->flags && win->cur_handle)
+                       unpin_handles[nr_unpin++] = win->cur_handle;
 
-               wins[nr_win++] = flip_win->dc_win;
+               tegra_fb_set_windowattr(tegra_fb, win, &data->win[i]);
 
-               flip_win->dc_win->flags = flip_win->win_data.flags;
-               if (!flip_win->dc_win->flags)
-                       continue;
+               wins[nr_win++] = win;
 
-               flip_win->dc_win->surface = flip_win->win_data.surface;
-               flip_win->dc_win->fmt = flip_win->win_data.fmt;
-               flip_win->dc_win->x = flip_win->win_data.x;
-               flip_win->dc_win->y = flip_win->win_data.y;
-               flip_win->dc_win->w = flip_win->win_data.w;
-               flip_win->dc_win->h = flip_win->win_data.h;
-               flip_win->dc_win->out_x = flip_win->win_data.out_x;
-               flip_win->dc_win->out_y = flip_win->win_data.out_y;
-               flip_win->dc_win->out_w = flip_win->win_data.out_w;
-               flip_win->dc_win->out_h = flip_win->win_data.out_h;
-               flip_win->dc_win->z = flip_win->win_data.z;
-               flip_win->dc_win->phys_addr = flip_win->win_data.phys_addr;
-               flip_win->dc_win->stride = flip_win->win_data.stride;
-
-               if (flip_win->pre_syncpt_id < 0)
+#if 0
+               if (flip_win->attr.pre_syncpt_id < 0)
                        continue;
+               printk("%08x %08x\n",
+                      flip_win->attr.pre_syncpt_id,
+                      flip_win->attr.pre_syncpt_val);
 
-               nvhost_syncpt_wait_timeout(&data->fb->ndev->host->syncpt,
-                                          flip_win->pre_syncpt_id,
-                                          flip_win->pre_syncpt_val,
+               nvhost_syncpt_wait_timeout(&tegra_fb->ndev->host->syncpt,
+                                          flip_win->attr.pre_syncpt_id,
+                                          flip_win->attr.pre_syncpt_val,
                                           msecs_to_jiffies(500));
+#endif
        }
 
-       if (!nr_win)
-               goto free_data;
-
        tegra_dc_update_windows(wins, nr_win);
        /* TODO: implement swapinterval here */
        tegra_dc_sync_windows(wins, nr_win);
 
-       tegra_dc_incr_syncpt_min(data->fb->win->dc, data->syncpt_max);
+       tegra_dc_incr_syncpt_min(tegra_fb->win->dc, data->syncpt_max);
 
        /* unpin and deref previous front buffers */
        for (i = 0; i < nr_unpin; i++) {
-               nvmap_unpin(data->fb->fb_nvmap, surfs[i]);
-               nvmap_free(data->fb->fb_nvmap, surfs[i]);
+               nvmap_unpin(tegra_fb->fb_nvmap, unpin_handles[i]);
+               nvmap_free(tegra_fb->fb_nvmap, unpin_handles[i]);
        }
 
-free_data:
        kfree(data);
 }
 
@@ -432,7 +440,6 @@ static int tegra_fb_flip(struct tegra_fb_info *tegra_fb,
 {
        struct tegra_fb_flip_data *data;
        struct tegra_fb_flip_win *flip_win;
-       struct tegra_dc *dc = tegra_fb->win->dc;
        u32 syncpt_max;
        int i, err;
 
@@ -442,51 +449,46 @@ static int tegra_fb_flip(struct tegra_fb_info *tegra_fb,
        if (WARN_ON(!tegra_fb->ndev))
                return -EFAULT;
 
-       data = kmalloc(sizeof(*data), GFP_KERNEL);
-       if (!data) {
-               dev_err(&tegra_fb->ndev->dev, "no memory for flip\n");
+       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       if (data == NULL) {
+               dev_err(&tegra_fb->ndev->dev,
+                       "can't allocate memory for flip\n");
                return -ENOMEM;
        }
 
-       INIT_WORK(&data->work, tegra_fb_flip_work);
+       INIT_WORK(&data->work, tegra_fb_flip_worker);
        data->fb = tegra_fb;
 
        for (i = 0; i < TEGRA_FB_FLIP_N_WINDOWS; i++) {
+               flip_win = &data->win[i];
 
-               flip_win = &data->windows[i];
-               flip_win->dc_win = tegra_dc_get_window(dc, args->win[i].index);
-               flip_win->pre_syncpt_id = args->win[i].pre_syncpt_id;
-               flip_win->pre_syncpt_val = args->win[i].pre_syncpt_val;
-
-               if (!flip_win->dc_win)
-                       continue;
+               memcpy(&flip_win->attr, &args->win[i], sizeof(flip_win->attr));
 
-               err = tegra_fb_set_windowattr(tegra_fb, &flip_win->win_data,
-                                             &args->win[i]);
-               if (err) {
-                       dev_err(&tegra_fb->ndev->dev, "error setting window "
-                               "attributes\n");
+               err = tegra_fb_pin_window(tegra_fb, flip_win);
+               if (err < 0) {
+                       dev_err(&tegra_fb->ndev->dev,
+                               "error setting window attributes\n");
                        goto surf_err;
                }
        }
 
-       syncpt_max = tegra_dc_incr_syncpt_max(dc);
+       syncpt_max = tegra_dc_incr_syncpt_max(tegra_fb->win->dc);
        data->syncpt_max = syncpt_max;
 
        queue_work(tegra_fb->flip_wq, &data->work);
 
        args->post_syncpt_val = syncpt_max;
-       args->post_syncpt_id = tegra_dc_get_syncpt_id(dc);
+       args->post_syncpt_id = tegra_dc_get_syncpt_id(tegra_fb->win->dc);
 
        return 0;
 
 surf_err:
        while (i--) {
-               if (data->windows[i].win_data.surface) {
+               if (data->win[i].handle) {
                        nvmap_unpin(tegra_fb->fb_nvmap,
-                                   data->windows[i].win_data.surface);
+                                   data->win[i].handle);
                        nvmap_free(tegra_fb->fb_nvmap,
-                                  data->windows[i].win_data.surface);
+                                  data->win[i].handle);
                }
        }
        kfree(data);
@@ -715,9 +717,9 @@ void tegra_fb_unregister(struct tegra_fb_info *fb_info)
 {
        struct fb_info *info = fb_info->info;
 
-       if (fb_info->win->surface) {
-               nvmap_unpin(fb_info->fb_nvmap, fb_info->win->surface);
-               nvmap_free(fb_info->fb_nvmap, fb_info->win->surface);
+       if (fb_info->win->cur_handle) {
+               nvmap_unpin(fb_info->fb_nvmap, fb_info->win->cur_handle);
+               nvmap_free(fb_info->fb_nvmap, fb_info->win->cur_handle);
        }
 
        if (fb_info->fb_nvmap)