These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / 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     /* Program pitch (distance between the 1st points of two adjacent lines).
237        Note that input pitch is BYTE value, but the 2D Pitch register uses
238        pixel values. Need Byte to pixel conversion.
239     */
240         {
241                 write_dpr(accel, DE_PITCH,
242                                 FIELD_VALUE(0, DE_PITCH, DESTINATION, (dPitch/Bpp)) |
243                                 FIELD_VALUE(0, DE_PITCH, SOURCE,      (sPitch/Bpp))); /* dpr10 */
244         }
245
246     /* Screen Window width in Pixels.
247        2D engine uses this value to calculate the linear address in frame buffer for a given point.
248     */
249         write_dpr(accel, DE_WINDOW_WIDTH,
250         FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, (dPitch/Bpp)) |
251         FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE,      (sPitch/Bpp))); /* dpr3c */
252
253         if (accel->de_wait() != 0)
254                 return -1;
255
256         {
257
258         write_dpr(accel, DE_SOURCE,
259                   FIELD_SET(0, DE_SOURCE, WRAP, DISABLE) |
260                   FIELD_VALUE(0, DE_SOURCE, X_K1, sx)   |
261                   FIELD_VALUE(0, DE_SOURCE, Y_K2, sy)); /* dpr0 */
262         write_dpr(accel, DE_DESTINATION,
263                   FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) |
264                   FIELD_VALUE(0, DE_DESTINATION, X,    dx)  |
265                   FIELD_VALUE(0, DE_DESTINATION, Y,    dy)); /* dpr04 */
266         write_dpr(accel, DE_DIMENSION,
267                   FIELD_VALUE(0, DE_DIMENSION, X,    width) |
268                   FIELD_VALUE(0, DE_DIMENSION, Y_ET, height)); /* dpr08 */
269
270         de_ctrl = FIELD_VALUE(0, DE_CONTROL, ROP, rop2) |
271                   FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
272                   FIELD_SET(0, DE_CONTROL, COMMAND, BITBLT) |
273                   ((nDirection == RIGHT_TO_LEFT) ?
274                   FIELD_SET(0, DE_CONTROL, DIRECTION, RIGHT_TO_LEFT)
275                   : FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT)) |
276                   FIELD_SET(0, DE_CONTROL, STATUS, START);
277         write_dpr(accel, DE_CONTROL, de_ctrl); /* dpr0c */
278
279         }
280
281         return 0;
282 }
283
284 static unsigned int deGetTransparency(struct lynx_accel *accel)
285 {
286         unsigned int de_ctrl;
287
288         de_ctrl = read_dpr(accel, DE_CONTROL);
289
290         de_ctrl &=
291                    FIELD_MASK(DE_CONTROL_TRANSPARENCY_MATCH) |
292                    FIELD_MASK(DE_CONTROL_TRANSPARENCY_SELECT)|
293                    FIELD_MASK(DE_CONTROL_TRANSPARENCY);
294
295         return de_ctrl;
296 }
297
298 int hw_imageblit(struct lynx_accel *accel,
299                  const char *pSrcbuf, /* pointer to start of source buffer in system memory */
300                  u32 srcDelta,          /* Pitch value (in bytes) of the source buffer, +ive means top down and -ive mean button up */
301                  u32 startBit, /* Mono data can start at any bit in a byte, this value should be 0 to 7 */
302                  u32 dBase,    /* Address of destination: offset in frame buffer */
303                  u32 dPitch,   /* Pitch value of destination surface in BYTE */
304                  u32 bytePerPixel,      /* Color depth of destination surface */
305                  u32 dx,
306                  u32 dy,       /* Starting coordinate of destination surface */
307                  u32 width,
308                  u32 height,   /* width and height of rectange in pixel value */
309                  u32 fColor,   /* Foreground color (corresponding to a 1 in the monochrome data */
310                  u32 bColor,   /* Background color (corresponding to a 0 in the monochrome data */
311                  u32 rop2)     /* ROP value */
312 {
313         unsigned int ulBytesPerScan;
314         unsigned int ul4BytesPerScan;
315         unsigned int ulBytesRemain;
316         unsigned int de_ctrl = 0;
317         unsigned char ajRemain[4];
318         int i, j;
319
320         startBit &= 7; /* Just make sure the start bit is within legal range */
321         ulBytesPerScan = (width + startBit + 7) / 8;
322         ul4BytesPerScan = ulBytesPerScan & ~3;
323         ulBytesRemain = ulBytesPerScan & 3;
324
325         if (accel->de_wait() != 0)
326                 return -1;
327
328         /* 2D Source Base.
329          Use 0 for HOST Blt.
330          */
331         write_dpr(accel, DE_WINDOW_SOURCE_BASE, 0);
332
333         /* 2D Destination Base.
334          It is an address offset (128 bit aligned) from the beginning of frame buffer.
335          */
336         write_dpr(accel, DE_WINDOW_DESTINATION_BASE, dBase);
337     /* Program pitch (distance between the 1st points of two adjacent lines).
338        Note that input pitch is BYTE value, but the 2D Pitch register uses
339        pixel values. Need Byte to pixel conversion.
340     */
341         {
342                 write_dpr(accel, DE_PITCH,
343                                 FIELD_VALUE(0, DE_PITCH, DESTINATION, dPitch/bytePerPixel) |
344                                 FIELD_VALUE(0, DE_PITCH, SOURCE,      dPitch/bytePerPixel)); /* dpr10 */
345         }
346
347         /* Screen Window width in Pixels.
348          2D engine uses this value to calculate the linear address in frame buffer for a given point.
349          */
350         write_dpr(accel, DE_WINDOW_WIDTH,
351                   FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, (dPitch/bytePerPixel)) |
352                   FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE,      (dPitch/bytePerPixel)));
353
354          /* Note: For 2D Source in Host Write, only X_K1_MONO field is needed, and Y_K2 field is not used.
355             For mono bitmap, use startBit for X_K1. */
356         write_dpr(accel, DE_SOURCE,
357                   FIELD_SET(0, DE_SOURCE, WRAP, DISABLE)       |
358                   FIELD_VALUE(0, DE_SOURCE, X_K1_MONO, startBit)); /* dpr00 */
359
360         write_dpr(accel, DE_DESTINATION,
361                   FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) |
362                   FIELD_VALUE(0, DE_DESTINATION, X,    dx)    |
363                   FIELD_VALUE(0, DE_DESTINATION, Y,    dy)); /* dpr04 */
364
365         write_dpr(accel, DE_DIMENSION,
366                   FIELD_VALUE(0, DE_DIMENSION, X,    width) |
367                   FIELD_VALUE(0, DE_DIMENSION, Y_ET, height)); /* dpr08 */
368
369         write_dpr(accel, DE_FOREGROUND, fColor);
370         write_dpr(accel, DE_BACKGROUND, bColor);
371
372         de_ctrl = FIELD_VALUE(0, DE_CONTROL, ROP, rop2)         |
373                 FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2)    |
374                 FIELD_SET(0, DE_CONTROL, COMMAND, HOST_WRITE) |
375                 FIELD_SET(0, DE_CONTROL, HOST, MONO)          |
376                 FIELD_SET(0, DE_CONTROL, STATUS, START);
377
378         write_dpr(accel, DE_CONTROL, de_ctrl | deGetTransparency(accel));
379
380         /* Write MONO data (line by line) to 2D Engine data port */
381         for (i = 0; i < height; i++) {
382                 /* For each line, send the data in chunks of 4 bytes */
383                 for (j = 0; j < (ul4BytesPerScan/4); j++)
384                         write_dpPort(accel, *(unsigned int *)(pSrcbuf + (j * 4)));
385
386                 if (ulBytesRemain) {
387                         memcpy(ajRemain, pSrcbuf+ul4BytesPerScan, ulBytesRemain);
388                         write_dpPort(accel, *(unsigned int *)ajRemain);
389                 }
390
391                 pSrcbuf += srcDelta;
392         }
393
394             return 0;
395 }
396