18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright 2007-8 Advanced Micro Devices, Inc.
38c2ecf20Sopenharmony_ci * Copyright 2008 Red Hat Inc.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
68c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
78c2ecf20Sopenharmony_ci * to deal in the Software without restriction, including without limitation
88c2ecf20Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
98c2ecf20Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
108c2ecf20Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice shall be included in
138c2ecf20Sopenharmony_ci * all copies or substantial portions of the Software.
148c2ecf20Sopenharmony_ci *
158c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
168c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
178c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
188c2ecf20Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
198c2ecf20Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
208c2ecf20Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
218c2ecf20Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE.
228c2ecf20Sopenharmony_ci *
238c2ecf20Sopenharmony_ci * Authors: Dave Airlie
248c2ecf20Sopenharmony_ci *          Alex Deucher
258c2ecf20Sopenharmony_ci */
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#include <drm/drm_device.h>
288c2ecf20Sopenharmony_ci#include <drm/radeon_drm.h>
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#include "radeon.h"
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_cistatic void radeon_lock_cursor(struct drm_crtc *crtc, bool lock)
338c2ecf20Sopenharmony_ci{
348c2ecf20Sopenharmony_ci	struct radeon_device *rdev = crtc->dev->dev_private;
358c2ecf20Sopenharmony_ci	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
368c2ecf20Sopenharmony_ci	uint32_t cur_lock;
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci	if (ASIC_IS_DCE4(rdev)) {
398c2ecf20Sopenharmony_ci		cur_lock = RREG32(EVERGREEN_CUR_UPDATE + radeon_crtc->crtc_offset);
408c2ecf20Sopenharmony_ci		if (lock)
418c2ecf20Sopenharmony_ci			cur_lock |= EVERGREEN_CURSOR_UPDATE_LOCK;
428c2ecf20Sopenharmony_ci		else
438c2ecf20Sopenharmony_ci			cur_lock &= ~EVERGREEN_CURSOR_UPDATE_LOCK;
448c2ecf20Sopenharmony_ci		WREG32(EVERGREEN_CUR_UPDATE + radeon_crtc->crtc_offset, cur_lock);
458c2ecf20Sopenharmony_ci	} else if (ASIC_IS_AVIVO(rdev)) {
468c2ecf20Sopenharmony_ci		cur_lock = RREG32(AVIVO_D1CUR_UPDATE + radeon_crtc->crtc_offset);
478c2ecf20Sopenharmony_ci		if (lock)
488c2ecf20Sopenharmony_ci			cur_lock |= AVIVO_D1CURSOR_UPDATE_LOCK;
498c2ecf20Sopenharmony_ci		else
508c2ecf20Sopenharmony_ci			cur_lock &= ~AVIVO_D1CURSOR_UPDATE_LOCK;
518c2ecf20Sopenharmony_ci		WREG32(AVIVO_D1CUR_UPDATE + radeon_crtc->crtc_offset, cur_lock);
528c2ecf20Sopenharmony_ci	} else {
538c2ecf20Sopenharmony_ci		cur_lock = RREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset);
548c2ecf20Sopenharmony_ci		if (lock)
558c2ecf20Sopenharmony_ci			cur_lock |= RADEON_CUR_LOCK;
568c2ecf20Sopenharmony_ci		else
578c2ecf20Sopenharmony_ci			cur_lock &= ~RADEON_CUR_LOCK;
588c2ecf20Sopenharmony_ci		WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, cur_lock);
598c2ecf20Sopenharmony_ci	}
608c2ecf20Sopenharmony_ci}
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_cistatic void radeon_hide_cursor(struct drm_crtc *crtc)
638c2ecf20Sopenharmony_ci{
648c2ecf20Sopenharmony_ci	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
658c2ecf20Sopenharmony_ci	struct radeon_device *rdev = crtc->dev->dev_private;
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	if (ASIC_IS_DCE4(rdev)) {
688c2ecf20Sopenharmony_ci		WREG32_IDX(EVERGREEN_CUR_CONTROL + radeon_crtc->crtc_offset,
698c2ecf20Sopenharmony_ci			   EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT) |
708c2ecf20Sopenharmony_ci			   EVERGREEN_CURSOR_URGENT_CONTROL(EVERGREEN_CURSOR_URGENT_1_2));
718c2ecf20Sopenharmony_ci	} else if (ASIC_IS_AVIVO(rdev)) {
728c2ecf20Sopenharmony_ci		WREG32_IDX(AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset,
738c2ecf20Sopenharmony_ci			   (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT));
748c2ecf20Sopenharmony_ci	} else {
758c2ecf20Sopenharmony_ci		u32 reg;
768c2ecf20Sopenharmony_ci		switch (radeon_crtc->crtc_id) {
778c2ecf20Sopenharmony_ci		case 0:
788c2ecf20Sopenharmony_ci			reg = RADEON_CRTC_GEN_CNTL;
798c2ecf20Sopenharmony_ci			break;
808c2ecf20Sopenharmony_ci		case 1:
818c2ecf20Sopenharmony_ci			reg = RADEON_CRTC2_GEN_CNTL;
828c2ecf20Sopenharmony_ci			break;
838c2ecf20Sopenharmony_ci		default:
848c2ecf20Sopenharmony_ci			return;
858c2ecf20Sopenharmony_ci		}
868c2ecf20Sopenharmony_ci		WREG32_IDX(reg, RREG32_IDX(reg) & ~RADEON_CRTC_CUR_EN);
878c2ecf20Sopenharmony_ci	}
888c2ecf20Sopenharmony_ci}
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_cistatic void radeon_show_cursor(struct drm_crtc *crtc)
918c2ecf20Sopenharmony_ci{
928c2ecf20Sopenharmony_ci	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
938c2ecf20Sopenharmony_ci	struct radeon_device *rdev = crtc->dev->dev_private;
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	if (radeon_crtc->cursor_out_of_bounds)
968c2ecf20Sopenharmony_ci		return;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	if (ASIC_IS_DCE4(rdev)) {
998c2ecf20Sopenharmony_ci		WREG32(EVERGREEN_CUR_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset,
1008c2ecf20Sopenharmony_ci		       upper_32_bits(radeon_crtc->cursor_addr));
1018c2ecf20Sopenharmony_ci		WREG32(EVERGREEN_CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
1028c2ecf20Sopenharmony_ci		       lower_32_bits(radeon_crtc->cursor_addr));
1038c2ecf20Sopenharmony_ci		WREG32(RADEON_MM_INDEX, EVERGREEN_CUR_CONTROL + radeon_crtc->crtc_offset);
1048c2ecf20Sopenharmony_ci		WREG32(RADEON_MM_DATA, EVERGREEN_CURSOR_EN |
1058c2ecf20Sopenharmony_ci		       EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT) |
1068c2ecf20Sopenharmony_ci		       EVERGREEN_CURSOR_URGENT_CONTROL(EVERGREEN_CURSOR_URGENT_1_2));
1078c2ecf20Sopenharmony_ci	} else if (ASIC_IS_AVIVO(rdev)) {
1088c2ecf20Sopenharmony_ci		if (rdev->family >= CHIP_RV770) {
1098c2ecf20Sopenharmony_ci			if (radeon_crtc->crtc_id)
1108c2ecf20Sopenharmony_ci				WREG32(R700_D2CUR_SURFACE_ADDRESS_HIGH,
1118c2ecf20Sopenharmony_ci				       upper_32_bits(radeon_crtc->cursor_addr));
1128c2ecf20Sopenharmony_ci			else
1138c2ecf20Sopenharmony_ci				WREG32(R700_D1CUR_SURFACE_ADDRESS_HIGH,
1148c2ecf20Sopenharmony_ci				       upper_32_bits(radeon_crtc->cursor_addr));
1158c2ecf20Sopenharmony_ci		}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci		WREG32(AVIVO_D1CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
1188c2ecf20Sopenharmony_ci		       lower_32_bits(radeon_crtc->cursor_addr));
1198c2ecf20Sopenharmony_ci		WREG32(RADEON_MM_INDEX, AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset);
1208c2ecf20Sopenharmony_ci		WREG32(RADEON_MM_DATA, AVIVO_D1CURSOR_EN |
1218c2ecf20Sopenharmony_ci		       (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT));
1228c2ecf20Sopenharmony_ci	} else {
1238c2ecf20Sopenharmony_ci		/* offset is from DISP(2)_BASE_ADDRESS */
1248c2ecf20Sopenharmony_ci		WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset,
1258c2ecf20Sopenharmony_ci		       radeon_crtc->cursor_addr - radeon_crtc->legacy_display_base_addr);
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci		switch (radeon_crtc->crtc_id) {
1288c2ecf20Sopenharmony_ci		case 0:
1298c2ecf20Sopenharmony_ci			WREG32(RADEON_MM_INDEX, RADEON_CRTC_GEN_CNTL);
1308c2ecf20Sopenharmony_ci			break;
1318c2ecf20Sopenharmony_ci		case 1:
1328c2ecf20Sopenharmony_ci			WREG32(RADEON_MM_INDEX, RADEON_CRTC2_GEN_CNTL);
1338c2ecf20Sopenharmony_ci			break;
1348c2ecf20Sopenharmony_ci		default:
1358c2ecf20Sopenharmony_ci			return;
1368c2ecf20Sopenharmony_ci		}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci		WREG32_P(RADEON_MM_DATA, (RADEON_CRTC_CUR_EN |
1398c2ecf20Sopenharmony_ci					  (RADEON_CRTC_CUR_MODE_24BPP << RADEON_CRTC_CUR_MODE_SHIFT)),
1408c2ecf20Sopenharmony_ci			 ~(RADEON_CRTC_CUR_EN | RADEON_CRTC_CUR_MODE_MASK));
1418c2ecf20Sopenharmony_ci	}
1428c2ecf20Sopenharmony_ci}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_cistatic int radeon_cursor_move_locked(struct drm_crtc *crtc, int x, int y)
1458c2ecf20Sopenharmony_ci{
1468c2ecf20Sopenharmony_ci	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
1478c2ecf20Sopenharmony_ci	struct radeon_device *rdev = crtc->dev->dev_private;
1488c2ecf20Sopenharmony_ci	int xorigin = 0, yorigin = 0;
1498c2ecf20Sopenharmony_ci	int w = radeon_crtc->cursor_width;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	radeon_crtc->cursor_x = x;
1528c2ecf20Sopenharmony_ci	radeon_crtc->cursor_y = y;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	if (ASIC_IS_AVIVO(rdev)) {
1558c2ecf20Sopenharmony_ci		/* avivo cursor are offset into the total surface */
1568c2ecf20Sopenharmony_ci		x += crtc->x;
1578c2ecf20Sopenharmony_ci		y += crtc->y;
1588c2ecf20Sopenharmony_ci	}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	if (x < 0)
1618c2ecf20Sopenharmony_ci		xorigin = min(-x, radeon_crtc->max_cursor_width - 1);
1628c2ecf20Sopenharmony_ci	if (y < 0)
1638c2ecf20Sopenharmony_ci		yorigin = min(-y, radeon_crtc->max_cursor_height - 1);
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	if (!ASIC_IS_AVIVO(rdev)) {
1668c2ecf20Sopenharmony_ci		x += crtc->x;
1678c2ecf20Sopenharmony_ci		y += crtc->y;
1688c2ecf20Sopenharmony_ci	}
1698c2ecf20Sopenharmony_ci	DRM_DEBUG("x %d y %d c->x %d c->y %d\n", x, y, crtc->x, crtc->y);
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	/* fixed on DCE6 and newer */
1728c2ecf20Sopenharmony_ci	if (ASIC_IS_AVIVO(rdev) && !ASIC_IS_DCE6(rdev)) {
1738c2ecf20Sopenharmony_ci		int i = 0;
1748c2ecf20Sopenharmony_ci		struct drm_crtc *crtc_p;
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci		/*
1778c2ecf20Sopenharmony_ci		 * avivo cursor image can't end on 128 pixel boundary or
1788c2ecf20Sopenharmony_ci		 * go past the end of the frame if both crtcs are enabled
1798c2ecf20Sopenharmony_ci		 *
1808c2ecf20Sopenharmony_ci		 * NOTE: It is safe to access crtc->enabled of other crtcs
1818c2ecf20Sopenharmony_ci		 * without holding either the mode_config lock or the other
1828c2ecf20Sopenharmony_ci		 * crtc's lock as long as write access to this flag _always_
1838c2ecf20Sopenharmony_ci		 * grabs all locks.
1848c2ecf20Sopenharmony_ci		 */
1858c2ecf20Sopenharmony_ci		list_for_each_entry(crtc_p, &crtc->dev->mode_config.crtc_list, head) {
1868c2ecf20Sopenharmony_ci			if (crtc_p->enabled)
1878c2ecf20Sopenharmony_ci				i++;
1888c2ecf20Sopenharmony_ci		}
1898c2ecf20Sopenharmony_ci		if (i > 1) {
1908c2ecf20Sopenharmony_ci			int cursor_end, frame_end;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci			cursor_end = x + w;
1938c2ecf20Sopenharmony_ci			frame_end = crtc->x + crtc->mode.crtc_hdisplay;
1948c2ecf20Sopenharmony_ci			if (cursor_end >= frame_end) {
1958c2ecf20Sopenharmony_ci				w = w - (cursor_end - frame_end);
1968c2ecf20Sopenharmony_ci				if (!(frame_end & 0x7f))
1978c2ecf20Sopenharmony_ci					w--;
1988c2ecf20Sopenharmony_ci			} else if (cursor_end <= 0) {
1998c2ecf20Sopenharmony_ci				goto out_of_bounds;
2008c2ecf20Sopenharmony_ci			} else if (!(cursor_end & 0x7f)) {
2018c2ecf20Sopenharmony_ci				w--;
2028c2ecf20Sopenharmony_ci			}
2038c2ecf20Sopenharmony_ci			if (w <= 0) {
2048c2ecf20Sopenharmony_ci				goto out_of_bounds;
2058c2ecf20Sopenharmony_ci			}
2068c2ecf20Sopenharmony_ci		}
2078c2ecf20Sopenharmony_ci	}
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	if (x <= (crtc->x - w) || y <= (crtc->y - radeon_crtc->cursor_height) ||
2108c2ecf20Sopenharmony_ci	    x >= (crtc->x + crtc->mode.hdisplay) ||
2118c2ecf20Sopenharmony_ci	    y >= (crtc->y + crtc->mode.vdisplay))
2128c2ecf20Sopenharmony_ci		goto out_of_bounds;
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	x += xorigin;
2158c2ecf20Sopenharmony_ci	y += yorigin;
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	if (ASIC_IS_DCE4(rdev)) {
2188c2ecf20Sopenharmony_ci		WREG32(EVERGREEN_CUR_POSITION + radeon_crtc->crtc_offset, (x << 16) | y);
2198c2ecf20Sopenharmony_ci		WREG32(EVERGREEN_CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin);
2208c2ecf20Sopenharmony_ci		WREG32(EVERGREEN_CUR_SIZE + radeon_crtc->crtc_offset,
2218c2ecf20Sopenharmony_ci		       ((w - 1) << 16) | (radeon_crtc->cursor_height - 1));
2228c2ecf20Sopenharmony_ci	} else if (ASIC_IS_AVIVO(rdev)) {
2238c2ecf20Sopenharmony_ci		WREG32(AVIVO_D1CUR_POSITION + radeon_crtc->crtc_offset, (x << 16) | y);
2248c2ecf20Sopenharmony_ci		WREG32(AVIVO_D1CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin);
2258c2ecf20Sopenharmony_ci		WREG32(AVIVO_D1CUR_SIZE + radeon_crtc->crtc_offset,
2268c2ecf20Sopenharmony_ci		       ((w - 1) << 16) | (radeon_crtc->cursor_height - 1));
2278c2ecf20Sopenharmony_ci	} else {
2288c2ecf20Sopenharmony_ci		x -= crtc->x;
2298c2ecf20Sopenharmony_ci		y -= crtc->y;
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci		if (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN)
2328c2ecf20Sopenharmony_ci			y *= 2;
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci		WREG32(RADEON_CUR_HORZ_VERT_OFF + radeon_crtc->crtc_offset,
2358c2ecf20Sopenharmony_ci		       (RADEON_CUR_LOCK
2368c2ecf20Sopenharmony_ci			| (xorigin << 16)
2378c2ecf20Sopenharmony_ci			| yorigin));
2388c2ecf20Sopenharmony_ci		WREG32(RADEON_CUR_HORZ_VERT_POSN + radeon_crtc->crtc_offset,
2398c2ecf20Sopenharmony_ci		       (RADEON_CUR_LOCK
2408c2ecf20Sopenharmony_ci			| (x << 16)
2418c2ecf20Sopenharmony_ci			| y));
2428c2ecf20Sopenharmony_ci		/* offset is from DISP(2)_BASE_ADDRESS */
2438c2ecf20Sopenharmony_ci		WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset,
2448c2ecf20Sopenharmony_ci		       radeon_crtc->cursor_addr - radeon_crtc->legacy_display_base_addr +
2458c2ecf20Sopenharmony_ci		       yorigin * 256);
2468c2ecf20Sopenharmony_ci	}
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	if (radeon_crtc->cursor_out_of_bounds) {
2498c2ecf20Sopenharmony_ci		radeon_crtc->cursor_out_of_bounds = false;
2508c2ecf20Sopenharmony_ci		if (radeon_crtc->cursor_bo)
2518c2ecf20Sopenharmony_ci			radeon_show_cursor(crtc);
2528c2ecf20Sopenharmony_ci	}
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	return 0;
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci out_of_bounds:
2578c2ecf20Sopenharmony_ci	if (!radeon_crtc->cursor_out_of_bounds) {
2588c2ecf20Sopenharmony_ci		radeon_hide_cursor(crtc);
2598c2ecf20Sopenharmony_ci		radeon_crtc->cursor_out_of_bounds = true;
2608c2ecf20Sopenharmony_ci	}
2618c2ecf20Sopenharmony_ci	return 0;
2628c2ecf20Sopenharmony_ci}
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ciint radeon_crtc_cursor_move(struct drm_crtc *crtc,
2658c2ecf20Sopenharmony_ci			    int x, int y)
2668c2ecf20Sopenharmony_ci{
2678c2ecf20Sopenharmony_ci	int ret;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	radeon_lock_cursor(crtc, true);
2708c2ecf20Sopenharmony_ci	ret = radeon_cursor_move_locked(crtc, x, y);
2718c2ecf20Sopenharmony_ci	radeon_lock_cursor(crtc, false);
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	return ret;
2748c2ecf20Sopenharmony_ci}
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ciint radeon_crtc_cursor_set2(struct drm_crtc *crtc,
2778c2ecf20Sopenharmony_ci			    struct drm_file *file_priv,
2788c2ecf20Sopenharmony_ci			    uint32_t handle,
2798c2ecf20Sopenharmony_ci			    uint32_t width,
2808c2ecf20Sopenharmony_ci			    uint32_t height,
2818c2ecf20Sopenharmony_ci			    int32_t hot_x,
2828c2ecf20Sopenharmony_ci			    int32_t hot_y)
2838c2ecf20Sopenharmony_ci{
2848c2ecf20Sopenharmony_ci	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
2858c2ecf20Sopenharmony_ci	struct radeon_device *rdev = crtc->dev->dev_private;
2868c2ecf20Sopenharmony_ci	struct drm_gem_object *obj;
2878c2ecf20Sopenharmony_ci	struct radeon_bo *robj;
2888c2ecf20Sopenharmony_ci	int ret;
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	if (!handle) {
2918c2ecf20Sopenharmony_ci		/* turn off cursor */
2928c2ecf20Sopenharmony_ci		radeon_hide_cursor(crtc);
2938c2ecf20Sopenharmony_ci		obj = NULL;
2948c2ecf20Sopenharmony_ci		goto unpin;
2958c2ecf20Sopenharmony_ci	}
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	if ((width > radeon_crtc->max_cursor_width) ||
2988c2ecf20Sopenharmony_ci	    (height > radeon_crtc->max_cursor_height)) {
2998c2ecf20Sopenharmony_ci		DRM_ERROR("bad cursor width or height %d x %d\n", width, height);
3008c2ecf20Sopenharmony_ci		return -EINVAL;
3018c2ecf20Sopenharmony_ci	}
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	obj = drm_gem_object_lookup(file_priv, handle);
3048c2ecf20Sopenharmony_ci	if (!obj) {
3058c2ecf20Sopenharmony_ci		DRM_ERROR("Cannot find cursor object %x for crtc %d\n", handle, radeon_crtc->crtc_id);
3068c2ecf20Sopenharmony_ci		return -ENOENT;
3078c2ecf20Sopenharmony_ci	}
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	robj = gem_to_radeon_bo(obj);
3108c2ecf20Sopenharmony_ci	ret = radeon_bo_reserve(robj, false);
3118c2ecf20Sopenharmony_ci	if (ret != 0) {
3128c2ecf20Sopenharmony_ci		drm_gem_object_put(obj);
3138c2ecf20Sopenharmony_ci		return ret;
3148c2ecf20Sopenharmony_ci	}
3158c2ecf20Sopenharmony_ci	/* Only 27 bit offset for legacy cursor */
3168c2ecf20Sopenharmony_ci	ret = radeon_bo_pin_restricted(robj, RADEON_GEM_DOMAIN_VRAM,
3178c2ecf20Sopenharmony_ci				       ASIC_IS_AVIVO(rdev) ? 0 : 1 << 27,
3188c2ecf20Sopenharmony_ci				       &radeon_crtc->cursor_addr);
3198c2ecf20Sopenharmony_ci	radeon_bo_unreserve(robj);
3208c2ecf20Sopenharmony_ci	if (ret) {
3218c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to pin new cursor BO (%d)\n", ret);
3228c2ecf20Sopenharmony_ci		drm_gem_object_put(obj);
3238c2ecf20Sopenharmony_ci		return ret;
3248c2ecf20Sopenharmony_ci	}
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	radeon_lock_cursor(crtc, true);
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	if (width != radeon_crtc->cursor_width ||
3298c2ecf20Sopenharmony_ci	    height != radeon_crtc->cursor_height ||
3308c2ecf20Sopenharmony_ci	    hot_x != radeon_crtc->cursor_hot_x ||
3318c2ecf20Sopenharmony_ci	    hot_y != radeon_crtc->cursor_hot_y) {
3328c2ecf20Sopenharmony_ci		int x, y;
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci		x = radeon_crtc->cursor_x + radeon_crtc->cursor_hot_x - hot_x;
3358c2ecf20Sopenharmony_ci		y = radeon_crtc->cursor_y + radeon_crtc->cursor_hot_y - hot_y;
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci		radeon_crtc->cursor_width = width;
3388c2ecf20Sopenharmony_ci		radeon_crtc->cursor_height = height;
3398c2ecf20Sopenharmony_ci		radeon_crtc->cursor_hot_x = hot_x;
3408c2ecf20Sopenharmony_ci		radeon_crtc->cursor_hot_y = hot_y;
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci		radeon_cursor_move_locked(crtc, x, y);
3438c2ecf20Sopenharmony_ci	}
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	radeon_show_cursor(crtc);
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	radeon_lock_cursor(crtc, false);
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ciunpin:
3508c2ecf20Sopenharmony_ci	if (radeon_crtc->cursor_bo) {
3518c2ecf20Sopenharmony_ci		struct radeon_bo *robj = gem_to_radeon_bo(radeon_crtc->cursor_bo);
3528c2ecf20Sopenharmony_ci		ret = radeon_bo_reserve(robj, false);
3538c2ecf20Sopenharmony_ci		if (likely(ret == 0)) {
3548c2ecf20Sopenharmony_ci			radeon_bo_unpin(robj);
3558c2ecf20Sopenharmony_ci			radeon_bo_unreserve(robj);
3568c2ecf20Sopenharmony_ci		}
3578c2ecf20Sopenharmony_ci		drm_gem_object_put(radeon_crtc->cursor_bo);
3588c2ecf20Sopenharmony_ci	}
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	radeon_crtc->cursor_bo = obj;
3618c2ecf20Sopenharmony_ci	return 0;
3628c2ecf20Sopenharmony_ci}
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci/**
3658c2ecf20Sopenharmony_ci * radeon_cursor_reset - Re-set the current cursor, if any.
3668c2ecf20Sopenharmony_ci *
3678c2ecf20Sopenharmony_ci * @crtc: drm crtc
3688c2ecf20Sopenharmony_ci *
3698c2ecf20Sopenharmony_ci * If the CRTC passed in currently has a cursor assigned, this function
3708c2ecf20Sopenharmony_ci * makes sure it's visible.
3718c2ecf20Sopenharmony_ci */
3728c2ecf20Sopenharmony_civoid radeon_cursor_reset(struct drm_crtc *crtc)
3738c2ecf20Sopenharmony_ci{
3748c2ecf20Sopenharmony_ci	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	if (radeon_crtc->cursor_bo) {
3778c2ecf20Sopenharmony_ci		radeon_lock_cursor(crtc, true);
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci		radeon_cursor_move_locked(crtc, radeon_crtc->cursor_x,
3808c2ecf20Sopenharmony_ci					  radeon_crtc->cursor_y);
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci		radeon_show_cursor(crtc);
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci		radeon_lock_cursor(crtc, false);
3858c2ecf20Sopenharmony_ci	}
3868c2ecf20Sopenharmony_ci}
387