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