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