1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright 2013 Matrox Graphics
5 * Author: Christopher Harvey <charvey@matrox.com>
10 #include "mgag200_drv.h"
12 static bool warn_transparent
= true;
13 static bool warn_palette
= true;
15 static int mgag200_cursor_update(struct mga_device
*mdev
, void *dst
, void *src
,
16 unsigned int width
, unsigned int height
)
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
;
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
);
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. */
43 /* Don't need to store transparent pixels as colours */
44 if (this_colour
>>24 == 0x0)
47 for (palette_iter
= &colour_set
[0]; palette_iter
!= next_space
; palette_iter
++) {
48 if (*palette_iter
== this_colour
) {
55 /* We only support 4bit paletted cursors */
56 if (colour_count
>= 16) {
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. */
64 *next_space
= this_colour
;
69 /* Program colours from cursor icon into palette */
70 for (i
= 0; i
< colour_count
; i
++) {
72 reg_index
= 0x8 + i
*0x4;
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);
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);
92 /* write colour index here */
93 for (i
= 0; i
< colour_count
; i
++) {
94 if (colour_set
[i
] == this_colour
) {
96 this_row
[col
/2] |= i
<<4;
103 memcpy_toio(dst
+ row
*48, &this_row
[0], 48);
109 static void mgag200_cursor_set_base(struct mga_device
*mdev
, u64 address
)
111 u8 addrl
= (address
>> 10) & 0xff;
112 u8 addrh
= (address
>> 18) & 0x3f;
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
);
119 static int mgag200_show_cursor(struct mga_device
*mdev
, void *src
,
120 unsigned int width
, unsigned int height
)
122 struct drm_device
*dev
= mdev
->dev
;
123 struct drm_gem_vram_object
*gbo
;
128 gbo
= mdev
->cursor
.gbo
[mdev
->cursor
.next_index
];
130 WREG8(MGA_CURPOSXL
, 0);
131 WREG8(MGA_CURPOSXH
, 0);
132 return -ENOTSUPP
; /* Didn't allocate space for cursors */
134 dst
= drm_gem_vram_vmap(gbo
);
137 dev_err(&dev
->pdev
->dev
,
138 "failed to map cursor updates: %d\n", ret
);
141 off
= drm_gem_vram_offset(gbo
);
144 dev_err(&dev
->pdev
->dev
,
145 "failed to get cursor scanout address: %d\n", ret
);
146 goto err_drm_gem_vram_vunmap
;
149 ret
= mgag200_cursor_update(mdev
, dst
, src
, width
, height
);
151 goto err_drm_gem_vram_vunmap
;
152 mgag200_cursor_set_base(mdev
, off
);
154 /* Adjust cursor control register to turn on the cursor */
155 WREG_DAC(MGA1064_CURSOR_CTL
, 4); /* 16-colour palletized cursor mode */
157 drm_gem_vram_vunmap(gbo
, dst
);
159 ++mdev
->cursor
.next_index
;
160 mdev
->cursor
.next_index
%= ARRAY_SIZE(mdev
->cursor
.gbo
);
164 err_drm_gem_vram_vunmap
:
165 drm_gem_vram_vunmap(gbo
, dst
);
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.
173 static void mgag200_hide_cursor(struct mga_device
*mdev
)
175 WREG8(MGA_CURPOSXL
, 0);
176 WREG8(MGA_CURPOSXH
, 0);
179 static void mgag200_move_cursor(struct mga_device
*mdev
, int x
, int y
)
185 if (WARN_ON(x
& ~0xffff))
187 if (WARN_ON(y
& ~0xffff))
190 WREG8(MGA_CURPOSXL
, x
& 0xff);
191 WREG8(MGA_CURPOSXH
, (x
>>8) & 0xff);
193 WREG8(MGA_CURPOSYL
, y
& 0xff);
194 WREG8(MGA_CURPOSYH
, (y
>>8) & 0xff);
197 int mgag200_cursor_init(struct mga_device
*mdev
)
199 struct drm_device
*dev
= mdev
->dev
;
200 size_t ncursors
= ARRAY_SIZE(mdev
->cursor
.gbo
);
204 struct drm_gem_vram_object
*gbo
;
206 size
= roundup(64 * 48, PAGE_SIZE
);
207 if (size
* ncursors
> mdev
->vram_fb_available
)
210 for (i
= 0; i
< ncursors
; ++i
) {
211 gbo
= drm_gem_vram_create(dev
, size
, 0);
214 goto err_drm_gem_vram_put
;
216 ret
= drm_gem_vram_pin(gbo
, DRM_GEM_VRAM_PL_FLAG_VRAM
|
217 DRM_GEM_VRAM_PL_FLAG_TOPDOWN
);
219 drm_gem_vram_put(gbo
);
220 goto err_drm_gem_vram_put
;
223 mdev
->cursor
.gbo
[i
] = gbo
;
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.
232 mdev
->vram_fb_available
-= ncursors
* size
;
236 err_drm_gem_vram_put
:
239 gbo
= mdev
->cursor
.gbo
[i
];
240 drm_gem_vram_unpin(gbo
);
241 drm_gem_vram_put(gbo
);
242 mdev
->cursor
.gbo
[i
] = NULL
;
247 void mgag200_cursor_fini(struct mga_device
*mdev
)
250 struct drm_gem_vram_object
*gbo
;
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
);
259 int mgag200_crtc_cursor_set(struct drm_crtc
*crtc
, struct drm_file
*file_priv
,
260 uint32_t handle
, uint32_t width
, uint32_t height
)
262 struct drm_device
*dev
= crtc
->dev
;
263 struct mga_device
*mdev
= (struct mga_device
*)dev
->dev_private
;
264 struct drm_gem_object
*obj
;
265 struct drm_gem_vram_object
*gbo
= NULL
;
269 if (!handle
|| !file_priv
) {
270 mgag200_hide_cursor(mdev
);
274 if (width
!= 64 || height
!= 64) {
275 WREG8(MGA_CURPOSXL
, 0);
276 WREG8(MGA_CURPOSXH
, 0);
280 obj
= drm_gem_object_lookup(file_priv
, handle
);
283 gbo
= drm_gem_vram_of_gem(obj
);
284 src
= drm_gem_vram_vmap(gbo
);
287 dev_err(&dev
->pdev
->dev
,
288 "failed to map user buffer updates\n");
289 goto err_drm_gem_object_put_unlocked
;
292 ret
= mgag200_show_cursor(mdev
, src
, width
, height
);
294 goto err_drm_gem_vram_vunmap
;
296 /* Now update internal buffer pointers */
297 drm_gem_vram_vunmap(gbo
, src
);
298 drm_gem_object_put_unlocked(obj
);
301 err_drm_gem_vram_vunmap
:
302 drm_gem_vram_vunmap(gbo
, src
);
303 err_drm_gem_object_put_unlocked
:
304 drm_gem_object_put_unlocked(obj
);
308 int mgag200_crtc_cursor_move(struct drm_crtc
*crtc
, int x
, int y
)
310 struct mga_device
*mdev
= (struct mga_device
*)crtc
->dev
->dev_private
;
312 /* Our origin is at (64,64) */
316 mgag200_move_cursor(mdev
, x
, y
);