1 #include <linux/module.h>
2 #include <linux/kernel.h>
3 #include <linux/errno.h>
4 #include <linux/string.h>
6 #include <linux/slab.h>
7 #include <linux/delay.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>
14 #include <linux/console.h>
15 #include <linux/platform_device.h>
16 #include <linux/screen_info.h>
19 #include "sm750_accel.h"
20 static inline void write_dpr(struct lynx_accel *accel, int offset, u32 regValue)
22 writel(regValue, accel->dprBase + offset);
25 static inline u32 read_dpr(struct lynx_accel *accel, int offset)
27 return readl(accel->dprBase + offset);
30 static inline void write_dpPort(struct lynx_accel *accel, u32 data)
32 writel(data, accel->dpPortBase);
35 void hw_de_init(struct lynx_accel *accel)
37 /* setup 2d engine registers */
40 write_dpr(accel, DE_MASKS, 0xFFFFFFFF);
45 clr = DE_STRETCH_FORMAT_PATTERN_XY | DE_STRETCH_FORMAT_PATTERN_Y_MASK |
46 DE_STRETCH_FORMAT_PATTERN_X_MASK |
47 DE_STRETCH_FORMAT_ADDRESSING_MASK |
48 DE_STRETCH_FORMAT_SOURCE_HEIGHT_MASK;
50 /* DE_STRETCH bpp format need be initialized in setMode routine */
51 write_dpr(accel, DE_STRETCH_FORMAT,
52 (read_dpr(accel, DE_STRETCH_FORMAT) & ~clr) | reg);
54 /* disable clipping and transparent */
55 write_dpr(accel, DE_CLIP_TL, 0); /* dpr2c */
56 write_dpr(accel, DE_CLIP_BR, 0); /* dpr30 */
58 write_dpr(accel, DE_COLOR_COMPARE_MASK, 0); /* dpr24 */
59 write_dpr(accel, DE_COLOR_COMPARE, 0);
61 clr = DE_CONTROL_TRANSPARENCY | DE_CONTROL_TRANSPARENCY_MATCH |
62 DE_CONTROL_TRANSPARENCY_SELECT;
65 write_dpr(accel, DE_CONTROL, read_dpr(accel, DE_CONTROL) & ~clr);
68 /* set2dformat only be called from setmode functions
69 * but if you need dual framebuffer driver,need call set2dformat
70 * every time you use 2d function
73 void hw_set2dformat(struct lynx_accel *accel, int fmt)
77 /* fmt=0,1,2 for 8,16,32,bpp on sm718/750/502 */
78 reg = read_dpr(accel, DE_STRETCH_FORMAT);
79 reg &= ~DE_STRETCH_FORMAT_PIXEL_FORMAT_MASK;
80 reg |= ((fmt << DE_STRETCH_FORMAT_PIXEL_FORMAT_SHIFT) &
81 DE_STRETCH_FORMAT_PIXEL_FORMAT_MASK);
82 write_dpr(accel, DE_STRETCH_FORMAT, reg);
85 int hw_fillrect(struct lynx_accel *accel,
86 u32 base, u32 pitch, u32 Bpp,
87 u32 x, u32 y, u32 width, u32 height,
92 if (accel->de_wait() != 0) {
93 /* int time wait and always busy,seems hardware
96 pr_debug("De engine always busy\n");
100 write_dpr(accel, DE_WINDOW_DESTINATION_BASE, base); /* dpr40 */
101 write_dpr(accel, DE_PITCH,
102 ((pitch / Bpp << DE_PITCH_DESTINATION_SHIFT) &
103 DE_PITCH_DESTINATION_MASK) |
104 (pitch / Bpp & DE_PITCH_SOURCE_MASK)); /* dpr10 */
106 write_dpr(accel, DE_WINDOW_WIDTH,
107 ((pitch / Bpp << DE_WINDOW_WIDTH_DST_SHIFT) &
108 DE_WINDOW_WIDTH_DST_MASK) |
109 (pitch / Bpp & DE_WINDOW_WIDTH_SRC_MASK)); /* dpr44 */
111 write_dpr(accel, DE_FOREGROUND, color); /* DPR14 */
113 write_dpr(accel, DE_DESTINATION,
114 ((x << DE_DESTINATION_X_SHIFT) & DE_DESTINATION_X_MASK) |
115 (y & DE_DESTINATION_Y_MASK)); /* dpr4 */
117 write_dpr(accel, DE_DIMENSION,
118 ((width << DE_DIMENSION_X_SHIFT) & DE_DIMENSION_X_MASK) |
119 (height & DE_DIMENSION_Y_ET_MASK)); /* dpr8 */
121 deCtrl = DE_CONTROL_STATUS | DE_CONTROL_LAST_PIXEL |
122 DE_CONTROL_COMMAND_RECTANGLE_FILL | DE_CONTROL_ROP_SELECT |
123 (rop & DE_CONTROL_ROP_MASK); /* dpr0xc */
125 write_dpr(accel, DE_CONTROL, deCtrl);
130 struct lynx_accel *accel,
131 unsigned int sBase, /* Address of source: offset in frame buffer */
132 unsigned int sPitch, /* Pitch value of source surface in BYTE */
134 unsigned int sy, /* Starting coordinate of source surface */
135 unsigned int dBase, /* Address of destination: offset in frame buffer */
136 unsigned int dPitch, /* Pitch value of destination surface in BYTE */
137 unsigned int Bpp, /* Color depth of destination surface */
139 unsigned int dy, /* Starting coordinate of destination surface */
141 unsigned int height, /* width and height of rectangle in pixel value */
142 unsigned int rop2) /* ROP value */
144 unsigned int nDirection, de_ctrl;
147 nDirection = LEFT_TO_RIGHT;
148 /* Direction of ROP2 operation: 1 = Left to Right, (-1) = Right to Left */
152 /* If source and destination are the same surface, need to check for overlay cases */
153 if (sBase == dBase && sPitch == dPitch) {
154 /* Determine direction of operation */
166 nDirection = BOTTOM_TO_TOP;
167 } else if (sy > dy) {
178 nDirection = TOP_TO_BOTTOM;
183 /* +------+---+------+
188 * +------+---+------+
191 nDirection = RIGHT_TO_LEFT;
195 /* +------+---+------+
200 * +------+---+------+
203 nDirection = LEFT_TO_RIGHT;
208 if ((nDirection == BOTTOM_TO_TOP) || (nDirection == RIGHT_TO_LEFT)) {
217 * DE_FOREGROUND are DE_BACKGROUND are don't care.
218 * DE_COLOR_COMPARE and DE_COLOR_COMPARE_MAKS
219 * are set by set deSetTransparency().
223 * It is an address offset (128 bit aligned)
224 * from the beginning of frame buffer.
226 write_dpr(accel, DE_WINDOW_SOURCE_BASE, sBase); /* dpr40 */
228 /* 2D Destination Base.
229 * It is an address offset (128 bit aligned)
230 * from the beginning of frame buffer.
232 write_dpr(accel, DE_WINDOW_DESTINATION_BASE, dBase); /* dpr44 */
234 /* Program pitch (distance between the 1st points of two adjacent lines).
235 * Note that input pitch is BYTE value, but the 2D Pitch register uses
236 * pixel values. Need Byte to pixel conversion.
238 write_dpr(accel, DE_PITCH,
239 ((dPitch / Bpp << DE_PITCH_DESTINATION_SHIFT) &
240 DE_PITCH_DESTINATION_MASK) |
241 (sPitch / Bpp & DE_PITCH_SOURCE_MASK)); /* dpr10 */
243 /* Screen Window width in Pixels.
244 * 2D engine uses this value to calculate the linear address in frame buffer
247 write_dpr(accel, DE_WINDOW_WIDTH,
248 ((dPitch / Bpp << DE_WINDOW_WIDTH_DST_SHIFT) &
249 DE_WINDOW_WIDTH_DST_MASK) |
250 (sPitch / Bpp & DE_WINDOW_WIDTH_SRC_MASK)); /* dpr3c */
252 if (accel->de_wait() != 0)
257 write_dpr(accel, DE_SOURCE,
258 ((sx << DE_SOURCE_X_K1_SHIFT) & DE_SOURCE_X_K1_MASK) |
259 (sy & DE_SOURCE_Y_K2_MASK)); /* dpr0 */
260 write_dpr(accel, DE_DESTINATION,
261 ((dx << DE_DESTINATION_X_SHIFT) & DE_DESTINATION_X_MASK) |
262 (dy & DE_DESTINATION_Y_MASK)); /* dpr04 */
263 write_dpr(accel, DE_DIMENSION,
264 ((width << DE_DIMENSION_X_SHIFT) & DE_DIMENSION_X_MASK) |
265 (height & DE_DIMENSION_Y_ET_MASK)); /* dpr08 */
267 de_ctrl = (rop2 & DE_CONTROL_ROP_MASK) | DE_CONTROL_ROP_SELECT |
268 ((nDirection == RIGHT_TO_LEFT) ? DE_CONTROL_DIRECTION : 0) |
269 DE_CONTROL_COMMAND_BITBLT | DE_CONTROL_STATUS;
270 write_dpr(accel, DE_CONTROL, de_ctrl); /* dpr0c */
277 static unsigned int deGetTransparency(struct lynx_accel *accel)
279 unsigned int de_ctrl;
281 de_ctrl = read_dpr(accel, DE_CONTROL);
283 de_ctrl &= (DE_CONTROL_TRANSPARENCY_MATCH |
284 DE_CONTROL_TRANSPARENCY_SELECT | DE_CONTROL_TRANSPARENCY);
289 int hw_imageblit(struct lynx_accel *accel,
290 const char *pSrcbuf, /* pointer to start of source buffer in system memory */
291 u32 srcDelta, /* Pitch value (in bytes) of the source buffer, +ive means top down and -ive mean button up */
292 u32 startBit, /* Mono data can start at any bit in a byte, this value should be 0 to 7 */
293 u32 dBase, /* Address of destination: offset in frame buffer */
294 u32 dPitch, /* Pitch value of destination surface in BYTE */
295 u32 bytePerPixel, /* Color depth of destination surface */
297 u32 dy, /* Starting coordinate of destination surface */
299 u32 height, /* width and height of rectangle in pixel value */
300 u32 fColor, /* Foreground color (corresponding to a 1 in the monochrome data */
301 u32 bColor, /* Background color (corresponding to a 0 in the monochrome data */
302 u32 rop2) /* ROP value */
304 unsigned int ulBytesPerScan;
305 unsigned int ul4BytesPerScan;
306 unsigned int ulBytesRemain;
307 unsigned int de_ctrl = 0;
308 unsigned char ajRemain[4];
311 startBit &= 7; /* Just make sure the start bit is within legal range */
312 ulBytesPerScan = (width + startBit + 7) / 8;
313 ul4BytesPerScan = ulBytesPerScan & ~3;
314 ulBytesRemain = ulBytesPerScan & 3;
316 if (accel->de_wait() != 0)
320 * Use 0 for HOST Blt.
322 write_dpr(accel, DE_WINDOW_SOURCE_BASE, 0);
324 /* 2D Destination Base.
325 * It is an address offset (128 bit aligned)
326 * from the beginning of frame buffer.
328 write_dpr(accel, DE_WINDOW_DESTINATION_BASE, dBase);
329 /* Program pitch (distance between the 1st points of two adjacent lines).
330 * Note that input pitch is BYTE value, but the 2D Pitch register uses
331 * pixel values. Need Byte to pixel conversion.
333 write_dpr(accel, DE_PITCH,
334 ((dPitch / bytePerPixel << DE_PITCH_DESTINATION_SHIFT) &
335 DE_PITCH_DESTINATION_MASK) |
336 (dPitch / bytePerPixel & DE_PITCH_SOURCE_MASK)); /* dpr10 */
338 /* Screen Window width in Pixels.
339 * 2D engine uses this value to calculate the linear address
340 * in frame buffer for a given point.
342 write_dpr(accel, DE_WINDOW_WIDTH,
343 ((dPitch / bytePerPixel << DE_WINDOW_WIDTH_DST_SHIFT) &
344 DE_WINDOW_WIDTH_DST_MASK) |
345 (dPitch / bytePerPixel & DE_WINDOW_WIDTH_SRC_MASK));
347 /* Note: For 2D Source in Host Write, only X_K1_MONO field is needed,
348 * and Y_K2 field is not used.
349 * For mono bitmap, use startBit for X_K1.
351 write_dpr(accel, DE_SOURCE,
352 (startBit << DE_SOURCE_X_K1_SHIFT) &
353 DE_SOURCE_X_K1_MONO_MASK); /* dpr00 */
355 write_dpr(accel, DE_DESTINATION,
356 ((dx << DE_DESTINATION_X_SHIFT) & DE_DESTINATION_X_MASK) |
357 (dy & DE_DESTINATION_Y_MASK)); /* dpr04 */
359 write_dpr(accel, DE_DIMENSION,
360 ((width << DE_DIMENSION_X_SHIFT) & DE_DIMENSION_X_MASK) |
361 (height & DE_DIMENSION_Y_ET_MASK)); /* dpr08 */
363 write_dpr(accel, DE_FOREGROUND, fColor);
364 write_dpr(accel, DE_BACKGROUND, bColor);
366 de_ctrl = (rop2 & DE_CONTROL_ROP_MASK) |
367 DE_CONTROL_ROP_SELECT | DE_CONTROL_COMMAND_HOST_WRITE |
368 DE_CONTROL_HOST | DE_CONTROL_STATUS;
370 write_dpr(accel, DE_CONTROL, de_ctrl | deGetTransparency(accel));
372 /* Write MONO data (line by line) to 2D Engine data port */
373 for (i = 0; i < height; i++) {
374 /* For each line, send the data in chunks of 4 bytes */
375 for (j = 0; j < (ul4BytesPerScan/4); j++)
376 write_dpPort(accel, *(unsigned int *)(pSrcbuf + (j * 4)));
379 memcpy(ajRemain, pSrcbuf+ul4BytesPerScan, ulBytesRemain);
380 write_dpPort(accel, *(unsigned int *)ajRemain);