Line data Source code
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 <dev/pci/drm/drmP.h>
27 : #include <dev/pci/drm/radeon_drm.h>
28 : #include "radeon.h"
29 :
30 0 : static void radeon_lock_cursor(struct drm_crtc *crtc, bool lock)
31 : {
32 0 : struct radeon_device *rdev = crtc->dev->dev_private;
33 0 : struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
34 : uint32_t cur_lock;
35 :
36 0 : if (ASIC_IS_DCE4(rdev)) {
37 0 : cur_lock = RREG32(EVERGREEN_CUR_UPDATE + radeon_crtc->crtc_offset);
38 0 : if (lock)
39 0 : cur_lock |= EVERGREEN_CURSOR_UPDATE_LOCK;
40 : else
41 0 : cur_lock &= ~EVERGREEN_CURSOR_UPDATE_LOCK;
42 0 : WREG32(EVERGREEN_CUR_UPDATE + radeon_crtc->crtc_offset, cur_lock);
43 0 : } else if (ASIC_IS_AVIVO(rdev)) {
44 0 : cur_lock = RREG32(AVIVO_D1CUR_UPDATE + radeon_crtc->crtc_offset);
45 0 : if (lock)
46 0 : cur_lock |= AVIVO_D1CURSOR_UPDATE_LOCK;
47 : else
48 0 : cur_lock &= ~AVIVO_D1CURSOR_UPDATE_LOCK;
49 0 : WREG32(AVIVO_D1CUR_UPDATE + radeon_crtc->crtc_offset, cur_lock);
50 0 : } else {
51 0 : cur_lock = RREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset);
52 0 : if (lock)
53 0 : cur_lock |= RADEON_CUR_LOCK;
54 : else
55 0 : cur_lock &= ~RADEON_CUR_LOCK;
56 0 : WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, cur_lock);
57 : }
58 0 : }
59 :
60 0 : static void radeon_hide_cursor(struct drm_crtc *crtc)
61 : {
62 0 : struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
63 0 : struct radeon_device *rdev = crtc->dev->dev_private;
64 :
65 0 : if (ASIC_IS_DCE4(rdev)) {
66 0 : WREG32_IDX(EVERGREEN_CUR_CONTROL + radeon_crtc->crtc_offset,
67 : EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT) |
68 : EVERGREEN_CURSOR_URGENT_CONTROL(EVERGREEN_CURSOR_URGENT_1_2));
69 0 : } else if (ASIC_IS_AVIVO(rdev)) {
70 0 : WREG32_IDX(AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset,
71 : (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT));
72 0 : } else {
73 : u32 reg;
74 0 : switch (radeon_crtc->crtc_id) {
75 : case 0:
76 : reg = RADEON_CRTC_GEN_CNTL;
77 0 : break;
78 : case 1:
79 : reg = RADEON_CRTC2_GEN_CNTL;
80 0 : break;
81 : default:
82 0 : return;
83 : }
84 0 : WREG32_IDX(reg, RREG32_IDX(reg) & ~RADEON_CRTC_CUR_EN);
85 0 : }
86 0 : }
87 :
88 0 : static void radeon_show_cursor(struct drm_crtc *crtc)
89 : {
90 0 : struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
91 0 : struct radeon_device *rdev = crtc->dev->dev_private;
92 :
93 0 : if (radeon_crtc->cursor_out_of_bounds)
94 0 : return;
95 :
96 0 : if (ASIC_IS_DCE4(rdev)) {
97 0 : WREG32(EVERGREEN_CUR_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset,
98 : upper_32_bits(radeon_crtc->cursor_addr));
99 0 : WREG32(EVERGREEN_CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
100 : lower_32_bits(radeon_crtc->cursor_addr));
101 0 : WREG32(RADEON_MM_INDEX, EVERGREEN_CUR_CONTROL + radeon_crtc->crtc_offset);
102 0 : WREG32(RADEON_MM_DATA, EVERGREEN_CURSOR_EN |
103 : EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT) |
104 : EVERGREEN_CURSOR_URGENT_CONTROL(EVERGREEN_CURSOR_URGENT_1_2));
105 0 : } else if (ASIC_IS_AVIVO(rdev)) {
106 0 : if (rdev->family >= CHIP_RV770) {
107 0 : if (radeon_crtc->crtc_id)
108 0 : WREG32(R700_D2CUR_SURFACE_ADDRESS_HIGH,
109 : upper_32_bits(radeon_crtc->cursor_addr));
110 : else
111 0 : WREG32(R700_D1CUR_SURFACE_ADDRESS_HIGH,
112 : upper_32_bits(radeon_crtc->cursor_addr));
113 : }
114 :
115 0 : WREG32(AVIVO_D1CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
116 : lower_32_bits(radeon_crtc->cursor_addr));
117 0 : WREG32(RADEON_MM_INDEX, AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset);
118 0 : WREG32(RADEON_MM_DATA, AVIVO_D1CURSOR_EN |
119 : (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT));
120 0 : } else {
121 : /* offset is from DISP(2)_BASE_ADDRESS */
122 0 : WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset,
123 : radeon_crtc->cursor_addr - radeon_crtc->legacy_display_base_addr);
124 :
125 0 : switch (radeon_crtc->crtc_id) {
126 : case 0:
127 0 : WREG32(RADEON_MM_INDEX, RADEON_CRTC_GEN_CNTL);
128 0 : break;
129 : case 1:
130 0 : WREG32(RADEON_MM_INDEX, RADEON_CRTC2_GEN_CNTL);
131 0 : break;
132 : default:
133 0 : return;
134 : }
135 :
136 0 : WREG32_P(RADEON_MM_DATA, (RADEON_CRTC_CUR_EN |
137 : (RADEON_CRTC_CUR_MODE_24BPP << RADEON_CRTC_CUR_MODE_SHIFT)),
138 : ~(RADEON_CRTC_CUR_EN | RADEON_CRTC_CUR_MODE_MASK));
139 : }
140 0 : }
141 :
142 0 : static int radeon_cursor_move_locked(struct drm_crtc *crtc, int x, int y)
143 : {
144 0 : struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
145 0 : struct radeon_device *rdev = crtc->dev->dev_private;
146 : int xorigin = 0, yorigin = 0;
147 0 : int w = radeon_crtc->cursor_width;
148 :
149 0 : radeon_crtc->cursor_x = x;
150 0 : radeon_crtc->cursor_y = y;
151 :
152 0 : if (ASIC_IS_AVIVO(rdev)) {
153 : /* avivo cursor are offset into the total surface */
154 0 : x += crtc->x;
155 0 : y += crtc->y;
156 0 : }
157 :
158 0 : if (x < 0)
159 0 : xorigin = min(-x, radeon_crtc->max_cursor_width - 1);
160 0 : if (y < 0)
161 0 : yorigin = min(-y, radeon_crtc->max_cursor_height - 1);
162 :
163 0 : if (!ASIC_IS_AVIVO(rdev)) {
164 0 : x += crtc->x;
165 0 : y += crtc->y;
166 0 : }
167 : DRM_DEBUG("x %d y %d c->x %d c->y %d\n", x, y, crtc->x, crtc->y);
168 :
169 : /* fixed on DCE6 and newer */
170 0 : if (ASIC_IS_AVIVO(rdev) && !ASIC_IS_DCE6(rdev)) {
171 : int i = 0;
172 : struct drm_crtc *crtc_p;
173 :
174 : /*
175 : * avivo cursor image can't end on 128 pixel boundary or
176 : * go past the end of the frame if both crtcs are enabled
177 : *
178 : * NOTE: It is safe to access crtc->enabled of other crtcs
179 : * without holding either the mode_config lock or the other
180 : * crtc's lock as long as write access to this flag _always_
181 : * grabs all locks.
182 : */
183 0 : list_for_each_entry(crtc_p, &crtc->dev->mode_config.crtc_list, head) {
184 0 : if (crtc_p->enabled)
185 0 : i++;
186 : }
187 0 : if (i > 1) {
188 : int cursor_end, frame_end;
189 :
190 0 : cursor_end = x + w;
191 0 : frame_end = crtc->x + crtc->mode.crtc_hdisplay;
192 0 : if (cursor_end >= frame_end) {
193 0 : w = w - (cursor_end - frame_end);
194 0 : if (!(frame_end & 0x7f))
195 0 : w--;
196 0 : } else if (cursor_end <= 0) {
197 0 : goto out_of_bounds;
198 0 : } else if (!(cursor_end & 0x7f)) {
199 0 : w--;
200 0 : }
201 0 : if (w <= 0) {
202 0 : goto out_of_bounds;
203 : }
204 0 : }
205 0 : }
206 :
207 0 : if (x <= (crtc->x - w) || y <= (crtc->y - radeon_crtc->cursor_height) ||
208 0 : x >= (crtc->x + crtc->mode.hdisplay) ||
209 0 : y >= (crtc->y + crtc->mode.vdisplay))
210 : goto out_of_bounds;
211 :
212 0 : x += xorigin;
213 0 : y += yorigin;
214 :
215 0 : if (ASIC_IS_DCE4(rdev)) {
216 0 : WREG32(EVERGREEN_CUR_POSITION + radeon_crtc->crtc_offset, (x << 16) | y);
217 0 : WREG32(EVERGREEN_CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin);
218 0 : WREG32(EVERGREEN_CUR_SIZE + radeon_crtc->crtc_offset,
219 : ((w - 1) << 16) | (radeon_crtc->cursor_height - 1));
220 0 : } else if (ASIC_IS_AVIVO(rdev)) {
221 0 : WREG32(AVIVO_D1CUR_POSITION + radeon_crtc->crtc_offset, (x << 16) | y);
222 0 : WREG32(AVIVO_D1CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin);
223 0 : WREG32(AVIVO_D1CUR_SIZE + radeon_crtc->crtc_offset,
224 : ((w - 1) << 16) | (radeon_crtc->cursor_height - 1));
225 0 : } else {
226 0 : x -= crtc->x;
227 0 : y -= crtc->y;
228 :
229 0 : if (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN)
230 0 : y *= 2;
231 :
232 0 : WREG32(RADEON_CUR_HORZ_VERT_OFF + radeon_crtc->crtc_offset,
233 : (RADEON_CUR_LOCK
234 : | (xorigin << 16)
235 : | yorigin));
236 0 : WREG32(RADEON_CUR_HORZ_VERT_POSN + radeon_crtc->crtc_offset,
237 : (RADEON_CUR_LOCK
238 : | (x << 16)
239 : | y));
240 : /* offset is from DISP(2)_BASE_ADDRESS */
241 0 : WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset,
242 : radeon_crtc->cursor_addr - radeon_crtc->legacy_display_base_addr +
243 : yorigin * 256);
244 : }
245 :
246 0 : if (radeon_crtc->cursor_out_of_bounds) {
247 0 : radeon_crtc->cursor_out_of_bounds = false;
248 0 : if (radeon_crtc->cursor_bo)
249 0 : radeon_show_cursor(crtc);
250 : }
251 :
252 0 : return 0;
253 :
254 : out_of_bounds:
255 0 : if (!radeon_crtc->cursor_out_of_bounds) {
256 0 : radeon_hide_cursor(crtc);
257 0 : radeon_crtc->cursor_out_of_bounds = true;
258 0 : }
259 0 : return 0;
260 0 : }
261 :
262 0 : int radeon_crtc_cursor_move(struct drm_crtc *crtc,
263 : int x, int y)
264 : {
265 : int ret;
266 :
267 0 : radeon_lock_cursor(crtc, true);
268 0 : ret = radeon_cursor_move_locked(crtc, x, y);
269 0 : radeon_lock_cursor(crtc, false);
270 :
271 0 : return ret;
272 : }
273 :
274 0 : int radeon_crtc_cursor_set2(struct drm_crtc *crtc,
275 : struct drm_file *file_priv,
276 : uint32_t handle,
277 : uint32_t width,
278 : uint32_t height,
279 : int32_t hot_x,
280 : int32_t hot_y)
281 : {
282 0 : struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
283 0 : struct radeon_device *rdev = crtc->dev->dev_private;
284 : struct drm_gem_object *obj;
285 : struct radeon_bo *robj;
286 : int ret;
287 :
288 0 : if (!handle) {
289 : /* turn off cursor */
290 0 : radeon_hide_cursor(crtc);
291 : obj = NULL;
292 0 : goto unpin;
293 : }
294 :
295 0 : if ((width > radeon_crtc->max_cursor_width) ||
296 0 : (height > radeon_crtc->max_cursor_height)) {
297 0 : DRM_ERROR("bad cursor width or height %d x %d\n", width, height);
298 0 : return -EINVAL;
299 : }
300 :
301 0 : obj = drm_gem_object_lookup(crtc->dev, file_priv, handle);
302 0 : if (!obj) {
303 0 : DRM_ERROR("Cannot find cursor object %x for crtc %d\n", handle, radeon_crtc->crtc_id);
304 0 : return -ENOENT;
305 : }
306 :
307 0 : robj = gem_to_radeon_bo(obj);
308 0 : ret = radeon_bo_reserve(robj, false);
309 0 : if (ret != 0) {
310 0 : drm_gem_object_unreference_unlocked(obj);
311 0 : return ret;
312 : }
313 : /* Only 27 bit offset for legacy cursor */
314 0 : ret = radeon_bo_pin_restricted(robj, RADEON_GEM_DOMAIN_VRAM,
315 0 : ASIC_IS_AVIVO(rdev) ? 0 : 1 << 27,
316 0 : &radeon_crtc->cursor_addr);
317 0 : radeon_bo_unreserve(robj);
318 0 : if (ret) {
319 0 : DRM_ERROR("Failed to pin new cursor BO (%d)\n", ret);
320 0 : drm_gem_object_unreference_unlocked(obj);
321 0 : return ret;
322 : }
323 :
324 0 : radeon_lock_cursor(crtc, true);
325 :
326 0 : if (width != radeon_crtc->cursor_width ||
327 0 : height != radeon_crtc->cursor_height ||
328 0 : hot_x != radeon_crtc->cursor_hot_x ||
329 0 : hot_y != radeon_crtc->cursor_hot_y) {
330 : int x, y;
331 :
332 0 : x = radeon_crtc->cursor_x + radeon_crtc->cursor_hot_x - hot_x;
333 0 : y = radeon_crtc->cursor_y + radeon_crtc->cursor_hot_y - hot_y;
334 :
335 0 : radeon_crtc->cursor_width = width;
336 0 : radeon_crtc->cursor_height = height;
337 0 : radeon_crtc->cursor_hot_x = hot_x;
338 0 : radeon_crtc->cursor_hot_y = hot_y;
339 :
340 0 : radeon_cursor_move_locked(crtc, x, y);
341 0 : }
342 :
343 0 : radeon_show_cursor(crtc);
344 :
345 0 : radeon_lock_cursor(crtc, false);
346 :
347 : unpin:
348 0 : if (radeon_crtc->cursor_bo) {
349 0 : struct radeon_bo *robj = gem_to_radeon_bo(radeon_crtc->cursor_bo);
350 0 : ret = radeon_bo_reserve(robj, false);
351 0 : if (likely(ret == 0)) {
352 0 : radeon_bo_unpin(robj);
353 0 : radeon_bo_unreserve(robj);
354 0 : }
355 0 : drm_gem_object_unreference_unlocked(radeon_crtc->cursor_bo);
356 0 : }
357 :
358 0 : radeon_crtc->cursor_bo = obj;
359 0 : return 0;
360 0 : }
361 :
362 : /**
363 : * radeon_cursor_reset - Re-set the current cursor, if any.
364 : *
365 : * @crtc: drm crtc
366 : *
367 : * If the CRTC passed in currently has a cursor assigned, this function
368 : * makes sure it's visible.
369 : */
370 0 : void radeon_cursor_reset(struct drm_crtc *crtc)
371 : {
372 0 : struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
373 :
374 0 : if (radeon_crtc->cursor_bo) {
375 0 : radeon_lock_cursor(crtc, true);
376 :
377 0 : radeon_cursor_move_locked(crtc, radeon_crtc->cursor_x,
378 0 : radeon_crtc->cursor_y);
379 :
380 0 : radeon_show_cursor(crtc);
381 :
382 0 : radeon_lock_cursor(crtc, false);
383 0 : }
384 0 : }
|