133b86c6a678b114c29c66f10552d43f8788bf1f
[kernel.git] / drivers / staging / sm7xx / smtc2d.c
1 /*
2  * Silicon Motion SM7XX 2D drawing engine functions.
3  *
4  * Copyright (C) 2006 Silicon Motion Technology Corp.
5  * Author: Boyod boyod.yang@siliconmotion.com.cn
6  *
7  * Copyright (C) 2009 Lemote, Inc.
8  * Author: Wu Zhangjin, wuzj@lemote.com
9  *
10  *  This file is subject to the terms and conditions of the GNU General Public
11  *  License. See the file COPYING in the main directory of this archive for
12  *  more details.
13  *
14  * Version 0.10.26192.21.01
15  *      - Add PowerPC support
16  *      - Add 2D support for Lynx -
17  * Verified on 2.6.19.2
18  *      Boyod.yang  <boyod.yang@siliconmotion.com.cn>
19  */
20
21 unsigned char smtc_de_busy;
22
23 void SMTC_write2Dreg(unsigned long nOffset, unsigned long nData)
24 {
25         writel(nData, smtc_2DBaseAddress + nOffset);
26 }
27
28 unsigned long SMTC_read2Dreg(unsigned long nOffset)
29 {
30         return readl(smtc_2DBaseAddress + nOffset);
31 }
32
33 void SMTC_write2Ddataport(unsigned long nOffset, unsigned long nData)
34 {
35         writel(nData, smtc_2Ddataport + nOffset);
36 }
37
38 /**********************************************************************
39  *
40  * deInit
41  *
42  * Purpose
43  *    Drawing engine initialization.
44  *
45  **********************************************************************/
46
47 void deInit(unsigned int nModeWidth, unsigned int nModeHeight,
48                 unsigned int bpp)
49 {
50         /* Get current power configuration. */
51         unsigned char clock;
52         clock = smtc_seqr(0x21);
53
54         /* initialize global 'mutex lock' variable */
55         smtc_de_busy = 0;
56
57         /* Enable 2D Drawing Engine */
58         smtc_seqw(0x21, clock & 0xF8);
59
60         SMTC_write2Dreg(DE_CLIP_TL,
61                         FIELD_VALUE(0, DE_CLIP_TL, TOP, 0) |
62                         FIELD_SET(0, DE_CLIP_TL, STATUS, DISABLE) |
63                         FIELD_SET(0, DE_CLIP_TL, INHIBIT, OUTSIDE) |
64                         FIELD_VALUE(0, DE_CLIP_TL, LEFT, 0));
65
66         if (bpp >= 24) {
67                 SMTC_write2Dreg(DE_PITCH,
68                                 FIELD_VALUE(0, DE_PITCH, DESTINATION,
69                                             nModeWidth * 3) | FIELD_VALUE(0,
70                                                                   DE_PITCH,
71                                                                   SOURCE,
72                                                                   nModeWidth
73                                                                   * 3));
74         } else {
75                 SMTC_write2Dreg(DE_PITCH,
76                                 FIELD_VALUE(0, DE_PITCH, DESTINATION,
77                                             nModeWidth) | FIELD_VALUE(0,
78                                                               DE_PITCH,
79                                                               SOURCE,
80                                                               nModeWidth));
81         }
82
83         SMTC_write2Dreg(DE_WINDOW_WIDTH,
84                         FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION,
85                                     nModeWidth) | FIELD_VALUE(0,
86                                                               DE_WINDOW_WIDTH,
87                                                               SOURCE,
88                                                               nModeWidth));
89
90         switch (bpp) {
91         case 8:
92                 SMTC_write2Dreg(DE_STRETCH_FORMAT,
93                                 FIELD_SET(0, DE_STRETCH_FORMAT, PATTERN_XY,
94                                           NORMAL) | FIELD_VALUE(0,
95                                                         DE_STRETCH_FORMAT,
96                                                         PATTERN_Y,
97                                                         0) |
98                                 FIELD_VALUE(0, DE_STRETCH_FORMAT, PATTERN_X,
99                                     0) | FIELD_SET(0, DE_STRETCH_FORMAT,
100                                                    PIXEL_FORMAT,
101                                                    8) | FIELD_SET(0,
102                                                           DE_STRETCH_FORMAT,
103                                                           ADDRESSING,
104                                                           XY) |
105                                 FIELD_VALUE(0, DE_STRETCH_FORMAT,
106                                         SOURCE_HEIGHT, 3));
107                 break;
108         case 24:
109                 SMTC_write2Dreg(DE_STRETCH_FORMAT,
110                                 FIELD_SET(0, DE_STRETCH_FORMAT, PATTERN_XY,
111                                           NORMAL) | FIELD_VALUE(0,
112                                                         DE_STRETCH_FORMAT,
113                                                         PATTERN_Y,
114                                                         0) |
115                                 FIELD_VALUE(0, DE_STRETCH_FORMAT, PATTERN_X,
116                                     0) | FIELD_SET(0, DE_STRETCH_FORMAT,
117                                                            PIXEL_FORMAT,
118                                                            24) | FIELD_SET(0,
119                                                            DE_STRETCH_FORMAT,
120                                                            ADDRESSING,
121                                                            XY) |
122                                 FIELD_VALUE(0, DE_STRETCH_FORMAT,
123                                         SOURCE_HEIGHT, 3));
124                 break;
125         case 16:
126         default:
127                 SMTC_write2Dreg(DE_STRETCH_FORMAT,
128                                 FIELD_SET(0, DE_STRETCH_FORMAT, PATTERN_XY,
129                                           NORMAL) | FIELD_VALUE(0,
130                                                         DE_STRETCH_FORMAT,
131                                                         PATTERN_Y,
132                                                         0) |
133                                 FIELD_VALUE(0, DE_STRETCH_FORMAT, PATTERN_X,
134                                     0) | FIELD_SET(0, DE_STRETCH_FORMAT,
135                                                            PIXEL_FORMAT,
136                                                            16) | FIELD_SET(0,
137                                                            DE_STRETCH_FORMAT,
138                                                            ADDRESSING,
139                                                            XY) |
140                                 FIELD_VALUE(0, DE_STRETCH_FORMAT,
141                                         SOURCE_HEIGHT, 3));
142                 break;
143         }
144
145         SMTC_write2Dreg(DE_MASKS,
146                         FIELD_VALUE(0, DE_MASKS, BYTE_MASK, 0xFFFF) |
147                         FIELD_VALUE(0, DE_MASKS, BIT_MASK, 0xFFFF));
148         SMTC_write2Dreg(DE_COLOR_COMPARE_MASK,
149                         FIELD_VALUE(0, DE_COLOR_COMPARE_MASK, MASKS, \
150                                 0xFFFFFF));
151         SMTC_write2Dreg(DE_COLOR_COMPARE,
152                         FIELD_VALUE(0, DE_COLOR_COMPARE, COLOR, 0xFFFFFF));
153 }
154
155 void deVerticalLine(unsigned long dst_base,
156                     unsigned long dst_pitch,
157                     unsigned long nX,
158                     unsigned long nY,
159                     unsigned long dst_height, unsigned long nColor)
160 {
161         deWaitForNotBusy();
162
163         SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE,
164                         FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE, ADDRESS,
165                                     dst_base));
166
167         SMTC_write2Dreg(DE_PITCH,
168                         FIELD_VALUE(0, DE_PITCH, DESTINATION, dst_pitch) |
169                         FIELD_VALUE(0, DE_PITCH, SOURCE, dst_pitch));
170
171         SMTC_write2Dreg(DE_WINDOW_WIDTH,
172                         FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION,
173                             dst_pitch) | FIELD_VALUE(0, DE_WINDOW_WIDTH,
174                                                      SOURCE,
175                                                      dst_pitch));
176
177         SMTC_write2Dreg(DE_FOREGROUND,
178                         FIELD_VALUE(0, DE_FOREGROUND, COLOR, nColor));
179
180         SMTC_write2Dreg(DE_DESTINATION,
181                         FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) |
182                         FIELD_VALUE(0, DE_DESTINATION, X, nX) |
183                         FIELD_VALUE(0, DE_DESTINATION, Y, nY));
184
185         SMTC_write2Dreg(DE_DIMENSION,
186                         FIELD_VALUE(0, DE_DIMENSION, X, 1) |
187                         FIELD_VALUE(0, DE_DIMENSION, Y_ET, dst_height));
188
189         SMTC_write2Dreg(DE_CONTROL,
190                         FIELD_SET(0, DE_CONTROL, STATUS, START) |
191                         FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT) |
192                         FIELD_SET(0, DE_CONTROL, MAJOR, Y) |
193                         FIELD_SET(0, DE_CONTROL, STEP_X, NEGATIVE) |
194                         FIELD_SET(0, DE_CONTROL, STEP_Y, POSITIVE) |
195                         FIELD_SET(0, DE_CONTROL, LAST_PIXEL, OFF) |
196                         FIELD_SET(0, DE_CONTROL, COMMAND, SHORT_STROKE) |
197                         FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
198                         FIELD_VALUE(0, DE_CONTROL, ROP, 0x0C));
199
200         smtc_de_busy = 1;
201 }
202
203 void deHorizontalLine(unsigned long dst_base,
204                       unsigned long dst_pitch,
205                       unsigned long nX,
206                       unsigned long nY,
207                       unsigned long dst_width, unsigned long nColor)
208 {
209         deWaitForNotBusy();
210
211         SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE,
212                         FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE, ADDRESS,
213                                     dst_base));
214
215         SMTC_write2Dreg(DE_PITCH,
216                         FIELD_VALUE(0, DE_PITCH, DESTINATION, dst_pitch) |
217                         FIELD_VALUE(0, DE_PITCH, SOURCE, dst_pitch));
218
219         SMTC_write2Dreg(DE_WINDOW_WIDTH,
220                         FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION,
221                             dst_pitch) | FIELD_VALUE(0, DE_WINDOW_WIDTH,
222                                                      SOURCE,
223                                                      dst_pitch));
224         SMTC_write2Dreg(DE_FOREGROUND,
225                         FIELD_VALUE(0, DE_FOREGROUND, COLOR, nColor));
226         SMTC_write2Dreg(DE_DESTINATION,
227                         FIELD_SET(0, DE_DESTINATION, WRAP,
228                           DISABLE) | FIELD_VALUE(0, DE_DESTINATION, X,
229                                                  nX) | FIELD_VALUE(0,
230                                                            DE_DESTINATION,
231                                                            Y,
232                                                            nY));
233         SMTC_write2Dreg(DE_DIMENSION,
234                         FIELD_VALUE(0, DE_DIMENSION, X,
235                             dst_width) | FIELD_VALUE(0, DE_DIMENSION,
236                                                      Y_ET, 1));
237         SMTC_write2Dreg(DE_CONTROL,
238                 FIELD_SET(0, DE_CONTROL, STATUS, START) | FIELD_SET(0,
239                                                             DE_CONTROL,
240                                                             DIRECTION,
241                                                             RIGHT_TO_LEFT)
242                 | FIELD_SET(0, DE_CONTROL, MAJOR, X) | FIELD_SET(0,
243                                                          DE_CONTROL,
244                                                          STEP_X,
245                                                          POSITIVE)
246                 | FIELD_SET(0, DE_CONTROL, STEP_Y,
247                             NEGATIVE) | FIELD_SET(0, DE_CONTROL,
248                                                   LAST_PIXEL,
249                                                   OFF) | FIELD_SET(0,
250                                                            DE_CONTROL,
251                                                            COMMAND,
252                                                            SHORT_STROKE)
253                 | FIELD_SET(0, DE_CONTROL, ROP_SELECT,
254                             ROP2) | FIELD_VALUE(0, DE_CONTROL, ROP,
255                                                 0x0C));
256
257         smtc_de_busy = 1;
258 }
259
260 void deLine(unsigned long dst_base,
261             unsigned long dst_pitch,
262             unsigned long nX1,
263             unsigned long nY1,
264             unsigned long nX2, unsigned long nY2, unsigned long nColor)
265 {
266         unsigned long nCommand =
267             FIELD_SET(0, DE_CONTROL, STATUS, START) |
268             FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT) |
269             FIELD_SET(0, DE_CONTROL, MAJOR, X) |
270             FIELD_SET(0, DE_CONTROL, STEP_X, POSITIVE) |
271             FIELD_SET(0, DE_CONTROL, STEP_Y, POSITIVE) |
272             FIELD_SET(0, DE_CONTROL, LAST_PIXEL, OFF) |
273             FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
274             FIELD_VALUE(0, DE_CONTROL, ROP, 0x0C);
275         unsigned long DeltaX;
276         unsigned long DeltaY;
277
278         /* Calculate delta X */
279         if (nX1 <= nX2)
280                 DeltaX = nX2 - nX1;
281         else {
282                 DeltaX = nX1 - nX2;
283                 nCommand = FIELD_SET(nCommand, DE_CONTROL, STEP_X, NEGATIVE);
284         }
285
286         /* Calculate delta Y */
287         if (nY1 <= nY2)
288                 DeltaY = nY2 - nY1;
289         else {
290                 DeltaY = nY1 - nY2;
291                 nCommand = FIELD_SET(nCommand, DE_CONTROL, STEP_Y, NEGATIVE);
292         }
293
294         /* Determine the major axis */
295         if (DeltaX < DeltaY)
296                 nCommand = FIELD_SET(nCommand, DE_CONTROL, MAJOR, Y);
297
298         /* Vertical line? */
299         if (nX1 == nX2)
300                 deVerticalLine(dst_base, dst_pitch, nX1, nY1, DeltaY, nColor);
301
302         /* Horizontal line? */
303         else if (nY1 == nY2)
304                 deHorizontalLine(dst_base, dst_pitch, nX1, nY1, \
305                                 DeltaX, nColor);
306
307         /* Diagonal line? */
308         else if (DeltaX == DeltaY) {
309                 deWaitForNotBusy();
310
311                 SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE,
312                                 FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE,
313                                             ADDRESS, dst_base));
314
315                 SMTC_write2Dreg(DE_PITCH,
316                                 FIELD_VALUE(0, DE_PITCH, DESTINATION,
317                                             dst_pitch) | FIELD_VALUE(0,
318                                                              DE_PITCH,
319                                                              SOURCE,
320                                                              dst_pitch));
321
322                 SMTC_write2Dreg(DE_WINDOW_WIDTH,
323                                 FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION,
324                                             dst_pitch) | FIELD_VALUE(0,
325                                                              DE_WINDOW_WIDTH,
326                                                              SOURCE,
327                                                              dst_pitch));
328
329                 SMTC_write2Dreg(DE_FOREGROUND,
330                                 FIELD_VALUE(0, DE_FOREGROUND, COLOR, nColor));
331
332                 SMTC_write2Dreg(DE_DESTINATION,
333                                 FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) |
334                                 FIELD_VALUE(0, DE_DESTINATION, X, 1) |
335                                 FIELD_VALUE(0, DE_DESTINATION, Y, nY1));
336
337                 SMTC_write2Dreg(DE_DIMENSION,
338                                 FIELD_VALUE(0, DE_DIMENSION, X, 1) |
339                                 FIELD_VALUE(0, DE_DIMENSION, Y_ET, DeltaX));
340
341                 SMTC_write2Dreg(DE_CONTROL,
342                                 FIELD_SET(nCommand, DE_CONTROL, COMMAND,
343                                           SHORT_STROKE));
344         }
345
346         /* Generic line */
347         else {
348                 unsigned int k1, k2, et, w;
349                 if (DeltaX < DeltaY) {
350                         k1 = 2 * DeltaX;
351                         et = k1 - DeltaY;
352                         k2 = et - DeltaY;
353                         w = DeltaY + 1;
354                 } else {
355                         k1 = 2 * DeltaY;
356                         et = k1 - DeltaX;
357                         k2 = et - DeltaX;
358                         w = DeltaX + 1;
359                 }
360
361                 deWaitForNotBusy();
362
363                 SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE,
364                                 FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE,
365                                             ADDRESS, dst_base));
366
367                 SMTC_write2Dreg(DE_PITCH,
368                                 FIELD_VALUE(0, DE_PITCH, DESTINATION,
369                                             dst_pitch) | FIELD_VALUE(0,
370                                                              DE_PITCH,
371                                                              SOURCE,
372                                                              dst_pitch));
373
374                 SMTC_write2Dreg(DE_WINDOW_WIDTH,
375                                 FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION,
376                                             dst_pitch) | FIELD_VALUE(0,
377                                                              DE_WINDOW_WIDTH,
378                                                              SOURCE,
379                                                              dst_pitch));
380
381                 SMTC_write2Dreg(DE_FOREGROUND,
382                                 FIELD_VALUE(0, DE_FOREGROUND, COLOR, nColor));
383
384                 SMTC_write2Dreg(DE_SOURCE,
385                                 FIELD_SET(0, DE_SOURCE, WRAP, DISABLE) |
386                                 FIELD_VALUE(0, DE_SOURCE, X_K1, k1) |
387                                 FIELD_VALUE(0, DE_SOURCE, Y_K2, k2));
388
389                 SMTC_write2Dreg(DE_DESTINATION,
390                                 FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) |
391                                 FIELD_VALUE(0, DE_DESTINATION, X, nX1) |
392                                 FIELD_VALUE(0, DE_DESTINATION, Y, nY1));
393
394                 SMTC_write2Dreg(DE_DIMENSION,
395                                 FIELD_VALUE(0, DE_DIMENSION, X, w) |
396                                 FIELD_VALUE(0, DE_DIMENSION, Y_ET, et));
397
398                 SMTC_write2Dreg(DE_CONTROL,
399                                 FIELD_SET(nCommand, DE_CONTROL, COMMAND,
400                                           LINE_DRAW));
401         }
402
403         smtc_de_busy = 1;
404 }
405
406 void deFillRect(unsigned long dst_base,
407                 unsigned long dst_pitch,
408                 unsigned long dst_X,
409                 unsigned long dst_Y,
410                 unsigned long dst_width,
411                 unsigned long dst_height, unsigned long nColor)
412 {
413         deWaitForNotBusy();
414
415         SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE,
416                         FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE, ADDRESS,
417                                     dst_base));
418
419         if (dst_pitch) {
420                 SMTC_write2Dreg(DE_PITCH,
421                                 FIELD_VALUE(0, DE_PITCH, DESTINATION,
422                                             dst_pitch) | FIELD_VALUE(0,
423                                                              DE_PITCH,
424                                                              SOURCE,
425                                                              dst_pitch));
426
427                 SMTC_write2Dreg(DE_WINDOW_WIDTH,
428                                 FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION,
429                                             dst_pitch) | FIELD_VALUE(0,
430                                                              DE_WINDOW_WIDTH,
431                                                              SOURCE,
432                                                              dst_pitch));
433         }
434
435         SMTC_write2Dreg(DE_FOREGROUND,
436                         FIELD_VALUE(0, DE_FOREGROUND, COLOR, nColor));
437
438         SMTC_write2Dreg(DE_DESTINATION,
439                         FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) |
440                         FIELD_VALUE(0, DE_DESTINATION, X, dst_X) |
441                         FIELD_VALUE(0, DE_DESTINATION, Y, dst_Y));
442
443         SMTC_write2Dreg(DE_DIMENSION,
444                         FIELD_VALUE(0, DE_DIMENSION, X, dst_width) |
445                         FIELD_VALUE(0, DE_DIMENSION, Y_ET, dst_height));
446
447         SMTC_write2Dreg(DE_CONTROL,
448                         FIELD_SET(0, DE_CONTROL, STATUS, START) |
449                         FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT) |
450                         FIELD_SET(0, DE_CONTROL, LAST_PIXEL, OFF) |
451                         FIELD_SET(0, DE_CONTROL, COMMAND, RECTANGLE_FILL) |
452                         FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
453                         FIELD_VALUE(0, DE_CONTROL, ROP, 0x0C));
454
455         smtc_de_busy = 1;
456 }
457
458 /**********************************************************************
459  *
460  * deRotatePattern
461  *
462  * Purpose
463  *    Rotate the given pattern if necessary
464  *
465  * Parameters
466  *    [in]
467  *         pPattern  - Pointer to DE_SURFACE structure containing
468  *                     pattern attributes
469  *         patternX  - X position (0-7) of pattern origin
470  *         patternY  - Y position (0-7) of pattern origin
471  *
472  *    [out]
473  *         pattern_dstaddr - Pointer to pre-allocated buffer containing
474  *         rotated pattern
475  *
476  **********************************************************************/
477 void deRotatePattern(unsigned char *pattern_dstaddr,
478                      unsigned long pattern_src_addr,
479                      unsigned long pattern_BPP,
480                      unsigned long pattern_stride, int patternX, int patternY)
481 {
482         unsigned int i;
483         unsigned long pattern[PATTERN_WIDTH * PATTERN_HEIGHT];
484         unsigned int x, y;
485         unsigned char *pjPatByte;
486
487         if (pattern_dstaddr != NULL) {
488                 deWaitForNotBusy();
489
490                 if (patternX || patternY) {
491                         /* Rotate pattern */
492                         pjPatByte = (unsigned char *)pattern;
493
494                         switch (pattern_BPP) {
495                         case 8:
496                                 {
497                                         for (y = 0; y < 8; y++) {
498                                                 unsigned char *pjBuffer =
499                                                     pattern_dstaddr +
500                                                     ((patternY + y) & 7) * 8;
501                                                 for (x = 0; x < 8; x++) {
502                                                         pjBuffer[(patternX +
503                                                                   x) & 7] =
504                                                             pjPatByte[x];
505                                                 }
506                                                 pjPatByte += pattern_stride;
507                                         }
508                                         break;
509                                 }
510
511                         case 16:
512                                 {
513                                         for (y = 0; y < 8; y++) {
514                                                 unsigned short *pjBuffer =
515                                                     (unsigned short *)
516                                                     pattern_dstaddr +
517                                                     ((patternY + y) & 7) * 8;
518                                                 for (x = 0; x < 8; x++) {
519                                                         pjBuffer[(patternX +
520                                                                   x) & 7] =
521                                                             ((unsigned short *)
522                                                              pjPatByte)[x];
523                                                 }
524                                                 pjPatByte += pattern_stride;
525                                         }
526                                         break;
527                                 }
528
529                         case 32:
530                                 {
531                                         for (y = 0; y < 8; y++) {
532                                                 unsigned long *pjBuffer =
533                                                     (unsigned long *)
534                                                     pattern_dstaddr +
535                                                     ((patternY + y) & 7) * 8;
536                                                 for (x = 0; x < 8; x++) {
537                                                         pjBuffer[(patternX +
538                                                                   x) & 7] =
539                                                             ((unsigned long *)
540                                                              pjPatByte)[x];
541                                                 }
542                                                 pjPatByte += pattern_stride;
543                                         }
544                                         break;
545                                 }
546                         }
547                 } else {
548                         /*Don't rotate,just copy pattern into pattern_dstaddr*/
549                         for (i = 0; i < (pattern_BPP * 2); i++) {
550                                 ((unsigned long *)pattern_dstaddr)[i] =
551                                     pattern[i];
552                         }
553                 }
554
555         }
556 }
557
558 /**********************************************************************
559  *
560  * deCopy
561  *
562  * Purpose
563  *    Copy a rectangular area of the source surface to a destination surface
564  *
565  * Remarks
566  *    Source bitmap must have the same color depth (BPP) as the destination
567  *    bitmap.
568  *
569 **********************************************************************/
570 void deCopy(unsigned long dst_base,
571             unsigned long dst_pitch,
572             unsigned long dst_BPP,
573             unsigned long dst_X,
574             unsigned long dst_Y,
575             unsigned long dst_width,
576             unsigned long dst_height,
577             unsigned long src_base,
578             unsigned long src_pitch,
579             unsigned long src_X,
580             unsigned long src_Y, pTransparent pTransp, unsigned char nROP2)
581 {
582         unsigned long nDirection = 0;
583         unsigned long nTransparent = 0;
584         /* Direction of ROP2 operation:
585          * 1 = Left to Right,
586          * (-1) = Right to Left
587          */
588         unsigned long opSign = 1;
589         /* xWidth is in pixels */
590         unsigned long xWidth = 192 / (dst_BPP / 8);
591         unsigned long de_ctrl = 0;
592
593         deWaitForNotBusy();
594
595         SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE,
596                         FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE, ADDRESS,
597                                     dst_base));
598
599         SMTC_write2Dreg(DE_WINDOW_SOURCE_BASE,
600                         FIELD_VALUE(0, DE_WINDOW_SOURCE_BASE, ADDRESS,
601                                     src_base));
602
603         if (dst_pitch && src_pitch) {
604                 SMTC_write2Dreg(DE_PITCH,
605                         FIELD_VALUE(0, DE_PITCH, DESTINATION,
606                                     dst_pitch) | FIELD_VALUE(0,
607                                                      DE_PITCH,
608                                                      SOURCE,
609                                                      src_pitch));
610
611                 SMTC_write2Dreg(DE_WINDOW_WIDTH,
612                         FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION,
613                                     dst_pitch) | FIELD_VALUE(0,
614                                                      DE_WINDOW_WIDTH,
615                                                      SOURCE,
616                                                      src_pitch));
617         }
618
619         /* Set transparent bits if necessary */
620         if (pTransp != NULL) {
621                 nTransparent =
622                     pTransp->match | pTransp->select | pTransp->control;
623
624                 /* Set color compare register */
625                 SMTC_write2Dreg(DE_COLOR_COMPARE,
626                                 FIELD_VALUE(0, DE_COLOR_COMPARE, COLOR,
627                                             pTransp->color));
628         }
629
630         /* Determine direction of operation */
631         if (src_Y < dst_Y) {
632                 /* +----------+
633                    |S         |
634                    |          +----------+
635                    |          |      |   |
636                    |          |      |   |
637                    +---|------+      |
638                    |               D |
639                    +----------+ */
640
641                 nDirection = BOTTOM_TO_TOP;
642         } else if (src_Y > dst_Y) {
643                 /* +----------+
644                    |D         |
645                    |          +----------+
646                    |          |      |   |
647                    |          |      |   |
648                    +---|------+      |
649                    |               S |
650                    +----------+ */
651
652                 nDirection = TOP_TO_BOTTOM;
653         } else {
654                 /* src_Y == dst_Y */
655
656                 if (src_X <= dst_X) {
657                         /* +------+---+------+
658                            |S     |   |     D|
659                            |      |   |      |
660                            |      |   |      |
661                            |      |   |      |
662                            +------+---+------+ */
663
664                         nDirection = RIGHT_TO_LEFT;
665                 } else {
666                         /* src_X > dst_X */
667
668                         /* +------+---+------+
669                            |D     |   |     S|
670                            |      |   |      |
671                            |      |   |      |
672                            |      |   |      |
673                            +------+---+------+ */
674
675                         nDirection = LEFT_TO_RIGHT;
676                 }
677         }
678
679         if ((nDirection == BOTTOM_TO_TOP) || (nDirection == RIGHT_TO_LEFT)) {
680                 src_X += dst_width - 1;
681                 src_Y += dst_height - 1;
682                 dst_X += dst_width - 1;
683                 dst_Y += dst_height - 1;
684                 opSign = (-1);
685         }
686
687         if (dst_BPP >= 24) {
688                 src_X *= 3;
689                 src_Y *= 3;
690                 dst_X *= 3;
691                 dst_Y *= 3;
692                 dst_width *= 3;
693                 if ((nDirection == BOTTOM_TO_TOP)
694                     || (nDirection == RIGHT_TO_LEFT)) {
695                         src_X += 2;
696                         dst_X += 2;
697                 }
698         }
699
700         /* Workaround for 192 byte hw bug */
701         if ((nROP2 != 0x0C) && ((dst_width * (dst_BPP / 8)) >= 192)) {
702                 /*
703                  * Perform the ROP2 operation in chunks of (xWidth *
704                  * dst_height)
705                  */
706                 while (1) {
707                         deWaitForNotBusy();
708
709                         SMTC_write2Dreg(DE_SOURCE,
710                                 FIELD_SET(0, DE_SOURCE, WRAP, DISABLE) |
711                                 FIELD_VALUE(0, DE_SOURCE, X_K1, src_X) |
712                                 FIELD_VALUE(0, DE_SOURCE, Y_K2, src_Y));
713
714                         SMTC_write2Dreg(DE_DESTINATION,
715                                 FIELD_SET(0, DE_DESTINATION, WRAP,
716                                   DISABLE) | FIELD_VALUE(0,
717                                                          DE_DESTINATION,
718                                                          X,
719                                                          dst_X)
720                         | FIELD_VALUE(0, DE_DESTINATION, Y,
721                                                       dst_Y));
722
723                         SMTC_write2Dreg(DE_DIMENSION,
724                                 FIELD_VALUE(0, DE_DIMENSION, X,
725                                     xWidth) | FIELD_VALUE(0,
726                                                           DE_DIMENSION,
727                                                           Y_ET,
728                                                           dst_height));
729
730                         de_ctrl =
731                             FIELD_VALUE(0, DE_CONTROL, ROP,
732                                 nROP2) | nTransparent | FIELD_SET(0,
733                                                           DE_CONTROL,
734                                                           ROP_SELECT,
735                                                           ROP2)
736                             | FIELD_SET(0, DE_CONTROL, COMMAND,
737                                 BITBLT) | ((nDirection ==
738                                             1) ? FIELD_SET(0,
739                                                    DE_CONTROL,
740                                                    DIRECTION,
741                                                    RIGHT_TO_LEFT)
742                                            : FIELD_SET(0, DE_CONTROL,
743                                                DIRECTION,
744                                                LEFT_TO_RIGHT)) |
745                             FIELD_SET(0, DE_CONTROL, STATUS, START);
746
747                         SMTC_write2Dreg(DE_CONTROL, de_ctrl);
748
749                         src_X += (opSign * xWidth);
750                         dst_X += (opSign * xWidth);
751                         dst_width -= xWidth;
752
753                         if (dst_width <= 0) {
754                                 /* ROP2 operation is complete */
755                                 break;
756                         }
757
758                         if (xWidth > dst_width)
759                                 xWidth = dst_width;
760                 }
761         } else {
762                 deWaitForNotBusy();
763                 SMTC_write2Dreg(DE_SOURCE,
764                         FIELD_SET(0, DE_SOURCE, WRAP, DISABLE) |
765                         FIELD_VALUE(0, DE_SOURCE, X_K1, src_X) |
766                         FIELD_VALUE(0, DE_SOURCE, Y_K2, src_Y));
767
768                 SMTC_write2Dreg(DE_DESTINATION,
769                         FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) |
770                         FIELD_VALUE(0, DE_DESTINATION, X, dst_X) |
771                         FIELD_VALUE(0, DE_DESTINATION, Y, dst_Y));
772
773                 SMTC_write2Dreg(DE_DIMENSION,
774                         FIELD_VALUE(0, DE_DIMENSION, X, dst_width) |
775                         FIELD_VALUE(0, DE_DIMENSION, Y_ET, dst_height));
776
777                 de_ctrl = FIELD_VALUE(0, DE_CONTROL, ROP, nROP2) |
778                     nTransparent |
779                     FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
780                     FIELD_SET(0, DE_CONTROL, COMMAND, BITBLT) |
781                     ((nDirection == 1) ? FIELD_SET(0, DE_CONTROL, DIRECTION,
782                                                    RIGHT_TO_LEFT)
783                      : FIELD_SET(0, DE_CONTROL, DIRECTION,
784                                  LEFT_TO_RIGHT)) | FIELD_SET(0, DE_CONTROL,
785                                                              STATUS, START);
786                 SMTC_write2Dreg(DE_CONTROL, de_ctrl);
787         }
788
789         smtc_de_busy = 1;
790 }
791
792 /*
793  * This function sets the pixel format that will apply to the 2D Engine.
794  */
795 void deSetPixelFormat(unsigned long bpp)
796 {
797         unsigned long de_format;
798
799         de_format = SMTC_read2Dreg(DE_STRETCH_FORMAT);
800
801         switch (bpp) {
802         case 8:
803                 de_format =
804                     FIELD_SET(de_format, DE_STRETCH_FORMAT, PIXEL_FORMAT, 8);
805                 break;
806         default:
807         case 16:
808                 de_format =
809                     FIELD_SET(de_format, DE_STRETCH_FORMAT, PIXEL_FORMAT, 16);
810                 break;
811         case 32:
812                 de_format =
813                     FIELD_SET(de_format, DE_STRETCH_FORMAT, PIXEL_FORMAT, 32);
814                 break;
815         }
816
817         SMTC_write2Dreg(DE_STRETCH_FORMAT, de_format);
818 }
819
820 /*
821  * System memory to Video memory monochrome expansion.
822  *
823  * Source is monochrome image in system memory.  This function expands the
824  * monochrome data to color image in video memory.
825  */
826
827 long deSystemMem2VideoMemMonoBlt(const char *pSrcbuf,
828                                  long srcDelta,
829                                  unsigned long startBit,
830                                  unsigned long dBase,
831                                  unsigned long dPitch,
832                                  unsigned long bpp,
833                                  unsigned long dx, unsigned long dy,
834                                  unsigned long width, unsigned long height,
835                                  unsigned long fColor,
836                                  unsigned long bColor,
837                                  unsigned long rop2) {
838         unsigned long bytePerPixel;
839         unsigned long ulBytesPerScan;
840         unsigned long ul4BytesPerScan;
841         unsigned long ulBytesRemain;
842         unsigned long de_ctrl = 0;
843         unsigned char ajRemain[4];
844         long i, j;
845
846         bytePerPixel = bpp / 8;
847
848         /* Just make sure the start bit is within legal range */
849         startBit &= 7;
850
851         ulBytesPerScan = (width + startBit + 7) / 8;
852         ul4BytesPerScan = ulBytesPerScan & ~3;
853         ulBytesRemain = ulBytesPerScan & 3;
854
855         if (smtc_de_busy)
856                 deWaitForNotBusy();
857
858         /*
859          * 2D Source Base.  Use 0 for HOST Blt.
860          */
861
862         SMTC_write2Dreg(DE_WINDOW_SOURCE_BASE, 0);
863
864         /*
865          * 2D Destination Base.
866          *
867          * It is an address offset (128 bit aligned) from the beginning of
868          * frame buffer.
869          */
870
871         SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE, dBase);
872
873         if (dPitch) {
874
875                 /*
876                  * Program pitch (distance between the 1st points of two
877                  * adjacent lines).
878                  *
879                  * Note that input pitch is BYTE value, but the 2D Pitch
880                  * register uses pixel values. Need Byte to pixel convertion.
881                  */
882
883                 SMTC_write2Dreg(DE_PITCH,
884                         FIELD_VALUE(0, DE_PITCH, DESTINATION,
885                             dPitch /
886                             bytePerPixel) | FIELD_VALUE(0,
887                                                         DE_PITCH,
888                                                         SOURCE,
889                                                         dPitch /
890                                                         bytePerPixel));
891
892                 /* Screen Window width in Pixels.
893                  *
894                  * 2D engine uses this value to calculate the linear address in
895                  * frame buffer for a given point.
896                  */
897
898                 SMTC_write2Dreg(DE_WINDOW_WIDTH,
899                         FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION,
900                             (dPitch /
901                              bytePerPixel)) | FIELD_VALUE(0,
902                                                           DE_WINDOW_WIDTH,
903                                                           SOURCE,
904                                                           (dPitch
905                                                            /
906                                                            bytePerPixel)));
907         }
908         /* Note: For 2D Source in Host Write, only X_K1 field is needed, and
909          * Y_K2 field is not used. For mono bitmap, use startBit for X_K1.
910          */
911
912         SMTC_write2Dreg(DE_SOURCE,
913                         FIELD_SET(0, DE_SOURCE, WRAP, DISABLE) |
914                         FIELD_VALUE(0, DE_SOURCE, X_K1, startBit) |
915                         FIELD_VALUE(0, DE_SOURCE, Y_K2, 0));
916
917         SMTC_write2Dreg(DE_DESTINATION,
918                         FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) |
919                         FIELD_VALUE(0, DE_DESTINATION, X, dx) |
920                         FIELD_VALUE(0, DE_DESTINATION, Y, dy));
921
922         SMTC_write2Dreg(DE_DIMENSION,
923                         FIELD_VALUE(0, DE_DIMENSION, X, width) |
924                         FIELD_VALUE(0, DE_DIMENSION, Y_ET, height));
925
926         SMTC_write2Dreg(DE_FOREGROUND, fColor);
927         SMTC_write2Dreg(DE_BACKGROUND, bColor);
928
929         if (bpp)
930                 deSetPixelFormat(bpp);
931         /* Set the pixel format of the destination */
932
933         de_ctrl = FIELD_VALUE(0, DE_CONTROL, ROP, rop2) |
934             FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
935             FIELD_SET(0, DE_CONTROL, COMMAND, HOST_WRITE) |
936             FIELD_SET(0, DE_CONTROL, HOST, MONO) |
937             FIELD_SET(0, DE_CONTROL, STATUS, START);
938
939         SMTC_write2Dreg(DE_CONTROL, de_ctrl | deGetTransparency());
940
941         /* Write MONO data (line by line) to 2D Engine data port */
942         for (i = 0; i < height; i++) {
943                 /* For each line, send the data in chunks of 4 bytes */
944                 for (j = 0; j < (ul4BytesPerScan / 4); j++)
945                         SMTC_write2Ddataport(0,
946                                              *(unsigned long *)(pSrcbuf +
947                                                                 (j * 4)));
948
949                 if (ulBytesRemain) {
950                         memcpy(ajRemain, pSrcbuf + ul4BytesPerScan,
951                                ulBytesRemain);
952                         SMTC_write2Ddataport(0, *(unsigned long *)ajRemain);
953                 }
954
955                 pSrcbuf += srcDelta;
956         }
957         smtc_de_busy = 1;
958
959         return 0;
960 }
961
962 /*
963  * This function gets the transparency status from DE_CONTROL register.
964  * It returns a double word with the transparent fields properly set,
965  * while other fields are 0.
966  */
967 unsigned long deGetTransparency(void)
968 {
969         unsigned long de_ctrl;
970
971         de_ctrl = SMTC_read2Dreg(DE_CONTROL);
972
973         de_ctrl &=
974             FIELD_MASK(DE_CONTROL_TRANSPARENCY_MATCH) |
975             FIELD_MASK(DE_CONTROL_TRANSPARENCY_SELECT) |
976             FIELD_MASK(DE_CONTROL_TRANSPARENCY);
977
978         return de_ctrl;
979 }