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