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