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