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