diff options
Diffstat (limited to 'drivers/video/cfbimgblt.c')
-rw-r--r-- | drivers/video/cfbimgblt.c | 339 |
1 files changed, 339 insertions, 0 deletions
diff --git a/drivers/video/cfbimgblt.c b/drivers/video/cfbimgblt.c new file mode 100644 index 000000000000..4c123abaa843 --- /dev/null +++ b/drivers/video/cfbimgblt.c | |||
@@ -0,0 +1,339 @@ | |||
1 | /* | ||
2 | * Generic BitBLT function for frame buffer with packed pixels of any depth. | ||
3 | * | ||
4 | * Copyright (C) June 1999 James Simmons | ||
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 | * This function copys a image from system memory to video memory. The | ||
13 | * image can be a bitmap where each 0 represents the background color and | ||
14 | * each 1 represents the foreground color. Great for font handling. It can | ||
15 | * also be a color image. This is determined by image_depth. The color image | ||
16 | * must be laid out exactly in the same format as the framebuffer. Yes I know | ||
17 | * their are cards with hardware that coverts images of various depths to the | ||
18 | * framebuffer depth. But not every card has this. All images must be rounded | ||
19 | * up to the nearest byte. For example a bitmap 12 bits wide must be two | ||
20 | * bytes width. | ||
21 | * | ||
22 | * Tony: | ||
23 | * Incorporate mask tables similar to fbcon-cfb*.c in 2.4 API. This speeds | ||
24 | * up the code significantly. | ||
25 | * | ||
26 | * Code for depths not multiples of BITS_PER_LONG is still kludgy, which is | ||
27 | * still processed a bit at a time. | ||
28 | * | ||
29 | * Also need to add code to deal with cards endians that are different than | ||
30 | * the native cpu endians. I also need to deal with MSB position in the word. | ||
31 | */ | ||
32 | #include <linux/config.h> | ||
33 | #include <linux/module.h> | ||
34 | #include <linux/string.h> | ||
35 | #include <linux/fb.h> | ||
36 | #include <asm/types.h> | ||
37 | |||
38 | #define DEBUG | ||
39 | |||
40 | #ifdef DEBUG | ||
41 | #define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt,__FUNCTION__,## args) | ||
42 | #else | ||
43 | #define DPRINTK(fmt, args...) | ||
44 | #endif | ||
45 | |||
46 | static u32 cfb_tab8[] = { | ||
47 | #if defined(__BIG_ENDIAN) | ||
48 | 0x00000000,0x000000ff,0x0000ff00,0x0000ffff, | ||
49 | 0x00ff0000,0x00ff00ff,0x00ffff00,0x00ffffff, | ||
50 | 0xff000000,0xff0000ff,0xff00ff00,0xff00ffff, | ||
51 | 0xffff0000,0xffff00ff,0xffffff00,0xffffffff | ||
52 | #elif defined(__LITTLE_ENDIAN) | ||
53 | 0x00000000,0xff000000,0x00ff0000,0xffff0000, | ||
54 | 0x0000ff00,0xff00ff00,0x00ffff00,0xffffff00, | ||
55 | 0x000000ff,0xff0000ff,0x00ff00ff,0xffff00ff, | ||
56 | 0x0000ffff,0xff00ffff,0x00ffffff,0xffffffff | ||
57 | #else | ||
58 | #error FIXME: No endianness?? | ||
59 | #endif | ||
60 | }; | ||
61 | |||
62 | static u32 cfb_tab16[] = { | ||
63 | #if defined(__BIG_ENDIAN) | ||
64 | 0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff | ||
65 | #elif defined(__LITTLE_ENDIAN) | ||
66 | 0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff | ||
67 | #else | ||
68 | #error FIXME: No endianness?? | ||
69 | #endif | ||
70 | }; | ||
71 | |||
72 | static u32 cfb_tab32[] = { | ||
73 | 0x00000000, 0xffffffff | ||
74 | }; | ||
75 | |||
76 | #define FB_WRITEL fb_writel | ||
77 | #define FB_READL fb_readl | ||
78 | |||
79 | #if defined (__BIG_ENDIAN) | ||
80 | #define LEFT_POS(bpp) (32 - bpp) | ||
81 | #define SHIFT_HIGH(val, bits) ((val) >> (bits)) | ||
82 | #define SHIFT_LOW(val, bits) ((val) << (bits)) | ||
83 | #else | ||
84 | #define LEFT_POS(bpp) (0) | ||
85 | #define SHIFT_HIGH(val, bits) ((val) << (bits)) | ||
86 | #define SHIFT_LOW(val, bits) ((val) >> (bits)) | ||
87 | #endif | ||
88 | |||
89 | static inline void color_imageblit(const struct fb_image *image, | ||
90 | struct fb_info *p, u8 __iomem *dst1, | ||
91 | u32 start_index, | ||
92 | u32 pitch_index) | ||
93 | { | ||
94 | /* Draw the penguin */ | ||
95 | u32 __iomem *dst, *dst2; | ||
96 | u32 color = 0, val, shift; | ||
97 | int i, n, bpp = p->var.bits_per_pixel; | ||
98 | u32 null_bits = 32 - bpp; | ||
99 | u32 *palette = (u32 *) p->pseudo_palette; | ||
100 | const u8 *src = image->data; | ||
101 | |||
102 | dst2 = (u32 __iomem *) dst1; | ||
103 | for (i = image->height; i--; ) { | ||
104 | n = image->width; | ||
105 | dst = (u32 __iomem *) dst1; | ||
106 | shift = 0; | ||
107 | val = 0; | ||
108 | |||
109 | if (start_index) { | ||
110 | u32 start_mask = ~(SHIFT_HIGH(~(u32)0, start_index)); | ||
111 | val = FB_READL(dst) & start_mask; | ||
112 | shift = start_index; | ||
113 | } | ||
114 | while (n--) { | ||
115 | if (p->fix.visual == FB_VISUAL_TRUECOLOR || | ||
116 | p->fix.visual == FB_VISUAL_DIRECTCOLOR ) | ||
117 | color = palette[*src]; | ||
118 | else | ||
119 | color = *src; | ||
120 | color <<= LEFT_POS(bpp); | ||
121 | val |= SHIFT_HIGH(color, shift); | ||
122 | if (shift >= null_bits) { | ||
123 | FB_WRITEL(val, dst++); | ||
124 | |||
125 | val = (shift == null_bits) ? 0 : | ||
126 | SHIFT_LOW(color, 32 - shift); | ||
127 | } | ||
128 | shift += bpp; | ||
129 | shift &= (32 - 1); | ||
130 | src++; | ||
131 | } | ||
132 | if (shift) { | ||
133 | u32 end_mask = SHIFT_HIGH(~(u32)0, shift); | ||
134 | |||
135 | FB_WRITEL((FB_READL(dst) & end_mask) | val, dst); | ||
136 | } | ||
137 | dst1 += p->fix.line_length; | ||
138 | if (pitch_index) { | ||
139 | dst2 += p->fix.line_length; | ||
140 | dst1 = (u8 __iomem *)((long __force)dst2 & ~(sizeof(u32) - 1)); | ||
141 | |||
142 | start_index += pitch_index; | ||
143 | start_index &= 32 - 1; | ||
144 | } | ||
145 | } | ||
146 | } | ||
147 | |||
148 | static inline void slow_imageblit(const struct fb_image *image, struct fb_info *p, | ||
149 | u8 __iomem *dst1, u32 fgcolor, | ||
150 | u32 bgcolor, | ||
151 | u32 start_index, | ||
152 | u32 pitch_index) | ||
153 | { | ||
154 | u32 shift, color = 0, bpp = p->var.bits_per_pixel; | ||
155 | u32 __iomem *dst, *dst2; | ||
156 | u32 val, pitch = p->fix.line_length; | ||
157 | u32 null_bits = 32 - bpp; | ||
158 | u32 spitch = (image->width+7)/8; | ||
159 | const u8 *src = image->data, *s; | ||
160 | u32 i, j, l; | ||
161 | |||
162 | dst2 = (u32 __iomem *) dst1; | ||
163 | |||
164 | for (i = image->height; i--; ) { | ||
165 | shift = val = 0; | ||
166 | l = 8; | ||
167 | j = image->width; | ||
168 | dst = (u32 __iomem *) dst1; | ||
169 | s = src; | ||
170 | |||
171 | /* write leading bits */ | ||
172 | if (start_index) { | ||
173 | u32 start_mask = ~(SHIFT_HIGH(~(u32)0, start_index)); | ||
174 | val = FB_READL(dst) & start_mask; | ||
175 | shift = start_index; | ||
176 | } | ||
177 | |||
178 | while (j--) { | ||
179 | l--; | ||
180 | color = (*s & (1 << l)) ? fgcolor : bgcolor; | ||
181 | color <<= LEFT_POS(bpp); | ||
182 | val |= SHIFT_HIGH(color, shift); | ||
183 | |||
184 | /* Did the bitshift spill bits to the next long? */ | ||
185 | if (shift >= null_bits) { | ||
186 | FB_WRITEL(val, dst++); | ||
187 | val = (shift == null_bits) ? 0 : | ||
188 | SHIFT_LOW(color,32 - shift); | ||
189 | } | ||
190 | shift += bpp; | ||
191 | shift &= (32 - 1); | ||
192 | if (!l) { l = 8; s++; }; | ||
193 | } | ||
194 | |||
195 | /* write trailing bits */ | ||
196 | if (shift) { | ||
197 | u32 end_mask = SHIFT_HIGH(~(u32)0, shift); | ||
198 | |||
199 | FB_WRITEL((FB_READL(dst) & end_mask) | val, dst); | ||
200 | } | ||
201 | |||
202 | dst1 += pitch; | ||
203 | src += spitch; | ||
204 | if (pitch_index) { | ||
205 | dst2 += pitch; | ||
206 | dst1 = (u8 __iomem *)((long __force)dst2 & ~(sizeof(u32) - 1)); | ||
207 | start_index += pitch_index; | ||
208 | start_index &= 32 - 1; | ||
209 | } | ||
210 | |||
211 | } | ||
212 | } | ||
213 | |||
214 | /* | ||
215 | * fast_imageblit - optimized monochrome color expansion | ||
216 | * | ||
217 | * Only if: bits_per_pixel == 8, 16, or 32 | ||
218 | * image->width is divisible by pixel/dword (ppw); | ||
219 | * fix->line_legth is divisible by 4; | ||
220 | * beginning and end of a scanline is dword aligned | ||
221 | */ | ||
222 | static inline void fast_imageblit(const struct fb_image *image, struct fb_info *p, | ||
223 | u8 __iomem *dst1, u32 fgcolor, | ||
224 | u32 bgcolor) | ||
225 | { | ||
226 | u32 fgx = fgcolor, bgx = bgcolor, bpp = p->var.bits_per_pixel; | ||
227 | u32 ppw = 32/bpp, spitch = (image->width + 7)/8; | ||
228 | u32 bit_mask, end_mask, eorx, shift; | ||
229 | const char *s = image->data, *src; | ||
230 | u32 __iomem *dst; | ||
231 | u32 *tab = NULL; | ||
232 | int i, j, k; | ||
233 | |||
234 | switch (bpp) { | ||
235 | case 8: | ||
236 | tab = cfb_tab8; | ||
237 | break; | ||
238 | case 16: | ||
239 | tab = cfb_tab16; | ||
240 | break; | ||
241 | case 32: | ||
242 | tab = cfb_tab32; | ||
243 | break; | ||
244 | } | ||
245 | |||
246 | for (i = ppw-1; i--; ) { | ||
247 | fgx <<= bpp; | ||
248 | bgx <<= bpp; | ||
249 | fgx |= fgcolor; | ||
250 | bgx |= bgcolor; | ||
251 | } | ||
252 | |||
253 | bit_mask = (1 << ppw) - 1; | ||
254 | eorx = fgx ^ bgx; | ||
255 | k = image->width/ppw; | ||
256 | |||
257 | for (i = image->height; i--; ) { | ||
258 | dst = (u32 __iomem *) dst1, shift = 8; src = s; | ||
259 | |||
260 | for (j = k; j--; ) { | ||
261 | shift -= ppw; | ||
262 | end_mask = tab[(*src >> shift) & bit_mask]; | ||
263 | FB_WRITEL((end_mask & eorx)^bgx, dst++); | ||
264 | if (!shift) { shift = 8; src++; } | ||
265 | } | ||
266 | dst1 += p->fix.line_length; | ||
267 | s += spitch; | ||
268 | } | ||
269 | } | ||
270 | |||
271 | void cfb_imageblit(struct fb_info *p, const struct fb_image *image) | ||
272 | { | ||
273 | u32 fgcolor, bgcolor, start_index, bitstart, pitch_index = 0; | ||
274 | u32 bpl = sizeof(u32), bpp = p->var.bits_per_pixel; | ||
275 | u32 width = image->width, height = image->height; | ||
276 | u32 dx = image->dx, dy = image->dy; | ||
277 | int x2, y2, vxres, vyres; | ||
278 | u8 __iomem *dst1; | ||
279 | |||
280 | if (p->state != FBINFO_STATE_RUNNING) | ||
281 | return; | ||
282 | |||
283 | vxres = p->var.xres_virtual; | ||
284 | vyres = p->var.yres_virtual; | ||
285 | /* | ||
286 | * We could use hardware clipping but on many cards you get around | ||
287 | * hardware clipping by writing to framebuffer directly like we are | ||
288 | * doing here. | ||
289 | */ | ||
290 | if (image->dx > vxres || image->dy > vyres) | ||
291 | return; | ||
292 | |||
293 | x2 = image->dx + image->width; | ||
294 | y2 = image->dy + image->height; | ||
295 | dx = image->dx > 0 ? image->dx : 0; | ||
296 | dy = image->dy > 0 ? image->dy : 0; | ||
297 | x2 = x2 < vxres ? x2 : vxres; | ||
298 | y2 = y2 < vyres ? y2 : vyres; | ||
299 | width = x2 - dx; | ||
300 | height = y2 - dy; | ||
301 | |||
302 | bitstart = (dy * p->fix.line_length * 8) + (dx * bpp); | ||
303 | start_index = bitstart & (32 - 1); | ||
304 | pitch_index = (p->fix.line_length & (bpl - 1)) * 8; | ||
305 | |||
306 | bitstart /= 8; | ||
307 | bitstart &= ~(bpl - 1); | ||
308 | dst1 = p->screen_base + bitstart; | ||
309 | |||
310 | if (p->fbops->fb_sync) | ||
311 | p->fbops->fb_sync(p); | ||
312 | |||
313 | if (image->depth == 1) { | ||
314 | if (p->fix.visual == FB_VISUAL_TRUECOLOR || | ||
315 | p->fix.visual == FB_VISUAL_DIRECTCOLOR) { | ||
316 | fgcolor = ((u32*)(p->pseudo_palette))[image->fg_color]; | ||
317 | bgcolor = ((u32*)(p->pseudo_palette))[image->bg_color]; | ||
318 | } else { | ||
319 | fgcolor = image->fg_color; | ||
320 | bgcolor = image->bg_color; | ||
321 | } | ||
322 | |||
323 | if (32 % bpp == 0 && !start_index && !pitch_index && | ||
324 | ((width & (32/bpp-1)) == 0) && | ||
325 | bpp >= 8 && bpp <= 32) | ||
326 | fast_imageblit(image, p, dst1, fgcolor, bgcolor); | ||
327 | else | ||
328 | slow_imageblit(image, p, dst1, fgcolor, bgcolor, | ||
329 | start_index, pitch_index); | ||
330 | } else | ||
331 | color_imageblit(image, p, dst1, start_index, pitch_index); | ||
332 | } | ||
333 | |||
334 | EXPORT_SYMBOL(cfb_imageblit); | ||
335 | |||
336 | MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>"); | ||
337 | MODULE_DESCRIPTION("Generic software accelerated imaging drawing"); | ||
338 | MODULE_LICENSE("GPL"); | ||
339 | |||