via_display.c revision 03bd066f
1/*
2 * Copyright 2015-2016 Kevin Brace
3 * Copyright 2005-2016 The OpenChrome Project
4 *                     [http://www.freedesktop.org/wiki/Openchrome]
5 * Copyright 2004-2005 The Unichrome Project  [unichrome.sf.net]
6 * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
7 * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sub license,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice (including the
17 * next paragraph) shall be included in all copies or substantial portions
18 * of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 * DEALINGS IN THE SOFTWARE.
27 */
28#ifdef HAVE_CONFIG_H
29#include "config.h"
30#endif
31
32#include "via_driver.h"
33
34/*
35 * Controls IGA1 DPMS State.
36 */
37void
38viaIGA1DPMSControl(ScrnInfoPtr pScrn, CARD8 dpmsControl)
39{
40    vgaHWPtr hwp = VGAHWPTR(pScrn);
41
42    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
43                        "Entered viaIGA1DPMSControl.\n"));
44
45    /* 3X5.36[5:4] - DPMS Control
46     *               00: On
47     *               01: Stand-by
48     *               10: Suspend
49     *               11: Off */
50    ViaCrtcMask(hwp, 0x36, dpmsControl << 4, 0x30);
51
52    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
53                        "Exiting viaIGA1DPMSControl.\n"));
54}
55
56/*
57 * Controls IGA2 display output on or off state.
58 */
59void
60viaIGA2DisplayOutput(ScrnInfoPtr pScrn, Bool outputState)
61{
62    vgaHWPtr hwp = VGAHWPTR(pScrn);
63
64    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
65                        "Entered viaIGA2DisplayOutput.\n"));
66
67    /* 3X5.6B[2] - IGA2 Screen Off
68     *             0: Screen on
69     *             1: Screen off */
70    ViaCrtcMask(hwp, 0x6B, outputState ? 0x00 : 0x04, 0x04);
71    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
72                "IGA2 Display Output: %s\n",
73                outputState ? "On" : "Off");
74
75    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
76                        "Exiting viaIGA2DisplayOutput.\n"));
77}
78
79/*
80 * Controls IGA2 display channel state.
81 */
82void
83viaIGA2DisplayChannel(ScrnInfoPtr pScrn, Bool channelState)
84{
85    vgaHWPtr hwp = VGAHWPTR(pScrn);
86
87    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
88                        "Entered viaIGA2DisplayChannel.\n"));
89
90    /* 3X5.6A[7] - Second Display Channel Enable
91     * 3X5.6A[6] - Second Display Channel Reset (0 for reset) */
92    ViaCrtcMask(hwp, 0x6A, 0x00, 0x40);
93    ViaCrtcMask(hwp, 0x6A, channelState ? 0x80 : 0x00, 0x80);
94    ViaCrtcMask(hwp, 0x6A, 0x40, 0x40);
95
96    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
97                "IGA2 Display Channel: %s\n",
98                channelState ? "On" : "Off");
99
100    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
101                        "Exiting viaIGA2DisplayChannel.\n"));
102}
103
104/*
105 * Initial settings for displays.
106 */
107void
108viaDisplayInit(ScrnInfoPtr pScrn)
109{
110    VIAPtr pVia = VIAPTR(pScrn);
111    vgaHWPtr hwp = VGAHWPTR(pScrn);
112
113    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
114                        "Entered viaDisplayInit.\n"));
115
116    ViaCrtcMask(hwp, 0x6A, 0x00, 0x3D);
117    hwp->writeCrtc(hwp, 0x6B, 0x00);
118    hwp->writeCrtc(hwp, 0x6C, 0x00);
119    hwp->writeCrtc(hwp, 0x79, 0x00);
120
121    /* (IGA1 Timing Plus 2, added in VT3259 A3 or later) */
122    if (pVia->Chipset != VIA_CLE266 && pVia->Chipset != VIA_KM400)
123        ViaCrtcMask(hwp, 0x47, 0x00, 0xC8);
124
125    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
126                        "Exiting viaDisplayInit.\n"));
127}
128
129/*
130 * Sets the primary or secondary display stream on internal TMDS.
131 */
132void
133ViaDisplaySetStreamOnDFP(ScrnInfoPtr pScrn, Bool primary)
134{
135    vgaHWPtr hwp = VGAHWPTR(pScrn);
136
137    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "ViaDisplaySetStreamOnDFP\n"));
138
139    if (primary)
140        ViaCrtcMask(hwp, 0x99, 0x00, 0x10);
141    else
142        ViaCrtcMask(hwp, 0x99, 0x10, 0x10);
143}
144
145static void
146ViaCRTCSetGraphicsRegisters(ScrnInfoPtr pScrn)
147{
148    vgaHWPtr hwp = VGAHWPTR(pScrn);
149
150    /* graphics registers */
151    hwp->writeGr(hwp, 0x00, 0x00);
152    hwp->writeGr(hwp, 0x01, 0x00);
153    hwp->writeGr(hwp, 0x02, 0x00);
154    hwp->writeGr(hwp, 0x03, 0x00);
155    hwp->writeGr(hwp, 0x04, 0x00);
156    hwp->writeGr(hwp, 0x05, 0x40);
157    hwp->writeGr(hwp, 0x06, 0x05);
158    hwp->writeGr(hwp, 0x07, 0x0F);
159    hwp->writeGr(hwp, 0x08, 0xFF);
160
161    ViaGrMask(hwp, 0x20, 0, 0xFF);
162    ViaGrMask(hwp, 0x21, 0, 0xFF);
163    ViaGrMask(hwp, 0x22, 0, 0xFF);
164}
165
166static void
167ViaCRTCSetAttributeRegisters(ScrnInfoPtr pScrn)
168{
169    vgaHWPtr hwp = VGAHWPTR(pScrn);
170    CARD8 i;
171
172    /* attribute registers */
173    for (i = 0; i <= 0xF; i++) {
174        hwp->writeAttr(hwp, i, i);
175    }
176    hwp->writeAttr(hwp, 0x10, 0x41);
177    hwp->writeAttr(hwp, 0x11, 0xFF);
178    hwp->writeAttr(hwp, 0x12, 0x0F);
179    hwp->writeAttr(hwp, 0x13, 0x00);
180    hwp->writeAttr(hwp, 0x14, 0x00);
181}
182
183void
184VIALoadRgbLut(ScrnInfoPtr pScrn, int start, int numColors, LOCO *colors)
185{
186    vgaHWPtr hwp = VGAHWPTR(pScrn);
187    int i, j;
188
189    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VIALoadRgbLut\n"));
190
191    hwp->enablePalette(hwp);
192    hwp->writeDacMask(hwp, 0xFF);
193
194    /* We need the same palette contents for both 16 and 24 bits, but X doesn't
195     * play: X's colormap handling is hopelessly intertwined with almost every
196     * X subsystem.  So we just space out RGB values over the 256*3. */
197
198    switch (pScrn->bitsPerPixel) {
199        case 16:
200            for (i = start; i < numColors; i++) {
201                hwp->writeDacWriteAddr(hwp, i * 4);
202                for (j = 0; j < 4; j++) {
203                    hwp->writeDacData(hwp, colors[i / 2].red);
204                    hwp->writeDacData(hwp, colors[i].green);
205                    hwp->writeDacData(hwp, colors[i / 2].blue);
206                }
207            }
208            break;
209        case 8:
210        case 24:
211        case 32:
212            for (i = start; i < numColors; i++) {
213                hwp->writeDacWriteAddr(hwp, i);
214                hwp->writeDacData(hwp, colors[i].red);
215                hwp->writeDacData(hwp, colors[i].green);
216                hwp->writeDacData(hwp, colors[i].blue);
217            }
218            break;
219        default:
220            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
221                       "Unsupported bitdepth: %d\n", pScrn->bitsPerPixel);
222            break;
223    }
224    hwp->disablePalette(hwp);
225}
226
227void
228ViaGammaDisable(ScrnInfoPtr pScrn)
229{
230    VIAPtr pVia = VIAPTR(pScrn);
231    vgaHWPtr hwp = VGAHWPTR(pScrn);
232
233    switch (pVia->Chipset) {
234        case VIA_CLE266:
235        case VIA_KM400:
236            ViaSeqMask(hwp, 0x16, 0x00, 0x80);
237            break;
238        default:
239            ViaCrtcMask(hwp, 0x33, 0x00, 0x80);
240            break;
241    }
242
243    /* Disable gamma on secondary */
244    /* This is needed or the hardware will lockup */
245    ViaSeqMask(hwp, 0x1A, 0x00, 0x01);
246    ViaCrtcMask(hwp, 0x6A, 0x00, 0x02);
247    switch (pVia->Chipset) {
248        case VIA_CLE266:
249        case VIA_KM400:
250        case VIA_K8M800:
251        case VIA_PM800:
252            break;
253        default:
254            ViaCrtcMask(hwp, 0x6A, 0x00, 0x20);
255            break;
256    }
257}
258
259void
260ViaCRTCInit(ScrnInfoPtr pScrn)
261{
262    vgaHWPtr hwp = VGAHWPTR(pScrn);
263
264    hwp->writeSeq(hwp, 0x10, 0x01); /* unlock extended registers */
265    ViaCrtcMask(hwp, 0x47, 0x00, 0x01); /* unlock CRT registers */
266    ViaCRTCSetGraphicsRegisters(pScrn);
267    ViaCRTCSetAttributeRegisters(pScrn);
268}
269
270/*
271 * Initialize common IGA (Integrated Graphics Accelerator) registers.
272 */
273void
274viaIGAInitCommon(ScrnInfoPtr pScrn)
275{
276    vgaHWPtr hwp = VGAHWPTR(pScrn);
277    VIAPtr pVia = VIAPTR(pScrn);
278#ifdef HAVE_DEBUG
279    CARD8 temp;
280#endif
281
282    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
283                        "Entered viaIGAInitCommon.\n"));
284
285    /* Unlock VIA Technologies extended VGA registers. */
286    /* 3C5.10[0] - Unlock Accessing of I/O Space
287     *             0: Disable
288     *             1: Enable */
289    ViaSeqMask(hwp, 0x10, 0x01, 0x01);
290
291    ViaCRTCSetGraphicsRegisters(pScrn);
292    ViaCRTCSetAttributeRegisters(pScrn);
293
294#ifdef HAVE_DEBUG
295    temp = hwp->readSeq(hwp, 0x15);
296    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
297                        "SR15: 0x%02X\n", temp));
298    temp = hwp->readSeq(hwp, 0x19);
299    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
300                        "SR19: 0x%02X\n", temp));
301    temp = hwp->readSeq(hwp, 0x1A);
302    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
303                        "SR1A: 0x%02X\n", temp));
304    temp = hwp->readSeq(hwp, 0x1B);
305    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
306                        "SR1B: 0x%02X\n", temp));
307    temp = hwp->readSeq(hwp, 0x1E);
308    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
309                        "SR1E: 0x%02X\n", temp));
310    temp = hwp->readSeq(hwp, 0x2A);
311    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
312                        "SR2A: 0x%02X\n", temp));
313    temp = hwp->readSeq(hwp, 0x2D);
314    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
315                        "SR2D: 0x%02X\n", temp));
316    temp = hwp->readSeq(hwp, 0x2E);
317    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
318                        "SR2E: 0x%02X\n", temp));
319    temp = hwp->readSeq(hwp, 0x3F);
320    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
321                        "SR3F: 0x%02X\n", temp));
322    temp = hwp->readSeq(hwp, 0x65);
323    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
324                        "SR65: 0x%02X\n", temp));
325    temp = hwp->readCrtc(hwp, 0x36);
326    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
327                        "CR36: 0x%02X\n", temp));
328
329    /* For UniChrome Pro and Chrome9. */
330    if ((pVia->Chipset != VIA_CLE266)
331        && (pVia->Chipset != VIA_KM400)) {
332        temp = hwp->readCrtc(hwp, 0x47);
333        DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
334                            "CR47: 0x%02X\n", temp));
335    }
336
337    temp = hwp->readCrtc(hwp, 0x6B);
338    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
339                        "CR6B: 0x%02X\n", temp));
340
341    if (pVia->Chipset == VIA_CLE266) {
342        temp = hwp->readCrtc(hwp, 0x6C);
343        DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
344                            "CR6C: 0x%02X\n", temp));
345    }
346
347#endif
348
349    /* Be careful with 3C5.15[5] - Wrap Around Disable.
350     * It must be set to 1 for correct operation. */
351    /* 3C5.15[7]   - 8/6 Bits LUT
352     *               0: 6-bit
353     *               1: 8-bit
354     * 3C5.15[6]   - Text Column Control
355     *               0: 80 column
356     *               1: 132 column
357     * 3C5.15[5]   - Wrap Around Disable
358     *               0: Disable (For Mode 0-13)
359     *               1: Enable
360     * 3C5.15[4]   - Hi Color Mode Select
361     *               0: 555
362     *               1: 565
363     * 3C5.15[3:2] - Display Color Depth Select
364     *               00: 8bpp
365     *               01: 16bpp
366     *               10: 30bpp
367     *               11: 32bpp
368     * 3C5.15[1]   - Extended Display Mode Enable
369     *               0: Disable
370     *               1: Enable
371     * 3C5.15[0]   - Reserved */
372    ViaSeqMask(hwp, 0x15, 0x22, 0x62);
373
374    /* 3C5.19[7] - Reserved
375     * 3C5.19[6] - MIU/AGP Interface Clock Control
376     *             0: Clocks always on
377     *             1: Enable clock gating
378     * 3C5.19[5] - P-Arbiter Interface Clock Control
379     *             0: Clocks always on
380     *             1: Enable clock gating
381     * 3C5.19[4] - AGP Interface Clock Control
382     *             0: Clocks always on
383     *             1: Enable clock gating
384     * 3C5.19[3] - Typical Arbiter Interface Clock Control
385     *             0: Clocks always on
386     *             1: Enable clock gating
387     * 3C5.19[2] - MC Interface Clock Control
388     *             0: Clocks always on
389     *             1: Enable clock gating
390     * 3C5.19[1] - Display Interface Clock Control
391     *             0: Clocks always on
392     *             1: Enable clock gating
393     * 3C5.19[0] - CPU Interface Clock Control
394     *             0: Clocks always on
395     *             1: Enable clock gating */
396    ViaSeqMask(hwp, 0x19, 0x7F, 0x7F);
397
398    /* 3C5.1A[7] - Read Cache Enable
399     *             0: Disable
400     *             1: Enable
401     * 3C5.1A[6] - Software Reset
402     *             0: Default value
403     *             1: Reset
404     * 3C5.1A[5] - DVI Sense
405     *             0: No connect
406     *             1: Connected
407     * 3C5.1A[4] - Second DVI Sense
408     *             0: No connect
409     *             1: Connected
410     * 3C5.1A[3] - Extended Mode Memory Access Enable
411     *             0: Disable
412     *             1: Enable
413     * 3C5.1A[2] - PCI Burst Write Wait State Select
414     *             0: 0 Wait state
415     *             1: 1 Wait state
416     * 3C5.1A[1] - Reserved
417     * 3C5.1A[0] - LUT Shadow Access
418     *             0: 3C6/3C7/3C8/3C9 addresses map to
419     *                Primary Display’s LUT
420     *             1: 3C6/3C7/3C8/3C9 addresses map to
421     *                Secondary Display’s LUT */
422    ViaSeqMask(hwp, 0x1A, 0x88, 0xC8);
423
424    /* Set DVP0 data drive strength to 0b11 (highest). */
425    /* 3C5.1B[1]   - DVP0 Data Drive Strength Bit [0]
426     *              (It could be for DIP0 (Digital Interface Port 0) for
427     *              CLE266. Reserved for CX700 / VX700 / VX800 / VX855 /
428     *              VX900. These newer devices do not have DVP0.) */
429    ViaSeqMask(hwp, 0x1B, 0x02, 0x02);
430
431    /* Set DVP0 clock drive strength to 0b11 (highest). */
432    /* 3C5.1E[7:6] - Video Capture Port Power Control
433     *               0x: Pad always off
434     *               10: Depend on the other control signal
435     *               11: Pad on/off according to the PMS
436     * 3C5.1E[5:4] - Digital Video Port 1 Power Control
437     *               0x: Pad always off
438     *               10: Depend on the other control signal
439     *               11: Pad on/off according to the PMS
440     * 3C5.1E[3]   - Spread Spectrum On/Off
441     *               0: Off
442     *               1: On
443     * 3C5.1E[2]   - DVP0 Clock Drive Strength Bit [0]
444     *               (It could be for DIP0 (Digital Interface Port 0) for
445     *               CLE266. Reserved for CX700 / VX700 / VX800 / VX855 /
446     *               VX900. These newer devices do not have DVP0.)
447     * 3C5.1E[1]   - Replace ECK by MCK
448     *               For BIST purpose.
449     * 3C5.1E[0]   - On/Off ROC ECK
450     *               0: Off
451     *               1: On */
452    ViaSeqMask(hwp, 0x1E, 0xF4, 0xF4);
453
454    /* Set DVP0 data drive strength to 0b11 (highest). */
455    /* Set DVP0 clock drive strength to 0b11 (highest). */
456    /* 3C5.2A[7]   - Reserved
457     * 3C5.2A[6]   - The Spread Spectrum Type Control
458     *               0: Original Type
459     *               1: FIFO Type
460     * 3C5.2A[5]   - DVP0 Data Drive Strength Bit [1]
461     *               (Reserved for CX700 / VX700 / VX800 / VX855 /
462     *               VX900. These devices do not have DVP0.)
463     * 3C5.2A[4]   - DVP0 Clock Drive Strength Bit [1]
464     *               (Reserved for CX700 / VX700 / VX800 / VX855 /
465     *               VX900. These devices do not have DVP0.)
466     * 3C5.2A[3:2] - LVDS Channel 2 I/O Pad Control
467     *               0x: Pad always off
468     *               10: Depend on the other control signal
469     *               11: Pad on/off according to the PMS
470     * 3C5.2A[1:0] - LVDS Channel 1 and DVI I/O Pad Control
471     *               0x: Pad always off
472     *               10: Depend on the other control signal
473     *               11: Pad on/off according to the PMS */
474    ViaSeqMask(hwp, 0x2A, 0x3F, 0x3F);
475
476    /* 3C5.2D[7:6] - E3_ECK_N Selection
477     *               00: E3_ECK_N
478     *               01: E3_ECK
479     *               10: delayed E3_ECK_N
480     *               11: delayed E3_ECK
481     * 3C5.2D[5:4] - VCK (Primary Display Clock) PLL Power Control
482     *               0x: PLL power-off
483     *               10: PLL always on
484     *               11: PLL on/off according to the PMS
485     * 3C5.2D[3:2] - LCK (Secondary Display Clock) PLL Power Control
486     *               0x: PLL power-off
487     *               10: PLL always on
488     *               11: PLL on/off according to the PMS
489     * 3C5.2D[1:0] - ECK (Engine Clock) PLL Power Control
490     *               0x: PLL power-off
491     *               10: PLL always on
492     *               11: PLL on/off according to the PMS */
493    ViaSeqMask(hwp, 0x2D, 0x03, 0xC3);
494
495    /* In Wyse X class mobile thin client, it was observed that setting
496     * SR2E[3:2] (3C5.2E[3:2]; PCI Master / DMA) to 0b11 (clock on / off
497     * according to the engine IDLE status) causes an X.Org Server boot
498     * failure. Setting this register to 0b10 (clock always on) corrects
499     * the problem. */
500    /* 3C5.2E[7:6] - Capturer (Gated Clock <ECK>)
501     *               0x: Clock off
502     *               10: Clock always on
503     *               11: Clock on/off according to the engine IDLE status
504     * 3C5.2E[5:4] - Video Processor (Gated Clock <ECK>)
505     *               0x: Clock off
506     *               10: Clock always on
507     *               11: Clock on/off according to the engine IDLE status
508     * 3C5.2E[3:2] - PCI Master/DMA (Gated Clock <ECK/CPUCK>)
509     *               0x: Clock off
510     *               10: Clock always on
511     *               11: Clock on/off according to the engine IDLE status
512     * 3C5.2E[1:0] - Video Playback Engine (V3/V4 Gated Clock <VCK>)
513     *               0x: Clock off
514     *               10: Clock always on
515     *               11: Clock on/off according to the engine IDLE status */
516    ViaSeqMask(hwp, 0x2E, 0xFB, 0xFF);
517
518    /* 3C5.3F[7:6] - CR Clock Control (Gated Clock <ECK>)
519     *               0x: Clock off
520     *               10: Clock always on
521     *               11: Clock on/off according to the engine IDLE status
522     * 3C5.3F[5:4] - 3D Clock Control (Gated Clock <ECK>)
523     *               0x: Clock off
524     *               10: Clock always on
525     *               11: Clock on/off according to the engine IDLE status
526     * 3C5.3F[3:2] - 2D Clock Control (Gated Clock <ECK/CPUCK>)
527     *               0x: Clock off
528     *               10: Clock always on
529     *               11: Clock on/off according to the engine IDLE status
530     * 3C5.3F[1:0] - Video Clock Control (Gated Clock <ECK>)
531     *               0x: Clock off
532     *               10: Clock always on
533     *               11: Clock on/off according to each engine IDLE status */
534    ViaSeqMask(hwp, 0x3F, 0xFF, 0xFF);
535
536    /* Set DVP1 data drive strength to 0b11 (highest). */
537    /* Set DVP1 clock drive strength to 0b11 (highest). */
538    /* 3C5.65[3:2] - DVP1 Clock Pads Driving Select
539     *               00: lowest
540     *               01: low
541     *               10: high
542     *               11: highest
543     * 3C5.65[1:0] - DVP1 Data Pads Driving Select
544     *               00: lowest
545     *               01: low
546     *               10: high
547     *               11: highest */
548    ViaSeqMask(hwp, 0x65, 0x0F, 0x0F);
549
550    /* 3X5.36[7]   - DPMS VSYNC Output
551     * 3X5.36[6]   - DPMS HSYNC Output
552     * 3X5.36[5:4] - DPMS Control
553     *               00: On
554     *               01: Stand-by
555     *               10: Suspend
556     *               11: Off
557     *               When the DPMS state is off, both HSYNC and VSYNC
558     *               are grounded, saving monitor power consumption.
559     * 3X5.36[3]   - Horizontal Total Bit [8]
560     * 3X5.36[2:1] - Reserved
561     * 3X5.36[0]   - PCI Power Management Control
562     *               0: Disable
563     *               1: Enable */
564    ViaCrtcMask(hwp, 0x36, 0x01, 0x01);
565
566    /* For UniChrome Pro and Chrome9. */
567    if ((pVia->Chipset != VIA_CLE266)
568        && (pVia->Chipset != VIA_KM400)) {
569        /* 3X5.47[7] - IGA1 Timing Plus 2 VCK
570         * 3X5.47[6] - IGA1 Timing Plus 4 VCK
571         * 3X5.47[5] - Peep at the PCI-bus
572         *             0: Disable
573         *             1: Enable
574         * 3X5.47[4] - Reserved
575         * 3X5.47[3] - IGA1 Timing Plus 6 VCK
576         * 3X5.47[2] - DACOFF Backdoor Register
577         * 3X5.47[1] - LCD Simultaneous Mode Backdoor Register for
578         *             8/9 Dot Clocks
579         * 3X5.47[0] - LCD Simultaneous Mode Backdoor Register for
580         *             Clock Select and CRTC Register Protect
581         *
582         */
583        ViaCrtcMask(hwp, 0x47, 0x00, 0x23);
584    }
585
586    /* 3X5.6B[3] - Simultaneous Display Enable
587     *             0: Disable
588     *             1: Enable */
589    ViaCrtcMask(hwp, 0x6B, 0x00, 0x08);
590
591    /* CLE266 only. */
592    if (pVia->Chipset == VIA_CLE266) {
593        /* The following register fields are for CLE266 only. */
594        /* 3X5.6C - Digital Interface Port 0 (DIP0) Control
595         * 3X5.6C[7]   - DIP0 Source
596         *               0: IGA1
597         *               1: IGA2
598         * 3X5.6C[4:2] - Appears to be related to DIP0 signal polarity
599         *               control. Used by CLE266A2 to workaround a bug when
600         *               it is utilizing an external TV encoder.
601         * 3X5.6C[1]   - Appears to be utilized when CLE266 is utilizing an
602         *               external TV encoder.
603         * 3X5.6C[0]   - Appears to be a bit to control internal / external
604         *               clock source or whether or not the VCK (IGA1 clock
605         *               source) comes from VCK PLL or from an external
606         *               source. This bit should be set to 1 when TV encoder
607         *               is in use. */
608        ViaCrtcMask(hwp, 0x6C, 0x00, 0x01);
609    }
610
611    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
612                        "Exiting viaIGAInitCommon.\n"));
613}
614
615/*
616 * Initialize IGA1 (Integrated Graphics Accelerator) registers.
617 */
618void
619viaIGA1Init(ScrnInfoPtr pScrn)
620{
621    vgaHWPtr hwp = VGAHWPTR(pScrn);
622    VIAPtr pVia = VIAPTR(pScrn);
623#ifdef HAVE_DEBUG
624    CARD8 temp;
625#endif
626
627    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
628                        "Entered viaIGA1Init.\n"));
629
630#ifdef HAVE_DEBUG
631    temp = hwp->readSeq(hwp, 0x1B);
632    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
633                        "SR1B: 0x%02X\n", temp));
634    temp = hwp->readSeq(hwp, 0x2D);
635    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
636                        "SR2D: 0x%02X\n", temp));
637    temp = hwp->readCrtc(hwp, 0x32);
638    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
639                        "CR32: 0x%02X\n", temp));
640    temp = hwp->readCrtc(hwp, 0x33);
641    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
642                        "CR33: 0x%02X\n", temp));
643
644    /* For UniChrome Pro and Chrome9. */
645    if ((pVia->Chipset != VIA_CLE266)
646        && (pVia->Chipset != VIA_KM400)) {
647        temp = hwp->readCrtc(hwp, 0x47);
648        DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
649                            "CR47: 0x%02X\n", temp));
650    }
651
652    temp = hwp->readCrtc(hwp, 0x6B);
653    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
654                        "CR6B: 0x%02X\n", temp));
655
656    /* For UniChrome Pro and Chrome9. */
657    if ((pVia->Chipset != VIA_CLE266)
658        && (pVia->Chipset != VIA_KM400)) {
659        temp = hwp->readCrtc(hwp, 0x6C);
660        DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
661                            "CR6C: 0x%02X\n", temp));
662    }
663
664#endif
665
666    /* 3C5.1B[7:6] - Secondary Display Engine (Gated Clock <LCK>)
667     *               0x: Clock always off
668     *               10: Clock always on
669     *               11: Clock on/off according to the
670     *                   Power Management Status (PMS)
671     * 3C5.1B[5:4] - Primary Display Engine (Gated Clock <VCK>)
672     *               0x: Clock always off
673     *               10: Clock always on
674     *               11: Clock on/off according to the PMS
675     * 3C5.1B[3:1] - Reserved
676     * 3C5.1B[0]   - Primary Display’s LUT On/Off
677     *               0: On
678     *               1: Off */
679    ViaSeqMask(hwp, 0x1B, 0x30, 0x31);
680
681    /* 3C5.2D[7:6] - E3_ECK_N Selection
682     *               00: E3_ECK_N
683     *               01: E3_ECK
684     *               10: delayed E3_ECK_N
685     *               11: delayed E3_ECK
686     * 3C5.2D[5:4] - VCK (Primary Display Clock) PLL Power Control
687     *               0x: PLL power-off
688     *               10: PLL always on
689     *               11: PLL on/off according to the PMS
690     * 3C5.2D[3:2] - LCK (Secondary Display Clock) PLL Power Control
691     *               0x: PLL power-off
692     *               10: PLL always on
693     *               11: PLL on/off according to the PMS
694     * 3C5.2D[1:0] - ECK (Engine Clock) PLL Power Control
695     *               0x: PLL power-off
696     *               10: PLL always on
697     *               11: PLL on/off according to the PMS */
698    ViaSeqMask(hwp, 0x2D, 0x30, 0x30);
699
700    /* 3X5.32[7:5] - HSYNC Delay Number by VCLK
701     *               000: No delay
702     *               001: Delay + 4 VCKs
703     *               010: Delay + 8 VCKs
704     *               011: Delay + 12 VCKs
705     *               100: Delay + 16 VCKs
706     *               101: Delay + 20 VCKs
707     *               Others: Undefined
708     * 3X5.32[4]   - Reserved
709     * 3X5.32[3]   - CRT SYNC Driving Selection
710     *               0: Low
711     *               1: High
712     * 3X5.32[2]   - Display End Blanking Enable
713     *               0: Disable
714     *               1: Enable
715     * 3X5.32[1]   - Digital Video Port (DVP) Gamma Correction
716     *               If the gamma correction of primary display is
717     *               turned on, the gamma correction in DVP can be
718     *               enabled / disabled by this bit.
719     *               0: Disable
720     *               1: Enable
721     * 3X5.32[0]   - Real-Time Flipping
722     *               0: Flip by the frame
723     *               1: Flip by each scan line */
724    ViaCrtcMask(hwp, 0x32, 0x04, 0xEF);
725
726    /* Keep interlace mode off.
727     * No shift for HSYNC.*/
728    /* 3X5.33[7]   - Primary Display Gamma Correction
729     *               0: Disable
730     *               1: Enable
731     * 3X5.33[6]   - Primary Display Interlace Mode
732     *               0: Disable
733     *               1: Enable
734     * 3X5.33[5]   - Horizontal Blanking End Bit [6]
735     * 3X5.33[4]   - Horizontal Synchronization Start Bit [8]
736     * 3X5.33[3]   - Prefetch Mode
737     *               0: Disable
738     *               1: Enable
739     * 3X5.33[2:0] - The Value will Shift the HSYNC to be Early than Planned
740     *               000: Shift to early time by 3 characters
741     *                    (VGA mode suggested value; default value)
742     *               001: Shift to early time by 4 characters
743     *               010: Shift to early time by 5 characters
744     *               011: Shift to early time by 6 characters
745     *               100: Shift to early time by 7 characters
746     *               101: Shift to early time by 0 character
747     *                    (Non-VGA mode suggested value)
748     *               110: Shift to early time by 1 character
749     *               111: Shift to early time by 2 characters */
750    ViaCrtcMask(hwp, 0x33, 0x05, 0xCF);
751
752    /* For UniChrome Pro and Chrome9. */
753    if ((pVia->Chipset != VIA_CLE266)
754        && (pVia->Chipset != VIA_KM400)) {
755        /* 3X5.47[7] - IGA1 Timing Plus 2 VCK
756         * 3X5.47[6] - IGA1 Timing Plus 4 VCK
757         * 3X5.47[5] - Peep at the PCI-bus
758         *             0: Disable
759         *             1: Enable
760         * 3X5.47[4] - Reserved
761         * 3X5.47[3] - IGA1 Timing Plus 6 VCK
762         * 3X5.47[2] - DACOFF Backdoor Register
763         * 3X5.47[1] - LCD Simultaneous Mode Backdoor Register for
764         *             8/9 Dot Clocks
765         * 3X5.47[0] - LCD Simultaneous Mode Backdoor Register for
766         *             Clock Select and CRTC Register Protect */
767        ViaCrtcMask(hwp, 0x47, 0x00, 0xCC);
768    }
769
770    /* TV out uses division by 2 mode.
771     * Other devices like analog (VGA), DVI, flat panel, etc.,
772     * use normal mode. */
773    /* 3X5.6B[7:6] - First Display Channel Clock Mode Selection
774     *               0x: Normal
775     *               1x: Division by 2 */
776    ViaCrtcMask(hwp, 0x6B, 0x00, 0xC0);
777
778    /* For UniChrome Pro and Chrome9. */
779    if ((pVia->Chipset != VIA_CLE266)
780        && (pVia->Chipset != VIA_KM400)) {
781        /* The following register fields are for UniChrome Pro and Chrome9. */
782        /* 3X5.6C[7:5] - VCK PLL Reference Clock Source Selection
783         *               000: From XI pin
784         *               001: From TVXI
785         *               01x: From TVPLL
786         *               100: DVP0TVCLKR
787         *               101: DVP1TVCLKR
788         *               110: CAP0 Clock
789         *               111: CAP1 Clock
790         * 3X5.6C[4]   - VCK Source Selection
791         *               0: VCK PLL output clock
792         *               1: VCK PLL reference clock */
793        ViaCrtcMask(hwp, 0x6C, 0x00, 0xF0);
794    }
795
796    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
797                        "Exiting viaIGA1Init.\n"));
798}
799
800void
801viaIGA1SetFBStartingAddress(xf86CrtcPtr crtc, int x, int y)
802{
803    ScrnInfoPtr pScrn = crtc->scrn;
804    VIAPtr pVia = VIAPTR(pScrn);
805    vgaHWPtr hwp = VGAHWPTR(pScrn);
806    drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
807    drmmode_ptr drmmode = drmmode_crtc->drmmode;
808    CARD32 Base;
809    CARD8 cr0c, cr0d, cr34, cr48;
810
811    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
812                        "Entered viaIGA1SetFBStartingAddress.\n"));
813
814    Base = (y * pScrn->displayWidth + x) * (pScrn->bitsPerPixel / 8);
815    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
816                        "Base Address: 0x%lx\n",
817                        Base));
818    Base = (Base + drmmode->front_bo->offset) >> 1;
819    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
820                "DRI Base Address: 0x%lx\n",
821                Base);
822
823    hwp->writeCrtc(hwp, 0x0D, Base & 0xFF);
824    hwp->writeCrtc(hwp, 0x0C, (Base & 0xFF00) >> 8);
825
826    if (!(pVia->Chipset == VIA_CLE266 && CLE266_REV_IS_AX(pVia->ChipRev))) {
827        ViaCrtcMask(hwp, 0x48, Base >> 24, 0x1F);
828    }
829
830    /* CR34 are fire bits. Must be written after CR0C, CR0D, and CR48. */
831    hwp->writeCrtc(hwp, 0x34, (Base & 0xFF0000) >> 16);
832
833#ifdef HAVE_DEBUG
834    cr0d = hwp->readCrtc(hwp, 0x0D);
835    cr0c = hwp->readCrtc(hwp, 0x0C);
836    cr34 = hwp->readCrtc(hwp, 0x34);
837    if (!(pVia->Chipset == VIA_CLE266 && CLE266_REV_IS_AX(pVia->ChipRev))) {
838        cr48 = hwp->readCrtc(hwp, 0x48);
839    }
840
841    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
842                        "CR0D: 0x%02X\n", cr0d));
843    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
844                        "CR0C: 0x%02X\n", cr0c));
845    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
846                        "CR34: 0x%02X\n", cr34));
847    if (!(pVia->Chipset == VIA_CLE266 && CLE266_REV_IS_AX(pVia->ChipRev))) {
848        DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
849                            "CR48: 0x%02X\n", cr48));
850    }
851
852#endif
853
854    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
855                        "Exiting viaIGA1SetFBStartingAddress.\n"));
856}
857
858void
859viaIGA1SetDisplayRegister(ScrnInfoPtr pScrn, DisplayModePtr mode)
860{
861    vgaHWPtr hwp = VGAHWPTR(pScrn);
862    VIAPtr pVia = VIAPTR(pScrn);
863    CARD16 temp;
864
865    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
866                        "Entered viaIGA1SetDisplayRegister.\n"));
867
868    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
869                "IGA1 Requested Screen Mode: %s\n", mode->name);
870
871    ViaCrtcMask(hwp, 0x11, 0x00, 0x80); /* modify starting address */
872    ViaCrtcMask(hwp, 0x03, 0x80, 0x80); /* enable vertical retrace access */
873
874    /* Set Misc Register */
875    temp = 0x23;
876    if (mode->Flags & V_NHSYNC)
877        temp |= 0x40;
878    if (mode->Flags & V_NVSYNC)
879        temp |= 0x80;
880    temp |= 0x0C; /* Undefined/external clock */
881    hwp->writeMiscOut(hwp, temp);
882
883    /* Sequence registers */
884    hwp->writeSeq(hwp, 0x00, 0x00);
885
886#if 0
887    if (mode->Flags & V_CLKDIV2)
888        hwp->writeSeq(hwp, 0x01, 0x09);
889    else
890#endif
891        hwp->writeSeq(hwp, 0x01, 0x01);
892
893    hwp->writeSeq(hwp, 0x02, 0x0F);
894    hwp->writeSeq(hwp, 0x03, 0x00);
895    hwp->writeSeq(hwp, 0x04, 0x0E);
896
897
898    /* Setting maximum scan line to 0. */
899    /* 3X5.09[4:0] - Maximum Scan Line */
900    ViaCrtcMask(hwp, 0x09, 0x00, 0x1F);
901
902
903    /* 3X5.14[6]   - Double Word Mode
904     *               Allows normal addressing or double-word addressing.
905     *               0: Normal word addressing
906     *               1: Double word addressing
907     * 3X5.14[4:0] - Underline Location */
908    ViaCrtcMask(hwp, 0x14, 0x00, 0x5F);
909
910
911    /* We are not using the split screen feature so line compare register
912     * should be set to 0x7FF. */
913    temp = 0x7FF;
914
915    /* 3X5.18[7:0] - Line Compare Bits [7:0] */
916    hwp->writeCrtc(hwp, 0x18, temp & 0xFF);
917
918    /* 3X5.07[4] - Line Compare Bit [8] */
919    ViaCrtcMask(hwp, 0x07, temp >> 4, 0x10);
920
921    /* 3X5.09[6] - Line Compare Bit [9] */
922    ViaCrtcMask(hwp, 0x09, temp >> 3, 0x40);
923
924    /* 3X5.35[4] - Line Compare Bit [10] */
925    ViaCrtcMask(hwp, 0x35, temp >> 6, 0x10);
926
927
928    /* Set the color depth for IGA1. */
929    switch (pScrn->bitsPerPixel) {
930    case 8:
931        /* Only CLE266.AX uses 6-bit LUT. */
932        if (pVia->Chipset == VIA_CLE266 && pVia->ChipRev < 15) {
933            /* 6-bit LUT */
934            /* 3C5.15[7]   - 8/6 Bits LUT
935             *               0: 6-bit
936             *               1: 8-bit
937             * 3C5.15[4]   - Hi Color Mode Select
938             *               0: 555
939             *               1: 565
940             * 3C5.15[3:2] - Display Color Depth Select
941             *               00: 8bpp
942             *               01: 16bpp
943             *               10: 30bpp
944             *               11: 32bpp */
945            ViaSeqMask(hwp, 0x15, 0x00, 0x9C);
946        } else {
947            /* 8-bit LUT */
948            ViaSeqMask(hwp, 0x15, 0x80, 0x9C);
949        }
950
951        break;
952    case 16:
953        ViaSeqMask(hwp, 0x15, 0x94, 0x9C);
954        break;
955    case 24:
956    case 32:
957        ViaSeqMask(hwp, 0x15, 0x9C, 0x9C);
958        break;
959    default:
960        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
961                    "Unsupported color depth: %d\n",
962                    pScrn->bitsPerPixel);
963        break;
964    }
965
966
967    /* 3X5.32[7:5] - HSYNC Delay Number by VCLK
968     *               000: No delay
969     *               001: Delay + 4 VCKs
970     *               010: Delay + 8 VCKs
971     *               011: Delay + 12 VCKs
972     *               100: Delay + 16 VCKs
973     *               101: Delay + 20 VCKs
974     *               Others: Undefined
975     * 3X5.32[4]   - Reserved
976     * 3X5.32[3]   - CRT SYNC Driving Selection
977     *               0: Low
978     *               1: High
979     * 3X5.32[2]   - Display End Blanking Enable
980     *               0: Disable
981     *               1: Enable
982     * 3X5.32[1]   - Digital Video Port (DVP) Gamma Correction
983     *               If the gamma correction of primary display is
984     *               turned on, the gamma correction in DVP can be
985     *               enabled / disabled by this bit.
986     *               0: Disable
987     *               1: Enable
988     * 3X5.32[0]   - Real-Time Flipping
989     *               0: Flip by the frame
990     *               1: Flip by each scan line */
991    ViaCrtcMask(hwp, 0x32, 0x04, 0xEC);
992
993    /* Keep interlace mode off.
994     * No shift for HSYNC.*/
995    /* 3X5.33[7]   - Primary Display Gamma Correction
996     *               0: Disable
997     *               1: Enable
998     * 3X5.33[6]   - Primary Display Interlace Mode
999     *               0: Disable
1000     *               1: Enable
1001     * 3X5.33[5]   - Horizontal Blanking End Bit [6]
1002     * 3X5.33[4]   - Horizontal Synchronization Start Bit [8]
1003     * 3X5.33[3]   - Prefetch Mode
1004     *               0: Disable
1005     *               1: Enable
1006     * 3X5.33[2:0] - The Value will Shift the HSYNC to be Early than Planned
1007     *               000: Shift to early time by 3 characters
1008     *                    (VGA mode suggested value; default value)
1009     *               001: Shift to early time by 4 characters
1010     *               010: Shift to early time by 5 characters
1011     *               011: Shift to early time by 6 characters
1012     *               100: Shift to early time by 7 characters
1013     *               101: Shift to early time by 0 character
1014     *                    (Non-VGA mode suggested value)
1015     *               110: Shift to early time by 1 character
1016     *               111: Shift to early time by 2 characters */
1017    ViaCrtcMask(hwp, 0x33, 0x05, 0x4F);
1018
1019    /* Set IGA1 to linear mode */
1020    /* 3X5.43[2]  - IGA1 Address Mode Selection
1021     *              0: Linear
1022     *              1: Tile */
1023    ViaCrtcMask(hwp, 0x43, 0x00, 0x04);
1024
1025
1026    /* Set IGA1 horizontal total.*/
1027    /* Due to IGA1 horizontal total being only 9 bits wide,
1028     * the adjusted horizontal total needs to be shifted by
1029     * 3 bit positions to the right.
1030     * In addition to that, this particular register requires the
1031     * value to be 5 less than the actual value being written. */
1032    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1033                        "IGA1 CrtcHTotal: %d\n", mode->CrtcHTotal));
1034    temp = (mode->CrtcHTotal >> 3) - 5;
1035
1036    /* 3X5.00[7:0] - Horizontal Total Bits [7:0] */
1037    hwp->writeCrtc(hwp, 0x00, temp & 0xFF);
1038
1039    /* 3X5.36[3] - Horizontal Total Bit [8] */
1040    ViaCrtcMask(hwp, 0x36, temp >> 5, 0x08);
1041
1042
1043    /* Set IGA1 horizontal display end. */
1044    /* Due to IGA1 horizontal display end being only 8 bits wide,
1045     * the adjusted horizontal display end needs to be shifted by
1046     * 3 bit positions to the right.
1047     * In addition to that, this particular register requires the
1048     * value to be 1 less than the actual value being written. */
1049    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1050                        "IGA1 CrtcHDisplay: %d\n", mode->CrtcHDisplay));
1051    temp = (mode->CrtcHDisplay >> 3) - 1;
1052
1053    /* 3X5.01[7:0] - Horizontal Display End Bits [7:0] */
1054    hwp->writeCrtc(hwp, 0x01, temp & 0xFF);
1055
1056
1057    /* Set IGA1 horizontal blank start. */
1058    /* Due to IGA1 horizontal blank start being only 8 bits wide,
1059     * the adjusted horizontal blank start needs to be shifted by
1060     * 3 bit positions to the right. */
1061    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1062                        "IGA1 CrtcHBlankStart: %d\n", mode->CrtcHBlankStart));
1063    temp = mode->CrtcHBlankStart >> 3;
1064
1065    /* 3X5.02[7:0] - Horizontal Blanking Start Bits [7:0] */
1066     hwp->writeCrtc(hwp, 0x02, temp & 0xFF);
1067
1068
1069    /* Set IGA1 horizontal blank end. */
1070    /* After shifting horizontal blank end by 3 bit positions to the
1071     * right, the 7 least significant bits are actually used.
1072     * In addition to that, this particular register requires the
1073     * value to be 1 less than the actual value being written. */
1074    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1075                        "IGA1 CrtcHBlankEnd: %d\n", mode->CrtcHBlankEnd));
1076    temp = (mode->CrtcHBlankEnd >> 3) - 1;
1077
1078    /* 3X5.03[4:0] - Horizontal Blanking End Bits [4:0] */
1079    ViaCrtcMask(hwp, 0x03, temp, 0x1F);
1080
1081    /* 3X5.05[7] - Horizontal Blanking End Bit [5] */
1082    ViaCrtcMask(hwp, 0x05, temp << 2, 0x80);
1083
1084    /* 3X5.33[5] - Horizontal Blanking End Bit [6] */
1085    ViaCrtcMask(hwp, 0x33, temp >> 1, 0x20);
1086
1087
1088    /* Set IGA1 horizontal synchronization start. */
1089    /* Due to IGA1 horizontal synchronization start being only 9 bits wide,
1090     * the adjusted horizontal synchronization start needs to be shifted by
1091     * 3 bit positions to the right. */
1092    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1093                        "IGA1 CrtcHSyncStart: %d\n", mode->CrtcHSyncStart));
1094    temp = mode->CrtcHSyncStart >> 3;
1095
1096    /* 3X5.04[7:0] - Horizontal Retrace Start Bits [7:0] */
1097    hwp->writeCrtc(hwp, 0x04, temp & 0xFF);
1098
1099    /* 3X5.33[4] - Horizontal Retrace Start Bit [8] */
1100    ViaCrtcMask(hwp, 0x33, temp >> 4, 0x10);
1101
1102
1103    /* Set IGA1 horizontal synchronization end. */
1104    /* After shifting horizontal synchronization end by 3 bit positions
1105     * to the right, the 5 least significant bits are actually used.
1106     * In addition to that, this particular register requires the
1107     * value to be 1 less than the actual value being written. */
1108    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1109                        "IGA1 CrtcHSyncEnd: %d\n", mode->CrtcHSyncEnd));
1110    temp = (mode->CrtcHSyncEnd >> 3) - 1;
1111
1112    /* 3X5.05[4:0] - Horizontal Retrace End Bits [4:0] */
1113    ViaCrtcMask(hwp, 0x05, temp, 0x1F);
1114
1115
1116    /* Set IGA1 vertical total. */
1117    /* Vertical total requires the value to be 2 less
1118     * than the actual value being written. */
1119    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1120                        "IGA1 CrtcVTotal: %d\n", mode->CrtcVTotal));
1121    temp = mode->CrtcVTotal - 2;
1122
1123    /* 3X5.06[7:0] - Vertical Total Period Bits [7:0] */
1124    hwp->writeCrtc(hwp, 0x06, temp & 0xFF);
1125
1126    /* 3X5.07[0] - Vertical Total Period Bit [8] */
1127    ViaCrtcMask(hwp, 0x07, temp >> 8, 0x01);
1128
1129    /* 3X5.07[5] - Vertical Total Period Bit [9] */
1130    ViaCrtcMask(hwp, 0x07, temp >> 4, 0x20);
1131
1132    /* 3X5.35[0] - Vertical Total Period Bit [10] */
1133    ViaCrtcMask(hwp, 0x35, temp >> 10, 0x01);
1134
1135
1136    /* Set IGA1 vertical display end. */
1137    /* Vertical display end requires the value to be 1 less
1138     * than the actual value being written. */
1139    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1140                        "IGA1 CrtcVDisplay: %d\n", mode->CrtcVDisplay));
1141    temp = mode->CrtcVDisplay - 1;
1142
1143    /* 3X5.12[7:0] - Vertical Active Data Period Bits [7:0] */
1144    hwp->writeCrtc(hwp, 0x12, temp & 0xFF);
1145
1146    /* 3X5.07[1] - Vertical Active Data Period Bit [8] */
1147    ViaCrtcMask(hwp, 0x07, temp >> 7, 0x02);
1148
1149    /* 3X5.07[6] - Vertical Active Data Period Bit [9] */
1150    ViaCrtcMask(hwp, 0x07, temp >> 3, 0x40);
1151
1152    /* 3X5.35[2] - Vertical Active Data Period Bit [10] */
1153    ViaCrtcMask(hwp, 0x35, temp >> 8, 0x04);
1154
1155
1156    /* Set IGA1 vertical blank start. */
1157    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1158                        "IGA1 CrtcVBlankStart: %d\n", mode->CrtcVBlankStart));
1159    temp = mode->CrtcVBlankStart;
1160
1161    /* 3X5.15[7:0] - Vertical Blanking Start Bits [7:0] */
1162    hwp->writeCrtc(hwp, 0x15, temp & 0xFF);
1163
1164    /* 3X5.07[3] - Vertical Blanking Start Bit [8] */
1165    ViaCrtcMask(hwp, 0x07, temp >> 5, 0x08);
1166
1167    /* 3X5.09[5] - Vertical Blanking Start Bit [9] */
1168    ViaCrtcMask(hwp, 0x09, temp >> 4, 0x20);
1169
1170    /* 3X5.35[3] - Vertical Blanking Start Bit [10] */
1171    ViaCrtcMask(hwp, 0x35, temp >> 7, 0x08);
1172
1173
1174    /* Set IGA1 vertical blank end. */
1175    /* Vertical blank end requires the value to be 1 less
1176     * than the actual value being written, and 8 LSB
1177     * (Least Significant Bits) are written straight into the
1178     * relevant register. */
1179    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1180                        "IGA1 CrtcVBlankEnd: %d\n", mode->CrtcVBlankEnd));
1181    temp = mode->CrtcVBlankEnd - 1;
1182
1183    /* 3X5.16[7:0] - Vertical Blanking End Bits [7:0] */
1184    hwp->writeCrtc(hwp, 0x16, temp & 0xFF);
1185
1186
1187    /* Set IGA1 vertical synchronization start. */
1188    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1189                        "IGA1 CrtcVSyncStart: %d\n", mode->CrtcVSyncStart));
1190    temp = mode->CrtcVSyncStart;
1191
1192    /* 3X5.10[7:0] - Vertical Retrace Start Bits [7:0] */
1193    hwp->writeCrtc(hwp, 0x10, temp & 0xFF);
1194
1195    /* 3X5.07[2] - Vertical Retrace Start Bit [8] */
1196    ViaCrtcMask(hwp, 0x07, temp >> 6, 0x04);
1197
1198    /* 3X5.07[7] - Vertical Retrace Start Bit [9] */
1199    ViaCrtcMask(hwp, 0x07, temp >> 2, 0x80);
1200
1201    /* 3X5.35[1] - Vertical Retrace Start Bit [10] */
1202    ViaCrtcMask(hwp, 0x35, temp >> 9, 0x02);
1203
1204
1205    /* Set IGA1 vertical synchronization end. */
1206    /* Vertical synchronization end requires the value to be 1 less
1207     * than the actual value being written, and 4 LSB
1208     * (Least Significant Bits) are written straight into the
1209     * relevant register. */
1210    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1211                        "IGA1 CrtcVSyncEnd: %d\n", mode->CrtcVSyncEnd));
1212    temp = mode->CrtcVSyncEnd - 1;
1213
1214    /*3X5.11[3:0] - Vertical Retrace End Bits [3:0] */
1215    ViaCrtcMask(hwp, 0x11, temp & 0x0F, 0x0F);
1216
1217
1218    /* Set IGA1 horizontal offset adjustment. */
1219    temp = (pScrn->displayWidth * (pScrn->bitsPerPixel >> 3)) >> 3;
1220
1221    /* Make sure that this is 32-byte aligned. */
1222    if (temp & 0x03) {
1223        temp += 0x03;
1224        temp &= ~0x03;
1225    }
1226
1227    /* 3X5.13[7:0] - Primary Display Horizontal Offset Bits [7:0] */
1228    hwp->writeCrtc(hwp, 0x13, temp & 0xFF);
1229
1230    /* 3X5.35[7:5] - Primary Display Horizontal Offset Bits [10:8] */
1231    ViaCrtcMask(hwp, 0x35, temp >> 3, 0xE0);
1232
1233
1234    /* Set IGA1 horizontal display fetch (read) count. */
1235    temp = (mode->CrtcHDisplay * (pScrn->bitsPerPixel >> 3)) >> 3;
1236
1237    /* Make sure that this is 32-byte aligned. */
1238    if (temp & 0x03) {
1239        temp += 0x03;
1240        temp &= ~0x03;
1241    }
1242
1243    /* Primary Display Horizontal Display Fetch Count Data needs to be
1244     * 16-byte aligned. */
1245    temp = temp >> 1;
1246
1247    /* 3C5.1C[7:0] - Primary Display Horizontal Display
1248     *               Fetch Count Data Bits [7:0] */
1249    hwp->writeSeq(hwp, 0x1C, temp & 0xFF);
1250
1251    /* 3C5.1D[1:0] - Primary Display Horizontal Display
1252     *               Fetch Count Data Bits [9:8] */
1253    ViaSeqMask(hwp, 0x1D, temp >> 8, 0x03);
1254
1255
1256    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1257                        "Exiting viaIGA1SetDisplayRegister.\n"));
1258}
1259
1260/*
1261 * Checks for limitations imposed by the available VGA timing registers.
1262 */
1263static ModeStatus
1264viaIGA1ModeValid(ScrnInfoPtr pScrn, DisplayModePtr mode)
1265{
1266    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1267                        "Entered viaIGA1ModeValid.\n"));
1268
1269    /* Note that horizontal total being written to VGA registers is
1270     * shifted to the right by 3 bit positions since only 9 bits are
1271     * available, and then 5 is subtracted from it. Hence, to check if
1272     * the screen can even be valid, opposite of that needs to happen.
1273     * That being said, to check if the number is within an acceptable range,
1274     * 1 is subtracted from 5, hence, 4 (5 - 1) is multiplied with 8 (i.e.,
1275     * 1 is shifted 3 bit positions to the left), and the resulting 32 is
1276     * added to 4096 (9 + 3 bits) to calculate the maximum horizontal total
1277     * IGA1 can handle. Ultimately, 4128 is the largest number VIA IGP's
1278     * IGA1 can handle. */
1279    if (mode->CrtcHTotal > (4096 + ((1 << 3) * (5 - 1))))
1280        return MODE_BAD_HVALUE;
1281
1282    if (mode->CrtcHDisplay > 2048)
1283        return MODE_BAD_HVALUE;
1284
1285    if (mode->CrtcHBlankStart > 2048)
1286        return MODE_BAD_HVALUE;
1287
1288    if ((mode->CrtcHBlankEnd - mode->CrtcHBlankStart) > 1025)
1289        return MODE_HBLANK_WIDE;
1290
1291    if (mode->CrtcHSyncStart > 4095)
1292        return MODE_BAD_HVALUE;
1293
1294    if ((mode->CrtcHSyncEnd - mode->CrtcHSyncStart) > 256)
1295        return MODE_HSYNC_WIDE;
1296
1297    if (mode->CrtcVTotal > 2049)
1298        return MODE_BAD_VVALUE;
1299
1300    if (mode->CrtcVDisplay > 2048)
1301        return MODE_BAD_VVALUE;
1302
1303    if (mode->CrtcVSyncStart > 2047)
1304        return MODE_BAD_VVALUE;
1305
1306    if ((mode->CrtcVSyncEnd - mode->CrtcVSyncStart) > 16)
1307        return MODE_VSYNC_WIDE;
1308
1309    if (mode->CrtcVBlankStart > 2048)
1310        return MODE_BAD_VVALUE;
1311
1312    if ((mode->CrtcVBlankEnd - mode->CrtcVBlankStart) > 257)
1313        return MODE_VBLANK_WIDE;
1314
1315    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1316                        "Exiting viaIGA1ModeValid.\n"));
1317    return MODE_OK;
1318}
1319
1320void
1321viaIGA1Save(ScrnInfoPtr pScrn)
1322{
1323    vgaHWPtr hwp = VGAHWPTR(pScrn);
1324    VIAPtr pVia = VIAPTR(pScrn);
1325    VIARegPtr Regs = &pVia->SavedReg;
1326
1327    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1328                        "Entered viaIGA1Save.\n"));
1329
1330    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1331                        "Saving sequencer registers.\n"));
1332
1333    /* Unlock extended registers. */
1334    hwp->writeSeq(hwp, 0x10, 0x01);
1335
1336    Regs->SR14 = hwp->readSeq(hwp, 0x14);
1337    Regs->SR15 = hwp->readSeq(hwp, 0x15);
1338    Regs->SR16 = hwp->readSeq(hwp, 0x16);
1339    Regs->SR17 = hwp->readSeq(hwp, 0x17);
1340    Regs->SR18 = hwp->readSeq(hwp, 0x18);
1341    Regs->SR19 = hwp->readSeq(hwp, 0x19);
1342
1343    /* PCI Bus Control */
1344    Regs->SR1A = hwp->readSeq(hwp, 0x1A);
1345
1346    Regs->SR1B = hwp->readSeq(hwp, 0x1B);
1347    Regs->SR1C = hwp->readSeq(hwp, 0x1C);
1348    Regs->SR1D = hwp->readSeq(hwp, 0x1D);
1349    Regs->SR1E = hwp->readSeq(hwp, 0x1E);
1350    Regs->SR1F = hwp->readSeq(hwp, 0x1F);
1351
1352    Regs->SR22 = hwp->readSeq(hwp, 0x22);
1353
1354    /* Registers 3C5.23 through 3C5.25 are not used by Chrome9.
1355     * Registers 3C5.27 through 3C5.29 are not used by Chrome9. */
1356    switch (pVia->Chipset) {
1357    case VIA_CLE266:
1358    case VIA_KM400:
1359    case VIA_PM800:
1360    case VIA_K8M800:
1361    case VIA_P4M800PRO:
1362    case VIA_CX700:
1363    case VIA_P4M890:
1364        Regs->SR23 = hwp->readSeq(hwp, 0x23);
1365        Regs->SR24 = hwp->readSeq(hwp, 0x24);
1366        Regs->SR25 = hwp->readSeq(hwp, 0x25);
1367
1368        Regs->SR27 = hwp->readSeq(hwp, 0x27);
1369        Regs->SR28 = hwp->readSeq(hwp, 0x28);
1370        Regs->SR29 = hwp->readSeq(hwp, 0x29);
1371        break;
1372    default:
1373        break;
1374    }
1375
1376    Regs->SR26 = hwp->readSeq(hwp, 0x26);
1377
1378    Regs->SR2A = hwp->readSeq(hwp, 0x2A);
1379    Regs->SR2B = hwp->readSeq(hwp, 0x2B);
1380    Regs->SR2D = hwp->readSeq(hwp, 0x2D);
1381    Regs->SR2E = hwp->readSeq(hwp, 0x2E);
1382
1383    /* Save PCI Configuration Memory Base Shadow 0 and 1.
1384     * These registers are available only in UniChrome, UniChrome Pro,
1385     * and UniChrome Pro II. */
1386    switch (pVia->Chipset) {
1387    case VIA_CLE266:
1388    case VIA_KM400:
1389    case VIA_PM800:
1390    case VIA_K8M800:
1391    case VIA_P4M800PRO:
1392    case VIA_CX700:
1393    case VIA_P4M890:
1394        Regs->SR2F = hwp->readSeq(hwp, 0x2F);
1395        Regs->SR30 = hwp->readSeq(hwp, 0x30);
1396        break;
1397    default:
1398        break;
1399    }
1400
1401    /* Save PLL settings and several miscellaneous registers.
1402     * For UniChrome, register 3C5.44 through 3C5.4B are saved.
1403     * For UniChrome Pro and Chrome9, register 3C5.44 through 3C5.4C
1404     * are saved. */
1405    Regs->SR44 = hwp->readSeq(hwp, 0x44);
1406    Regs->SR45 = hwp->readSeq(hwp, 0x45);
1407    Regs->SR46 = hwp->readSeq(hwp, 0x46);
1408    Regs->SR47 = hwp->readSeq(hwp, 0x47);
1409    Regs->SR48 = hwp->readSeq(hwp, 0x48);
1410    Regs->SR49 = hwp->readSeq(hwp, 0x49);
1411    Regs->SR4A = hwp->readSeq(hwp, 0x4A);
1412    Regs->SR4B = hwp->readSeq(hwp, 0x4B);
1413
1414    switch (pVia->Chipset) {
1415    case VIA_PM800:
1416    case VIA_K8M800:
1417    case VIA_P4M800PRO:
1418    case VIA_CX700:
1419    case VIA_P4M890:
1420    case VIA_K8M890:
1421    case VIA_P4M900:
1422    case VIA_VX800:
1423    case VIA_VX855:
1424    case VIA_VX900:
1425
1426        Regs->SR4C = hwp->readSeq(hwp, 0x4C);
1427
1428    /* Save register 3C5.4D.
1429     * According to CX700 / VX700 (UniChrome Pro II) Open Graphics
1430     * Programming Manual Part I: Graphics Core / 2D,
1431     * this register is called Dual Channel Memory Control.
1432     * According to VX800 / VX855 / VX900 (Chrome9 HC3 / HCM / HD)
1433     * Open Graphics Programming Manual Part I: Graphics Core / 2D,
1434     * this register is called Preemptive Arbiter Control.
1435     * It is likely that this register is also supported in UniChrome Pro. */
1436        Regs->SR4D = hwp->readSeq(hwp, 0x4D);
1437
1438        Regs->SR4E = hwp->readSeq(hwp, 0x4E);
1439        Regs->SR4F = hwp->readSeq(hwp, 0x4F);
1440        break;
1441    default:
1442        break;
1443    }
1444
1445    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1446                        "Finished saving sequencer registers.\n"));
1447
1448    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1449                        "Saving IGA1 registers.\n"));
1450
1451    /* UniChrome Pro or later */
1452    switch (pVia->Chipset) {
1453    case VIA_PM800:
1454    case VIA_K8M800:
1455    case VIA_P4M800PRO:
1456    case VIA_CX700:
1457    case VIA_P4M890:
1458    case VIA_K8M890:
1459    case VIA_P4M900:
1460    case VIA_VX800:
1461    case VIA_VX855:
1462    case VIA_VX900:
1463
1464        /* Display Fetch Blocking Control */
1465        Regs->CR30 = hwp->readCrtc(hwp, 0x30);
1466
1467        /* Half Line Position */
1468        Regs->CR31 = hwp->readCrtc(hwp, 0x31);
1469        break;
1470    default:
1471        break;
1472    }
1473
1474    Regs->CR32 = hwp->readCrtc(hwp, 0x32);
1475    Regs->CR33 = hwp->readCrtc(hwp, 0x33);
1476    Regs->CR35 = hwp->readCrtc(hwp, 0x35);
1477    Regs->CR36 = hwp->readCrtc(hwp, 0x36);
1478
1479    /* UniChrome Pro or later */
1480    switch (pVia->Chipset) {
1481    case VIA_PM800:
1482    case VIA_K8M800:
1483    case VIA_P4M800PRO:
1484    case VIA_CX700:
1485    case VIA_P4M890:
1486    case VIA_K8M890:
1487    case VIA_P4M900:
1488    case VIA_VX800:
1489    case VIA_VX855:
1490    case VIA_VX900:
1491
1492        /* DAC Control Register */
1493        Regs->CR37 = hwp->readCrtc(hwp, 0x37);
1494        break;
1495    default:
1496        break;
1497    }
1498
1499    Regs->CR38 = hwp->readCrtc(hwp, 0x38);
1500    Regs->CR39 = hwp->readCrtc(hwp, 0x39);
1501    Regs->CR3A = hwp->readCrtc(hwp, 0x3A);
1502    Regs->CR3B = hwp->readCrtc(hwp, 0x3B);
1503    Regs->CR3C = hwp->readCrtc(hwp, 0x3C);
1504    Regs->CR3D = hwp->readCrtc(hwp, 0x3D);
1505    Regs->CR3E = hwp->readCrtc(hwp, 0x3E);
1506    Regs->CR3F = hwp->readCrtc(hwp, 0x3F);
1507
1508    Regs->CR40 = hwp->readCrtc(hwp, 0x40);
1509
1510    /* UniChrome Pro or later */
1511    switch (pVia->Chipset) {
1512    case VIA_PM800:
1513    case VIA_K8M800:
1514    case VIA_P4M800PRO:
1515    case VIA_CX700:
1516    case VIA_P4M890:
1517    case VIA_K8M890:
1518    case VIA_P4M900:
1519    case VIA_VX800:
1520    case VIA_VX855:
1521    case VIA_VX900:
1522
1523        Regs->CR43 = hwp->readCrtc(hwp, 0x43);
1524        Regs->CR45 = hwp->readCrtc(hwp, 0x45);
1525        break;
1526    default:
1527        break;
1528    }
1529
1530    Regs->CR46 = hwp->readCrtc(hwp, 0x46);
1531    Regs->CR47 = hwp->readCrtc(hwp, 0x47);
1532
1533    /* Starting Address */
1534    /* Start Address High */
1535    Regs->CR0C = hwp->readCrtc(hwp, 0x0C);
1536
1537    /* Start Address Low */
1538    Regs->CR0D = hwp->readCrtc(hwp, 0x0D);
1539
1540    /* UniChrome Pro or later */
1541    switch (pVia->Chipset) {
1542    case VIA_PM800:
1543    case VIA_K8M800:
1544    case VIA_P4M800PRO:
1545    case VIA_CX700:
1546    case VIA_P4M890:
1547    case VIA_K8M890:
1548    case VIA_P4M900:
1549    case VIA_VX800:
1550    case VIA_VX855:
1551    case VIA_VX900:
1552
1553        /* Starting Address Overflow[28:24] */
1554        Regs->CR48 = hwp->readCrtc(hwp, 0x48);
1555        break;
1556    default:
1557        break;
1558    }
1559
1560    /* Starting Address Overflow[23:16] */
1561    Regs->CR34 = hwp->readCrtc(hwp, 0x34);
1562
1563    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1564                        "Finished saving IGA1 registers.\n"));
1565
1566    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1567                        "Exiting viaIGA1Save.\n"));
1568}
1569
1570void
1571viaIGA1Restore(ScrnInfoPtr pScrn)
1572{
1573    vgaHWPtr hwp = VGAHWPTR(pScrn);
1574    VIAPtr pVia = VIAPTR(pScrn);
1575    VIARegPtr Regs = &pVia->SavedReg;
1576
1577    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1578                        "Entered viaIGA1Restore.\n"));
1579
1580    /* Unlock extended registers. */
1581    hwp->writeSeq(hwp, 0x10, 0x01);
1582
1583    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1584                        "Restoring sequencer registers.\n"));
1585
1586    hwp->writeSeq(hwp, 0x14, Regs->SR14);
1587    hwp->writeSeq(hwp, 0x15, Regs->SR15);
1588    hwp->writeSeq(hwp, 0x16, Regs->SR16);
1589    hwp->writeSeq(hwp, 0x17, Regs->SR17);
1590    hwp->writeSeq(hwp, 0x18, Regs->SR18);
1591    hwp->writeSeq(hwp, 0x19, Regs->SR19);
1592
1593    /* PCI Bus Control */
1594    hwp->writeSeq(hwp, 0x1A, Regs->SR1A);
1595
1596    hwp->writeSeq(hwp, 0x1B, Regs->SR1B);
1597    hwp->writeSeq(hwp, 0x1C, Regs->SR1C);
1598    hwp->writeSeq(hwp, 0x1D, Regs->SR1D);
1599    hwp->writeSeq(hwp, 0x1E, Regs->SR1E);
1600    hwp->writeSeq(hwp, 0x1F, Regs->SR1F);
1601
1602    hwp->writeSeq(hwp, 0x22, Regs->SR22);
1603
1604    /* Registers 3C5.23 through 3C5.25 are not used by Chrome9.
1605     * Registers 3C5.27 through 3C5.29 are not used by Chrome9. */
1606    switch (pVia->Chipset) {
1607    case VIA_CLE266:
1608    case VIA_KM400:
1609    case VIA_PM800:
1610    case VIA_K8M800:
1611    case VIA_P4M800PRO:
1612    case VIA_CX700:
1613    case VIA_P4M890:
1614
1615        hwp->writeSeq(hwp, 0x23, Regs->SR23);
1616        hwp->writeSeq(hwp, 0x24, Regs->SR24);
1617        hwp->writeSeq(hwp, 0x25, Regs->SR25);
1618
1619        hwp->writeSeq(hwp, 0x27, Regs->SR27);
1620        hwp->writeSeq(hwp, 0x28, Regs->SR28);
1621        hwp->writeSeq(hwp, 0x29, Regs->SR29);
1622        break;
1623    default:
1624        break;
1625    }
1626
1627    hwp->writeSeq(hwp, 0x26, Regs->SR26);
1628
1629    hwp->writeSeq(hwp, 0x2A, Regs->SR2A);
1630    hwp->writeSeq(hwp, 0x2B, Regs->SR2B);
1631
1632    hwp->writeSeq(hwp, 0x2D, Regs->SR2D);
1633    hwp->writeSeq(hwp, 0x2E, Regs->SR2E);
1634
1635    /* Restore PCI Configuration Memory Base Shadow 0 and 1.
1636     * These registers are available only in UniChrome, UniChrome Pro,
1637     * and UniChrome Pro II. */
1638    switch (pVia->Chipset) {
1639    case VIA_CLE266:
1640    case VIA_KM400:
1641    case VIA_PM800:
1642    case VIA_K8M800:
1643    case VIA_P4M800PRO:
1644    case VIA_CX700:
1645    case VIA_P4M890:
1646
1647        hwp->writeSeq(hwp, 0x2F, Regs->SR2F);
1648        hwp->writeSeq(hwp, 0x30, Regs->SR30);
1649        break;
1650    default:
1651        break;
1652    }
1653
1654    /* Restore PLL settings and several miscellaneous registers.
1655     * For UniChrome, register 3C5.44 through 3C5.4B are restored.
1656     * For UniChrome Pro and Chrome 9, register 3C5.44 through 3C5.4C
1657     * are restored. */
1658    switch (pVia->Chipset) {
1659    case VIA_CLE266:
1660    case VIA_KM400:
1661        /* Engine Clock (ECK) PLL settings */
1662        hwp->writeSeq(hwp, 0x48, Regs->SR48);
1663        hwp->writeSeq(hwp, 0x49, Regs->SR49);
1664
1665        /* Memory Clock (MCK) PLL settings */
1666        hwp->writeSeq(hwp, 0x4a, Regs->SR4A);
1667        hwp->writeSeq(hwp, 0x4b, Regs->SR4B);
1668
1669        /* Primary Display Clock (VCK) PLL settings */
1670        hwp->writeSeq(hwp, 0x46, Regs->SR46);
1671        hwp->writeSeq(hwp, 0x47, Regs->SR47);
1672
1673        /* Secondary Display Clock (LCDCK) PLL settings */
1674        hwp->writeSeq(hwp, 0x44, Regs->SR44);
1675        hwp->writeSeq(hwp, 0x45, Regs->SR45);
1676        break;
1677    default:
1678        /* Engine Clock (ECK) PLL settings */
1679        hwp->writeSeq(hwp, 0x47, Regs->SR47);
1680        hwp->writeSeq(hwp, 0x48, Regs->SR48);
1681        hwp->writeSeq(hwp, 0x49, Regs->SR49);
1682
1683        /* Reset ECK PLL. */
1684        hwp->writeSeq(hwp, 0x40, hwp->readSeq(hwp, 0x40) | 0x01); /* Set SR40[0] to 1 */
1685        hwp->writeSeq(hwp, 0x40, hwp->readSeq(hwp, 0x40) & (~0x01)); /* Set SR40[0] to 0 */
1686
1687
1688        /* Primary Display Clock (VCK) PLL settings */
1689        hwp->writeSeq(hwp, 0x44, Regs->SR44);
1690        hwp->writeSeq(hwp, 0x45, Regs->SR45);
1691        hwp->writeSeq(hwp, 0x46, Regs->SR46);
1692
1693        /* Reset VCK PLL. */
1694        hwp->writeSeq(hwp, 0x40, hwp->readSeq(hwp, 0x40) | 0x02); /* Set SR40[1] to 1 */
1695        hwp->writeSeq(hwp, 0x40, hwp->readSeq(hwp, 0x40) & (~0x02)); /* Set SR40[1] to 0 */
1696
1697
1698        /* Secondary Display Clock (LCDCK) PLL settings */
1699        hwp->writeSeq(hwp, 0x4A, Regs->SR4A);
1700        hwp->writeSeq(hwp, 0x4B, Regs->SR4B);
1701        hwp->writeSeq(hwp, 0x4C, Regs->SR4C);
1702
1703        /* Reset LCDCK PLL. */
1704        hwp->writeSeq(hwp, 0x40, hwp->readSeq(hwp, 0x40) | 0x04); /* Set SR40[2] to 1 */
1705        hwp->writeSeq(hwp, 0x40, hwp->readSeq(hwp, 0x40) & (~0x04)); /* Set SR40[2] to 0 */
1706        break;
1707    }
1708
1709    switch (pVia->Chipset) {
1710    case VIA_PM800:
1711    case VIA_K8M800:
1712    case VIA_P4M800PRO:
1713    case VIA_CX700:
1714    case VIA_P4M890:
1715    case VIA_K8M890:
1716    case VIA_P4M900:
1717    case VIA_VX800:
1718    case VIA_VX855:
1719    case VIA_VX900:
1720
1721    /* Restore register 3C5.4D.
1722     * According to CX700 / VX700 (UniChrome Pro II) Open Graphics
1723     * Programming Manual Part I: Graphics Core / 2D,
1724     * this register is called Dual Channel Memory Control.
1725     * According to VX800 / VX855 / VX900 (Chrome9 HC3 / HCM / HD)
1726     * Open Graphics Programming Manual Part I: Graphics Core / 2D,
1727     * this register is called Preemptive Arbiter Control.
1728     * It is likely that this register is also supported in UniChrome Pro. */
1729        hwp->writeSeq(hwp, 0x4D, Regs->SR4D);
1730
1731        hwp->writeSeq(hwp, 0x4E, Regs->SR4E);
1732        hwp->writeSeq(hwp, 0x4F, Regs->SR4F);
1733        break;
1734    default:
1735        break;
1736    }
1737
1738    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1739                        "Finished restoring sequencer registers.\n"));
1740
1741/* Reset dot clocks. */
1742    ViaSeqMask(hwp, 0x40, 0x06, 0x06);
1743    ViaSeqMask(hwp, 0x40, 0x00, 0x06);
1744
1745    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1746                        "Restoring IGA1 registers.\n"));
1747
1748/* UniChrome Pro or later */
1749    switch (pVia->Chipset) {
1750    case VIA_PM800:
1751    case VIA_K8M800:
1752    case VIA_P4M800PRO:
1753    case VIA_CX700:
1754    case VIA_P4M890:
1755    case VIA_K8M890:
1756    case VIA_P4M900:
1757    case VIA_VX800:
1758    case VIA_VX855:
1759    case VIA_VX900:
1760
1761        /* Display Fetch Blocking Control */
1762        hwp->writeCrtc(hwp, 0x30, Regs->CR30);
1763
1764        /* Half Line Position */
1765        hwp->writeCrtc(hwp, 0x31, Regs->CR31);
1766        break;
1767    default:
1768        break;
1769    }
1770
1771    /* Restore CRTC controller extended registers. */
1772    /* Mode Control */
1773    hwp->writeCrtc(hwp, 0x32, Regs->CR32);
1774
1775    /* HSYNCH Adjuster */
1776    hwp->writeCrtc(hwp, 0x33, Regs->CR33);
1777
1778    /* Extended Overflow */
1779    hwp->writeCrtc(hwp, 0x35, Regs->CR35);
1780
1781    /* Power Management 3 (Monitor Control) */
1782    hwp->writeCrtc(hwp, 0x36, Regs->CR36);
1783
1784/* UniChrome Pro or later */
1785    switch (pVia->Chipset) {
1786    case VIA_PM800:
1787    case VIA_K8M800:
1788    case VIA_P4M800PRO:
1789    case VIA_CX700:
1790    case VIA_P4M890:
1791    case VIA_K8M890:
1792    case VIA_P4M900:
1793    case VIA_VX800:
1794    case VIA_VX855:
1795    case VIA_VX900:
1796
1797        /* DAC control Register */
1798        hwp->writeCrtc(hwp, 0x37, Regs->CR37);
1799        break;
1800    default:
1801        break;
1802    }
1803
1804    hwp->writeCrtc(hwp, 0x38, Regs->CR38);
1805    hwp->writeCrtc(hwp, 0x39, Regs->CR39);
1806    hwp->writeCrtc(hwp, 0x3A, Regs->CR3A);
1807    hwp->writeCrtc(hwp, 0x3B, Regs->CR3B);
1808    hwp->writeCrtc(hwp, 0x3C, Regs->CR3C);
1809    hwp->writeCrtc(hwp, 0x3D, Regs->CR3D);
1810    hwp->writeCrtc(hwp, 0x3E, Regs->CR3E);
1811    hwp->writeCrtc(hwp, 0x3F, Regs->CR3F);
1812
1813    hwp->writeCrtc(hwp, 0x40, Regs->CR40);
1814
1815    /* UniChrome Pro or later */
1816    switch (pVia->Chipset) {
1817    case VIA_PM800:
1818    case VIA_K8M800:
1819    case VIA_P4M800PRO:
1820    case VIA_CX700:
1821    case VIA_P4M890:
1822    case VIA_K8M890:
1823    case VIA_P4M900:
1824    case VIA_VX800:
1825    case VIA_VX855:
1826    case VIA_VX900:
1827
1828        hwp->writeCrtc(hwp, 0x43, Regs->CR43);
1829        hwp->writeCrtc(hwp, 0x45, Regs->CR45);
1830        break;
1831    default:
1832        break;
1833    }
1834
1835    hwp->writeCrtc(hwp, 0x46, Regs->CR46);
1836    hwp->writeCrtc(hwp, 0x47, Regs->CR47);
1837
1838    /* Starting Address */
1839    /* Start Address High */
1840    hwp->writeCrtc(hwp, 0x0C, Regs->CR0C);
1841
1842    /* Start Address Low */
1843    hwp->writeCrtc(hwp, 0x0D, Regs->CR0D);
1844
1845    /* UniChrome Pro or later */
1846    switch (pVia->Chipset) {
1847    case VIA_PM800:
1848    case VIA_K8M800:
1849    case VIA_P4M800PRO:
1850    case VIA_CX700:
1851    case VIA_P4M890:
1852    case VIA_K8M890:
1853    case VIA_P4M900:
1854    case VIA_VX800:
1855    case VIA_VX855:
1856    case VIA_VX900:
1857
1858        /* Starting Address Overflow[28:24] */
1859        hwp->writeCrtc(hwp, 0x48, Regs->CR48);
1860        break;
1861    default:
1862        break;
1863    }
1864
1865    /* CR34 is fire bits. Must be written after CR0C, CR0D, and CR48.
1866     * Starting Address Overflow[23:16] */
1867    hwp->writeCrtc(hwp, 0x34, Regs->CR34);
1868
1869    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1870                        "Finished restoring IGA1 registers.\n"));
1871
1872    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1873                        "Exiting viaIGA1Restore.\n"));
1874}
1875
1876/*
1877 * Initialize IGA2 (Integrated Graphics Accelerator) registers.
1878 */
1879void
1880viaIGA2Init(ScrnInfoPtr pScrn)
1881{
1882    vgaHWPtr hwp = VGAHWPTR(pScrn);
1883    VIAPtr pVia = VIAPTR(pScrn);
1884#ifdef HAVE_DEBUG
1885    CARD8 temp;
1886#endif
1887
1888    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1889                        "Entered viaIGA2Init.\n"));
1890
1891#ifdef HAVE_DEBUG
1892    temp = hwp->readSeq(hwp, 0x1B);
1893    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1894                        "SR1B: 0x%02X\n", temp));
1895    temp = hwp->readSeq(hwp, 0x2D);
1896    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1897                        "SR2D: 0x%02X\n", temp));
1898    temp = hwp->readCrtc(hwp, 0x6A);
1899    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1900                        "CR6A: 0x%02X\n", temp));
1901    temp = hwp->readCrtc(hwp, 0x6B);
1902    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1903                        "CR6B: 0x%02X\n", temp));
1904
1905    /* For UniChrome Pro and Chrome9. */
1906    if ((pVia->Chipset != VIA_CLE266)
1907        && (pVia->Chipset != VIA_KM400)) {
1908        temp = hwp->readCrtc(hwp, 0x6C);
1909        DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1910                            "CR6C: 0x%02X\n", temp));
1911    }
1912
1913    temp = hwp->readCrtc(hwp, 0x79);
1914    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1915                        "CR79: 0x%02X\n", temp));
1916
1917#endif
1918
1919    /* 3C5.1B[7:6] - Secondary Display Engine (Gated Clock <LCK>)
1920     *               0x: Clock always off
1921     *               10: Clock always on
1922     *               11: Clock on/off according to the
1923     *                   Power Management Status (PMS)
1924     * 3C5.1B[5:4] - Primary Display Engine (Gated Clock <VCK>)
1925     *               0x: Clock always off
1926     *               10: Clock always on
1927     *               11: Clock on/off according to the PMS
1928     * 3C5.1B[3:1] - Reserved
1929     * 3C5.1B[0]   - Primary Display’s LUT On/Off
1930     *               0: On
1931     *               1: Off */
1932    ViaSeqMask(hwp, 0x1B, 0xC0, 0xC0);
1933
1934    /* 3C5.2D[7:6] - E3_ECK_N Selection
1935     *               00: E3_ECK_N
1936     *               01: E3_ECK
1937     *               10: delayed E3_ECK_N
1938     *               11: delayed E3_ECK
1939     * 3C5.2D[5:4] - VCK (Primary Display Clock) PLL Power Control
1940     *               0x: PLL power-off
1941     *               10: PLL always on
1942     *               11: PLL on/off according to the PMS
1943     * 3C5.2D[3:2] - LCK (Secondary Display Clock) PLL Power Control
1944     *               0x: PLL power-off
1945     *               10: PLL always on
1946     *               11: PLL on/off according to the PMS
1947     * 3C5.2D[1:0] - ECK (Engine Clock) PLL Power Control
1948     *               0x: PLL power-off
1949     *               10: PLL always on
1950     *               11: PLL on/off according to the PMS */
1951    ViaSeqMask(hwp, 0x2D, 0x0C, 0x0C);
1952
1953    /* 3X5.6A[7] - Second Display Channel Enable
1954     *             0: Disable
1955     *             1: Enable
1956     * 3X5.6A[6] - Second Display Channel Reset
1957     *             0: Reset
1958     * 3X5.6A[5] - Second Display 8/6 Bits LUT
1959     *             0: 6-bit
1960     *             1: 8-bit
1961     * 3X5.6A[4] - Horizontal Count by 2
1962     *             0: Disable
1963     *             1: Enable
1964     * 3X5.6A[1] - LCD Gamma Enable
1965     *             0: Disable
1966     *             1: Enable
1967     * 3X5.6A[0] - LCD Pre-fetch Mode Enable
1968     *             0: Disable
1969     *             1: Enable */
1970    ViaCrtcMask(hwp, 0x6A, 0x80, 0xB3);
1971
1972    /* TV out uses division by 2 mode.
1973     * Other devices like analog (VGA), DVI, flat panel, etc.,
1974     * use normal mode. */
1975    /* 3X5.6B[5:4] - Second Display Channel Clock Mode Selection
1976     *               0x: Normal
1977     *               1x: Division by 2
1978     * 3X5.6B[2]   - IGA2 Screen Off
1979     *               0: Normal
1980     *               1: Screen off
1981     * 3X5.6B[1]   - IGA2 Screen Off Selection Method
1982     *               0: IGA2 Screen off
1983     *               1: IGA1 Screen off */
1984    ViaCrtcMask(hwp, 0x6B, 0x00, 0x36);
1985
1986    /* For UniChrome Pro and Chrome9. */
1987    if ((pVia->Chipset != VIA_CLE266)
1988        && (pVia->Chipset != VIA_KM400)) {
1989        /* The following register fields are for UniChrome Pro and Chrome9. */
1990        /* 3X5.6C[3:1] - LCDCK PLL Reference Clock Source Selection
1991         *               000: From XI pin
1992         *               001: From TVXI
1993         *               01x: From TVPLL
1994         *               100: DVP0TVCLKR
1995         *               101: DVP1TVCLKR
1996         *               110: CAP0 Clock
1997         *               111: CAP1 Clock
1998         * 3X5.6C[0]   - LCDCK Source Selection
1999         *               0: LCDCK PLL output clock
2000         *               1: LCDCK PLL reference clock */
2001        ViaCrtcMask(hwp, 0x6C, 0x00, 0x0F);
2002    }
2003
2004    /* Disable LCD scaling */
2005    /* 3X5.79[0] - LCD Scaling Enable
2006     *             0: Disable
2007     *             1: Enable */
2008    ViaCrtcMask(hwp, 0x79, 0x00, 0x01);
2009
2010    /* Set DVP0 (Digital Video Port 0) source to IGA2. */
2011    /* 3X5.96[7]   - DVP0 ALPHA Enable
2012     *               0: Disable
2013     *               1: Enable
2014     * 3X5.96[6]   - DVP0 VSYNC Polarity
2015     *               0: Positive
2016     *               1: Negative
2017     * 3X5.96[5]   - DVP0 HSYNC Polarity
2018     *               0: Positive
2019     *               1: Negative
2020     * 3X5.96[4]   - DVP0 Data Source Selection 0
2021     *               0: Primary Display
2022     *               1: Secondary Display
2023     * 3X5.96[3]   - DVP0 Clock Polarity
2024     * 3X5.96[2:0] - DVP0 Clock Adjust
2025     *               Valid Value: 0 through 7 */
2026    ViaCrtcMask(hwp, 0x96, 0x10, 0x10);
2027
2028    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2029                        "Exiting viaIGA2Init.\n"));
2030}
2031
2032void
2033viaIGA2SetFBStartingAddress(xf86CrtcPtr crtc, int x, int y)
2034{
2035    ScrnInfoPtr pScrn = crtc->scrn;
2036    vgaHWPtr hwp = VGAHWPTR(pScrn);
2037    drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2038    drmmode_ptr drmmode = drmmode_crtc->drmmode;
2039    CARD32 Base, tmp;
2040    CARD8 cr62, cr63, cr64, cra3;
2041
2042    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2043                        "Entered viaIGA2SetFBStartingAddress.\n"));
2044
2045    Base = (y * pScrn->displayWidth + x) * (pScrn->bitsPerPixel / 8);
2046    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2047                        "Base Address: 0x%lx\n",
2048                        Base));
2049    Base = (Base + drmmode->front_bo->offset) >> 3;
2050    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2051                "DRI Base Address: 0x%lx\n",
2052                Base);
2053
2054    tmp = hwp->readCrtc(hwp, 0x62) & 0x01;
2055    tmp |= (Base & 0x7F) << 1;
2056    hwp->writeCrtc(hwp, 0x62, tmp);
2057
2058    hwp->writeCrtc(hwp, 0x63, (Base & 0x7F80) >> 7);
2059    hwp->writeCrtc(hwp, 0x64, (Base & 0x7F8000) >> 15);
2060    hwp->writeCrtc(hwp, 0xA3, (Base & 0x03800000) >> 23);
2061
2062#ifdef HAVE_DEBUG
2063    cr62 = hwp->readCrtc(hwp, 0x62);
2064    cr63 = hwp->readCrtc(hwp, 0x63);
2065    cr64 = hwp->readCrtc(hwp, 0x64);
2066    cra3 = hwp->readCrtc(hwp, 0xA3);
2067
2068    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2069                        "CR62: 0x%02X\n", cr62));
2070    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2071                        "CR63: 0x%02X\n", cr63));
2072    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2073                        "CR64: 0x%02X\n", cr64));
2074    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2075                        "CRA3: 0x%02X\n", cra3));
2076#endif
2077
2078    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2079                        "Exiting viaIGA2SetFBStartingAddress.\n"));
2080}
2081
2082void
2083viaIGA2SetDisplayRegister(ScrnInfoPtr pScrn, DisplayModePtr mode)
2084{
2085    VIAPtr pVia = VIAPTR(pScrn);
2086    vgaHWPtr hwp = VGAHWPTR(pScrn);
2087    CARD16 temp;
2088
2089    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2090                        "Entered viaIGA2SetDisplayRegister.\n"));
2091
2092    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2093                "Requested Screen Mode: %s\n", mode->name);
2094
2095    /* Set the color depth for IGA2. */
2096    switch (pScrn->bitsPerPixel) {
2097        case 8:
2098            /* Only CLE266.AX uses 6-bit LUT. */
2099            if (pVia->Chipset == VIA_CLE266 && pVia->ChipRev < 15) {
2100                /* 6-bit LUT */
2101                /* 3X5.6A[5] - Second Display 8/6 Bits LUT
2102                 *             0: 6-bit
2103                 *             1: 8-bit */
2104                ViaCrtcMask(hwp, 0x6A, 0x00, 0x20);
2105            } else {
2106                /* Set IGA2 display LUT to 8-bit */
2107                ViaCrtcMask(hwp, 0x6A, 0x20, 0x20);
2108            }
2109
2110            ViaCrtcMask(hwp, 0x67, 0x00, 0xC0);
2111            break;
2112        case 16:
2113            ViaCrtcMask(hwp, 0x67, 0x40, 0xC0);
2114            break;
2115        case 24:
2116        case 32:
2117            ViaCrtcMask(hwp, 0x67, 0xC0, 0xC0);
2118            break;
2119        default:
2120            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
2121                        "Unsupported color depth: %d\n",
2122                        pScrn->bitsPerPixel);
2123            break;
2124    }
2125
2126    /* LVDS Channel 1 and 2 should be controlled by PMS
2127     * (Power Management Status). */
2128    ViaSeqMask(hwp, 0x2A, 0x0F, 0x0F);
2129
2130    /* 3X5.99[3:0] appears to be a register to adjust an LCD panel
2131     * (the official name of the register is unknown). */
2132    if (pVia->Chipset == VIA_P4M900) {
2133        ViaCrtcMask(hwp, 0x99, 0x08, 0x0F);
2134    }
2135
2136    /* IGA2 for DFP Low. */
2137    ViaCrtcMask(hwp, 0x99, 0x10, 0x10);
2138
2139    /* Use IGA2 for DVP1 Data Source Selection 0. */
2140    ViaCrtcMask(hwp, 0x9B, 0x10, 0x10);
2141
2142    /* Linear Mode */
2143    ViaCrtcMask(hwp, 0x62, 0x00, 0x01);
2144
2145
2146    /* Set IGA2 horizontal total pixels.*/
2147    /* Horizontal Total Period: 4096 - 1 (max) */
2148    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2149                        "IGA2 CrtcHTotal: %d\n", mode->CrtcHTotal));
2150    temp = mode->CrtcHTotal - 1;
2151
2152    /* 3X5.50[7:0] - Horizontal Total Period Bits [7:0] */
2153    hwp->writeCrtc(hwp, 0x50, temp & 0xFF);
2154
2155    /* 3X5.55[3:0] - Horizontal Total Period Bits [11:8] */
2156    ViaCrtcMask(hwp, 0x55, temp >> 8, 0x0F);
2157
2158
2159    /* Set IGA2 horizontal display end position. */
2160    /* Horizontal Active Data Period: 2048 - 1 (max) */
2161    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2162                        "IGA2 CrtcHDisplay: %d\n", mode->CrtcHDisplay));
2163    temp = mode->CrtcHDisplay - 1;
2164
2165    /* 3X5.51[7:0] - Horizontal Active Data Period Bits [7:0] */
2166    hwp->writeCrtc(hwp, 0x51, temp & 0xFF);
2167
2168    /* 3X5.55[6:4] - Horizontal Active Data Period Bits [10:8] */
2169    ViaCrtcMask(hwp, 0x55, temp >> 4, 0x70);
2170
2171
2172    /* Set IGA2 horizontal blank start. */
2173    /* Horizontal Blanking Start: 2048 - 1 (max) */
2174    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2175                        "IGA2 CrtcHBlankStart: %d\n", mode->CrtcHBlankStart));
2176    temp = mode->CrtcHBlankStart;
2177
2178    /* 3X5.52[7:0] - Horizontal Blanking Start Bits [7:0] */
2179    hwp->writeCrtc(hwp, 0x52, temp & 0xFF);
2180
2181    /* 3X5.54[2:0] - Horizontal Blanking Start Bits [10:8] */
2182    ViaCrtcMask(hwp, 0x54, temp >> 8, 0x07);
2183
2184
2185    /* Set IGA2 horizontal blank end. */
2186    /* Horizontal Blanking End: 4096 - 1 (max) */
2187    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2188                        "IGA2 CrtcHBlankEnd: %d\n", mode->CrtcHBlankEnd));
2189    temp = mode->CrtcHBlankEnd - 1;
2190
2191    /* 3X5.53[7:0] - Horizontal Blanking End Bits [7:0] */
2192    hwp->writeCrtc(hwp, 0x53, temp & 0xFF);
2193
2194    /* 3X5.54[5:3] - Horizontal Blanking End Bits [10:8] */
2195    ViaCrtcMask(hwp, 0x54, temp >> 5, 0x38);
2196
2197    /* 3X5.5D[6] - Horizontal Blanking End Bit [11] */
2198    ViaCrtcMask(hwp, 0x5D, temp >> 5, 0x40);
2199
2200
2201    /* Set IGA2 horizontal synchronization start. */
2202    /* Horizontal Retrace Start: 2047 (max, UniChrome),
2203     *                           4095 (max, UniChrome Pro and Chrome9) */
2204    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2205                        "IGA2 CrtcHSyncStart: %d\n", mode->CrtcHSyncStart));
2206    temp = mode->CrtcHSyncStart;
2207
2208    /* 3X5.56[7:0] - Horizontal Retrace Start Bits [7:0] */
2209    hwp->writeCrtc(hwp, 0x56, temp & 0xFF);
2210
2211    /* 3X5.54[7:6] - Horizontal Retrace Start Bits [9:8] */
2212    ViaCrtcMask(hwp, 0x54, temp >> 2, 0xC0);
2213
2214    /* 3X5.5C[7] - Horizontal Retrace Start Bit [10] */
2215    ViaCrtcMask(hwp, 0x5C, temp >> 3, 0x80);
2216
2217    /* For UniChrome Pro and Chrome9. */
2218    if ((pVia->Chipset != VIA_CLE266)
2219        && (pVia->Chipset != VIA_KM400)) {
2220
2221        /* 3X5.5D[7] - Horizontal Retrace Start Bit [11] */
2222        ViaCrtcMask(hwp, 0x5D, temp >> 4, 0x80);
2223    }
2224
2225
2226    /* Set IGA2 horizontal synchronization end. */
2227    /* Horizontal Retrace End: 511 (max) */
2228    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2229                        "IGA2 CrtcHSyncEnd: %d\n", mode->CrtcHSyncEnd));
2230    temp = mode->CrtcHSyncEnd - 1;
2231
2232    /* 3X5.57[7:0] - Horizontal Retrace End Bits [7:0] */
2233    hwp->writeCrtc(hwp, 0x57, temp & 0xFF);
2234
2235    /* 3X5.5C[6] - Horizontal Retrace End Bit [8] */
2236    ViaCrtcMask(hwp, 0x5C, temp >> 2, 0x40);
2237
2238
2239    /* Set IGA2 vertical total pixels. */
2240    /* Vertical Total Period: 2048 - 1 (max) */
2241    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2242                        "IGA2 CrtcVTotal: %d\n", mode->CrtcVTotal));
2243    temp = mode->CrtcVTotal - 1;
2244
2245    /* 3X5.58[7:0] - Vertical Total Period Bits [7:0] */
2246    hwp->writeCrtc(hwp, 0x58, temp & 0xFF);
2247
2248    /* 3X5.5D[2:0] - Vertical Total Period Bits [10:8] */
2249    ViaCrtcMask(hwp, 0x5D, temp >> 8, 0x07);
2250
2251
2252    /* Set IGA2 vertical display end position. */
2253    /* Vertical Active Data Period: 2048 - 1 (max) */
2254    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2255                        "IGA2 CrtcVDisplay: %d\n", mode->CrtcVDisplay));
2256    temp = mode->CrtcVDisplay - 1;
2257
2258    /* 3X5.59[7:0] - Vertical Active Data Period Bits [7:0] */
2259    hwp->writeCrtc(hwp, 0x59, temp & 0xFF);
2260
2261    /* 3X5.5D[5:3] - Vertical Active Data Period Bits [10:8] */
2262    ViaCrtcMask(hwp, 0x5D, temp >> 5, 0x38);
2263
2264
2265    /* Set IGA2 vertical blank start. */
2266    /* Vertical Blanking Start: 2048 - 1 (max) */
2267    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2268                        "IGA2 CrtcVBlankStart: %d\n", mode->CrtcVBlankStart));
2269    temp = mode->CrtcVBlankStart;
2270
2271    /* 3X5.5A[7:0] - Vertical Blanking Start Bits [7:0] */
2272    hwp->writeCrtc(hwp, 0x5A, temp & 0xFF);
2273
2274    /* 3X5.5C[2:0] - Vertical Blanking Start Bits [10:8] */
2275    ViaCrtcMask(hwp, 0x5C, temp >> 8, 0x07);
2276
2277
2278    /* Set IGA2 vertical blank end. */
2279    /* Vertical Blanking End: 4096 - 1 (max) */
2280    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2281                        "IGA2 CrtcVBlankEnd: %d\n", mode->CrtcVBlankEnd));
2282    temp = mode->CrtcVBlankEnd - 1;
2283
2284    /* 3X5.5B[7:0] - Vertical Blanking End Bits [7:0] */
2285    hwp->writeCrtc(hwp, 0x5B, temp & 0xFF);
2286
2287    /* 3X5.5C[5:3] - Vertical Blanking End Bits [10:8] */
2288    ViaCrtcMask(hwp, 0x5C, temp >> 5, 0x38);
2289
2290
2291    /* Set IGA2 vertical synchronization start. */
2292    /* Horizontal Retrace Start: 2047 (max) */
2293    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2294                        "IGA2 CrtcVSyncStart: %d\n", mode->CrtcVSyncStart));
2295    temp = mode->CrtcVSyncStart;
2296
2297    /* 3X5.5E[7:0] - Vertical Retrace Start Bits [7:0] */
2298    hwp->writeCrtc(hwp, 0x5E, temp & 0xFF);
2299
2300    /* 3X5.5F[7:5] - Vertical Retrace Start Bits [10:8] */
2301    ViaCrtcMask(hwp, 0x5F, temp >> 3, 0xE0);
2302
2303
2304    /* Set IGA2 vertical synchronization end. */
2305    /* Vertical Retrace End: 32 (max) */
2306    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2307                        "IGA2 CrtcVSyncEnd: %d\n", mode->CrtcVSyncEnd));
2308    temp = mode->CrtcVSyncEnd - 1;
2309
2310    /*3X5.5F[4:0] - Vertical Retrace End Bits [4:0] */
2311    ViaCrtcMask(hwp, 0x5F, temp & 0x1F, 0x1F);
2312
2313
2314    /* Set IGA2 horizontal offset adjustment. */
2315    temp = (pScrn->displayWidth * (pScrn->bitsPerPixel >> 3)) >> 3;
2316
2317    /* Make sure that this is 32-byte aligned. */
2318    if (temp & 0x03) {
2319        temp += 0x03;
2320        temp &= ~0x03;
2321    }
2322
2323    /* 3X5.66[7:0] - Second Display Horizontal Offset Bits [7:0] */
2324    hwp->writeCrtc(hwp, 0x66, temp & 0xFF);
2325
2326    /* 3X5.67[1:0] - Second Display Horizontal Offset Bits [9:8] */
2327    ViaCrtcMask(hwp, 0x67, temp >> 8, 0x03);
2328
2329
2330    /* Set IGA2 alignment. */
2331    temp = (mode->CrtcHDisplay * (pScrn->bitsPerPixel >> 3)) >> 3;
2332
2333    /* Make sure that this is 32-byte aligned. */
2334    if (temp & 0x03) {
2335        temp += 0x03;
2336        temp &= ~0x03;
2337    }
2338
2339    /* 3X5.65[7:0] - Second Display Horizontal
2340     * 2-Quadword Count Data Bits [7:0] */
2341    hwp->writeCrtc(hwp, 0x65, (temp >> 1) & 0xFF);
2342
2343    /* 3X5.67[3:2] - Second Display Horizontal
2344     * 2-Quadword Count Data Bits [9:8] */
2345    ViaCrtcMask(hwp, 0x67, temp >> 7, 0x0C);
2346
2347    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2348                        "Exiting viaIGA2SetDisplayRegister.\n"));
2349}
2350
2351static ModeStatus
2352viaIGA2ModeValid(ScrnInfoPtr pScrn, DisplayModePtr mode)
2353{
2354    VIAPtr pVia = VIAPTR(pScrn);
2355
2356    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2357                        "Entered viaIGA2ModeValid.\n"));
2358
2359    if (mode->CrtcHTotal > 4096)
2360        return MODE_BAD_HVALUE;
2361
2362    if (mode->CrtcHDisplay > 2048)
2363        return MODE_BAD_HVALUE;
2364
2365    if (mode->CrtcHBlankStart > 2048)
2366        return MODE_BAD_HVALUE;
2367
2368    if (mode->CrtcHBlankEnd > 4096)
2369        return MODE_HBLANK_WIDE;
2370
2371    if ((((pVia->Chipset == VIA_CLE266) || (pVia->Chipset == VIA_KM400))
2372            && (mode->CrtcHSyncStart > 2048))
2373        || (((pVia->Chipset != VIA_CLE266) && (pVia->Chipset != VIA_KM400))
2374            && (mode->CrtcHSyncStart > 4096)))
2375        return MODE_BAD_HVALUE;
2376
2377    if ((mode->CrtcHSyncEnd - mode->CrtcHSyncStart) > 512)
2378        return MODE_HSYNC_WIDE;
2379
2380    if (mode->CrtcVTotal > 2048)
2381        return MODE_BAD_VVALUE;
2382
2383    if (mode->CrtcVDisplay > 2048)
2384        return MODE_BAD_VVALUE;
2385
2386    if (mode->CrtcVBlankStart > 2048)
2387        return MODE_BAD_VVALUE;
2388
2389    if (mode->CrtcVBlankEnd > 2048)
2390        return MODE_VBLANK_WIDE;
2391
2392    if (mode->CrtcVSyncStart > 2048)
2393        return MODE_BAD_VVALUE;
2394
2395    if ((mode->CrtcVSyncEnd - mode->CrtcVSyncStart) > 32)
2396        return MODE_VSYNC_WIDE;
2397
2398    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2399                        "Exiting viaIGA2ModeValid.\n"));
2400    return MODE_OK;
2401}
2402
2403void
2404viaIGA2Save(ScrnInfoPtr pScrn)
2405{
2406    vgaHWPtr hwp = VGAHWPTR(pScrn);
2407    VIAPtr pVia = VIAPTR(pScrn);
2408    VIARegPtr Regs = &pVia->SavedReg;
2409    int i;
2410
2411    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2412                        "Entered viaIGA2Save.\n"));
2413
2414    /* Unlock extended registers. */
2415    hwp->writeSeq(hwp, 0x10, 0x01);
2416
2417    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2418                        "Saving IGA2 registers.\n"));
2419
2420    for (i = 0; i < (0x88 - 0x50 + 1); i++) {
2421        Regs->EXCR[i + (0x50 - 0x50)] = hwp->readCrtc(hwp, i + 0x50);
2422
2423    }
2424
2425    for (i = 0; i < (0x92 - 0x8A + 1); i++) {
2426        Regs->EXCR[i + (0x8A - 0x50)] = hwp->readCrtc(hwp, i + 0x8A);
2427
2428    }
2429
2430    for (i = 0; i < (0xA3 - 0x94 + 1); i++) {
2431        Regs->EXCR[i + (0x94 - 0x50)] = hwp->readCrtc(hwp, i + 0x94);
2432
2433    }
2434
2435    Regs->EXCR[0xA4 - 0x50] = hwp->readCrtc(hwp, 0xA4);
2436
2437    for (i = 0; i < (0xAC - 0xA5 + 1); i++) {
2438        Regs->EXCR[i + (0xA5 - 0x50)] = hwp->readCrtc(hwp, i + 0xA5);
2439
2440    }
2441
2442    /* Chrome 9 */
2443    switch (pVia->Chipset) {
2444    case VIA_K8M890:
2445    case VIA_P4M900:
2446    case VIA_VX800:
2447    case VIA_VX855:
2448    case VIA_VX900:
2449        Regs->EXCR[0xAF - 0x50] = hwp->readCrtc(hwp, 0xAF);
2450        break;
2451    default:
2452        break;
2453    }
2454
2455    /* Chrome 9, Chrome 9 HC, and Chrome 9 HC3 */
2456    switch (pVia->Chipset) {
2457    case VIA_K8M890:
2458    case VIA_P4M900:
2459    case VIA_VX800:
2460        for (i = 0; i < (0xCD - 0xB0 + 1); i++) {
2461            Regs->EXCR[i + (0xB0 - 0x50)] = hwp->readCrtc(hwp, i + 0xB0);
2462
2463        }
2464
2465        break;
2466    default:
2467        break;
2468    }
2469
2470    switch (pVia->Chipset) {
2471
2472    /* UniChrome Pro and UniChrome Pro II */
2473    case VIA_PM800:
2474    case VIA_K8M800:
2475    case VIA_P4M800PRO:
2476    case VIA_CX700:
2477    case VIA_P4M890:
2478        for (i = 0; i < (0xD7 - 0xD0 + 1); i++) {
2479            Regs->EXCR[i + (0xD0 - 0x50)] = hwp->readCrtc(hwp, i + 0xD0);
2480
2481        }
2482
2483        break;
2484
2485    /* Chrome 9 */
2486    case VIA_K8M890:
2487    case VIA_P4M900:
2488    case VIA_VX800:
2489    case VIA_VX855:
2490    case VIA_VX900:
2491        for (i = 0; i < (0xEC - 0xD0 + 1); i++) {
2492            Regs->EXCR[i + (0xD0 - 0x50)] = hwp->readCrtc(hwp, i + 0xD0);
2493
2494        }
2495
2496        break;
2497    default:
2498        break;
2499    }
2500
2501    /* Chrome 9 */
2502    switch (pVia->Chipset) {
2503    case VIA_K8M890:
2504    case VIA_P4M900:
2505    case VIA_VX800:
2506    case VIA_VX855:
2507    case VIA_VX900:
2508        for (i = 0; i < (0xF5 - 0xF0 + 1); i++) {
2509            Regs->EXCR[i + (0xF0 - 0x50)] = hwp->readCrtc(hwp, i + 0xF0);
2510
2511        }
2512
2513        break;
2514    default:
2515        break;
2516    }
2517
2518    /* Chrome 9 HCM and Chrome 9 HD */
2519    if ((pVia->Chipset == VIA_VX855) || (pVia->Chipset == VIA_VX900)) {
2520        for (i = 0; i < (0xFC - 0xF6 + 1); i++) {
2521            Regs->EXCR[i + (0xF6 - 0x50)] = hwp->readCrtc(hwp, i + 0xF6);
2522
2523        }
2524    }
2525
2526    /* Chrome 9 HD */
2527    if (pVia->Chipset == VIA_VX900) {
2528        Regs->EXCR[0xFD - 0x50] = hwp->readCrtc(hwp, 0xFD);
2529
2530    }
2531
2532    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2533                        "Finished saving IGA2 registers.\n"));
2534
2535    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2536                        "Exiting viaIGA2Save.\n"));
2537}
2538
2539void
2540viaIGA2Restore(ScrnInfoPtr pScrn)
2541{
2542    vgaHWPtr hwp = VGAHWPTR(pScrn);
2543    VIAPtr pVia = VIAPTR(pScrn);
2544    VIARegPtr Regs = &pVia->SavedReg;
2545    int i;
2546
2547    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2548                        "Entered viaIGA2Restore.\n"));
2549
2550    /* Unlock extended registers. */
2551    hwp->writeSeq(hwp, 0x10, 0x01);
2552
2553    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2554                        "Restoring IGA2 registers.\n"));
2555
2556    for (i = 0; i < (0x5F - 0x50 + 1); i++) {
2557        hwp->writeCrtc(hwp, i + 0x50, Regs->EXCR[i + (0x50 - 0x50)]);
2558
2559    }
2560
2561    for (i = 0; i < (0x69 - 0x62 + 1); i++) {
2562        hwp->writeCrtc(hwp, i + 0x62, Regs->EXCR[i + (0x62 - 0x50)]);
2563
2564    }
2565
2566    for (i = 0; i < (0x88 - 0x6D + 1); i++) {
2567        hwp->writeCrtc(hwp, i + 0x6D, Regs->EXCR[i + (0x6D - 0x50)]);
2568
2569    }
2570
2571    for (i = 0; i < (0x92 - 0x8A + 1); i++) {
2572        hwp->writeCrtc(hwp, i + 0x8A, Regs->EXCR[i + (0x8A - 0x50)]);
2573
2574    }
2575
2576    for (i = 0; i < (0xA3 - 0x94 + 1); i++) {
2577        hwp->writeCrtc(hwp, i + 0x94, Regs->EXCR[i + (0x94 - 0x50)]);
2578
2579    }
2580
2581    /* UniChrome Pro and UniChrome Pro II */
2582    switch (pVia->Chipset) {
2583    case VIA_PM800:
2584    case VIA_K8M800:
2585    case VIA_P4M800PRO:
2586    case VIA_CX700:
2587    case VIA_P4M890:
2588        hwp->writeCrtc(hwp, 0xA4, Regs->EXCR[0xA4 - 0x50]);
2589        break;
2590    default:
2591        break;
2592    }
2593
2594    for (i = 0; i < (0xAC - 0xA5 + 1); i++) {
2595        hwp->writeCrtc(hwp, i + 0xA5, Regs->EXCR[i + (0xA5 - 0x50)]);
2596
2597    }
2598
2599    /* Chrome 9 */
2600    switch (pVia->Chipset) {
2601    case VIA_K8M890:
2602    case VIA_P4M900:
2603    case VIA_VX800:
2604    case VIA_VX855:
2605    case VIA_VX900:
2606        hwp->writeCrtc(hwp, 0xAF, Regs->EXCR[0xAF - 0x50]);
2607        break;
2608    default:
2609        break;
2610    }
2611
2612    /* Chrome 9, Chrome 9 HC, and Chrome 9 HC3 */
2613    switch (pVia->Chipset) {
2614    case VIA_K8M890:
2615    case VIA_P4M900:
2616    case VIA_VX800:
2617        for (i = 0; i < (0xCD - 0xB0 + 1); i++) {
2618            hwp->writeCrtc(hwp, i + 0xB0, Regs->EXCR[i + (0xB0 - 0x50)]);
2619
2620        }
2621
2622        break;
2623    default:
2624        break;
2625    }
2626
2627    switch (pVia->Chipset) {
2628    /* UniChrome Pro and UniChrome Pro II */
2629    case VIA_PM800:
2630    case VIA_K8M800:
2631    case VIA_P4M800PRO:
2632    case VIA_CX700:
2633    case VIA_P4M890:
2634        for (i = 0; i < (0xD7 - 0xD0 + 1); i++) {
2635            hwp->writeCrtc(hwp, i + 0xD0, Regs->EXCR[i + (0xD0 - 0x50)]);
2636
2637        }
2638
2639        break;
2640
2641    /* Chrome 9 */
2642    case VIA_K8M890:
2643    case VIA_P4M900:
2644    case VIA_VX800:
2645    case VIA_VX855:
2646    case VIA_VX900:
2647        for (i = 0; i < (0xEC - 0xD0 + 1); i++) {
2648            hwp->writeCrtc(hwp, i + 0xD0, Regs->EXCR[i + (0xD0 - 0x50)]);
2649
2650        }
2651
2652        break;
2653    default:
2654        break;
2655    }
2656
2657    /* Chrome 9 */
2658    switch (pVia->Chipset) {
2659    case VIA_K8M890:
2660    case VIA_P4M900:
2661    case VIA_VX800:
2662    case VIA_VX855:
2663    case VIA_VX900:
2664        for (i = 0; i < (0xF5 - 0xF0 + 1); i++) {
2665            hwp->writeCrtc(hwp, i + 0xF0, Regs->EXCR[i + (0xF0 - 0x50)]);
2666
2667        }
2668
2669        break;
2670    default:
2671        break;
2672    }
2673
2674    /* Chrome 9 HCM and Chrome 9 HD */
2675    if ((pVia->Chipset == VIA_VX855) || (pVia->Chipset == VIA_VX900)) {
2676        for (i = 0; i < (0xFC - 0xF6 + 1); i++) {
2677            hwp->writeCrtc(hwp, i + 0xF6, Regs->EXCR[i + (0xF6 - 0x50)]);
2678
2679        }
2680    }
2681
2682    /* Chrome 9 HD */
2683    if (pVia->Chipset == VIA_VX900) {
2684        hwp->writeCrtc(hwp, 0xFD, Regs->EXCR[0xFD - 0x50]);
2685
2686    }
2687
2688    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2689                        "Finished restoring IGA2 registers.\n"));
2690
2691    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2692                        "Exiting viaIGA2Restore.\n"));
2693}
2694
2695/*
2696 * Not tested yet
2697 */
2698void
2699ViaShadowCRTCSetMode(ScrnInfoPtr pScrn, DisplayModePtr mode)
2700{
2701    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "ViaShadowCRTCSetMode\n"));
2702
2703    vgaHWPtr hwp = VGAHWPTR(pScrn);
2704    CARD16 temp;
2705
2706    temp = (mode->CrtcHTotal >> 3) - 5;
2707    hwp->writeCrtc(hwp, 0x6D, temp & 0xFF);
2708    ViaCrtcMask(hwp, 0x71, temp >> 5, 0x08);
2709
2710    temp = (mode->CrtcHBlankEnd >> 3) - 1;
2711    hwp->writeCrtc(hwp, 0x6E, temp & 0xFF);
2712
2713    temp = mode->CrtcVTotal - 2;
2714    hwp->writeCrtc(hwp, 0x6F, temp & 0xFF);
2715    ViaCrtcMask(hwp, 0x71, temp >> 8, 0x07);
2716
2717    temp = mode->CrtcVDisplay - 1;
2718    hwp->writeCrtc(hwp, 0x70, temp & 0xFF);
2719    ViaCrtcMask(hwp, 0x71, temp >> 4, 0x70);
2720
2721    temp = mode->CrtcVBlankStart - 1;
2722    hwp->writeCrtc(hwp, 0x72, temp & 0xFF);
2723    ViaCrtcMask(hwp, 0x74, temp >> 4, 0x70);
2724
2725    temp = mode->CrtcVTotal - 1;
2726    hwp->writeCrtc(hwp, 0x73, temp & 0xFF);
2727    ViaCrtcMask(hwp, 0x74, temp >> 8, 0x07);
2728
2729    ViaCrtcMask(hwp, 0x76, mode->CrtcVSyncEnd, 0x0F);
2730
2731    temp = mode->CrtcVSyncStart;
2732    hwp->writeCrtc(hwp, 0x75, temp & 0xFF);
2733    ViaCrtcMask(hwp, 0x76, temp >> 4, 0x70);
2734}
2735
2736static void
2737iga1_crtc_dpms(xf86CrtcPtr crtc, int mode)
2738{
2739    ScrnInfoPtr pScrn = crtc->scrn;
2740    VIAPtr pVia = VIAPTR(pScrn);
2741    VIABIOSInfoPtr pBIOSInfo = pVia->pBIOSInfo;
2742
2743    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2744                        "Entered iga1_crtc_dpms.\n"));
2745
2746    switch (mode) {
2747    case DPMSModeOn:
2748        viaIGA1DPMSControl(pScrn, 0x00);
2749        break;
2750
2751    case DPMSModeStandby:
2752        viaIGA1DPMSControl(pScrn, 0x01);
2753        break;
2754
2755    case DPMSModeSuspend:
2756        viaIGA1DPMSControl(pScrn, 0x02);
2757        break;
2758
2759    case DPMSModeOff:
2760        viaIGA1DPMSControl(pScrn, 0x03);
2761        break;
2762
2763	default:
2764        xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Invalid DPMS Mode: %d\n",
2765                    mode);
2766        break;
2767    }
2768    //vgaHWSaveScreen(pScrn->pScreen, mode);
2769
2770    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2771                        "Exiting iga1_crtc_dpms.\n"));
2772}
2773
2774static void
2775iga1_crtc_save(xf86CrtcPtr crtc)
2776{
2777    ScrnInfoPtr pScrn = crtc->scrn;
2778    vgaHWPtr hwp = VGAHWPTR(pScrn);
2779    VIAPtr pVia = VIAPTR(pScrn);
2780
2781    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2782                        "Entered iga1_crtc_save.\n"));
2783
2784    vgaHWProtect(pScrn, TRUE);
2785
2786    /* Save the standard VGA registers. */
2787    if (xf86IsPrimaryPci(pVia->PciInfo)) {
2788        vgaHWSave(pScrn, &hwp->SavedReg, VGA_SR_ALL);
2789    } else {
2790        vgaHWSave(pScrn, &hwp->SavedReg, VGA_SR_MODE);
2791    }
2792
2793    viaIGA1Save(pScrn);
2794
2795    vgaHWProtect(pScrn, FALSE);
2796    vgaHWUnlock(hwp);
2797
2798    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2799                        "Exiting iga1_crtc_save.\n"));
2800}
2801
2802static void
2803iga1_crtc_restore(xf86CrtcPtr crtc)
2804{
2805    ScrnInfoPtr pScrn = crtc->scrn;
2806    vgaHWPtr hwp = VGAHWPTR(pScrn);
2807    VIAPtr pVia = VIAPTR(pScrn);
2808    CARD8 tmp;
2809
2810    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2811                        "Entered iga1_crtc_restore.\n"));
2812
2813    vgaHWProtect(pScrn, TRUE);
2814
2815    /* Restore the standard VGA registers. */
2816    if (xf86IsPrimaryPci(pVia->PciInfo)) {
2817        vgaHWRestore(pScrn, &hwp->SavedReg, VGA_SR_ALL);
2818    } else {
2819        vgaHWRestore(pScrn, &hwp->SavedReg, VGA_SR_MODE);
2820    }
2821
2822    /* Gamma must be disabled before restoring palette. */
2823    ViaGammaDisable(pScrn);
2824
2825    viaIGA1Restore(pScrn);
2826
2827    ViaDisablePrimaryFIFO(pScrn);
2828
2829    vgaHWProtect(pScrn, FALSE);
2830    vgaHWLock(hwp);
2831
2832    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2833                        "Exiting iga1_crtc_restore.\n"));
2834}
2835
2836static Bool
2837iga1_crtc_lock(xf86CrtcPtr crtc)
2838{
2839    return FALSE;
2840}
2841
2842static void
2843iga1_crtc_unlock(xf86CrtcPtr crtc)
2844{
2845}
2846
2847static Bool
2848iga1_crtc_mode_fixup(xf86CrtcPtr crtc, DisplayModePtr mode,
2849                        DisplayModePtr adjusted_mode)
2850{
2851    ScrnInfoPtr pScrn = crtc->scrn;
2852    VIAPtr pVia = VIAPTR(pScrn);
2853    CARD32 temp;
2854    ModeStatus modestatus;
2855
2856    if ((mode->Clock < pScrn->clockRanges->minClock) ||
2857        (mode->Clock > pScrn->clockRanges->maxClock)) {
2858        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2859                   "Clock for mode \"%s\" outside of allowed range (%u (%u - %u))\n",
2860                   mode->name, mode->Clock, pScrn->clockRanges->minClock,
2861                   pScrn->clockRanges->maxClock);
2862        return FALSE;
2863    }
2864
2865    modestatus = viaIGA1ModeValid(pScrn, mode);
2866    if (modestatus != MODE_OK) {
2867        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Not using mode \"%s\" : %s.\n",
2868                   mode->name, xf86ModeStatusToString(modestatus));
2869        return FALSE;
2870    }
2871
2872    temp = mode->CrtcHDisplay * mode->CrtcVDisplay * mode->VRefresh *
2873            (pScrn->bitsPerPixel >> 3);
2874    if (pVia->pBIOSInfo->Bandwidth < temp) {
2875        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2876                    "Required bandwidth is not available. (%u > %u)\n",
2877                    (unsigned)temp, (unsigned)pVia->pBIOSInfo->Bandwidth);
2878        return FALSE;
2879    }
2880    return TRUE;
2881}
2882
2883static void
2884iga1_crtc_prepare (xf86CrtcPtr crtc)
2885{
2886}
2887
2888static void
2889iga1_crtc_set_origin(xf86CrtcPtr crtc, int x, int y)
2890{
2891    ScrnInfoPtr pScrn = crtc->scrn;
2892    VIAPtr pVia = VIAPTR(pScrn);
2893
2894    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2895                        "Entered iga1_crtc_set_origin.\n"));
2896
2897    viaIGA1SetFBStartingAddress(crtc, x, y);
2898    VIAVidAdjustFrame(pScrn, x, y);
2899
2900    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2901                        "Exiting iga1_crtc_set_origin.\n"));
2902}
2903
2904static void
2905iga1_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
2906                    DisplayModePtr adjusted_mode,
2907                    int x, int y)
2908{
2909    ScrnInfoPtr pScrn = crtc->scrn;
2910    vgaHWPtr hwp = VGAHWPTR(pScrn);
2911    VIAPtr pVia = VIAPTR(pScrn);
2912    VIABIOSInfoPtr pBIOSInfo = pVia->pBIOSInfo;
2913
2914    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2915                        "Entered iga1_crtc_mode_set.\n"));
2916
2917    if (!vgaHWInit(pScrn, adjusted_mode)) {
2918        DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2919                            "vgaHWInit failed.\n"));
2920        DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2921                            "Exiting iga1_crtc_mode_set.\n"));
2922        return;
2923    }
2924
2925    /* Turn off IGA1 during mode setting. */
2926    viaIGA1DPMSControl(pScrn, 0x03);
2927
2928    viaIGAInitCommon(pScrn);
2929    viaIGA1Init(pScrn);
2930    ViaCRTCInit(pScrn);
2931
2932    /* Turn off Screen */
2933    ViaCrtcMask(hwp, 0x17, 0x00, 0x80);
2934
2935    /* Disable IGA1 */
2936    ViaSeqMask(hwp, 0x59, 0x00, 0x80);
2937
2938    viaIGA1SetDisplayRegister(pScrn, adjusted_mode);
2939    ViaSetPrimaryFIFO(pScrn, adjusted_mode);
2940
2941    pBIOSInfo->Clock = ViaModeDotClockTranslate(pScrn, adjusted_mode);
2942    pBIOSInfo->ClockExternal = FALSE;
2943    ViaSetPrimaryDotclock(pScrn, pBIOSInfo->Clock);
2944    ViaSetUseExternalClock(hwp);
2945    ViaCrtcMask(hwp, 0x6B, 0x00, 0x01);
2946
2947    hwp->disablePalette(hwp);
2948
2949    /* Enable IGA1 */
2950    ViaSeqMask(hwp, 0x59, 0x80, 0x80);
2951
2952    /* Turn on Screen */
2953    ViaCrtcMask(hwp, 0x17, 0x80, 0x80);
2954
2955    viaIGA1SetFBStartingAddress(crtc, x, y);
2956    VIAVidAdjustFrame(pScrn, x, y);
2957
2958    /* Turn on IGA1 now that mode setting is done. */
2959    viaIGA1DPMSControl(pScrn, 0x00);
2960
2961    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2962                        "Exiting iga1_crtc_mode_set.\n"));
2963}
2964
2965static void
2966iga1_crtc_gamma_set(xf86CrtcPtr crtc, CARD16 *red, CARD16 *green, CARD16 *blue,
2967					int size)
2968{
2969    ScrnInfoPtr pScrn = crtc->scrn;
2970    vgaHWPtr hwp = VGAHWPTR(pScrn);
2971    VIAPtr pVia = VIAPTR(pScrn);
2972    int SR1A, SR1B, CR67, CR6A;
2973    LOCO *colors;
2974    int i;
2975
2976    colors = malloc(size * sizeof(*colors));
2977    if (colors == NULL)
2978	return;
2979
2980    for (i = 0; i < size; i++) {
2981        colors[i].red = red[i] >> 8;
2982        colors[i].green = green[i] >> 8;
2983        colors[i].blue = blue[i] >> 8;
2984    }
2985
2986    if (pScrn->bitsPerPixel != 8) {
2987        switch (pVia->Chipset) {
2988        case VIA_CLE266:
2989        case VIA_KM400:
2990            ViaSeqMask(hwp, 0x16, 0x80, 0x80);
2991            break;
2992        default:
2993            ViaCrtcMask(hwp, 0x33, 0x80, 0x80);
2994            break;
2995        }
2996
2997        ViaSeqMask(hwp, 0x1A, 0x00, 0x01);
2998        VIALoadRgbLut(pScrn, 0, size, colors);
2999
3000    } else {
3001
3002        SR1A = hwp->readSeq(hwp, 0x1A);
3003        SR1B = hwp->readSeq(hwp, 0x1B);
3004        CR67 = hwp->readCrtc(hwp, 0x67);
3005        CR6A = hwp->readCrtc(hwp, 0x6A);
3006
3007        for (i = 0; i < size; i++) {
3008            hwp->writeDacWriteAddr(hwp, i);
3009            hwp->writeDacData(hwp, colors[i].red);
3010            hwp->writeDacData(hwp, colors[i].green);
3011            hwp->writeDacData(hwp, colors[i].blue);
3012        }
3013    }
3014    free(colors);
3015}
3016
3017static void *
3018iga1_crtc_shadow_allocate (xf86CrtcPtr crtc, int width, int height)
3019{
3020    return NULL;
3021}
3022
3023static PixmapPtr
3024iga1_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
3025{
3026    return NULL;
3027}
3028
3029static void
3030iga1_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data)
3031{
3032}
3033
3034/*
3035    Set the cursor foreground and background colors.  In 8bpp, fg and
3036    bg are indices into the current colormap unless the
3037    HARDWARE_CURSOR_TRUECOLOR_AT_8BPP flag is set.  In that case
3038    and in all other bpps the fg and bg are in 8-8-8 RGB format.
3039*/
3040static void
3041iga1_crtc_set_cursor_colors (xf86CrtcPtr crtc, int bg, int fg)
3042{
3043    ScrnInfoPtr pScrn = crtc->scrn;
3044    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
3045    VIAPtr pVia = VIAPTR(pScrn);
3046    CARD32 temp;
3047
3048    if (xf86_config->cursor_fg)
3049        return;
3050
3051    /* Don't recolour the image if we don't have to. */
3052    if (fg == xf86_config->cursor_fg && bg == xf86_config->cursor_bg)
3053        return;
3054
3055    switch(pVia->Chipset) {
3056    case VIA_PM800:
3057    case VIA_CX700:
3058    case VIA_P4M890:
3059    case VIA_P4M900:
3060    case VIA_VX800:
3061    case VIA_VX855:
3062    case VIA_VX900:
3063        temp = VIAGETREG(PRIM_HI_CTRL);
3064        VIASETREG(PRIM_HI_CTRL, temp & 0xFFFFFFFE);
3065        break;
3066
3067    default:
3068        temp = VIAGETREG(HI_CONTROL);
3069        VIASETREG(HI_CONTROL, temp & 0xFFFFFFFE);
3070        break;
3071    }
3072
3073    xf86_config->cursor_fg = fg;
3074    xf86_config->cursor_bg = bg;
3075}
3076
3077static void
3078iga1_crtc_set_cursor_position (xf86CrtcPtr crtc, int x, int y)
3079{
3080    ScrnInfoPtr pScrn = crtc->scrn;
3081    VIAPtr pVia = VIAPTR(pScrn);
3082    unsigned xoff, yoff;
3083
3084    if (x < 0) {
3085        xoff = ((-x) & 0xFE);
3086        x = 0;
3087    } else {
3088        xoff = 0;
3089    }
3090
3091    if (y < 0) {
3092        yoff = ((-y) & 0xFE);
3093        y = 0;
3094    } else {
3095        yoff = 0;
3096    }
3097
3098    switch(pVia->Chipset) {
3099    case VIA_PM800:
3100    case VIA_CX700:
3101    case VIA_P4M890:
3102    case VIA_P4M900:
3103    case VIA_VX800:
3104    case VIA_VX855:
3105    case VIA_VX900:
3106        VIASETREG(PRIM_HI_POSSTART,    ((x    << 16) | (y    & 0x07ff)));
3107        VIASETREG(PRIM_HI_CENTEROFFSET, ((xoff << 16) | (yoff & 0x07ff)));
3108        break;
3109
3110    default:
3111        VIASETREG(HI_POSSTART,    ((x    << 16) | (y    & 0x07ff)));
3112        VIASETREG(HI_CENTEROFFSET, ((xoff << 16) | (yoff & 0x07ff)));
3113        break;
3114    }
3115}
3116
3117static void
3118iga1_crtc_show_cursor (xf86CrtcPtr crtc)
3119{
3120    drmmode_crtc_private_ptr iga = crtc->driver_private;
3121    ScrnInfoPtr pScrn = crtc->scrn;
3122    VIAPtr pVia = VIAPTR(pScrn);
3123
3124    switch(pVia->Chipset) {
3125    case VIA_PM800:
3126    case VIA_CX700:
3127    case VIA_P4M890:
3128    case VIA_P4M900:
3129    case VIA_VX800:
3130    case VIA_VX855:
3131    case VIA_VX900:
3132        VIASETREG(PRIM_HI_FBOFFSET, iga->cursor_bo->offset);
3133        VIASETREG(PRIM_HI_CTRL, 0x36000005);
3134        break;
3135
3136    default:
3137        /* Mono Cursor Display Path [bit31]: Primary */
3138        VIASETREG(HI_FBOFFSET, iga->cursor_bo->offset);
3139        VIASETREG(HI_CONTROL, 0x76000005);
3140        break;
3141    }
3142}
3143
3144static void
3145iga1_crtc_hide_cursor (xf86CrtcPtr crtc)
3146{
3147    ScrnInfoPtr pScrn = crtc->scrn;
3148    VIAPtr pVia = VIAPTR(pScrn);
3149    CARD32 temp;
3150
3151    switch(pVia->Chipset) {
3152    case VIA_PM800:
3153    case VIA_CX700:
3154    case VIA_P4M890:
3155    case VIA_P4M900:
3156    case VIA_VX800:
3157    case VIA_VX855:
3158    case VIA_VX900:
3159        temp = VIAGETREG(PRIM_HI_CTRL);
3160        VIASETREG(PRIM_HI_CTRL, temp & 0xFFFFFFFA);
3161        break;
3162
3163    default:
3164        temp = VIAGETREG(HI_CONTROL);
3165        /* Hardware cursor disable [bit0] */
3166        VIASETREG(HI_CONTROL, temp & 0xFFFFFFFA);
3167        break;
3168    }
3169}
3170
3171static void
3172iga_crtc_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *image)
3173{
3174    drmmode_crtc_private_ptr iga = crtc->driver_private;
3175    ScrnInfoPtr pScrn = crtc->scrn;
3176    void *dst;
3177
3178    dst = drm_bo_map(pScrn, iga->cursor_bo);
3179    memset(dst, 0x00, iga->cursor_bo->size);
3180    memcpy(dst, image, iga->cursor_bo->size);
3181    drm_bo_unmap(pScrn, iga->cursor_bo);
3182}
3183
3184static void
3185iga_crtc_commit(xf86CrtcPtr crtc)
3186{
3187    ScrnInfoPtr pScrn = crtc->scrn;
3188    VIAPtr pVia = VIAPTR(pScrn);
3189
3190    if (crtc->scrn->pScreen != NULL && pVia->drmmode.hwcursor)
3191        xf86_reload_cursors(crtc->scrn->pScreen);
3192}
3193
3194static void
3195iga_crtc_destroy(xf86CrtcPtr crtc)
3196{
3197    if (crtc->driver_private)
3198        free(crtc->driver_private);
3199}
3200
3201const xf86CrtcFuncsRec iga1_crtc_funcs = {
3202    .dpms                   = iga1_crtc_dpms,
3203    .save                   = iga1_crtc_save,
3204    .restore                = iga1_crtc_restore,
3205    .lock                   = iga1_crtc_lock,
3206    .unlock                 = iga1_crtc_unlock,
3207    .mode_fixup             = iga1_crtc_mode_fixup,
3208    .prepare                = iga1_crtc_prepare,
3209    .mode_set               = iga1_crtc_mode_set,
3210    .commit                 = iga_crtc_commit,
3211    .gamma_set              = iga1_crtc_gamma_set,
3212    .shadow_create          = iga1_crtc_shadow_create,
3213    .shadow_allocate        = iga1_crtc_shadow_allocate,
3214    .shadow_destroy         = iga1_crtc_shadow_destroy,
3215    .set_cursor_colors      = iga1_crtc_set_cursor_colors,
3216    .set_cursor_position    = iga1_crtc_set_cursor_position,
3217    .show_cursor            = iga1_crtc_show_cursor,
3218    .hide_cursor            = iga1_crtc_hide_cursor,
3219    .load_cursor_argb       = iga_crtc_load_cursor_argb,
3220#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) > 2
3221    .set_origin             = iga1_crtc_set_origin,
3222#endif
3223    .destroy                = iga_crtc_destroy,
3224};
3225
3226static void
3227iga2_crtc_dpms(xf86CrtcPtr crtc, int mode)
3228{
3229    ScrnInfoPtr pScrn = crtc->scrn;
3230    VIAPtr pVia = VIAPTR(pScrn);
3231    VIABIOSInfoPtr pBIOSInfo = pVia->pBIOSInfo;
3232
3233    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3234                        "Entered iga2_crtc_dpms.\n"));
3235
3236    switch (mode) {
3237    case DPMSModeOn:
3238        viaIGA2DisplayOutput(pScrn, TRUE);
3239        break;
3240
3241    case DPMSModeStandby:
3242    case DPMSModeSuspend:
3243    case DPMSModeOff:
3244        viaIGA2DisplayOutput(pScrn, FALSE);
3245        break;
3246
3247    default:
3248        xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Invalid DPMS mode: %d\n",
3249                    mode);
3250        break;
3251    }
3252    //vgaHWSaveScreen(pScrn->pScreen, mode);
3253
3254    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3255                        "Exiting iga2_crtc_dpms.\n"));
3256}
3257
3258static void
3259iga2_crtc_save(xf86CrtcPtr crtc)
3260{
3261    ScrnInfoPtr pScrn = crtc->scrn;
3262    vgaHWPtr hwp = VGAHWPTR(pScrn);
3263    VIAPtr pVia = VIAPTR(pScrn);
3264
3265    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3266                        "Entered iga2_crtc_save.\n"));
3267
3268    viaIGA2Save(pScrn);
3269
3270    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3271                        "Exiting iga2_crtc_save.\n"));
3272}
3273
3274static void
3275iga2_crtc_restore(xf86CrtcPtr crtc)
3276{
3277    ScrnInfoPtr pScrn = crtc->scrn;
3278    vgaHWPtr hwp = VGAHWPTR(pScrn);
3279    VIAPtr pVia = VIAPTR(pScrn);
3280    CARD8 tmp;
3281
3282    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3283                        "Entered iga2_crtc_restore.\n"));
3284
3285    viaIGA2Restore(pScrn);
3286
3287    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3288                        "Exiting iga2_crtc_restore.\n"));
3289}
3290
3291static Bool
3292iga2_crtc_lock(xf86CrtcPtr crtc)
3293{
3294    return FALSE;
3295}
3296
3297static void
3298iga2_crtc_unlock(xf86CrtcPtr crtc)
3299{
3300}
3301
3302static Bool
3303iga2_crtc_mode_fixup(xf86CrtcPtr crtc, DisplayModePtr mode,
3304                        DisplayModePtr adjusted_mode)
3305{
3306    ScrnInfoPtr pScrn = crtc->scrn;
3307    VIAPtr pVia = VIAPTR(pScrn);
3308    CARD32 temp;
3309    ModeStatus modestatus;
3310
3311    if ((mode->Clock < pScrn->clockRanges->minClock) ||
3312        (mode->Clock > pScrn->clockRanges->maxClock)) {
3313        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3314                   "Clock for mode \"%s\" outside of allowed range (%u (%u - %u))\n",
3315                   mode->name, mode->Clock, pScrn->clockRanges->minClock,
3316                   pScrn->clockRanges->maxClock);
3317        return FALSE;
3318    }
3319
3320    modestatus = viaIGA2ModeValid(pScrn, mode);
3321    if (modestatus != MODE_OK) {
3322        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Not using mode \"%s\" : %s.\n",
3323                   mode->name, xf86ModeStatusToString(modestatus));
3324        return FALSE;
3325    }
3326
3327    temp = mode->CrtcHDisplay * mode->CrtcVDisplay * mode->VRefresh *
3328            (pScrn->bitsPerPixel >> 3);
3329    if (pVia->pBIOSInfo->Bandwidth < temp) {
3330        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3331                    "Required bandwidth is not available. (%u > %u)\n",
3332			        (unsigned)temp, (unsigned)pVia->pBIOSInfo->Bandwidth);
3333        return FALSE;
3334    }
3335    return TRUE;
3336}
3337
3338static void
3339iga2_crtc_prepare (xf86CrtcPtr crtc)
3340{
3341}
3342
3343static void
3344iga2_crtc_set_origin(xf86CrtcPtr crtc, int x, int y)
3345{
3346    ScrnInfoPtr pScrn = crtc->scrn;
3347    VIAPtr pVia = VIAPTR(pScrn);
3348
3349    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3350                        "Entered iga2_crtc_set_origin.\n"));
3351
3352    viaIGA2SetFBStartingAddress(crtc, x, y);
3353    VIAVidAdjustFrame(pScrn, x, y);
3354
3355    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3356                        "Exiting iga2_crtc_set_origin.\n"));
3357}
3358
3359static void
3360iga2_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
3361                    DisplayModePtr adjusted_mode, int x, int y)
3362{
3363    ScrnInfoPtr pScrn = crtc->scrn;
3364    vgaHWPtr hwp = VGAHWPTR(pScrn);
3365    VIAPtr pVia = VIAPTR(pScrn);
3366    VIABIOSInfoPtr pBIOSInfo = pVia->pBIOSInfo;
3367
3368    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3369                        "Entered iga2_crtc_mode_set.\n"));
3370
3371    if (!vgaHWInit(pScrn, adjusted_mode)) {
3372        DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3373                            "vgaHWInit failed.\n"));
3374        DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3375                            "Exiting iga2_crtc_mode_set.\n"));
3376        return;
3377    }
3378
3379    /* Turn off IGA2 during mode setting. */
3380    viaIGA2DisplayOutput(pScrn, FALSE);
3381
3382    viaIGAInitCommon(pScrn);
3383    viaIGA2Init(pScrn);
3384    ViaCRTCInit(pScrn);
3385
3386    viaIGA2SetDisplayRegister(pScrn, adjusted_mode);
3387    ViaSetSecondaryFIFO(pScrn, adjusted_mode);
3388    pBIOSInfo->Clock = ViaModeDotClockTranslate(pScrn, adjusted_mode);
3389    pBIOSInfo->ClockExternal = FALSE;
3390    ViaSetSecondaryDotclock(pScrn, pBIOSInfo->Clock);
3391    ViaSetUseExternalClock(hwp);
3392
3393    hwp->disablePalette(hwp);
3394
3395    viaIGA2DisplayChannel(pScrn, TRUE);
3396
3397    viaIGA2SetFBStartingAddress(crtc, x, y);
3398    VIAVidAdjustFrame(pScrn, x, y);
3399
3400    /* Turn on IGA2 now that mode setting is done. */
3401    viaIGA2DisplayOutput(pScrn, TRUE);
3402
3403    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3404                        "Exiting iga2_crtc_mode_set.\n"));
3405}
3406
3407static void
3408iga2_crtc_gamma_set(xf86CrtcPtr crtc, CARD16 *red, CARD16 *green, CARD16 *blue,
3409					int size)
3410{
3411    ScrnInfoPtr pScrn = crtc->scrn;
3412    vgaHWPtr hwp = VGAHWPTR(pScrn);
3413    VIAPtr pVia = VIAPTR(pScrn);
3414    int SR1A, SR1B, CR67, CR6A;
3415    int i;
3416    LOCO *colors;
3417
3418    colors = malloc(size * sizeof(*colors));
3419    if (colors == NULL)
3420	return;
3421
3422    for (i = 0; i < size; i++) {
3423        colors[i].red = red[i] >> 8;
3424        colors[i].green = green[i] >> 8;
3425        colors[i].blue = blue[i] >> 8;
3426    }
3427
3428    if (pScrn->bitsPerPixel != 8) {
3429        if (!(pVia->Chipset == VIA_CLE266 &&
3430            CLE266_REV_IS_AX(pVia->ChipRev))) {
3431            ViaSeqMask(hwp, 0x1A, 0x01, 0x01);
3432            ViaCrtcMask(hwp, 0x6A, 0x02, 0x02);
3433
3434            switch (pVia->Chipset) {
3435            case VIA_CLE266:
3436            case VIA_KM400:
3437            case VIA_K8M800:
3438            case VIA_PM800:
3439                break;
3440
3441            default:
3442                ViaCrtcMask(hwp, 0x6A, 0x20, 0x20);
3443                break;
3444            }
3445            VIALoadRgbLut(pScrn, 0, size, colors);
3446        }
3447    } else {
3448        SR1A = hwp->readSeq(hwp, 0x1A);
3449        SR1B = hwp->readSeq(hwp, 0x1B);
3450        CR67 = hwp->readCrtc(hwp, 0x67);
3451        CR6A = hwp->readCrtc(hwp, 0x6A);
3452
3453        ViaSeqMask(hwp, 0x1A, 0x01, 0x01);
3454        ViaSeqMask(hwp, 0x1B, 0x80, 0x80);
3455        ViaCrtcMask(hwp, 0x67, 0x00, 0xC0);
3456        ViaCrtcMask(hwp, 0x6A, 0xC0, 0xC0);
3457
3458        for (i = 0; i < size; i++) {
3459            hwp->writeDacWriteAddr(hwp, i);
3460            hwp->writeDacData(hwp, colors[i].red);
3461            hwp->writeDacData(hwp, colors[i].green);
3462            hwp->writeDacData(hwp, colors[i].blue);
3463        }
3464
3465        hwp->writeSeq(hwp, 0x1A, SR1A);
3466        hwp->writeSeq(hwp, 0x1B, SR1B);
3467        hwp->writeCrtc(hwp, 0x67, CR67);
3468        hwp->writeCrtc(hwp, 0x6A, CR6A);
3469
3470        /* Screen 0 palette was changed by mode setting of Screen 1,
3471         * so load it again. */
3472        for (i = 0; i < size; i++) {
3473            hwp->writeDacWriteAddr(hwp, i);
3474            hwp->writeDacData(hwp, colors[i].red);
3475            hwp->writeDacData(hwp, colors[i].green);
3476            hwp->writeDacData(hwp, colors[i].blue);
3477        }
3478    }
3479    free(colors);
3480}
3481
3482static void *
3483iga2_crtc_shadow_allocate (xf86CrtcPtr crtc, int width, int height)
3484{
3485    return NULL;
3486}
3487
3488static PixmapPtr
3489iga2_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
3490{
3491    return NULL;
3492}
3493
3494static void
3495iga2_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data)
3496{
3497}
3498
3499/*
3500    Set the cursor foreground and background colors.  In 8bpp, fg and
3501    bg are indices into the current colormap unless the
3502    HARDWARE_CURSOR_TRUECOLOR_AT_8BPP flag is set.  In that case
3503    and in all other bpps the fg and bg are in 8-8-8 RGB format.
3504*/
3505static void
3506iga2_crtc_set_cursor_colors(xf86CrtcPtr crtc, int bg, int fg)
3507{
3508    drmmode_crtc_private_ptr iga = crtc->driver_private;
3509    ScrnInfoPtr pScrn = crtc->scrn;
3510    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
3511    int height = 64, width = 64, i;
3512    VIAPtr pVia = VIAPTR(pScrn);
3513    CARD32 pixel, temp, *dst;
3514
3515    if (xf86_config->cursor_fg)
3516        return;
3517
3518    fg |= 0xff000000;
3519    bg |= 0xff000000;
3520
3521    /* Don't recolour the image if we don't have to. */
3522    if (fg == xf86_config->cursor_fg && bg == xf86_config->cursor_bg)
3523        return;
3524
3525    switch(pVia->Chipset) {
3526    case VIA_PM800:
3527    case VIA_CX700:
3528    case VIA_P4M890:
3529    case VIA_P4M900:
3530    case VIA_VX800:
3531    case VIA_VX855:
3532    case VIA_VX900:
3533        temp = VIAGETREG(HI_CONTROL);
3534        VIASETREG(HI_CONTROL, temp & 0xFFFFFFFE);
3535        break;
3536
3537    default:
3538        temp = VIAGETREG(HI_CONTROL);
3539        VIASETREG(HI_CONTROL, temp & 0xFFFFFFFE);
3540        height = width = 32;
3541        break;
3542    }
3543
3544    dst = drm_bo_map(pScrn, iga->cursor_bo);
3545    for (i = 0; i < width * height; i++, dst++)
3546        if ((pixel = *dst))
3547            *dst = (pixel == xf86_config->cursor_fg) ? fg : bg;
3548    drm_bo_unmap(pScrn, iga->cursor_bo);
3549
3550    xf86_config->cursor_fg = fg;
3551    xf86_config->cursor_bg = bg;
3552}
3553
3554static void
3555iga2_crtc_set_cursor_position(xf86CrtcPtr crtc, int x, int y)
3556{
3557    ScrnInfoPtr pScrn = crtc->scrn;
3558    VIAPtr pVia = VIAPTR(pScrn);
3559    unsigned xoff, yoff;
3560
3561    if (x < 0) {
3562        xoff = ((-x) & 0xFE);
3563        x = 0;
3564    } else {
3565        xoff = 0;
3566    }
3567
3568    if (y < 0) {
3569        yoff = ((-y) & 0xFE);
3570        y = 0;
3571    } else {
3572        yoff = 0;
3573    }
3574
3575    switch(pVia->Chipset) {
3576    case VIA_PM800:
3577    case VIA_CX700:
3578    case VIA_P4M890:
3579    case VIA_P4M900:
3580    case VIA_VX800:
3581    case VIA_VX855:
3582    case VIA_VX900:
3583        VIASETREG(HI_POSSTART,    ((x    << 16) | (y    & 0x07ff)));
3584        VIASETREG(HI_CENTEROFFSET, ((xoff << 16) | (yoff & 0x07ff)));
3585        break;
3586
3587    default:
3588        VIASETREG(HI_POSSTART,    ((x    << 16) | (y    & 0x07ff)));
3589        VIASETREG(HI_CENTEROFFSET, ((xoff << 16) | (yoff & 0x07ff)));
3590        break;
3591    }
3592}
3593
3594static void
3595iga2_crtc_show_cursor(xf86CrtcPtr crtc)
3596{
3597    drmmode_crtc_private_ptr iga = crtc->driver_private;
3598    ScrnInfoPtr pScrn = crtc->scrn;
3599    VIAPtr pVia = VIAPTR(pScrn);
3600
3601    switch(pVia->Chipset) {
3602    case VIA_PM800:
3603    case VIA_CX700:
3604    case VIA_P4M890:
3605    case VIA_P4M900:
3606    case VIA_VX800:
3607    case VIA_VX855:
3608    case VIA_VX900:
3609        VIASETREG(HI_FBOFFSET, iga->cursor_bo->offset);
3610        VIASETREG(HI_CONTROL, 0xB6000005);
3611        break;
3612
3613    default:
3614        /* Mono Cursor Display Path [bit31]: Secondary */
3615        /* FIXME For CLE266 and KM400 try to enable 32x32 cursor size [bit1] */
3616        VIASETREG(HI_FBOFFSET, iga->cursor_bo->offset);
3617        VIASETREG(HI_CONTROL, 0xF6000005);
3618        break;
3619    }
3620}
3621
3622static void
3623iga2_crtc_hide_cursor(xf86CrtcPtr crtc)
3624{
3625    ScrnInfoPtr pScrn = crtc->scrn;
3626    VIAPtr pVia = VIAPTR(pScrn);
3627    CARD32 temp;
3628
3629    switch(pVia->Chipset) {
3630    case VIA_PM800:
3631    case VIA_CX700:
3632    case VIA_P4M890:
3633    case VIA_P4M900:
3634    case VIA_VX800:
3635    case VIA_VX855:
3636    case VIA_VX900:
3637	    temp = VIAGETREG(HI_CONTROL);
3638        VIASETREG(HI_CONTROL, temp & 0xFFFFFFFA);
3639        break;
3640
3641    default:
3642        temp = VIAGETREG(HI_CONTROL);
3643        /* Hardware cursor disable [bit0] */
3644        VIASETREG(HI_CONTROL, temp & 0xFFFFFFFA);
3645        break;
3646	}
3647}
3648
3649const xf86CrtcFuncsRec iga2_crtc_funcs = {
3650    .dpms                   = iga2_crtc_dpms,
3651    .save                   = iga2_crtc_save,
3652    .restore                = iga2_crtc_restore,
3653    .lock                   = iga2_crtc_lock,
3654    .unlock                 = iga2_crtc_unlock,
3655    .mode_fixup             = iga2_crtc_mode_fixup,
3656    .prepare                = iga2_crtc_prepare,
3657    .mode_set               = iga2_crtc_mode_set,
3658    .commit                 = iga_crtc_commit,
3659    .gamma_set              = iga2_crtc_gamma_set,
3660    .shadow_create          = iga2_crtc_shadow_create,
3661    .shadow_allocate        = iga2_crtc_shadow_allocate,
3662    .shadow_destroy         = iga2_crtc_shadow_destroy,
3663    .set_cursor_colors      = iga2_crtc_set_cursor_colors,
3664    .set_cursor_position    = iga2_crtc_set_cursor_position,
3665    .show_cursor            = iga2_crtc_show_cursor,
3666    .hide_cursor            = iga2_crtc_hide_cursor,
3667    .load_cursor_argb       = iga_crtc_load_cursor_argb,
3668#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) > 2
3669    .set_origin             = iga2_crtc_set_origin,
3670#endif
3671    .destroy                = iga_crtc_destroy,
3672};
3673