1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright 2013 Matrox Graphics
5 * Author: Christopher Harvey <charvey@matrox.com>
8 #include <drm/drm_pci.h>
10 #include "mgag200_drv.h"
12 static bool warn_transparent = true;
13 static bool warn_palette = true;
16 * Hide the cursor off screen. We can't disable the cursor hardware because
17 * it takes too long to re-activate and causes momentary corruption.
19 static void mgag200_hide_cursor(struct mga_device *mdev)
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;
28 static void mgag200_move_cursor(struct mga_device *mdev, int x, int y)
34 if (WARN_ON(x & ~0xffff))
36 if (WARN_ON(y & ~0xffff))
39 WREG8(MGA_CURPOSXL, x & 0xff);
40 WREG8(MGA_CURPOSXH, (x>>8) & 0xff);
42 WREG8(MGA_CURPOSYL, y & 0xff);
43 WREG8(MGA_CURPOSYH, (y>>8) & 0xff);
46 int mgag200_cursor_init(struct mga_device *mdev)
48 struct drm_device *dev = mdev->dev;
51 * Make small buffers to store a hardware cursor (double
52 * buffered icon updates)
54 mdev->cursor.pixels_1 = drm_gem_vram_create(dev, &dev->vram_mm->bdev,
55 roundup(48*64, PAGE_SIZE),
57 mdev->cursor.pixels_2 = drm_gem_vram_create(dev, &dev->vram_mm->bdev,
58 roundup(48*64, PAGE_SIZE),
60 if (IS_ERR(mdev->cursor.pixels_2) || IS_ERR(mdev->cursor.pixels_1)) {
61 mdev->cursor.pixels_1 = NULL;
62 mdev->cursor.pixels_2 = NULL;
63 dev_warn(&dev->pdev->dev,
64 "Could not allocate space for cursors. Not doing hardware cursors.\n");
66 mdev->cursor.pixels_current = NULL;
71 void mgag200_cursor_fini(struct mga_device *mdev)
74 int mgag200_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
75 uint32_t handle, uint32_t width, uint32_t height)
77 struct drm_device *dev = crtc->dev;
78 struct mga_device *mdev = (struct mga_device *)dev->dev_private;
79 struct drm_gem_vram_object *pixels_1 = mdev->cursor.pixels_1;
80 struct drm_gem_vram_object *pixels_2 = mdev->cursor.pixels_2;
81 struct drm_gem_vram_object *pixels_current = mdev->cursor.pixels_current;
82 struct drm_gem_vram_object *pixels_next;
83 struct drm_gem_object *obj;
84 struct drm_gem_vram_object *gbo = NULL;
87 unsigned int i, row, col;
88 uint32_t colour_set[16];
89 uint32_t *next_space = &colour_set[0];
90 uint32_t *palette_iter;
99 if (!pixels_1 || !pixels_2) {
100 WREG8(MGA_CURPOSXL, 0);
101 WREG8(MGA_CURPOSXH, 0);
102 return -ENOTSUPP; /* Didn't allocate space for cursors */
105 if (WARN_ON(pixels_current &&
106 pixels_1 != pixels_current &&
107 pixels_2 != pixels_current)) {
108 return -ENOTSUPP; /* inconsistent state */
111 if (!handle || !file_priv) {
112 mgag200_hide_cursor(mdev);
116 if (width != 64 || height != 64) {
117 WREG8(MGA_CURPOSXL, 0);
118 WREG8(MGA_CURPOSXH, 0);
122 if (pixels_current == pixels_1)
123 pixels_next = pixels_2;
125 pixels_next = pixels_1;
127 obj = drm_gem_object_lookup(file_priv, handle);
130 gbo = drm_gem_vram_of_gem(obj);
131 src = drm_gem_vram_vmap(gbo);
134 dev_err(&dev->pdev->dev,
135 "failed to map user buffer updates\n");
136 goto err_drm_gem_object_put_unlocked;
139 /* Pin and map up-coming buffer to write colour indices */
140 ret = drm_gem_vram_pin(pixels_next, DRM_GEM_VRAM_PL_FLAG_VRAM);
142 dev_err(&dev->pdev->dev,
143 "failed to pin cursor buffer: %d\n", ret);
144 goto err_drm_gem_vram_vunmap;
146 dst = drm_gem_vram_kmap(pixels_next, true, NULL);
149 dev_err(&dev->pdev->dev,
150 "failed to kmap cursor updates: %d\n", ret);
151 goto err_drm_gem_vram_unpin_dst;
153 gpu_addr = drm_gem_vram_offset(pixels_next);
156 dev_err(&dev->pdev->dev,
157 "failed to get cursor scanout address: %d\n", ret);
158 goto err_drm_gem_vram_kunmap_dst;
160 dst_gpu = (u64)gpu_addr;
162 memset(&colour_set[0], 0, sizeof(uint32_t)*16);
163 /* width*height*4 = 16384 */
164 for (i = 0; i < 16384; i += 4) {
165 this_colour = ioread32(src + i);
166 /* No transparency */
167 if (this_colour>>24 != 0xff &&
168 this_colour>>24 != 0x0) {
169 if (warn_transparent) {
170 dev_info(&dev->pdev->dev, "Video card doesn't support cursors with partial transparency.\n");
171 dev_info(&dev->pdev->dev, "Not enabling hardware cursor.\n");
172 warn_transparent = false; /* Only tell the user once. */
175 goto err_drm_gem_vram_kunmap_dst;
177 /* Don't need to store transparent pixels as colours */
178 if (this_colour>>24 == 0x0)
181 for (palette_iter = &colour_set[0]; palette_iter != next_space; palette_iter++) {
182 if (*palette_iter == this_colour) {
189 /* We only support 4bit paletted cursors */
190 if (colour_count >= 16) {
192 dev_info(&dev->pdev->dev, "Video card only supports cursors with up to 16 colours.\n");
193 dev_info(&dev->pdev->dev, "Not enabling hardware cursor.\n");
194 warn_palette = false; /* Only tell the user once. */
197 goto err_drm_gem_vram_kunmap_dst;
199 *next_space = this_colour;
204 /* Program colours from cursor icon into palette */
205 for (i = 0; i < colour_count; i++) {
207 reg_index = 0x8 + i*0x4;
209 reg_index = 0x60 + i*0x3;
210 WREG_DAC(reg_index, colour_set[i] & 0xff);
211 WREG_DAC(reg_index+1, colour_set[i]>>8 & 0xff);
212 WREG_DAC(reg_index+2, colour_set[i]>>16 & 0xff);
213 BUG_ON((colour_set[i]>>24 & 0xff) != 0xff);
216 /* now write colour indices into hardware cursor buffer */
217 for (row = 0; row < 64; row++) {
218 memset(&this_row[0], 0, 48);
219 for (col = 0; col < 64; col++) {
220 this_colour = ioread32(src + 4*(col + 64*row));
221 /* write transparent pixels */
222 if (this_colour>>24 == 0x0) {
223 this_row[47 - col/8] |= 0x80>>(col%8);
227 /* write colour index here */
228 for (i = 0; i < colour_count; i++) {
229 if (colour_set[i] == this_colour) {
231 this_row[col/2] |= i<<4;
233 this_row[col/2] |= i;
238 memcpy_toio(dst + row*48, &this_row[0], 48);
241 /* Program gpu address of cursor buffer */
242 WREG_DAC(MGA1064_CURSOR_BASE_ADR_LOW, (u8)((dst_gpu>>10) & 0xff));
243 WREG_DAC(MGA1064_CURSOR_BASE_ADR_HI, (u8)((dst_gpu>>18) & 0x3f));
245 /* Adjust cursor control register to turn on the cursor */
246 WREG_DAC(MGA1064_CURSOR_CTL, 4); /* 16-colour palletized cursor mode */
248 /* Now update internal buffer pointers */
250 drm_gem_vram_unpin(pixels_current);
251 mdev->cursor.pixels_current = pixels_next;
253 drm_gem_vram_kunmap(pixels_next);
254 drm_gem_vram_vunmap(gbo, src);
255 drm_gem_object_put_unlocked(obj);
259 err_drm_gem_vram_kunmap_dst:
260 drm_gem_vram_kunmap(pixels_next);
261 err_drm_gem_vram_unpin_dst:
262 drm_gem_vram_unpin(pixels_next);
263 err_drm_gem_vram_vunmap:
264 drm_gem_vram_vunmap(gbo, src);
265 err_drm_gem_object_put_unlocked:
266 drm_gem_object_put_unlocked(obj);
270 int mgag200_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
272 struct mga_device *mdev = (struct mga_device *)crtc->dev->dev_private;
274 /* Our origin is at (64,64) */
278 mgag200_move_cursor(mdev, x, y);