xref: /linux/drivers/gpu/drm/radeon/radeon_cursor.c (revision a8ad0bd84f986072314595d05444719fdf29e412)
1771fe6b9SJerome Glisse /*
2771fe6b9SJerome Glisse  * Copyright 2007-8 Advanced Micro Devices, Inc.
3771fe6b9SJerome Glisse  * Copyright 2008 Red Hat Inc.
4771fe6b9SJerome Glisse  *
5771fe6b9SJerome Glisse  * Permission is hereby granted, free of charge, to any person obtaining a
6771fe6b9SJerome Glisse  * copy of this software and associated documentation files (the "Software"),
7771fe6b9SJerome Glisse  * to deal in the Software without restriction, including without limitation
8771fe6b9SJerome Glisse  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9771fe6b9SJerome Glisse  * and/or sell copies of the Software, and to permit persons to whom the
10771fe6b9SJerome Glisse  * Software is furnished to do so, subject to the following conditions:
11771fe6b9SJerome Glisse  *
12771fe6b9SJerome Glisse  * The above copyright notice and this permission notice shall be included in
13771fe6b9SJerome Glisse  * all copies or substantial portions of the Software.
14771fe6b9SJerome Glisse  *
15771fe6b9SJerome Glisse  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16771fe6b9SJerome Glisse  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17771fe6b9SJerome Glisse  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18771fe6b9SJerome Glisse  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
19771fe6b9SJerome Glisse  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20771fe6b9SJerome Glisse  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21771fe6b9SJerome Glisse  * OTHER DEALINGS IN THE SOFTWARE.
22771fe6b9SJerome Glisse  *
23771fe6b9SJerome Glisse  * Authors: Dave Airlie
24771fe6b9SJerome Glisse  *          Alex Deucher
25771fe6b9SJerome Glisse  */
26760285e7SDavid Howells #include <drm/drmP.h>
27760285e7SDavid Howells #include <drm/radeon_drm.h>
28771fe6b9SJerome Glisse #include "radeon.h"
29771fe6b9SJerome Glisse 
30771fe6b9SJerome Glisse static void radeon_lock_cursor(struct drm_crtc *crtc, bool lock)
31771fe6b9SJerome Glisse {
32771fe6b9SJerome Glisse 	struct radeon_device *rdev = crtc->dev->dev_private;
33771fe6b9SJerome Glisse 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
34771fe6b9SJerome Glisse 	uint32_t cur_lock;
35771fe6b9SJerome Glisse 
36bcc1c2a1SAlex Deucher 	if (ASIC_IS_DCE4(rdev)) {
37bcc1c2a1SAlex Deucher 		cur_lock = RREG32(EVERGREEN_CUR_UPDATE + radeon_crtc->crtc_offset);
38bcc1c2a1SAlex Deucher 		if (lock)
39bcc1c2a1SAlex Deucher 			cur_lock |= EVERGREEN_CURSOR_UPDATE_LOCK;
40bcc1c2a1SAlex Deucher 		else
41bcc1c2a1SAlex Deucher 			cur_lock &= ~EVERGREEN_CURSOR_UPDATE_LOCK;
42bcc1c2a1SAlex Deucher 		WREG32(EVERGREEN_CUR_UPDATE + radeon_crtc->crtc_offset, cur_lock);
43bcc1c2a1SAlex Deucher 	} else if (ASIC_IS_AVIVO(rdev)) {
44771fe6b9SJerome Glisse 		cur_lock = RREG32(AVIVO_D1CUR_UPDATE + radeon_crtc->crtc_offset);
45771fe6b9SJerome Glisse 		if (lock)
46771fe6b9SJerome Glisse 			cur_lock |= AVIVO_D1CURSOR_UPDATE_LOCK;
47771fe6b9SJerome Glisse 		else
48771fe6b9SJerome Glisse 			cur_lock &= ~AVIVO_D1CURSOR_UPDATE_LOCK;
49771fe6b9SJerome Glisse 		WREG32(AVIVO_D1CUR_UPDATE + radeon_crtc->crtc_offset, cur_lock);
50771fe6b9SJerome Glisse 	} else {
51771fe6b9SJerome Glisse 		cur_lock = RREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset);
52771fe6b9SJerome Glisse 		if (lock)
53771fe6b9SJerome Glisse 			cur_lock |= RADEON_CUR_LOCK;
54771fe6b9SJerome Glisse 		else
55771fe6b9SJerome Glisse 			cur_lock &= ~RADEON_CUR_LOCK;
56771fe6b9SJerome Glisse 		WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, cur_lock);
57771fe6b9SJerome Glisse 	}
58771fe6b9SJerome Glisse }
59771fe6b9SJerome Glisse 
60771fe6b9SJerome Glisse static void radeon_hide_cursor(struct drm_crtc *crtc)
61771fe6b9SJerome Glisse {
62771fe6b9SJerome Glisse 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
63771fe6b9SJerome Glisse 	struct radeon_device *rdev = crtc->dev->dev_private;
64771fe6b9SJerome Glisse 
65bcc1c2a1SAlex Deucher 	if (ASIC_IS_DCE4(rdev)) {
662ef9bdfeSDaniel Vetter 		WREG32_IDX(EVERGREEN_CUR_CONTROL + radeon_crtc->crtc_offset,
672ef9bdfeSDaniel Vetter 			   EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT) |
68f4254a2bSAlex Deucher 			   EVERGREEN_CURSOR_URGENT_CONTROL(EVERGREEN_CURSOR_URGENT_1_2));
69bcc1c2a1SAlex Deucher 	} else if (ASIC_IS_AVIVO(rdev)) {
702ef9bdfeSDaniel Vetter 		WREG32_IDX(AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset,
712ef9bdfeSDaniel Vetter 			   (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT));
72771fe6b9SJerome Glisse 	} else {
732ef9bdfeSDaniel Vetter 		u32 reg;
74771fe6b9SJerome Glisse 		switch (radeon_crtc->crtc_id) {
75771fe6b9SJerome Glisse 		case 0:
762ef9bdfeSDaniel Vetter 			reg = RADEON_CRTC_GEN_CNTL;
77771fe6b9SJerome Glisse 			break;
78771fe6b9SJerome Glisse 		case 1:
792ef9bdfeSDaniel Vetter 			reg = RADEON_CRTC2_GEN_CNTL;
80771fe6b9SJerome Glisse 			break;
81771fe6b9SJerome Glisse 		default:
82771fe6b9SJerome Glisse 			return;
83771fe6b9SJerome Glisse 		}
842ef9bdfeSDaniel Vetter 		WREG32_IDX(reg, RREG32_IDX(reg) & ~RADEON_CRTC_CUR_EN);
85771fe6b9SJerome Glisse 	}
86771fe6b9SJerome Glisse }
87771fe6b9SJerome Glisse 
88771fe6b9SJerome Glisse static void radeon_show_cursor(struct drm_crtc *crtc)
89771fe6b9SJerome Glisse {
90771fe6b9SJerome Glisse 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
91771fe6b9SJerome Glisse 	struct radeon_device *rdev = crtc->dev->dev_private;
92771fe6b9SJerome Glisse 
93bcc1c2a1SAlex Deucher 	if (ASIC_IS_DCE4(rdev)) {
948991668aSMichel Dänzer 		WREG32(EVERGREEN_CUR_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset,
958991668aSMichel Dänzer 		       upper_32_bits(radeon_crtc->cursor_addr));
968991668aSMichel Dänzer 		WREG32(EVERGREEN_CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
978991668aSMichel Dänzer 		       lower_32_bits(radeon_crtc->cursor_addr));
98bcc1c2a1SAlex Deucher 		WREG32(RADEON_MM_INDEX, EVERGREEN_CUR_CONTROL + radeon_crtc->crtc_offset);
99bcc1c2a1SAlex Deucher 		WREG32(RADEON_MM_DATA, EVERGREEN_CURSOR_EN |
100f4254a2bSAlex Deucher 		       EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT) |
101f4254a2bSAlex Deucher 		       EVERGREEN_CURSOR_URGENT_CONTROL(EVERGREEN_CURSOR_URGENT_1_2));
102bcc1c2a1SAlex Deucher 	} else if (ASIC_IS_AVIVO(rdev)) {
1038991668aSMichel Dänzer 		if (rdev->family >= CHIP_RV770) {
1048991668aSMichel Dänzer 			if (radeon_crtc->crtc_id)
1058991668aSMichel Dänzer 				WREG32(R700_D2CUR_SURFACE_ADDRESS_HIGH,
1068991668aSMichel Dänzer 				       upper_32_bits(radeon_crtc->cursor_addr));
1078991668aSMichel Dänzer 			else
1088991668aSMichel Dänzer 				WREG32(R700_D1CUR_SURFACE_ADDRESS_HIGH,
1098991668aSMichel Dänzer 				       upper_32_bits(radeon_crtc->cursor_addr));
1108991668aSMichel Dänzer 		}
1118991668aSMichel Dänzer 
1128991668aSMichel Dänzer 		WREG32(AVIVO_D1CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
1138991668aSMichel Dänzer 		       lower_32_bits(radeon_crtc->cursor_addr));
114771fe6b9SJerome Glisse 		WREG32(RADEON_MM_INDEX, AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset);
115771fe6b9SJerome Glisse 		WREG32(RADEON_MM_DATA, AVIVO_D1CURSOR_EN |
116771fe6b9SJerome Glisse 		       (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT));
117771fe6b9SJerome Glisse 	} else {
1188991668aSMichel Dänzer 		/* offset is from DISP(2)_BASE_ADDRESS */
1198991668aSMichel Dänzer 		WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset,
1208991668aSMichel Dänzer 		       radeon_crtc->cursor_addr - radeon_crtc->legacy_display_base_addr);
1218991668aSMichel Dänzer 
122771fe6b9SJerome Glisse 		switch (radeon_crtc->crtc_id) {
123771fe6b9SJerome Glisse 		case 0:
124771fe6b9SJerome Glisse 			WREG32(RADEON_MM_INDEX, RADEON_CRTC_GEN_CNTL);
125771fe6b9SJerome Glisse 			break;
126771fe6b9SJerome Glisse 		case 1:
127771fe6b9SJerome Glisse 			WREG32(RADEON_MM_INDEX, RADEON_CRTC2_GEN_CNTL);
128771fe6b9SJerome Glisse 			break;
129771fe6b9SJerome Glisse 		default:
130771fe6b9SJerome Glisse 			return;
131771fe6b9SJerome Glisse 		}
132771fe6b9SJerome Glisse 
133771fe6b9SJerome Glisse 		WREG32_P(RADEON_MM_DATA, (RADEON_CRTC_CUR_EN |
134771fe6b9SJerome Glisse 					  (RADEON_CRTC_CUR_MODE_24BPP << RADEON_CRTC_CUR_MODE_SHIFT)),
135771fe6b9SJerome Glisse 			 ~(RADEON_CRTC_CUR_EN | RADEON_CRTC_CUR_MODE_MASK));
136771fe6b9SJerome Glisse 	}
137771fe6b9SJerome Glisse }
138771fe6b9SJerome Glisse 
1393feba08dSMichel Dänzer static int radeon_cursor_move_locked(struct drm_crtc *crtc, int x, int y)
1403feba08dSMichel Dänzer {
1413feba08dSMichel Dänzer 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
1423feba08dSMichel Dänzer 	struct radeon_device *rdev = crtc->dev->dev_private;
1433feba08dSMichel Dänzer 	int xorigin = 0, yorigin = 0;
1443feba08dSMichel Dänzer 	int w = radeon_crtc->cursor_width;
1453feba08dSMichel Dänzer 
1463feba08dSMichel Dänzer 	if (ASIC_IS_AVIVO(rdev)) {
1473feba08dSMichel Dänzer 		/* avivo cursor are offset into the total surface */
1483feba08dSMichel Dänzer 		x += crtc->x;
1493feba08dSMichel Dänzer 		y += crtc->y;
1503feba08dSMichel Dänzer 	}
1513feba08dSMichel Dänzer 	DRM_DEBUG("x %d y %d c->x %d c->y %d\n", x, y, crtc->x, crtc->y);
1523feba08dSMichel Dänzer 
1533feba08dSMichel Dänzer 	if (x < 0) {
1543feba08dSMichel Dänzer 		xorigin = min(-x, radeon_crtc->max_cursor_width - 1);
1553feba08dSMichel Dänzer 		x = 0;
1563feba08dSMichel Dänzer 	}
1573feba08dSMichel Dänzer 	if (y < 0) {
1583feba08dSMichel Dänzer 		yorigin = min(-y, radeon_crtc->max_cursor_height - 1);
1593feba08dSMichel Dänzer 		y = 0;
1603feba08dSMichel Dänzer 	}
1613feba08dSMichel Dänzer 
1623feba08dSMichel Dänzer 	/* fixed on DCE6 and newer */
1633feba08dSMichel Dänzer 	if (ASIC_IS_AVIVO(rdev) && !ASIC_IS_DCE6(rdev)) {
1643feba08dSMichel Dänzer 		int i = 0;
1653feba08dSMichel Dänzer 		struct drm_crtc *crtc_p;
1663feba08dSMichel Dänzer 
1673feba08dSMichel Dänzer 		/*
1683feba08dSMichel Dänzer 		 * avivo cursor image can't end on 128 pixel boundary or
1693feba08dSMichel Dänzer 		 * go past the end of the frame if both crtcs are enabled
1703feba08dSMichel Dänzer 		 *
1713feba08dSMichel Dänzer 		 * NOTE: It is safe to access crtc->enabled of other crtcs
1723feba08dSMichel Dänzer 		 * without holding either the mode_config lock or the other
1733feba08dSMichel Dänzer 		 * crtc's lock as long as write access to this flag _always_
1743feba08dSMichel Dänzer 		 * grabs all locks.
1753feba08dSMichel Dänzer 		 */
1763feba08dSMichel Dänzer 		list_for_each_entry(crtc_p, &crtc->dev->mode_config.crtc_list, head) {
1773feba08dSMichel Dänzer 			if (crtc_p->enabled)
1783feba08dSMichel Dänzer 				i++;
1793feba08dSMichel Dänzer 		}
1803feba08dSMichel Dänzer 		if (i > 1) {
1813feba08dSMichel Dänzer 			int cursor_end, frame_end;
1823feba08dSMichel Dänzer 
1833feba08dSMichel Dänzer 			cursor_end = x - xorigin + w;
1843feba08dSMichel Dänzer 			frame_end = crtc->x + crtc->mode.crtc_hdisplay;
1853feba08dSMichel Dänzer 			if (cursor_end >= frame_end) {
1863feba08dSMichel Dänzer 				w = w - (cursor_end - frame_end);
1873feba08dSMichel Dänzer 				if (!(frame_end & 0x7f))
1883feba08dSMichel Dänzer 					w--;
1893feba08dSMichel Dänzer 			} else {
1903feba08dSMichel Dänzer 				if (!(cursor_end & 0x7f))
1913feba08dSMichel Dänzer 					w--;
1923feba08dSMichel Dänzer 			}
1933feba08dSMichel Dänzer 			if (w <= 0) {
1943feba08dSMichel Dänzer 				w = 1;
1953feba08dSMichel Dänzer 				cursor_end = x - xorigin + w;
1963feba08dSMichel Dänzer 				if (!(cursor_end & 0x7f)) {
1973feba08dSMichel Dänzer 					x--;
1983feba08dSMichel Dänzer 					WARN_ON_ONCE(x < 0);
1993feba08dSMichel Dänzer 				}
2003feba08dSMichel Dänzer 			}
2013feba08dSMichel Dänzer 		}
2023feba08dSMichel Dänzer 	}
2033feba08dSMichel Dänzer 
2043feba08dSMichel Dänzer 	if (ASIC_IS_DCE4(rdev)) {
2053feba08dSMichel Dänzer 		WREG32(EVERGREEN_CUR_POSITION + radeon_crtc->crtc_offset, (x << 16) | y);
2063feba08dSMichel Dänzer 		WREG32(EVERGREEN_CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin);
2073feba08dSMichel Dänzer 		WREG32(EVERGREEN_CUR_SIZE + radeon_crtc->crtc_offset,
2083feba08dSMichel Dänzer 		       ((w - 1) << 16) | (radeon_crtc->cursor_height - 1));
2093feba08dSMichel Dänzer 	} else if (ASIC_IS_AVIVO(rdev)) {
2103feba08dSMichel Dänzer 		WREG32(AVIVO_D1CUR_POSITION + radeon_crtc->crtc_offset, (x << 16) | y);
2113feba08dSMichel Dänzer 		WREG32(AVIVO_D1CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin);
2123feba08dSMichel Dänzer 		WREG32(AVIVO_D1CUR_SIZE + radeon_crtc->crtc_offset,
2133feba08dSMichel Dänzer 		       ((w - 1) << 16) | (radeon_crtc->cursor_height - 1));
2143feba08dSMichel Dänzer 	} else {
2153feba08dSMichel Dänzer 		if (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN)
2163feba08dSMichel Dänzer 			y *= 2;
2173feba08dSMichel Dänzer 
2183feba08dSMichel Dänzer 		WREG32(RADEON_CUR_HORZ_VERT_OFF + radeon_crtc->crtc_offset,
2193feba08dSMichel Dänzer 		       (RADEON_CUR_LOCK
2203feba08dSMichel Dänzer 			| (xorigin << 16)
2213feba08dSMichel Dänzer 			| yorigin));
2223feba08dSMichel Dänzer 		WREG32(RADEON_CUR_HORZ_VERT_POSN + radeon_crtc->crtc_offset,
2233feba08dSMichel Dänzer 		       (RADEON_CUR_LOCK
2243feba08dSMichel Dänzer 			| (x << 16)
2253feba08dSMichel Dänzer 			| y));
2263feba08dSMichel Dänzer 		/* offset is from DISP(2)_BASE_ADDRESS */
227cd404af0SMichel Dänzer 		WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset,
228cd404af0SMichel Dänzer 		       radeon_crtc->cursor_addr - radeon_crtc->legacy_display_base_addr +
229cd404af0SMichel Dänzer 		       yorigin * 256);
2303feba08dSMichel Dänzer 	}
2313feba08dSMichel Dänzer 
2323feba08dSMichel Dänzer 	radeon_crtc->cursor_x = x;
2333feba08dSMichel Dänzer 	radeon_crtc->cursor_y = y;
2343feba08dSMichel Dänzer 
2353feba08dSMichel Dänzer 	return 0;
2363feba08dSMichel Dänzer }
2373feba08dSMichel Dänzer 
2383feba08dSMichel Dänzer int radeon_crtc_cursor_move(struct drm_crtc *crtc,
2393feba08dSMichel Dänzer 			    int x, int y)
2403feba08dSMichel Dänzer {
2413feba08dSMichel Dänzer 	int ret;
2423feba08dSMichel Dänzer 
2433feba08dSMichel Dänzer 	radeon_lock_cursor(crtc, true);
2443feba08dSMichel Dänzer 	ret = radeon_cursor_move_locked(crtc, x, y);
2453feba08dSMichel Dänzer 	radeon_lock_cursor(crtc, false);
2463feba08dSMichel Dänzer 
2473feba08dSMichel Dänzer 	return ret;
2483feba08dSMichel Dänzer }
24978b1a601SMichel Dänzer 
25078b1a601SMichel Dänzer int radeon_crtc_cursor_set2(struct drm_crtc *crtc,
251771fe6b9SJerome Glisse 			    struct drm_file *file_priv,
252771fe6b9SJerome Glisse 			    uint32_t handle,
253771fe6b9SJerome Glisse 			    uint32_t width,
25478b1a601SMichel Dänzer 			    uint32_t height,
25578b1a601SMichel Dänzer 			    int32_t hot_x,
25678b1a601SMichel Dänzer 			    int32_t hot_y)
257771fe6b9SJerome Glisse {
258771fe6b9SJerome Glisse 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
259cd404af0SMichel Dänzer 	struct radeon_device *rdev = crtc->dev->dev_private;
260771fe6b9SJerome Glisse 	struct drm_gem_object *obj;
261cd404af0SMichel Dänzer 	struct radeon_bo *robj;
262771fe6b9SJerome Glisse 	int ret;
263771fe6b9SJerome Glisse 
264771fe6b9SJerome Glisse 	if (!handle) {
265771fe6b9SJerome Glisse 		/* turn off cursor */
266771fe6b9SJerome Glisse 		radeon_hide_cursor(crtc);
267771fe6b9SJerome Glisse 		obj = NULL;
268771fe6b9SJerome Glisse 		goto unpin;
269771fe6b9SJerome Glisse 	}
270771fe6b9SJerome Glisse 
2719e05fa1dSAlex Deucher 	if ((width > radeon_crtc->max_cursor_width) ||
2729e05fa1dSAlex Deucher 	    (height > radeon_crtc->max_cursor_height)) {
273771fe6b9SJerome Glisse 		DRM_ERROR("bad cursor width or height %d x %d\n", width, height);
274771fe6b9SJerome Glisse 		return -EINVAL;
275771fe6b9SJerome Glisse 	}
276771fe6b9SJerome Glisse 
277*a8ad0bd8SChris Wilson 	obj = drm_gem_object_lookup(file_priv, handle);
278771fe6b9SJerome Glisse 	if (!obj) {
279771fe6b9SJerome Glisse 		DRM_ERROR("Cannot find cursor object %x for crtc %d\n", handle, radeon_crtc->crtc_id);
280bf79cb91SChris Wilson 		return -ENOENT;
281771fe6b9SJerome Glisse 	}
282771fe6b9SJerome Glisse 
283cd404af0SMichel Dänzer 	robj = gem_to_radeon_bo(obj);
284cd404af0SMichel Dänzer 	ret = radeon_bo_reserve(robj, false);
285cd404af0SMichel Dänzer 	if (ret != 0) {
286cd404af0SMichel Dänzer 		drm_gem_object_unreference_unlocked(obj);
287cd404af0SMichel Dänzer 		return ret;
288cd404af0SMichel Dänzer 	}
289cd404af0SMichel Dänzer 	/* Only 27 bit offset for legacy cursor */
290cd404af0SMichel Dänzer 	ret = radeon_bo_pin_restricted(robj, RADEON_GEM_DOMAIN_VRAM,
291cd404af0SMichel Dänzer 				       ASIC_IS_AVIVO(rdev) ? 0 : 1 << 27,
292cd404af0SMichel Dänzer 				       &radeon_crtc->cursor_addr);
293cd404af0SMichel Dänzer 	radeon_bo_unreserve(robj);
294cd404af0SMichel Dänzer 	if (ret) {
295cd404af0SMichel Dänzer 		DRM_ERROR("Failed to pin new cursor BO (%d)\n", ret);
296cd404af0SMichel Dänzer 		drm_gem_object_unreference_unlocked(obj);
297cd404af0SMichel Dänzer 		return ret;
298cd404af0SMichel Dänzer 	}
299cd404af0SMichel Dänzer 
30045e5f6a2SIlija Hadzic 	radeon_crtc->cursor_width = width;
30145e5f6a2SIlija Hadzic 	radeon_crtc->cursor_height = height;
30245e5f6a2SIlija Hadzic 
303771fe6b9SJerome Glisse 	radeon_lock_cursor(crtc, true);
3042e007e61SMichel Dänzer 
3052e007e61SMichel Dänzer 	if (hot_x != radeon_crtc->cursor_hot_x ||
3062e007e61SMichel Dänzer 	    hot_y != radeon_crtc->cursor_hot_y) {
3072e007e61SMichel Dänzer 		int x, y;
3082e007e61SMichel Dänzer 
3092e007e61SMichel Dänzer 		x = radeon_crtc->cursor_x + radeon_crtc->cursor_hot_x - hot_x;
3102e007e61SMichel Dänzer 		y = radeon_crtc->cursor_y + radeon_crtc->cursor_hot_y - hot_y;
3112e007e61SMichel Dänzer 
3122e007e61SMichel Dänzer 		radeon_cursor_move_locked(crtc, x, y);
3132e007e61SMichel Dänzer 
3142e007e61SMichel Dänzer 		radeon_crtc->cursor_hot_x = hot_x;
3152e007e61SMichel Dänzer 		radeon_crtc->cursor_hot_y = hot_y;
3162e007e61SMichel Dänzer 	}
3172e007e61SMichel Dänzer 
318771fe6b9SJerome Glisse 	radeon_show_cursor(crtc);
3196d3759faSMichel Dänzer 
320771fe6b9SJerome Glisse 	radeon_lock_cursor(crtc, false);
321771fe6b9SJerome Glisse 
322771fe6b9SJerome Glisse unpin:
323771fe6b9SJerome Glisse 	if (radeon_crtc->cursor_bo) {
3246d3759faSMichel Dänzer 		struct radeon_bo *robj = gem_to_radeon_bo(radeon_crtc->cursor_bo);
325654c59cfSMichel Dänzer 		ret = radeon_bo_reserve(robj, false);
326654c59cfSMichel Dänzer 		if (likely(ret == 0)) {
327654c59cfSMichel Dänzer 			radeon_bo_unpin(robj);
328654c59cfSMichel Dänzer 			radeon_bo_unreserve(robj);
329654c59cfSMichel Dänzer 		}
330bc9025bdSLuca Barbieri 		drm_gem_object_unreference_unlocked(radeon_crtc->cursor_bo);
331771fe6b9SJerome Glisse 	}
332771fe6b9SJerome Glisse 
333771fe6b9SJerome Glisse 	radeon_crtc->cursor_bo = obj;
334771fe6b9SJerome Glisse 	return 0;
3356d3759faSMichel Dänzer }
336771fe6b9SJerome Glisse 
3376d3759faSMichel Dänzer /**
3386d3759faSMichel Dänzer  * radeon_cursor_reset - Re-set the current cursor, if any.
3396d3759faSMichel Dänzer  *
3406d3759faSMichel Dänzer  * @crtc: drm crtc
3416d3759faSMichel Dänzer  *
3426d3759faSMichel Dänzer  * If the CRTC passed in currently has a cursor assigned, this function
3436d3759faSMichel Dänzer  * makes sure it's visible.
3446d3759faSMichel Dänzer  */
3456d3759faSMichel Dänzer void radeon_cursor_reset(struct drm_crtc *crtc)
3466d3759faSMichel Dänzer {
3476d3759faSMichel Dänzer 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
3486d3759faSMichel Dänzer 
3496d3759faSMichel Dänzer 	if (radeon_crtc->cursor_bo) {
3506d3759faSMichel Dänzer 		radeon_lock_cursor(crtc, true);
3516d3759faSMichel Dänzer 
3526d3759faSMichel Dänzer 		radeon_cursor_move_locked(crtc, radeon_crtc->cursor_x,
3536d3759faSMichel Dänzer 					  radeon_crtc->cursor_y);
3546d3759faSMichel Dänzer 
3556d3759faSMichel Dänzer 		radeon_show_cursor(crtc);
3566d3759faSMichel Dänzer 
3576d3759faSMichel Dänzer 		radeon_lock_cursor(crtc, false);
3586d3759faSMichel Dänzer 	}
359771fe6b9SJerome Glisse }
360