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) 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
;
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(WPMINFO2
) {
118 mpitch
= ACCESS_FBINFO(fbcon
).var
.xres_virtual
;
120 ACCESS_FBINFO(fbops
).fb_copyarea
= cfb_copyarea
;
121 ACCESS_FBINFO(fbops
).fb_fillrect
= cfb_fillrect
;
122 ACCESS_FBINFO(fbops
).fb_imageblit
= cfb_imageblit
;
123 ACCESS_FBINFO(fbops
).fb_cursor
= NULL
;
125 accel
= (ACCESS_FBINFO(fbcon
).var
.accel_flags
& FB_ACCELF_TEXT
) == FB_ACCELF_TEXT
;
127 switch (ACCESS_FBINFO(fbcon
).var
.bits_per_pixel
) {
128 case 4: maccess
= 0x00000000; /* accelerate as 8bpp video */
129 mpitch
= (mpitch
>> 1) | 0x8000; /* disable linearization */
130 mopmode
= M_OPMODE_4BPP
;
131 matrox_cfb4_pal(ACCESS_FBINFO(cmap
));
132 if (accel
&& !(mpitch
& 1)) {
133 ACCESS_FBINFO(fbops
).fb_copyarea
= matroxfb_cfb4_copyarea
;
134 ACCESS_FBINFO(fbops
).fb_fillrect
= matroxfb_cfb4_fillrect
;
137 case 8: maccess
= 0x00000000;
138 mopmode
= M_OPMODE_8BPP
;
139 matrox_cfb8_pal(ACCESS_FBINFO(cmap
));
141 ACCESS_FBINFO(fbops
).fb_copyarea
= matroxfb_copyarea
;
142 ACCESS_FBINFO(fbops
).fb_fillrect
= matroxfb_fillrect
;
143 ACCESS_FBINFO(fbops
).fb_imageblit
= matroxfb_imageblit
;
146 case 16: if (ACCESS_FBINFO(fbcon
).var
.green
.length
== 5)
147 maccess
= 0xC0000001;
149 maccess
= 0x40000001;
150 mopmode
= M_OPMODE_16BPP
;
152 ACCESS_FBINFO(fbops
).fb_copyarea
= matroxfb_copyarea
;
153 ACCESS_FBINFO(fbops
).fb_fillrect
= matroxfb_fillrect
;
154 ACCESS_FBINFO(fbops
).fb_imageblit
= matroxfb_imageblit
;
157 case 24: maccess
= 0x00000003;
158 mopmode
= M_OPMODE_24BPP
;
160 ACCESS_FBINFO(fbops
).fb_copyarea
= matroxfb_copyarea
;
161 ACCESS_FBINFO(fbops
).fb_fillrect
= matroxfb_fillrect
;
162 ACCESS_FBINFO(fbops
).fb_imageblit
= matroxfb_imageblit
;
165 case 32: maccess
= 0x00000002;
166 mopmode
= M_OPMODE_32BPP
;
168 ACCESS_FBINFO(fbops
).fb_copyarea
= matroxfb_copyarea
;
169 ACCESS_FBINFO(fbops
).fb_fillrect
= matroxfb_fillrect
;
170 ACCESS_FBINFO(fbops
).fb_imageblit
= matroxfb_imageblit
;
173 default: maccess
= 0x00000000;
174 mopmode
= 0x00000000;
175 break; /* turn off acceleration!!! */
178 mga_outl(M_PITCH
, mpitch
);
179 mga_outl(M_YDSTORG
, curr_ydstorg(MINFO
));
180 if (ACCESS_FBINFO(capable
.plnwt
))
181 mga_outl(M_PLNWT
, -1);
182 if (ACCESS_FBINFO(capable
.srcorg
)) {
183 mga_outl(M_SRCORG
, 0);
184 mga_outl(M_DSTORG
, 0);
186 mga_outl(M_OPMODE
, mopmode
);
187 mga_outl(M_CXBNDRY
, 0xFFFF0000);
189 mga_outl(M_YBOT
, 0x01FFFFFF);
190 mga_outl(M_MACCESS
, maccess
);
191 ACCESS_FBINFO(accel
.m_dwg_rect
) = M_DWG_TRAP
| M_DWG_SOLID
| M_DWG_ARZERO
| M_DWG_SGNZERO
| M_DWG_SHIFTZERO
;
192 if (isMilleniumII(MINFO
)) ACCESS_FBINFO(accel
.m_dwg_rect
) |= M_DWG_TRANSC
;
193 ACCESS_FBINFO(accel
.m_opmode
) = mopmode
;
196 EXPORT_SYMBOL(matrox_cfbX_init
);
198 static void matrox_accel_bmove(WPMINFO
int vxres
, int sy
, int sx
, int dy
, int dx
, int height
, int width
) {
206 if ((dy
< sy
) || ((dy
== sy
) && (dx
<= sx
))) {
208 mga_outl(M_DWGCTL
, M_DWG_BITBLT
| M_DWG_SHIFTZERO
| M_DWG_SGNZERO
|
209 M_DWG_BFCOL
| M_DWG_REPLACE
);
210 mga_outl(M_AR5
, vxres
);
212 start
= sy
*vxres
+sx
+curr_ydstorg(MINFO
);
216 mga_outl(M_DWGCTL
, M_DWG_BITBLT
| M_DWG_SHIFTZERO
| M_DWG_BFCOL
| M_DWG_REPLACE
);
218 mga_outl(M_AR5
, -vxres
);
220 end
= (sy
+height
-1)*vxres
+sx
+curr_ydstorg(MINFO
);
225 mga_outl(M_AR0
, end
);
226 mga_outl(M_AR3
, start
);
227 mga_outl(M_FXBNDRY
, ((dx
+width
)<<16) | dx
);
228 mga_ydstlen(dy
, height
);
234 static void matrox_accel_bmove_lin(WPMINFO
int vxres
, int sy
, int sx
, int dy
, int dx
, int height
, int width
) {
242 if ((dy
< sy
) || ((dy
== sy
) && (dx
<= sx
))) {
244 mga_outl(M_DWGCTL
, M_DWG_BITBLT
| M_DWG_SHIFTZERO
| M_DWG_SGNZERO
|
245 M_DWG_BFCOL
| M_DWG_REPLACE
);
246 mga_outl(M_AR5
, vxres
);
248 start
= sy
*vxres
+sx
+curr_ydstorg(MINFO
);
252 mga_outl(M_DWGCTL
, M_DWG_BITBLT
| M_DWG_SHIFTZERO
| M_DWG_BFCOL
| M_DWG_REPLACE
);
254 mga_outl(M_AR5
, -vxres
);
256 end
= (sy
+height
-1)*vxres
+sx
+curr_ydstorg(MINFO
);
261 mga_outl(M_AR0
, end
);
262 mga_outl(M_AR3
, start
);
263 mga_outl(M_FXBNDRY
, ((dx
+width
)<<16) | dx
);
264 mga_outl(M_YDST
, dy
*vxres
>> 5);
265 mga_outl(M_LEN
| M_EXEC
, height
);
271 static void matroxfb_cfb4_copyarea(struct fb_info
* info
, const struct fb_copyarea
* area
) {
272 MINFO_FROM_INFO(info
);
274 if ((area
->sx
| area
->dx
| area
->width
) & 1)
275 cfb_copyarea(info
, area
);
277 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);
280 static void matroxfb_copyarea(struct fb_info
* info
, const struct fb_copyarea
* area
) {
281 MINFO_FROM_INFO(info
);
283 matrox_accel_bmove(PMINFO
ACCESS_FBINFO(fbcon
.var
.xres_virtual
), area
->sy
, area
->sx
, area
->dy
, area
->dx
, area
->height
, area
->width
);
286 static void matroxfb_accel_clear(WPMINFO u_int32_t color
, int sy
, int sx
, int height
,
295 mga_outl(M_DWGCTL
, ACCESS_FBINFO(accel
.m_dwg_rect
) | M_DWG_REPLACE
);
296 mga_outl(M_FCOL
, color
);
297 mga_outl(M_FXBNDRY
, ((sx
+ width
) << 16) | sx
);
298 mga_ydstlen(sy
, height
);
304 static void matroxfb_fillrect(struct fb_info
* info
, const struct fb_fillrect
* rect
) {
305 MINFO_FROM_INFO(info
);
309 matroxfb_accel_clear(PMINFO ((u_int32_t
*)info
->pseudo_palette
)[rect
->color
], rect
->dy
, rect
->dx
, rect
->height
, rect
->width
);
314 static void matroxfb_cfb4_clear(WPMINFO u_int32_t bgx
, int sy
, int sx
, int height
, int width
) {
336 mga_outl(M_DWGCTL
, ACCESS_FBINFO(accel
.m_dwg_rect
) | M_DWG_REPLACE2
);
337 mga_outl(M_FCOL
, bgx
);
338 mga_outl(M_FXBNDRY
, ((sx
+ width
) << 16) | sx
);
339 mga_outl(M_YDST
, sy
* ACCESS_FBINFO(fbcon
).var
.xres_virtual
>> 6);
340 mga_outl(M_LEN
| M_EXEC
, height
);
344 u_int32_t step
= ACCESS_FBINFO(fbcon
).var
.xres_virtual
>> 1;
345 vaddr_t vbase
= ACCESS_FBINFO(video
.vbase
);
347 unsigned int uaddr
= sy
* step
+ sx
- 1;
349 u_int8_t bgx2
= bgx
& 0xF0;
350 for (loop
= height
; loop
> 0; loop
--) {
351 mga_writeb(vbase
, uaddr
, (mga_readb(vbase
, uaddr
) & 0x0F) | bgx2
);
356 unsigned int uaddr
= sy
* step
+ sx
+ width
;
358 u_int8_t bgx2
= bgx
& 0x0F;
359 for (loop
= height
; loop
> 0; loop
--) {
360 mga_writeb(vbase
, uaddr
, (mga_readb(vbase
, uaddr
) & 0xF0) | bgx2
);
369 static void matroxfb_cfb4_fillrect(struct fb_info
* info
, const struct fb_fillrect
* rect
) {
370 MINFO_FROM_INFO(info
);
374 matroxfb_cfb4_clear(PMINFO ((u_int32_t
*)info
->pseudo_palette
)[rect
->color
], rect
->dy
, rect
->dx
, rect
->height
, rect
->width
);
379 static void matroxfb_1bpp_imageblit(WPMINFO u_int32_t fgx
, u_int32_t bgx
,
380 const u_int8_t
* chardata
, int width
, int height
, int yy
, int xx
) {
391 DBG_HEAVY(__FUNCTION__
);
393 step
= (width
+ 7) >> 3;
394 charcell
= height
* step
;
395 xlen
= (charcell
+ 3) & ~3;
396 ydstlen
= (yy
<< 16) | height
;
397 if (width
== step
<< 3) {
398 ar0
= height
* width
- 1;
409 mga_outl(M_DWGCTL
, M_DWG_ILOAD
| M_DWG_SGNZERO
| M_DWG_SHIFTZERO
| M_DWG_BMONOWF
| M_DWG_LINEAR
| M_DWG_REPLACE
);
411 mga_outl(M_DWGCTL
, M_DWG_ILOAD
| M_DWG_SGNZERO
| M_DWG_SHIFTZERO
| M_DWG_BMONOWF
| M_DWG_REPLACE
);
412 mga_outl(M_FCOL
, fgx
);
413 mga_outl(M_BCOL
, bgx
);
414 fxbndry
= ((xx
+ width
- 1) << 16) | xx
;
415 mmio
= ACCESS_FBINFO(mmio
.vbase
);
418 mga_writel(mmio
, M_FXBNDRY
, fxbndry
);
419 mga_writel(mmio
, M_AR0
, ar0
);
420 mga_writel(mmio
, M_AR3
, 0);
422 mga_writel(mmio
, M_YDSTLEN
| M_EXEC
, ydstlen
);
423 mga_memcpy_toio(mmio
, chardata
, xlen
);
425 mga_writel(mmio
, M_AR5
, 0);
426 mga_writel(mmio
, M_YDSTLEN
| M_EXEC
, ydstlen
);
427 if ((step
& 3) == 0) {
428 /* Great. Source has 32bit aligned lines, so we can feed them
429 directly to the accelerator. */
430 mga_memcpy_toio(mmio
, chardata
, charcell
);
431 } else if (step
== 1) {
432 /* Special case for 1..8bit widths */
434 #if defined(__BIG_ENDIAN)
435 fb_writel((*chardata
) << 24, mmio
.vaddr
);
437 fb_writel(*chardata
, mmio
.vaddr
);
441 } else if (step
== 2) {
442 /* Special case for 9..15bit widths */
444 #if defined(__BIG_ENDIAN)
445 fb_writel((*(u_int16_t
*)chardata
) << 16, mmio
.vaddr
);
447 fb_writel(*(u_int16_t
*)chardata
, mmio
.vaddr
);
452 /* Tell... well, why bother... */
456 for (i
= 0; i
< step
; i
+= 4) {
457 /* Hope that there are at least three readable bytes beyond the end of bitmap */
458 fb_writel(get_unaligned((u_int32_t
*)(chardata
+ i
)),mmio
.vaddr
);
469 static void matroxfb_imageblit(struct fb_info
* info
, const struct fb_image
* image
) {
470 MINFO_FROM_INFO(info
);
472 DBG_HEAVY(__FUNCTION__
);
474 if (image
->depth
== 1) {
477 fgx
= ((u_int32_t
*)info
->pseudo_palette
)[image
->fg_color
];
478 bgx
= ((u_int32_t
*)info
->pseudo_palette
)[image
->bg_color
];
479 matroxfb_1bpp_imageblit(PMINFO fgx
, bgx
, image
->data
, image
->width
, image
->height
, image
->dy
, image
->dx
);
481 /* Danger! image->depth is useless: logo painting code always
482 passes framebuffer color depth here, although logo data are
483 always 8bpp and info->pseudo_palette is changed to contain
484 logo palette to be used (but only for true/direct-color... sic...).
485 So do it completely in software... */
486 cfb_imageblit(info
, image
);
490 MODULE_LICENSE("GPL");