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