1 // SPDX-License-Identifier: GPL-2.0-only
4 * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400
6 * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
8 * Version: 1.65 2002/08/14
10 * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org>
12 * Contributors: "menion?" <menion@mindless.com>
13 * Betatesting, fixes, ideas
15 * "Kurt Garloff" <garloff@suse.de>
16 * Betatesting, fixes, ideas, videomodes, videomodes timmings
18 * "Tom Rini" <trini@kernel.crashing.org>
19 * MTRR stuff, PPC cleanups, betatesting, fixes, ideas
21 * "Bibek Sahu" <scorpio@dodds.net>
22 * Access device through readb|w|l and write b|w|l
23 * Extensive debugging stuff
25 * "Daniel Haun" <haund@usa.net>
26 * Testing, hardware cursor fixes
28 * "Scott Wood" <sawst46+@pitt.edu>
31 * "Gerd Knorr" <kraxel@goldbach.isdn.cs.tu-berlin.de>
34 * "Kelly French" <targon@hazmat.com>
35 * "Fernando Herrera" <fherrera@eurielec.etsit.upm.es>
36 * Betatesting, bug reporting
38 * "Pablo Bianucci" <pbian@pccp.com.ar>
39 * Fixes, ideas, betatesting
41 * "Inaky Perez Gonzalez" <inaky@peloncho.fis.ucm.es>
42 * Fixes, enhandcements, ideas, betatesting
44 * "Ryuichi Oikawa" <roikawa@rr.iiij4u.or.jp>
45 * PPC betatesting, PPC support, backward compatibility
47 * "Paul Womar" <Paul@pwomar.demon.co.uk>
48 * "Owen Waller" <O.Waller@ee.qub.ac.uk>
51 * "Thomas Pornin" <pornin@bolet.ens.fr>
54 * "Pieter van Leuven" <pvl@iae.nl>
55 * "Ulf Jaenicke-Roessler" <ujr@physik.phy.tu-dresden.de>
58 * "H. Peter Arvin" <hpa@transmeta.com>
61 * "Cort Dougan" <cort@cs.nmt.edu>
62 * CHRP fixes and PReP cleanup
64 * "Mark Vojkovich" <mvojkovi@ucsd.edu>
67 * (following author is not in any relation with this code, but his code
68 * is included in this driver)
70 * Based on framebuffer driver for VBE 2.0 compliant graphic boards
71 * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
73 * (following author is not in any relation with this code, but his ideas
74 * were used when writing this driver)
76 * FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk>
80 #include "matroxfb_accel.h"
81 #include "matroxfb_DAC1064.h"
82 #include "matroxfb_Ti3026.h"
83 #include "matroxfb_misc.h"
85 #define curr_ydstorg(x) ((x)->curr.ydstorg.pixels)
87 #define mga_ydstlen(y,l) mga_outl(M_YDSTLEN | M_EXEC, ((y) << 16) | (l))
89 static inline void matrox_cfb4_pal(u_int32_t
* pal
) {
92 for (i
= 0; i
< 16; i
++) {
93 pal
[i
] = i
* 0x11111111U
;
97 static inline void matrox_cfb8_pal(u_int32_t
* pal
) {
100 for (i
= 0; i
< 16; i
++) {
101 pal
[i
] = i
* 0x01010101U
;
105 static void matroxfb_copyarea(struct fb_info
* info
, const struct fb_copyarea
* area
);
106 static void matroxfb_fillrect(struct fb_info
* info
, const struct fb_fillrect
* rect
);
107 static void matroxfb_imageblit(struct fb_info
* info
, const struct fb_image
* image
);
108 static void matroxfb_cfb4_fillrect(struct fb_info
* info
, const struct fb_fillrect
* rect
);
109 static void matroxfb_cfb4_copyarea(struct fb_info
* info
, const struct fb_copyarea
* area
);
111 void matrox_cfbX_init(struct matrox_fb_info
*minfo
)
120 mpitch
= minfo
->fbcon
.var
.xres_virtual
;
122 minfo
->fbops
.fb_copyarea
= cfb_copyarea
;
123 minfo
->fbops
.fb_fillrect
= cfb_fillrect
;
124 minfo
->fbops
.fb_imageblit
= cfb_imageblit
;
125 minfo
->fbops
.fb_cursor
= NULL
;
127 accel
= (minfo
->fbcon
.var
.accel_flags
& FB_ACCELF_TEXT
) == FB_ACCELF_TEXT
;
129 switch (minfo
->fbcon
.var
.bits_per_pixel
) {
130 case 4: maccess
= 0x00000000; /* accelerate as 8bpp video */
131 mpitch
= (mpitch
>> 1) | 0x8000; /* disable linearization */
132 mopmode
= M_OPMODE_4BPP
;
133 matrox_cfb4_pal(minfo
->cmap
);
134 if (accel
&& !(mpitch
& 1)) {
135 minfo
->fbops
.fb_copyarea
= matroxfb_cfb4_copyarea
;
136 minfo
->fbops
.fb_fillrect
= matroxfb_cfb4_fillrect
;
139 case 8: maccess
= 0x00000000;
140 mopmode
= M_OPMODE_8BPP
;
141 matrox_cfb8_pal(minfo
->cmap
);
143 minfo
->fbops
.fb_copyarea
= matroxfb_copyarea
;
144 minfo
->fbops
.fb_fillrect
= matroxfb_fillrect
;
145 minfo
->fbops
.fb_imageblit
= matroxfb_imageblit
;
148 case 16: if (minfo
->fbcon
.var
.green
.length
== 5)
149 maccess
= 0xC0000001;
151 maccess
= 0x40000001;
152 mopmode
= M_OPMODE_16BPP
;
154 minfo
->fbops
.fb_copyarea
= matroxfb_copyarea
;
155 minfo
->fbops
.fb_fillrect
= matroxfb_fillrect
;
156 minfo
->fbops
.fb_imageblit
= matroxfb_imageblit
;
159 case 24: maccess
= 0x00000003;
160 mopmode
= M_OPMODE_24BPP
;
162 minfo
->fbops
.fb_copyarea
= matroxfb_copyarea
;
163 minfo
->fbops
.fb_fillrect
= matroxfb_fillrect
;
164 minfo
->fbops
.fb_imageblit
= matroxfb_imageblit
;
167 case 32: maccess
= 0x00000002;
168 mopmode
= M_OPMODE_32BPP
;
170 minfo
->fbops
.fb_copyarea
= matroxfb_copyarea
;
171 minfo
->fbops
.fb_fillrect
= matroxfb_fillrect
;
172 minfo
->fbops
.fb_imageblit
= matroxfb_imageblit
;
175 default: maccess
= 0x00000000;
176 mopmode
= 0x00000000;
177 break; /* turn off acceleration!!! */
180 mga_outl(M_PITCH
, mpitch
);
181 mga_outl(M_YDSTORG
, curr_ydstorg(minfo
));
182 if (minfo
->capable
.plnwt
)
183 mga_outl(M_PLNWT
, -1);
184 if (minfo
->capable
.srcorg
) {
185 mga_outl(M_SRCORG
, 0);
186 mga_outl(M_DSTORG
, 0);
188 mga_outl(M_OPMODE
, mopmode
);
189 mga_outl(M_CXBNDRY
, 0xFFFF0000);
191 mga_outl(M_YBOT
, 0x01FFFFFF);
192 mga_outl(M_MACCESS
, maccess
);
193 minfo
->accel
.m_dwg_rect
= M_DWG_TRAP
| M_DWG_SOLID
| M_DWG_ARZERO
| M_DWG_SGNZERO
| M_DWG_SHIFTZERO
;
194 if (isMilleniumII(minfo
)) minfo
->accel
.m_dwg_rect
|= M_DWG_TRANSC
;
195 minfo
->accel
.m_opmode
= mopmode
;
196 minfo
->accel
.m_access
= maccess
;
197 minfo
->accel
.m_pitch
= mpitch
;
200 EXPORT_SYMBOL(matrox_cfbX_init
);
202 static void matrox_accel_restore_maccess(struct matrox_fb_info
*minfo
)
204 mga_outl(M_MACCESS
, minfo
->accel
.m_access
);
205 mga_outl(M_PITCH
, minfo
->accel
.m_pitch
);
208 static void matrox_accel_bmove(struct matrox_fb_info
*minfo
, int vxres
, int sy
,
209 int sx
, int dy
, int dx
, int height
, int width
)
218 if ((dy
< sy
) || ((dy
== sy
) && (dx
<= sx
))) {
220 matrox_accel_restore_maccess(minfo
);
221 mga_outl(M_DWGCTL
, M_DWG_BITBLT
| M_DWG_SHIFTZERO
| M_DWG_SGNZERO
|
222 M_DWG_BFCOL
| M_DWG_REPLACE
);
223 mga_outl(M_AR5
, vxres
);
225 start
= sy
*vxres
+sx
+curr_ydstorg(minfo
);
229 matrox_accel_restore_maccess(minfo
);
230 mga_outl(M_DWGCTL
, M_DWG_BITBLT
| M_DWG_SHIFTZERO
| M_DWG_BFCOL
| M_DWG_REPLACE
);
232 mga_outl(M_AR5
, -vxres
);
234 end
= (sy
+height
-1)*vxres
+sx
+curr_ydstorg(minfo
);
239 matrox_accel_restore_maccess(minfo
);
240 mga_outl(M_AR0
, end
);
241 mga_outl(M_AR3
, start
);
242 mga_outl(M_FXBNDRY
, ((dx
+width
)<<16) | dx
);
243 mga_ydstlen(dy
, height
);
249 static void matrox_accel_bmove_lin(struct matrox_fb_info
*minfo
, int vxres
,
250 int sy
, int sx
, int dy
, int dx
, int height
,
260 if ((dy
< sy
) || ((dy
== sy
) && (dx
<= sx
))) {
262 matrox_accel_restore_maccess(minfo
);
263 mga_outl(M_DWGCTL
, M_DWG_BITBLT
| M_DWG_SHIFTZERO
| M_DWG_SGNZERO
|
264 M_DWG_BFCOL
| M_DWG_REPLACE
);
265 mga_outl(M_AR5
, vxres
);
267 start
= sy
*vxres
+sx
+curr_ydstorg(minfo
);
271 matrox_accel_restore_maccess(minfo
);
272 mga_outl(M_DWGCTL
, M_DWG_BITBLT
| M_DWG_SHIFTZERO
| M_DWG_BFCOL
| M_DWG_REPLACE
);
274 mga_outl(M_AR5
, -vxres
);
276 end
= (sy
+height
-1)*vxres
+sx
+curr_ydstorg(minfo
);
281 matrox_accel_restore_maccess(minfo
);
282 mga_outl(M_AR0
, end
);
283 mga_outl(M_AR3
, start
);
284 mga_outl(M_FXBNDRY
, ((dx
+width
)<<16) | dx
);
285 mga_outl(M_YDST
, dy
*vxres
>> 5);
286 mga_outl(M_LEN
| M_EXEC
, height
);
292 static void matroxfb_cfb4_copyarea(struct fb_info
* info
, const struct fb_copyarea
* area
) {
293 struct matrox_fb_info
*minfo
= info2minfo(info
);
295 if ((area
->sx
| area
->dx
| area
->width
) & 1)
296 cfb_copyarea(info
, area
);
298 matrox_accel_bmove_lin(minfo
, minfo
->fbcon
.var
.xres_virtual
>> 1, area
->sy
, area
->sx
>> 1, area
->dy
, area
->dx
>> 1, area
->height
, area
->width
>> 1);
301 static void matroxfb_copyarea(struct fb_info
* info
, const struct fb_copyarea
* area
) {
302 struct matrox_fb_info
*minfo
= info2minfo(info
);
304 matrox_accel_bmove(minfo
, minfo
->fbcon
.var
.xres_virtual
, area
->sy
, area
->sx
, area
->dy
, area
->dx
, area
->height
, area
->width
);
307 static void matroxfb_accel_clear(struct matrox_fb_info
*minfo
, u_int32_t color
,
308 int sy
, int sx
, int height
, int width
)
317 matrox_accel_restore_maccess(minfo
);
318 mga_outl(M_DWGCTL
, minfo
->accel
.m_dwg_rect
| M_DWG_REPLACE
);
319 mga_outl(M_FCOL
, color
);
320 mga_outl(M_FXBNDRY
, ((sx
+ width
) << 16) | sx
);
321 mga_ydstlen(sy
, height
);
327 static void matroxfb_fillrect(struct fb_info
* info
, const struct fb_fillrect
* rect
) {
328 struct matrox_fb_info
*minfo
= info2minfo(info
);
332 matroxfb_accel_clear(minfo
, ((u_int32_t
*)info
->pseudo_palette
)[rect
->color
], rect
->dy
, rect
->dx
, rect
->height
, rect
->width
);
337 static void matroxfb_cfb4_clear(struct matrox_fb_info
*minfo
, u_int32_t bgx
,
338 int sy
, int sx
, int height
, int width
)
361 matrox_accel_restore_maccess(minfo
);
362 mga_outl(M_DWGCTL
, minfo
->accel
.m_dwg_rect
| M_DWG_REPLACE2
);
363 mga_outl(M_FCOL
, bgx
);
364 mga_outl(M_FXBNDRY
, ((sx
+ width
) << 16) | sx
);
365 mga_outl(M_YDST
, sy
* minfo
->fbcon
.var
.xres_virtual
>> 6);
366 mga_outl(M_LEN
| M_EXEC
, height
);
370 u_int32_t step
= minfo
->fbcon
.var
.xres_virtual
>> 1;
371 vaddr_t vbase
= minfo
->video
.vbase
;
373 unsigned int uaddr
= sy
* step
+ sx
- 1;
375 u_int8_t bgx2
= bgx
& 0xF0;
376 for (loop
= height
; loop
> 0; loop
--) {
377 mga_writeb(vbase
, uaddr
, (mga_readb(vbase
, uaddr
) & 0x0F) | bgx2
);
382 unsigned int uaddr
= sy
* step
+ sx
+ width
;
384 u_int8_t bgx2
= bgx
& 0x0F;
385 for (loop
= height
; loop
> 0; loop
--) {
386 mga_writeb(vbase
, uaddr
, (mga_readb(vbase
, uaddr
) & 0xF0) | bgx2
);
395 static void matroxfb_cfb4_fillrect(struct fb_info
* info
, const struct fb_fillrect
* rect
) {
396 struct matrox_fb_info
*minfo
= info2minfo(info
);
400 matroxfb_cfb4_clear(minfo
, ((u_int32_t
*)info
->pseudo_palette
)[rect
->color
], rect
->dy
, rect
->dx
, rect
->height
, rect
->width
);
405 static void matroxfb_1bpp_imageblit(struct matrox_fb_info
*minfo
, u_int32_t fgx
,
406 u_int32_t bgx
, const u_int8_t
*chardata
,
407 int width
, int height
, int yy
, int xx
)
421 step
= (width
+ 7) >> 3;
422 charcell
= height
* step
;
423 xlen
= (charcell
+ 3) & ~3;
424 ydstlen
= (yy
<< 16) | height
;
425 if (width
== step
<< 3) {
426 ar0
= height
* width
- 1;
436 matrox_accel_restore_maccess(minfo
);
438 mga_outl(M_DWGCTL
, M_DWG_ILOAD
| M_DWG_SGNZERO
| M_DWG_SHIFTZERO
| M_DWG_BMONOWF
| M_DWG_LINEAR
| M_DWG_REPLACE
);
440 mga_outl(M_DWGCTL
, M_DWG_ILOAD
| M_DWG_SGNZERO
| M_DWG_SHIFTZERO
| M_DWG_BMONOWF
| M_DWG_REPLACE
);
441 mga_outl(M_FCOL
, fgx
);
442 mga_outl(M_BCOL
, bgx
);
443 fxbndry
= ((xx
+ width
- 1) << 16) | xx
;
444 mmio
= minfo
->mmio
.vbase
;
447 matrox_accel_restore_maccess(minfo
);
448 mga_writel(mmio
, M_FXBNDRY
, fxbndry
);
449 mga_writel(mmio
, M_AR0
, ar0
);
450 mga_writel(mmio
, M_AR3
, 0);
452 mga_writel(mmio
, M_YDSTLEN
| M_EXEC
, ydstlen
);
453 mga_memcpy_toio(mmio
, chardata
, xlen
);
455 mga_writel(mmio
, M_AR5
, 0);
456 mga_writel(mmio
, M_YDSTLEN
| M_EXEC
, ydstlen
);
457 if ((step
& 3) == 0) {
458 /* Great. Source has 32bit aligned lines, so we can feed them
459 directly to the accelerator. */
460 mga_memcpy_toio(mmio
, chardata
, charcell
);
461 } else if (step
== 1) {
462 /* Special case for 1..8bit widths */
464 #if defined(__BIG_ENDIAN)
465 fb_writel((*chardata
) << 24, mmio
.vaddr
);
467 fb_writel(*chardata
, mmio
.vaddr
);
471 } else if (step
== 2) {
472 /* Special case for 9..15bit widths */
474 #if defined(__BIG_ENDIAN)
475 fb_writel((*(u_int16_t
*)chardata
) << 16, mmio
.vaddr
);
477 fb_writel(*(u_int16_t
*)chardata
, mmio
.vaddr
);
482 /* Tell... well, why bother... */
486 for (i
= 0; i
< step
; i
+= 4) {
487 /* Hope that there are at least three readable bytes beyond the end of bitmap */
488 fb_writel(get_unaligned((u_int32_t
*)(chardata
+ i
)),mmio
.vaddr
);
499 static void matroxfb_imageblit(struct fb_info
* info
, const struct fb_image
* image
) {
500 struct matrox_fb_info
*minfo
= info2minfo(info
);
504 if (image
->depth
== 1) {
507 fgx
= ((u_int32_t
*)info
->pseudo_palette
)[image
->fg_color
];
508 bgx
= ((u_int32_t
*)info
->pseudo_palette
)[image
->bg_color
];
509 matroxfb_1bpp_imageblit(minfo
, fgx
, bgx
, image
->data
, image
->width
, image
->height
, image
->dy
, image
->dx
);
511 /* Danger! image->depth is useless: logo painting code always
512 passes framebuffer color depth here, although logo data are
513 always 8bpp and info->pseudo_palette is changed to contain
514 logo palette to be used (but only for true/direct-color... sic...).
515 So do it completely in software... */
516 cfb_imageblit(info
, image
);
520 MODULE_DESCRIPTION("Accelerated fbops for Matrox Millennium/Mystique/G100/G200/G400/G450/G550");
521 MODULE_LICENSE("GPL");