]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/blob - drivers/video/tegra/dc/cursor.c
video: tegra: dc: cleanup cursor suspend code
[sojka/nv-tegra/linux-3.10.git] / drivers / video / tegra / dc / cursor.c
1 /*
2  * drivers/video/tegra/dc/cursor.c
3  *
4  * Copyright (c) 2011-2016, NVIDIA CORPORATION, All rights reserved.
5  *
6  * Author:
7  *  Robert Morell <rmorell@nvidia.com>
8  *  Jon Mayo <jmayo@nvidia.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/module.h>
22 #include <linux/kernel.h>
23 #include <linux/errno.h>
24 #include <linux/mutex.h>
25
26 #include "dc_priv.h"
27 #include "dc_reg.h"
28
29 /* modify val with cursor field set for a given size.
30  * ignore val if it is NULL.
31  * return non-zero on error, and clear val. */
32 static inline int cursor_size_value(enum tegra_dc_cursor_size size, u32 *val)
33 {
34         u32 scratch = 0;
35         if (!val)
36                 val = &scratch;
37         switch (size) {
38         case TEGRA_DC_CURSOR_SIZE_32X32:
39                 *val |= CURSOR_SIZE_32;
40                 return 0;
41         case TEGRA_DC_CURSOR_SIZE_64X64:
42                 *val |= CURSOR_SIZE_64;
43                 return 0;
44 #if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC)
45         case TEGRA_DC_CURSOR_SIZE_128X128:
46                 *val |= CURSOR_SIZE_128;
47                 return 0;
48         case TEGRA_DC_CURSOR_SIZE_256X256:
49                 *val |= CURSOR_SIZE_256;
50                 return 0;
51 #endif
52         }
53         *val = 0;
54         return -EINVAL;
55 }
56
57 /* modify val with cursor format.
58  * ignore val if it is NULL.
59  * return non-zero on error, and clear val. */
60 static inline u32 cursor_format_value(enum tegra_dc_cursor_format format,
61         u32 *val)
62 {
63         u32 scratch = 0;
64         if (!val)
65                 val = &scratch;
66         switch (format) {
67         case TEGRA_DC_CURSOR_FORMAT_2BIT_LEGACY:
68                 /* MODE_SELECT_LEGACY */
69                 *val |= CURSOR_MODE_SELECT(0);
70                 return 0;
71 #if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && \
72         !defined(CONFIG_ARCH_TEGRA_3x_SOC)
73         case TEGRA_DC_CURSOR_FORMAT_RGBA_NON_PREMULT_ALPHA:
74 # if !defined(CONFIG_TEGRA_NVDISPLAY)
75                 /* MODE_SELECT_NORMAL */
76                 *val |= CURSOR_MODE_SELECT(1);
77 #endif
78 # if !defined(CONFIG_ARCH_TEGRA_11x_SOC)
79                 /* CURSOR_ALPHA, K1_TIMES_SRC, NEG_K1_TIMES_SRC */
80                 *val |= CURSOR_ALPHA(255) | CURSOR_DST_BLEND_FACTOR_SELECT(2);
81                 *val |= CURSOR_SRC_BLEND_FACTOR_SELECT(1);
82 # endif
83                 return 0;
84 #endif
85 #if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && \
86         !defined(CONFIG_ARCH_TEGRA_3x_SOC) && \
87         !defined(CONFIG_ARCH_TEGRA_11x_SOC)
88         case TEGRA_DC_CURSOR_FORMAT_RGBA_PREMULT_ALPHA:
89                 *val |= CURSOR_MODE_SELECT(1);
90                 *val |= CURSOR_ALPHA(255) | CURSOR_DST_BLEND_FACTOR_SELECT(2);
91                 *val |= CURSOR_SRC_BLEND_FACTOR_SELECT(0);
92                 return 0;
93 #endif
94 #if defined(CONFIG_TEGRA_NVDISPLAY)
95         case TEGRA_DC_CURSOR_FORMAT_RGBA_XOR:
96                 /* MODE_SELECT_NORMAL */
97                 *val |= CURSOR_COMP_MODE(1);
98                 /* CURSOR_ALPHA, K1, NEG_K1_TIMES_SRC */
99                 *val |= CURSOR_ALPHA(255) | CURSOR_DST_BLEND_FACTOR_SELECT(1);
100                 *val |= CURSOR_SRC_BLEND_FACTOR_SELECT(1);
101                 return 0;
102 #endif
103         default:
104                 pr_err("%s: invalid format 0x%x\n", __func__, format);
105                 break;
106         }
107         *val = 0;
108         return -EINVAL;
109 }
110
111 static unsigned int set_cursor_start_addr(struct tegra_dc *dc,
112         enum tegra_dc_cursor_size size, dma_addr_t phys_addr)
113 {
114         u32 val = 0;
115         int clip_win;
116
117         BUG_ON(phys_addr & ~CURSOR_START_ADDR_MASK);
118
119         dc->cursor.phys_addr = phys_addr;
120         dc->cursor.size = size;
121         /* this should not fail, as tegra_dc_cursor_image() checks the size */
122         if (WARN(cursor_size_value(size, &val), "invalid cursor size."))
123                 return 0;
124
125         clip_win = dc->cursor.clip_win;
126         val |= CURSOR_CLIP_SHIFT_BITS(clip_win);
127 #if defined(CONFIG_ARCH_TEGRA_2x_SOC) || defined(CONFIG_ARCH_TEGRA_3x_SOC) || \
128         defined(CONFIG_ARCH_TEGRA_11x_SOC) || defined(CONFIG_ARCH_TEGRA_14x_SOC)
129         tegra_dc_writel(dc, val | CURSOR_START_ADDR(((unsigned long)phys_addr)),
130                         DC_DISP_CURSOR_START_ADDR);
131 #else
132         /* TODO: check calculation with HW */
133         tegra_dc_writel(dc, (u32)(CURSOR_START_ADDR_HI(phys_addr)),
134                         DC_DISP_CURSOR_START_ADDR_HI);
135         tegra_dc_writel(dc, (u32)(val | CURSOR_START_ADDR_LOW(phys_addr)),
136                         DC_DISP_CURSOR_START_ADDR);
137 #endif
138
139 #if defined(CONFIG_TEGRA_NVDISPLAY)
140         WARN_ON((phys_addr & 0x3FF) != 0);
141 #endif
142
143 #if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && \
144         !defined(CONFIG_ARCH_TEGRA_3x_SOC) && \
145         !defined(CONFIG_ARCH_TEGRA_11x_SOC) && \
146         !defined(CONFIG_ARCH_TEGRA_14x_SOC)
147         tegra_dc_writel(dc, CURSOR_UPDATE, DC_CMD_STATE_CONTROL);
148         tegra_dc_writel(dc, CURSOR_ACT_REQ, DC_CMD_STATE_CONTROL);
149         return 0;
150 #else
151         return 1;
152 #endif
153 }
154
155 static int set_cursor_position(struct tegra_dc *dc, s16 x, s16 y)
156 {
157 #if defined(CONFIG_TEGRA_NVDISPLAY)
158         nvdisp_set_cursor_position(dc, x, y);
159 #else
160         tegra_dc_writel(dc, CURSOR_POSITION(x, y), DC_DISP_CURSOR_POSITION);
161 #endif
162
163 #if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && \
164         !defined(CONFIG_ARCH_TEGRA_3x_SOC) && \
165         !defined(CONFIG_ARCH_TEGRA_11x_SOC) && \
166         !defined(CONFIG_ARCH_TEGRA_14x_SOC)
167         tegra_dc_writel(dc, CURSOR_UPDATE, DC_CMD_STATE_CONTROL);
168         tegra_dc_writel(dc, CURSOR_ACT_REQ, DC_CMD_STATE_CONTROL);
169         return 0;
170 #else
171         return 1;
172 #endif
173 }
174
175 static int set_cursor_activation_control(struct tegra_dc *dc)
176 {
177 #if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && \
178         !defined(CONFIG_ARCH_TEGRA_3x_SOC) && \
179         !defined(CONFIG_ARCH_TEGRA_11x_SOC) && \
180         !defined(CONFIG_ARCH_TEGRA_14x_SOC) && \
181         !defined(CONFIG_TEGRA_NVDISPLAY)
182         u32 reg = tegra_dc_readl(dc, DC_CMD_REG_ACT_CONTROL);
183
184         if ((reg & (1 << CURSOR_ACT_CNTR_SEL)) ==
185             (CURSOR_ACT_CNTR_SEL_V << CURSOR_ACT_CNTR_SEL)) {
186                 reg &= ~(1 << CURSOR_ACT_CNTR_SEL);
187                 reg |= (CURSOR_ACT_CNTR_SEL_V << CURSOR_ACT_CNTR_SEL);
188                 tegra_dc_writel(dc, reg, DC_CMD_REG_ACT_CONTROL);
189                 return 1;
190         }
191 #endif
192         return 0;
193 }
194
195 static int set_cursor_enable(struct tegra_dc *dc, bool enable)
196 {
197         u32 val = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
198         if (!!(val & CURSOR_ENABLE) != enable) {
199                 val &= ~CURSOR_ENABLE;
200                 if (enable)
201                         val |= CURSOR_ENABLE;
202                 tegra_dc_writel(dc, val, DC_DISP_DISP_WIN_OPTIONS);
203                 return 1;
204         }
205         dc->cursor.enabled = enable;
206         return 0;
207 }
208
209 static int set_cursor_blend(struct tegra_dc *dc, u32 format)
210 {
211         u32 val = tegra_dc_readl(dc, DC_DISP_BLEND_CURSOR_CONTROL);
212
213         u32 newval = WINH_CURS_SELECT(0);
214
215         /* this should not fail, as tegra_dc_cursor_image() checks the format */
216         if (WARN(cursor_format_value(format, &newval), "invalid cursor format"))
217                 return 0;
218
219         if (val != newval) {
220                 tegra_dc_writel(dc, newval, DC_DISP_BLEND_CURSOR_CONTROL);
221                 return 1;
222         }
223         dc->cursor.format = format;
224
225         return 0;
226 }
227
228 static int set_cursor_fg_bg(struct tegra_dc *dc, u32 fg, u32 bg)
229 {
230         int general_update_needed = 0;
231
232 #if !defined(CONFIG_TEGRA_NVDISPLAY)
233         /* TODO: check fg/bg against data structure, don't read the HW */
234         if (fg != tegra_dc_readl(dc, DC_DISP_CURSOR_FOREGROUND)) {
235                 tegra_dc_writel(dc, fg, DC_DISP_CURSOR_FOREGROUND);
236                 general_update_needed |= 1;
237         }
238
239         if (bg != tegra_dc_readl(dc, DC_DISP_CURSOR_BACKGROUND)) {
240                 tegra_dc_writel(dc, bg, DC_DISP_CURSOR_BACKGROUND);
241                 general_update_needed |= 1;
242         }
243         dc->cursor.fg = fg;
244         dc->cursor.bg = bg;
245 #endif
246
247         return general_update_needed;
248 }
249
250 static void tegra_dc_cursor_do_update(struct tegra_dc *dc,
251         bool need_general_update)
252 {
253 #if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && \
254         !defined(CONFIG_ARCH_TEGRA_3x_SOC) && \
255         !defined(CONFIG_ARCH_TEGRA_11x_SOC) && \
256         !defined(CONFIG_ARCH_TEGRA_14x_SOC)
257         tegra_dc_writel(dc, CURSOR_UPDATE, DC_CMD_STATE_CONTROL);
258         tegra_dc_writel(dc, CURSOR_ACT_REQ, DC_CMD_STATE_CONTROL);
259 #else
260         need_general_update = true;
261 #endif
262         if (need_general_update) {
263                 tegra_dc_writel(dc, GENERAL_UPDATE, DC_CMD_STATE_CONTROL);
264                 tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
265         }
266 }
267
268 static int tegra_dc_cursor_program(struct tegra_dc *dc)
269 {
270         bool need_general_update = false;
271
272         if (!dc->enabled)
273                 return 0;
274         /* these checks are redundant */
275         if (cursor_size_value(dc->cursor.size, NULL))
276                 return -EINVAL;
277         if (cursor_format_value(dc->cursor.format, NULL))
278                 return -EINVAL;
279
280         mutex_lock(&dc->lock);
281         if (!dc->cursor.dirty) {
282                 mutex_unlock(&dc->lock);
283                 return 0;
284         }
285         tegra_dc_get(dc);
286
287         need_general_update |= set_cursor_start_addr(dc, dc->cursor.size,
288                 dc->cursor.phys_addr);
289
290         need_general_update |= set_cursor_fg_bg(dc,
291                 dc->cursor.fg, dc->cursor.bg);
292
293         need_general_update |= set_cursor_blend(dc, dc->cursor.format);
294
295         need_general_update |= set_cursor_enable(dc, dc->cursor.enabled);
296
297         need_general_update |= set_cursor_position(dc,
298                 dc->cursor.x, dc->cursor.y);
299
300         need_general_update |= set_cursor_activation_control(dc);
301
302         tegra_dc_cursor_do_update(dc, need_general_update);
303
304         tegra_dc_put(dc);
305         dc->cursor.dirty = false;
306         mutex_unlock(&dc->lock);
307
308         return 0;
309 }
310
311 int tegra_dc_cursor_image(struct tegra_dc *dc,
312         enum tegra_dc_cursor_format format, enum tegra_dc_cursor_size size,
313         u32 fg, u32 bg, dma_addr_t phys_addr)
314 {
315         if (cursor_size_value(size, NULL))
316                 return -EINVAL;
317
318         if (cursor_format_value(format, NULL))
319                 return -EINVAL;
320
321         mutex_lock(&dc->lock);
322         dc->cursor.fg = fg;
323         dc->cursor.bg = bg;
324         dc->cursor.size = size;
325         dc->cursor.format = format;
326         dc->cursor.phys_addr = phys_addr;
327         dc->cursor.dirty = true;
328         mutex_unlock(&dc->lock);
329
330         return tegra_dc_cursor_program(dc);
331 }
332
333 int tegra_dc_cursor_set(struct tegra_dc *dc, bool enable, int x, int y)
334 {
335         mutex_lock(&dc->lock);
336         dc->cursor.x = x;
337         dc->cursor.y = y;
338         dc->cursor.enabled = enable;
339         dc->cursor.dirty = true;
340         mutex_unlock(&dc->lock);
341
342         return tegra_dc_cursor_program(dc);
343 }
344
345 /* clip:
346  * 0 - display
347  * 1 - window A
348  * 2 - window B
349  * 3 - window C
350  */
351 int tegra_dc_cursor_clip(struct tegra_dc *dc, unsigned clip)
352 {
353         mutex_lock(&dc->lock);
354         dc->cursor.clip_win = clip;
355         dc->cursor.dirty = true;
356         mutex_unlock(&dc->lock);
357
358         return tegra_dc_cursor_program(dc);
359 }
360
361 /* disable the cursor on suspend. but leave the state unmodified */
362 int tegra_dc_cursor_suspend(struct tegra_dc *dc)
363 {
364         if (!dc->enabled)
365                 return 0;
366         mutex_lock(&dc->lock);
367         tegra_dc_get(dc);
368         set_cursor_enable(dc, false);
369         tegra_dc_cursor_do_update(dc, true);
370         dc->cursor.dirty = true;
371         tegra_dc_put(dc);
372         mutex_unlock(&dc->lock);
373         return 0;
374 }
375
376 /* restore the state */
377 int tegra_dc_cursor_resume(struct tegra_dc *dc)
378 {
379         return tegra_dc_cursor_program(dc);
380 }