root/drivers/gpu/drm/radeon/radeon_cursor.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. radeon_lock_cursor
  2. radeon_hide_cursor
  3. radeon_show_cursor
  4. radeon_cursor_move_locked
  5. radeon_crtc_cursor_move
  6. radeon_crtc_cursor_set2
  7. radeon_cursor_reset

   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 
  27 #include <drm/drm_device.h>
  28 #include <drm/radeon_drm.h>
  29 
  30 #include "radeon.h"
  31 
  32 static void radeon_lock_cursor(struct drm_crtc *crtc, bool lock)
  33 {
  34         struct radeon_device *rdev = crtc->dev->dev_private;
  35         struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
  36         uint32_t cur_lock;
  37 
  38         if (ASIC_IS_DCE4(rdev)) {
  39                 cur_lock = RREG32(EVERGREEN_CUR_UPDATE + radeon_crtc->crtc_offset);
  40                 if (lock)
  41                         cur_lock |= EVERGREEN_CURSOR_UPDATE_LOCK;
  42                 else
  43                         cur_lock &= ~EVERGREEN_CURSOR_UPDATE_LOCK;
  44                 WREG32(EVERGREEN_CUR_UPDATE + radeon_crtc->crtc_offset, cur_lock);
  45         } else if (ASIC_IS_AVIVO(rdev)) {
  46                 cur_lock = RREG32(AVIVO_D1CUR_UPDATE + radeon_crtc->crtc_offset);
  47                 if (lock)
  48                         cur_lock |= AVIVO_D1CURSOR_UPDATE_LOCK;
  49                 else
  50                         cur_lock &= ~AVIVO_D1CURSOR_UPDATE_LOCK;
  51                 WREG32(AVIVO_D1CUR_UPDATE + radeon_crtc->crtc_offset, cur_lock);
  52         } else {
  53                 cur_lock = RREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset);
  54                 if (lock)
  55                         cur_lock |= RADEON_CUR_LOCK;
  56                 else
  57                         cur_lock &= ~RADEON_CUR_LOCK;
  58                 WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, cur_lock);
  59         }
  60 }
  61 
  62 static void radeon_hide_cursor(struct drm_crtc *crtc)
  63 {
  64         struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
  65         struct radeon_device *rdev = crtc->dev->dev_private;
  66 
  67         if (ASIC_IS_DCE4(rdev)) {
  68                 WREG32_IDX(EVERGREEN_CUR_CONTROL + radeon_crtc->crtc_offset,
  69                            EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT) |
  70                            EVERGREEN_CURSOR_URGENT_CONTROL(EVERGREEN_CURSOR_URGENT_1_2));
  71         } else if (ASIC_IS_AVIVO(rdev)) {
  72                 WREG32_IDX(AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset,
  73                            (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT));
  74         } else {
  75                 u32 reg;
  76                 switch (radeon_crtc->crtc_id) {
  77                 case 0:
  78                         reg = RADEON_CRTC_GEN_CNTL;
  79                         break;
  80                 case 1:
  81                         reg = RADEON_CRTC2_GEN_CNTL;
  82                         break;
  83                 default:
  84                         return;
  85                 }
  86                 WREG32_IDX(reg, RREG32_IDX(reg) & ~RADEON_CRTC_CUR_EN);
  87         }
  88 }
  89 
  90 static void radeon_show_cursor(struct drm_crtc *crtc)
  91 {
  92         struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
  93         struct radeon_device *rdev = crtc->dev->dev_private;
  94 
  95         if (radeon_crtc->cursor_out_of_bounds)
  96                 return;
  97 
  98         if (ASIC_IS_DCE4(rdev)) {
  99                 WREG32(EVERGREEN_CUR_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset,
 100                        upper_32_bits(radeon_crtc->cursor_addr));
 101                 WREG32(EVERGREEN_CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
 102                        lower_32_bits(radeon_crtc->cursor_addr));
 103                 WREG32(RADEON_MM_INDEX, EVERGREEN_CUR_CONTROL + radeon_crtc->crtc_offset);
 104                 WREG32(RADEON_MM_DATA, EVERGREEN_CURSOR_EN |
 105                        EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT) |
 106                        EVERGREEN_CURSOR_URGENT_CONTROL(EVERGREEN_CURSOR_URGENT_1_2));
 107         } else if (ASIC_IS_AVIVO(rdev)) {
 108                 if (rdev->family >= CHIP_RV770) {
 109                         if (radeon_crtc->crtc_id)
 110                                 WREG32(R700_D2CUR_SURFACE_ADDRESS_HIGH,
 111                                        upper_32_bits(radeon_crtc->cursor_addr));
 112                         else
 113                                 WREG32(R700_D1CUR_SURFACE_ADDRESS_HIGH,
 114                                        upper_32_bits(radeon_crtc->cursor_addr));
 115                 }
 116 
 117                 WREG32(AVIVO_D1CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
 118                        lower_32_bits(radeon_crtc->cursor_addr));
 119                 WREG32(RADEON_MM_INDEX, AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset);
 120                 WREG32(RADEON_MM_DATA, AVIVO_D1CURSOR_EN |
 121                        (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT));
 122         } else {
 123                 /* offset is from DISP(2)_BASE_ADDRESS */
 124                 WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset,
 125                        radeon_crtc->cursor_addr - radeon_crtc->legacy_display_base_addr);
 126 
 127                 switch (radeon_crtc->crtc_id) {
 128                 case 0:
 129                         WREG32(RADEON_MM_INDEX, RADEON_CRTC_GEN_CNTL);
 130                         break;
 131                 case 1:
 132                         WREG32(RADEON_MM_INDEX, RADEON_CRTC2_GEN_CNTL);
 133                         break;
 134                 default:
 135                         return;
 136                 }
 137 
 138                 WREG32_P(RADEON_MM_DATA, (RADEON_CRTC_CUR_EN |
 139                                           (RADEON_CRTC_CUR_MODE_24BPP << RADEON_CRTC_CUR_MODE_SHIFT)),
 140                          ~(RADEON_CRTC_CUR_EN | RADEON_CRTC_CUR_MODE_MASK));
 141         }
 142 }
 143 
 144 static int radeon_cursor_move_locked(struct drm_crtc *crtc, int x, int y)
 145 {
 146         struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
 147         struct radeon_device *rdev = crtc->dev->dev_private;
 148         int xorigin = 0, yorigin = 0;
 149         int w = radeon_crtc->cursor_width;
 150 
 151         radeon_crtc->cursor_x = x;
 152         radeon_crtc->cursor_y = y;
 153 
 154         if (ASIC_IS_AVIVO(rdev)) {
 155                 /* avivo cursor are offset into the total surface */
 156                 x += crtc->x;
 157                 y += crtc->y;
 158         }
 159 
 160         if (x < 0)
 161                 xorigin = min(-x, radeon_crtc->max_cursor_width - 1);
 162         if (y < 0)
 163                 yorigin = min(-y, radeon_crtc->max_cursor_height - 1);
 164 
 165         if (!ASIC_IS_AVIVO(rdev)) {
 166                 x += crtc->x;
 167                 y += crtc->y;
 168         }
 169         DRM_DEBUG("x %d y %d c->x %d c->y %d\n", x, y, crtc->x, crtc->y);
 170 
 171         /* fixed on DCE6 and newer */
 172         if (ASIC_IS_AVIVO(rdev) && !ASIC_IS_DCE6(rdev)) {
 173                 int i = 0;
 174                 struct drm_crtc *crtc_p;
 175 
 176                 /*
 177                  * avivo cursor image can't end on 128 pixel boundary or
 178                  * go past the end of the frame if both crtcs are enabled
 179                  *
 180                  * NOTE: It is safe to access crtc->enabled of other crtcs
 181                  * without holding either the mode_config lock or the other
 182                  * crtc's lock as long as write access to this flag _always_
 183                  * grabs all locks.
 184                  */
 185                 list_for_each_entry(crtc_p, &crtc->dev->mode_config.crtc_list, head) {
 186                         if (crtc_p->enabled)
 187                                 i++;
 188                 }
 189                 if (i > 1) {
 190                         int cursor_end, frame_end;
 191 
 192                         cursor_end = x + w;
 193                         frame_end = crtc->x + crtc->mode.crtc_hdisplay;
 194                         if (cursor_end >= frame_end) {
 195                                 w = w - (cursor_end - frame_end);
 196                                 if (!(frame_end & 0x7f))
 197                                         w--;
 198                         } else if (cursor_end <= 0) {
 199                                 goto out_of_bounds;
 200                         } else if (!(cursor_end & 0x7f)) {
 201                                 w--;
 202                         }
 203                         if (w <= 0) {
 204                                 goto out_of_bounds;
 205                         }
 206                 }
 207         }
 208 
 209         if (x <= (crtc->x - w) || y <= (crtc->y - radeon_crtc->cursor_height) ||
 210             x >= (crtc->x + crtc->mode.hdisplay) ||
 211             y >= (crtc->y + crtc->mode.vdisplay))
 212                 goto out_of_bounds;
 213 
 214         x += xorigin;
 215         y += yorigin;
 216 
 217         if (ASIC_IS_DCE4(rdev)) {
 218                 WREG32(EVERGREEN_CUR_POSITION + radeon_crtc->crtc_offset, (x << 16) | y);
 219                 WREG32(EVERGREEN_CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin);
 220                 WREG32(EVERGREEN_CUR_SIZE + radeon_crtc->crtc_offset,
 221                        ((w - 1) << 16) | (radeon_crtc->cursor_height - 1));
 222         } else if (ASIC_IS_AVIVO(rdev)) {
 223                 WREG32(AVIVO_D1CUR_POSITION + radeon_crtc->crtc_offset, (x << 16) | y);
 224                 WREG32(AVIVO_D1CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin);
 225                 WREG32(AVIVO_D1CUR_SIZE + radeon_crtc->crtc_offset,
 226                        ((w - 1) << 16) | (radeon_crtc->cursor_height - 1));
 227         } else {
 228                 x -= crtc->x;
 229                 y -= crtc->y;
 230 
 231                 if (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN)
 232                         y *= 2;
 233 
 234                 WREG32(RADEON_CUR_HORZ_VERT_OFF + radeon_crtc->crtc_offset,
 235                        (RADEON_CUR_LOCK
 236                         | (xorigin << 16)
 237                         | yorigin));
 238                 WREG32(RADEON_CUR_HORZ_VERT_POSN + radeon_crtc->crtc_offset,
 239                        (RADEON_CUR_LOCK
 240                         | (x << 16)
 241                         | y));
 242                 /* offset is from DISP(2)_BASE_ADDRESS */
 243                 WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset,
 244                        radeon_crtc->cursor_addr - radeon_crtc->legacy_display_base_addr +
 245                        yorigin * 256);
 246         }
 247 
 248         if (radeon_crtc->cursor_out_of_bounds) {
 249                 radeon_crtc->cursor_out_of_bounds = false;
 250                 if (radeon_crtc->cursor_bo)
 251                         radeon_show_cursor(crtc);
 252         }
 253 
 254         return 0;
 255 
 256  out_of_bounds:
 257         if (!radeon_crtc->cursor_out_of_bounds) {
 258                 radeon_hide_cursor(crtc);
 259                 radeon_crtc->cursor_out_of_bounds = true;
 260         }
 261         return 0;
 262 }
 263 
 264 int radeon_crtc_cursor_move(struct drm_crtc *crtc,
 265                             int x, int y)
 266 {
 267         int ret;
 268 
 269         radeon_lock_cursor(crtc, true);
 270         ret = radeon_cursor_move_locked(crtc, x, y);
 271         radeon_lock_cursor(crtc, false);
 272 
 273         return ret;
 274 }
 275 
 276 int radeon_crtc_cursor_set2(struct drm_crtc *crtc,
 277                             struct drm_file *file_priv,
 278                             uint32_t handle,
 279                             uint32_t width,
 280                             uint32_t height,
 281                             int32_t hot_x,
 282                             int32_t hot_y)
 283 {
 284         struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
 285         struct radeon_device *rdev = crtc->dev->dev_private;
 286         struct drm_gem_object *obj;
 287         struct radeon_bo *robj;
 288         int ret;
 289 
 290         if (!handle) {
 291                 /* turn off cursor */
 292                 radeon_hide_cursor(crtc);
 293                 obj = NULL;
 294                 goto unpin;
 295         }
 296 
 297         if ((width > radeon_crtc->max_cursor_width) ||
 298             (height > radeon_crtc->max_cursor_height)) {
 299                 DRM_ERROR("bad cursor width or height %d x %d\n", width, height);
 300                 return -EINVAL;
 301         }
 302 
 303         obj = drm_gem_object_lookup(file_priv, handle);
 304         if (!obj) {
 305                 DRM_ERROR("Cannot find cursor object %x for crtc %d\n", handle, radeon_crtc->crtc_id);
 306                 return -ENOENT;
 307         }
 308 
 309         robj = gem_to_radeon_bo(obj);
 310         ret = radeon_bo_reserve(robj, false);
 311         if (ret != 0) {
 312                 drm_gem_object_put_unlocked(obj);
 313                 return ret;
 314         }
 315         /* Only 27 bit offset for legacy cursor */
 316         ret = radeon_bo_pin_restricted(robj, RADEON_GEM_DOMAIN_VRAM,
 317                                        ASIC_IS_AVIVO(rdev) ? 0 : 1 << 27,
 318                                        &radeon_crtc->cursor_addr);
 319         radeon_bo_unreserve(robj);
 320         if (ret) {
 321                 DRM_ERROR("Failed to pin new cursor BO (%d)\n", ret);
 322                 drm_gem_object_put_unlocked(obj);
 323                 return ret;
 324         }
 325 
 326         radeon_lock_cursor(crtc, true);
 327 
 328         if (width != radeon_crtc->cursor_width ||
 329             height != radeon_crtc->cursor_height ||
 330             hot_x != radeon_crtc->cursor_hot_x ||
 331             hot_y != radeon_crtc->cursor_hot_y) {
 332                 int x, y;
 333 
 334                 x = radeon_crtc->cursor_x + radeon_crtc->cursor_hot_x - hot_x;
 335                 y = radeon_crtc->cursor_y + radeon_crtc->cursor_hot_y - hot_y;
 336 
 337                 radeon_crtc->cursor_width = width;
 338                 radeon_crtc->cursor_height = height;
 339                 radeon_crtc->cursor_hot_x = hot_x;
 340                 radeon_crtc->cursor_hot_y = hot_y;
 341 
 342                 radeon_cursor_move_locked(crtc, x, y);
 343         }
 344 
 345         radeon_show_cursor(crtc);
 346 
 347         radeon_lock_cursor(crtc, false);
 348 
 349 unpin:
 350         if (radeon_crtc->cursor_bo) {
 351                 struct radeon_bo *robj = gem_to_radeon_bo(radeon_crtc->cursor_bo);
 352                 ret = radeon_bo_reserve(robj, false);
 353                 if (likely(ret == 0)) {
 354                         radeon_bo_unpin(robj);
 355                         radeon_bo_unreserve(robj);
 356                 }
 357                 drm_gem_object_put_unlocked(radeon_crtc->cursor_bo);
 358         }
 359 
 360         radeon_crtc->cursor_bo = obj;
 361         return 0;
 362 }
 363 
 364 /**
 365  * radeon_cursor_reset - Re-set the current cursor, if any.
 366  *
 367  * @crtc: drm crtc
 368  *
 369  * If the CRTC passed in currently has a cursor assigned, this function
 370  * makes sure it's visible.
 371  */
 372 void radeon_cursor_reset(struct drm_crtc *crtc)
 373 {
 374         struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
 375 
 376         if (radeon_crtc->cursor_bo) {
 377                 radeon_lock_cursor(crtc, true);
 378 
 379                 radeon_cursor_move_locked(crtc, radeon_crtc->cursor_x,
 380                                           radeon_crtc->cursor_y);
 381 
 382                 radeon_show_cursor(crtc);
 383 
 384                 radeon_lock_cursor(crtc, false);
 385         }
 386 }

/* [<][>][^][v][top][bottom][index][help] */