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	{
101		/* int time wait and always busy,seems hardware
102		 * got something error */
103		pr_debug("%s:De engine always bussy\n",__func__);
104		return -1;
105	}
106
107	write_dpr(accel,DE_WINDOW_DESTINATION_BASE,base);//dpr40
108	write_dpr(accel,DE_PITCH,
109			FIELD_VALUE(0,DE_PITCH,DESTINATION,pitch/Bpp)|
110			FIELD_VALUE(0,DE_PITCH,SOURCE,pitch/Bpp));//dpr10
111
112	write_dpr(accel,DE_WINDOW_WIDTH,
113			FIELD_VALUE(0,DE_WINDOW_WIDTH,DESTINATION,pitch/Bpp)|
114			FIELD_VALUE(0,DE_WINDOW_WIDTH,SOURCE,pitch/Bpp));//dpr44
115
116	write_dpr(accel,DE_FOREGROUND,color);//DPR14
117
118	write_dpr(accel,DE_DESTINATION,
119			FIELD_SET(0,DE_DESTINATION,WRAP,DISABLE)|
120			FIELD_VALUE(0,DE_DESTINATION,X,x)|
121			FIELD_VALUE(0,DE_DESTINATION,Y,y));//dpr4
122
123	write_dpr(accel,DE_DIMENSION,
124			FIELD_VALUE(0,DE_DIMENSION,X,width)|
125			FIELD_VALUE(0,DE_DIMENSION,Y_ET,height));//dpr8
126
127	deCtrl =
128		FIELD_SET(0,DE_CONTROL,STATUS,START)|
129		FIELD_SET(0,DE_CONTROL,DIRECTION,LEFT_TO_RIGHT)|
130		FIELD_SET(0,DE_CONTROL,LAST_PIXEL,ON)|
131		FIELD_SET(0,DE_CONTROL,COMMAND,RECTANGLE_FILL)|
132		FIELD_SET(0,DE_CONTROL,ROP_SELECT,ROP2)|
133		FIELD_VALUE(0,DE_CONTROL,ROP,rop);//dpr0xc
134
135	write_dpr(accel,DE_CONTROL,deCtrl);
136	return 0;
137}
138
139int hw_copyarea(
140struct lynx_accel * accel,
141unsigned int sBase,  /* Address of source: offset in frame buffer */
142unsigned int sPitch, /* Pitch value of source surface in BYTE */
143unsigned int sx,
144unsigned int sy,     /* Starting coordinate of source surface */
145unsigned int dBase,  /* Address of destination: offset in frame buffer */
146unsigned int dPitch, /* Pitch value of destination surface in BYTE */
147unsigned int Bpp,    /* Color depth of destination surface */
148unsigned int dx,
149unsigned int dy,     /* Starting coordinate of destination surface */
150unsigned int width,
151unsigned int height, /* width and height of rectangle in pixel value */
152unsigned int rop2)   /* ROP value */
153{
154    unsigned int nDirection, de_ctrl;
155    int opSign;
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    {
164        /* Determine direction of operation */
165        if (sy < dy)
166        {
167            /* +----------+
168               |S         |
169               |   +----------+
170               |   |      |   |
171               |   |      |   |
172               +---|------+   |
173                   |         D|
174                   +----------+ */
175
176            nDirection = BOTTOM_TO_TOP;
177        }
178        else if (sy > dy)
179        {
180            /* +----------+
181               |D         |
182               |   +----------+
183               |   |      |   |
184               |   |      |   |
185               +---|------+   |
186                   |         S|
187                   +----------+ */
188
189            nDirection = TOP_TO_BOTTOM;
190        }
191        else
192        {
193            /* sy == dy */
194
195            if (sx <= dx)
196            {
197                /* +------+---+------+
198                   |S     |   |     D|
199                   |      |   |      |
200                   |      |   |      |
201                   |      |   |      |
202                   +------+---+------+ */
203
204                nDirection = RIGHT_TO_LEFT;
205            }
206            else
207            {
208                /* sx > dx */
209
210                /* +------+---+------+
211                   |D     |   |     S|
212                   |      |   |      |
213                   |      |   |      |
214                   |      |   |      |
215                   +------+---+------+ */
216
217                nDirection = LEFT_TO_RIGHT;
218            }
219        }
220    }
221
222    if ((nDirection == BOTTOM_TO_TOP) || (nDirection == RIGHT_TO_LEFT))
223    {
224        sx += width - 1;
225        sy += height - 1;
226        dx += width - 1;
227        dy += height - 1;
228        opSign = (-1);
229    }
230
231    /* Note:
232       DE_FOREGROUND are DE_BACKGROUND are don't care.
233       DE_COLOR_COMPARE and DE_COLOR_COMPARE_MAKS are set by set deSetTransparency().
234    */
235
236    /* 2D Source Base.
237       It is an address offset (128 bit aligned) from the beginning of frame buffer.
238    */
239    write_dpr(accel,DE_WINDOW_SOURCE_BASE, sBase);//dpr40
240
241    /* 2D Destination Base.
242       It is an address offset (128 bit aligned) from the beginning of frame buffer.
243    */
244    write_dpr(accel,DE_WINDOW_DESTINATION_BASE, dBase);//dpr44
245
246#if 0
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 convertion.
250    */
251	if(Bpp == 3){
252			sx *= 3;
253			dx *= 3;
254			width *= 3;
255		write_dpr(accel,DE_PITCH,
256				FIELD_VALUE(0, DE_PITCH, DESTINATION, dPitch) |
257				FIELD_VALUE(0, DE_PITCH, SOURCE,      sPitch));//dpr10
258	}
259	else
260#endif
261	{
262		write_dpr(accel,DE_PITCH,
263				FIELD_VALUE(0, DE_PITCH, DESTINATION, (dPitch/Bpp)) |
264				FIELD_VALUE(0, DE_PITCH, SOURCE,      (sPitch/Bpp)));//dpr10
265	}
266
267    /* Screen Window width in Pixels.
268       2D engine uses this value to calculate the linear address in frame buffer for a given point.
269    */
270    write_dpr(accel,DE_WINDOW_WIDTH,
271        FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, (dPitch/Bpp)) |
272        FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE,      (sPitch/Bpp)));//dpr3c
273
274	if (accel->de_wait() != 0){
275		return -1;
276	}
277
278    {
279
280        write_dpr(accel,DE_SOURCE,
281            FIELD_SET  (0, DE_SOURCE, WRAP, DISABLE) |
282            FIELD_VALUE(0, DE_SOURCE, X_K1, sx)   |
283            FIELD_VALUE(0, DE_SOURCE, Y_K2, sy));//dpr0
284        write_dpr(accel,DE_DESTINATION,
285            FIELD_SET  (0, DE_DESTINATION, WRAP, DISABLE) |
286            FIELD_VALUE(0, DE_DESTINATION, X,    dx)  |
287            FIELD_VALUE(0, DE_DESTINATION, Y,    dy));//dpr04
288        write_dpr(accel,DE_DIMENSION,
289            FIELD_VALUE(0, DE_DIMENSION, X,    width) |
290            FIELD_VALUE(0, DE_DIMENSION, Y_ET, height));//dpr08
291
292        de_ctrl =
293            FIELD_VALUE(0, DE_CONTROL, ROP, rop2) |
294            FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
295            FIELD_SET(0, DE_CONTROL, COMMAND, BITBLT) |
296            ((nDirection == RIGHT_TO_LEFT) ?
297            FIELD_SET(0, DE_CONTROL, DIRECTION, RIGHT_TO_LEFT)
298            : FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT)) |
299            FIELD_SET(0, DE_CONTROL, STATUS, START);
300		write_dpr(accel,DE_CONTROL,de_ctrl);//dpr0c
301    }
302
303    return 0;
304}
305
306static unsigned int deGetTransparency(struct lynx_accel * accel)
307{
308    unsigned int de_ctrl;
309
310    de_ctrl = read_dpr(accel,DE_CONTROL);
311
312    de_ctrl &=
313        FIELD_MASK(DE_CONTROL_TRANSPARENCY_MATCH) |
314        FIELD_MASK(DE_CONTROL_TRANSPARENCY_SELECT)|
315        FIELD_MASK(DE_CONTROL_TRANSPARENCY);
316
317    return de_ctrl;
318}
319
320int hw_imageblit(struct lynx_accel *accel,
321		 const char *pSrcbuf, /* pointer to start of source buffer in system memory */
322		 u32 srcDelta,          /* Pitch value (in bytes) of the source buffer, +ive means top down and -ive mean button up */
323		 u32 startBit, /* Mono data can start at any bit in a byte, this value should be 0 to 7 */
324		 u32 dBase,    /* Address of destination: offset in frame buffer */
325		 u32 dPitch,   /* Pitch value of destination surface in BYTE */
326		 u32 bytePerPixel,      /* Color depth of destination surface */
327		 u32 dx,
328		 u32 dy,       /* Starting coordinate of destination surface */
329		 u32 width,
330		 u32 height,   /* width and height of rectange in pixel value */
331		 u32 fColor,   /* Foreground color (corresponding to a 1 in the monochrome data */
332		 u32 bColor,   /* Background color (corresponding to a 0 in the monochrome data */
333		 u32 rop2)     /* ROP value */
334{
335    unsigned int ulBytesPerScan;
336    unsigned int ul4BytesPerScan;
337    unsigned int ulBytesRemain;
338    unsigned int de_ctrl = 0;
339    unsigned char ajRemain[4];
340    int i, j;
341
342    startBit &= 7; /* Just make sure the start bit is within legal range */
343    ulBytesPerScan = (width + startBit + 7) / 8;
344    ul4BytesPerScan = ulBytesPerScan & ~3;
345    ulBytesRemain = ulBytesPerScan & 3;
346
347	if(accel->de_wait() != 0)
348    {
349//		inf_msg("*** ImageBlit return -1 ***\n");
350        return -1;
351    }
352
353    /* 2D Source Base.
354       Use 0 for HOST Blt.
355    */
356    write_dpr(accel,DE_WINDOW_SOURCE_BASE, 0);
357
358    /* 2D Destination Base.
359       It is an address offset (128 bit aligned) from the beginning of frame buffer.
360    */
361    write_dpr(accel,DE_WINDOW_DESTINATION_BASE, dBase);
362#if 0
363    /* Program pitch (distance between the 1st points of two adjacent lines).
364       Note that input pitch is BYTE value, but the 2D Pitch register uses
365       pixel values. Need Byte to pixel convertion.
366    */
367	if(bytePerPixel == 3 ){
368		dx *= 3;
369		width *= 3;
370		startBit *= 3;
371		write_dpr(accel,DE_PITCH,
372				FIELD_VALUE(0, DE_PITCH, DESTINATION, dPitch) |
373				FIELD_VALUE(0, DE_PITCH, SOURCE,      dPitch));//dpr10
374
375	}
376	else
377#endif
378	{
379		write_dpr(accel,DE_PITCH,
380				FIELD_VALUE(0, DE_PITCH, DESTINATION, dPitch/bytePerPixel) |
381				FIELD_VALUE(0, DE_PITCH, SOURCE,      dPitch/bytePerPixel));//dpr10
382	}
383
384    /* Screen Window width in Pixels.
385       2D engine uses this value to calculate the linear address in frame buffer for a given point.
386    */
387    write_dpr(accel,DE_WINDOW_WIDTH,
388        FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, (dPitch/bytePerPixel)) |
389        FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE,      (dPitch/bytePerPixel)));
390
391    /* Note: For 2D Source in Host Write, only X_K1_MONO field is needed, and Y_K2 field is not used.
392             For mono bitmap, use startBit for X_K1. */
393    write_dpr(accel,DE_SOURCE,
394        FIELD_SET  (0, DE_SOURCE, WRAP, DISABLE)       |
395        FIELD_VALUE(0, DE_SOURCE, X_K1_MONO, startBit));//dpr00
396
397    write_dpr(accel,DE_DESTINATION,
398        FIELD_SET  (0, DE_DESTINATION, WRAP, DISABLE) |
399        FIELD_VALUE(0, DE_DESTINATION, X,    dx)    |
400        FIELD_VALUE(0, DE_DESTINATION, Y,    dy));//dpr04
401
402    write_dpr(accel,DE_DIMENSION,
403        FIELD_VALUE(0, DE_DIMENSION, X,    width) |
404        FIELD_VALUE(0, DE_DIMENSION, Y_ET, height));//dpr08
405
406    write_dpr(accel,DE_FOREGROUND, fColor);
407    write_dpr(accel,DE_BACKGROUND, bColor);
408
409	de_ctrl = FIELD_VALUE(0, DE_CONTROL, ROP, rop2)         |
410		FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2)    |
411		FIELD_SET(0, DE_CONTROL, COMMAND, HOST_WRITE) |
412		FIELD_SET(0, DE_CONTROL, HOST, MONO)          |
413		FIELD_SET(0, DE_CONTROL, STATUS, START);
414
415	write_dpr(accel,DE_CONTROL, de_ctrl | deGetTransparency(accel));
416
417    /* Write MONO data (line by line) to 2D Engine data port */
418    for (i=0; i<height; i++)
419    {
420        /* For each line, send the data in chunks of 4 bytes */
421        for (j=0; j<(ul4BytesPerScan/4); j++)
422        {
423            write_dpPort(accel, *(unsigned int *)(pSrcbuf + (j * 4)));
424        }
425
426        if (ulBytesRemain)
427        {
428            memcpy(ajRemain, pSrcbuf+ul4BytesPerScan, ulBytesRemain);
429            write_dpPort(accel, *(unsigned int *)ajRemain);
430        }
431
432        pSrcbuf += srcDelta;
433    }
434
435    return 0;
436}
437
438