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