fc4b02a3a92da2e425db26157865f59d672d5818
[linux-2.6.git] / drivers / video / tegra / dc / overlay.c
1 /*
2  * drivers/video/tegra/overlay/overlay.c
3  *
4  * Copyright (c) 2010-2011, NVIDIA Corporation.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
14  * more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19  */
20
21 #include <linux/kernel.h>
22 #include <linux/list.h>
23 #include <linux/miscdevice.h>
24 #include <linux/mm.h>
25 #include <linux/mutex.h>
26 #include <linux/sched.h>
27 #include <linux/spinlock.h>
28 #include <linux/tegra_overlay.h>
29 #include <linux/uaccess.h>
30
31 #include <asm/atomic.h>
32
33 #include <mach/dc.h>
34 #include <mach/fb.h>
35 #include <mach/nvhost.h>
36
37 #include "dc_priv.h"
38 #include "../nvmap/nvmap.h"
39 #include "overlay.h"
40
41 DEFINE_MUTEX(tegra_flip_lock);
42
43 struct overlay_client;
44
45 struct overlay {
46         struct overlay_client   *owner;
47 };
48
49 struct tegra_overlay_info {
50         struct miscdevice       dev;
51
52         struct list_head        clients;
53         spinlock_t              clients_lock;
54
55         struct overlay          overlays[DC_N_WINDOWS];
56         struct mutex            overlays_lock;
57
58         struct nvhost_device    *ndev;
59
60         struct nvmap_client     *overlay_nvmap;
61
62         struct tegra_dc         *dc;
63
64         struct tegra_dc_blend   blend;
65
66         struct workqueue_struct *flip_wq;
67
68         /* Big enough for tegra_dc%u when %u < 10 */
69         char                    name[10];
70 };
71
72 struct overlay_client {
73         struct tegra_overlay_info       *dev;
74         struct list_head                list;
75         struct task_struct              *task;
76         struct nvmap_client             *user_nvmap;
77 };
78
79 struct tegra_overlay_flip_win {
80         struct tegra_overlay_windowattr attr;
81         struct nvmap_handle_ref         *handle;
82         dma_addr_t                      phys_addr;
83 };
84
85 struct tegra_overlay_flip_data {
86         struct work_struct              work;
87         struct tegra_overlay_info       *overlay;
88         struct tegra_overlay_flip_win   win[TEGRA_FB_FLIP_N_WINDOWS];
89         u32                             syncpt_max;
90         u32                             flags;
91 };
92
93 /* Overlay window manipulation */
94 static int tegra_overlay_pin_window(struct tegra_overlay_info *overlay,
95                                     struct tegra_overlay_flip_win *flip_win,
96                                     struct nvmap_client *user_nvmap)
97 {
98         struct nvmap_handle_ref *win_dupe;
99         struct nvmap_handle *win_handle;
100         unsigned long buff_id = flip_win->attr.buff_id;
101
102         if (!buff_id)
103                 return 0;
104
105         win_handle = nvmap_get_handle_id(user_nvmap, buff_id);
106         if (win_handle == NULL) {
107                 dev_err(&overlay->ndev->dev, "%s: flip invalid "
108                         "handle %08lx\n", current->comm, buff_id);
109                 return -EPERM;
110         }
111
112         /* duplicate the new framebuffer's handle into the fb driver's
113          * nvmap context, to ensure that the handle won't be freed as
114          * long as it is in-use by the fb driver */
115         win_dupe = nvmap_duplicate_handle_id(overlay->overlay_nvmap, buff_id);
116         nvmap_handle_put(win_handle);
117
118         if (IS_ERR(win_dupe)) {
119                 dev_err(&overlay->ndev->dev, "couldn't duplicate handle\n");
120                 return PTR_ERR(win_dupe);
121         }
122
123         flip_win->handle = win_dupe;
124
125         flip_win->phys_addr = nvmap_pin(overlay->overlay_nvmap, win_dupe);
126         if (IS_ERR((void *)flip_win->phys_addr)) {
127                 dev_err(&overlay->ndev->dev, "couldn't pin handle\n");
128                 nvmap_free(overlay->overlay_nvmap, win_dupe);
129                 return PTR_ERR((void *)flip_win->phys_addr);
130         }
131
132         return 0;
133 }
134
135 static int tegra_overlay_set_windowattr(struct tegra_overlay_info *overlay,
136                                         struct tegra_dc_win *win,
137                                         const struct tegra_overlay_flip_win *flip_win)
138 {
139         int xres, yres;
140         if (flip_win->handle == NULL) {
141                 win->flags = 0;
142                 win->cur_handle = NULL;
143                 return 0;
144         }
145
146         xres = overlay->dc->mode.h_active;
147         yres = overlay->dc->mode.v_active;
148
149         win->flags = TEGRA_WIN_FLAG_ENABLED;
150         if (flip_win->attr.blend == TEGRA_FB_WIN_BLEND_PREMULT)
151                 win->flags |= TEGRA_WIN_FLAG_BLEND_PREMULT;
152         else if (flip_win->attr.blend == TEGRA_FB_WIN_BLEND_COVERAGE)
153                 win->flags |= TEGRA_WIN_FLAG_BLEND_COVERAGE;
154         if (flip_win->attr.flags & TEGRA_FB_WIN_FLAG_INVERT_H)
155                 win->flags |= TEGRA_WIN_FLAG_INVERT_H;
156         if (flip_win->attr.flags & TEGRA_FB_WIN_FLAG_INVERT_V)
157                 win->flags |= TEGRA_WIN_FLAG_INVERT_V;
158         if (flip_win->attr.flags & TEGRA_FB_WIN_FLAG_TILED)
159                 win->flags |= TEGRA_WIN_FLAG_TILED;
160
161         win->fmt = flip_win->attr.pixformat;
162         win->x = flip_win->attr.x;
163         win->y = flip_win->attr.y;
164         win->w = flip_win->attr.w;
165         win->h = flip_win->attr.h;
166         win->out_x = flip_win->attr.out_x;
167         win->out_y = flip_win->attr.out_y;
168         win->out_w = flip_win->attr.out_w;
169         win->out_h = flip_win->attr.out_h;
170
171         WARN_ONCE(win->out_x >= xres,
172                 "%s:application window x offset(%d) exceeds display width(%d)\n",
173                 dev_name(&win->dc->ndev->dev), win->out_x, xres);
174         WARN_ONCE(win->out_y >= yres,
175                 "%s:application window y offset(%d) exceeds display height(%d)\n",
176                 dev_name(&win->dc->ndev->dev), win->out_y, yres);
177         WARN_ONCE(win->out_x + win->out_w > xres && win->out_x < xres,
178                 "%s:application window width(%d) exceeds display width(%d)\n",
179                 dev_name(&win->dc->ndev->dev), win->out_x + win->out_w, xres);
180         WARN_ONCE(win->out_y + win->out_h > yres && win->out_y < yres,
181                 "%s:application window height(%d) exceeds display height(%d)\n",
182                 dev_name(&win->dc->ndev->dev), win->out_y + win->out_h, yres);
183
184         if (((win->out_x + win->out_w) > xres) && (win->out_x < xres)) {
185                 long new_w = xres - win->out_x;
186                 win->w = win->w * new_w / win->out_w;
187                 win->out_w = new_w;
188         }
189         if (((win->out_y + win->out_h) > yres) && (win->out_y < yres)) {
190                 long new_h = yres - win->out_y;
191                 win->h = win->h * new_h / win->out_h;
192                 win->out_h = new_h;
193         }
194
195         win->z = flip_win->attr.z;
196         win->cur_handle = flip_win->handle;
197
198         /* STOPSHIP verify that this won't read outside of the surface */
199         win->phys_addr = flip_win->phys_addr + flip_win->attr.offset;
200         win->offset_u = flip_win->attr.offset_u + flip_win->attr.offset;
201         win->offset_v = flip_win->attr.offset_v + flip_win->attr.offset;
202         win->stride = flip_win->attr.stride;
203         win->stride_uv = flip_win->attr.stride_uv;
204
205         if ((s32)flip_win->attr.pre_syncpt_id >= 0) {
206                 nvhost_syncpt_wait_timeout(&overlay->ndev->host->syncpt,
207                                            flip_win->attr.pre_syncpt_id,
208                                            flip_win->attr.pre_syncpt_val,
209                                            msecs_to_jiffies(500),
210                                            NULL);
211         }
212
213         /* Store the blend state incase we need to reorder later */
214         overlay->blend.z[win->idx] = win->z;
215         overlay->blend.flags[win->idx] = win->flags & TEGRA_WIN_BLEND_FLAGS_MASK;
216
217         return 0;
218 }
219
220 /* overlay policy for premult is dst alpha, which needs reassignment */
221 /* of blend settings for the DC */
222 static void tegra_overlay_blend_reorder(struct tegra_dc_blend *blend,
223                                         struct tegra_dc_win *windows[])
224 {
225         int idx, below;
226
227         /* Copy across the original blend state to each window */
228         for (idx = 0; idx < DC_N_WINDOWS; idx++) {
229                 windows[idx]->z = blend->z[idx];
230                 windows[idx]->flags &= ~TEGRA_WIN_BLEND_FLAGS_MASK;
231                 windows[idx]->flags |= blend->flags[idx];
232         }
233
234         /* Find a window with PreMult */
235         for (idx = 0; idx < DC_N_WINDOWS; idx++) {
236                 if (blend->flags[idx] == TEGRA_WIN_FLAG_BLEND_PREMULT)
237                         break;
238         }
239         if (idx == DC_N_WINDOWS)
240                 return;
241
242         /* Find the window directly below it */
243         for (below = 0; below < DC_N_WINDOWS; below++) {
244                 if (below == idx)
245                         continue;
246                 if (blend->z[below] > blend->z[idx])
247                         break;
248         }
249         if (below == DC_N_WINDOWS)
250                 return;
251
252         /* Switch the flags and the ordering */
253         windows[idx]->z = blend->z[below];
254         windows[idx]->flags &= ~TEGRA_WIN_BLEND_FLAGS_MASK;
255         windows[idx]->flags |= blend->flags[below];
256         windows[below]->z = blend->z[idx];
257         windows[below]->flags &= ~TEGRA_WIN_BLEND_FLAGS_MASK;
258         windows[below]->flags |= blend->flags[idx];
259 }
260
261 static void tegra_overlay_flip_worker(struct work_struct *work)
262 {
263         struct tegra_overlay_flip_data *data =
264                 container_of(work, struct tegra_overlay_flip_data, work);
265         struct tegra_overlay_info *overlay = data->overlay;
266         struct tegra_dc_win *win;
267         struct tegra_dc_win *wins[TEGRA_FB_FLIP_N_WINDOWS];
268         struct nvmap_handle_ref *unpin_handles[TEGRA_FB_FLIP_N_WINDOWS];
269         int i, nr_win = 0, nr_unpin = 0;
270
271         data = container_of(work, struct tegra_overlay_flip_data, work);
272
273         for (i = 0; i < TEGRA_FB_FLIP_N_WINDOWS; i++) {
274                 struct tegra_overlay_flip_win *flip_win = &data->win[i];
275                 int idx = flip_win->attr.index;
276
277                 if (idx == -1)
278                         continue;
279
280                 win = tegra_dc_get_window(overlay->dc, idx);
281
282                 if (!win)
283                         continue;
284
285                 if (win->flags && win->cur_handle)
286                         unpin_handles[nr_unpin++] = win->cur_handle;
287
288                 tegra_overlay_set_windowattr(overlay, win, &data->win[i]);
289
290                 wins[nr_win++] = win;
291
292 #if 0
293                 if (flip_win->attr.pre_syncpt_id < 0)
294                         continue;
295                 printk("%08x %08x\n",
296                        flip_win->attr.pre_syncpt_id,
297                        flip_win->attr.pre_syncpt_val);
298
299                 nvhost_syncpt_wait_timeout(&overlay->ndev->host->syncpt,
300                                            flip_win->attr.pre_syncpt_id,
301                                            flip_win->attr.pre_syncpt_val,
302                                            msecs_to_jiffies(500));
303 #endif
304         }
305
306         if (data->flags & TEGRA_OVERLAY_FLIP_FLAG_BLEND_REORDER) {
307                 struct tegra_dc_win *dcwins[DC_N_WINDOWS];
308
309                 for (i = 0; i < DC_N_WINDOWS; i++)
310                         dcwins[i] = tegra_dc_get_window(overlay->dc, i);
311
312                 tegra_overlay_blend_reorder(&overlay->blend, dcwins);
313                 tegra_dc_update_windows(dcwins, DC_N_WINDOWS);
314                 tegra_dc_sync_windows(dcwins, DC_N_WINDOWS);
315         } else {
316                 tegra_dc_update_windows(wins, nr_win);
317                 /* TODO: implement swapinterval here */
318                 tegra_dc_sync_windows(wins, nr_win);
319         }
320
321                 tegra_dc_incr_syncpt_min(overlay->dc, data->syncpt_max);
322
323         /* unpin and deref previous front buffers */
324         for (i = 0; i < nr_unpin; i++) {
325                 nvmap_unpin(overlay->overlay_nvmap, unpin_handles[i]);
326                 nvmap_free(overlay->overlay_nvmap, unpin_handles[i]);
327         }
328
329         kfree(data);
330 }
331
332 static int tegra_overlay_flip(struct tegra_overlay_info *overlay,
333                               struct tegra_overlay_flip_args *args,
334                               struct nvmap_client *user_nvmap)
335 {
336         struct tegra_overlay_flip_data *data;
337         struct tegra_overlay_flip_win *flip_win;
338         u32 syncpt_max;
339         int i, err;
340
341         if (WARN_ON(!overlay->ndev))
342                 return -EFAULT;
343
344         mutex_lock(&tegra_flip_lock);
345         if (!overlay->dc->enabled) {
346                 mutex_unlock(&tegra_flip_lock);
347                 return -EFAULT;
348         }
349
350         data = kzalloc(sizeof(*data), GFP_KERNEL);
351         if (data == NULL) {
352                 dev_err(&overlay->ndev->dev,
353                         "can't allocate memory for flip\n");
354                 mutex_unlock(&tegra_flip_lock);
355                 return -ENOMEM;
356         }
357
358         INIT_WORK(&data->work, tegra_overlay_flip_worker);
359         data->overlay = overlay;
360         data->flags = args->flags;
361
362         for (i = 0; i < TEGRA_FB_FLIP_N_WINDOWS; i++) {
363                 flip_win = &data->win[i];
364
365                 memcpy(&flip_win->attr, &args->win[i], sizeof(flip_win->attr));
366
367                 if (flip_win->attr.index == -1)
368                         continue;
369
370                 err = tegra_overlay_pin_window(overlay, flip_win, user_nvmap);
371                 if (err < 0) {
372                         dev_err(&overlay->ndev->dev,
373                                 "error setting window attributes\n");
374                         goto surf_err;
375                 }
376         }
377
378         syncpt_max = tegra_dc_incr_syncpt_max(overlay->dc);
379         data->syncpt_max = syncpt_max;
380
381         queue_work(overlay->flip_wq, &data->work);
382
383         /*
384          * Before the queued flip_wq get scheduled, we set the EMC clock to the
385          * default value in order to do FLIP without glitch.
386          */
387         tegra_dc_set_default_emc(overlay->dc);
388
389         args->post_syncpt_val = syncpt_max;
390         args->post_syncpt_id = tegra_dc_get_syncpt_id(overlay->dc);
391         mutex_unlock(&tegra_flip_lock);
392
393         return 0;
394
395 surf_err:
396         while (i--) {
397                 if (data->win[i].handle) {
398                         nvmap_unpin(overlay->overlay_nvmap,
399                                     data->win[i].handle);
400                         nvmap_free(overlay->overlay_nvmap,
401                                    data->win[i].handle);
402                 }
403         }
404         kfree(data);
405         mutex_unlock(&tegra_flip_lock);
406         return err;
407 }
408 static void tegra_overlay_set_emc_freq(struct tegra_overlay_info *dev)
409 {
410         unsigned long emc_freq = 0;
411         int i;
412
413         for (i = 0; i < dev->dc->n_windows; i++) {
414                 if (dev->overlays[i].owner != NULL)
415                         emc_freq += dev->dc->mode.pclk*(i==1?2:1) *
416                                         CONFIG_TEGRA_EMC_TO_DDR_CLOCK;
417         }
418         clk_set_rate(dev->dc->emc_clk, emc_freq);
419 }
420
421 /* Overlay functions */
422 static bool tegra_overlay_get(struct overlay_client *client, int idx)
423 {
424         struct tegra_overlay_info *dev = client->dev;
425         bool ret = false;
426
427         if (idx < 0 || idx > dev->dc->n_windows)
428                 return ret;
429
430         mutex_lock(&dev->overlays_lock);
431         if (dev->overlays[idx].owner == NULL) {
432                 dev->overlays[idx].owner = client;
433                 ret = true;
434                 if (dev->dc->mode.pclk != 0)
435                         tegra_overlay_set_emc_freq(dev);
436         }
437         mutex_unlock(&dev->overlays_lock);
438
439         return ret;
440 }
441
442 static void tegra_overlay_put_locked(struct overlay_client *client, int idx)
443 {
444         struct tegra_overlay_flip_args flip_args;
445         struct tegra_overlay_info *dev = client->dev;
446
447         if (idx < 0 || idx > dev->dc->n_windows)
448                 return;
449
450         if (dev->overlays[idx].owner != client)
451                 return;
452
453         dev->overlays[idx].owner = NULL;
454
455         flip_args.win[0].index = idx;
456         flip_args.win[0].buff_id = 0;
457         flip_args.win[1].index = -1;
458         flip_args.win[2].index = -1;
459         flip_args.flags = 0;
460
461         tegra_overlay_flip(dev, &flip_args, NULL);
462         if (dev->dc->mode.pclk != 0)
463                 tegra_overlay_set_emc_freq(dev);
464 }
465
466 static void tegra_overlay_put(struct overlay_client *client, int idx)
467 {
468         mutex_lock(&client->dev->overlays_lock);
469         tegra_overlay_put_locked(client, idx);
470         mutex_unlock(&client->dev->overlays_lock);
471 }
472
473 /* Ioctl implementations */
474 static int tegra_overlay_ioctl_open(struct overlay_client *client,
475                                     void __user *arg)
476 {
477         int idx = -1;
478
479         if (copy_from_user(&idx, arg, sizeof(idx)))
480                 return -EFAULT;
481
482         if (!tegra_overlay_get(client, idx))
483                 return -EBUSY;
484
485         if (copy_to_user(arg, &idx, sizeof(idx))) {
486                 tegra_overlay_put(client, idx);
487                 return -EFAULT;
488         }
489
490         return 0;
491 }
492
493 static int tegra_overlay_ioctl_close(struct overlay_client *client,
494                                      void __user *arg)
495 {
496         int err = 0;
497         int idx;
498
499         if (copy_from_user(&idx, arg, sizeof(idx)))
500                 return -EFAULT;
501
502         if (idx < 0 || idx > client->dev->dc->n_windows)
503                 return -EINVAL;
504
505         mutex_lock(&client->dev->overlays_lock);
506         if (client->dev->overlays[idx].owner == client)
507                 tegra_overlay_put_locked(client, idx);
508         else
509                 err = -EINVAL;
510         mutex_unlock(&client->dev->overlays_lock);
511
512         return err;
513 }
514
515 static int tegra_overlay_ioctl_flip(struct overlay_client *client,
516                                     void __user *arg)
517 {
518         int i = 0;
519         int idx = 0;
520         bool found_one = false;
521         struct tegra_overlay_flip_args flip_args;
522
523         if (!client->dev->dc->enabled)
524                 return -EPIPE;
525
526         if (copy_from_user(&flip_args, arg, sizeof(flip_args)))
527                 return -EFAULT;
528
529         for (i = 0; i < TEGRA_FB_FLIP_N_WINDOWS; i++) {
530                 idx = flip_args.win[i].index;
531                 if (idx == -1) {
532                         flip_args.win[i].buff_id = 0;
533                         continue;
534                 }
535
536                 if (idx < 0 || idx > client->dev->dc->n_windows) {
537                         dev_err(&client->dev->ndev->dev,
538                                 "Flipping an invalid overlay! %d\n", idx);
539                         flip_args.win[i].index = -1;
540                         flip_args.win[i].buff_id = 0;
541                         continue;
542                 }
543
544                 if (client->dev->overlays[idx].owner != client) {
545                         dev_err(&client->dev->ndev->dev,
546                                 "Flipping a non-owned overlay! %d\n", idx);
547                         flip_args.win[i].index = -1;
548                         flip_args.win[i].buff_id = 0;
549                         continue;
550                 }
551
552                 found_one = true;
553         }
554
555         if (!found_one)
556                 return -EFAULT;
557
558         tegra_overlay_flip(client->dev, &flip_args, client->user_nvmap);
559
560         if (copy_to_user(arg, &flip_args, sizeof(flip_args)))
561                 return -EFAULT;
562
563         return 0;
564 }
565
566 static int tegra_overlay_ioctl_set_nvmap_fd(struct overlay_client *client,
567                                             void __user *arg)
568 {
569         int fd;
570         struct nvmap_client *nvmap = NULL;
571
572         if (copy_from_user(&fd, arg, sizeof(fd)))
573                 return -EFAULT;
574
575         if (fd < 0)
576                 return -EINVAL;
577
578         nvmap = nvmap_client_get_file(fd);
579         if (IS_ERR(nvmap))
580                 return PTR_ERR(nvmap);
581
582         if (client->user_nvmap)
583                 nvmap_client_put(client->user_nvmap);
584
585         client->user_nvmap = nvmap;
586
587         return 0;
588 }
589
590 /* File operations */
591 static int tegra_overlay_open(struct inode *inode, struct file *filp)
592 {
593         struct miscdevice *miscdev = filp->private_data;
594         struct tegra_overlay_info *dev = container_of(miscdev,
595                                                       struct tegra_overlay_info,
596                                                       dev);
597         struct overlay_client *priv;
598         unsigned long flags;
599         int ret;
600
601         ret = nonseekable_open(inode, filp);
602         if (unlikely(ret))
603                 return ret;
604
605         priv = kzalloc(sizeof(*priv), GFP_KERNEL);
606         if (!priv)
607                 return -ENOMEM;
608
609         priv->dev = dev;
610
611         get_task_struct(current);
612         priv->task = current;
613
614         spin_lock_irqsave(&dev->clients_lock, flags);
615         list_add(&priv->list, &dev->clients);
616         spin_unlock_irqrestore(&dev->clients_lock, flags);
617
618         filp->private_data = priv;
619         return 0;
620 }
621
622 static int tegra_overlay_release(struct inode *inode, struct file *filp)
623 {
624         struct overlay_client *client = filp->private_data;
625         unsigned long flags;
626         int i;
627
628         mutex_lock(&client->dev->overlays_lock);
629         for (i = 0; i < client->dev->dc->n_windows; i++)
630                 if (client->dev->overlays[i].owner == client)
631                         tegra_overlay_put_locked(client, i);
632         mutex_unlock(&client->dev->overlays_lock);
633
634         spin_lock_irqsave(&client->dev->clients_lock, flags);
635         list_del(&client->list);
636         spin_unlock_irqrestore(&client->dev->clients_lock, flags);
637
638         nvmap_client_put(client->user_nvmap);
639         put_task_struct(client->task);
640
641         kfree(client);
642         return 0;
643 }
644
645 static long tegra_overlay_ioctl(struct file *filp, unsigned int cmd,
646                                 unsigned long arg)
647 {
648         struct overlay_client *client = filp->private_data;
649         int err = 0;
650         void __user *uarg = (void __user *)arg;
651
652         if (_IOC_TYPE(cmd) != TEGRA_OVERLAY_IOCTL_MAGIC)
653                 return -ENOTTY;
654
655         if (_IOC_NR(cmd) < TEGRA_OVERLAY_IOCTL_MIN_NR)
656                 return -ENOTTY;
657
658         if (_IOC_NR(cmd) > TEGRA_OVERLAY_IOCTL_MAX_NR)
659                 return -ENOTTY;
660
661         if (_IOC_DIR(cmd) & _IOC_READ)
662                 err = !access_ok(VERIFY_WRITE, uarg, _IOC_SIZE(cmd));
663         if (_IOC_DIR(cmd) & _IOC_WRITE)
664                 err = !access_ok(VERIFY_READ, uarg, _IOC_SIZE(cmd));
665
666         if (err)
667                 return -EFAULT;
668
669         switch (cmd) {
670         case TEGRA_OVERLAY_IOCTL_OPEN_WINDOW:
671                 err = tegra_overlay_ioctl_open(client, uarg);
672                 break;
673         case TEGRA_OVERLAY_IOCTL_CLOSE_WINDOW:
674                 err = tegra_overlay_ioctl_close(client, uarg);
675                 break;
676         case TEGRA_OVERLAY_IOCTL_FLIP:
677                 err = tegra_overlay_ioctl_flip(client, uarg);
678                 break;
679         case TEGRA_OVERLAY_IOCTL_SET_NVMAP_FD:
680                 err = tegra_overlay_ioctl_set_nvmap_fd(client, uarg);
681                 break;
682         default:
683                 return -ENOTTY;
684         }
685         return err;
686 }
687
688 static const struct file_operations overlay_fops = {
689         .owner          = THIS_MODULE,
690         .open           = tegra_overlay_open,
691         .release        = tegra_overlay_release,
692         .unlocked_ioctl = tegra_overlay_ioctl,
693 };
694
695 /* Registration */
696 struct tegra_overlay_info *tegra_overlay_register(struct nvhost_device *ndev,
697                                                   struct tegra_dc *dc)
698 {
699         struct tegra_overlay_info *dev;
700         int e;
701
702         dev = kzalloc(sizeof(*dev), GFP_KERNEL);
703         if (!dev) {
704                 dev_err(&ndev->dev, "out of memory for device\n");
705                 return ERR_PTR(-ENOMEM);
706         }
707
708         snprintf(dev->name, sizeof(dev->name), "tegra_dc%u", ndev->id);
709
710         dev->ndev = ndev;
711         dev->dev.minor = MISC_DYNAMIC_MINOR;
712         dev->dev.name = dev->name;
713         dev->dev.fops = &overlay_fops;
714         dev->dev.parent = &ndev->dev;
715
716         spin_lock_init(&dev->clients_lock);
717         INIT_LIST_HEAD(&dev->clients);
718
719         mutex_init(&dev->overlays_lock);
720
721         e = misc_register(&dev->dev);
722         if (e) {
723                 dev_err(&ndev->dev, "unable to register miscdevice %s\n",
724                         dev->dev.name);
725                 goto fail;
726         }
727
728         dev->overlay_nvmap = nvmap_create_client(nvmap_dev, "overlay");
729         if (!dev->overlay_nvmap) {
730                 dev_err(&ndev->dev, "couldn't create nvmap client\n");
731                 e = -ENOMEM;
732                 goto err_free;
733         }
734
735         dev->flip_wq = create_singlethread_workqueue(dev_name(&ndev->dev));
736         if (!dev->flip_wq) {
737                 dev_err(&ndev->dev, "couldn't create flip work-queue\n");
738                 e = -ENOMEM;
739                 goto err_delete_wq;
740         }
741
742         dev->dc = dc;
743
744         dev_info(&ndev->dev, "registered overlay\n");
745
746         return dev;
747
748 err_delete_wq:
749 err_free:
750 fail:
751         if (dev->dev.minor != MISC_DYNAMIC_MINOR)
752                 misc_deregister(&dev->dev);
753         kfree(dev);
754         return ERR_PTR(e);
755 }
756
757 void tegra_overlay_unregister(struct tegra_overlay_info *info)
758 {
759         misc_deregister(&info->dev);
760
761         kfree(info);
762 }
763
764 void tegra_overlay_disable(struct tegra_overlay_info *overlay_info)
765 {
766         mutex_lock(&tegra_flip_lock);
767         flush_workqueue(overlay_info->flip_wq);
768         mutex_unlock(&tegra_flip_lock);
769 }