1254885Sdumbbell/* 2254885Sdumbbell * Copyright 2007-8 Advanced Micro Devices, Inc. 3254885Sdumbbell * Copyright 2008 Red Hat Inc. 4254885Sdumbbell * 5254885Sdumbbell * Permission is hereby granted, free of charge, to any person obtaining a 6254885Sdumbbell * copy of this software and associated documentation files (the "Software"), 7254885Sdumbbell * to deal in the Software without restriction, including without limitation 8254885Sdumbbell * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9254885Sdumbbell * and/or sell copies of the Software, and to permit persons to whom the 10254885Sdumbbell * Software is furnished to do so, subject to the following conditions: 11254885Sdumbbell * 12254885Sdumbbell * The above copyright notice and this permission notice shall be included in 13254885Sdumbbell * all copies or substantial portions of the Software. 14254885Sdumbbell * 15254885Sdumbbell * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16254885Sdumbbell * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17254885Sdumbbell * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18254885Sdumbbell * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 19254885Sdumbbell * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 20254885Sdumbbell * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 21254885Sdumbbell * OTHER DEALINGS IN THE SOFTWARE. 22254885Sdumbbell * 23254885Sdumbbell * Authors: Dave Airlie 24254885Sdumbbell * Alex Deucher 25254885Sdumbbell */ 26254885Sdumbbell 27254885Sdumbbell#include <sys/cdefs.h> 28254885Sdumbbell__FBSDID("$FreeBSD: releng/10.3/sys/dev/drm2/radeon/radeon_cursor.c 254885 2013-08-25 19:37:15Z dumbbell $"); 29254885Sdumbbell 30254885Sdumbbell#include <dev/drm2/drmP.h> 31254885Sdumbbell#include <dev/drm2/radeon/radeon_drm.h> 32254885Sdumbbell#include "radeon.h" 33254885Sdumbbell 34254885Sdumbbell#define CURSOR_WIDTH 64 35254885Sdumbbell#define CURSOR_HEIGHT 64 36254885Sdumbbell 37254885Sdumbbellstatic void radeon_lock_cursor(struct drm_crtc *crtc, bool lock) 38254885Sdumbbell{ 39254885Sdumbbell struct radeon_device *rdev = crtc->dev->dev_private; 40254885Sdumbbell struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 41254885Sdumbbell uint32_t cur_lock; 42254885Sdumbbell 43254885Sdumbbell if (ASIC_IS_DCE4(rdev)) { 44254885Sdumbbell cur_lock = RREG32(EVERGREEN_CUR_UPDATE + radeon_crtc->crtc_offset); 45254885Sdumbbell if (lock) 46254885Sdumbbell cur_lock |= EVERGREEN_CURSOR_UPDATE_LOCK; 47254885Sdumbbell else 48254885Sdumbbell cur_lock &= ~EVERGREEN_CURSOR_UPDATE_LOCK; 49254885Sdumbbell WREG32(EVERGREEN_CUR_UPDATE + radeon_crtc->crtc_offset, cur_lock); 50254885Sdumbbell } else if (ASIC_IS_AVIVO(rdev)) { 51254885Sdumbbell cur_lock = RREG32(AVIVO_D1CUR_UPDATE + radeon_crtc->crtc_offset); 52254885Sdumbbell if (lock) 53254885Sdumbbell cur_lock |= AVIVO_D1CURSOR_UPDATE_LOCK; 54254885Sdumbbell else 55254885Sdumbbell cur_lock &= ~AVIVO_D1CURSOR_UPDATE_LOCK; 56254885Sdumbbell WREG32(AVIVO_D1CUR_UPDATE + radeon_crtc->crtc_offset, cur_lock); 57254885Sdumbbell } else { 58254885Sdumbbell cur_lock = RREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset); 59254885Sdumbbell if (lock) 60254885Sdumbbell cur_lock |= RADEON_CUR_LOCK; 61254885Sdumbbell else 62254885Sdumbbell cur_lock &= ~RADEON_CUR_LOCK; 63254885Sdumbbell WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, cur_lock); 64254885Sdumbbell } 65254885Sdumbbell} 66254885Sdumbbell 67254885Sdumbbellstatic void radeon_hide_cursor(struct drm_crtc *crtc) 68254885Sdumbbell{ 69254885Sdumbbell struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 70254885Sdumbbell struct radeon_device *rdev = crtc->dev->dev_private; 71254885Sdumbbell 72254885Sdumbbell if (ASIC_IS_DCE4(rdev)) { 73254885Sdumbbell WREG32_IDX(EVERGREEN_CUR_CONTROL + radeon_crtc->crtc_offset, 74254885Sdumbbell EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT) | 75254885Sdumbbell EVERGREEN_CURSOR_URGENT_CONTROL(EVERGREEN_CURSOR_URGENT_1_2)); 76254885Sdumbbell } else if (ASIC_IS_AVIVO(rdev)) { 77254885Sdumbbell WREG32_IDX(AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset, 78254885Sdumbbell (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT)); 79254885Sdumbbell } else { 80254885Sdumbbell u32 reg; 81254885Sdumbbell switch (radeon_crtc->crtc_id) { 82254885Sdumbbell case 0: 83254885Sdumbbell reg = RADEON_CRTC_GEN_CNTL; 84254885Sdumbbell break; 85254885Sdumbbell case 1: 86254885Sdumbbell reg = RADEON_CRTC2_GEN_CNTL; 87254885Sdumbbell break; 88254885Sdumbbell default: 89254885Sdumbbell return; 90254885Sdumbbell } 91254885Sdumbbell WREG32_IDX(reg, RREG32_IDX(reg) & ~RADEON_CRTC_CUR_EN); 92254885Sdumbbell } 93254885Sdumbbell} 94254885Sdumbbell 95254885Sdumbbellstatic void radeon_show_cursor(struct drm_crtc *crtc) 96254885Sdumbbell{ 97254885Sdumbbell struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 98254885Sdumbbell struct radeon_device *rdev = crtc->dev->dev_private; 99254885Sdumbbell 100254885Sdumbbell if (ASIC_IS_DCE4(rdev)) { 101254885Sdumbbell WREG32(RADEON_MM_INDEX, EVERGREEN_CUR_CONTROL + radeon_crtc->crtc_offset); 102254885Sdumbbell WREG32(RADEON_MM_DATA, EVERGREEN_CURSOR_EN | 103254885Sdumbbell EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT) | 104254885Sdumbbell EVERGREEN_CURSOR_URGENT_CONTROL(EVERGREEN_CURSOR_URGENT_1_2)); 105254885Sdumbbell } else if (ASIC_IS_AVIVO(rdev)) { 106254885Sdumbbell WREG32(RADEON_MM_INDEX, AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset); 107254885Sdumbbell WREG32(RADEON_MM_DATA, AVIVO_D1CURSOR_EN | 108254885Sdumbbell (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT)); 109254885Sdumbbell } else { 110254885Sdumbbell switch (radeon_crtc->crtc_id) { 111254885Sdumbbell case 0: 112254885Sdumbbell WREG32(RADEON_MM_INDEX, RADEON_CRTC_GEN_CNTL); 113254885Sdumbbell break; 114254885Sdumbbell case 1: 115254885Sdumbbell WREG32(RADEON_MM_INDEX, RADEON_CRTC2_GEN_CNTL); 116254885Sdumbbell break; 117254885Sdumbbell default: 118254885Sdumbbell return; 119254885Sdumbbell } 120254885Sdumbbell 121254885Sdumbbell WREG32_P(RADEON_MM_DATA, (RADEON_CRTC_CUR_EN | 122254885Sdumbbell (RADEON_CRTC_CUR_MODE_24BPP << RADEON_CRTC_CUR_MODE_SHIFT)), 123254885Sdumbbell ~(RADEON_CRTC_CUR_EN | RADEON_CRTC_CUR_MODE_MASK)); 124254885Sdumbbell } 125254885Sdumbbell} 126254885Sdumbbell 127254885Sdumbbellstatic void radeon_set_cursor(struct drm_crtc *crtc, struct drm_gem_object *obj, 128254885Sdumbbell uint64_t gpu_addr) 129254885Sdumbbell{ 130254885Sdumbbell struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 131254885Sdumbbell struct radeon_device *rdev = crtc->dev->dev_private; 132254885Sdumbbell 133254885Sdumbbell if (ASIC_IS_DCE4(rdev)) { 134254885Sdumbbell WREG32(EVERGREEN_CUR_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset, 135254885Sdumbbell upper_32_bits(gpu_addr)); 136254885Sdumbbell WREG32(EVERGREEN_CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset, 137254885Sdumbbell gpu_addr & 0xffffffff); 138254885Sdumbbell } else if (ASIC_IS_AVIVO(rdev)) { 139254885Sdumbbell if (rdev->family >= CHIP_RV770) { 140254885Sdumbbell if (radeon_crtc->crtc_id) 141254885Sdumbbell WREG32(R700_D2CUR_SURFACE_ADDRESS_HIGH, upper_32_bits(gpu_addr)); 142254885Sdumbbell else 143254885Sdumbbell WREG32(R700_D1CUR_SURFACE_ADDRESS_HIGH, upper_32_bits(gpu_addr)); 144254885Sdumbbell } 145254885Sdumbbell WREG32(AVIVO_D1CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset, 146254885Sdumbbell gpu_addr & 0xffffffff); 147254885Sdumbbell } else { 148254885Sdumbbell radeon_crtc->legacy_cursor_offset = gpu_addr - radeon_crtc->legacy_display_base_addr; 149254885Sdumbbell /* offset is from DISP(2)_BASE_ADDRESS */ 150254885Sdumbbell WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, radeon_crtc->legacy_cursor_offset); 151254885Sdumbbell } 152254885Sdumbbell} 153254885Sdumbbell 154254885Sdumbbellint radeon_crtc_cursor_set(struct drm_crtc *crtc, 155254885Sdumbbell struct drm_file *file_priv, 156254885Sdumbbell uint32_t handle, 157254885Sdumbbell uint32_t width, 158254885Sdumbbell uint32_t height) 159254885Sdumbbell{ 160254885Sdumbbell struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 161254885Sdumbbell struct radeon_device *rdev = crtc->dev->dev_private; 162254885Sdumbbell struct drm_gem_object *obj; 163254885Sdumbbell struct radeon_bo *robj; 164254885Sdumbbell uint64_t gpu_addr; 165254885Sdumbbell int ret; 166254885Sdumbbell 167254885Sdumbbell if (!handle) { 168254885Sdumbbell /* turn off cursor */ 169254885Sdumbbell radeon_hide_cursor(crtc); 170254885Sdumbbell obj = NULL; 171254885Sdumbbell goto unpin; 172254885Sdumbbell } 173254885Sdumbbell 174254885Sdumbbell if ((width > CURSOR_WIDTH) || (height > CURSOR_HEIGHT)) { 175254885Sdumbbell DRM_ERROR("bad cursor width or height %d x %d\n", width, height); 176254885Sdumbbell return -EINVAL; 177254885Sdumbbell } 178254885Sdumbbell 179254885Sdumbbell obj = drm_gem_object_lookup(crtc->dev, file_priv, handle); 180254885Sdumbbell if (!obj) { 181254885Sdumbbell DRM_ERROR("Cannot find cursor object %x for crtc %d\n", handle, radeon_crtc->crtc_id); 182254885Sdumbbell return -ENOENT; 183254885Sdumbbell } 184254885Sdumbbell 185254885Sdumbbell robj = gem_to_radeon_bo(obj); 186254885Sdumbbell ret = radeon_bo_reserve(robj, false); 187254885Sdumbbell if (unlikely(ret != 0)) 188254885Sdumbbell goto fail; 189254885Sdumbbell /* Only 27 bit offset for legacy cursor */ 190254885Sdumbbell ret = radeon_bo_pin_restricted(robj, RADEON_GEM_DOMAIN_VRAM, 191254885Sdumbbell ASIC_IS_AVIVO(rdev) ? 0 : 1 << 27, 192254885Sdumbbell &gpu_addr); 193254885Sdumbbell radeon_bo_unreserve(robj); 194254885Sdumbbell if (ret) 195254885Sdumbbell goto fail; 196254885Sdumbbell 197254885Sdumbbell radeon_crtc->cursor_width = width; 198254885Sdumbbell radeon_crtc->cursor_height = height; 199254885Sdumbbell 200254885Sdumbbell radeon_lock_cursor(crtc, true); 201254885Sdumbbell radeon_set_cursor(crtc, obj, gpu_addr); 202254885Sdumbbell radeon_show_cursor(crtc); 203254885Sdumbbell radeon_lock_cursor(crtc, false); 204254885Sdumbbell 205254885Sdumbbellunpin: 206254885Sdumbbell if (radeon_crtc->cursor_bo) { 207254885Sdumbbell robj = gem_to_radeon_bo(radeon_crtc->cursor_bo); 208254885Sdumbbell ret = radeon_bo_reserve(robj, false); 209254885Sdumbbell if (likely(ret == 0)) { 210254885Sdumbbell radeon_bo_unpin(robj); 211254885Sdumbbell radeon_bo_unreserve(robj); 212254885Sdumbbell } 213254885Sdumbbell drm_gem_object_unreference_unlocked(radeon_crtc->cursor_bo); 214254885Sdumbbell } 215254885Sdumbbell 216254885Sdumbbell radeon_crtc->cursor_bo = obj; 217254885Sdumbbell return 0; 218254885Sdumbbellfail: 219254885Sdumbbell drm_gem_object_unreference_unlocked(obj); 220254885Sdumbbell 221254885Sdumbbell return ret; 222254885Sdumbbell} 223254885Sdumbbell 224254885Sdumbbellint radeon_crtc_cursor_move(struct drm_crtc *crtc, 225254885Sdumbbell int x, int y) 226254885Sdumbbell{ 227254885Sdumbbell struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 228254885Sdumbbell struct radeon_device *rdev = crtc->dev->dev_private; 229254885Sdumbbell int xorigin = 0, yorigin = 0; 230254885Sdumbbell int w = radeon_crtc->cursor_width; 231254885Sdumbbell 232254885Sdumbbell if (ASIC_IS_AVIVO(rdev)) { 233254885Sdumbbell /* avivo cursor are offset into the total surface */ 234254885Sdumbbell x += crtc->x; 235254885Sdumbbell y += crtc->y; 236254885Sdumbbell } 237254885Sdumbbell DRM_DEBUG("x %d y %d c->x %d c->y %d\n", x, y, crtc->x, crtc->y); 238254885Sdumbbell 239254885Sdumbbell if (x < 0) { 240254885Sdumbbell xorigin = min(-x, CURSOR_WIDTH - 1); 241254885Sdumbbell x = 0; 242254885Sdumbbell } 243254885Sdumbbell if (y < 0) { 244254885Sdumbbell yorigin = min(-y, CURSOR_HEIGHT - 1); 245254885Sdumbbell y = 0; 246254885Sdumbbell } 247254885Sdumbbell 248254885Sdumbbell /* fixed on DCE6 and newer */ 249254885Sdumbbell if (ASIC_IS_AVIVO(rdev) && !ASIC_IS_DCE6(rdev)) { 250254885Sdumbbell int i = 0; 251254885Sdumbbell struct drm_crtc *crtc_p; 252254885Sdumbbell 253254885Sdumbbell /* avivo cursor image can't end on 128 pixel boundary or 254254885Sdumbbell * go past the end of the frame if both crtcs are enabled 255254885Sdumbbell */ 256254885Sdumbbell list_for_each_entry(crtc_p, &crtc->dev->mode_config.crtc_list, head) { 257254885Sdumbbell if (crtc_p->enabled) 258254885Sdumbbell i++; 259254885Sdumbbell } 260254885Sdumbbell if (i > 1) { 261254885Sdumbbell int cursor_end, frame_end; 262254885Sdumbbell 263254885Sdumbbell cursor_end = x - xorigin + w; 264254885Sdumbbell frame_end = crtc->x + crtc->mode.crtc_hdisplay; 265254885Sdumbbell if (cursor_end >= frame_end) { 266254885Sdumbbell w = w - (cursor_end - frame_end); 267254885Sdumbbell if (!(frame_end & 0x7f)) 268254885Sdumbbell w--; 269254885Sdumbbell } else { 270254885Sdumbbell if (!(cursor_end & 0x7f)) 271254885Sdumbbell w--; 272254885Sdumbbell } 273254885Sdumbbell if (w <= 0) { 274254885Sdumbbell w = 1; 275254885Sdumbbell cursor_end = x - xorigin + w; 276254885Sdumbbell if (!(cursor_end & 0x7f)) { 277254885Sdumbbell x--; 278254885Sdumbbell if (x < 0) { 279254885Sdumbbell DRM_ERROR("%s: x(%d) < 0", __func__, x); 280254885Sdumbbell } 281254885Sdumbbell } 282254885Sdumbbell } 283254885Sdumbbell } 284254885Sdumbbell } 285254885Sdumbbell 286254885Sdumbbell radeon_lock_cursor(crtc, true); 287254885Sdumbbell if (ASIC_IS_DCE4(rdev)) { 288254885Sdumbbell WREG32(EVERGREEN_CUR_POSITION + radeon_crtc->crtc_offset, (x << 16) | y); 289254885Sdumbbell WREG32(EVERGREEN_CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin); 290254885Sdumbbell WREG32(EVERGREEN_CUR_SIZE + radeon_crtc->crtc_offset, 291254885Sdumbbell ((w - 1) << 16) | (radeon_crtc->cursor_height - 1)); 292254885Sdumbbell } else if (ASIC_IS_AVIVO(rdev)) { 293254885Sdumbbell WREG32(AVIVO_D1CUR_POSITION + radeon_crtc->crtc_offset, (x << 16) | y); 294254885Sdumbbell WREG32(AVIVO_D1CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin); 295254885Sdumbbell WREG32(AVIVO_D1CUR_SIZE + radeon_crtc->crtc_offset, 296254885Sdumbbell ((w - 1) << 16) | (radeon_crtc->cursor_height - 1)); 297254885Sdumbbell } else { 298254885Sdumbbell if (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN) 299254885Sdumbbell y *= 2; 300254885Sdumbbell 301254885Sdumbbell WREG32(RADEON_CUR_HORZ_VERT_OFF + radeon_crtc->crtc_offset, 302254885Sdumbbell (RADEON_CUR_LOCK 303254885Sdumbbell | (xorigin << 16) 304254885Sdumbbell | yorigin)); 305254885Sdumbbell WREG32(RADEON_CUR_HORZ_VERT_POSN + radeon_crtc->crtc_offset, 306254885Sdumbbell (RADEON_CUR_LOCK 307254885Sdumbbell | (x << 16) 308254885Sdumbbell | y)); 309254885Sdumbbell /* offset is from DISP(2)_BASE_ADDRESS */ 310254885Sdumbbell WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, (radeon_crtc->legacy_cursor_offset + 311254885Sdumbbell (yorigin * 256))); 312254885Sdumbbell } 313254885Sdumbbell radeon_lock_cursor(crtc, false); 314254885Sdumbbell 315254885Sdumbbell return 0; 316254885Sdumbbell} 317