Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
cfbfillrect.c
Go to the documentation of this file.
1 /*
2  * Generic fillrect for frame buffers with packed pixels of any depth.
3  *
4  * Copyright (C) 2000 James Simmons ([email protected])
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 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  unsigned long first, last;
39 
40  if (!n)
41  return;
42 
43  first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask);
44  last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask);
45 
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 
91 static void
92 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  unsigned long first, last;
96 
97  if (!n)
98  return;
99 
100  first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
101  last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
102 
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)
138  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 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  unsigned long val = pat, dat;
151  unsigned long first, last;
152 
153  if (!n)
154  return;
155 
156  first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask);
157  last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask);
158 
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 
216 static void
217 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  unsigned long first, last, dat;
222 
223  if (!n)
224  return;
225 
226  first = FB_SHIFT_HIGH(p, ~0UL, dst_idx);
227  last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits));
228 
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 
278 void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
279 {
280  unsigned long pat, pat2, fg;
281  unsigned long width = rect->width, height = rect->height;
282  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 
290  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  u32 bswapmask = fb_compute_bswapmask(p);
307  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  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);
327  fill_op32(p, dst, dst_idx, pat, width*bpp, bits,
328  bswapmask);
329  dst_idx += p->fix.line_length*8;
330  }
331  } else {
332  int right, r;
333  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  right = left;
338  left = bpp - right;
339 #else
340  right = bpp - left;
341 #endif
342  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:
350  printk(KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n");
351  fill_op = bitfill_unaligned;
352  break;
353  }
354  while (height--) {
355  dst += dst_idx / bits;
356  dst_idx &= (bits - 1);
357  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,
361  width*bpp, bits);
362  dst_idx += p->fix.line_length*8;
363  }
364  }
365 }
366 
368 
369 MODULE_AUTHOR("James Simmons <[email protected]>");
370 MODULE_DESCRIPTION("Generic software accelerated fill rectangle");
371 MODULE_LICENSE("GPL");