162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright 2007-8 Advanced Micro Devices, Inc.
362306a36Sopenharmony_ci * Copyright 2008 Red Hat Inc.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
662306a36Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
762306a36Sopenharmony_ci * to deal in the Software without restriction, including without limitation
862306a36Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
962306a36Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
1062306a36Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci * The above copyright notice and this permission notice shall be included in
1362306a36Sopenharmony_ci * all copies or substantial portions of the Software.
1462306a36Sopenharmony_ci *
1562306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1662306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1762306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1862306a36Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
1962306a36Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
2062306a36Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2162306a36Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE.
2262306a36Sopenharmony_ci *
2362306a36Sopenharmony_ci * Authors: Dave Airlie
2462306a36Sopenharmony_ci *          Alex Deucher
2562306a36Sopenharmony_ci */
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#include <drm/drm_device.h>
2862306a36Sopenharmony_ci#include <drm/radeon_drm.h>
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#include "radeon.h"
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cistatic void radeon_lock_cursor(struct drm_crtc *crtc, bool lock)
3362306a36Sopenharmony_ci{
3462306a36Sopenharmony_ci	struct radeon_device *rdev = crtc->dev->dev_private;
3562306a36Sopenharmony_ci	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
3662306a36Sopenharmony_ci	uint32_t cur_lock;
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	if (ASIC_IS_DCE4(rdev)) {
3962306a36Sopenharmony_ci		cur_lock = RREG32(EVERGREEN_CUR_UPDATE + radeon_crtc->crtc_offset);
4062306a36Sopenharmony_ci		if (lock)
4162306a36Sopenharmony_ci			cur_lock |= EVERGREEN_CURSOR_UPDATE_LOCK;
4262306a36Sopenharmony_ci		else
4362306a36Sopenharmony_ci			cur_lock &= ~EVERGREEN_CURSOR_UPDATE_LOCK;
4462306a36Sopenharmony_ci		WREG32(EVERGREEN_CUR_UPDATE + radeon_crtc->crtc_offset, cur_lock);
4562306a36Sopenharmony_ci	} else if (ASIC_IS_AVIVO(rdev)) {
4662306a36Sopenharmony_ci		cur_lock = RREG32(AVIVO_D1CUR_UPDATE + radeon_crtc->crtc_offset);
4762306a36Sopenharmony_ci		if (lock)
4862306a36Sopenharmony_ci			cur_lock |= AVIVO_D1CURSOR_UPDATE_LOCK;
4962306a36Sopenharmony_ci		else
5062306a36Sopenharmony_ci			cur_lock &= ~AVIVO_D1CURSOR_UPDATE_LOCK;
5162306a36Sopenharmony_ci		WREG32(AVIVO_D1CUR_UPDATE + radeon_crtc->crtc_offset, cur_lock);
5262306a36Sopenharmony_ci	} else {
5362306a36Sopenharmony_ci		cur_lock = RREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset);
5462306a36Sopenharmony_ci		if (lock)
5562306a36Sopenharmony_ci			cur_lock |= RADEON_CUR_LOCK;
5662306a36Sopenharmony_ci		else
5762306a36Sopenharmony_ci			cur_lock &= ~RADEON_CUR_LOCK;
5862306a36Sopenharmony_ci		WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, cur_lock);
5962306a36Sopenharmony_ci	}
6062306a36Sopenharmony_ci}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cistatic void radeon_hide_cursor(struct drm_crtc *crtc)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
6562306a36Sopenharmony_ci	struct radeon_device *rdev = crtc->dev->dev_private;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	if (ASIC_IS_DCE4(rdev)) {
6862306a36Sopenharmony_ci		WREG32_IDX(EVERGREEN_CUR_CONTROL + radeon_crtc->crtc_offset,
6962306a36Sopenharmony_ci			   EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT) |
7062306a36Sopenharmony_ci			   EVERGREEN_CURSOR_URGENT_CONTROL(EVERGREEN_CURSOR_URGENT_1_2));
7162306a36Sopenharmony_ci	} else if (ASIC_IS_AVIVO(rdev)) {
7262306a36Sopenharmony_ci		WREG32_IDX(AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset,
7362306a36Sopenharmony_ci			   (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT));
7462306a36Sopenharmony_ci	} else {
7562306a36Sopenharmony_ci		u32 reg;
7662306a36Sopenharmony_ci		switch (radeon_crtc->crtc_id) {
7762306a36Sopenharmony_ci		case 0:
7862306a36Sopenharmony_ci			reg = RADEON_CRTC_GEN_CNTL;
7962306a36Sopenharmony_ci			break;
8062306a36Sopenharmony_ci		case 1:
8162306a36Sopenharmony_ci			reg = RADEON_CRTC2_GEN_CNTL;
8262306a36Sopenharmony_ci			break;
8362306a36Sopenharmony_ci		default:
8462306a36Sopenharmony_ci			return;
8562306a36Sopenharmony_ci		}
8662306a36Sopenharmony_ci		WREG32_IDX(reg, RREG32_IDX(reg) & ~RADEON_CRTC_CUR_EN);
8762306a36Sopenharmony_ci	}
8862306a36Sopenharmony_ci}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cistatic void radeon_show_cursor(struct drm_crtc *crtc)
9162306a36Sopenharmony_ci{
9262306a36Sopenharmony_ci	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
9362306a36Sopenharmony_ci	struct radeon_device *rdev = crtc->dev->dev_private;
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	if (radeon_crtc->cursor_out_of_bounds)
9662306a36Sopenharmony_ci		return;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	if (ASIC_IS_DCE4(rdev)) {
9962306a36Sopenharmony_ci		WREG32(EVERGREEN_CUR_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset,
10062306a36Sopenharmony_ci		       upper_32_bits(radeon_crtc->cursor_addr));
10162306a36Sopenharmony_ci		WREG32(EVERGREEN_CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
10262306a36Sopenharmony_ci		       lower_32_bits(radeon_crtc->cursor_addr));
10362306a36Sopenharmony_ci		WREG32(RADEON_MM_INDEX, EVERGREEN_CUR_CONTROL + radeon_crtc->crtc_offset);
10462306a36Sopenharmony_ci		WREG32(RADEON_MM_DATA, EVERGREEN_CURSOR_EN |
10562306a36Sopenharmony_ci		       EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT) |
10662306a36Sopenharmony_ci		       EVERGREEN_CURSOR_URGENT_CONTROL(EVERGREEN_CURSOR_URGENT_1_2));
10762306a36Sopenharmony_ci	} else if (ASIC_IS_AVIVO(rdev)) {
10862306a36Sopenharmony_ci		if (rdev->family >= CHIP_RV770) {
10962306a36Sopenharmony_ci			if (radeon_crtc->crtc_id)
11062306a36Sopenharmony_ci				WREG32(R700_D2CUR_SURFACE_ADDRESS_HIGH,
11162306a36Sopenharmony_ci				       upper_32_bits(radeon_crtc->cursor_addr));
11262306a36Sopenharmony_ci			else
11362306a36Sopenharmony_ci				WREG32(R700_D1CUR_SURFACE_ADDRESS_HIGH,
11462306a36Sopenharmony_ci				       upper_32_bits(radeon_crtc->cursor_addr));
11562306a36Sopenharmony_ci		}
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci		WREG32(AVIVO_D1CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
11862306a36Sopenharmony_ci		       lower_32_bits(radeon_crtc->cursor_addr));
11962306a36Sopenharmony_ci		WREG32(RADEON_MM_INDEX, AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset);
12062306a36Sopenharmony_ci		WREG32(RADEON_MM_DATA, AVIVO_D1CURSOR_EN |
12162306a36Sopenharmony_ci		       (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT));
12262306a36Sopenharmony_ci	} else {
12362306a36Sopenharmony_ci		/* offset is from DISP(2)_BASE_ADDRESS */
12462306a36Sopenharmony_ci		WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset,
12562306a36Sopenharmony_ci		       radeon_crtc->cursor_addr - radeon_crtc->legacy_display_base_addr);
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci		switch (radeon_crtc->crtc_id) {
12862306a36Sopenharmony_ci		case 0:
12962306a36Sopenharmony_ci			WREG32(RADEON_MM_INDEX, RADEON_CRTC_GEN_CNTL);
13062306a36Sopenharmony_ci			break;
13162306a36Sopenharmony_ci		case 1:
13262306a36Sopenharmony_ci			WREG32(RADEON_MM_INDEX, RADEON_CRTC2_GEN_CNTL);
13362306a36Sopenharmony_ci			break;
13462306a36Sopenharmony_ci		default:
13562306a36Sopenharmony_ci			return;
13662306a36Sopenharmony_ci		}
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci		WREG32_P(RADEON_MM_DATA, (RADEON_CRTC_CUR_EN |
13962306a36Sopenharmony_ci					  (RADEON_CRTC_CUR_MODE_24BPP << RADEON_CRTC_CUR_MODE_SHIFT)),
14062306a36Sopenharmony_ci			 ~(RADEON_CRTC_CUR_EN | RADEON_CRTC_CUR_MODE_MASK));
14162306a36Sopenharmony_ci	}
14262306a36Sopenharmony_ci}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_cistatic int radeon_cursor_move_locked(struct drm_crtc *crtc, int x, int y)
14562306a36Sopenharmony_ci{
14662306a36Sopenharmony_ci	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
14762306a36Sopenharmony_ci	struct radeon_device *rdev = crtc->dev->dev_private;
14862306a36Sopenharmony_ci	int xorigin = 0, yorigin = 0;
14962306a36Sopenharmony_ci	int w = radeon_crtc->cursor_width;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	radeon_crtc->cursor_x = x;
15262306a36Sopenharmony_ci	radeon_crtc->cursor_y = y;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	if (ASIC_IS_AVIVO(rdev)) {
15562306a36Sopenharmony_ci		/* avivo cursor are offset into the total surface */
15662306a36Sopenharmony_ci		x += crtc->x;
15762306a36Sopenharmony_ci		y += crtc->y;
15862306a36Sopenharmony_ci	}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	if (x < 0)
16162306a36Sopenharmony_ci		xorigin = min(-x, radeon_crtc->max_cursor_width - 1);
16262306a36Sopenharmony_ci	if (y < 0)
16362306a36Sopenharmony_ci		yorigin = min(-y, radeon_crtc->max_cursor_height - 1);
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	if (!ASIC_IS_AVIVO(rdev)) {
16662306a36Sopenharmony_ci		x += crtc->x;
16762306a36Sopenharmony_ci		y += crtc->y;
16862306a36Sopenharmony_ci	}
16962306a36Sopenharmony_ci	DRM_DEBUG("x %d y %d c->x %d c->y %d\n", x, y, crtc->x, crtc->y);
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	/* fixed on DCE6 and newer */
17262306a36Sopenharmony_ci	if (ASIC_IS_AVIVO(rdev) && !ASIC_IS_DCE6(rdev)) {
17362306a36Sopenharmony_ci		int i = 0;
17462306a36Sopenharmony_ci		struct drm_crtc *crtc_p;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci		/*
17762306a36Sopenharmony_ci		 * avivo cursor image can't end on 128 pixel boundary or
17862306a36Sopenharmony_ci		 * go past the end of the frame if both crtcs are enabled
17962306a36Sopenharmony_ci		 *
18062306a36Sopenharmony_ci		 * NOTE: It is safe to access crtc->enabled of other crtcs
18162306a36Sopenharmony_ci		 * without holding either the mode_config lock or the other
18262306a36Sopenharmony_ci		 * crtc's lock as long as write access to this flag _always_
18362306a36Sopenharmony_ci		 * grabs all locks.
18462306a36Sopenharmony_ci		 */
18562306a36Sopenharmony_ci		list_for_each_entry(crtc_p, &crtc->dev->mode_config.crtc_list, head) {
18662306a36Sopenharmony_ci			if (crtc_p->enabled)
18762306a36Sopenharmony_ci				i++;
18862306a36Sopenharmony_ci		}
18962306a36Sopenharmony_ci		if (i > 1) {
19062306a36Sopenharmony_ci			int cursor_end, frame_end;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci			cursor_end = x + w;
19362306a36Sopenharmony_ci			frame_end = crtc->x + crtc->mode.crtc_hdisplay;
19462306a36Sopenharmony_ci			if (cursor_end >= frame_end) {
19562306a36Sopenharmony_ci				w = w - (cursor_end - frame_end);
19662306a36Sopenharmony_ci				if (!(frame_end & 0x7f))
19762306a36Sopenharmony_ci					w--;
19862306a36Sopenharmony_ci			} else if (cursor_end <= 0) {
19962306a36Sopenharmony_ci				goto out_of_bounds;
20062306a36Sopenharmony_ci			} else if (!(cursor_end & 0x7f)) {
20162306a36Sopenharmony_ci				w--;
20262306a36Sopenharmony_ci			}
20362306a36Sopenharmony_ci			if (w <= 0) {
20462306a36Sopenharmony_ci				goto out_of_bounds;
20562306a36Sopenharmony_ci			}
20662306a36Sopenharmony_ci		}
20762306a36Sopenharmony_ci	}
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	if (x <= (crtc->x - w) || y <= (crtc->y - radeon_crtc->cursor_height) ||
21062306a36Sopenharmony_ci	    x >= (crtc->x + crtc->mode.hdisplay) ||
21162306a36Sopenharmony_ci	    y >= (crtc->y + crtc->mode.vdisplay))
21262306a36Sopenharmony_ci		goto out_of_bounds;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	x += xorigin;
21562306a36Sopenharmony_ci	y += yorigin;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	if (ASIC_IS_DCE4(rdev)) {
21862306a36Sopenharmony_ci		WREG32(EVERGREEN_CUR_POSITION + radeon_crtc->crtc_offset, (x << 16) | y);
21962306a36Sopenharmony_ci		WREG32(EVERGREEN_CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin);
22062306a36Sopenharmony_ci		WREG32(EVERGREEN_CUR_SIZE + radeon_crtc->crtc_offset,
22162306a36Sopenharmony_ci		       ((w - 1) << 16) | (radeon_crtc->cursor_height - 1));
22262306a36Sopenharmony_ci	} else if (ASIC_IS_AVIVO(rdev)) {
22362306a36Sopenharmony_ci		WREG32(AVIVO_D1CUR_POSITION + radeon_crtc->crtc_offset, (x << 16) | y);
22462306a36Sopenharmony_ci		WREG32(AVIVO_D1CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin);
22562306a36Sopenharmony_ci		WREG32(AVIVO_D1CUR_SIZE + radeon_crtc->crtc_offset,
22662306a36Sopenharmony_ci		       ((w - 1) << 16) | (radeon_crtc->cursor_height - 1));
22762306a36Sopenharmony_ci	} else {
22862306a36Sopenharmony_ci		x -= crtc->x;
22962306a36Sopenharmony_ci		y -= crtc->y;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci		if (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN)
23262306a36Sopenharmony_ci			y *= 2;
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci		WREG32(RADEON_CUR_HORZ_VERT_OFF + radeon_crtc->crtc_offset,
23562306a36Sopenharmony_ci		       (RADEON_CUR_LOCK
23662306a36Sopenharmony_ci			| (xorigin << 16)
23762306a36Sopenharmony_ci			| yorigin));
23862306a36Sopenharmony_ci		WREG32(RADEON_CUR_HORZ_VERT_POSN + radeon_crtc->crtc_offset,
23962306a36Sopenharmony_ci		       (RADEON_CUR_LOCK
24062306a36Sopenharmony_ci			| (x << 16)
24162306a36Sopenharmony_ci			| y));
24262306a36Sopenharmony_ci		/* offset is from DISP(2)_BASE_ADDRESS */
24362306a36Sopenharmony_ci		WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset,
24462306a36Sopenharmony_ci		       radeon_crtc->cursor_addr - radeon_crtc->legacy_display_base_addr +
24562306a36Sopenharmony_ci		       yorigin * 256);
24662306a36Sopenharmony_ci	}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	if (radeon_crtc->cursor_out_of_bounds) {
24962306a36Sopenharmony_ci		radeon_crtc->cursor_out_of_bounds = false;
25062306a36Sopenharmony_ci		if (radeon_crtc->cursor_bo)
25162306a36Sopenharmony_ci			radeon_show_cursor(crtc);
25262306a36Sopenharmony_ci	}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	return 0;
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci out_of_bounds:
25762306a36Sopenharmony_ci	if (!radeon_crtc->cursor_out_of_bounds) {
25862306a36Sopenharmony_ci		radeon_hide_cursor(crtc);
25962306a36Sopenharmony_ci		radeon_crtc->cursor_out_of_bounds = true;
26062306a36Sopenharmony_ci	}
26162306a36Sopenharmony_ci	return 0;
26262306a36Sopenharmony_ci}
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ciint radeon_crtc_cursor_move(struct drm_crtc *crtc,
26562306a36Sopenharmony_ci			    int x, int y)
26662306a36Sopenharmony_ci{
26762306a36Sopenharmony_ci	int ret;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	radeon_lock_cursor(crtc, true);
27062306a36Sopenharmony_ci	ret = radeon_cursor_move_locked(crtc, x, y);
27162306a36Sopenharmony_ci	radeon_lock_cursor(crtc, false);
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	return ret;
27462306a36Sopenharmony_ci}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ciint radeon_crtc_cursor_set2(struct drm_crtc *crtc,
27762306a36Sopenharmony_ci			    struct drm_file *file_priv,
27862306a36Sopenharmony_ci			    uint32_t handle,
27962306a36Sopenharmony_ci			    uint32_t width,
28062306a36Sopenharmony_ci			    uint32_t height,
28162306a36Sopenharmony_ci			    int32_t hot_x,
28262306a36Sopenharmony_ci			    int32_t hot_y)
28362306a36Sopenharmony_ci{
28462306a36Sopenharmony_ci	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
28562306a36Sopenharmony_ci	struct radeon_device *rdev = crtc->dev->dev_private;
28662306a36Sopenharmony_ci	struct drm_gem_object *obj;
28762306a36Sopenharmony_ci	struct radeon_bo *robj;
28862306a36Sopenharmony_ci	int ret;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	if (!handle) {
29162306a36Sopenharmony_ci		/* turn off cursor */
29262306a36Sopenharmony_ci		radeon_hide_cursor(crtc);
29362306a36Sopenharmony_ci		obj = NULL;
29462306a36Sopenharmony_ci		goto unpin;
29562306a36Sopenharmony_ci	}
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	if ((width > radeon_crtc->max_cursor_width) ||
29862306a36Sopenharmony_ci	    (height > radeon_crtc->max_cursor_height)) {
29962306a36Sopenharmony_ci		DRM_ERROR("bad cursor width or height %d x %d\n", width, height);
30062306a36Sopenharmony_ci		return -EINVAL;
30162306a36Sopenharmony_ci	}
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	obj = drm_gem_object_lookup(file_priv, handle);
30462306a36Sopenharmony_ci	if (!obj) {
30562306a36Sopenharmony_ci		DRM_ERROR("Cannot find cursor object %x for crtc %d\n", handle, radeon_crtc->crtc_id);
30662306a36Sopenharmony_ci		return -ENOENT;
30762306a36Sopenharmony_ci	}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	robj = gem_to_radeon_bo(obj);
31062306a36Sopenharmony_ci	ret = radeon_bo_reserve(robj, false);
31162306a36Sopenharmony_ci	if (ret != 0) {
31262306a36Sopenharmony_ci		drm_gem_object_put(obj);
31362306a36Sopenharmony_ci		return ret;
31462306a36Sopenharmony_ci	}
31562306a36Sopenharmony_ci	/* Only 27 bit offset for legacy cursor */
31662306a36Sopenharmony_ci	ret = radeon_bo_pin_restricted(robj, RADEON_GEM_DOMAIN_VRAM,
31762306a36Sopenharmony_ci				       ASIC_IS_AVIVO(rdev) ? 0 : 1 << 27,
31862306a36Sopenharmony_ci				       &radeon_crtc->cursor_addr);
31962306a36Sopenharmony_ci	radeon_bo_unreserve(robj);
32062306a36Sopenharmony_ci	if (ret) {
32162306a36Sopenharmony_ci		DRM_ERROR("Failed to pin new cursor BO (%d)\n", ret);
32262306a36Sopenharmony_ci		drm_gem_object_put(obj);
32362306a36Sopenharmony_ci		return ret;
32462306a36Sopenharmony_ci	}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	radeon_lock_cursor(crtc, true);
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	if (width != radeon_crtc->cursor_width ||
32962306a36Sopenharmony_ci	    height != radeon_crtc->cursor_height ||
33062306a36Sopenharmony_ci	    hot_x != radeon_crtc->cursor_hot_x ||
33162306a36Sopenharmony_ci	    hot_y != radeon_crtc->cursor_hot_y) {
33262306a36Sopenharmony_ci		int x, y;
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci		x = radeon_crtc->cursor_x + radeon_crtc->cursor_hot_x - hot_x;
33562306a36Sopenharmony_ci		y = radeon_crtc->cursor_y + radeon_crtc->cursor_hot_y - hot_y;
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci		radeon_crtc->cursor_width = width;
33862306a36Sopenharmony_ci		radeon_crtc->cursor_height = height;
33962306a36Sopenharmony_ci		radeon_crtc->cursor_hot_x = hot_x;
34062306a36Sopenharmony_ci		radeon_crtc->cursor_hot_y = hot_y;
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci		radeon_cursor_move_locked(crtc, x, y);
34362306a36Sopenharmony_ci	}
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	radeon_show_cursor(crtc);
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	radeon_lock_cursor(crtc, false);
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ciunpin:
35062306a36Sopenharmony_ci	if (radeon_crtc->cursor_bo) {
35162306a36Sopenharmony_ci		struct radeon_bo *robj = gem_to_radeon_bo(radeon_crtc->cursor_bo);
35262306a36Sopenharmony_ci		ret = radeon_bo_reserve(robj, false);
35362306a36Sopenharmony_ci		if (likely(ret == 0)) {
35462306a36Sopenharmony_ci			radeon_bo_unpin(robj);
35562306a36Sopenharmony_ci			radeon_bo_unreserve(robj);
35662306a36Sopenharmony_ci		}
35762306a36Sopenharmony_ci		drm_gem_object_put(radeon_crtc->cursor_bo);
35862306a36Sopenharmony_ci	}
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	radeon_crtc->cursor_bo = obj;
36162306a36Sopenharmony_ci	return 0;
36262306a36Sopenharmony_ci}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci/**
36562306a36Sopenharmony_ci * radeon_cursor_reset - Re-set the current cursor, if any.
36662306a36Sopenharmony_ci *
36762306a36Sopenharmony_ci * @crtc: drm crtc
36862306a36Sopenharmony_ci *
36962306a36Sopenharmony_ci * If the CRTC passed in currently has a cursor assigned, this function
37062306a36Sopenharmony_ci * makes sure it's visible.
37162306a36Sopenharmony_ci */
37262306a36Sopenharmony_civoid radeon_cursor_reset(struct drm_crtc *crtc)
37362306a36Sopenharmony_ci{
37462306a36Sopenharmony_ci	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	if (radeon_crtc->cursor_bo) {
37762306a36Sopenharmony_ci		radeon_lock_cursor(crtc, true);
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci		radeon_cursor_move_locked(crtc, radeon_crtc->cursor_x,
38062306a36Sopenharmony_ci					  radeon_crtc->cursor_y);
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci		radeon_show_cursor(crtc);
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci		radeon_lock_cursor(crtc, false);
38562306a36Sopenharmony_ci	}
38662306a36Sopenharmony_ci}
387