pcmcia: CompactFlash driver for PA Semi Electra boards
[pv_ops_mirror.git] / drivers / video / cfbfillrect.c
blob23d70a12e4daa273bbb16280d3c8f26c682901f2
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/module.h>
21 #include <linux/string.h>
22 #include <linux/fb.h>
23 #include <asm/types.h>
24 #include "fb_draw.h"
26 #if BITS_PER_LONG == 32
27 # define FB_WRITEL fb_writel
28 # define FB_READL fb_readl
29 #else
30 # define FB_WRITEL fb_writeq
31 # define FB_READL fb_readq
32 #endif
35 * Aligned pattern fill using 32/64-bit memory accesses
38 static void
39 bitfill_aligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
40 unsigned n, int bits, u32 bswapmask)
42 unsigned long first, last;
44 if (!n)
45 return;
47 first = fb_shifted_pixels_mask_long(dst_idx, bswapmask);
48 last = ~fb_shifted_pixels_mask_long((dst_idx+n) % bits, bswapmask);
50 if (dst_idx+n <= bits) {
51 // Single word
52 if (last)
53 first &= last;
54 FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
55 } else {
56 // Multiple destination words
58 // Leading bits
59 if (first!= ~0UL) {
60 FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
61 dst++;
62 n -= bits - dst_idx;
65 // Main chunk
66 n /= bits;
67 while (n >= 8) {
68 FB_WRITEL(pat, dst++);
69 FB_WRITEL(pat, dst++);
70 FB_WRITEL(pat, dst++);
71 FB_WRITEL(pat, dst++);
72 FB_WRITEL(pat, dst++);
73 FB_WRITEL(pat, dst++);
74 FB_WRITEL(pat, dst++);
75 FB_WRITEL(pat, dst++);
76 n -= 8;
78 while (n--)
79 FB_WRITEL(pat, dst++);
81 // Trailing bits
82 if (last)
83 FB_WRITEL(comp(pat, FB_READL(dst), last), dst);
89 * Unaligned generic pattern fill using 32/64-bit memory accesses
90 * The pattern must have been expanded to a full 32/64-bit value
91 * Left/right are the appropriate shifts to convert to the pattern to be
92 * used for the next 32/64-bit word
95 static void
96 bitfill_unaligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
97 int left, int right, unsigned n, int bits)
99 unsigned long first, last;
101 if (!n)
102 return;
104 first = FB_SHIFT_HIGH(~0UL, dst_idx);
105 last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
107 if (dst_idx+n <= bits) {
108 // Single word
109 if (last)
110 first &= last;
111 FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
112 } else {
113 // Multiple destination words
114 // Leading bits
115 if (first) {
116 FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
117 dst++;
118 pat = pat << left | pat >> right;
119 n -= bits - dst_idx;
122 // Main chunk
123 n /= bits;
124 while (n >= 4) {
125 FB_WRITEL(pat, dst++);
126 pat = pat << left | pat >> right;
127 FB_WRITEL(pat, dst++);
128 pat = pat << left | pat >> right;
129 FB_WRITEL(pat, dst++);
130 pat = pat << left | pat >> right;
131 FB_WRITEL(pat, dst++);
132 pat = pat << left | pat >> right;
133 n -= 4;
135 while (n--) {
136 FB_WRITEL(pat, dst++);
137 pat = pat << left | pat >> right;
140 // Trailing bits
141 if (last)
142 FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
147 * Aligned pattern invert using 32/64-bit memory accesses
149 static void
150 bitfill_aligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
151 unsigned n, int bits, u32 bswapmask)
153 unsigned long val = pat, dat;
154 unsigned long first, last;
156 if (!n)
157 return;
159 first = fb_shifted_pixels_mask_long(dst_idx, bswapmask);
160 last = ~fb_shifted_pixels_mask_long((dst_idx+n) % bits, bswapmask);
162 if (dst_idx+n <= bits) {
163 // Single word
164 if (last)
165 first &= last;
166 dat = FB_READL(dst);
167 FB_WRITEL(comp(dat ^ val, dat, first), dst);
168 } else {
169 // Multiple destination words
170 // Leading bits
171 if (first!=0UL) {
172 dat = FB_READL(dst);
173 FB_WRITEL(comp(dat ^ val, dat, first), dst);
174 dst++;
175 n -= bits - dst_idx;
178 // Main chunk
179 n /= bits;
180 while (n >= 8) {
181 FB_WRITEL(FB_READL(dst) ^ val, dst);
182 dst++;
183 FB_WRITEL(FB_READL(dst) ^ val, dst);
184 dst++;
185 FB_WRITEL(FB_READL(dst) ^ val, dst);
186 dst++;
187 FB_WRITEL(FB_READL(dst) ^ val, dst);
188 dst++;
189 FB_WRITEL(FB_READL(dst) ^ val, dst);
190 dst++;
191 FB_WRITEL(FB_READL(dst) ^ val, dst);
192 dst++;
193 FB_WRITEL(FB_READL(dst) ^ val, dst);
194 dst++;
195 FB_WRITEL(FB_READL(dst) ^ val, dst);
196 dst++;
197 n -= 8;
199 while (n--) {
200 FB_WRITEL(FB_READL(dst) ^ val, dst);
201 dst++;
203 // Trailing bits
204 if (last) {
205 dat = FB_READL(dst);
206 FB_WRITEL(comp(dat ^ val, dat, last), dst);
213 * Unaligned generic pattern invert using 32/64-bit memory accesses
214 * The pattern must have been expanded to a full 32/64-bit value
215 * Left/right are the appropriate shifts to convert to the pattern to be
216 * used for the next 32/64-bit word
219 static void
220 bitfill_unaligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
221 int left, int right, unsigned n, int bits)
223 unsigned long first, last, dat;
225 if (!n)
226 return;
228 first = FB_SHIFT_HIGH(~0UL, dst_idx);
229 last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
231 if (dst_idx+n <= bits) {
232 // Single word
233 if (last)
234 first &= last;
235 dat = FB_READL(dst);
236 FB_WRITEL(comp(dat ^ pat, dat, first), dst);
237 } else {
238 // Multiple destination words
240 // Leading bits
241 if (first != 0UL) {
242 dat = FB_READL(dst);
243 FB_WRITEL(comp(dat ^ pat, dat, first), dst);
244 dst++;
245 pat = pat << left | pat >> right;
246 n -= bits - dst_idx;
249 // Main chunk
250 n /= bits;
251 while (n >= 4) {
252 FB_WRITEL(FB_READL(dst) ^ pat, dst);
253 dst++;
254 pat = pat << left | pat >> right;
255 FB_WRITEL(FB_READL(dst) ^ pat, dst);
256 dst++;
257 pat = pat << left | pat >> right;
258 FB_WRITEL(FB_READL(dst) ^ pat, dst);
259 dst++;
260 pat = pat << left | pat >> right;
261 FB_WRITEL(FB_READL(dst) ^ pat, dst);
262 dst++;
263 pat = pat << left | pat >> right;
264 n -= 4;
266 while (n--) {
267 FB_WRITEL(FB_READL(dst) ^ pat, dst);
268 dst++;
269 pat = pat << left | pat >> right;
272 // Trailing bits
273 if (last) {
274 dat = FB_READL(dst);
275 FB_WRITEL(comp(dat ^ pat, dat, last), dst);
280 void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
282 unsigned long pat, fg;
283 unsigned long width = rect->width, height = rect->height;
284 int bits = BITS_PER_LONG, bytes = bits >> 3;
285 u32 bpp = p->var.bits_per_pixel;
286 unsigned long __iomem *dst;
287 int dst_idx, left;
289 if (p->state != FBINFO_STATE_RUNNING)
290 return;
292 if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
293 p->fix.visual == FB_VISUAL_DIRECTCOLOR )
294 fg = ((u32 *) (p->pseudo_palette))[rect->color];
295 else
296 fg = rect->color;
298 pat = pixel_to_pat( bpp, fg);
300 dst = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1));
301 dst_idx = ((unsigned long)p->screen_base & (bytes - 1))*8;
302 dst_idx += rect->dy*p->fix.line_length*8+rect->dx*bpp;
303 /* FIXME For now we support 1-32 bpp only */
304 left = bits % bpp;
305 if (p->fbops->fb_sync)
306 p->fbops->fb_sync(p);
307 if (!left) {
308 u32 bswapmask = fb_compute_bswapmask(p);
309 void (*fill_op32)(unsigned long __iomem *dst, int dst_idx,
310 unsigned long pat, unsigned n, int bits,
311 u32 bswapmask) = NULL;
313 switch (rect->rop) {
314 case ROP_XOR:
315 fill_op32 = bitfill_aligned_rev;
316 break;
317 case ROP_COPY:
318 fill_op32 = bitfill_aligned;
319 break;
320 default:
321 printk( KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n");
322 fill_op32 = bitfill_aligned;
323 break;
325 while (height--) {
326 dst += dst_idx >> (ffs(bits) - 1);
327 dst_idx &= (bits - 1);
328 fill_op32(dst, dst_idx, pat, width*bpp, bits, bswapmask);
329 dst_idx += p->fix.line_length*8;
331 } else {
332 int right;
333 int r;
334 int rot = (left-dst_idx) % bpp;
335 void (*fill_op)(unsigned long __iomem *dst, int dst_idx,
336 unsigned long pat, int left, int right,
337 unsigned n, int bits) = NULL;
339 /* rotate pattern to correct start position */
340 pat = pat << rot | pat >> (bpp-rot);
342 right = bpp-left;
343 switch (rect->rop) {
344 case ROP_XOR:
345 fill_op = bitfill_unaligned_rev;
346 break;
347 case ROP_COPY:
348 fill_op = bitfill_unaligned;
349 break;
350 default:
351 printk( KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n");
352 fill_op = bitfill_unaligned;
353 break;
355 while (height--) {
356 dst += dst_idx >> (ffs(bits) - 1);
357 dst_idx &= (bits - 1);
358 fill_op(dst, dst_idx, pat, left, right,
359 width*bpp, bits);
360 r = (p->fix.line_length*8) % bpp;
361 pat = pat << (bpp-r) | pat >> r;
362 dst_idx += p->fix.line_length*8;
367 EXPORT_SYMBOL(cfb_fillrect);
369 MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
370 MODULE_DESCRIPTION("Generic software accelerated fill rectangle");
371 MODULE_LICENSE("GPL");