Merge tag 'sound-5.14-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai...
[linux-2.6-microblaze.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 /**
134  * sm750_hw_copyarea
135  * @accel: Acceleration device data
136  * @sBase: Address of source: offset in frame buffer
137  * @sPitch: Pitch value of source surface in BYTE
138  * @sx: Starting x coordinate of source surface
139  * @sy: Starting y coordinate of source surface
140  * @dBase: Address of destination: offset in frame buffer
141  * @dPitch: Pitch value of destination surface in BYTE
142  * @Bpp: Color depth of destination surface
143  * @dx: Starting x coordinate of destination surface
144  * @dy: Starting y coordinate of destination surface
145  * @width: width of rectangle in pixel value
146  * @height: height of rectangle in pixel value
147  * @rop2: ROP value
148  */
149 int sm750_hw_copyarea(struct lynx_accel *accel,
150                       unsigned int sBase, unsigned int sPitch,
151                       unsigned int sx, unsigned int sy,
152                       unsigned int dBase, unsigned int dPitch,
153                       unsigned int Bpp, unsigned int dx, unsigned int dy,
154                       unsigned int width, unsigned int height,
155                       unsigned int rop2)
156 {
157         unsigned int nDirection, de_ctrl;
158
159         nDirection = LEFT_TO_RIGHT;
160         /* Direction of ROP2 operation: 1 = Left to Right, (-1) = Right to Left */
161         de_ctrl = 0;
162
163         /* If source and destination are the same surface, need to check for overlay cases */
164         if (sBase == dBase && sPitch == dPitch) {
165                 /* Determine direction of operation */
166                 if (sy < dy) {
167                         /*  +----------+
168                          *  |S         |
169                          *  |   +----------+
170                          *  |   |      |   |
171                          *  |   |      |   |
172                          *  +---|------+   |
173                          *      |         D|
174                          *      +----------+
175                          */
176
177                         nDirection = BOTTOM_TO_TOP;
178                 } else if (sy > dy) {
179                         /*  +----------+
180                          *  |D         |
181                          *  |   +----------+
182                          *  |   |      |   |
183                          *  |   |      |   |
184                          *  +---|------+   |
185                          *      |         S|
186                          *      +----------+
187                          */
188
189                         nDirection = TOP_TO_BOTTOM;
190                 } else {
191                         /* sy == dy */
192
193                         if (sx <= dx) {
194                                 /* +------+---+------+
195                                  * |S     |   |     D|
196                                  * |      |   |      |
197                                  * |      |   |      |
198                                  * |      |   |      |
199                                  * +------+---+------+
200                                  */
201
202                                 nDirection = RIGHT_TO_LEFT;
203                         } else {
204                         /* sx > dx */
205
206                                 /* +------+---+------+
207                                  * |D     |   |     S|
208                                  * |      |   |      |
209                                  * |      |   |      |
210                                  * |      |   |      |
211                                  * +------+---+------+
212                                  */
213
214                                 nDirection = LEFT_TO_RIGHT;
215                         }
216                 }
217         }
218
219         if ((nDirection == BOTTOM_TO_TOP) || (nDirection == RIGHT_TO_LEFT)) {
220                 sx += width - 1;
221                 sy += height - 1;
222                 dx += width - 1;
223                 dy += height - 1;
224         }
225
226         /*
227          * Note:
228          * DE_FOREGROUND and DE_BACKGROUND are don't care.
229          * DE_COLOR_COMPARE and DE_COLOR_COMPARE_MAKS
230          * are set by set deSetTransparency().
231          */
232
233         /*
234          * 2D Source Base.
235          * It is an address offset (128 bit aligned)
236          * from the beginning of frame buffer.
237          */
238         write_dpr(accel, DE_WINDOW_SOURCE_BASE, sBase); /* dpr40 */
239
240         /*
241          * 2D Destination Base.
242          * It is an address offset (128 bit aligned)
243          * from the beginning of frame buffer.
244          */
245         write_dpr(accel, DE_WINDOW_DESTINATION_BASE, dBase); /* dpr44 */
246
247         /*
248          * Program pitch (distance between the 1st points of two adjacent lines).
249          * Note that input pitch is BYTE value, but the 2D Pitch register uses
250          * pixel values. Need Byte to pixel conversion.
251          */
252         write_dpr(accel, DE_PITCH,
253                   ((dPitch / Bpp << DE_PITCH_DESTINATION_SHIFT) &
254                    DE_PITCH_DESTINATION_MASK) |
255                   (sPitch / Bpp & DE_PITCH_SOURCE_MASK)); /* dpr10 */
256
257         /*
258          * Screen Window width in Pixels.
259          * 2D engine uses this value to calculate the linear address in frame buffer
260          * for a given point.
261          */
262         write_dpr(accel, DE_WINDOW_WIDTH,
263                   ((dPitch / Bpp << DE_WINDOW_WIDTH_DST_SHIFT) &
264                    DE_WINDOW_WIDTH_DST_MASK) |
265                   (sPitch / Bpp & DE_WINDOW_WIDTH_SRC_MASK)); /* dpr3c */
266
267         if (accel->de_wait() != 0)
268                 return -1;
269
270         write_dpr(accel, DE_SOURCE,
271                   ((sx << DE_SOURCE_X_K1_SHIFT) & DE_SOURCE_X_K1_MASK) |
272                   (sy & DE_SOURCE_Y_K2_MASK)); /* dpr0 */
273         write_dpr(accel, DE_DESTINATION,
274                   ((dx << DE_DESTINATION_X_SHIFT) & DE_DESTINATION_X_MASK) |
275                   (dy & DE_DESTINATION_Y_MASK)); /* dpr04 */
276         write_dpr(accel, DE_DIMENSION,
277                   ((width << DE_DIMENSION_X_SHIFT) & DE_DIMENSION_X_MASK) |
278                   (height & DE_DIMENSION_Y_ET_MASK)); /* dpr08 */
279
280         de_ctrl = (rop2 & DE_CONTROL_ROP_MASK) | DE_CONTROL_ROP_SELECT |
281                 ((nDirection == RIGHT_TO_LEFT) ? DE_CONTROL_DIRECTION : 0) |
282                 DE_CONTROL_COMMAND_BITBLT | DE_CONTROL_STATUS;
283         write_dpr(accel, DE_CONTROL, de_ctrl); /* dpr0c */
284
285         return 0;
286 }
287
288 static unsigned int deGetTransparency(struct lynx_accel *accel)
289 {
290         unsigned int de_ctrl;
291
292         de_ctrl = read_dpr(accel, DE_CONTROL);
293
294         de_ctrl &= (DE_CONTROL_TRANSPARENCY_MATCH |
295                     DE_CONTROL_TRANSPARENCY_SELECT | DE_CONTROL_TRANSPARENCY);
296
297         return de_ctrl;
298 }
299
300 /**
301  * sm750_hw_imageblit
302  * @accel: Acceleration device data
303  * @pSrcbuf: pointer to start of source buffer in system memory
304  * @srcDelta: Pitch value (in bytes) of the source buffer, +ive means top down
305  *            and -ive mean button up
306  * @startBit: Mono data can start at any bit in a byte, this value should be
307  *            0 to 7
308  * @dBase: Address of destination: offset in frame buffer
309  * @dPitch: Pitch value of destination surface in BYTE
310  * @bytePerPixel: Color depth of destination surface
311  * @dx: Starting x coordinate of destination surface
312  * @dy: Starting y coordinate of destination surface
313  * @width: width of rectangle in pixel value
314  * @height: height of rectangle in pixel value
315  * @fColor: Foreground color (corresponding to a 1 in the monochrome data
316  * @bColor: Background color (corresponding to a 0 in the monochrome data
317  * @rop2: ROP value
318  */
319 int sm750_hw_imageblit(struct lynx_accel *accel, const char *pSrcbuf,
320                        u32 srcDelta, u32 startBit, u32 dBase, u32 dPitch,
321                        u32 bytePerPixel, u32 dx, u32 dy, u32 width,
322                        u32 height, u32 fColor, u32 bColor, u32 rop2)
323 {
324         unsigned int ulBytesPerScan;
325         unsigned int ul4BytesPerScan;
326         unsigned int ulBytesRemain;
327         unsigned int de_ctrl = 0;
328         unsigned char ajRemain[4];
329         int i, j;
330
331         startBit &= 7; /* Just make sure the start bit is within legal range */
332         ulBytesPerScan = (width + startBit + 7) / 8;
333         ul4BytesPerScan = ulBytesPerScan & ~3;
334         ulBytesRemain = ulBytesPerScan & 3;
335
336         if (accel->de_wait() != 0)
337                 return -1;
338
339         /*
340          * 2D Source Base.
341          * Use 0 for HOST Blt.
342          */
343         write_dpr(accel, DE_WINDOW_SOURCE_BASE, 0);
344
345         /* 2D Destination Base.
346          * It is an address offset (128 bit aligned)
347          * from the beginning of frame buffer.
348          */
349         write_dpr(accel, DE_WINDOW_DESTINATION_BASE, dBase);
350
351         /*
352          * Program pitch (distance between the 1st points of two adjacent
353          * lines). Note that input pitch is BYTE value, but the 2D Pitch
354          * register uses pixel values. Need Byte to pixel conversion.
355          */
356         write_dpr(accel, DE_PITCH,
357                   ((dPitch / bytePerPixel << DE_PITCH_DESTINATION_SHIFT) &
358                    DE_PITCH_DESTINATION_MASK) |
359                   (dPitch / bytePerPixel & DE_PITCH_SOURCE_MASK)); /* dpr10 */
360
361         /*
362          * Screen Window width in Pixels.
363          * 2D engine uses this value to calculate the linear address
364          * in frame buffer for a given point.
365          */
366         write_dpr(accel, DE_WINDOW_WIDTH,
367                   ((dPitch / bytePerPixel << DE_WINDOW_WIDTH_DST_SHIFT) &
368                    DE_WINDOW_WIDTH_DST_MASK) |
369                   (dPitch / bytePerPixel & DE_WINDOW_WIDTH_SRC_MASK));
370
371          /*
372           * Note: For 2D Source in Host Write, only X_K1_MONO field is needed,
373           * and Y_K2 field is not used.
374           * For mono bitmap, use startBit for X_K1.
375           */
376         write_dpr(accel, DE_SOURCE,
377                   (startBit << DE_SOURCE_X_K1_SHIFT) &
378                   DE_SOURCE_X_K1_MONO_MASK); /* dpr00 */
379
380         write_dpr(accel, DE_DESTINATION,
381                   ((dx << DE_DESTINATION_X_SHIFT) & DE_DESTINATION_X_MASK) |
382                   (dy & DE_DESTINATION_Y_MASK)); /* dpr04 */
383
384         write_dpr(accel, DE_DIMENSION,
385                   ((width << DE_DIMENSION_X_SHIFT) & DE_DIMENSION_X_MASK) |
386                   (height & DE_DIMENSION_Y_ET_MASK)); /* dpr08 */
387
388         write_dpr(accel, DE_FOREGROUND, fColor);
389         write_dpr(accel, DE_BACKGROUND, bColor);
390
391         de_ctrl = (rop2 & DE_CONTROL_ROP_MASK) |
392                 DE_CONTROL_ROP_SELECT | DE_CONTROL_COMMAND_HOST_WRITE |
393                 DE_CONTROL_HOST | DE_CONTROL_STATUS;
394
395         write_dpr(accel, DE_CONTROL, de_ctrl | deGetTransparency(accel));
396
397         /* Write MONO data (line by line) to 2D Engine data port */
398         for (i = 0; i < height; i++) {
399                 /* For each line, send the data in chunks of 4 bytes */
400                 for (j = 0; j < (ul4BytesPerScan / 4); j++)
401                         write_dpPort(accel, *(unsigned int *)(pSrcbuf + (j * 4)));
402
403                 if (ulBytesRemain) {
404                         memcpy(ajRemain, pSrcbuf + ul4BytesPerScan,
405                                ulBytesRemain);
406                         write_dpPort(accel, *(unsigned int *)ajRemain);
407                 }
408
409                 pSrcbuf += srcDelta;
410         }
411
412         return 0;
413 }
414