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