]>
Commit | Line | Data |
---|---|---|
81dee67e SM |
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 | ||
81dee67e SM |
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 | { | |
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 | ||
139 | int hw_copyarea( | |
140 | struct lynx_accel * accel, | |
141 | unsigned int sBase, /* Address of source: offset in frame buffer */ | |
142 | unsigned int sPitch, /* Pitch value of source surface in BYTE */ | |
143 | unsigned int sx, | |
144 | unsigned int sy, /* Starting coordinate of source surface */ | |
145 | unsigned int dBase, /* Address of destination: offset in frame buffer */ | |
146 | unsigned int dPitch, /* Pitch value of destination surface in BYTE */ | |
147 | unsigned int Bpp, /* Color depth of destination surface */ | |
148 | unsigned int dx, | |
149 | unsigned int dy, /* Starting coordinate of destination surface */ | |
150 | unsigned int width, | |
151 | unsigned int height, /* width and height of rectangle in pixel value */ | |
152 | unsigned 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 | ||
306 | static 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 | ||
7c6f3fdc GKH |
320 | int 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 */ | |
81dee67e SM |
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 |