Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
radeon_cursor.c
Go to the documentation of this file.
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 #include <drm/drmP.h>
27 #include <drm/radeon_drm.h>
28 #include "radeon.h"
29 
30 #define CURSOR_WIDTH 64
31 #define CURSOR_HEIGHT 64
32 
33 static void radeon_lock_cursor(struct drm_crtc *crtc, bool lock)
34 {
35  struct radeon_device *rdev = crtc->dev->dev_private;
36  struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
37  uint32_t cur_lock;
38 
39  if (ASIC_IS_DCE4(rdev)) {
40  cur_lock = RREG32(EVERGREEN_CUR_UPDATE + radeon_crtc->crtc_offset);
41  if (lock)
42  cur_lock |= EVERGREEN_CURSOR_UPDATE_LOCK;
43  else
44  cur_lock &= ~EVERGREEN_CURSOR_UPDATE_LOCK;
45  WREG32(EVERGREEN_CUR_UPDATE + radeon_crtc->crtc_offset, cur_lock);
46  } else if (ASIC_IS_AVIVO(rdev)) {
47  cur_lock = RREG32(AVIVO_D1CUR_UPDATE + radeon_crtc->crtc_offset);
48  if (lock)
49  cur_lock |= AVIVO_D1CURSOR_UPDATE_LOCK;
50  else
51  cur_lock &= ~AVIVO_D1CURSOR_UPDATE_LOCK;
52  WREG32(AVIVO_D1CUR_UPDATE + radeon_crtc->crtc_offset, cur_lock);
53  } else {
54  cur_lock = RREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset);
55  if (lock)
56  cur_lock |= RADEON_CUR_LOCK;
57  else
58  cur_lock &= ~RADEON_CUR_LOCK;
59  WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, cur_lock);
60  }
61 }
62 
63 static void radeon_hide_cursor(struct drm_crtc *crtc)
64 {
65  struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
66  struct radeon_device *rdev = crtc->dev->dev_private;
67 
68  if (ASIC_IS_DCE4(rdev)) {
72  } else if (ASIC_IS_AVIVO(rdev)) {
75  } else {
76  switch (radeon_crtc->crtc_id) {
77  case 0:
79  break;
80  case 1:
82  break;
83  default:
84  return;
85  }
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 (ASIC_IS_DCE4(rdev)) {
100  } else if (ASIC_IS_AVIVO(rdev)) {
104  } else {
105  switch (radeon_crtc->crtc_id) {
106  case 0:
108  break;
109  case 1:
111  break;
112  default:
113  return;
114  }
115 
119  }
120 }
121 
122 static void radeon_set_cursor(struct drm_crtc *crtc, struct drm_gem_object *obj,
123  uint64_t gpu_addr)
124 {
125  struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
126  struct radeon_device *rdev = crtc->dev->dev_private;
127 
128  if (ASIC_IS_DCE4(rdev)) {
130  upper_32_bits(gpu_addr));
132  gpu_addr & 0xffffffff);
133  } else if (ASIC_IS_AVIVO(rdev)) {
134  if (rdev->family >= CHIP_RV770) {
135  if (radeon_crtc->crtc_id)
137  else
139  }
141  gpu_addr & 0xffffffff);
142  } else {
143  radeon_crtc->legacy_cursor_offset = gpu_addr - radeon_crtc->legacy_display_base_addr;
144  /* offset is from DISP(2)_BASE_ADDRESS */
145  WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, radeon_crtc->legacy_cursor_offset);
146  }
147 }
148 
150  struct drm_file *file_priv,
152  uint32_t width,
154 {
155  struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
156  struct radeon_device *rdev = crtc->dev->dev_private;
157  struct drm_gem_object *obj;
158  struct radeon_bo *robj;
159  uint64_t gpu_addr;
160  int ret;
161 
162  if (!handle) {
163  /* turn off cursor */
164  radeon_hide_cursor(crtc);
165  obj = NULL;
166  goto unpin;
167  }
168 
169  if ((width > CURSOR_WIDTH) || (height > CURSOR_HEIGHT)) {
170  DRM_ERROR("bad cursor width or height %d x %d\n", width, height);
171  return -EINVAL;
172  }
173 
174  obj = drm_gem_object_lookup(crtc->dev, file_priv, handle);
175  if (!obj) {
176  DRM_ERROR("Cannot find cursor object %x for crtc %d\n", handle, radeon_crtc->crtc_id);
177  return -ENOENT;
178  }
179 
180  robj = gem_to_radeon_bo(obj);
181  ret = radeon_bo_reserve(robj, false);
182  if (unlikely(ret != 0))
183  goto fail;
184  /* Only 27 bit offset for legacy cursor */
186  ASIC_IS_AVIVO(rdev) ? 0 : 1 << 27,
187  &gpu_addr);
188  radeon_bo_unreserve(robj);
189  if (ret)
190  goto fail;
191 
192  radeon_crtc->cursor_width = width;
193  radeon_crtc->cursor_height = height;
194 
195  radeon_lock_cursor(crtc, true);
196  radeon_set_cursor(crtc, obj, gpu_addr);
197  radeon_show_cursor(crtc);
198  radeon_lock_cursor(crtc, false);
199 
200 unpin:
201  if (radeon_crtc->cursor_bo) {
202  robj = gem_to_radeon_bo(radeon_crtc->cursor_bo);
203  ret = radeon_bo_reserve(robj, false);
204  if (likely(ret == 0)) {
205  radeon_bo_unpin(robj);
206  radeon_bo_unreserve(robj);
207  }
208  drm_gem_object_unreference_unlocked(radeon_crtc->cursor_bo);
209  }
210 
211  radeon_crtc->cursor_bo = obj;
212  return 0;
213 fail:
214  drm_gem_object_unreference_unlocked(obj);
215 
216  return ret;
217 }
218 
220  int x, int y)
221 {
222  struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
223  struct radeon_device *rdev = crtc->dev->dev_private;
224  int xorigin = 0, yorigin = 0;
225  int w = radeon_crtc->cursor_width;
226 
227  if (ASIC_IS_AVIVO(rdev)) {
228  /* avivo cursor are offset into the total surface */
229  x += crtc->x;
230  y += crtc->y;
231  }
232  DRM_DEBUG("x %d y %d c->x %d c->y %d\n", x, y, crtc->x, crtc->y);
233 
234  if (x < 0) {
235  xorigin = min(-x, CURSOR_WIDTH - 1);
236  x = 0;
237  }
238  if (y < 0) {
239  yorigin = min(-y, CURSOR_HEIGHT - 1);
240  y = 0;
241  }
242 
243  if (ASIC_IS_AVIVO(rdev)) {
244  int i = 0;
245  struct drm_crtc *crtc_p;
246 
247  /* avivo cursor image can't end on 128 pixel boundary or
248  * go past the end of the frame if both crtcs are enabled
249  */
250  list_for_each_entry(crtc_p, &crtc->dev->mode_config.crtc_list, head) {
251  if (crtc_p->enabled)
252  i++;
253  }
254  if (i > 1) {
255  int cursor_end, frame_end;
256 
257  cursor_end = x - xorigin + w;
258  frame_end = crtc->x + crtc->mode.crtc_hdisplay;
259  if (cursor_end >= frame_end) {
260  w = w - (cursor_end - frame_end);
261  if (!(frame_end & 0x7f))
262  w--;
263  } else {
264  if (!(cursor_end & 0x7f))
265  w--;
266  }
267  if (w <= 0) {
268  w = 1;
269  cursor_end = x - xorigin + w;
270  if (!(cursor_end & 0x7f)) {
271  x--;
272  WARN_ON_ONCE(x < 0);
273  }
274  }
275  }
276  }
277 
278  radeon_lock_cursor(crtc, true);
279  if (ASIC_IS_DCE4(rdev)) {
280  WREG32(EVERGREEN_CUR_POSITION + radeon_crtc->crtc_offset, (x << 16) | y);
281  WREG32(EVERGREEN_CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin);
282  WREG32(EVERGREEN_CUR_SIZE + radeon_crtc->crtc_offset,
283  ((w - 1) << 16) | (radeon_crtc->cursor_height - 1));
284  } else if (ASIC_IS_AVIVO(rdev)) {
285  WREG32(AVIVO_D1CUR_POSITION + radeon_crtc->crtc_offset, (x << 16) | y);
286  WREG32(AVIVO_D1CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin);
287  WREG32(AVIVO_D1CUR_SIZE + radeon_crtc->crtc_offset,
288  ((w - 1) << 16) | (radeon_crtc->cursor_height - 1));
289  } else {
290  if (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN)
291  y *= 2;
292 
295  | (xorigin << 16)
296  | yorigin));
299  | (x << 16)
300  | y));
301  /* offset is from DISP(2)_BASE_ADDRESS */
302  WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, (radeon_crtc->legacy_cursor_offset +
303  (yorigin * 256)));
304  }
305  radeon_lock_cursor(crtc, false);
306 
307  return 0;
308 }