root/drivers/gpu/drm/mgag200/mgag200_cursor.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mga_hide_cursor
  2. mga_crtc_cursor_set
  3. mga_crtc_cursor_move

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

/* [<][>][^][v][top][bottom][index][help] */