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 struct srcu_notifier_head tegra_dc_flip_notifier_list;
279 static bool init_tegra_dc_flip_notifier_list_called;
280 static int __init init_tegra_dc_flip_notifier_list(void)
281 {
282         srcu_init_notifier_head(&tegra_dc_flip_notifier_list);
283         init_tegra_dc_flip_notifier_list_called = true;
284         return 0;
285 }
286
287 pure_initcall(init_tegra_dc_flip_notifier_list);
288
289 int tegra_dc_register_flip_notifier(struct notifier_block *nb)
290 {
291         WARN_ON(!init_tegra_dc_flip_notifier_list_called);
292
293         return srcu_notifier_chain_register(
294                         &tegra_dc_flip_notifier_list, nb);
295 }
296 EXPORT_SYMBOL(tegra_dc_register_flip_notifier);
297
298 int tegra_dc_unregister_flip_notifier(struct notifier_block *nb)
299 {
300         return srcu_notifier_chain_unregister(&tegra_dc_flip_notifier_list, nb);
301 }
302 EXPORT_SYMBOL(tegra_dc_unregister_flip_notifier);
303
304 static void tegra_dc_ext_flip_worker(struct work_struct *work)
305 {
306         struct tegra_dc_ext_flip_data *data =
307                 container_of(work, struct tegra_dc_ext_flip_data, work);
308         struct tegra_dc_ext *ext = data->ext;
309         struct tegra_dc_win *wins[DC_N_WINDOWS];
310         struct nvmap_handle_ref *unpin_handles[DC_N_WINDOWS *
311                                                TEGRA_DC_NUM_PLANES];
312         struct nvmap_handle_ref *old_handle;
313         int i, nr_unpin = 0, nr_win = 0;
314         bool skip_flip = false;
315
316         for (i = 0; i < DC_N_WINDOWS; i++) {
317                 struct tegra_dc_ext_flip_win *flip_win = &data->win[i];
318                 int index = flip_win->attr.index;
319                 struct tegra_dc_win *win;
320                 struct tegra_dc_ext_win *ext_win;
321
322                 if (index < 0)
323                         continue;
324
325                 win = tegra_dc_get_window(ext->dc, index);
326                 ext_win = &ext->win[index];
327
328                 if (!(atomic_dec_and_test(&ext_win->nr_pending_flips)) &&
329                         (flip_win->attr.flags & TEGRA_DC_EXT_FLIP_FLAG_CURSOR))
330                         skip_flip = true;
331
332                 if (win->flags & TEGRA_WIN_FLAG_ENABLED) {
333                         int j;
334                         for (j = 0; j < TEGRA_DC_NUM_PLANES; j++) {
335                                 if (skip_flip)
336                                         old_handle = flip_win->handle[j];
337                                 else
338                                         old_handle = ext_win->cur_handle[j];
339
340                                 if (!old_handle)
341                                         continue;
342
343                                 unpin_handles[nr_unpin++] = old_handle;
344                         }
345                 }
346
347                 if (!skip_flip)
348                         tegra_dc_ext_set_windowattr(ext, win, &data->win[i]);
349
350                 wins[nr_win++] = win;
351         }
352
353         if (!skip_flip) {
354                 tegra_dc_update_windows(wins, nr_win);
355                 /* TODO: implement swapinterval here */
356                 tegra_dc_sync_windows(wins, nr_win);
357                 if (!tegra_dc_has_multiple_dc())
358                         srcu_notifier_call_chain(&tegra_dc_flip_notifier_list,
359                                                  1UL, NULL);
360         }
361
362         for (i = 0; i < DC_N_WINDOWS; i++) {
363                 struct tegra_dc_ext_flip_win *flip_win = &data->win[i];
364                 int index = flip_win->attr.index;
365
366                 if (index < 0)
367                         continue;
368
369                 tegra_dc_incr_syncpt_min(ext->dc, index,
370                         flip_win->syncpt_max);
371         }
372
373         /* unpin and deref previous front buffers */
374         for (i = 0; i < nr_unpin; i++) {
375                 nvmap_unpin(ext->nvmap, unpin_handles[i]);
376                 nvmap_free(ext->nvmap, unpin_handles[i]);
377         }
378
379         kfree(data);
380 }
381
382 static int lock_windows_for_flip(struct tegra_dc_ext_user *user,
383                                  struct tegra_dc_ext_flip *args)
384 {
385         struct tegra_dc_ext *ext = user->ext;
386         u8 idx_mask = 0;
387         int i;
388
389         for (i = 0; i < DC_N_WINDOWS; i++) {
390                 int index = args->win[i].index;
391
392                 if (index < 0)
393                         continue;
394
395                 idx_mask |= BIT(index);
396         }
397
398         for (i = 0; i < DC_N_WINDOWS; i++) {
399                 struct tegra_dc_ext_win *win;
400
401                 if (!(idx_mask & BIT(i)))
402                         continue;
403
404                 win = &ext->win[i];
405
406                 mutex_lock(&win->lock);
407
408                 if (win->user != user)
409                         goto fail_unlock;
410         }
411
412         return 0;
413
414 fail_unlock:
415         do {
416                 if (!(idx_mask & BIT(i)))
417                         continue;
418
419                 mutex_unlock(&ext->win[i].lock);
420         } while (i--);
421
422         return -EACCES;
423 }
424
425 static void unlock_windows_for_flip(struct tegra_dc_ext_user *user,
426                                     struct tegra_dc_ext_flip *args)
427 {
428         struct tegra_dc_ext *ext = user->ext;
429         u8 idx_mask = 0;
430         int i;
431
432         for (i = 0; i < DC_N_WINDOWS; i++) {
433                 int index = args->win[i].index;
434
435                 if (index < 0)
436                         continue;
437
438                 idx_mask |= BIT(index);
439         }
440
441         for (i = DC_N_WINDOWS - 1; i >= 0; i--) {
442                 if (!(idx_mask & BIT(i)))
443                         continue;
444
445                 mutex_unlock(&ext->win[i].lock);
446         }
447 }
448
449 static int sanitize_flip_args(struct tegra_dc_ext_user *user,
450                               struct tegra_dc_ext_flip *args)
451 {
452         int i, used_windows = 0;
453
454         for (i = 0; i < DC_N_WINDOWS; i++) {
455                 int index = args->win[i].index;
456
457                 if (index < 0)
458                         continue;
459
460                 if (index >= DC_N_WINDOWS)
461                         return -EINVAL;
462
463                 if (used_windows & BIT(index))
464                         return -EINVAL;
465
466                 used_windows |= BIT(index);
467         }
468
469         if (!used_windows)
470                 return -EINVAL;
471
472         return 0;
473 }
474
475 static int tegra_dc_ext_flip(struct tegra_dc_ext_user *user,
476                              struct tegra_dc_ext_flip *args)
477 {
478         struct tegra_dc_ext *ext = user->ext;
479         struct tegra_dc_ext_flip_data *data;
480         int work_index = -1;
481         int i, ret = 0;
482
483 #ifdef CONFIG_ANDROID
484         int index_check[DC_N_WINDOWS] = {0, };
485         int zero_index_id = 0;
486 #endif
487
488         if (!user->nvmap)
489                 return -EFAULT;
490
491         ret = sanitize_flip_args(user, args);
492         if (ret)
493                 return ret;
494
495         data = kzalloc(sizeof(*data), GFP_KERNEL);
496         if (!data)
497                 return -ENOMEM;
498
499         INIT_WORK(&data->work, tegra_dc_ext_flip_worker);
500         data->ext = ext;
501
502 #ifdef CONFIG_ANDROID
503         for (i = 0; i < DC_N_WINDOWS; i++) {
504                 index_check[i] = args->win[i].index;
505                 if (index_check[i] == 0)
506                         zero_index_id = i;
507         }
508
509         if (index_check[DC_N_WINDOWS - 1] != 0) {
510                 struct tegra_dc_ext_flip_windowattr win_temp;
511                 win_temp = args->win[DC_N_WINDOWS - 1];
512                 args->win[DC_N_WINDOWS - 1] = args->win[zero_index_id];
513                 args->win[zero_index_id] = win_temp;
514         }
515 #endif
516
517         for (i = 0; i < DC_N_WINDOWS; i++) {
518                 struct tegra_dc_ext_flip_win *flip_win = &data->win[i];
519                 int index = args->win[i].index;
520
521                 memcpy(&flip_win->attr, &args->win[i], sizeof(flip_win->attr));
522
523                 if (index < 0)
524                         continue;
525
526                 ret = tegra_dc_ext_pin_window(user, flip_win->attr.buff_id,
527                                               &flip_win->handle[TEGRA_DC_Y],
528                                               &flip_win->phys_addr);
529                 if (ret)
530                         goto fail_pin;
531
532                 if (flip_win->attr.buff_id_u) {
533                         ret = tegra_dc_ext_pin_window(user,
534                                               flip_win->attr.buff_id_u,
535                                               &flip_win->handle[TEGRA_DC_U],
536                                               &flip_win->phys_addr_u);
537                         if (ret)
538                                 goto fail_pin;
539                 } else {
540                         flip_win->handle[TEGRA_DC_U] = NULL;
541                         flip_win->phys_addr_u = 0;
542                 }
543
544                 if (flip_win->attr.buff_id_v) {
545                         ret = tegra_dc_ext_pin_window(user,
546                                               flip_win->attr.buff_id_v,
547                                               &flip_win->handle[TEGRA_DC_V],
548                                               &flip_win->phys_addr_v);
549                         if (ret)
550                                 goto fail_pin;
551                 } else {
552                         flip_win->handle[TEGRA_DC_V] = NULL;
553                         flip_win->phys_addr_v = 0;
554                 }
555         }
556
557         ret = lock_windows_for_flip(user, args);
558         if (ret)
559                 goto fail_pin;
560
561         if (!ext->enabled) {
562                 ret = -ENXIO;
563                 goto unlock;
564         }
565
566         for (i = 0; i < DC_N_WINDOWS; i++) {
567                 u32 syncpt_max;
568                 int index = args->win[i].index;
569                 struct tegra_dc_win *win;
570                 struct tegra_dc_ext_win *ext_win;
571
572                 if (index < 0)
573                         continue;
574
575                 win = tegra_dc_get_window(ext->dc, index);
576                 ext_win = &ext->win[index];
577
578                 syncpt_max = tegra_dc_incr_syncpt_max(ext->dc, index);
579
580                 data->win[i].syncpt_max = syncpt_max;
581
582                 /*
583                  * Any of these windows' syncpoints should be equivalent for
584                  * the client, so we just send back an arbitrary one of them
585                  */
586                 args->post_syncpt_val = syncpt_max;
587                 args->post_syncpt_id = tegra_dc_get_syncpt_id(ext->dc, index);
588                 work_index = index;
589
590                 atomic_inc(&ext->win[work_index].nr_pending_flips);
591         }
592         if (work_index < 0) {
593                 ret = -EINVAL;
594                 goto unlock;
595         }
596         queue_work(ext->win[work_index].flip_wq, &data->work);
597
598         unlock_windows_for_flip(user, args);
599
600         return 0;
601
602 unlock:
603         unlock_windows_for_flip(user, args);
604
605 fail_pin:
606         for (i = 0; i < DC_N_WINDOWS; i++) {
607                 int j;
608                 for (j = 0; j < TEGRA_DC_NUM_PLANES; j++) {
609                         if (!data->win[i].handle[j])
610                                 continue;
611
612                         nvmap_unpin(ext->nvmap, data->win[i].handle[j]);
613                         nvmap_free(ext->nvmap, data->win[i].handle[j]);
614                 }
615         }
616         kfree(data);
617
618         return ret;
619 }
620
621 static int tegra_dc_ext_set_csc(struct tegra_dc_ext_user *user,
622                                 struct tegra_dc_ext_csc *new_csc)
623 {
624         unsigned int index = new_csc->win_index;
625         struct tegra_dc *dc = user->ext->dc;
626         struct tegra_dc_ext_win *ext_win;
627         struct tegra_dc_csc *csc;
628
629         if (index >= DC_N_WINDOWS)
630                 return -EINVAL;
631
632         ext_win = &user->ext->win[index];
633         csc = &dc->windows[index].csc;
634
635         mutex_lock(&ext_win->lock);
636
637         if (ext_win->user != user) {
638                 mutex_unlock(&ext_win->lock);
639                 return -EACCES;
640         }
641
642         csc->yof =   new_csc->yof;
643         csc->kyrgb = new_csc->kyrgb;
644         csc->kur =   new_csc->kur;
645         csc->kvr =   new_csc->kvr;
646         csc->kug =   new_csc->kug;
647         csc->kvg =   new_csc->kvg;
648         csc->kub =   new_csc->kub;
649         csc->kvb =   new_csc->kvb;
650
651         tegra_dc_update_csc(dc, index);
652
653         mutex_unlock(&ext_win->lock);
654
655         return 0;
656 }
657
658 static int set_lut_channel(u16 *channel_from_user,
659                            u8 *channel_to,
660                            u32 start,
661                            u32 len)
662 {
663         int i;
664         u16 lut16bpp[256];
665
666         if (channel_from_user) {
667                 if (copy_from_user(lut16bpp, channel_from_user, len<<1))
668                         return 1;
669
670                 for (i = 0; i < len; i++)
671                         channel_to[start+i] = lut16bpp[i]>>8;
672         } else {
673                 for (i = 0; i < len; i++)
674                         channel_to[start+i] = start+i;
675         }
676
677         return 0;
678 }
679
680 static int tegra_dc_ext_set_lut(struct tegra_dc_ext_user *user,
681                                 struct tegra_dc_ext_lut *new_lut)
682 {
683         int err;
684         unsigned int index = new_lut->win_index;
685         u32 start = new_lut->start;
686         u32 len = new_lut->len;
687
688         struct tegra_dc *dc = user->ext->dc;
689         struct tegra_dc_ext_win *ext_win;
690         struct tegra_dc_lut *lut;
691
692         if (index >= DC_N_WINDOWS)
693                 return -EINVAL;
694
695         if ((start >= 256) || (len > 256) || ((start + len) > 256))
696                 return -EINVAL;
697
698         ext_win = &user->ext->win[index];
699         lut = &dc->windows[index].lut;
700
701         mutex_lock(&ext_win->lock);
702
703         if (ext_win->user != user) {
704                 mutex_unlock(&ext_win->lock);
705                 return -EACCES;
706         }
707
708         err = set_lut_channel(new_lut->r, lut->r, start, len) |
709               set_lut_channel(new_lut->g, lut->g, start, len) |
710               set_lut_channel(new_lut->b, lut->b, start, len);
711
712         if (err) {
713                 mutex_unlock(&ext_win->lock);
714                 return -EFAULT;
715         }
716
717         tegra_dc_update_lut(dc, index,
718                         new_lut->flags & TEGRA_DC_EXT_LUT_FLAGS_FBOVERRIDE);
719
720         mutex_unlock(&ext_win->lock);
721
722         return 0;
723 }
724
725 static u32 tegra_dc_ext_get_vblank_syncpt(struct tegra_dc_ext_user *user)
726 {
727         struct tegra_dc *dc = user->ext->dc;
728
729         return dc->vblank_syncpt;
730 }
731
732 static int tegra_dc_ext_get_status(struct tegra_dc_ext_user *user,
733                                    struct tegra_dc_ext_status *status)
734 {
735         struct tegra_dc *dc = user->ext->dc;
736
737         memset(status, 0, sizeof(*status));
738
739         if (dc->enabled)
740                 status->flags |= TEGRA_DC_EXT_FLAGS_ENABLED;
741
742         return 0;
743 }
744
745 static int tegra_dc_ext_get_feature(struct tegra_dc_ext_user *user,
746                                    struct tegra_dc_ext_feature *feature)
747 {
748         struct tegra_dc *dc = user->ext->dc;
749         struct tegra_dc_feature *table = dc->feature;
750
751         if (dc->enabled && feature->entries) {
752                 feature->length = table->num_entries;
753                 memcpy(feature->entries, table->entries, table->num_entries *
754                                         sizeof(struct tegra_dc_feature_entry));
755         }
756
757         return 0;
758 }
759
760 static long tegra_dc_ioctl(struct file *filp, unsigned int cmd,
761                            unsigned long arg)
762 {
763         void __user *user_arg = (void __user *)arg;
764         struct tegra_dc_ext_user *user = filp->private_data;
765
766         switch (cmd) {
767         case TEGRA_DC_EXT_SET_NVMAP_FD:
768                 return tegra_dc_ext_set_nvmap_fd(user, arg);
769
770         case TEGRA_DC_EXT_GET_WINDOW:
771                 return tegra_dc_ext_get_window(user, arg);
772         case TEGRA_DC_EXT_PUT_WINDOW:
773                 return tegra_dc_ext_put_window(user, arg);
774
775         case TEGRA_DC_EXT_FLIP:
776         {
777                 struct tegra_dc_ext_flip args;
778                 int ret;
779
780                 if (copy_from_user(&args, user_arg, sizeof(args)))
781                         return -EFAULT;
782
783                 ret = tegra_dc_ext_flip(user, &args);
784
785                 if (copy_to_user(user_arg, &args, sizeof(args)))
786                         return -EFAULT;
787
788                 return ret;
789         }
790
791         case TEGRA_DC_EXT_GET_CURSOR:
792                 return tegra_dc_ext_get_cursor(user);
793         case TEGRA_DC_EXT_PUT_CURSOR:
794                 return tegra_dc_ext_put_cursor(user);
795         case TEGRA_DC_EXT_SET_CURSOR_IMAGE:
796         {
797                 struct tegra_dc_ext_cursor_image args;
798
799                 if (copy_from_user(&args, user_arg, sizeof(args)))
800                         return -EFAULT;
801
802                 return tegra_dc_ext_set_cursor_image(user, &args);
803         }
804         case TEGRA_DC_EXT_SET_CURSOR:
805         {
806                 struct tegra_dc_ext_cursor args;
807
808                 if (copy_from_user(&args, user_arg, sizeof(args)))
809                         return -EFAULT;
810
811                 return tegra_dc_ext_set_cursor(user, &args);
812         }
813
814         case TEGRA_DC_EXT_SET_CSC:
815         {
816                 struct tegra_dc_ext_csc args;
817
818                 if (copy_from_user(&args, user_arg, sizeof(args)))
819                         return -EFAULT;
820
821                 return tegra_dc_ext_set_csc(user, &args);
822         }
823
824         case TEGRA_DC_EXT_GET_VBLANK_SYNCPT:
825         {
826                 u32 syncpt = tegra_dc_ext_get_vblank_syncpt(user);
827
828                 if (copy_to_user(user_arg, &syncpt, sizeof(syncpt)))
829                         return -EFAULT;
830
831                 return 0;
832         }
833
834         case TEGRA_DC_EXT_GET_STATUS:
835         {
836                 struct tegra_dc_ext_status args;
837                 int ret;
838
839                 ret = tegra_dc_ext_get_status(user, &args);
840
841                 if (copy_to_user(user_arg, &args, sizeof(args)))
842                         return -EFAULT;
843
844                 return ret;
845         }
846
847         case TEGRA_DC_EXT_SET_LUT:
848         {
849                 struct tegra_dc_ext_lut args;
850
851                 if (copy_from_user(&args, user_arg, sizeof(args)))
852                         return -EFAULT;
853
854                 return tegra_dc_ext_set_lut(user, &args);
855         }
856
857         case TEGRA_DC_EXT_GET_FEATURES:
858         {
859                 struct tegra_dc_ext_feature args;
860                 int ret;
861
862                 if (copy_from_user(&args, user_arg, sizeof(args)))
863                         return -EFAULT;
864
865                 ret = tegra_dc_ext_get_feature(user, &args);
866
867                 if (copy_to_user(user_arg, &args, sizeof(args)))
868                         return -EFAULT;
869
870                 return ret;
871         }
872
873         default:
874                 return -EINVAL;
875         }
876 }
877
878 static int tegra_dc_open(struct inode *inode, struct file *filp)
879 {
880         struct tegra_dc_ext_user *user;
881         struct tegra_dc_ext *ext;
882
883         user = kzalloc(sizeof(*user), GFP_KERNEL);
884         if (!user)
885                 return -ENOMEM;
886
887         ext = container_of(inode->i_cdev, struct tegra_dc_ext, cdev);
888         user->ext = ext;
889
890         filp->private_data = user;
891
892         return 0;
893 }
894
895 static int tegra_dc_release(struct inode *inode, struct file *filp)
896 {
897         struct tegra_dc_ext_user *user = filp->private_data;
898         struct tegra_dc_ext *ext = user->ext;
899         unsigned int i;
900
901         for (i = 0; i < DC_N_WINDOWS; i++) {
902                 if (ext->win[i].user == user)
903                         tegra_dc_ext_put_window(user, i);
904         }
905         if (ext->cursor.user == user)
906                 tegra_dc_ext_put_cursor(user);
907
908         if (user->nvmap)
909                 nvmap_client_put(user->nvmap);
910
911         kfree(user);
912
913         return 0;
914 }
915
916 static int tegra_dc_ext_setup_windows(struct tegra_dc_ext *ext)
917 {
918         int i, ret;
919
920         for (i = 0; i < ext->dc->n_windows; i++) {
921                 struct tegra_dc_ext_win *win = &ext->win[i];
922                 char name[32];
923
924                 win->ext = ext;
925                 win->idx = i;
926
927                 snprintf(name, sizeof(name), "tegradc.%d/%c",
928                          ext->dc->ndev->id, 'a' + i);
929                 win->flip_wq = create_singlethread_workqueue(name);
930                 if (!win->flip_wq) {
931                         ret = -ENOMEM;
932                         goto cleanup;
933                 }
934
935                 mutex_init(&win->lock);
936         }
937
938         return 0;
939
940 cleanup:
941         while (i--) {
942                 struct tegra_dc_ext_win *win = &ext->win[i];
943                 destroy_workqueue(win->flip_wq);
944         }
945
946         return ret;
947 }
948
949 static const struct file_operations tegra_dc_devops = {
950         .owner =                THIS_MODULE,
951         .open =                 tegra_dc_open,
952         .release =              tegra_dc_release,
953         .unlocked_ioctl =       tegra_dc_ioctl,
954 };
955
956 struct tegra_dc_ext *tegra_dc_ext_register(struct nvhost_device *ndev,
957                                            struct tegra_dc *dc)
958 {
959         int ret;
960         struct tegra_dc_ext *ext;
961         int devno;
962
963         ext = kzalloc(sizeof(*ext), GFP_KERNEL);
964         if (!ext)
965                 return ERR_PTR(-ENOMEM);
966
967         BUG_ON(!tegra_dc_ext_devno);
968         devno = tegra_dc_ext_devno + head_count + 1;
969
970         cdev_init(&ext->cdev, &tegra_dc_devops);
971         ext->cdev.owner = THIS_MODULE;
972         ret = cdev_add(&ext->cdev, devno, 1);
973         if (ret) {
974                 dev_err(&ndev->dev, "Failed to create character device\n");
975                 goto cleanup_alloc;
976         }
977
978         ext->dev = device_create(tegra_dc_ext_class,
979                                  &ndev->dev,
980                                  devno,
981                                  NULL,
982                                  "tegra_dc_%d",
983                                  ndev->id);
984
985         if (IS_ERR(ext->dev)) {
986                 ret = PTR_ERR(ext->dev);
987                 goto cleanup_cdev;
988         }
989
990         ext->dc = dc;
991
992         ext->nvmap = nvmap_create_client(nvmap_dev, "tegra_dc_ext");
993         if (!ext->nvmap) {
994                 ret = -ENOMEM;
995                 goto cleanup_device;
996         }
997
998         ret = tegra_dc_ext_setup_windows(ext);
999         if (ret)
1000                 goto cleanup_nvmap;
1001
1002         mutex_init(&ext->cursor.lock);
1003
1004         head_count++;
1005
1006         return ext;
1007
1008 cleanup_nvmap:
1009         nvmap_client_put(ext->nvmap);
1010
1011 cleanup_device:
1012         device_del(ext->dev);
1013
1014 cleanup_cdev:
1015         cdev_del(&ext->cdev);
1016
1017 cleanup_alloc:
1018         kfree(ext);
1019
1020         return ERR_PTR(ret);
1021 }
1022
1023 void tegra_dc_ext_unregister(struct tegra_dc_ext *ext)
1024 {
1025         int i;
1026
1027         for (i = 0; i < ext->dc->n_windows; i++) {
1028                 struct tegra_dc_ext_win *win = &ext->win[i];
1029
1030                 flush_workqueue(win->flip_wq);
1031                 destroy_workqueue(win->flip_wq);
1032         }
1033
1034         nvmap_client_put(ext->nvmap);
1035         device_del(ext->dev);
1036         cdev_del(&ext->cdev);
1037
1038         kfree(ext);
1039
1040         head_count--;
1041 }
1042
1043 int __init tegra_dc_ext_module_init(void)
1044 {
1045         int ret;
1046
1047         tegra_dc_ext_class = class_create(THIS_MODULE, "tegra_dc_ext");
1048         if (!tegra_dc_ext_class) {
1049                 printk(KERN_ERR "tegra_dc_ext: failed to create class\n");
1050                 return -ENOMEM;
1051         }
1052
1053         /* Reserve one character device per head, plus the control device */
1054         ret = alloc_chrdev_region(&tegra_dc_ext_devno,
1055                                   0, TEGRA_MAX_DC + 1,
1056                                   "tegra_dc_ext");
1057         if (ret)
1058                 goto cleanup_class;
1059
1060         ret = tegra_dc_ext_control_init();
1061         if (ret)
1062                 goto cleanup_region;
1063
1064         return 0;
1065
1066 cleanup_region:
1067         unregister_chrdev_region(tegra_dc_ext_devno, TEGRA_MAX_DC);
1068
1069 cleanup_class:
1070         class_destroy(tegra_dc_ext_class);
1071
1072         return ret;
1073 }
1074
1075 void __exit tegra_dc_ext_module_exit(void)
1076 {
1077         unregister_chrdev_region(tegra_dc_ext_devno, TEGRA_MAX_DC);
1078         class_destroy(tegra_dc_ext_class);
1079 }