1 /*
2 * Copyright 2005-2016 The OpenChrome Project
3 * [https://www.freedesktop.org/wiki/Openchrome]
4 * Copyright 2004-2005 The Unichrome Project [unichrome.sf.net]
5 * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
6 * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sub license,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the
16 * next paragraph) shall be included in all copies or substantial portions
17 * of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
22 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 * DEALINGS IN THE SOFTWARE.
26 */
27
28 /*
29 * via_analog.c
30 *
31 * Handles the initialization and management of analog VGA related
32 * resources.
33 *
34 */
35
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
39
40 #include "via_driver.h"
41 #include <unistd.h>
42
43
44 /*
45 * Enables or disables analog VGA output by controlling DAC
46 * (Digital to Analog Converter) output state.
47 */
48 static void
viaAnalogOutput(ScrnInfoPtr pScrn,Bool outputState)49 viaAnalogOutput(ScrnInfoPtr pScrn, Bool outputState)
50 {
51 vgaHWPtr hwp = VGAHWPTR(pScrn);
52
53 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
54 "Entered viaAnalogOutput.\n"));
55
56 /* This register controls analog VGA DAC output state. */
57 /* 3X5.47[2] - DACOFF Backdoor Register
58 * 0: DAC on
59 * 1: DAC off */
60 ViaCrtcMask(hwp, 0x47, outputState ? 0x00 : 0x04, 0x04);
61 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
62 "Analog VGA Output: %s\n",
63 outputState ? "On" : "Off");
64
65 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
66 "Exiting viaAnalogOutput.\n"));
67 }
68
69 /*
70 * Specifies IGA1 or IGA2 for analog VGA DAC source.
71 */
72 static void
viaAnalogSetDisplaySource(ScrnInfoPtr pScrn,CARD8 displaySource)73 viaAnalogSetDisplaySource(ScrnInfoPtr pScrn, CARD8 displaySource)
74 {
75 vgaHWPtr hwp = VGAHWPTR(pScrn);
76 CARD8 value = displaySource;
77
78 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
79 "Entered viaAnalogSetDisplaySource.\n"));
80
81 ViaSeqMask(hwp, 0x16, value << 6, 0x40);
82 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
83 "Analog VGA Display Output Source: IGA%d\n",
84 (value & 0x01) + 1);
85
86 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
87 "Exiting viaAnalogSetDisplaySource.\n"));
88 }
89
90 /*
91 * Intializes analog VGA related registers.
92 */
93 static void
viaAnalogInit(ScrnInfoPtr pScrn)94 viaAnalogInit(ScrnInfoPtr pScrn)
95 {
96 vgaHWPtr hwp = VGAHWPTR(pScrn);
97 VIAPtr pVia = VIAPTR(pScrn);
98
99 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
100 "Entered viaAnalogInit.\n"));
101
102 /* 3X5.37[7] - DAC Power Save Control 1
103 * 0: Depend on Rx3X5.37[5:4] setting
104 * 1: DAC always goes into power save mode
105 * 3X5.37[6] - DAC Power Down Control
106 * 0: Depend on Rx3X5.47[2] setting
107 * 1: DAC never goes to power down mode
108 * 3X5.37[5:4] - DAC Power Save Control 2
109 * 00: DAC never goes to power save mode
110 * 01: DAC goes to power save mode by line
111 * 10: DAC goes to power save mode by frame
112 * 11: DAC goes to power save mode by line and frame
113 * 3X5.37[3] - DAC PEDESTAL Control
114 * 3X5.37[2:0] - DAC Factor
115 * (Default: 100) */
116 ViaCrtcMask(hwp, 0x37, 0x04, 0xFF);
117
118 switch (pVia->Chipset) {
119 case VIA_CX700:
120 case VIA_VX800:
121 case VIA_VX855:
122 case VIA_VX900:
123 /* 3C5.5E[0] - CRT DACOFF Setting
124 * 1: CRT DACOFF controlled by 3C5.01[5] */
125 ViaSeqMask(hwp, 0x5E, 0x01, 0x01);
126 break;
127 default:
128 break;
129 }
130
131 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
132 "Exiting viaAnalogInit.\n"));
133 }
134
135 /*
136 * Sets the polarity of horizontal synchronization and vertical
137 * synchronization.
138 */
139 static void
viaAnalogSetSyncPolarity(ScrnInfoPtr pScrn,DisplayModePtr mode)140 viaAnalogSetSyncPolarity(ScrnInfoPtr pScrn, DisplayModePtr mode)
141 {
142 vgaHWPtr hwp = VGAHWPTR(pScrn);
143 CARD8 miscRegister;
144
145 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
146 "Entered viaAnalogSetSyncPolarity.\n"));
147
148 /* Set certain bits of miscellaneous output register
149 * meant for IGA1. */
150 miscRegister = hwp->readMiscOut(hwp);
151 if (mode->Flags & V_NHSYNC) {
152 miscRegister |= 0x40;
153 } else {
154 miscRegister &= (~0x40);
155 }
156
157 if (mode->Flags & V_NVSYNC) {
158 miscRegister |= 0x80;
159 } else {
160 miscRegister &= (~0x80);
161 }
162
163 hwp->writeMiscOut(hwp, miscRegister);
164
165 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
166 "Exiting viaAnalogSetSyncPolarity.\n"));
167 }
168
169
170 static void
via_analog_create_resources(xf86OutputPtr output)171 via_analog_create_resources(xf86OutputPtr output)
172 {
173 }
174
175 static void
via_analog_dpms(xf86OutputPtr output,int mode)176 via_analog_dpms(xf86OutputPtr output, int mode)
177 {
178 ScrnInfoPtr pScrn = output->scrn;
179
180 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
181 "Entered via_analog_dpms.\n"));
182
183 switch (mode) {
184 case DPMSModeOn:
185 viaAnalogOutput(pScrn, TRUE);
186 break;
187 case DPMSModeStandby:
188 case DPMSModeSuspend:
189 case DPMSModeOff:
190 viaAnalogOutput(pScrn, FALSE);
191 break;
192 default:
193 break;
194 }
195
196 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
197 "Exiting via_analog_dpms.\n"));
198 }
199
200 static void
via_analog_save(xf86OutputPtr output)201 via_analog_save(xf86OutputPtr output)
202 {
203 }
204
205 static void
via_analog_restore(xf86OutputPtr output)206 via_analog_restore(xf86OutputPtr output)
207 {
208 }
209
210 static int
via_analog_mode_valid(xf86OutputPtr output,DisplayModePtr pMode)211 via_analog_mode_valid(xf86OutputPtr output, DisplayModePtr pMode)
212 {
213 ScrnInfoPtr pScrn = output->scrn;
214
215 if (!ViaModeDotClockTranslate(pScrn, pMode))
216 return MODE_NOCLOCK;
217 return MODE_OK;
218 }
219
220 static Bool
via_analog_mode_fixup(xf86OutputPtr output,DisplayModePtr mode,DisplayModePtr adjusted_mode)221 via_analog_mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
222 DisplayModePtr adjusted_mode)
223 {
224 return TRUE;
225 }
226
227 static void
via_analog_prepare(xf86OutputPtr output)228 via_analog_prepare(xf86OutputPtr output)
229 {
230 via_analog_dpms(output, DPMSModeOff);
231 }
232
233 static void
via_analog_commit(xf86OutputPtr output)234 via_analog_commit(xf86OutputPtr output)
235 {
236 via_analog_dpms(output, DPMSModeOn);
237 }
238
239 static void
via_analog_mode_set(xf86OutputPtr output,DisplayModePtr mode,DisplayModePtr adjusted_mode)240 via_analog_mode_set(xf86OutputPtr output, DisplayModePtr mode,
241 DisplayModePtr adjusted_mode)
242 {
243 ScrnInfoPtr pScrn = output->scrn;
244 drmmode_crtc_private_ptr iga = output->crtc->driver_private;
245
246 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
247 "Entered via_analog_mode_set.\n"));
248
249 if (output->crtc) {
250 viaAnalogInit(pScrn);
251 viaAnalogSetSyncPolarity(pScrn, adjusted_mode);
252 viaAnalogSetDisplaySource(pScrn, iga->index ? 0x01 : 0x00);
253 }
254
255 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
256 "Exiting via_analog_mode_set.\n"));
257 }
258
259 static xf86OutputStatus
via_analog_detect(xf86OutputPtr output)260 via_analog_detect(xf86OutputPtr output)
261 {
262 xf86OutputStatus status = XF86OutputStatusDisconnected;
263 ScrnInfoPtr pScrn = output->scrn;
264 VIAPtr pVia = VIAPTR(pScrn);
265 xf86MonPtr mon;
266
267 /* Probe I2C Bus 1 to see if a VGA monitor is connected. */
268 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
269 "Probing for a VGA monitor on I2C Bus 1.\n");
270 mon = xf86OutputGetEDID(output, pVia->pI2CBus1);
271 if (mon && (!mon->features.input_type)) {
272 xf86OutputSetEDID(output, mon);
273 status = XF86OutputStatusConnected;
274 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
275 "Detected a VGA monitor on I2C Bus 1.\n");
276 } else {
277 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
278 "Did not detect a VGA monitor on I2C Bus 1.\n");
279
280 /* Probe I2C Bus 2 to see if a VGA monitor is connected. */
281 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
282 "Probing for a VGA monitor on I2C Bus 2.\n");
283 mon = xf86OutputGetEDID(output, pVia->pI2CBus2);
284 if (mon && (!mon->features.input_type)) {
285 xf86OutputSetEDID(output, mon);
286 status = XF86OutputStatusConnected;
287 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
288 "Detected a VGA monitor on I2C Bus 2.\n");
289 } else {
290 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
291 "Did not detect a VGA monitor on I2C Bus 2.\n");
292
293 /* Perform manual detection of a VGA monitor since */
294 /* it was not detected via I2C buses. */
295 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
296 "Now perform manual detection of a VGA "
297 "monitor.\n");
298 vgaHWPtr hwp = VGAHWPTR(pScrn);
299 CARD8 SR01 = hwp->readSeq(hwp, 0x01);
300 CARD8 SR40 = hwp->readSeq(hwp, 0x40);
301 CARD8 CR36 = hwp->readCrtc(hwp, 0x36);
302
303 /* We have to power on the display to detect it */
304 ViaSeqMask(hwp, 0x01, 0x00, 0x20);
305 ViaCrtcMask(hwp, 0x36, 0x00, 0xF0);
306
307 /* Wait for vblank */
308 usleep(16);
309
310 /* Detect the load on pins */
311 ViaSeqMask(hwp, 0x40, 0x80, 0x80);
312
313 if ((VIA_CX700 == pVia->Chipset) ||
314 (VIA_VX800 == pVia->Chipset) ||
315 (VIA_VX855 == pVia->Chipset) ||
316 (VIA_VX900 == pVia->Chipset))
317 ViaSeqMask(hwp, 0x40, 0x00, 0x80);
318
319 if (ViaVgahwIn(hwp, 0x3C2) & 0x20) {
320 status = XF86OutputStatusConnected;
321 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
322 "Detected a VGA monitor using manual "
323 "detection method.\n");
324 }
325
326 if ((VIA_CX700 == pVia->Chipset) ||
327 (VIA_VX800 == pVia->Chipset) ||
328 (VIA_VX855 == pVia->Chipset) ||
329 (VIA_VX900 == pVia->Chipset))
330 ViaSeqMask(hwp, 0x40, 0x00, 0x80);
331
332 /* Restore previous state */
333 hwp->writeSeq(hwp, 0x40, SR40);
334 hwp->writeSeq(hwp, 0x01, SR01);
335 hwp->writeCrtc(hwp, 0x36, CR36);
336 }
337 }
338
339 return status;
340 }
341
342 #ifdef RANDR_12_INTERFACE
343 static Bool
via_analog_set_property(xf86OutputPtr output,Atom property,RRPropertyValuePtr value)344 via_analog_set_property(xf86OutputPtr output, Atom property,
345 RRPropertyValuePtr value)
346 {
347 return TRUE;
348 }
349 #endif
350
351 #ifdef RANDR_13_INTERFACE
352 static Bool
via_analog_get_property(xf86OutputPtr output,Atom property)353 via_analog_get_property(xf86OutputPtr output, Atom property)
354 {
355 return FALSE;
356 }
357 #endif
358
359 static void
via_analog_destroy(xf86OutputPtr output)360 via_analog_destroy(xf86OutputPtr output)
361 {
362 }
363
364 static const xf86OutputFuncsRec via_analog_funcs = {
365 .create_resources = via_analog_create_resources,
366 .dpms = via_analog_dpms,
367 .save = via_analog_save,
368 .restore = via_analog_restore,
369 .mode_valid = via_analog_mode_valid,
370 .mode_fixup = via_analog_mode_fixup,
371 .prepare = via_analog_prepare,
372 .commit = via_analog_commit,
373 .mode_set = via_analog_mode_set,
374 .detect = via_analog_detect,
375 .get_modes = xf86OutputGetEDIDModes,
376 #ifdef RANDR_12_INTERFACE
377 .set_property = via_analog_set_property,
378 #endif
379 #ifdef RANDR_13_INTERFACE
380 .get_property = via_analog_get_property,
381 #endif
382 .destroy = via_analog_destroy,
383 };
384
385 void
via_analog_init(ScrnInfoPtr pScrn)386 via_analog_init(ScrnInfoPtr pScrn)
387 {
388 VIAPtr pVia = VIAPTR(pScrn);
389 VIABIOSInfoPtr pBIOSInfo = pVia->pBIOSInfo;
390 xf86OutputPtr output = NULL;
391 char outputNameBuffer[32];
392
393 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
394 "Entered via_analog_init.\n"));
395
396 if (!pVia->pI2CBus1 || !pVia->pI2CBus2) {
397 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
398 "I2C Bus 1 or I2C Bus 2 does not exist.\n");
399 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
400 "Exiting via_analog_init.\n"));
401 return;
402 }
403
404 /* The code to dynamically designate the output name for
405 * xrandr was borrowed from xf86-video-r128 DDX. */
406 sprintf(outputNameBuffer, "VGA-%d", (pVia->numberVGA + 1));
407 output = xf86OutputCreate(pScrn, &via_analog_funcs, outputNameBuffer);
408
409 /* While there are two (2) display controllers registered with the
410 * X.Org Server, it is often desirable to fix the analog VGA output
411 * to IGA1 since LVDS FP (Flat Panel) typically prefers IGA2. (While
412 * it is not used at this point, only IGA2 contains panel resolution
413 * scaling functionality. IGA1 does not have this.)
414 * With this arrangement, DVI should end up getting assigned to IGA2
415 * since DVI can go to either display controller without limitations.
416 * This should be the case for TV as well. */
417 output->possible_crtcs = (1 << 0);
418
419 output->possible_clones = 0;
420 output->interlaceAllowed = TRUE;
421 output->doubleScanAllowed = FALSE;
422 pBIOSInfo->analog = output;
423
424 /* Increment the number of analog VGA connectors. */
425 pVia->numberVGA++;
426
427 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,
428 "Exiting via_analog_init.\n"));
429 }
430