via_outputs.c revision 1a337bac
1/*
2 * Copyright 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
29/*
30 * via_outputs.c
31 *
32 * Everything to do with setting and changing xf86Outputs.
33 *
34 */
35
36#ifdef HAVE_CONFIG_H
37#include "config.h"
38#endif
39
40#include "via_driver.h"
41#include <unistd.h>
42
43/*
44 * Modetable nonsense.
45 *
46 */
47#include "via_mode.h"
48
49static void
50ViaPrintMode(ScrnInfoPtr pScrn, DisplayModePtr mode)
51{
52    xf86PrintModeline(pScrn->scrnIndex, mode);
53
54    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CrtcHDisplay: 0x%x\n",
55               mode->CrtcHDisplay);
56    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CrtcHBlankStart: 0x%x\n",
57               mode->CrtcHBlankStart);
58    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CrtcHSyncStart: 0x%x\n",
59               mode->CrtcHSyncStart);
60    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CrtcHSyncEnd: 0x%x\n",
61               mode->CrtcHSyncEnd);
62    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CrtcHBlankEnd: 0x%x\n",
63               mode->CrtcHBlankEnd);
64    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CrtcHTotal: 0x%x\n",
65               mode->CrtcHTotal);
66    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CrtcHSkew: 0x%x\n",
67               mode->CrtcHSkew);
68    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CrtcVDisplay: 0x%x\n",
69               mode->CrtcVDisplay);
70    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CrtcVBlankStart: 0x%x\n",
71               mode->CrtcVBlankStart);
72    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CrtcVSyncStart: 0x%x\n",
73               mode->CrtcVSyncStart);
74    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CrtcVSyncEnd: 0x%x\n",
75               mode->CrtcVSyncEnd);
76    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CrtcVBlankEnd: 0x%x\n",
77               mode->CrtcVBlankEnd);
78    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CrtcVTotal: 0x%x\n",
79               mode->CrtcVTotal);
80
81}
82
83/*
84 *
85 * TV specific code.
86 *
87 */
88void
89ViaTVSave(ScrnInfoPtr pScrn)
90{
91    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
92
93    if (pBIOSInfo->TVSave)
94        pBIOSInfo->TVSave(pScrn);
95}
96
97void
98ViaTVRestore(ScrnInfoPtr pScrn)
99{
100    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
101
102    if (pBIOSInfo->TVRestore)
103        pBIOSInfo->TVRestore(pScrn);
104}
105
106static Bool
107ViaTVDACSense(ScrnInfoPtr pScrn)
108{
109    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
110
111    if (pBIOSInfo->TVDACSense)
112        return pBIOSInfo->TVDACSense(pScrn);
113    return FALSE;
114}
115
116static void
117ViaTVSetMode(xf86CrtcPtr crtc, DisplayModePtr mode)
118{
119    ScrnInfoPtr pScrn = crtc->scrn;
120    VIAPtr pVia = VIAPTR(pScrn);
121    VIABIOSInfoPtr pBIOSInfo = pVia->pBIOSInfo;
122
123    if (pBIOSInfo->TVModeI2C)
124        pBIOSInfo->TVModeI2C(pScrn, mode);
125
126    if (pBIOSInfo->TVModeCrtc)
127        pBIOSInfo->TVModeCrtc(crtc, mode);
128
129    /* TV reset. */
130    xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x1D, 0x00);
131    xf86I2CWriteByte(pBIOSInfo->TVI2CDev, 0x1D, 0x80);
132}
133
134void
135ViaTVPower(ScrnInfoPtr pScrn, Bool On)
136{
137    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
138
139#ifdef HAVE_DEBUG
140    if (On)
141        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "ViaTVPower: On.\n");
142    else
143        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "ViaTVPower: Off.\n");
144#endif
145
146    if (pBIOSInfo->TVPower)
147        pBIOSInfo->TVPower(pScrn, On);
148}
149
150#ifdef HAVE_DEBUG
151void
152ViaTVPrintRegs(ScrnInfoPtr pScrn)
153{
154    VIABIOSInfoPtr pBIOSInfo = VIAPTR(pScrn)->pBIOSInfo;
155
156    if (pBIOSInfo->TVPrintRegs)
157        pBIOSInfo->TVPrintRegs(pScrn);
158}
159#endif /* HAVE_DEBUG */
160
161static void
162via_tv_create_resources(xf86OutputPtr output)
163{
164}
165
166#ifdef RANDR_12_INTERFACE
167static Bool
168via_tv_set_property(xf86OutputPtr output, Atom property,
169                    RRPropertyValuePtr value)
170{
171    return TRUE;
172}
173
174static Bool
175via_tv_get_property(xf86OutputPtr output, Atom property)
176{
177    return FALSE;
178}
179#endif
180
181static void
182via_tv_dpms(xf86OutputPtr output, int mode)
183{
184    ScrnInfoPtr pScrn = output->scrn;
185
186    switch (mode) {
187    case DPMSModeOn:
188        ViaTVPower(pScrn, TRUE);
189        break;
190
191    case DPMSModeStandby:
192    case DPMSModeSuspend:
193    case DPMSModeOff:
194        ViaTVPower(pScrn, FALSE);
195        break;
196    }
197}
198
199static void
200via_tv_save(xf86OutputPtr output)
201{
202    ScrnInfoPtr pScrn = output->scrn;
203
204    ViaTVSave(pScrn);
205}
206
207static void
208via_tv_restore(xf86OutputPtr output)
209{
210    ScrnInfoPtr pScrn = output->scrn;
211
212    ViaTVRestore(pScrn);
213}
214
215static int
216via_tv_mode_valid(xf86OutputPtr output, DisplayModePtr pMode)
217{
218    ScrnInfoPtr pScrn = output->scrn;
219    VIAPtr pVia = VIAPTR(pScrn);
220    int ret = MODE_OK;
221
222    if (!ViaModeDotClockTranslate(pScrn, pMode))
223        return MODE_NOCLOCK;
224
225    return ret;
226}
227
228static Bool
229via_tv_mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
230                  DisplayModePtr adjusted_mode)
231{
232    return TRUE;
233}
234
235static void
236via_tv_prepare(xf86OutputPtr output)
237{
238    via_tv_dpms(output, DPMSModeOff);
239}
240
241static void
242via_tv_commit(xf86OutputPtr output)
243{
244    via_tv_dpms(output, DPMSModeOn);
245}
246
247static void
248ViaDisplayEnableDVO(ScrnInfoPtr pScrn, int port)
249{
250    vgaHWPtr hwp = VGAHWPTR(pScrn);
251
252    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "ViaDisplayEnableDVO, port: %d\n",
253                     port));
254    switch (port) {
255    case VIA_DI_PORT_DVP0:
256        ViaSeqMask(hwp, 0x1E, 0xC0, 0xC0);
257        break;
258    case VIA_DI_PORT_DVP1:
259        ViaSeqMask(hwp, 0x1E, 0x30, 0x30);
260        break;
261    }
262}
263
264static void
265ViaDisplayDisableDVO(ScrnInfoPtr pScrn, int port)
266{
267    vgaHWPtr hwp = VGAHWPTR(pScrn);
268
269    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "ViaDisplayDisableDVO, port: %d\n",
270                     port));
271    switch (port) {
272    case VIA_DI_PORT_DVP0:
273        ViaSeqMask(hwp, 0x1E, 0x00, 0xC0);
274        break;
275    case VIA_DI_PORT_DVP1:
276        ViaSeqMask(hwp, 0x1E, 0x00, 0x30);
277        break;
278    }
279}
280
281static void
282ViaDisplaySetStreamOnDVO(ScrnInfoPtr pScrn, int port, int iga)
283{
284    vgaHWPtr hwp = VGAHWPTR(pScrn);
285    int regNum;
286
287    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "ViaDisplaySetStreamOnDVO, port: %d\n",
288                     port));
289
290    switch (port) {
291        case VIA_DI_PORT_DVP0:
292            regNum = 0x96;
293            break;
294        case VIA_DI_PORT_DVP1:
295            regNum = 0x9B;
296            break;
297        case VIA_DI_PORT_DFPLOW:
298            regNum = 0x97;
299            break;
300        case VIA_DI_PORT_DFPHIGH:
301            regNum = 0x99;
302            break;
303    }
304
305    if (!iga)
306        ViaCrtcMask(hwp, regNum, 0x00, 0x10);
307    else
308        ViaCrtcMask(hwp, regNum, 0x10, 0x10);
309}
310
311static void
312via_tv_mode_set(xf86OutputPtr output, DisplayModePtr mode,
313                DisplayModePtr adjusted_mode)
314{
315    ScrnInfoPtr pScrn = output->scrn;
316    VIAPtr pVia = VIAPTR(pScrn);
317    VIABIOSInfoPtr pBIOSInfo = pVia->pBIOSInfo;
318
319    /* TV on FirstCrtc */
320    if (output->crtc) {
321        drmmode_crtc_private_ptr iga = output->crtc->driver_private;
322
323        ViaDisplaySetStreamOnDVO(pScrn, pBIOSInfo->TVDIPort, iga->index);
324    }
325    ViaDisplayEnableDVO(pScrn, pBIOSInfo->TVDIPort);
326
327    ViaTVSetMode(output->crtc, adjusted_mode);
328
329    pVia->FirstInit = FALSE;
330}
331
332static xf86OutputStatus
333via_tv_detect(xf86OutputPtr output)
334{
335    xf86OutputStatus status = XF86OutputStatusDisconnected;
336    ScrnInfoPtr pScrn = output->scrn;
337
338    if (ViaTVDACSense(pScrn))
339        status = XF86OutputStatusConnected;
340    return status;
341}
342
343static DisplayModePtr
344via_tv_get_modes(xf86OutputPtr output)
345{
346    DisplayModePtr modes = NULL, mode = NULL;
347    ScrnInfoPtr pScrn = output->scrn;
348    VIAPtr pVia = VIAPTR(pScrn);
349    int i;
350
351    for (i = 0; i < pVia->pBIOSInfo->TVNumModes; i++) {
352        mode = xf86DuplicateMode(&pVia->pBIOSInfo->TVModes[i]);
353        modes = xf86ModesAdd(modes, mode);
354    }
355    return modes;
356}
357
358static void
359via_tv_destroy(xf86OutputPtr output)
360{
361}
362
363static const xf86OutputFuncsRec via_tv_funcs = {
364    .create_resources   = via_tv_create_resources,
365#ifdef RANDR_12_INTERFACE
366    .set_property       = via_tv_set_property,
367#endif
368#ifdef RANDR_13_INTERFACE
369    .get_property       = via_tv_get_property,
370#endif
371    .dpms               = via_tv_dpms,
372    .save               = via_tv_save,
373    .restore            = via_tv_restore,
374    .mode_valid         = via_tv_mode_valid,
375    .mode_fixup         = via_tv_mode_fixup,
376    .prepare            = via_tv_prepare,
377    .commit             = via_tv_commit,
378    .mode_set           = via_tv_mode_set,
379    .detect             = via_tv_detect,
380    .get_modes          = via_tv_get_modes,
381    .destroy            = via_tv_destroy,
382};
383
384/*
385 *
386 */
387static Bool
388via_tv_init(ScrnInfoPtr pScrn)
389{
390    VIAPtr pVia = VIAPTR(pScrn);
391    VIABIOSInfoPtr pBIOSInfo = pVia->pBIOSInfo;
392    xf86OutputPtr output = NULL;
393
394    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
395                        "Entered via_tv_init.\n"));
396
397    /* preset some pBIOSInfo TV related values -- move up */
398    pBIOSInfo->TVEncoder = VIA_NONETV;
399    pBIOSInfo->TVI2CDev = NULL;
400    pBIOSInfo->TVSave = NULL;
401    pBIOSInfo->TVRestore = NULL;
402    pBIOSInfo->TVDACSense = NULL;
403    pBIOSInfo->TVModeValid = NULL;
404    pBIOSInfo->TVModeI2C = NULL;
405    pBIOSInfo->TVModeCrtc = NULL;
406    pBIOSInfo->TVPower = NULL;
407    pBIOSInfo->TVModes = NULL;
408    pBIOSInfo->TVPrintRegs = NULL;
409    pBIOSInfo->LCDPower = NULL;
410    pBIOSInfo->TVNumRegs = 0;
411
412    /*
413     * On an SK43G (KM400/Ch7011), false positive detections at a VT162x
414     * chip were observed, so try to detect the Ch7011 first.
415     */
416    if (pVia->pI2CBus2 && xf86I2CProbeAddress(pVia->pI2CBus2, 0xEC))
417        pBIOSInfo->TVI2CDev = ViaCH7xxxDetect(pScrn, pVia->pI2CBus2, 0xEC);
418    else if (pVia->pI2CBus2 && xf86I2CProbeAddress(pVia->pI2CBus2, 0x40))
419        pBIOSInfo->TVI2CDev = ViaVT162xDetect(pScrn, pVia->pI2CBus2, 0x40);
420    else if (pVia->pI2CBus3 && xf86I2CProbeAddress(pVia->pI2CBus3, 0x40))
421        pBIOSInfo->TVI2CDev = ViaVT162xDetect(pScrn, pVia->pI2CBus3, 0x40);
422    else if (pVia->pI2CBus2 && xf86I2CProbeAddress(pVia->pI2CBus2, 0xEA))
423        pBIOSInfo->TVI2CDev = ViaCH7xxxDetect(pScrn, pVia->pI2CBus2, 0xEA);
424    else if (pVia->pI2CBus3 && xf86I2CProbeAddress(pVia->pI2CBus3, 0xEA))
425        pBIOSInfo->TVI2CDev = ViaCH7xxxDetect(pScrn, pVia->pI2CBus3, 0xEA);
426
427    if (!pBIOSInfo->TVI2CDev) {
428        xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
429                    "Did not detect a TV encoder.\n");
430        DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
431                            "Exiting via_tv_init.\n"));
432
433        return FALSE;
434    }
435
436    switch (pBIOSInfo->TVEncoder) {
437        case VIA_VT1621:
438        case VIA_VT1622:
439        case VIA_VT1623:
440        case VIA_VT1625:
441            ViaVT162xInit(pScrn);
442            break;
443        case VIA_CH7011:
444        case VIA_CH7019A:
445        case VIA_CH7019B:
446            ViaCH7xxxInit(pScrn);
447            break;
448        default:
449            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
450                        "Was not able to initialize a known TV encoder.\n");
451            DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
452                                "Exiting via_tv_init.\n"));
453            return FALSE;
454            break;
455    }
456
457    if (!pBIOSInfo->TVSave || !pBIOSInfo->TVRestore
458        || !pBIOSInfo->TVDACSense || !pBIOSInfo->TVModeValid
459        || !pBIOSInfo->TVModeI2C || !pBIOSInfo->TVModeCrtc
460        || !pBIOSInfo->TVPower || !pBIOSInfo->TVModes
461        || !pBIOSInfo->TVPrintRegs) {
462
463        xf86DestroyI2CDevRec(pBIOSInfo->TVI2CDev, TRUE);
464
465        pBIOSInfo->TVI2CDev = NULL;
466        pBIOSInfo->TVOutput = TVOUTPUT_NONE;
467        pBIOSInfo->TVEncoder = VIA_NONETV;
468        pBIOSInfo->TVI2CDev = NULL;
469        pBIOSInfo->TVSave = NULL;
470        pBIOSInfo->TVRestore = NULL;
471        pBIOSInfo->TVDACSense = NULL;
472        pBIOSInfo->TVModeValid = NULL;
473        pBIOSInfo->TVModeI2C = NULL;
474        pBIOSInfo->TVModeCrtc = NULL;
475        pBIOSInfo->TVPower = NULL;
476        pBIOSInfo->TVModes = NULL;
477        pBIOSInfo->TVPrintRegs = NULL;
478        pBIOSInfo->TVNumRegs = 0;
479
480        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
481                   "TV encoder was not properly initialized.\n");
482        DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
483                            "Exiting via_tv_init.\n"));
484        return FALSE;
485    }
486
487    output = xf86OutputCreate(pScrn, &via_tv_funcs, "TV-1");
488    pVia->FirstInit = TRUE;
489
490    if (output) {
491        /* Allow tv output on both crtcs, set bit 0 and 1. */
492        output->possible_crtcs = 0x3;
493    } else {
494        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
495                   "Failed to register TV-1.\n");
496    }
497
498    pBIOSInfo->tv = output;
499    /* Save now */
500    pBIOSInfo->TVSave(pScrn);
501
502#ifdef HAVE_DEBUG
503    if (VIAPTR(pScrn)->PrintTVRegs)
504        pBIOSInfo->TVPrintRegs(pScrn);
505#endif
506
507    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
508                        "Exiting via_tv_init.\n"));
509    return TRUE;
510}
511
512/*
513 * Enables or disables analog VGA output by controlling DAC
514 * (Digital to Analog Converter) output state.
515 */
516static void
517viaAnalogOutput(ScrnInfoPtr pScrn, Bool outputState)
518{
519    vgaHWPtr hwp = VGAHWPTR(pScrn);
520
521    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
522                        "Entered viaAnalogOutput.\n"));
523
524    /* This register controls analog VGA DAC output state. */
525    /* 3X5.47[2] - DACOFF Backdoor Register
526     *             0: DAC on
527     *             1: DAC off */
528    ViaCrtcMask(hwp, 0x47, outputState ? 0x00 : 0x04, 0x04);
529    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
530                "Analog VGA Output: %s\n",
531                outputState ? "On" : "Off");
532
533    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
534                        "Exiting viaAnalogOutput.\n"));
535}
536
537/*
538 * Specifies IGA1 or IGA2 for analog VGA DAC source.
539 */
540static void
541viaAnalogSource(ScrnInfoPtr pScrn, CARD8 displaySource)
542{
543    vgaHWPtr hwp = VGAHWPTR(pScrn);
544    CARD8 value = displaySource;
545
546    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
547                        "Entered viaAnalogSource.\n"));
548
549    ViaSeqMask(hwp, 0x16, value << 6, 0x40);
550    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
551                "Analog VGA Output Source: IGA%d\n",
552                (value & 0x01) + 1);
553
554    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
555                        "Exiting viaAnalogSource.\n"));
556}
557
558/*
559 * Intializes analog VGA related registers.
560 */
561static void
562viaAnalogInit(ScrnInfoPtr pScrn)
563{
564    vgaHWPtr hwp = VGAHWPTR(pScrn);
565    VIAPtr pVia = VIAPTR(pScrn);
566
567    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
568                        "Entered viaAnalogInit.\n"));
569
570    /* 3X5.37[7]   - DAC Power Save Control 1
571     *               0: Depend on Rx3X5.37[5:4] setting
572     *               1: DAC always goes into power save mode
573     * 3X5.37[6]   - DAC Power Down Control
574     *               0: Depend on Rx3X5.47[2] setting
575     *               1: DAC never goes to power down mode
576     * 3X5.37[5:4] - DAC Power Save Control 2
577     *               00: DAC never goes to power save mode
578     *               01: DAC goes to power save mode by line
579     *               10: DAC goes to power save mode by frame
580     *               11: DAC goes to power save mode by line and frame
581     * 3X5.37[3]   - DAC PEDESTAL Control
582     * 3X5.37[2:0] - DAC Factor
583     *               (Default: 100) */
584    ViaCrtcMask(hwp, 0x37, 0x04, 0xFF);
585
586    switch (pVia->Chipset) {
587    case VIA_CX700:
588    case VIA_VX800:
589    case VIA_VX855:
590    case VIA_VX900:
591        /* 3C5.5E[0] - CRT DACOFF Setting
592         *             1: CRT DACOFF controlled by 3C5.01[5] */
593        ViaSeqMask(hwp, 0x5E, 0x01, 0x01);
594        break;
595    default:
596        break;
597    }
598
599    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
600                        "Exiting viaAnalogInit.\n"));
601}
602
603static void
604via_analog_create_resources(xf86OutputPtr output)
605{
606}
607
608#ifdef RANDR_12_INTERFACE
609static Bool
610via_analog_set_property(xf86OutputPtr output, Atom property,
611                        RRPropertyValuePtr value)
612{
613    return TRUE;
614}
615
616static Bool
617via_analog_get_property(xf86OutputPtr output, Atom property)
618{
619    return FALSE;
620}
621#endif
622
623static void
624via_analog_dpms(xf86OutputPtr output, int mode)
625{
626    ScrnInfoPtr pScrn = output->scrn;
627
628    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
629                        "Entered via_analog_dpms.\n"));
630
631    switch (mode) {
632    case DPMSModeOn:
633        viaAnalogOutput(pScrn, TRUE);
634        break;
635    case DPMSModeStandby:
636    case DPMSModeSuspend:
637    case DPMSModeOff:
638        viaAnalogOutput(pScrn, FALSE);
639        break;
640    default:
641        break;
642    }
643
644    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
645                        "Exiting via_analog_dpms.\n"));
646}
647
648static void
649via_analog_save(xf86OutputPtr output)
650{
651}
652
653static void
654via_analog_restore(xf86OutputPtr output)
655{
656}
657
658static int
659via_analog_mode_valid(xf86OutputPtr output, DisplayModePtr pMode)
660{
661    ScrnInfoPtr pScrn = output->scrn;
662
663    if (!ViaModeDotClockTranslate(pScrn, pMode))
664        return MODE_NOCLOCK;
665    return MODE_OK;
666}
667
668static Bool
669via_analog_mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
670                      DisplayModePtr adjusted_mode)
671{
672    return TRUE;
673}
674
675static void
676via_analog_prepare(xf86OutputPtr output)
677{
678    via_analog_dpms(output, DPMSModeOff);
679}
680
681static void
682via_analog_commit(xf86OutputPtr output)
683{
684    via_analog_dpms(output, DPMSModeOn);
685}
686
687static void
688via_analog_mode_set(xf86OutputPtr output, DisplayModePtr mode,
689                    DisplayModePtr adjusted_mode)
690{
691    ScrnInfoPtr pScrn = output->scrn;
692    vgaHWPtr hwp = VGAHWPTR(pScrn);
693    drmmode_crtc_private_ptr iga = output->crtc->driver_private;
694
695    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
696                        "Entered via_analog_mode_set.\n"));
697
698    viaAnalogInit(pScrn);
699
700    if (output->crtc) {
701        viaAnalogSource(pScrn, iga->index ? 0x01 : 0x00);
702    }
703
704    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
705                        "Exiting via_analog_mode_set.\n"));
706}
707
708static xf86OutputStatus
709via_analog_detect(xf86OutputPtr output)
710{
711    xf86OutputStatus status = XF86OutputStatusDisconnected;
712    ScrnInfoPtr pScrn = output->scrn;
713    VIAPtr pVia = VIAPTR(pScrn);
714    xf86MonPtr mon;
715
716    /* Probe I2C Bus 1 to see if a VGA monitor is connected. */
717    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
718                "Probing for a VGA monitor on I2C Bus 1.\n");
719    mon = xf86OutputGetEDID(output, pVia->pI2CBus1);
720    if (mon && (!mon->features.input_type)) {
721        xf86OutputSetEDID(output, mon);
722        status = XF86OutputStatusConnected;
723        xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
724                    "Detected a VGA monitor on I2C Bus 1.\n");
725    } else {
726        xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
727                    "Did not detect a VGA monitor on I2C Bus 1.\n");
728
729        /* Probe I2C Bus 2 to see if a VGA monitor is connected. */
730        xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
731                    "Probing for a VGA monitor on I2C Bus 2.\n");
732        mon = xf86OutputGetEDID(output, pVia->pI2CBus2);
733        if (mon && (!mon->features.input_type)) {
734            xf86OutputSetEDID(output, mon);
735            status = XF86OutputStatusConnected;
736            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
737                        "Detected a VGA monitor on I2C Bus 2.\n");
738        } else {
739            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
740                        "Did not detect a VGA monitor on I2C Bus 2.\n");
741
742            /* Perform manual detection of a VGA monitor since */
743            /* it was not detected via I2C buses. */
744            xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
745                        "Now perform manual detection of a VGA "
746                        "monitor.\n");
747            vgaHWPtr hwp = VGAHWPTR(pScrn);
748            CARD8 SR01 = hwp->readSeq(hwp, 0x01);
749            CARD8 SR40 = hwp->readSeq(hwp, 0x40);
750            CARD8 CR36 = hwp->readCrtc(hwp, 0x36);
751
752            /* We have to power on the display to detect it */
753            ViaSeqMask(hwp, 0x01, 0x00, 0x20);
754            ViaCrtcMask(hwp, 0x36, 0x00, 0xF0);
755
756            /* Wait for vblank */
757            usleep(16);
758
759            /* Detect the load on pins */
760            ViaSeqMask(hwp, 0x40, 0x80, 0x80);
761
762            if ((VIA_CX700 == pVia->Chipset) ||
763                (VIA_VX800 == pVia->Chipset) ||
764                (VIA_VX855 == pVia->Chipset) ||
765                (VIA_VX900 == pVia->Chipset))
766                ViaSeqMask(hwp, 0x40, 0x00, 0x80);
767
768            if (ViaVgahwIn(hwp, 0x3C2) & 0x20) {
769                status = XF86OutputStatusConnected;
770                xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
771                            "Detected a VGA monitor using manual "
772                            "detection method.\n");
773            }
774
775            if ((VIA_CX700 == pVia->Chipset) ||
776                (VIA_VX800 == pVia->Chipset) ||
777                (VIA_VX855 == pVia->Chipset) ||
778                (VIA_VX900 == pVia->Chipset))
779                ViaSeqMask(hwp, 0x40, 0x00, 0x80);
780
781            /* Restore previous state */
782            hwp->writeSeq(hwp, 0x40, SR40);
783            hwp->writeSeq(hwp, 0x01, SR01);
784            hwp->writeCrtc(hwp, 0x36, CR36);
785        }
786    }
787
788    return status;
789}
790
791static void
792via_analog_destroy(xf86OutputPtr output)
793{
794}
795
796static const xf86OutputFuncsRec via_analog_funcs = {
797    .create_resources   = via_analog_create_resources,
798#ifdef RANDR_12_INTERFACE
799    .set_property       = via_analog_set_property,
800#endif
801#ifdef RANDR_13_INTERFACE
802    .get_property       = via_analog_get_property,
803#endif
804    .dpms               = via_analog_dpms,
805    .save               = via_analog_save,
806    .restore            = via_analog_restore,
807    .mode_valid         = via_analog_mode_valid,
808    .mode_fixup         = via_analog_mode_fixup,
809    .prepare            = via_analog_prepare,
810    .commit             = via_analog_commit,
811    .mode_set           = via_analog_mode_set,
812    .detect             = via_analog_detect,
813    .get_modes          = xf86OutputGetEDIDModes,
814    .destroy            = via_analog_destroy,
815};
816
817void
818via_analog_init(ScrnInfoPtr pScrn)
819{
820    VIAPtr pVia = VIAPTR(pScrn);
821    VIABIOSInfoPtr pBIOSInfo = pVia->pBIOSInfo;
822    xf86OutputPtr output = NULL;
823
824    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
825                        "Entered via_analog_init.\n"));
826
827    if (!pVia->pI2CBus1 || !pVia->pI2CBus2) {
828        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
829                    "I2C Bus 1 or I2C Bus 2 does not exist.\n");
830        DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
831                            "Exiting via_analog_init.\n"));
832        return;
833    }
834
835    output = xf86OutputCreate(pScrn, &via_analog_funcs, "VGA-1");
836
837    output->possible_crtcs = 0x3;
838    output->possible_clones = 0;
839    output->interlaceAllowed = TRUE;
840    output->doubleScanAllowed = FALSE;
841    pBIOSInfo->analog = output;
842
843    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
844                        "Exiting via_analog_init.\n"));
845}
846
847static void
848via_dvi_create_resources(xf86OutputPtr output)
849{
850}
851
852#ifdef RANDR_12_INTERFACE
853static Bool
854via_dvi_set_property(xf86OutputPtr output, Atom property,
855                     RRPropertyValuePtr value)
856{
857    return TRUE;
858}
859
860static Bool
861via_dvi_get_property(xf86OutputPtr output, Atom property)
862{
863    return FALSE;
864}
865#endif
866
867static void
868via_dvi_dpms(xf86OutputPtr output, int mode)
869{
870    ScrnInfoPtr pScrn = output->scrn;
871
872    switch (mode) {
873    case DPMSModeOn:
874        via_vt1632_power(output, TRUE);
875        break;
876    case DPMSModeStandby:
877    case DPMSModeSuspend:
878    case DPMSModeOff:
879        via_vt1632_power(output, FALSE);
880        break;
881    default:
882        break;
883    }
884}
885
886static void
887via_dvi_save(xf86OutputPtr output)
888{
889    via_vt1632_save(output);
890}
891
892static void
893via_dvi_restore(xf86OutputPtr output)
894{
895    via_vt1632_restore(output);
896}
897
898static int
899via_dvi_mode_valid(xf86OutputPtr output, DisplayModePtr pMode)
900{
901    return via_vt1632_mode_valid(output, pMode);
902}
903
904static Bool
905via_dvi_mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
906                   DisplayModePtr adjusted_mode)
907{
908    return TRUE;
909}
910
911static void
912via_dvi_prepare(xf86OutputPtr output)
913{
914}
915
916static void
917via_dvi_commit(xf86OutputPtr output)
918{
919}
920
921static void
922via_dvi_mode_set(xf86OutputPtr output, DisplayModePtr mode,
923                 DisplayModePtr adjusted_mode)
924{
925    ScrnInfoPtr pScrn = output->scrn;
926    vgaHWPtr hwp = VGAHWPTR(pScrn);
927
928    via_vt1632_mode_set(output, mode, adjusted_mode);
929}
930
931static xf86OutputStatus
932via_dvi_detect(xf86OutputPtr output)
933{
934    xf86OutputStatus status = XF86OutputStatusDisconnected;
935    ScrnInfoPtr pScrn = output->scrn;
936    VIAPtr pVia = VIAPTR(pScrn);
937    ViaVT1632Ptr Private = output->driver_private;
938    xf86MonPtr mon;
939
940    /* Check for the DVI presence via VT1632A first before accessing
941     * I2C bus. */
942    status = via_vt1632_detect(output);
943    if (status == XF86OutputStatusConnected) {
944
945        /* Since DVI presence was established, access the I2C bus
946         * assigned to DVI. */
947        mon = xf86OutputGetEDID(output, Private->VT1632I2CDev->pI2CBus);
948
949        /* Is the interface type digital? */
950        if (mon && DIGITAL(mon->features.input_type)) {
951            xf86OutputSetEDID(output, mon);
952        } else {
953            status = XF86OutputStatusDisconnected;
954        }
955    }
956
957    return status;
958}
959
960static void
961via_dvi_destroy(xf86OutputPtr output)
962{
963}
964
965static const xf86OutputFuncsRec via_dvi_funcs = {
966    .create_resources   = via_dvi_create_resources,
967#ifdef RANDR_12_INTERFACE
968    .set_property       = via_dvi_set_property,
969#endif
970#ifdef RANDR_13_INTERFACE
971    .get_property       = via_dvi_get_property,
972#endif
973    .dpms               = via_dvi_dpms,
974    .save               = via_dvi_save,
975    .restore            = via_dvi_restore,
976    .mode_valid         = via_dvi_mode_valid,
977    .mode_fixup         = via_dvi_mode_fixup,
978    .prepare            = via_dvi_prepare,
979    .commit             = via_dvi_commit,
980    .mode_set           = via_dvi_mode_set,
981    .detect             = via_dvi_detect,
982    .get_modes          = xf86OutputGetEDIDModes,
983    .destroy            = via_dvi_destroy,
984};
985
986void
987via_dvi_init(ScrnInfoPtr pScrn)
988{
989    VIAPtr pVia = VIAPTR(pScrn);
990    xf86OutputPtr output = NULL;
991    ViaVT1632Ptr private_data = NULL;
992    I2CBusPtr pBus = NULL;
993    I2CDevPtr pDev = NULL;
994    I2CSlaveAddr addr = 0x10;
995
996    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
997                        "Entered via_dvi_init.\n"));
998
999    if (!pVia->pI2CBus2 || !pVia->pI2CBus3) {
1000        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1001                    "I2C Bus 2 or I2C Bus 3 does not exist.\n");
1002        DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1003                    "Exiting via_dvi_init.\n"));
1004        return;
1005    }
1006
1007    if (xf86I2CProbeAddress(pVia->pI2CBus3, addr)) {
1008        DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1009                            "Will probe I2C Bus 3 for a possible "
1010                            "external TMDS transmitter.\n"));
1011        pBus = pVia->pI2CBus3;
1012    } else if (xf86I2CProbeAddress(pVia->pI2CBus2, addr)) {
1013        DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1014                            "Will probe I2C Bus 2 for a possible "
1015                            "external TMDS transmitter.\n"));
1016        pBus = pVia->pI2CBus2;
1017    } else {
1018        xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1019                    "Did not find a possible external TMDS transmitter "
1020                    "on I2C Bus 2 or I2C Bus 3.\n");
1021        DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1022                            "Exiting via_dvi_init.\n"));
1023        return;
1024    }
1025
1026    pDev = xf86CreateI2CDevRec();
1027    if (!pDev) {
1028        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1029                    "Failed to create an I2C bus structure.\n");
1030        DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1031                            "Exiting via_dvi_init.\n"));
1032        return;
1033    }
1034
1035    pDev->DevName = "VT1632A";
1036    pDev->SlaveAddr = addr;
1037    pDev->pI2CBus = pBus;
1038    if (!xf86I2CDevInit(pDev)) {
1039        xf86DestroyI2CDevRec(pDev, TRUE);
1040        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1041                    "Failed to initialize a device on I2C bus.\n");
1042        DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1043                            "Exiting via_dvi_init.\n"));
1044        return;
1045    }
1046
1047    if (!via_vt1632_probe(pScrn, pDev)) {
1048        xf86DestroyI2CDevRec(pDev, TRUE);
1049        DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1050                            "Exiting via_dvi_init.\n"));
1051        return;
1052    }
1053
1054    private_data = via_vt1632_init(pScrn, pDev);
1055    if (!private_data) {
1056        xf86DestroyI2CDevRec(pDev, TRUE);
1057        DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1058                            "Exiting via_dvi_init.\n"));
1059        return;
1060    }
1061
1062    output = xf86OutputCreate(pScrn, &via_dvi_funcs, "DVI-1");
1063    if (output) {
1064        output->driver_private = private_data;
1065        output->possible_crtcs = 0x2;
1066        output->possible_clones = 0;
1067        output->interlaceAllowed = FALSE;
1068        output->doubleScanAllowed = FALSE;
1069    }
1070
1071    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1072                        "Exiting via_dvi_init.\n"));
1073}
1074
1075/*
1076 * Reads off the VIA Technologies IGP pin strapping for
1077 * display detection purposes.
1078 */
1079void
1080viaProbePinStrapping(ScrnInfoPtr pScrn)
1081{
1082    vgaHWPtr hwp = VGAHWPTR(pScrn);
1083    VIAPtr pVia = VIAPTR(pScrn);
1084    CARD8 sr12, sr13, sr5a;
1085
1086    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1087                        "Entered viaProbePinStrapping.\n"));
1088
1089    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1090                "Probing VIA Technologies IGP pin strapping . . .\n");
1091
1092    if ((pVia->Chipset == VIA_CX700)
1093        || (pVia->Chipset == VIA_VX800)
1094        || (pVia->Chipset == VIA_VX855)
1095        || (pVia->Chipset == VIA_VX900)) {
1096
1097        sr5a = hwp->readSeq(hwp, 0x5A);
1098        DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1099                            "SR5A: 0x%02X\n", sr5a));
1100        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1101                    "Setting 3C5.5A[0] to 0.\n");
1102        ViaSeqMask(hwp, 0x5A, sr5a & 0xFE, 0x01);
1103    }
1104
1105    sr12 = hwp->readSeq(hwp, 0x12);
1106    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1107                        "SR12: 0x%02X\n", sr12));
1108    sr13 = hwp->readSeq(hwp, 0x13);
1109    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1110                        "SR13: 0x%02X\n", sr13));
1111
1112    switch (pVia->Chipset) {
1113    case VIA_CLE266:
1114    case VIA_KM400:
1115
1116        /* 3C5.12[4] - FPD17 pin strapping
1117         *             0: TMDS transmitter (DVI) / capture device
1118         *             1: Flat panel */
1119        if (sr12 & 0x10) {
1120            xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1121                        "A flat panel is connected to "
1122                        "flat panel interface.\n");
1123
1124            /* 3C5.12[3:0] - FPD16-13 pin strapping
1125             *               0 ~ 15: Flat panel code defined
1126             *                       by VIA Technologies */
1127            xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1128                        "Detected Flat Panel Type from "
1129                        "Strapping Pins: %d\n", sr12 & 0x0F);
1130        } else {
1131            xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1132                        "A TMDS transmitter (DVI) / capture device is "
1133                        "connected to flat panel interface.\n");
1134        }
1135
1136        /* 3C5.12[5] - FPD18 pin strapping
1137         *             0: TMDS transmitter (DVI)
1138         *             1: TV encoder */
1139        if (sr12 & 0x20) {
1140            xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1141                        "A TMDS transmitter (DVI) is connected to "
1142                        "DVI port.\n");
1143        } else {
1144            xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1145                        "A TV encoder is connected to "
1146                        "DVI port.\n");
1147
1148            /* 3C5.13[4:3] - FPD21-20 pin strapping
1149             *               00: PAL
1150             *               01: NTSC
1151             *               10: PAL-N
1152             *               11: PAL-NC */
1153            if (sr13 & 0x04) {
1154                xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1155                            "NTSC for the TV encoder.\n");
1156            } else {
1157                if (!(sr13 & 0x08)) {
1158                    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1159                                "PAL for the TV encoder.\n");
1160                } else {
1161                    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1162                                "PAL%s for the TV encoder.\n",
1163                                sr13 & 0x04 ? "-NC" : "-N");
1164                }
1165            }
1166
1167            /* 3C5.12[6] - FPD19 pin strapping
1168             *             0: 525 lines (NTSC)
1169             *             1: 625 lines (PAL) */
1170            xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1171                        "%s lines for the TV encoder.\n",
1172                        sr12 & 0x40 ? "625" : "525");
1173        }
1174
1175        break;
1176
1177    case VIA_K8M800:
1178    case VIA_PM800:
1179    case VIA_P4M800PRO:
1180
1181        /* 3C5.12[6] - DVP0D6 pin strapping
1182         *             0: Disable DVP0 (Digital Video Port 0) for
1183         *                DVI or TV out use
1184         *             1: Enable DVP0 (Digital Video Port 0) for
1185         *                DVI or TV out use */
1186        if (sr12 & 0x40) {
1187
1188            /* 3C5.12[5] - DVP0D5 pin strapping
1189             *             0: TMDS transmitter (DVI)
1190             *             1: TV encoder */
1191            if (sr12 & 0x20) {
1192                xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1193                            "A TV encoder is detected on "
1194                            "DVP0 (Digital Video Port 0).\n");
1195            } else {
1196                xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1197                            "A TMDS transmitter (DVI) is detected on "
1198                            "DVP0 (Digital Video Port 0).\n");
1199            }
1200        }
1201
1202
1203        /* 3C5.13[3] - DVP0D8 pin strapping
1204         *             0: AGP pins are used for AGP
1205         *             1: AGP pins are used by FPDP
1206         *             (Flat Panel Display Port) */
1207        if (sr13 & 0x08) {
1208
1209            /* 3C5.12[4] - DVP0D4 pin strapping
1210             *             0: Dual 12-bit FPDP (Flat Panel Display Port)
1211             *             1: 24-bit FPDP  (Flat Panel Display Port) */
1212            if (sr12 & 0x10) {
1213                xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1214                            "24-bit FPDP (Flat Panel Display Port) "
1215                            "detected.\n");
1216
1217                /* 3C5.12[3:0] - DVP0D3-0 pin strapping
1218                 *               0 ~ 15: Flat panel code defined
1219                 *                       by VIA Technologies */
1220                xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1221                            "Detected Flat Panel Type from "
1222                            "Strapping Pins: %d\n", sr12 & 0x0F);
1223            } else {
1224
1225                /* 3C5.12[6] - DVP0D6 pin strapping
1226                 *             0: Disable DVP0 (Digital Video Port 0) for
1227                 *                DVI or TV out use
1228                 *             1: Enable DVP0 (Digital Video Port 0) for
1229                 *                DVI or TV out use
1230                 * 3C5.12[5] - DVP0D5 pin strapping
1231                 *             0: TMDS transmitter (DVI)
1232                 *             1: TV encoder */
1233                if ((!(sr12 & 0x40)) && (!(sr12 & 0x20))) {
1234                    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1235                                "A TV encoder is connected to "
1236                                "FPDP (Flat Panel Display Port).\n");
1237                } else {
1238                    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1239                                "Dual 12-bit FPDP (Flat Panel Display Port) "
1240                                "detected.\n");
1241
1242                    /* 3C5.12[3:0] - DVP0D3-0 pin strapping
1243                     *               0 ~ 15: Flat panel code defined
1244                     *                       by VIA Technologies */
1245                    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1246                                "Detected Flat Panel Type from "
1247                                "Strapping Pins: %d\n", sr12 & 0x0F);
1248                }
1249            }
1250        }
1251
1252        break;
1253
1254    default:
1255        break;
1256    }
1257
1258    if ((pVia->Chipset == VIA_CX700)
1259        || (pVia->Chipset == VIA_VX800)
1260        || (pVia->Chipset == VIA_VX855)
1261        || (pVia->Chipset == VIA_VX900)) {
1262
1263        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1264                    "Setting 3C5.5A[0] to 1.\n");
1265        ViaSeqMask(hwp, 0x5A, sr5a | 0x01, 0x01);
1266
1267        sr12 = hwp->readSeq(hwp, 0x12);
1268        DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1269                            "SR12: 0x%02X\n", sr12));
1270        sr13 = hwp->readSeq(hwp, 0x13);
1271        DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1272                            "SR13: 0x%02X\n", sr13));
1273
1274        /* 3C5.13[7:6] - Integrated LVDS / DVI Mode Select
1275         *               (DVP1D15-14 pin strapping)
1276         *               00: LVDS1 + LVDS2
1277         *               01: DVI + LVDS2
1278         *               10: Dual LVDS Channel (High Resolution Panel)
1279         *               11: One DVI only (decrease the clock jitter) */
1280        switch (sr13 & 0xC0) {
1281        case 0x00:
1282            xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1283                        "LVDS1 + LVDS2 detected.\n");
1284            break;
1285        case 0x40:
1286            xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1287                        "Single Link DVI + LVDS2 detected.\n");
1288            break;
1289        case 0x80:
1290            xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1291                        "Dual Channel LVDS detected.\n");
1292            break;
1293        case 0xC0:
1294            xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1295                        "Single Link DVI detected.\n");
1296            break;
1297        default:
1298            break;
1299        }
1300
1301        hwp->writeSeq(hwp, 0x5A, sr5a);
1302
1303    }
1304
1305    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1306                        "Exiting viaProbePinStrapping.\n"));
1307}
1308
1309void
1310viaOutputDetect(ScrnInfoPtr pScrn)
1311{
1312    VIAPtr pVia = VIAPTR(pScrn);
1313    VIABIOSInfoPtr pBIOSInfo = pVia->pBIOSInfo;
1314
1315    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1316                        "Entered viaOutputDetect.\n"));
1317
1318    pBIOSInfo->analog = NULL;
1319
1320    /* Read off the VIA Technologies IGP pin strapping for
1321       display detection purposes. */
1322    viaProbePinStrapping(pScrn);
1323
1324    /* LVDS */
1325    via_lvds_init(pScrn);
1326
1327    /* VGA */
1328    via_analog_init(pScrn);
1329
1330    /* TV */
1331    via_tv_init(pScrn);
1332
1333    /* External TMDS Transmitter (DVI) */
1334    via_dvi_init(pScrn);
1335
1336    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1337                        "Exiting viaOutputDetect.\n"));
1338}
1339
1340#ifdef HAVE_DEBUG
1341/*
1342 * Returns:
1343 *   Bit[7] 2nd Path
1344 *   Bit[6] 1/0 MHS Enable/Disable
1345 *   Bit[5] 0 = Bypass Callback, 1 = Enable Callback
1346 *   Bit[4] 0 = Hot-Key Sequence Control (OEM Specific)
1347 *   Bit[3] LCD
1348 *   Bit[2] TV
1349 *   Bit[1] CRT
1350 *   Bit[0] DVI
1351 */
1352static CARD8
1353VIAGetActiveDisplay(ScrnInfoPtr pScrn)
1354{
1355    vgaHWPtr hwp = VGAHWPTR(pScrn);
1356    CARD8 tmp;
1357
1358    tmp = (hwp->readCrtc(hwp, 0x3E) >> 4);
1359    tmp |= ((hwp->readCrtc(hwp, 0x3B) & 0x18) << 3);
1360
1361    return tmp;
1362}
1363#endif /* HAVE_DEBUG */
1364
1365/*
1366 *
1367 */
1368CARD32
1369ViaGetMemoryBandwidth(ScrnInfoPtr pScrn)
1370{
1371    VIAPtr pVia = VIAPTR(pScrn);
1372
1373    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1374                     "ViaGetMemoryBandwidth. Memory type: %d\n",
1375                     pVia->MemClk));
1376
1377    switch (pVia->MemClk) {
1378        case VIA_MEM_SDR66:
1379        case VIA_MEM_SDR100:
1380        case VIA_MEM_SDR133:
1381            return VIA_BW_MIN;
1382        case VIA_MEM_DDR200:
1383            return VIA_BW_DDR200;
1384        case VIA_MEM_DDR266:
1385        case VIA_MEM_DDR333:
1386        case VIA_MEM_DDR400:
1387            return VIA_BW_DDR400;
1388        case VIA_MEM_DDR533:
1389        case VIA_MEM_DDR667:
1390            return VIA_BW_DDR667;
1391        case VIA_MEM_DDR800:
1392        case VIA_MEM_DDR1066:
1393            return VIA_BW_DDR1066;
1394        default:
1395            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1396                       "ViaBandwidthAllowed: Unknown memory type: %d\n",
1397                       pVia->MemClk);
1398            return VIA_BW_MIN;
1399    }
1400}
1401
1402/*
1403 *
1404 * Some very common abstractions.
1405 *
1406 */
1407
1408/*
1409 * Standard vga call really.
1410 * Needs to be called to reset the dotclock (after SR40:2/1 reset)
1411 */
1412void
1413ViaSetUseExternalClock(vgaHWPtr hwp)
1414{
1415    CARD8 data;
1416
1417    DEBUG(xf86DrvMsg(hwp->pScrn->scrnIndex, X_INFO,
1418                     "ViaSetUseExternalClock\n"));
1419
1420    data = hwp->readMiscOut(hwp);
1421    hwp->writeMiscOut(hwp, data | 0x0C);
1422}
1423
1424/*
1425 *
1426 */
1427static void
1428ViaSetDotclock(ScrnInfoPtr pScrn, CARD32 clock, int base, int probase)
1429{
1430    vgaHWPtr hwp = VGAHWPTR(pScrn);
1431    VIAPtr pVia = VIAPTR(pScrn);
1432
1433    DEBUG(xf86DrvMsg(hwp->pScrn->scrnIndex, X_INFO,
1434                     "ViaSetDotclock to 0x%06x\n", (unsigned)clock));
1435
1436    if ((pVia->Chipset == VIA_CLE266) || (pVia->Chipset == VIA_KM400)) {
1437        hwp->writeSeq(hwp, base, clock >> 8);
1438        hwp->writeSeq(hwp, base+1, clock & 0xFF);
1439    } else {  /* unichrome pro */
1440        union pllparams pll;
1441        int dtz, dr, dn, dm;
1442        pll.packed = clock;
1443        dtz = pll.params.dtz;
1444        dr  = pll.params.dr;
1445        dn  = pll.params.dn;
1446        dm  = pll.params.dm;
1447
1448        /* The VX855 and VX900 do not modify dm/dn, but earlier chipsets do. */
1449        if ((pVia->Chipset != VIA_VX855) && (pVia->Chipset != VIA_VX900)) {
1450            dm -= 2;
1451            dn -= 2;
1452        }
1453
1454        hwp->writeSeq(hwp, probase, dm & 0xff);
1455        hwp->writeSeq(hwp, probase+1,
1456                      ((dm >> 8) & 0x03) | (dr << 2) | ((dtz & 1) << 7));
1457        hwp->writeSeq(hwp, probase+2, (dn & 0x7f) | ((dtz & 2) << 6));
1458    }
1459}
1460
1461/*
1462 *
1463 */
1464void
1465ViaSetPrimaryDotclock(ScrnInfoPtr pScrn, CARD32 clock)
1466{
1467    vgaHWPtr hwp = VGAHWPTR(pScrn);
1468
1469    ViaSetDotclock(pScrn, clock, 0x46, 0x44);
1470
1471    ViaSeqMask(hwp, 0x40, 0x02, 0x02);
1472    ViaSeqMask(hwp, 0x40, 0x00, 0x02);
1473}
1474
1475/*
1476 *
1477 */
1478void
1479ViaSetSecondaryDotclock(ScrnInfoPtr pScrn, CARD32 clock)
1480{
1481    vgaHWPtr hwp = VGAHWPTR(pScrn);
1482
1483    ViaSetDotclock(pScrn, clock, 0x44, 0x4A);
1484
1485    ViaSeqMask(hwp, 0x40, 0x04, 0x04);
1486    ViaSeqMask(hwp, 0x40, 0x00, 0x04);
1487}
1488
1489/*
1490 *
1491 */
1492static void
1493ViaSetECKDotclock(ScrnInfoPtr pScrn, CARD32 clock)
1494{
1495    /* Does the non-pro chip have an ECK clock ? */
1496    ViaSetDotclock(pScrn, clock, 0, 0x47);
1497}
1498
1499static CARD32
1500ViaComputeDotClock(unsigned clock)
1501{
1502    double fout, fref, err, minErr;
1503    CARD32 dr, dn, dm, maxdm, maxdn;
1504    CARD32 factual, best;
1505
1506    fref = 14.31818e6;
1507    fout = (double)clock * 1.e3;
1508
1509    factual = ~0;
1510    maxdm = 127;
1511    maxdn = 7;
1512    minErr = 1e10;
1513    best = 0;
1514
1515    for (dr = 0; dr < 4; ++dr) {
1516        for (dn = (dr == 0) ? 2 : 1; dn <= maxdn; ++dn) {
1517            for (dm = 1; dm <= maxdm; ++dm) {
1518                factual = fref * dm;
1519                factual /= (dn << dr);
1520                err = fabs((double)factual / fout - 1.);
1521                if (err < minErr) {
1522                    minErr = err;
1523                    best = (dm & 127) | ((dn & 31) << 8) | (dr << 14);
1524                }
1525            }
1526        }
1527    }
1528    return best;
1529}
1530
1531static CARD32
1532ViaComputeProDotClock(unsigned clock)
1533{
1534    double fvco, fout, fref, err, minErr;
1535    CARD32 dr = 0, dn, dm, maxdm, maxdn;
1536    CARD32 factual;
1537    union pllparams bestClock;
1538
1539    fref = 14.318e6;
1540    fout = (double)clock * 1.e3;
1541
1542    factual = ~0;
1543    maxdm = factual / 14318000U;
1544    minErr = 1.e10;
1545    bestClock.packed = 0U;
1546
1547    do {
1548        fvco = fout * (1 << dr);
1549    } while (fvco < 300.e6 && dr++ < 8);
1550
1551    if (dr == 8) {
1552        return 0;
1553    }
1554
1555    if (clock < 30000)
1556        maxdn = 8;
1557    else if (clock < 45000)
1558        maxdn = 7;
1559    else if (clock < 170000)
1560        maxdn = 6;
1561    else
1562        maxdn = 5;
1563
1564    for (dn = 2; dn < maxdn; ++dn) {
1565        for (dm = 2; dm < maxdm; ++dm) {
1566            factual = 14318000U * dm;
1567            factual /= dn << dr;
1568            if ((err = fabs((double)factual / fout - 1.)) < 0.005) {
1569                if (err < minErr) {
1570                    minErr = err;
1571                    bestClock.params.dtz = 1;
1572                    bestClock.params.dr = dr;
1573                    bestClock.params.dn = dn;
1574                    bestClock.params.dm = dm;
1575                }
1576            }
1577        }
1578    }
1579
1580    return bestClock.packed;
1581}
1582
1583/*
1584 *
1585 */
1586CARD32
1587ViaModeDotClockTranslate(ScrnInfoPtr pScrn, DisplayModePtr mode)
1588{
1589    VIAPtr pVia = VIAPTR(pScrn);
1590    int i;
1591
1592    if ((pVia->Chipset == VIA_CLE266) || (pVia->Chipset == VIA_KM400)) {
1593        CARD32 best1 = 0, best2;
1594
1595        for (i = 0; ViaDotClocks[i].DotClock; i++)
1596            if (ViaDotClocks[i].DotClock == mode->Clock) {
1597                best1 = ViaDotClocks[i].UniChrome;
1598                break;
1599            }
1600
1601        best2 = ViaComputeDotClock(mode->Clock);
1602
1603        DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1604                         "ViaComputeDotClock %d : %04x : %04x\n",
1605                         mode->Clock, (unsigned int)best1,
1606                         (unsigned int)best2));
1607
1608        return best2;
1609    } else {
1610        for (i = 0; ViaDotClocks[i].DotClock; i++)
1611            if (ViaDotClocks[i].DotClock == mode->Clock)
1612                return ViaDotClocks[i].UniChromePro.packed;
1613        return ViaComputeProDotClock(mode->Clock);
1614    }
1615
1616    return 0;
1617}
1618
1619void
1620viaTMDSPower(ScrnInfoPtr pScrn, Bool On)
1621{
1622
1623    vgaHWPtr hwp = VGAHWPTR(pScrn);
1624
1625    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1626                        "Entered viaTMDSPower.\n"));
1627
1628    if (On) {
1629        /* Power on TMDS */
1630        ViaCrtcMask(hwp, 0xD2, 0x00, 0x08);
1631    } else {
1632        /* Power off TMDS */
1633        ViaCrtcMask(hwp, 0xD2, 0x08, 0x08);
1634    }
1635
1636    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1637                "Integrated TMDS (DVI) Power: %s\n",
1638                On ? "On" : "Off");
1639
1640    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1641                        "Exiting viaTMDSPower.\n"));
1642}
1643