atimode.c revision 1b12faf6
1/*
2 * Copyright 2000 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of Marc Aurele La France not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission.  Marc Aurele La France makes no representations
11 * about the suitability of this software for any purpose.  It is provided
12 * "as-is" without express or implied warranty.
13 *
14 * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO
16 * EVENT SHALL MARC AURELE LA FRANCE BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20 * PERFORMANCE OF THIS SOFTWARE.
21 */
22
23#ifdef HAVE_CONFIG_H
24#include "config.h"
25#endif
26
27#include <string.h>
28
29#include "ati.h"
30#include "atichip.h"
31#include "atidac.h"
32#include "atidsp.h"
33#include "atimach64.h"
34#include "atimach64io.h"
35#include "atimode.h"
36#include "atiprint.h"
37#include "atirgb514.h"
38#include "ativga.h"
39#include "atiwonder.h"
40#include "atiwonderio.h"
41
42#ifdef TV_OUT
43
44#include "vbe.h"
45
46#endif /* TV_OUT */
47
48#ifndef AVOID_CPIO
49
50/*
51 * ATICopyVGAMemory --
52 *
53 * This function is called to copy one or all banks of a VGA plane.
54 */
55static void
56ATICopyVGAMemory
57(
58    ATIPtr   pATI,
59    ATIHWPtr pATIHW,
60    pointer  *saveptr,
61    pointer  *from,
62    pointer  *to
63)
64{
65    unsigned int iBank;
66
67    for (iBank = 0;  iBank < pATIHW->nBank;  iBank++)
68    {
69        (*pATIHW->SetBank)(pATI, iBank);
70        (void)memcpy(*to, *from, 0x00010000U);
71        *saveptr = (char *)(*saveptr) + 0x00010000U;
72    }
73}
74
75/*
76 * ATISwap --
77 *
78 * This function saves/restores video memory contents during video mode
79 * switches.
80 */
81static void
82ATISwap
83(
84    int      iScreen,
85    ATIPtr   pATI,
86    ATIHWPtr pATIHW,
87    Bool     ToFB
88)
89{
90    pointer save, *from, *to;
91    unsigned int iPlane = 0, PlaneMask = 1;
92    CARD8 seq2, seq4, gra1, gra3, gra4, gra5, gra6, gra8;
93
94    /*
95     * This is only done for non-accelerator modes.  If the video state on
96     * server entry was an accelerator mode, the application that relinquished
97     * the console had better do the Right Thing (tm) anyway by saving and
98     * restoring its own video memory contents.
99     */
100    if (pATIHW->crtc != ATI_CRTC_VGA)
101        return;
102
103    if (ToFB)
104    {
105        if (!pATIHW->frame_buffer)
106            return;
107
108        from = &save;
109        to = &pATI->pBank;
110    }
111    else
112    {
113        /* Allocate the memory */
114        if (!pATIHW->frame_buffer)
115        {
116            pATIHW->frame_buffer =
117                (pointer)malloc(pATIHW->nBank * pATIHW->nPlane * 0x00010000U);
118            if (!pATIHW->frame_buffer)
119            {
120                xf86DrvMsg(iScreen, X_WARNING,
121                    "Temporary frame buffer could not be allocated.\n");
122                return;
123            }
124        }
125
126        from = &pATI->pBank;
127        to = &save;
128    }
129
130    /* Turn off screen */
131    ATIVGASaveScreen(pATI, SCREEN_SAVER_ON);
132
133    /* Save register values to be modified */
134    seq2 = GetReg(SEQX, 0x02U);
135    seq4 = GetReg(SEQX, 0x04U);
136    gra1 = GetReg(GRAX, 0x01U);
137    gra3 = GetReg(GRAX, 0x03U);
138    gra5 = GetReg(GRAX, 0x05U);
139    gra6 = GetReg(GRAX, 0x06U);
140    gra8 = GetReg(GRAX, 0x08U);
141
142    save = pATIHW->frame_buffer;
143
144    /* Temporarily normalise the mode */
145    if (gra1 != 0x00U)
146        PutReg(GRAX, 0x01U, 0x00U);
147    if (gra3 != 0x00U)
148        PutReg(GRAX, 0x03U, 0x00U);
149    if (gra6 != 0x05U)
150        PutReg(GRAX, 0x06U, 0x05U);
151    if (gra8 != 0xFFU)
152        PutReg(GRAX, 0x08U, 0xFFU);
153
154    if (seq4 & 0x08U)
155    {
156        /* Setup packed mode memory */
157        if (seq2 != 0x0FU)
158            PutReg(SEQX, 0x02U, 0x0FU);
159        if (seq4 != 0x0AU)
160            PutReg(SEQX, 0x04U, 0x0AU);
161        if (pATI->Chip < ATI_CHIP_264CT)
162        {
163            if (gra5 != 0x00U)
164                PutReg(GRAX, 0x05U, 0x00U);
165        }
166        else
167        {
168            if (gra5 != 0x40U)
169                PutReg(GRAX, 0x05U, 0x40U);
170        }
171
172        ATICopyVGAMemory(pATI, pATIHW, &save, from, to);
173
174        if (seq2 != 0x0FU)
175            PutReg(SEQX, 0x02U, seq2);
176        if (seq4 != 0x0AU)
177            PutReg(SEQX, 0x04U, seq4);
178        if (pATI->Chip < ATI_CHIP_264CT)
179        {
180            if (gra5 != 0x00U)
181                PutReg(GRAX, 0x05U, gra5);
182        }
183        else
184        {
185            if (gra5 != 0x40U)
186                PutReg(GRAX, 0x05U, gra5);
187        }
188    }
189    else
190    {
191        gra4 = GetReg(GRAX, 0x04U);
192
193        /* Setup planar mode memory */
194        if (seq4 != 0x06U)
195            PutReg(SEQX, 0x04U, 0x06U);
196        if (gra5 != 0x00U)
197            PutReg(GRAX, 0x05U, 0x00U);
198
199        for (;  iPlane < pATIHW->nPlane;  iPlane++)
200        {
201            PutReg(SEQX, 0x02U, PlaneMask);
202            PutReg(GRAX, 0x04U, iPlane);
203            ATICopyVGAMemory(pATI, pATIHW, &save, from, to);
204            PlaneMask <<= 1;
205        }
206
207        PutReg(SEQX, 0x02U, seq2);
208        if (seq4 != 0x06U)
209            PutReg(SEQX, 0x04U, seq4);
210        PutReg(GRAX, 0x04U, gra4);
211        if (gra5 != 0x00U)
212            PutReg(GRAX, 0x05U, gra5);
213    }
214
215    /* Restore registers */
216    if (gra1 != 0x00U)
217        PutReg(GRAX, 0x01U, gra1);
218    if (gra3 != 0x00U)
219        PutReg(GRAX, 0x03U, gra3);
220    if (gra6 != 0x05U)
221        PutReg(GRAX, 0x06U, gra6);
222    if (gra8 != 0xFFU)
223        PutReg(GRAX, 0x08U, gra8);
224
225    /* Back to bank 0 */
226    (*pATIHW->SetBank)(pATI, 0);
227}
228
229#endif /* AVOID_CPIO */
230
231/*
232 * ATIModePreInit --
233 *
234 * This function initialises an ATIHWRec with information common to all video
235 * states generated by the driver.
236 */
237void
238ATIModePreInit
239(
240    ScrnInfoPtr pScreenInfo,
241    ATIPtr      pATI,
242    ATIHWPtr    pATIHW
243)
244{
245    CARD32 lcd_index;
246
247#ifndef AVOID_CPIO
248
249    if (pATI->VGAAdapter)
250    {
251        /* Fill in VGA data */
252        ATIVGAPreInit(pATI, pATIHW);
253
254        /* Fill in VGA Wonder data */
255        if (pATI->CPIO_VGAWonder)
256            ATIVGAWonderPreInit(pATI, pATIHW);
257    }
258
259#endif /* AVOID_CPIO */
260
261    {
262        /* Fill in Mach64 data */
263        ATIMach64PreInit(pScreenInfo, pATI, pATIHW);
264
265        if (pATI->Chip >= ATI_CHIP_264CT)
266        {
267            /* Ensure proper VCLK source */
268            pATIHW->pll_vclk_cntl = ATIMach64GetPLLReg(PLL_VCLK_CNTL) |
269                (PLL_VCLK_SRC_SEL | PLL_VCLK_RESET);
270
271            /* Set provisional values for other PLL registers */
272            pATIHW->pll_vclk_post_div = ATIMach64GetPLLReg(PLL_VCLK_POST_DIV);
273            pATIHW->pll_vclk0_fb_div = ATIMach64GetPLLReg(PLL_VCLK0_FB_DIV);
274            pATIHW->pll_vclk1_fb_div = ATIMach64GetPLLReg(PLL_VCLK1_FB_DIV);
275            pATIHW->pll_vclk2_fb_div = ATIMach64GetPLLReg(PLL_VCLK2_FB_DIV);
276            pATIHW->pll_vclk3_fb_div = ATIMach64GetPLLReg(PLL_VCLK3_FB_DIV);
277            pATIHW->pll_xclk_cntl = ATIMach64GetPLLReg(PLL_XCLK_CNTL);
278
279            /* For now disable extended reference and feedback dividers */
280            if (pATI->Chip >= ATI_CHIP_264LT)
281                pATIHW->pll_ext_vpll_cntl =
282                    ATIMach64GetPLLReg(PLL_EXT_VPLL_CNTL) &
283                    ~(PLL_EXT_VPLL_EN | PLL_EXT_VPLL_VGA_EN |
284                      PLL_EXT_VPLL_INSYNC);
285
286            /* Initialise CRTC data for LCD panels */
287            if (pATI->LCDPanelID >= 0)
288            {
289                if (pATI->Chip == ATI_CHIP_264LT)
290                {
291                    pATIHW->lcd_gen_ctrl = inr(LCD_GEN_CTRL);
292                }
293                else /* if ((pATI->Chip == ATI_CHIP_264LTPRO) ||
294                            (pATI->Chip == ATI_CHIP_264XL) ||
295                            (pATI->Chip == ATI_CHIP_MOBILITY)) */
296                {
297                    lcd_index = inr(LCD_INDEX);
298                    pATIHW->lcd_index = lcd_index &
299                        ~(LCD_REG_INDEX | LCD_DISPLAY_DIS | LCD_SRC_SEL |
300                          LCD_CRTC2_DISPLAY_DIS);
301                    if (pATI->Chip != ATI_CHIP_264XL)
302                        pATIHW->lcd_index |= LCD_CRTC2_DISPLAY_DIS;
303                    pATIHW->config_panel =
304                        ATIMach64GetLCDReg(LCD_CONFIG_PANEL) |
305                        DONT_SHADOW_HEND;
306                    pATIHW->lcd_gen_ctrl =
307                        ATIMach64GetLCDReg(LCD_GEN_CNTL) & ~CRTC_RW_SELECT;
308                    outr(LCD_INDEX, lcd_index);
309                }
310
311                pATIHW->lcd_gen_ctrl &=
312                    ~(HORZ_DIVBY2_EN | DIS_HOR_CRT_DIVBY2 | MCLK_PM_EN |
313                      VCLK_DAC_PM_EN | USE_SHADOWED_VEND |
314                      USE_SHADOWED_ROWCUR | SHADOW_EN | SHADOW_RW_EN);
315                pATIHW->lcd_gen_ctrl |= DONT_SHADOW_VPAR | LOCK_8DOT;
316
317                if (!pATI->OptionPanelDisplay)
318                {
319                    /*
320                     * Use primary CRTC to drive the CRT.  Turn off panel
321                     * interface.
322                     */
323                    pATIHW->lcd_gen_ctrl &= ~LCD_ON;
324                    pATIHW->lcd_gen_ctrl |= CRT_ON;
325                }
326                else
327                {
328                    /* Use primary CRTC to drive the panel */
329                    pATIHW->lcd_gen_ctrl |= LCD_ON;
330
331                    /* If requested, also force CRT on */
332                    if (pATI->OptionCRTDisplay)
333                        pATIHW->lcd_gen_ctrl |= CRT_ON;
334                }
335            }
336        }
337        else if (pATI->DAC == ATI_DAC_IBMRGB514)
338        {
339            ATIRGB514PreInit(pATI, pATIHW);
340        }
341    }
342
343    /* Set RAMDAC data */
344    ATIDACPreInit(pScreenInfo, pATI, pATIHW);
345}
346
347/*
348 * ATIModeSave --
349 *
350 * This function saves the current video state.
351 */
352void
353ATIModeSave
354(
355    ScrnInfoPtr pScreenInfo,
356    ATIPtr      pATI,
357    ATIHWPtr    pATIHW
358)
359{
360
361#ifndef AVOID_CPIO
362
363    int Index;
364
365    /* Get back to bank 0 */
366    (*pATIHW->SetBank)(pATI, 0);
367
368#endif /* AVOID_CPIO */
369
370    if (pATI->Chip >= ATI_CHIP_264CT)
371    {
372        pATIHW->pll_vclk_cntl = ATIMach64GetPLLReg(PLL_VCLK_CNTL) |
373            PLL_VCLK_RESET;
374        pATIHW->pll_vclk_post_div = ATIMach64GetPLLReg(PLL_VCLK_POST_DIV);
375        pATIHW->pll_vclk0_fb_div = ATIMach64GetPLLReg(PLL_VCLK0_FB_DIV);
376        pATIHW->pll_vclk1_fb_div = ATIMach64GetPLLReg(PLL_VCLK1_FB_DIV);
377        pATIHW->pll_vclk2_fb_div = ATIMach64GetPLLReg(PLL_VCLK2_FB_DIV);
378        pATIHW->pll_vclk3_fb_div = ATIMach64GetPLLReg(PLL_VCLK3_FB_DIV);
379        pATIHW->pll_xclk_cntl = ATIMach64GetPLLReg(PLL_XCLK_CNTL);
380        if (pATI->Chip >= ATI_CHIP_264LT)
381            pATIHW->pll_ext_vpll_cntl = ATIMach64GetPLLReg(PLL_EXT_VPLL_CNTL);
382
383        /* Save LCD registers */
384        if (pATI->LCDPanelID >= 0)
385        {
386            if (pATI->Chip == ATI_CHIP_264LT)
387            {
388                pATIHW->horz_stretching = inr(HORZ_STRETCHING);
389                pATIHW->vert_stretching = inr(VERT_STRETCHING);
390                pATIHW->lcd_gen_ctrl = inr(LCD_GEN_CTRL);
391
392                /* Set up to save non-shadow registers */
393                outr(LCD_GEN_CTRL, pATIHW->lcd_gen_ctrl & ~SHADOW_RW_EN);
394            }
395            else /* if ((pATI->Chip == ATI_CHIP_264LTPRO) ||
396                        (pATI->Chip == ATI_CHIP_264XL) ||
397                        (pATI->Chip == ATI_CHIP_MOBILITY)) */
398            {
399                pATIHW->lcd_index = inr(LCD_INDEX);
400                pATIHW->config_panel = ATIMach64GetLCDReg(LCD_CONFIG_PANEL);
401                pATIHW->lcd_gen_ctrl = ATIMach64GetLCDReg(LCD_GEN_CNTL);
402                pATIHW->horz_stretching =
403                    ATIMach64GetLCDReg(LCD_HORZ_STRETCHING);
404                pATIHW->vert_stretching =
405                    ATIMach64GetLCDReg(LCD_VERT_STRETCHING);
406                pATIHW->ext_vert_stretch =
407                    ATIMach64GetLCDReg(LCD_EXT_VERT_STRETCH);
408
409                /* Set up to save non-shadow registers */
410                ATIMach64PutLCDReg(LCD_GEN_CNTL,
411                    pATIHW->lcd_gen_ctrl & ~(CRTC_RW_SELECT | SHADOW_RW_EN));
412            }
413        }
414    }
415
416#ifndef AVOID_CPIO
417
418    if (pATI->VGAAdapter)
419    {
420        /* Save VGA data */
421        ATIVGASave(pATI, pATIHW);
422
423        /* Save VGA Wonder data */
424        if (pATI->CPIO_VGAWonder)
425            ATIVGAWonderSave(pATI, pATIHW);
426    }
427
428#endif /* AVOID_CPIO */
429
430    {
431        /* Save Mach64 data */
432        ATIMach64Save(pATI, pATIHW);
433
434        if (pATI->Chip >= ATI_CHIP_264VTB)
435        {
436            /* Save DSP data */
437            ATIDSPSave(pATI, pATIHW);
438
439            if (pATI->LCDPanelID >= 0)
440            {
441                /* Switch to shadow registers */
442                if (pATI->Chip == ATI_CHIP_264LT)
443                    outr(LCD_GEN_CTRL, pATIHW->lcd_gen_ctrl | SHADOW_RW_EN);
444                else /* if ((pATI->Chip == ATI_CHIP_264LTPRO) ||
445                            (pATI->Chip == ATI_CHIP_264XL) ||
446                            (pATI->Chip == ATI_CHIP_MOBILITY)) */
447                    ATIMach64PutLCDReg(LCD_GEN_CNTL,
448                        (pATIHW->lcd_gen_ctrl & ~CRTC_RW_SELECT) |
449                        SHADOW_RW_EN);
450
451#ifndef AVOID_CPIO
452
453                /* Save shadow VGA CRTC registers */
454                for (Index = 0;
455                     Index < NumberOf(pATIHW->shadow_vga);
456                     Index++)
457                    pATIHW->shadow_vga[Index] =
458                        GetReg(CRTX(pATI->CPIO_VGABase), Index);
459
460#endif /* AVOID_CPIO */
461
462                /* Save shadow Mach64 CRTC registers */
463                pATIHW->shadow_h_total_disp = inr(CRTC_H_TOTAL_DISP);
464                pATIHW->shadow_h_sync_strt_wid = inr(CRTC_H_SYNC_STRT_WID);
465                pATIHW->shadow_v_total_disp = inr(CRTC_V_TOTAL_DISP);
466                pATIHW->shadow_v_sync_strt_wid = inr(CRTC_V_SYNC_STRT_WID);
467
468                /* Restore CRTC selection and shadow state */
469                if (pATI->Chip == ATI_CHIP_264LT)
470                {
471                    outr(LCD_GEN_CTRL, pATIHW->lcd_gen_ctrl);
472                }
473                else /* if ((pATI->Chip == ATI_CHIP_264LTPRO) ||
474                            (pATI->Chip == ATI_CHIP_264XL) ||
475                            (pATI->Chip == ATI_CHIP_MOBILITY)) */
476                {
477                    ATIMach64PutLCDReg(LCD_GEN_CNTL, pATIHW->lcd_gen_ctrl);
478                    outr(LCD_INDEX, pATIHW->lcd_index);
479                }
480            }
481        }
482        else if (pATI->DAC == ATI_DAC_IBMRGB514)
483            ATIRGB514Save(pATI, pATIHW);
484    }
485
486    /* Save RAMDAC state */
487    ATIDACSave(pATI, pATIHW);
488
489    if (pATIHW != &pATI->NewHW)
490    {
491        pATIHW->FeedbackDivider = 0;    /* Don't programme clock */
492    }
493
494#ifndef AVOID_CPIO
495
496        /* Save video memory */
497        ATISwap(pScreenInfo->scrnIndex, pATI, pATIHW, FALSE);
498
499    if (pATI->VGAAdapter)
500        ATIVGASaveScreen(pATI, SCREEN_SAVER_OFF);       /* Turn on screen */
501
502#endif /* AVOID_CPIO */
503
504}
505
506/*
507 * ATIModeCalculate --
508 *
509 * This function fills in an ATIHWRec with all register values needed to enable
510 * a video state.  It's important that this be done without modifying the
511 * current video state.
512 */
513Bool
514ATIModeCalculate
515(
516    int            iScreen,
517    ATIPtr         pATI,
518    ATIHWPtr       pATIHW,
519    DisplayModePtr pMode
520)
521{
522    CARD32 lcd_index;
523    int Index, ECPClock, MaxScalerClock;
524
525    /* Fill in Mach64 data */
526    ATIMach64Calculate(pATI, pATIHW, pMode);
527
528    /* Set up LCD register values */
529    if (pATI->LCDPanelID >= 0)
530    {
531        int VDisplay = pMode->VDisplay;
532
533        if (pMode->Flags & V_DBLSCAN)
534            VDisplay <<= 1;
535        if (pMode->VScan > 1)
536            VDisplay *= pMode->VScan;
537        if (pMode->Flags & V_INTERLACE)
538            VDisplay >>= 1;
539
540        /* Ensure secondary CRTC is completely disabled */
541        pATIHW->crtc_gen_cntl &= ~(CRTC2_EN | CRTC2_PIX_WIDTH);
542
543        if (pATI->Chip == ATI_CHIP_264LT)
544        {
545            pATIHW->horz_stretching = inr(HORZ_STRETCHING);
546        }
547        else /* if ((pATI->Chip == ATI_CHIP_264LTPRO) ||
548                    (pATI->Chip == ATI_CHIP_264XL) ||
549                    (pATI->Chip == ATI_CHIP_MOBILITY)) */
550        {
551            lcd_index = inr(LCD_INDEX);
552            pATIHW->horz_stretching = ATIMach64GetLCDReg(LCD_HORZ_STRETCHING);
553            pATIHW->ext_vert_stretch =
554                ATIMach64GetLCDReg(LCD_EXT_VERT_STRETCH) &
555                ~(AUTO_VERT_RATIO | VERT_STRETCH_MODE | VERT_STRETCH_RATIO3);
556
557            /*
558             * Don't use vertical blending if the mode is too wide or not
559             * vertically stretched.
560             */
561            if (pATI->OptionPanelDisplay &&
562                (pMode->HDisplay <= pATI->LCDVBlendFIFOSize) &&
563                (VDisplay < pATI->LCDVertical))
564                pATIHW->ext_vert_stretch |= VERT_STRETCH_MODE;
565
566            outr(LCD_INDEX, lcd_index);
567        }
568
569        pATIHW->horz_stretching &=
570            ~(HORZ_STRETCH_RATIO | HORZ_STRETCH_LOOP | AUTO_HORZ_RATIO |
571              HORZ_STRETCH_MODE | HORZ_STRETCH_EN);
572        if (pATI->OptionPanelDisplay &&
573            (pMode->HDisplay < pATI->LCDHorizontal))
574        do
575        {
576            /*
577             * The horizontal blender misbehaves when HDisplay is less than a
578             * a certain threshold (440 for a 1024-wide panel).  It doesn't
579             * stretch such modes enough.  Use pixel replication instead of
580             * blending to stretch modes that can be made to exactly fit the
581             * panel width.  The undocumented "NoLCDBlend" option allows the
582             * pixel-replicated mode to be slightly wider or narrower than the
583             * panel width.  It also causes a mode that is exactly half as wide
584             * as the panel to be pixel-replicated, rather than blended.
585             */
586            int HDisplay  = pMode->HDisplay & ~7;
587            int nStretch  = pATI->LCDHorizontal / HDisplay;
588            int Remainder = pATI->LCDHorizontal % HDisplay;
589
590            if ((!Remainder && ((nStretch > 2) || !pATI->OptionBlend)) ||
591                (((HDisplay * 16) / pATI->LCDHorizontal) < 7))
592            {
593                static const char StretchLoops[] = {10, 12, 13, 15, 16};
594                int horz_stretch_loop = -1, BestRemainder;
595                int Numerator = HDisplay, Denominator = pATI->LCDHorizontal;
596
597                ATIReduceRatio(&Numerator, &Denominator);
598
599                BestRemainder = (Numerator * 16) / Denominator;
600                Index = NumberOf(StretchLoops);
601                while (--Index >= 0)
602                {
603                    Remainder =
604                        ((Denominator - Numerator) * StretchLoops[Index]) %
605                        Denominator;
606                    if (Remainder < BestRemainder)
607                    {
608                        horz_stretch_loop = Index;
609                        if (!(BestRemainder = Remainder))
610                            break;
611                    }
612#if 0
613                    /*
614                     * Enabling this code allows the pixel-replicated mode to
615                     * be slightly wider than the panel width.
616                     */
617                    Remainder = Denominator - Remainder;
618                    if (Remainder < BestRemainder)
619                    {
620                        horz_stretch_loop = Index;
621                        BestRemainder = Remainder;
622                    }
623#endif
624                }
625
626                if ((horz_stretch_loop >= 0) &&
627                    (!BestRemainder || !pATI->OptionBlend))
628                {
629                    int horz_stretch_ratio = 0, Accumulator = 0;
630                    int reuse_previous = 1;
631
632                    Index = StretchLoops[horz_stretch_loop];
633
634                    while (--Index >= 0)
635                    {
636                        if (Accumulator > 0)
637                            horz_stretch_ratio |= reuse_previous;
638                        else
639                            Accumulator += Denominator;
640                        Accumulator -= Numerator;
641                        reuse_previous <<= 1;
642                    }
643
644                    pATIHW->horz_stretching |= HORZ_STRETCH_EN |
645                        SetBits(horz_stretch_loop, HORZ_STRETCH_LOOP) |
646                        SetBits(horz_stretch_ratio, HORZ_STRETCH_RATIO);
647                    break;      /* Out of the do { ... } while (0) */
648                }
649            }
650
651            pATIHW->horz_stretching |= (HORZ_STRETCH_MODE | HORZ_STRETCH_EN) |
652                SetBits((HDisplay * (MaxBits(HORZ_STRETCH_BLEND) + 1)) /
653                        pATI->LCDHorizontal, HORZ_STRETCH_BLEND);
654        } while (0);
655
656        if (!pATI->OptionPanelDisplay || (VDisplay >= pATI->LCDVertical))
657        {
658            pATIHW->vert_stretching = 0;
659        }
660        else
661        {
662            pATIHW->vert_stretching = (VERT_STRETCH_USE0 | VERT_STRETCH_EN) |
663                SetBits((VDisplay * (MaxBits(VERT_STRETCH_RATIO0) + 1)) /
664                        pATI->LCDVertical, VERT_STRETCH_RATIO0);
665        }
666
667#ifndef AVOID_CPIO
668
669        /* Copy non-shadow CRTC register values to the shadow set */
670        for (Index = 0;  Index < NumberOf(pATIHW->shadow_vga);  Index++)
671            pATIHW->shadow_vga[Index] = pATIHW->crt[Index];
672
673#endif /* AVOID_CPIO */
674
675        pATIHW->shadow_h_total_disp = pATIHW->crtc_h_total_disp;
676        pATIHW->shadow_h_sync_strt_wid = pATIHW->crtc_h_sync_strt_wid;
677        pATIHW->shadow_v_total_disp = pATIHW->crtc_v_total_disp;
678        pATIHW->shadow_v_sync_strt_wid = pATIHW->crtc_v_sync_strt_wid;
679    }
680
681    /* Fill in clock data */
682    if (!ATIClockCalculate(iScreen, pATI, pATIHW, pMode))
683        return FALSE;
684
685    /* Setup ECP clock divider */
686    if (pATI->Chip >= ATI_CHIP_264VT)
687    {
688        if (pATI->Chip <= ATI_CHIP_264VT3)
689            MaxScalerClock = 80000;
690        else if (pATI->Chip <= ATI_CHIP_264GT2C)
691            MaxScalerClock = 100000;
692        else if (pATI->Chip == ATI_CHIP_264GTPRO)
693            MaxScalerClock = 125000;
694        else if (pATI->Chip <= ATI_CHIP_MOBILITY)
695            MaxScalerClock = 135000;
696        else
697            MaxScalerClock = 80000;     /* Conservative */
698        pATIHW->pll_vclk_cntl &= ~PLL_ECP_DIV;
699#ifdef TV_OUT
700	if (pATI->OptionTvOut) {
701	   /* XXX Don't do this for TVOut! */
702	}
703	else
704#endif /* TV_OUT */
705	{
706	   ECPClock = pMode->SynthClock;
707	   for (Index = 0;  (ECPClock > MaxScalerClock) && (Index < 2);  Index++)
708	      ECPClock >>= 1;
709	   pATIHW->pll_vclk_cntl |= SetBits(Index, PLL_ECP_DIV);
710	}
711    }
712    else if (pATI->DAC == ATI_DAC_IBMRGB514)
713    {
714        ATIRGB514Calculate(pATI, pATIHW, pMode);
715    }
716
717    return TRUE;
718}
719
720#ifdef TV_OUT
721
722static void
723ATISetVBEMode
724(
725    ScrnInfoPtr pScreenInfo,
726    ATIPtr      pATI,
727    ATIHWPtr    pATIHW
728)
729{
730    if (pATIHW->crtc == ATI_CRTC_MACH64) {
731	int vbemode, modekey;
732
733	/* Find a suitable VESA VBE mode, if one exists */
734	modekey = (pScreenInfo->depth << 16) |
735	    (pScreenInfo->currentMode->HDisplay);
736
737	switch (modekey) {
738	case (15<<16)|(640):
739	    vbemode = 0x110;
740	    break;
741	case (16<<16)|(640):
742	    vbemode = 0x111;
743	    break;
744#if 0
745	case (24<<16)|(640):
746	    vbemode = 0x112;
747	    break;
748#endif
749	case (15<<16)|(800):
750	    vbemode = 0x113;
751	    break;
752	case (16<<16)|(800):
753	    vbemode = 0x114;
754	    break;
755#if 0
756	case (24<<16)|(800):
757	    vbemode = 0x115;
758	    break;
759#endif
760	case (15<<16)|(1024):
761	    vbemode = 0x116;
762	    break;
763	case (16<<16)|(1024):
764	    vbemode = 0x117;
765	    break;
766#if 0
767	case (24<<16)|(1024):
768	    vbemode = 0x118;
769	    break;
770#endif
771	default:
772	    xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO,
773		       "Mode not supported for TV-Out: depth: %d HDisplay: %d\n",
774		       modekey>>16, modekey & 0xffff);
775	    return;
776	}
777
778	if (pATI->pVBE) {
779
780            /* Preserve video memory contents */
781            vbemode |= (1<<15);
782
783	    if (VBESetVBEMode(pATI->pVBE, vbemode, NULL)) {
784		xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO,
785			   "VBESetMode: 0x%X (width: %d, pitch: %d, depth: %d)\n",
786			   vbemode,
787			   pScreenInfo->currentMode->HDisplay,
788			   pScreenInfo->displayWidth,
789			   pScreenInfo->depth);
790		outr(CRTC_OFF_PITCH,
791		     SetBits(pScreenInfo->displayWidth>>3, CRTC_PITCH));
792	    } else {
793		xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, "VBESetMode failed.\n");
794	    }
795	} else {
796	    xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, "VBE module not loaded.\n");
797	}
798    } else {
799	/* restore text mode with VBESetMode */
800	if (pATI->pVBE) {
801	    if (VBESetVBEMode(pATI->pVBE, pATI->vbemode, NULL)) {
802		xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, "Restoring VESA mode: 0x%x\n",
803			   pATI->vbemode);
804	    } else {
805	        xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, "VBESetMode failed.\n");
806	    }
807	} else {
808	    xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, "VBE module not loaded.\n");
809	}
810    }
811    if (xf86ServerIsExiting()) {
812	if (pATI->pVBE) vbeFree(pATI->pVBE);
813	if (pATI->pInt10) xf86FreeInt10(pATI->pInt10);
814    }
815}
816
817#endif /* TV_OUT */
818
819/*
820 * ATIModeSet --
821 *
822 * This function sets a video mode.  It writes out all video state data that
823 * has been previously calculated or saved.
824 */
825void
826ATIModeSet
827(
828    ScrnInfoPtr pScreenInfo,
829    ATIPtr      pATI,
830    ATIHWPtr    pATIHW
831)
832{
833
834#ifndef AVOID_CPIO
835
836    int Index;
837
838    /* Get back to bank 0 */
839    (*pATIHW->SetBank)(pATI, 0);
840
841#endif /* AVOID_CPIO */
842
843    {
844        /* Stop CRTC */
845        outr(CRTC_GEN_CNTL,
846            pATIHW->crtc_gen_cntl & ~(CRTC_EXT_DISP_EN | CRTC_EN));
847
848        if (pATI->Chip >= ATI_CHIP_264CT)
849        {
850            ATIMach64PutPLLReg(PLL_VCLK_CNTL, pATIHW->pll_vclk_cntl);
851            ATIMach64PutPLLReg(PLL_VCLK_POST_DIV, pATIHW->pll_vclk_post_div);
852            ATIMach64PutPLLReg(PLL_VCLK0_FB_DIV, pATIHW->pll_vclk0_fb_div);
853            ATIMach64PutPLLReg(PLL_VCLK1_FB_DIV, pATIHW->pll_vclk1_fb_div);
854            ATIMach64PutPLLReg(PLL_VCLK2_FB_DIV, pATIHW->pll_vclk2_fb_div);
855            ATIMach64PutPLLReg(PLL_VCLK3_FB_DIV, pATIHW->pll_vclk3_fb_div);
856            ATIMach64PutPLLReg(PLL_XCLK_CNTL, pATIHW->pll_xclk_cntl);
857            if (pATI->Chip >= ATI_CHIP_264LT)
858                ATIMach64PutPLLReg(PLL_EXT_VPLL_CNTL,
859                    pATIHW->pll_ext_vpll_cntl);
860            ATIMach64PutPLLReg(PLL_VCLK_CNTL,
861                pATIHW->pll_vclk_cntl & ~PLL_VCLK_RESET);
862
863            /* Load LCD registers */
864            if (pATI->LCDPanelID >= 0)
865            {
866                if (pATI->Chip == ATI_CHIP_264LT)
867                {
868                    /* Update non-shadow registers first */
869                    outr(LCD_GEN_CTRL, pATIHW->lcd_gen_ctrl & ~SHADOW_RW_EN);
870
871                    /* Temporarily disable stretching */
872                    outr(HORZ_STRETCHING, pATIHW->horz_stretching &
873                        ~(HORZ_STRETCH_MODE | HORZ_STRETCH_EN));
874                    outr(VERT_STRETCHING, pATIHW->vert_stretching &
875                        ~(VERT_STRETCH_RATIO1 | VERT_STRETCH_RATIO2 |
876                          VERT_STRETCH_USE0 | VERT_STRETCH_EN));
877                }
878                else /* if ((pATI->Chip == ATI_CHIP_264LTPRO) ||
879                            (pATI->Chip == ATI_CHIP_264XL) ||
880                            (pATI->Chip == ATI_CHIP_MOBILITY)) */
881                {
882                    /* Update non-shadow registers first */
883                    ATIMach64PutLCDReg(LCD_CONFIG_PANEL, pATIHW->config_panel);
884                    ATIMach64PutLCDReg(LCD_GEN_CNTL, pATIHW->lcd_gen_ctrl &
885                        ~(CRTC_RW_SELECT | SHADOW_RW_EN));
886
887                    /* Temporarily disable stretching */
888                    ATIMach64PutLCDReg(LCD_HORZ_STRETCHING,
889                        pATIHW->horz_stretching &
890                        ~(HORZ_STRETCH_MODE | HORZ_STRETCH_EN));
891                    ATIMach64PutLCDReg(LCD_VERT_STRETCHING,
892                        pATIHW->vert_stretching &
893                        ~(VERT_STRETCH_RATIO1 | VERT_STRETCH_RATIO2 |
894                          VERT_STRETCH_USE0 | VERT_STRETCH_EN));
895                }
896            }
897        }
898    }
899
900    switch (pATIHW->crtc)
901    {
902
903#ifndef AVOID_CPIO
904
905        case ATI_CRTC_VGA:
906            /* Start sequencer reset */
907            PutReg(SEQX, 0x00U, 0x00U);
908
909            /* Set pixel clock */
910            if ((pATIHW->FeedbackDivider > 0))
911                ATIClockSet(pATI, pATIHW);
912
913            /* Set up RAMDAC */
914            if (pATI->DAC == ATI_DAC_IBMRGB514)
915                ATIRGB514Set(pATI, pATIHW);
916
917            /* Load VGA Wonder */
918            if (pATI->CPIO_VGAWonder)
919                ATIVGAWonderSet(pATI, pATIHW);
920
921            /* Load VGA device */
922            ATIVGASet(pATI, pATIHW);
923
924            /* Load Mach64 registers */
925            {
926                /* Load MMIO registers */
927                if (pATI->Block0Base)
928                    ATIMach64Set(pATI, pATIHW);
929
930                outr(CRTC_GEN_CNTL, pATIHW->crtc_gen_cntl);
931                outr(CUR_CLR0, pATIHW->cur_clr0);
932                outr(CUR_CLR1, pATIHW->cur_clr1);
933                outr(CUR_OFFSET, pATIHW->cur_offset);
934                outr(CUR_HORZ_VERT_POSN, pATIHW->cur_horz_vert_posn);
935                outr(CUR_HORZ_VERT_OFF, pATIHW->cur_horz_vert_off);
936                outr(BUS_CNTL, pATIHW->bus_cntl);
937                outr(MEM_VGA_WP_SEL, pATIHW->mem_vga_wp_sel);
938                outr(MEM_VGA_RP_SEL, pATIHW->mem_vga_rp_sel);
939                outr(DAC_CNTL, pATIHW->dac_cntl);
940                outr(GEN_TEST_CNTL, pATIHW->gen_test_cntl | GEN_GUI_EN);
941                outr(GEN_TEST_CNTL, pATIHW->gen_test_cntl);
942                outr(GEN_TEST_CNTL, pATIHW->gen_test_cntl | GEN_GUI_EN);
943                outr(CONFIG_CNTL, pATIHW->config_cntl);
944                if (pATI->Chip >= ATI_CHIP_264CT)
945                {
946                    outr(CRTC_H_TOTAL_DISP, pATIHW->crtc_h_total_disp);
947                    outr(CRTC_H_SYNC_STRT_WID, pATIHW->crtc_h_sync_strt_wid);
948                    outr(CRTC_V_TOTAL_DISP, pATIHW->crtc_v_total_disp);
949                    outr(CRTC_V_SYNC_STRT_WID, pATIHW->crtc_v_sync_strt_wid);
950                    outr(CRTC_OFF_PITCH, pATIHW->crtc_off_pitch);
951                    if (pATI->Chip >= ATI_CHIP_264VTB)
952                    {
953                        outr(MEM_CNTL, pATIHW->mem_cntl);
954                        outr(MPP_CONFIG, pATIHW->mpp_config);
955                        outr(MPP_STROBE_SEQ, pATIHW->mpp_strobe_seq);
956                        outr(TVO_CNTL, pATIHW->tvo_cntl);
957                    }
958                }
959            }
960
961            break;
962
963#endif /* AVOID_CPIO */
964
965        case ATI_CRTC_MACH64:
966            /* Load Mach64 CRTC registers */
967            ATIMach64Set(pATI, pATIHW);
968
969#ifndef AVOID_CPIO
970
971            if (pATI->VGAAdapter)
972            {
973                /* Oddly enough, these need to be set also, maybe others */
974                PutReg(SEQX, 0x02U, pATIHW->seq[2]);
975                PutReg(SEQX, 0x04U, pATIHW->seq[4]);
976                PutReg(GRAX, 0x06U, pATIHW->gra[6]);
977                if (pATI->CPIO_VGAWonder)
978                    ATIModifyExtReg(pATI, 0xB6U, -1, 0x00U, pATIHW->b6);
979            }
980
981#endif /* AVOID_CPIO */
982
983            break;
984
985        default:
986            break;
987    }
988
989    if (pATI->LCDPanelID >= 0)
990    {
991        /* Switch to shadow registers */
992        if (pATI->Chip == ATI_CHIP_264LT)
993            outr(LCD_GEN_CTRL, pATIHW->lcd_gen_ctrl | SHADOW_RW_EN);
994        else /* if ((pATI->Chip == ATI_CHIP_264LTPRO) ||
995                    (pATI->Chip == ATI_CHIP_264XL) ||
996                    (pATI->Chip == ATI_CHIP_MOBILITY)) */
997            ATIMach64PutLCDReg(LCD_GEN_CNTL,
998                (pATIHW->lcd_gen_ctrl & ~CRTC_RW_SELECT) | SHADOW_RW_EN);
999
1000        /* Restore shadow registers */
1001        switch (pATIHW->crtc)
1002        {
1003
1004#ifndef AVOID_CPIO
1005
1006            case ATI_CRTC_VGA:
1007                for (Index = 0;
1008                     Index < NumberOf(pATIHW->shadow_vga);
1009                     Index++)
1010                    PutReg(CRTX(pATI->CPIO_VGABase), Index,
1011                        pATIHW->shadow_vga[Index]);
1012                /* Fall through */
1013
1014#endif /* AVOID_CPIO */
1015
1016            case ATI_CRTC_MACH64:
1017                outr(CRTC_H_TOTAL_DISP, pATIHW->shadow_h_total_disp);
1018                outr(CRTC_H_SYNC_STRT_WID, pATIHW->shadow_h_sync_strt_wid);
1019                outr(CRTC_V_TOTAL_DISP, pATIHW->shadow_v_total_disp);
1020                outr(CRTC_V_SYNC_STRT_WID, pATIHW->shadow_v_sync_strt_wid);
1021                break;
1022
1023            default:
1024                break;
1025        }
1026
1027        /* Restore CRTC selection & shadow state and enable stretching */
1028        if (pATI->Chip == ATI_CHIP_264LT)
1029        {
1030            outr(LCD_GEN_CTRL, pATIHW->lcd_gen_ctrl);
1031            outr(HORZ_STRETCHING, pATIHW->horz_stretching);
1032            outr(VERT_STRETCHING, pATIHW->vert_stretching);
1033        }
1034        else /* if ((pATI->Chip == ATI_CHIP_264LTPRO) ||
1035                    (pATI->Chip == ATI_CHIP_264XL) ||
1036                    (pATI->Chip == ATI_CHIP_MOBILITY)) */
1037        {
1038            ATIMach64PutLCDReg(LCD_GEN_CNTL, pATIHW->lcd_gen_ctrl);
1039            ATIMach64PutLCDReg(LCD_HORZ_STRETCHING, pATIHW->horz_stretching);
1040            ATIMach64PutLCDReg(LCD_VERT_STRETCHING, pATIHW->vert_stretching);
1041            ATIMach64PutLCDReg(LCD_EXT_VERT_STRETCH, pATIHW->ext_vert_stretch);
1042            outr(LCD_INDEX, pATIHW->lcd_index);
1043        }
1044    }
1045
1046    /*
1047     * Set DSP registers.  Note that, for some reason, sequencer resets clear
1048     * the DSP_CONFIG register on early integrated controllers.
1049     */
1050    if (pATI->Chip >= ATI_CHIP_264VTB)
1051        ATIDSPSet(pATI, pATIHW);
1052
1053    /* Load RAMDAC */
1054    ATIDACSet(pATI, pATIHW);
1055
1056    /* Reset hardware cursor caching */
1057    pATI->CursorXOffset = pATI->CursorYOffset = (CARD16)(-1);
1058
1059#ifdef TV_OUT
1060
1061    /* Set VBE mode for TV-Out */
1062    if (pATI->OptionTvOut /* && pATI->tvActive */)
1063	ATISetVBEMode(pScreenInfo, pATI, pATIHW);
1064
1065#endif /* TV_OUT */
1066
1067#ifndef AVOID_CPIO
1068
1069    /* Restore video memory */
1070    ATISwap(pScreenInfo->scrnIndex, pATI, pATIHW, TRUE);
1071
1072    if (pATI->VGAAdapter)
1073        ATIVGASaveScreen(pATI, SCREEN_SAVER_OFF);       /* Turn on screen */
1074
1075#endif /* AVOID_CPIO */
1076
1077    if ((xf86GetVerbosity() > 3) && (pATIHW == &pATI->NewHW))
1078    {
1079        xf86ErrorFVerb(4, "\n After setting mode \"%s\":\n\n",
1080            pScreenInfo->currentMode->name);
1081        ATIPrintMode(pScreenInfo->currentMode);
1082        ATIPrintRegisters(pATI);
1083    }
1084}
1085