0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027 #include <drm/drm_device.h>
0028 #include <drm/radeon_drm.h>
0029
0030 #include "radeon.h"
0031
0032 static void radeon_lock_cursor(struct drm_crtc *crtc, bool lock)
0033 {
0034 struct radeon_device *rdev = crtc->dev->dev_private;
0035 struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
0036 uint32_t cur_lock;
0037
0038 if (ASIC_IS_DCE4(rdev)) {
0039 cur_lock = RREG32(EVERGREEN_CUR_UPDATE + radeon_crtc->crtc_offset);
0040 if (lock)
0041 cur_lock |= EVERGREEN_CURSOR_UPDATE_LOCK;
0042 else
0043 cur_lock &= ~EVERGREEN_CURSOR_UPDATE_LOCK;
0044 WREG32(EVERGREEN_CUR_UPDATE + radeon_crtc->crtc_offset, cur_lock);
0045 } else if (ASIC_IS_AVIVO(rdev)) {
0046 cur_lock = RREG32(AVIVO_D1CUR_UPDATE + radeon_crtc->crtc_offset);
0047 if (lock)
0048 cur_lock |= AVIVO_D1CURSOR_UPDATE_LOCK;
0049 else
0050 cur_lock &= ~AVIVO_D1CURSOR_UPDATE_LOCK;
0051 WREG32(AVIVO_D1CUR_UPDATE + radeon_crtc->crtc_offset, cur_lock);
0052 } else {
0053 cur_lock = RREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset);
0054 if (lock)
0055 cur_lock |= RADEON_CUR_LOCK;
0056 else
0057 cur_lock &= ~RADEON_CUR_LOCK;
0058 WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, cur_lock);
0059 }
0060 }
0061
0062 static void radeon_hide_cursor(struct drm_crtc *crtc)
0063 {
0064 struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
0065 struct radeon_device *rdev = crtc->dev->dev_private;
0066
0067 if (ASIC_IS_DCE4(rdev)) {
0068 WREG32_IDX(EVERGREEN_CUR_CONTROL + radeon_crtc->crtc_offset,
0069 EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT) |
0070 EVERGREEN_CURSOR_URGENT_CONTROL(EVERGREEN_CURSOR_URGENT_1_2));
0071 } else if (ASIC_IS_AVIVO(rdev)) {
0072 WREG32_IDX(AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset,
0073 (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT));
0074 } else {
0075 u32 reg;
0076 switch (radeon_crtc->crtc_id) {
0077 case 0:
0078 reg = RADEON_CRTC_GEN_CNTL;
0079 break;
0080 case 1:
0081 reg = RADEON_CRTC2_GEN_CNTL;
0082 break;
0083 default:
0084 return;
0085 }
0086 WREG32_IDX(reg, RREG32_IDX(reg) & ~RADEON_CRTC_CUR_EN);
0087 }
0088 }
0089
0090 static void radeon_show_cursor(struct drm_crtc *crtc)
0091 {
0092 struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
0093 struct radeon_device *rdev = crtc->dev->dev_private;
0094
0095 if (radeon_crtc->cursor_out_of_bounds)
0096 return;
0097
0098 if (ASIC_IS_DCE4(rdev)) {
0099 WREG32(EVERGREEN_CUR_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset,
0100 upper_32_bits(radeon_crtc->cursor_addr));
0101 WREG32(EVERGREEN_CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
0102 lower_32_bits(radeon_crtc->cursor_addr));
0103 WREG32(RADEON_MM_INDEX, EVERGREEN_CUR_CONTROL + radeon_crtc->crtc_offset);
0104 WREG32(RADEON_MM_DATA, EVERGREEN_CURSOR_EN |
0105 EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT) |
0106 EVERGREEN_CURSOR_URGENT_CONTROL(EVERGREEN_CURSOR_URGENT_1_2));
0107 } else if (ASIC_IS_AVIVO(rdev)) {
0108 if (rdev->family >= CHIP_RV770) {
0109 if (radeon_crtc->crtc_id)
0110 WREG32(R700_D2CUR_SURFACE_ADDRESS_HIGH,
0111 upper_32_bits(radeon_crtc->cursor_addr));
0112 else
0113 WREG32(R700_D1CUR_SURFACE_ADDRESS_HIGH,
0114 upper_32_bits(radeon_crtc->cursor_addr));
0115 }
0116
0117 WREG32(AVIVO_D1CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
0118 lower_32_bits(radeon_crtc->cursor_addr));
0119 WREG32(RADEON_MM_INDEX, AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset);
0120 WREG32(RADEON_MM_DATA, AVIVO_D1CURSOR_EN |
0121 (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT));
0122 } else {
0123
0124 WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset,
0125 radeon_crtc->cursor_addr - radeon_crtc->legacy_display_base_addr);
0126
0127 switch (radeon_crtc->crtc_id) {
0128 case 0:
0129 WREG32(RADEON_MM_INDEX, RADEON_CRTC_GEN_CNTL);
0130 break;
0131 case 1:
0132 WREG32(RADEON_MM_INDEX, RADEON_CRTC2_GEN_CNTL);
0133 break;
0134 default:
0135 return;
0136 }
0137
0138 WREG32_P(RADEON_MM_DATA, (RADEON_CRTC_CUR_EN |
0139 (RADEON_CRTC_CUR_MODE_24BPP << RADEON_CRTC_CUR_MODE_SHIFT)),
0140 ~(RADEON_CRTC_CUR_EN | RADEON_CRTC_CUR_MODE_MASK));
0141 }
0142 }
0143
0144 static int radeon_cursor_move_locked(struct drm_crtc *crtc, int x, int y)
0145 {
0146 struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
0147 struct radeon_device *rdev = crtc->dev->dev_private;
0148 int xorigin = 0, yorigin = 0;
0149 int w = radeon_crtc->cursor_width;
0150
0151 radeon_crtc->cursor_x = x;
0152 radeon_crtc->cursor_y = y;
0153
0154 if (ASIC_IS_AVIVO(rdev)) {
0155
0156 x += crtc->x;
0157 y += crtc->y;
0158 }
0159
0160 if (x < 0)
0161 xorigin = min(-x, radeon_crtc->max_cursor_width - 1);
0162 if (y < 0)
0163 yorigin = min(-y, radeon_crtc->max_cursor_height - 1);
0164
0165 if (!ASIC_IS_AVIVO(rdev)) {
0166 x += crtc->x;
0167 y += crtc->y;
0168 }
0169 DRM_DEBUG("x %d y %d c->x %d c->y %d\n", x, y, crtc->x, crtc->y);
0170
0171
0172 if (ASIC_IS_AVIVO(rdev) && !ASIC_IS_DCE6(rdev)) {
0173 int i = 0;
0174 struct drm_crtc *crtc_p;
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185 list_for_each_entry(crtc_p, &crtc->dev->mode_config.crtc_list, head) {
0186 if (crtc_p->enabled)
0187 i++;
0188 }
0189 if (i > 1) {
0190 int cursor_end, frame_end;
0191
0192 cursor_end = x + w;
0193 frame_end = crtc->x + crtc->mode.crtc_hdisplay;
0194 if (cursor_end >= frame_end) {
0195 w = w - (cursor_end - frame_end);
0196 if (!(frame_end & 0x7f))
0197 w--;
0198 } else if (cursor_end <= 0) {
0199 goto out_of_bounds;
0200 } else if (!(cursor_end & 0x7f)) {
0201 w--;
0202 }
0203 if (w <= 0) {
0204 goto out_of_bounds;
0205 }
0206 }
0207 }
0208
0209 if (x <= (crtc->x - w) || y <= (crtc->y - radeon_crtc->cursor_height) ||
0210 x >= (crtc->x + crtc->mode.hdisplay) ||
0211 y >= (crtc->y + crtc->mode.vdisplay))
0212 goto out_of_bounds;
0213
0214 x += xorigin;
0215 y += yorigin;
0216
0217 if (ASIC_IS_DCE4(rdev)) {
0218 WREG32(EVERGREEN_CUR_POSITION + radeon_crtc->crtc_offset, (x << 16) | y);
0219 WREG32(EVERGREEN_CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin);
0220 WREG32(EVERGREEN_CUR_SIZE + radeon_crtc->crtc_offset,
0221 ((w - 1) << 16) | (radeon_crtc->cursor_height - 1));
0222 } else if (ASIC_IS_AVIVO(rdev)) {
0223 WREG32(AVIVO_D1CUR_POSITION + radeon_crtc->crtc_offset, (x << 16) | y);
0224 WREG32(AVIVO_D1CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin);
0225 WREG32(AVIVO_D1CUR_SIZE + radeon_crtc->crtc_offset,
0226 ((w - 1) << 16) | (radeon_crtc->cursor_height - 1));
0227 } else {
0228 x -= crtc->x;
0229 y -= crtc->y;
0230
0231 if (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN)
0232 y *= 2;
0233
0234 WREG32(RADEON_CUR_HORZ_VERT_OFF + radeon_crtc->crtc_offset,
0235 (RADEON_CUR_LOCK
0236 | (xorigin << 16)
0237 | yorigin));
0238 WREG32(RADEON_CUR_HORZ_VERT_POSN + radeon_crtc->crtc_offset,
0239 (RADEON_CUR_LOCK
0240 | (x << 16)
0241 | y));
0242
0243 WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset,
0244 radeon_crtc->cursor_addr - radeon_crtc->legacy_display_base_addr +
0245 yorigin * 256);
0246 }
0247
0248 if (radeon_crtc->cursor_out_of_bounds) {
0249 radeon_crtc->cursor_out_of_bounds = false;
0250 if (radeon_crtc->cursor_bo)
0251 radeon_show_cursor(crtc);
0252 }
0253
0254 return 0;
0255
0256 out_of_bounds:
0257 if (!radeon_crtc->cursor_out_of_bounds) {
0258 radeon_hide_cursor(crtc);
0259 radeon_crtc->cursor_out_of_bounds = true;
0260 }
0261 return 0;
0262 }
0263
0264 int radeon_crtc_cursor_move(struct drm_crtc *crtc,
0265 int x, int y)
0266 {
0267 int ret;
0268
0269 radeon_lock_cursor(crtc, true);
0270 ret = radeon_cursor_move_locked(crtc, x, y);
0271 radeon_lock_cursor(crtc, false);
0272
0273 return ret;
0274 }
0275
0276 int radeon_crtc_cursor_set2(struct drm_crtc *crtc,
0277 struct drm_file *file_priv,
0278 uint32_t handle,
0279 uint32_t width,
0280 uint32_t height,
0281 int32_t hot_x,
0282 int32_t hot_y)
0283 {
0284 struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
0285 struct radeon_device *rdev = crtc->dev->dev_private;
0286 struct drm_gem_object *obj;
0287 struct radeon_bo *robj;
0288 int ret;
0289
0290 if (!handle) {
0291
0292 radeon_hide_cursor(crtc);
0293 obj = NULL;
0294 goto unpin;
0295 }
0296
0297 if ((width > radeon_crtc->max_cursor_width) ||
0298 (height > radeon_crtc->max_cursor_height)) {
0299 DRM_ERROR("bad cursor width or height %d x %d\n", width, height);
0300 return -EINVAL;
0301 }
0302
0303 obj = drm_gem_object_lookup(file_priv, handle);
0304 if (!obj) {
0305 DRM_ERROR("Cannot find cursor object %x for crtc %d\n", handle, radeon_crtc->crtc_id);
0306 return -ENOENT;
0307 }
0308
0309 robj = gem_to_radeon_bo(obj);
0310 ret = radeon_bo_reserve(robj, false);
0311 if (ret != 0) {
0312 drm_gem_object_put(obj);
0313 return ret;
0314 }
0315
0316 ret = radeon_bo_pin_restricted(robj, RADEON_GEM_DOMAIN_VRAM,
0317 ASIC_IS_AVIVO(rdev) ? 0 : 1 << 27,
0318 &radeon_crtc->cursor_addr);
0319 radeon_bo_unreserve(robj);
0320 if (ret) {
0321 DRM_ERROR("Failed to pin new cursor BO (%d)\n", ret);
0322 drm_gem_object_put(obj);
0323 return ret;
0324 }
0325
0326 radeon_lock_cursor(crtc, true);
0327
0328 if (width != radeon_crtc->cursor_width ||
0329 height != radeon_crtc->cursor_height ||
0330 hot_x != radeon_crtc->cursor_hot_x ||
0331 hot_y != radeon_crtc->cursor_hot_y) {
0332 int x, y;
0333
0334 x = radeon_crtc->cursor_x + radeon_crtc->cursor_hot_x - hot_x;
0335 y = radeon_crtc->cursor_y + radeon_crtc->cursor_hot_y - hot_y;
0336
0337 radeon_crtc->cursor_width = width;
0338 radeon_crtc->cursor_height = height;
0339 radeon_crtc->cursor_hot_x = hot_x;
0340 radeon_crtc->cursor_hot_y = hot_y;
0341
0342 radeon_cursor_move_locked(crtc, x, y);
0343 }
0344
0345 radeon_show_cursor(crtc);
0346
0347 radeon_lock_cursor(crtc, false);
0348
0349 unpin:
0350 if (radeon_crtc->cursor_bo) {
0351 struct radeon_bo *robj = gem_to_radeon_bo(radeon_crtc->cursor_bo);
0352 ret = radeon_bo_reserve(robj, false);
0353 if (likely(ret == 0)) {
0354 radeon_bo_unpin(robj);
0355 radeon_bo_unreserve(robj);
0356 }
0357 drm_gem_object_put(radeon_crtc->cursor_bo);
0358 }
0359
0360 radeon_crtc->cursor_bo = obj;
0361 return 0;
0362 }
0363
0364
0365
0366
0367
0368
0369
0370
0371
0372 void radeon_cursor_reset(struct drm_crtc *crtc)
0373 {
0374 struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
0375
0376 if (radeon_crtc->cursor_bo) {
0377 radeon_lock_cursor(crtc, true);
0378
0379 radeon_cursor_move_locked(crtc, radeon_crtc->cursor_x,
0380 radeon_crtc->cursor_y);
0381
0382 radeon_show_cursor(crtc);
0383
0384 radeon_lock_cursor(crtc, false);
0385 }
0386 }