Merge branch 'pm-cpufreq'
[linux-2.6-block.git] / drivers / staging / sm750fb / sm750_accel.c
1 #include<linux/module.h>
2 #include<linux/kernel.h>
3 #include<linux/errno.h>
4 #include<linux/string.h>
5 #include<linux/mm.h>
6 #include<linux/slab.h>
7 #include<linux/delay.h>
8 #include<linux/fb.h>
9 #include<linux/ioport.h>
10 #include<linux/init.h>
11 #include<linux/pci.h>
12 #include<linux/vmalloc.h>
13 #include<linux/pagemap.h>
14 #include <linux/console.h>
15 #include<linux/platform_device.h>
16 #include<linux/screen_info.h>
17
18 #include "sm750.h"
19 #include "sm750_accel.h"
20 #include "sm750_help.h"
21 static inline void write_dpr(struct lynx_accel *accel, int offset, u32 regValue)
22 {
23         writel(regValue, accel->dprBase + offset);
24 }
25
26 static inline u32 read_dpr(struct lynx_accel *accel, int offset)
27 {
28         return readl(accel->dprBase + offset);
29 }
30
31 static inline void write_dpPort(struct lynx_accel *accel, u32 data)
32 {
33         writel(data, accel->dpPortBase);
34 }
35
36 void hw_de_init(struct lynx_accel *accel)
37 {
38         /* setup 2d engine registers */
39         u32 reg, clr;
40
41         write_dpr(accel, DE_MASKS, 0xFFFFFFFF);
42
43         /* dpr1c */
44         reg = FIELD_SET(0, DE_STRETCH_FORMAT, PATTERN_XY, NORMAL)|
45                 FIELD_VALUE(0, DE_STRETCH_FORMAT, PATTERN_Y, 0)|
46                 FIELD_VALUE(0, DE_STRETCH_FORMAT, PATTERN_X, 0)|
47                 FIELD_SET(0, DE_STRETCH_FORMAT, ADDRESSING, XY)|
48                 FIELD_VALUE(0, DE_STRETCH_FORMAT, SOURCE_HEIGHT, 3);
49
50         clr = FIELD_CLEAR(DE_STRETCH_FORMAT, PATTERN_XY)&
51                 FIELD_CLEAR(DE_STRETCH_FORMAT, PATTERN_Y)&
52                 FIELD_CLEAR(DE_STRETCH_FORMAT, PATTERN_X)&
53                 FIELD_CLEAR(DE_STRETCH_FORMAT, ADDRESSING)&
54                 FIELD_CLEAR(DE_STRETCH_FORMAT, SOURCE_HEIGHT);
55
56         /* DE_STRETCH bpp format need be initilized in setMode routine */
57         write_dpr(accel, DE_STRETCH_FORMAT, (read_dpr(accel, DE_STRETCH_FORMAT) & clr) | reg);
58
59         /* disable clipping and transparent */
60         write_dpr(accel, DE_CLIP_TL, 0); /* dpr2c */
61         write_dpr(accel, DE_CLIP_BR, 0); /* dpr30 */
62
63         write_dpr(accel, DE_COLOR_COMPARE_MASK, 0); /* dpr24 */
64         write_dpr(accel, DE_COLOR_COMPARE, 0);
65
66         reg = FIELD_SET(0, DE_CONTROL, TRANSPARENCY, DISABLE)|
67                 FIELD_SET(0, DE_CONTROL, TRANSPARENCY_MATCH, OPAQUE)|
68                 FIELD_SET(0, DE_CONTROL, TRANSPARENCY_SELECT, SOURCE);
69
70         clr = FIELD_CLEAR(DE_CONTROL, TRANSPARENCY)&
71                 FIELD_CLEAR(DE_CONTROL, TRANSPARENCY_MATCH)&
72                 FIELD_CLEAR(DE_CONTROL, TRANSPARENCY_SELECT);
73
74         /* dpr0c */
75         write_dpr(accel, DE_CONTROL, (read_dpr(accel, DE_CONTROL)&clr)|reg);
76 }
77
78 /* set2dformat only be called from setmode functions
79  * but if you need dual framebuffer driver,need call set2dformat
80  * every time you use 2d function */
81
82 void hw_set2dformat(struct lynx_accel *accel, int fmt)
83 {
84         u32 reg;
85
86         /* fmt=0,1,2 for 8,16,32,bpp on sm718/750/502 */
87         reg = read_dpr(accel, DE_STRETCH_FORMAT);
88         reg = FIELD_VALUE(reg, DE_STRETCH_FORMAT, PIXEL_FORMAT, fmt);
89         write_dpr(accel, DE_STRETCH_FORMAT, reg);
90 }
91
92 int hw_fillrect(struct lynx_accel *accel,
93                                 u32 base, u32 pitch, u32 Bpp,
94                                 u32 x, u32 y, u32 width, u32 height,
95                                 u32 color, u32 rop)
96 {
97         u32 deCtrl;
98
99         if (accel->de_wait() != 0) {
100                 /* int time wait and always busy,seems hardware
101                  * got something error */
102                 pr_debug("De engine always busy\n");
103                 return -1;
104         }
105
106         write_dpr(accel, DE_WINDOW_DESTINATION_BASE, base); /* dpr40 */
107         write_dpr(accel, DE_PITCH,
108                         FIELD_VALUE(0, DE_PITCH, DESTINATION, pitch/Bpp)|
109                         FIELD_VALUE(0, DE_PITCH, SOURCE, pitch/Bpp)); /* dpr10 */
110
111         write_dpr(accel, DE_WINDOW_WIDTH,
112                         FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, pitch/Bpp)|
113                         FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE, pitch/Bpp)); /* dpr44 */
114
115         write_dpr(accel, DE_FOREGROUND, color); /* DPR14 */
116
117         write_dpr(accel, DE_DESTINATION,
118                         FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE)|
119                         FIELD_VALUE(0, DE_DESTINATION, X, x)|
120                         FIELD_VALUE(0, DE_DESTINATION, Y, y)); /* dpr4 */
121
122         write_dpr(accel, DE_DIMENSION,
123                         FIELD_VALUE(0, DE_DIMENSION, X, width)|
124                         FIELD_VALUE(0, DE_DIMENSION, Y_ET, height)); /* dpr8 */
125
126         deCtrl =
127                 FIELD_SET(0, DE_CONTROL, STATUS, START)|
128                 FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT)|
129                 FIELD_SET(0, DE_CONTROL, LAST_PIXEL, ON)|
130                 FIELD_SET(0, DE_CONTROL, COMMAND, RECTANGLE_FILL)|
131                 FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2)|
132                 FIELD_VALUE(0, DE_CONTROL, ROP, rop); /* dpr0xc */
133
134         write_dpr(accel, DE_CONTROL, deCtrl);
135         return 0;
136 }
137
138 int hw_copyarea(
139 struct lynx_accel *accel,
140 unsigned int sBase,  /* Address of source: offset in frame buffer */
141 unsigned int sPitch, /* Pitch value of source surface in BYTE */
142 unsigned int sx,
143 unsigned int sy,     /* Starting coordinate of source surface */
144 unsigned int dBase,  /* Address of destination: offset in frame buffer */
145 unsigned int dPitch, /* Pitch value of destination surface in BYTE */
146 unsigned int Bpp,    /* Color depth of destination surface */
147 unsigned int dx,
148 unsigned int dy,     /* Starting coordinate of destination surface */
149 unsigned int width,
150 unsigned int height, /* width and height of rectangle in pixel value */
151 unsigned int rop2)   /* ROP value */
152 {
153         unsigned int nDirection, de_ctrl;
154         int opSign;
155
156         nDirection = LEFT_TO_RIGHT;
157         /* Direction of ROP2 operation: 1 = Left to Right, (-1) = Right to Left */
158         opSign = 1;
159         de_ctrl = 0;
160
161         /* If source and destination are the same surface, need to check for overlay cases */
162         if (sBase == dBase && sPitch == dPitch) {
163                 /* Determine direction of operation */
164                 if (sy < dy) {
165                         /* +----------+
166                            |S         |
167                            |   +----------+
168                            |   |      |   |
169                            |   |      |   |
170                            +---|------+   |
171                            |         D|
172                            +----------+ */
173
174                         nDirection = BOTTOM_TO_TOP;
175                 } else if (sy > dy) {
176                         /* +----------+
177                            |D         |
178                            |   +----------+
179                            |   |      |   |
180                            |   |      |   |
181                            +---|------+   |
182                            |         S|
183                            +----------+ */
184
185                         nDirection = TOP_TO_BOTTOM;
186                 } else {
187                         /* sy == dy */
188
189                         if (sx <= dx) {
190                                 /* +------+---+------+
191                                    |S     |   |     D|
192                                    |      |   |      |
193                                    |      |   |      |
194                                    |      |   |      |
195                                    +------+---+------+ */
196
197                                 nDirection = RIGHT_TO_LEFT;
198                         } else {
199                         /* sx > dx */
200
201                                 /* +------+---+------+
202                                    |D     |   |     S|
203                                    |      |   |      |
204                                    |      |   |      |
205                                    |      |   |      |
206                                    +------+---+------+ */
207
208                                 nDirection = LEFT_TO_RIGHT;
209                         }
210                 }
211         }
212
213         if ((nDirection == BOTTOM_TO_TOP) || (nDirection == RIGHT_TO_LEFT)) {
214                 sx += width - 1;
215                 sy += height - 1;
216                 dx += width - 1;
217                 dy += height - 1;
218                 opSign = (-1);
219         }
220
221         /* Note:
222            DE_FOREGROUND are DE_BACKGROUND are don't care.
223           DE_COLOR_COMPARE and DE_COLOR_COMPARE_MAKS are set by set deSetTransparency().
224          */
225
226         /* 2D Source Base.
227          It is an address offset (128 bit aligned) from the beginning of frame buffer.
228          */
229         write_dpr(accel, DE_WINDOW_SOURCE_BASE, sBase); /* dpr40 */
230
231         /* 2D Destination Base.
232          It is an address offset (128 bit aligned) from the beginning of frame buffer.
233          */
234         write_dpr(accel, DE_WINDOW_DESTINATION_BASE, dBase); /* dpr44 */
235
236 #if 0
237     /* Program pitch (distance between the 1st points of two adjacent lines).
238        Note that input pitch is BYTE value, but the 2D Pitch register uses
239        pixel values. Need Byte to pixel conversion.
240     */
241         if (Bpp == 3) {
242                         sx *= 3;
243                         dx *= 3;
244                         width *= 3;
245                 write_dpr(accel, DE_PITCH,
246                                 FIELD_VALUE(0, DE_PITCH, DESTINATION, dPitch) |
247                                 FIELD_VALUE(0, DE_PITCH, SOURCE,      sPitch)); /* dpr10 */
248         } else
249 #endif
250         {
251                 write_dpr(accel, DE_PITCH,
252                                 FIELD_VALUE(0, DE_PITCH, DESTINATION, (dPitch/Bpp)) |
253                                 FIELD_VALUE(0, DE_PITCH, SOURCE,      (sPitch/Bpp))); /* dpr10 */
254         }
255
256     /* Screen Window width in Pixels.
257        2D engine uses this value to calculate the linear address in frame buffer for a given point.
258     */
259         write_dpr(accel, DE_WINDOW_WIDTH,
260         FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, (dPitch/Bpp)) |
261         FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE,      (sPitch/Bpp))); /* dpr3c */
262
263         if (accel->de_wait() != 0)
264                 return -1;
265
266         {
267
268         write_dpr(accel, DE_SOURCE,
269                   FIELD_SET(0, DE_SOURCE, WRAP, DISABLE) |
270                   FIELD_VALUE(0, DE_SOURCE, X_K1, sx)   |
271                   FIELD_VALUE(0, DE_SOURCE, Y_K2, sy)); /* dpr0 */
272         write_dpr(accel, DE_DESTINATION,
273                   FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) |
274                   FIELD_VALUE(0, DE_DESTINATION, X,    dx)  |
275                   FIELD_VALUE(0, DE_DESTINATION, Y,    dy)); /* dpr04 */
276         write_dpr(accel, DE_DIMENSION,
277                   FIELD_VALUE(0, DE_DIMENSION, X,    width) |
278                   FIELD_VALUE(0, DE_DIMENSION, Y_ET, height)); /* dpr08 */
279
280         de_ctrl = FIELD_VALUE(0, DE_CONTROL, ROP, rop2) |
281                   FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
282                   FIELD_SET(0, DE_CONTROL, COMMAND, BITBLT) |
283                   ((nDirection == RIGHT_TO_LEFT) ?
284                   FIELD_SET(0, DE_CONTROL, DIRECTION, RIGHT_TO_LEFT)
285                   : FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT)) |
286                   FIELD_SET(0, DE_CONTROL, STATUS, START);
287         write_dpr(accel, DE_CONTROL, de_ctrl); /* dpr0c */
288
289         }
290
291         return 0;
292 }
293
294 static unsigned int deGetTransparency(struct lynx_accel *accel)
295 {
296         unsigned int de_ctrl;
297
298         de_ctrl = read_dpr(accel, DE_CONTROL);
299
300         de_ctrl &=
301                    FIELD_MASK(DE_CONTROL_TRANSPARENCY_MATCH) |
302                    FIELD_MASK(DE_CONTROL_TRANSPARENCY_SELECT)|
303                    FIELD_MASK(DE_CONTROL_TRANSPARENCY);
304
305         return de_ctrl;
306 }
307
308 int hw_imageblit(struct lynx_accel *accel,
309                  const char *pSrcbuf, /* pointer to start of source buffer in system memory */
310                  u32 srcDelta,          /* Pitch value (in bytes) of the source buffer, +ive means top down and -ive mean button up */
311                  u32 startBit, /* Mono data can start at any bit in a byte, this value should be 0 to 7 */
312                  u32 dBase,    /* Address of destination: offset in frame buffer */
313                  u32 dPitch,   /* Pitch value of destination surface in BYTE */
314                  u32 bytePerPixel,      /* Color depth of destination surface */
315                  u32 dx,
316                  u32 dy,       /* Starting coordinate of destination surface */
317                  u32 width,
318                  u32 height,   /* width and height of rectange in pixel value */
319                  u32 fColor,   /* Foreground color (corresponding to a 1 in the monochrome data */
320                  u32 bColor,   /* Background color (corresponding to a 0 in the monochrome data */
321                  u32 rop2)     /* ROP value */
322 {
323         unsigned int ulBytesPerScan;
324         unsigned int ul4BytesPerScan;
325         unsigned int ulBytesRemain;
326         unsigned int de_ctrl = 0;
327         unsigned char ajRemain[4];
328         int i, j;
329
330         startBit &= 7; /* Just make sure the start bit is within legal range */
331         ulBytesPerScan = (width + startBit + 7) / 8;
332         ul4BytesPerScan = ulBytesPerScan & ~3;
333         ulBytesRemain = ulBytesPerScan & 3;
334
335         if (accel->de_wait() != 0)
336                 return -1;
337
338         /* 2D Source Base.
339          Use 0 for HOST Blt.
340          */
341         write_dpr(accel, DE_WINDOW_SOURCE_BASE, 0);
342
343         /* 2D Destination Base.
344          It is an address offset (128 bit aligned) from the beginning of frame buffer.
345          */
346         write_dpr(accel, DE_WINDOW_DESTINATION_BASE, dBase);
347 #if 0
348     /* Program pitch (distance between the 1st points of two adjacent lines).
349        Note that input pitch is BYTE value, but the 2D Pitch register uses
350        pixel values. Need Byte to pixel conversion.
351     */
352         if (bytePerPixel == 3) {
353                 dx *= 3;
354                 width *= 3;
355                 startBit *= 3;
356                 write_dpr(accel, DE_PITCH,
357                                 FIELD_VALUE(0, DE_PITCH, DESTINATION, dPitch) |
358                                 FIELD_VALUE(0, DE_PITCH, SOURCE,      dPitch)); /* dpr10 */
359
360         } else
361 #endif
362         {
363                 write_dpr(accel, DE_PITCH,
364                                 FIELD_VALUE(0, DE_PITCH, DESTINATION, dPitch/bytePerPixel) |
365                                 FIELD_VALUE(0, DE_PITCH, SOURCE,      dPitch/bytePerPixel)); /* dpr10 */
366         }
367
368         /* Screen Window width in Pixels.
369          2D engine uses this value to calculate the linear address in frame buffer for a given point.
370          */
371         write_dpr(accel, DE_WINDOW_WIDTH,
372                   FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, (dPitch/bytePerPixel)) |
373                   FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE,      (dPitch/bytePerPixel)));
374
375          /* Note: For 2D Source in Host Write, only X_K1_MONO field is needed, and Y_K2 field is not used.
376             For mono bitmap, use startBit for X_K1. */
377         write_dpr(accel, DE_SOURCE,
378                   FIELD_SET(0, DE_SOURCE, WRAP, DISABLE)       |
379                   FIELD_VALUE(0, DE_SOURCE, X_K1_MONO, startBit)); /* dpr00 */
380
381         write_dpr(accel, DE_DESTINATION,
382                   FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) |
383                   FIELD_VALUE(0, DE_DESTINATION, X,    dx)    |
384                   FIELD_VALUE(0, DE_DESTINATION, Y,    dy)); /* dpr04 */
385
386         write_dpr(accel, DE_DIMENSION,
387                   FIELD_VALUE(0, DE_DIMENSION, X,    width) |
388                   FIELD_VALUE(0, DE_DIMENSION, Y_ET, height)); /* dpr08 */
389
390         write_dpr(accel, DE_FOREGROUND, fColor);
391         write_dpr(accel, DE_BACKGROUND, bColor);
392
393         de_ctrl = FIELD_VALUE(0, DE_CONTROL, ROP, rop2)         |
394                 FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2)    |
395                 FIELD_SET(0, DE_CONTROL, COMMAND, HOST_WRITE) |
396                 FIELD_SET(0, DE_CONTROL, HOST, MONO)          |
397                 FIELD_SET(0, DE_CONTROL, STATUS, START);
398
399         write_dpr(accel, DE_CONTROL, de_ctrl | deGetTransparency(accel));
400
401         /* Write MONO data (line by line) to 2D Engine data port */
402         for (i = 0; i < height; i++) {
403                 /* For each line, send the data in chunks of 4 bytes */
404                 for (j = 0; j < (ul4BytesPerScan/4); j++)
405                         write_dpPort(accel, *(unsigned int *)(pSrcbuf + (j * 4)));
406
407                 if (ulBytesRemain) {
408                         memcpy(ajRemain, pSrcbuf+ul4BytesPerScan, ulBytesRemain);
409                         write_dpPort(accel, *(unsigned int *)ajRemain);
410                 }
411
412                 pSrcbuf += srcDelta;
413         }
414
415             return 0;
416 }
417