MOXA linux-2.6.x / linux-2.6.9-uc0 from sdlinux-moxaart.tgz
[linux-2.6.9-moxart.git] / drivers / video / cfbfillrect.c
blob4a94bf85e79e6dcdf54f3d23208eea7419c15c6d
1 /*
2 * Generic fillrect for frame buffers with packed pixels of any depth.
4 * Copyright (C) 2000 James Simmons (jsimmons@linux-fbdev.org)
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file COPYING in the main directory of this archive for
8 * more details.
10 * NOTES:
12 * The code for depths like 24 that don't have integer number of pixels per
13 * long is broken and needs to be fixed. For now I turned these types of
14 * mode off.
16 * Also need to add code to deal with cards endians that are different than
17 * the native cpu endians. I also need to deal with MSB position in the word.
20 #include <linux/config.h>
21 #include <linux/module.h>
22 #include <linux/string.h>
23 #include <linux/fb.h>
24 #include <asm/types.h>
26 #if BITS_PER_LONG == 32
27 #define FB_WRITEL fb_writel
28 #define FB_READL fb_readl
29 #define BYTES_PER_LONG 4
30 #define SHIFT_PER_LONG 5
31 #else
32 #define FB_WRITEL fb_writeq
33 #define FB_READL fb_readq
34 #define BYTES_PER_LONG 8
35 #define SHIFT_PER_LONG 6
36 #endif
38 #define EXP1(x) 0xffffffffU*x
39 #define EXP2(x) 0x55555555U*x
40 #define EXP4(x) 0x11111111U*0x ## x
42 typedef u32 pixel_t;
44 static const u32 bpp1tab[2] = {
45 EXP1(0), EXP1(1)
48 static const u32 bpp2tab[4] = {
49 EXP2(0), EXP2(1), EXP2(2), EXP2(3)
52 static const u32 bpp4tab[16] = {
53 EXP4(0), EXP4(1), EXP4(2), EXP4(3), EXP4(4), EXP4(5), EXP4(6), EXP4(7),
54 EXP4(8), EXP4(9), EXP4(a), EXP4(b), EXP4(c), EXP4(d), EXP4(e), EXP4(f)
58 * Compose two values, using a bitmask as decision value
59 * This is equivalent to (a & mask) | (b & ~mask)
62 static inline unsigned long comp(unsigned long a, unsigned long b,
63 unsigned long mask)
65 return ((a ^ b) & mask) ^ b;
68 static inline u32 pixel_to_pat32(const struct fb_info *p, pixel_t pixel)
70 u32 pat = pixel;
72 switch (p->var.bits_per_pixel) {
73 case 1:
74 pat = bpp1tab[pat];
75 break;
77 case 2:
78 pat = bpp2tab[pat];
79 break;
81 case 4:
82 pat = bpp4tab[pat];
83 break;
85 case 8:
86 pat |= pat << 8;
87 // Fall through
88 case 16:
89 pat |= pat << 16;
90 // Fall through
91 case 32:
92 break;
94 return pat;
98 * Expand a pixel value to a generic 32/64-bit pattern and rotate it to
99 * the correct start position
102 static inline unsigned long pixel_to_pat(const struct fb_info *p,
103 pixel_t pixel, int left)
105 unsigned long pat = pixel;
106 u32 bpp = p->var.bits_per_pixel;
107 int i;
109 /* expand pixel value */
110 for (i = bpp; i < BITS_PER_LONG; i *= 2)
111 pat |= pat << i;
113 /* rotate pattern to correct start position */
114 pat = pat << left | pat >> (bpp-left);
115 return pat;
119 * Unaligned 32-bit pattern fill using 32/64-bit memory accesses
122 void bitfill32(unsigned long __iomem *dst, int dst_idx, u32 pat, u32 n)
124 unsigned long val = pat;
125 unsigned long first, last;
127 if (!n)
128 return;
130 #if BITS_PER_LONG == 64
131 val |= val << 32;
132 #endif
134 first = ~0UL >> dst_idx;
135 last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
137 if (dst_idx+n <= BITS_PER_LONG) {
138 // Single word
139 if (last)
140 first &= last;
141 FB_WRITEL(comp(val, FB_READL(dst), first), dst);
142 } else {
143 // Multiple destination words
144 // Leading bits
145 if (first) {
146 FB_WRITEL(comp(val, FB_READL(dst), first), dst);
147 dst++;
148 n -= BITS_PER_LONG-dst_idx;
151 // Main chunk
152 n /= BITS_PER_LONG;
153 while (n >= 8) {
154 FB_WRITEL(val, dst++);
155 FB_WRITEL(val, dst++);
156 FB_WRITEL(val, dst++);
157 FB_WRITEL(val, dst++);
158 FB_WRITEL(val, dst++);
159 FB_WRITEL(val, dst++);
160 FB_WRITEL(val, dst++);
161 FB_WRITEL(val, dst++);
162 n -= 8;
164 while (n--)
165 FB_WRITEL(val, dst++);
167 // Trailing bits
168 if (last)
169 FB_WRITEL(comp(val, FB_READL(dst), first), dst);
175 * Unaligned generic pattern fill using 32/64-bit memory accesses
176 * The pattern must have been expanded to a full 32/64-bit value
177 * Left/right are the appropriate shifts to convert to the pattern to be
178 * used for the next 32/64-bit word
181 void bitfill(unsigned long __iomem *dst, int dst_idx, unsigned long pat, int left,
182 int right, u32 n)
184 unsigned long first, last;
186 if (!n)
187 return;
189 first = ~0UL >> dst_idx;
190 last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
192 if (dst_idx+n <= BITS_PER_LONG) {
193 // Single word
194 if (last)
195 first &= last;
196 FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
197 } else {
198 // Multiple destination words
199 // Leading bits
200 if (first) {
201 FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
202 dst++;
203 pat = pat << left | pat >> right;
204 n -= BITS_PER_LONG-dst_idx;
207 // Main chunk
208 n /= BITS_PER_LONG;
209 while (n >= 4) {
210 FB_WRITEL(pat, dst++);
211 pat = pat << left | pat >> right;
212 FB_WRITEL(pat, dst++);
213 pat = pat << left | pat >> right;
214 FB_WRITEL(pat, dst++);
215 pat = pat << left | pat >> right;
216 FB_WRITEL(pat, dst++);
217 pat = pat << left | pat >> right;
218 n -= 4;
220 while (n--) {
221 FB_WRITEL(pat, dst++);
222 pat = pat << left | pat >> right;
225 // Trailing bits
226 if (last)
227 FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
231 void bitfill32_rev(unsigned long __iomem *dst, int dst_idx, u32 pat, u32 n)
233 unsigned long val = pat, dat;
234 unsigned long first, last;
236 if (!n)
237 return;
239 #if BITS_PER_LONG == 64
240 val |= val << 32;
241 #endif
243 first = ~0UL >> dst_idx;
244 last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
246 if (dst_idx+n <= BITS_PER_LONG) {
247 // Single word
248 if (last)
249 first &= last;
250 dat = FB_READL(dst);
251 FB_WRITEL(comp(dat ^ val, dat, first), dst);
252 } else {
253 // Multiple destination words
254 // Leading bits
255 if (first) {
256 dat = FB_READL(dst);
257 FB_WRITEL(comp(dat ^ val, dat, first), dst);
258 dst++;
259 n -= BITS_PER_LONG-dst_idx;
262 // Main chunk
263 n /= BITS_PER_LONG;
264 while (n >= 8) {
265 FB_WRITEL(FB_READL(dst) ^ val, dst);
266 dst++;
267 FB_WRITEL(FB_READL(dst) ^ val, dst);
268 dst++;
269 FB_WRITEL(FB_READL(dst) ^ val, dst);
270 dst++;
271 FB_WRITEL(FB_READL(dst) ^ val, dst);
272 dst++;
273 FB_WRITEL(FB_READL(dst) ^ val, dst);
274 dst++;
275 FB_WRITEL(FB_READL(dst) ^ val, dst);
276 dst++;
277 FB_WRITEL(FB_READL(dst) ^ val, dst);
278 dst++;
279 FB_WRITEL(FB_READL(dst) ^ val, dst);
280 dst++;
281 n -= 8;
283 while (n--) {
284 FB_WRITEL(FB_READL(dst) ^ val, dst);
285 dst++;
287 // Trailing bits
288 if (last) {
289 dat = FB_READL(dst);
290 FB_WRITEL(comp(dat ^ val, dat, first), dst);
297 * Unaligned generic pattern fill using 32/64-bit memory accesses
298 * The pattern must have been expanded to a full 32/64-bit value
299 * Left/right are the appropriate shifts to convert to the pattern to be
300 * used for the next 32/64-bit word
303 void bitfill_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat, int left,
304 int right, u32 n)
306 unsigned long first, last, dat;
308 if (!n)
309 return;
311 first = ~0UL >> dst_idx;
312 last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
314 if (dst_idx+n <= BITS_PER_LONG) {
315 // Single word
316 if (last)
317 first &= last;
318 dat = FB_READL(dst);
319 FB_WRITEL(comp(dat ^ pat, dat, first), dst);
320 } else {
321 // Multiple destination words
322 // Leading bits
323 if (first) {
324 dat = FB_READL(dst);
325 FB_WRITEL(comp(dat ^ pat, dat, first), dst);
326 dst++;
327 pat = pat << left | pat >> right;
328 n -= BITS_PER_LONG-dst_idx;
331 // Main chunk
332 n /= BITS_PER_LONG;
333 while (n >= 4) {
334 FB_WRITEL(FB_READL(dst) ^ pat, dst);
335 dst++;
336 pat = pat << left | pat >> right;
337 FB_WRITEL(FB_READL(dst) ^ pat, dst);
338 dst++;
339 pat = pat << left | pat >> right;
340 FB_WRITEL(FB_READL(dst) ^ pat, dst);
341 dst++;
342 pat = pat << left | pat >> right;
343 FB_WRITEL(FB_READL(dst) ^ pat, dst);
344 dst++;
345 pat = pat << left | pat >> right;
346 n -= 4;
348 while (n--) {
349 FB_WRITEL(FB_READL(dst) ^ pat, dst);
350 dst++;
351 pat = pat << left | pat >> right;
354 // Trailing bits
355 if (last) {
356 dat = FB_READL(dst);
357 FB_WRITEL(comp(dat ^ pat, dat, first), dst);
362 void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
364 u32 bpp = p->var.bits_per_pixel;
365 unsigned long x2, y2, vxres, vyres;
366 unsigned long height, width, fg;
367 unsigned long __iomem *dst;
368 int dst_idx, left;
370 if (p->state != FBINFO_STATE_RUNNING)
371 return;
373 /* We want rotation but lack hardware to do it for us. */
374 if (!p->fbops->fb_rotate && p->var.rotate) {
377 vxres = p->var.xres_virtual;
378 vyres = p->var.yres_virtual;
380 if (!rect->width || !rect->height ||
381 rect->dx > vxres || rect->dy > vyres)
382 return;
384 /* We could use hardware clipping but on many cards you get around
385 * hardware clipping by writing to framebuffer directly. */
387 x2 = rect->dx + rect->width;
388 y2 = rect->dy + rect->height;
389 x2 = x2 < vxres ? x2 : vxres;
390 y2 = y2 < vyres ? y2 : vyres;
391 width = x2 - rect->dx;
392 height = y2 - rect->dy;
394 if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
395 p->fix.visual == FB_VISUAL_DIRECTCOLOR )
396 fg = ((u32 *) (p->pseudo_palette))[rect->color];
397 else
398 fg = rect->color;
400 dst = (unsigned long __iomem *)((unsigned long)p->screen_base &
401 ~(BYTES_PER_LONG-1));
402 dst_idx = ((unsigned long)p->screen_base & (BYTES_PER_LONG-1))*8;
403 dst_idx += rect->dy*p->fix.line_length*8+rect->dx*bpp;
404 /* FIXME For now we support 1-32 bpp only */
405 left = BITS_PER_LONG % bpp;
406 if (p->fbops->fb_sync)
407 p->fbops->fb_sync(p);
408 if (!left) {
409 u32 pat = pixel_to_pat32(p, fg);
410 void (*fill_op32)(unsigned long __iomem *dst, int dst_idx, u32 pat,
411 u32 n) = NULL;
413 switch (rect->rop) {
414 case ROP_XOR:
415 fill_op32 = bitfill32_rev;
416 break;
417 case ROP_COPY:
418 default:
419 fill_op32 = bitfill32;
420 break;
422 while (height--) {
423 dst += dst_idx >> SHIFT_PER_LONG;
424 dst_idx &= (BITS_PER_LONG-1);
425 fill_op32(dst, dst_idx, pat, width*bpp);
426 dst_idx += p->fix.line_length*8;
428 } else {
429 unsigned long pat = pixel_to_pat(p, fg, (left-dst_idx) % bpp);
430 int right = bpp-left;
431 int r;
432 void (*fill_op)(unsigned long __iomem *dst, int dst_idx,
433 unsigned long pat, int left, int right,
434 u32 n) = NULL;
436 switch (rect->rop) {
437 case ROP_XOR:
438 fill_op = bitfill_rev;
439 break;
440 case ROP_COPY:
441 default:
442 fill_op = bitfill;
443 break;
445 while (height--) {
446 dst += dst_idx >> SHIFT_PER_LONG;
447 dst_idx &= (BITS_PER_LONG-1);
448 fill_op(dst, dst_idx, pat, left, right,
449 width*bpp);
450 r = (p->fix.line_length*8) % bpp;
451 pat = pat << (bpp-r) | pat >> r;
452 dst_idx += p->fix.line_length*8;
457 EXPORT_SYMBOL(cfb_fillrect);
459 MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
460 MODULE_DESCRIPTION("Generic software accelerated fill rectangle");
461 MODULE_LICENSE("GPL");