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