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  */
53 void
viaDIP0SetDisplaySource(ScrnInfoPtr pScrn,CARD8 displaySource)54 viaDIP0SetDisplaySource(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  */
79 void
viaDIP0EnableIOPads(ScrnInfoPtr pScrn,CARD8 ioPadState)80 viaDIP0EnableIOPads(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  */
108 void
viaDIP0SetClockDriveStrength(ScrnInfoPtr pScrn,CARD8 clockDriveStrength)109 viaDIP0SetClockDriveStrength(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  */
134 void
viaDIP0SetDataDriveStrength(ScrnInfoPtr pScrn,CARD8 dataDriveStrength)135 viaDIP0SetDataDriveStrength(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  */
160 void
viaDVP0SetDisplaySource(ScrnInfoPtr pScrn,CARD8 displaySource)161 viaDVP0SetDisplaySource(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  */
185 void
viaDVP0EnableIOPads(ScrnInfoPtr pScrn,CARD8 ioPadState)186 viaDVP0EnableIOPads(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  */
213 void
viaDVP0SetClockDriveStrength(ScrnInfoPtr pScrn,CARD8 clockDriveStrength)214 viaDVP0SetClockDriveStrength(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  */
238 void
viaDVP0SetDataDriveStrength(ScrnInfoPtr pScrn,CARD8 dataDriveStrength)239 viaDVP0SetDataDriveStrength(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  */
264 void
viaDVP1SetDisplaySource(ScrnInfoPtr pScrn,CARD8 displaySource)265 viaDVP1SetDisplaySource(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  */
289 void
viaDVP1EnableIOPads(ScrnInfoPtr pScrn,CARD8 ioPadState)290 viaDVP1EnableIOPads(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  */
317 void
viaDVP1SetClockDriveStrength(ScrnInfoPtr pScrn,CARD8 clockDriveStrength)318 viaDVP1SetClockDriveStrength(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  */
343 void
viaDVP1SetDataDriveStrength(ScrnInfoPtr pScrn,CARD8 dataDriveStrength)344 viaDVP1SetDataDriveStrength(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  */
370 void
viaDFPLowSetDisplaySource(ScrnInfoPtr pScrn,CARD8 displaySource)371 viaDFPLowSetDisplaySource(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  */
395 void
viaDFPLowEnableIOPads(ScrnInfoPtr pScrn,CARD8 ioPadState)396 viaDFPLowEnableIOPads(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  */
424 void
viaProbePinStrapping(ScrnInfoPtr pScrn)425 viaProbePinStrapping(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 
654 void
viaOutputDetect(ScrnInfoPtr pScrn)655 viaOutputDetect(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  */
706 static CARD8
VIAGetActiveDisplay(ScrnInfoPtr pScrn)707 VIAGetActiveDisplay(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  */
722 CARD32
ViaGetMemoryBandwidth(ScrnInfoPtr pScrn)723 ViaGetMemoryBandwidth(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  */
766 void
ViaSetUseExternalClock(vgaHWPtr hwp)767 ViaSetUseExternalClock(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  */
781 static void
ViaSetDotclock(ScrnInfoPtr pScrn,CARD32 clock,int base,int probase)782 ViaSetDotclock(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  */
818 void
ViaSetPrimaryDotclock(ScrnInfoPtr pScrn,CARD32 clock)819 ViaSetPrimaryDotclock(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  */
832 void
ViaSetSecondaryDotclock(ScrnInfoPtr pScrn,CARD32 clock)833 ViaSetSecondaryDotclock(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  */
846 static void
ViaSetECKDotclock(ScrnInfoPtr pScrn,CARD32 clock)847 ViaSetECKDotclock(ScrnInfoPtr pScrn, CARD32 clock)
848 {
849     /* Does the non-pro chip have an ECK clock ? */
850     ViaSetDotclock(pScrn, clock, 0, 0x47);
851 }
852 
853 static CARD32
ViaComputeDotClock(unsigned clock)854 ViaComputeDotClock(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 
885 static CARD32
ViaComputeProDotClock(unsigned clock)886 ViaComputeProDotClock(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  */
939 CARD32
ViaModeDotClockTranslate(ScrnInfoPtr pScrn,DisplayModePtr mode)940 ViaModeDotClockTranslate(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