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