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        obj = drm_gem_object_lookup(crtc->dev, file_priv, handle);
 171        if (!obj) {
 172                DRM_ERROR("Cannot find cursor object %x for crtc %d\n", handle, radeon_crtc->crtc_id);
 173                return -ENOENT;
 174        }
 175
 176        ret = radeon_gem_object_pin(obj, RADEON_GEM_DOMAIN_VRAM, &gpu_addr);
 177        if (ret)
 178                goto fail;
 179
 180        radeon_crtc->cursor_width = width;
 181        radeon_crtc->cursor_height = height;
 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 (ASIC_IS_AVIVO(rdev)) {
 212                /* avivo cursor are offset into the total surface */
 213                x += crtc->x;
 214                y += crtc->y;
 215        }
 216        DRM_DEBUG("x %d y %d c->x %d c->y %d\n", x, y, crtc->x, crtc->y);
 217
 218        if (x < 0) {
 219                xorigin = min(-x, CURSOR_WIDTH - 1);
 220                x = 0;
 221        }
 222        if (y < 0) {
 223                yorigin = min(-y, CURSOR_HEIGHT - 1);
 224                y = 0;
 225        }
 226
 227        if (ASIC_IS_AVIVO(rdev)) {
 228                int i = 0;
 229                struct drm_crtc *crtc_p;
 230
 231                /* avivo cursor image can't end on 128 pixel boundary or
 232                 * go past the end of the frame if both crtcs are enabled
 233                 */
 234                list_for_each_entry(crtc_p, &crtc->dev->mode_config.crtc_list, head) {
 235                        if (crtc_p->enabled)
 236                                i++;
 237                }
 238                if (i > 1) {
 239                        int cursor_end, frame_end;
 240
 241                        cursor_end = x - xorigin + w;
 242                        frame_end = crtc->x + crtc->mode.crtc_hdisplay;
 243                        if (cursor_end >= frame_end) {
 244                                w = w - (cursor_end - frame_end);
 245                                if (!(frame_end & 0x7f))
 246                                        w--;
 247                        } else {
 248                                if (!(cursor_end & 0x7f))
 249                                        w--;
 250                        }
 251                        if (w <= 0)
 252                                w = 1;
 253                }
 254        }
 255
 256        radeon_lock_cursor(crtc, true);
 257        if (ASIC_IS_DCE4(rdev)) {
 258                WREG32(EVERGREEN_CUR_POSITION + radeon_crtc->crtc_offset, (x << 16) | 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, (x << 16) | y);
 264                WREG32(AVIVO_D1CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin);
 265                WREG32(AVIVO_D1CUR_SIZE + radeon_crtc->crtc_offset,
 266                       ((w - 1) << 16) | (radeon_crtc->cursor_height - 1));
 267        } else {
 268                if (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN)
 269                        y *= 2;
 270
 271                WREG32(RADEON_CUR_HORZ_VERT_OFF + radeon_crtc->crtc_offset,
 272                       (RADEON_CUR_LOCK
 273                        | (xorigin << 16)
 274                        | yorigin));
 275                WREG32(RADEON_CUR_HORZ_VERT_POSN + radeon_crtc->crtc_offset,
 276                       (RADEON_CUR_LOCK
 277                        | (x << 16)
 278                        | y));
 279                /* offset is from DISP(2)_BASE_ADDRESS */
 280                WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, (radeon_crtc->legacy_cursor_offset +
 281                                                                      (yorigin * 256)));
 282        }
 283        radeon_lock_cursor(crtc, false);
 284
 285        return 0;
 286}
 287