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"
21static inline void write_dpr(struct lynx_accel *accel, int offset, u32 regValue)
22{
23	writel(regValue, accel->dprBase + offset);
24}
25
26static inline u32 read_dpr(struct lynx_accel *accel, int offset)
27{
28	return readl(accel->dprBase + offset);
29}
30
31static inline void write_dpPort(struct lynx_accel *accel, u32 data)
32{
33	writel(data, accel->dpPortBase);
34}
35
36void 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
82void 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
92int 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
138int hw_copyarea(
139struct lynx_accel *accel,
140unsigned int sBase,  /* Address of source: offset in frame buffer */
141unsigned int sPitch, /* Pitch value of source surface in BYTE */
142unsigned int sx,
143unsigned int sy,     /* Starting coordinate of source surface */
144unsigned int dBase,  /* Address of destination: offset in frame buffer */
145unsigned int dPitch, /* Pitch value of destination surface in BYTE */
146unsigned int Bpp,    /* Color depth of destination surface */
147unsigned int dx,
148unsigned int dy,     /* Starting coordinate of destination surface */
149unsigned int width,
150unsigned int height, /* width and height of rectangle in pixel value */
151unsigned 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
284static 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
298int 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