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