Linux-libre 5.4.48-gnu
[librecmc/linux-libre.git] / drivers / gpu / drm / radeon / radeon_cursor.c
1 /*
2  * Copyright 2007-8 Advanced Micro Devices, Inc.
3  * Copyright 2008 Red Hat Inc.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
19  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21  * OTHER DEALINGS IN THE SOFTWARE.
22  *
23  * Authors: Dave Airlie
24  *          Alex Deucher
25  */
26
27 #include <drm/drm_device.h>
28 #include <drm/radeon_drm.h>
29
30 #include "radeon.h"
31
32 static void radeon_lock_cursor(struct drm_crtc *crtc, bool lock)
33 {
34         struct radeon_device *rdev = crtc->dev->dev_private;
35         struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
36         uint32_t cur_lock;
37
38         if (ASIC_IS_DCE4(rdev)) {
39                 cur_lock = RREG32(EVERGREEN_CUR_UPDATE + radeon_crtc->crtc_offset);
40                 if (lock)
41                         cur_lock |= EVERGREEN_CURSOR_UPDATE_LOCK;
42                 else
43                         cur_lock &= ~EVERGREEN_CURSOR_UPDATE_LOCK;
44                 WREG32(EVERGREEN_CUR_UPDATE + radeon_crtc->crtc_offset, cur_lock);
45         } else if (ASIC_IS_AVIVO(rdev)) {
46                 cur_lock = RREG32(AVIVO_D1CUR_UPDATE + radeon_crtc->crtc_offset);
47                 if (lock)
48                         cur_lock |= AVIVO_D1CURSOR_UPDATE_LOCK;
49                 else
50                         cur_lock &= ~AVIVO_D1CURSOR_UPDATE_LOCK;
51                 WREG32(AVIVO_D1CUR_UPDATE + radeon_crtc->crtc_offset, cur_lock);
52         } else {
53                 cur_lock = RREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset);
54                 if (lock)
55                         cur_lock |= RADEON_CUR_LOCK;
56                 else
57                         cur_lock &= ~RADEON_CUR_LOCK;
58                 WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, cur_lock);
59         }
60 }
61
62 static void radeon_hide_cursor(struct drm_crtc *crtc)
63 {
64         struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
65         struct radeon_device *rdev = crtc->dev->dev_private;
66
67         if (ASIC_IS_DCE4(rdev)) {
68                 WREG32_IDX(EVERGREEN_CUR_CONTROL + radeon_crtc->crtc_offset,
69                            EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT) |
70                            EVERGREEN_CURSOR_URGENT_CONTROL(EVERGREEN_CURSOR_URGENT_1_2));
71         } else if (ASIC_IS_AVIVO(rdev)) {
72                 WREG32_IDX(AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset,
73                            (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT));
74         } else {
75                 u32 reg;
76                 switch (radeon_crtc->crtc_id) {
77                 case 0:
78                         reg = RADEON_CRTC_GEN_CNTL;
79                         break;
80                 case 1:
81                         reg = RADEON_CRTC2_GEN_CNTL;
82                         break;
83                 default:
84                         return;
85                 }
86                 WREG32_IDX(reg, RREG32_IDX(reg) & ~RADEON_CRTC_CUR_EN);
87         }
88 }
89
90 static void radeon_show_cursor(struct drm_crtc *crtc)
91 {
92         struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
93         struct radeon_device *rdev = crtc->dev->dev_private;
94
95         if (radeon_crtc->cursor_out_of_bounds)
96                 return;
97
98         if (ASIC_IS_DCE4(rdev)) {
99                 WREG32(EVERGREEN_CUR_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset,
100                        upper_32_bits(radeon_crtc->cursor_addr));
101                 WREG32(EVERGREEN_CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
102                        lower_32_bits(radeon_crtc->cursor_addr));
103                 WREG32(RADEON_MM_INDEX, EVERGREEN_CUR_CONTROL + radeon_crtc->crtc_offset);
104                 WREG32(RADEON_MM_DATA, EVERGREEN_CURSOR_EN |
105                        EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT) |
106                        EVERGREEN_CURSOR_URGENT_CONTROL(EVERGREEN_CURSOR_URGENT_1_2));
107         } else if (ASIC_IS_AVIVO(rdev)) {
108                 if (rdev->family >= CHIP_RV770) {
109                         if (radeon_crtc->crtc_id)
110                                 WREG32(R700_D2CUR_SURFACE_ADDRESS_HIGH,
111                                        upper_32_bits(radeon_crtc->cursor_addr));
112                         else
113                                 WREG32(R700_D1CUR_SURFACE_ADDRESS_HIGH,
114                                        upper_32_bits(radeon_crtc->cursor_addr));
115                 }
116
117                 WREG32(AVIVO_D1CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
118                        lower_32_bits(radeon_crtc->cursor_addr));
119                 WREG32(RADEON_MM_INDEX, AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset);
120                 WREG32(RADEON_MM_DATA, AVIVO_D1CURSOR_EN |
121                        (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT));
122         } else {
123                 /* offset is from DISP(2)_BASE_ADDRESS */
124                 WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset,
125                        radeon_crtc->cursor_addr - radeon_crtc->legacy_display_base_addr);
126
127                 switch (radeon_crtc->crtc_id) {
128                 case 0:
129                         WREG32(RADEON_MM_INDEX, RADEON_CRTC_GEN_CNTL);
130                         break;
131                 case 1:
132                         WREG32(RADEON_MM_INDEX, RADEON_CRTC2_GEN_CNTL);
133                         break;
134                 default:
135                         return;
136                 }
137
138                 WREG32_P(RADEON_MM_DATA, (RADEON_CRTC_CUR_EN |
139                                           (RADEON_CRTC_CUR_MODE_24BPP << RADEON_CRTC_CUR_MODE_SHIFT)),
140                          ~(RADEON_CRTC_CUR_EN | RADEON_CRTC_CUR_MODE_MASK));
141         }
142 }
143
144 static int radeon_cursor_move_locked(struct drm_crtc *crtc, int x, int y)
145 {
146         struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
147         struct radeon_device *rdev = crtc->dev->dev_private;
148         int xorigin = 0, yorigin = 0;
149         int w = radeon_crtc->cursor_width;
150
151         radeon_crtc->cursor_x = x;
152         radeon_crtc->cursor_y = y;
153
154         if (ASIC_IS_AVIVO(rdev)) {
155                 /* avivo cursor are offset into the total surface */
156                 x += crtc->x;
157                 y += crtc->y;
158         }
159
160         if (x < 0)
161                 xorigin = min(-x, radeon_crtc->max_cursor_width - 1);
162         if (y < 0)
163                 yorigin = min(-y, radeon_crtc->max_cursor_height - 1);
164
165         if (!ASIC_IS_AVIVO(rdev)) {
166                 x += crtc->x;
167                 y += crtc->y;
168         }
169         DRM_DEBUG("x %d y %d c->x %d c->y %d\n", x, y, crtc->x, crtc->y);
170
171         /* fixed on DCE6 and newer */
172         if (ASIC_IS_AVIVO(rdev) && !ASIC_IS_DCE6(rdev)) {
173                 int i = 0;
174                 struct drm_crtc *crtc_p;
175
176                 /*
177                  * avivo cursor image can't end on 128 pixel boundary or
178                  * go past the end of the frame if both crtcs are enabled
179                  *
180                  * NOTE: It is safe to access crtc->enabled of other crtcs
181                  * without holding either the mode_config lock or the other
182                  * crtc's lock as long as write access to this flag _always_
183                  * grabs all locks.
184                  */
185                 list_for_each_entry(crtc_p, &crtc->dev->mode_config.crtc_list, head) {
186                         if (crtc_p->enabled)
187                                 i++;
188                 }
189                 if (i > 1) {
190                         int cursor_end, frame_end;
191
192                         cursor_end = x + w;
193                         frame_end = crtc->x + crtc->mode.crtc_hdisplay;
194                         if (cursor_end >= frame_end) {
195                                 w = w - (cursor_end - frame_end);
196                                 if (!(frame_end & 0x7f))
197                                         w--;
198                         } else if (cursor_end <= 0) {
199                                 goto out_of_bounds;
200                         } else if (!(cursor_end & 0x7f)) {
201                                 w--;
202                         }
203                         if (w <= 0) {
204                                 goto out_of_bounds;
205                         }
206                 }
207         }
208
209         if (x <= (crtc->x - w) || y <= (crtc->y - radeon_crtc->cursor_height) ||
210             x >= (crtc->x + crtc->mode.hdisplay) ||
211             y >= (crtc->y + crtc->mode.vdisplay))
212                 goto out_of_bounds;
213
214         x += xorigin;
215         y += yorigin;
216
217         if (ASIC_IS_DCE4(rdev)) {
218                 WREG32(EVERGREEN_CUR_POSITION + radeon_crtc->crtc_offset, (x << 16) | y);
219                 WREG32(EVERGREEN_CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin);
220                 WREG32(EVERGREEN_CUR_SIZE + radeon_crtc->crtc_offset,
221                        ((w - 1) << 16) | (radeon_crtc->cursor_height - 1));
222         } else if (ASIC_IS_AVIVO(rdev)) {
223                 WREG32(AVIVO_D1CUR_POSITION + radeon_crtc->crtc_offset, (x << 16) | y);
224                 WREG32(AVIVO_D1CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin);
225                 WREG32(AVIVO_D1CUR_SIZE + radeon_crtc->crtc_offset,
226                        ((w - 1) << 16) | (radeon_crtc->cursor_height - 1));
227         } else {
228                 x -= crtc->x;
229                 y -= crtc->y;
230
231                 if (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN)
232                         y *= 2;
233
234                 WREG32(RADEON_CUR_HORZ_VERT_OFF + radeon_crtc->crtc_offset,
235                        (RADEON_CUR_LOCK
236                         | (xorigin << 16)
237                         | yorigin));
238                 WREG32(RADEON_CUR_HORZ_VERT_POSN + radeon_crtc->crtc_offset,
239                        (RADEON_CUR_LOCK
240                         | (x << 16)
241                         | y));
242                 /* offset is from DISP(2)_BASE_ADDRESS */
243                 WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset,
244                        radeon_crtc->cursor_addr - radeon_crtc->legacy_display_base_addr +
245                        yorigin * 256);
246         }
247
248         if (radeon_crtc->cursor_out_of_bounds) {
249                 radeon_crtc->cursor_out_of_bounds = false;
250                 if (radeon_crtc->cursor_bo)
251                         radeon_show_cursor(crtc);
252         }
253
254         return 0;
255
256  out_of_bounds:
257         if (!radeon_crtc->cursor_out_of_bounds) {
258                 radeon_hide_cursor(crtc);
259                 radeon_crtc->cursor_out_of_bounds = true;
260         }
261         return 0;
262 }
263
264 int radeon_crtc_cursor_move(struct drm_crtc *crtc,
265                             int x, int y)
266 {
267         int ret;
268
269         radeon_lock_cursor(crtc, true);
270         ret = radeon_cursor_move_locked(crtc, x, y);
271         radeon_lock_cursor(crtc, false);
272
273         return ret;
274 }
275
276 int radeon_crtc_cursor_set2(struct drm_crtc *crtc,
277                             struct drm_file *file_priv,
278                             uint32_t handle,
279                             uint32_t width,
280                             uint32_t height,
281                             int32_t hot_x,
282                             int32_t hot_y)
283 {
284         struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
285         struct radeon_device *rdev = crtc->dev->dev_private;
286         struct drm_gem_object *obj;
287         struct radeon_bo *robj;
288         int ret;
289
290         if (!handle) {
291                 /* turn off cursor */
292                 radeon_hide_cursor(crtc);
293                 obj = NULL;
294                 goto unpin;
295         }
296
297         if ((width > radeon_crtc->max_cursor_width) ||
298             (height > radeon_crtc->max_cursor_height)) {
299                 DRM_ERROR("bad cursor width or height %d x %d\n", width, height);
300                 return -EINVAL;
301         }
302
303         obj = drm_gem_object_lookup(file_priv, handle);
304         if (!obj) {
305                 DRM_ERROR("Cannot find cursor object %x for crtc %d\n", handle, radeon_crtc->crtc_id);
306                 return -ENOENT;
307         }
308
309         robj = gem_to_radeon_bo(obj);
310         ret = radeon_bo_reserve(robj, false);
311         if (ret != 0) {
312                 drm_gem_object_put_unlocked(obj);
313                 return ret;
314         }
315         /* Only 27 bit offset for legacy cursor */
316         ret = radeon_bo_pin_restricted(robj, RADEON_GEM_DOMAIN_VRAM,
317                                        ASIC_IS_AVIVO(rdev) ? 0 : 1 << 27,
318                                        &radeon_crtc->cursor_addr);
319         radeon_bo_unreserve(robj);
320         if (ret) {
321                 DRM_ERROR("Failed to pin new cursor BO (%d)\n", ret);
322                 drm_gem_object_put_unlocked(obj);
323                 return ret;
324         }
325
326         radeon_lock_cursor(crtc, true);
327
328         if (width != radeon_crtc->cursor_width ||
329             height != radeon_crtc->cursor_height ||
330             hot_x != radeon_crtc->cursor_hot_x ||
331             hot_y != radeon_crtc->cursor_hot_y) {
332                 int x, y;
333
334                 x = radeon_crtc->cursor_x + radeon_crtc->cursor_hot_x - hot_x;
335                 y = radeon_crtc->cursor_y + radeon_crtc->cursor_hot_y - hot_y;
336
337                 radeon_crtc->cursor_width = width;
338                 radeon_crtc->cursor_height = height;
339                 radeon_crtc->cursor_hot_x = hot_x;
340                 radeon_crtc->cursor_hot_y = hot_y;
341
342                 radeon_cursor_move_locked(crtc, x, y);
343         }
344
345         radeon_show_cursor(crtc);
346
347         radeon_lock_cursor(crtc, false);
348
349 unpin:
350         if (radeon_crtc->cursor_bo) {
351                 struct radeon_bo *robj = gem_to_radeon_bo(radeon_crtc->cursor_bo);
352                 ret = radeon_bo_reserve(robj, false);
353                 if (likely(ret == 0)) {
354                         radeon_bo_unpin(robj);
355                         radeon_bo_unreserve(robj);
356                 }
357                 drm_gem_object_put_unlocked(radeon_crtc->cursor_bo);
358         }
359
360         radeon_crtc->cursor_bo = obj;
361         return 0;
362 }
363
364 /**
365  * radeon_cursor_reset - Re-set the current cursor, if any.
366  *
367  * @crtc: drm crtc
368  *
369  * If the CRTC passed in currently has a cursor assigned, this function
370  * makes sure it's visible.
371  */
372 void radeon_cursor_reset(struct drm_crtc *crtc)
373 {
374         struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
375
376         if (radeon_crtc->cursor_bo) {
377                 radeon_lock_cursor(crtc, true);
378
379                 radeon_cursor_move_locked(crtc, radeon_crtc->cursor_x,
380                                           radeon_crtc->cursor_y);
381
382                 radeon_show_cursor(crtc);
383
384                 radeon_lock_cursor(crtc, false);
385         }
386 }