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