disp_gu1.c revision f29dbc25
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    } else {
367        if (gfx_cpu_version == GFX_CPU_PYRAMID)
368            pitch = (size <= 2048) ? 2048 : 4096;
369        else
370            pitch = 2048;
371    }
372
373    WRITE_REG32(DC_LINE_DELTA, pitch >> 2);
374
375    if (PanelEnable) {
376        size = pMode->hactive;
377        if (bpp > 8)
378            size <<= 1;
379    }
380
381    /* ADD 2 TO SIZE FOR POSSIBLE START ADDRESS ALIGNMENTS */
382    WRITE_REG32(DC_BUF_SIZE, (size >> 3) + 2);
383
384    /* ALWAYS ENABLE "PANEL" DATA FROM MEDIAGX */
385    /* That is really just the 18 BPP data bus to the companion chip */
386    ocfg = DC_OCFG_PCKE | DC_OCFG_PDEL | DC_OCFG_PDEH;
387
388    /* SET PIXEL FORMAT */
389    if (bpp == 8)
390        ocfg |= DC_OCFG_8BPP;
391    else if (bpp == 15)
392        ocfg |= DC_OCFG_555;
393
394    /* ENABLE TIMING GENERATOR, SYNCS, AND FP DATA */
395    tcfg = DC_TCFG_FPPE | DC_TCFG_HSYE | DC_TCFG_VSYE | DC_TCFG_BLKE |
396        DC_TCFG_TGEN;
397
398    /* SET FIFO PRIORITY, DCLK MULTIPLIER, AND FIFO ENABLE */
399    /* Default 6/5 for FIFO, 2x for DCLK multiplier. */
400    gcfg =
401        (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],
617                bpp) == GFX_STATUS_OK)
618            return (1);
619    }
620    return (0);
621}
622
623/*----------------------------------------------------------------------------
624 * GFX_SET_DISPLAY_TIMINGS
625 *
626 * This routine sets the display controller mode using the specified timing
627 * values (as opposed to using the tables internal to Durango).
628 *
629 * Returns GFX_STATUS_OK on success, GFX_STATUS_ERROR otherwise.
630 *----------------------------------------------------------------------------
631 */
632#if GFX_DISPLAY_DYNAMIC
633int
634gu1_set_display_timings(unsigned short bpp, unsigned short flags,
635    unsigned short hactive, unsigned short hblankstart,
636    unsigned short hsyncstart, unsigned short hsyncend,
637    unsigned short hblankend, unsigned short htotal,
638    unsigned short vactive, unsigned short vblankstart,
639    unsigned short vsyncstart, unsigned short vsyncend,
640    unsigned short vblankend, unsigned short vtotal, 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, unsigned long frequency)
650#endif
651{
652    /* SET MODE STRUCTURE WITH SPECIFIED VALUES */
653
654    gfx_display_mode.flags = 0;
655    if (flags & 1)
656        gfx_display_mode.flags |= GFX_MODE_NEG_HSYNC;
657    if (flags & 2)
658        gfx_display_mode.flags |= GFX_MODE_NEG_VSYNC;
659    if (flags & 0x1000)
660        gfx_display_mode.flags |= GFX_MODE_LOCK_TIMING;
661    gfx_display_mode.hactive = hactive;
662    gfx_display_mode.hblankstart = hblankstart;
663    gfx_display_mode.hsyncstart = hsyncstart;
664    gfx_display_mode.hsyncend = hsyncend;
665    gfx_display_mode.hblankend = hblankend;
666    gfx_display_mode.htotal = htotal;
667    gfx_display_mode.vactive = vactive;
668    gfx_display_mode.vblankstart = vblankstart;
669    gfx_display_mode.vsyncstart = vsyncstart;
670    gfx_display_mode.vsyncend = vsyncend;
671    gfx_display_mode.vblankend = vblankend;
672    gfx_display_mode.vtotal = vtotal;
673    gfx_display_mode.frequency = frequency;
674
675    /* CALL ROUTINE TO SET MODE */
676    return (gu1_set_specified_mode(&gfx_display_mode, bpp));
677}
678
679/*----------------------------------------------------------------------------
680 * GFX_SET_VTOTAL
681 *
682 * This routine sets the display controller vertical total to
683 * "vtotal". As a side effect it also sets vertical blank end.
684 * It should be used when only this value needs to be changed,
685 * due to speed considerations.
686 *
687 * Note: it is the caller's responsibility to make sure that
688 * a legal vtotal is used, i.e. that "vtotal" is greater than or
689 * equal to vsync end.
690 *
691 * Always returns 0.
692 *----------------------------------------------------------------------------
693 */
694#if GFX_DISPLAY_DYNAMIC
695int
696gu1_set_vtotal(unsigned short vtotal)
697#else
698int
699gfx_set_vtotal(unsigned short vtotal)
700#endif
701{
702    unsigned long unlock, tcfg, timing1, timing2;
703
704    /* UNLOCK THE DISPLAY CONTROLLER REGISTERS */
705    unlock = READ_REG32(DC_UNLOCK);
706    WRITE_REG32(DC_UNLOCK, DC_UNLOCK_VALUE);
707
708    /* READ THE CURRENT GX VALUES */
709    tcfg = READ_REG32(DC_TIMING_CFG);
710    timing1 = READ_REG32(DC_V_TIMING_1);
711    timing2 = READ_REG32(DC_V_TIMING_2);
712
713    /* DISABLE THE TIMING GENERATOR */
714    WRITE_REG32(DC_TIMING_CFG, tcfg & ~(unsigned long)DC_TCFG_TGEN);
715
716    /* WRITE NEW TIMING VALUES */
717    WRITE_REG32(DC_V_TIMING_1,
718        (timing1 & 0xffff) | (unsigned long)(vtotal - 1) << 16);
719    WRITE_REG32(DC_V_TIMING_2,
720        (timing2 & 0xffff) | (unsigned long)(vtotal - 1) << 16);
721
722    /* RESTORE GX VALUES */
723    WRITE_REG32(DC_TIMING_CFG, tcfg);
724    WRITE_REG32(DC_UNLOCK, unlock);
725
726    return (0);
727}
728
729/*---------------------------------------------------------------------------
730 * gfx_set_display_pitch
731 *
732 * This routine sets the pitch of the frame buffer to the specified value.
733 *---------------------------------------------------------------------------
734 */
735#if GFX_DISPLAY_DYNAMIC
736void
737gu1_set_display_pitch(unsigned short pitch)
738#else
739void
740gfx_set_display_pitch(unsigned short pitch)
741#endif
742{
743    unsigned long value = 0;
744    unsigned long lock = READ_REG32(DC_UNLOCK);
745
746    value = READ_REG32(DC_LINE_DELTA) & 0xFFFFF000;
747    value |= (pitch >> 2);
748    WRITE_REG32(DC_UNLOCK, DC_UNLOCK_VALUE);
749    WRITE_REG32(DC_LINE_DELTA, value);
750    WRITE_REG32(DC_UNLOCK, lock);
751
752    /* ALSO UPDATE PITCH IN GRAPHICS ENGINE */
753    /* Pyramid alone supports 4K line pitch */
754    value = (unsigned long)READ_REG16(GP_BLIT_STATUS);
755    value &= ~(BC_FB_WIDTH_2048 | BC_FB_WIDTH_4096);
756
757    if ((gfx_cpu_version == GFX_CPU_PYRAMID) && (pitch > 2048))
758        value |= BC_FB_WIDTH_4096;
759
760    else if (pitch > 1024)
761        value |= BC_FB_WIDTH_2048;
762
763    WRITE_REG16(GP_BLIT_STATUS, (unsigned short)value);
764    return;
765}
766
767/*---------------------------------------------------------------------------
768 * gfx_set_display_offset
769 *
770 * This routine sets the start address of the frame buffer.  It is
771 * typically used to pan across a virtual desktop (frame buffer larger than
772 * the displayed screen) or to flip the display between multiple buffers.
773 *---------------------------------------------------------------------------
774 */
775#if GFX_DISPLAY_DYNAMIC
776void
777gu1_set_display_offset(unsigned long offset)
778#else
779void
780gfx_set_display_offset(unsigned long offset)
781#endif
782{
783    /* UPDATE FRAME BUFFER OFFSET */
784
785    unsigned long lock;
786
787    lock = READ_REG32(DC_UNLOCK);
788    WRITE_REG32(DC_UNLOCK, DC_UNLOCK_VALUE);
789
790    /* START ADDRESS EFFECTS DISPLAY COMPRESSION */
791    /* Disable compression for non-zero start addresss values.            */
792    /* Enable compression if offset is zero and comression is intended to */
793    /* be enabled from a previous call to "gfx_set_compression_enable".   */
794    /* Compression should be disabled BEFORE the offset is changed        */
795    /* and enabled AFTER the offset is changed.                           */
796    if (offset == 0) {
797        WRITE_REG32(DC_FB_ST_OFFSET, offset);
798        if (gfx_compression_enabled) {
799            /* WAIT FOR THE OFFSET TO BE LATCHED */
800            gfx_wait_vertical_blank();
801            gu1_enable_compression();
802        }
803    } else {
804        /* ONLY DISABLE COMPRESSION ONCE */
805        if (gfx_compression_active)
806            gu1_disable_compression();
807
808        WRITE_REG32(DC_FB_ST_OFFSET, offset);
809    }
810
811    WRITE_REG32(DC_UNLOCK, lock);
812}
813
814/*---------------------------------------------------------------------------
815 * gfx_set_display_palette_entry
816 *
817 * This routine sets an palette entry in the display controller.
818 * A 32-bit X:R:G:B value.
819 *---------------------------------------------------------------------------
820 */
821#if GFX_DISPLAY_DYNAMIC
822int
823gu1_set_display_palette_entry(unsigned long index, unsigned long palette)
824#else
825int
826gfx_set_display_palette_entry(unsigned long index, unsigned long palette)
827#endif
828{
829    unsigned long data;
830
831    if (index > 0xFF)
832        return GFX_STATUS_BAD_PARAMETER;
833
834    WRITE_REG32(DC_PAL_ADDRESS, index);
835    data = ((palette >> 2) & 0x0003F) |
836        ((palette >> 4) & 0x00FC0) | ((palette >> 6) & 0x3F000);
837    WRITE_REG32(DC_PAL_DATA, data);
838
839    return (0);
840}
841
842/*---------------------------------------------------------------------------
843 * gfx_set_display_palette
844 *
845 * This routine sets the entire palette in the display controller.
846 * A pointer is provided to a 256 entry table of 32-bit X:R:G:B values.
847 *
848 * Restriction:
849 * Due to SC1200 Issue #748 (in Notes DB) this function should be called only
850 * when DCLK is active, i.e PLL is already powered up and genlock is not
851 * active.
852 *---------------------------------------------------------------------------
853 */
854#if GFX_DISPLAY_DYNAMIC
855int
856gu1_set_display_palette(unsigned long *palette)
857#else
858int
859gfx_set_display_palette(unsigned long *palette)
860#endif
861{
862    unsigned long data, i;
863
864    WRITE_REG32(DC_PAL_ADDRESS, 0);
865    if (palette) {
866        for (i = 0; i < 256; i++) {
867            /* CONVERT 24 BPP COLOR DATA TO 18 BPP COLOR DATA */
868            data = ((palette[i] >> 2) & 0x0003F) |
869                ((palette[i] >> 4) & 0x00FC0) | ((palette[i] >> 6) & 0x3F000);
870            WRITE_REG32(DC_PAL_DATA, data);
871        }
872    }
873    return (0);
874}
875
876/*---------------------------------------------------------------------------
877 * gfx_set_cursor_enable
878 *
879 * This routine enables or disables the hardware cursor.
880 *
881 * WARNING: The cusrsor start offset must be set by setting the cursor
882 * position before calling this routine to assure that memory reads do not
883 * go past the end of graphics memory (this can hang GXm).
884 *---------------------------------------------------------------------------
885 */
886#if GFX_DISPLAY_DYNAMIC
887void
888gu1_set_cursor_enable(int enable)
889#else
890void
891gfx_set_cursor_enable(int enable)
892#endif
893{
894    unsigned long unlock, gcfg;
895
896    /* SET OR CLEAR CURSOR ENABLE BIT */
897    unlock = READ_REG32(DC_UNLOCK);
898    gcfg = READ_REG32(DC_GENERAL_CFG);
899    if (enable)
900        gcfg |= DC_GCFG_CURE;
901    else
902        gcfg &= ~(DC_GCFG_CURE);
903
904    /* WRITE NEW REGISTER VALUE */
905    WRITE_REG32(DC_UNLOCK, DC_UNLOCK_VALUE);
906    WRITE_REG32(DC_GENERAL_CFG, gcfg);
907    WRITE_REG32(DC_UNLOCK, unlock);
908}
909
910/*---------------------------------------------------------------------------
911 * gfx_set_cursor_colors
912 *
913 * This routine sets the colors of the hardware cursor.
914 *
915 * Restriction:
916 * Due to SC1200 Issue #748 (in Notes DB) this function should be called only
917 * when DCLK is active, i.e PLL is already powered up.
918 *---------------------------------------------------------------------------
919 */
920#if GFX_DISPLAY_DYNAMIC
921void
922gu1_set_cursor_colors(unsigned long bkcolor, unsigned long fgcolor)
923#else
924void
925gfx_set_cursor_colors(unsigned long bkcolor, unsigned long fgcolor)
926#endif
927{
928    unsigned long value;
929
930    /* If genlock is enabled DCLK might be disabled in vertical blank. */
931    /* Due to SC1200 Issue #748 in Notes DB this would fail the cursor color settings */
932    /* So Wait for vertical blank to end */
933
934#if GFX_VIDEO_SC1200
935    if (gfx_test_timing_active())
936        while ((gfx_get_vline()) > gfx_get_vactive()) ;
937#endif
938    /* SET CURSOR COLORS */
939    WRITE_REG32(DC_PAL_ADDRESS, 0x100);
940    value = ((bkcolor & 0x000000FC) >> 2) |
941        ((bkcolor & 0x0000FC00) >> (2 + 8 - 6)) |
942        ((bkcolor & 0x00FC0000) >> (2 + 16 - 12));
943    WRITE_REG32(DC_PAL_DATA, value);
944    value = ((fgcolor & 0x000000FC) >> 2) |
945        ((fgcolor & 0x0000FC00) >> (2 + 8 - 6)) |
946        ((fgcolor & 0x00FC0000) >> (2 + 16 - 12));
947    WRITE_REG32(DC_PAL_DATA, value);
948}
949
950/*---------------------------------------------------------------------------
951 * gfx_set_cursor_position
952 *
953 * This routine sets the position of the hardware cusror.  The starting
954 * offset of the cursor buffer must be specified so that the routine can
955 * properly clip scanlines if the cursor is off the top of the screen.
956 *---------------------------------------------------------------------------
957 */
958#if GFX_DISPLAY_DYNAMIC
959void
960gu1_set_cursor_position(unsigned long memoffset,
961    unsigned short xpos, unsigned short ypos,
962    unsigned short xhotspot, unsigned short yhotspot)
963#else
964void
965gfx_set_cursor_position(unsigned long memoffset,
966    unsigned short xpos, unsigned short ypos,
967    unsigned short xhotspot, unsigned short yhotspot)
968#endif
969{
970    unsigned long unlock;
971
972    short x, y;
973    short xoffset = 0;
974    short yoffset = 0;
975
976    /* SUPPORT CURSOR IN EMULATED VGA MODES */
977    /* Timings are for twice the resolution */
978    if (gfx_pixel_double)
979        xpos <<= 1;
980
981    if (gfx_line_double)
982        ypos <<= 1;
983
984    x = (short)xpos - (short)xhotspot;
985    y = (short)ypos - (short)yhotspot;
986    if (x < -31)
987        return;
988
989    if (y < -31)
990        return;
991
992    if (x < 0) {
993        xoffset = -x;
994        x = 0;
995    }
996
997    if (y < 0) {
998        yoffset = -y;
999        y = 0;
1000    }
1001
1002    memoffset += (unsigned long)yoffset << 3;
1003
1004    if (PanelEnable) {
1005        if ((ModeWidth > PanelWidth) || (ModeHeight > PanelHeight)) {
1006            gfx_enable_panning(xpos, ypos);
1007            x = x - (short)panelLeft;
1008            y = y - (short)panelTop;
1009        }
1010    }
1011
1012    /* SET CURSOR POSITION */
1013    unlock = READ_REG32(DC_UNLOCK);
1014    WRITE_REG32(DC_UNLOCK, DC_UNLOCK_VALUE);
1015    WRITE_REG32(DC_CURS_ST_OFFSET, memoffset);
1016    WRITE_REG32(DC_CURSOR_X, (unsigned long)x |
1017        (((unsigned long)xoffset) << 11));
1018    WRITE_REG32(DC_CURSOR_Y, (unsigned long)y |
1019        (((unsigned long)yoffset) << 11));
1020    WRITE_REG32(DC_UNLOCK, unlock);
1021}
1022
1023/*---------------------------------------------------------------------------
1024 * gfx_set_cursor_shape32
1025 *
1026 * This routine loads 32x32 cursor data into the specified location in
1027 * graphics memory.
1028 *---------------------------------------------------------------------------
1029 */
1030#if GFX_DISPLAY_DYNAMIC
1031void
1032gu1_set_cursor_shape32(unsigned long memoffset,
1033    unsigned long *andmask, unsigned long *xormask)
1034#else
1035void
1036gfx_set_cursor_shape32(unsigned long memoffset,
1037    unsigned long *andmask, unsigned long *xormask)
1038#endif
1039{
1040    int i;
1041    unsigned long value;
1042
1043    for (i = 0; i < 32; i++) {
1044        /* CONVERT TO 16 BITS AND MASK, 16 BITS XOR MASK PER DWORD */
1045        value = (andmask[i] & 0xFFFF0000) | (xormask[i] >> 16);
1046        WRITE_FB32(memoffset, value);
1047        memoffset += 4;
1048        value = (andmask[i] << 16) | (xormask[i] & 0x0000FFFF);
1049        WRITE_FB32(memoffset, value);
1050        memoffset += 4;
1051    }
1052}
1053
1054/*---------------------------------------------------------------------------
1055 * gu1_enable_compression
1056 *
1057 * This is a private routine to this module (not exposed in the Durango API).
1058 * It enables display compression.
1059 *---------------------------------------------------------------------------
1060 */
1061void
1062gu1_enable_compression(void)
1063{
1064    int i;
1065    unsigned long unlock, gcfg, offset;
1066
1067    /* DO NOT ENABLE IF START ADDRESS IS NOT ZERO */
1068    offset = READ_REG32(DC_FB_ST_OFFSET) & 0x003FFFFF;
1069    if (offset != 0)
1070        return;
1071
1072    /* DO NOT ENABLE IF WE ARE WITHIN AN EMULATED VGA MODE */
1073    if (gfx_line_double || gfx_pixel_double)
1074        return;
1075
1076    /* SET GLOBAL INDICATOR */
1077    gfx_compression_active = 1;
1078
1079    /* CLEAR DIRTY/VALID BITS IN MEMORY CONTROLLER */
1080    /* Software is required to do this before enabling compression. */
1081    /* Don't want controller to think that old lines are still valid. */
1082    for (i = 0; i < 1024; i++) {
1083        WRITE_REG32(MC_DR_ADD, i);
1084        WRITE_REG32(MC_DR_ACC, 0);
1085    }
1086
1087    /* TURN ON COMPRESSION CONTROL BITS */
1088    unlock = READ_REG32(DC_UNLOCK);
1089    gcfg = READ_REG32(DC_GENERAL_CFG);
1090    gcfg |= DC_GCFG_CMPE | DC_GCFG_DECE;
1091    WRITE_REG32(DC_UNLOCK, DC_UNLOCK_VALUE);
1092    WRITE_REG32(DC_GENERAL_CFG, gcfg);
1093    WRITE_REG32(DC_UNLOCK, unlock);
1094}
1095
1096/*---------------------------------------------------------------------------
1097 * gu1_disable_compression
1098 *
1099 * This is a private routine to this module (not exposed in the Durango API).
1100 * It disables display compression.
1101 *---------------------------------------------------------------------------
1102 */
1103void
1104gu1_disable_compression(void)
1105{
1106    unsigned long unlock, gcfg;
1107
1108    /* SET GLOBAL INDICATOR */
1109    gfx_compression_active = 0;
1110
1111    /* TURN OFF COMPRESSION CONTROL BITS */
1112    unlock = READ_REG32(DC_UNLOCK);
1113    gcfg = READ_REG32(DC_GENERAL_CFG);
1114    gcfg &= ~(DC_GCFG_CMPE | DC_GCFG_DECE);
1115    WRITE_REG32(DC_UNLOCK, DC_UNLOCK_VALUE);
1116    WRITE_REG32(DC_GENERAL_CFG, gcfg);
1117    WRITE_REG32(DC_UNLOCK, unlock);
1118}
1119
1120/*---------------------------------------------------------------------------
1121 * gfx_set_compression_enable
1122 *
1123 * This routine enables or disables display compression.
1124 *---------------------------------------------------------------------------
1125 */
1126#if GFX_DISPLAY_DYNAMIC
1127int
1128gu1_set_compression_enable(int enable)
1129#else
1130int
1131gfx_set_compression_enable(int enable)
1132#endif
1133{
1134    /* SET GLOBAL VARIABLE FOR INTENDED STATE */
1135    /* Compression can only be enabled for non-zero start address values. */
1136    /* Keep state to enable compression on start address changes. */
1137    gfx_compression_enabled = enable;
1138    if (enable)
1139        gu1_enable_compression();
1140    else
1141        gu1_disable_compression();
1142
1143    return (0);
1144}
1145
1146/*---------------------------------------------------------------------------
1147 * gfx_set_compression_offset
1148 *
1149 * This routine sets the base offset for the compression buffer.
1150 *---------------------------------------------------------------------------
1151 */
1152#if GFX_DISPLAY_DYNAMIC
1153int
1154gu1_set_compression_offset(unsigned long offset)
1155#else
1156int
1157gfx_set_compression_offset(unsigned long offset)
1158#endif
1159{
1160    unsigned long lock;
1161
1162    /* MUST BE 16-BYTE ALIGNED FOR GXLV */
1163    if (offset & 0x0F)
1164        return (1);
1165
1166    /* SET REGISTER VALUE */
1167    lock = READ_REG32(DC_UNLOCK);
1168    WRITE_REG32(DC_UNLOCK, DC_UNLOCK_VALUE);
1169    WRITE_REG32(DC_CB_ST_OFFSET, offset);
1170    WRITE_REG32(DC_UNLOCK, lock);
1171    return (0);
1172}
1173
1174/*---------------------------------------------------------------------------
1175 * gfx_set_compression_pitch
1176 *
1177 * This routine sets the pitch, in bytes, of the compression buffer.
1178 *---------------------------------------------------------------------------
1179 */
1180#if GFX_DISPLAY_DYNAMIC
1181int
1182gu1_set_compression_pitch(unsigned short pitch)
1183#else
1184int
1185gfx_set_compression_pitch(unsigned short pitch)
1186#endif
1187{
1188    unsigned long lock, line_delta;
1189
1190    /* SET REGISTER VALUE */
1191    lock = READ_REG32(DC_UNLOCK);
1192    line_delta = READ_REG32(DC_LINE_DELTA) & 0xFF800FFF;
1193    line_delta |= ((unsigned long)pitch << 10l) & 0x007FF000;
1194    WRITE_REG32(DC_UNLOCK, DC_UNLOCK_VALUE);
1195    WRITE_REG32(DC_LINE_DELTA, line_delta);
1196    WRITE_REG32(DC_UNLOCK, lock);
1197    return (0);
1198}
1199
1200/*---------------------------------------------------------------------------
1201 * gfx_set_compression_size
1202 *
1203 * This routine sets the line size of the compression buffer, which is the
1204 * maximum number of bytes allowed to store a compressed line.
1205 *---------------------------------------------------------------------------
1206 */
1207#if GFX_DISPLAY_DYNAMIC
1208int
1209gu1_set_compression_size(unsigned short size)
1210#else
1211int
1212gfx_set_compression_size(unsigned short size)
1213#endif
1214{
1215    unsigned long lock, buf_size;
1216
1217    /* SUBTRACT 16 FROM SIZE                          */
1218    /* The display controller will actually write     */
1219    /* 2 extra QWords.  So, if we assume that "size"  */
1220    /* refers to the allocated size, we must subtract */
1221    /* 16 bytes.                                      */
1222    size -= 16;
1223
1224    /* SET REGISTER VALUE */
1225    lock = READ_REG32(DC_UNLOCK);
1226    buf_size = READ_REG32(DC_BUF_SIZE) & 0xFFFF01FF;
1227    buf_size |= (((size >> 2) + 1) & 0x7F) << 9;
1228    WRITE_REG32(DC_UNLOCK, DC_UNLOCK_VALUE);
1229    WRITE_REG32(DC_BUF_SIZE, buf_size);
1230    WRITE_REG32(DC_UNLOCK, lock);
1231    return (0);
1232}
1233
1234/*---------------------------------------------------------------------------
1235 * gfx_set_display_video_enable (PRIVATE ROUTINE - NOT PART OF API)
1236 *
1237 * This routine enables/disables video on GX.
1238 *---------------------------------------------------------------------------
1239 */
1240#if GFX_DISPLAY_DYNAMIC
1241void
1242gu1_set_display_video_enable(int enable)
1243#else
1244void
1245gfx_set_display_video_enable(int enable)
1246#endif
1247{
1248    unsigned long lock, gcfg, buf_size;
1249
1250    lock = READ_REG32(DC_UNLOCK);
1251    gcfg = READ_REG32(DC_GENERAL_CFG);
1252    buf_size = READ_REG32(DC_BUF_SIZE);
1253
1254    WRITE_REG32(DC_UNLOCK, DC_UNLOCK_VALUE);
1255
1256    vid_enabled = enable;
1257
1258    /* SET THE BUFFER SIZE TO A NON-ZERO VALUE ONLY WHEN */
1259    /* ENABLING VIDEO                                    */
1260    if (enable) {
1261        gcfg |= (DC_GCFG_VIDE | DC_GCFG_VRDY);
1262        WRITE_REG32(DC_GENERAL_CFG, gcfg);
1263
1264        WRITE_REG32(DC_BUF_SIZE, (buf_size & 0x0000FFFFl) | vid_buf_size);
1265    }
1266    /* CLEAR THE VIDEO BUFFER SIZE WHEN DISABLING VIDEO  */
1267    else {
1268        gcfg &= ~(DC_GCFG_VIDE);
1269        WRITE_REG32(DC_GENERAL_CFG, gcfg);
1270
1271        vid_buf_size = buf_size & 0xFFFF0000l;
1272        WRITE_REG32(DC_BUF_SIZE, buf_size & 0x0000FFFFl);
1273    }
1274
1275    WRITE_REG32(DC_UNLOCK, lock);
1276    return;
1277}
1278
1279/*---------------------------------------------------------------------------
1280 * gfx_set_display_video_size (PRIVATE ROUTINE - NOT PART OF API)
1281 *
1282 * This routine is called by "gfx_set_video_size".  It abstracts the
1283 * version of the display controller from the video overlay routines.
1284 *---------------------------------------------------------------------------
1285 */
1286#if GFX_DISPLAY_DYNAMIC
1287void
1288gu1_set_display_video_size(unsigned short width, unsigned short height)
1289#else
1290void
1291gfx_set_display_video_size(unsigned short width, unsigned short height)
1292#endif
1293{
1294    unsigned long lock, size, value;
1295
1296    size = (unsigned long)(width << 1) * (unsigned long)height;
1297
1298    /* STORE THE VIDEO BUFFER SIZE AS A GLOBAL */
1299    vid_buf_size = ((size + 63) >> 6) << 16;
1300
1301    lock = READ_REG32(DC_UNLOCK);
1302    WRITE_REG32(DC_UNLOCK, DC_UNLOCK_VALUE);
1303    value = READ_REG32(DC_BUF_SIZE) & 0x0000FFFF;
1304    value |= vid_buf_size;
1305    WRITE_REG32(DC_BUF_SIZE, value);
1306    WRITE_REG32(DC_UNLOCK, lock);
1307}
1308
1309/*---------------------------------------------------------------------------
1310 * gfx_set_display_video_offset (PRIVATE ROUTINE - NOT PART OF API)
1311 *
1312 * This routine is called by "gfx_set_video_offset".  It abstracts the
1313 * version of the display controller from the video overlay routines.
1314 *---------------------------------------------------------------------------
1315 */
1316#if GFX_DISPLAY_DYNAMIC
1317void
1318gu1_set_display_video_offset(unsigned long offset)
1319#else
1320void
1321gfx_set_display_video_offset(unsigned long offset)
1322#endif
1323{
1324    unsigned long lock;
1325
1326    lock = READ_REG32(DC_UNLOCK);
1327    WRITE_REG32(DC_UNLOCK, DC_UNLOCK_VALUE);
1328    offset &= 0x003FFFFF;
1329    WRITE_REG32(DC_VID_ST_OFFSET, offset);
1330    WRITE_REG32(DC_UNLOCK, lock);
1331}
1332
1333/*---------------------------------------------------------------------------
1334 * gfx_set_display_priority_high
1335 *
1336 * This routine controls the x-bus round robin arbitration mechanism.
1337 * When enable is TRUE, graphics pipeline requests and non-critical display
1338 * controller requests are arbitrated at the same priority as processor
1339 * requests. When FALSE processor requests are arbitrated at a higher priority
1340 *---------------------------------------------------------------------------
1341 */
1342#if GFX_DISPLAY_DYNAMIC
1343void
1344gu1_set_display_priority_high(int enable)
1345#else
1346void
1347gfx_set_display_priority_high(int enable)
1348#endif
1349{
1350    unsigned long lock, control;
1351
1352    lock = READ_REG32(DC_UNLOCK);
1353    control = READ_REG32(MC_MEM_CNTRL1);
1354    WRITE_REG32(DC_UNLOCK, DC_UNLOCK_VALUE);
1355    if (enable)
1356        control |= MC_XBUSARB;
1357    else
1358        control &= ~(MC_XBUSARB);
1359    WRITE_REG32(MC_MEM_CNTRL1, control);
1360    WRITE_REG32(DC_UNLOCK, lock);
1361    return;
1362}
1363
1364/*---------------------------------------------------------------------------
1365 * gfx_test_timing_active
1366 *---------------------------------------------------------------------------
1367 */
1368#if GFX_DISPLAY_DYNAMIC
1369int
1370gu1_test_timing_active(void)
1371#else
1372int
1373gfx_test_timing_active(void)
1374#endif
1375{
1376    if (READ_REG32(DC_TIMING_CFG) & DC_TCFG_TGEN)
1377        return (1);
1378    else
1379        return (0);
1380}
1381
1382/*---------------------------------------------------------------------------
1383 * gfx_test_vertical_active
1384 *---------------------------------------------------------------------------
1385 */
1386#if GFX_DISPLAY_DYNAMIC
1387int
1388gu1_test_vertical_active(void)
1389#else
1390int
1391gfx_test_vertical_active(void)
1392#endif
1393{
1394    if (READ_REG32(DC_TIMING_CFG) & DC_TCFG_VNA)
1395        return (0);
1396    else
1397        return (1);
1398}
1399
1400/*---------------------------------------------------------------------------
1401 * gfx_wait_vertical_blank
1402 *---------------------------------------------------------------------------
1403 */
1404#if GFX_DISPLAY_DYNAMIC
1405int
1406gu1_wait_vertical_blank(void)
1407#else
1408int
1409gfx_wait_vertical_blank(void)
1410#endif
1411{
1412    if (gfx_test_timing_active()) {
1413        while (!gfx_test_vertical_active()) ;
1414        while (gfx_test_vertical_active()) ;
1415    }
1416
1417    return (0);
1418}
1419
1420/*---------------------------------------------------------------------------
1421 * gfx_enable_panning
1422 *
1423 * This routine  enables the panning when the Mode is bigger than the panel
1424 * size.
1425 *---------------------------------------------------------------------------
1426 */
1427#if GFX_DISPLAY_DYNAMIC
1428void
1429gu1_enable_panning(int x, int y)
1430#else
1431void
1432gfx_enable_panning(int x, int y)
1433#endif
1434{
1435    unsigned long modeBytesPerPixel;
1436    unsigned long modeBytesPerScanline = 0;
1437    unsigned long startAddress = 0;
1438
1439    modeBytesPerPixel = (gbpp + 7) / 8;
1440    modeBytesPerScanline =
1441        (((ModeWidth + 1023) / 1024) * 1024) * modeBytesPerPixel;
1442
1443    /* TEST FOR NO-WORK */
1444    if (x >= DeltaX && (unsigned short)x < (PanelWidth + DeltaX) &&
1445        y >= DeltaY && (unsigned short)y < (PanelHeight + DeltaY))
1446        return;
1447
1448    /* ADJUST PANNING VARIABLES WHEN CURSOR EXCEEDS BOUNDARY       */
1449    /* Test the boundary conditions for each coordinate and update */
1450    /* all variables and the starting offset accordingly.          */
1451    if (x < DeltaX)
1452        DeltaX = x;
1453    else if ((unsigned short)x >= (DeltaX + PanelWidth))
1454        DeltaX = x - PanelWidth + 1;
1455
1456    if (y < DeltaY)
1457        DeltaY = y;
1458    else if ((unsigned short)y >= (DeltaY + PanelHeight))
1459        DeltaY = y - PanelHeight + 1;
1460
1461    /* CALCULATE THE START OFFSET */
1462    startAddress =
1463        (DeltaX * modeBytesPerPixel) + (DeltaY * modeBytesPerScanline);
1464
1465    gfx_set_display_offset(startAddress);
1466
1467    /* SET PANEL COORDINATES                    */
1468    /* Panel's x position must be DWORD aligned */
1469    panelTop = DeltaY;
1470    panelLeft = DeltaX * modeBytesPerPixel;
1471
1472    if (panelLeft & 3)
1473        panelLeft = (panelLeft & 0xFFFFFFFC) + 4;
1474
1475    panelLeft /= modeBytesPerPixel;
1476
1477}
1478
1479/*---------------------------------------------------------------------------
1480 * gfx_set_fixed_timings
1481 *---------------------------------------------------------------------------
1482 */
1483#if GFX_DISPLAY_DYNAMIC
1484int
1485gu1_set_fixed_timings(int panelResX, int panelResY, unsigned short width,
1486    unsigned short height, unsigned short bpp)
1487#else
1488int
1489gfx_set_fixed_timings(int panelResX, int panelResY, unsigned short width,
1490    unsigned short height, unsigned short bpp)
1491#endif
1492{
1493    unsigned int mode;
1494
1495    ModeWidth = width;
1496    ModeHeight = height;
1497    PanelWidth = (unsigned short)panelResX;
1498    PanelHeight = (unsigned short)panelResY;
1499    PanelEnable = 1;
1500
1501    /* LOOP THROUGH THE AVAILABLE MODES TO FIND A MATCH */
1502    for (mode = 0; mode < NUM_FIXED_TIMINGS_MODES; mode++) {
1503        if ((FixedParams[mode].xres == width) &&
1504            (FixedParams[mode].yres == height) &&
1505            (FixedParams[mode].panelresx == panelResX) &&
1506            (FixedParams[mode].panelresy == panelResY)) {
1507
1508            /* SET THE 92xx FOR THE SELECTED MODE */
1509            FIXEDTIMINGS *fmode = &FixedParams[mode];
1510
1511            gfx_set_display_timings(bpp, 3, fmode->hactive,
1512                fmode->hblankstart, fmode->hsyncstart, fmode->hsyncend,
1513                fmode->hblankend, fmode->htotal, fmode->vactive,
1514                fmode->vblankstart, fmode->vsyncstart, fmode->vsyncend,
1515                fmode->vblankend, fmode->vtotal, fmode->frequency);
1516
1517            return (1);
1518        }                              /* end if() */
1519    }                                  /* end for() */
1520
1521    return (-1);
1522}
1523
1524/*---------------------------------------------------------------------------
1525 * gfx_set_panel_present
1526 *---------------------------------------------------------------------------
1527 */
1528#if GFX_DISPLAY_DYNAMIC
1529int
1530gu1_set_panel_present(int panelResX, int panelResY, unsigned short width,
1531    unsigned short height, unsigned short bpp)
1532#else
1533int
1534gfx_set_panel_present(int panelResX, int panelResY, unsigned short width,
1535    unsigned short height, unsigned short bpp)
1536#endif
1537{
1538    /* SET VALID BPP         */
1539    /* 16BPP is the default. */
1540    if (bpp != 8 && bpp != 15 && bpp != 16)
1541        bpp = 16;
1542
1543    /* RECORD PANEL PARAMETERS */
1544    /* This routine does not touch any panel timings.  It is used when custom
1545     * panel settings are set up in advance by the BIOS or an application, but
1546     * the application still requires access to other panel functionality
1547     * provided by Durango (i.e. panning)
1548     * */
1549
1550    ModeWidth = width;
1551    ModeHeight = height;
1552    PanelWidth = (unsigned short)panelResX;
1553    PanelHeight = (unsigned short)panelResY;
1554    PanelEnable = 1;
1555    gbpp = bpp;
1556
1557    /* PROGRAM THE BPP IN THE DISPLAY CONTROLLER */
1558    gfx_set_display_bpp(bpp);
1559
1560    return (GFX_STATUS_OK);
1561}
1562
1563/*-----------------------------------------------------------------------*
1564 * THE FOLLOWING READ ROUTINES ARE ALWAYS INCLUDED:                      *
1565 * gfx_get_hsync_end, gfx_get_htotal, gfx_get_vsync_end, gfx_get_vtotal  *
1566 * are used by the video overlay routines.                               *
1567 *                                                                       *
1568 * gfx_get_vline and gfx_vactive are used to prevent an issue for the    *
1569 * SC1200.                                                               *
1570 *                                                                       *
1571 * The others are part of the Durango API.                               *
1572 *-----------------------------------------------------------------------*/
1573
1574/*---------------------------------------------------------------------------
1575 * gfx_get_display_pitch
1576 *
1577 * This routine returns the current pitch of the frame buffer, in bytes.
1578 *---------------------------------------------------------------------------
1579 */
1580#if GFX_DISPLAY_DYNAMIC
1581unsigned short
1582gu1_get_display_pitch(void)
1583#else
1584unsigned short
1585gfx_get_display_pitch(void)
1586#endif
1587{
1588    unsigned long value;
1589
1590    if (gfx_cpu_version == GFX_CPU_PYRAMID) {
1591        /* Pyramid update for 4KB line pitch */
1592        value = (READ_REG32(DC_LINE_DELTA) & 0x07FF) << 2;
1593    } else {
1594        value = (READ_REG32(DC_LINE_DELTA) & 0x03FF) << 2;
1595    }
1596
1597    return ((unsigned short)value);
1598}
1599
1600/*----------------------------------------------------------------------------
1601 * GFX_GET_DISPLAY_DETAILS
1602 *
1603 * This routine gets the specified display mode.
1604 *
1605 * Returns 1 if successful, 0 if mode could not be get.
1606 *----------------------------------------------------------------------------
1607 */
1608#if GFX_DISPLAY_DYNAMIC
1609int
1610gu1_get_display_details(unsigned int mode, int *xres, int *yres, int *hz)
1611#else
1612int
1613gfx_get_display_details(unsigned int mode, int *xres, int *yres, int *hz)
1614#endif
1615{
1616    if (mode < NUM_GX_DISPLAY_MODES) {
1617        if (DisplayParams[mode].flags & GFX_MODE_56HZ)
1618            *hz = 56;
1619        else if (DisplayParams[mode].flags & GFX_MODE_60HZ)
1620            *hz = 60;
1621        else if (DisplayParams[mode].flags & GFX_MODE_70HZ)
1622            *hz = 70;
1623        else if (DisplayParams[mode].flags & GFX_MODE_72HZ)
1624            *hz = 72;
1625        else if (DisplayParams[mode].flags & GFX_MODE_75HZ)
1626            *hz = 75;
1627        else if (DisplayParams[mode].flags & GFX_MODE_85HZ)
1628            *hz = 85;
1629
1630        *xres = DisplayParams[mode].hactive;
1631        *yres = DisplayParams[mode].vactive;
1632
1633        return (1);
1634    }
1635    return (0);
1636}
1637
1638/*----------------------------------------------------------------------------
1639 * GFX_GET_DISPLAY_MODE_COUNT
1640 *
1641 * Returns number of modes supported.
1642 *----------------------------------------------------------------------------
1643 */
1644#if GFX_DISPLAY_DYNAMIC
1645int
1646gu1_get_display_mode_count(void)
1647#else
1648int
1649gfx_get_display_mode_count(void)
1650#endif
1651{
1652    return (NUM_GX_DISPLAY_MODES);
1653}
1654
1655/*----------------------------------------------------------------------------
1656 * gfx_get_frame_buffer_line_size
1657 *
1658 * Returns the current frame buffer line size, in bytes
1659 *----------------------------------------------------------------------------
1660 */
1661#if GFX_DISPLAY_DYNAMIC
1662unsigned long
1663gu1_get_frame_buffer_line_size(void)
1664#else
1665unsigned long
1666gfx_get_frame_buffer_line_size(void)
1667#endif
1668{
1669    return ((READ_REG32(DC_BUF_SIZE) & 0x1FF) << 3);
1670}
1671
1672/*----------------------------------------------------------------------------
1673 * gfx_mode_frequency_supported
1674 *
1675 * This routine examines if the requested mode with pixel frequency is supported.
1676 *
1677 * Returns >0 if successful , <0 if freq. could not be found and matched.
1678 *----------------------------------------------------------------------------
1679 */
1680#if GFX_DISPLAY_DYNAMIC
1681int
1682gu1_mode_frequency_supported(int xres, int yres, int bpp,
1683    unsigned long frequency)
1684#else
1685int
1686gfx_mode_frequency_supported(int xres, int yres, int bpp,
1687    unsigned long frequency)
1688#endif
1689{
1690    unsigned int index;
1691    unsigned long value;
1692    unsigned long bpp_flag = 0;
1693
1694    bpp_flag = GFX_MODE_8BPP;
1695    if (bpp > 8)
1696        bpp_flag = GFX_MODE_16BPP;
1697
1698    for (index = 0; index < NUM_GX_DISPLAY_MODES; index++) {
1699        if ((DisplayParams[index].hactive == (unsigned short)xres) &&
1700            (DisplayParams[index].vactive == (unsigned short)yres) &&
1701            (DisplayParams[index].flags & bpp_flag) &&
1702            (DisplayParams[index].frequency == frequency)) {
1703            int hz = 0;
1704
1705            value = DisplayParams[index].flags;
1706
1707            if (value & GFX_MODE_56HZ)
1708                hz = 56;
1709            else if (value & GFX_MODE_60HZ)
1710                hz = 60;
1711            else if (value & GFX_MODE_70HZ)
1712                hz = 70;
1713            else if (value & GFX_MODE_72HZ)
1714                hz = 72;
1715            else if (value & GFX_MODE_75HZ)
1716                hz = 75;
1717            else if (value & GFX_MODE_85HZ)
1718                hz = 85;
1719
1720            return (hz);
1721        }
1722    }
1723    return (-1);
1724}
1725
1726/*----------------------------------------------------------------------------
1727 * gfx_refreshrate_from_frequency
1728 *
1729 * This routine maps the frequency to close match refresh rate
1730 *----------------------------------------------------------------------------
1731 */
1732#if GFX_DISPLAY_DYNAMIC
1733int
1734gu1_get_refreshrate_from_frequency(int xres, int yres, int bpp, int *hz,
1735    unsigned long frequency)
1736#else
1737int
1738gfx_get_refreshrate_from_frequency(int xres, int yres, int bpp, int *hz,
1739    unsigned long frequency)
1740#endif
1741{
1742    unsigned int index, closematch = 0;
1743    unsigned long value;
1744    unsigned long bpp_flag = 0;
1745    long min, diff;
1746
1747    *hz = 60;
1748
1749    bpp_flag = GFX_MODE_8BPP;
1750    if (bpp > 8)
1751        bpp_flag = GFX_MODE_16BPP;
1752
1753    /* FIND THE REGISTER VALUES FOR THE DESIRED FREQUENCY */
1754    /* Search the table for the closest frequency (16.16 format). */
1755    min = 0x7fffffff;
1756    for (index = 0; index < NUM_GX_DISPLAY_MODES; index++) {
1757        if ((DisplayParams[index].htotal == (unsigned short)xres) &&
1758            (DisplayParams[index].vtotal == (unsigned short)yres) &&
1759            (DisplayParams[index].flags & bpp_flag)) {
1760            diff = (long)frequency - (long)DisplayParams[index].frequency;
1761            if (diff < 0)
1762                diff = -diff;
1763
1764            if (diff < min) {
1765                min = diff;
1766                closematch = index;
1767            }
1768        }
1769    }
1770
1771    value = DisplayParams[closematch].flags;
1772
1773    if (value & GFX_MODE_56HZ)
1774        *hz = 56;
1775    else if (value & GFX_MODE_60HZ)
1776        *hz = 60;
1777    else if (value & GFX_MODE_70HZ)
1778        *hz = 70;
1779    else if (value & GFX_MODE_72HZ)
1780        *hz = 72;
1781    else if (value & GFX_MODE_75HZ)
1782        *hz = 75;
1783    else if (value & GFX_MODE_85HZ)
1784        *hz = 85;
1785
1786    return (1);
1787}
1788
1789/*----------------------------------------------------------------------------
1790 * gfx_refreshrate_from_mode
1791 *
1792 * This routine is identical to the gfx_get_refreshrate_from_frequency,
1793 * except that the active timing values are compared instead of the total
1794 * values.  Some modes (such as 70Hz and 72Hz) may be confused in this routine
1795 *----------------------------------------------------------------------------
1796 */
1797#if GFX_DISPLAY_DYNAMIC
1798int
1799gu1_get_refreshrate_from_mode(int xres, int yres, int bpp, int *hz,
1800    unsigned long frequency)
1801#else
1802int
1803gfx_get_refreshrate_from_mode(int xres, int yres, int bpp, int *hz,
1804    unsigned long frequency)
1805#endif
1806{
1807    unsigned int index, closematch = 0;
1808    unsigned long value;
1809    unsigned long bpp_flag = 0;
1810    long min, diff;
1811
1812    *hz = 60;
1813
1814    bpp_flag = GFX_MODE_8BPP;
1815    if (bpp > 8)
1816        bpp_flag = GFX_MODE_16BPP;
1817
1818    /* FIND THE REGISTER VALUES FOR THE DESIRED FREQUENCY */
1819    /* Search the table for the closest frequency (16.16 format). */
1820    min = 0x7fffffff;
1821    for (index = 0; index < NUM_GX_DISPLAY_MODES; index++) {
1822        if ((DisplayParams[index].hactive == (unsigned short)xres) &&
1823            (DisplayParams[index].vactive == (unsigned short)yres) &&
1824            (DisplayParams[index].flags & bpp_flag)) {
1825            diff = (long)frequency - (long)DisplayParams[index].frequency;
1826            if (diff < 0)
1827                diff = -diff;
1828
1829            if (diff < min) {
1830                min = diff;
1831                closematch = index;
1832            }
1833        }
1834    }
1835
1836    value = DisplayParams[closematch].flags;
1837
1838    if (value & GFX_MODE_56HZ)
1839        *hz = 56;
1840    else if (value & GFX_MODE_60HZ)
1841        *hz = 60;
1842    else if (value & GFX_MODE_70HZ)
1843        *hz = 70;
1844    else if (value & GFX_MODE_72HZ)
1845        *hz = 72;
1846    else if (value & GFX_MODE_75HZ)
1847        *hz = 75;
1848    else if (value & GFX_MODE_85HZ)
1849        *hz = 85;
1850
1851    return (1);
1852}
1853
1854/*----------------------------------------------------------------------------
1855 * gfx_get_frequency_from_refreshrate
1856 *
1857 * This routine maps the refresh rate to the closest matching PLL frequency.
1858 *----------------------------------------------------------------------------
1859 */
1860#if GFX_DISPLAY_DYNAMIC
1861int
1862gu1_get_frequency_from_refreshrate(int xres, int yres, int bpp, int hz,
1863    int *frequency)
1864#else
1865int
1866gfx_get_frequency_from_refreshrate(int xres, int yres, int bpp, int hz,
1867    int *frequency)
1868#endif
1869{
1870    unsigned int index;
1871    int retval = -1;
1872    unsigned long hz_flag = 0;
1873    unsigned long bpp_flag = 0;
1874
1875    *frequency = 0;
1876
1877    if (hz == 56)
1878        hz_flag = GFX_MODE_56HZ;
1879    else if (hz == 60)
1880        hz_flag = GFX_MODE_60HZ;
1881    else if (hz == 70)
1882        hz_flag = GFX_MODE_70HZ;
1883    else if (hz == 72)
1884        hz_flag = GFX_MODE_72HZ;
1885    else if (hz == 75)
1886        hz_flag = GFX_MODE_75HZ;
1887    else if (hz == 85)
1888        hz_flag = GFX_MODE_85HZ;
1889
1890    bpp_flag = GFX_MODE_8BPP;
1891    if (bpp > 8)
1892        bpp_flag = GFX_MODE_16BPP;
1893
1894    /* FIND THE REGISTER VALUES FOR THE DESIRED FREQUENCY */
1895
1896    for (index = 0; index < NUM_GX_DISPLAY_MODES; index++) {
1897        if ((DisplayParams[index].hactive == (unsigned short)xres) &&
1898            (DisplayParams[index].vactive == (unsigned short)yres) &&
1899            (DisplayParams[index].flags & bpp_flag) &&
1900            (DisplayParams[index].flags & hz_flag)) {
1901            *frequency = DisplayParams[index].frequency;
1902            retval = 1;
1903        }
1904    }
1905    return retval;
1906}
1907
1908/*---------------------------------------------------------------------------
1909 * gfx_get_max_supported_pixel_clock
1910 *
1911 * This routine returns the maximum recommended speed for the pixel clock.  The
1912 * return value is an integer of the format xxxyyy, where xxx.yyy is the maximum
1913 * floating point pixel clock speed.
1914 *---------------------------------------------------------------------------
1915 */
1916#if GFX_DISPLAY_DYNAMIC
1917unsigned long
1918gu1_get_max_supported_pixel_clock(void)
1919#else
1920unsigned long
1921gfx_get_max_supported_pixel_clock(void)
1922#endif
1923{
1924    /* ALL CHIPS CAN HANDLE 1280X1024@85HZ - 157.5 MHz */
1925    return 157500;
1926}
1927
1928/*----------------------------------------------------------------------------
1929 * gfx_get_display_mode
1930 *
1931 * This routine gets the specified display mode.
1932 *
1933 * Returns: >0 if successful and mode returned, <0 if mode could not be found.
1934 *----------------------------------------------------------------------------
1935 */
1936#if GFX_DISPLAY_DYNAMIC
1937int
1938gu1_get_display_mode(int *xres, int *yres, int *bpp, int *hz)
1939#else
1940int
1941gfx_get_display_mode(int *xres, int *yres, int *bpp, int *hz)
1942#endif
1943{
1944    unsigned int mode = 0;
1945    unsigned long pll_freq = 0, bpp_flag = 0;
1946
1947    *xres = gfx_get_hactive();
1948    *yres = gfx_get_vactive();
1949    *bpp = gfx_get_display_bpp();
1950    pll_freq = gfx_get_clock_frequency();
1951
1952    /* SUPPORT EMULATED VGA MODES */
1953    if (gfx_pixel_double)
1954        *xres >>= 1;
1955
1956    if (gfx_line_double)
1957        *yres >>= 1;
1958
1959    /* SET BPP FLAGS TO LIMIT MODE SELECTION */
1960    bpp_flag = GFX_MODE_8BPP;
1961    if (*bpp > 8)
1962        bpp_flag = GFX_MODE_16BPP;
1963
1964    for (mode = 0; mode < NUM_GX_DISPLAY_MODES; mode++) {
1965        if ((DisplayParams[mode].hactive == (unsigned short)*xres) &&
1966            (DisplayParams[mode].vactive == (unsigned short)*yres) &&
1967            (DisplayParams[mode].frequency == pll_freq) &&
1968            (DisplayParams[mode].flags & bpp_flag)) {
1969
1970            pll_freq = DisplayParams[mode].flags;
1971
1972            if (pll_freq & GFX_MODE_56HZ)
1973                *hz = 56;
1974            else if (pll_freq & GFX_MODE_60HZ)
1975                *hz = 60;
1976            else if (pll_freq & GFX_MODE_70HZ)
1977                *hz = 70;
1978            else if (pll_freq & GFX_MODE_72HZ)
1979                *hz = 72;
1980            else if (pll_freq & GFX_MODE_75HZ)
1981                *hz = 75;
1982            else if (pll_freq & GFX_MODE_85HZ)
1983                *hz = 85;
1984
1985            return (1);
1986        }
1987    }
1988    return (-1);
1989}
1990
1991/*---------------------------------------------------------------------------
1992 * gfx_get_hactive
1993 *---------------------------------------------------------------------------
1994 */
1995#if GFX_DISPLAY_DYNAMIC
1996unsigned short
1997gu1_get_hactive(void)
1998#else
1999unsigned short
2000gfx_get_hactive(void)
2001#endif
2002{
2003    return ((unsigned short)((READ_REG32(DC_H_TIMING_1) & 0x07F8) + 8));
2004}
2005
2006/*---------------------------------------------------------------------------
2007 * gfx_get_hsync_start
2008 *---------------------------------------------------------------------------
2009 */
2010#if GFX_DISPLAY_DYNAMIC
2011unsigned short
2012gu1_get_hsync_start(void)
2013#else
2014unsigned short
2015gfx_get_hsync_start(void)
2016#endif
2017{
2018    return ((unsigned short)((READ_REG32(DC_H_TIMING_3) & 0x07F8) + 8));
2019}
2020
2021/*---------------------------------------------------------------------------
2022 * gfx_get_hsync_end
2023 *---------------------------------------------------------------------------
2024 */
2025#if GFX_DISPLAY_DYNAMIC
2026unsigned short
2027gu1_get_hsync_end(void)
2028#else
2029unsigned short
2030gfx_get_hsync_end(void)
2031#endif
2032{
2033    return ((unsigned short)(((READ_REG32(DC_H_TIMING_3) >> 16) & 0x07F8) +
2034            8));
2035}
2036
2037/*---------------------------------------------------------------------------
2038 * gfx_get_htotal
2039 *---------------------------------------------------------------------------
2040 */
2041#if GFX_DISPLAY_DYNAMIC
2042unsigned short
2043gu1_get_htotal(void)
2044#else
2045unsigned short
2046gfx_get_htotal(void)
2047#endif
2048{
2049    return ((unsigned short)(((READ_REG32(DC_H_TIMING_1) >> 16) & 0x07F8) +
2050            8));
2051}
2052
2053/*---------------------------------------------------------------------------
2054 * gfx_get_vactive
2055 *---------------------------------------------------------------------------
2056 */
2057#if GFX_DISPLAY_DYNAMIC
2058unsigned short
2059gu1_get_vactive(void)
2060#else
2061unsigned short
2062gfx_get_vactive(void)
2063#endif
2064{
2065    return ((unsigned short)((READ_REG32(DC_V_TIMING_1) & 0x07FF) + 1));
2066}
2067
2068/*---------------------------------------------------------------------------
2069 * gfx_get_vsync_end
2070 *---------------------------------------------------------------------------
2071 */
2072#if GFX_DISPLAY_DYNAMIC
2073unsigned short
2074gu1_get_vsync_end(void)
2075#else
2076unsigned short
2077gfx_get_vsync_end(void)
2078#endif
2079{
2080    return ((unsigned short)(((READ_REG32(DC_V_TIMING_3) >> 16) & 0x07FF) +
2081            1));
2082}
2083
2084/*---------------------------------------------------------------------------
2085 * gfx_get_vtotal
2086 *---------------------------------------------------------------------------
2087 */
2088#if GFX_DISPLAY_DYNAMIC
2089unsigned short
2090gu1_get_vtotal(void)
2091#else
2092unsigned short
2093gfx_get_vtotal(void)
2094#endif
2095{
2096    return ((unsigned short)(((READ_REG32(DC_V_TIMING_1) >> 16) & 0x07FF) +
2097            1));
2098}
2099
2100/*-----------------------------------------------------------------------------
2101 * gfx_get_display_bpp
2102 *
2103 * This routine returns the current color depth of the active display.
2104 *-----------------------------------------------------------------------------
2105 */
2106#if GFX_DISPLAY_DYNAMIC
2107unsigned short
2108gu1_get_display_bpp(void)
2109#else
2110unsigned short
2111gfx_get_display_bpp(void)
2112#endif
2113{
2114    switch (READ_REG32(DC_OUTPUT_CFG) & 3) {
2115    case 0:
2116        return (16);
2117    case 2:
2118        return (15);
2119    }
2120    return (8);
2121}
2122
2123/*---------------------------------------------------------------------------
2124 * gfx_get_vline
2125 *---------------------------------------------------------------------------
2126 */
2127#if GFX_DISPLAY_DYNAMIC
2128unsigned short
2129gu1_get_vline(void)
2130#else
2131unsigned short
2132gfx_get_vline(void)
2133#endif
2134{
2135    unsigned short current_scan_line;
2136
2137    /* Read similar value twice to ensure that the value is not transitioning */
2138    do {
2139        current_scan_line =
2140            (unsigned short)READ_REG32(DC_V_LINE_CNT) & 0x07FF;
2141    } while (current_scan_line !=
2142        (unsigned short)(READ_REG32(DC_V_LINE_CNT) & 0x07FF));
2143
2144    return (current_scan_line);
2145}
2146
2147/*-----------------------------------------------------------------------------
2148 * gfx_get_display_offset
2149 *-----------------------------------------------------------------------------
2150 */
2151#if GFX_DISPLAY_DYNAMIC
2152unsigned long
2153gu1_get_display_offset(void)
2154#else
2155unsigned long
2156gfx_get_display_offset(void)
2157#endif
2158{
2159    return (READ_REG32(DC_FB_ST_OFFSET) & 0x003FFFFF);
2160}
2161
2162/*-----------------------------------------------------------------------------
2163 * gfx_get_cursor_offset
2164 *-----------------------------------------------------------------------------
2165 */
2166#if GFX_DISPLAY_DYNAMIC
2167unsigned long
2168gu1_get_cursor_offset(void)
2169#else
2170unsigned long
2171gfx_get_cursor_offset(void)
2172#endif
2173{
2174    return (READ_REG32(DC_CURS_ST_OFFSET) & 0x003FFFFF);
2175}
2176
2177#if GFX_READ_ROUTINES
2178
2179/*************************************************************/
2180/*  READ ROUTINES  |  INCLUDED FOR DIAGNOSTIC PURPOSES ONLY  */
2181/*************************************************************/
2182
2183/*---------------------------------------------------------------------------
2184 * gfx_get_hblank_start
2185 *---------------------------------------------------------------------------
2186 */
2187#if GFX_DISPLAY_DYNAMIC
2188unsigned short
2189gu1_get_hblank_start(void)
2190#else
2191unsigned short
2192gfx_get_hblank_start(void)
2193#endif
2194{
2195    return ((unsigned short)((READ_REG32(DC_H_TIMING_2) & 0x07F8) + 8));
2196}
2197
2198/*---------------------------------------------------------------------------
2199 * gfx_get_hblank_end
2200 *---------------------------------------------------------------------------
2201 */
2202#if GFX_DISPLAY_DYNAMIC
2203unsigned short
2204gu1_get_hblank_end(void)
2205#else
2206unsigned short
2207gfx_get_hblank_end(void)
2208#endif
2209{
2210    return ((unsigned short)(((READ_REG32(DC_H_TIMING_2) >> 16) & 0x07F8) +
2211            8));
2212}
2213
2214/*---------------------------------------------------------------------------
2215 * gfx_get_vblank_start
2216 *---------------------------------------------------------------------------
2217 */
2218#if GFX_DISPLAY_DYNAMIC
2219unsigned short
2220gu1_get_vblank_start(void)
2221#else
2222unsigned short
2223gfx_get_vblank_start(void)
2224#endif
2225{
2226    return ((unsigned short)((READ_REG32(DC_V_TIMING_2) & 0x07FF) + 1));
2227}
2228
2229/*---------------------------------------------------------------------------
2230 * gfx_get_vsync_start
2231 *---------------------------------------------------------------------------
2232 */
2233#if GFX_DISPLAY_DYNAMIC
2234unsigned short
2235gu1_get_vsync_start(void)
2236#else
2237unsigned short
2238gfx_get_vsync_start(void)
2239#endif
2240{
2241    return ((unsigned short)((READ_REG32(DC_V_TIMING_3) & 0x07FF) + 1));
2242}
2243
2244/*---------------------------------------------------------------------------
2245 * gfx_get_vblank_end
2246 *---------------------------------------------------------------------------
2247 */
2248#if GFX_DISPLAY_DYNAMIC
2249unsigned short
2250gu1_get_vblank_end(void)
2251#else
2252unsigned short
2253gfx_get_vblank_end(void)
2254#endif
2255{
2256    return ((unsigned short)(((READ_REG32(DC_V_TIMING_2) >> 16) & 0x07FF) +
2257            1));
2258}
2259
2260/*-----------------------------------------------------------------------------
2261 * gfx_get_display_palette_entry
2262 *-----------------------------------------------------------------------------
2263 */
2264#if GFX_DISPLAY_DYNAMIC
2265int
2266gu1_get_display_palette_entry(unsigned long index, unsigned long *palette)
2267#else
2268int
2269gfx_get_display_palette_entry(unsigned long index, unsigned long *palette)
2270#endif
2271{
2272    unsigned long data;
2273
2274    if (index > 0xFF)
2275        return GFX_STATUS_BAD_PARAMETER;
2276
2277    WRITE_REG32(DC_PAL_ADDRESS, index);
2278    data = READ_REG32(DC_PAL_DATA);
2279    data = ((data << 2) & 0x000000FC) |
2280        ((data << 4) & 0x0000FC00) | ((data << 6) & 0x00FC0000);
2281
2282    *palette = data;
2283    return 0;
2284}
2285
2286/*-----------------------------------------------------------------------------
2287 * gfx_get_display_palette
2288 *-----------------------------------------------------------------------------
2289 */
2290#if GFX_DISPLAY_DYNAMIC
2291void
2292gu1_get_display_palette(unsigned long *palette)
2293#else
2294void
2295gfx_get_display_palette(unsigned long *palette)
2296#endif
2297{
2298    unsigned long i, data;
2299
2300    WRITE_REG32(DC_PAL_ADDRESS, 0);
2301    for (i = 0; i < 256; i++) {
2302        data = READ_REG32(DC_PAL_DATA);
2303        data = ((data << 2) & 0x000000FC) |
2304            ((data << 4) & 0x0000FC00) | ((data << 6) & 0x00FC0000);
2305        palette[i] = data;
2306    }
2307}
2308
2309/*-----------------------------------------------------------------------------
2310 * gfx_get_cursor_enable
2311 *-----------------------------------------------------------------------------
2312 */
2313#if GFX_DISPLAY_DYNAMIC
2314unsigned long
2315gu1_get_cursor_enable(void)
2316#else
2317unsigned long
2318gfx_get_cursor_enable(void)
2319#endif
2320{
2321    return (READ_REG32(DC_GENERAL_CFG) & DC_GCFG_CURE);
2322}
2323
2324/*-----------------------------------------------------------------------------
2325 * gfx_get_cursor_position
2326 *-----------------------------------------------------------------------------
2327 */
2328#if GFX_DISPLAY_DYNAMIC
2329unsigned long
2330gu1_get_cursor_position(void)
2331#else
2332unsigned long
2333gfx_get_cursor_position(void)
2334#endif
2335{
2336    return ((READ_REG32(DC_CURSOR_X) & 0x07FF) |
2337        ((READ_REG32(DC_CURSOR_Y) << 16) & 0x03FF0000));
2338}
2339
2340/*-----------------------------------------------------------------------------
2341 * gfx_get_cursor_clip
2342 *-----------------------------------------------------------------------------
2343 */
2344#if GFX_DISPLAY_DYNAMIC
2345unsigned long
2346gu1_get_cursor_clip(void)
2347#else
2348unsigned long
2349gfx_get_cursor_clip(void)
2350#endif
2351{
2352    return (((READ_REG32(DC_CURSOR_X) >> 11) & 0x01F) |
2353        ((READ_REG32(DC_CURSOR_Y) << 5) & 0x1F0000));
2354}
2355
2356/*-----------------------------------------------------------------------------
2357 * gfx_get_cursor_color
2358 *-----------------------------------------------------------------------------
2359 */
2360#if GFX_DISPLAY_DYNAMIC
2361unsigned long
2362gu1_get_cursor_color(int color)
2363#else
2364unsigned long
2365gfx_get_cursor_color(int color)
2366#endif
2367{
2368    unsigned long data;
2369
2370    if (color) {
2371        WRITE_REG32(DC_PAL_ADDRESS, 0x101);
2372    } else {
2373        WRITE_REG32(DC_PAL_ADDRESS, 0x100);
2374    }
2375    data = READ_REG32(DC_PAL_DATA);
2376    data = ((data << 6) & 0x00FC0000) |
2377        ((data << 4) & 0x0000FC00) | ((data << 2) & 0x000000FC);
2378    return (data);
2379}
2380
2381/*-----------------------------------------------------------------------------
2382 * gfx_get_compression_enable
2383 *-----------------------------------------------------------------------------
2384 */
2385#if GFX_DISPLAY_DYNAMIC
2386int
2387gu1_get_compression_enable(void)
2388#else
2389int
2390gfx_get_compression_enable(void)
2391#endif
2392{
2393    unsigned long gcfg;
2394
2395    gcfg = READ_REG32(DC_GENERAL_CFG);
2396    if (gcfg & DC_GCFG_CMPE)
2397        return (1);
2398    else
2399        return (0);
2400}
2401
2402/*-----------------------------------------------------------------------------
2403 * gfx_get_compression_offset
2404 *-----------------------------------------------------------------------------
2405 */
2406#if GFX_DISPLAY_DYNAMIC
2407unsigned long
2408gu1_get_compression_offset(void)
2409#else
2410unsigned long
2411gfx_get_compression_offset(void)
2412#endif
2413{
2414    unsigned long offset;
2415
2416    offset = READ_REG32(DC_CB_ST_OFFSET) & 0x003FFFFF;
2417    return (offset);
2418}
2419
2420/*-----------------------------------------------------------------------------
2421 * gfx_get_compression_pitch
2422 *-----------------------------------------------------------------------------
2423 */
2424#if GFX_DISPLAY_DYNAMIC
2425unsigned short
2426gu1_get_compression_pitch(void)
2427#else
2428unsigned short
2429gfx_get_compression_pitch(void)
2430#endif
2431{
2432    unsigned short pitch;
2433
2434    pitch = (unsigned short)(READ_REG32(DC_LINE_DELTA) >> 12) & 0x03FF;
2435    return (pitch << 2);
2436}
2437
2438/*-----------------------------------------------------------------------------
2439 * gfx_get_compression_size
2440 *-----------------------------------------------------------------------------
2441 */
2442#if GFX_DISPLAY_DYNAMIC
2443unsigned short
2444gu1_get_compression_size(void)
2445#else
2446unsigned short
2447gfx_get_compression_size(void)
2448#endif
2449{
2450    unsigned short size;
2451
2452    size = (unsigned short)((READ_REG32(DC_BUF_SIZE) >> 9) & 0x7F) - 1;
2453    return ((size << 2) + 16);
2454}
2455
2456/*-----------------------------------------------------------------------------
2457 * gfx_get_valid_bit
2458 *-----------------------------------------------------------------------------
2459 */
2460#if GFX_DISPLAY_DYNAMIC
2461int
2462gu1_get_valid_bit(int line)
2463#else
2464int
2465gfx_get_valid_bit(int line)
2466#endif
2467{
2468    int valid;
2469
2470    WRITE_REG32(MC_DR_ADD, line);
2471    valid = (int)READ_REG32(MC_DR_ACC) & 1;
2472    return (valid);
2473}
2474
2475/*---------------------------------------------------------------------------
2476 * gfx_get_display_video_offset (PRIVATE ROUTINE - NOT PART OF API)
2477 *
2478 * This routine is called by "gfx_get_video_offset".  It abstracts the
2479 * version of the display controller from the video overlay routines.
2480 *---------------------------------------------------------------------------
2481 */
2482#if GFX_DISPLAY_DYNAMIC
2483unsigned long
2484gu1_get_display_video_offset(void)
2485#else
2486unsigned long
2487gfx_get_display_video_offset(void)
2488#endif
2489{
2490    return (READ_REG32(DC_VID_ST_OFFSET) & 0x003FFFFF);
2491}
2492
2493/*---------------------------------------------------------------------------
2494 * gfx_get_display_video_size (PRIVATE ROUTINE - NOT PART OF API)
2495 *
2496 * This routine is called by "gfx_get_video_size".  It abstracts the
2497 * version of the display controller from the video overlay routines.
2498 *---------------------------------------------------------------------------
2499 */
2500#if GFX_DISPLAY_DYNAMIC
2501unsigned long
2502gu1_get_display_video_size(void)
2503#else
2504unsigned long
2505gfx_get_display_video_size(void)
2506#endif
2507{
2508    /* RETURN TOTAL SIZE, IN BYTES */
2509    return ((READ_REG32(DC_BUF_SIZE) >> 10) & 0x000FFFC0);
2510}
2511
2512/*-----------------------------------------------------------------------------
2513 * gfx_get_display_priority_high
2514 *-----------------------------------------------------------------------------
2515 */
2516#if GFX_DISPLAY_DYNAMIC
2517int
2518gu1_get_display_priority_high(void)
2519#else
2520int
2521gfx_get_display_priority_high(void)
2522#endif
2523{
2524    if (READ_REG32(MC_MEM_CNTRL1) & MC_XBUSARB)
2525        return (1);
2526    else
2527        return (0);
2528}
2529
2530#endif /* GFX_READ_ROUTINES */
2531
2532/* END OF FILE */
2533