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