linux/drivers/gpu/drm/radeon/radeon_cursor.c
<<
>>
Prefs
   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
  32static 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
  62static 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
  90static 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
 144static 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
 264int 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
 276int 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(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(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
 349unpin:
 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(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 */
 372void 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}
 387