3 * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400
5 * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
7 * Version: 1.65 2002/08/14
9 * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org>
11 * Contributors: "menion?" <menion@mindless.com>
12 * Betatesting, fixes, ideas
14 * "Kurt Garloff" <garloff@suse.de>
15 * Betatesting, fixes, ideas, videomodes, videomodes timmings
17 * "Tom Rini" <trini@kernel.crashing.org>
18 * MTRR stuff, PPC cleanups, betatesting, fixes, ideas
20 * "Bibek Sahu" <scorpio@dodds.net>
21 * Access device through readb|w|l and write b|w|l
22 * Extensive debugging stuff
24 * "Daniel Haun" <haund@usa.net>
25 * Testing, hardware cursor fixes
27 * "Scott Wood" <sawst46+@pitt.edu>
30 * "Gerd Knorr" <kraxel@goldbach.isdn.cs.tu-berlin.de>
33 * "Kelly French" <targon@hazmat.com>
34 * "Fernando Herrera" <fherrera@eurielec.etsit.upm.es>
35 * Betatesting, bug reporting
37 * "Pablo Bianucci" <pbian@pccp.com.ar>
38 * Fixes, ideas, betatesting
40 * "Inaky Perez Gonzalez" <inaky@peloncho.fis.ucm.es>
41 * Fixes, enhandcements, ideas, betatesting
43 * "Ryuichi Oikawa" <roikawa@rr.iiij4u.or.jp>
44 * PPC betatesting, PPC support, backward compatibility
46 * "Paul Womar" <Paul@pwomar.demon.co.uk>
47 * "Owen Waller" <O.Waller@ee.qub.ac.uk>
50 * "Thomas Pornin" <pornin@bolet.ens.fr>
53 * "Pieter van Leuven" <pvl@iae.nl>
54 * "Ulf Jaenicke-Roessler" <ujr@physik.phy.tu-dresden.de>
57 * "H. Peter Arvin" <hpa@transmeta.com>
60 * "Cort Dougan" <cort@cs.nmt.edu>
61 * CHRP fixes and PReP cleanup
63 * "Mark Vojkovich" <mvojkovi@ucsd.edu>
66 * (following author is not in any relation with this code, but his code
67 * is included in this driver)
69 * Based on framebuffer driver for VBE 2.0 compliant graphic boards
70 * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
72 * (following author is not in any relation with this code, but his ideas
73 * were used when writing this driver)
75 * FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk>
79 #include "matroxfb_accel.h"
80 #include "matroxfb_DAC1064.h"
81 #include "matroxfb_Ti3026.h"
82 #include "matroxfb_misc.h"
84 #define curr_ydstorg(x) ((x)->curr.ydstorg.pixels)
86 #define mga_ydstlen(y,l) mga_outl(M_YDSTLEN | M_EXEC, ((y) << 16) | (l))
88 static inline void matrox_cfb4_pal(u_int32_t
* pal
) {
91 for (i
= 0; i
< 16; i
++) {
92 pal
[i
] = i
* 0x11111111U
;
96 static inline void matrox_cfb8_pal(u_int32_t
* pal
) {
99 for (i
= 0; i
< 16; i
++) {
100 pal
[i
] = i
* 0x01010101U
;
104 static void matroxfb_copyarea(struct fb_info
* info
, const struct fb_copyarea
* area
);
105 static void matroxfb_fillrect(struct fb_info
* info
, const struct fb_fillrect
* rect
);
106 static void matroxfb_imageblit(struct fb_info
* info
, const struct fb_image
* image
);
107 static void matroxfb_cfb4_fillrect(struct fb_info
* info
, const struct fb_fillrect
* rect
);
108 static void matroxfb_cfb4_copyarea(struct fb_info
* info
, const struct fb_copyarea
* area
);
110 void matrox_cfbX_init(struct matrox_fb_info
*minfo
)
119 mpitch
= minfo
->fbcon
.var
.xres_virtual
;
121 minfo
->fbops
.fb_copyarea
= cfb_copyarea
;
122 minfo
->fbops
.fb_fillrect
= cfb_fillrect
;
123 minfo
->fbops
.fb_imageblit
= cfb_imageblit
;
124 minfo
->fbops
.fb_cursor
= NULL
;
126 accel
= (minfo
->fbcon
.var
.accel_flags
& FB_ACCELF_TEXT
) == FB_ACCELF_TEXT
;
128 switch (minfo
->fbcon
.var
.bits_per_pixel
) {
129 case 4: maccess
= 0x00000000; /* accelerate as 8bpp video */
130 mpitch
= (mpitch
>> 1) | 0x8000; /* disable linearization */
131 mopmode
= M_OPMODE_4BPP
;
132 matrox_cfb4_pal(minfo
->cmap
);
133 if (accel
&& !(mpitch
& 1)) {
134 minfo
->fbops
.fb_copyarea
= matroxfb_cfb4_copyarea
;
135 minfo
->fbops
.fb_fillrect
= matroxfb_cfb4_fillrect
;
138 case 8: maccess
= 0x00000000;
139 mopmode
= M_OPMODE_8BPP
;
140 matrox_cfb8_pal(minfo
->cmap
);
142 minfo
->fbops
.fb_copyarea
= matroxfb_copyarea
;
143 minfo
->fbops
.fb_fillrect
= matroxfb_fillrect
;
144 minfo
->fbops
.fb_imageblit
= matroxfb_imageblit
;
147 case 16: if (minfo
->fbcon
.var
.green
.length
== 5)
148 maccess
= 0xC0000001;
150 maccess
= 0x40000001;
151 mopmode
= M_OPMODE_16BPP
;
153 minfo
->fbops
.fb_copyarea
= matroxfb_copyarea
;
154 minfo
->fbops
.fb_fillrect
= matroxfb_fillrect
;
155 minfo
->fbops
.fb_imageblit
= matroxfb_imageblit
;
158 case 24: maccess
= 0x00000003;
159 mopmode
= M_OPMODE_24BPP
;
161 minfo
->fbops
.fb_copyarea
= matroxfb_copyarea
;
162 minfo
->fbops
.fb_fillrect
= matroxfb_fillrect
;
163 minfo
->fbops
.fb_imageblit
= matroxfb_imageblit
;
166 case 32: maccess
= 0x00000002;
167 mopmode
= M_OPMODE_32BPP
;
169 minfo
->fbops
.fb_copyarea
= matroxfb_copyarea
;
170 minfo
->fbops
.fb_fillrect
= matroxfb_fillrect
;
171 minfo
->fbops
.fb_imageblit
= matroxfb_imageblit
;
174 default: maccess
= 0x00000000;
175 mopmode
= 0x00000000;
176 break; /* turn off acceleration!!! */
179 mga_outl(M_PITCH
, mpitch
);
180 mga_outl(M_YDSTORG
, curr_ydstorg(minfo
));
181 if (minfo
->capable
.plnwt
)
182 mga_outl(M_PLNWT
, -1);
183 if (minfo
->capable
.srcorg
) {
184 mga_outl(M_SRCORG
, 0);
185 mga_outl(M_DSTORG
, 0);
187 mga_outl(M_OPMODE
, mopmode
);
188 mga_outl(M_CXBNDRY
, 0xFFFF0000);
190 mga_outl(M_YBOT
, 0x01FFFFFF);
191 mga_outl(M_MACCESS
, maccess
);
192 minfo
->accel
.m_dwg_rect
= M_DWG_TRAP
| M_DWG_SOLID
| M_DWG_ARZERO
| M_DWG_SGNZERO
| M_DWG_SHIFTZERO
;
193 if (isMilleniumII(minfo
)) minfo
->accel
.m_dwg_rect
|= M_DWG_TRANSC
;
194 minfo
->accel
.m_opmode
= mopmode
;
195 minfo
->accel
.m_access
= maccess
;
196 minfo
->accel
.m_pitch
= mpitch
;
199 EXPORT_SYMBOL(matrox_cfbX_init
);
201 static void matrox_accel_restore_maccess(struct matrox_fb_info
*minfo
)
203 mga_outl(M_MACCESS
, minfo
->accel
.m_access
);
204 mga_outl(M_PITCH
, minfo
->accel
.m_pitch
);
207 static void matrox_accel_bmove(struct matrox_fb_info
*minfo
, int vxres
, int sy
,
208 int sx
, int dy
, int dx
, int height
, int width
)
217 if ((dy
< sy
) || ((dy
== sy
) && (dx
<= sx
))) {
219 matrox_accel_restore_maccess(minfo
);
220 mga_outl(M_DWGCTL
, M_DWG_BITBLT
| M_DWG_SHIFTZERO
| M_DWG_SGNZERO
|
221 M_DWG_BFCOL
| M_DWG_REPLACE
);
222 mga_outl(M_AR5
, vxres
);
224 start
= sy
*vxres
+sx
+curr_ydstorg(minfo
);
228 matrox_accel_restore_maccess(minfo
);
229 mga_outl(M_DWGCTL
, M_DWG_BITBLT
| M_DWG_SHIFTZERO
| M_DWG_BFCOL
| M_DWG_REPLACE
);
231 mga_outl(M_AR5
, -vxres
);
233 end
= (sy
+height
-1)*vxres
+sx
+curr_ydstorg(minfo
);
238 matrox_accel_restore_maccess(minfo
);
239 mga_outl(M_AR0
, end
);
240 mga_outl(M_AR3
, start
);
241 mga_outl(M_FXBNDRY
, ((dx
+width
)<<16) | dx
);
242 mga_ydstlen(dy
, height
);
248 static void matrox_accel_bmove_lin(struct matrox_fb_info
*minfo
, int vxres
,
249 int sy
, int sx
, int dy
, int dx
, int height
,
259 if ((dy
< sy
) || ((dy
== sy
) && (dx
<= sx
))) {
261 matrox_accel_restore_maccess(minfo
);
262 mga_outl(M_DWGCTL
, M_DWG_BITBLT
| M_DWG_SHIFTZERO
| M_DWG_SGNZERO
|
263 M_DWG_BFCOL
| M_DWG_REPLACE
);
264 mga_outl(M_AR5
, vxres
);
266 start
= sy
*vxres
+sx
+curr_ydstorg(minfo
);
270 matrox_accel_restore_maccess(minfo
);
271 mga_outl(M_DWGCTL
, M_DWG_BITBLT
| M_DWG_SHIFTZERO
| M_DWG_BFCOL
| M_DWG_REPLACE
);
273 mga_outl(M_AR5
, -vxres
);
275 end
= (sy
+height
-1)*vxres
+sx
+curr_ydstorg(minfo
);
280 matrox_accel_restore_maccess(minfo
);
281 mga_outl(M_AR0
, end
);
282 mga_outl(M_AR3
, start
);
283 mga_outl(M_FXBNDRY
, ((dx
+width
)<<16) | dx
);
284 mga_outl(M_YDST
, dy
*vxres
>> 5);
285 mga_outl(M_LEN
| M_EXEC
, height
);
291 static void matroxfb_cfb4_copyarea(struct fb_info
* info
, const struct fb_copyarea
* area
) {
292 struct matrox_fb_info
*minfo
= info2minfo(info
);
294 if ((area
->sx
| area
->dx
| area
->width
) & 1)
295 cfb_copyarea(info
, area
);
297 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);
300 static void matroxfb_copyarea(struct fb_info
* info
, const struct fb_copyarea
* area
) {
301 struct matrox_fb_info
*minfo
= info2minfo(info
);
303 matrox_accel_bmove(minfo
, minfo
->fbcon
.var
.xres_virtual
, area
->sy
, area
->sx
, area
->dy
, area
->dx
, area
->height
, area
->width
);
306 static void matroxfb_accel_clear(struct matrox_fb_info
*minfo
, u_int32_t color
,
307 int sy
, int sx
, int height
, int width
)
316 matrox_accel_restore_maccess(minfo
);
317 mga_outl(M_DWGCTL
, minfo
->accel
.m_dwg_rect
| M_DWG_REPLACE
);
318 mga_outl(M_FCOL
, color
);
319 mga_outl(M_FXBNDRY
, ((sx
+ width
) << 16) | sx
);
320 mga_ydstlen(sy
, height
);
326 static void matroxfb_fillrect(struct fb_info
* info
, const struct fb_fillrect
* rect
) {
327 struct matrox_fb_info
*minfo
= info2minfo(info
);
331 matroxfb_accel_clear(minfo
, ((u_int32_t
*)info
->pseudo_palette
)[rect
->color
], rect
->dy
, rect
->dx
, rect
->height
, rect
->width
);
336 static void matroxfb_cfb4_clear(struct matrox_fb_info
*minfo
, u_int32_t bgx
,
337 int sy
, int sx
, int height
, int width
)
360 matrox_accel_restore_maccess(minfo
);
361 mga_outl(M_DWGCTL
, minfo
->accel
.m_dwg_rect
| M_DWG_REPLACE2
);
362 mga_outl(M_FCOL
, bgx
);
363 mga_outl(M_FXBNDRY
, ((sx
+ width
) << 16) | sx
);
364 mga_outl(M_YDST
, sy
* minfo
->fbcon
.var
.xres_virtual
>> 6);
365 mga_outl(M_LEN
| M_EXEC
, height
);
369 u_int32_t step
= minfo
->fbcon
.var
.xres_virtual
>> 1;
370 vaddr_t vbase
= minfo
->video
.vbase
;
372 unsigned int uaddr
= sy
* step
+ sx
- 1;
374 u_int8_t bgx2
= bgx
& 0xF0;
375 for (loop
= height
; loop
> 0; loop
--) {
376 mga_writeb(vbase
, uaddr
, (mga_readb(vbase
, uaddr
) & 0x0F) | bgx2
);
381 unsigned int uaddr
= sy
* step
+ sx
+ width
;
383 u_int8_t bgx2
= bgx
& 0x0F;
384 for (loop
= height
; loop
> 0; loop
--) {
385 mga_writeb(vbase
, uaddr
, (mga_readb(vbase
, uaddr
) & 0xF0) | bgx2
);
394 static void matroxfb_cfb4_fillrect(struct fb_info
* info
, const struct fb_fillrect
* rect
) {
395 struct matrox_fb_info
*minfo
= info2minfo(info
);
399 matroxfb_cfb4_clear(minfo
, ((u_int32_t
*)info
->pseudo_palette
)[rect
->color
], rect
->dy
, rect
->dx
, rect
->height
, rect
->width
);
404 static void matroxfb_1bpp_imageblit(struct matrox_fb_info
*minfo
, u_int32_t fgx
,
405 u_int32_t bgx
, const u_int8_t
*chardata
,
406 int width
, int height
, int yy
, int xx
)
420 step
= (width
+ 7) >> 3;
421 charcell
= height
* step
;
422 xlen
= (charcell
+ 3) & ~3;
423 ydstlen
= (yy
<< 16) | height
;
424 if (width
== step
<< 3) {
425 ar0
= height
* width
- 1;
435 matrox_accel_restore_maccess(minfo
);
437 mga_outl(M_DWGCTL
, M_DWG_ILOAD
| M_DWG_SGNZERO
| M_DWG_SHIFTZERO
| M_DWG_BMONOWF
| M_DWG_LINEAR
| M_DWG_REPLACE
);
439 mga_outl(M_DWGCTL
, M_DWG_ILOAD
| M_DWG_SGNZERO
| M_DWG_SHIFTZERO
| M_DWG_BMONOWF
| M_DWG_REPLACE
);
440 mga_outl(M_FCOL
, fgx
);
441 mga_outl(M_BCOL
, bgx
);
442 fxbndry
= ((xx
+ width
- 1) << 16) | xx
;
443 mmio
= minfo
->mmio
.vbase
;
446 matrox_accel_restore_maccess(minfo
);
447 mga_writel(mmio
, M_FXBNDRY
, fxbndry
);
448 mga_writel(mmio
, M_AR0
, ar0
);
449 mga_writel(mmio
, M_AR3
, 0);
451 mga_writel(mmio
, M_YDSTLEN
| M_EXEC
, ydstlen
);
452 mga_memcpy_toio(mmio
, chardata
, xlen
);
454 mga_writel(mmio
, M_AR5
, 0);
455 mga_writel(mmio
, M_YDSTLEN
| M_EXEC
, ydstlen
);
456 if ((step
& 3) == 0) {
457 /* Great. Source has 32bit aligned lines, so we can feed them
458 directly to the accelerator. */
459 mga_memcpy_toio(mmio
, chardata
, charcell
);
460 } else if (step
== 1) {
461 /* Special case for 1..8bit widths */
463 #if defined(__BIG_ENDIAN)
464 fb_writel((*chardata
) << 24, mmio
.vaddr
);
466 fb_writel(*chardata
, mmio
.vaddr
);
470 } else if (step
== 2) {
471 /* Special case for 9..15bit widths */
473 #if defined(__BIG_ENDIAN)
474 fb_writel((*(u_int16_t
*)chardata
) << 16, mmio
.vaddr
);
476 fb_writel(*(u_int16_t
*)chardata
, mmio
.vaddr
);
481 /* Tell... well, why bother... */
485 for (i
= 0; i
< step
; i
+= 4) {
486 /* Hope that there are at least three readable bytes beyond the end of bitmap */
487 fb_writel(get_unaligned((u_int32_t
*)(chardata
+ i
)),mmio
.vaddr
);
498 static void matroxfb_imageblit(struct fb_info
* info
, const struct fb_image
* image
) {
499 struct matrox_fb_info
*minfo
= info2minfo(info
);
503 if (image
->depth
== 1) {
506 fgx
= ((u_int32_t
*)info
->pseudo_palette
)[image
->fg_color
];
507 bgx
= ((u_int32_t
*)info
->pseudo_palette
)[image
->bg_color
];
508 matroxfb_1bpp_imageblit(minfo
, fgx
, bgx
, image
->data
, image
->width
, image
->height
, image
->dy
, image
->dx
);
510 /* Danger! image->depth is useless: logo painting code always
511 passes framebuffer color depth here, although logo data are
512 always 8bpp and info->pseudo_palette is changed to contain
513 logo palette to be used (but only for true/direct-color... sic...).
514 So do it completely in software... */
515 cfb_imageblit(info
, image
);
519 MODULE_LICENSE("GPL");