Revert "Merge commit 'main-jb-2012.08.03-B4' into t114-0806"
[linux-2.6.git] / drivers / video / tegra / dc / ext / dev.c
1 /*
2  * drivers/video/tegra/dc/dev.c
3  *
4  * Copyright (c) 2011-2012, NVIDIA CORPORATION, All rights reserved.
5  *
6  * Author: Robert Morell <rmorell@nvidia.com>
7  * Some code based on fbdev extensions written by:
8  *      Erik Gilling <konkers@android.com>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful, but WITHOUT
16  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
18  * more details.
19  */
20
21 #include <linux/file.h>
22 #include <linux/fs.h>
23 #include <linux/uaccess.h>
24 #include <linux/slab.h>
25 #include <linux/workqueue.h>
26 #include <linux/export.h>
27
28 #include <video/tegra_dc_ext.h>
29
30 #include <mach/dc.h>
31 #include <linux/nvmap.h>
32 #include <mach/tegra_dc_ext.h>
33
34 /* XXX ew */
35 #include "../dc_priv.h"
36 #include "../dc_config.h"
37 /* XXX ew 2 */
38 #include "../../host/dev.h"
39 /* XXX ew 3 */
40 #include "../../nvmap/nvmap.h"
41 #include "tegra_dc_ext_priv.h"
42
43 int tegra_dc_ext_devno;
44 struct class *tegra_dc_ext_class;
45 static int head_count;
46
47 struct tegra_dc_ext_flip_win {
48         struct tegra_dc_ext_flip_windowattr     attr;
49         struct nvmap_handle_ref                 *handle[TEGRA_DC_NUM_PLANES];
50         dma_addr_t                              phys_addr;
51         dma_addr_t                              phys_addr_u;
52         dma_addr_t                              phys_addr_v;
53         u32                                     syncpt_max;
54 };
55
56 struct tegra_dc_ext_flip_data {
57         struct tegra_dc_ext             *ext;
58         struct work_struct              work;
59         struct tegra_dc_ext_flip_win    win[DC_N_WINDOWS];
60 };
61
62 int tegra_dc_ext_get_num_outputs(void)
63 {
64         /* TODO: decouple output count from head count */
65         return head_count;
66 }
67
68 static int tegra_dc_ext_set_nvmap_fd(struct tegra_dc_ext_user *user,
69                                      int fd)
70 {
71         struct nvmap_client *nvmap = NULL;
72
73         if (fd >= 0) {
74                 nvmap = nvmap_client_get_file(fd);
75                 if (IS_ERR(nvmap))
76                         return PTR_ERR(nvmap);
77         }
78
79         if (user->nvmap)
80                 nvmap_client_put(user->nvmap);
81
82         user->nvmap = nvmap;
83
84         return 0;
85 }
86
87 static int tegra_dc_ext_get_window(struct tegra_dc_ext_user *user,
88                                    unsigned int n)
89 {
90         struct tegra_dc_ext *ext = user->ext;
91         struct tegra_dc_ext_win *win;
92         int ret = 0;
93
94         if (n >= DC_N_WINDOWS)
95                 return -EINVAL;
96
97         win = &ext->win[n];
98
99         mutex_lock(&win->lock);
100
101         if (!win->user)
102                 win->user = user;
103         else if (win->user != user)
104                 ret = -EBUSY;
105
106         mutex_unlock(&win->lock);
107
108         return ret;
109 }
110
111 static int tegra_dc_ext_put_window(struct tegra_dc_ext_user *user,
112                                    unsigned int n)
113 {
114         struct tegra_dc_ext *ext = user->ext;
115         struct tegra_dc_ext_win *win;
116         int ret = 0;
117
118         if (n >= DC_N_WINDOWS)
119                 return -EINVAL;
120
121         win = &ext->win[n];
122
123         mutex_lock(&win->lock);
124
125         if (win->user == user) {
126                 flush_workqueue(win->flip_wq);
127                 win->user = 0;
128         } else {
129                 ret = -EACCES;
130         }
131
132         mutex_unlock(&win->lock);
133
134         return ret;
135 }
136
137 static void set_enable(struct tegra_dc_ext *ext, bool en)
138 {
139         int i;
140
141         /*
142          * Take all locks to make sure any flip requests or cursor moves are
143          * out of their critical sections
144          */
145         for (i = 0; i < ext->dc->n_windows; i++)
146                 mutex_lock(&ext->win[i].lock);
147         mutex_lock(&ext->cursor.lock);
148
149         ext->enabled = en;
150
151         mutex_unlock(&ext->cursor.lock);
152         for (i = ext->dc->n_windows - 1; i >= 0 ; i--)
153                 mutex_unlock(&ext->win[i].lock);
154 }
155
156 void tegra_dc_ext_enable(struct tegra_dc_ext *ext)
157 {
158         set_enable(ext, true);
159 }
160
161 void tegra_dc_ext_disable(struct tegra_dc_ext *ext)
162 {
163         int i;
164         set_enable(ext, false);
165
166         /*
167          * Flush the flip queue -- note that this must be called with dc->lock
168          * unlocked or else it will hang.
169          */
170         for (i = 0; i < ext->dc->n_windows; i++) {
171                 struct tegra_dc_ext_win *win = &ext->win[i];
172
173                 flush_workqueue(win->flip_wq);
174         }
175 }
176
177 int tegra_dc_ext_check_windowattr(struct tegra_dc_ext *ext,
178                                                 struct tegra_dc_win *win)
179 {
180         long *addr;
181         struct tegra_dc *dc = ext->dc;
182
183         /* Check the window format */
184         addr = tegra_dc_parse_feature(dc, win->idx, GET_WIN_FORMATS);
185         if (!test_bit(win->fmt, addr)) {
186                 dev_err(&dc->ndev->dev, "Color format of window %d is"
187                                                 " invalid.\n", win->idx);
188                 goto fail;
189         }
190
191         /* Check window size */
192         addr = tegra_dc_parse_feature(dc, win->idx, GET_WIN_SIZE);
193         if (CHECK_SIZE(win->out_w, addr[MIN_WIDTH], addr[MAX_WIDTH]) ||
194                 CHECK_SIZE(win->out_h, addr[MIN_HEIGHT], addr[MAX_HEIGHT])) {
195                 dev_err(&dc->ndev->dev, "Size of window %d is"
196                                                 " invalid.\n", win->idx);
197                 goto fail;
198         }
199
200         return 0;
201 fail:
202         return -EINVAL;
203 }
204
205 static int tegra_dc_ext_set_windowattr(struct tegra_dc_ext *ext,
206                                struct tegra_dc_win *win,
207                                const struct tegra_dc_ext_flip_win *flip_win)
208 {
209         int err = 0;
210         struct tegra_dc_ext_win *ext_win = &ext->win[win->idx];
211
212         if (flip_win->handle[TEGRA_DC_Y] == NULL) {
213                 win->flags = 0;
214                 memset(ext_win->cur_handle, 0, sizeof(ext_win->cur_handle));
215                 return 0;
216         }
217
218         win->flags = TEGRA_WIN_FLAG_ENABLED;
219         if (flip_win->attr.blend == TEGRA_DC_EXT_BLEND_PREMULT)
220                 win->flags |= TEGRA_WIN_FLAG_BLEND_PREMULT;
221         else if (flip_win->attr.blend == TEGRA_DC_EXT_BLEND_COVERAGE)
222                 win->flags |= TEGRA_WIN_FLAG_BLEND_COVERAGE;
223         if (flip_win->attr.flags & TEGRA_DC_EXT_FLIP_FLAG_TILED)
224                 win->flags |= TEGRA_WIN_FLAG_TILED;
225         if (flip_win->attr.flags & TEGRA_DC_EXT_FLIP_FLAG_INVERT_H)
226                 win->flags |= TEGRA_WIN_FLAG_INVERT_H;
227         if (flip_win->attr.flags & TEGRA_DC_EXT_FLIP_FLAG_INVERT_V)
228                 win->flags |= TEGRA_WIN_FLAG_INVERT_V;
229         if (flip_win->attr.flags & TEGRA_DC_EXT_FLIP_FLAG_GLOBAL_ALPHA)
230                 win->global_alpha = flip_win->attr.global_alpha;
231         else
232                 win->global_alpha = 255;
233         win->fmt = flip_win->attr.pixformat;
234         win->x.full = flip_win->attr.x;
235         win->y.full = flip_win->attr.y;
236         win->w.full = flip_win->attr.w;
237         win->h.full = flip_win->attr.h;
238         /* XXX verify that this doesn't go outside display's active region */
239         win->out_x = flip_win->attr.out_x;
240         win->out_y = flip_win->attr.out_y;
241         win->out_w = flip_win->attr.out_w;
242         win->out_h = flip_win->attr.out_h;
243         win->z = flip_win->attr.z;
244         memcpy(ext_win->cur_handle, flip_win->handle,
245                sizeof(ext_win->cur_handle));
246
247         /* XXX verify that this won't read outside of the surface */
248         win->phys_addr = flip_win->phys_addr + flip_win->attr.offset;
249
250         win->phys_addr_u = flip_win->handle[TEGRA_DC_U] ?
251                 flip_win->phys_addr_u : flip_win->phys_addr;
252         win->phys_addr_u += flip_win->attr.offset_u;
253
254         win->phys_addr_v = flip_win->handle[TEGRA_DC_V] ?
255                 flip_win->phys_addr_v : flip_win->phys_addr;
256         win->phys_addr_v += flip_win->attr.offset_v;
257
258         win->stride = flip_win->attr.stride;
259         win->stride_uv = flip_win->attr.stride_uv;
260
261         err = tegra_dc_ext_check_windowattr(ext, win);
262         if (err < 0)
263                 dev_err(&ext->dc->ndev->dev,
264                                 "Window atrributes are invalid.\n");
265
266         if ((s32)flip_win->attr.pre_syncpt_id >= 0) {
267                 nvhost_syncpt_wait_timeout(
268                                 &nvhost_get_host(ext->dc->ndev)->syncpt,
269                                 flip_win->attr.pre_syncpt_id,
270                                 flip_win->attr.pre_syncpt_val,
271                                 msecs_to_jiffies(500), NULL);
272         }
273
274
275         return 0;
276 }
277
278 static void tegra_dc_ext_flip_worker(struct work_struct *work)
279 {
280         struct tegra_dc_ext_flip_data *data =
281                 container_of(work, struct tegra_dc_ext_flip_data, work);
282         struct tegra_dc_ext *ext = data->ext;
283         struct tegra_dc_win *wins[DC_N_WINDOWS];
284         struct nvmap_handle_ref *unpin_handles[DC_N_WINDOWS *
285                                                TEGRA_DC_NUM_PLANES];
286         struct nvmap_handle_ref *old_handle;
287         int i, nr_unpin = 0, nr_win = 0;
288         bool skip_flip = false;
289
290         for (i = 0; i < DC_N_WINDOWS; i++) {
291                 struct tegra_dc_ext_flip_win *flip_win = &data->win[i];
292                 int index = flip_win->attr.index;
293                 struct tegra_dc_win *win;
294                 struct tegra_dc_ext_win *ext_win;
295
296                 if (index < 0)
297                         continue;
298
299                 win = tegra_dc_get_window(ext->dc, index);
300                 ext_win = &ext->win[index];
301
302                 if (!(atomic_dec_and_test(&ext_win->nr_pending_flips)) &&
303                         (flip_win->attr.flags & TEGRA_DC_EXT_FLIP_FLAG_CURSOR))
304                         skip_flip = true;
305
306                 if (win->flags & TEGRA_WIN_FLAG_ENABLED) {
307                         int j;
308                         for (j = 0; j < TEGRA_DC_NUM_PLANES; j++) {
309                                 if (skip_flip)
310                                         old_handle = flip_win->handle[j];
311                                 else
312                                         old_handle = ext_win->cur_handle[j];
313
314                                 if (!old_handle)
315                                         continue;
316
317                                 unpin_handles[nr_unpin++] = old_handle;
318                         }
319                 }
320
321                 if (!skip_flip)
322                         tegra_dc_ext_set_windowattr(ext, win, &data->win[i]);
323
324                 wins[nr_win++] = win;
325         }
326
327         if (!skip_flip) {
328                 tegra_dc_update_windows(wins, nr_win);
329                 /* TODO: implement swapinterval here */
330                 tegra_dc_sync_windows(wins, nr_win);
331         }
332
333         for (i = 0; i < DC_N_WINDOWS; i++) {
334                 struct tegra_dc_ext_flip_win *flip_win = &data->win[i];
335                 int index = flip_win->attr.index;
336
337                 if (index < 0)
338                         continue;
339
340                 tegra_dc_incr_syncpt_min(ext->dc, index,
341                         flip_win->syncpt_max);
342         }
343
344         /* unpin and deref previous front buffers */
345         for (i = 0; i < nr_unpin; i++) {
346                 nvmap_unpin(ext->nvmap, unpin_handles[i]);
347                 nvmap_free(ext->nvmap, unpin_handles[i]);
348         }
349
350         kfree(data);
351 }
352
353 static int lock_windows_for_flip(struct tegra_dc_ext_user *user,
354                                  struct tegra_dc_ext_flip *args)
355 {
356         struct tegra_dc_ext *ext = user->ext;
357         u8 idx_mask = 0;
358         int i;
359
360         for (i = 0; i < DC_N_WINDOWS; i++) {
361                 int index = args->win[i].index;
362
363                 if (index < 0)
364                         continue;
365
366                 idx_mask |= BIT(index);
367         }
368
369         for (i = 0; i < DC_N_WINDOWS; i++) {
370                 struct tegra_dc_ext_win *win;
371
372                 if (!(idx_mask & BIT(i)))
373                         continue;
374
375                 win = &ext->win[i];
376
377                 mutex_lock(&win->lock);
378
379                 if (win->user != user)
380                         goto fail_unlock;
381         }
382
383         return 0;
384
385 fail_unlock:
386         do {
387                 if (!(idx_mask & BIT(i)))
388                         continue;
389
390                 mutex_unlock(&ext->win[i].lock);
391         } while (i--);
392
393         return -EACCES;
394 }
395
396 static void unlock_windows_for_flip(struct tegra_dc_ext_user *user,
397                                     struct tegra_dc_ext_flip *args)
398 {
399         struct tegra_dc_ext *ext = user->ext;
400         u8 idx_mask = 0;
401         int i;
402
403         for (i = 0; i < DC_N_WINDOWS; i++) {
404                 int index = args->win[i].index;
405
406                 if (index < 0)
407                         continue;
408
409                 idx_mask |= BIT(index);
410         }
411
412         for (i = DC_N_WINDOWS - 1; i >= 0; i--) {
413                 if (!(idx_mask & BIT(i)))
414                         continue;
415
416                 mutex_unlock(&ext->win[i].lock);
417         }
418 }
419
420 static int sanitize_flip_args(struct tegra_dc_ext_user *user,
421                               struct tegra_dc_ext_flip *args)
422 {
423         int i, used_windows = 0;
424
425         for (i = 0; i < DC_N_WINDOWS; i++) {
426                 int index = args->win[i].index;
427
428                 if (index < 0)
429                         continue;
430
431                 if (index >= DC_N_WINDOWS)
432                         return -EINVAL;
433
434                 if (used_windows & BIT(index))
435                         return -EINVAL;
436
437                 used_windows |= BIT(index);
438         }
439
440         if (!used_windows)
441                 return -EINVAL;
442
443         return 0;
444 }
445
446 static int tegra_dc_ext_flip(struct tegra_dc_ext_user *user,
447                              struct tegra_dc_ext_flip *args)
448 {
449         struct tegra_dc_ext *ext = user->ext;
450         struct tegra_dc_ext_flip_data *data;
451         int work_index = -1;
452         int i, ret = 0;
453
454 #ifdef CONFIG_ANDROID
455         int index_check[DC_N_WINDOWS] = {0, };
456         int zero_index_id = 0;
457 #endif
458
459         if (!user->nvmap)
460                 return -EFAULT;
461
462         ret = sanitize_flip_args(user, args);
463         if (ret)
464                 return ret;
465
466         data = kzalloc(sizeof(*data), GFP_KERNEL);
467         if (!data)
468                 return -ENOMEM;
469
470         INIT_WORK(&data->work, tegra_dc_ext_flip_worker);
471         data->ext = ext;
472
473 #ifdef CONFIG_ANDROID
474         for (i = 0; i < DC_N_WINDOWS; i++) {
475                 index_check[i] = args->win[i].index;
476                 if (index_check[i] == 0)
477                         zero_index_id = i;
478         }
479
480         if (index_check[DC_N_WINDOWS - 1] != 0) {
481                 struct tegra_dc_ext_flip_windowattr win_temp;
482                 win_temp = args->win[DC_N_WINDOWS - 1];
483                 args->win[DC_N_WINDOWS - 1] = args->win[zero_index_id];
484                 args->win[zero_index_id] = win_temp;
485         }
486 #endif
487
488         for (i = 0; i < DC_N_WINDOWS; i++) {
489                 struct tegra_dc_ext_flip_win *flip_win = &data->win[i];
490                 int index = args->win[i].index;
491
492                 memcpy(&flip_win->attr, &args->win[i], sizeof(flip_win->attr));
493
494                 if (index < 0)
495                         continue;
496
497                 ret = tegra_dc_ext_pin_window(user, flip_win->attr.buff_id,
498                                               &flip_win->handle[TEGRA_DC_Y],
499                                               &flip_win->phys_addr);
500                 if (ret)
501                         goto fail_pin;
502
503                 if (flip_win->attr.buff_id_u) {
504                         ret = tegra_dc_ext_pin_window(user,
505                                               flip_win->attr.buff_id_u,
506                                               &flip_win->handle[TEGRA_DC_U],
507                                               &flip_win->phys_addr_u);
508                         if (ret)
509                                 goto fail_pin;
510                 } else {
511                         flip_win->handle[TEGRA_DC_U] = NULL;
512                         flip_win->phys_addr_u = 0;
513                 }
514
515                 if (flip_win->attr.buff_id_v) {
516                         ret = tegra_dc_ext_pin_window(user,
517                                               flip_win->attr.buff_id_v,
518                                               &flip_win->handle[TEGRA_DC_V],
519                                               &flip_win->phys_addr_v);
520                         if (ret)
521                                 goto fail_pin;
522                 } else {
523                         flip_win->handle[TEGRA_DC_V] = NULL;
524                         flip_win->phys_addr_v = 0;
525                 }
526         }
527
528         ret = lock_windows_for_flip(user, args);
529         if (ret)
530                 goto fail_pin;
531
532         if (!ext->enabled) {
533                 ret = -ENXIO;
534                 goto unlock;
535         }
536
537         for (i = 0; i < DC_N_WINDOWS; i++) {
538                 u32 syncpt_max;
539                 int index = args->win[i].index;
540                 struct tegra_dc_win *win;
541                 struct tegra_dc_ext_win *ext_win;
542
543                 if (index < 0)
544                         continue;
545
546                 win = tegra_dc_get_window(ext->dc, index);
547                 ext_win = &ext->win[index];
548
549                 syncpt_max = tegra_dc_incr_syncpt_max(ext->dc, index);
550
551                 data->win[i].syncpt_max = syncpt_max;
552
553                 /*
554                  * Any of these windows' syncpoints should be equivalent for
555                  * the client, so we just send back an arbitrary one of them
556                  */
557                 args->post_syncpt_val = syncpt_max;
558                 args->post_syncpt_id = tegra_dc_get_syncpt_id(ext->dc, index);
559                 work_index = index;
560
561                 atomic_inc(&ext->win[work_index].nr_pending_flips);
562         }
563         if (work_index < 0) {
564                 ret = -EINVAL;
565                 goto unlock;
566         }
567         queue_work(ext->win[work_index].flip_wq, &data->work);
568
569         unlock_windows_for_flip(user, args);
570
571         return 0;
572
573 unlock:
574         unlock_windows_for_flip(user, args);
575
576 fail_pin:
577         for (i = 0; i < DC_N_WINDOWS; i++) {
578                 int j;
579                 for (j = 0; j < TEGRA_DC_NUM_PLANES; j++) {
580                         if (!data->win[i].handle[j])
581                                 continue;
582
583                         nvmap_unpin(ext->nvmap, data->win[i].handle[j]);
584                         nvmap_free(ext->nvmap, data->win[i].handle[j]);
585                 }
586         }
587         kfree(data);
588
589         return ret;
590 }
591
592 static int tegra_dc_ext_set_csc(struct tegra_dc_ext_user *user,
593                                 struct tegra_dc_ext_csc *new_csc)
594 {
595         unsigned int index = new_csc->win_index;
596         struct tegra_dc *dc = user->ext->dc;
597         struct tegra_dc_ext_win *ext_win;
598         struct tegra_dc_csc *csc;
599
600         if (index >= DC_N_WINDOWS)
601                 return -EINVAL;
602
603         ext_win = &user->ext->win[index];
604         csc = &dc->windows[index].csc;
605
606         mutex_lock(&ext_win->lock);
607
608         if (ext_win->user != user) {
609                 mutex_unlock(&ext_win->lock);
610                 return -EACCES;
611         }
612
613         csc->yof =   new_csc->yof;
614         csc->kyrgb = new_csc->kyrgb;
615         csc->kur =   new_csc->kur;
616         csc->kvr =   new_csc->kvr;
617         csc->kug =   new_csc->kug;
618         csc->kvg =   new_csc->kvg;
619         csc->kub =   new_csc->kub;
620         csc->kvb =   new_csc->kvb;
621
622         tegra_dc_update_csc(dc, index);
623
624         mutex_unlock(&ext_win->lock);
625
626         return 0;
627 }
628
629 static int set_lut_channel(u16 *channel_from_user,
630                            u8 *channel_to,
631                            u32 start,
632                            u32 len)
633 {
634         int i;
635         u16 lut16bpp[256];
636
637         if (channel_from_user) {
638                 if (copy_from_user(lut16bpp, channel_from_user, len<<1))
639                         return 1;
640
641                 for (i = 0; i < len; i++)
642                         channel_to[start+i] = lut16bpp[i]>>8;
643         } else {
644                 for (i = 0; i < len; i++)
645                         channel_to[start+i] = start+i;
646         }
647
648         return 0;
649 }
650
651 static int tegra_dc_ext_set_lut(struct tegra_dc_ext_user *user,
652                                 struct tegra_dc_ext_lut *new_lut)
653 {
654         int err;
655         unsigned int index = new_lut->win_index;
656         u32 start = new_lut->start;
657         u32 len = new_lut->len;
658
659         struct tegra_dc *dc = user->ext->dc;
660         struct tegra_dc_ext_win *ext_win;
661         struct tegra_dc_lut *lut;
662
663         if (index >= DC_N_WINDOWS)
664                 return -EINVAL;
665
666         if ((start >= 256) || (len > 256) || ((start + len) > 256))
667                 return -EINVAL;
668
669         ext_win = &user->ext->win[index];
670         lut = &dc->windows[index].lut;
671
672         mutex_lock(&ext_win->lock);
673
674         if (ext_win->user != user) {
675                 mutex_unlock(&ext_win->lock);
676                 return -EACCES;
677         }
678
679         err = set_lut_channel(new_lut->r, lut->r, start, len) |
680               set_lut_channel(new_lut->g, lut->g, start, len) |
681               set_lut_channel(new_lut->b, lut->b, start, len);
682
683         if (err) {
684                 mutex_unlock(&ext_win->lock);
685                 return -EFAULT;
686         }
687
688         tegra_dc_update_lut(dc, index,
689                         new_lut->flags & TEGRA_DC_EXT_LUT_FLAGS_FBOVERRIDE);
690
691         mutex_unlock(&ext_win->lock);
692
693         return 0;
694 }
695
696 static u32 tegra_dc_ext_get_vblank_syncpt(struct tegra_dc_ext_user *user)
697 {
698         struct tegra_dc *dc = user->ext->dc;
699
700         return dc->vblank_syncpt;
701 }
702
703 static int tegra_dc_ext_get_status(struct tegra_dc_ext_user *user,
704                                    struct tegra_dc_ext_status *status)
705 {
706         struct tegra_dc *dc = user->ext->dc;
707
708         memset(status, 0, sizeof(*status));
709
710         if (dc->enabled)
711                 status->flags |= TEGRA_DC_EXT_FLAGS_ENABLED;
712
713         return 0;
714 }
715
716 static int tegra_dc_ext_get_feature(struct tegra_dc_ext_user *user,
717                                    struct tegra_dc_ext_feature *feature)
718 {
719         struct tegra_dc *dc = user->ext->dc;
720         struct tegra_dc_feature *table = dc->feature;
721
722         if (dc->enabled && feature->entries) {
723                 feature->length = table->num_entries;
724                 memcpy(feature->entries, table->entries, table->num_entries *
725                                         sizeof(struct tegra_dc_feature_entry));
726         }
727
728         return 0;
729 }
730
731 static long tegra_dc_ioctl(struct file *filp, unsigned int cmd,
732                            unsigned long arg)
733 {
734         void __user *user_arg = (void __user *)arg;
735         struct tegra_dc_ext_user *user = filp->private_data;
736
737         switch (cmd) {
738         case TEGRA_DC_EXT_SET_NVMAP_FD:
739                 return tegra_dc_ext_set_nvmap_fd(user, arg);
740
741         case TEGRA_DC_EXT_GET_WINDOW:
742                 return tegra_dc_ext_get_window(user, arg);
743         case TEGRA_DC_EXT_PUT_WINDOW:
744                 return tegra_dc_ext_put_window(user, arg);
745
746         case TEGRA_DC_EXT_FLIP:
747         {
748                 struct tegra_dc_ext_flip args;
749                 int ret;
750
751                 if (copy_from_user(&args, user_arg, sizeof(args)))
752                         return -EFAULT;
753
754                 ret = tegra_dc_ext_flip(user, &args);
755
756                 if (copy_to_user(user_arg, &args, sizeof(args)))
757                         return -EFAULT;
758
759                 return ret;
760         }
761
762         case TEGRA_DC_EXT_GET_CURSOR:
763                 return tegra_dc_ext_get_cursor(user);
764         case TEGRA_DC_EXT_PUT_CURSOR:
765                 return tegra_dc_ext_put_cursor(user);
766         case TEGRA_DC_EXT_SET_CURSOR_IMAGE:
767         {
768                 struct tegra_dc_ext_cursor_image args;
769
770                 if (copy_from_user(&args, user_arg, sizeof(args)))
771                         return -EFAULT;
772
773                 return tegra_dc_ext_set_cursor_image(user, &args);
774         }
775         case TEGRA_DC_EXT_SET_CURSOR:
776         {
777                 struct tegra_dc_ext_cursor args;
778
779                 if (copy_from_user(&args, user_arg, sizeof(args)))
780                         return -EFAULT;
781
782                 return tegra_dc_ext_set_cursor(user, &args);
783         }
784
785         case TEGRA_DC_EXT_SET_CSC:
786         {
787                 struct tegra_dc_ext_csc args;
788
789                 if (copy_from_user(&args, user_arg, sizeof(args)))
790                         return -EFAULT;
791
792                 return tegra_dc_ext_set_csc(user, &args);
793         }
794
795         case TEGRA_DC_EXT_GET_VBLANK_SYNCPT:
796         {
797                 u32 syncpt = tegra_dc_ext_get_vblank_syncpt(user);
798
799                 if (copy_to_user(user_arg, &syncpt, sizeof(syncpt)))
800                         return -EFAULT;
801
802                 return 0;
803         }
804
805         case TEGRA_DC_EXT_GET_STATUS:
806         {
807                 struct tegra_dc_ext_status args;
808                 int ret;
809
810                 ret = tegra_dc_ext_get_status(user, &args);
811
812                 if (copy_to_user(user_arg, &args, sizeof(args)))
813                         return -EFAULT;
814
815                 return ret;
816         }
817
818         case TEGRA_DC_EXT_SET_LUT:
819         {
820                 struct tegra_dc_ext_lut args;
821
822                 if (copy_from_user(&args, user_arg, sizeof(args)))
823                         return -EFAULT;
824
825                 return tegra_dc_ext_set_lut(user, &args);
826         }
827
828         case TEGRA_DC_EXT_GET_FEATURES:
829         {
830                 struct tegra_dc_ext_feature args;
831                 int ret;
832
833                 if (copy_from_user(&args, user_arg, sizeof(args)))
834                         return -EFAULT;
835
836                 ret = tegra_dc_ext_get_feature(user, &args);
837
838                 if (copy_to_user(user_arg, &args, sizeof(args)))
839                         return -EFAULT;
840
841                 return ret;
842         }
843
844         default:
845                 return -EINVAL;
846         }
847 }
848
849 static int tegra_dc_open(struct inode *inode, struct file *filp)
850 {
851         struct tegra_dc_ext_user *user;
852         struct tegra_dc_ext *ext;
853
854         user = kzalloc(sizeof(*user), GFP_KERNEL);
855         if (!user)
856                 return -ENOMEM;
857
858         ext = container_of(inode->i_cdev, struct tegra_dc_ext, cdev);
859         user->ext = ext;
860
861         filp->private_data = user;
862
863         return 0;
864 }
865
866 static int tegra_dc_release(struct inode *inode, struct file *filp)
867 {
868         struct tegra_dc_ext_user *user = filp->private_data;
869         struct tegra_dc_ext *ext = user->ext;
870         unsigned int i;
871
872         for (i = 0; i < DC_N_WINDOWS; i++) {
873                 if (ext->win[i].user == user)
874                         tegra_dc_ext_put_window(user, i);
875         }
876         if (ext->cursor.user == user)
877                 tegra_dc_ext_put_cursor(user);
878
879         if (user->nvmap)
880                 nvmap_client_put(user->nvmap);
881
882         kfree(user);
883
884         return 0;
885 }
886
887 static int tegra_dc_ext_setup_windows(struct tegra_dc_ext *ext)
888 {
889         int i, ret;
890
891         for (i = 0; i < ext->dc->n_windows; i++) {
892                 struct tegra_dc_ext_win *win = &ext->win[i];
893                 char name[32];
894
895                 win->ext = ext;
896                 win->idx = i;
897
898                 snprintf(name, sizeof(name), "tegradc.%d/%c",
899                          ext->dc->ndev->id, 'a' + i);
900                 win->flip_wq = create_singlethread_workqueue(name);
901                 if (!win->flip_wq) {
902                         ret = -ENOMEM;
903                         goto cleanup;
904                 }
905
906                 mutex_init(&win->lock);
907         }
908
909         return 0;
910
911 cleanup:
912         while (i--) {
913                 struct tegra_dc_ext_win *win = &ext->win[i];
914                 destroy_workqueue(win->flip_wq);
915         }
916
917         return ret;
918 }
919
920 static const struct file_operations tegra_dc_devops = {
921         .owner =                THIS_MODULE,
922         .open =                 tegra_dc_open,
923         .release =              tegra_dc_release,
924         .unlocked_ioctl =       tegra_dc_ioctl,
925 };
926
927 struct tegra_dc_ext *tegra_dc_ext_register(struct nvhost_device *ndev,
928                                            struct tegra_dc *dc)
929 {
930         int ret;
931         struct tegra_dc_ext *ext;
932         int devno;
933
934         ext = kzalloc(sizeof(*ext), GFP_KERNEL);
935         if (!ext)
936                 return ERR_PTR(-ENOMEM);
937
938         BUG_ON(!tegra_dc_ext_devno);
939         devno = tegra_dc_ext_devno + head_count + 1;
940
941         cdev_init(&ext->cdev, &tegra_dc_devops);
942         ext->cdev.owner = THIS_MODULE;
943         ret = cdev_add(&ext->cdev, devno, 1);
944         if (ret) {
945                 dev_err(&ndev->dev, "Failed to create character device\n");
946                 goto cleanup_alloc;
947         }
948
949         ext->dev = device_create(tegra_dc_ext_class,
950                                  &ndev->dev,
951                                  devno,
952                                  NULL,
953                                  "tegra_dc_%d",
954                                  ndev->id);
955
956         if (IS_ERR(ext->dev)) {
957                 ret = PTR_ERR(ext->dev);
958                 goto cleanup_cdev;
959         }
960
961         ext->dc = dc;
962
963         ext->nvmap = nvmap_create_client(nvmap_dev, "tegra_dc_ext");
964         if (!ext->nvmap) {
965                 ret = -ENOMEM;
966                 goto cleanup_device;
967         }
968
969         ret = tegra_dc_ext_setup_windows(ext);
970         if (ret)
971                 goto cleanup_nvmap;
972
973         mutex_init(&ext->cursor.lock);
974
975         head_count++;
976
977         return ext;
978
979 cleanup_nvmap:
980         nvmap_client_put(ext->nvmap);
981
982 cleanup_device:
983         device_del(ext->dev);
984
985 cleanup_cdev:
986         cdev_del(&ext->cdev);
987
988 cleanup_alloc:
989         kfree(ext);
990
991         return ERR_PTR(ret);
992 }
993
994 void tegra_dc_ext_unregister(struct tegra_dc_ext *ext)
995 {
996         int i;
997
998         for (i = 0; i < ext->dc->n_windows; i++) {
999                 struct tegra_dc_ext_win *win = &ext->win[i];
1000
1001                 flush_workqueue(win->flip_wq);
1002                 destroy_workqueue(win->flip_wq);
1003         }
1004
1005         nvmap_client_put(ext->nvmap);
1006         device_del(ext->dev);
1007         cdev_del(&ext->cdev);
1008
1009         kfree(ext);
1010
1011         head_count--;
1012 }
1013
1014 int __init tegra_dc_ext_module_init(void)
1015 {
1016         int ret;
1017
1018         tegra_dc_ext_class = class_create(THIS_MODULE, "tegra_dc_ext");
1019         if (!tegra_dc_ext_class) {
1020                 printk(KERN_ERR "tegra_dc_ext: failed to create class\n");
1021                 return -ENOMEM;
1022         }
1023
1024         /* Reserve one character device per head, plus the control device */
1025         ret = alloc_chrdev_region(&tegra_dc_ext_devno,
1026                                   0, TEGRA_MAX_DC + 1,
1027                                   "tegra_dc_ext");
1028         if (ret)
1029                 goto cleanup_class;
1030
1031         ret = tegra_dc_ext_control_init();
1032         if (ret)
1033                 goto cleanup_region;
1034
1035         return 0;
1036
1037 cleanup_region:
1038         unregister_chrdev_region(tegra_dc_ext_devno, TEGRA_MAX_DC);
1039
1040 cleanup_class:
1041         class_destroy(tegra_dc_ext_class);
1042
1043         return ret;
1044 }
1045
1046 void __exit tegra_dc_ext_module_exit(void)
1047 {
1048         unregister_chrdev_region(tegra_dc_ext_devno, TEGRA_MAX_DC);
1049         class_destroy(tegra_dc_ext_class);
1050 }