staging: sm750fb: change definition of DE_STRETCH_FORMAT fields
[cascardo/linux.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 =  0x3;
45
46         clr = DE_STRETCH_FORMAT_PATTERN_XY | DE_STRETCH_FORMAT_PATTERN_Y_MASK |
47                 DE_STRETCH_FORMAT_PATTERN_X_MASK |
48                 DE_STRETCH_FORMAT_ADDRESSING_MASK |
49                 DE_STRETCH_FORMAT_SOURCE_HEIGHT_MASK;
50
51         /* DE_STRETCH bpp format need be initialized in setMode routine */
52         write_dpr(accel, DE_STRETCH_FORMAT,
53                   (read_dpr(accel, DE_STRETCH_FORMAT) & ~clr) | reg);
54
55         /* disable clipping and transparent */
56         write_dpr(accel, DE_CLIP_TL, 0); /* dpr2c */
57         write_dpr(accel, DE_CLIP_BR, 0); /* dpr30 */
58
59         write_dpr(accel, DE_COLOR_COMPARE_MASK, 0); /* dpr24 */
60         write_dpr(accel, DE_COLOR_COMPARE, 0);
61
62         clr = DE_CONTROL_TRANSPARENCY | DE_CONTROL_TRANSPARENCY_MATCH |
63                 DE_CONTROL_TRANSPARENCY_SELECT;
64
65         /* dpr0c */
66         write_dpr(accel, DE_CONTROL, read_dpr(accel, DE_CONTROL) & ~clr);
67 }
68
69 /* set2dformat only be called from setmode functions
70  * but if you need dual framebuffer driver,need call set2dformat
71  * every time you use 2d function */
72
73 void hw_set2dformat(struct lynx_accel *accel, int fmt)
74 {
75         u32 reg;
76
77         /* fmt=0,1,2 for 8,16,32,bpp on sm718/750/502 */
78         reg = read_dpr(accel, DE_STRETCH_FORMAT);
79         reg &= ~DE_STRETCH_FORMAT_PIXEL_FORMAT_MASK;
80         reg |= ((fmt << DE_STRETCH_FORMAT_PIXEL_FORMAT_SHIFT) &
81                 DE_STRETCH_FORMAT_PIXEL_FORMAT_MASK);
82         write_dpr(accel, DE_STRETCH_FORMAT, reg);
83 }
84
85 int hw_fillrect(struct lynx_accel *accel,
86                                 u32 base, u32 pitch, u32 Bpp,
87                                 u32 x, u32 y, u32 width, u32 height,
88                                 u32 color, u32 rop)
89 {
90         u32 deCtrl;
91
92         if (accel->de_wait() != 0) {
93                 /* int time wait and always busy,seems hardware
94                  * got something error */
95                 pr_debug("De engine always busy\n");
96                 return -1;
97         }
98
99         write_dpr(accel, DE_WINDOW_DESTINATION_BASE, base); /* dpr40 */
100         write_dpr(accel, DE_PITCH,
101                   ((pitch / Bpp << DE_PITCH_DESTINATION_SHIFT) &
102                    DE_PITCH_DESTINATION_MASK) |
103                   (pitch / Bpp & DE_PITCH_SOURCE_MASK)); /* dpr10 */
104
105         write_dpr(accel, DE_WINDOW_WIDTH,
106                         FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, pitch/Bpp)|
107                         FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE, pitch/Bpp)); /* dpr44 */
108
109         write_dpr(accel, DE_FOREGROUND, color); /* DPR14 */
110
111         write_dpr(accel, DE_DESTINATION,
112                   ((x << DE_DESTINATION_X_SHIFT) & DE_DESTINATION_X_MASK) |
113                   (y & DE_DESTINATION_Y_MASK)); /* dpr4 */
114
115         write_dpr(accel, DE_DIMENSION,
116                   ((width << DE_DIMENSION_X_SHIFT) & DE_DIMENSION_X_MASK) |
117                   (height & DE_DIMENSION_Y_ET_MASK)); /* dpr8 */
118
119         deCtrl = DE_CONTROL_STATUS | DE_CONTROL_LAST_PIXEL |
120                 DE_CONTROL_COMMAND_RECTANGLE_FILL | DE_CONTROL_ROP_SELECT |
121                 (rop & DE_CONTROL_ROP_MASK); /* dpr0xc */
122
123         write_dpr(accel, DE_CONTROL, deCtrl);
124         return 0;
125 }
126
127 int hw_copyarea(
128 struct lynx_accel *accel,
129 unsigned int sBase,  /* Address of source: offset in frame buffer */
130 unsigned int sPitch, /* Pitch value of source surface in BYTE */
131 unsigned int sx,
132 unsigned int sy,     /* Starting coordinate of source surface */
133 unsigned int dBase,  /* Address of destination: offset in frame buffer */
134 unsigned int dPitch, /* Pitch value of destination surface in BYTE */
135 unsigned int Bpp,    /* Color depth of destination surface */
136 unsigned int dx,
137 unsigned int dy,     /* Starting coordinate of destination surface */
138 unsigned int width,
139 unsigned int height, /* width and height of rectangle in pixel value */
140 unsigned int rop2)   /* ROP value */
141 {
142         unsigned int nDirection, de_ctrl;
143         int opSign;
144
145         nDirection = LEFT_TO_RIGHT;
146         /* Direction of ROP2 operation: 1 = Left to Right, (-1) = Right to Left */
147         opSign = 1;
148         de_ctrl = 0;
149
150         /* If source and destination are the same surface, need to check for overlay cases */
151         if (sBase == dBase && sPitch == dPitch) {
152                 /* Determine direction of operation */
153                 if (sy < dy) {
154                         /* +----------+
155                            |S         |
156                            |   +----------+
157                            |   |      |   |
158                            |   |      |   |
159                            +---|------+   |
160                            |         D|
161                            +----------+ */
162
163                         nDirection = BOTTOM_TO_TOP;
164                 } else if (sy > dy) {
165                         /* +----------+
166                            |D         |
167                            |   +----------+
168                            |   |      |   |
169                            |   |      |   |
170                            +---|------+   |
171                            |         S|
172                            +----------+ */
173
174                         nDirection = TOP_TO_BOTTOM;
175                 } else {
176                         /* sy == dy */
177
178                         if (sx <= dx) {
179                                 /* +------+---+------+
180                                    |S     |   |     D|
181                                    |      |   |      |
182                                    |      |   |      |
183                                    |      |   |      |
184                                    +------+---+------+ */
185
186                                 nDirection = RIGHT_TO_LEFT;
187                         } else {
188                         /* sx > dx */
189
190                                 /* +------+---+------+
191                                    |D     |   |     S|
192                                    |      |   |      |
193                                    |      |   |      |
194                                    |      |   |      |
195                                    +------+---+------+ */
196
197                                 nDirection = LEFT_TO_RIGHT;
198                         }
199                 }
200         }
201
202         if ((nDirection == BOTTOM_TO_TOP) || (nDirection == RIGHT_TO_LEFT)) {
203                 sx += width - 1;
204                 sy += height - 1;
205                 dx += width - 1;
206                 dy += height - 1;
207                 opSign = (-1);
208         }
209
210         /* Note:
211            DE_FOREGROUND are DE_BACKGROUND are don't care.
212           DE_COLOR_COMPARE and DE_COLOR_COMPARE_MAKS are set by set deSetTransparency().
213          */
214
215         /* 2D Source Base.
216          It is an address offset (128 bit aligned) from the beginning of frame buffer.
217          */
218         write_dpr(accel, DE_WINDOW_SOURCE_BASE, sBase); /* dpr40 */
219
220         /* 2D Destination Base.
221          It is an address offset (128 bit aligned) from the beginning of frame buffer.
222          */
223         write_dpr(accel, DE_WINDOW_DESTINATION_BASE, dBase); /* dpr44 */
224
225     /* Program pitch (distance between the 1st points of two adjacent lines).
226        Note that input pitch is BYTE value, but the 2D Pitch register uses
227        pixel values. Need Byte to pixel conversion.
228     */
229         write_dpr(accel, DE_PITCH,
230                   ((dPitch / Bpp << DE_PITCH_DESTINATION_SHIFT) &
231                    DE_PITCH_DESTINATION_MASK) |
232                   (sPitch / Bpp & DE_PITCH_SOURCE_MASK)); /* dpr10 */
233
234     /* Screen Window width in Pixels.
235        2D engine uses this value to calculate the linear address in frame buffer for a given point.
236     */
237         write_dpr(accel, DE_WINDOW_WIDTH,
238         FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, (dPitch/Bpp)) |
239         FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE,      (sPitch/Bpp))); /* dpr3c */
240
241         if (accel->de_wait() != 0)
242                 return -1;
243
244         {
245
246         write_dpr(accel, DE_SOURCE,
247                   ((sx << DE_SOURCE_X_K1_SHIFT) & DE_SOURCE_X_K1_MASK) |
248                   (sy & DE_SOURCE_Y_K2_MASK)); /* dpr0 */
249         write_dpr(accel, DE_DESTINATION,
250                   ((dx << DE_DESTINATION_X_SHIFT) & DE_DESTINATION_X_MASK) |
251                   (dy & DE_DESTINATION_Y_MASK)); /* dpr04 */
252         write_dpr(accel, DE_DIMENSION,
253                   ((width << DE_DIMENSION_X_SHIFT) & DE_DIMENSION_X_MASK) |
254                   (height & DE_DIMENSION_Y_ET_MASK)); /* dpr08 */
255
256         de_ctrl = (rop2 & DE_CONTROL_ROP_MASK) | DE_CONTROL_ROP_SELECT |
257                 ((nDirection == RIGHT_TO_LEFT) ? DE_CONTROL_DIRECTION : 0) |
258                 DE_CONTROL_COMMAND_BITBLT | DE_CONTROL_STATUS;
259         write_dpr(accel, DE_CONTROL, de_ctrl); /* dpr0c */
260
261         }
262
263         return 0;
264 }
265
266 static unsigned int deGetTransparency(struct lynx_accel *accel)
267 {
268         unsigned int de_ctrl;
269
270         de_ctrl = read_dpr(accel, DE_CONTROL);
271
272         de_ctrl &= (DE_CONTROL_TRANSPARENCY_MATCH |
273                     DE_CONTROL_TRANSPARENCY_SELECT | DE_CONTROL_TRANSPARENCY);
274
275         return de_ctrl;
276 }
277
278 int hw_imageblit(struct lynx_accel *accel,
279                  const char *pSrcbuf, /* pointer to start of source buffer in system memory */
280                  u32 srcDelta,          /* Pitch value (in bytes) of the source buffer, +ive means top down and -ive mean button up */
281                  u32 startBit, /* Mono data can start at any bit in a byte, this value should be 0 to 7 */
282                  u32 dBase,    /* Address of destination: offset in frame buffer */
283                  u32 dPitch,   /* Pitch value of destination surface in BYTE */
284                  u32 bytePerPixel,      /* Color depth of destination surface */
285                  u32 dx,
286                  u32 dy,       /* Starting coordinate of destination surface */
287                  u32 width,
288                  u32 height,   /* width and height of rectangle in pixel value */
289                  u32 fColor,   /* Foreground color (corresponding to a 1 in the monochrome data */
290                  u32 bColor,   /* Background color (corresponding to a 0 in the monochrome data */
291                  u32 rop2)     /* ROP value */
292 {
293         unsigned int ulBytesPerScan;
294         unsigned int ul4BytesPerScan;
295         unsigned int ulBytesRemain;
296         unsigned int de_ctrl = 0;
297         unsigned char ajRemain[4];
298         int i, j;
299
300         startBit &= 7; /* Just make sure the start bit is within legal range */
301         ulBytesPerScan = (width + startBit + 7) / 8;
302         ul4BytesPerScan = ulBytesPerScan & ~3;
303         ulBytesRemain = ulBytesPerScan & 3;
304
305         if (accel->de_wait() != 0)
306                 return -1;
307
308         /* 2D Source Base.
309          Use 0 for HOST Blt.
310          */
311         write_dpr(accel, DE_WINDOW_SOURCE_BASE, 0);
312
313         /* 2D Destination Base.
314          It is an address offset (128 bit aligned) from the beginning of frame buffer.
315          */
316         write_dpr(accel, DE_WINDOW_DESTINATION_BASE, dBase);
317     /* Program pitch (distance between the 1st points of two adjacent lines).
318        Note that input pitch is BYTE value, but the 2D Pitch register uses
319        pixel values. Need Byte to pixel conversion.
320     */
321         write_dpr(accel, DE_PITCH,
322                   ((dPitch / bytePerPixel << DE_PITCH_DESTINATION_SHIFT) &
323                    DE_PITCH_DESTINATION_MASK) |
324                   (dPitch / bytePerPixel & DE_PITCH_SOURCE_MASK)); /* dpr10 */
325
326         /* Screen Window width in Pixels.
327          2D engine uses this value to calculate the linear address in frame buffer for a given point.
328          */
329         write_dpr(accel, DE_WINDOW_WIDTH,
330                   FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, (dPitch/bytePerPixel)) |
331                   FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE,      (dPitch/bytePerPixel)));
332
333          /* Note: For 2D Source in Host Write, only X_K1_MONO field is needed, and Y_K2 field is not used.
334             For mono bitmap, use startBit for X_K1. */
335         write_dpr(accel, DE_SOURCE,
336                   (startBit << DE_SOURCE_X_K1_SHIFT) &
337                   DE_SOURCE_X_K1_MONO_MASK); /* dpr00 */
338
339         write_dpr(accel, DE_DESTINATION,
340                   ((dx << DE_DESTINATION_X_SHIFT) & DE_DESTINATION_X_MASK) |
341                   (dy & DE_DESTINATION_Y_MASK)); /* dpr04 */
342
343         write_dpr(accel, DE_DIMENSION,
344                   ((width << DE_DIMENSION_X_SHIFT) & DE_DIMENSION_X_MASK) |
345                   (height & DE_DIMENSION_Y_ET_MASK)); /* dpr08 */
346
347         write_dpr(accel, DE_FOREGROUND, fColor);
348         write_dpr(accel, DE_BACKGROUND, bColor);
349
350         de_ctrl = (rop2 & DE_CONTROL_ROP_MASK) |
351                 DE_CONTROL_ROP_SELECT | DE_CONTROL_COMMAND_HOST_WRITE |
352                 DE_CONTROL_HOST | DE_CONTROL_STATUS;
353
354         write_dpr(accel, DE_CONTROL, de_ctrl | deGetTransparency(accel));
355
356         /* Write MONO data (line by line) to 2D Engine data port */
357         for (i = 0; i < height; i++) {
358                 /* For each line, send the data in chunks of 4 bytes */
359                 for (j = 0; j < (ul4BytesPerScan/4); j++)
360                         write_dpPort(accel, *(unsigned int *)(pSrcbuf + (j * 4)));
361
362                 if (ulBytesRemain) {
363                         memcpy(ajRemain, pSrcbuf+ul4BytesPerScan, ulBytesRemain);
364                         write_dpPort(accel, *(unsigned int *)ajRemain);
365                 }
366
367                 pSrcbuf += srcDelta;
368         }
369
370             return 0;
371 }
372