blob: 64b35766b2a26bf28ccb1cfb55990c159008ca45 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Generic fillrect for frame buffers with packed pixels of any depth.
3 *
4 * Copyright (C) 2000 James Simmons (jsimmons@linux-fbdev.org)
5 *
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.
9 *
10 * NOTES:
11 *
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.
15 *
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.
18 *
19 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070020#include <linux/module.h>
21#include <linux/string.h>
22#include <linux/fb.h>
23#include <asm/types.h>
Antonino A. Daplasdc0e6e02007-05-08 00:39:08 -070024#include "fb_draw.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070025
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
33
34 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -070035 * Aligned pattern fill using 32/64-bit memory accesses
36 */
37
38static void
Anton Vorontsove4c690e2008-04-28 02:14:49 -070039bitfill_aligned(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
40 unsigned long pat, unsigned n, int bits, u32 bswapmask)
Linus Torvalds1da177e2005-04-16 15:20:36 -070041{
42 unsigned long first, last;
43
44 if (!n)
45 return;
46
Anton Vorontsove4c690e2008-04-28 02:14:49 -070047 first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask);
48 last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask);
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
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
57
58 // Leading bits
59 if (first!= ~0UL) {
60 FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
61 dst++;
62 n -= bits - dst_idx;
63 }
64
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;
77 }
78 while (n--)
79 FB_WRITEL(pat, dst++);
80
81 // Trailing bits
82 if (last)
83 FB_WRITEL(comp(pat, FB_READL(dst), last), dst);
84 }
85}
86
87
88 /*
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
93 */
94
95static void
Anton Vorontsove4c690e2008-04-28 02:14:49 -070096bitfill_unaligned(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
97 unsigned long pat, int left, int right, unsigned n, int bits)
Linus Torvalds1da177e2005-04-16 15:20:36 -070098{
99 unsigned long first, last;
100
101 if (!n)
102 return;
103
Anton Vorontsove4c690e2008-04-28 02:14:49 -0700104 first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
105 last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106
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;
120 }
121
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;
134 }
135 while (n--) {
136 FB_WRITEL(pat, dst++);
137 pat = pat << left | pat >> right;
138 }
139
140 // Trailing bits
141 if (last)
142 FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
143 }
144}
145
146 /*
147 * Aligned pattern invert using 32/64-bit memory accesses
148 */
149static void
Anton Vorontsove4c690e2008-04-28 02:14:49 -0700150bitfill_aligned_rev(struct fb_info *p, unsigned long __iomem *dst,
151 int dst_idx, unsigned long pat, unsigned n, int bits,
152 u32 bswapmask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153{
154 unsigned long val = pat, dat;
155 unsigned long first, last;
156
157 if (!n)
158 return;
159
Anton Vorontsove4c690e2008-04-28 02:14:49 -0700160 first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask);
161 last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162
163 if (dst_idx+n <= bits) {
164 // Single word
165 if (last)
166 first &= last;
167 dat = FB_READL(dst);
168 FB_WRITEL(comp(dat ^ val, dat, first), dst);
169 } else {
170 // Multiple destination words
171 // Leading bits
172 if (first!=0UL) {
173 dat = FB_READL(dst);
174 FB_WRITEL(comp(dat ^ val, dat, first), dst);
175 dst++;
176 n -= bits - dst_idx;
177 }
178
179 // Main chunk
180 n /= bits;
181 while (n >= 8) {
182 FB_WRITEL(FB_READL(dst) ^ val, dst);
183 dst++;
184 FB_WRITEL(FB_READL(dst) ^ val, dst);
185 dst++;
186 FB_WRITEL(FB_READL(dst) ^ val, dst);
187 dst++;
188 FB_WRITEL(FB_READL(dst) ^ val, dst);
189 dst++;
190 FB_WRITEL(FB_READL(dst) ^ val, dst);
191 dst++;
192 FB_WRITEL(FB_READL(dst) ^ val, dst);
193 dst++;
194 FB_WRITEL(FB_READL(dst) ^ val, dst);
195 dst++;
196 FB_WRITEL(FB_READL(dst) ^ val, dst);
197 dst++;
198 n -= 8;
199 }
200 while (n--) {
201 FB_WRITEL(FB_READL(dst) ^ val, dst);
202 dst++;
203 }
204 // Trailing bits
205 if (last) {
206 dat = FB_READL(dst);
207 FB_WRITEL(comp(dat ^ val, dat, last), dst);
208 }
209 }
210}
211
212
213 /*
214 * Unaligned generic pattern invert using 32/64-bit memory accesses
215 * The pattern must have been expanded to a full 32/64-bit value
216 * Left/right are the appropriate shifts to convert to the pattern to be
217 * used for the next 32/64-bit word
218 */
219
220static void
Anton Vorontsove4c690e2008-04-28 02:14:49 -0700221bitfill_unaligned_rev(struct fb_info *p, unsigned long __iomem *dst,
222 int dst_idx, unsigned long pat, int left, int right,
223 unsigned n, int bits)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224{
225 unsigned long first, last, dat;
226
227 if (!n)
228 return;
229
Anton Vorontsove4c690e2008-04-28 02:14:49 -0700230 first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
231 last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232
233 if (dst_idx+n <= bits) {
234 // Single word
235 if (last)
236 first &= last;
237 dat = FB_READL(dst);
238 FB_WRITEL(comp(dat ^ pat, dat, first), dst);
239 } else {
240 // Multiple destination words
241
242 // Leading bits
243 if (first != 0UL) {
244 dat = FB_READL(dst);
245 FB_WRITEL(comp(dat ^ pat, dat, first), dst);
246 dst++;
247 pat = pat << left | pat >> right;
248 n -= bits - dst_idx;
249 }
250
251 // Main chunk
252 n /= bits;
253 while (n >= 4) {
254 FB_WRITEL(FB_READL(dst) ^ pat, dst);
255 dst++;
256 pat = pat << left | pat >> right;
257 FB_WRITEL(FB_READL(dst) ^ pat, dst);
258 dst++;
259 pat = pat << left | pat >> right;
260 FB_WRITEL(FB_READL(dst) ^ pat, dst);
261 dst++;
262 pat = pat << left | pat >> right;
263 FB_WRITEL(FB_READL(dst) ^ pat, dst);
264 dst++;
265 pat = pat << left | pat >> right;
266 n -= 4;
267 }
268 while (n--) {
269 FB_WRITEL(FB_READL(dst) ^ pat, dst);
270 dst++;
271 pat = pat << left | pat >> right;
272 }
273
274 // Trailing bits
275 if (last) {
276 dat = FB_READL(dst);
277 FB_WRITEL(comp(dat ^ pat, dat, last), dst);
278 }
279 }
280}
281
282void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
283{
Antonino A. Daplasb4d8aea2005-11-07 01:00:39 -0800284 unsigned long pat, fg;
285 unsigned long width = rect->width, height = rect->height;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 int bits = BITS_PER_LONG, bytes = bits >> 3;
287 u32 bpp = p->var.bits_per_pixel;
288 unsigned long __iomem *dst;
289 int dst_idx, left;
290
291 if (p->state != FBINFO_STATE_RUNNING)
292 return;
293
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
295 p->fix.visual == FB_VISUAL_DIRECTCOLOR )
296 fg = ((u32 *) (p->pseudo_palette))[rect->color];
297 else
298 fg = rect->color;
299
300 pat = pixel_to_pat( bpp, fg);
301
302 dst = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1));
303 dst_idx = ((unsigned long)p->screen_base & (bytes - 1))*8;
304 dst_idx += rect->dy*p->fix.line_length*8+rect->dx*bpp;
305 /* FIXME For now we support 1-32 bpp only */
306 left = bits % bpp;
307 if (p->fbops->fb_sync)
308 p->fbops->fb_sync(p);
309 if (!left) {
Pavel Pisa779121e2007-10-16 01:29:21 -0700310 u32 bswapmask = fb_compute_bswapmask(p);
Anton Vorontsove4c690e2008-04-28 02:14:49 -0700311 void (*fill_op32)(struct fb_info *p,
312 unsigned long __iomem *dst, int dst_idx,
Pavel Pisa779121e2007-10-16 01:29:21 -0700313 unsigned long pat, unsigned n, int bits,
314 u32 bswapmask) = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315
316 switch (rect->rop) {
317 case ROP_XOR:
318 fill_op32 = bitfill_aligned_rev;
319 break;
320 case ROP_COPY:
321 fill_op32 = bitfill_aligned;
322 break;
323 default:
324 printk( KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n");
325 fill_op32 = bitfill_aligned;
326 break;
327 }
328 while (height--) {
329 dst += dst_idx >> (ffs(bits) - 1);
330 dst_idx &= (bits - 1);
Anton Vorontsove4c690e2008-04-28 02:14:49 -0700331 fill_op32(p, dst, dst_idx, pat, width*bpp, bits,
332 bswapmask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 dst_idx += p->fix.line_length*8;
334 }
335 } else {
336 int right;
337 int r;
338 int rot = (left-dst_idx) % bpp;
Anton Vorontsove4c690e2008-04-28 02:14:49 -0700339 void (*fill_op)(struct fb_info *p, unsigned long __iomem *dst,
340 int dst_idx, unsigned long pat, int left,
341 int right, unsigned n, int bits) = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342
343 /* rotate pattern to correct start position */
344 pat = pat << rot | pat >> (bpp-rot);
345
346 right = bpp-left;
347 switch (rect->rop) {
348 case ROP_XOR:
349 fill_op = bitfill_unaligned_rev;
350 break;
351 case ROP_COPY:
352 fill_op = bitfill_unaligned;
353 break;
354 default:
355 printk( KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n");
356 fill_op = bitfill_unaligned;
357 break;
358 }
359 while (height--) {
360 dst += dst_idx >> (ffs(bits) - 1);
361 dst_idx &= (bits - 1);
Anton Vorontsove4c690e2008-04-28 02:14:49 -0700362 fill_op(p, dst, dst_idx, pat, left, right,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 width*bpp, bits);
364 r = (p->fix.line_length*8) % bpp;
365 pat = pat << (bpp-r) | pat >> r;
366 dst_idx += p->fix.line_length*8;
367 }
368 }
369}
370
371EXPORT_SYMBOL(cfb_fillrect);
372
373MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
374MODULE_DESCRIPTION("Generic software accelerated fill rectangle");
375MODULE_LICENSE("GPL");