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#include "drmP.h"
  27#include "radeon_drm.h"
  28#include "radeon.h"
  29
  30#define CURSOR_WIDTH 64
  31#define CURSOR_HEIGHT 64
  32
  33static void radeon_lock_cursor(struct drm_crtc *crtc, bool lock)
  34{
  35        struct radeon_device *rdev = crtc->dev->dev_private;
  36        struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
  37        uint32_t cur_lock;
  38
  39        if (ASIC_IS_DCE4(rdev)) {
  40                cur_lock = RREG32(EVERGREEN_CUR_UPDATE + radeon_crtc->crtc_offset);
  41                if (lock)
  42                        cur_lock |= EVERGREEN_CURSOR_UPDATE_LOCK;
  43                else
  44                        cur_lock &= ~EVERGREEN_CURSOR_UPDATE_LOCK;
  45                WREG32(EVERGREEN_CUR_UPDATE + radeon_crtc->crtc_offset, cur_lock);
  46        } else if (ASIC_IS_AVIVO(rdev)) {
  47                cur_lock = RREG32(AVIVO_D1CUR_UPDATE + radeon_crtc->crtc_offset);
  48                if (lock)
  49                        cur_lock |= AVIVO_D1CURSOR_UPDATE_LOCK;
  50                else
  51                        cur_lock &= ~AVIVO_D1CURSOR_UPDATE_LOCK;
  52                WREG32(AVIVO_D1CUR_UPDATE + radeon_crtc->crtc_offset, cur_lock);
  53        } else {
  54                cur_lock = RREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset);
  55                if (lock)
  56                        cur_lock |= RADEON_CUR_LOCK;
  57                else
  58                        cur_lock &= ~RADEON_CUR_LOCK;
  59                WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, cur_lock);
  60        }
  61}
  62
  63static void radeon_hide_cursor(struct drm_crtc *crtc)
  64{
  65        struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
  66        struct radeon_device *rdev = crtc->dev->dev_private;
  67
  68        if (ASIC_IS_DCE4(rdev)) {
  69                WREG32(RADEON_MM_INDEX, EVERGREEN_CUR_CONTROL + radeon_crtc->crtc_offset);
  70                WREG32(RADEON_MM_DATA, EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT));
  71        } else if (ASIC_IS_AVIVO(rdev)) {
  72                WREG32(RADEON_MM_INDEX, AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset);
  73                WREG32(RADEON_MM_DATA, (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT));
  74        } else {
  75                switch (radeon_crtc->crtc_id) {
  76                case 0:
  77                        WREG32(RADEON_MM_INDEX, RADEON_CRTC_GEN_CNTL);
  78                        break;
  79                case 1:
  80                        WREG32(RADEON_MM_INDEX, RADEON_CRTC2_GEN_CNTL);
  81                        break;
  82                default:
  83                        return;
  84                }
  85                WREG32_P(RADEON_MM_DATA, 0, ~RADEON_CRTC_CUR_EN);
  86        }
  87}
  88
  89static void radeon_show_cursor(struct drm_crtc *crtc)
  90{
  91        struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
  92        struct radeon_device *rdev = crtc->dev->dev_private;
  93
  94        if (ASIC_IS_DCE4(rdev)) {
  95                WREG32(RADEON_MM_INDEX, EVERGREEN_CUR_CONTROL + radeon_crtc->crtc_offset);
  96                WREG32(RADEON_MM_DATA, EVERGREEN_CURSOR_EN |
  97                       EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT));
  98        } else if (ASIC_IS_AVIVO(rdev)) {
  99                WREG32(RADEON_MM_INDEX, AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset);
 100                WREG32(RADEON_MM_DATA, AVIVO_D1CURSOR_EN |
 101                       (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT));
 102        } else {
 103                switch (radeon_crtc->crtc_id) {
 104                case 0:
 105                        WREG32(RADEON_MM_INDEX, RADEON_CRTC_GEN_CNTL);
 106                        break;
 107                case 1:
 108                        WREG32(RADEON_MM_INDEX, RADEON_CRTC2_GEN_CNTL);
 109                        break;
 110                default:
 111                        return;
 112                }
 113
 114                WREG32_P(RADEON_MM_DATA, (RADEON_CRTC_CUR_EN |
 115                                          (RADEON_CRTC_CUR_MODE_24BPP << RADEON_CRTC_CUR_MODE_SHIFT)),
 116                         ~(RADEON_CRTC_CUR_EN | RADEON_CRTC_CUR_MODE_MASK));
 117        }
 118}
 119
 120static void radeon_set_cursor(struct drm_crtc *crtc, struct drm_gem_object *obj,
 121                              uint64_t gpu_addr)
 122{
 123        struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
 124        struct radeon_device *rdev = crtc->dev->dev_private;
 125
 126        if (ASIC_IS_DCE4(rdev)) {
 127                WREG32(EVERGREEN_CUR_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset,
 128                       upper_32_bits(gpu_addr));
 129                WREG32(EVERGREEN_CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
 130                       gpu_addr & 0xffffffff);
 131        } else if (ASIC_IS_AVIVO(rdev)) {
 132                if (rdev->family >= CHIP_RV770) {
 133                        if (radeon_crtc->crtc_id)
 134                                WREG32(R700_D2CUR_SURFACE_ADDRESS_HIGH, upper_32_bits(gpu_addr));
 135                        else
 136                                WREG32(R700_D1CUR_SURFACE_ADDRESS_HIGH, upper_32_bits(gpu_addr));
 137                }
 138                WREG32(AVIVO_D1CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
 139                       gpu_addr & 0xffffffff);
 140        } else {
 141                radeon_crtc->legacy_cursor_offset = gpu_addr - radeon_crtc->legacy_display_base_addr;
 142                /* offset is from DISP(2)_BASE_ADDRESS */
 143                WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, radeon_crtc->legacy_cursor_offset);
 144        }
 145}
 146
 147int radeon_crtc_cursor_set(struct drm_crtc *crtc,
 148                           struct drm_file *file_priv,
 149                           uint32_t handle,
 150                           uint32_t width,
 151                           uint32_t height)
 152{
 153        struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
 154        struct drm_gem_object *obj;
 155        uint64_t gpu_addr;
 156        int ret;
 157
 158        if (!handle) {
 159                /* turn off cursor */
 160                radeon_hide_cursor(crtc);
 161                obj = NULL;
 162                goto unpin;
 163        }
 164
 165        if ((width > CURSOR_WIDTH) || (height > CURSOR_HEIGHT)) {
 166                DRM_ERROR("bad cursor width or height %d x %d\n", width, height);
 167                return -EINVAL;
 168        }
 169
 170        radeon_crtc->cursor_width = width;
 171        radeon_crtc->cursor_height = height;
 172
 173        obj = drm_gem_object_lookup(crtc->dev, file_priv, handle);
 174        if (!obj) {
 175                DRM_ERROR("Cannot find cursor object %x for crtc %d\n", handle, radeon_crtc->crtc_id);
 176                return -ENOENT;
 177        }
 178
 179        ret = radeon_gem_object_pin(obj, RADEON_GEM_DOMAIN_VRAM, &gpu_addr);
 180        if (ret)
 181                goto fail;
 182
 183        radeon_lock_cursor(crtc, true);
 184        /* XXX only 27 bit offset for legacy cursor */
 185        radeon_set_cursor(crtc, obj, gpu_addr);
 186        radeon_show_cursor(crtc);
 187        radeon_lock_cursor(crtc, false);
 188
 189unpin:
 190        if (radeon_crtc->cursor_bo) {
 191                radeon_gem_object_unpin(radeon_crtc->cursor_bo);
 192                drm_gem_object_unreference_unlocked(radeon_crtc->cursor_bo);
 193        }
 194
 195        radeon_crtc->cursor_bo = obj;
 196        return 0;
 197fail:
 198        drm_gem_object_unreference_unlocked(obj);
 199
 200        return ret;
 201}
 202
 203int radeon_crtc_cursor_move(struct drm_crtc *crtc,
 204                            int x, int y)
 205{
 206        struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
 207        struct radeon_device *rdev = crtc->dev->dev_private;
 208        int xorigin = 0, yorigin = 0;
 209        int w = radeon_crtc->cursor_width;
 210
 211        if (x < 0)
 212                xorigin = -x + 1;
 213        if (y < 0)
 214                yorigin = -y + 1;
 215        if (xorigin >= CURSOR_WIDTH)
 216                xorigin = CURSOR_WIDTH - 1;
 217        if (yorigin >= CURSOR_HEIGHT)
 218                yorigin = CURSOR_HEIGHT - 1;
 219
 220        if (ASIC_IS_AVIVO(rdev)) {
 221                int i = 0;
 222                struct drm_crtc *crtc_p;
 223
 224                /* avivo cursor are offset into the total surface */
 225                x += crtc->x;
 226                y += crtc->y;
 227                DRM_DEBUG("x %d y %d c->x %d c->y %d\n", x, y, crtc->x, crtc->y);
 228
 229                /* avivo cursor image can't end on 128 pixel boundry or
 230                 * go past the end of the frame if both crtcs are enabled
 231                 */
 232                list_for_each_entry(crtc_p, &crtc->dev->mode_config.crtc_list, head) {
 233                        if (crtc_p->enabled)
 234                                i++;
 235                }
 236                if (i > 1) {
 237                        int cursor_end, frame_end;
 238
 239                        cursor_end = x - xorigin + w;
 240                        frame_end = crtc->x + crtc->mode.crtc_hdisplay;
 241                        if (cursor_end >= frame_end) {
 242                                w = w - (cursor_end - frame_end);
 243                                if (!(frame_end & 0x7f))
 244                                        w--;
 245                        } else {
 246                                if (!(cursor_end & 0x7f))
 247                                        w--;
 248                        }
 249                        if (w <= 0)
 250                                w = 1;
 251                }
 252        }
 253
 254        radeon_lock_cursor(crtc, true);
 255        if (ASIC_IS_DCE4(rdev)) {
 256                WREG32(EVERGREEN_CUR_POSITION + radeon_crtc->crtc_offset,
 257                       ((xorigin ? 0 : x) << 16) |
 258                       (yorigin ? 0 : y));
 259                WREG32(EVERGREEN_CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin);
 260                WREG32(EVERGREEN_CUR_SIZE + radeon_crtc->crtc_offset,
 261                       ((w - 1) << 16) | (radeon_crtc->cursor_height - 1));
 262        } else if (ASIC_IS_AVIVO(rdev)) {
 263                WREG32(AVIVO_D1CUR_POSITION + radeon_crtc->crtc_offset,
 264                             ((xorigin ? 0 : x) << 16) |
 265                             (yorigin ? 0 : y));
 266                WREG32(AVIVO_D1CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin);
 267                WREG32(AVIVO_D1CUR_SIZE + radeon_crtc->crtc_offset,
 268                       ((w - 1) << 16) | (radeon_crtc->cursor_height - 1));
 269        } else {
 270                if (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN)
 271                        y *= 2;
 272
 273                WREG32(RADEON_CUR_HORZ_VERT_OFF + radeon_crtc->crtc_offset,
 274                       (RADEON_CUR_LOCK
 275                        | (xorigin << 16)
 276                        | yorigin));
 277                WREG32(RADEON_CUR_HORZ_VERT_POSN + radeon_crtc->crtc_offset,
 278                       (RADEON_CUR_LOCK
 279                        | ((xorigin ? 0 : x) << 16)
 280                        | (yorigin ? 0 : y)));
 281                /* offset is from DISP(2)_BASE_ADDRESS */
 282                WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, (radeon_crtc->legacy_cursor_offset +
 283                                                                      (yorigin * 256)));
 284        }
 285        radeon_lock_cursor(crtc, false);
 286
 287        return 0;
 288}
 289