xref: /OK3568_Linux_fs/kernel/drivers/video/fbdev/matrox/matroxfb_accel.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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