1/* Copyright (c) 2005 Advanced Micro Devices, Inc.
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a copy
4 * of this software and associated documentation files (the "Software"), to
5 * deal in the Software without restriction, including without limitation the
6 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7 * sell copies of the Software, and to permit persons to whom the Software is
8 * furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19 * IN THE SOFTWARE.
20 *
21 * Neither the name of the Advanced Micro Devices, Inc. nor the names of its
22 * contributors may be used to endorse or promote products derived from this
23 * software without specific prior written permission.
24 * */
25
26/*
27 * This file contains routines to program the 2D acceleration hardware for
28 * the second generation graphics unit.
29 *
30 * Basic rendering routines (common to all Geode processors):
31 *    gfx_set_bpp
32 *    gfx_set_solid_pattern
33 *    gfx_set_mono_pattern
34 *    gfx_set_color_pattern
35 *    gfx_set_solid_source
36 *    gfx_set_mono_source
37 *    gfx_set_raster_operation
38 *    gfx_pattern_fill
39 *    gfx_color_pattern_fill
40 *    gfx_screen_to_screen_blt
41 *    gfx_screen_to_screen_xblt
42 *    gfx_color_bitmap_to_screen_blt
43 *    gfx_color_bitmap_to_screen_xblt
44 *    gfx_mono_bitmap_to_screen_blt
45 *    gfx_bresenham_line
46 *    gfx_wait_until_idle
47 *
48 * Extended rendering routines for second generation functionality:
49 *    gfx2_set_source_stride
50 *    gfx2_set_destination_stride
51 *    gfx2_set_pattern_origins
52 *    gfx2_set_source_transparency
53 *    gfx2_set_alpha_mode
54 *    gfx2_set_alpha_value
55 *    gfx2_pattern_fill
56 *    gfx2_color_pattern_fill
57 *    gfx2_screen_to_screen_blt
58 *    gfx2_mono_expand_blt
59 *    gfx2_color_bitmap_to_screen_blt
60 *    gfx2_mono_bitmap_to_screen_blt
61 *    gfx2_bresenham_line
62 *    gfx2_sync_to_vblank
63 * */
64
65#define GU2_WAIT_PENDING		\
66		while(READ_GP32(MGP_BLT_STATUS) & MGP_BS_BLT_PENDING)
67#define GU2_WAIT_BUSY			\
68		while(READ_GP32(MGP_BLT_STATUS) & MGP_BS_BLT_BUSY)
69#define GU2_WAIT_HALF_EMPTY		\
70		while(!(READ_GP32(MGP_BLT_STATUS) & MGP_BS_HALF_EMPTY))
71
72/* PATTERN SWIZZLES */
73
74#define WORD_SWIZZLE(x) (((x) << 16) | ((x) >> 16))
75#define BYTE_SWIZZLE(x) (((x) << 24) | ((x) >> 24) | (((x) << 8) & 	\
76						0x00FF0000) | (((x) >> 8) & 0x0000FF00))
77
78/* GLOBAL VARIABLES USED BY THE RENDERING ROUTINES */
79
80unsigned long gu2_bpp;
81unsigned long gu2_pitch = 1280;
82unsigned long gu2_src_pitch = 1280;
83unsigned long gu2_dst_pitch = 1280;
84unsigned long gu2_xshift = 1;
85unsigned long gu2_pattern_origin = 0;
86unsigned long gu2_rop32;
87unsigned long gu2_alpha32 = 0;
88unsigned long gu2_alpha_value = 0;
89unsigned long gu2_alpha_mode = 0;
90unsigned long gu2_alpha_active = 0;
91unsigned short gu2_alpha_blt_mode = 0;
92unsigned short gu2_alpha_vec_mode = 0;
93unsigned short gu2_blt_mode = 0;
94unsigned short gu2_vector_mode = 0;
95unsigned short gu2_bm_throttle = 0;
96unsigned short gu2_vm_throttle = 0;
97int gu2_current_line = 0;
98
99/* Kill a warning */
100void gfx_reset_pitch(unsigned short pitch);
101
102/*---------------------------------------------------------------------------
103 * GFX_RESET_PITCH (PRIVATE ROUTINE - NOT PART OF API)
104 *
105 * This routine resets all pitches in the graphics engine to one value.
106 *---------------------------------------------------------------------------
107 */
108#if GFX_2DACCEL_DYNAMIC
109void
110gu2_reset_pitch(unsigned short pitch)
111#else
112void
113gfx_reset_pitch(unsigned short pitch)
114#endif
115{
116    gu2_pitch = pitch;
117    gu2_dst_pitch = pitch;
118    gu2_src_pitch = pitch;
119}
120
121/*---------------------------------------------------------------------------
122 * GFX_SET_BPP
123 *
124 * This routine sets the bits per pixel value in the graphics engine.
125 * It is also stored in the static variable "gu2_bpp" to use in the future
126 * calls to the rendering routines.  That variable contains the hardware
127 * specific value to load into the MGP_RASTER_MODE register.
128 *---------------------------------------------------------------------------
129 */
130#if GFX_2DACCEL_DYNAMIC
131void
132gu2_set_bpp(unsigned short bpp)
133#else
134void
135gfx_set_bpp(unsigned short bpp)
136#endif
137{
138    GFXbpp = bpp;
139
140    /* CONVERT TO BPP/FORMAT VALUE */
141    /* Save in global to combine with ROP later. */
142    /* Could write register here and then use byte access for */
143    /* the ROP, but would need to set other 24 bits to make */
144    /* sure all are set to their appropriate values. */
145
146    switch (bpp) {
147    case 8:
148        gu2_bpp = MGP_RM_BPPFMT_332;
149        gu2_xshift = 0;
150        break;
151    case 12:
152        gu2_bpp = MGP_RM_BPPFMT_4444;
153        gu2_xshift = 1;
154        break;
155    case 15:
156        gu2_bpp = MGP_RM_BPPFMT_1555;
157        gu2_xshift = 1;
158        break;
159    case 16:
160        gu2_bpp = MGP_RM_BPPFMT_565;
161        gu2_xshift = 1;
162        break;
163    case 32:
164        gu2_bpp = MGP_RM_BPPFMT_8888;
165        gu2_xshift = 2;
166        break;
167    }
168
169    /* SET INITIAL ROP BASED ONLY ON BPP */
170    /* Needs to be set before loading any pattern or source colors. */
171    /* We must wait for BUSY because these bits are not pipelined   */
172    /* in the hardware.                                             */
173
174    GU2_WAIT_BUSY;
175    WRITE_GP32(MGP_RASTER_MODE, gu2_bpp);
176}
177
178/*
179 *---------------------------------------------------------------------------
180 * GFX_SET_SOLID_SOURCE
181 *
182 * This routine is used to specify a solid source color.  For the Xfree96
183 * display driver, the source color is used to specify a planemask and the
184 * ROP is adjusted accordingly.
185 *---------------------------------------------------------------------------
186 */
187#if GFX_2DACCEL_DYNAMIC
188void
189gu2_set_solid_source(unsigned long color)
190#else
191void
192gfx_set_solid_source(unsigned long color)
193#endif
194{
195    /* CLEAR TRANSPARENCY FLAG */
196
197    GFXsourceFlags = 0;
198
199    /* WRITE REGISTERS TO SPECIFY SOURCE COLOR */
200
201    GU2_WAIT_PENDING;
202    WRITE_GP32(MGP_SRC_COLOR_FG, color);
203}
204
205/*
206 *---------------------------------------------------------------------------
207 * GFX_SET_MONO_SOURCE
208 *
209 * This routine is used to specify the monochrome source colors.
210 * It must be called *after* loading any pattern data (those routines
211 * clear the source flags).
212 *---------------------------------------------------------------------------
213 */
214#if GFX_2DACCEL_DYNAMIC
215void
216gu2_set_mono_source(unsigned long bgcolor, unsigned long fgcolor,
217                    unsigned short transparent)
218#else
219void
220gfx_set_mono_source(unsigned long bgcolor, unsigned long fgcolor,
221                    unsigned short transparent)
222#endif
223{
224    /* SET TRANSPARENCY FLAG */
225
226    GFXsourceFlags = transparent ? MGP_RM_SRC_TRANS : 0;
227
228    /* WRITE COLOR VALUES */
229
230    GU2_WAIT_PENDING;
231    WRITE_GP32(MGP_SRC_COLOR_FG, fgcolor);
232    WRITE_GP32(MGP_SRC_COLOR_BG, bgcolor);
233}
234
235/*
236 *---------------------------------------------------------------------------
237 * GFX_SET_SOLID_PATTERN
238 *
239 * This routine is used to specify a solid pattern color.  It is called
240 * before performing solid rectangle fills or more complicated BLTs that
241 * use a solid pattern color.
242 *
243 * The driver should always call "gfx_load_raster_operation" after a call
244 * to this routine to make sure that the pattern flags are set appropriately.
245 *---------------------------------------------------------------------------
246 */
247#if GFX_2DACCEL_DYNAMIC
248void
249gu2_set_solid_pattern(unsigned long color)
250#else
251void
252gfx_set_solid_pattern(unsigned long color)
253#endif
254{
255    /* CLEAR TRANSPARENCY FLAG */
256
257    GFXsourceFlags = 0;
258
259    /* SET PATTERN FLAGS */
260
261    GFXpatternFlags = 0;
262
263    /* POLL UNTIL ABLE TO WRITE THE PATTERN COLOR */
264
265    GU2_WAIT_PENDING;
266    WRITE_GP32(MGP_RASTER_MODE, gu2_bpp);
267    WRITE_GP32(MGP_PAT_COLOR_0, color);
268}
269
270/*
271 *---------------------------------------------------------------------------
272 * GFX_SET_MONO_PATTERN
273 *
274 * This routine is used to specify a monochrome pattern.
275 *---------------------------------------------------------------------------
276 */
277#if GFX_2DACCEL_DYNAMIC
278void
279gu2_set_mono_pattern(unsigned long bgcolor, unsigned long fgcolor,
280                     unsigned long data0, unsigned long data1,
281                     unsigned char transparent)
282#else
283void
284gfx_set_mono_pattern(unsigned long bgcolor, unsigned long fgcolor,
285                     unsigned long data0, unsigned long data1,
286                     unsigned char transparent)
287#endif
288{
289    /* CLEAR TRANSPARENCY FLAG */
290
291    GFXsourceFlags = 0;
292
293    /* SET PATTERN FLAGS */
294
295    if (transparent)
296        GFXpatternFlags = MGP_RM_PAT_MONO | MGP_RM_PAT_TRANS;
297    else
298        GFXpatternFlags = MGP_RM_PAT_MONO;
299
300    /* POLL UNTIL ABLE TO WRITE THE PATTERN COLOR */
301
302    GU2_WAIT_PENDING;
303    WRITE_GP32(MGP_RASTER_MODE, gu2_bpp | GFXpatternFlags);
304    WRITE_GP32(MGP_PAT_COLOR_0, bgcolor);
305    WRITE_GP32(MGP_PAT_COLOR_1, fgcolor);
306    WRITE_GP32(MGP_PAT_DATA_0, data0);
307    WRITE_GP32(MGP_PAT_DATA_1, data1);
308}
309
310/*
311 *---------------------------------------------------------------------------
312 * GFX_SET_COLOR_PATTERN
313 *
314 * This routine is used to specify a color pattern.
315 *---------------------------------------------------------------------------
316 */
317#if GFX_2DACCEL_DYNAMIC
318void
319gu2_set_color_pattern(unsigned long bgcolor, unsigned long fgcolor,
320                      unsigned long data0, unsigned long data1,
321                      unsigned long data2, unsigned long data3,
322                      unsigned char transparent)
323#else
324void
325gfx_set_color_pattern(unsigned long bgcolor, unsigned long fgcolor,
326                      unsigned long data0, unsigned long data1,
327                      unsigned long data2, unsigned long data3,
328                      unsigned char transparent)
329#endif
330{
331    /* REMOVE */
332}
333
334/*
335 *---------------------------------------------------------------------------
336 * GFX_LOAD_COLOR_PATTERN_LINE
337 *
338 * This routine is used to load a single line of a 8x8 color pattern.
339 *---------------------------------------------------------------------------  */
340#if GFX_2DACCEL_DYNAMIC
341void
342gu2_load_color_pattern_line(short y, unsigned long *pattern_8x8)
343#else
344void
345gfx_load_color_pattern_line(short y, unsigned long *pattern_8x8)
346#endif
347{
348    unsigned long temp1, temp2, temp3, temp4;
349
350    /* CLEAR TRANSPARENCY FLAG */
351
352    GFXsourceFlags = 0;
353
354    /* SET PATTERN FLAGS */
355
356    GFXpatternFlags = MGP_RM_PAT_COLOR;
357
358    /* OVERRIDE THE RASTER MODE REGISTER */
359    /* If the pattern format is set to anything but color  */
360    /* before loading the registers, some of the data will */
361    /* be duplicated according to the current mode.        */
362
363    GU2_WAIT_PENDING;
364    WRITE_GP32(MGP_RASTER_MODE,
365               (gu2_rop32 & ~MGP_RM_PAT_FLAGS) | MGP_RM_PAT_COLOR);
366
367    /* LOAD THE PATTERN DATA */
368    /* This routine is designed to work in tandem with gfx_pattern_fill.  */
369    /* It is used for cases when multiple BLTs with color pattern data    */
370    /* are desired on the same line.  It would be inefficient to          */
371    /* repeatedly call gfx_color_pattern_fill for each single-line BLT.   */
372    /* So, we will simply replicate the pattern data across all available */
373    /* lines such that the pattern y origin plays no part in the BLT.     */
374
375    /* 8 BPP */
376
377    if (gu2_xshift == 0) {
378        pattern_8x8 += (y & 7) << 1;
379        temp1 = BYTE_SWIZZLE(pattern_8x8[0]);
380        temp2 = BYTE_SWIZZLE(pattern_8x8[1]);
381        WRITE_GP32(MGP_PAT_DATA_1, temp1);
382        WRITE_GP32(MGP_PAT_DATA_0, temp2);
383        WRITE_GP32(MGP_PAT_COLOR_1, temp1);
384        WRITE_GP32(MGP_PAT_COLOR_0, temp2);
385
386        GU2_WAIT_BUSY;
387        WRITE_GP32(MGP_PAT_COLOR_3, temp1);
388        WRITE_GP32(MGP_PAT_COLOR_2, temp2);
389        WRITE_GP32(MGP_PAT_COLOR_5, temp1);
390        WRITE_GP32(MGP_PAT_COLOR_4, temp2);
391    }
392    else if (gu2_xshift == 1) {
393        pattern_8x8 += (y & 7) << 2;
394        temp1 = WORD_SWIZZLE(pattern_8x8[0]);
395        temp2 = WORD_SWIZZLE(pattern_8x8[1]);
396        temp3 = WORD_SWIZZLE(pattern_8x8[2]);
397        temp4 = WORD_SWIZZLE(pattern_8x8[3]);
398
399        WRITE_GP32(MGP_PAT_COLOR_1, temp1);
400        WRITE_GP32(MGP_PAT_COLOR_0, temp2);
401        WRITE_GP32(MGP_PAT_DATA_1, temp3);
402        WRITE_GP32(MGP_PAT_DATA_0, temp4);
403
404        GU2_WAIT_BUSY;
405        WRITE_GP32(MGP_PAT_COLOR_5, temp1);
406        WRITE_GP32(MGP_PAT_COLOR_4, temp2);
407        WRITE_GP32(MGP_PAT_COLOR_3, temp3);
408        WRITE_GP32(MGP_PAT_COLOR_2, temp4);
409    }
410    else {
411        pattern_8x8 += (y & 7) << 3;
412
413        WRITE_GP32(MGP_PAT_COLOR_1, pattern_8x8[4]);
414        WRITE_GP32(MGP_PAT_COLOR_0, pattern_8x8[5]);
415        WRITE_GP32(MGP_PAT_DATA_1, pattern_8x8[6]);
416        WRITE_GP32(MGP_PAT_DATA_0, pattern_8x8[7]);
417
418        GU2_WAIT_BUSY;
419        WRITE_GP32(MGP_PAT_COLOR_5, pattern_8x8[0]);
420        WRITE_GP32(MGP_PAT_COLOR_4, pattern_8x8[1]);
421        WRITE_GP32(MGP_PAT_COLOR_3, pattern_8x8[2]);
422        WRITE_GP32(MGP_PAT_COLOR_2, pattern_8x8[3]);
423    }
424}
425
426/*
427 *---------------------------------------------------------------------------
428 * GFX_SET_RASTER_OPERATION
429 *
430 * This routine loads the specified raster operation.  It sets the pattern
431 * flags appropriately.
432 *---------------------------------------------------------------------------
433 */
434#if GFX_2DACCEL_DYNAMIC
435void
436gu2_set_raster_operation(unsigned char rop)
437#else
438void
439gfx_set_raster_operation(unsigned char rop)
440#endif
441{
442    gu2_blt_mode = 0;
443
444    /* DISABLE ALPHA BLENDING */
445
446    gu2_alpha_active = 0;
447
448    /* GENERATE 32-BIT VERSION OF ROP WITH PATTERN FLAGS */
449
450    gu2_rop32 = (unsigned long) rop | GFXpatternFlags | gu2_bpp;
451
452    /* CHECK IF SOURCE FLAGS SHOULD BE MERGED */
453
454    if ((rop & 0x33) ^ ((rop >> 2) & 0x33))
455        gu2_rop32 |= GFXsourceFlags;
456    else
457        gu2_blt_mode = 0x40;
458
459    /* SET FLAG INDICATING ROP REQUIRES DESTINATION DATA */
460    /* True if even bits (0:2:4:6) do not equal the corresponding */
461    /* even bits (1:3:5:7). */
462
463    if ((rop & 0x55) ^ ((rop >> 1) & 0x55)) {
464        gu2_blt_mode |= MGP_BM_DST_REQ;
465        gu2_vector_mode = MGP_VM_DST_REQ;
466    }
467    else {
468        gu2_vector_mode = 0;
469    }
470}
471
472/*
473 *----------------------------------------------------------------------------
474 * GFX_PATTERN_FILL
475 *
476 * This routine is used to fill a rectangular region.  The pattern must
477 * be previously loaded using one of GFX_load_*_pattern routines.  Also, the
478 * raster operation must be previously specified using the
479 * "GFX_load_raster_operation" routine.
480 *
481 *      X               screen X position (left)
482 *      Y               screen Y position (top)
483 *      WIDTH           width of rectangle, in pixels
484 *      HEIGHT          height of rectangle, in scanlines
485 *----------------------------------------------------------------------------
486 */
487#if GFX_2DACCEL_DYNAMIC
488void
489gu2_pattern_fill(unsigned short x, unsigned short y,
490                 unsigned short width, unsigned short height)
491#else
492void
493gfx_pattern_fill(unsigned short x, unsigned short y,
494                 unsigned short width, unsigned short height)
495#endif
496{
497    unsigned long offset = 0, size;
498
499    size = (((unsigned long) width) << 16) | height;
500
501    /* CALCULATE STARTING OFFSET */
502
503    offset = (unsigned long) y *gu2_pitch + (((unsigned long) x) << gu2_xshift);
504
505    /* CHECK IF PATTERN ORIGINS NEED TO BE SET */
506
507    if (GFXpatternFlags) {
508        /* COMBINE X AND Y PATTERN ORIGINS WITH OFFSET */
509
510        offset |= ((unsigned long) (x & 7)) << 26;
511        offset |= ((unsigned long) (y & 7)) << 29;
512    }
513
514    /* POLL UNTIL ABLE TO WRITE TO THE REGISTERS */
515    /* Put off poll for as long as possible (do most calculations first). */
516
517    GU2_WAIT_PENDING;
518    WRITE_GP32(MGP_RASTER_MODE, gu2_rop32);
519    WRITE_GP32(MGP_DST_OFFSET, offset);
520    WRITE_GP32(MGP_WID_HEIGHT, size);
521    WRITE_GP32(MGP_STRIDE, gu2_pitch);
522    WRITE_GP32(MGP_BLT_MODE, gu2_blt_mode);
523}
524
525/*
526 *----------------------------------------------------------------------------
527 * GFX_COLOR_PATTERN_FILL
528 *
529 * This routine is used to render a rectangle using the current raster
530 * operation and the specified color pattern.  It allows an 8x8 color
531 * pattern to be rendered without multiple calls to the gfx_set_color_pattern
532 * and gfx_pattern_fill routines.
533 *
534 *      X               screen X position (left)
535 *      Y               screen Y position (top)
536 *      WIDTH           width of rectangle, in pixels
537 *      HEIGHT          height of rectangle, in scanlines
538 *      *PATTERN		pointer to 8x8 color pattern data
539 *----------------------------------------------------------------------------
540 */
541#if GFX_2DACCEL_DYNAMIC
542void
543gu2_color_pattern_fill(unsigned short x, unsigned short y,
544                       unsigned short width, unsigned short height,
545                       unsigned long *pattern)
546#else
547void
548gfx_color_pattern_fill(unsigned short x, unsigned short y,
549                       unsigned short width, unsigned short height,
550                       unsigned long *pattern)
551#endif
552{
553    /* CALL GFX2 ROUTINE TO AVOID DUPLICATION OF CODE */
554
555    unsigned long offset = (unsigned long) y * gu2_pitch +
556        (((unsigned long) x) << gu2_xshift);
557    unsigned long origin = gu2_pattern_origin;
558    unsigned long pitch = gu2_dst_pitch;
559
560    gfx2_set_pattern_origin(x, y);
561    gfx2_set_destination_stride((unsigned short) gu2_pitch);
562    gfx2_color_pattern_fill(offset, width, height, pattern);
563
564    /* RESTORE GFX2 VALUES */
565
566    gu2_pattern_origin = origin;
567    gu2_dst_pitch = pitch;
568}
569
570/*
571 *----------------------------------------------------------------------------
572 * SCREEN TO SCREEN BLT
573 *
574 * This routine should be used to perform a screen to screen BLT when the
575 * ROP does not require destination data.
576 *
577 *      SRCX            screen X position to copy from
578 *      SRCY            screen Y position to copy from
579 *      DSTX            screen X position to copy to
580 *      DSTY            screen Y position to copy to
581 *      WIDTH           width of rectangle, in pixels
582 *      HEIGHT          height of rectangle, in scanlines
583 *----------------------------------------------------------------------------
584 */
585#if GFX_2DACCEL_DYNAMIC
586void
587gu2_screen_to_screen_blt(unsigned short srcx, unsigned short srcy,
588                         unsigned short dstx, unsigned short dsty,
589                         unsigned short width, unsigned short height)
590#else
591void
592gfx_screen_to_screen_blt(unsigned short srcx, unsigned short srcy,
593                         unsigned short dstx, unsigned short dsty,
594                         unsigned short width, unsigned short height)
595#endif
596{
597    unsigned long srcoffset, dstoffset, size;
598    unsigned short blt_mode;
599
600    size = (((unsigned long) width) << 16) | height;
601
602    /* CALCULATE THE DIRECTION OF THE BLT */
603
604    blt_mode = (gu2_blt_mode & ~MGP_BM_SRC_TYPE_MASK) | MGP_BM_SRC_FB;
605    if (dstx > srcx) {
606        blt_mode |= MGP_BM_NEG_XDIR;
607        srcx += width - 1;
608        dstx += width - 1;
609    }
610    if (dsty > srcy) {
611        blt_mode |= MGP_BM_NEG_YDIR;
612        srcy += height - 1;
613        dsty += height - 1;
614    }
615
616    /* CALCULATE STARTING OFFSETS */
617
618    srcoffset = (unsigned long) srcy *gu2_pitch +
619        (((unsigned long) srcx) << gu2_xshift);
620    dstoffset = ((unsigned long) dsty * gu2_pitch +
621                 (((unsigned long) dstx) << gu2_xshift)) & 0xFFFFFF;
622
623    /* MERGE PATTERN INFORMATION */
624    /* This must be done after the x and y coordinates have been updated,  */
625    /* as the x and y pattern origins correspond to the first ROPed pixel. */
626
627    if (GFXpatternFlags) {
628        /* COMBINE X AND Y PATTERN ORIGINS WITH OFFSET */
629
630        dstoffset |= ((unsigned long) (dstx & 7)) << 26;
631        dstoffset |= ((unsigned long) (dsty & 7)) << 29;
632    }
633
634    /* TURN INTO BYTE ADDRESS IF NEGATIVE X DIRECTION */
635    /* This is a quirk of the hardware. */
636
637    if (blt_mode & MGP_BM_NEG_XDIR) {
638        srcoffset += (1 << gu2_xshift) - 1;
639        dstoffset += (1 << gu2_xshift) - 1;
640    }
641
642    /* POLL UNTIL ABLE TO WRITE TO THE REGISTERS */
643    /* Put off poll for as long as possible (do most calculations first). */
644
645    GU2_WAIT_PENDING;
646    WRITE_GP32(MGP_RASTER_MODE, gu2_rop32 | GFXsourceFlags);
647    WRITE_GP32(MGP_SRC_OFFSET, srcoffset);
648    WRITE_GP32(MGP_DST_OFFSET, dstoffset);
649    WRITE_GP32(MGP_WID_HEIGHT, size);
650    WRITE_GP32(MGP_STRIDE, gu2_pitch | (gu2_pitch << 16));
651    WRITE_GP16(MGP_BLT_MODE, blt_mode);
652}
653
654/*
655 *----------------------------------------------------------------------------
656 * SCREEN TO SCREEN TRANSPARENT BLT
657 *
658 * This routine should be used to perform a screen to screen BLT when a
659 * specified color should by transparent.  The only supported ROP is SRCCOPY.
660 *
661 *      SRCX            screen X position to copy from
662 *      SRCY            screen Y position to copy from
663 *      DSTX            screen X position to copy to
664 *      DSTY            screen Y position to copy to
665 *      WIDTH           width of rectangle, in pixels
666 *      HEIGHT          height of rectangle, in scanlines
667 *      COLOR           transparent color
668 *----------------------------------------------------------------------------
669 */
670#if GFX_2DACCEL_DYNAMIC
671void
672gu2_screen_to_screen_xblt(unsigned short srcx, unsigned short srcy,
673                          unsigned short dstx, unsigned short dsty,
674                          unsigned short width, unsigned short height,
675                          unsigned long color)
676#else
677void
678gfx_screen_to_screen_xblt(unsigned short srcx, unsigned short srcy,
679                          unsigned short dstx, unsigned short dsty,
680                          unsigned short width, unsigned short height,
681                          unsigned long color)
682#endif
683{
684    unsigned long rop32;
685
686    /* SAVE ORIGINAL RASTER MODE SETTINGS */
687
688    rop32 = gu2_rop32;
689
690    /* WRITE REGISTERS TO SPECIFY COLOR TRANSPARENCY */
691    /* Match GU1 implementation that only allows SRCCOPY for the ROP. */
692
693    GU2_WAIT_PENDING;
694    WRITE_GP32(MGP_SRC_COLOR_FG, color);
695    WRITE_GP32(MGP_SRC_COLOR_BG, 0xFFFFFFFF);
696
697    /* SET GLOBAL RASTER SETTINGS */
698    /* This is needed, as the screen-to-screen BLT      */
699    /* routine will overwrite the raster mode register. */
700
701    gu2_rop32 = gu2_bpp | MGP_RM_SRC_TRANS | 0xCC;
702
703    /* CALL NORMAL SCREEN TO SCREEN BLT ROUTINE */
704
705    gfx_screen_to_screen_blt(srcx, srcy, dstx, dsty, width, height);
706
707    /* RESTORE GLOBAL RASTER SETTINGS */
708
709    gu2_rop32 = rop32;
710}
711
712/*
713 *----------------------------------------------------------------------------
714 * COLOR BITMAP TO SCREEN BLT
715 *
716 * This routine transfers color bitmap data to the screen.
717 *
718 *      SRCX            X offset within source bitmap
719 *      SRCY            Y offset within source bitmap
720 *      DSTX            screen X position to render data
721 *      DSTY            screen Y position to render data
722 *      WIDTH           width of rectangle, in pixels
723 *      HEIGHT          height of rectangle, in scanlines
724 *      *DATA           pointer to bitmap data
725 *      PITCH           pitch of bitmap data (bytes between scanlines)
726 *
727 * Transparency is handled by another routine.
728 *----------------------------------------------------------------------------
729 */
730
731#if GFX_2DACCEL_DYNAMIC
732void
733gu2_color_bitmap_to_screen_blt(unsigned short srcx, unsigned short srcy,
734                               unsigned short dstx, unsigned short dsty,
735                               unsigned short width, unsigned short height,
736                               unsigned char *data, long pitch)
737#else
738void
739gfx_color_bitmap_to_screen_blt(unsigned short srcx, unsigned short srcy,
740                               unsigned short dstx, unsigned short dsty,
741                               unsigned short width, unsigned short height,
742                               unsigned char *data, long pitch)
743#endif
744{
745    unsigned long dstoffset, srcoffset, size, bytes;
746    unsigned long offset, temp_offset;
747    unsigned long dword_bytes, bytes_extra;
748    unsigned short blt_mode;
749
750    blt_mode = (gu2_blt_mode & ~MGP_BM_SRC_TYPE_MASK) | MGP_BM_SRC_FB;
751    size = (((unsigned long) width) << 16) | 1;
752
753    /* CALCULATE STARTING OFFSETS */
754
755    offset = (unsigned long) srcy *pitch + ((unsigned long) srcx << gu2_xshift);
756
757    dstoffset = (unsigned long) dsty *gu2_pitch +
758        (((unsigned long) dstx) << gu2_xshift);
759
760    /* CHECK IF PATTERN ORIGINS NEED TO BE SET */
761
762    if (GFXpatternFlags) {
763        /* COMBINE X AND Y PATTERN ORIGINS WITH OFFSET */
764
765        dstoffset |= ((unsigned long) (dstx & 7)) << 26;
766        dstoffset |= ((unsigned long) (dsty & 7)) << 29;
767    }
768
769    bytes = width << gu2_xshift;
770    dword_bytes = bytes & ~0x3L;
771    bytes_extra = bytes & 0x3L;
772
773    /* POLL UNTIL ABLE TO WRITE TO THE REGISTERS */
774    /* Put off poll for as long as possible (do most calculations first).   */
775    /* The source offset is always 0 since we allow misaligned dword reads. */
776    /* We must wait for BLT busy because the GP may be executing a screen   */
777    /* to screen BLT from the scratchpad area.                              */
778
779    GU2_WAIT_BUSY;
780    WRITE_GP32(MGP_RASTER_MODE, gu2_rop32 | GFXsourceFlags);
781    WRITE_GP32(MGP_WID_HEIGHT, size);
782    WRITE_GP32(MGP_STRIDE, gu2_pitch);
783
784    /* WRITE DATA ONE LINE AT A TIME */
785    /* For speed reasons, data is written to an offscreen scratch area and then        */
786    /* BLTed using a screen to screen BLT. This is similar to the GX1 BLT buffers, but */
787    /* slightly more efficient in that we can queue up data while the GP is rendering  */
788    /* a line.                                                                         */
789
790    while (height--) {
791        temp_offset = offset;
792        srcoffset = gfx_gx2_scratch_base;
793        if (gu2_current_line)
794            srcoffset += 8192;
795
796        GU2_WAIT_PENDING;
797        WRITE_GP32(MGP_SRC_OFFSET, srcoffset);
798        WRITE_GP32(MGP_DST_OFFSET, dstoffset);
799        dstoffset += gu2_pitch;
800        dstoffset += 0x20000000;
801
802        WRITE_FRAME_BUFFER_STRING32(srcoffset, dword_bytes, data, temp_offset);
803        if (bytes_extra) {
804            temp_offset += dword_bytes;
805            srcoffset += dword_bytes;
806            WRITE_FRAME_BUFFER_STRING8(srcoffset, bytes_extra, data,
807                                       temp_offset);
808        }
809        WRITE_GP16(MGP_BLT_MODE, blt_mode);
810        offset += pitch;
811        gu2_current_line = 1 - gu2_current_line;
812    }
813}
814
815/*
816 *----------------------------------------------------------------------------
817 * COLOR BITMAP TO SCREEN TRANSPARENT BLT
818 *
819 * This routine transfers color bitmap data to the screen with transparency.
820 * The transparent color is specified.  The only supported ROP is SRCCOPY,
821 * meaning that transparency cannot be applied if the ROP requires
822 * destination data (this is a hardware restriction).
823 *
824 *      SRCX            X offset within source bitmap
825 *      SRCY            Y offset within source bitmap
826 *      DSTX            screen X position to render data
827 *      DSTY            screen Y position to render data
828 *      WIDTH           width of rectangle, in pixels
829 *      HEIGHT          height of rectangle, in scanlines
830 *      *DATA           pointer to bitmap data
831 *      PITCH           pitch of bitmap data (bytes between scanlines)
832 *      COLOR           transparent color
833 *----------------------------------------------------------------------------
834 */
835#if GFX_2DACCEL_DYNAMIC
836void
837gu2_color_bitmap_to_screen_xblt(unsigned short srcx, unsigned short srcy,
838                                unsigned short dstx, unsigned short dsty,
839                                unsigned short width, unsigned short height,
840                                unsigned char *data, long pitch,
841                                unsigned long color)
842#else
843void
844gfx_color_bitmap_to_screen_xblt(unsigned short srcx, unsigned short srcy,
845                                unsigned short dstx, unsigned short dsty,
846                                unsigned short width, unsigned short height,
847                                unsigned char *data, long pitch,
848                                unsigned long color)
849#endif
850{
851    unsigned long rop32;
852
853    /* SAVE EXISTING RASTER MODE SETTINGS */
854
855    rop32 = gu2_rop32;
856
857    /* WRITE REGISTERS TO SPECIFY COLOR TRANSPARENCY */
858    /* Match GU1 implementation that only allows SRCCOPY for the ROP. */
859
860    GU2_WAIT_PENDING;
861    WRITE_GP32(MGP_SRC_COLOR_FG, color);
862    WRITE_GP32(MGP_SRC_COLOR_BG, 0xFFFFFFFF);
863
864    /* SET GLOBAL RASTER SETTINGS */
865    /* This is needed, as the screen-to-screen BLT      */
866    /* routine will overwrite the raster mode register. */
867
868    gu2_rop32 = gu2_bpp | MGP_RM_SRC_TRANS | 0xCC;
869
870    /* CALL NORMAL COLOR BITMAP TO SCREEN BLT ROUTINE */
871
872    gfx_color_bitmap_to_screen_blt(srcx, srcy, dstx, dsty, width, height,
873                                   data, pitch);
874
875    /* RESTORE RASTER SETTINGS */
876
877    gu2_rop32 = rop32;
878}
879
880/*
881 *----------------------------------------------------------------------------
882 * MONOCHROME BITMAP TO SCREEN BLT
883 *
884 * This routine transfers monochrome bitmap data to the screen.
885 *
886 *      SRCX            X offset within source bitmap
887 *      SRCY            Y offset within source bitmap
888 *      DSTX            screen X position to render data
889 *      DSTY            screen Y position to render data
890 *      WIDTH           width of rectangle, in pixels
891 *      HEIGHT          height of rectangle, in scanlines
892 *      *DATA           pointer to bitmap data
893 *      PITCH           pitch of bitmap data (bytes between scanlines)
894 *----------------------------------------------------------------------------
895 */
896#if GFX_2DACCEL_DYNAMIC
897void
898gu2_mono_bitmap_to_screen_blt(unsigned short srcx, unsigned short srcy,
899                              unsigned short dstx, unsigned short dsty,
900                              unsigned short width, unsigned short height,
901                              unsigned char *data, short pitch)
902#else
903void
904gfx_mono_bitmap_to_screen_blt(unsigned short srcx, unsigned short srcy,
905                              unsigned short dstx, unsigned short dsty,
906                              unsigned short width, unsigned short height,
907                              unsigned char *data, short pitch)
908#endif
909{
910    unsigned long dstoffset, size, bytes;
911    unsigned long offset, temp_offset, temp1 = 0, temp2 = 0;
912    unsigned long i, j = 0, fifo_lines, dwords_extra, bytes_extra;
913    unsigned long shift = 0;
914
915    size = (((unsigned long) width) << 16) | height;
916
917    /* CALCULATE STARTING OFFSETS */
918
919    offset = (unsigned long) srcy *pitch + ((unsigned long) srcx >> 3);
920
921    dstoffset = (unsigned long) dsty *gu2_pitch +
922        (((unsigned long) dstx) << gu2_xshift);
923
924    /* CHECK IF PATTERN ORIGINS NEED TO BE SET */
925
926    if (GFXpatternFlags) {
927        /* COMBINE X AND Y PATTERN ORIGINS WITH OFFSET */
928
929        dstoffset |= ((unsigned long) (dstx & 7)) << 26;
930        dstoffset |= ((unsigned long) (dsty & 7)) << 29;
931    }
932
933    bytes = ((srcx & 7) + width + 7) >> 3;
934    fifo_lines = bytes >> 5;
935    dwords_extra = (bytes & 0x0000001Cl) >> 2;
936    bytes_extra = bytes & 0x00000003l;
937
938    /* POLL UNTIL ABLE TO WRITE TO THE REGISTERS */
939    /* Put off poll for as long as possible (do most calculations first).   */
940    /* The source offset is always 0 since we allow misaligned dword reads. */
941    /* Need to wait for busy instead of pending, since hardware clears      */
942    /* the host data FIFO at the beginning of a BLT.                        */
943
944    GU2_WAIT_PENDING;
945    WRITE_GP32(MGP_RASTER_MODE, gu2_rop32 | GFXsourceFlags);
946    WRITE_GP32(MGP_SRC_OFFSET, ((unsigned long) srcx & 7) << 26);
947    WRITE_GP32(MGP_DST_OFFSET, dstoffset);
948    WRITE_GP32(MGP_WID_HEIGHT, size);
949    WRITE_GP32(MGP_STRIDE, gu2_pitch);
950    WRITE_GP16(MGP_BLT_MODE,
951               (gu2_blt_mode & ~MGP_BM_SRC_TYPE_MASK) | MGP_BM_SRC_HOST |
952               MGP_BM_SRC_MONO);
953
954    /* WAIT FOR BLT TO BE LATCHED */
955
956    GU2_WAIT_PENDING;
957
958    /* WRITE ALL OF THE DATA TO THE HOST SOURCE REGISTER */
959
960    while (height--) {
961        temp_offset = offset;
962
963        /* WRITE ALL FULL FIFO LINES */
964
965        for (i = 0; i < fifo_lines; i++) {
966            GU2_WAIT_HALF_EMPTY;
967            WRITE_GPREG_STRING32(MGP_HST_SOURCE, 8, j, data, temp_offset,
968                                 temp1);
969            temp_offset += 32;
970        }
971
972        /* WRITE ALL FULL DWORDS */
973
974        GU2_WAIT_HALF_EMPTY;
975        if (dwords_extra) {
976            WRITE_GPREG_STRING32(MGP_HST_SOURCE, dwords_extra, i, data,
977                                 temp_offset, temp1);
978            temp_offset += (dwords_extra << 2);
979        }
980
981        /* WRITE REMAINING BYTES */
982
983        shift = 0;
984        if (bytes_extra)
985            WRITE_GPREG_STRING8(MGP_HST_SOURCE, bytes_extra, shift, i, data,
986                                temp_offset, temp1, temp2);
987
988        offset += pitch;
989    }
990}
991
992/*---------------------------------------------------------------------------
993 * GFX_TEXT_BLT
994 *
995 * This routine is similar to the gfx_mono_bitmap_to_screen_blt routine
996 * but assumes that source data is byte-packed.
997 *---------------------------------------------------------------------------
998 */
999#if GFX_2DACCEL_DYNAMIC
1000void
1001gu2_text_blt(unsigned short dstx, unsigned short dsty, unsigned short width,
1002             unsigned short height, unsigned char *data)
1003#else
1004void
1005gfx_text_blt(unsigned short dstx, unsigned short dsty, unsigned short width,
1006             unsigned short height, unsigned char *data)
1007#endif
1008{
1009    unsigned long size, bytes;
1010    unsigned long dstoffset, temp1 = 0, temp2 = 0, temp_offset = 0;
1011    unsigned long i, j = 0, fifo_lines, dwords_extra, bytes_extra;
1012    unsigned long shift;
1013
1014    size = (((unsigned long) width) << 16) | height;
1015
1016    dstoffset = (unsigned long) dsty *gu2_pitch +
1017        (((unsigned long) dstx) << gu2_xshift);
1018
1019    /* CHECK IF PATTERN ORIGINS NEED TO BE SET */
1020
1021    if (GFXpatternFlags) {
1022        /* COMBINE X AND Y PATTERN ORIGINS WITH OFFSET */
1023
1024        dstoffset |= ((unsigned long) (dstx & 7)) << 26;
1025        dstoffset |= ((unsigned long) (dsty & 7)) << 29;
1026    }
1027
1028    /* CALCULATE STARTING OFFSETS */
1029
1030    bytes = ((width + 7) >> 3) * height;
1031    fifo_lines = bytes >> 5;
1032    dwords_extra = (bytes & 0x0000001Cl) >> 2;
1033    bytes_extra = bytes & 0x00000003l;
1034
1035    /* POLL UNTIL ABLE TO WRITE TO THE REGISTERS */
1036
1037    GU2_WAIT_PENDING;
1038    WRITE_GP32(MGP_RASTER_MODE, gu2_rop32 | GFXsourceFlags);
1039    WRITE_GP32(MGP_SRC_OFFSET, 0);
1040    WRITE_GP32(MGP_DST_OFFSET, dstoffset);
1041    WRITE_GP32(MGP_WID_HEIGHT, size);
1042    WRITE_GP32(MGP_STRIDE, gu2_pitch);
1043    WRITE_GP16(MGP_BLT_MODE,
1044               (gu2_blt_mode & ~MGP_BM_SRC_TYPE_MASK) | MGP_BM_SRC_HOST |
1045               MGP_BM_SRC_BP_MONO);
1046
1047    /* WAIT FOR BLT TO BE LATCHED */
1048
1049    GU2_WAIT_PENDING;
1050
1051    /* WRITE ALL FULL FIFO LINES */
1052
1053    for (i = 0; i < fifo_lines; i++) {
1054        GU2_WAIT_HALF_EMPTY;
1055        WRITE_GPREG_STRING32(MGP_HST_SOURCE, 8, j, data, temp_offset, temp1);
1056        temp_offset += 32;
1057    }
1058
1059    /* WRITE ALL FULL DWORDS */
1060
1061    if (dwords_extra || bytes_extra) {
1062        GU2_WAIT_HALF_EMPTY;
1063        if (dwords_extra) {
1064            WRITE_GPREG_STRING32(MGP_HST_SOURCE, dwords_extra, i, data,
1065                                 temp_offset, temp1);
1066            temp_offset += (dwords_extra << 2);
1067        }
1068        if (bytes_extra) {
1069            shift = 0;
1070            WRITE_GPREG_STRING8(MGP_HST_SOURCE, bytes_extra, shift, i, data,
1071                                temp_offset, temp1, temp2);
1072        }
1073    }
1074}
1075
1076/*
1077 *----------------------------------------------------------------------------
1078 * BRESENHAM LINE
1079 *
1080 * This routine draws a vector using the specified Bresenham parameters.
1081 * Currently this file does not support a routine that accepts the two
1082 * endpoints of a vector and calculates the Bresenham parameters.  If it
1083 * ever does, this routine is still required for vectors that have been
1084 * clipped.
1085 *
1086 *      X               screen X position to start vector
1087 *      Y               screen Y position to start vector
1088 *      LENGTH          length of the vector, in pixels
1089 *      INITERR         Bresenham initial error term
1090 *      AXIALERR        Bresenham axial error term
1091 *      DIAGERR         Bresenham diagonal error term
1092 *      FLAGS           VM_YMAJOR, VM_MAJOR_INC, VM_MINOR_INC
1093 *----------------------------------------------------------------------------
1094 */
1095#if GFX_2DACCEL_DYNAMIC
1096void
1097gu2_bresenham_line(unsigned short x, unsigned short y,
1098                   unsigned short length, unsigned short initerr,
1099                   unsigned short axialerr, unsigned short diagerr,
1100                   unsigned short flags)
1101#else
1102void
1103gfx_bresenham_line(unsigned short x, unsigned short y,
1104                   unsigned short length, unsigned short initerr,
1105                   unsigned short axialerr, unsigned short diagerr,
1106                   unsigned short flags)
1107#endif
1108{
1109    unsigned long offset;
1110    unsigned long data1 = (((unsigned long) axialerr) << 16) | diagerr;
1111    unsigned long data2 = (((unsigned long) length) << 16) | initerr;
1112    unsigned short vector_mode = gu2_vector_mode | flags;
1113
1114    /* CALCULATE STARTING OFFSET */
1115
1116    offset = (unsigned long) y *gu2_pitch + (((unsigned long) x) << gu2_xshift);
1117
1118    /* CHECK NULL LENGTH */
1119
1120    if (!length)
1121        return;
1122
1123    /* POLL UNTIL ABLE TO WRITE TO THE REGISTERS */
1124    /* Put off poll for as long as possible (do most calculations first). */
1125
1126    GU2_WAIT_PENDING;
1127    WRITE_GP32(MGP_RASTER_MODE, gu2_rop32);
1128    WRITE_GP32(MGP_DST_OFFSET, offset);
1129    WRITE_GP32(MGP_VEC_ERR, data1);
1130    WRITE_GP32(MGP_VEC_LEN, data2);
1131    WRITE_GP32(MGP_STRIDE, gu2_pitch);
1132    WRITE_GP32(MGP_VECTOR_MODE, vector_mode);
1133}
1134
1135/*---------------------------------------------------------------------------
1136 * GFX_WAIT_UNTIL_IDLE
1137 *
1138 * This routine waits until the graphics engine is idle.  This is required
1139 * before allowing direct access to the frame buffer.
1140 *---------------------------------------------------------------------------
1141 */
1142#if GFX_2DACCEL_DYNAMIC
1143void
1144gu2_wait_until_idle(void)
1145#else
1146void
1147gfx_wait_until_idle(void)
1148#endif
1149{
1150    while (READ_GP32(MGP_BLT_STATUS) & MGP_BS_BLT_BUSY);
1151}
1152
1153/*---------------------------------------------------------------------------
1154 * GFX_TEST_BLT_PENDING
1155 *
1156 * This routine returns 1 if a BLT is pending, meaning that a call to
1157 * perform a rendering operation would stall.  Otherwise it returns 0.
1158 * It is used by Darwin during random testing to only start a BLT
1159 * operation when it knows the Durango routines won't spin on graphics
1160 * (so Darwin can continue to do frame buffer reads and writes).
1161 *---------------------------------------------------------------------------
1162 */
1163#if GFX_2DACCEL_DYNAMIC
1164int
1165gu2_test_blt_pending(void)
1166#else
1167int
1168gfx_test_blt_pending(void)
1169#endif
1170{
1171    if (READ_GP32(MGP_BLT_STATUS) & MGP_BS_BLT_PENDING)
1172        return (1);
1173    return (0);
1174}
1175
1176/*---------------------------------------------------------------------------
1177 * NEW ROUTINES FOR REDCLOUD
1178 *---------------------------------------------------------------------------
1179 */
1180
1181/*---------------------------------------------------------------------------
1182 * GFX2_SET_SOURCE_STRIDE
1183 *
1184 * This routine sets the stride to be used in successive screen to screen
1185 * BLTs (used by gfx2_screen_to_screen_blt and gfx2_mono_expand_blt).
1186 *---------------------------------------------------------------------------
1187 */
1188#if GFX_2DACCEL_DYNAMIC
1189void
1190gu22_set_source_stride(unsigned short stride)
1191#else
1192void
1193gfx2_set_source_stride(unsigned short stride)
1194#endif
1195{
1196    /* SAVE STRIDE TO BE USED LATER */
1197
1198    gu2_src_pitch = (unsigned long) stride;
1199}
1200
1201/*---------------------------------------------------------------------------
1202 * GFX2_SET_DESTINATION_STRIDE
1203 *
1204 * This routine sets the stride used when rendering to the screen.
1205 *---------------------------------------------------------------------------
1206 */
1207#if GFX_2DACCEL_DYNAMIC
1208void
1209gu22_set_destination_stride(unsigned short stride)
1210#else
1211void
1212gfx2_set_destination_stride(unsigned short stride)
1213#endif
1214{
1215    /* SAVE STRIDE TO BE USED LATER */
1216
1217    gu2_dst_pitch = (unsigned long) stride;
1218}
1219
1220/*---------------------------------------------------------------------------
1221 * GFX2_SET_PATTERN_ORIGIN
1222 *
1223 * This routine sets the origin within an 8x8 pattern.  It is needed if
1224 * using a monochrome or color pattern (not used for a solid pattern).
1225 *---------------------------------------------------------------------------
1226 */
1227#if GFX_2DACCEL_DYNAMIC
1228void
1229gu22_set_pattern_origin(int x, int y)
1230#else
1231void
1232gfx2_set_pattern_origin(int x, int y)
1233#endif
1234{
1235    /* STORE IN FORMAT THAT CAN BE COMBINED WITH THE DESTINATION OFFSET */
1236
1237    gu2_pattern_origin = (((unsigned long) (x & 7)) << 26) |
1238        (((unsigned long) (y & 7)) << 29);
1239}
1240
1241/*---------------------------------------------------------------------------
1242 * GFX2_SET_SOURCE_TRANSPARENCY
1243 *
1244 * This routine sets the source transparency color and mask to be used
1245 * in future rendering operations.  If both the color and mask are set
1246 * to zero (normally completely transparent), those values indicate that
1247 * transparency should be disabled.
1248 *---------------------------------------------------------------------------
1249 */
1250#if GFX_2DACCEL_DYNAMIC
1251void
1252gu22_set_source_transparency(unsigned long color, unsigned long mask)
1253#else
1254void
1255gfx2_set_source_transparency(unsigned long color, unsigned long mask)
1256#endif
1257{
1258    /* WRITE REGISTERS TO SPECIFY COLOR TRANSPARENCY */
1259
1260    GU2_WAIT_PENDING;
1261    WRITE_GP32(MGP_SRC_COLOR_FG, color);
1262    WRITE_GP32(MGP_SRC_COLOR_BG, mask);
1263
1264    /* SET TRANSPARENCY FLAG */
1265
1266    GFXsourceFlags = (color || mask) ? MGP_RM_SRC_TRANS : 0;
1267}
1268
1269/*---------------------------------------------------------------------------
1270 * GFX2_SET_ALPHA_MODE
1271 *
1272 * This routine sets the alpha blending mode to be used in successive
1273 * rendering operations.
1274 *---------------------------------------------------------------------------
1275 */
1276#if GFX_2DACCEL_DYNAMIC
1277void
1278gu22_set_alpha_mode(int mode)
1279#else
1280void
1281gfx2_set_alpha_mode(int mode)
1282#endif
1283{
1284    /* SAVE ALPHA MODE FOR LATER */
1285
1286    gu2_alpha_mode = mode;
1287}
1288
1289/*---------------------------------------------------------------------------
1290 * GFX2_SET_ALPHA_VALUE
1291 *
1292 * This routine sets the alpha value to be used with certain alpha blending
1293 * modes (ALPHA_MODE_BLEND).
1294 *---------------------------------------------------------------------------
1295 */
1296#if GFX_2DACCEL_DYNAMIC
1297void
1298gu22_set_alpha_value(unsigned char value)
1299#else
1300void
1301gfx2_set_alpha_value(unsigned char value)
1302#endif
1303{
1304    /* SAVE ALPHA VALUE TO BE USED LATER */
1305
1306    gu2_alpha_value = (unsigned long) value;
1307
1308    /* SET GLOBAL FLAG */
1309    /* gfx2_* routines will use this flag to program alpha values */
1310    /* appropriately.  Normal gfx_* routines will always write    */
1311    /* the current ROP settings.  In this way, the alpha mode     */
1312    /* affects only second generation routines.                   */
1313
1314    gu2_alpha_active = 1;
1315
1316    switch (gu2_alpha_mode) {
1317    case ALPHA_MODE_BLEND:
1318
1319        /* GENERATE 32-BIT VERSION OF RASTER MODE REGISTER */
1320        /* Pattern data is not involved in the operation.  */
1321
1322        gu2_alpha32 = gu2_alpha_value | gu2_bpp;
1323
1324        /* HANDLE SPECIAL CASES FOR ENDPOINTS              */
1325        /* The 8-bit hardware alpha value is always        */
1326        /* interpreted as a fraction.  Consequently, there */
1327        /* is no way to use values of 255 or 0 to exclude  */
1328        /* one of the inputs.                              */
1329
1330        switch (gu2_alpha_value) {
1331            /* DESTINATION ONLY                               */
1332            /* Operation is alpha * A, where A is destination */
1333            /* and alpha is 1.                                */
1334
1335        case 0:
1336
1337            gu2_alpha32 |= MGP_RM_SELECT_ALPHA_1 |
1338                MGP_RM_ALPHA_TIMES_A |
1339                MGP_RM_ALPHA_TO_RGB | MGP_RM_DEST_FROM_CHAN_A;
1340            break;
1341
1342            /* SOURCE ONLY                                    */
1343            /* Operation is alpha * A, where A is source and  */
1344            /* alpha is 1.                                    */
1345
1346        case 255:
1347
1348            gu2_alpha32 |= MGP_RM_SELECT_ALPHA_1 |
1349                MGP_RM_ALPHA_TO_RGB | MGP_RM_ALPHA_TIMES_A;
1350            break;
1351
1352            /* DEFAULT                                        */
1353            /* Operation is alpha * A + (1 - alpha) * B;      */
1354            /* A is source, B is destination and alpha is the */
1355            /* programmed 8-bit value.                        */
1356
1357        default:
1358
1359            gu2_alpha32 |= MGP_RM_SELECT_ALPHA_R |
1360                MGP_RM_ALPHA_TO_RGB | MGP_RM_ALPHA_A_PLUS_BETA_B;
1361
1362        }
1363
1364        /* CHECK IF SOURCE INFORMATION SHOULD BE MERGED    */
1365        /* Alpha value of 0 indicates destination only.    */
1366
1367        if (gu2_alpha_value != 0)
1368            gu2_alpha32 |= GFXsourceFlags;
1369
1370        /* SET FLAG FOR DESTINATION DATA IF NECESSARY      */
1371        /* Alpha value of 255 indicates no destination     */
1372
1373        if (gu2_alpha_value != 255) {
1374            gu2_alpha_blt_mode = MGP_BM_DST_REQ;
1375            gu2_alpha_vec_mode = MGP_VM_DST_REQ;
1376        }
1377
1378        break;
1379    }
1380}
1381
1382/*---------------------------------------------------------------------------
1383 * GFX2_PATTERN_FILL
1384 *
1385 * This routine is similar to the gfx_pattern_fill routine, but allows the
1386 * use of an arbitrary destination stride.  The rendering position is
1387 * also specified as an offset instead of an (x,y) position.
1388 *---------------------------------------------------------------------------
1389 */
1390#if GFX_2DACCEL_DYNAMIC
1391void
1392gu22_pattern_fill(unsigned long dstoffset, unsigned short width,
1393                  unsigned short height)
1394#else
1395void
1396gfx2_pattern_fill(unsigned long dstoffset, unsigned short width,
1397                  unsigned short height)
1398#endif
1399{
1400    unsigned long size;
1401
1402    size = (((unsigned long) width) << 16) | height;
1403
1404    /* POLL UNTIL ABLE TO WRITE TO THE REGISTERS */
1405    /* Put off poll for as long as possible (do most calculations first). */
1406
1407    GU2_WAIT_PENDING;
1408    WRITE_GP32(MGP_RASTER_MODE, gu2_rop32);
1409    WRITE_GP32(MGP_DST_OFFSET, dstoffset | gu2_pattern_origin);
1410    WRITE_GP32(MGP_WID_HEIGHT, size);
1411    WRITE_GP32(MGP_STRIDE, gu2_dst_pitch);
1412    WRITE_GP32(MGP_BLT_MODE, gu2_blt_mode | gu2_bm_throttle);
1413    gu2_bm_throttle = 0;
1414    gu2_vm_throttle = 0;
1415}
1416
1417/*---------------------------------------------------------------------------
1418 * GFX2_COLOR_PATTERN_FILL
1419 *
1420 * This routine is used to render a rectangle using the current raster
1421 * operation and the specified color pattern.  It allows an 8x8 color
1422 * pattern to be rendered without multiple calls to the gfx_set_color_pattern
1423 * and gfx_pattern_fill routines.
1424 *---------------------------------------------------------------------------
1425 */
1426#if GFX_2DACCEL_DYNAMIC
1427void
1428gu22_color_pattern_fill(unsigned long dstoffset, unsigned short width,
1429                        unsigned short height, unsigned long *pattern)
1430#else
1431void
1432gfx2_color_pattern_fill(unsigned long dstoffset, unsigned short width,
1433                        unsigned short height, unsigned long *pattern)
1434#endif
1435{
1436    int pass;
1437    unsigned long lines, size, patxorigin, patoffset;
1438
1439    /* ONLY USE HW PATTERN ORIGIN FOR THE X DIRECTION */
1440    /* Y direction handled by referencing proper location in pattern data. */
1441
1442    patxorigin = (gu2_pattern_origin) & 0x1C000000;
1443
1444    /* OVERRIDE PATTERN FLAGS IN ROP TO FORCE COLOR PATTERN */
1445
1446    GU2_WAIT_PENDING;
1447    WRITE_GP32(MGP_RASTER_MODE,
1448               (gu2_rop32 & ~MGP_RM_PAT_FLAGS) | MGP_RM_PAT_COLOR);
1449
1450    /* ATTEMPT TO OPTIMIZE */
1451    /* If possible, we can perform the pattern fill in only a few passes    */
1452    /* This is performed by multiplying the pitch by an appropriate amount. */
1453    /* Consequently, if the multiplied pitch exceeds 16 bits, this          */
1454    /* optimization is impossible.                                          */
1455
1456    if ((gu2_dst_pitch << (gu2_xshift + 1)) <= 0xFFFF) {
1457        /* HANDLE VARIOUS COLOR DEPTHS DIFFERENTLY */
1458
1459        switch (gu2_xshift) {
1460        case 0:                /* 8 BPP */
1461
1462            /* TWO PASSES FOR 8 BPP */
1463            /* Render every other line per pass by doubling the pitch. */
1464
1465            patoffset = (gu2_pattern_origin >> 28) & 0x0E;
1466            for (pass = 0; pass < 2; pass++) {
1467                /* CAN WRITE SOME PATTERN REGISTERS WHILE "PENDING" */
1468
1469                GU2_WAIT_PENDING;
1470                WRITE_GP32(MGP_DST_OFFSET, dstoffset | patxorigin);
1471                lines = (height + 1 - pass) >> 1;
1472                if (!lines)
1473                    break;
1474                size = (((unsigned long) width) << 16) | lines;
1475                WRITE_GP32(MGP_WID_HEIGHT, size);
1476                WRITE_GP32(MGP_STRIDE, gu2_dst_pitch << 1);
1477                WRITE_GP32(MGP_PAT_DATA_1, BYTE_SWIZZLE(pattern[patoffset]));
1478                WRITE_GP32(MGP_PAT_DATA_0,
1479                           BYTE_SWIZZLE(pattern[patoffset + 1]));
1480                patoffset = (patoffset + 4) & 0x0E;
1481                WRITE_GP32(MGP_PAT_COLOR_1, BYTE_SWIZZLE(pattern[patoffset]));
1482                WRITE_GP32(MGP_PAT_COLOR_0,
1483                           BYTE_SWIZZLE(pattern[patoffset + 1]));
1484                patoffset = (patoffset + 4) & 0x0E;
1485
1486                /* NEED TO WAIT UNTIL IDLE FOR COLORS 2 THROUGH 5 */
1487                /* Those registers are not pipelined. */
1488
1489                GU2_WAIT_BUSY;
1490                WRITE_GP32(MGP_PAT_COLOR_3, BYTE_SWIZZLE(pattern[patoffset]));
1491                WRITE_GP32(MGP_PAT_COLOR_2,
1492                           BYTE_SWIZZLE(pattern[patoffset + 1]));
1493                patoffset = (patoffset + 4) & 0x0E;
1494                WRITE_GP32(MGP_PAT_COLOR_5, BYTE_SWIZZLE(pattern[patoffset]));
1495                WRITE_GP32(MGP_PAT_COLOR_4,
1496                           BYTE_SWIZZLE(pattern[patoffset + 1]));
1497                WRITE_GP16(MGP_BLT_MODE, gu2_blt_mode | gu2_bm_throttle);
1498                gu2_bm_throttle = 0;
1499                gu2_vm_throttle = 0;
1500
1501                /* ADJUST FOR NEXT PASS */
1502
1503                dstoffset += gu2_dst_pitch;
1504                patoffset = (patoffset + 6) & 0x0E;
1505            }
1506            break;
1507
1508        case 1:                /* 12, 15, OR 16 BPP */
1509
1510            /* FOUR PASSES FOR 16 BPP */
1511            /* Render every 4th line per pass by quadrupling the pitch. */
1512
1513            patoffset = (gu2_pattern_origin >> 27) & 0x1C;
1514            for (pass = 0; pass < 4; pass++) {
1515                /* CAN WRITE SOME PATTERN REGISTERS WHILE "PENDING" */
1516
1517                GU2_WAIT_PENDING;
1518                WRITE_GP32(MGP_DST_OFFSET, dstoffset | patxorigin);
1519                lines = (height + 3 - pass) >> 2;
1520                if (!lines)
1521                    break;
1522                size = (((unsigned long) width) << 16) | lines;
1523                WRITE_GP32(MGP_WID_HEIGHT, size);
1524                WRITE_GP32(MGP_STRIDE, gu2_dst_pitch << 2);
1525                WRITE_GP32(MGP_PAT_COLOR_1, WORD_SWIZZLE(pattern[patoffset]));
1526                WRITE_GP32(MGP_PAT_COLOR_0,
1527                           WORD_SWIZZLE(pattern[patoffset + 1]));
1528                WRITE_GP32(MGP_PAT_DATA_1,
1529                           WORD_SWIZZLE(pattern[patoffset + 2]));
1530                WRITE_GP32(MGP_PAT_DATA_0,
1531                           WORD_SWIZZLE(pattern[patoffset + 3]));
1532                patoffset = (patoffset + 16) & 0x1C;
1533
1534                /* NEED TO WAIT UNTIL IDLE FOR COLORS 2 THROUGH 5 */
1535                /* Those registers are not pipelined. */
1536
1537                GU2_WAIT_BUSY;
1538                WRITE_GP32(MGP_PAT_COLOR_5, WORD_SWIZZLE(pattern[patoffset]));
1539                WRITE_GP32(MGP_PAT_COLOR_4,
1540                           WORD_SWIZZLE(pattern[patoffset + 1]));
1541                WRITE_GP32(MGP_PAT_COLOR_3,
1542                           WORD_SWIZZLE(pattern[patoffset + 2]));
1543                WRITE_GP32(MGP_PAT_COLOR_2,
1544                           WORD_SWIZZLE(pattern[patoffset + 3]));
1545                WRITE_GP16(MGP_BLT_MODE, gu2_blt_mode | gu2_bm_throttle);
1546                gu2_bm_throttle = 0;
1547                gu2_vm_throttle = 0;
1548
1549                /* ADJUST FOR NEXT PASS */
1550
1551                dstoffset += gu2_dst_pitch;
1552                patoffset = (patoffset + 20) & 0x1C;
1553            }
1554            break;
1555
1556        case 2:                /* 32 BPP */
1557
1558            /* EIGHT PASSES FOR 32 BPP */
1559            /* Render every 8th line per pass by setting pitch * 8. */
1560
1561            patoffset = (gu2_pattern_origin >> 26) & 0x38;
1562            for (pass = 0; pass < 8; pass++) {
1563                /* CAN WRITE SOME PATTERN REGISTERS WHILE "PENDING" */
1564
1565                GU2_WAIT_PENDING;
1566                WRITE_GP32(MGP_DST_OFFSET, dstoffset | patxorigin);
1567                lines = (height + 7 - pass) >> 3;
1568                if (!lines)
1569                    break;
1570                size = (((unsigned long) width) << 16) | lines;
1571                WRITE_GP32(MGP_WID_HEIGHT, size);
1572                WRITE_GP32(MGP_STRIDE, gu2_dst_pitch << 3);
1573                WRITE_GP32(MGP_PAT_COLOR_1, pattern[patoffset + 4]);
1574                WRITE_GP32(MGP_PAT_COLOR_0, pattern[patoffset + 5]);
1575                WRITE_GP32(MGP_PAT_DATA_1, pattern[patoffset + 6]);
1576                WRITE_GP32(MGP_PAT_DATA_0, pattern[patoffset + 7]);
1577
1578                /* NEED TO WAIT UNTIL IDLE FOR COLORS 2 THROUGH 5 */
1579                /* Those registers are not pipelined. */
1580
1581                GU2_WAIT_BUSY;
1582                WRITE_GP32(MGP_PAT_COLOR_5, pattern[patoffset]);
1583                WRITE_GP32(MGP_PAT_COLOR_4, pattern[patoffset + 1]);
1584                WRITE_GP32(MGP_PAT_COLOR_3, pattern[patoffset + 2]);
1585                WRITE_GP32(MGP_PAT_COLOR_2, pattern[patoffset + 3]);
1586                WRITE_GP16(MGP_BLT_MODE, gu2_blt_mode | gu2_bm_throttle);
1587                gu2_bm_throttle = 0;
1588                gu2_vm_throttle = 0;
1589
1590                /* ADJUST FOR NEXT PASS */
1591
1592                dstoffset += gu2_dst_pitch;
1593                patoffset = (patoffset + 8) & 0x38;
1594            }
1595            break;
1596        }
1597    }
1598
1599    else {
1600        WRITE_GP32(MGP_STRIDE, gu2_dst_pitch);
1601
1602        switch (gu2_xshift) {
1603        case 0:                /* 8 BPP - 4 LINES PER PASS */
1604
1605            patoffset = (gu2_pattern_origin >> 28) & 0x0E;
1606            while (height) {
1607                lines = height > 4 ? 4 : height;
1608
1609                /* CAN WRITE SOME REGISTERS WHILE PENDING */
1610
1611                WRITE_GP32(MGP_DST_OFFSET, dstoffset | patxorigin);
1612                WRITE_GP32(MGP_WID_HEIGHT,
1613                           (((unsigned long) width) << 16) | lines);
1614                WRITE_GP32(MGP_PAT_DATA_1, BYTE_SWIZZLE(pattern[patoffset]));
1615                WRITE_GP32(MGP_PAT_DATA_0,
1616                           BYTE_SWIZZLE(pattern[patoffset + 1]));
1617                patoffset = (patoffset + 2) & 0x0E;
1618                WRITE_GP32(MGP_PAT_COLOR_1, BYTE_SWIZZLE(pattern[patoffset]));
1619                WRITE_GP32(MGP_PAT_COLOR_0,
1620                           BYTE_SWIZZLE(pattern[patoffset + 1]));
1621                patoffset = (patoffset + 2) & 0x0E;
1622
1623                /* NEED TO WAIT UNTIL IDLE FOR COLORS 2 THROUGH 5 */
1624                /* Those registers are not pipelined.             */
1625
1626                GU2_WAIT_BUSY;
1627                WRITE_GP32(MGP_PAT_COLOR_3, BYTE_SWIZZLE(pattern[patoffset]));
1628                WRITE_GP32(MGP_PAT_COLOR_2,
1629                           BYTE_SWIZZLE(pattern[patoffset + 1]));
1630                patoffset = (patoffset + 2) & 0x0E;
1631                WRITE_GP32(MGP_PAT_COLOR_5, BYTE_SWIZZLE(pattern[patoffset]));
1632                WRITE_GP32(MGP_PAT_COLOR_4,
1633                           BYTE_SWIZZLE(pattern[patoffset + 1]));
1634                patoffset = (patoffset + 2) & 0x0E;
1635                WRITE_GP16(MGP_BLT_MODE, gu2_blt_mode | gu2_bm_throttle);
1636
1637                /* ADJUST FOR NEXT PASS */
1638
1639                dstoffset += gu2_dst_pitch << 2;
1640                height -= (unsigned short) lines;
1641            }
1642            break;
1643
1644        case 1:                /* 12, 15 AND 16 BPP - 2 LINES PER PASS */
1645
1646            patoffset = (gu2_pattern_origin >> 27) & 0x1C;
1647            while (height) {
1648                lines = height > 2 ? 2 : height;
1649
1650                /* CAN WRITE SOME REGISTERS WHILE PENDING */
1651
1652                WRITE_GP32(MGP_DST_OFFSET, dstoffset | patxorigin);
1653                WRITE_GP32(MGP_WID_HEIGHT,
1654                           (((unsigned long) width) << 16) | lines);
1655                WRITE_GP32(MGP_PAT_COLOR_1, WORD_SWIZZLE(pattern[patoffset]));
1656                WRITE_GP32(MGP_PAT_COLOR_0,
1657                           WORD_SWIZZLE(pattern[patoffset + 1]));
1658                WRITE_GP32(MGP_PAT_DATA_1,
1659                           WORD_SWIZZLE(pattern[patoffset + 2]));
1660                WRITE_GP32(MGP_PAT_DATA_0,
1661                           WORD_SWIZZLE(pattern[patoffset + 3]));
1662                patoffset = (patoffset + 4) & 0x1C;
1663
1664                /* NEED TO WAIT UNTIL IDLE FOR COLORS 2 THROUGH 5 */
1665                /* Those registers are not pipelined.             */
1666
1667                GU2_WAIT_BUSY;
1668                WRITE_GP32(MGP_PAT_COLOR_5, WORD_SWIZZLE(pattern[patoffset]));
1669                WRITE_GP32(MGP_PAT_COLOR_4,
1670                           WORD_SWIZZLE(pattern[patoffset + 1]));
1671                WRITE_GP32(MGP_PAT_COLOR_3,
1672                           WORD_SWIZZLE(pattern[patoffset + 2]));
1673                WRITE_GP32(MGP_PAT_COLOR_2,
1674                           WORD_SWIZZLE(pattern[patoffset + 3]));
1675                patoffset = (patoffset + 4) & 0x1C;
1676                WRITE_GP16(MGP_BLT_MODE, gu2_blt_mode | gu2_bm_throttle);
1677
1678                /* ADJUST FOR NEXT PASS */
1679
1680                dstoffset += gu2_dst_pitch << 1;
1681                height -= (unsigned short) lines;
1682            }
1683            break;
1684
1685        case 2:                /* 32 BPP - 1 LINE PER PASS */
1686
1687            patoffset = (gu2_pattern_origin >> 26) & 0x38;
1688            while (height) {
1689                /* CAN WRITE SOME REGISTERS WHILE PENDING */
1690
1691                WRITE_GP32(MGP_DST_OFFSET, dstoffset | patxorigin);
1692                WRITE_GP32(MGP_WID_HEIGHT,
1693                           (((unsigned long) width) << 16) | 1l);
1694                WRITE_GP32(MGP_PAT_COLOR_1, pattern[patoffset + 4]);
1695                WRITE_GP32(MGP_PAT_COLOR_0, pattern[patoffset + 5]);
1696                WRITE_GP32(MGP_PAT_DATA_1, pattern[patoffset + 6]);
1697                WRITE_GP32(MGP_PAT_DATA_0, pattern[patoffset + 7]);
1698
1699                /* NEED TO WAIT UNTIL IDLE FOR COLORS 2 THROUGH 5 */
1700                /* Those registers are not pipelined.             */
1701
1702                GU2_WAIT_BUSY;
1703                WRITE_GP32(MGP_PAT_COLOR_5, pattern[patoffset]);
1704                WRITE_GP32(MGP_PAT_COLOR_4, pattern[patoffset + 1]);
1705                WRITE_GP32(MGP_PAT_COLOR_3, pattern[patoffset + 2]);
1706                WRITE_GP32(MGP_PAT_COLOR_2, pattern[patoffset + 3]);
1707                patoffset = (patoffset + 8) & 0x38;
1708                WRITE_GP16(MGP_BLT_MODE, gu2_blt_mode | gu2_bm_throttle);
1709
1710                /* ADJUST FOR NEXT PASS */
1711
1712                dstoffset += gu2_dst_pitch;
1713                height--;
1714            }
1715            break;
1716        }
1717
1718    }
1719
1720}
1721
1722/*---------------------------------------------------------------------------
1723 * GFX2_SCREEN_TO_SCREEN_BLT
1724 *
1725 * This routine is similar to the gfx_screen_to_screen_blt routine but
1726 * allows the use of arbitrary source and destination strides and alpha
1727 * blending.  It also allows the use of an arbitrary ROP with transparency.
1728 *---------------------------------------------------------------------------
1729 */
1730#if GFX_2DACCEL_DYNAMIC
1731void
1732gu22_screen_to_screen_blt(unsigned long srcoffset, unsigned long dstoffset,
1733                          unsigned short width, unsigned short height,
1734                          int flags)
1735#else
1736void
1737gfx2_screen_to_screen_blt(unsigned long srcoffset, unsigned long dstoffset,
1738                          unsigned short width, unsigned short height,
1739                          int flags)
1740#endif
1741{
1742    unsigned long size, xbytes;
1743    unsigned short blt_mode;
1744
1745    size = (((unsigned long) width) << 16) | height;
1746
1747    /* USE ALPHA SETTINGS, IF REQUESTED */
1748
1749    if (gu2_alpha_active)
1750        blt_mode = gu2_alpha_blt_mode | MGP_BM_SRC_FB;
1751
1752    else
1753        blt_mode = (gu2_blt_mode & ~MGP_BM_SRC_TYPE_MASK) | MGP_BM_SRC_FB;
1754
1755    /* CALCULATE THE DIRECTION OF THE BLT */
1756    /* Using offsets, so flags from the calling routine are needed. */
1757
1758    if (flags & 1) {
1759        xbytes = (width - 1) << gu2_xshift;
1760        srcoffset += xbytes;
1761        dstoffset += xbytes;
1762        blt_mode |= MGP_BM_NEG_XDIR;
1763    }
1764    if (flags & 2) {
1765        srcoffset += (height - 1) * gu2_src_pitch;
1766        dstoffset += (height - 1) * gu2_dst_pitch;
1767        blt_mode |= MGP_BM_NEG_YDIR;
1768    }
1769
1770    /* TURN INTO BYTE ADDRESS IF NEGATIVE X DIRECTION */
1771    /* This is a quirk of the hardware. */
1772
1773    if (blt_mode & MGP_BM_NEG_XDIR) {
1774        srcoffset += (1 << gu2_xshift) - 1;
1775        dstoffset += (1 << gu2_xshift) - 1;
1776    }
1777
1778    /* POLL UNTIL ABLE TO WRITE TO THE REGISTERS */
1779    /* Put off poll for as long as possible (do most calculations first). */
1780
1781    GU2_WAIT_PENDING;
1782
1783    if (gu2_alpha_active) {
1784        WRITE_GP32(MGP_RASTER_MODE, gu2_alpha32);
1785    }
1786    else {
1787        WRITE_GP32(MGP_RASTER_MODE, gu2_rop32 | GFXsourceFlags);
1788    }
1789
1790    WRITE_GP32(MGP_SRC_OFFSET, srcoffset);
1791    WRITE_GP32(MGP_DST_OFFSET, dstoffset | gu2_pattern_origin);
1792    WRITE_GP32(MGP_WID_HEIGHT, size);
1793    WRITE_GP32(MGP_STRIDE, gu2_dst_pitch | (gu2_src_pitch << 16));
1794    WRITE_GP16(MGP_BLT_MODE, blt_mode | gu2_bm_throttle);
1795    gu2_bm_throttle = 0;
1796    gu2_vm_throttle = 0;
1797}
1798
1799/*---------------------------------------------------------------------------
1800 * GFX2_MONO_EXPAND_BLT
1801 *
1802 * This routine is similar to the gfx2_screen_to_screen_blt routine but
1803 * expands monochrome data stored in graphics memory.
1804 * WARNING: This routine assumes that the regions in graphics memory
1805 * will not overlap, and therefore does not check the BLT direction.
1806 *---------------------------------------------------------------------------
1807 */
1808#if GFX_2DACCEL_DYNAMIC
1809void
1810gu22_mono_expand_blt(unsigned long srcbase, unsigned short srcx,
1811                     unsigned short srcy, unsigned long dstoffset,
1812                     unsigned short width, unsigned short height,
1813                     int byte_packed)
1814#else
1815void
1816gfx2_mono_expand_blt(unsigned long srcbase, unsigned short srcx,
1817                     unsigned short srcy, unsigned long dstoffset,
1818                     unsigned short width, unsigned short height,
1819                     int byte_packed)
1820#endif
1821{
1822    unsigned long size, srcoffset;
1823    unsigned short blt_mode;
1824
1825    size = (((unsigned long) width) << 16) | height;
1826
1827    /* CALCULATE SOURCE OFFSET */
1828
1829    srcoffset = srcbase + (unsigned long) srcy *gu2_src_pitch;
1830
1831    srcoffset += srcx >> 3;
1832    srcoffset |= ((unsigned long) srcx & 7) << 26;
1833
1834    /* POLL UNTIL ABLE TO WRITE TO THE REGISTERS */
1835    /* Put off poll for as long as possible (do most calculations first). */
1836
1837    GU2_WAIT_PENDING;
1838
1839    if (gu2_alpha_active) {
1840        blt_mode = gu2_alpha_blt_mode;
1841
1842        WRITE_GP32(MGP_RASTER_MODE, gu2_alpha32);
1843    }
1844    else {
1845        blt_mode = (gu2_blt_mode & ~MGP_BM_SRC_TYPE_MASK);
1846
1847        WRITE_GP32(MGP_RASTER_MODE, gu2_rop32 | GFXsourceFlags);
1848    }
1849
1850    if (byte_packed)
1851        blt_mode |= MGP_BM_SRC_FB | MGP_BM_SRC_BP_MONO | gu2_bm_throttle;
1852    else
1853        blt_mode |= MGP_BM_SRC_FB | MGP_BM_SRC_MONO | gu2_bm_throttle;
1854
1855    WRITE_GP32(MGP_SRC_OFFSET, srcoffset);
1856    WRITE_GP32(MGP_DST_OFFSET, dstoffset | gu2_pattern_origin);
1857    WRITE_GP32(MGP_WID_HEIGHT, size);
1858    WRITE_GP32(MGP_STRIDE, gu2_dst_pitch | (gu2_src_pitch << 16));
1859    WRITE_GP16(MGP_BLT_MODE, blt_mode);
1860    gu2_bm_throttle = 0;
1861    gu2_vm_throttle = 0;
1862}
1863
1864/*---------------------------------------------------------------------------
1865 * GFX2_COLOR_BITMAP_TO_SCREEN_BLT
1866 *
1867 * This routine is similar to the gfx_color_bitmap_to_screen_blt routine
1868 * but allows the use of an arbitrary destination stride and alpha blending.
1869 * It also allows the use of an arbitrary ROP with transparency.
1870 *---------------------------------------------------------------------------
1871 */
1872#if GFX_2DACCEL_DYNAMIC
1873void
1874gu22_color_bitmap_to_screen_blt(unsigned short srcx, unsigned short srcy,
1875                                unsigned long dstoffset, unsigned short width,
1876                                unsigned short height, unsigned char *data,
1877                                short pitch)
1878#else
1879void
1880gfx2_color_bitmap_to_screen_blt(unsigned short srcx, unsigned short srcy,
1881                                unsigned long dstoffset, unsigned short width,
1882                                unsigned short height, unsigned char *data,
1883                                short pitch)
1884#endif
1885{
1886    unsigned long size, bytes;
1887    unsigned long offset, temp_offset;
1888    unsigned long srcoffset, dword_bytes, bytes_extra;
1889    unsigned short blt_mode;
1890
1891    size = (((unsigned long) width) << 16) | 1;
1892
1893    /* CALCULATE STARTING OFFSETS */
1894
1895    offset = (unsigned long) srcy *pitch + ((unsigned long) srcx << gu2_xshift);
1896
1897    dstoffset |= gu2_pattern_origin;
1898
1899    bytes = width << gu2_xshift;
1900    dword_bytes = bytes & ~0x3L;
1901    bytes_extra = bytes & 0x3L;
1902
1903    /* POLL UNTIL ABLE TO WRITE TO THE REGISTERS */
1904    /* Put off poll for as long as possible (do most calculations first).   */
1905    /* The source offset is always 0 since we allow misaligned dword reads. */
1906    /* We must wait for BLT busy because the GP may be executing a screen   */
1907    /* to screen BLT from the scratchpad area.                              */
1908
1909    GU2_WAIT_BUSY;
1910
1911    if (gu2_alpha_active) {
1912        blt_mode = gu2_alpha_blt_mode;
1913
1914        WRITE_GP32(MGP_RASTER_MODE, gu2_alpha32);
1915    }
1916    else {
1917        blt_mode = (gu2_blt_mode & ~MGP_BM_SRC_TYPE_MASK);
1918
1919        WRITE_GP32(MGP_RASTER_MODE, gu2_rop32 | GFXsourceFlags);
1920    }
1921    blt_mode |= MGP_BM_SRC_FB | gu2_bm_throttle;
1922    gu2_bm_throttle = 0;
1923    gu2_vm_throttle = 0;
1924
1925    WRITE_GP32(MGP_WID_HEIGHT, size);
1926
1927    /* WRITE DATA ONE LINE AT A TIME */
1928    /* For speed reasons, data is written to an offscreen scratch area and
1929     * then BLTed using a screen to screen BLT. This is similar to the GX1 BLT
1930     * buffers, but slightly more efficient in that we can queue up data while
1931     * the GP is rendering a line.
1932     * */
1933
1934    while (height--) {
1935        temp_offset = offset;
1936        srcoffset = gfx_gx2_scratch_base;
1937        if (gu2_current_line)
1938            srcoffset += 8192;
1939
1940        GU2_WAIT_PENDING;
1941        WRITE_GP32(MGP_SRC_OFFSET, srcoffset);
1942        WRITE_GP32(MGP_DST_OFFSET, dstoffset);
1943        dstoffset += gu2_dst_pitch;
1944        dstoffset += 0x20000000;
1945
1946        WRITE_FRAME_BUFFER_STRING32(srcoffset, dword_bytes, data, temp_offset);
1947        if (bytes_extra) {
1948            temp_offset += dword_bytes;
1949            srcoffset += dword_bytes;
1950            WRITE_FRAME_BUFFER_STRING8(srcoffset, bytes_extra, data,
1951                                       temp_offset);
1952        }
1953        WRITE_GP16(MGP_BLT_MODE, blt_mode);
1954        offset += pitch;
1955        gu2_current_line = 1 - gu2_current_line;
1956    }
1957}
1958
1959/*---------------------------------------------------------------------------
1960 * GFX2_TEXT_BLT
1961 *
1962 * This routine is similar to the gfx2_mono_bitmap_to_screen_blt routine
1963 * but assumes that source data is byte-packed.
1964 *---------------------------------------------------------------------------
1965 */
1966#if GFX_2DACCEL_DYNAMIC
1967void
1968gu22_text_blt(unsigned long dstoffset, unsigned short width,
1969              unsigned short height, unsigned char *data)
1970#else
1971void
1972gfx2_text_blt(unsigned long dstoffset, unsigned short width,
1973              unsigned short height, unsigned char *data)
1974#endif
1975{
1976    unsigned long size, bytes;
1977    unsigned long temp1 = 0, temp2 = 0, temp_offset = 0;
1978    unsigned long i, j = 0, fifo_lines, dwords_extra, bytes_extra;
1979    unsigned long shift;
1980    unsigned short blt_mode;
1981
1982    size = (((unsigned long) width) << 16) | height;
1983
1984    /* CALCULATE STARTING OFFSETS */
1985
1986    bytes = ((width + 7) >> 3) * height;
1987    fifo_lines = bytes >> 5;
1988    dwords_extra = (bytes & 0x0000001Cl) >> 2;
1989    bytes_extra = bytes & 0x00000003l;
1990
1991    /* POLL UNTIL ABLE TO WRITE TO THE REGISTERS */
1992
1993    GU2_WAIT_PENDING;
1994
1995    if (gu2_alpha_active) {
1996        blt_mode = gu2_alpha_blt_mode;
1997
1998        WRITE_GP32(MGP_RASTER_MODE, gu2_alpha32);
1999    }
2000    else {
2001        blt_mode = (gu2_blt_mode & ~MGP_BM_SRC_TYPE_MASK);
2002
2003        WRITE_GP32(MGP_RASTER_MODE, gu2_rop32 | GFXsourceFlags);
2004    }
2005
2006    WRITE_GP32(MGP_SRC_OFFSET, 0);
2007    WRITE_GP32(MGP_DST_OFFSET, dstoffset | gu2_pattern_origin);
2008    WRITE_GP32(MGP_WID_HEIGHT, size);
2009    WRITE_GP32(MGP_STRIDE, gu2_dst_pitch);
2010    WRITE_GP16(MGP_BLT_MODE, blt_mode | MGP_BM_SRC_HOST |
2011               MGP_BM_SRC_BP_MONO | gu2_bm_throttle);
2012    gu2_bm_throttle = 0;
2013    gu2_vm_throttle = 0;
2014
2015    /* WAIT FOR BLT TO BE LATCHED */
2016
2017    GU2_WAIT_PENDING;
2018
2019    /* WRITE ALL FULL FIFO LINES */
2020
2021    for (i = 0; i < fifo_lines; i++) {
2022        GU2_WAIT_HALF_EMPTY;
2023        WRITE_GPREG_STRING32(MGP_HST_SOURCE, 8, j, data, temp_offset, temp1);
2024        temp_offset += 32;
2025    }
2026
2027    /* WRITE ALL FULL DWORDS */
2028
2029    if (dwords_extra || bytes_extra) {
2030        GU2_WAIT_HALF_EMPTY;
2031        if (dwords_extra) {
2032            WRITE_GPREG_STRING32(MGP_HST_SOURCE, dwords_extra, i, data,
2033                                 temp_offset, temp1);
2034            temp_offset += (dwords_extra << 2);
2035        }
2036        if (bytes_extra) {
2037            shift = 0;
2038            WRITE_GPREG_STRING8(MGP_HST_SOURCE, bytes_extra, shift, i, data,
2039                                temp_offset, temp1, temp2);
2040        }
2041    }
2042}
2043
2044/*---------------------------------------------------------------------------
2045 * GFX2_MONO_BITMAP_TO_SCREEN_BLT
2046 *
2047 * This routine is similar to the gfx_mono_bitmap_to_screen_blt routine
2048 * but allows the use of an arbitrary destination stride and alpha blending.
2049 *---------------------------------------------------------------------------
2050 */
2051#if GFX_2DACCEL_DYNAMIC
2052void
2053gu22_mono_bitmap_to_screen_blt(unsigned short srcx, unsigned short srcy,
2054                               unsigned long dstoffset, unsigned short width,
2055                               unsigned short height, unsigned char *data,
2056                               short pitch)
2057#else
2058void
2059gfx2_mono_bitmap_to_screen_blt(unsigned short srcx, unsigned short srcy,
2060                               unsigned long dstoffset, unsigned short width,
2061                               unsigned short height, unsigned char *data,
2062                               short pitch)
2063#endif
2064{
2065    unsigned long size, bytes;
2066    unsigned long offset, temp_offset, temp1 = 0, temp2 = 0;
2067    unsigned long i, j = 0, fifo_lines, dwords_extra, bytes_extra;
2068    unsigned long shift = 0;
2069    unsigned short blt_mode;
2070
2071    size = (((unsigned long) width) << 16) | height;
2072
2073    /* CALCULATE STARTING OFFSETS */
2074
2075    offset = (unsigned long) srcy *pitch + ((unsigned long) srcx >> 3);
2076
2077    bytes = ((srcx & 7) + width + 7) >> 3;
2078    fifo_lines = bytes >> 5;
2079    dwords_extra = (bytes & 0x0000001Cl) >> 2;
2080    bytes_extra = bytes & 0x00000003l;
2081
2082    /* POLL UNTIL ABLE TO WRITE TO THE REGISTERS */
2083
2084    GU2_WAIT_PENDING;
2085
2086    if (gu2_alpha_active) {
2087        blt_mode = gu2_alpha_blt_mode;
2088
2089        WRITE_GP32(MGP_RASTER_MODE, gu2_alpha32);
2090    }
2091    else {
2092        blt_mode = (gu2_blt_mode & ~MGP_BM_SRC_TYPE_MASK);
2093
2094        WRITE_GP32(MGP_RASTER_MODE, gu2_rop32 | GFXsourceFlags);
2095    }
2096
2097    WRITE_GP32(MGP_SRC_OFFSET, ((unsigned long) srcx & 7) << 26);
2098    WRITE_GP32(MGP_DST_OFFSET, dstoffset | gu2_pattern_origin);
2099    WRITE_GP32(MGP_WID_HEIGHT, size);
2100    WRITE_GP32(MGP_STRIDE, gu2_dst_pitch);
2101    WRITE_GP16(MGP_BLT_MODE, blt_mode | MGP_BM_SRC_HOST |
2102               MGP_BM_SRC_MONO | gu2_bm_throttle);
2103    gu2_bm_throttle = 0;
2104    gu2_vm_throttle = 0;
2105
2106    /* WAIT FOR BLT TO BE LATCHED */
2107
2108    GU2_WAIT_PENDING;
2109
2110    /* WRITE ALL OF THE DATA TO THE HOST SOURCE REGISTER */
2111
2112    while (height--) {
2113        temp_offset = offset;
2114
2115        /* WRITE ALL FULL FIFO LINES */
2116
2117        for (i = 0; i < fifo_lines; i++) {
2118            GU2_WAIT_HALF_EMPTY;
2119            WRITE_GPREG_STRING32(MGP_HST_SOURCE, 8, j, data, temp_offset,
2120                                 temp1);
2121            temp_offset += 32;
2122        }
2123
2124        /* WRITE ALL FULL DWORDS */
2125
2126        GU2_WAIT_HALF_EMPTY;
2127        if (dwords_extra)
2128            WRITE_GPREG_STRING32(MGP_HST_SOURCE, dwords_extra, i, data,
2129                                 temp_offset, temp1);
2130        temp_offset += (dwords_extra << 2);
2131
2132        /* WRITE REMAINING BYTES */
2133
2134        shift = 0;
2135        if (bytes_extra)
2136            WRITE_GPREG_STRING8(MGP_HST_SOURCE, bytes_extra, shift, i, data,
2137                                temp_offset, temp1, temp2);
2138
2139        offset += pitch;
2140    }
2141}
2142
2143/*---------------------------------------------------------------------------
2144 * GFX2_BRESENHAM_LINE
2145 *
2146 * This routine is similar to the gfx_bresenam_line routine but allows
2147 * the use of an arbitrary destination stride.
2148 *---------------------------------------------------------------------------
2149 */
2150#if GFX_2DACCEL_DYNAMIC
2151void
2152gu22_bresenham_line(unsigned long dstoffset,
2153                    unsigned short length, unsigned short initerr,
2154                    unsigned short axialerr, unsigned short diagerr,
2155                    unsigned short flags)
2156#else
2157void
2158gfx2_bresenham_line(unsigned long dstoffset,
2159                    unsigned short length, unsigned short initerr,
2160                    unsigned short axialerr, unsigned short diagerr,
2161                    unsigned short flags)
2162#endif
2163{
2164    unsigned long vector_mode = gu2_vector_mode | flags;
2165    unsigned long data1 = (((unsigned long) axialerr) << 16) | diagerr;
2166    unsigned long data2 = (((unsigned long) length) << 16) | initerr;
2167
2168    /* CHECK NULL LENGTH */
2169
2170    if (!length)
2171        return;
2172
2173    /* POLL UNTIL ABLE TO WRITE TO THE REGISTERS */
2174    /* Put off poll for as long as possible (do most calculations first). */
2175
2176    GU2_WAIT_PENDING;
2177
2178    if (gu2_alpha_active) {
2179        vector_mode = gu2_alpha_vec_mode | flags;
2180
2181        WRITE_GP32(MGP_RASTER_MODE, gu2_alpha32);
2182    }
2183    else
2184        WRITE_GP32(MGP_RASTER_MODE, gu2_rop32);
2185
2186    WRITE_GP32(MGP_DST_OFFSET, dstoffset | gu2_pattern_origin);
2187    WRITE_GP32(MGP_VEC_ERR, data1);
2188    WRITE_GP32(MGP_VEC_LEN, data2);
2189    WRITE_GP32(MGP_STRIDE, gu2_dst_pitch);
2190    WRITE_GP32(MGP_VECTOR_MODE, vector_mode | gu2_vm_throttle);
2191    gu2_bm_throttle = 0;
2192    gu2_vm_throttle = 0;
2193}
2194
2195/*---------------------------------------------------------------------------
2196 * GFX2_SYNC_TO_VBLANK
2197 *
2198 * This routine sets a flag to synchronize the next rendering routine to
2199 * VBLANK.  The flag is cleared by the rendering routine.
2200 *---------------------------------------------------------------------------
2201 */
2202#if GFX_2DACCEL_DYNAMIC
2203void
2204gu22_sync_to_vblank(void)
2205#else
2206void
2207gfx2_sync_to_vblank(void)
2208#endif
2209{
2210    /* SET FLAGS TO THROTTLE NEXT RENDERING ROUTINE */
2211
2212    gu2_bm_throttle = MGP_BM_THROTTLE;
2213    gu2_vm_throttle = MGP_VM_THROTTLE;
2214}
2215
2216/* END OF FILE */
2217