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 writting 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) ACCESS_FBINFO2(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
;
97 static inline void matrox_cfb8_pal(u_int32_t
* pal
) {
100 for (i
= 0; i
< 16; i
++) {
101 pal
[i
] = i
* 0x01010101U
;
106 static void matroxfb_copyarea(struct fb_info
* info
, const struct fb_copyarea
* area
);
107 static void matroxfb_fillrect(struct fb_info
* info
, const struct fb_fillrect
* rect
);
108 static void matroxfb_imageblit(struct fb_info
* info
, const struct fb_image
* image
);
109 static void matroxfb_cfb4_fillrect(struct fb_info
* info
, const struct fb_fillrect
* rect
);
110 static void matroxfb_cfb4_copyarea(struct fb_info
* info
, const struct fb_copyarea
* area
);
112 void matrox_cfbX_init(WPMINFO2
) {
120 mpitch
= ACCESS_FBINFO(fbcon
).var
.xres_virtual
;
122 ACCESS_FBINFO(fbops
).fb_copyarea
= cfb_copyarea
;
123 ACCESS_FBINFO(fbops
).fb_fillrect
= cfb_fillrect
;
124 ACCESS_FBINFO(fbops
).fb_imageblit
= cfb_imageblit
;
125 ACCESS_FBINFO(fbops
).fb_cursor
= soft_cursor
;
127 accel
= (ACCESS_FBINFO(fbcon
).var
.accel_flags
& FB_ACCELF_TEXT
) == FB_ACCELF_TEXT
;
129 switch (ACCESS_FBINFO(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(ACCESS_FBINFO(cmap
));
134 if (accel
&& !(mpitch
& 1)) {
135 ACCESS_FBINFO(fbops
).fb_copyarea
= matroxfb_cfb4_copyarea
;
136 ACCESS_FBINFO(fbops
).fb_fillrect
= matroxfb_cfb4_fillrect
;
139 case 8: maccess
= 0x00000000;
140 mopmode
= M_OPMODE_8BPP
;
141 matrox_cfb8_pal(ACCESS_FBINFO(cmap
));
143 ACCESS_FBINFO(fbops
).fb_copyarea
= matroxfb_copyarea
;
144 ACCESS_FBINFO(fbops
).fb_fillrect
= matroxfb_fillrect
;
145 ACCESS_FBINFO(fbops
).fb_imageblit
= matroxfb_imageblit
;
148 case 16: if (ACCESS_FBINFO(fbcon
).var
.green
.length
== 5) {
149 maccess
= 0xC0000001;
150 ACCESS_FBINFO(cmap
[16]) = 0x7FFF7FFF;
152 maccess
= 0x40000001;
153 ACCESS_FBINFO(cmap
[16]) = 0xFFFFFFFF;
155 mopmode
= M_OPMODE_16BPP
;
157 ACCESS_FBINFO(fbops
).fb_copyarea
= matroxfb_copyarea
;
158 ACCESS_FBINFO(fbops
).fb_fillrect
= matroxfb_fillrect
;
159 ACCESS_FBINFO(fbops
).fb_imageblit
= matroxfb_imageblit
;
162 case 24: maccess
= 0x00000003;
163 mopmode
= M_OPMODE_24BPP
;
164 ACCESS_FBINFO(cmap
[16]) = 0xFFFFFFFF;
166 ACCESS_FBINFO(fbops
).fb_copyarea
= matroxfb_copyarea
;
167 ACCESS_FBINFO(fbops
).fb_fillrect
= matroxfb_fillrect
;
168 ACCESS_FBINFO(fbops
).fb_imageblit
= matroxfb_imageblit
;
171 case 32: maccess
= 0x00000002;
172 mopmode
= M_OPMODE_32BPP
;
173 ACCESS_FBINFO(cmap
[16]) = 0xFFFFFFFF;
175 ACCESS_FBINFO(fbops
).fb_copyarea
= matroxfb_copyarea
;
176 ACCESS_FBINFO(fbops
).fb_fillrect
= matroxfb_fillrect
;
177 ACCESS_FBINFO(fbops
).fb_imageblit
= matroxfb_imageblit
;
180 default: maccess
= 0x00000000;
181 mopmode
= 0x00000000;
182 break; /* turn off acceleration!!! */
185 mga_outl(M_PITCH
, mpitch
);
186 mga_outl(M_YDSTORG
, curr_ydstorg(MINFO
));
187 if (ACCESS_FBINFO(capable
.plnwt
))
188 mga_outl(M_PLNWT
, -1);
189 if (ACCESS_FBINFO(capable
.srcorg
)) {
190 mga_outl(M_SRCORG
, 0);
191 mga_outl(M_DSTORG
, 0);
193 mga_outl(M_OPMODE
, mopmode
);
194 mga_outl(M_CXBNDRY
, 0xFFFF0000);
196 mga_outl(M_YBOT
, 0x01FFFFFF);
197 mga_outl(M_MACCESS
, maccess
);
198 ACCESS_FBINFO(accel
.m_dwg_rect
) = M_DWG_TRAP
| M_DWG_SOLID
| M_DWG_ARZERO
| M_DWG_SGNZERO
| M_DWG_SHIFTZERO
;
199 if (isMilleniumII(MINFO
)) ACCESS_FBINFO(accel
.m_dwg_rect
) |= M_DWG_TRANSC
;
200 ACCESS_FBINFO(accel
.m_opmode
) = mopmode
;
203 EXPORT_SYMBOL(matrox_cfbX_init
);
205 static void matrox_accel_bmove(WPMINFO
int vxres
, int sy
, int sx
, int dy
, int dx
, int height
, int width
) {
213 if ((dy
< sy
) || ((dy
== sy
) && (dx
<= sx
))) {
215 mga_outl(M_DWGCTL
, M_DWG_BITBLT
| M_DWG_SHIFTZERO
| M_DWG_SGNZERO
|
216 M_DWG_BFCOL
| M_DWG_REPLACE
);
217 mga_outl(M_AR5
, vxres
);
219 start
= sy
*vxres
+sx
+curr_ydstorg(MINFO
);
223 mga_outl(M_DWGCTL
, M_DWG_BITBLT
| M_DWG_SHIFTZERO
| M_DWG_BFCOL
| M_DWG_REPLACE
);
225 mga_outl(M_AR5
, -vxres
);
227 end
= (sy
+height
-1)*vxres
+sx
+curr_ydstorg(MINFO
);
232 mga_outl(M_AR0
, end
);
233 mga_outl(M_AR3
, start
);
234 mga_outl(M_FXBNDRY
, ((dx
+width
)<<16) | dx
);
235 mga_ydstlen(dy
, height
);
241 static void matrox_accel_bmove_lin(WPMINFO
int vxres
, int sy
, int sx
, int dy
, int dx
, int height
, int width
) {
249 if ((dy
< sy
) || ((dy
== sy
) && (dx
<= sx
))) {
251 mga_outl(M_DWGCTL
, M_DWG_BITBLT
| M_DWG_SHIFTZERO
| M_DWG_SGNZERO
|
252 M_DWG_BFCOL
| M_DWG_REPLACE
);
253 mga_outl(M_AR5
, vxres
);
255 start
= sy
*vxres
+sx
+curr_ydstorg(MINFO
);
259 mga_outl(M_DWGCTL
, M_DWG_BITBLT
| M_DWG_SHIFTZERO
| M_DWG_BFCOL
| M_DWG_REPLACE
);
261 mga_outl(M_AR5
, -vxres
);
263 end
= (sy
+height
-1)*vxres
+sx
+curr_ydstorg(MINFO
);
268 mga_outl(M_AR0
, end
);
269 mga_outl(M_AR3
, start
);
270 mga_outl(M_FXBNDRY
, ((dx
+width
)<<16) | dx
);
271 mga_outl(M_YDST
, dy
*vxres
>> 5);
272 mga_outl(M_LEN
| M_EXEC
, height
);
278 static void matroxfb_cfb4_copyarea(struct fb_info
* info
, const struct fb_copyarea
* area
) {
279 MINFO_FROM_INFO(info
);
281 if ((area
->sx
| area
->dx
| area
->width
) & 1)
282 cfb_copyarea(info
, area
);
284 matrox_accel_bmove_lin(PMINFO
ACCESS_FBINFO(fbcon
.var
.xres_virtual
) >> 1, area
->sy
, area
->sx
>> 1, area
->dy
, area
->dx
>> 1, area
->height
, area
->width
>> 1);
287 static void matroxfb_copyarea(struct fb_info
* info
, const struct fb_copyarea
* area
) {
288 MINFO_FROM_INFO(info
);
290 matrox_accel_bmove(PMINFO
ACCESS_FBINFO(fbcon
.var
.xres_virtual
), area
->sy
, area
->sx
, area
->dy
, area
->dx
, area
->height
, area
->width
);
293 static void matroxfb_accel_clear(WPMINFO u_int32_t color
, int sy
, int sx
, int height
,
302 mga_outl(M_DWGCTL
, ACCESS_FBINFO(accel
.m_dwg_rect
) | M_DWG_REPLACE
);
303 mga_outl(M_FCOL
, color
);
304 mga_outl(M_FXBNDRY
, ((sx
+ width
) << 16) | sx
);
305 mga_ydstlen(sy
, height
);
311 static void matroxfb_fillrect(struct fb_info
* info
, const struct fb_fillrect
* rect
) {
312 MINFO_FROM_INFO(info
);
316 matroxfb_accel_clear(PMINFO ((u_int32_t
*)info
->pseudo_palette
)[rect
->color
], rect
->dy
, rect
->dx
, rect
->height
, rect
->width
);
321 static void matroxfb_cfb4_clear(WPMINFO u_int32_t bgx
, int sy
, int sx
, int height
, int width
) {
343 mga_outl(M_DWGCTL
, ACCESS_FBINFO(accel
.m_dwg_rect
) | M_DWG_REPLACE2
);
344 mga_outl(M_FCOL
, bgx
);
345 mga_outl(M_FXBNDRY
, ((sx
+ width
) << 16) | sx
);
346 mga_outl(M_YDST
, sy
* ACCESS_FBINFO(fbcon
).var
.xres_virtual
>> 6);
347 mga_outl(M_LEN
| M_EXEC
, height
);
351 u_int32_t step
= ACCESS_FBINFO(fbcon
).var
.xres_virtual
>> 1;
352 vaddr_t vbase
= ACCESS_FBINFO(video
.vbase
);
354 unsigned int uaddr
= sy
* step
+ sx
- 1;
356 u_int8_t bgx2
= bgx
& 0xF0;
357 for (loop
= height
; loop
> 0; loop
--) {
358 mga_writeb(vbase
, uaddr
, (mga_readb(vbase
, uaddr
) & 0x0F) | bgx2
);
363 unsigned int uaddr
= sy
* step
+ sx
+ width
;
365 u_int8_t bgx2
= bgx
& 0x0F;
366 for (loop
= height
; loop
> 0; loop
--) {
367 mga_writeb(vbase
, uaddr
, (mga_readb(vbase
, uaddr
) & 0xF0) | bgx2
);
376 static void matroxfb_cfb4_fillrect(struct fb_info
* info
, const struct fb_fillrect
* rect
) {
377 MINFO_FROM_INFO(info
);
381 matroxfb_cfb4_clear(PMINFO ((u_int32_t
*)info
->pseudo_palette
)[rect
->color
], rect
->dy
, rect
->dx
, rect
->height
, rect
->width
);
386 static void matroxfb_1bpp_imageblit(WPMINFO u_int32_t fgx
, u_int32_t bgx
,
387 const u_int8_t
* chardata
, int width
, int height
, int yy
, int xx
) {
398 DBG_HEAVY(__FUNCTION__
);
400 step
= (width
+ 7) >> 3;
401 charcell
= height
* step
;
402 xlen
= (charcell
+ 3) & ~3;
403 ydstlen
= (yy
<< 16) | height
;
404 if (width
== step
<< 3) {
405 ar0
= height
* width
- 1;
416 mga_outl(M_DWGCTL
, M_DWG_ILOAD
| M_DWG_SGNZERO
| M_DWG_SHIFTZERO
| M_DWG_BMONOWF
| M_DWG_LINEAR
| M_DWG_REPLACE
);
418 mga_outl(M_DWGCTL
, M_DWG_ILOAD
| M_DWG_SGNZERO
| M_DWG_SHIFTZERO
| M_DWG_BMONOWF
| M_DWG_REPLACE
);
419 mga_outl(M_FCOL
, fgx
);
420 mga_outl(M_BCOL
, bgx
);
421 fxbndry
= ((xx
+ width
- 1) << 16) | xx
;
422 mmio
= ACCESS_FBINFO(mmio
.vbase
);
425 mga_writel(mmio
, M_FXBNDRY
, fxbndry
);
426 mga_writel(mmio
, M_AR0
, ar0
);
427 mga_writel(mmio
, M_AR3
, 0);
429 mga_writel(mmio
, M_YDSTLEN
| M_EXEC
, ydstlen
);
430 mga_memcpy_toio(mmio
, chardata
, xlen
);
432 mga_writel(mmio
, M_AR5
, 0);
433 mga_writel(mmio
, M_YDSTLEN
| M_EXEC
, ydstlen
);
434 if ((step
& 3) == 0) {
435 /* Great. Source has 32bit aligned lines, so we can feed them
436 directly to the accelerator. */
437 mga_memcpy_toio(mmio
, chardata
, charcell
);
438 } else if (step
== 1) {
439 /* Special case for 1..8bit widths */
441 #if defined(__BIG_ENDIAN)
442 fb_writel((*chardata
) << 24, mmio
.vaddr
);
444 fb_writel(*chardata
, mmio
.vaddr
);
448 } else if (step
== 2) {
449 /* Special case for 9..15bit widths */
451 #if defined(__BIG_ENDIAN)
452 fb_writel((*(u_int16_t
*)chardata
) << 16, mmio
.vaddr
);
454 fb_writel(*(u_int16_t
*)chardata
, mmio
.vaddr
);
459 /* Tell... well, why bother... */
463 for (i
= 0; i
< step
; i
+= 4) {
464 /* Hope that there are at least three readable bytes beyond the end of bitmap */
465 fb_writel(get_unaligned((u_int32_t
*)(chardata
+ i
)),mmio
.vaddr
);
476 static void matroxfb_imageblit(struct fb_info
* info
, const struct fb_image
* image
) {
477 MINFO_FROM_INFO(info
);
479 DBG_HEAVY(__FUNCTION__
);
481 if (image
->depth
== 1) {
484 fgx
= ((u_int32_t
*)info
->pseudo_palette
)[image
->fg_color
];
485 bgx
= ((u_int32_t
*)info
->pseudo_palette
)[image
->bg_color
];
486 matroxfb_1bpp_imageblit(PMINFO fgx
, bgx
, image
->data
, image
->width
, image
->height
, image
->dy
, image
->dx
);
488 /* Danger! image->depth is useless: logo painting code always
489 passes framebuffer color depth here, although logo data are
490 always 8bpp and info->pseudo_palette is changed to contain
491 logo palette to be used (but only for true/direct-color... sic...).
492 So do it completely in software... */
493 cfb_imageblit(info
, image
);
497 MODULE_LICENSE("GPL");