• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
radeon_lock_cursor(struct drm_crtc * crtc,bool lock)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 
radeon_hide_cursor(struct drm_crtc * crtc)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 
radeon_show_cursor(struct drm_crtc * crtc)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 
radeon_cursor_move_locked(struct drm_crtc * crtc,int x,int y)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 
radeon_crtc_cursor_move(struct drm_crtc * crtc,int x,int y)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 
radeon_crtc_cursor_set2(struct drm_crtc * crtc,struct drm_file * file_priv,uint32_t handle,uint32_t width,uint32_t height,int32_t hot_x,int32_t hot_y)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(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(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(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  */
radeon_cursor_reset(struct drm_crtc * crtc)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 }
387