Branch data Line data Source code
1 : : /*
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 : : * 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 : : */
16 : : #include <linux/module.h>
17 : : #include <linux/string.h>
18 : : #include <linux/fb.h>
19 : : #include <asm/types.h>
20 : : #include "fb_draw.h"
21 : :
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 : : /*
31 : : * Aligned pattern fill using 32/64-bit memory accesses
32 : : */
33 : :
34 : : static void
35 : 0 : bitfill_aligned(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
36 : : unsigned long pat, unsigned n, int bits, u32 bswapmask)
37 : : {
38 : 0 : unsigned long first, last;
39 : :
40 [ # # ]: 0 : if (!n)
41 : : return;
42 : :
43 [ # # ]: 0 : first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask);
44 : 0 : last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask);
45 : :
46 [ # # ]: 0 : if (dst_idx+n <= bits) {
47 : : // Single word
48 [ # # ]: 0 : if (last)
49 : 0 : first &= last;
50 : 0 : FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
51 : : } else {
52 : : // Multiple destination words
53 : :
54 : : // Leading bits
55 [ # # ]: 0 : if (first!= ~0UL) {
56 : 0 : FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
57 : 0 : dst++;
58 : 0 : n -= bits - dst_idx;
59 : : }
60 : :
61 : : // Main chunk
62 : 0 : n /= bits;
63 [ # # ]: 0 : while (n >= 8) {
64 : 0 : FB_WRITEL(pat, dst++);
65 : 0 : FB_WRITEL(pat, dst++);
66 : 0 : FB_WRITEL(pat, dst++);
67 : 0 : FB_WRITEL(pat, dst++);
68 : 0 : FB_WRITEL(pat, dst++);
69 : 0 : FB_WRITEL(pat, dst++);
70 : 0 : FB_WRITEL(pat, dst++);
71 : 0 : FB_WRITEL(pat, dst++);
72 : 0 : n -= 8;
73 : : }
74 [ # # ]: 0 : while (n--)
75 : 0 : FB_WRITEL(pat, dst++);
76 : :
77 : : // Trailing bits
78 [ # # ]: 0 : if (last)
79 : 0 : 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 : :
91 : : static void
92 : 0 : bitfill_unaligned(struct fb_info *p, unsigned long __iomem *dst, int dst_idx,
93 : : unsigned long pat, int left, int right, unsigned n, int bits)
94 : : {
95 : 0 : unsigned long first, last;
96 : :
97 [ # # ]: 0 : if (!n)
98 : : return;
99 : :
100 [ # # ]: 0 : first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
101 : 0 : last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
102 : :
103 [ # # ]: 0 : if (dst_idx+n <= bits) {
104 : : // Single word
105 [ # # ]: 0 : if (last)
106 : 0 : first &= last;
107 : 0 : FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
108 : : } else {
109 : : // Multiple destination words
110 : : // Leading bits
111 [ # # ]: 0 : if (first) {
112 : 0 : FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
113 : 0 : dst++;
114 : 0 : pat = pat << left | pat >> right;
115 : 0 : n -= bits - dst_idx;
116 : : }
117 : :
118 : : // Main chunk
119 : 0 : n /= bits;
120 [ # # ]: 0 : while (n >= 4) {
121 : 0 : FB_WRITEL(pat, dst++);
122 : 0 : pat = pat << left | pat >> right;
123 : 0 : FB_WRITEL(pat, dst++);
124 : 0 : pat = pat << left | pat >> right;
125 : 0 : FB_WRITEL(pat, dst++);
126 : 0 : pat = pat << left | pat >> right;
127 : 0 : FB_WRITEL(pat, dst++);
128 : 0 : pat = pat << left | pat >> right;
129 : 0 : n -= 4;
130 : : }
131 [ # # ]: 0 : while (n--) {
132 : 0 : FB_WRITEL(pat, dst++);
133 : 0 : pat = pat << left | pat >> right;
134 : : }
135 : :
136 : : // Trailing bits
137 [ # # ]: 0 : if (last)
138 : 0 : FB_WRITEL(comp(pat, FB_READL(dst), last), dst);
139 : : }
140 : : }
141 : :
142 : : /*
143 : : * Aligned pattern invert using 32/64-bit memory accesses
144 : : */
145 : : static void
146 : 0 : bitfill_aligned_rev(struct fb_info *p, unsigned long __iomem *dst,
147 : : int dst_idx, unsigned long pat, unsigned n, int bits,
148 : : u32 bswapmask)
149 : : {
150 : 0 : unsigned long val = pat, dat;
151 : 0 : unsigned long first, last;
152 : :
153 [ # # ]: 0 : if (!n)
154 : : return;
155 : :
156 [ # # ]: 0 : first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask);
157 : 0 : last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask);
158 : :
159 [ # # ]: 0 : if (dst_idx+n <= bits) {
160 : : // Single word
161 [ # # ]: 0 : if (last)
162 : 0 : first &= last;
163 : 0 : dat = FB_READL(dst);
164 : 0 : FB_WRITEL(comp(dat ^ val, dat, first), dst);
165 : : } else {
166 : : // Multiple destination words
167 : : // Leading bits
168 [ # # ]: 0 : if (first!=0UL) {
169 : 0 : dat = FB_READL(dst);
170 : 0 : FB_WRITEL(comp(dat ^ val, dat, first), dst);
171 : 0 : dst++;
172 : 0 : n -= bits - dst_idx;
173 : : }
174 : :
175 : : // Main chunk
176 : 0 : n /= bits;
177 [ # # ]: 0 : while (n >= 8) {
178 : 0 : FB_WRITEL(FB_READL(dst) ^ val, dst);
179 : 0 : dst++;
180 : 0 : FB_WRITEL(FB_READL(dst) ^ val, dst);
181 : 0 : dst++;
182 : 0 : FB_WRITEL(FB_READL(dst) ^ val, dst);
183 : 0 : dst++;
184 : 0 : FB_WRITEL(FB_READL(dst) ^ val, dst);
185 : 0 : dst++;
186 : 0 : FB_WRITEL(FB_READL(dst) ^ val, dst);
187 : 0 : dst++;
188 : 0 : FB_WRITEL(FB_READL(dst) ^ val, dst);
189 : 0 : dst++;
190 : 0 : FB_WRITEL(FB_READL(dst) ^ val, dst);
191 : 0 : dst++;
192 : 0 : FB_WRITEL(FB_READL(dst) ^ val, dst);
193 : 0 : dst++;
194 : 0 : n -= 8;
195 : : }
196 [ # # ]: 0 : while (n--) {
197 : 0 : FB_WRITEL(FB_READL(dst) ^ val, dst);
198 : 0 : dst++;
199 : : }
200 : : // Trailing bits
201 [ # # ]: 0 : if (last) {
202 : 0 : dat = FB_READL(dst);
203 : 0 : 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 : :
216 : : static void
217 : 0 : bitfill_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)
220 : : {
221 : 0 : unsigned long first, last, dat;
222 : :
223 [ # # ]: 0 : if (!n)
224 : : return;
225 : :
226 [ # # ]: 0 : first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
227 : 0 : last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
228 : :
229 [ # # ]: 0 : if (dst_idx+n <= bits) {
230 : : // Single word
231 [ # # ]: 0 : if (last)
232 : 0 : first &= last;
233 : 0 : dat = FB_READL(dst);
234 : 0 : FB_WRITEL(comp(dat ^ pat, dat, first), dst);
235 : : } else {
236 : : // Multiple destination words
237 : :
238 : : // Leading bits
239 [ # # ]: 0 : if (first != 0UL) {
240 : 0 : dat = FB_READL(dst);
241 : 0 : FB_WRITEL(comp(dat ^ pat, dat, first), dst);
242 : 0 : dst++;
243 : 0 : pat = pat << left | pat >> right;
244 : 0 : n -= bits - dst_idx;
245 : : }
246 : :
247 : : // Main chunk
248 : 0 : n /= bits;
249 [ # # ]: 0 : while (n >= 4) {
250 : 0 : FB_WRITEL(FB_READL(dst) ^ pat, dst);
251 : 0 : dst++;
252 : 0 : pat = pat << left | pat >> right;
253 : 0 : FB_WRITEL(FB_READL(dst) ^ pat, dst);
254 : 0 : dst++;
255 : 0 : pat = pat << left | pat >> right;
256 : 0 : FB_WRITEL(FB_READL(dst) ^ pat, dst);
257 : 0 : dst++;
258 : 0 : pat = pat << left | pat >> right;
259 : 0 : FB_WRITEL(FB_READL(dst) ^ pat, dst);
260 : 0 : dst++;
261 : 0 : pat = pat << left | pat >> right;
262 : 0 : n -= 4;
263 : : }
264 [ # # ]: 0 : while (n--) {
265 : 0 : FB_WRITEL(FB_READL(dst) ^ pat, dst);
266 : 0 : dst++;
267 : 0 : pat = pat << left | pat >> right;
268 : : }
269 : :
270 : : // Trailing bits
271 [ # # ]: 0 : if (last) {
272 : 0 : dat = FB_READL(dst);
273 : 0 : FB_WRITEL(comp(dat ^ pat, dat, last), dst);
274 : : }
275 : : }
276 : : }
277 : :
278 : 0 : void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
279 : : {
280 : 0 : unsigned long pat, pat2, fg;
281 : 0 : unsigned long width = rect->width, height = rect->height;
282 : 0 : int bits = BITS_PER_LONG, bytes = bits >> 3;
283 : 0 : u32 bpp = p->var.bits_per_pixel;
284 : 0 : unsigned long __iomem *dst;
285 : 0 : int dst_idx, left;
286 : :
287 [ # # ]: 0 : if (p->state != FBINFO_STATE_RUNNING)
288 : : return;
289 : :
290 [ # # ]: 0 : if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
291 : : p->fix.visual == FB_VISUAL_DIRECTCOLOR )
292 : 0 : fg = ((u32 *) (p->pseudo_palette))[rect->color];
293 : : else
294 : 0 : fg = rect->color;
295 : :
296 : 0 : pat = pixel_to_pat(bpp, fg);
297 : :
298 : 0 : dst = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1));
299 : 0 : dst_idx = ((unsigned long)p->screen_base & (bytes - 1))*8;
300 : 0 : dst_idx += rect->dy*p->fix.line_length*8+rect->dx*bpp;
301 : : /* FIXME For now we support 1-32 bpp only */
302 : 0 : left = bits % bpp;
303 [ # # ]: 0 : if (p->fbops->fb_sync)
304 : 0 : p->fbops->fb_sync(p);
305 [ # # ]: 0 : if (!left) {
306 : 0 : u32 bswapmask = fb_compute_bswapmask(p);
307 : 0 : void (*fill_op32)(struct fb_info *p,
308 : : unsigned long __iomem *dst, int dst_idx,
309 : : unsigned long pat, unsigned n, int bits,
310 : : u32 bswapmask) = NULL;
311 : :
312 [ # # # ]: 0 : switch (rect->rop) {
313 : : case ROP_XOR:
314 : : fill_op32 = bitfill_aligned_rev;
315 : : break;
316 : 0 : case ROP_COPY:
317 : 0 : fill_op32 = bitfill_aligned;
318 : 0 : break;
319 : 0 : default:
320 : 0 : printk( KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n");
321 : 0 : fill_op32 = bitfill_aligned;
322 : 0 : break;
323 : : }
324 [ # # ]: 0 : while (height--) {
325 : 0 : dst += dst_idx >> (ffs(bits) - 1);
326 : 0 : dst_idx &= (bits - 1);
327 : 0 : fill_op32(p, dst, dst_idx, pat, width*bpp, bits,
328 : : bswapmask);
329 : 0 : dst_idx += p->fix.line_length*8;
330 : : }
331 : : } else {
332 : 0 : int right, r;
333 : 0 : 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;
336 : : #ifdef __LITTLE_ENDIAN
337 : 0 : right = left;
338 : 0 : left = bpp - right;
339 : : #else
340 : : right = bpp - left;
341 : : #endif
342 [ # # # ]: 0 : switch (rect->rop) {
343 : : case ROP_XOR:
344 : : fill_op = bitfill_unaligned_rev;
345 : : break;
346 : 0 : case ROP_COPY:
347 : 0 : fill_op = bitfill_unaligned;
348 : 0 : break;
349 : 0 : default:
350 : 0 : printk(KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n");
351 : 0 : fill_op = bitfill_unaligned;
352 : 0 : break;
353 : : }
354 [ # # ]: 0 : while (height--) {
355 : 0 : dst += dst_idx / bits;
356 : 0 : dst_idx &= (bits - 1);
357 : 0 : r = dst_idx % bpp;
358 : : /* rotate pattern to the correct start position */
359 : 0 : pat2 = le_long_to_cpu(rolx(cpu_to_le_long(pat), r, bpp));
360 : 0 : fill_op(p, dst, dst_idx, pat2, left, right,
361 : : width*bpp, bits);
362 : 0 : dst_idx += p->fix.line_length*8;
363 : : }
364 : : }
365 : : }
366 : :
367 : : EXPORT_SYMBOL(cfb_fillrect);
368 : :
369 : : MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
370 : : MODULE_DESCRIPTION("Generic software accelerated fill rectangle");
371 : : MODULE_LICENSE("GPL");
|