Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2007-8 Advanced Micro Devices, Inc.
0003  * Copyright 2008 Red Hat Inc.
0004  *
0005  * Permission is hereby granted, free of charge, to any person obtaining a
0006  * copy of this software and associated documentation files (the "Software"),
0007  * to deal in the Software without restriction, including without limitation
0008  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0009  * and/or sell copies of the Software, and to permit persons to whom the
0010  * Software is furnished to do so, subject to the following conditions:
0011  *
0012  * The above copyright notice and this permission notice shall be included in
0013  * all copies or substantial portions of the Software.
0014  *
0015  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0016  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0017  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0018  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
0019  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0020  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0021  * OTHER DEALINGS IN THE SOFTWARE.
0022  *
0023  * Authors: Dave Airlie
0024  *          Alex Deucher
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         /* offset is from DISP(2)_BASE_ADDRESS */
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         /* avivo cursor are offset into the total surface */
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     /* fixed on DCE6 and newer */
0172     if (ASIC_IS_AVIVO(rdev) && !ASIC_IS_DCE6(rdev)) {
0173         int i = 0;
0174         struct drm_crtc *crtc_p;
0175 
0176         /*
0177          * avivo cursor image can't end on 128 pixel boundary or
0178          * go past the end of the frame if both crtcs are enabled
0179          *
0180          * NOTE: It is safe to access crtc->enabled of other crtcs
0181          * without holding either the mode_config lock or the other
0182          * crtc's lock as long as write access to this flag _always_
0183          * grabs all locks.
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         /* offset is from DISP(2)_BASE_ADDRESS */
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         /* turn off cursor */
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     /* Only 27 bit offset for legacy cursor */
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  * radeon_cursor_reset - Re-set the current cursor, if any.
0366  *
0367  * @crtc: drm crtc
0368  *
0369  * If the CRTC passed in currently has a cursor assigned, this function
0370  * makes sure it's visible.
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 }