linux/drivers/gpu/drm/mgag200/mgag200_cursor.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright 2013 Matrox Graphics
   4 *
   5 * Author: Christopher Harvey <charvey@matrox.com>
   6 */
   7
   8#include <drm/drmP.h>
   9#include "mgag200_drv.h"
  10
  11static bool warn_transparent = true;
  12static bool warn_palette = true;
  13
  14/*
  15  Hide the cursor off screen. We can't disable the cursor hardware because it
  16  takes too long to re-activate and causes momentary corruption
  17*/
  18static void mga_hide_cursor(struct mga_device *mdev)
  19{
  20        WREG8(MGA_CURPOSXL, 0);
  21        WREG8(MGA_CURPOSXH, 0);
  22        if (mdev->cursor.pixels_current)
  23                drm_gem_vram_unpin(mdev->cursor.pixels_current);
  24        mdev->cursor.pixels_current = NULL;
  25}
  26
  27int mga_crtc_cursor_set(struct drm_crtc *crtc,
  28                        struct drm_file *file_priv,
  29                        uint32_t handle,
  30                        uint32_t width,
  31                        uint32_t height)
  32{
  33        struct drm_device *dev = crtc->dev;
  34        struct mga_device *mdev = (struct mga_device *)dev->dev_private;
  35        struct drm_gem_vram_object *pixels_1 = mdev->cursor.pixels_1;
  36        struct drm_gem_vram_object *pixels_2 = mdev->cursor.pixels_2;
  37        struct drm_gem_vram_object *pixels_current = mdev->cursor.pixels_current;
  38        struct drm_gem_vram_object *pixels_next;
  39        struct drm_gem_object *obj;
  40        struct drm_gem_vram_object *gbo = NULL;
  41        int ret = 0;
  42        u8 *src, *dst;
  43        unsigned int i, row, col;
  44        uint32_t colour_set[16];
  45        uint32_t *next_space = &colour_set[0];
  46        uint32_t *palette_iter;
  47        uint32_t this_colour;
  48        bool found = false;
  49        int colour_count = 0;
  50        s64 gpu_addr;
  51        u64 dst_gpu;
  52        u8 reg_index;
  53        u8 this_row[48];
  54
  55        if (!pixels_1 || !pixels_2) {
  56                WREG8(MGA_CURPOSXL, 0);
  57                WREG8(MGA_CURPOSXH, 0);
  58                return -ENOTSUPP; /* Didn't allocate space for cursors */
  59        }
  60
  61        if (WARN_ON(pixels_current &&
  62                    pixels_1 != pixels_current &&
  63                    pixels_2 != pixels_current)) {
  64                return -ENOTSUPP; /* inconsistent state */
  65        }
  66
  67        if (!handle || !file_priv) {
  68                mga_hide_cursor(mdev);
  69                return 0;
  70        }
  71
  72        if (width != 64 || height != 64) {
  73                WREG8(MGA_CURPOSXL, 0);
  74                WREG8(MGA_CURPOSXH, 0);
  75                return -EINVAL;
  76        }
  77
  78        if (pixels_current == pixels_1)
  79                pixels_next = pixels_2;
  80        else
  81                pixels_next = pixels_1;
  82
  83        obj = drm_gem_object_lookup(file_priv, handle);
  84        if (!obj)
  85                return -ENOENT;
  86        gbo = drm_gem_vram_of_gem(obj);
  87        ret = drm_gem_vram_pin(gbo, 0);
  88        if (ret) {
  89                dev_err(&dev->pdev->dev, "failed to lock user bo\n");
  90                goto err_drm_gem_object_put_unlocked;
  91        }
  92        src = drm_gem_vram_kmap(gbo, true, NULL);
  93        if (IS_ERR(src)) {
  94                ret = PTR_ERR(src);
  95                dev_err(&dev->pdev->dev,
  96                        "failed to kmap user buffer updates\n");
  97                goto err_drm_gem_vram_unpin_src;
  98        }
  99
 100        /* Pin and map up-coming buffer to write colour indices */
 101        ret = drm_gem_vram_pin(pixels_next, 0);
 102        if (ret)
 103                dev_err(&dev->pdev->dev,
 104                        "failed to pin cursor buffer: %d\n", ret);
 105                goto err_drm_gem_vram_kunmap_src;
 106        dst = drm_gem_vram_kmap(pixels_next, true, NULL);
 107        if (IS_ERR(dst)) {
 108                ret = PTR_ERR(dst);
 109                dev_err(&dev->pdev->dev,
 110                        "failed to kmap cursor updates: %d\n", ret);
 111                goto err_drm_gem_vram_unpin_dst;
 112        }
 113        gpu_addr = drm_gem_vram_offset(pixels_2);
 114        if (gpu_addr < 0) {
 115                ret = (int)gpu_addr;
 116                dev_err(&dev->pdev->dev,
 117                        "failed to get cursor scanout address: %d\n", ret);
 118                goto err_drm_gem_vram_kunmap_dst;
 119        }
 120        dst_gpu = (u64)gpu_addr;
 121
 122        memset(&colour_set[0], 0, sizeof(uint32_t)*16);
 123        /* width*height*4 = 16384 */
 124        for (i = 0; i < 16384; i += 4) {
 125                this_colour = ioread32(src + i);
 126                /* No transparency */
 127                if (this_colour>>24 != 0xff &&
 128                        this_colour>>24 != 0x0) {
 129                        if (warn_transparent) {
 130                                dev_info(&dev->pdev->dev, "Video card doesn't support cursors with partial transparency.\n");
 131                                dev_info(&dev->pdev->dev, "Not enabling hardware cursor.\n");
 132                                warn_transparent = false; /* Only tell the user once. */
 133                        }
 134                        ret = -EINVAL;
 135                        goto err_drm_gem_vram_kunmap_dst;
 136                }
 137                /* Don't need to store transparent pixels as colours */
 138                if (this_colour>>24 == 0x0)
 139                        continue;
 140                found = false;
 141                for (palette_iter = &colour_set[0]; palette_iter != next_space; palette_iter++) {
 142                        if (*palette_iter == this_colour) {
 143                                found = true;
 144                                break;
 145                        }
 146                }
 147                if (found)
 148                        continue;
 149                /* We only support 4bit paletted cursors */
 150                if (colour_count >= 16) {
 151                        if (warn_palette) {
 152                                dev_info(&dev->pdev->dev, "Video card only supports cursors with up to 16 colours.\n");
 153                                dev_info(&dev->pdev->dev, "Not enabling hardware cursor.\n");
 154                                warn_palette = false; /* Only tell the user once. */
 155                        }
 156                        ret = -EINVAL;
 157                        goto err_drm_gem_vram_kunmap_dst;
 158                }
 159                *next_space = this_colour;
 160                next_space++;
 161                colour_count++;
 162        }
 163
 164        /* Program colours from cursor icon into palette */
 165        for (i = 0; i < colour_count; i++) {
 166                if (i <= 2)
 167                        reg_index = 0x8 + i*0x4;
 168                else
 169                        reg_index = 0x60 + i*0x3;
 170                WREG_DAC(reg_index, colour_set[i] & 0xff);
 171                WREG_DAC(reg_index+1, colour_set[i]>>8 & 0xff);
 172                WREG_DAC(reg_index+2, colour_set[i]>>16 & 0xff);
 173                BUG_ON((colour_set[i]>>24 & 0xff) != 0xff);
 174        }
 175
 176        /* now write colour indices into hardware cursor buffer */
 177        for (row = 0; row < 64; row++) {
 178                memset(&this_row[0], 0, 48);
 179                for (col = 0; col < 64; col++) {
 180                        this_colour = ioread32(src + 4*(col + 64*row));
 181                        /* write transparent pixels */
 182                        if (this_colour>>24 == 0x0) {
 183                                this_row[47 - col/8] |= 0x80>>(col%8);
 184                                continue;
 185                        }
 186
 187                        /* write colour index here */
 188                        for (i = 0; i < colour_count; i++) {
 189                                if (colour_set[i] == this_colour) {
 190                                        if (col % 2)
 191                                                this_row[col/2] |= i<<4;
 192                                        else
 193                                                this_row[col/2] |= i;
 194                                        break;
 195                                }
 196                        }
 197                }
 198                memcpy_toio(dst + row*48, &this_row[0], 48);
 199        }
 200
 201        /* Program gpu address of cursor buffer */
 202        WREG_DAC(MGA1064_CURSOR_BASE_ADR_LOW, (u8)((dst_gpu>>10) & 0xff));
 203        WREG_DAC(MGA1064_CURSOR_BASE_ADR_HI, (u8)((dst_gpu>>18) & 0x3f));
 204
 205        /* Adjust cursor control register to turn on the cursor */
 206        WREG_DAC(MGA1064_CURSOR_CTL, 4); /* 16-colour palletized cursor mode */
 207
 208        /* Now update internal buffer pointers */
 209        if (pixels_current)
 210                drm_gem_vram_unpin(pixels_current);
 211        mdev->cursor.pixels_current = pixels_next;
 212
 213        drm_gem_vram_kunmap(pixels_next);
 214        drm_gem_vram_unpin(pixels_next);
 215        drm_gem_vram_kunmap(gbo);
 216        drm_gem_vram_unpin(gbo);
 217        drm_gem_object_put_unlocked(obj);
 218
 219        return 0;
 220
 221err_drm_gem_vram_kunmap_dst:
 222        drm_gem_vram_kunmap(pixels_next);
 223err_drm_gem_vram_unpin_dst:
 224        drm_gem_vram_unpin(pixels_next);
 225err_drm_gem_vram_kunmap_src:
 226        drm_gem_vram_kunmap(gbo);
 227err_drm_gem_vram_unpin_src:
 228        drm_gem_vram_unpin(gbo);
 229err_drm_gem_object_put_unlocked:
 230        drm_gem_object_put_unlocked(obj);
 231        return ret;
 232}
 233
 234int mga_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
 235{
 236        struct mga_device *mdev = (struct mga_device *)crtc->dev->dev_private;
 237        /* Our origin is at (64,64) */
 238        x += 64;
 239        y += 64;
 240
 241        BUG_ON(x <= 0);
 242        BUG_ON(y <= 0);
 243        BUG_ON(x & ~0xffff);
 244        BUG_ON(y & ~0xffff);
 245
 246        WREG8(MGA_CURPOSXL, x & 0xff);
 247        WREG8(MGA_CURPOSXH, (x>>8) & 0xff);
 248
 249        WREG8(MGA_CURPOSYL, y & 0xff);
 250        WREG8(MGA_CURPOSYH, (y>>8) & 0xff);
 251        return 0;
 252}
 253