1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * Version: 1.65 2002/08/14
9*4882a593Smuzhiyun *
10*4882a593Smuzhiyun * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org>
11*4882a593Smuzhiyun *
12*4882a593Smuzhiyun * Contributors: "menion?" <menion@mindless.com>
13*4882a593Smuzhiyun * Betatesting, fixes, ideas
14*4882a593Smuzhiyun *
15*4882a593Smuzhiyun * "Kurt Garloff" <garloff@suse.de>
16*4882a593Smuzhiyun * Betatesting, fixes, ideas, videomodes, videomodes timmings
17*4882a593Smuzhiyun *
18*4882a593Smuzhiyun * "Tom Rini" <trini@kernel.crashing.org>
19*4882a593Smuzhiyun * MTRR stuff, PPC cleanups, betatesting, fixes, ideas
20*4882a593Smuzhiyun *
21*4882a593Smuzhiyun * "Bibek Sahu" <scorpio@dodds.net>
22*4882a593Smuzhiyun * Access device through readb|w|l and write b|w|l
23*4882a593Smuzhiyun * Extensive debugging stuff
24*4882a593Smuzhiyun *
25*4882a593Smuzhiyun * "Daniel Haun" <haund@usa.net>
26*4882a593Smuzhiyun * Testing, hardware cursor fixes
27*4882a593Smuzhiyun *
28*4882a593Smuzhiyun * "Scott Wood" <sawst46+@pitt.edu>
29*4882a593Smuzhiyun * Fixes
30*4882a593Smuzhiyun *
31*4882a593Smuzhiyun * "Gerd Knorr" <kraxel@goldbach.isdn.cs.tu-berlin.de>
32*4882a593Smuzhiyun * Betatesting
33*4882a593Smuzhiyun *
34*4882a593Smuzhiyun * "Kelly French" <targon@hazmat.com>
35*4882a593Smuzhiyun * "Fernando Herrera" <fherrera@eurielec.etsit.upm.es>
36*4882a593Smuzhiyun * Betatesting, bug reporting
37*4882a593Smuzhiyun *
38*4882a593Smuzhiyun * "Pablo Bianucci" <pbian@pccp.com.ar>
39*4882a593Smuzhiyun * Fixes, ideas, betatesting
40*4882a593Smuzhiyun *
41*4882a593Smuzhiyun * "Inaky Perez Gonzalez" <inaky@peloncho.fis.ucm.es>
42*4882a593Smuzhiyun * Fixes, enhandcements, ideas, betatesting
43*4882a593Smuzhiyun *
44*4882a593Smuzhiyun * "Ryuichi Oikawa" <roikawa@rr.iiij4u.or.jp>
45*4882a593Smuzhiyun * PPC betatesting, PPC support, backward compatibility
46*4882a593Smuzhiyun *
47*4882a593Smuzhiyun * "Paul Womar" <Paul@pwomar.demon.co.uk>
48*4882a593Smuzhiyun * "Owen Waller" <O.Waller@ee.qub.ac.uk>
49*4882a593Smuzhiyun * PPC betatesting
50*4882a593Smuzhiyun *
51*4882a593Smuzhiyun * "Thomas Pornin" <pornin@bolet.ens.fr>
52*4882a593Smuzhiyun * Alpha betatesting
53*4882a593Smuzhiyun *
54*4882a593Smuzhiyun * "Pieter van Leuven" <pvl@iae.nl>
55*4882a593Smuzhiyun * "Ulf Jaenicke-Roessler" <ujr@physik.phy.tu-dresden.de>
56*4882a593Smuzhiyun * G100 testing
57*4882a593Smuzhiyun *
58*4882a593Smuzhiyun * "H. Peter Arvin" <hpa@transmeta.com>
59*4882a593Smuzhiyun * Ideas
60*4882a593Smuzhiyun *
61*4882a593Smuzhiyun * "Cort Dougan" <cort@cs.nmt.edu>
62*4882a593Smuzhiyun * CHRP fixes and PReP cleanup
63*4882a593Smuzhiyun *
64*4882a593Smuzhiyun * "Mark Vojkovich" <mvojkovi@ucsd.edu>
65*4882a593Smuzhiyun * G400 support
66*4882a593Smuzhiyun *
67*4882a593Smuzhiyun * (following author is not in any relation with this code, but his code
68*4882a593Smuzhiyun * is included in this driver)
69*4882a593Smuzhiyun *
70*4882a593Smuzhiyun * Based on framebuffer driver for VBE 2.0 compliant graphic boards
71*4882a593Smuzhiyun * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
72*4882a593Smuzhiyun *
73*4882a593Smuzhiyun * (following author is not in any relation with this code, but his ideas
74*4882a593Smuzhiyun * were used when writing this driver)
75*4882a593Smuzhiyun *
76*4882a593Smuzhiyun * FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk>
77*4882a593Smuzhiyun *
78*4882a593Smuzhiyun */
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun #include "matroxfb_accel.h"
81*4882a593Smuzhiyun #include "matroxfb_DAC1064.h"
82*4882a593Smuzhiyun #include "matroxfb_Ti3026.h"
83*4882a593Smuzhiyun #include "matroxfb_misc.h"
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun #define curr_ydstorg(x) ((x)->curr.ydstorg.pixels)
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun #define mga_ydstlen(y,l) mga_outl(M_YDSTLEN | M_EXEC, ((y) << 16) | (l))
88*4882a593Smuzhiyun
matrox_cfb4_pal(u_int32_t * pal)89*4882a593Smuzhiyun static inline void matrox_cfb4_pal(u_int32_t* pal) {
90*4882a593Smuzhiyun unsigned int i;
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun for (i = 0; i < 16; i++) {
93*4882a593Smuzhiyun pal[i] = i * 0x11111111U;
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun
matrox_cfb8_pal(u_int32_t * pal)97*4882a593Smuzhiyun static inline void matrox_cfb8_pal(u_int32_t* pal) {
98*4882a593Smuzhiyun unsigned int i;
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun for (i = 0; i < 16; i++) {
101*4882a593Smuzhiyun pal[i] = i * 0x01010101U;
102*4882a593Smuzhiyun }
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun static void matroxfb_copyarea(struct fb_info* info, const struct fb_copyarea* area);
106*4882a593Smuzhiyun static void matroxfb_fillrect(struct fb_info* info, const struct fb_fillrect* rect);
107*4882a593Smuzhiyun static void matroxfb_imageblit(struct fb_info* info, const struct fb_image* image);
108*4882a593Smuzhiyun static void matroxfb_cfb4_fillrect(struct fb_info* info, const struct fb_fillrect* rect);
109*4882a593Smuzhiyun static void matroxfb_cfb4_copyarea(struct fb_info* info, const struct fb_copyarea* area);
110*4882a593Smuzhiyun
matrox_cfbX_init(struct matrox_fb_info * minfo)111*4882a593Smuzhiyun void matrox_cfbX_init(struct matrox_fb_info *minfo)
112*4882a593Smuzhiyun {
113*4882a593Smuzhiyun u_int32_t maccess;
114*4882a593Smuzhiyun u_int32_t mpitch;
115*4882a593Smuzhiyun u_int32_t mopmode;
116*4882a593Smuzhiyun int accel;
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun DBG(__func__)
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun mpitch = minfo->fbcon.var.xres_virtual;
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun minfo->fbops.fb_copyarea = cfb_copyarea;
123*4882a593Smuzhiyun minfo->fbops.fb_fillrect = cfb_fillrect;
124*4882a593Smuzhiyun minfo->fbops.fb_imageblit = cfb_imageblit;
125*4882a593Smuzhiyun minfo->fbops.fb_cursor = NULL;
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun accel = (minfo->fbcon.var.accel_flags & FB_ACCELF_TEXT) == FB_ACCELF_TEXT;
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun switch (minfo->fbcon.var.bits_per_pixel) {
130*4882a593Smuzhiyun case 4: maccess = 0x00000000; /* accelerate as 8bpp video */
131*4882a593Smuzhiyun mpitch = (mpitch >> 1) | 0x8000; /* disable linearization */
132*4882a593Smuzhiyun mopmode = M_OPMODE_4BPP;
133*4882a593Smuzhiyun matrox_cfb4_pal(minfo->cmap);
134*4882a593Smuzhiyun if (accel && !(mpitch & 1)) {
135*4882a593Smuzhiyun minfo->fbops.fb_copyarea = matroxfb_cfb4_copyarea;
136*4882a593Smuzhiyun minfo->fbops.fb_fillrect = matroxfb_cfb4_fillrect;
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun break;
139*4882a593Smuzhiyun case 8: maccess = 0x00000000;
140*4882a593Smuzhiyun mopmode = M_OPMODE_8BPP;
141*4882a593Smuzhiyun matrox_cfb8_pal(minfo->cmap);
142*4882a593Smuzhiyun if (accel) {
143*4882a593Smuzhiyun minfo->fbops.fb_copyarea = matroxfb_copyarea;
144*4882a593Smuzhiyun minfo->fbops.fb_fillrect = matroxfb_fillrect;
145*4882a593Smuzhiyun minfo->fbops.fb_imageblit = matroxfb_imageblit;
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun break;
148*4882a593Smuzhiyun case 16: if (minfo->fbcon.var.green.length == 5)
149*4882a593Smuzhiyun maccess = 0xC0000001;
150*4882a593Smuzhiyun else
151*4882a593Smuzhiyun maccess = 0x40000001;
152*4882a593Smuzhiyun mopmode = M_OPMODE_16BPP;
153*4882a593Smuzhiyun if (accel) {
154*4882a593Smuzhiyun minfo->fbops.fb_copyarea = matroxfb_copyarea;
155*4882a593Smuzhiyun minfo->fbops.fb_fillrect = matroxfb_fillrect;
156*4882a593Smuzhiyun minfo->fbops.fb_imageblit = matroxfb_imageblit;
157*4882a593Smuzhiyun }
158*4882a593Smuzhiyun break;
159*4882a593Smuzhiyun case 24: maccess = 0x00000003;
160*4882a593Smuzhiyun mopmode = M_OPMODE_24BPP;
161*4882a593Smuzhiyun if (accel) {
162*4882a593Smuzhiyun minfo->fbops.fb_copyarea = matroxfb_copyarea;
163*4882a593Smuzhiyun minfo->fbops.fb_fillrect = matroxfb_fillrect;
164*4882a593Smuzhiyun minfo->fbops.fb_imageblit = matroxfb_imageblit;
165*4882a593Smuzhiyun }
166*4882a593Smuzhiyun break;
167*4882a593Smuzhiyun case 32: maccess = 0x00000002;
168*4882a593Smuzhiyun mopmode = M_OPMODE_32BPP;
169*4882a593Smuzhiyun if (accel) {
170*4882a593Smuzhiyun minfo->fbops.fb_copyarea = matroxfb_copyarea;
171*4882a593Smuzhiyun minfo->fbops.fb_fillrect = matroxfb_fillrect;
172*4882a593Smuzhiyun minfo->fbops.fb_imageblit = matroxfb_imageblit;
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun break;
175*4882a593Smuzhiyun default: maccess = 0x00000000;
176*4882a593Smuzhiyun mopmode = 0x00000000;
177*4882a593Smuzhiyun break; /* turn off acceleration!!! */
178*4882a593Smuzhiyun }
179*4882a593Smuzhiyun mga_fifo(8);
180*4882a593Smuzhiyun mga_outl(M_PITCH, mpitch);
181*4882a593Smuzhiyun mga_outl(M_YDSTORG, curr_ydstorg(minfo));
182*4882a593Smuzhiyun if (minfo->capable.plnwt)
183*4882a593Smuzhiyun mga_outl(M_PLNWT, -1);
184*4882a593Smuzhiyun if (minfo->capable.srcorg) {
185*4882a593Smuzhiyun mga_outl(M_SRCORG, 0);
186*4882a593Smuzhiyun mga_outl(M_DSTORG, 0);
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun mga_outl(M_OPMODE, mopmode);
189*4882a593Smuzhiyun mga_outl(M_CXBNDRY, 0xFFFF0000);
190*4882a593Smuzhiyun mga_outl(M_YTOP, 0);
191*4882a593Smuzhiyun mga_outl(M_YBOT, 0x01FFFFFF);
192*4882a593Smuzhiyun mga_outl(M_MACCESS, maccess);
193*4882a593Smuzhiyun minfo->accel.m_dwg_rect = M_DWG_TRAP | M_DWG_SOLID | M_DWG_ARZERO | M_DWG_SGNZERO | M_DWG_SHIFTZERO;
194*4882a593Smuzhiyun if (isMilleniumII(minfo)) minfo->accel.m_dwg_rect |= M_DWG_TRANSC;
195*4882a593Smuzhiyun minfo->accel.m_opmode = mopmode;
196*4882a593Smuzhiyun minfo->accel.m_access = maccess;
197*4882a593Smuzhiyun minfo->accel.m_pitch = mpitch;
198*4882a593Smuzhiyun }
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun EXPORT_SYMBOL(matrox_cfbX_init);
201*4882a593Smuzhiyun
matrox_accel_restore_maccess(struct matrox_fb_info * minfo)202*4882a593Smuzhiyun static void matrox_accel_restore_maccess(struct matrox_fb_info *minfo)
203*4882a593Smuzhiyun {
204*4882a593Smuzhiyun mga_outl(M_MACCESS, minfo->accel.m_access);
205*4882a593Smuzhiyun mga_outl(M_PITCH, minfo->accel.m_pitch);
206*4882a593Smuzhiyun }
207*4882a593Smuzhiyun
matrox_accel_bmove(struct matrox_fb_info * minfo,int vxres,int sy,int sx,int dy,int dx,int height,int width)208*4882a593Smuzhiyun static void matrox_accel_bmove(struct matrox_fb_info *minfo, int vxres, int sy,
209*4882a593Smuzhiyun int sx, int dy, int dx, int height, int width)
210*4882a593Smuzhiyun {
211*4882a593Smuzhiyun int start, end;
212*4882a593Smuzhiyun CRITFLAGS
213*4882a593Smuzhiyun
214*4882a593Smuzhiyun DBG(__func__)
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun CRITBEGIN
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun if ((dy < sy) || ((dy == sy) && (dx <= sx))) {
219*4882a593Smuzhiyun mga_fifo(4);
220*4882a593Smuzhiyun matrox_accel_restore_maccess(minfo);
221*4882a593Smuzhiyun mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_SGNZERO |
222*4882a593Smuzhiyun M_DWG_BFCOL | M_DWG_REPLACE);
223*4882a593Smuzhiyun mga_outl(M_AR5, vxres);
224*4882a593Smuzhiyun width--;
225*4882a593Smuzhiyun start = sy*vxres+sx+curr_ydstorg(minfo);
226*4882a593Smuzhiyun end = start+width;
227*4882a593Smuzhiyun } else {
228*4882a593Smuzhiyun mga_fifo(5);
229*4882a593Smuzhiyun matrox_accel_restore_maccess(minfo);
230*4882a593Smuzhiyun mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_BFCOL | M_DWG_REPLACE);
231*4882a593Smuzhiyun mga_outl(M_SGN, 5);
232*4882a593Smuzhiyun mga_outl(M_AR5, -vxres);
233*4882a593Smuzhiyun width--;
234*4882a593Smuzhiyun end = (sy+height-1)*vxres+sx+curr_ydstorg(minfo);
235*4882a593Smuzhiyun start = end+width;
236*4882a593Smuzhiyun dy += height-1;
237*4882a593Smuzhiyun }
238*4882a593Smuzhiyun mga_fifo(6);
239*4882a593Smuzhiyun matrox_accel_restore_maccess(minfo);
240*4882a593Smuzhiyun mga_outl(M_AR0, end);
241*4882a593Smuzhiyun mga_outl(M_AR3, start);
242*4882a593Smuzhiyun mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx);
243*4882a593Smuzhiyun mga_ydstlen(dy, height);
244*4882a593Smuzhiyun WaitTillIdle();
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun CRITEND
247*4882a593Smuzhiyun }
248*4882a593Smuzhiyun
matrox_accel_bmove_lin(struct matrox_fb_info * minfo,int vxres,int sy,int sx,int dy,int dx,int height,int width)249*4882a593Smuzhiyun static void matrox_accel_bmove_lin(struct matrox_fb_info *minfo, int vxres,
250*4882a593Smuzhiyun int sy, int sx, int dy, int dx, int height,
251*4882a593Smuzhiyun int width)
252*4882a593Smuzhiyun {
253*4882a593Smuzhiyun int start, end;
254*4882a593Smuzhiyun CRITFLAGS
255*4882a593Smuzhiyun
256*4882a593Smuzhiyun DBG(__func__)
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun CRITBEGIN
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun if ((dy < sy) || ((dy == sy) && (dx <= sx))) {
261*4882a593Smuzhiyun mga_fifo(4);
262*4882a593Smuzhiyun matrox_accel_restore_maccess(minfo);
263*4882a593Smuzhiyun mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_SGNZERO |
264*4882a593Smuzhiyun M_DWG_BFCOL | M_DWG_REPLACE);
265*4882a593Smuzhiyun mga_outl(M_AR5, vxres);
266*4882a593Smuzhiyun width--;
267*4882a593Smuzhiyun start = sy*vxres+sx+curr_ydstorg(minfo);
268*4882a593Smuzhiyun end = start+width;
269*4882a593Smuzhiyun } else {
270*4882a593Smuzhiyun mga_fifo(5);
271*4882a593Smuzhiyun matrox_accel_restore_maccess(minfo);
272*4882a593Smuzhiyun mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_BFCOL | M_DWG_REPLACE);
273*4882a593Smuzhiyun mga_outl(M_SGN, 5);
274*4882a593Smuzhiyun mga_outl(M_AR5, -vxres);
275*4882a593Smuzhiyun width--;
276*4882a593Smuzhiyun end = (sy+height-1)*vxres+sx+curr_ydstorg(minfo);
277*4882a593Smuzhiyun start = end+width;
278*4882a593Smuzhiyun dy += height-1;
279*4882a593Smuzhiyun }
280*4882a593Smuzhiyun mga_fifo(7);
281*4882a593Smuzhiyun matrox_accel_restore_maccess(minfo);
282*4882a593Smuzhiyun mga_outl(M_AR0, end);
283*4882a593Smuzhiyun mga_outl(M_AR3, start);
284*4882a593Smuzhiyun mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx);
285*4882a593Smuzhiyun mga_outl(M_YDST, dy*vxres >> 5);
286*4882a593Smuzhiyun mga_outl(M_LEN | M_EXEC, height);
287*4882a593Smuzhiyun WaitTillIdle();
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun CRITEND
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun
matroxfb_cfb4_copyarea(struct fb_info * info,const struct fb_copyarea * area)292*4882a593Smuzhiyun static void matroxfb_cfb4_copyarea(struct fb_info* info, const struct fb_copyarea* area) {
293*4882a593Smuzhiyun struct matrox_fb_info *minfo = info2minfo(info);
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun if ((area->sx | area->dx | area->width) & 1)
296*4882a593Smuzhiyun cfb_copyarea(info, area);
297*4882a593Smuzhiyun else
298*4882a593Smuzhiyun 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);
299*4882a593Smuzhiyun }
300*4882a593Smuzhiyun
matroxfb_copyarea(struct fb_info * info,const struct fb_copyarea * area)301*4882a593Smuzhiyun static void matroxfb_copyarea(struct fb_info* info, const struct fb_copyarea* area) {
302*4882a593Smuzhiyun struct matrox_fb_info *minfo = info2minfo(info);
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun matrox_accel_bmove(minfo, minfo->fbcon.var.xres_virtual, area->sy, area->sx, area->dy, area->dx, area->height, area->width);
305*4882a593Smuzhiyun }
306*4882a593Smuzhiyun
matroxfb_accel_clear(struct matrox_fb_info * minfo,u_int32_t color,int sy,int sx,int height,int width)307*4882a593Smuzhiyun static void matroxfb_accel_clear(struct matrox_fb_info *minfo, u_int32_t color,
308*4882a593Smuzhiyun int sy, int sx, int height, int width)
309*4882a593Smuzhiyun {
310*4882a593Smuzhiyun CRITFLAGS
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun DBG(__func__)
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun CRITBEGIN
315*4882a593Smuzhiyun
316*4882a593Smuzhiyun mga_fifo(7);
317*4882a593Smuzhiyun matrox_accel_restore_maccess(minfo);
318*4882a593Smuzhiyun mga_outl(M_DWGCTL, minfo->accel.m_dwg_rect | M_DWG_REPLACE);
319*4882a593Smuzhiyun mga_outl(M_FCOL, color);
320*4882a593Smuzhiyun mga_outl(M_FXBNDRY, ((sx + width) << 16) | sx);
321*4882a593Smuzhiyun mga_ydstlen(sy, height);
322*4882a593Smuzhiyun WaitTillIdle();
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun CRITEND
325*4882a593Smuzhiyun }
326*4882a593Smuzhiyun
matroxfb_fillrect(struct fb_info * info,const struct fb_fillrect * rect)327*4882a593Smuzhiyun static void matroxfb_fillrect(struct fb_info* info, const struct fb_fillrect* rect) {
328*4882a593Smuzhiyun struct matrox_fb_info *minfo = info2minfo(info);
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun switch (rect->rop) {
331*4882a593Smuzhiyun case ROP_COPY:
332*4882a593Smuzhiyun matroxfb_accel_clear(minfo, ((u_int32_t *)info->pseudo_palette)[rect->color], rect->dy, rect->dx, rect->height, rect->width);
333*4882a593Smuzhiyun break;
334*4882a593Smuzhiyun }
335*4882a593Smuzhiyun }
336*4882a593Smuzhiyun
matroxfb_cfb4_clear(struct matrox_fb_info * minfo,u_int32_t bgx,int sy,int sx,int height,int width)337*4882a593Smuzhiyun static void matroxfb_cfb4_clear(struct matrox_fb_info *minfo, u_int32_t bgx,
338*4882a593Smuzhiyun int sy, int sx, int height, int width)
339*4882a593Smuzhiyun {
340*4882a593Smuzhiyun int whattodo;
341*4882a593Smuzhiyun CRITFLAGS
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun DBG(__func__)
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun CRITBEGIN
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun whattodo = 0;
348*4882a593Smuzhiyun if (sx & 1) {
349*4882a593Smuzhiyun sx ++;
350*4882a593Smuzhiyun if (!width) return;
351*4882a593Smuzhiyun width --;
352*4882a593Smuzhiyun whattodo = 1;
353*4882a593Smuzhiyun }
354*4882a593Smuzhiyun if (width & 1) {
355*4882a593Smuzhiyun whattodo |= 2;
356*4882a593Smuzhiyun }
357*4882a593Smuzhiyun width >>= 1;
358*4882a593Smuzhiyun sx >>= 1;
359*4882a593Smuzhiyun if (width) {
360*4882a593Smuzhiyun mga_fifo(7);
361*4882a593Smuzhiyun matrox_accel_restore_maccess(minfo);
362*4882a593Smuzhiyun mga_outl(M_DWGCTL, minfo->accel.m_dwg_rect | M_DWG_REPLACE2);
363*4882a593Smuzhiyun mga_outl(M_FCOL, bgx);
364*4882a593Smuzhiyun mga_outl(M_FXBNDRY, ((sx + width) << 16) | sx);
365*4882a593Smuzhiyun mga_outl(M_YDST, sy * minfo->fbcon.var.xres_virtual >> 6);
366*4882a593Smuzhiyun mga_outl(M_LEN | M_EXEC, height);
367*4882a593Smuzhiyun WaitTillIdle();
368*4882a593Smuzhiyun }
369*4882a593Smuzhiyun if (whattodo) {
370*4882a593Smuzhiyun u_int32_t step = minfo->fbcon.var.xres_virtual >> 1;
371*4882a593Smuzhiyun vaddr_t vbase = minfo->video.vbase;
372*4882a593Smuzhiyun if (whattodo & 1) {
373*4882a593Smuzhiyun unsigned int uaddr = sy * step + sx - 1;
374*4882a593Smuzhiyun u_int32_t loop;
375*4882a593Smuzhiyun u_int8_t bgx2 = bgx & 0xF0;
376*4882a593Smuzhiyun for (loop = height; loop > 0; loop --) {
377*4882a593Smuzhiyun mga_writeb(vbase, uaddr, (mga_readb(vbase, uaddr) & 0x0F) | bgx2);
378*4882a593Smuzhiyun uaddr += step;
379*4882a593Smuzhiyun }
380*4882a593Smuzhiyun }
381*4882a593Smuzhiyun if (whattodo & 2) {
382*4882a593Smuzhiyun unsigned int uaddr = sy * step + sx + width;
383*4882a593Smuzhiyun u_int32_t loop;
384*4882a593Smuzhiyun u_int8_t bgx2 = bgx & 0x0F;
385*4882a593Smuzhiyun for (loop = height; loop > 0; loop --) {
386*4882a593Smuzhiyun mga_writeb(vbase, uaddr, (mga_readb(vbase, uaddr) & 0xF0) | bgx2);
387*4882a593Smuzhiyun uaddr += step;
388*4882a593Smuzhiyun }
389*4882a593Smuzhiyun }
390*4882a593Smuzhiyun }
391*4882a593Smuzhiyun
392*4882a593Smuzhiyun CRITEND
393*4882a593Smuzhiyun }
394*4882a593Smuzhiyun
matroxfb_cfb4_fillrect(struct fb_info * info,const struct fb_fillrect * rect)395*4882a593Smuzhiyun static void matroxfb_cfb4_fillrect(struct fb_info* info, const struct fb_fillrect* rect) {
396*4882a593Smuzhiyun struct matrox_fb_info *minfo = info2minfo(info);
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun switch (rect->rop) {
399*4882a593Smuzhiyun case ROP_COPY:
400*4882a593Smuzhiyun matroxfb_cfb4_clear(minfo, ((u_int32_t *)info->pseudo_palette)[rect->color], rect->dy, rect->dx, rect->height, rect->width);
401*4882a593Smuzhiyun break;
402*4882a593Smuzhiyun }
403*4882a593Smuzhiyun }
404*4882a593Smuzhiyun
matroxfb_1bpp_imageblit(struct matrox_fb_info * minfo,u_int32_t fgx,u_int32_t bgx,const u_int8_t * chardata,int width,int height,int yy,int xx)405*4882a593Smuzhiyun static void matroxfb_1bpp_imageblit(struct matrox_fb_info *minfo, u_int32_t fgx,
406*4882a593Smuzhiyun u_int32_t bgx, const u_int8_t *chardata,
407*4882a593Smuzhiyun int width, int height, int yy, int xx)
408*4882a593Smuzhiyun {
409*4882a593Smuzhiyun u_int32_t step;
410*4882a593Smuzhiyun u_int32_t ydstlen;
411*4882a593Smuzhiyun u_int32_t xlen;
412*4882a593Smuzhiyun u_int32_t ar0;
413*4882a593Smuzhiyun u_int32_t charcell;
414*4882a593Smuzhiyun u_int32_t fxbndry;
415*4882a593Smuzhiyun vaddr_t mmio;
416*4882a593Smuzhiyun int easy;
417*4882a593Smuzhiyun CRITFLAGS
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun DBG_HEAVY(__func__);
420*4882a593Smuzhiyun
421*4882a593Smuzhiyun step = (width + 7) >> 3;
422*4882a593Smuzhiyun charcell = height * step;
423*4882a593Smuzhiyun xlen = (charcell + 3) & ~3;
424*4882a593Smuzhiyun ydstlen = (yy << 16) | height;
425*4882a593Smuzhiyun if (width == step << 3) {
426*4882a593Smuzhiyun ar0 = height * width - 1;
427*4882a593Smuzhiyun easy = 1;
428*4882a593Smuzhiyun } else {
429*4882a593Smuzhiyun ar0 = width - 1;
430*4882a593Smuzhiyun easy = 0;
431*4882a593Smuzhiyun }
432*4882a593Smuzhiyun
433*4882a593Smuzhiyun CRITBEGIN
434*4882a593Smuzhiyun
435*4882a593Smuzhiyun mga_fifo(5);
436*4882a593Smuzhiyun matrox_accel_restore_maccess(minfo);
437*4882a593Smuzhiyun if (easy)
438*4882a593Smuzhiyun mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE);
439*4882a593Smuzhiyun else
440*4882a593Smuzhiyun mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_REPLACE);
441*4882a593Smuzhiyun mga_outl(M_FCOL, fgx);
442*4882a593Smuzhiyun mga_outl(M_BCOL, bgx);
443*4882a593Smuzhiyun fxbndry = ((xx + width - 1) << 16) | xx;
444*4882a593Smuzhiyun mmio = minfo->mmio.vbase;
445*4882a593Smuzhiyun
446*4882a593Smuzhiyun mga_fifo(8);
447*4882a593Smuzhiyun matrox_accel_restore_maccess(minfo);
448*4882a593Smuzhiyun mga_writel(mmio, M_FXBNDRY, fxbndry);
449*4882a593Smuzhiyun mga_writel(mmio, M_AR0, ar0);
450*4882a593Smuzhiyun mga_writel(mmio, M_AR3, 0);
451*4882a593Smuzhiyun if (easy) {
452*4882a593Smuzhiyun mga_writel(mmio, M_YDSTLEN | M_EXEC, ydstlen);
453*4882a593Smuzhiyun mga_memcpy_toio(mmio, chardata, xlen);
454*4882a593Smuzhiyun } else {
455*4882a593Smuzhiyun mga_writel(mmio, M_AR5, 0);
456*4882a593Smuzhiyun mga_writel(mmio, M_YDSTLEN | M_EXEC, ydstlen);
457*4882a593Smuzhiyun if ((step & 3) == 0) {
458*4882a593Smuzhiyun /* Great. Source has 32bit aligned lines, so we can feed them
459*4882a593Smuzhiyun directly to the accelerator. */
460*4882a593Smuzhiyun mga_memcpy_toio(mmio, chardata, charcell);
461*4882a593Smuzhiyun } else if (step == 1) {
462*4882a593Smuzhiyun /* Special case for 1..8bit widths */
463*4882a593Smuzhiyun while (height--) {
464*4882a593Smuzhiyun #if defined(__BIG_ENDIAN)
465*4882a593Smuzhiyun fb_writel((*chardata) << 24, mmio.vaddr);
466*4882a593Smuzhiyun #else
467*4882a593Smuzhiyun fb_writel(*chardata, mmio.vaddr);
468*4882a593Smuzhiyun #endif
469*4882a593Smuzhiyun chardata++;
470*4882a593Smuzhiyun }
471*4882a593Smuzhiyun } else if (step == 2) {
472*4882a593Smuzhiyun /* Special case for 9..15bit widths */
473*4882a593Smuzhiyun while (height--) {
474*4882a593Smuzhiyun #if defined(__BIG_ENDIAN)
475*4882a593Smuzhiyun fb_writel((*(u_int16_t*)chardata) << 16, mmio.vaddr);
476*4882a593Smuzhiyun #else
477*4882a593Smuzhiyun fb_writel(*(u_int16_t*)chardata, mmio.vaddr);
478*4882a593Smuzhiyun #endif
479*4882a593Smuzhiyun chardata += 2;
480*4882a593Smuzhiyun }
481*4882a593Smuzhiyun } else {
482*4882a593Smuzhiyun /* Tell... well, why bother... */
483*4882a593Smuzhiyun while (height--) {
484*4882a593Smuzhiyun size_t i;
485*4882a593Smuzhiyun
486*4882a593Smuzhiyun for (i = 0; i < step; i += 4) {
487*4882a593Smuzhiyun /* Hope that there are at least three readable bytes beyond the end of bitmap */
488*4882a593Smuzhiyun fb_writel(get_unaligned((u_int32_t*)(chardata + i)),mmio.vaddr);
489*4882a593Smuzhiyun }
490*4882a593Smuzhiyun chardata += step;
491*4882a593Smuzhiyun }
492*4882a593Smuzhiyun }
493*4882a593Smuzhiyun }
494*4882a593Smuzhiyun WaitTillIdle();
495*4882a593Smuzhiyun CRITEND
496*4882a593Smuzhiyun }
497*4882a593Smuzhiyun
498*4882a593Smuzhiyun
matroxfb_imageblit(struct fb_info * info,const struct fb_image * image)499*4882a593Smuzhiyun static void matroxfb_imageblit(struct fb_info* info, const struct fb_image* image) {
500*4882a593Smuzhiyun struct matrox_fb_info *minfo = info2minfo(info);
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun DBG_HEAVY(__func__);
503*4882a593Smuzhiyun
504*4882a593Smuzhiyun if (image->depth == 1) {
505*4882a593Smuzhiyun u_int32_t fgx, bgx;
506*4882a593Smuzhiyun
507*4882a593Smuzhiyun fgx = ((u_int32_t*)info->pseudo_palette)[image->fg_color];
508*4882a593Smuzhiyun bgx = ((u_int32_t*)info->pseudo_palette)[image->bg_color];
509*4882a593Smuzhiyun matroxfb_1bpp_imageblit(minfo, fgx, bgx, image->data, image->width, image->height, image->dy, image->dx);
510*4882a593Smuzhiyun } else {
511*4882a593Smuzhiyun /* Danger! image->depth is useless: logo painting code always
512*4882a593Smuzhiyun passes framebuffer color depth here, although logo data are
513*4882a593Smuzhiyun always 8bpp and info->pseudo_palette is changed to contain
514*4882a593Smuzhiyun logo palette to be used (but only for true/direct-color... sic...).
515*4882a593Smuzhiyun So do it completely in software... */
516*4882a593Smuzhiyun cfb_imageblit(info, image);
517*4882a593Smuzhiyun }
518*4882a593Smuzhiyun }
519*4882a593Smuzhiyun
520*4882a593Smuzhiyun MODULE_LICENSE("GPL");
521