xref: /linux/drivers/gpu/drm/radeon/radeon_cursor.c (revision 4b4193256c8d3bc3a5397b5cd9494c2ad386317d)
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  */
26f9183127SSam Ravnborg 
27f9183127SSam Ravnborg #include <drm/drm_device.h>
28760285e7SDavid Howells #include <drm/radeon_drm.h>
29f9183127SSam Ravnborg 
30771fe6b9SJerome Glisse #include "radeon.h"
31771fe6b9SJerome Glisse 
radeon_lock_cursor(struct drm_crtc * crtc,bool lock)32771fe6b9SJerome Glisse static void radeon_lock_cursor(struct drm_crtc *crtc, bool lock)
33771fe6b9SJerome Glisse {
34771fe6b9SJerome Glisse 	struct radeon_device *rdev = crtc->dev->dev_private;
35771fe6b9SJerome Glisse 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
36771fe6b9SJerome Glisse 	uint32_t cur_lock;
37771fe6b9SJerome Glisse 
38bcc1c2a1SAlex Deucher 	if (ASIC_IS_DCE4(rdev)) {
39bcc1c2a1SAlex Deucher 		cur_lock = RREG32(EVERGREEN_CUR_UPDATE + radeon_crtc->crtc_offset);
40bcc1c2a1SAlex Deucher 		if (lock)
41bcc1c2a1SAlex Deucher 			cur_lock |= EVERGREEN_CURSOR_UPDATE_LOCK;
42bcc1c2a1SAlex Deucher 		else
43bcc1c2a1SAlex Deucher 			cur_lock &= ~EVERGREEN_CURSOR_UPDATE_LOCK;
44bcc1c2a1SAlex Deucher 		WREG32(EVERGREEN_CUR_UPDATE + radeon_crtc->crtc_offset, cur_lock);
45bcc1c2a1SAlex Deucher 	} else if (ASIC_IS_AVIVO(rdev)) {
46771fe6b9SJerome Glisse 		cur_lock = RREG32(AVIVO_D1CUR_UPDATE + radeon_crtc->crtc_offset);
47771fe6b9SJerome Glisse 		if (lock)
48771fe6b9SJerome Glisse 			cur_lock |= AVIVO_D1CURSOR_UPDATE_LOCK;
49771fe6b9SJerome Glisse 		else
50771fe6b9SJerome Glisse 			cur_lock &= ~AVIVO_D1CURSOR_UPDATE_LOCK;
51771fe6b9SJerome Glisse 		WREG32(AVIVO_D1CUR_UPDATE + radeon_crtc->crtc_offset, cur_lock);
52771fe6b9SJerome Glisse 	} else {
53771fe6b9SJerome Glisse 		cur_lock = RREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset);
54771fe6b9SJerome Glisse 		if (lock)
55771fe6b9SJerome Glisse 			cur_lock |= RADEON_CUR_LOCK;
56771fe6b9SJerome Glisse 		else
57771fe6b9SJerome Glisse 			cur_lock &= ~RADEON_CUR_LOCK;
58771fe6b9SJerome Glisse 		WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, cur_lock);
59771fe6b9SJerome Glisse 	}
60771fe6b9SJerome Glisse }
61771fe6b9SJerome Glisse 
radeon_hide_cursor(struct drm_crtc * crtc)62771fe6b9SJerome Glisse static void radeon_hide_cursor(struct drm_crtc *crtc)
63771fe6b9SJerome Glisse {
64771fe6b9SJerome Glisse 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
65771fe6b9SJerome Glisse 	struct radeon_device *rdev = crtc->dev->dev_private;
66771fe6b9SJerome Glisse 
67bcc1c2a1SAlex Deucher 	if (ASIC_IS_DCE4(rdev)) {
682ef9bdfeSDaniel Vetter 		WREG32_IDX(EVERGREEN_CUR_CONTROL + radeon_crtc->crtc_offset,
692ef9bdfeSDaniel Vetter 			   EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT) |
70f4254a2bSAlex Deucher 			   EVERGREEN_CURSOR_URGENT_CONTROL(EVERGREEN_CURSOR_URGENT_1_2));
71bcc1c2a1SAlex Deucher 	} else if (ASIC_IS_AVIVO(rdev)) {
722ef9bdfeSDaniel Vetter 		WREG32_IDX(AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset,
732ef9bdfeSDaniel Vetter 			   (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT));
74771fe6b9SJerome Glisse 	} else {
752ef9bdfeSDaniel Vetter 		u32 reg;
76771fe6b9SJerome Glisse 		switch (radeon_crtc->crtc_id) {
77771fe6b9SJerome Glisse 		case 0:
782ef9bdfeSDaniel Vetter 			reg = RADEON_CRTC_GEN_CNTL;
79771fe6b9SJerome Glisse 			break;
80771fe6b9SJerome Glisse 		case 1:
812ef9bdfeSDaniel Vetter 			reg = RADEON_CRTC2_GEN_CNTL;
82771fe6b9SJerome Glisse 			break;
83771fe6b9SJerome Glisse 		default:
84771fe6b9SJerome Glisse 			return;
85771fe6b9SJerome Glisse 		}
862ef9bdfeSDaniel Vetter 		WREG32_IDX(reg, RREG32_IDX(reg) & ~RADEON_CRTC_CUR_EN);
87771fe6b9SJerome Glisse 	}
88771fe6b9SJerome Glisse }
89771fe6b9SJerome Glisse 
radeon_show_cursor(struct drm_crtc * crtc)90771fe6b9SJerome Glisse static void radeon_show_cursor(struct drm_crtc *crtc)
91771fe6b9SJerome Glisse {
92771fe6b9SJerome Glisse 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
93771fe6b9SJerome Glisse 	struct radeon_device *rdev = crtc->dev->dev_private;
94771fe6b9SJerome Glisse 
956b16cf77SMichel Dänzer 	if (radeon_crtc->cursor_out_of_bounds)
966b16cf77SMichel Dänzer 		return;
976b16cf77SMichel Dänzer 
98bcc1c2a1SAlex Deucher 	if (ASIC_IS_DCE4(rdev)) {
998991668aSMichel Dänzer 		WREG32(EVERGREEN_CUR_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset,
1008991668aSMichel Dänzer 		       upper_32_bits(radeon_crtc->cursor_addr));
1018991668aSMichel Dänzer 		WREG32(EVERGREEN_CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
1028991668aSMichel Dänzer 		       lower_32_bits(radeon_crtc->cursor_addr));
103bcc1c2a1SAlex Deucher 		WREG32(RADEON_MM_INDEX, EVERGREEN_CUR_CONTROL + radeon_crtc->crtc_offset);
104bcc1c2a1SAlex Deucher 		WREG32(RADEON_MM_DATA, EVERGREEN_CURSOR_EN |
105f4254a2bSAlex Deucher 		       EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT) |
106f4254a2bSAlex Deucher 		       EVERGREEN_CURSOR_URGENT_CONTROL(EVERGREEN_CURSOR_URGENT_1_2));
107bcc1c2a1SAlex Deucher 	} else if (ASIC_IS_AVIVO(rdev)) {
1088991668aSMichel Dänzer 		if (rdev->family >= CHIP_RV770) {
1098991668aSMichel Dänzer 			if (radeon_crtc->crtc_id)
1108991668aSMichel Dänzer 				WREG32(R700_D2CUR_SURFACE_ADDRESS_HIGH,
1118991668aSMichel Dänzer 				       upper_32_bits(radeon_crtc->cursor_addr));
1128991668aSMichel Dänzer 			else
1138991668aSMichel Dänzer 				WREG32(R700_D1CUR_SURFACE_ADDRESS_HIGH,
1148991668aSMichel Dänzer 				       upper_32_bits(radeon_crtc->cursor_addr));
1158991668aSMichel Dänzer 		}
1168991668aSMichel Dänzer 
1178991668aSMichel Dänzer 		WREG32(AVIVO_D1CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
1188991668aSMichel Dänzer 		       lower_32_bits(radeon_crtc->cursor_addr));
119771fe6b9SJerome Glisse 		WREG32(RADEON_MM_INDEX, AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset);
120771fe6b9SJerome Glisse 		WREG32(RADEON_MM_DATA, AVIVO_D1CURSOR_EN |
121771fe6b9SJerome Glisse 		       (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT));
122771fe6b9SJerome Glisse 	} else {
1238991668aSMichel Dänzer 		/* offset is from DISP(2)_BASE_ADDRESS */
1248991668aSMichel Dänzer 		WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset,
1258991668aSMichel Dänzer 		       radeon_crtc->cursor_addr - radeon_crtc->legacy_display_base_addr);
1268991668aSMichel Dänzer 
127771fe6b9SJerome Glisse 		switch (radeon_crtc->crtc_id) {
128771fe6b9SJerome Glisse 		case 0:
129771fe6b9SJerome Glisse 			WREG32(RADEON_MM_INDEX, RADEON_CRTC_GEN_CNTL);
130771fe6b9SJerome Glisse 			break;
131771fe6b9SJerome Glisse 		case 1:
132771fe6b9SJerome Glisse 			WREG32(RADEON_MM_INDEX, RADEON_CRTC2_GEN_CNTL);
133771fe6b9SJerome Glisse 			break;
134771fe6b9SJerome Glisse 		default:
135771fe6b9SJerome Glisse 			return;
136771fe6b9SJerome Glisse 		}
137771fe6b9SJerome Glisse 
138771fe6b9SJerome Glisse 		WREG32_P(RADEON_MM_DATA, (RADEON_CRTC_CUR_EN |
139771fe6b9SJerome Glisse 					  (RADEON_CRTC_CUR_MODE_24BPP << RADEON_CRTC_CUR_MODE_SHIFT)),
140771fe6b9SJerome Glisse 			 ~(RADEON_CRTC_CUR_EN | RADEON_CRTC_CUR_MODE_MASK));
141771fe6b9SJerome Glisse 	}
142771fe6b9SJerome Glisse }
143771fe6b9SJerome Glisse 
radeon_cursor_move_locked(struct drm_crtc * crtc,int x,int y)1443feba08dSMichel Dänzer static int radeon_cursor_move_locked(struct drm_crtc *crtc, int x, int y)
1453feba08dSMichel Dänzer {
1463feba08dSMichel Dänzer 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
1473feba08dSMichel Dänzer 	struct radeon_device *rdev = crtc->dev->dev_private;
1483feba08dSMichel Dänzer 	int xorigin = 0, yorigin = 0;
1493feba08dSMichel Dänzer 	int w = radeon_crtc->cursor_width;
1503feba08dSMichel Dänzer 
1514349bd77SMichel Dänzer 	radeon_crtc->cursor_x = x;
1524349bd77SMichel Dänzer 	radeon_crtc->cursor_y = y;
1534349bd77SMichel Dänzer 
1543feba08dSMichel Dänzer 	if (ASIC_IS_AVIVO(rdev)) {
1553feba08dSMichel Dänzer 		/* avivo cursor are offset into the total surface */
1563feba08dSMichel Dänzer 		x += crtc->x;
1573feba08dSMichel Dänzer 		y += crtc->y;
1583feba08dSMichel Dänzer 	}
1593feba08dSMichel Dänzer 
1606b16cf77SMichel Dänzer 	if (x < 0)
1613feba08dSMichel Dänzer 		xorigin = min(-x, radeon_crtc->max_cursor_width - 1);
1626b16cf77SMichel Dänzer 	if (y < 0)
1633feba08dSMichel Dänzer 		yorigin = min(-y, radeon_crtc->max_cursor_height - 1);
1646b16cf77SMichel Dänzer 
1656b16cf77SMichel Dänzer 	if (!ASIC_IS_AVIVO(rdev)) {
1666b16cf77SMichel Dänzer 		x += crtc->x;
1676b16cf77SMichel Dänzer 		y += crtc->y;
1683feba08dSMichel Dänzer 	}
1696b16cf77SMichel Dänzer 	DRM_DEBUG("x %d y %d c->x %d c->y %d\n", x, y, crtc->x, crtc->y);
1703feba08dSMichel Dänzer 
1713feba08dSMichel Dänzer 	/* fixed on DCE6 and newer */
1723feba08dSMichel Dänzer 	if (ASIC_IS_AVIVO(rdev) && !ASIC_IS_DCE6(rdev)) {
1733feba08dSMichel Dänzer 		int i = 0;
1743feba08dSMichel Dänzer 		struct drm_crtc *crtc_p;
1753feba08dSMichel Dänzer 
1763feba08dSMichel Dänzer 		/*
1773feba08dSMichel Dänzer 		 * avivo cursor image can't end on 128 pixel boundary or
1783feba08dSMichel Dänzer 		 * go past the end of the frame if both crtcs are enabled
1793feba08dSMichel Dänzer 		 *
1803feba08dSMichel Dänzer 		 * NOTE: It is safe to access crtc->enabled of other crtcs
1813feba08dSMichel Dänzer 		 * without holding either the mode_config lock or the other
1823feba08dSMichel Dänzer 		 * crtc's lock as long as write access to this flag _always_
1833feba08dSMichel Dänzer 		 * grabs all locks.
1843feba08dSMichel Dänzer 		 */
1853feba08dSMichel Dänzer 		list_for_each_entry(crtc_p, &crtc->dev->mode_config.crtc_list, head) {
1863feba08dSMichel Dänzer 			if (crtc_p->enabled)
1873feba08dSMichel Dänzer 				i++;
1883feba08dSMichel Dänzer 		}
1893feba08dSMichel Dänzer 		if (i > 1) {
1903feba08dSMichel Dänzer 			int cursor_end, frame_end;
1913feba08dSMichel Dänzer 
1926b16cf77SMichel Dänzer 			cursor_end = x + w;
1933feba08dSMichel Dänzer 			frame_end = crtc->x + crtc->mode.crtc_hdisplay;
1943feba08dSMichel Dänzer 			if (cursor_end >= frame_end) {
1953feba08dSMichel Dänzer 				w = w - (cursor_end - frame_end);
1963feba08dSMichel Dänzer 				if (!(frame_end & 0x7f))
1973feba08dSMichel Dänzer 					w--;
1986b16cf77SMichel Dänzer 			} else if (cursor_end <= 0) {
1996b16cf77SMichel Dänzer 				goto out_of_bounds;
2006b16cf77SMichel Dänzer 			} else if (!(cursor_end & 0x7f)) {
2013feba08dSMichel Dänzer 				w--;
2023feba08dSMichel Dänzer 			}
2033feba08dSMichel Dänzer 			if (w <= 0) {
2046b16cf77SMichel Dänzer 				goto out_of_bounds;
2053feba08dSMichel Dänzer 			}
2063feba08dSMichel Dänzer 		}
2073feba08dSMichel Dänzer 	}
2086b16cf77SMichel Dänzer 
2096b16cf77SMichel Dänzer 	if (x <= (crtc->x - w) || y <= (crtc->y - radeon_crtc->cursor_height) ||
210d74c67ddSMichel Dänzer 	    x >= (crtc->x + crtc->mode.hdisplay) ||
211d74c67ddSMichel Dänzer 	    y >= (crtc->y + crtc->mode.vdisplay))
2126b16cf77SMichel Dänzer 		goto out_of_bounds;
2136b16cf77SMichel Dänzer 
2146b16cf77SMichel Dänzer 	x += xorigin;
2156b16cf77SMichel Dänzer 	y += yorigin;
2163feba08dSMichel Dänzer 
2173feba08dSMichel Dänzer 	if (ASIC_IS_DCE4(rdev)) {
2183feba08dSMichel Dänzer 		WREG32(EVERGREEN_CUR_POSITION + radeon_crtc->crtc_offset, (x << 16) | y);
2193feba08dSMichel Dänzer 		WREG32(EVERGREEN_CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin);
2203feba08dSMichel Dänzer 		WREG32(EVERGREEN_CUR_SIZE + radeon_crtc->crtc_offset,
2213feba08dSMichel Dänzer 		       ((w - 1) << 16) | (radeon_crtc->cursor_height - 1));
2223feba08dSMichel Dänzer 	} else if (ASIC_IS_AVIVO(rdev)) {
2233feba08dSMichel Dänzer 		WREG32(AVIVO_D1CUR_POSITION + radeon_crtc->crtc_offset, (x << 16) | y);
2243feba08dSMichel Dänzer 		WREG32(AVIVO_D1CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin);
2253feba08dSMichel Dänzer 		WREG32(AVIVO_D1CUR_SIZE + radeon_crtc->crtc_offset,
2263feba08dSMichel Dänzer 		       ((w - 1) << 16) | (radeon_crtc->cursor_height - 1));
2273feba08dSMichel Dänzer 	} else {
2286b16cf77SMichel Dänzer 		x -= crtc->x;
2296b16cf77SMichel Dänzer 		y -= crtc->y;
2306b16cf77SMichel Dänzer 
2313feba08dSMichel Dänzer 		if (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN)
2323feba08dSMichel Dänzer 			y *= 2;
2333feba08dSMichel Dänzer 
2343feba08dSMichel Dänzer 		WREG32(RADEON_CUR_HORZ_VERT_OFF + radeon_crtc->crtc_offset,
2353feba08dSMichel Dänzer 		       (RADEON_CUR_LOCK
2363feba08dSMichel Dänzer 			| (xorigin << 16)
2373feba08dSMichel Dänzer 			| yorigin));
2383feba08dSMichel Dänzer 		WREG32(RADEON_CUR_HORZ_VERT_POSN + radeon_crtc->crtc_offset,
2393feba08dSMichel Dänzer 		       (RADEON_CUR_LOCK
2403feba08dSMichel Dänzer 			| (x << 16)
2413feba08dSMichel Dänzer 			| y));
2423feba08dSMichel Dänzer 		/* offset is from DISP(2)_BASE_ADDRESS */
243cd404af0SMichel Dänzer 		WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset,
244cd404af0SMichel Dänzer 		       radeon_crtc->cursor_addr - radeon_crtc->legacy_display_base_addr +
245cd404af0SMichel Dänzer 		       yorigin * 256);
2463feba08dSMichel Dänzer 	}
2473feba08dSMichel Dänzer 
2486b16cf77SMichel Dänzer 	if (radeon_crtc->cursor_out_of_bounds) {
2496b16cf77SMichel Dänzer 		radeon_crtc->cursor_out_of_bounds = false;
2506b16cf77SMichel Dänzer 		if (radeon_crtc->cursor_bo)
2516b16cf77SMichel Dänzer 			radeon_show_cursor(crtc);
2526b16cf77SMichel Dänzer 	}
2536b16cf77SMichel Dänzer 
2546b16cf77SMichel Dänzer 	return 0;
2556b16cf77SMichel Dänzer 
2566b16cf77SMichel Dänzer  out_of_bounds:
2576b16cf77SMichel Dänzer 	if (!radeon_crtc->cursor_out_of_bounds) {
2586b16cf77SMichel Dänzer 		radeon_hide_cursor(crtc);
2596b16cf77SMichel Dänzer 		radeon_crtc->cursor_out_of_bounds = true;
2606b16cf77SMichel Dänzer 	}
2613feba08dSMichel Dänzer 	return 0;
2623feba08dSMichel Dänzer }
2633feba08dSMichel Dänzer 
radeon_crtc_cursor_move(struct drm_crtc * crtc,int x,int y)2643feba08dSMichel Dänzer int radeon_crtc_cursor_move(struct drm_crtc *crtc,
2653feba08dSMichel Dänzer 			    int x, int y)
2663feba08dSMichel Dänzer {
2673feba08dSMichel Dänzer 	int ret;
2683feba08dSMichel Dänzer 
2693feba08dSMichel Dänzer 	radeon_lock_cursor(crtc, true);
2703feba08dSMichel Dänzer 	ret = radeon_cursor_move_locked(crtc, x, y);
2713feba08dSMichel Dänzer 	radeon_lock_cursor(crtc, false);
2723feba08dSMichel Dänzer 
2733feba08dSMichel Dänzer 	return ret;
2743feba08dSMichel Dänzer }
27578b1a601SMichel Dänzer 
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)27678b1a601SMichel Dänzer int radeon_crtc_cursor_set2(struct drm_crtc *crtc,
277771fe6b9SJerome Glisse 			    struct drm_file *file_priv,
278771fe6b9SJerome Glisse 			    uint32_t handle,
279771fe6b9SJerome Glisse 			    uint32_t width,
28078b1a601SMichel Dänzer 			    uint32_t height,
28178b1a601SMichel Dänzer 			    int32_t hot_x,
28278b1a601SMichel Dänzer 			    int32_t hot_y)
283771fe6b9SJerome Glisse {
284771fe6b9SJerome Glisse 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
285cd404af0SMichel Dänzer 	struct radeon_device *rdev = crtc->dev->dev_private;
286771fe6b9SJerome Glisse 	struct drm_gem_object *obj;
287cd404af0SMichel Dänzer 	struct radeon_bo *robj;
288771fe6b9SJerome Glisse 	int ret;
289771fe6b9SJerome Glisse 
290771fe6b9SJerome Glisse 	if (!handle) {
291771fe6b9SJerome Glisse 		/* turn off cursor */
292771fe6b9SJerome Glisse 		radeon_hide_cursor(crtc);
293771fe6b9SJerome Glisse 		obj = NULL;
294771fe6b9SJerome Glisse 		goto unpin;
295771fe6b9SJerome Glisse 	}
296771fe6b9SJerome Glisse 
2979e05fa1dSAlex Deucher 	if ((width > radeon_crtc->max_cursor_width) ||
2989e05fa1dSAlex Deucher 	    (height > radeon_crtc->max_cursor_height)) {
299771fe6b9SJerome Glisse 		DRM_ERROR("bad cursor width or height %d x %d\n", width, height);
300771fe6b9SJerome Glisse 		return -EINVAL;
301771fe6b9SJerome Glisse 	}
302771fe6b9SJerome Glisse 
303a8ad0bd8SChris Wilson 	obj = drm_gem_object_lookup(file_priv, handle);
304771fe6b9SJerome Glisse 	if (!obj) {
305771fe6b9SJerome Glisse 		DRM_ERROR("Cannot find cursor object %x for crtc %d\n", handle, radeon_crtc->crtc_id);
306bf79cb91SChris Wilson 		return -ENOENT;
307771fe6b9SJerome Glisse 	}
308771fe6b9SJerome Glisse 
309cd404af0SMichel Dänzer 	robj = gem_to_radeon_bo(obj);
310cd404af0SMichel Dänzer 	ret = radeon_bo_reserve(robj, false);
311cd404af0SMichel Dänzer 	if (ret != 0) {
312*f11fb66aSEmil Velikov 		drm_gem_object_put(obj);
313cd404af0SMichel Dänzer 		return ret;
314cd404af0SMichel Dänzer 	}
315cd404af0SMichel Dänzer 	/* Only 27 bit offset for legacy cursor */
316cd404af0SMichel Dänzer 	ret = radeon_bo_pin_restricted(robj, RADEON_GEM_DOMAIN_VRAM,
317cd404af0SMichel Dänzer 				       ASIC_IS_AVIVO(rdev) ? 0 : 1 << 27,
318cd404af0SMichel Dänzer 				       &radeon_crtc->cursor_addr);
319cd404af0SMichel Dänzer 	radeon_bo_unreserve(robj);
320cd404af0SMichel Dänzer 	if (ret) {
321cd404af0SMichel Dänzer 		DRM_ERROR("Failed to pin new cursor BO (%d)\n", ret);
322*f11fb66aSEmil Velikov 		drm_gem_object_put(obj);
323cd404af0SMichel Dänzer 		return ret;
324cd404af0SMichel Dänzer 	}
325cd404af0SMichel Dänzer 
326771fe6b9SJerome Glisse 	radeon_lock_cursor(crtc, true);
3272e007e61SMichel Dänzer 
328dcab0fa6SMichel Dänzer 	if (width != radeon_crtc->cursor_width ||
329dcab0fa6SMichel Dänzer 	    height != radeon_crtc->cursor_height ||
330dcab0fa6SMichel Dänzer 	    hot_x != radeon_crtc->cursor_hot_x ||
3312e007e61SMichel Dänzer 	    hot_y != radeon_crtc->cursor_hot_y) {
3322e007e61SMichel Dänzer 		int x, y;
3332e007e61SMichel Dänzer 
3342e007e61SMichel Dänzer 		x = radeon_crtc->cursor_x + radeon_crtc->cursor_hot_x - hot_x;
3352e007e61SMichel Dänzer 		y = radeon_crtc->cursor_y + radeon_crtc->cursor_hot_y - hot_y;
3362e007e61SMichel Dänzer 
337dcab0fa6SMichel Dänzer 		radeon_crtc->cursor_width = width;
338dcab0fa6SMichel Dänzer 		radeon_crtc->cursor_height = height;
3392e007e61SMichel Dänzer 		radeon_crtc->cursor_hot_x = hot_x;
3402e007e61SMichel Dänzer 		radeon_crtc->cursor_hot_y = hot_y;
3416b16cf77SMichel Dänzer 
3426b16cf77SMichel Dänzer 		radeon_cursor_move_locked(crtc, x, y);
3432e007e61SMichel Dänzer 	}
3442e007e61SMichel Dänzer 
345771fe6b9SJerome Glisse 	radeon_show_cursor(crtc);
3466d3759faSMichel Dänzer 
347771fe6b9SJerome Glisse 	radeon_lock_cursor(crtc, false);
348771fe6b9SJerome Glisse 
349771fe6b9SJerome Glisse unpin:
350771fe6b9SJerome Glisse 	if (radeon_crtc->cursor_bo) {
3516d3759faSMichel Dänzer 		struct radeon_bo *robj = gem_to_radeon_bo(radeon_crtc->cursor_bo);
352654c59cfSMichel Dänzer 		ret = radeon_bo_reserve(robj, false);
353654c59cfSMichel Dänzer 		if (likely(ret == 0)) {
354654c59cfSMichel Dänzer 			radeon_bo_unpin(robj);
355654c59cfSMichel Dänzer 			radeon_bo_unreserve(robj);
356654c59cfSMichel Dänzer 		}
357*f11fb66aSEmil Velikov 		drm_gem_object_put(radeon_crtc->cursor_bo);
358771fe6b9SJerome Glisse 	}
359771fe6b9SJerome Glisse 
360771fe6b9SJerome Glisse 	radeon_crtc->cursor_bo = obj;
361771fe6b9SJerome Glisse 	return 0;
3626d3759faSMichel Dänzer }
363771fe6b9SJerome Glisse 
3646d3759faSMichel Dänzer /**
3656d3759faSMichel Dänzer  * radeon_cursor_reset - Re-set the current cursor, if any.
3666d3759faSMichel Dänzer  *
3676d3759faSMichel Dänzer  * @crtc: drm crtc
3686d3759faSMichel Dänzer  *
3696d3759faSMichel Dänzer  * If the CRTC passed in currently has a cursor assigned, this function
3706d3759faSMichel Dänzer  * makes sure it's visible.
3716d3759faSMichel Dänzer  */
radeon_cursor_reset(struct drm_crtc * crtc)3726d3759faSMichel Dänzer void radeon_cursor_reset(struct drm_crtc *crtc)
3736d3759faSMichel Dänzer {
3746d3759faSMichel Dänzer 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
3756d3759faSMichel Dänzer 
3766d3759faSMichel Dänzer 	if (radeon_crtc->cursor_bo) {
3776d3759faSMichel Dänzer 		radeon_lock_cursor(crtc, true);
3786d3759faSMichel Dänzer 
3796d3759faSMichel Dänzer 		radeon_cursor_move_locked(crtc, radeon_crtc->cursor_x,
3806d3759faSMichel Dänzer 					  radeon_crtc->cursor_y);
3816d3759faSMichel Dänzer 
3826d3759faSMichel Dänzer 		radeon_show_cursor(crtc);
3836d3759faSMichel Dänzer 
3846d3759faSMichel Dänzer 		radeon_lock_cursor(crtc, false);
3856d3759faSMichel Dänzer 	}
386771fe6b9SJerome Glisse }
387