blob: ba9f58b2a5e86e65a29aa3cabc67d45087b933b9 [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 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070012 * Also need to add code to deal with cards endians that are different than
13 * the native cpu endians. I also need to deal with MSB position in the word.
14 *
15 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070016#include <linux/module.h>
17#include <linux/string.h>
18#include <linux/fb.h>
19#include <asm/types.h>
Antonino A. Daplasdc0e6e02007-05-08 00:39:08 -070020#include "fb_draw.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070021
22#if BITS_PER_LONG == 32
23# define FB_WRITEL fb_writel
24# define FB_READL fb_readl
25#else
26# define FB_WRITEL fb_writeq
27# define FB_READL fb_readq
28#endif
29
30 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -070031 * Aligned pattern fill using 32/64-bit memory accesses
32 */
33
34static void
Anton Vorontsove4c690e2008-04-28 02:14:49 -070035bitfill_aligned(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
36 unsigned long pat, unsigned n, int bits, u32 bswapmask)
Linus Torvalds1da177e2005-04-16 15:20:36 -070037{
38 unsigned long first, last;
39
40 if (!n)
41 return;
42
Anton Vorontsove4c690e2008-04-28 02:14:49 -070043 first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask);
44 last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask);
Linus Torvalds1da177e2005-04-16 15:20:36 -070045
46 if (dst_idx+n <= bits) {
47 // Single word
48 if (last)
49 first &= last;
50 FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
51 } else {
52 // Multiple destination words
53
54 // Leading bits
55 if (first!= ~0UL) {
56 FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
57 dst++;
58 n -= bits - dst_idx;
59 }
60
61 // Main chunk
62 n /= bits;
63 while (n >= 8) {
64 FB_WRITEL(pat, dst++);
65 FB_WRITEL(pat, dst++);
66 FB_WRITEL(pat, dst++);
67 FB_WRITEL(pat, dst++);
68 FB_WRITEL(pat, dst++);
69 FB_WRITEL(pat, dst++);
70 FB_WRITEL(pat, dst++);
71 FB_WRITEL(pat, dst++);
72 n -= 8;
73 }
74 while (n--)
75 FB_WRITEL(pat, dst++);
76
77 // Trailing bits
78 if (last)
79 FB_WRITEL(comp(pat, FB_READL(dst), last), dst);
80 }
81}
82
83
84 /*
85 * Unaligned generic pattern fill using 32/64-bit memory accesses
86 * The pattern must have been expanded to a full 32/64-bit value
87 * Left/right are the appropriate shifts to convert to the pattern to be
88 * used for the next 32/64-bit word
89 */
90
91static void
Anton Vorontsove4c690e2008-04-28 02:14:49 -070092bitfill_unaligned(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
93 unsigned long pat, int left, int right, unsigned n, int bits)
Linus Torvalds1da177e2005-04-16 15:20:36 -070094{
95 unsigned long first, last;
96
97 if (!n)
98 return;
99
Anton Vorontsove4c690e2008-04-28 02:14:49 -0700100 first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
101 last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102
103 if (dst_idx+n <= bits) {
104 // Single word
105 if (last)
106 first &= last;
107 FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
108 } else {
109 // Multiple destination words
110 // Leading bits
111 if (first) {
112 FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
113 dst++;
114 pat = pat << left | pat >> right;
115 n -= bits - dst_idx;
116 }
117
118 // Main chunk
119 n /= bits;
120 while (n >= 4) {
121 FB_WRITEL(pat, dst++);
122 pat = pat << left | pat >> right;
123 FB_WRITEL(pat, dst++);
124 pat = pat << left | pat >> right;
125 FB_WRITEL(pat, dst++);
126 pat = pat << left | pat >> right;
127 FB_WRITEL(pat, dst++);
128 pat = pat << left | pat >> right;
129 n -= 4;
130 }
131 while (n--) {
132 FB_WRITEL(pat, dst++);
133 pat = pat << left | pat >> right;
134 }
135
136 // Trailing bits
137 if (last)
Michal Januszewskibdca0f92009-05-06 16:02:56 -0700138 FB_WRITEL(comp(pat, FB_READL(dst), last), dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139 }
140}
141
142 /*
143 * Aligned pattern invert using 32/64-bit memory accesses
144 */
145static void
Anton Vorontsove4c690e2008-04-28 02:14:49 -0700146bitfill_aligned_rev(struct fb_info *p, unsigned long __iomem *dst,
147 int dst_idx, unsigned long pat, unsigned n, int bits,
148 u32 bswapmask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149{
150 unsigned long val = pat, dat;
151 unsigned long first, last;
152
153 if (!n)
154 return;
155
Anton Vorontsove4c690e2008-04-28 02:14:49 -0700156 first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask);
157 last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158
159 if (dst_idx+n <= bits) {
160 // Single word
161 if (last)
162 first &= last;
163 dat = FB_READL(dst);
164 FB_WRITEL(comp(dat ^ val, dat, first), dst);
165 } else {
166 // Multiple destination words
167 // Leading bits
168 if (first!=0UL) {
169 dat = FB_READL(dst);
170 FB_WRITEL(comp(dat ^ val, dat, first), dst);
171 dst++;
172 n -= bits - dst_idx;
173 }
174
175 // Main chunk
176 n /= bits;
177 while (n >= 8) {
178 FB_WRITEL(FB_READL(dst) ^ val, dst);
179 dst++;
180 FB_WRITEL(FB_READL(dst) ^ val, dst);
181 dst++;
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 n -= 8;
195 }
196 while (n--) {
197 FB_WRITEL(FB_READL(dst) ^ val, dst);
198 dst++;
199 }
200 // Trailing bits
201 if (last) {
202 dat = FB_READL(dst);
203 FB_WRITEL(comp(dat ^ val, dat, last), dst);
204 }
205 }
206}
207
208
209 /*
210 * Unaligned generic pattern invert using 32/64-bit memory accesses
211 * The pattern must have been expanded to a full 32/64-bit value
212 * Left/right are the appropriate shifts to convert to the pattern to be
213 * used for the next 32/64-bit word
214 */
215
216static void
Anton Vorontsove4c690e2008-04-28 02:14:49 -0700217bitfill_unaligned_rev(struct fb_info *p, unsigned long __iomem *dst,
218 int dst_idx, unsigned long pat, int left, int right,
219 unsigned n, int bits)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220{
221 unsigned long first, last, dat;
222
223 if (!n)
224 return;
225
Anton Vorontsove4c690e2008-04-28 02:14:49 -0700226 first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
227 last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228
229 if (dst_idx+n <= bits) {
230 // Single word
231 if (last)
232 first &= last;
233 dat = FB_READL(dst);
234 FB_WRITEL(comp(dat ^ pat, dat, first), dst);
235 } else {
236 // Multiple destination words
237
238 // Leading bits
239 if (first != 0UL) {
240 dat = FB_READL(dst);
241 FB_WRITEL(comp(dat ^ pat, dat, first), dst);
242 dst++;
243 pat = pat << left | pat >> right;
244 n -= bits - dst_idx;
245 }
246
247 // Main chunk
248 n /= bits;
249 while (n >= 4) {
250 FB_WRITEL(FB_READL(dst) ^ pat, dst);
251 dst++;
252 pat = pat << left | pat >> right;
253 FB_WRITEL(FB_READL(dst) ^ pat, dst);
254 dst++;
255 pat = pat << left | pat >> right;
256 FB_WRITEL(FB_READL(dst) ^ pat, dst);
257 dst++;
258 pat = pat << left | pat >> right;
259 FB_WRITEL(FB_READL(dst) ^ pat, dst);
260 dst++;
261 pat = pat << left | pat >> right;
262 n -= 4;
263 }
264 while (n--) {
265 FB_WRITEL(FB_READL(dst) ^ pat, dst);
266 dst++;
267 pat = pat << left | pat >> right;
268 }
269
270 // Trailing bits
271 if (last) {
272 dat = FB_READL(dst);
273 FB_WRITEL(comp(dat ^ pat, dat, last), dst);
274 }
275 }
276}
277
278void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
279{
Michal Januszewskibdca0f92009-05-06 16:02:56 -0700280 unsigned long pat, pat2, fg;
Antonino A. Daplasb4d8aea2005-11-07 01:00:39 -0800281 unsigned long width = rect->width, height = rect->height;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 int bits = BITS_PER_LONG, bytes = bits >> 3;
283 u32 bpp = p->var.bits_per_pixel;
284 unsigned long __iomem *dst;
285 int dst_idx, left;
286
287 if (p->state != FBINFO_STATE_RUNNING)
288 return;
289
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290 if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
291 p->fix.visual == FB_VISUAL_DIRECTCOLOR )
292 fg = ((u32 *) (p->pseudo_palette))[rect->color];
293 else
294 fg = rect->color;
295
Michal Januszewskibdca0f92009-05-06 16:02:56 -0700296 pat = pixel_to_pat(bpp, fg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297
298 dst = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1));
299 dst_idx = ((unsigned long)p->screen_base & (bytes - 1))*8;
300 dst_idx += rect->dy*p->fix.line_length*8+rect->dx*bpp;
301 /* FIXME For now we support 1-32 bpp only */
302 left = bits % bpp;
303 if (p->fbops->fb_sync)
304 p->fbops->fb_sync(p);
305 if (!left) {
Pavel Pisa779121e2007-10-16 01:29:21 -0700306 u32 bswapmask = fb_compute_bswapmask(p);
Anton Vorontsove4c690e2008-04-28 02:14:49 -0700307 void (*fill_op32)(struct fb_info *p,
308 unsigned long __iomem *dst, int dst_idx,
Pavel Pisa779121e2007-10-16 01:29:21 -0700309 unsigned long pat, unsigned n, int bits,
310 u32 bswapmask) = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311
312 switch (rect->rop) {
313 case ROP_XOR:
314 fill_op32 = bitfill_aligned_rev;
315 break;
316 case ROP_COPY:
317 fill_op32 = bitfill_aligned;
318 break;
319 default:
320 printk( KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n");
321 fill_op32 = bitfill_aligned;
322 break;
323 }
324 while (height--) {
325 dst += dst_idx >> (ffs(bits) - 1);
326 dst_idx &= (bits - 1);
Anton Vorontsove4c690e2008-04-28 02:14:49 -0700327 fill_op32(p, dst, dst_idx, pat, width*bpp, bits,
328 bswapmask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 dst_idx += p->fix.line_length*8;
330 }
331 } else {
Michal Januszewskibdca0f92009-05-06 16:02:56 -0700332 int right, r;
Anton Vorontsove4c690e2008-04-28 02:14:49 -0700333 void (*fill_op)(struct fb_info *p, unsigned long __iomem *dst,
334 int dst_idx, unsigned long pat, int left,
335 int right, unsigned n, int bits) = NULL;
Michal Januszewskibdca0f92009-05-06 16:02:56 -0700336#ifdef __LITTLE_ENDIAN
337 right = left;
338 left = bpp - right;
339#else
340 right = bpp - left;
341#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 switch (rect->rop) {
343 case ROP_XOR:
344 fill_op = bitfill_unaligned_rev;
345 break;
346 case ROP_COPY:
347 fill_op = bitfill_unaligned;
348 break;
349 default:
Michal Januszewskibdca0f92009-05-06 16:02:56 -0700350 printk(KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 fill_op = bitfill_unaligned;
352 break;
353 }
354 while (height--) {
Michal Januszewskibdca0f92009-05-06 16:02:56 -0700355 dst += dst_idx / bits;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 dst_idx &= (bits - 1);
Michal Januszewskibdca0f92009-05-06 16:02:56 -0700357 r = dst_idx % bpp;
358 /* rotate pattern to the correct start position */
359 pat2 = le_long_to_cpu(rolx(cpu_to_le_long(pat), r, bpp));
360 fill_op(p, dst, dst_idx, pat2, left, right,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 width*bpp, bits);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 dst_idx += p->fix.line_length*8;
363 }
364 }
365}
366
367EXPORT_SYMBOL(cfb_fillrect);
368
369MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
370MODULE_DESCRIPTION("Generic software accelerated fill rectangle");
371MODULE_LICENSE("GPL");