1 /*
2  * Copyright 2007-2015 The Openchrome Project
3  *                     [https://www.freedesktop.org/wiki/Openchrome]
4  * Copyright 1998-2007 VIA Technologies, Inc. All Rights Reserved.
5  * Copyright 2001-2007 S3 Graphics, Inc. All Rights Reserved.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the "Software"),
9  * to deal in the Software without restriction, including without limitation
10  * the rights to use, copy, modify, merge, publish, distribute, sub license,
11  * and/or sell copies of the Software, and to permit persons to whom the
12  * Software is furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice (including the
15  * next paragraph) shall be included in all copies or substantial portions
16  * of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24  * DEALINGS IN THE SOFTWARE.
25  */
26 
27 /*
28  * Integrated LVDS power management functions.
29  */
30 
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34 
35 #include "via_driver.h"
36 #include "via_mode.h"
37 #include <unistd.h>
38 
39 /*
40  * Option handling.
41  */
42 enum ViaPanelOpts {
43     OPTION_CENTER
44 };
45 
46 static OptionInfoRec ViaPanelOptions[] =
47 {
48     {OPTION_CENTER,     "Center",       OPTV_BOOLEAN,   {0},    FALSE},
49     {-1,                NULL,           OPTV_NONE,      {0},    FALSE}
50 };
51 
52 /* These table values were copied from lcd.c of VIA Frame
53  * Buffer device driver. */
54 /* {int Width, int Height, bool useDualEdge, bool useDithering}; */
55 static ViaPanelModeRec ViaPanelNativeModes[] = {
56     { 640,  480, FALSE,  TRUE},
57     { 800,  600, FALSE,  TRUE},
58     {1024,  768, FALSE,  TRUE},
59     {1280,  768, FALSE,  TRUE},
60     {1280, 1024,  TRUE,  TRUE},
61     {1400, 1050,  TRUE,  TRUE},
62     {1600, 1200,  TRUE,  TRUE},
63     {1280,  800, FALSE,  TRUE},
64     { 800,  480, FALSE,  TRUE},
65     {1024,  768,  TRUE,  TRUE},
66     {1024,  768, FALSE, FALSE},
67     {1024,  768,  TRUE, FALSE},
68     {1280,  768, FALSE, FALSE},
69     {1280, 1024,  TRUE, FALSE},
70     {1400, 1050,  TRUE, FALSE},
71     {1600, 1200,  TRUE, FALSE},
72     {1366,  768, FALSE, FALSE},
73     {1024,  600, FALSE,  TRUE},
74     {1280,  768,  TRUE,  TRUE},
75     {1280,  800, FALSE,  TRUE},
76     {1360,  768, FALSE, FALSE},
77     {1280,  768,  TRUE, FALSE},
78     { 480,  640, FALSE,  TRUE},
79     {1200,  900, FALSE, FALSE}};
80 
81 #define MODEPREFIX(name) NULL, NULL, name, 0, M_T_DRIVER | M_T_DEFAULT
82 #define MODESUFFIX 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,FALSE,FALSE,0,NULL,0,0.0,0.0
83 
84 static DisplayModeRec OLPCMode = {
85     MODEPREFIX("1200x900"),
86     57275, 1200, 1208, 1216, 1240, 0,
87     900,  905,  908,  912, 0,
88     V_NHSYNC | V_NVSYNC, MODESUFFIX
89 };
90 
91 /*
92 	1. Formula:
93 		2^13 X 0.0698uSec [1/14.318MHz] = 8192 X 0.0698uSec =572.1uSec
94 		Timer = Counter x 572 uSec
95 	2. Note:
96 		0.0698 uSec is too small to compute for hardware. So we multiply a
97 		reference value(2^13) to make it big enough to compute for hardware.
98 	3. Note:
99 		The meaning of the TD0~TD3 are count of the clock.
100 		TD(sec) = (sec)/(per clock) x (count of clocks)
101 */
102 
103 #define TD0 200
104 #define TD1 25
105 #define TD2 0
106 #define TD3 25
107 
108 /*
109  * Sets CX700 or later single chipset's LVDS1 I/O pad state.
110  */
111 void
viaLVDS1SetIOPadSetting(ScrnInfoPtr pScrn,CARD8 ioPadState)112 viaLVDS1SetIOPadSetting(ScrnInfoPtr pScrn, CARD8 ioPadState)
113 {
114     vgaHWPtr hwp = VGAHWPTR(pScrn);
115 
116     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
117                         "Entered viaLVDS1SetIOPadSetting.\n"));
118 
119     /* Set LVDS1 I/O pad state. */
120     /* 3C5.2A[1:0] - LVDS1 I/O Pad Control */
121     ViaSeqMask(hwp, 0x2A, ioPadState, 0x03);
122     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
123                 "LVDS1 I/O Pad State: %d\n",
124                 (ioPadState & 0x03));
125 
126     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
127                         "Exiting viaLVDS1SetIOPadSetting.\n"));
128 }
129 
130 /*
131  * Sets IGA1 or IGA2 as the display output source for VIA Technologies
132  * Chrome IGP LVDS1 integrated LVDS transmitter.
133  */
134 static void
viaLVDS1SetDisplaySource(ScrnInfoPtr pScrn,CARD8 displaySource)135 viaLVDS1SetDisplaySource(ScrnInfoPtr pScrn, CARD8 displaySource)
136 {
137     vgaHWPtr hwp = VGAHWPTR(pScrn);
138     CARD8 temp = displaySource;
139 
140     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
141                         "Entered viaLVDS1SetDisplaySource.\n"));
142 
143     /* Set LVDS1 integrated LVDS transmitter display output source. */
144     /* 3X5.99[4] - LVDS Channel 1 Data Source Selection
145      *             0: Primary Display
146      *             1: Secondary Display */
147     ViaCrtcMask(hwp, 0x99, temp << 4, 0x10);
148     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
149                 "LVDS1 Integrated LVDS Transmitter Display Output "
150                 "Source: IGA%d\n",
151                 (temp & 0x01) + 1);
152 
153     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
154                         "Exiting viaLVDS1SetDisplaySource.\n"));
155 }
156 
157 /*
158  * Sets LVDS1 (LVDS Channel 1) integrated LVDS transmitter format.
159  */
160 static void
viaLVDS1SetFormat(ScrnInfoPtr pScrn,CARD8 format)161 viaLVDS1SetFormat(ScrnInfoPtr pScrn, CARD8 format)
162 {
163     vgaHWPtr hwp = VGAHWPTR(pScrn);
164 
165     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
166                         "Entered viaLVDS1SetFormat.\n"));
167 
168     /* Set LVDS1 format. */
169     /* 3X5.D2[1] - LVDS Channel 1 Format Selection
170      *             0: SPWG Mode
171      *             1: OPENLDI Mode */
172     ViaCrtcMask(hwp, 0xD2, format << 1, 0x02);
173     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
174                 "LVDS1 Format: %s\n",
175                 (format & 0x01) ? "OPENLDI" : "SPWG");
176 
177     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
178                         "Exiting viaLVDS1SetFormat.\n"));
179 }
180 
181 /*
182  * Sets CX700 or later single chipset's LVDS2 I/O pad state.
183  */
184 static void
viaLVDS2SetIOPadSetting(ScrnInfoPtr pScrn,CARD8 ioPadState)185 viaLVDS2SetIOPadSetting(ScrnInfoPtr pScrn, CARD8 ioPadState)
186 {
187     vgaHWPtr hwp = VGAHWPTR(pScrn);
188 
189     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
190                         "Entered viaLVDS2SetIOPadSetting.\n"));
191 
192     /* Set LVDS2 I/O pad state. */
193     /* 3C5.2A[3:2] - LVDS2 I/O Pad Control */
194     ViaSeqMask(hwp, 0x2A, ioPadState << 2, 0x0C);
195     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
196                 "LVDS2 I/O Pad State: %d\n",
197                 (ioPadState & 0x03));
198 
199     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
200                         "Exiting viaLVDS2SetIOPadSetting.\n"));
201 }
202 
203 /*
204  * Sets IGA1 or IGA2 as the display output source for VIA Technologies
205  * Chrome IGP LVDS2 integrated LVDS transmitter.
206  */
207 static void
viaLVDS2SetDisplaySource(ScrnInfoPtr pScrn,CARD8 displaySource)208 viaLVDS2SetDisplaySource(ScrnInfoPtr pScrn, CARD8 displaySource)
209 {
210     vgaHWPtr hwp = VGAHWPTR(pScrn);
211     CARD8 temp = displaySource;
212 
213     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
214                         "Entered viaLVDS2SetDisplaySource.\n"));
215 
216     /* Set LVDS2 integrated LVDS transmitter display output source. */
217     /* 3X5.97[4] - LVDS Channel 2 Data Source Selection
218      *             0: Primary Display
219      *             1: Secondary Display */
220     ViaCrtcMask(hwp, 0x97, temp << 4, 0x10);
221     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
222                 "LVDS2 Integrated LVDS Transmitter Display Output "
223                 "Source: IGA%d\n",
224                 (temp & 0x01) + 1);
225 
226     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
227                         "Exiting viaLVDS2SetDisplaySource.\n"));
228 }
229 
230 /*
231  * Sets LVDS2 (LVDS Channel 2) integrated LVDS transmitter delay tap.
232  */
233 static void
viaLVDS2SetDelayTap(ScrnInfoPtr pScrn,CARD8 delayTap)234 viaLVDS2SetDelayTap(ScrnInfoPtr pScrn, CARD8 delayTap)
235 {
236     vgaHWPtr hwp = VGAHWPTR(pScrn);
237 
238     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
239                         "Entered viaLVDS2SetDelayTap.\n"));
240 
241     /* Set LVDS2 delay tap. */
242     /* 3X5.97[3:0] - LVDS2 Delay Tap */
243     ViaCrtcMask(hwp, 0x97, delayTap, 0x0F);
244 
245     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
246                 "LVDS2 Delay Tap: %d\n",
247                 (delayTap & 0x0F));
248 
249     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
250                         "Exiting viaLVDS2SetDelayTap.\n"));
251 }
252 
253 /*
254  * Sets LVDS2 (LVDS Channel 2) integrated LVDS transmitter format.
255  */
256 static void
viaLVDS2SetFormat(ScrnInfoPtr pScrn,CARD8 format)257 viaLVDS2SetFormat(ScrnInfoPtr pScrn, CARD8 format)
258 {
259     vgaHWPtr hwp = VGAHWPTR(pScrn);
260 
261     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
262                         "Entered viaLVDS2SetFormat.\n"));
263 
264     /* Set LVDS2 format. */
265     /* 3X5.D2[0] - LVDS Channel 2 Format Selection
266      *             0: SPWG Mode
267      *             1: OPENLDI Mode */
268     ViaCrtcMask(hwp, 0xD2, format, 0x01);
269     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
270                 "LVDS2 Format: %s\n",
271                 (format & 0x01) ? "OPENLDI" : "SPWG");
272 
273     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
274                         "Exiting viaLVDS2SetFormat.\n"));
275 }
276 
277 /*
278  * Sets IGA1 or IGA2 as the display output source for VIA Technologies
279  * Chrome IGP DFP (Digital Flat Panel) High interface.
280  */
281 static void
viaDFPHighSetDisplaySource(ScrnInfoPtr pScrn,CARD8 displaySource)282 viaDFPHighSetDisplaySource(ScrnInfoPtr pScrn, CARD8 displaySource)
283 {
284     vgaHWPtr hwp = VGAHWPTR(pScrn);
285     CARD8 temp = displaySource;
286 
287     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
288                         "Entered viaDFPHighSetDisplaySource.\n"));
289 
290     /* Set DFP High display output source. */
291     /* 3X5.97[4] - DFP High Data Source Selection
292      *             0: Primary Display
293      *             1: Secondary Display */
294     ViaCrtcMask(hwp, 0x97, temp << 4, 0x10);
295     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
296                 "DFP High Display Output Source: IGA%d\n",
297                 (temp & 0x01) + 1);
298 
299     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
300                         "Exiting viaDFPHighSetDisplaySource.\n"));
301 }
302 
303 /*
304  * Sets DFP (Digital Flat Panel) Low interface delay tap.
305  */
306 static void
viaDFPLowSetDelayTap(ScrnInfoPtr pScrn,CARD8 delayTap)307 viaDFPLowSetDelayTap(ScrnInfoPtr pScrn, CARD8 delayTap)
308 {
309     vgaHWPtr hwp = VGAHWPTR(pScrn);
310 
311     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
312                         "Entered viaDFPLowSetDelayTap.\n"));
313 
314     /* Set DFP Low interface delay tap. */
315     /* 3X5.99[3:0] - DFP Low Delay Tap */
316     ViaCrtcMask(hwp, 0x99, delayTap, 0x0F);
317     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
318                 "DFP Low Delay Tap: %d\n",
319                 (delayTap & 0x0F));
320 
321     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
322                         "Exiting viaDFPLowSetDelayTap.\n"));
323 }
324 
325 /*
326  * Sets DFP (Digital Flat Panel) High interface delay tap.
327  */
328 static void
viaDFPHighSetDelayTap(ScrnInfoPtr pScrn,CARD8 delayTap)329 viaDFPHighSetDelayTap(ScrnInfoPtr pScrn, CARD8 delayTap)
330 {
331     vgaHWPtr hwp = VGAHWPTR(pScrn);
332 
333     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
334                         "Entered viaDFPHighSetDelayTap.\n"));
335 
336     /* Set DFP High interface delay tap. */
337     /* 3X5.97[3:0] - DFP High Delay Tap */
338     ViaCrtcMask(hwp, 0x97, delayTap, 0x0F);
339     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
340                 "DFP High Delay Tap: %d\n",
341                 (delayTap & 0x0F));
342 
343     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
344                         "Exiting viaDFPHighSetDelayTap.\n"));
345 }
346 
347 /*
348  * Turns LVDS2 output color dithering on or off. (18-bit color display vs.
349  * 24-bit color display)
350  */
351 static void
viaLVDS2SetDithering(ScrnInfoPtr pScrn,CARD8 ditheringStatus)352 viaLVDS2SetDithering(ScrnInfoPtr pScrn, CARD8 ditheringStatus)
353 {
354     vgaHWPtr hwp = VGAHWPTR(pScrn);
355 
356     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
357                         "Entered viaLVDS2SetDithering.\n"));
358 
359     /* Set LVDS2 output color dithering bit. */
360     /* 3X5.D4[6] - LVDS Channel 2 Output Bits
361      *             0: 24 bits (dithering off)
362      *             1: 18 bits (dithering on) */
363     ViaCrtcMask(hwp, 0xD4, ditheringStatus ? 0x40 : 0x00, 0x40);
364 
365     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
366                 "LVDS2 Output Color Dithering: %s\n",
367                 ditheringStatus ? "On (18 bit)" : "Off (24 bit)");
368 
369     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
370                         "Exiting viaLVDS2SetDithering.\n"));
371 }
372 
373 /*
374  * Sets output format of LVDS2 to rotation or sequential mode.
375  */
376 static void
viaLVDS2SetOutputFormat(ScrnInfoPtr pScrn,CARD8 outputFormat)377 viaLVDS2SetOutputFormat(ScrnInfoPtr pScrn, CARD8 outputFormat)
378 {
379     vgaHWPtr hwp = VGAHWPTR(pScrn);
380 
381     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
382                         "Entered viaLVDS2SetOutputFormat.\n"));
383 
384     /* Set LVDS2 output format. */
385     /* 3X5.D4[7] - LVDS Channel 2 Output Format
386      *             0: Rotation
387      *             1: Sequential */
388     ViaCrtcMask(hwp, 0xD4, outputFormat ? 0x80 : 0x00, 0x80);
389 
390     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
391                 "LVDS2 Output Format: %s\n",
392                 outputFormat ? "Sequential" : "Rotation");
393 
394     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
395                         "Exiting viaLVDS2SetOutputFormat.\n"));
396 }
397 
398 /*
399  * Sets PCIe based 2 chip chipset's pin multiplexed DVP0 I/O pad state.
400  */
401 static void
viaDVP0PCIeSetIOPadSetting(ScrnInfoPtr pScrn,CARD8 ioPadState)402 viaDVP0PCIeSetIOPadSetting(ScrnInfoPtr pScrn, CARD8 ioPadState)
403 {
404     vgaHWPtr hwp = VGAHWPTR(pScrn);
405 
406     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
407                         "Entered viaDVP0PCIeSetIOPadSetting.\n"));
408 
409     /* Set pin multiplexed DVP1 I/O pad state. */
410     /* 3C5.2A[3:2] - DVP0 I/O Pad Control */
411     ViaSeqMask(hwp, 0x2A, ioPadState << 2, 0x0C);
412     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
413                 "DVP0 I/O Pad State: %d\n",
414                 (ioPadState & 0x03));
415 
416     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
417                         "Exiting viaDVP0PCIeSetIOPadSetting.\n"));
418 }
419 
420 /*
421  * Sets PCIe based 2 chip chipset's pin multiplexed DVP1 I/O pad state.
422  */
423 static void
viaDVP1PCIeSetIOPadSetting(ScrnInfoPtr pScrn,CARD8 ioPadState)424 viaDVP1PCIeSetIOPadSetting(ScrnInfoPtr pScrn, CARD8 ioPadState)
425 {
426     vgaHWPtr hwp = VGAHWPTR(pScrn);
427 
428     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
429                         "Entered viaDVP1PCIeSetIOPadSetting.\n"));
430 
431     /* Set pin multiplexed DVP0 I/O pad state. */
432     /* 3C5.2A[1:0] - DVP1 I/O Pad Control */
433     ViaSeqMask(hwp, 0x2A, ioPadState, 0x03);
434     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
435                 "DVP1 I/O Pad State: %d\n",
436                 (ioPadState & 0x03));
437 
438     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
439                         "Exiting viaDVP1PCIeSetIOPadSetting.\n"));
440 }
441 
442 static void
viaFPIOPadSetting(ScrnInfoPtr pScrn,Bool ioPadOn)443 viaFPIOPadSetting(ScrnInfoPtr pScrn, Bool ioPadOn)
444 {
445     vgaHWPtr hwp = VGAHWPTR(pScrn);
446     VIAPtr pVia = VIAPTR(pScrn);
447     CARD8 sr12, sr13, sr5a;
448 
449     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
450                         "Entered viaFPIOPadSetting.\n"));
451 
452     if ((pVia->Chipset == VIA_CX700)
453         || (pVia->Chipset == VIA_VX800)
454         || (pVia->Chipset == VIA_VX855)
455         || (pVia->Chipset == VIA_VX900)) {
456 
457         sr5a = hwp->readSeq(hwp, 0x5A);
458         DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
459                             "SR5A: 0x%02X\n", sr5a));
460         DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
461                             "Setting 3C5.5A[0] to 0.\n"));
462         ViaSeqMask(hwp, 0x5A, sr5a & 0xFE, 0x01);
463     }
464 
465     sr12 = hwp->readSeq(hwp, 0x12);
466     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
467                         "SR12: 0x%02X\n", sr12));
468     sr13 = hwp->readSeq(hwp, 0x13);
469     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
470                         "SR13: 0x%02X\n", sr13));
471 
472     switch (pVia->Chipset) {
473     case VIA_CLE266:
474         break;
475     case VIA_KM400:
476     case VIA_K8M800:
477     case VIA_PM800:
478     case VIA_P4M800PRO:
479         break;
480     case VIA_P4M890:
481     case VIA_K8M890:
482     case VIA_P4M900:
483         /* The tricky thing about VIA Technologies PCI Express based
484          * north bridge / south bridge 2 chip chipset is that
485          * it pin multiplexes DVP0 / DVP1 with north bridge's PCI
486          * Express x16 link. In particular, HP 2133 Mini-Note's WLAN
487          * is connected to north bridge's PCI Express Lane 0, but the
488          * Lane 0 is also pin multiplexed with DVP0. What this means is
489          * turning on DVP0 without probing the relevant strapping pin
490          * to determine the connected panel interface type will lead to
491          * the PCIe based WLAN to getting disabled by OpenChrome DDX
492          * when X.Org Server starts.
493          *     The current remedy for this will be to turn on DVP0
494          * only when an 18-bit / 24-bit interface flat panel is
495          * connected. */
496         /* 3C5.12[4] - DVP0D4 pin strapping
497          *             0: Use DVP1 only for a flat panel.
498          *             1: Use DVP0 and DVP1 for a flat panel */
499         if (sr12 & 0x10) {
500             /* Since an 18-bit / 24-bit flat panel is being used, actively
501              * control DVP0. */
502             viaDVP0PCIeSetIOPadSetting(pScrn, ioPadOn ? 0x03 : 0x00);
503         } else {
504             /* Keep DVP0 powered down. Otherwise, it will interfere with
505              * PCIe Lane 0 through 7. */
506             viaDVP0PCIeSetIOPadSetting(pScrn, 0x00);
507         }
508 
509         /* Control DVP1 for a flat panel. */
510         viaDVP1PCIeSetIOPadSetting(pScrn, ioPadOn ? 0x03 : 0x00);
511         break;
512     case VIA_CX700:
513     case VIA_VX800:
514     case VIA_VX855:
515     case VIA_VX900:
516         /* 3C5.13[7:6] - DVP1D15 and DVP1D14 pin strappings
517          *               00: LVDS1 + LVDS2
518          *               01: DVI + LVDS2
519          *               10: Dual LVDS (LVDS1 + LVDS2 used
520          *                   simultaneously)
521          *               11: DVI only */
522         if ((((~(sr13 & 0x80)) && (~(sr13 & 0x40)))
523              || ((sr13 & 0x80) && (~(sr13 & 0x40))))
524            && (!pVia->isVIANanoBook)) {
525 
526             viaLVDS1SetIOPadSetting(pScrn, ioPadOn ? 0x03 : 0x00);
527         }
528 
529         if (((~(sr13 & 0x80)) || (~(sr13 & 0x40)))
530            || (pVia->isVIANanoBook)) {
531 
532             viaLVDS2SetIOPadSetting(pScrn, ioPadOn ? 0x03 : 0x00);
533         }
534         break;
535     default:
536         break;
537     }
538 
539     if ((pVia->Chipset == VIA_CX700)
540         || (pVia->Chipset == VIA_VX800)
541         || (pVia->Chipset == VIA_VX855)
542         || (pVia->Chipset == VIA_VX900)) {
543 
544         hwp->writeSeq(hwp, 0x5A, sr5a);
545         DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
546                             "Restoring 3C5.5A[0].\n"));
547     }
548 
549     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
550                         "Exiting viaFPIOPadSetting.\n"));
551 }
552 
553 static void
ViaLVDSSoftwarePowerFirstSequence(ScrnInfoPtr pScrn,Bool on)554 ViaLVDSSoftwarePowerFirstSequence(ScrnInfoPtr pScrn, Bool on)
555 {
556     vgaHWPtr hwp = VGAHWPTR(pScrn);
557 
558     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "ViaLVDSSoftwarePowerFirstSequence: %d\n", on));
559     if (on) {
560 
561         /* Software control power sequence ON*/
562         hwp->writeCrtc(hwp, 0x91, hwp->readCrtc(hwp, 0x91) & 0x7F);
563         hwp->writeCrtc(hwp, 0x91, hwp->readCrtc(hwp, 0x91) | 0x01);
564         usleep(TD0);
565 
566         /* VDD ON*/
567         hwp->writeCrtc(hwp, 0x91, hwp->readCrtc(hwp, 0x91) | 0x10);
568         usleep(TD1);
569 
570         /* DATA ON */
571         hwp->writeCrtc(hwp, 0x91, hwp->readCrtc(hwp, 0x91) | 0x08);
572         usleep(TD2);
573 
574         /* VEE ON (unused on vt3353)*/
575         hwp->writeCrtc(hwp, 0x91, hwp->readCrtc(hwp, 0x91) | 0x04);
576         usleep(TD3);
577 
578         /* Back-Light ON */
579         hwp->writeCrtc(hwp, 0x91, hwp->readCrtc(hwp, 0x91) | 0x02);
580     } else {
581         /* Back-Light OFF */
582         hwp->writeCrtc(hwp, 0x91, hwp->readCrtc(hwp, 0x91) & 0xFD);
583         usleep(TD3);
584 
585         /* VEE OFF (unused on vt3353)*/
586         hwp->writeCrtc(hwp, 0x91, hwp->readCrtc(hwp, 0x91) & 0xFB);
587         usleep(TD2);
588 
589         /* DATA OFF */
590         hwp->writeCrtc(hwp, 0x91, hwp->readCrtc(hwp, 0x91) & 0xF7);
591         usleep(TD1);
592 
593         /* VDD OFF */
594         hwp->writeCrtc(hwp, 0x91, hwp->readCrtc(hwp, 0x91) & 0xEF);
595     }
596 }
597 
598 static void
ViaLVDSSoftwarePowerSecondSequence(ScrnInfoPtr pScrn,Bool on)599 ViaLVDSSoftwarePowerSecondSequence(ScrnInfoPtr pScrn, Bool on)
600 {
601     vgaHWPtr hwp = VGAHWPTR(pScrn);
602 
603     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "ViaLVDSSoftwarePowerSecondSequence: %d\n", on));
604     if (on) {
605         /* Secondary power hardware power sequence enable 0:off 1: on */
606         hwp->writeCrtc(hwp, 0xD4, hwp->readCrtc(hwp, 0xD4) & 0xFD);
607 
608         /* Software control power sequence ON */
609         hwp->writeCrtc(hwp, 0xD3, hwp->readCrtc(hwp, 0xD3) | 0x01);
610         usleep(TD0);
611 
612         /* VDD ON*/
613         hwp->writeCrtc(hwp, 0xD3, hwp->readCrtc(hwp, 0xD3) | 0x10);
614         usleep(TD1);
615 
616         /* DATA ON */
617         hwp->writeCrtc(hwp, 0xD3, hwp->readCrtc(hwp, 0xD3) | 0x08);
618         usleep(TD2);
619 
620         /* VEE ON (unused on vt3353)*/
621         hwp->writeCrtc(hwp, 0xD3, hwp->readCrtc(hwp, 0xD3) | 0x04);
622         usleep(TD3);
623 
624         /* Back-Light ON */
625         hwp->writeCrtc(hwp, 0xD3, hwp->readCrtc(hwp, 0xD3) | 0x02);
626     } else {
627         /* Back-Light OFF */
628         hwp->writeCrtc(hwp, 0xD3, hwp->readCrtc(hwp, 0xD3) & 0xFD);
629         usleep(TD3);
630 
631         /* VEE OFF */
632         hwp->writeCrtc(hwp, 0xD3, hwp->readCrtc(hwp, 0xD3) & 0xFB);
633         /* Delay TD2 msec. */
634         usleep(TD2);
635 
636         /* DATA OFF */
637         hwp->writeCrtc(hwp, 0xD3, hwp->readCrtc(hwp, 0xD3) & 0xF7);
638         /* Delay TD1 msec. */
639         usleep(TD1);
640 
641         /* VDD OFF */
642         hwp->writeCrtc(hwp, 0xD3, hwp->readCrtc(hwp, 0xD3) & 0xEF);
643     }
644 }
645 
646 
647 static void
ViaLVDSHardwarePowerFirstSequence(ScrnInfoPtr pScrn,Bool on)648 ViaLVDSHardwarePowerFirstSequence(ScrnInfoPtr pScrn, Bool on)
649 {
650     vgaHWPtr hwp = VGAHWPTR(pScrn);
651 
652     if (on) {
653         /* Use hardware control power sequence. */
654         hwp->writeCrtc(hwp, 0x91, hwp->readCrtc(hwp, 0x91) & 0xFE);
655         /* Turn on back light. */
656         hwp->writeCrtc(hwp, 0x91, hwp->readCrtc(hwp, 0x91) & 0x3F);
657         /* Turn on hardware power sequence. */
658         hwp->writeCrtc(hwp, 0x6A, hwp->readCrtc(hwp, 0x6A) | 0x08);
659     } else {
660         /* Turn off power sequence. */
661         hwp->writeCrtc(hwp, 0x6A, hwp->readCrtc(hwp, 0x6A) & 0xF7);
662         usleep(1);
663         /* Turn off back light. */
664         hwp->writeCrtc(hwp, 0x91, 0xC0);
665     }
666 }
667 
668 static void
ViaLVDSHardwarePowerSecondSequence(ScrnInfoPtr pScrn,Bool on)669 ViaLVDSHardwarePowerSecondSequence(ScrnInfoPtr pScrn, Bool on)
670 {
671     vgaHWPtr hwp = VGAHWPTR(pScrn);
672 
673     if (on) {
674         /* Use hardware control power sequence. */
675         hwp->writeCrtc(hwp, 0xD3, hwp->readCrtc(hwp, 0xD3) & 0xFE);
676         /* Turn on back light. */
677         hwp->writeCrtc(hwp, 0xD3, hwp->readCrtc(hwp, 0xD3) & 0x3F);
678         /* Turn on hardware power sequence. */
679         hwp->writeCrtc(hwp, 0xD4, hwp->readCrtc(hwp, 0xD4) | 0x02);
680     } else {
681         /* Turn off power sequence. */
682         hwp->writeCrtc(hwp, 0xD4, hwp->readCrtc(hwp, 0xD4) & 0xFD);
683         usleep(1);
684         /* Turn off back light. */
685         hwp->writeCrtc(hwp, 0xD3, 0xC0);
686     }
687 }
688 
689 static void
ViaLVDSPowerChannel(ScrnInfoPtr pScrn,Bool on)690 ViaLVDSPowerChannel(ScrnInfoPtr pScrn, Bool on)
691 {
692     vgaHWPtr hwp = VGAHWPTR(pScrn);
693     CARD8 lvdsMask;
694 
695     if (on) {
696         /* LVDS0: 0x7F, LVDS1: 0xBF */
697         lvdsMask = 0x7F & 0xBF;
698         hwp->writeCrtc(hwp, 0xD2, hwp->readCrtc(hwp, 0xD2) & lvdsMask);
699     } else {
700         /* LVDS0: 0x80, LVDS1: 0x40 */
701         lvdsMask = 0x80 | 0x40;
702         hwp->writeCrtc(hwp, 0xD2, hwp->readCrtc(hwp, 0xD2) | lvdsMask);
703     }
704 }
705 
706 static void
ViaLVDSPower(ScrnInfoPtr pScrn,Bool Power_On)707 ViaLVDSPower(ScrnInfoPtr pScrn, Bool Power_On)
708 {
709     vgaHWPtr hwp = VGAHWPTR(pScrn);
710     VIAPtr pVia = VIAPTR(pScrn);
711     CARD8 crd2;
712 
713     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
714                         "Entered ViaLVDSPower.\n"));
715 
716     /*
717      * VX800, CX700 have HW issue, so we'd better use SW power sequence
718      * Fix Ticket #308
719      */
720     switch (pVia->Chipset) {
721     case VIA_CX700:
722     case VIA_VX800:
723 
724         /* Is the integrated TMDS transmitter (DVI) not in use? */
725         crd2 = hwp->readCrtc(hwp, 0xD2);
726         if (((pVia->Chipset == VIA_CX700)
727                 || (pVia->Chipset == VIA_VX800)
728                 || (pVia->Chipset == VIA_VX855)
729                 || (pVia->Chipset == VIA_VX900))
730             && (!(crd2 & 0x10))) {
731             ViaLVDSSoftwarePowerFirstSequence(pScrn, Power_On);
732         }
733 
734         ViaLVDSSoftwarePowerSecondSequence(pScrn, Power_On);
735         break;
736 
737     case VIA_VX855:
738     case VIA_VX900:
739         /* Is the integrated TMDS transmitter (DVI) not in use? */
740         crd2 = hwp->readCrtc(hwp, 0xD2);
741         if (((pVia->Chipset == VIA_CX700)
742                 || (pVia->Chipset == VIA_VX800)
743                 || (pVia->Chipset == VIA_VX855)
744                 || (pVia->Chipset == VIA_VX900))
745             && (!(crd2 & 0x10))) {
746             ViaLVDSHardwarePowerFirstSequence(pScrn, Power_On);
747         }
748 
749         ViaLVDSHardwarePowerSecondSequence(pScrn, Power_On);
750         break;
751     default:
752         ViaLVDSHardwarePowerFirstSequence(pScrn, Power_On);
753         ViaLVDSHardwarePowerSecondSequence(pScrn, Power_On);
754         break;
755     }
756 
757     ViaLVDSPowerChannel(pScrn, Power_On);
758 
759     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
760                 "Integrated LVDS Flat Panel Power: %s\n",
761                 Power_On ? "On" : "Off");
762 
763     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
764                         "Exiting ViaLVDSPower.\n"));
765 }
766 
767 static void
ViaLCDPowerSequence(vgaHWPtr hwp,VIALCDPowerSeqRec Sequence)768 ViaLCDPowerSequence(vgaHWPtr hwp, VIALCDPowerSeqRec Sequence)
769 {
770     int i;
771 
772     for (i = 0; i < Sequence.numEntry; i++) {
773         ViaVgahwMask(hwp, 0x300 + Sequence.port[i], Sequence.offset[i],
774                      0x301 + Sequence.port[i], Sequence.data[i],
775                      Sequence.mask[i]);
776         usleep(Sequence.delay[i]);
777     }
778 }
779 
780 static void
ViaLCDPower(xf86OutputPtr output,Bool Power_On)781 ViaLCDPower(xf86OutputPtr output, Bool Power_On)
782 {
783     ViaPanelInfoPtr Panel = output->driver_private;
784     ScrnInfoPtr pScrn = output->scrn;
785     vgaHWPtr hwp = VGAHWPTR(pScrn);
786     VIAPtr pVia = VIAPTR(pScrn);
787     VIABIOSInfoPtr pBIOSInfo = pVia->pBIOSInfo;
788     int i;
789 
790     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
791                         "Entered ViaLCDPower.\n"));
792 
793     /* Enable LCD */
794     if (Power_On)
795         ViaCrtcMask(hwp, 0x6A, 0x08, 0x08);
796     else
797         ViaCrtcMask(hwp, 0x6A, 0x00, 0x08);
798 
799     if (pBIOSInfo->LCDPower)
800         pBIOSInfo->LCDPower(pScrn, Power_On);
801 
802     /* Find Panel Size Index for PowerSeq Table */
803     if (pVia->Chipset == VIA_CLE266) {
804         if (Panel->NativeModeIndex != VIA_PANEL_INVALID) {
805             for (i = 0; i < NumPowerOn; i++) {
806                 if (lcdTable[Panel->PanelIndex].powerSeq
807                     == powerOn[i].powerSeq)
808                     break;
809             }
810         } else
811             i = 0;
812     } else
813         /* KM and K8M use PowerSeq Table index 2. */
814         i = 2;
815 
816     usleep(1);
817     if (Power_On)
818         ViaLCDPowerSequence(hwp, powerOn[i]);
819     else
820         ViaLCDPowerSequence(hwp, powerOff[i]);
821     usleep(1);
822 
823     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
824                 "Integrated LVDS Flat Panel Power: %s\n",
825                 Power_On ? "On" : "Off");
826 
827     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
828                         "Exiting ViaLCDPower.\n"));
829 }
830 
831 /*
832  * Try to interpret EDID ourselves.
833  */
834 static Bool
ViaPanelGetSizeFromEDID(ScrnInfoPtr pScrn,xf86MonPtr pMon,int * width,int * height)835 ViaPanelGetSizeFromEDID(ScrnInfoPtr pScrn, xf86MonPtr pMon,
836                         int *width, int *height)
837 {
838     int i, max_hsize = 0, vsize = 0;
839 
840     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VIAGetPanelSizeFromEDID\n"));
841 
842     /* !!! Why are we not checking VESA modes? */
843 
844     /* checking standard timings */
845     for (i = 0; i < STD_TIMINGS; i++)
846         if ((pMon->timings2[i].hsize > 256)
847             && (pMon->timings2[i].hsize > max_hsize)) {
848             max_hsize = pMon->timings2[i].hsize;
849             vsize = pMon->timings2[i].vsize;
850         }
851 
852     if (max_hsize != 0) {
853         *width = max_hsize;
854         *height = vsize;
855         return TRUE;
856     }
857 
858     /* checking detailed monitor section */
859 
860     /* !!! skip Ranges and standard timings */
861 
862     /* check detailed timings */
863     for (i = 0; i < DET_TIMINGS; i++)
864         if (pMon->det_mon[i].type == DT) {
865             struct detailed_timings timing = pMon->det_mon[i].section.d_timings;
866 
867             /* ignore v_active for now */
868             if ((timing.clock > 15000000) && (timing.h_active > max_hsize)) {
869                 max_hsize = timing.h_active;
870                 vsize = timing.v_active;
871             }
872         }
873 
874     if (max_hsize != 0) {
875         *width = max_hsize;
876         *height = vsize;
877         return TRUE;
878     }
879     return FALSE;
880 }
881 
882 static Bool
ViaPanelGetSizeFromDDCv1(xf86OutputPtr output,int * width,int * height)883 ViaPanelGetSizeFromDDCv1(xf86OutputPtr output, int *width, int *height)
884 {
885     ScrnInfoPtr pScrn = output->scrn;
886     VIAPtr pVia = VIAPTR(pScrn);
887     xf86MonPtr pMon;
888 
889     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
890                         "Entered VIAGetPanelSizeFromDDCv1.\n"));
891 
892     if (!pVia->pI2CBus2) {
893         xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
894                     "I2C Bus 2 does not exist.\n");
895         DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
896                             "Exiting VIAGetPanelSizeFromDDCv1.\n"));
897         return FALSE;
898     }
899 
900     if (!xf86I2CProbeAddress(pVia->pI2CBus2, 0xA0)) {
901         xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
902                     "I2C device on I2C Bus 2 does not support EDID.\n");
903         DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
904                             "Exiting VIAGetPanelSizeFromDDCv1.\n"));
905         return FALSE;
906     }
907 
908     /* Probe I2C Bus 2 to see if a flat panel is connected. */
909     xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
910                 "Probing for a flat panel on I2C Bus 2.\n");
911     pMon = xf86OutputGetEDID(output, pVia->pI2CBus2);
912     if (pMon && DIGITAL(pMon->features.input_type)) {
913         xf86OutputSetEDID(output, pMon);
914         xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
915                     "Detected a flat panel on I2C Bus 2.\n");
916     } else {
917         xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
918                     "Did not detect a flat panel on I2C Bus 2.\n");
919         DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
920                             "Exiting VIAGetPanelSizeFromDDCv1.\n"));
921         return FALSE;
922 
923     }
924 
925     if (!ViaPanelGetSizeFromEDID(pScrn, pMon, width, height)) {
926         xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
927                     "Unable to obtain panel size from EDID information.\n");
928         DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
929                             "Exiting VIAGetPanelSizeFromDDCv1.\n"));
930         return FALSE;
931     }
932 
933     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
934                         "VIAGetPanelSizeFromDDCv1: (%d X %d)\n",
935                         *width, *height));
936     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
937                         "Exiting VIAGetPanelSizeFromDDCv1.\n"));
938     return TRUE;
939 }
940 
941 /*
942  * Gets the native panel resolution from scratch pad registers.
943  */
944 static void
viaLVDSGetFPInfoFromScratchPad(xf86OutputPtr output)945 viaLVDSGetFPInfoFromScratchPad(xf86OutputPtr output)
946 {
947     ScrnInfoPtr pScrn = output->scrn;
948     vgaHWPtr hwp = VGAHWPTR(pScrn);
949     ViaPanelInfoPtr panel = output->driver_private;
950     CARD8 index;
951 
952     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
953                      "Entered viaLVDSGetFPInfoFromScratchPad.\n"));
954 
955     index = hwp->readCrtc(hwp, 0x3F) & 0x0F;
956 
957     panel->NativeModeIndex = index;
958     panel->NativeWidth = ViaPanelNativeModes[index].Width;
959     panel->NativeHeight = ViaPanelNativeModes[index].Height;
960     panel->useDualEdge = ViaPanelNativeModes[index].useDualEdge;
961     panel->useDithering = ViaPanelNativeModes[index].useDithering;
962 
963     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
964                "VIA Technologies VGA BIOS Scratch Pad Register "
965                "Flat Panel Index: %d\n",
966                panel->NativeModeIndex);
967     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
968                "Flat Panel Native Resolution: %dx%d\n",
969                panel->NativeWidth, panel->NativeHeight);
970     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
971                "Flat Panel Dual Edge Transfer: %s\n",
972                panel->useDualEdge ? "On" : "Off");
973     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
974                "Flat Panel Output Color Dithering: %s\n",
975                panel->useDithering ? "On (18 bit)" : "Off (24 bit)");
976 
977     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
978                      "Exiting viaLVDSGetFPInfoFromScratchPad.\n"));
979 }
980 
981 static void
ViaPanelCenterMode(DisplayModePtr mode,DisplayModePtr adjusted_mode)982 ViaPanelCenterMode(DisplayModePtr mode, DisplayModePtr adjusted_mode)
983 {
984     int panelHSyncTime = adjusted_mode->HSyncEnd - adjusted_mode->HSyncStart;
985     int panelVSyncTime = adjusted_mode->VSyncEnd - adjusted_mode->VSyncStart;
986     int panelHBlankStart = adjusted_mode->HDisplay;
987     int panelVBlankStart = adjusted_mode->VDisplay;
988     int hBorder = (adjusted_mode->HDisplay - mode->HDisplay)/2;
989     int vBorder = (adjusted_mode->VDisplay - mode->VDisplay)/2;
990     int newHBlankStart = hBorder + mode->HDisplay;
991     int newVBlankStart = vBorder + mode->VDisplay;
992 
993     adjusted_mode->HDisplay = mode->HDisplay;
994     adjusted_mode->HSyncStart = (adjusted_mode->HSyncStart - panelHBlankStart) + newHBlankStart;
995     adjusted_mode->HSyncEnd = adjusted_mode->HSyncStart + panelHSyncTime;
996     adjusted_mode->VDisplay = mode->VDisplay;
997     adjusted_mode->VSyncStart = (adjusted_mode->VSyncStart - panelVBlankStart) + newVBlankStart;
998     adjusted_mode->VSyncEnd = adjusted_mode->VSyncStart + panelVSyncTime;
999     /* Adjust Crtc H and V */
1000     adjusted_mode->CrtcHDisplay = adjusted_mode->HDisplay;
1001     adjusted_mode->CrtcHBlankStart = newHBlankStart;
1002     adjusted_mode->CrtcHBlankEnd = adjusted_mode->CrtcHTotal - hBorder;
1003     adjusted_mode->CrtcHSyncStart = adjusted_mode->HSyncStart;
1004     adjusted_mode->CrtcHSyncEnd = adjusted_mode->HSyncEnd;
1005     adjusted_mode->CrtcVDisplay = adjusted_mode->VDisplay;
1006     adjusted_mode->CrtcVBlankStart = newVBlankStart;
1007     adjusted_mode->CrtcVBlankEnd = adjusted_mode->CrtcVTotal - vBorder;
1008     adjusted_mode->CrtcVSyncStart = adjusted_mode->VSyncStart;
1009     adjusted_mode->CrtcVSyncEnd = adjusted_mode->VSyncEnd;
1010 }
1011 
1012 static void
ViaPanelScale(ScrnInfoPtr pScrn,int resWidth,int resHeight,int panelWidth,int panelHeight)1013 ViaPanelScale(ScrnInfoPtr pScrn, int resWidth, int resHeight,
1014               int panelWidth, int panelHeight)
1015 {
1016     VIAPtr pVia = VIAPTR(pScrn);
1017     vgaHWPtr hwp = VGAHWPTR(pScrn);
1018     int horScalingFactor = 0;
1019     int verScalingFactor = 0;
1020     CARD8 cra2 = 0;
1021     CARD8 cr77 = 0;
1022     CARD8 cr78 = 0;
1023     CARD8 cr79 = 0;
1024     CARD8 cr9f = 0;
1025     Bool scaling = FALSE;
1026 
1027     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1028                     "ViaPanelScale: %d,%d -> %d,%d\n",
1029                     resWidth, resHeight, panelWidth, panelHeight));
1030 
1031     if (resWidth < panelWidth) {
1032         /* Load Horizontal Scaling Factor */
1033         if (pVia->Chipset != VIA_CLE266 && pVia->Chipset != VIA_KM400) {
1034             horScalingFactor = ((resWidth - 1) * 4096) / (panelWidth - 1);
1035 
1036             /* Horizontal scaling enabled */
1037             cra2 = 0xC0;
1038             cr9f = horScalingFactor & 0x0003;   /* HSCaleFactor[1:0] at CR9F[1:0] */
1039         } else {
1040             /* TODO: Need testing */
1041             horScalingFactor = ((resWidth - 1) * 1024) / (panelWidth - 1);
1042         }
1043 
1044         cr77 = (horScalingFactor & 0x03FC) >> 2;   /* HSCaleFactor[9:2] at CR77[7:0] */
1045         cr79 = (horScalingFactor & 0x0C00) >> 10;  /* HSCaleFactor[11:10] at CR79[5:4] */
1046         cr79 <<= 4;
1047         scaling = TRUE;
1048     }
1049 
1050     if (resHeight < panelHeight) {
1051         /* Load Vertical Scaling Factor */
1052         if (pVia->Chipset != VIA_CLE266 && pVia->Chipset != VIA_KM400) {
1053             verScalingFactor = ((resHeight - 1) * 2048) / (panelHeight - 1);
1054 
1055             /* Vertical scaling enabled */
1056             cra2 |= 0x08;
1057             cr79 |= ((verScalingFactor & 0x0001) << 3); /* VSCaleFactor[0] at CR79[3] */
1058         } else {
1059             /* TODO: Need testing */
1060             verScalingFactor = ((resHeight - 1) * 1024) / (panelHeight - 1);
1061         }
1062 
1063         cr78 |= (verScalingFactor & 0x01FE) >> 1;           /* VSCaleFactor[8:1] at CR78[7:0] */
1064 
1065         cr79 |= ((verScalingFactor & 0x0600) >> 9) << 6;    /* VSCaleFactor[10:9] at CR79[7:6] */
1066         scaling = TRUE;
1067     }
1068 
1069     if (scaling) {
1070         DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1071                 "Scaling factor: horizontal %d (0x%x), vertical %d (0x%x)\n",
1072         horScalingFactor, horScalingFactor,
1073         verScalingFactor, verScalingFactor));
1074 
1075         ViaCrtcMask(hwp, 0x77, cr77, 0xFF);
1076         ViaCrtcMask(hwp, 0x78, cr78, 0xFF);
1077         ViaCrtcMask(hwp, 0x79, cr79, 0xF8);
1078 
1079         if (pVia->Chipset != VIA_CLE266 && pVia->Chipset != VIA_KM400) {
1080             ViaCrtcMask(hwp, 0x9F, cr9f, 0x03);
1081         }
1082         ViaCrtcMask(hwp, 0x79, 0x03, 0x03);
1083     } else {
1084         /*  Disable panel scale */
1085         ViaCrtcMask(hwp, 0x79, 0x00, 0x01);
1086     }
1087 
1088     if (pVia->Chipset != VIA_CLE266 && pVia->Chipset != VIA_KM400) {
1089         ViaCrtcMask(hwp, 0xA2, cra2, 0xC8);
1090     }
1091 
1092     /* Horizontal scaling selection: interpolation */
1093     // ViaCrtcMask(hwp, 0x79, 0x02, 0x02);
1094     // else
1095     // ViaCrtcMask(hwp, 0x79, 0x00, 0x02);
1096     /* Horizontal scaling factor selection original / linear */
1097     //ViaCrtcMask(hwp, 0xA2, 0x40, 0x40);
1098 }
1099 
1100 static void
ViaPanelScaleDisable(ScrnInfoPtr pScrn)1101 ViaPanelScaleDisable(ScrnInfoPtr pScrn)
1102 {
1103     VIAPtr pVia = VIAPTR(pScrn);
1104     vgaHWPtr hwp = VGAHWPTR(pScrn);
1105 
1106     ViaCrtcMask(hwp, 0x79, 0x00, 0x01);
1107     /* Disable VX900 down scaling */
1108     if (pVia->Chipset == VIA_VX900)
1109         ViaCrtcMask(hwp, 0x89, 0x00, 0x01);
1110     if (pVia->Chipset != VIA_CLE266 && pVia->Chipset != VIA_KM400)
1111         ViaCrtcMask(hwp, 0xA2, 0x00, 0xC8);
1112 }
1113 
1114 static void
via_lvds_create_resources(xf86OutputPtr output)1115 via_lvds_create_resources(xf86OutputPtr output)
1116 {
1117 }
1118 
1119 static void
via_lvds_dpms(xf86OutputPtr output,int mode)1120 via_lvds_dpms(xf86OutputPtr output, int mode)
1121 {
1122     ScrnInfoPtr pScrn = output->scrn;
1123     VIAPtr pVia = VIAPTR(pScrn);
1124 
1125     switch (mode) {
1126     case DPMSModeOn:
1127         switch (pVia->Chipset) {
1128         case VIA_PM800:
1129         case VIA_P4M800PRO:
1130         case VIA_P4M890:
1131         case VIA_K8M890:
1132         case VIA_P4M900:
1133         case VIA_CX700:
1134         case VIA_VX800:
1135         case VIA_VX855:
1136         case VIA_VX900:
1137             ViaLVDSPower(pScrn, TRUE);
1138             break;
1139         default:
1140             ViaLCDPower(output, TRUE);
1141             break;
1142         }
1143 
1144         viaFPIOPadSetting(pScrn, TRUE);
1145         break;
1146 
1147     case DPMSModeStandby:
1148     case DPMSModeSuspend:
1149     case DPMSModeOff:
1150         switch (pVia->Chipset) {
1151         case VIA_PM800:
1152         case VIA_P4M800PRO:
1153         case VIA_P4M890:
1154         case VIA_K8M890:
1155         case VIA_P4M900:
1156         case VIA_CX700:
1157         case VIA_VX800:
1158         case VIA_VX855:
1159         case VIA_VX900:
1160             ViaLVDSPower(pScrn, FALSE);
1161             break;
1162         default:
1163             ViaLCDPower(output, FALSE);
1164             break;
1165         }
1166 
1167         viaFPIOPadSetting(pScrn, FALSE);
1168         break;
1169     }
1170 }
1171 
1172 static void
via_lvds_save(xf86OutputPtr output)1173 via_lvds_save(xf86OutputPtr output)
1174 {
1175 }
1176 
1177 static void
via_lvds_restore(xf86OutputPtr output)1178 via_lvds_restore(xf86OutputPtr output)
1179 {
1180     ViaLCDPower(output, TRUE);
1181 }
1182 
1183 static int
via_lvds_mode_valid(xf86OutputPtr output,DisplayModePtr pMode)1184 via_lvds_mode_valid(xf86OutputPtr output, DisplayModePtr pMode)
1185 {
1186     ScrnInfoPtr pScrn = output->scrn;
1187     ViaPanelInfoPtr Panel = output->driver_private;
1188 
1189     if (Panel->NativeWidth < pMode->HDisplay ||
1190         Panel->NativeHeight < pMode->VDisplay)
1191         return MODE_PANEL;
1192 
1193     if (!Panel->Scale && Panel->NativeHeight != pMode->VDisplay &&
1194          Panel->NativeWidth != pMode->HDisplay)
1195         return MODE_PANEL;
1196 
1197     if (!ViaModeDotClockTranslate(pScrn, pMode))
1198         return MODE_NOCLOCK;
1199 
1200     return MODE_OK;
1201 }
1202 
1203 static Bool
via_lvds_mode_fixup(xf86OutputPtr output,DisplayModePtr mode,DisplayModePtr adjusted_mode)1204 via_lvds_mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
1205                     DisplayModePtr adjusted_mode)
1206 {
1207     ViaPanelInfoPtr Panel = output->driver_private;
1208 
1209     xf86SetModeCrtc(adjusted_mode, 0);
1210     if (!Panel->Center && (mode->HDisplay < Panel->NativeWidth ||
1211         mode->VDisplay < Panel->NativeHeight)) {
1212         Panel->Scale = TRUE;
1213     } else {
1214         Panel->Scale = FALSE;
1215         ViaPanelCenterMode(mode, adjusted_mode);
1216     }
1217     return TRUE;
1218 }
1219 
1220 static void
via_lvds_prepare(xf86OutputPtr output)1221 via_lvds_prepare(xf86OutputPtr output)
1222 {
1223     ScrnInfoPtr pScrn = output->scrn;
1224 
1225     via_lvds_dpms(output, DPMSModeOff);
1226     viaFPIOPadSetting(pScrn, FALSE);
1227 }
1228 
1229 static void
via_lvds_commit(xf86OutputPtr output)1230 via_lvds_commit(xf86OutputPtr output)
1231 {
1232     ScrnInfoPtr pScrn = output->scrn;
1233 
1234     via_lvds_dpms(output, DPMSModeOn);
1235     viaFPIOPadSetting(pScrn, TRUE);
1236 }
1237 
1238 static void
via_lvds_mode_set(xf86OutputPtr output,DisplayModePtr mode,DisplayModePtr adjusted_mode)1239 via_lvds_mode_set(xf86OutputPtr output, DisplayModePtr mode,
1240                     DisplayModePtr adjusted_mode)
1241 {
1242     ViaPanelInfoPtr Panel = output->driver_private;
1243     ScrnInfoPtr pScrn = output->scrn;
1244     drmmode_crtc_private_ptr iga = output->crtc->driver_private;
1245     VIAPtr pVia = VIAPTR(pScrn);
1246 
1247     if (output->crtc) {
1248         if (Panel->Scale) {
1249             ViaPanelScale(pScrn, mode->HDisplay, mode->VDisplay,
1250                             Panel->NativeWidth,
1251                             Panel->NativeHeight);
1252         } else {
1253             ViaPanelScaleDisable(pScrn);
1254         }
1255 
1256         switch (pVia->Chipset) {
1257         case VIA_P4M900:
1258             viaDFPLowSetDelayTap(pScrn, 0x08);
1259             break;
1260         case VIA_CX700:
1261             viaLVDS2SetDelayTap(pScrn, 0x01);
1262             break;
1263         default:
1264             break;
1265         }
1266 
1267 
1268         switch (pVia->Chipset) {
1269         case VIA_KM400:
1270         case VIA_K8M800:
1271         case VIA_PM800:
1272         case VIA_P4M800PRO:
1273             viaDFPLowSetDisplaySource(pScrn, iga->index ? 0x01 : 0x00);
1274             viaDFPHighSetDisplaySource(pScrn, iga->index ? 0x01 : 0x00);
1275             break;
1276         case VIA_P4M890:
1277         case VIA_K8M890:
1278         case VIA_P4M900:
1279             viaDFPLowSetDisplaySource(pScrn, iga->index ? 0x01 : 0x00);
1280             viaDVP1SetDisplaySource(pScrn, iga->index ? 0x01 : 0x00);
1281             break;
1282         case VIA_CX700:
1283         case VIA_VX800:
1284         case VIA_VX855:
1285         case VIA_VX900:
1286             viaLVDS2SetDisplaySource(pScrn, iga->index ? 0x01 : 0x00);
1287 
1288             /* Set LVDS2 output color dithering. */
1289             viaLVDS2SetDithering(pScrn, Panel->useDithering ? TRUE : FALSE);
1290 
1291             /* Set LVDS2 output format to sequential mode. */
1292             viaLVDS2SetOutputFormat(pScrn, 0x01);
1293 
1294             /* Set LVDS2 output to OPENLDI mode. */
1295             viaLVDS2SetFormat(pScrn, 0x01);
1296             break;
1297         default:
1298             break;
1299         }
1300     }
1301 }
1302 
1303 static xf86OutputStatus
via_lvds_detect(xf86OutputPtr output)1304 via_lvds_detect(xf86OutputPtr output)
1305 {
1306     xf86OutputStatus status = XF86OutputStatusDisconnected;
1307     ScrnInfoPtr pScrn = output->scrn;
1308     VIAPtr pVia = VIAPTR(pScrn);
1309     ViaPanelInfoPtr panel = output->driver_private;
1310 
1311     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1312                         "Entered via_lvds_detect.\n"));
1313 
1314     /* Hardcode panel size for the OLPC XO-1.5. */
1315     if (pVia->IsOLPCXO15) {
1316         xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1317                     "Setting up OLPC XO-1.5 flat panel.\n");
1318         panel->NativeWidth = 1200;
1319         panel->NativeHeight = 900;
1320         status = XF86OutputStatusConnected;
1321         goto exit;
1322     }
1323 
1324     /* For now, FP detection code will not scan the I2C bus
1325      * in order to obtain EDID since it is often used by DVI
1326      * as well. Hence, reading off the CRTC scratch pad register
1327      * supplied by the VGA BIOS is the only method available
1328      * to figure out the FP native screen resolution. */
1329     viaLVDSGetFPInfoFromScratchPad(output);
1330     status = XF86OutputStatusConnected;
1331 
1332 exit:
1333     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1334                         "Exiting via_lvds_detect.\n"));
1335     return status;
1336 }
1337 
1338 static DisplayModePtr
via_lvds_get_modes(xf86OutputPtr output)1339 via_lvds_get_modes(xf86OutputPtr output)
1340 {
1341     ViaPanelInfoPtr pPanel = output->driver_private;
1342     ScrnInfoPtr pScrn = output->scrn;
1343     DisplayModePtr pDisplay_Mode = NULL;
1344 
1345     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1346                         "Entered via_lvds_get_modes.\n"));
1347 
1348     if (output->status == XF86OutputStatusConnected) {
1349         if (!output->MonInfo) {
1350             /*
1351              * Generates a display mode for the native panel resolution,
1352              * using CVT.
1353              */
1354             if (pPanel->NativeWidth && pPanel->NativeHeight) {
1355                 VIAPtr pVia = VIAPTR(pScrn);
1356 
1357                 if (pVia->IsOLPCXO15) {
1358                     pDisplay_Mode = xf86DuplicateMode(&OLPCMode);
1359                 } else {
1360                     pDisplay_Mode = xf86CVTMode(pPanel->NativeWidth, pPanel->NativeHeight,
1361                                     60.0f, FALSE, FALSE);
1362                 }
1363 
1364                 if (pDisplay_Mode) {
1365                     pDisplay_Mode->CrtcHDisplay = pDisplay_Mode->HDisplay;
1366                     pDisplay_Mode->CrtcHSyncStart = pDisplay_Mode->HSyncStart;
1367                     pDisplay_Mode->CrtcHSyncEnd = pDisplay_Mode->HSyncEnd;
1368                     pDisplay_Mode->CrtcHTotal = pDisplay_Mode->HTotal;
1369                     pDisplay_Mode->CrtcHSkew = pDisplay_Mode->HSkew;
1370                     pDisplay_Mode->CrtcVDisplay = pDisplay_Mode->VDisplay;
1371                     pDisplay_Mode->CrtcVSyncStart = pDisplay_Mode->VSyncStart;
1372                     pDisplay_Mode->CrtcVSyncEnd = pDisplay_Mode->VSyncEnd;
1373                     pDisplay_Mode->CrtcVTotal = pDisplay_Mode->VTotal;
1374 
1375                     pDisplay_Mode->CrtcVBlankStart = min(pDisplay_Mode->CrtcVSyncStart, pDisplay_Mode->CrtcVDisplay);
1376                     pDisplay_Mode->CrtcVBlankEnd = max(pDisplay_Mode->CrtcVSyncEnd, pDisplay_Mode->CrtcVTotal);
1377                     pDisplay_Mode->CrtcHBlankStart = min(pDisplay_Mode->CrtcHSyncStart, pDisplay_Mode->CrtcHDisplay);
1378                     pDisplay_Mode->CrtcHBlankEnd = max(pDisplay_Mode->CrtcHSyncEnd, pDisplay_Mode->CrtcHTotal);
1379                     pDisplay_Mode->type = M_T_DRIVER | M_T_PREFERRED;
1380                 } else {
1381                     xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1382                                 "Out of memory. Size: %zu bytes\n", sizeof(DisplayModeRec));
1383                 }
1384             } else {
1385                 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1386                             "Invalid Flat Panel Screen Resolution: "
1387                             "%dx%d\n",
1388                             pPanel->NativeWidth, pPanel->NativeHeight);
1389             }
1390         } else {
1391             pDisplay_Mode = xf86OutputGetEDIDModes(output);
1392         }
1393     }
1394     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1395                         "Exiting via_lvds_get_modes.\n"));
1396     return pDisplay_Mode;
1397 }
1398 
1399 #ifdef RANDR_12_INTERFACE
1400 static Bool
via_lvds_set_property(xf86OutputPtr output,Atom property,RRPropertyValuePtr value)1401 via_lvds_set_property(xf86OutputPtr output, Atom property,
1402                         RRPropertyValuePtr value)
1403 {
1404     return FALSE;
1405 }
1406 
1407 static Bool
via_lvds_get_property(xf86OutputPtr output,Atom property)1408 via_lvds_get_property(xf86OutputPtr output, Atom property)
1409 {
1410     return FALSE;
1411 }
1412 #endif
1413 
1414 static void
via_lvds_destroy(xf86OutputPtr output)1415 via_lvds_destroy(xf86OutputPtr output)
1416 {
1417     if (output->driver_private)
1418         free(output->driver_private);
1419     output->driver_private = NULL;
1420 }
1421 
1422 static const xf86OutputFuncsRec via_lvds_funcs = {
1423     .create_resources   = via_lvds_create_resources,
1424     .dpms               = via_lvds_dpms,
1425     .save               = via_lvds_save,
1426     .restore            = via_lvds_restore,
1427     .mode_valid         = via_lvds_mode_valid,
1428     .mode_fixup         = via_lvds_mode_fixup,
1429     .prepare            = via_lvds_prepare,
1430     .commit             = via_lvds_commit,
1431     .mode_set           = via_lvds_mode_set,
1432     .detect             = via_lvds_detect,
1433     .get_modes          = via_lvds_get_modes,
1434 #ifdef RANDR_12_INTERFACE
1435     .set_property       = via_lvds_set_property,
1436 #endif
1437 #ifdef RANDR_13_INTERFACE
1438     .get_property       = via_lvds_get_property,
1439 #endif
1440     .destroy            = via_lvds_destroy
1441 };
1442 
1443 
1444 void
via_lvds_init(ScrnInfoPtr pScrn)1445 via_lvds_init(ScrnInfoPtr pScrn)
1446 {
1447     ViaPanelInfoPtr Panel = (ViaPanelInfoPtr) xnfcalloc(sizeof(ViaPanelInfoRec), 1);
1448     OptionInfoPtr  Options = xnfalloc(sizeof(ViaPanelOptions));
1449     MessageType from = X_DEFAULT;
1450     VIAPtr pVia = VIAPTR(pScrn);
1451     xf86OutputPtr output = NULL;
1452     vgaHWPtr hwp = VGAHWPTR(pScrn);
1453     CARD8 cr3b = 0x00;
1454     CARD8 cr3b_mask = 0x00;
1455     char outputNameBuffer[32];
1456 
1457     if (!Panel)
1458         return;
1459 
1460     /* Apparently this is the way VIA Technologies passes */
1461     /* the presence of a flat panel to the device driver */
1462     /* via BIOS setup. */
1463     if (pVia->Chipset == VIA_CLE266) {
1464         cr3b_mask = 0x08;
1465     } else {
1466         cr3b_mask = 0x02;
1467     }
1468 
1469     cr3b = hwp->readCrtc(hwp, 0x3B) & cr3b_mask;
1470 
1471     if (!cr3b) {
1472         return;
1473     }
1474 
1475     memcpy(Options, ViaPanelOptions, sizeof(ViaPanelOptions));
1476     xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, Options);
1477 
1478     Panel->NativeModeIndex = VIA_PANEL_INVALID;
1479 
1480     /* LCD Center/Expend Option */
1481     Panel->Center = FALSE;
1482     from = xf86GetOptValBool(Options, OPTION_CENTER, &Panel->Center)
1483             ? X_CONFIG : X_DEFAULT;
1484     xf86DrvMsg(pScrn->scrnIndex, from, "LVDS-0 : DVI Center is %s.\n",
1485                Panel->Center ? "enabled" : "disabled");
1486 
1487     /* The code to dynamically designate a particular FP (i.e., FP-1,
1488      * FP-2, etc.) for xrandr was borrowed from xf86-video-r128 DDX. */
1489     sprintf(outputNameBuffer, "FP-%d", (pVia->numberFP + 1));
1490     output = xf86OutputCreate(pScrn, &via_lvds_funcs, outputNameBuffer);
1491 
1492     if (output)  {
1493         output->driver_private = Panel;
1494 
1495         /* While there are two (2) display controllers registered with the
1496          * X.Org Server, it is often desirable to fix FP (Flat Panel) to
1497          * IGA2 since only IGA2 contains panel resolution scaling
1498          * functionality. IGA1 does not have this. */
1499         output->possible_crtcs = 1 << 1;
1500 
1501         output->possible_clones = 0;
1502         output->interlaceAllowed = FALSE;
1503         output->doubleScanAllowed = FALSE;
1504 
1505         /* Increment the number of FP connectors. */
1506         pVia->numberFP++;
1507 
1508         if (pVia->IsOLPCXO15) {
1509             output->mm_height = 152;
1510             output->mm_width = 114;
1511         }
1512     } else {
1513         free(Panel);
1514     }
1515 }
1516