1 /* 2 * Copyright 2007-8 Advanced Micro Devices, Inc. 3 * Copyright 2008 Red Hat Inc. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be included in 13 * all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 19 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 21 * OTHER DEALINGS IN THE SOFTWARE. 22 * 23 * Authors: Dave Airlie 24 * Alex Deucher 25 * 26 * $FreeBSD: head/sys/dev/drm2/radeon/radeon_cursor.c 254885 2013-08-25 19:37:15Z dumbbell $ 27 */ 28 29 #include <drm/drmP.h> 30 #include <uapi_drm/radeon_drm.h> 31 #include "radeon.h" 32 33 #define CURSOR_WIDTH 64 34 #define CURSOR_HEIGHT 64 35 36 static void radeon_lock_cursor(struct drm_crtc *crtc, bool lock) 37 { 38 struct radeon_device *rdev = crtc->dev->dev_private; 39 struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 40 uint32_t cur_lock; 41 42 if (ASIC_IS_DCE4(rdev)) { 43 cur_lock = RREG32(EVERGREEN_CUR_UPDATE + radeon_crtc->crtc_offset); 44 if (lock) 45 cur_lock |= EVERGREEN_CURSOR_UPDATE_LOCK; 46 else 47 cur_lock &= ~EVERGREEN_CURSOR_UPDATE_LOCK; 48 WREG32(EVERGREEN_CUR_UPDATE + radeon_crtc->crtc_offset, cur_lock); 49 } else if (ASIC_IS_AVIVO(rdev)) { 50 cur_lock = RREG32(AVIVO_D1CUR_UPDATE + radeon_crtc->crtc_offset); 51 if (lock) 52 cur_lock |= AVIVO_D1CURSOR_UPDATE_LOCK; 53 else 54 cur_lock &= ~AVIVO_D1CURSOR_UPDATE_LOCK; 55 WREG32(AVIVO_D1CUR_UPDATE + radeon_crtc->crtc_offset, cur_lock); 56 } else { 57 cur_lock = RREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset); 58 if (lock) 59 cur_lock |= RADEON_CUR_LOCK; 60 else 61 cur_lock &= ~RADEON_CUR_LOCK; 62 WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, cur_lock); 63 } 64 } 65 66 static void radeon_hide_cursor(struct drm_crtc *crtc) 67 { 68 struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 69 struct radeon_device *rdev = crtc->dev->dev_private; 70 71 if (ASIC_IS_DCE4(rdev)) { 72 WREG32_IDX(EVERGREEN_CUR_CONTROL + radeon_crtc->crtc_offset, 73 EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT) | 74 EVERGREEN_CURSOR_URGENT_CONTROL(EVERGREEN_CURSOR_URGENT_1_2)); 75 } else if (ASIC_IS_AVIVO(rdev)) { 76 WREG32_IDX(AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset, 77 (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT)); 78 } else { 79 u32 reg; 80 switch (radeon_crtc->crtc_id) { 81 case 0: 82 reg = RADEON_CRTC_GEN_CNTL; 83 break; 84 case 1: 85 reg = RADEON_CRTC2_GEN_CNTL; 86 break; 87 default: 88 return; 89 } 90 WREG32_IDX(reg, RREG32_IDX(reg) & ~RADEON_CRTC_CUR_EN); 91 } 92 } 93 94 static void radeon_show_cursor(struct drm_crtc *crtc) 95 { 96 struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 97 struct radeon_device *rdev = crtc->dev->dev_private; 98 99 if (ASIC_IS_DCE4(rdev)) { 100 WREG32(RADEON_MM_INDEX, EVERGREEN_CUR_CONTROL + radeon_crtc->crtc_offset); 101 WREG32(RADEON_MM_DATA, EVERGREEN_CURSOR_EN | 102 EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT) | 103 EVERGREEN_CURSOR_URGENT_CONTROL(EVERGREEN_CURSOR_URGENT_1_2)); 104 } else if (ASIC_IS_AVIVO(rdev)) { 105 WREG32(RADEON_MM_INDEX, AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset); 106 WREG32(RADEON_MM_DATA, AVIVO_D1CURSOR_EN | 107 (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT)); 108 } else { 109 switch (radeon_crtc->crtc_id) { 110 case 0: 111 WREG32(RADEON_MM_INDEX, RADEON_CRTC_GEN_CNTL); 112 break; 113 case 1: 114 WREG32(RADEON_MM_INDEX, RADEON_CRTC2_GEN_CNTL); 115 break; 116 default: 117 return; 118 } 119 120 WREG32_P(RADEON_MM_DATA, (RADEON_CRTC_CUR_EN | 121 (RADEON_CRTC_CUR_MODE_24BPP << RADEON_CRTC_CUR_MODE_SHIFT)), 122 ~(RADEON_CRTC_CUR_EN | RADEON_CRTC_CUR_MODE_MASK)); 123 } 124 } 125 126 static void radeon_set_cursor(struct drm_crtc *crtc, struct drm_gem_object *obj, 127 uint64_t gpu_addr) 128 { 129 struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 130 struct radeon_device *rdev = crtc->dev->dev_private; 131 132 if (ASIC_IS_DCE4(rdev)) { 133 WREG32(EVERGREEN_CUR_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset, 134 upper_32_bits(gpu_addr)); 135 WREG32(EVERGREEN_CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset, 136 gpu_addr & 0xffffffff); 137 } else if (ASIC_IS_AVIVO(rdev)) { 138 if (rdev->family >= CHIP_RV770) { 139 if (radeon_crtc->crtc_id) 140 WREG32(R700_D2CUR_SURFACE_ADDRESS_HIGH, upper_32_bits(gpu_addr)); 141 else 142 WREG32(R700_D1CUR_SURFACE_ADDRESS_HIGH, upper_32_bits(gpu_addr)); 143 } 144 WREG32(AVIVO_D1CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset, 145 gpu_addr & 0xffffffff); 146 } else { 147 radeon_crtc->legacy_cursor_offset = gpu_addr - radeon_crtc->legacy_display_base_addr; 148 /* offset is from DISP(2)_BASE_ADDRESS */ 149 WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, radeon_crtc->legacy_cursor_offset); 150 } 151 } 152 153 int radeon_crtc_cursor_set(struct drm_crtc *crtc, 154 struct drm_file *file_priv, 155 uint32_t handle, 156 uint32_t width, 157 uint32_t height) 158 { 159 struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 160 struct radeon_device *rdev = crtc->dev->dev_private; 161 struct drm_gem_object *obj; 162 struct radeon_bo *robj; 163 uint64_t gpu_addr; 164 int ret; 165 166 if (!handle) { 167 /* turn off cursor */ 168 radeon_hide_cursor(crtc); 169 obj = NULL; 170 goto unpin; 171 } 172 173 if ((width > CURSOR_WIDTH) || (height > CURSOR_HEIGHT)) { 174 DRM_ERROR("bad cursor width or height %d x %d\n", width, height); 175 return -EINVAL; 176 } 177 178 obj = drm_gem_object_lookup(crtc->dev, file_priv, handle); 179 if (!obj) { 180 DRM_ERROR("Cannot find cursor object %x for crtc %d\n", handle, radeon_crtc->crtc_id); 181 return -ENOENT; 182 } 183 184 robj = gem_to_radeon_bo(obj); 185 ret = radeon_bo_reserve(robj, false); 186 if (unlikely(ret != 0)) 187 goto fail; 188 /* Only 27 bit offset for legacy cursor */ 189 ret = radeon_bo_pin_restricted(robj, RADEON_GEM_DOMAIN_VRAM, 190 ASIC_IS_AVIVO(rdev) ? 0 : 1 << 27, 191 &gpu_addr); 192 radeon_bo_unreserve(robj); 193 if (ret) 194 goto fail; 195 196 radeon_crtc->cursor_width = width; 197 radeon_crtc->cursor_height = height; 198 199 radeon_lock_cursor(crtc, true); 200 radeon_set_cursor(crtc, obj, gpu_addr); 201 radeon_show_cursor(crtc); 202 radeon_lock_cursor(crtc, false); 203 204 unpin: 205 if (radeon_crtc->cursor_bo) { 206 robj = gem_to_radeon_bo(radeon_crtc->cursor_bo); 207 ret = radeon_bo_reserve(robj, false); 208 if (likely(ret == 0)) { 209 radeon_bo_unpin(robj); 210 radeon_bo_unreserve(robj); 211 } 212 drm_gem_object_unreference_unlocked(radeon_crtc->cursor_bo); 213 } 214 215 radeon_crtc->cursor_bo = obj; 216 return 0; 217 fail: 218 drm_gem_object_unreference_unlocked(obj); 219 220 return ret; 221 } 222 223 int radeon_crtc_cursor_move(struct drm_crtc *crtc, 224 int x, int y) 225 { 226 struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 227 struct radeon_device *rdev = crtc->dev->dev_private; 228 int xorigin = 0, yorigin = 0; 229 int w = radeon_crtc->cursor_width; 230 231 if (ASIC_IS_AVIVO(rdev)) { 232 /* avivo cursor are offset into the total surface */ 233 x += crtc->x; 234 y += crtc->y; 235 } 236 DRM_DEBUG("x %d y %d c->x %d c->y %d\n", x, y, crtc->x, crtc->y); 237 238 if (x < 0) { 239 xorigin = min(-x, CURSOR_WIDTH - 1); 240 x = 0; 241 } 242 if (y < 0) { 243 yorigin = min(-y, CURSOR_HEIGHT - 1); 244 y = 0; 245 } 246 247 /* fixed on DCE6 and newer */ 248 if (ASIC_IS_AVIVO(rdev) && !ASIC_IS_DCE6(rdev)) { 249 int i = 0; 250 struct drm_crtc *crtc_p; 251 252 /* avivo cursor image can't end on 128 pixel boundary or 253 * go past the end of the frame if both crtcs are enabled 254 */ 255 list_for_each_entry(crtc_p, &crtc->dev->mode_config.crtc_list, head) { 256 if (crtc_p->enabled) 257 i++; 258 } 259 if (i > 1) { 260 int cursor_end, frame_end; 261 262 cursor_end = x - xorigin + w; 263 frame_end = crtc->x + crtc->mode.crtc_hdisplay; 264 if (cursor_end >= frame_end) { 265 w = w - (cursor_end - frame_end); 266 if (!(frame_end & 0x7f)) 267 w--; 268 } else { 269 if (!(cursor_end & 0x7f)) 270 w--; 271 } 272 if (w <= 0) { 273 w = 1; 274 cursor_end = x - xorigin + w; 275 if (!(cursor_end & 0x7f)) { 276 x--; 277 if (x < 0) { 278 DRM_ERROR("%s: x(%d) < 0", __func__, x); 279 } 280 } 281 } 282 } 283 } 284 285 radeon_lock_cursor(crtc, true); 286 if (ASIC_IS_DCE4(rdev)) { 287 WREG32(EVERGREEN_CUR_POSITION + radeon_crtc->crtc_offset, (x << 16) | y); 288 WREG32(EVERGREEN_CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin); 289 WREG32(EVERGREEN_CUR_SIZE + radeon_crtc->crtc_offset, 290 ((w - 1) << 16) | (radeon_crtc->cursor_height - 1)); 291 } else if (ASIC_IS_AVIVO(rdev)) { 292 WREG32(AVIVO_D1CUR_POSITION + radeon_crtc->crtc_offset, (x << 16) | y); 293 WREG32(AVIVO_D1CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin); 294 WREG32(AVIVO_D1CUR_SIZE + radeon_crtc->crtc_offset, 295 ((w - 1) << 16) | (radeon_crtc->cursor_height - 1)); 296 } else { 297 if (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN) 298 y *= 2; 299 300 WREG32(RADEON_CUR_HORZ_VERT_OFF + radeon_crtc->crtc_offset, 301 (RADEON_CUR_LOCK 302 | (xorigin << 16) 303 | yorigin)); 304 WREG32(RADEON_CUR_HORZ_VERT_POSN + radeon_crtc->crtc_offset, 305 (RADEON_CUR_LOCK 306 | (x << 16) 307 | y)); 308 /* offset is from DISP(2)_BASE_ADDRESS */ 309 WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, (radeon_crtc->legacy_cursor_offset + 310 (yorigin * 256))); 311 } 312 radeon_lock_cursor(crtc, false); 313 314 return 0; 315 } 316