blob: 71623b4f8ca26581dbf4f8258734685fbd55e079 [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
39bitfill_aligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat, unsigned n, int bits)
40{
41 unsigned long first, last;
42
43 if (!n)
44 return;
45
Antonino A. Daplasbe0d9b62005-12-12 22:17:21 -080046 first = FB_SHIFT_HIGH(~0UL, dst_idx);
47 last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
Linus Torvalds1da177e2005-04-16 15:20:36 -070048
49 if (dst_idx+n <= bits) {
50 // Single word
51 if (last)
52 first &= last;
53 FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
54 } else {
55 // Multiple destination words
56
57 // Leading bits
58 if (first!= ~0UL) {
59 FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
60 dst++;
61 n -= bits - dst_idx;
62 }
63
64 // Main chunk
65 n /= bits;
66 while (n >= 8) {
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 FB_WRITEL(pat, dst++);
73 FB_WRITEL(pat, dst++);
74 FB_WRITEL(pat, dst++);
75 n -= 8;
76 }
77 while (n--)
78 FB_WRITEL(pat, dst++);
79
80 // Trailing bits
81 if (last)
82 FB_WRITEL(comp(pat, FB_READL(dst), last), dst);
83 }
84}
85
86
87 /*
88 * Unaligned generic pattern fill using 32/64-bit memory accesses
89 * The pattern must have been expanded to a full 32/64-bit value
90 * Left/right are the appropriate shifts to convert to the pattern to be
91 * used for the next 32/64-bit word
92 */
93
94static void
95bitfill_unaligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
96 int left, int right, unsigned n, int bits)
97{
98 unsigned long first, last;
99
100 if (!n)
101 return;
102
Antonino A. Daplasbe0d9b62005-12-12 22:17:21 -0800103 first = FB_SHIFT_HIGH(~0UL, dst_idx);
104 last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105
106 if (dst_idx+n <= bits) {
107 // Single word
108 if (last)
109 first &= last;
110 FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
111 } else {
112 // Multiple destination words
113 // Leading bits
114 if (first) {
115 FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
116 dst++;
117 pat = pat << left | pat >> right;
118 n -= bits - dst_idx;
119 }
120
121 // Main chunk
122 n /= bits;
123 while (n >= 4) {
124 FB_WRITEL(pat, dst++);
125 pat = pat << left | pat >> right;
126 FB_WRITEL(pat, dst++);
127 pat = pat << left | pat >> right;
128 FB_WRITEL(pat, dst++);
129 pat = pat << left | pat >> right;
130 FB_WRITEL(pat, dst++);
131 pat = pat << left | pat >> right;
132 n -= 4;
133 }
134 while (n--) {
135 FB_WRITEL(pat, dst++);
136 pat = pat << left | pat >> right;
137 }
138
139 // Trailing bits
140 if (last)
141 FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
142 }
143}
144
145 /*
146 * Aligned pattern invert using 32/64-bit memory accesses
147 */
148static void
149bitfill_aligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat, unsigned n, int bits)
150{
151 unsigned long val = pat, dat;
152 unsigned long first, last;
153
154 if (!n)
155 return;
156
Antonino A. Daplasbe0d9b62005-12-12 22:17:21 -0800157 first = FB_SHIFT_HIGH(~0UL, dst_idx);
158 last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159
160 if (dst_idx+n <= bits) {
161 // Single word
162 if (last)
163 first &= last;
164 dat = FB_READL(dst);
165 FB_WRITEL(comp(dat ^ val, dat, first), dst);
166 } else {
167 // Multiple destination words
168 // Leading bits
169 if (first!=0UL) {
170 dat = FB_READL(dst);
171 FB_WRITEL(comp(dat ^ val, dat, first), dst);
172 dst++;
173 n -= bits - dst_idx;
174 }
175
176 // Main chunk
177 n /= bits;
178 while (n >= 8) {
179 FB_WRITEL(FB_READL(dst) ^ val, dst);
180 dst++;
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 n -= 8;
196 }
197 while (n--) {
198 FB_WRITEL(FB_READL(dst) ^ val, dst);
199 dst++;
200 }
201 // Trailing bits
202 if (last) {
203 dat = FB_READL(dst);
204 FB_WRITEL(comp(dat ^ val, dat, last), dst);
205 }
206 }
207}
208
209
210 /*
211 * Unaligned generic pattern invert using 32/64-bit memory accesses
212 * The pattern must have been expanded to a full 32/64-bit value
213 * Left/right are the appropriate shifts to convert to the pattern to be
214 * used for the next 32/64-bit word
215 */
216
217static void
218bitfill_unaligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
219 int left, int right, unsigned n, int bits)
220{
221 unsigned long first, last, dat;
222
223 if (!n)
224 return;
225
Antonino A. Daplasbe0d9b62005-12-12 22:17:21 -0800226 first = FB_SHIFT_HIGH(~0UL, dst_idx);
227 last = ~(FB_SHIFT_HIGH(~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{
Antonino A. Daplasb4d8aea2005-11-07 01:00:39 -0800280 unsigned long pat, fg;
281 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
296 pat = pixel_to_pat( bpp, fg);
297
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) {
306 void (*fill_op32)(unsigned long __iomem *dst, int dst_idx,
307 unsigned long pat, unsigned n, int bits) = NULL;
308
309 switch (rect->rop) {
310 case ROP_XOR:
311 fill_op32 = bitfill_aligned_rev;
312 break;
313 case ROP_COPY:
314 fill_op32 = bitfill_aligned;
315 break;
316 default:
317 printk( KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n");
318 fill_op32 = bitfill_aligned;
319 break;
320 }
321 while (height--) {
322 dst += dst_idx >> (ffs(bits) - 1);
323 dst_idx &= (bits - 1);
324 fill_op32(dst, dst_idx, pat, width*bpp, bits);
325 dst_idx += p->fix.line_length*8;
326 }
327 } else {
328 int right;
329 int r;
330 int rot = (left-dst_idx) % bpp;
331 void (*fill_op)(unsigned long __iomem *dst, int dst_idx,
332 unsigned long pat, int left, int right,
333 unsigned n, int bits) = NULL;
334
335 /* rotate pattern to correct start position */
336 pat = pat << rot | pat >> (bpp-rot);
337
338 right = bpp-left;
339 switch (rect->rop) {
340 case ROP_XOR:
341 fill_op = bitfill_unaligned_rev;
342 break;
343 case ROP_COPY:
344 fill_op = bitfill_unaligned;
345 break;
346 default:
347 printk( KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n");
348 fill_op = bitfill_unaligned;
349 break;
350 }
351 while (height--) {
352 dst += dst_idx >> (ffs(bits) - 1);
353 dst_idx &= (bits - 1);
354 fill_op(dst, dst_idx, pat, left, right,
355 width*bpp, bits);
356 r = (p->fix.line_length*8) % bpp;
357 pat = pat << (bpp-r) | pat >> r;
358 dst_idx += p->fix.line_length*8;
359 }
360 }
361}
362
363EXPORT_SYMBOL(cfb_fillrect);
364
365MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
366MODULE_DESCRIPTION("Generic software accelerated fill rectangle");
367MODULE_LICENSE("GPL");