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