2 * Copyright (c) 2007 NVIDIA, Corporation
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
12 * The above copyright notice and this permission notice shall be included
13 * in all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 #include <X11/extensions/dpms.h>
29 #include "nv_include.h"
30 #include "nv50_display.h"
31 #include "nv50_output.h"
34 NV50DacSetPClk(xf86OutputPtr output, int pclk)
36 ScrnInfoPtr pScrn = output->scrn;
37 NVPtr pNv = NVPTR(pScrn);
38 NVWrite(pNv, 0x00614280 + NV50OrOffset(output) * 0x800, 0);
42 NV50DacDPMSSet(xf86OutputPtr output, int mode)
45 ScrnInfoPtr pScrn = output->scrn;
46 NVPtr pNv = NVPTR(pScrn);
49 * DPMSModeOn everything on
50 * DPMSModeStandby hsync disabled, vsync enabled
51 * DPMSModeSuspend hsync enabled, vsync disabled
52 * DPMSModeOff sync disabled
54 while(NVRead(pNv, NV50_DAC0_DPMS_CTRL + NV50OrOffset(output) * 0x800) & NV50_DAC_DPMS_CTRL_PENDING);
56 tmp = NVRead(pNv, NV50_DAC0_DPMS_CTRL + NV50OrOffset(output) * 0x800);
58 tmp |= NV50_DAC_DPMS_CTRL_PENDING;
60 if(mode == DPMSModeStandby || mode == DPMSModeOff)
61 tmp |= NV50_DAC_DPMS_CTRL_HSYNC_OFF;
62 if(mode == DPMSModeSuspend || mode == DPMSModeOff)
63 tmp |= NV50_DAC_DPMS_CTRL_VSYNC_OFF;
64 if(mode != DPMSModeOn)
65 tmp |= NV50_DAC_DPMS_CTRL_BLANK;
66 if(mode == DPMSModeOff)
67 tmp |= NV50_DAC_DPMS_CTRL_OFF;
69 NVWrite(pNv, NV50_DAC0_DPMS_CTRL + NV50OrOffset(output) * 0x800, tmp);
73 NV50DacModeFixup(xf86OutputPtr output, DisplayModePtr mode,
74 DisplayModePtr adjusted_mode)
80 NV50DacModeSet(xf86OutputPtr output, DisplayModePtr mode,
81 DisplayModePtr adjusted_mode)
83 ScrnInfoPtr pScrn = output->scrn;
84 const int dacOff = 0x80 * NV50OrOffset(output);
85 uint32_t mode_ctl = NV50_DAC_MODE_CTRL_OFF;
86 uint32_t mode_ctl2 = 0;
89 NV50DisplayCommand(pScrn, NV50_DAC0_MODE_CTRL + dacOff, mode_ctl);
94 NVCrtcPrivatePtr nv_crtc = output->crtc->driver_private;
95 if (nv_crtc->head == 1)
96 mode_ctl |= NV50_DAC_MODE_CTRL_CRTC1;
98 mode_ctl |= NV50_DAC_MODE_CTRL_CRTC0;
106 if (adjusted_mode->Flags & V_NHSYNC)
107 mode_ctl2 |= NV50_DAC_MODE_CTRL2_NHSYNC;
109 if (adjusted_mode->Flags & V_NVSYNC)
110 mode_ctl2 |= NV50_DAC_MODE_CTRL2_NVSYNC;
112 // This wouldn't be necessary, but the server is stupid and calls
113 // NV50DacDPMSSet after the output is disconnected, even though the hardware
114 // turns it off automatically.
115 NV50DacDPMSSet(output, DPMSModeOn);
117 NV50DisplayCommand(pScrn, NV50_DAC0_MODE_CTRL + dacOff, mode_ctl);
119 NV50DisplayCommand(pScrn, NV50_DAC0_MODE_CTRL2 + dacOff, mode_ctl2);
121 NV50CrtcSetScale(output->crtc, adjusted_mode, SCALE_PANEL);
125 * Perform DAC load detection to determine if there is a connected display.
127 static xf86OutputStatus
128 NV50DacDetect(xf86OutputPtr output)
130 NVOutputPrivatePtr nv_output = output->driver_private;
133 if (nv_output->pDDCBus == NULL)
134 return XF86OutputStatusDisconnected;
136 ddc_mon = NV50OutputGetEDID(output, nv_output->pDDCBus);
137 if (!ddc_mon && !NV50DacLoadDetect(output))
138 return XF86OutputStatusDisconnected;
140 if (ddc_mon && ddc_mon->features.input_type) /* DVI? */
141 return XF86OutputStatusDisconnected;
144 xf86OutputSetEDID(output, ddc_mon);
146 return XF86OutputStatusConnected;
150 NV50DacLoadDetect(xf86OutputPtr output)
152 ScrnInfoPtr pScrn = output->scrn;
153 NVPtr pNv = NVPTR(pScrn);
154 const int scrnIndex = pScrn->scrnIndex;
156 CARD32 load, tmp, tmp2;
158 xf86DrvMsg(scrnIndex, X_PROBED, "Trying load detection on VGA%i ... ",
159 NV50OrOffset(output));
161 NVWrite(pNv, 0x0061a010 + NV50OrOffset(output) * 0x800, 0x00000001);
162 tmp2 = NVRead(pNv, NV50_DAC0_DPMS_CTRL + NV50OrOffset(output) * 0x800);
164 NVWrite(pNv, NV50_DAC0_DPMS_CTRL + NV50OrOffset(output) * 0x800, 0x00150000 | NV50_DAC_DPMS_CTRL_PENDING);
165 while(NVRead(pNv, NV50_DAC0_DPMS_CTRL + NV50OrOffset(output) * 0x800) & NV50_DAC_DPMS_CTRL_PENDING);
166 tmp = (pNv->NVArch == 0x50) ? 420 : 340;
167 NVWrite(pNv, 0x0061a00c + NV50OrOffset(output) * 0x800, tmp | 0x100000);
168 sigstate = xf86BlockSIGIO();
170 xf86UnblockSIGIO(sigstate);
171 load = NVRead(pNv, 0x0061a00c + NV50OrOffset(output) * 0x800);
172 NVWrite(pNv, 0x0061a00c + NV50OrOffset(output) * 0x800, 0);
173 NVWrite(pNv, NV50_DAC0_DPMS_CTRL + NV50OrOffset(output) * 0x800, NV50_DAC_DPMS_CTRL_PENDING | tmp2);
175 // Use this DAC if all three channels show load.
176 if((load & 0x38000000) == 0x38000000) {
177 xf86ErrorF("found one!\n");
181 xf86ErrorF("nothing.\n");
186 NV50DacDestroy(xf86OutputPtr output)
188 NV50OutputDestroy(output);
190 xfree(output->driver_private);
191 output->driver_private = NULL;
194 static const xf86OutputFuncsRec NV50DacOutputFuncs = {
195 .dpms = NV50DacDPMSSet,
198 .mode_valid = NV50OutputModeValid,
199 .mode_fixup = NV50DacModeFixup,
200 .prepare = NV50OutputPrepare,
201 .commit = NV50OutputCommit,
202 .mode_set = NV50DacModeSet,
203 .detect = NV50DacDetect,
204 .get_modes = NV50OutputGetDDCModes,
205 .destroy = NV50DacDestroy,
208 const xf86OutputFuncsRec * nv50_get_analog_output_funcs()
210 return &NV50DacOutputFuncs;