Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.8-rc6 319 lines 7.8 kB view raw
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 <linux/pci.h> 9 10#include "mgag200_drv.h" 11 12static bool warn_transparent = true; 13static bool warn_palette = true; 14 15static int mgag200_cursor_update(struct mga_device *mdev, void *dst, void *src, 16 unsigned int width, unsigned int height) 17{ 18 struct drm_device *dev = mdev->dev; 19 unsigned int i, row, col; 20 uint32_t colour_set[16]; 21 uint32_t *next_space = &colour_set[0]; 22 uint32_t *palette_iter; 23 uint32_t this_colour; 24 bool found = false; 25 int colour_count = 0; 26 u8 reg_index; 27 u8 this_row[48]; 28 29 memset(&colour_set[0], 0, sizeof(uint32_t)*16); 30 /* width*height*4 = 16384 */ 31 for (i = 0; i < 16384; i += 4) { 32 this_colour = ioread32(src + i); 33 /* No transparency */ 34 if (this_colour>>24 != 0xff && 35 this_colour>>24 != 0x0) { 36 if (warn_transparent) { 37 dev_info(&dev->pdev->dev, "Video card doesn't support cursors with partial transparency.\n"); 38 dev_info(&dev->pdev->dev, "Not enabling hardware cursor.\n"); 39 warn_transparent = false; /* Only tell the user once. */ 40 } 41 return -EINVAL; 42 } 43 /* Don't need to store transparent pixels as colours */ 44 if (this_colour>>24 == 0x0) 45 continue; 46 found = false; 47 for (palette_iter = &colour_set[0]; palette_iter != next_space; palette_iter++) { 48 if (*palette_iter == this_colour) { 49 found = true; 50 break; 51 } 52 } 53 if (found) 54 continue; 55 /* We only support 4bit paletted cursors */ 56 if (colour_count >= 16) { 57 if (warn_palette) { 58 dev_info(&dev->pdev->dev, "Video card only supports cursors with up to 16 colours.\n"); 59 dev_info(&dev->pdev->dev, "Not enabling hardware cursor.\n"); 60 warn_palette = false; /* Only tell the user once. */ 61 } 62 return -EINVAL; 63 } 64 *next_space = this_colour; 65 next_space++; 66 colour_count++; 67 } 68 69 /* Program colours from cursor icon into palette */ 70 for (i = 0; i < colour_count; i++) { 71 if (i <= 2) 72 reg_index = 0x8 + i*0x4; 73 else 74 reg_index = 0x60 + i*0x3; 75 WREG_DAC(reg_index, colour_set[i] & 0xff); 76 WREG_DAC(reg_index+1, colour_set[i]>>8 & 0xff); 77 WREG_DAC(reg_index+2, colour_set[i]>>16 & 0xff); 78 BUG_ON((colour_set[i]>>24 & 0xff) != 0xff); 79 } 80 81 /* now write colour indices into hardware cursor buffer */ 82 for (row = 0; row < 64; row++) { 83 memset(&this_row[0], 0, 48); 84 for (col = 0; col < 64; col++) { 85 this_colour = ioread32(src + 4*(col + 64*row)); 86 /* write transparent pixels */ 87 if (this_colour>>24 == 0x0) { 88 this_row[47 - col/8] |= 0x80>>(col%8); 89 continue; 90 } 91 92 /* write colour index here */ 93 for (i = 0; i < colour_count; i++) { 94 if (colour_set[i] == this_colour) { 95 if (col % 2) 96 this_row[col/2] |= i<<4; 97 else 98 this_row[col/2] |= i; 99 break; 100 } 101 } 102 } 103 memcpy_toio(dst + row*48, &this_row[0], 48); 104 } 105 106 return 0; 107} 108 109static void mgag200_cursor_set_base(struct mga_device *mdev, u64 address) 110{ 111 u8 addrl = (address >> 10) & 0xff; 112 u8 addrh = (address >> 18) & 0x3f; 113 114 /* Program gpu address of cursor buffer */ 115 WREG_DAC(MGA1064_CURSOR_BASE_ADR_LOW, addrl); 116 WREG_DAC(MGA1064_CURSOR_BASE_ADR_HI, addrh); 117} 118 119static int mgag200_show_cursor(struct mga_device *mdev, void *src, 120 unsigned int width, unsigned int height) 121{ 122 struct drm_device *dev = mdev->dev; 123 struct drm_gem_vram_object *gbo; 124 void *dst; 125 s64 off; 126 int ret; 127 128 gbo = mdev->cursor.gbo[mdev->cursor.next_index]; 129 if (!gbo) { 130 WREG8(MGA_CURPOSXL, 0); 131 WREG8(MGA_CURPOSXH, 0); 132 return -ENOTSUPP; /* Didn't allocate space for cursors */ 133 } 134 dst = drm_gem_vram_vmap(gbo); 135 if (IS_ERR(dst)) { 136 ret = PTR_ERR(dst); 137 dev_err(&dev->pdev->dev, 138 "failed to map cursor updates: %d\n", ret); 139 return ret; 140 } 141 off = drm_gem_vram_offset(gbo); 142 if (off < 0) { 143 ret = (int)off; 144 dev_err(&dev->pdev->dev, 145 "failed to get cursor scanout address: %d\n", ret); 146 goto err_drm_gem_vram_vunmap; 147 } 148 149 ret = mgag200_cursor_update(mdev, dst, src, width, height); 150 if (ret) 151 goto err_drm_gem_vram_vunmap; 152 mgag200_cursor_set_base(mdev, off); 153 154 /* Adjust cursor control register to turn on the cursor */ 155 WREG_DAC(MGA1064_CURSOR_CTL, 4); /* 16-colour palletized cursor mode */ 156 157 drm_gem_vram_vunmap(gbo, dst); 158 159 ++mdev->cursor.next_index; 160 mdev->cursor.next_index %= ARRAY_SIZE(mdev->cursor.gbo); 161 162 return 0; 163 164err_drm_gem_vram_vunmap: 165 drm_gem_vram_vunmap(gbo, dst); 166 return ret; 167} 168 169/* 170 * Hide the cursor off screen. We can't disable the cursor hardware because 171 * it takes too long to re-activate and causes momentary corruption. 172 */ 173static void mgag200_hide_cursor(struct mga_device *mdev) 174{ 175 WREG8(MGA_CURPOSXL, 0); 176 WREG8(MGA_CURPOSXH, 0); 177} 178 179static void mgag200_move_cursor(struct mga_device *mdev, int x, int y) 180{ 181 if (WARN_ON(x <= 0)) 182 return; 183 if (WARN_ON(y <= 0)) 184 return; 185 if (WARN_ON(x & ~0xffff)) 186 return; 187 if (WARN_ON(y & ~0xffff)) 188 return; 189 190 WREG8(MGA_CURPOSXL, x & 0xff); 191 WREG8(MGA_CURPOSXH, (x>>8) & 0xff); 192 193 WREG8(MGA_CURPOSYL, y & 0xff); 194 WREG8(MGA_CURPOSYH, (y>>8) & 0xff); 195} 196 197int mgag200_cursor_init(struct mga_device *mdev) 198{ 199 struct drm_device *dev = mdev->dev; 200 size_t ncursors = ARRAY_SIZE(mdev->cursor.gbo); 201 size_t size; 202 int ret; 203 size_t i; 204 struct drm_gem_vram_object *gbo; 205 206 size = roundup(64 * 48, PAGE_SIZE); 207 if (size * ncursors > mdev->vram_fb_available) 208 return -ENOMEM; 209 210 for (i = 0; i < ncursors; ++i) { 211 gbo = drm_gem_vram_create(dev, size, 0); 212 if (IS_ERR(gbo)) { 213 ret = PTR_ERR(gbo); 214 goto err_drm_gem_vram_put; 215 } 216 ret = drm_gem_vram_pin(gbo, DRM_GEM_VRAM_PL_FLAG_VRAM | 217 DRM_GEM_VRAM_PL_FLAG_TOPDOWN); 218 if (ret) { 219 drm_gem_vram_put(gbo); 220 goto err_drm_gem_vram_put; 221 } 222 223 mdev->cursor.gbo[i] = gbo; 224 } 225 226 /* 227 * At the high end of video memory, we reserve space for 228 * buffer objects. The cursor plane uses this memory to store 229 * a double-buffered image of the current cursor. Hence, it's 230 * not available for framebuffers. 231 */ 232 mdev->vram_fb_available -= ncursors * size; 233 234 return 0; 235 236err_drm_gem_vram_put: 237 while (i) { 238 --i; 239 gbo = mdev->cursor.gbo[i]; 240 drm_gem_vram_unpin(gbo); 241 drm_gem_vram_put(gbo); 242 mdev->cursor.gbo[i] = NULL; 243 } 244 return ret; 245} 246 247void mgag200_cursor_fini(struct mga_device *mdev) 248{ 249 size_t i; 250 struct drm_gem_vram_object *gbo; 251 252 for (i = 0; i < ARRAY_SIZE(mdev->cursor.gbo); ++i) { 253 gbo = mdev->cursor.gbo[i]; 254 drm_gem_vram_unpin(gbo); 255 drm_gem_vram_put(gbo); 256 } 257} 258 259int mgag200_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, 260 uint32_t handle, uint32_t width, uint32_t height) 261{ 262 struct drm_device *dev = crtc->dev; 263 struct mga_device *mdev = to_mga_device(dev); 264 struct drm_gem_object *obj; 265 struct drm_gem_vram_object *gbo = NULL; 266 int ret; 267 u8 *src; 268 269 if (!handle || !file_priv) { 270 mgag200_hide_cursor(mdev); 271 return 0; 272 } 273 274 if (width != 64 || height != 64) { 275 WREG8(MGA_CURPOSXL, 0); 276 WREG8(MGA_CURPOSXH, 0); 277 return -EINVAL; 278 } 279 280 obj = drm_gem_object_lookup(file_priv, handle); 281 if (!obj) 282 return -ENOENT; 283 gbo = drm_gem_vram_of_gem(obj); 284 src = drm_gem_vram_vmap(gbo); 285 if (IS_ERR(src)) { 286 ret = PTR_ERR(src); 287 dev_err(&dev->pdev->dev, 288 "failed to map user buffer updates\n"); 289 goto err_drm_gem_object_put_unlocked; 290 } 291 292 ret = mgag200_show_cursor(mdev, src, width, height); 293 if (ret) 294 goto err_drm_gem_vram_vunmap; 295 296 /* Now update internal buffer pointers */ 297 drm_gem_vram_vunmap(gbo, src); 298 drm_gem_object_put_unlocked(obj); 299 300 return 0; 301err_drm_gem_vram_vunmap: 302 drm_gem_vram_vunmap(gbo, src); 303err_drm_gem_object_put_unlocked: 304 drm_gem_object_put_unlocked(obj); 305 return ret; 306} 307 308int mgag200_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) 309{ 310 struct mga_device *mdev = to_mga_device(crtc->dev); 311 312 /* Our origin is at (64,64) */ 313 x += 64; 314 y += 64; 315 316 mgag200_move_cursor(mdev, x, y); 317 318 return 0; 319}