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
26void gu1_enable_compression(void);      /* private routine definition */
27void gu1_disable_compression(void);     /* private routine definition */
28void gfx_reset_video(void);     /* private routine definition */
29int gfx_set_display_control(int sync_polarities);       /* private routine
30                                                         * definition */
31int gu1_set_specified_mode(DISPLAYMODE * pMode, int bpp);
32
33/* VIDEO BUFFER SIZE */
34
35unsigned long vid_buf_size = 0;
36int vid_enabled = 0;
37
38/*----------------------------------------------------------------------------
39 * GU1_DELAY_APPROXIMATE (PRIVATE ROUTINE - NOT PART OF DURANGO API)
40 *
41 * Delay the requested number of milliseconds by reading a register.  This
42 * function generally takes longer than the requested time.
43 *----------------------------------------------------------------------------
44 */
45
46#define READS_PER_MILLISECOND 60000L
47
48void
49gu1_delay_approximate(unsigned long milliseconds)
50{
51    /* ASSUME 300 MHz, 5 CLOCKS PER READ */
52
53    unsigned long loop;
54
55    loop = milliseconds * READS_PER_MILLISECOND;
56    while (loop-- > 0) {
57        READ_REG32(DC_UNLOCK);
58    }
59}
60
61/*----------------------------------------------------------------------------
62 * GU1_DELAY_PRECISE (PRIVATE ROUTINE - NOT PART OF DURANGO API)
63 *
64 * Delay the number of milliseconds on a more precise level, varying only by
65 * 1/10 of a ms.  This function should only be called if an SC1200 is present.
66 *----------------------------------------------------------------------------
67 */
68void
69gu1_delay_precise(unsigned long milliseconds)
70{
71#if GFX_VIDEO_SC1200
72
73#define LOOP 1000
74    unsigned long i, timer_start, timer_end, total_ticks, previous_ticks,
75        temp_ticks;
76
77    /* Get current time */
78    timer_start = IND(SC1200_CB_BASE_ADDR + SC1200_CB_TMVALUE);
79
80    /* Calculate expected end time */
81    if (INB(SC1200_CB_BASE_ADDR + SC1200_CB_TMCNFG) & SC1200_TMCLKSEL_27MHZ)
82        total_ticks = 27000 * milliseconds;     /* timer resolution is 27 MHz */
83    else
84        total_ticks = 1000 * milliseconds;      /* timer resolution is 1 MHz */
85
86    if (total_ticks > ((unsigned long) 0xffffffff - timer_start))
87        /* wrap-around */
88        timer_end = total_ticks - ((unsigned long) 0xffffffff - timer_start);
89    else
90        timer_end = timer_start + total_ticks;
91
92    /* in case of wrap around */
93    if (timer_end < timer_start) {
94        previous_ticks = timer_start;
95        while (1) {
96            temp_ticks = IND(SC1200_CB_BASE_ADDR + SC1200_CB_TMVALUE);
97            if (temp_ticks < previous_ticks)
98                break;
99            else
100                previous_ticks = temp_ticks;
101            for (i = 0; i < LOOP; i++)
102                READ_REG32(DC_UNLOCK);
103        }
104    }
105
106    /* now the non-wrap around part */
107    while (1) {
108        for (i = 0; i < LOOP; i++)
109            READ_REG32(DC_UNLOCK);
110        if (IND(SC1200_CB_BASE_ADDR + SC1200_CB_TMVALUE) > timer_end)
111            break;
112    }
113#endif                          /* GFX_VIDEO_SC1200 */
114}
115
116/*----------------------------------------------------------------------------
117 * WARNING!!!! INACCURATE DELAY MECHANISM
118 *
119 * In an effort to keep the code self contained and operating system
120 * independent, the delay loop just performs reads of a display controller
121 * register.  This time will vary for faster processors.  The delay can always
122 * be longer than intended, only effecting the time of the mode switch
123 * (obviously want it to still be under a second).  Problems with the hardware
124 * only arise if the delay is not long enough.
125 *
126 * For the SC1200, the high resolution timer can be used as an accurate
127 * mechanism for keeping time. However, in order to avoid a busy loop of IO
128 * reads, the timer is polled in-between busy loops, and therefore the actual
129 * delay might be longer than the requested delay by the time of one busy loop
130 * (which on a 200 MHz system took 95 us)
131 *
132 * There are thus two delay functions which are called from the main API
133 * routine.
134 * One is meant to be more precise and should only called if an SC1200 is
135 * present.
136 *----------------------------------------------------------------------------
137 */
138#if GFX_DISPLAY_DYNAMIC
139void
140gu1_delay_milliseconds(unsigned long milliseconds)
141#else
142void
143gfx_delay_milliseconds(unsigned long milliseconds)
144#endif
145{
146#if GFX_VIDEO_SC1200
147#if GFX_VIDEO_DYNAMIC
148    if (gfx_video_type == GFX_VIDEO_TYPE_SC1200) {
149#endif
150        gu1_delay_precise(milliseconds);
151        return;
152#if GFX_VIDEO_DYNAMIC
153    }
154#endif
155#endif                          /* GFX_VIDEO_SC1200 */
156    gu1_delay_approximate(milliseconds);
157}
158
159#if GFX_DISPLAY_DYNAMIC
160void
161gu1_delay_microseconds(unsigned long microseconds)
162#else
163void
164gfx_delay_microseconds(unsigned long microseconds)
165#endif
166{
167    /* ASSUME 300 MHz, 2 CLOCKS PER INCREMENT */
168    unsigned long loop_count = microseconds * 150;
169
170    while (loop_count-- > 0) {
171        ;
172    }
173}
174
175/*----------------------------------------------------------------------------
176 * GFX_VIDEO_SHUTDOWN
177 *
178 * This routine disables the display controller output.
179 *----------------------------------------------------------------------------
180 */
181void
182gu1_video_shutdown(void)
183{
184    unsigned long unlock;
185    unsigned long gcfg, tcfg;
186
187    /* DISABLE COMPRESSION */
188    gu1_disable_compression();
189
190    /* ALSO DISABLE VIDEO */
191    /* Use private "reset video" routine to do all that is needed. */
192    /* SC1200, for example, also disables the alpha blending regions. */
193    gfx_reset_video();
194
195    /* UNLOCK THE DISPLAY CONTROLLER REGISTERS */
196    unlock = READ_REG32(DC_UNLOCK);
197    WRITE_REG32(DC_UNLOCK, DC_UNLOCK_VALUE);
198
199    /* READ THE CURRENT GX VALUES */
200    gcfg = READ_REG32(DC_GENERAL_CFG);
201    tcfg = READ_REG32(DC_TIMING_CFG);
202
203    /* BLANK THE GX DISPLAY AND DISABLE THE TIMING GENERATOR */
204    tcfg &= ~((unsigned long) DC_TCFG_BLKE | (unsigned long) DC_TCFG_TGEN);
205    WRITE_REG32(DC_TIMING_CFG, tcfg);
206
207    /* DELAY: WAIT FOR PENDING MEMORY REQUESTS */
208    /* This delay is used to make sure that all pending requests to the */
209    /* memory controller have completed before disabling the FIFO load. */
210    gfx_delay_milliseconds(1);
211
212    /* DISABLE DISPLAY FIFO LOAD AND DISABLE COMPRESSION */
213    gcfg &= ~(unsigned long) (DC_GCFG_DFLE | DC_GCFG_CMPE | DC_GCFG_DECE);
214    WRITE_REG32(DC_GENERAL_CFG, gcfg);
215    WRITE_REG32(DC_UNLOCK, unlock);
216    return;
217}
218
219/*----------------------------------------------------------------------------
220 * GFX_SET_DISPLAY_BPP
221 *
222 * This routine programs the bpp in the display controller.
223 *----------------------------------------------------------------------------
224 */
225#if GFX_DISPLAY_DYNAMIC
226int
227gu1_set_display_bpp(unsigned short bpp)
228#else
229int
230gfx_set_display_bpp(unsigned short bpp)
231#endif
232{
233    unsigned long ocfg, lock;
234
235    lock = READ_REG32(DC_UNLOCK);
236    ocfg = READ_REG32(DC_OUTPUT_CFG) & ~(DC_OCFG_8BPP | DC_OCFG_555);
237
238    /* SET DC PIXEL FORMAT */
239    if (bpp == 8)
240        ocfg |= DC_OCFG_8BPP;
241    else if (bpp == 15)
242        ocfg |= DC_OCFG_555;
243    else if (bpp != 16)
244        return GFX_STATUS_BAD_PARAMETER;
245
246    WRITE_REG32(DC_UNLOCK, DC_UNLOCK_VALUE);
247    WRITE_REG32(DC_OUTPUT_CFG, ocfg);
248    WRITE_REG32(DC_UNLOCK, lock);
249
250    /* SET BPP IN GRAPHICS PIPELINE */
251    gfx_set_bpp(bpp);
252
253    return 0;
254}
255
256/*----------------------------------------------------------------------------
257 * GFX_SET_SPECIFIED_MODE
258 * This routine uses the parameters in the specified display mode structure
259 * to program the display controller hardware.
260 *----------------------------------------------------------------------------
261 */
262int
263gu1_set_specified_mode(DISPLAYMODE * pMode, int bpp)
264{
265    unsigned long unlock, value;
266    unsigned long gcfg, tcfg, ocfg;
267    unsigned long size, pitch;
268    unsigned long hactive, vactive;
269
270    gbpp = bpp;
271
272    /* CHECK WHETHER TIMING CHANGE IS ALLOWED */
273    /* Flag used for locking also overrides timing change restriction */
274    if (gfx_timing_lock && !(pMode->flags & GFX_MODE_LOCK_TIMING))
275        return GFX_STATUS_ERROR;
276
277    /* SET GLOBAL FLAG */
278    if (pMode->flags & GFX_MODE_LOCK_TIMING)
279        gfx_timing_lock = 1;
280
281    /* DISABLE COMPRESSION */
282    gu1_disable_compression();
283
284    /* ALSO DISABLE VIDEO */
285    /* Use private "reset video" routine to do all that is needed. */
286    /* SC1200, for example, also disables the alpha blending regions. */
287    gfx_reset_video();
288
289    /* UNLOCK THE DISPLAY CONTROLLER REGISTERS */
290    unlock = READ_REG32(DC_UNLOCK);
291    WRITE_REG32(DC_UNLOCK, DC_UNLOCK_VALUE);
292
293    /* READ THE CURRENT GX VALUES */
294    gcfg = READ_REG32(DC_GENERAL_CFG);
295    tcfg = READ_REG32(DC_TIMING_CFG);
296
297    /* BLANK THE GX DISPLAY AND DISABLE THE TIMING GENERATOR */
298    tcfg &= ~((unsigned long) DC_TCFG_BLKE | (unsigned long) DC_TCFG_TGEN);
299    WRITE_REG32(DC_TIMING_CFG, tcfg);
300
301    /* DELAY: WAIT FOR PENDING MEMORY REQUESTS
302     * This delay is used to make sure that all pending requests to the
303     * memory controller have completed before disabling the FIFO load.
304     */
305    gfx_delay_milliseconds(1);
306
307    /* DISABLE DISPLAY FIFO LOAD AND DISABLE COMPRESSION */
308    gcfg &= ~(unsigned long) (DC_GCFG_DFLE | DC_GCFG_CMPE | DC_GCFG_DECE);
309    WRITE_REG32(DC_GENERAL_CFG, gcfg);
310
311    /* CLEAR THE "DCLK_MUL" FIELD */
312    gcfg &= ~(unsigned long) (DC_GCFG_DDCK | DC_GCFG_DPCK | DC_GCFG_DFCK);
313    gcfg &= ~(unsigned long) DC_GCFG_DCLK_MASK;
314    WRITE_REG32(DC_GENERAL_CFG, gcfg);
315
316    /* SET THE DOT CLOCK FREQUENCY */
317    /* Mask off the divide by two bit (bit 31) */
318    gfx_set_clock_frequency(pMode->frequency & 0x7FFFFFFF);
319
320    /* DELAY: WAIT FOR THE PLL TO SETTLE */
321    /* This allows the dot clock frequency that was just set to settle. */
322    gfx_delay_milliseconds(1);
323
324    /* SET THE "DCLK_MUL" FIELD OF DC_GENERAL_CFG */
325    /* The GX hardware divides the dot clock, so 2x really means that the */
326    /* internal dot clock equals the external dot clock. */
327    if (pMode->frequency & 0x80000000)
328        gcfg |= 0x0040;
329    else
330        gcfg |= 0x0080;
331
332    WRITE_REG32(DC_GENERAL_CFG, gcfg);
333
334    /* DELAY: WAIT FOR THE ADL TO LOCK */
335    /* This allows the clock generatation within GX to settle.  This is */
336    /* needed since some of the register writes that follow require that */
337    /* clock to be present. */
338    gfx_delay_milliseconds(1);
339
340    /* SET THE GX DISPLAY CONTROLLER PARAMETERS */
341    WRITE_REG32(DC_FB_ST_OFFSET, 0);
342    WRITE_REG32(DC_CB_ST_OFFSET, 0);
343    WRITE_REG32(DC_CURS_ST_OFFSET, 0);
344
345    /* SET LINE SIZE AND PITCH */
346    /* Flat panels use the current flat panel line size to    */
347    /* calculate the pitch, but load the true line size       */
348    /* for the mode into the "Frame Buffer Line Size" field   */
349    /* of DC_BUF_SIZE.                                        */
350    if (PanelEnable)
351        size = ModeWidth;
352    else
353        size = pMode->hactive;
354
355    if (bpp > 8)
356        size <<= 1;
357
358    /* ONLY PYRAMID SUPPORTS 4K LINE SIZE */
359    if (size <= 1024) {
360        pitch = 1024;
361        /* SPECIAL CASE  */
362        /* Graphics acceleration in 16-bit pixel line double modes */
363        /* requires a pitch of 2048.                               */
364        if ((pMode->flags & GFX_MODE_LINE_DOUBLE) && bpp > 8)
365            pitch <<= 1;
366    }
367    else {
368        if (gfx_cpu_version == GFX_CPU_PYRAMID)
369            pitch = (size <= 2048) ? 2048 : 4096;
370        else
371            pitch = 2048;
372    }
373
374    WRITE_REG32(DC_LINE_DELTA, pitch >> 2);
375
376    if (PanelEnable) {
377        size = pMode->hactive;
378        if (bpp > 8)
379            size <<= 1;
380    }
381
382    /* ADD 2 TO SIZE FOR POSSIBLE START ADDRESS ALIGNMENTS */
383    WRITE_REG32(DC_BUF_SIZE, (size >> 3) + 2);
384
385    /* ALWAYS ENABLE "PANEL" DATA FROM MEDIAGX */
386    /* That is really just the 18 BPP data bus to the companion chip */
387    ocfg = DC_OCFG_PCKE | DC_OCFG_PDEL | DC_OCFG_PDEH;
388
389    /* SET PIXEL FORMAT */
390    if (bpp == 8)
391        ocfg |= DC_OCFG_8BPP;
392    else if (bpp == 15)
393        ocfg |= DC_OCFG_555;
394
395    /* ENABLE TIMING GENERATOR, SYNCS, AND FP DATA */
396    tcfg = DC_TCFG_FPPE | DC_TCFG_HSYE | DC_TCFG_VSYE | DC_TCFG_BLKE |
397        DC_TCFG_TGEN;
398
399    /* SET FIFO PRIORITY, DCLK MULTIPLIER, AND FIFO ENABLE */
400    /* Default 6/5 for FIFO, 2x for DCLK multiplier. */
401    gcfg = (6 << DC_GCFG_DFHPEL_POS) | (5 << DC_GCFG_DFHPSL_POS) | DC_GCFG_DFLE;
402
403    /* INCREASE FIFO PRIORITY FOR LARGE MODES */
404    if (pMode->hactive == 1280 && pMode->vactive == 1024) {
405        if ((bpp == 8) && (pMode->flags & GFX_MODE_85HZ))
406            gcfg =
407                (8l << DC_GCFG_DFHPEL_POS) | (7l << DC_GCFG_DFHPSL_POS) |
408                DC_GCFG_DFLE;
409
410        if ((bpp > 8) && (pMode->flags & GFX_MODE_75HZ))
411            gcfg =
412                (7l << DC_GCFG_DFHPEL_POS) | (6l << DC_GCFG_DFHPSL_POS) |
413                DC_GCFG_DFLE;
414
415        if ((bpp > 8) && (pMode->flags & GFX_MODE_85HZ))
416            gcfg =
417                (9l << DC_GCFG_DFHPEL_POS) | (8l << DC_GCFG_DFHPSL_POS) |
418                DC_GCFG_DFLE;
419    }
420
421    /* SET DOT CLOCK MULTIPLIER */
422    /* Bit 31 of frequency indicates divide frequency by two */
423    if (pMode->frequency & 0x80000000)
424        gcfg |= (1l << DC_GCFG_DCLK_POS);
425    else
426        gcfg |= (2l << DC_GCFG_DCLK_POS);
427
428    /* DIVIDE VIDEO CLOCK */
429    /* CPU core frequencies above 266 MHz will divide the video */
430    /* clock by 4 to ensure that we are running below 150 MHz.  */
431    if (gfx_cpu_frequency > 266)
432        gcfg |= DC_GCFG_VCLK_DIV;
433
434    /* ALWAYS ENABLE VIDEO IN THE DISPLAY CONTROLLER */
435    /* Enabling video at an inopportune momemt can corrupt the DC fetch */
436    /* engine and cause screen artifacts or system hang.                */
437    gcfg |= (DC_GCFG_VIDE | DC_GCFG_VRDY);
438
439    /* SET THE PIXEL AND LINE DOUBLE BITS IF NECESSARY */
440    hactive = pMode->hactive;
441    vactive = pMode->vactive;
442    gfx_line_double = 0;
443    gfx_pixel_double = 0;
444
445    if (pMode->flags & GFX_MODE_LINE_DOUBLE) {
446        gcfg |= DC_GCFG_LDBL;
447        hactive <<= 1;
448
449        /* SET GLOBAL FLAG */
450        gfx_line_double = 1;
451    }
452
453    if (pMode->flags & GFX_MODE_PIXEL_DOUBLE) {
454        tcfg |= DC_TCFG_PXDB;
455        vactive <<= 1;
456
457        /* SET GLOBAL FLAG */
458        gfx_pixel_double = 1;
459    }
460
461    /* COMBINE AND SET TIMING VALUES */
462
463    value = (unsigned long) (hactive - 1) |
464        (((unsigned long) (pMode->htotal - 1)) << 16);
465    WRITE_REG32(DC_H_TIMING_1, value);
466    value = (unsigned long) (pMode->hblankstart - 1) |
467        (((unsigned long) (pMode->hblankend - 1)) << 16);
468    WRITE_REG32(DC_H_TIMING_2, value);
469    value = (unsigned long) (pMode->hsyncstart - 1) |
470        (((unsigned long) (pMode->hsyncend - 1)) << 16);
471    WRITE_REG32(DC_H_TIMING_3, value);
472    WRITE_REG32(DC_FP_H_TIMING, value);
473    value = (unsigned long) (vactive - 1) |
474        (((unsigned long) (pMode->vtotal - 1)) << 16);
475    WRITE_REG32(DC_V_TIMING_1, value);
476    value = (unsigned long) (pMode->vblankstart - 1) |
477        (((unsigned long) (pMode->vblankend - 1)) << 16);
478    WRITE_REG32(DC_V_TIMING_2, value);
479    value = (unsigned long) (pMode->vsyncstart - 1) |
480        (((unsigned long) (pMode->vsyncend - 1)) << 16);
481    WRITE_REG32(DC_V_TIMING_3, value);
482    value = (unsigned long) (pMode->vsyncstart - 2) |
483        (((unsigned long) (pMode->vsyncend - 2)) << 16);
484    WRITE_REG32(DC_FP_V_TIMING, value);
485
486    WRITE_REG32(DC_OUTPUT_CFG, ocfg);
487    WRITE_REG32(DC_TIMING_CFG, tcfg);
488    gfx_delay_milliseconds(1);  /* delay after TIMING_CFG */
489    WRITE_REG32(DC_GENERAL_CFG, gcfg);
490
491    /* ENABLE FLAT PANEL CENTERING */
492    /* For 640x480 modes displayed with the 9211 within a 800x600 */
493    /* flat panel display, turn on flat panel centering.          */
494    if (PanelEnable) {
495        if (ModeWidth < PanelWidth) {
496            tcfg = READ_REG32(DC_TIMING_CFG);
497            tcfg = tcfg | DC_TCFG_FCEN;
498            WRITE_REG32(DC_TIMING_CFG, tcfg);
499            gfx_delay_milliseconds(1);  /* delay after TIMING_CFG */
500        }
501    }
502
503    /* CONFIGURE DISPLAY OUTPUT FROM VIDEO PROCESSOR */
504    gfx_set_display_control(((pMode->flags & GFX_MODE_NEG_HSYNC) ? 1 : 0) |
505                            ((pMode->flags & GFX_MODE_NEG_VSYNC) ? 2 : 0));
506
507    /* RESTORE VALUE OF DC_UNLOCK */
508    WRITE_REG32(DC_UNLOCK, unlock);
509
510    /* ALSO WRITE GP_BLIT_STATUS FOR PITCH AND 8/18 BPP */
511    /* Remember, only Pyramid supports 4K line pitch    */
512    value = 0;
513    if (bpp > 8)
514        value |= BC_16BPP;
515    if ((gfx_cpu_version == GFX_CPU_PYRAMID) && (pitch > 2048))
516        value |= BC_FB_WIDTH_4096;
517    else if (pitch > 1024)
518        value |= BC_FB_WIDTH_2048;
519
520    WRITE_REG16(GP_BLIT_STATUS, (unsigned short) value);
521
522    return GFX_STATUS_OK;
523}                               /* end gfx_set_specified_mode() */
524
525/*----------------------------------------------------------------------------
526 * GFX_IS_DISPLAY_MODE_SUPPORTED
527 *
528 * This routine sets the specified display mode.
529 *
530 * Returns the index of the mode if successful and mode returned, -1 if the
531 * mode could not be found.
532 *----------------------------------------------------------------------------
533 */
534#if GFX_DISPLAY_DYNAMIC
535int
536gu1_is_display_mode_supported(int xres, int yres, int bpp, int hz)
537#else
538int
539gfx_is_display_mode_supported(int xres, int yres, int bpp, int hz)
540#endif
541{
542    unsigned int mode = 0;
543    unsigned long hz_flag = 0, bpp_flag = 0;
544
545    /* SET FLAGS TO MATCH REFRESH RATE */
546    if (hz == 56)
547        hz_flag = GFX_MODE_56HZ;
548    else if (hz == 60)
549        hz_flag = GFX_MODE_60HZ;
550    else if (hz == 70)
551        hz_flag = GFX_MODE_70HZ;
552    else if (hz == 72)
553        hz_flag = GFX_MODE_72HZ;
554    else if (hz == 75)
555        hz_flag = GFX_MODE_75HZ;
556    else if (hz == 85)
557        hz_flag = GFX_MODE_85HZ;
558    else
559        return -1;
560
561    /* SET BPP FLAGS TO LIMIT MODE SELECTION */
562    if (bpp == 8)
563        bpp_flag = GFX_MODE_8BPP;
564    else if (bpp == 15)
565        bpp_flag = GFX_MODE_15BPP;
566    else if (bpp == 16)
567        bpp_flag = GFX_MODE_16BPP;
568    else
569        return -1;
570
571    /* ONLY PYRAMID SUPPORTS 4K PITCH */
572    if (gfx_cpu_version != GFX_CPU_PYRAMID && xres > 1024) {
573        if (bpp > 8)
574            return (-1);        /* return with mode not found */
575    }
576
577    /* LOOP THROUGH THE AVAILABLE MODES TO FIND A MATCH */
578    for (mode = 0; mode < NUM_GX_DISPLAY_MODES; mode++) {
579        if ((DisplayParams[mode].hactive == (unsigned short) xres) &&
580            (DisplayParams[mode].vactive == (unsigned short) yres) &&
581            (DisplayParams[mode].flags & hz_flag) &&
582            (DisplayParams[mode].flags & bpp_flag)) {
583
584            /* SET THE DISPLAY CONTROLLER FOR THE SELECTED MODE */
585            return (mode);
586        }
587    }
588    return (-1);
589}
590
591/*----------------------------------------------------------------------------
592 * GFX_SET_DISPLAY_MODE
593 *
594 * This routine sets the specified display mode.
595 *
596 * Returns 1 if successful, 0 if mode could not be set.
597 *----------------------------------------------------------------------------
598 */
599#if GFX_DISPLAY_DYNAMIC
600int
601gu1_set_display_mode(int xres, int yres, int bpp, int hz)
602#else
603int
604gfx_set_display_mode(int xres, int yres, int bpp, int hz)
605#endif
606{
607    int mode;
608
609    /* DISABLE FLAT PANEL */
610    /* Flat Panel settings are enabled by the function gfx_set_fixed_timings
611     * and disabled by gfx_set_display_mode. */
612    PanelEnable = 0;
613
614    mode = gfx_is_display_mode_supported(xres, yres, bpp, hz);
615    if (mode >= 0) {
616        if (gu1_set_specified_mode(&DisplayParams[mode], bpp) == GFX_STATUS_OK)
617            return (1);
618    }
619    return (0);
620}
621
622/*----------------------------------------------------------------------------
623 * GFX_SET_DISPLAY_TIMINGS
624 *
625 * This routine sets the display controller mode using the specified timing
626 * values (as opposed to using the tables internal to Durango).
627 *
628 * Returns GFX_STATUS_OK on success, GFX_STATUS_ERROR otherwise.
629 *----------------------------------------------------------------------------
630 */
631#if GFX_DISPLAY_DYNAMIC
632int
633gu1_set_display_timings(unsigned short bpp, unsigned short flags,
634                        unsigned short hactive, unsigned short hblankstart,
635                        unsigned short hsyncstart, unsigned short hsyncend,
636                        unsigned short hblankend, unsigned short htotal,
637                        unsigned short vactive, unsigned short vblankstart,
638                        unsigned short vsyncstart, unsigned short vsyncend,
639                        unsigned short vblankend, unsigned short vtotal,
640                        unsigned long frequency)
641#else
642int
643gfx_set_display_timings(unsigned short bpp, unsigned short flags,
644                        unsigned short hactive, unsigned short hblankstart,
645                        unsigned short hsyncstart, unsigned short hsyncend,
646                        unsigned short hblankend, unsigned short htotal,
647                        unsigned short vactive, unsigned short vblankstart,
648                        unsigned short vsyncstart, unsigned short vsyncend,
649                        unsigned short vblankend, unsigned short vtotal,
650                        unsigned long frequency)
651#endif
652{
653    /* SET MODE STRUCTURE WITH SPECIFIED VALUES */
654
655    gfx_display_mode.flags = 0;
656    if (flags & 1)
657        gfx_display_mode.flags |= GFX_MODE_NEG_HSYNC;
658    if (flags & 2)
659        gfx_display_mode.flags |= GFX_MODE_NEG_VSYNC;
660    if (flags & 0x1000)
661        gfx_display_mode.flags |= GFX_MODE_LOCK_TIMING;
662    gfx_display_mode.hactive = hactive;
663    gfx_display_mode.hblankstart = hblankstart;
664    gfx_display_mode.hsyncstart = hsyncstart;
665    gfx_display_mode.hsyncend = hsyncend;
666    gfx_display_mode.hblankend = hblankend;
667    gfx_display_mode.htotal = htotal;
668    gfx_display_mode.vactive = vactive;
669    gfx_display_mode.vblankstart = vblankstart;
670    gfx_display_mode.vsyncstart = vsyncstart;
671    gfx_display_mode.vsyncend = vsyncend;
672    gfx_display_mode.vblankend = vblankend;
673    gfx_display_mode.vtotal = vtotal;
674    gfx_display_mode.frequency = frequency;
675
676    /* CALL ROUTINE TO SET MODE */
677    return (gu1_set_specified_mode(&gfx_display_mode, bpp));
678}
679
680/*----------------------------------------------------------------------------
681 * GFX_SET_VTOTAL
682 *
683 * This routine sets the display controller vertical total to
684 * "vtotal". As a side effect it also sets vertical blank end.
685 * It should be used when only this value needs to be changed,
686 * due to speed considerations.
687 *
688 * Note: it is the caller's responsibility to make sure that
689 * a legal vtotal is used, i.e. that "vtotal" is greater than or
690 * equal to vsync end.
691 *
692 * Always returns 0.
693 *----------------------------------------------------------------------------
694 */
695#if GFX_DISPLAY_DYNAMIC
696int
697gu1_set_vtotal(unsigned short vtotal)
698#else
699int
700gfx_set_vtotal(unsigned short vtotal)
701#endif
702{
703    unsigned long unlock, tcfg, timing1, timing2;
704
705    /* UNLOCK THE DISPLAY CONTROLLER REGISTERS */
706    unlock = READ_REG32(DC_UNLOCK);
707    WRITE_REG32(DC_UNLOCK, DC_UNLOCK_VALUE);
708
709    /* READ THE CURRENT GX VALUES */
710    tcfg = READ_REG32(DC_TIMING_CFG);
711    timing1 = READ_REG32(DC_V_TIMING_1);
712    timing2 = READ_REG32(DC_V_TIMING_2);
713
714    /* DISABLE THE TIMING GENERATOR */
715    WRITE_REG32(DC_TIMING_CFG, tcfg & ~(unsigned long) DC_TCFG_TGEN);
716
717    /* WRITE NEW TIMING VALUES */
718    WRITE_REG32(DC_V_TIMING_1,
719                (timing1 & 0xffff) | (unsigned long) (vtotal - 1) << 16);
720    WRITE_REG32(DC_V_TIMING_2,
721                (timing2 & 0xffff) | (unsigned long) (vtotal - 1) << 16);
722
723    /* RESTORE GX VALUES */
724    WRITE_REG32(DC_TIMING_CFG, tcfg);
725    WRITE_REG32(DC_UNLOCK, unlock);
726
727    return (0);
728}
729
730/*---------------------------------------------------------------------------
731 * gfx_set_display_pitch
732 *
733 * This routine sets the pitch of the frame buffer to the specified value.
734 *---------------------------------------------------------------------------
735 */
736#if GFX_DISPLAY_DYNAMIC
737void
738gu1_set_display_pitch(unsigned short pitch)
739#else
740void
741gfx_set_display_pitch(unsigned short pitch)
742#endif
743{
744    unsigned long value = 0;
745    unsigned long lock = READ_REG32(DC_UNLOCK);
746
747    value = READ_REG32(DC_LINE_DELTA) & 0xFFFFF000;
748    value |= (pitch >> 2);
749    WRITE_REG32(DC_UNLOCK, DC_UNLOCK_VALUE);
750    WRITE_REG32(DC_LINE_DELTA, value);
751    WRITE_REG32(DC_UNLOCK, lock);
752
753    /* ALSO UPDATE PITCH IN GRAPHICS ENGINE */
754    /* Pyramid alone supports 4K line pitch */
755    value = (unsigned long) READ_REG16(GP_BLIT_STATUS);
756    value &= ~(BC_FB_WIDTH_2048 | BC_FB_WIDTH_4096);
757
758    if ((gfx_cpu_version == GFX_CPU_PYRAMID) && (pitch > 2048))
759        value |= BC_FB_WIDTH_4096;
760
761    else if (pitch > 1024)
762        value |= BC_FB_WIDTH_2048;
763
764    WRITE_REG16(GP_BLIT_STATUS, (unsigned short) value);
765    return;
766}
767
768/*---------------------------------------------------------------------------
769 * gfx_set_display_offset
770 *
771 * This routine sets the start address of the frame buffer.  It is
772 * typically used to pan across a virtual desktop (frame buffer larger than
773 * the displayed screen) or to flip the display between multiple buffers.
774 *---------------------------------------------------------------------------
775 */
776#if GFX_DISPLAY_DYNAMIC
777void
778gu1_set_display_offset(unsigned long offset)
779#else
780void
781gfx_set_display_offset(unsigned long offset)
782#endif
783{
784    /* UPDATE FRAME BUFFER OFFSET */
785
786    unsigned long lock;
787
788    lock = READ_REG32(DC_UNLOCK);
789    WRITE_REG32(DC_UNLOCK, DC_UNLOCK_VALUE);
790
791    /* START ADDRESS EFFECTS DISPLAY COMPRESSION */
792    /* Disable compression for non-zero start address values.              */
793    /* Enable compression if offset is zero and compression is intended to */
794    /* be enabled from a previous call to "gfx_set_compression_enable".    */
795    /* Compression should be disabled BEFORE the offset is changed         */
796    /* and enabled AFTER the offset is changed.                            */
797    if (offset == 0) {
798        WRITE_REG32(DC_FB_ST_OFFSET, offset);
799        if (gfx_compression_enabled) {
800            /* WAIT FOR THE OFFSET TO BE LATCHED */
801            gfx_wait_vertical_blank();
802            gu1_enable_compression();
803        }
804    }
805    else {
806        /* ONLY DISABLE COMPRESSION ONCE */
807        if (gfx_compression_active)
808            gu1_disable_compression();
809
810        WRITE_REG32(DC_FB_ST_OFFSET, offset);
811    }
812
813    WRITE_REG32(DC_UNLOCK, lock);
814}
815
816/*---------------------------------------------------------------------------
817 * gfx_set_display_palette_entry
818 *
819 * This routine sets an palette entry in the display controller.
820 * A 32-bit X:R:G:B value.
821 *---------------------------------------------------------------------------
822 */
823#if GFX_DISPLAY_DYNAMIC
824int
825gu1_set_display_palette_entry(unsigned long index, unsigned long palette)
826#else
827int
828gfx_set_display_palette_entry(unsigned long index, unsigned long palette)
829#endif
830{
831    unsigned long data;
832
833    if (index > 0xFF)
834        return GFX_STATUS_BAD_PARAMETER;
835
836    WRITE_REG32(DC_PAL_ADDRESS, index);
837    data = ((palette >> 2) & 0x0003F) |
838        ((palette >> 4) & 0x00FC0) | ((palette >> 6) & 0x3F000);
839    WRITE_REG32(DC_PAL_DATA, data);
840
841    return (0);
842}
843
844/*---------------------------------------------------------------------------
845 * gfx_set_display_palette
846 *
847 * This routine sets the entire palette in the display controller.
848 * A pointer is provided to a 256 entry table of 32-bit X:R:G:B values.
849 *
850 * Restriction:
851 * Due to SC1200 Issue #748 (in Notes DB) this function should be called only
852 * when DCLK is active, i.e PLL is already powered up and genlock is not
853 * active.
854 *---------------------------------------------------------------------------
855 */
856#if GFX_DISPLAY_DYNAMIC
857int
858gu1_set_display_palette(unsigned long *palette)
859#else
860int
861gfx_set_display_palette(unsigned long *palette)
862#endif
863{
864    unsigned long data, i;
865
866    WRITE_REG32(DC_PAL_ADDRESS, 0);
867    if (palette) {
868        for (i = 0; i < 256; i++) {
869            /* CONVERT 24 BPP COLOR DATA TO 18 BPP COLOR DATA */
870            data = ((palette[i] >> 2) & 0x0003F) |
871                ((palette[i] >> 4) & 0x00FC0) | ((palette[i] >> 6) & 0x3F000);
872            WRITE_REG32(DC_PAL_DATA, data);
873        }
874    }
875    return (0);
876}
877
878/*---------------------------------------------------------------------------
879 * gfx_set_cursor_enable
880 *
881 * This routine enables or disables the hardware cursor.
882 *
883 * WARNING: The cusrsor start offset must be set by setting the cursor
884 * position before calling this routine to assure that memory reads do not
885 * go past the end of graphics memory (this can hang GXm).
886 *---------------------------------------------------------------------------
887 */
888#if GFX_DISPLAY_DYNAMIC
889void
890gu1_set_cursor_enable(int enable)
891#else
892void
893gfx_set_cursor_enable(int enable)
894#endif
895{
896    unsigned long unlock, gcfg;
897
898    /* SET OR CLEAR CURSOR ENABLE BIT */
899    unlock = READ_REG32(DC_UNLOCK);
900    gcfg = READ_REG32(DC_GENERAL_CFG);
901    if (enable)
902        gcfg |= DC_GCFG_CURE;
903    else
904        gcfg &= ~(DC_GCFG_CURE);
905
906    /* WRITE NEW REGISTER VALUE */
907    WRITE_REG32(DC_UNLOCK, DC_UNLOCK_VALUE);
908    WRITE_REG32(DC_GENERAL_CFG, gcfg);
909    WRITE_REG32(DC_UNLOCK, unlock);
910}
911
912/*---------------------------------------------------------------------------
913 * gfx_set_cursor_colors
914 *
915 * This routine sets the colors of the hardware cursor.
916 *
917 * Restriction:
918 * Due to SC1200 Issue #748 (in Notes DB) this function should be called only
919 * when DCLK is active, i.e PLL is already powered up.
920 *---------------------------------------------------------------------------
921 */
922#if GFX_DISPLAY_DYNAMIC
923void
924gu1_set_cursor_colors(unsigned long bkcolor, unsigned long fgcolor)
925#else
926void
927gfx_set_cursor_colors(unsigned long bkcolor, unsigned long fgcolor)
928#endif
929{
930    unsigned long value;
931
932    /* If genlock is enabled DCLK might be disabled in vertical blank. */
933    /* Due to SC1200 Issue #748 in Notes DB this would fail the cursor color settings */
934    /* So Wait for vertical blank to end */
935
936#if GFX_VIDEO_SC1200
937    if (gfx_test_timing_active())
938        while ((gfx_get_vline()) > gfx_get_vactive());
939#endif
940    /* SET CURSOR COLORS */
941    WRITE_REG32(DC_PAL_ADDRESS, 0x100);
942    value = ((bkcolor & 0x000000FC) >> 2) |
943        ((bkcolor & 0x0000FC00) >> (2 + 8 - 6)) |
944        ((bkcolor & 0x00FC0000) >> (2 + 16 - 12));
945    WRITE_REG32(DC_PAL_DATA, value);
946    value = ((fgcolor & 0x000000FC) >> 2) |
947        ((fgcolor & 0x0000FC00) >> (2 + 8 - 6)) |
948        ((fgcolor & 0x00FC0000) >> (2 + 16 - 12));
949    WRITE_REG32(DC_PAL_DATA, value);
950}
951
952/*---------------------------------------------------------------------------
953 * gfx_set_cursor_position
954 *
955 * This routine sets the position of the hardware cusror.  The starting
956 * offset of the cursor buffer must be specified so that the routine can
957 * properly clip scanlines if the cursor is off the top of the screen.
958 *---------------------------------------------------------------------------
959 */
960#if GFX_DISPLAY_DYNAMIC
961void
962gu1_set_cursor_position(unsigned long memoffset,
963                        unsigned short xpos, unsigned short ypos,
964                        unsigned short xhotspot, unsigned short yhotspot)
965#else
966void
967gfx_set_cursor_position(unsigned long memoffset,
968                        unsigned short xpos, unsigned short ypos,
969                        unsigned short xhotspot, unsigned short yhotspot)
970#endif
971{
972    unsigned long unlock;
973
974    short x, y;
975    short xoffset = 0;
976    short yoffset = 0;
977
978    /* SUPPORT CURSOR IN EMULATED VGA MODES */
979    /* Timings are for twice the resolution */
980    if (gfx_pixel_double)
981        xpos <<= 1;
982
983    if (gfx_line_double)
984        ypos <<= 1;
985
986    x = (short) xpos - (short) xhotspot;
987    y = (short) ypos - (short) yhotspot;
988    if (x < -31)
989        return;
990
991    if (y < -31)
992        return;
993
994    if (x < 0) {
995        xoffset = -x;
996        x = 0;
997    }
998
999    if (y < 0) {
1000        yoffset = -y;
1001        y = 0;
1002    }
1003
1004    memoffset += (unsigned long) yoffset << 3;
1005
1006    if (PanelEnable) {
1007        if ((ModeWidth > PanelWidth) || (ModeHeight > PanelHeight)) {
1008            gfx_enable_panning(xpos, ypos);
1009            x = x - (short) panelLeft;
1010            y = y - (short) panelTop;
1011        }
1012    }
1013
1014    /* SET CURSOR POSITION */
1015    unlock = READ_REG32(DC_UNLOCK);
1016    WRITE_REG32(DC_UNLOCK, DC_UNLOCK_VALUE);
1017    WRITE_REG32(DC_CURS_ST_OFFSET, memoffset);
1018    WRITE_REG32(DC_CURSOR_X, (unsigned long) x |
1019                (((unsigned long) xoffset) << 11));
1020    WRITE_REG32(DC_CURSOR_Y, (unsigned long) y |
1021                (((unsigned long) yoffset) << 11));
1022    WRITE_REG32(DC_UNLOCK, unlock);
1023}
1024
1025/*---------------------------------------------------------------------------
1026 * gfx_set_cursor_shape32
1027 *
1028 * This routine loads 32x32 cursor data into the specified location in
1029 * graphics memory.
1030 *---------------------------------------------------------------------------
1031 */
1032#if GFX_DISPLAY_DYNAMIC
1033void
1034gu1_set_cursor_shape32(unsigned long memoffset,
1035                       unsigned long *andmask, unsigned long *xormask)
1036#else
1037void
1038gfx_set_cursor_shape32(unsigned long memoffset,
1039                       unsigned long *andmask, unsigned long *xormask)
1040#endif
1041{
1042    int i;
1043    unsigned long value;
1044
1045    for (i = 0; i < 32; i++) {
1046        /* CONVERT TO 16 BITS AND MASK, 16 BITS XOR MASK PER DWORD */
1047        value = (andmask[i] & 0xFFFF0000) | (xormask[i] >> 16);
1048        WRITE_FB32(memoffset, value);
1049        memoffset += 4;
1050        value = (andmask[i] << 16) | (xormask[i] & 0x0000FFFF);
1051        WRITE_FB32(memoffset, value);
1052        memoffset += 4;
1053    }
1054}
1055
1056/*---------------------------------------------------------------------------
1057 * gu1_enable_compression
1058 *
1059 * This is a private routine to this module (not exposed in the Durango API).
1060 * It enables display compression.
1061 *---------------------------------------------------------------------------
1062 */
1063void
1064gu1_enable_compression(void)
1065{
1066    int i;
1067    unsigned long unlock, gcfg, offset;
1068
1069    /* DO NOT ENABLE IF START ADDRESS IS NOT ZERO */
1070    offset = READ_REG32(DC_FB_ST_OFFSET) & 0x003FFFFF;
1071    if (offset != 0)
1072        return;
1073
1074    /* DO NOT ENABLE IF WE ARE WITHIN AN EMULATED VGA MODE */
1075    if (gfx_line_double || gfx_pixel_double)
1076        return;
1077
1078    /* SET GLOBAL INDICATOR */
1079    gfx_compression_active = 1;
1080
1081    /* CLEAR DIRTY/VALID BITS IN MEMORY CONTROLLER */
1082    /* Software is required to do this before enabling compression. */
1083    /* Don't want controller to think that old lines are still valid. */
1084    for (i = 0; i < 1024; i++) {
1085        WRITE_REG32(MC_DR_ADD, i);
1086        WRITE_REG32(MC_DR_ACC, 0);
1087    }
1088
1089    /* TURN ON COMPRESSION CONTROL BITS */
1090    unlock = READ_REG32(DC_UNLOCK);
1091    gcfg = READ_REG32(DC_GENERAL_CFG);
1092    gcfg |= DC_GCFG_CMPE | DC_GCFG_DECE;
1093    WRITE_REG32(DC_UNLOCK, DC_UNLOCK_VALUE);
1094    WRITE_REG32(DC_GENERAL_CFG, gcfg);
1095    WRITE_REG32(DC_UNLOCK, unlock);
1096}
1097
1098/*---------------------------------------------------------------------------
1099 * gu1_disable_compression
1100 *
1101 * This is a private routine to this module (not exposed in the Durango API).
1102 * It disables display compression.
1103 *---------------------------------------------------------------------------
1104 */
1105void
1106gu1_disable_compression(void)
1107{
1108    unsigned long unlock, gcfg;
1109
1110    /* SET GLOBAL INDICATOR */
1111    gfx_compression_active = 0;
1112
1113    /* TURN OFF COMPRESSION CONTROL BITS */
1114    unlock = READ_REG32(DC_UNLOCK);
1115    gcfg = READ_REG32(DC_GENERAL_CFG);
1116    gcfg &= ~(DC_GCFG_CMPE | DC_GCFG_DECE);
1117    WRITE_REG32(DC_UNLOCK, DC_UNLOCK_VALUE);
1118    WRITE_REG32(DC_GENERAL_CFG, gcfg);
1119    WRITE_REG32(DC_UNLOCK, unlock);
1120}
1121
1122/*---------------------------------------------------------------------------
1123 * gfx_set_compression_enable
1124 *
1125 * This routine enables or disables display compression.
1126 *---------------------------------------------------------------------------
1127 */
1128#if GFX_DISPLAY_DYNAMIC
1129int
1130gu1_set_compression_enable(int enable)
1131#else
1132int
1133gfx_set_compression_enable(int enable)
1134#endif
1135{
1136    /* SET GLOBAL VARIABLE FOR INTENDED STATE */
1137    /* Compression can only be enabled for non-zero start address values. */
1138    /* Keep state to enable compression on start address changes. */
1139    gfx_compression_enabled = enable;
1140    if (enable)
1141        gu1_enable_compression();
1142    else
1143        gu1_disable_compression();
1144
1145    return (0);
1146}
1147
1148/*---------------------------------------------------------------------------
1149 * gfx_set_compression_offset
1150 *
1151 * This routine sets the base offset for the compression buffer.
1152 *---------------------------------------------------------------------------
1153 */
1154#if GFX_DISPLAY_DYNAMIC
1155int
1156gu1_set_compression_offset(unsigned long offset)
1157#else
1158int
1159gfx_set_compression_offset(unsigned long offset)
1160#endif
1161{
1162    unsigned long lock;
1163
1164    /* MUST BE 16-BYTE ALIGNED FOR GXLV */
1165    if (offset & 0x0F)
1166        return (1);
1167
1168    /* SET REGISTER VALUE */
1169    lock = READ_REG32(DC_UNLOCK);
1170    WRITE_REG32(DC_UNLOCK, DC_UNLOCK_VALUE);
1171    WRITE_REG32(DC_CB_ST_OFFSET, offset);
1172    WRITE_REG32(DC_UNLOCK, lock);
1173    return (0);
1174}
1175
1176/*---------------------------------------------------------------------------
1177 * gfx_set_compression_pitch
1178 *
1179 * This routine sets the pitch, in bytes, of the compression buffer.
1180 *---------------------------------------------------------------------------
1181 */
1182#if GFX_DISPLAY_DYNAMIC
1183int
1184gu1_set_compression_pitch(unsigned short pitch)
1185#else
1186int
1187gfx_set_compression_pitch(unsigned short pitch)
1188#endif
1189{
1190    unsigned long lock, line_delta;
1191
1192    /* SET REGISTER VALUE */
1193    lock = READ_REG32(DC_UNLOCK);
1194    line_delta = READ_REG32(DC_LINE_DELTA) & 0xFF800FFF;
1195    line_delta |= ((unsigned long) pitch << 10l) & 0x007FF000;
1196    WRITE_REG32(DC_UNLOCK, DC_UNLOCK_VALUE);
1197    WRITE_REG32(DC_LINE_DELTA, line_delta);
1198    WRITE_REG32(DC_UNLOCK, lock);
1199    return (0);
1200}
1201
1202/*---------------------------------------------------------------------------
1203 * gfx_set_compression_size
1204 *
1205 * This routine sets the line size of the compression buffer, which is the
1206 * maximum number of bytes allowed to store a compressed line.
1207 *---------------------------------------------------------------------------
1208 */
1209#if GFX_DISPLAY_DYNAMIC
1210int
1211gu1_set_compression_size(unsigned short size)
1212#else
1213int
1214gfx_set_compression_size(unsigned short size)
1215#endif
1216{
1217    unsigned long lock, buf_size;
1218
1219    /* SUBTRACT 16 FROM SIZE                          */
1220    /* The display controller will actually write     */
1221    /* 2 extra QWords.  So, if we assume that "size"  */
1222    /* refers to the allocated size, we must subtract */
1223    /* 16 bytes.                                      */
1224    size -= 16;
1225
1226    /* SET REGISTER VALUE */
1227    lock = READ_REG32(DC_UNLOCK);
1228    buf_size = READ_REG32(DC_BUF_SIZE) & 0xFFFF01FF;
1229    buf_size |= (((size >> 2) + 1) & 0x7F) << 9;
1230    WRITE_REG32(DC_UNLOCK, DC_UNLOCK_VALUE);
1231    WRITE_REG32(DC_BUF_SIZE, buf_size);
1232    WRITE_REG32(DC_UNLOCK, lock);
1233    return (0);
1234}
1235
1236/*---------------------------------------------------------------------------
1237 * gfx_set_display_video_enable (PRIVATE ROUTINE - NOT PART OF API)
1238 *
1239 * This routine enables/disables video on GX.
1240 *---------------------------------------------------------------------------
1241 */
1242#if GFX_DISPLAY_DYNAMIC
1243void
1244gu1_set_display_video_enable(int enable)
1245#else
1246void
1247gfx_set_display_video_enable(int enable)
1248#endif
1249{
1250    unsigned long lock, gcfg, buf_size;
1251
1252    lock = READ_REG32(DC_UNLOCK);
1253    gcfg = READ_REG32(DC_GENERAL_CFG);
1254    buf_size = READ_REG32(DC_BUF_SIZE);
1255
1256    WRITE_REG32(DC_UNLOCK, DC_UNLOCK_VALUE);
1257
1258    vid_enabled = enable;
1259
1260    /* SET THE BUFFER SIZE TO A NON-ZERO VALUE ONLY WHEN */
1261    /* ENABLING VIDEO                                    */
1262    if (enable) {
1263        gcfg |= (DC_GCFG_VIDE | DC_GCFG_VRDY);
1264        WRITE_REG32(DC_GENERAL_CFG, gcfg);
1265
1266        WRITE_REG32(DC_BUF_SIZE, (buf_size & 0x0000FFFFl) | vid_buf_size);
1267    }
1268    /* CLEAR THE VIDEO BUFFER SIZE WHEN DISABLING VIDEO  */
1269    else {
1270        gcfg &= ~(DC_GCFG_VIDE);
1271        WRITE_REG32(DC_GENERAL_CFG, gcfg);
1272
1273        vid_buf_size = buf_size & 0xFFFF0000l;
1274        WRITE_REG32(DC_BUF_SIZE, buf_size & 0x0000FFFFl);
1275    }
1276
1277    WRITE_REG32(DC_UNLOCK, lock);
1278    return;
1279}
1280
1281/*---------------------------------------------------------------------------
1282 * gfx_set_display_video_size (PRIVATE ROUTINE - NOT PART OF API)
1283 *
1284 * This routine is called by "gfx_set_video_size".  It abstracts the
1285 * version of the display controller from the video overlay routines.
1286 *---------------------------------------------------------------------------
1287 */
1288#if GFX_DISPLAY_DYNAMIC
1289void
1290gu1_set_display_video_size(unsigned short width, unsigned short height)
1291#else
1292void
1293gfx_set_display_video_size(unsigned short width, unsigned short height)
1294#endif
1295{
1296    unsigned long lock, size, value;
1297
1298    size = (unsigned long) (width << 1) * (unsigned long) height;
1299
1300    /* STORE THE VIDEO BUFFER SIZE AS A GLOBAL */
1301    vid_buf_size = ((size + 63) >> 6) << 16;
1302
1303    lock = READ_REG32(DC_UNLOCK);
1304    WRITE_REG32(DC_UNLOCK, DC_UNLOCK_VALUE);
1305    value = READ_REG32(DC_BUF_SIZE) & 0x0000FFFF;
1306    value |= vid_buf_size;
1307    WRITE_REG32(DC_BUF_SIZE, value);
1308    WRITE_REG32(DC_UNLOCK, lock);
1309}
1310
1311/*---------------------------------------------------------------------------
1312 * gfx_set_display_video_offset (PRIVATE ROUTINE - NOT PART OF API)
1313 *
1314 * This routine is called by "gfx_set_video_offset".  It abstracts the
1315 * version of the display controller from the video overlay routines.
1316 *---------------------------------------------------------------------------
1317 */
1318#if GFX_DISPLAY_DYNAMIC
1319void
1320gu1_set_display_video_offset(unsigned long offset)
1321#else
1322void
1323gfx_set_display_video_offset(unsigned long offset)
1324#endif
1325{
1326    unsigned long lock;
1327
1328    lock = READ_REG32(DC_UNLOCK);
1329    WRITE_REG32(DC_UNLOCK, DC_UNLOCK_VALUE);
1330    offset &= 0x003FFFFF;
1331    WRITE_REG32(DC_VID_ST_OFFSET, offset);
1332    WRITE_REG32(DC_UNLOCK, lock);
1333}
1334
1335/*---------------------------------------------------------------------------
1336 * gfx_set_display_priority_high
1337 *
1338 * This routine controls the x-bus round robin arbitration mechanism.
1339 * When enable is TRUE, graphics pipeline requests and non-critical display
1340 * controller requests are arbitrated at the same priority as processor
1341 * requests. When FALSE processor requests are arbitrated at a higher priority
1342 *---------------------------------------------------------------------------
1343 */
1344#if GFX_DISPLAY_DYNAMIC
1345void
1346gu1_set_display_priority_high(int enable)
1347#else
1348void
1349gfx_set_display_priority_high(int enable)
1350#endif
1351{
1352    unsigned long lock, control;
1353
1354    lock = READ_REG32(DC_UNLOCK);
1355    control = READ_REG32(MC_MEM_CNTRL1);
1356    WRITE_REG32(DC_UNLOCK, DC_UNLOCK_VALUE);
1357    if (enable)
1358        control |= MC_XBUSARB;
1359    else
1360        control &= ~(MC_XBUSARB);
1361    WRITE_REG32(MC_MEM_CNTRL1, control);
1362    WRITE_REG32(DC_UNLOCK, lock);
1363    return;
1364}
1365
1366/*---------------------------------------------------------------------------
1367 * gfx_test_timing_active
1368 *---------------------------------------------------------------------------
1369 */
1370#if GFX_DISPLAY_DYNAMIC
1371int
1372gu1_test_timing_active(void)
1373#else
1374int
1375gfx_test_timing_active(void)
1376#endif
1377{
1378    if (READ_REG32(DC_TIMING_CFG) & DC_TCFG_TGEN)
1379        return (1);
1380    else
1381        return (0);
1382}
1383
1384/*---------------------------------------------------------------------------
1385 * gfx_test_vertical_active
1386 *---------------------------------------------------------------------------
1387 */
1388#if GFX_DISPLAY_DYNAMIC
1389int
1390gu1_test_vertical_active(void)
1391#else
1392int
1393gfx_test_vertical_active(void)
1394#endif
1395{
1396    if (READ_REG32(DC_TIMING_CFG) & DC_TCFG_VNA)
1397        return (0);
1398    else
1399        return (1);
1400}
1401
1402/*---------------------------------------------------------------------------
1403 * gfx_wait_vertical_blank
1404 *---------------------------------------------------------------------------
1405 */
1406#if GFX_DISPLAY_DYNAMIC
1407int
1408gu1_wait_vertical_blank(void)
1409#else
1410int
1411gfx_wait_vertical_blank(void)
1412#endif
1413{
1414    if (gfx_test_timing_active()) {
1415        while (!gfx_test_vertical_active());
1416        while (gfx_test_vertical_active());
1417    }
1418
1419    return (0);
1420}
1421
1422/*---------------------------------------------------------------------------
1423 * gfx_enable_panning
1424 *
1425 * This routine  enables the panning when the Mode is bigger than the panel
1426 * size.
1427 *---------------------------------------------------------------------------
1428 */
1429#if GFX_DISPLAY_DYNAMIC
1430void
1431gu1_enable_panning(int x, int y)
1432#else
1433void
1434gfx_enable_panning(int x, int y)
1435#endif
1436{
1437    unsigned long modeBytesPerPixel;
1438    unsigned long modeBytesPerScanline = 0;
1439    unsigned long startAddress = 0;
1440
1441    modeBytesPerPixel = (gbpp + 7) / 8;
1442    modeBytesPerScanline =
1443        (((ModeWidth + 1023) / 1024) * 1024) * modeBytesPerPixel;
1444
1445    /* TEST FOR NO-WORK */
1446    if (x >= DeltaX && (unsigned short) x < (PanelWidth + DeltaX) &&
1447        y >= DeltaY && (unsigned short) y < (PanelHeight + DeltaY))
1448        return;
1449
1450    /* ADJUST PANNING VARIABLES WHEN CURSOR EXCEEDS BOUNDARY       */
1451    /* Test the boundary conditions for each coordinate and update */
1452    /* all variables and the starting offset accordingly.          */
1453    if (x < DeltaX)
1454        DeltaX = x;
1455    else if ((unsigned short) x >= (DeltaX + PanelWidth))
1456        DeltaX = x - PanelWidth + 1;
1457
1458    if (y < DeltaY)
1459        DeltaY = y;
1460    else if ((unsigned short) y >= (DeltaY + PanelHeight))
1461        DeltaY = y - PanelHeight + 1;
1462
1463    /* CALCULATE THE START OFFSET */
1464    startAddress =
1465        (DeltaX * modeBytesPerPixel) + (DeltaY * modeBytesPerScanline);
1466
1467    gfx_set_display_offset(startAddress);
1468
1469    /* SET PANEL COORDINATES                    */
1470    /* Panel's x position must be DWORD aligned */
1471    panelTop = DeltaY;
1472    panelLeft = DeltaX * modeBytesPerPixel;
1473
1474    if (panelLeft & 3)
1475        panelLeft = (panelLeft & 0xFFFFFFFC) + 4;
1476
1477    panelLeft /= modeBytesPerPixel;
1478
1479}
1480
1481/*---------------------------------------------------------------------------
1482 * gfx_set_fixed_timings
1483 *---------------------------------------------------------------------------
1484 */
1485#if GFX_DISPLAY_DYNAMIC
1486int
1487gu1_set_fixed_timings(int panelResX, int panelResY, unsigned short width,
1488                      unsigned short height, unsigned short bpp)
1489#else
1490int
1491gfx_set_fixed_timings(int panelResX, int panelResY, unsigned short width,
1492                      unsigned short height, unsigned short bpp)
1493#endif
1494{
1495    unsigned int mode;
1496
1497    ModeWidth = width;
1498    ModeHeight = height;
1499    PanelWidth = (unsigned short) panelResX;
1500    PanelHeight = (unsigned short) panelResY;
1501    PanelEnable = 1;
1502
1503    /* LOOP THROUGH THE AVAILABLE MODES TO FIND A MATCH */
1504    for (mode = 0; mode < NUM_FIXED_TIMINGS_MODES; mode++) {
1505        if ((FixedParams[mode].xres == width) &&
1506            (FixedParams[mode].yres == height) &&
1507            (FixedParams[mode].panelresx == panelResX) &&
1508            (FixedParams[mode].panelresy == panelResY)) {
1509
1510            /* SET THE 92xx FOR THE SELECTED MODE */
1511            FIXEDTIMINGS *fmode = &FixedParams[mode];
1512
1513            gfx_set_display_timings(bpp, 3, fmode->hactive,
1514                                    fmode->hblankstart, fmode->hsyncstart,
1515                                    fmode->hsyncend, fmode->hblankend,
1516                                    fmode->htotal, fmode->vactive,
1517                                    fmode->vblankstart, fmode->vsyncstart,
1518                                    fmode->vsyncend, fmode->vblankend,
1519                                    fmode->vtotal, fmode->frequency);
1520
1521            return (1);
1522        }                       /* end if() */
1523    }                           /* end for() */
1524
1525    return (-1);
1526}
1527
1528/*---------------------------------------------------------------------------
1529 * gfx_set_panel_present
1530 *---------------------------------------------------------------------------
1531 */
1532#if GFX_DISPLAY_DYNAMIC
1533int
1534gu1_set_panel_present(int panelResX, int panelResY, unsigned short width,
1535                      unsigned short height, unsigned short bpp)
1536#else
1537int
1538gfx_set_panel_present(int panelResX, int panelResY, unsigned short width,
1539                      unsigned short height, unsigned short bpp)
1540#endif
1541{
1542    /* SET VALID BPP         */
1543    /* 16BPP is the default. */
1544    if (bpp != 8 && bpp != 15 && bpp != 16)
1545        bpp = 16;
1546
1547    /* RECORD PANEL PARAMETERS */
1548    /* This routine does not touch any panel timings.  It is used when custom
1549     * panel settings are set up in advance by the BIOS or an application, but
1550     * the application still requires access to other panel functionality
1551     * provided by Durango (i.e. panning)
1552     * */
1553
1554    ModeWidth = width;
1555    ModeHeight = height;
1556    PanelWidth = (unsigned short) panelResX;
1557    PanelHeight = (unsigned short) panelResY;
1558    PanelEnable = 1;
1559    gbpp = bpp;
1560
1561    /* PROGRAM THE BPP IN THE DISPLAY CONTROLLER */
1562    gfx_set_display_bpp(bpp);
1563
1564    return (GFX_STATUS_OK);
1565}
1566
1567/*-----------------------------------------------------------------------*
1568 * THE FOLLOWING READ ROUTINES ARE ALWAYS INCLUDED:                      *
1569 * gfx_get_hsync_end, gfx_get_htotal, gfx_get_vsync_end, gfx_get_vtotal  *
1570 * are used by the video overlay routines.                               *
1571 *                                                                       *
1572 * gfx_get_vline and gfx_vactive are used to prevent an issue for the    *
1573 * SC1200.                                                               *
1574 *                                                                       *
1575 * The others are part of the Durango API.                               *
1576 *-----------------------------------------------------------------------*/
1577
1578/*---------------------------------------------------------------------------
1579 * gfx_get_display_pitch
1580 *
1581 * This routine returns the current pitch of the frame buffer, in bytes.
1582 *---------------------------------------------------------------------------
1583 */
1584#if GFX_DISPLAY_DYNAMIC
1585unsigned short
1586gu1_get_display_pitch(void)
1587#else
1588unsigned short
1589gfx_get_display_pitch(void)
1590#endif
1591{
1592    unsigned long value;
1593
1594    if (gfx_cpu_version == GFX_CPU_PYRAMID) {
1595        /* Pyramid update for 4KB line pitch */
1596        value = (READ_REG32(DC_LINE_DELTA) & 0x07FF) << 2;
1597    }
1598    else {
1599        value = (READ_REG32(DC_LINE_DELTA) & 0x03FF) << 2;
1600    }
1601
1602    return ((unsigned short) value);
1603}
1604
1605/*----------------------------------------------------------------------------
1606 * GFX_GET_DISPLAY_DETAILS
1607 *
1608 * This routine gets the specified display mode.
1609 *
1610 * Returns 1 if successful, 0 if mode could not be get.
1611 *----------------------------------------------------------------------------
1612 */
1613#if GFX_DISPLAY_DYNAMIC
1614int
1615gu1_get_display_details(unsigned int mode, int *xres, int *yres, int *hz)
1616#else
1617int
1618gfx_get_display_details(unsigned int mode, int *xres, int *yres, int *hz)
1619#endif
1620{
1621    if (mode < NUM_GX_DISPLAY_MODES) {
1622        if (DisplayParams[mode].flags & GFX_MODE_56HZ)
1623            *hz = 56;
1624        else if (DisplayParams[mode].flags & GFX_MODE_60HZ)
1625            *hz = 60;
1626        else if (DisplayParams[mode].flags & GFX_MODE_70HZ)
1627            *hz = 70;
1628        else if (DisplayParams[mode].flags & GFX_MODE_72HZ)
1629            *hz = 72;
1630        else if (DisplayParams[mode].flags & GFX_MODE_75HZ)
1631            *hz = 75;
1632        else if (DisplayParams[mode].flags & GFX_MODE_85HZ)
1633            *hz = 85;
1634
1635        *xres = DisplayParams[mode].hactive;
1636        *yres = DisplayParams[mode].vactive;
1637
1638        return (1);
1639    }
1640    return (0);
1641}
1642
1643/*----------------------------------------------------------------------------
1644 * GFX_GET_DISPLAY_MODE_COUNT
1645 *
1646 * Returns number of modes supported.
1647 *----------------------------------------------------------------------------
1648 */
1649#if GFX_DISPLAY_DYNAMIC
1650int
1651gu1_get_display_mode_count(void)
1652#else
1653int
1654gfx_get_display_mode_count(void)
1655#endif
1656{
1657    return (NUM_GX_DISPLAY_MODES);
1658}
1659
1660/*----------------------------------------------------------------------------
1661 * gfx_get_frame_buffer_line_size
1662 *
1663 * Returns the current frame buffer line size, in bytes
1664 *----------------------------------------------------------------------------
1665 */
1666#if GFX_DISPLAY_DYNAMIC
1667unsigned long
1668gu1_get_frame_buffer_line_size(void)
1669#else
1670unsigned long
1671gfx_get_frame_buffer_line_size(void)
1672#endif
1673{
1674    return ((READ_REG32(DC_BUF_SIZE) & 0x1FF) << 3);
1675}
1676
1677/*----------------------------------------------------------------------------
1678 * gfx_mode_frequency_supported
1679 *
1680 * This routine examines if the requested mode with pixel frequency is supported.
1681 *
1682 * Returns >0 if successful , <0 if freq. could not be found and matched.
1683 *----------------------------------------------------------------------------
1684 */
1685#if GFX_DISPLAY_DYNAMIC
1686int
1687gu1_mode_frequency_supported(int xres, int yres, int bpp,
1688                             unsigned long frequency)
1689#else
1690int
1691gfx_mode_frequency_supported(int xres, int yres, int bpp,
1692                             unsigned long frequency)
1693#endif
1694{
1695    unsigned int index;
1696    unsigned long value;
1697    unsigned long bpp_flag = 0;
1698
1699    bpp_flag = GFX_MODE_8BPP;
1700    if (bpp > 8)
1701        bpp_flag = GFX_MODE_16BPP;
1702
1703    for (index = 0; index < NUM_GX_DISPLAY_MODES; index++) {
1704        if ((DisplayParams[index].hactive == (unsigned short) xres) &&
1705            (DisplayParams[index].vactive == (unsigned short) yres) &&
1706            (DisplayParams[index].flags & bpp_flag) &&
1707            (DisplayParams[index].frequency == frequency)) {
1708            int hz = 0;
1709
1710            value = DisplayParams[index].flags;
1711
1712            if (value & GFX_MODE_56HZ)
1713                hz = 56;
1714            else if (value & GFX_MODE_60HZ)
1715                hz = 60;
1716            else if (value & GFX_MODE_70HZ)
1717                hz = 70;
1718            else if (value & GFX_MODE_72HZ)
1719                hz = 72;
1720            else if (value & GFX_MODE_75HZ)
1721                hz = 75;
1722            else if (value & GFX_MODE_85HZ)
1723                hz = 85;
1724
1725            return (hz);
1726        }
1727    }
1728    return (-1);
1729}
1730
1731/*----------------------------------------------------------------------------
1732 * gfx_refreshrate_from_frequency
1733 *
1734 * This routine maps the frequency to close match refresh rate
1735 *----------------------------------------------------------------------------
1736 */
1737#if GFX_DISPLAY_DYNAMIC
1738int
1739gu1_get_refreshrate_from_frequency(int xres, int yres, int bpp, int *hz,
1740                                   unsigned long frequency)
1741#else
1742int
1743gfx_get_refreshrate_from_frequency(int xres, int yres, int bpp, int *hz,
1744                                   unsigned long frequency)
1745#endif
1746{
1747    unsigned int index, closematch = 0;
1748    unsigned long value;
1749    unsigned long bpp_flag = 0;
1750    long min, diff;
1751
1752    *hz = 60;
1753
1754    bpp_flag = GFX_MODE_8BPP;
1755    if (bpp > 8)
1756        bpp_flag = GFX_MODE_16BPP;
1757
1758    /* FIND THE REGISTER VALUES FOR THE DESIRED FREQUENCY */
1759    /* Search the table for the closest frequency (16.16 format). */
1760    min = 0x7fffffff;
1761    for (index = 0; index < NUM_GX_DISPLAY_MODES; index++) {
1762        if ((DisplayParams[index].htotal == (unsigned short) xres) &&
1763            (DisplayParams[index].vtotal == (unsigned short) yres) &&
1764            (DisplayParams[index].flags & bpp_flag)) {
1765            diff = (long) frequency - (long) DisplayParams[index].frequency;
1766            if (diff < 0)
1767                diff = -diff;
1768
1769            if (diff < min) {
1770                min = diff;
1771                closematch = index;
1772            }
1773        }
1774    }
1775
1776    value = DisplayParams[closematch].flags;
1777
1778    if (value & GFX_MODE_56HZ)
1779        *hz = 56;
1780    else if (value & GFX_MODE_60HZ)
1781        *hz = 60;
1782    else if (value & GFX_MODE_70HZ)
1783        *hz = 70;
1784    else if (value & GFX_MODE_72HZ)
1785        *hz = 72;
1786    else if (value & GFX_MODE_75HZ)
1787        *hz = 75;
1788    else if (value & GFX_MODE_85HZ)
1789        *hz = 85;
1790
1791    return (1);
1792}
1793
1794/*----------------------------------------------------------------------------
1795 * gfx_refreshrate_from_mode
1796 *
1797 * This routine is identical to the gfx_get_refreshrate_from_frequency,
1798 * except that the active timing values are compared instead of the total
1799 * values.  Some modes (such as 70Hz and 72Hz) may be confused in this routine
1800 *----------------------------------------------------------------------------
1801 */
1802#if GFX_DISPLAY_DYNAMIC
1803int
1804gu1_get_refreshrate_from_mode(int xres, int yres, int bpp, int *hz,
1805                              unsigned long frequency)
1806#else
1807int
1808gfx_get_refreshrate_from_mode(int xres, int yres, int bpp, int *hz,
1809                              unsigned long frequency)
1810#endif
1811{
1812    unsigned int index, closematch = 0;
1813    unsigned long value;
1814    unsigned long bpp_flag = 0;
1815    long min, diff;
1816
1817    *hz = 60;
1818
1819    bpp_flag = GFX_MODE_8BPP;
1820    if (bpp > 8)
1821        bpp_flag = GFX_MODE_16BPP;
1822
1823    /* FIND THE REGISTER VALUES FOR THE DESIRED FREQUENCY */
1824    /* Search the table for the closest frequency (16.16 format). */
1825    min = 0x7fffffff;
1826    for (index = 0; index < NUM_GX_DISPLAY_MODES; index++) {
1827        if ((DisplayParams[index].hactive == (unsigned short) xres) &&
1828            (DisplayParams[index].vactive == (unsigned short) yres) &&
1829            (DisplayParams[index].flags & bpp_flag)) {
1830            diff = (long) frequency - (long) DisplayParams[index].frequency;
1831            if (diff < 0)
1832                diff = -diff;
1833
1834            if (diff < min) {
1835                min = diff;
1836                closematch = index;
1837            }
1838        }
1839    }
1840
1841    value = DisplayParams[closematch].flags;
1842
1843    if (value & GFX_MODE_56HZ)
1844        *hz = 56;
1845    else if (value & GFX_MODE_60HZ)
1846        *hz = 60;
1847    else if (value & GFX_MODE_70HZ)
1848        *hz = 70;
1849    else if (value & GFX_MODE_72HZ)
1850        *hz = 72;
1851    else if (value & GFX_MODE_75HZ)
1852        *hz = 75;
1853    else if (value & GFX_MODE_85HZ)
1854        *hz = 85;
1855
1856    return (1);
1857}
1858
1859/*----------------------------------------------------------------------------
1860 * gfx_get_frequency_from_refreshrate
1861 *
1862 * This routine maps the refresh rate to the closest matching PLL frequency.
1863 *----------------------------------------------------------------------------
1864 */
1865#if GFX_DISPLAY_DYNAMIC
1866int
1867gu1_get_frequency_from_refreshrate(int xres, int yres, int bpp, int hz,
1868                                   int *frequency)
1869#else
1870int
1871gfx_get_frequency_from_refreshrate(int xres, int yres, int bpp, int hz,
1872                                   int *frequency)
1873#endif
1874{
1875    unsigned int index;
1876    int retval = -1;
1877    unsigned long hz_flag = 0;
1878    unsigned long bpp_flag = 0;
1879
1880    *frequency = 0;
1881
1882    if (hz == 56)
1883        hz_flag = GFX_MODE_56HZ;
1884    else if (hz == 60)
1885        hz_flag = GFX_MODE_60HZ;
1886    else if (hz == 70)
1887        hz_flag = GFX_MODE_70HZ;
1888    else if (hz == 72)
1889        hz_flag = GFX_MODE_72HZ;
1890    else if (hz == 75)
1891        hz_flag = GFX_MODE_75HZ;
1892    else if (hz == 85)
1893        hz_flag = GFX_MODE_85HZ;
1894
1895    bpp_flag = GFX_MODE_8BPP;
1896    if (bpp > 8)
1897        bpp_flag = GFX_MODE_16BPP;
1898
1899    /* FIND THE REGISTER VALUES FOR THE DESIRED FREQUENCY */
1900
1901    for (index = 0; index < NUM_GX_DISPLAY_MODES; index++) {
1902        if ((DisplayParams[index].hactive == (unsigned short) xres) &&
1903            (DisplayParams[index].vactive == (unsigned short) yres) &&
1904            (DisplayParams[index].flags & bpp_flag) &&
1905            (DisplayParams[index].flags & hz_flag)) {
1906            *frequency = DisplayParams[index].frequency;
1907            retval = 1;
1908        }
1909    }
1910    return retval;
1911}
1912
1913/*---------------------------------------------------------------------------
1914 * gfx_get_max_supported_pixel_clock
1915 *
1916 * This routine returns the maximum recommended speed for the pixel clock.  The
1917 * return value is an integer of the format xxxyyy, where xxx.yyy is the maximum
1918 * floating point pixel clock speed.
1919 *---------------------------------------------------------------------------
1920 */
1921#if GFX_DISPLAY_DYNAMIC
1922unsigned long
1923gu1_get_max_supported_pixel_clock(void)
1924#else
1925unsigned long
1926gfx_get_max_supported_pixel_clock(void)
1927#endif
1928{
1929    /* ALL CHIPS CAN HANDLE 1280X1024@85HZ - 157.5 MHz */
1930    return 157500;
1931}
1932
1933/*----------------------------------------------------------------------------
1934 * gfx_get_display_mode
1935 *
1936 * This routine gets the specified display mode.
1937 *
1938 * Returns: >0 if successful and mode returned, <0 if mode could not be found.
1939 *----------------------------------------------------------------------------
1940 */
1941#if GFX_DISPLAY_DYNAMIC
1942int
1943gu1_get_display_mode(int *xres, int *yres, int *bpp, int *hz)
1944#else
1945int
1946gfx_get_display_mode(int *xres, int *yres, int *bpp, int *hz)
1947#endif
1948{
1949    unsigned int mode = 0;
1950    unsigned long pll_freq = 0, bpp_flag = 0;
1951
1952    *xres = gfx_get_hactive();
1953    *yres = gfx_get_vactive();
1954    *bpp = gfx_get_display_bpp();
1955    pll_freq = gfx_get_clock_frequency();
1956
1957    /* SUPPORT EMULATED VGA MODES */
1958    if (gfx_pixel_double)
1959        *xres >>= 1;
1960
1961    if (gfx_line_double)
1962        *yres >>= 1;
1963
1964    /* SET BPP FLAGS TO LIMIT MODE SELECTION */
1965    bpp_flag = GFX_MODE_8BPP;
1966    if (*bpp > 8)
1967        bpp_flag = GFX_MODE_16BPP;
1968
1969    for (mode = 0; mode < NUM_GX_DISPLAY_MODES; mode++) {
1970        if ((DisplayParams[mode].hactive == (unsigned short) *xres) &&
1971            (DisplayParams[mode].vactive == (unsigned short) *yres) &&
1972            (DisplayParams[mode].frequency == pll_freq) &&
1973            (DisplayParams[mode].flags & bpp_flag)) {
1974
1975            pll_freq = DisplayParams[mode].flags;
1976
1977            if (pll_freq & GFX_MODE_56HZ)
1978                *hz = 56;
1979            else if (pll_freq & GFX_MODE_60HZ)
1980                *hz = 60;
1981            else if (pll_freq & GFX_MODE_70HZ)
1982                *hz = 70;
1983            else if (pll_freq & GFX_MODE_72HZ)
1984                *hz = 72;
1985            else if (pll_freq & GFX_MODE_75HZ)
1986                *hz = 75;
1987            else if (pll_freq & GFX_MODE_85HZ)
1988                *hz = 85;
1989
1990            return (1);
1991        }
1992    }
1993    return (-1);
1994}
1995
1996/*---------------------------------------------------------------------------
1997 * gfx_get_hactive
1998 *---------------------------------------------------------------------------
1999 */
2000#if GFX_DISPLAY_DYNAMIC
2001unsigned short
2002gu1_get_hactive(void)
2003#else
2004unsigned short
2005gfx_get_hactive(void)
2006#endif
2007{
2008    return ((unsigned short) ((READ_REG32(DC_H_TIMING_1) & 0x07F8) + 8));
2009}
2010
2011/*---------------------------------------------------------------------------
2012 * gfx_get_hsync_start
2013 *---------------------------------------------------------------------------
2014 */
2015#if GFX_DISPLAY_DYNAMIC
2016unsigned short
2017gu1_get_hsync_start(void)
2018#else
2019unsigned short
2020gfx_get_hsync_start(void)
2021#endif
2022{
2023    return ((unsigned short) ((READ_REG32(DC_H_TIMING_3) & 0x07F8) + 8));
2024}
2025
2026/*---------------------------------------------------------------------------
2027 * gfx_get_hsync_end
2028 *---------------------------------------------------------------------------
2029 */
2030#if GFX_DISPLAY_DYNAMIC
2031unsigned short
2032gu1_get_hsync_end(void)
2033#else
2034unsigned short
2035gfx_get_hsync_end(void)
2036#endif
2037{
2038    return ((unsigned short) (((READ_REG32(DC_H_TIMING_3) >> 16) & 0x07F8) +
2039                              8));
2040}
2041
2042/*---------------------------------------------------------------------------
2043 * gfx_get_htotal
2044 *---------------------------------------------------------------------------
2045 */
2046#if GFX_DISPLAY_DYNAMIC
2047unsigned short
2048gu1_get_htotal(void)
2049#else
2050unsigned short
2051gfx_get_htotal(void)
2052#endif
2053{
2054    return ((unsigned short) (((READ_REG32(DC_H_TIMING_1) >> 16) & 0x07F8) +
2055                              8));
2056}
2057
2058/*---------------------------------------------------------------------------
2059 * gfx_get_vactive
2060 *---------------------------------------------------------------------------
2061 */
2062#if GFX_DISPLAY_DYNAMIC
2063unsigned short
2064gu1_get_vactive(void)
2065#else
2066unsigned short
2067gfx_get_vactive(void)
2068#endif
2069{
2070    return ((unsigned short) ((READ_REG32(DC_V_TIMING_1) & 0x07FF) + 1));
2071}
2072
2073/*---------------------------------------------------------------------------
2074 * gfx_get_vsync_end
2075 *---------------------------------------------------------------------------
2076 */
2077#if GFX_DISPLAY_DYNAMIC
2078unsigned short
2079gu1_get_vsync_end(void)
2080#else
2081unsigned short
2082gfx_get_vsync_end(void)
2083#endif
2084{
2085    return ((unsigned short) (((READ_REG32(DC_V_TIMING_3) >> 16) & 0x07FF) +
2086                              1));
2087}
2088
2089/*---------------------------------------------------------------------------
2090 * gfx_get_vtotal
2091 *---------------------------------------------------------------------------
2092 */
2093#if GFX_DISPLAY_DYNAMIC
2094unsigned short
2095gu1_get_vtotal(void)
2096#else
2097unsigned short
2098gfx_get_vtotal(void)
2099#endif
2100{
2101    return ((unsigned short) (((READ_REG32(DC_V_TIMING_1) >> 16) & 0x07FF) +
2102                              1));
2103}
2104
2105/*-----------------------------------------------------------------------------
2106 * gfx_get_display_bpp
2107 *
2108 * This routine returns the current color depth of the active display.
2109 *-----------------------------------------------------------------------------
2110 */
2111#if GFX_DISPLAY_DYNAMIC
2112unsigned short
2113gu1_get_display_bpp(void)
2114#else
2115unsigned short
2116gfx_get_display_bpp(void)
2117#endif
2118{
2119    switch (READ_REG32(DC_OUTPUT_CFG) & 3) {
2120    case 0:
2121        return (16);
2122    case 2:
2123        return (15);
2124    }
2125    return (8);
2126}
2127
2128/*---------------------------------------------------------------------------
2129 * gfx_get_vline
2130 *---------------------------------------------------------------------------
2131 */
2132#if GFX_DISPLAY_DYNAMIC
2133unsigned short
2134gu1_get_vline(void)
2135#else
2136unsigned short
2137gfx_get_vline(void)
2138#endif
2139{
2140    unsigned short current_scan_line;
2141
2142    /* Read similar value twice to ensure that the value is not transitioning */
2143    do {
2144        current_scan_line = (unsigned short) READ_REG32(DC_V_LINE_CNT) & 0x07FF;
2145    } while (current_scan_line !=
2146             (unsigned short) (READ_REG32(DC_V_LINE_CNT) & 0x07FF));
2147
2148    return (current_scan_line);
2149}
2150
2151/*-----------------------------------------------------------------------------
2152 * gfx_get_display_offset
2153 *-----------------------------------------------------------------------------
2154 */
2155#if GFX_DISPLAY_DYNAMIC
2156unsigned long
2157gu1_get_display_offset(void)
2158#else
2159unsigned long
2160gfx_get_display_offset(void)
2161#endif
2162{
2163    return (READ_REG32(DC_FB_ST_OFFSET) & 0x003FFFFF);
2164}
2165
2166/*-----------------------------------------------------------------------------
2167 * gfx_get_cursor_offset
2168 *-----------------------------------------------------------------------------
2169 */
2170#if GFX_DISPLAY_DYNAMIC
2171unsigned long
2172gu1_get_cursor_offset(void)
2173#else
2174unsigned long
2175gfx_get_cursor_offset(void)
2176#endif
2177{
2178    return (READ_REG32(DC_CURS_ST_OFFSET) & 0x003FFFFF);
2179}
2180
2181#if GFX_READ_ROUTINES
2182
2183/*************************************************************/
2184/*  READ ROUTINES  |  INCLUDED FOR DIAGNOSTIC PURPOSES ONLY  */
2185/*************************************************************/
2186
2187/*---------------------------------------------------------------------------
2188 * gfx_get_hblank_start
2189 *---------------------------------------------------------------------------
2190 */
2191#if GFX_DISPLAY_DYNAMIC
2192unsigned short
2193gu1_get_hblank_start(void)
2194#else
2195unsigned short
2196gfx_get_hblank_start(void)
2197#endif
2198{
2199    return ((unsigned short) ((READ_REG32(DC_H_TIMING_2) & 0x07F8) + 8));
2200}
2201
2202/*---------------------------------------------------------------------------
2203 * gfx_get_hblank_end
2204 *---------------------------------------------------------------------------
2205 */
2206#if GFX_DISPLAY_DYNAMIC
2207unsigned short
2208gu1_get_hblank_end(void)
2209#else
2210unsigned short
2211gfx_get_hblank_end(void)
2212#endif
2213{
2214    return ((unsigned short) (((READ_REG32(DC_H_TIMING_2) >> 16) & 0x07F8) +
2215                              8));
2216}
2217
2218/*---------------------------------------------------------------------------
2219 * gfx_get_vblank_start
2220 *---------------------------------------------------------------------------
2221 */
2222#if GFX_DISPLAY_DYNAMIC
2223unsigned short
2224gu1_get_vblank_start(void)
2225#else
2226unsigned short
2227gfx_get_vblank_start(void)
2228#endif
2229{
2230    return ((unsigned short) ((READ_REG32(DC_V_TIMING_2) & 0x07FF) + 1));
2231}
2232
2233/*---------------------------------------------------------------------------
2234 * gfx_get_vsync_start
2235 *---------------------------------------------------------------------------
2236 */
2237#if GFX_DISPLAY_DYNAMIC
2238unsigned short
2239gu1_get_vsync_start(void)
2240#else
2241unsigned short
2242gfx_get_vsync_start(void)
2243#endif
2244{
2245    return ((unsigned short) ((READ_REG32(DC_V_TIMING_3) & 0x07FF) + 1));
2246}
2247
2248/*---------------------------------------------------------------------------
2249 * gfx_get_vblank_end
2250 *---------------------------------------------------------------------------
2251 */
2252#if GFX_DISPLAY_DYNAMIC
2253unsigned short
2254gu1_get_vblank_end(void)
2255#else
2256unsigned short
2257gfx_get_vblank_end(void)
2258#endif
2259{
2260    return ((unsigned short) (((READ_REG32(DC_V_TIMING_2) >> 16) & 0x07FF) +
2261                              1));
2262}
2263
2264/*-----------------------------------------------------------------------------
2265 * gfx_get_display_palette_entry
2266 *-----------------------------------------------------------------------------
2267 */
2268#if GFX_DISPLAY_DYNAMIC
2269int
2270gu1_get_display_palette_entry(unsigned long index, unsigned long *palette)
2271#else
2272int
2273gfx_get_display_palette_entry(unsigned long index, unsigned long *palette)
2274#endif
2275{
2276    unsigned long data;
2277
2278    if (index > 0xFF)
2279        return GFX_STATUS_BAD_PARAMETER;
2280
2281    WRITE_REG32(DC_PAL_ADDRESS, index);
2282    data = READ_REG32(DC_PAL_DATA);
2283    data = ((data << 2) & 0x000000FC) |
2284        ((data << 4) & 0x0000FC00) | ((data << 6) & 0x00FC0000);
2285
2286    *palette = data;
2287    return 0;
2288}
2289
2290/*-----------------------------------------------------------------------------
2291 * gfx_get_display_palette
2292 *-----------------------------------------------------------------------------
2293 */
2294#if GFX_DISPLAY_DYNAMIC
2295void
2296gu1_get_display_palette(unsigned long *palette)
2297#else
2298void
2299gfx_get_display_palette(unsigned long *palette)
2300#endif
2301{
2302    unsigned long i, data;
2303
2304    WRITE_REG32(DC_PAL_ADDRESS, 0);
2305    for (i = 0; i < 256; i++) {
2306        data = READ_REG32(DC_PAL_DATA);
2307        data = ((data << 2) & 0x000000FC) |
2308            ((data << 4) & 0x0000FC00) | ((data << 6) & 0x00FC0000);
2309        palette[i] = data;
2310    }
2311}
2312
2313/*-----------------------------------------------------------------------------
2314 * gfx_get_cursor_enable
2315 *-----------------------------------------------------------------------------
2316 */
2317#if GFX_DISPLAY_DYNAMIC
2318unsigned long
2319gu1_get_cursor_enable(void)
2320#else
2321unsigned long
2322gfx_get_cursor_enable(void)
2323#endif
2324{
2325    return (READ_REG32(DC_GENERAL_CFG) & DC_GCFG_CURE);
2326}
2327
2328/*-----------------------------------------------------------------------------
2329 * gfx_get_cursor_position
2330 *-----------------------------------------------------------------------------
2331 */
2332#if GFX_DISPLAY_DYNAMIC
2333unsigned long
2334gu1_get_cursor_position(void)
2335#else
2336unsigned long
2337gfx_get_cursor_position(void)
2338#endif
2339{
2340    return ((READ_REG32(DC_CURSOR_X) & 0x07FF) |
2341            ((READ_REG32(DC_CURSOR_Y) << 16) & 0x03FF0000));
2342}
2343
2344/*-----------------------------------------------------------------------------
2345 * gfx_get_cursor_clip
2346 *-----------------------------------------------------------------------------
2347 */
2348#if GFX_DISPLAY_DYNAMIC
2349unsigned long
2350gu1_get_cursor_clip(void)
2351#else
2352unsigned long
2353gfx_get_cursor_clip(void)
2354#endif
2355{
2356    return (((READ_REG32(DC_CURSOR_X) >> 11) & 0x01F) |
2357            ((READ_REG32(DC_CURSOR_Y) << 5) & 0x1F0000));
2358}
2359
2360/*-----------------------------------------------------------------------------
2361 * gfx_get_cursor_color
2362 *-----------------------------------------------------------------------------
2363 */
2364#if GFX_DISPLAY_DYNAMIC
2365unsigned long
2366gu1_get_cursor_color(int color)
2367#else
2368unsigned long
2369gfx_get_cursor_color(int color)
2370#endif
2371{
2372    unsigned long data;
2373
2374    if (color) {
2375        WRITE_REG32(DC_PAL_ADDRESS, 0x101);
2376    }
2377    else {
2378        WRITE_REG32(DC_PAL_ADDRESS, 0x100);
2379    }
2380    data = READ_REG32(DC_PAL_DATA);
2381    data = ((data << 6) & 0x00FC0000) |
2382        ((data << 4) & 0x0000FC00) | ((data << 2) & 0x000000FC);
2383    return (data);
2384}
2385
2386/*-----------------------------------------------------------------------------
2387 * gfx_get_compression_enable
2388 *-----------------------------------------------------------------------------
2389 */
2390#if GFX_DISPLAY_DYNAMIC
2391int
2392gu1_get_compression_enable(void)
2393#else
2394int
2395gfx_get_compression_enable(void)
2396#endif
2397{
2398    unsigned long gcfg;
2399
2400    gcfg = READ_REG32(DC_GENERAL_CFG);
2401    if (gcfg & DC_GCFG_CMPE)
2402        return (1);
2403    else
2404        return (0);
2405}
2406
2407/*-----------------------------------------------------------------------------
2408 * gfx_get_compression_offset
2409 *-----------------------------------------------------------------------------
2410 */
2411#if GFX_DISPLAY_DYNAMIC
2412unsigned long
2413gu1_get_compression_offset(void)
2414#else
2415unsigned long
2416gfx_get_compression_offset(void)
2417#endif
2418{
2419    unsigned long offset;
2420
2421    offset = READ_REG32(DC_CB_ST_OFFSET) & 0x003FFFFF;
2422    return (offset);
2423}
2424
2425/*-----------------------------------------------------------------------------
2426 * gfx_get_compression_pitch
2427 *-----------------------------------------------------------------------------
2428 */
2429#if GFX_DISPLAY_DYNAMIC
2430unsigned short
2431gu1_get_compression_pitch(void)
2432#else
2433unsigned short
2434gfx_get_compression_pitch(void)
2435#endif
2436{
2437    unsigned short pitch;
2438
2439    pitch = (unsigned short) (READ_REG32(DC_LINE_DELTA) >> 12) & 0x03FF;
2440    return (pitch << 2);
2441}
2442
2443/*-----------------------------------------------------------------------------
2444 * gfx_get_compression_size
2445 *-----------------------------------------------------------------------------
2446 */
2447#if GFX_DISPLAY_DYNAMIC
2448unsigned short
2449gu1_get_compression_size(void)
2450#else
2451unsigned short
2452gfx_get_compression_size(void)
2453#endif
2454{
2455    unsigned short size;
2456
2457    size = (unsigned short) ((READ_REG32(DC_BUF_SIZE) >> 9) & 0x7F) - 1;
2458    return ((size << 2) + 16);
2459}
2460
2461/*-----------------------------------------------------------------------------
2462 * gfx_get_valid_bit
2463 *-----------------------------------------------------------------------------
2464 */
2465#if GFX_DISPLAY_DYNAMIC
2466int
2467gu1_get_valid_bit(int line)
2468#else
2469int
2470gfx_get_valid_bit(int line)
2471#endif
2472{
2473    int valid;
2474
2475    WRITE_REG32(MC_DR_ADD, line);
2476    valid = (int) READ_REG32(MC_DR_ACC) & 1;
2477    return (valid);
2478}
2479
2480/*---------------------------------------------------------------------------
2481 * gfx_get_display_video_offset (PRIVATE ROUTINE - NOT PART OF API)
2482 *
2483 * This routine is called by "gfx_get_video_offset".  It abstracts the
2484 * version of the display controller from the video overlay routines.
2485 *---------------------------------------------------------------------------
2486 */
2487#if GFX_DISPLAY_DYNAMIC
2488unsigned long
2489gu1_get_display_video_offset(void)
2490#else
2491unsigned long
2492gfx_get_display_video_offset(void)
2493#endif
2494{
2495    return (READ_REG32(DC_VID_ST_OFFSET) & 0x003FFFFF);
2496}
2497
2498/*---------------------------------------------------------------------------
2499 * gfx_get_display_video_size (PRIVATE ROUTINE - NOT PART OF API)
2500 *
2501 * This routine is called by "gfx_get_video_size".  It abstracts the
2502 * version of the display controller from the video overlay routines.
2503 *---------------------------------------------------------------------------
2504 */
2505#if GFX_DISPLAY_DYNAMIC
2506unsigned long
2507gu1_get_display_video_size(void)
2508#else
2509unsigned long
2510gfx_get_display_video_size(void)
2511#endif
2512{
2513    /* RETURN TOTAL SIZE, IN BYTES */
2514    return ((READ_REG32(DC_BUF_SIZE) >> 10) & 0x000FFFC0);
2515}
2516
2517/*-----------------------------------------------------------------------------
2518 * gfx_get_display_priority_high
2519 *-----------------------------------------------------------------------------
2520 */
2521#if GFX_DISPLAY_DYNAMIC
2522int
2523gu1_get_display_priority_high(void)
2524#else
2525int
2526gfx_get_display_priority_high(void)
2527#endif
2528{
2529    if (READ_REG32(MC_MEM_CNTRL1) & MC_XBUSARB)
2530        return (1);
2531    else
2532        return (0);
2533}
2534
2535#endif                          /* GFX_READ_ROUTINES */
2536
2537/* END OF FILE */
2538