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