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