1 /*
2  *  linux/drivers/video/cfb32.c -- Low level frame buffer operations for 32 bpp
3  *				   truecolor packed pixels
4  *
5  *	Created 28 Dec 1997 by Geert Uytterhoeven
6  *
7  *  This file is subject to the terms and conditions of the GNU General Public
8  *  License.  See the file COPYING in the main directory of this archive for
9  *  more details.
10  */
11 
12 #include <linux/module.h>
13 #include <linux/tty.h>
14 #include <linux/console.h>
15 #include <linux/string.h>
16 #include <linux/fb.h>
17 
18 #include <video/fbcon.h>
19 #include <video/fbcon-cfb32.h>
20 
21 
22     /*
23      *  32 bpp packed pixels
24      */
25 
fbcon_cfb32_setup(struct display * p)26 void fbcon_cfb32_setup(struct display *p)
27 {
28     p->next_line = p->line_length ? p->line_length : p->var.xres_virtual<<2;
29     p->next_plane = 0;
30 }
31 
fbcon_cfb32_bmove(struct display * p,int sy,int sx,int dy,int dx,int height,int width)32 void fbcon_cfb32_bmove(struct display *p, int sy, int sx, int dy, int dx,
33 		       int height, int width)
34 {
35     int bytes = p->next_line, linesize = bytes * fontheight(p), rows;
36     u8 *src, *dst;
37 
38     if (sx == 0 && dx == 0 && width * fontwidth(p) * 4 == bytes) {
39 	fb_memmove(p->screen_base + dy * linesize,
40 		  p->screen_base + sy * linesize,
41 		  height * linesize);
42 	return;
43     }
44     if (fontwidthlog(p)) {
45 	sx <<= fontwidthlog(p)+2;
46 	dx <<= fontwidthlog(p)+2;
47 	width <<= fontwidthlog(p)+2;
48     } else {
49 	sx *= fontwidth(p)*4;
50 	dx *= fontwidth(p)*4;
51 	width *= fontwidth(p)*4;
52     }
53     if (dy < sy || (dy == sy && dx < sx)) {
54 	src = p->screen_base + sy * linesize + sx;
55 	dst = p->screen_base + dy * linesize + dx;
56 	for (rows = height * fontheight(p); rows--;) {
57 	    fb_memmove(dst, src, width);
58 	    src += bytes;
59 	    dst += bytes;
60 	}
61     } else {
62 	src = p->screen_base + (sy+height) * linesize + sx - bytes;
63 	dst = p->screen_base + (dy+height) * linesize + dx - bytes;
64 	for (rows = height * fontheight(p); rows--;) {
65 	    fb_memmove(dst, src, width);
66 	    src -= bytes;
67 	    dst -= bytes;
68 	}
69     }
70 }
71 
rectfill(u8 * dest,int width,int height,u32 data,int linesize)72 static inline void rectfill(u8 *dest, int width, int height, u32 data,
73 			    int linesize)
74 {
75     int i;
76 
77     while (height-- > 0) {
78 	u32 *p = (u32 *)dest;
79 	for (i = 0; i < width/4; i++) {
80 	    fb_writel(data, p++);
81 	    fb_writel(data, p++);
82 	    fb_writel(data, p++);
83 	    fb_writel(data, p++);
84 	}
85 	if (width & 2) {
86 	    fb_writel(data, p++);
87 	    fb_writel(data, p++);
88 	}
89 	if (width & 1)
90 	    fb_writel(data, p++);
91 	dest += linesize;
92     }
93 }
94 
fbcon_cfb32_clear(struct vc_data * conp,struct display * p,int sy,int sx,int height,int width)95 void fbcon_cfb32_clear(struct vc_data *conp, struct display *p, int sy, int sx,
96 		       int height, int width)
97 {
98     u8 *dest;
99     int bytes = p->next_line, lines = height * fontheight(p);
100     u32 bgx;
101 
102     dest = p->screen_base + sy * fontheight(p) * bytes + sx * fontwidth(p) * 4;
103 
104     bgx = ((u32 *)p->dispsw_data)[attr_bgcol_ec(p, conp)];
105 
106     width *= fontwidth(p)/4;
107     if (width * 16 == bytes)
108 	rectfill(dest, lines * width * 4, 1, bgx, bytes);
109     else
110 	rectfill(dest, width * 4, lines, bgx, bytes);
111 }
112 
fbcon_cfb32_putc(struct vc_data * conp,struct display * p,int c,int yy,int xx)113 void fbcon_cfb32_putc(struct vc_data *conp, struct display *p, int c, int yy,
114 		      int xx)
115 {
116     u8 *dest, *cdat, bits;
117     int bytes = p->next_line, rows;
118     u32 eorx, fgx, bgx, *pt;
119 
120     dest = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 4;
121     if (fontwidth(p) <= 8)
122 	cdat = p->fontdata + (c & p->charmask) * fontheight(p);
123     else
124 	cdat = p->fontdata + ((c & p->charmask) * fontheight(p) << 1);
125     fgx = ((u32 *)p->dispsw_data)[attr_fgcol(p, c)];
126     bgx = ((u32 *)p->dispsw_data)[attr_bgcol(p, c)];
127     eorx = fgx ^ bgx;
128 
129     for (rows = fontheight(p); rows--; dest += bytes) {
130 	bits = *cdat++;
131 	pt = (u32 *) dest;
132 	fb_writel((-(bits >> 7) & eorx) ^ bgx, pt++);
133 	fb_writel((-(bits >> 6 & 1) & eorx) ^ bgx, pt++);
134 	fb_writel((-(bits >> 5 & 1) & eorx) ^ bgx, pt++);
135 	fb_writel((-(bits >> 4 & 1) & eorx) ^ bgx, pt++);
136 	if (fontwidth(p) < 8)
137 	    continue;
138 	fb_writel((-(bits >> 3 & 1) & eorx) ^ bgx, pt++);
139 	fb_writel((-(bits >> 2 & 1) & eorx) ^ bgx, pt++);
140 	fb_writel((-(bits >> 1 & 1) & eorx) ^ bgx, pt++);
141 	fb_writel((-(bits & 1) & eorx) ^ bgx, pt++);
142 	if (fontwidth(p) < 12)
143 	    continue;
144 	bits = *cdat++;
145 	fb_writel((-(bits >> 7) & eorx) ^ bgx, pt++);
146 	fb_writel((-(bits >> 6 & 1) & eorx) ^ bgx, pt++);
147 	fb_writel((-(bits >> 5 & 1) & eorx) ^ bgx, pt++);
148 	fb_writel((-(bits >> 4 & 1) & eorx) ^ bgx, pt++);
149 	if (fontwidth(p) < 16)
150 	    continue;
151 	fb_writel((-(bits >> 3 & 1) & eorx) ^ bgx, pt++);
152 	fb_writel((-(bits >> 2 & 1) & eorx) ^ bgx, pt++);
153 	fb_writel((-(bits >> 1 & 1) & eorx) ^ bgx, pt++);
154 	fb_writel((-(bits & 1) & eorx) ^ bgx, pt++);
155     }
156 }
157 
fbcon_cfb32_putcs(struct vc_data * conp,struct display * p,const unsigned short * s,int count,int yy,int xx)158 void fbcon_cfb32_putcs(struct vc_data *conp, struct display *p,
159 		       const unsigned short *s, int count, int yy, int xx)
160 {
161     u8 *cdat, *dest, *dest0, bits;
162     u16 c;
163     int rows, bytes = p->next_line;
164     u32 eorx, fgx, bgx, *pt;
165 
166     dest0 = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 4;
167     c = scr_readw(s);
168     fgx = ((u32 *)p->dispsw_data)[attr_fgcol(p, c)];
169     bgx = ((u32 *)p->dispsw_data)[attr_bgcol(p, c)];
170     eorx = fgx ^ bgx;
171     while (count--) {
172 	c = scr_readw(s++) & p->charmask;
173 	if (fontwidth(p) <= 8)
174 	    cdat = p->fontdata + c * fontheight(p);
175 	else
176 	    cdat = p->fontdata + (c * fontheight(p) << 1);
177 	for (rows = fontheight(p), dest = dest0; rows--; dest += bytes) {
178 	    bits = *cdat++;
179 	    pt = (u32 *) dest;
180 	    fb_writel((-(bits >> 7) & eorx) ^ bgx, pt++);
181 	    fb_writel((-(bits >> 6 & 1) & eorx) ^ bgx, pt++);
182 	    fb_writel((-(bits >> 5 & 1) & eorx) ^ bgx, pt++);
183 	    fb_writel((-(bits >> 4 & 1) & eorx) ^ bgx, pt++);
184 	    if (fontwidth(p) < 8)
185 		continue;
186 	    fb_writel((-(bits >> 3 & 1) & eorx) ^ bgx, pt++);
187 	    fb_writel((-(bits >> 2 & 1) & eorx) ^ bgx, pt++);
188 	    fb_writel((-(bits >> 1 & 1) & eorx) ^ bgx, pt++);
189 	    fb_writel((-(bits & 1) & eorx) ^ bgx, pt++);
190 	    if (fontwidth(p) < 12)
191 		continue;
192 	    bits = *cdat++;
193 	    fb_writel((-(bits >> 7) & eorx) ^ bgx, pt++);
194 	    fb_writel((-(bits >> 6 & 1) & eorx) ^ bgx, pt++);
195 	    fb_writel((-(bits >> 5 & 1) & eorx) ^ bgx, pt++);
196 	    fb_writel((-(bits >> 4 & 1) & eorx) ^ bgx, pt++);
197 	    if (fontwidth(p) < 16)
198 		continue;
199 	    fb_writel((-(bits >> 3 & 1) & eorx) ^ bgx, pt++);
200 	    fb_writel((-(bits >> 2 & 1) & eorx) ^ bgx, pt++);
201 	    fb_writel((-(bits >> 1 & 1) & eorx) ^ bgx, pt++);
202 	    fb_writel((-(bits & 1) & eorx) ^ bgx, pt++);
203 	}
204 	dest0 += fontwidth(p)*4;
205     }
206 }
207 
fbcon_cfb32_revc(struct display * p,int xx,int yy)208 void fbcon_cfb32_revc(struct display *p, int xx, int yy)
209 {
210     u8 *dest;
211     int bytes = p->next_line, rows;
212 
213     dest = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 4;
214     for (rows = fontheight(p); rows--; dest += bytes) {
215 	switch (fontwidth(p)) {
216 	case 16:
217 	    fb_writel(fb_readl(dest+(4*12)) ^ 0xffffffff, dest+(4*12));
218 	    fb_writel(fb_readl(dest+(4*13)) ^ 0xffffffff, dest+(4*13));
219 	    fb_writel(fb_readl(dest+(4*14)) ^ 0xffffffff, dest+(4*14));
220 	    fb_writel(fb_readl(dest+(4*15)) ^ 0xffffffff, dest+(4*15));
221 	    /* FALL THROUGH */
222 	case 12:
223 	    fb_writel(fb_readl(dest+(4*8)) ^ 0xffffffff, dest+(4*8));
224 	    fb_writel(fb_readl(dest+(4*9)) ^ 0xffffffff, dest+(4*9));
225 	    fb_writel(fb_readl(dest+(4*10)) ^ 0xffffffff, dest+(4*10));
226 	    fb_writel(fb_readl(dest+(4*11)) ^ 0xffffffff, dest+(4*11));
227 	    /* FALL THROUGH */
228 	case 8:
229 	    fb_writel(fb_readl(dest+(4*4)) ^ 0xffffffff, dest+(4*4));
230 	    fb_writel(fb_readl(dest+(4*5)) ^ 0xffffffff, dest+(4*5));
231 	    fb_writel(fb_readl(dest+(4*6)) ^ 0xffffffff, dest+(4*6));
232 	    fb_writel(fb_readl(dest+(4*7)) ^ 0xffffffff, dest+(4*7));
233 	    /* FALL THROUGH */
234 	case 4:
235 	    fb_writel(fb_readl(dest+(4*0)) ^ 0xffffffff, dest+(4*0));
236 	    fb_writel(fb_readl(dest+(4*1)) ^ 0xffffffff, dest+(4*1));
237 	    fb_writel(fb_readl(dest+(4*2)) ^ 0xffffffff, dest+(4*2));
238 	    fb_writel(fb_readl(dest+(4*3)) ^ 0xffffffff, dest+(4*3));
239 	    /* FALL THROUGH */
240 	}
241     }
242 }
243 
fbcon_cfb32_clear_margins(struct vc_data * conp,struct display * p,int bottom_only)244 void fbcon_cfb32_clear_margins(struct vc_data *conp, struct display *p,
245 			       int bottom_only)
246 {
247     int bytes = p->next_line;
248     u32 bgx;
249 
250     unsigned int right_start = conp->vc_cols*fontwidth(p);
251     unsigned int bottom_start = conp->vc_rows*fontheight(p);
252     unsigned int right_width, bottom_width;
253 
254     bgx = ((u32 *)p->dispsw_data)[attr_bgcol_ec(p, conp)];
255 
256     if (!bottom_only && (right_width = p->var.xres-right_start))
257 	rectfill(p->screen_base+right_start*4, right_width,
258 		 p->var.yres_virtual, bgx, bytes);
259     if ((bottom_width = p->var.yres-bottom_start))
260 	rectfill(p->screen_base+(p->var.yoffset+bottom_start)*bytes,
261 		 right_start, bottom_width, bgx, bytes);
262 }
263 
264 
265     /*
266      *  `switch' for the low level operations
267      */
268 
269 struct display_switch fbcon_cfb32 = {
270     setup:		fbcon_cfb32_setup,
271     bmove:		fbcon_cfb32_bmove,
272     clear:		fbcon_cfb32_clear,
273     putc:		fbcon_cfb32_putc,
274     putcs:		fbcon_cfb32_putcs,
275     revc:		fbcon_cfb32_revc,
276     clear_margins:	fbcon_cfb32_clear_margins,
277     fontwidthmask:	FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
278 };
279 
280 
281 #ifdef MODULE
282 MODULE_LICENSE("GPL");
283 
init_module(void)284 int init_module(void)
285 {
286     return 0;
287 }
288 
cleanup_module(void)289 void cleanup_module(void)
290 {}
291 #endif /* MODULE */
292 
293 
294     /*
295      *  Visible symbols for modules
296      */
297 
298 EXPORT_SYMBOL(fbcon_cfb32);
299 EXPORT_SYMBOL(fbcon_cfb32_setup);
300 EXPORT_SYMBOL(fbcon_cfb32_bmove);
301 EXPORT_SYMBOL(fbcon_cfb32_clear);
302 EXPORT_SYMBOL(fbcon_cfb32_putc);
303 EXPORT_SYMBOL(fbcon_cfb32_putcs);
304 EXPORT_SYMBOL(fbcon_cfb32_revc);
305 EXPORT_SYMBOL(fbcon_cfb32_clear_margins);
306