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
;
197 EXPORT_SYMBOL(matrox_cfbX_init
);
199 static void matrox_accel_bmove(struct matrox_fb_info
*minfo
, int vxres
, int sy
,
200 int sx
, int dy
, int dx
, int height
, int width
)
209 if ((dy
< sy
) || ((dy
== sy
) && (dx
<= sx
))) {
211 mga_outl(M_DWGCTL
, M_DWG_BITBLT
| M_DWG_SHIFTZERO
| M_DWG_SGNZERO
|
212 M_DWG_BFCOL
| M_DWG_REPLACE
);
213 mga_outl(M_AR5
, vxres
);
215 start
= sy
*vxres
+sx
+curr_ydstorg(minfo
);
219 mga_outl(M_DWGCTL
, M_DWG_BITBLT
| M_DWG_SHIFTZERO
| M_DWG_BFCOL
| M_DWG_REPLACE
);
221 mga_outl(M_AR5
, -vxres
);
223 end
= (sy
+height
-1)*vxres
+sx
+curr_ydstorg(minfo
);
228 mga_outl(M_AR0
, end
);
229 mga_outl(M_AR3
, start
);
230 mga_outl(M_FXBNDRY
, ((dx
+width
)<<16) | dx
);
231 mga_ydstlen(dy
, height
);
237 static void matrox_accel_bmove_lin(struct matrox_fb_info
*minfo
, int vxres
,
238 int sy
, int sx
, int dy
, int dx
, int height
,
248 if ((dy
< sy
) || ((dy
== sy
) && (dx
<= sx
))) {
250 mga_outl(M_DWGCTL
, M_DWG_BITBLT
| M_DWG_SHIFTZERO
| M_DWG_SGNZERO
|
251 M_DWG_BFCOL
| M_DWG_REPLACE
);
252 mga_outl(M_AR5
, vxres
);
254 start
= sy
*vxres
+sx
+curr_ydstorg(minfo
);
258 mga_outl(M_DWGCTL
, M_DWG_BITBLT
| M_DWG_SHIFTZERO
| M_DWG_BFCOL
| M_DWG_REPLACE
);
260 mga_outl(M_AR5
, -vxres
);
262 end
= (sy
+height
-1)*vxres
+sx
+curr_ydstorg(minfo
);
267 mga_outl(M_AR0
, end
);
268 mga_outl(M_AR3
, start
);
269 mga_outl(M_FXBNDRY
, ((dx
+width
)<<16) | dx
);
270 mga_outl(M_YDST
, dy
*vxres
>> 5);
271 mga_outl(M_LEN
| M_EXEC
, height
);
277 static void matroxfb_cfb4_copyarea(struct fb_info
* info
, const struct fb_copyarea
* area
) {
278 struct matrox_fb_info
*minfo
= info2minfo(info
);
280 if ((area
->sx
| area
->dx
| area
->width
) & 1)
281 cfb_copyarea(info
, area
);
283 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);
286 static void matroxfb_copyarea(struct fb_info
* info
, const struct fb_copyarea
* area
) {
287 struct matrox_fb_info
*minfo
= info2minfo(info
);
289 matrox_accel_bmove(minfo
, minfo
->fbcon
.var
.xres_virtual
, area
->sy
, area
->sx
, area
->dy
, area
->dx
, area
->height
, area
->width
);
292 static void matroxfb_accel_clear(struct matrox_fb_info
*minfo
, u_int32_t color
,
293 int sy
, int sx
, int height
, int width
)
302 mga_outl(M_DWGCTL
, minfo
->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 struct matrox_fb_info
*minfo
= info2minfo(info
);
316 matroxfb_accel_clear(minfo
, ((u_int32_t
*)info
->pseudo_palette
)[rect
->color
], rect
->dy
, rect
->dx
, rect
->height
, rect
->width
);
321 static void matroxfb_cfb4_clear(struct matrox_fb_info
*minfo
, u_int32_t bgx
,
322 int sy
, int sx
, int height
, int width
)
345 mga_outl(M_DWGCTL
, minfo
->accel
.m_dwg_rect
| M_DWG_REPLACE2
);
346 mga_outl(M_FCOL
, bgx
);
347 mga_outl(M_FXBNDRY
, ((sx
+ width
) << 16) | sx
);
348 mga_outl(M_YDST
, sy
* minfo
->fbcon
.var
.xres_virtual
>> 6);
349 mga_outl(M_LEN
| M_EXEC
, height
);
353 u_int32_t step
= minfo
->fbcon
.var
.xres_virtual
>> 1;
354 vaddr_t vbase
= minfo
->video
.vbase
;
356 unsigned int uaddr
= sy
* step
+ sx
- 1;
358 u_int8_t bgx2
= bgx
& 0xF0;
359 for (loop
= height
; loop
> 0; loop
--) {
360 mga_writeb(vbase
, uaddr
, (mga_readb(vbase
, uaddr
) & 0x0F) | bgx2
);
365 unsigned int uaddr
= sy
* step
+ sx
+ width
;
367 u_int8_t bgx2
= bgx
& 0x0F;
368 for (loop
= height
; loop
> 0; loop
--) {
369 mga_writeb(vbase
, uaddr
, (mga_readb(vbase
, uaddr
) & 0xF0) | bgx2
);
378 static void matroxfb_cfb4_fillrect(struct fb_info
* info
, const struct fb_fillrect
* rect
) {
379 struct matrox_fb_info
*minfo
= info2minfo(info
);
383 matroxfb_cfb4_clear(minfo
, ((u_int32_t
*)info
->pseudo_palette
)[rect
->color
], rect
->dy
, rect
->dx
, rect
->height
, rect
->width
);
388 static void matroxfb_1bpp_imageblit(struct matrox_fb_info
*minfo
, u_int32_t fgx
,
389 u_int32_t bgx
, const u_int8_t
*chardata
,
390 int width
, int height
, int yy
, int xx
)
404 step
= (width
+ 7) >> 3;
405 charcell
= height
* step
;
406 xlen
= (charcell
+ 3) & ~3;
407 ydstlen
= (yy
<< 16) | height
;
408 if (width
== step
<< 3) {
409 ar0
= height
* width
- 1;
420 mga_outl(M_DWGCTL
, M_DWG_ILOAD
| M_DWG_SGNZERO
| M_DWG_SHIFTZERO
| M_DWG_BMONOWF
| M_DWG_LINEAR
| M_DWG_REPLACE
);
422 mga_outl(M_DWGCTL
, M_DWG_ILOAD
| M_DWG_SGNZERO
| M_DWG_SHIFTZERO
| M_DWG_BMONOWF
| M_DWG_REPLACE
);
423 mga_outl(M_FCOL
, fgx
);
424 mga_outl(M_BCOL
, bgx
);
425 fxbndry
= ((xx
+ width
- 1) << 16) | xx
;
426 mmio
= minfo
->mmio
.vbase
;
429 mga_writel(mmio
, M_FXBNDRY
, fxbndry
);
430 mga_writel(mmio
, M_AR0
, ar0
);
431 mga_writel(mmio
, M_AR3
, 0);
433 mga_writel(mmio
, M_YDSTLEN
| M_EXEC
, ydstlen
);
434 mga_memcpy_toio(mmio
, chardata
, xlen
);
436 mga_writel(mmio
, M_AR5
, 0);
437 mga_writel(mmio
, M_YDSTLEN
| M_EXEC
, ydstlen
);
438 if ((step
& 3) == 0) {
439 /* Great. Source has 32bit aligned lines, so we can feed them
440 directly to the accelerator. */
441 mga_memcpy_toio(mmio
, chardata
, charcell
);
442 } else if (step
== 1) {
443 /* Special case for 1..8bit widths */
445 #if defined(__BIG_ENDIAN)
446 fb_writel((*chardata
) << 24, mmio
.vaddr
);
448 fb_writel(*chardata
, mmio
.vaddr
);
452 } else if (step
== 2) {
453 /* Special case for 9..15bit widths */
455 #if defined(__BIG_ENDIAN)
456 fb_writel((*(u_int16_t
*)chardata
) << 16, mmio
.vaddr
);
458 fb_writel(*(u_int16_t
*)chardata
, mmio
.vaddr
);
463 /* Tell... well, why bother... */
467 for (i
= 0; i
< step
; i
+= 4) {
468 /* Hope that there are at least three readable bytes beyond the end of bitmap */
469 fb_writel(get_unaligned((u_int32_t
*)(chardata
+ i
)),mmio
.vaddr
);
480 static void matroxfb_imageblit(struct fb_info
* info
, const struct fb_image
* image
) {
481 struct matrox_fb_info
*minfo
= info2minfo(info
);
485 if (image
->depth
== 1) {
488 fgx
= ((u_int32_t
*)info
->pseudo_palette
)[image
->fg_color
];
489 bgx
= ((u_int32_t
*)info
->pseudo_palette
)[image
->bg_color
];
490 matroxfb_1bpp_imageblit(minfo
, fgx
, bgx
, image
->data
, image
->width
, image
->height
, image
->dy
, image
->dx
);
492 /* Danger! image->depth is useless: logo painting code always
493 passes framebuffer color depth here, although logo data are
494 always 8bpp and info->pseudo_palette is changed to contain
495 logo palette to be used (but only for true/direct-color... sic...).
496 So do it completely in software... */
497 cfb_imageblit(info
, image
);
501 MODULE_LICENSE("GPL");