35a86d477f17871abc9874ae2bd05a9d4c888dce
[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-2013, 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         unsigned long val;
66         int clip_win;
67
68         tegra_dc_writel(dc,
69                 CURSOR_COLOR(args->foreground.r,
70                              args->foreground.g,
71                              args->foreground.b),
72                 DC_DISP_CURSOR_FOREGROUND);
73         tegra_dc_writel(dc,
74                 CURSOR_COLOR(args->background.r,
75                              args->background.g,
76                              args->background.b),
77                 DC_DISP_CURSOR_BACKGROUND);
78
79         BUG_ON(phys_addr & ~CURSOR_START_ADDR_MASK);
80
81         switch (TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE(args->flags)) {
82         case TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_64x64:
83                 val = CURSOR_SIZE_64;
84                 break;
85         case TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_128x128:
86                 val = CURSOR_SIZE_128;
87                 break;
88         case TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_256x256:
89                 val = CURSOR_SIZE_256;
90                 break;
91         default:
92                 val = 0;
93         }
94
95         /* Get the cursor clip window number */
96         clip_win = CURSOR_CLIP_GET_WINDOW(tegra_dc_readl(dc,
97                                           DC_DISP_CURSOR_START_ADDR));
98         val |= clip_win;
99
100         tegra_dc_writel(dc,
101                 val | CURSOR_START_ADDR(((unsigned long) phys_addr)),
102                 DC_DISP_CURSOR_START_ADDR);
103
104         if (args->flags & TEGRA_DC_EXT_CURSOR_FLAGS_RGBA_NORMAL)
105                 tegra_dc_writel(dc,
106                                 CURSOR_MODE_SELECT(1),
107                                 DC_DISP_BLEND_CURSOR_CONTROL);
108         else
109                 tegra_dc_writel(dc,
110                                 CURSOR_MODE_SELECT(0),
111                                 DC_DISP_BLEND_CURSOR_CONTROL);
112 }
113
114 int tegra_dc_ext_set_cursor_image(struct tegra_dc_ext_user *user,
115                                   struct tegra_dc_ext_cursor_image *args)
116 {
117         struct tegra_dc_ext *ext = user->ext;
118         struct tegra_dc *dc = ext->dc;
119         struct nvmap_handle_ref *handle, *old_handle;
120         dma_addr_t phys_addr;
121         u32 size;
122         int ret;
123
124         if (!user->nvmap)
125                 return -EFAULT;
126
127         size = TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE(args->flags);
128 #if defined(CONFIG_ARCH_TEGRA_2x_SOC) || defined(CONFIG_ARCH_TEGRA_3x_SOC)
129         if (size != TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_32x32 &&
130             size !=  TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_64x64)
131                 return -EINVAL;
132 #else
133         if (size != TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_32x32 &&
134             size !=  TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_64x64 &&
135             size !=  TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_128x128 &&
136             size !=  TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_256x256)
137                 return -EINVAL;
138 #endif
139
140 #if defined(CONFIG_ARCH_TEGRA_2x_SOC) || defined(CONFIG_ARCH_TEGRA_3x_SOC)
141         if (args->flags & TEGRA_DC_EXT_CURSOR_FLAGS_RGBA_NORMAL)
142                 return -EINVAL;
143 #endif
144
145         mutex_lock(&ext->cursor.lock);
146
147         if (ext->cursor.user != user) {
148                 ret = -EACCES;
149                 goto unlock;
150         }
151
152         if (!ext->enabled) {
153                 ret = -ENXIO;
154                 goto unlock;
155         }
156
157         old_handle = ext->cursor.cur_handle;
158
159         ret = tegra_dc_ext_pin_window(user, args->buff_id, &handle, &phys_addr);
160         if (ret)
161                 goto unlock;
162
163         ext->cursor.cur_handle = handle;
164
165         mutex_lock(&dc->lock);
166         tegra_dc_get(dc);
167
168         set_cursor_image_hw(dc, args, phys_addr);
169
170         tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
171         tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
172
173         tegra_dc_put(dc);
174         /* XXX sync here? */
175
176         mutex_unlock(&dc->lock);
177
178         mutex_unlock(&ext->cursor.lock);
179
180         if (old_handle) {
181                 nvmap_unpin(ext->nvmap, old_handle);
182                 nvmap_free(ext->nvmap, old_handle);
183         }
184
185         return 0;
186
187 unlock:
188         mutex_unlock(&ext->cursor.lock);
189
190         return ret;
191 }
192
193 int tegra_dc_ext_set_cursor(struct tegra_dc_ext_user *user,
194                             struct tegra_dc_ext_cursor *args)
195 {
196         struct tegra_dc_ext *ext = user->ext;
197         struct tegra_dc *dc = ext->dc;
198         u32 val;
199         bool enable;
200         int ret;
201
202         mutex_lock(&ext->cursor.lock);
203
204         if (ext->cursor.user != user) {
205                 ret = -EACCES;
206                 goto unlock;
207         }
208
209         if (!ext->enabled) {
210                 ret = -ENXIO;
211                 goto unlock;
212         }
213
214         enable = !!(args->flags & TEGRA_DC_EXT_CURSOR_FLAGS_VISIBLE);
215
216         mutex_lock(&dc->lock);
217         tegra_dc_get(dc);
218
219         val = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
220         if (!!(val & CURSOR_ENABLE) != enable) {
221                 val &= ~CURSOR_ENABLE;
222                 if (enable)
223                         val |= CURSOR_ENABLE;
224                 tegra_dc_writel(dc, val, DC_DISP_DISP_WIN_OPTIONS);
225         }
226
227         tegra_dc_writel(dc, CURSOR_POSITION(args->x, args->y),
228                 DC_DISP_CURSOR_POSITION);
229
230         tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
231         tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
232
233         /* TODO: need to sync here?  hopefully can avoid this, but need to
234          * figure out interaction w/ rest of GENERAL_ACT_REQ */
235
236         tegra_dc_put(dc);
237         mutex_unlock(&dc->lock);
238
239         mutex_unlock(&ext->cursor.lock);
240
241         return 0;
242
243 unlock:
244         mutex_unlock(&ext->cursor.lock);
245
246         return ret;
247 }
248
249 int tegra_dc_ext_cursor_clip(struct tegra_dc_ext_user *user,
250                             int *args)
251 {
252         struct tegra_dc_ext *ext = user->ext;
253         struct tegra_dc *dc = ext->dc;
254         int ret;
255         unsigned long reg_val;
256
257         mutex_lock(&ext->cursor.lock);
258
259         if (ext->cursor.user != user) {
260                 ret = -EACCES;
261                 goto unlock;
262         }
263
264         if (!ext->enabled) {
265                 ret = -ENXIO;
266                 goto unlock;
267         }
268
269         mutex_lock(&dc->lock);
270         tegra_dc_get(dc);
271
272         reg_val = tegra_dc_readl(dc, DC_DISP_CURSOR_START_ADDR);
273         reg_val &= ~CURSOR_CLIP_SHIFT_BITS(3); /* Clear out the old value */
274         tegra_dc_writel(dc, reg_val | CURSOR_CLIP_SHIFT_BITS(*args),
275                         DC_DISP_CURSOR_START_ADDR);
276
277         tegra_dc_put(dc);
278         mutex_unlock(&dc->lock);
279
280         mutex_unlock(&ext->cursor.lock);
281
282         return 0;
283
284 unlock:
285         mutex_unlock(&ext->cursor.lock);
286
287         return ret;
288 }