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>
7 #include <linux/slab.h>
8 #include <linux/delay.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>
20 #include "sm750_accel.h"
21 static inline void write_dpr(struct lynx_accel *accel, int offset, u32 regValue)
23 writel(regValue, accel->dprBase + offset);
26 static inline u32 read_dpr(struct lynx_accel *accel, int offset)
28 return readl(accel->dprBase + offset);
31 static inline void write_dpPort(struct lynx_accel *accel, u32 data)
33 writel(data, accel->dpPortBase);
36 void sm750_hw_de_init(struct lynx_accel *accel)
38 /* setup 2d engine registers */
41 write_dpr(accel, DE_MASKS, 0xFFFFFFFF);
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;
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);
56 /* disable clipping and transparent */
57 write_dpr(accel, DE_CLIP_TL, 0); /* dpr2c */
58 write_dpr(accel, DE_CLIP_BR, 0); /* dpr30 */
60 write_dpr(accel, DE_COLOR_COMPARE_MASK, 0); /* dpr24 */
61 write_dpr(accel, DE_COLOR_COMPARE, 0);
63 clr = DE_CONTROL_TRANSPARENCY | DE_CONTROL_TRANSPARENCY_MATCH |
64 DE_CONTROL_TRANSPARENCY_SELECT;
67 write_dpr(accel, DE_CONTROL, read_dpr(accel, DE_CONTROL) & ~clr);
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
76 void sm750_hw_set2dformat(struct lynx_accel *accel, int fmt)
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);
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,
95 if (accel->de_wait() != 0) {
97 * int time wait and always busy,seems hardware
100 pr_debug("De engine always busy\n");
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 */
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 */
115 write_dpr(accel, DE_FOREGROUND, color); /* DPR14 */
117 write_dpr(accel, DE_DESTINATION,
118 ((x << DE_DESTINATION_X_SHIFT) & DE_DESTINATION_X_MASK) |
119 (y & DE_DESTINATION_Y_MASK)); /* dpr4 */
121 write_dpr(accel, DE_DIMENSION,
122 ((width << DE_DIMENSION_X_SHIFT) & DE_DIMENSION_X_MASK) |
123 (height & DE_DIMENSION_Y_ET_MASK)); /* dpr8 */
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 */
129 write_dpr(accel, DE_CONTROL, deCtrl);
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
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,
156 unsigned int nDirection, de_ctrl;
158 nDirection = LEFT_TO_RIGHT;
159 /* Direction of ROP2 operation: 1 = Left to Right, (-1) = Right to Left */
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 */
176 nDirection = BOTTOM_TO_TOP;
177 } else if (sy > dy) {
188 nDirection = TOP_TO_BOTTOM;
193 /* +------+---+------+
198 * +------+---+------+
201 nDirection = RIGHT_TO_LEFT;
205 /* +------+---+------+
210 * +------+---+------+
213 nDirection = LEFT_TO_RIGHT;
218 if ((nDirection == BOTTOM_TO_TOP) || (nDirection == RIGHT_TO_LEFT)) {
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().
234 * It is an address offset (128 bit aligned)
235 * from the beginning of frame buffer.
237 write_dpr(accel, DE_WINDOW_SOURCE_BASE, sBase); /* dpr40 */
240 * 2D Destination Base.
241 * It is an address offset (128 bit aligned)
242 * from the beginning of frame buffer.
244 write_dpr(accel, DE_WINDOW_DESTINATION_BASE, dBase); /* dpr44 */
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.
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 */
257 * Screen Window width in Pixels.
258 * 2D engine uses this value to calculate the linear address in frame buffer
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 */
266 if (accel->de_wait() != 0)
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 */
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 */
287 static unsigned int deGetTransparency(struct lynx_accel *accel)
289 unsigned int de_ctrl;
291 de_ctrl = read_dpr(accel, DE_CONTROL);
293 de_ctrl &= (DE_CONTROL_TRANSPARENCY_MATCH |
294 DE_CONTROL_TRANSPARENCY_SELECT | DE_CONTROL_TRANSPARENCY);
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
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
317 int 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)
322 unsigned int ulBytesPerScan;
323 unsigned int ul4BytesPerScan;
324 unsigned int ulBytesRemain;
325 unsigned int de_ctrl = 0;
326 unsigned char ajRemain[4];
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;
334 if (accel->de_wait() != 0)
339 * Use 0 for HOST Blt.
341 write_dpr(accel, DE_WINDOW_SOURCE_BASE, 0);
343 /* 2D Destination Base.
344 * It is an address offset (128 bit aligned)
345 * from the beginning of frame buffer.
347 write_dpr(accel, DE_WINDOW_DESTINATION_BASE, dBase);
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.
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 */
360 * Screen Window width in Pixels.
361 * 2D engine uses this value to calculate the linear address
362 * in frame buffer for a given point.
364 write_dpr(accel, DE_WINDOW_WIDTH,
365 ((dPitch / bytePerPixel << DE_WINDOW_WIDTH_DST_SHIFT) &
366 DE_WINDOW_WIDTH_DST_MASK) |
367 (dPitch / bytePerPixel & DE_WINDOW_WIDTH_SRC_MASK));
370 * Note: For 2D Source in Host Write, only X_K1_MONO field is needed,
371 * and Y_K2 field is not used.
372 * For mono bitmap, use startBit for X_K1.
374 write_dpr(accel, DE_SOURCE,
375 (startBit << DE_SOURCE_X_K1_SHIFT) &
376 DE_SOURCE_X_K1_MONO_MASK); /* dpr00 */
378 write_dpr(accel, DE_DESTINATION,
379 ((dx << DE_DESTINATION_X_SHIFT) & DE_DESTINATION_X_MASK) |
380 (dy & DE_DESTINATION_Y_MASK)); /* dpr04 */
382 write_dpr(accel, DE_DIMENSION,
383 ((width << DE_DIMENSION_X_SHIFT) & DE_DIMENSION_X_MASK) |
384 (height & DE_DIMENSION_Y_ET_MASK)); /* dpr08 */
386 write_dpr(accel, DE_FOREGROUND, fColor);
387 write_dpr(accel, DE_BACKGROUND, bColor);
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;
393 write_dpr(accel, DE_CONTROL, de_ctrl | deGetTransparency(accel));
395 /* Write MONO data (line by line) to 2D Engine data port */
396 for (i = 0; i < height; i++) {
397 /* For each line, send the data in chunks of 4 bytes */
398 for (j = 0; j < (ul4BytesPerScan / 4); j++)
399 write_dpPort(accel, *(unsigned int *)(pSrcbuf + (j * 4)));
402 memcpy(ajRemain, pSrcbuf + ul4BytesPerScan,
404 write_dpPort(accel, *(unsigned int *)ajRemain);