1/*
2 * Copyright 2016 Kevin Brace
3 * Copyright 2005-2016 The OpenChrome Project
4 *                     [https://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
49/*
50 * Sets IGA1 or IGA2 as the display output source for DIP0
51 * (Digital Interface Port 0) interface for CLE266 only.
52 */
53void
54viaDIP0SetDisplaySource(ScrnInfoPtr pScrn, CARD8 displaySource)
55{
56    vgaHWPtr hwp = VGAHWPTR(pScrn);
57    CARD8 temp = displaySource;
58
59    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
60                        "Entered viaDIP0SetDisplaySource.\n"));
61
62    /* Set DIP0 display output source. */
63    /* 3X5.6C[7] - DIP0 (Digital Interface Port 0) Data Source Selection
64     *             0: Primary Display (IGA1)
65     *             1: Secondary Display (IGA2) */
66    ViaCrtcMask(hwp, 0x6C, temp << 7, 0x80);
67    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
68                "DIP0 Display Output Source: IGA%d\n",
69                (temp & 0x01) + 1);
70
71    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
72                        "Exiting viaDIP0SetDisplaySource.\n"));
73}
74
75/*
76 * Sets DIP0 (Digital Interface Port 0) I/O pad state.
77 * This function is for CLE266 chipset only.
78 */
79void
80viaDIP0EnableIOPads(ScrnInfoPtr pScrn, CARD8 ioPadState)
81{
82    vgaHWPtr hwp = VGAHWPTR(pScrn);
83
84    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
85                        "Entered viaDIP0EnableIOPads.\n"));
86
87    /* Set DIP0 I/O pad state. */
88    /* 3C5.1E[7:6] - DIP0 Power Control
89     *               0x: Pad always off
90     *               10: Depend on the other control signal
91     *               11: Pad on/off according to the
92     *                   Power Management Status (PMS) */
93    ViaSeqMask(hwp, 0x1E, ioPadState << 6, 0xC0);
94    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
95                "DIP0 I/O Pad State: %s\n",
96                (ioPadState & 0x02) ?
97                    (ioPadState & 0x01) ? "Automatic On / Off" : "Conditional"
98                : "Off");
99
100    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
101                        "Exiting viaDIP0EnableIOPads.\n"));
102}
103
104/*
105 * Sets DIP0 (Digital Interface Port 0) clock I/O pad drive strength
106 * for CLE266 chipset only.
107 */
108void
109viaDIP0SetClockDriveStrength(ScrnInfoPtr pScrn, CARD8 clockDriveStrength)
110{
111    vgaHWPtr hwp = VGAHWPTR(pScrn);
112
113    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
114                        "Entered viaDIP0SetClockDriveStrength.\n"));
115
116    /* 3C5.1E[2] - DIP0 Clock Drive Strength Bit [0] */
117    ViaSeqMask(hwp, 0x1E, clockDriveStrength << 2, 0x04);
118
119    /* 3C5.2A[4] - DIP0 Clock Drive Strength Bit [1] */
120    ViaSeqMask(hwp, 0x2A, clockDriveStrength << 3, 0x10);
121
122    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
123                "DIP0 Clock I/O Pad Drive Strength: %u\n",
124                clockDriveStrength & 0x03);
125
126    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
127                        "Exiting viaDIP0SetClockDriveStrength.\n"));
128}
129
130/*
131 * Sets DIP0 (Digital Interface Port 0) data I/O pads drive strength
132 * for CLE266 chipset only.
133 */
134void
135viaDIP0SetDataDriveStrength(ScrnInfoPtr pScrn, CARD8 dataDriveStrength)
136{
137    vgaHWPtr hwp = VGAHWPTR(pScrn);
138
139    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
140                        "Entered viaDIP0SetDataDriveStrength.\n"));
141
142    /* 3C5.1B[1] - DIP0 Data Drive Strength Bit [0] */
143    ViaSeqMask(hwp, 0x1B, dataDriveStrength << 1, 0x02);
144
145    /* 3C5.2A[5] - DIP0 Data Drive Strength Bit [1] */
146    ViaSeqMask(hwp, 0x2A, dataDriveStrength << 4, 0x20);
147
148    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
149                "DIP0 Data I/O Pads Drive Strength: %u\n",
150                dataDriveStrength);
151
152    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
153                        "Exiting viaDIP0SetDataDriveStrength.\n"));
154}
155
156/*
157 * Sets IGA1 or IGA2 as the display output source for DVP0
158 * (Digital Video Port) interface.
159 */
160void
161viaDVP0SetDisplaySource(ScrnInfoPtr pScrn, CARD8 displaySource)
162{
163    vgaHWPtr hwp = VGAHWPTR(pScrn);
164    CARD8 temp = displaySource;
165
166    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
167                        "Entered viaDVP0SetDisplaySource.\n"));
168
169    /* Set DVP0 display output source. */
170    /* 3X5.96[4] - DVP0 Data Source Selection
171     *             0: Primary Display
172     *             1: Secondary Display */
173    ViaCrtcMask(hwp, 0x96, temp << 4, 0x10);
174    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
175                "DVP0 Display Output Source: IGA%d\n",
176                (temp & 0x01) + 1);
177
178    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
179                        "Exiting viaDVP0SetDisplaySource.\n"));
180}
181
182/*
183 * Sets DVP0 (Digital Video Port 0) I/O pad state.
184 */
185void
186viaDVP0EnableIOPads(ScrnInfoPtr pScrn, CARD8 ioPadState)
187{
188    vgaHWPtr hwp = VGAHWPTR(pScrn);
189
190    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
191                        "Entered viaDVP0EnableIOPads.\n"));
192
193    /* Set DVP0 I/O pad state. */
194    /* 3C5.1E[7:6] - DVP0 Power Control
195     *               0x: Pad always off
196     *               10: Depend on the other control signal
197     *               11: Pad on/off according to the
198     *                   Power Management Status (PMS) */
199    ViaSeqMask(hwp, 0x1E, ioPadState << 6, 0xC0);
200    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
201                "DVP0 I/O Pad State: %s\n",
202                (ioPadState & 0x02) ?
203                    (ioPadState & 0x01) ? "Automatic On / Off" : "Conditional"
204                : "Off");
205
206    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
207                        "Exiting viaDVP0EnableIOPads.\n"));
208}
209
210/*
211 * Sets DVP0 (Digital Video Port 0) clock I/O pad drive strength.
212 */
213void
214viaDVP0SetClockDriveStrength(ScrnInfoPtr pScrn, CARD8 clockDriveStrength)
215{
216    vgaHWPtr hwp = VGAHWPTR(pScrn);
217
218    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
219                        "Entered viaDVP0SetClockDriveStrength.\n"));
220
221    /* 3C5.1E[2] - DVP0 Clock Drive Strength Bit [0] */
222    ViaSeqMask(hwp, 0x1E, clockDriveStrength << 2, 0x04);
223
224    /* 3C5.2A[4] - DVP0 Clock Drive Strength Bit [1] */
225    ViaSeqMask(hwp, 0x2A, clockDriveStrength << 3, 0x10);
226
227    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
228                "DVP0 Clock I/O Pad Drive Strength: %u\n",
229                clockDriveStrength & 0x03);
230
231    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
232                        "Exiting viaDVP0SetClockDriveStrength.\n"));
233}
234
235/*
236 * Sets DVP0 (Digital Video Port 0) data I/O pads drive strength.
237 */
238void
239viaDVP0SetDataDriveStrength(ScrnInfoPtr pScrn, CARD8 dataDriveStrength)
240{
241    vgaHWPtr hwp = VGAHWPTR(pScrn);
242
243    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
244                        "Entered viaDVP0SetDataDriveStrength.\n"));
245
246    /* 3C5.1B[1] - DVP0 Data Drive Strength Bit [0] */
247    ViaSeqMask(hwp, 0x1B, dataDriveStrength << 1, 0x02);
248
249    /* 3C5.2A[5] - DVP0 Data Drive Strength Bit [1] */
250    ViaSeqMask(hwp, 0x2A, dataDriveStrength << 4, 0x20);
251
252    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
253                "DVP0 Data I/O Pads Drive Strength: %u\n",
254                dataDriveStrength);
255
256    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
257                        "Exiting viaDVP0SetDataDriveStrength.\n"));
258}
259
260/*
261 * Sets IGA1 or IGA2 as the display output source for DVP1
262 * (Digital Video Port) interface.
263 */
264void
265viaDVP1SetDisplaySource(ScrnInfoPtr pScrn, CARD8 displaySource)
266{
267    vgaHWPtr hwp = VGAHWPTR(pScrn);
268    CARD8 temp = displaySource;
269
270    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
271                        "Entered viaDVP1SetDisplaySource.\n"));
272
273    /* Set DVP1 display output source. */
274    /* 3X5.9B[4] - DVP1 Data Source Selection
275     *             0: Primary Display
276     *             1: Secondary Display */
277    ViaCrtcMask(hwp, 0x9B, temp << 4, 0x10);
278    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
279                "DVP1 Display Output Source: IGA%d\n",
280                (temp & 0x01) + 1);
281
282    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
283                        "Exiting viaDVP1SetDisplaySource.\n"));
284}
285
286/*
287 * Sets DVP1 (Digital Video Port 1) I/O pad state.
288 */
289void
290viaDVP1EnableIOPads(ScrnInfoPtr pScrn, CARD8 ioPadState)
291{
292    vgaHWPtr hwp = VGAHWPTR(pScrn);
293
294    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
295                        "Entered viaDVP1EnableIOPads.\n"));
296
297    /* Set DVP1 I/O pad state. */
298    /* 3C5.1E[5:4] - DVP1 Power Control
299     *               0x: Pad always off
300     *               10: Depend on the other control signal
301     *               11: Pad on/off according to the
302     *                   Power Management Status (PMS) */
303    ViaSeqMask(hwp, 0x1E, ioPadState << 4, 0x30);
304    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
305                "DVP1 I/O Pad State: %s\n",
306                (ioPadState & 0x02) ?
307                    (ioPadState & 0x01) ? "Automatic On / Off": "Conditional"
308                : "Off");
309
310    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
311                        "Exiting viaDVP1EnableIOPads.\n"));
312}
313
314/*
315 * Sets DVP1 (Digital Video Port 1) clock I/O pad drive strength.
316 */
317void
318viaDVP1SetClockDriveStrength(ScrnInfoPtr pScrn, CARD8 clockDriveStrength)
319{
320    vgaHWPtr hwp = VGAHWPTR(pScrn);
321
322    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
323                        "Entered viaDVP1SetClockDriveStrength.\n"));
324
325    /* 3C5.65[3:2] - DVP1 Clock Pads Driving Select
326     *               00: lowest
327     *               01: low
328     *               10: high
329     *               11: highest */
330    ViaSeqMask(hwp, 0x65, clockDriveStrength << 2, 0x0C);
331
332    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
333                "DVP1 Clock I/O Pad Drive Strength: %u\n",
334                clockDriveStrength & 0x03);
335
336    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
337                        "Exiting viaDVP1SetClockDriveStrength.\n"));
338}
339
340/*
341 * Sets DVP1 (Digital Video Port 1) data I/O pads drive strength.
342 */
343void
344viaDVP1SetDataDriveStrength(ScrnInfoPtr pScrn, CARD8 dataDriveStrength)
345{
346    vgaHWPtr hwp = VGAHWPTR(pScrn);
347
348    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
349                        "Entered viaDVP1SetDataDriveStrength.\n"));
350
351    /* 3C5.65[1:0] - DVP1 Data Pads Driving Select
352     *               00: lowest
353     *               01: low
354     *               10: high
355     *               11: highest */
356    ViaSeqMask(hwp, 0x65, dataDriveStrength, 0x03);
357
358    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
359                "DVP1 Data I/O Pads Drive Strength: %u\n",
360                dataDriveStrength & 0x03);
361
362    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
363                        "Exiting viaDVP1SetDataDriveStrength.\n"));
364}
365
366/*
367 * Sets IGA1 or IGA2 as the display output source for VIA Technologies
368 * Chrome IGP DFP (Digital Flat Panel) Low interface.
369 */
370void
371viaDFPLowSetDisplaySource(ScrnInfoPtr pScrn, CARD8 displaySource)
372{
373    vgaHWPtr hwp = VGAHWPTR(pScrn);
374    CARD8 temp = displaySource;
375
376    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
377                        "Entered viaDFPLowSetDisplaySource.\n"));
378
379    /* Set DFP Low display output source. */
380    /* 3X5.99[4] - DFP Low Data Source Selection
381     *             0: Primary Display
382     *             1: Secondary Display */
383    ViaCrtcMask(hwp, 0x99, temp << 4, 0x10);
384    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
385                "DFP Low Display Output Source: IGA%d\n",
386                (temp & 0x01) + 1);
387
388    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
389                        "Exiting viaDFPLowSetDisplaySource.\n"));
390}
391
392/*
393 * Sets DFP (Digital Flat Panel) Low I/O pad state.
394 */
395void
396viaDFPLowEnableIOPads(ScrnInfoPtr pScrn, CARD8 ioPadState)
397{
398    vgaHWPtr hwp = VGAHWPTR(pScrn);
399
400    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
401                        "Entered viaDFPLowEnableIOPads.\n"));
402
403    /* Set DFP Low I/O pad state. */
404    /* 3C5.2A[1:0] - DFP Low Power Control
405     *               0x: Pad always off
406     *               10: Depend on the other control signal
407     *               11: Pad on/off according to the
408     *                   Power Management Status (PMS) */
409    ViaSeqMask(hwp, 0x2A, ioPadState, 0x03);
410    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
411                "DFP Low I/O Pad State: %s\n",
412                (ioPadState & 0x02) ?
413                    (ioPadState & 0x01) ? "Automatic On / Off": "Conditional"
414                : "Off");
415
416    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
417                        "Exiting viaDFPLowEnableIOPads.\n"));
418}
419
420/*
421 * Reads off the VIA Technologies IGP pin strapping for
422 * display detection purposes.
423 */
424void
425viaProbePinStrapping(ScrnInfoPtr pScrn)
426{
427    vgaHWPtr hwp = VGAHWPTR(pScrn);
428    VIAPtr pVia = VIAPTR(pScrn);
429    CARD8 sr12, sr13, sr5a;
430
431    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
432                        "Entered viaProbePinStrapping.\n"));
433
434    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
435                "Probing VIA Technologies IGP pin strapping . . .\n");
436
437    if ((pVia->Chipset == VIA_CX700)
438        || (pVia->Chipset == VIA_VX800)
439        || (pVia->Chipset == VIA_VX855)
440        || (pVia->Chipset == VIA_VX900)) {
441
442        sr5a = hwp->readSeq(hwp, 0x5A);
443        DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
444                            "SR5A: 0x%02X\n", sr5a));
445        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
446                    "Setting 3C5.5A[0] to 0.\n");
447        ViaSeqMask(hwp, 0x5A, sr5a & 0xFE, 0x01);
448    }
449
450    sr12 = hwp->readSeq(hwp, 0x12);
451    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
452                        "SR12: 0x%02X\n", sr12));
453    sr13 = hwp->readSeq(hwp, 0x13);
454    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
455                        "SR13: 0x%02X\n", sr13));
456
457    switch (pVia->Chipset) {
458    case VIA_CLE266:
459
460        /* 3C5.12[4] - FPD17 pin strapping
461         *             0: TMDS transmitter (DVI) / capture device
462         *             1: Flat panel */
463        if (sr12 & 0x10) {
464            xf86DrvMsg(pScrn->scrnIndex, X_INFO,
465                        "A flat panel is connected to "
466                        "flat panel interface.\n");
467
468            /* 3C5.12[3:0] - FPD16-13 pin strapping
469             *               0 ~ 15: Flat panel code defined
470             *                       by VIA Technologies */
471            xf86DrvMsg(pScrn->scrnIndex, X_INFO,
472                        "Detected Flat Panel Type from "
473                        "Strapping Pins: %d\n", sr12 & 0x0F);
474        } else {
475            xf86DrvMsg(pScrn->scrnIndex, X_INFO,
476                        "A TMDS transmitter (DVI) / capture device is "
477                        "connected to DIP0.\n");
478        }
479
480        /* 3C5.12[5] - FPD18 pin strapping
481         *             0: TMDS transmitter (DVI)
482         *             1: TV encoder */
483        if (sr12 & 0x20) {
484            xf86DrvMsg(pScrn->scrnIndex, X_INFO,
485                        "A TV encoder is connected to "
486                        "DIP0.\n");
487
488            /* 3C5.13[4:3] - FPD21-20 pin strapping
489             *               00: PAL
490             *               01: NTSC
491             *               10: PAL-N
492             *               11: PAL-NC */
493            if ((!(sr13 & 0x08)) && (sr13 & 0x04)) {
494                xf86DrvMsg(pScrn->scrnIndex, X_INFO,
495                            "NTSC for the TV encoder.\n");
496            } else {
497                if (!(sr13 & 0x08)) {
498                    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
499                                "PAL for the TV encoder.\n");
500                } else {
501                    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
502                                "PAL%s for the TV encoder.\n",
503                                (sr13 & 0x04) ? "-NC" : "-N");
504                }
505            }
506
507            /* 3C5.12[6] - FPD19 pin strapping
508             *             0: 525 lines (NTSC)
509             *             1: 625 lines (PAL) */
510            xf86DrvMsg(pScrn->scrnIndex, X_INFO,
511                        "%s lines for the TV encoder.\n",
512                        (sr12 & 0x40) ? "625" : "525");
513        } else {
514            xf86DrvMsg(pScrn->scrnIndex, X_INFO,
515                        "A TMDS transmitter (DVI) is connected to "
516                        "DIP0.\n");
517        }
518
519        break;
520
521    case VIA_KM400:
522    case VIA_K8M800:
523    case VIA_PM800:
524    case VIA_P4M800PRO:
525
526        /* 3C5.12[6] - DVP0D6 pin strapping
527         *             0: Disable DVP0 (Digital Video Port 0) for
528         *                DVI or TV out use
529         *             1: Enable DVP0 (Digital Video Port 0) for
530         *                DVI or TV out use */
531        if (sr12 & 0x40) {
532
533            /* 3C5.12[5] - DVP0D5 pin strapping
534             *             0: TMDS transmitter (DVI)
535             *             1: TV encoder */
536            if (sr12 & 0x20) {
537                xf86DrvMsg(pScrn->scrnIndex, X_INFO,
538                            "A TV encoder is detected on "
539                            "DVP0 (Digital Video Port 0).\n");
540            } else {
541                xf86DrvMsg(pScrn->scrnIndex, X_INFO,
542                            "A TMDS transmitter (DVI) is detected on "
543                            "DVP0 (Digital Video Port 0).\n");
544            }
545        }
546
547
548        /* 3C5.13[3] - DVP0D8 pin strapping
549         *             0: AGP pins are used for AGP
550         *             1: AGP pins are used by FPDP
551         *             (Flat Panel Display Port) */
552        if (sr13 & 0x08) {
553
554            /* 3C5.12[4] - DVP0D4 pin strapping
555             *             0: Dual 12-bit FPDP (Flat Panel Display Port)
556             *             1: 24-bit FPDP (Flat Panel Display Port) */
557            if (sr12 & 0x10) {
558                xf86DrvMsg(pScrn->scrnIndex, X_INFO,
559                            "24-bit FPDP (Flat Panel Display Port) "
560                            "detected.\n");
561
562                /* 3C5.12[3:0] - DVP0D3-0 pin strapping
563                 *               0 ~ 15: Flat panel code defined
564                 *                       by VIA Technologies */
565                xf86DrvMsg(pScrn->scrnIndex, X_INFO,
566                            "Detected Flat Panel Type from "
567                            "Strapping Pins: %d\n", sr12 & 0x0F);
568            } else {
569
570                /* 3C5.12[6] - DVP0D6 pin strapping
571                 *             0: Disable DVP0 (Digital Video Port 0) for
572                 *                DVI or TV out use
573                 *             1: Enable DVP0 (Digital Video Port 0) for
574                 *                DVI or TV out use
575                 * 3C5.12[5] - DVP0D5 pin strapping
576                 *             0: TMDS transmitter (DVI)
577                 *             1: TV encoder */
578                if ((!(sr12 & 0x40)) && (!(sr12 & 0x20))) {
579                    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
580                                "A TV encoder is connected to "
581                                "FPDP (Flat Panel Display Port).\n");
582                } else {
583                    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
584                                "Dual 12-bit FPDP (Flat Panel Display Port) "
585                                "detected.\n");
586
587                    /* 3C5.12[3:0] - DVP0D3-0 pin strapping
588                     *               0 ~ 15: Flat panel code defined
589                     *                       by VIA Technologies */
590                    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
591                                "Detected Flat Panel Type from "
592                                "Strapping Pins: %d\n", sr12 & 0x0F);
593                }
594            }
595        }
596
597        break;
598
599    default:
600        break;
601    }
602
603    if ((pVia->Chipset == VIA_CX700)
604        || (pVia->Chipset == VIA_VX800)
605        || (pVia->Chipset == VIA_VX855)
606        || (pVia->Chipset == VIA_VX900)) {
607
608        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
609                    "Setting 3C5.5A[0] to 1.\n");
610        ViaSeqMask(hwp, 0x5A, sr5a | 0x01, 0x01);
611
612        sr12 = hwp->readSeq(hwp, 0x12);
613        DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
614                            "SR12: 0x%02X\n", sr12));
615        sr13 = hwp->readSeq(hwp, 0x13);
616        DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
617                            "SR13: 0x%02X\n", sr13));
618
619        /* 3C5.13[7:6] - Integrated LVDS / DVI Mode Select
620         *               (DVP1D15-14 pin strapping)
621         *               00: LVDS1 + LVDS2
622         *               01: DVI + LVDS2
623         *               10: Dual LVDS Channel (High Resolution Panel)
624         *               11: One DVI only (decrease the clock jitter) */
625        switch (sr13 & 0xC0) {
626        case 0x00:
627            xf86DrvMsg(pScrn->scrnIndex, X_INFO,
628                        "LVDS1 + LVDS2 detected.\n");
629            break;
630        case 0x40:
631            xf86DrvMsg(pScrn->scrnIndex, X_INFO,
632                        "Single Link DVI + LVDS2 detected.\n");
633            break;
634        case 0x80:
635            xf86DrvMsg(pScrn->scrnIndex, X_INFO,
636                        "Dual Channel LVDS detected.\n");
637            break;
638        case 0xC0:
639            xf86DrvMsg(pScrn->scrnIndex, X_INFO,
640                        "Single Link DVI detected.\n");
641            break;
642        default:
643            break;
644        }
645
646        hwp->writeSeq(hwp, 0x5A, sr5a);
647
648    }
649
650    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
651                        "Exiting viaProbePinStrapping.\n"));
652}
653
654void
655viaOutputDetect(ScrnInfoPtr pScrn)
656{
657    VIAPtr pVia = VIAPTR(pScrn);
658    VIABIOSInfoPtr pBIOSInfo = pVia->pBIOSInfo;
659
660    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
661                        "Entered viaOutputDetect.\n"));
662
663    pBIOSInfo->analog = NULL;
664
665    /* Initialize the number of VGA connectors. */
666    pVia->numberVGA = 0;
667
668    /* Initialize the number of DVI connectors. */
669    pVia->numberDVI = 0;
670
671    /* Initialize the number of FP connectors. */
672    pVia->numberFP = 0;
673
674    /* Read off the VIA Technologies IGP pin strapping for
675       display detection purposes. */
676    viaProbePinStrapping(pScrn);
677
678    /* VGA */
679    via_analog_init(pScrn);
680
681    /* TV */
682    via_tv_init(pScrn);
683
684    /* DVI */
685    via_dvi_init(pScrn);
686
687    /* LVDS */
688    via_lvds_init(pScrn);
689
690    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
691                        "Exiting viaOutputDetect.\n"));
692}
693
694#ifdef HAVE_DEBUG
695/*
696 * Returns:
697 *   Bit[7] 2nd Path
698 *   Bit[6] 1/0 MHS Enable/Disable
699 *   Bit[5] 0 = Bypass Callback, 1 = Enable Callback
700 *   Bit[4] 0 = Hot-Key Sequence Control (OEM Specific)
701 *   Bit[3] LCD
702 *   Bit[2] TV
703 *   Bit[1] CRT
704 *   Bit[0] DVI
705 */
706static CARD8
707VIAGetActiveDisplay(ScrnInfoPtr pScrn)
708{
709    vgaHWPtr hwp = VGAHWPTR(pScrn);
710    CARD8 tmp;
711
712    tmp = (hwp->readCrtc(hwp, 0x3E) >> 4);
713    tmp |= ((hwp->readCrtc(hwp, 0x3B) & 0x18) << 3);
714
715    return tmp;
716}
717#endif /* HAVE_DEBUG */
718
719/*
720 *
721 */
722CARD32
723ViaGetMemoryBandwidth(ScrnInfoPtr pScrn)
724{
725    VIAPtr pVia = VIAPTR(pScrn);
726
727    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
728                     "ViaGetMemoryBandwidth. Memory type: %d\n",
729                     pVia->MemClk));
730
731    switch (pVia->MemClk) {
732        case VIA_MEM_SDR66:
733        case VIA_MEM_SDR100:
734        case VIA_MEM_SDR133:
735            return VIA_BW_MIN;
736        case VIA_MEM_DDR200:
737            return VIA_BW_DDR200;
738        case VIA_MEM_DDR266:
739        case VIA_MEM_DDR333:
740        case VIA_MEM_DDR400:
741            return VIA_BW_DDR400;
742        case VIA_MEM_DDR533:
743        case VIA_MEM_DDR667:
744            return VIA_BW_DDR667;
745        case VIA_MEM_DDR800:
746        case VIA_MEM_DDR1066:
747            return VIA_BW_DDR1066;
748        default:
749            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
750                       "ViaBandwidthAllowed: Unknown memory type: %d\n",
751                       pVia->MemClk);
752            return VIA_BW_MIN;
753    }
754}
755
756/*
757 *
758 * Some very common abstractions.
759 *
760 */
761
762/*
763 * Standard vga call really.
764 * Needs to be called to reset the dotclock (after SR40:2/1 reset)
765 */
766void
767ViaSetUseExternalClock(vgaHWPtr hwp)
768{
769    CARD8 data;
770
771    DEBUG(xf86DrvMsg(hwp->pScrn->scrnIndex, X_INFO,
772                     "ViaSetUseExternalClock\n"));
773
774    data = hwp->readMiscOut(hwp);
775    hwp->writeMiscOut(hwp, data | 0x0C);
776}
777
778/*
779 *
780 */
781static void
782ViaSetDotclock(ScrnInfoPtr pScrn, CARD32 clock, int base, int probase)
783{
784    vgaHWPtr hwp = VGAHWPTR(pScrn);
785    VIAPtr pVia = VIAPTR(pScrn);
786
787    DEBUG(xf86DrvMsg(hwp->pScrn->scrnIndex, X_INFO,
788                     "ViaSetDotclock to 0x%06x\n", (unsigned)clock));
789
790    if ((pVia->Chipset == VIA_CLE266) || (pVia->Chipset == VIA_KM400)) {
791        hwp->writeSeq(hwp, base, clock >> 8);
792        hwp->writeSeq(hwp, base+1, clock & 0xFF);
793    } else {  /* unichrome pro */
794        union pllparams pll;
795        int dtz, dr, dn, dm;
796        pll.packed = clock;
797        dtz = pll.params.dtz;
798        dr  = pll.params.dr;
799        dn  = pll.params.dn;
800        dm  = pll.params.dm;
801
802        /* The VX855 and VX900 do not modify dm/dn, but earlier chipsets do. */
803        if ((pVia->Chipset != VIA_VX855) && (pVia->Chipset != VIA_VX900)) {
804            dm -= 2;
805            dn -= 2;
806        }
807
808        hwp->writeSeq(hwp, probase, dm & 0xff);
809        hwp->writeSeq(hwp, probase+1,
810                      ((dm >> 8) & 0x03) | (dr << 2) | ((dtz & 1) << 7));
811        hwp->writeSeq(hwp, probase+2, (dn & 0x7f) | ((dtz & 2) << 6));
812    }
813}
814
815/*
816 *
817 */
818void
819ViaSetPrimaryDotclock(ScrnInfoPtr pScrn, CARD32 clock)
820{
821    vgaHWPtr hwp = VGAHWPTR(pScrn);
822
823    ViaSetDotclock(pScrn, clock, 0x46, 0x44);
824
825    ViaSeqMask(hwp, 0x40, 0x02, 0x02);
826    ViaSeqMask(hwp, 0x40, 0x00, 0x02);
827}
828
829/*
830 *
831 */
832void
833ViaSetSecondaryDotclock(ScrnInfoPtr pScrn, CARD32 clock)
834{
835    vgaHWPtr hwp = VGAHWPTR(pScrn);
836
837    ViaSetDotclock(pScrn, clock, 0x44, 0x4A);
838
839    ViaSeqMask(hwp, 0x40, 0x04, 0x04);
840    ViaSeqMask(hwp, 0x40, 0x00, 0x04);
841}
842
843/*
844 *
845 */
846static void
847ViaSetECKDotclock(ScrnInfoPtr pScrn, CARD32 clock)
848{
849    /* Does the non-pro chip have an ECK clock ? */
850    ViaSetDotclock(pScrn, clock, 0, 0x47);
851}
852
853static CARD32
854ViaComputeDotClock(unsigned clock)
855{
856    double fout, fref, err, minErr;
857    CARD32 dr, dn, dm, maxdm, maxdn;
858    CARD32 factual, best;
859
860    fref = 14.31818e6;
861    fout = (double)clock * 1.e3;
862
863    factual = ~0;
864    maxdm = 127;
865    maxdn = 7;
866    minErr = 1e10;
867    best = 0;
868
869    for (dr = 0; dr < 4; ++dr) {
870        for (dn = (dr == 0) ? 2 : 1; dn <= maxdn; ++dn) {
871            for (dm = 1; dm <= maxdm; ++dm) {
872                factual = fref * dm;
873                factual /= (dn << dr);
874                err = fabs((double)factual / fout - 1.);
875                if (err < minErr) {
876                    minErr = err;
877                    best = (dm & 127) | ((dn & 31) << 8) | (dr << 14);
878                }
879            }
880        }
881    }
882    return best;
883}
884
885static CARD32
886ViaComputeProDotClock(unsigned clock)
887{
888    double fvco, fout, err, minErr;
889    CARD32 dr = 0, dn, dm, maxdm, maxdn;
890    CARD32 factual;
891    union pllparams bestClock;
892
893    fout = (double)clock * 1.e3;
894
895    factual = ~0;
896    maxdm = factual / 14318000U;
897    minErr = 1.e10;
898    bestClock.packed = 0U;
899
900    do {
901        fvco = fout * (1 << dr);
902    } while (fvco < 300.e6 && dr++ < 8);
903
904    if (dr == 8) {
905        return 0;
906    }
907
908    if (clock < 30000)
909        maxdn = 8;
910    else if (clock < 45000)
911        maxdn = 7;
912    else if (clock < 170000)
913        maxdn = 6;
914    else
915        maxdn = 5;
916
917    for (dn = 2; dn < maxdn; ++dn) {
918        for (dm = 2; dm < maxdm; ++dm) {
919            factual = 14318000U * dm;
920            factual /= dn << dr;
921            if ((err = fabs((double)factual / fout - 1.)) < 0.005) {
922                if (err < minErr) {
923                    minErr = err;
924                    bestClock.params.dtz = 1;
925                    bestClock.params.dr = dr;
926                    bestClock.params.dn = dn;
927                    bestClock.params.dm = dm;
928                }
929            }
930        }
931    }
932
933    return bestClock.packed;
934}
935
936/*
937 *
938 */
939CARD32
940ViaModeDotClockTranslate(ScrnInfoPtr pScrn, DisplayModePtr mode)
941{
942    VIAPtr pVia = VIAPTR(pScrn);
943    int i;
944
945    if ((pVia->Chipset == VIA_CLE266) || (pVia->Chipset == VIA_KM400)) {
946        CARD32 best1 = 0, best2;
947
948        for (i = 0; ViaDotClocks[i].DotClock; i++)
949            if (ViaDotClocks[i].DotClock == mode->Clock) {
950                best1 = ViaDotClocks[i].UniChrome;
951                break;
952            }
953
954        best2 = ViaComputeDotClock(mode->Clock);
955
956        DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
957                         "ViaComputeDotClock %d : %04x : %04x\n",
958                         mode->Clock, (unsigned int)best1,
959                         (unsigned int)best2));
960
961        return best2;
962    } else {
963        for (i = 0; ViaDotClocks[i].DotClock; i++)
964            if (ViaDotClocks[i].DotClock == mode->Clock)
965                return ViaDotClocks[i].UniChromePro.packed;
966        return ViaComputeProDotClock(mode->Clock);
967    }
968
969    return 0;
970}
971