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