ebfa6eb08ffa87df9012855d56eb96e2d59f06fd
[linux-2.6.git] / drivers / video / tegra / dc / ext / cursor.c
1 /*
2  * drivers/video/tegra/dc/ext/cursor.c
3  *
4  * Copyright (c) 2011-2012, NVIDIA CORPORATION, All rights reserved.
5  *
6  * Author: Robert Morell <rmorell@nvidia.com>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful, but WITHOUT
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
16  * more details.
17  */
18
19 #include <video/tegra_dc_ext.h>
20
21 #include "tegra_dc_ext_priv.h"
22
23 /* ugh */
24 #include "../dc_priv.h"
25 #include "../dc_reg.h"
26
27 int tegra_dc_ext_get_cursor(struct tegra_dc_ext_user *user)
28 {
29         struct tegra_dc_ext *ext = user->ext;
30         int ret = 0;
31
32         mutex_lock(&ext->cursor.lock);
33
34         if (!ext->cursor.user)
35                 ext->cursor.user = user;
36         else if (ext->cursor.user != user)
37                 ret = -EBUSY;
38
39         mutex_unlock(&ext->cursor.lock);
40
41         return ret;
42 }
43
44 int tegra_dc_ext_put_cursor(struct tegra_dc_ext_user *user)
45 {
46         struct tegra_dc_ext *ext = user->ext;
47         int ret = 0;
48
49         mutex_lock(&ext->cursor.lock);
50
51         if (ext->cursor.user == user)
52                 ext->cursor.user = 0;
53         else
54                 ret = -EACCES;
55
56         mutex_unlock(&ext->cursor.lock);
57
58         return ret;
59 }
60
61 static void set_cursor_image_hw(struct tegra_dc *dc,
62                                 struct tegra_dc_ext_cursor_image *args,
63                                 dma_addr_t phys_addr)
64 {
65         int clip_win;
66
67         tegra_dc_writel(dc,
68                 CURSOR_COLOR(args->foreground.r,
69                              args->foreground.g,
70                              args->foreground.b),
71                 DC_DISP_CURSOR_FOREGROUND);
72         tegra_dc_writel(dc,
73                 CURSOR_COLOR(args->background.r,
74                              args->background.g,
75                              args->background.b),
76                 DC_DISP_CURSOR_BACKGROUND);
77
78         BUG_ON(phys_addr & ~CURSOR_START_ADDR_MASK);
79
80         /* Get the cursor clip window number */
81         clip_win = CURSOR_CLIP_GET_WINDOW(tegra_dc_readl(dc,
82                                           DC_DISP_CURSOR_START_ADDR));
83
84         tegra_dc_writel(dc, CURSOR_CLIP_SHIFT_BITS(clip_win) |
85                 CURSOR_START_ADDR(((unsigned long) phys_addr)) |
86                 ((args->flags & TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_64x64) ?
87                         CURSOR_SIZE_64 : 0),
88                 DC_DISP_CURSOR_START_ADDR);
89 }
90
91 int tegra_dc_ext_set_cursor_image(struct tegra_dc_ext_user *user,
92                                   struct tegra_dc_ext_cursor_image *args)
93 {
94         struct tegra_dc_ext *ext = user->ext;
95         struct tegra_dc *dc = ext->dc;
96         struct nvmap_handle_ref *handle, *old_handle;
97         dma_addr_t phys_addr;
98         u32 size;
99         int ret;
100
101         if (!user->nvmap)
102                 return -EFAULT;
103
104         size = args->flags & (TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_32x32 |
105                               TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_64x64);
106
107         if (size != TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_32x32 &&
108             size !=  TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_64x64)
109                 return -EINVAL;
110
111         mutex_lock(&ext->cursor.lock);
112
113         if (ext->cursor.user != user) {
114                 ret = -EACCES;
115                 goto unlock;
116         }
117
118         if (!ext->enabled) {
119                 ret = -ENXIO;
120                 goto unlock;
121         }
122
123         old_handle = ext->cursor.cur_handle;
124
125         ret = tegra_dc_ext_pin_window(user, args->buff_id, &handle, &phys_addr);
126         if (ret)
127                 goto unlock;
128
129         ext->cursor.cur_handle = handle;
130
131         mutex_lock(&dc->lock);
132         tegra_dc_io_start(dc);
133         tegra_dc_hold_dc_out(dc);
134
135         set_cursor_image_hw(dc, args, phys_addr);
136
137         tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
138         tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
139
140         tegra_dc_release_dc_out(dc);
141         tegra_dc_io_end(dc);
142         /* XXX sync here? */
143
144         mutex_unlock(&dc->lock);
145
146         mutex_unlock(&ext->cursor.lock);
147
148         if (old_handle) {
149                 nvmap_unpin(ext->nvmap, old_handle);
150                 nvmap_free(ext->nvmap, old_handle);
151         }
152
153         return 0;
154
155 unlock:
156         mutex_unlock(&ext->cursor.lock);
157
158         return ret;
159 }
160
161 int tegra_dc_ext_set_cursor(struct tegra_dc_ext_user *user,
162                             struct tegra_dc_ext_cursor *args)
163 {
164         struct tegra_dc_ext *ext = user->ext;
165         struct tegra_dc *dc = ext->dc;
166         u32 win_options;
167         bool enable;
168         int ret;
169
170         mutex_lock(&ext->cursor.lock);
171
172         if (ext->cursor.user != user) {
173                 ret = -EACCES;
174                 goto unlock;
175         }
176
177         if (!ext->enabled) {
178                 ret = -ENXIO;
179                 goto unlock;
180         }
181
182         enable = !!(args->flags & TEGRA_DC_EXT_CURSOR_FLAGS_VISIBLE);
183
184         mutex_lock(&dc->lock);
185         tegra_dc_io_start(dc);
186         tegra_dc_hold_dc_out(dc);
187
188         win_options = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
189         if (!!(win_options & CURSOR_ENABLE) != enable) {
190                 win_options &= ~CURSOR_ENABLE;
191                 if (enable)
192                         win_options |= CURSOR_ENABLE;
193                 tegra_dc_writel(dc, win_options, DC_DISP_DISP_WIN_OPTIONS);
194         }
195
196         tegra_dc_writel(dc, CURSOR_POSITION(args->x, args->y),
197                 DC_DISP_CURSOR_POSITION);
198
199         tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
200         tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
201
202         /* TODO: need to sync here?  hopefully can avoid this, but need to
203          * figure out interaction w/ rest of GENERAL_ACT_REQ */
204
205         tegra_dc_release_dc_out(dc);
206         tegra_dc_io_end(dc);
207         mutex_unlock(&dc->lock);
208
209         mutex_unlock(&ext->cursor.lock);
210
211         return 0;
212
213 unlock:
214         mutex_unlock(&ext->cursor.lock);
215
216         return ret;
217 }
218
219 int tegra_dc_ext_cursor_clip(struct tegra_dc_ext_user *user,
220                             int *args)
221 {
222         struct tegra_dc_ext *ext = user->ext;
223         struct tegra_dc *dc = ext->dc;
224         int ret;
225         unsigned long reg_val;
226
227         mutex_lock(&ext->cursor.lock);
228
229         if (ext->cursor.user != user) {
230                 ret = -EACCES;
231                 goto unlock;
232         }
233
234         if (!ext->enabled) {
235                 ret = -ENXIO;
236                 goto unlock;
237         }
238
239         mutex_lock(&dc->lock);
240         tegra_dc_io_start(dc);
241         tegra_dc_hold_dc_out(dc);
242
243         reg_val = tegra_dc_readl(dc, DC_DISP_CURSOR_START_ADDR);
244         reg_val &= ~CURSOR_CLIP_SHIFT_BITS(3); /* Clear out the old value */
245         tegra_dc_writel(dc, reg_val | CURSOR_CLIP_SHIFT_BITS(*args),
246                         DC_DISP_CURSOR_START_ADDR);
247
248         tegra_dc_release_dc_out(dc);
249         tegra_dc_io_end(dc);
250         mutex_unlock(&dc->lock);
251
252         mutex_unlock(&ext->cursor.lock);
253
254         return 0;
255
256 unlock:
257         mutex_unlock(&ext->cursor.lock);
258
259         return ret;
260 }