049256052b1aff2548ab48ea37b5c07543c62eb7
[linux-flexiantxendom0-natty.git] / drivers / video / mb862xx / mb862xxfb_accel.c
1 /*
2  * drivers/mb862xx/mb862xxfb_accel.c
3  *
4  * Fujitsu Carmine/Coral-P(A)/Lime framebuffer driver acceleration support
5  *
6  * (C) 2007 Alexander Shishkin <virtuoso@slind.org>
7  * (C) 2009 Valentin Sitdikov <valentin.sitdikov@siemens.com>
8  * (C) 2009 Siemens AG
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License version 2 as
12  * published by the Free Software Foundation.
13  *
14  */
15 #include <linux/fb.h>
16 #include <linux/delay.h>
17 #include <linux/init.h>
18 #include <linux/interrupt.h>
19 #include <linux/pci.h>
20 #if defined(CONFIG_OF)
21 #include <linux/of_platform.h>
22 #endif
23 #include "mb862xxfb.h"
24 #include "mb862xx_reg.h"
25 #include "mb862xxfb_accel.h"
26
27 static void mb862xxfb_write_fifo(u32 count, u32 *data, struct fb_info *info)
28 {
29         struct mb862xxfb_par *par = info->par;
30         static u32 free;
31
32         u32 total = 0;
33         while (total < count) {
34                 if (free) {
35                         outreg(geo, GDC_GEO_REG_INPUT_FIFO, data[total]);
36                         total++;
37                         free--;
38                 } else {
39                         free = (u32) inreg(draw, GDC_REG_FIFO_COUNT);
40                 }
41         }
42 }
43
44 static void mb86290fb_copyarea(struct fb_info *info,
45                                const struct fb_copyarea *area)
46 {
47         __u32 cmd[6];
48
49         cmd[0] = (GDC_TYPE_SETREGISTER << 24) | (1 << 16) | GDC_REG_MODE_BITMAP;
50         /* Set raster operation */
51         cmd[1] = (2 << 7) | (GDC_ROP_COPY << 9);
52         cmd[2] = GDC_TYPE_BLTCOPYP << 24;
53
54         if (area->sx >= area->dx && area->sy >= area->dy)
55                 cmd[2] |= GDC_CMD_BLTCOPY_TOP_LEFT << 16;
56         else if (area->sx >= area->dx && area->sy <= area->dy)
57                 cmd[2] |= GDC_CMD_BLTCOPY_BOTTOM_LEFT << 16;
58         else if (area->sx <= area->dx && area->sy >= area->dy)
59                 cmd[2] |= GDC_CMD_BLTCOPY_TOP_RIGHT << 16;
60         else
61                 cmd[2] |= GDC_CMD_BLTCOPY_BOTTOM_RIGHT << 16;
62
63         cmd[3] = (area->sy << 16) | area->sx;
64         cmd[4] = (area->dy << 16) | area->dx;
65         cmd[5] = (area->height << 16) | area->width;
66         mb862xxfb_write_fifo(6, cmd, info);
67 }
68
69 /*
70  * Fill in the cmd array /GDC FIFO commands/ to draw a 1bit image.
71  * Make sure cmd has enough room!
72  */
73 static void mb86290fb_imageblit1(u32 *cmd, u16 step, u16 dx, u16 dy,
74                                  u16 width, u16 height, u32 fgcolor,
75                                  u32 bgcolor, const struct fb_image *image,
76                                  struct fb_info *info)
77 {
78         int i;
79         unsigned const char *line;
80         u16 bytes;
81
82         /* set colors and raster operation regs */
83         cmd[0] = (GDC_TYPE_SETREGISTER << 24) | (1 << 16) | GDC_REG_MODE_BITMAP;
84         /* Set raster operation */
85         cmd[1] = (2 << 7) | (GDC_ROP_COPY << 9);
86         cmd[2] =
87             (GDC_TYPE_SETCOLORREGISTER << 24) | (GDC_CMD_BODY_FORE_COLOR << 16);
88         cmd[3] = fgcolor;
89         cmd[4] =
90             (GDC_TYPE_SETCOLORREGISTER << 24) | (GDC_CMD_BODY_BACK_COLOR << 16);
91         cmd[5] = bgcolor;
92
93         i = 0;
94         line = image->data;
95         bytes = (image->width + 7) >> 3;
96
97         /* and the image */
98         cmd[6] = (GDC_TYPE_DRAWBITMAPP << 24) |
99             (GDC_CMD_BITMAP << 16) | (2 + (step * height));
100         cmd[7] = (dy << 16) | dx;
101         cmd[8] = (height << 16) | width;
102
103         while (i < height) {
104                 memcpy(&cmd[9 + i * step], line, step << 2);
105 #ifdef __LITTLE_ENDIAN
106                 {
107                         int k = 0;
108                         for (k = 0; k < step; k++)
109                                 cmd[9 + i * step + k] =
110                                     cpu_to_be32(cmd[9 + i * step + k]);
111                 }
112 #endif
113                 line += bytes;
114                 i++;
115         }
116 }
117
118 /*
119  * Fill in the cmd array /GDC FIFO commands/ to draw a 8bit image.
120  * Make sure cmd has enough room!
121  */
122 static void mb86290fb_imageblit8(u32 *cmd, u16 step, u16 dx, u16 dy,
123                                  u16 width, u16 height, u32 fgcolor,
124                                  u32 bgcolor, const struct fb_image *image,
125                                  struct fb_info *info)
126 {
127         int i, j;
128         unsigned const char *line, *ptr;
129         u16 bytes;
130
131         cmd[0] = (GDC_TYPE_DRAWBITMAPP << 24) |
132             (GDC_CMD_BLT_DRAW << 16) | (2 + (height * step));
133         cmd[1] = (dy << 16) | dx;
134         cmd[2] = (height << 16) | width;
135
136         i = 0;
137         line = ptr = image->data;
138         bytes = image->width;
139
140         while (i < height) {
141                 ptr = line;
142                 for (j = 0; j < step; j++) {
143                         cmd[3 + i * step + j] =
144                             (((u32 *) (info->pseudo_palette))[*ptr]) & 0xffff;
145                         ptr++;
146                         cmd[3 + i * step + j] |=
147                             ((((u32 *) (info->
148                                         pseudo_palette))[*ptr]) & 0xffff) << 16;
149                         ptr++;
150                 }
151
152                 line += bytes;
153                 i++;
154         }
155 }
156
157 /*
158  * Fill in the cmd array /GDC FIFO commands/ to draw a 16bit image.
159  * Make sure cmd has enough room!
160  */
161 static void mb86290fb_imageblit16(u32 *cmd, u16 step, u16 dx, u16 dy,
162                                   u16 width, u16 height, u32 fgcolor,
163                                   u32 bgcolor, const struct fb_image *image,
164                                   struct fb_info *info)
165 {
166         int i;
167         unsigned const char *line;
168         u16 bytes;
169
170         i = 0;
171         line = image->data;
172         bytes = image->width << 1;
173
174         cmd[0] = (GDC_TYPE_DRAWBITMAPP << 24) |
175             (GDC_CMD_BLT_DRAW << 16) | (2 + step * height);
176         cmd[1] = (dy << 16) | dx;
177         cmd[2] = (height << 16) | width;
178
179         while (i < height) {
180                 memcpy(&cmd[3 + i * step], line, step);
181                 line += bytes;
182                 i++;
183         }
184 }
185
186 static void mb86290fb_imageblit(struct fb_info *info,
187                                 const struct fb_image *image)
188 {
189         int mdr;
190         u32 *cmd = NULL;
191         void (*cmdfn) (u32 *, u16, u16, u16, u16, u16, u32, u32,
192                        const struct fb_image *, struct fb_info *) = NULL;
193         u32 cmdlen;
194         u32 fgcolor = 0, bgcolor = 0;
195         u16 step;
196
197         u16 width = image->width, height = image->height;
198         u16 dx = image->dx, dy = image->dy;
199         int x2, y2, vxres, vyres;
200
201         mdr = (GDC_ROP_COPY << 9);
202         x2 = image->dx + image->width;
203         y2 = image->dy + image->height;
204         vxres = info->var.xres_virtual;
205         vyres = info->var.yres_virtual;
206         x2 = min(x2, vxres);
207         y2 = min(y2, vyres);
208         width = x2 - dx;
209         height = y2 - dy;
210
211         switch (image->depth) {
212         case 1:
213                 step = (width + 31) >> 5;
214                 cmdlen = 9 + height * step;
215                 cmdfn = mb86290fb_imageblit1;
216                 if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
217                     info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
218                         fgcolor =
219                             ((u32 *) (info->pseudo_palette))[image->fg_color];
220                         bgcolor =
221                             ((u32 *) (info->pseudo_palette))[image->bg_color];
222                 } else {
223                         fgcolor = image->fg_color;
224                         bgcolor = image->bg_color;
225                 }
226
227                 break;
228
229         case 8:
230                 step = (width + 1) >> 1;
231                 cmdlen = 3 + height * step;
232                 cmdfn = mb86290fb_imageblit8;
233                 break;
234
235         case 16:
236                 step = (width + 1) >> 1;
237                 cmdlen = 3 + height * step;
238                 cmdfn = mb86290fb_imageblit16;
239                 break;
240
241         default:
242                 cfb_imageblit(info, image);
243                 return;
244         }
245
246         cmd = kmalloc(cmdlen * 4, GFP_DMA);
247         if (!cmd)
248                 return cfb_imageblit(info, image);
249         cmdfn(cmd, step, dx, dy, width, height, fgcolor, bgcolor, image, info);
250         mb862xxfb_write_fifo(cmdlen, cmd, info);
251         kfree(cmd);
252 }
253
254 static void mb86290fb_fillrect(struct fb_info *info,
255                                const struct fb_fillrect *rect)
256 {
257
258         u32 x2, y2, vxres, vyres, height, width, fg;
259         u32 cmd[7];
260
261         vxres = info->var.xres_virtual;
262         vyres = info->var.yres_virtual;
263
264         if (!rect->width || !rect->height || rect->dx > vxres
265             || rect->dy > vyres)
266                 return;
267
268         /* We could use hardware clipping but on many cards you get around
269          * hardware clipping by writing to framebuffer directly. */
270         x2 = rect->dx + rect->width;
271         y2 = rect->dy + rect->height;
272         x2 = min(x2, vxres);
273         y2 = min(y2, vyres);
274         width = x2 - rect->dx;
275         height = y2 - rect->dy;
276         if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
277             info->fix.visual == FB_VISUAL_DIRECTCOLOR)
278                 fg = ((u32 *) (info->pseudo_palette))[rect->color];
279         else
280                 fg = rect->color;
281
282         switch (rect->rop) {
283
284         case ROP_XOR:
285                 /* Set raster operation */
286                 cmd[1] = (2 << 7) | (GDC_ROP_XOR << 9);
287                 break;
288
289         case ROP_COPY:
290                 /* Set raster operation */
291                 cmd[1] = (2 << 7) | (GDC_ROP_COPY << 9);
292                 break;
293
294         }
295
296         cmd[0] = (GDC_TYPE_SETREGISTER << 24) | (1 << 16) | GDC_REG_MODE_BITMAP;
297         /* cmd[1] set earlier */
298         cmd[2] =
299             (GDC_TYPE_SETCOLORREGISTER << 24) | (GDC_CMD_BODY_FORE_COLOR << 16);
300         cmd[3] = fg;
301         cmd[4] = (GDC_TYPE_DRAWRECTP << 24) | (GDC_CMD_BLT_FILL << 16);
302         cmd[5] = (rect->dy << 16) | (rect->dx);
303         cmd[6] = (height << 16) | width;
304
305         mb862xxfb_write_fifo(7, cmd, info);
306 }
307
308 void mb862xxfb_init_accel(struct fb_info *info, int xres)
309 {
310         struct mb862xxfb_par *par = info->par;
311
312         if (info->var.bits_per_pixel == 32) {
313                 info->fbops->fb_fillrect = cfb_fillrect;
314                 info->fbops->fb_copyarea = cfb_copyarea;
315                 info->fbops->fb_imageblit = cfb_imageblit;
316         } else {
317                 outreg(disp, GC_L0EM, 3);
318                 info->fbops->fb_fillrect = mb86290fb_fillrect;
319                 info->fbops->fb_copyarea = mb86290fb_copyarea;
320                 info->fbops->fb_imageblit = mb86290fb_imageblit;
321         }
322         outreg(draw, GDC_REG_DRAW_BASE, 0);
323         outreg(draw, GDC_REG_MODE_MISC, 0x8000);
324         outreg(draw, GDC_REG_X_RESOLUTION, xres);
325
326         info->flags |=
327             FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT |
328             FBINFO_HWACCEL_IMAGEBLIT;
329         info->fix.accel = 0xff; /*FIXME: add right define */
330 }
331 EXPORT_SYMBOL(mb862xxfb_init_accel);