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 NVOutputPrivatePtr nv_output = output->driver_private;
37 ScrnInfoPtr pScrn = output->scrn;
38 NVPtr pNv = NVPTR(pScrn);
39 NVWrite(pNv, 0x00614280 + nv_output->output_resource * 0x800, 0);
43 NV50DacDPMSSet(xf86OutputPtr output, int mode)
46 NVOutputPrivatePtr nv_output = output->driver_private;
47 ScrnInfoPtr pScrn = output->scrn;
48 NVPtr pNv = NVPTR(pScrn);
51 * DPMSModeOn everything on
52 * DPMSModeStandby hsync disabled, vsync enabled
53 * DPMSModeSuspend hsync enabled, vsync disabled
54 * DPMSModeOff sync disabled
56 while(NVRead(pNv, 0x0061a004 + nv_output->output_resource * 0x800) & 0x80000000);
58 tmp = NVRead(pNv, 0x0061a004 + nv_output->output_resource * 0x800);
62 if(mode == DPMSModeStandby || mode == DPMSModeOff)
64 if(mode == DPMSModeSuspend || mode == DPMSModeOff)
66 if(mode != DPMSModeOn)
68 if(mode == DPMSModeOff)
71 NVWrite(pNv, 0x0061a004 + nv_output->output_resource * 0x800, tmp);
75 NV50DacModeFixup(xf86OutputPtr output, DisplayModePtr mode,
76 DisplayModePtr adjusted_mode)
82 NV50DacModeSet(xf86OutputPtr output, DisplayModePtr mode,
83 DisplayModePtr adjusted_mode)
85 ScrnInfoPtr pScrn = output->scrn;
86 NVOutputPrivatePtr nv_output = output->driver_private;
87 const int dacOff = 0x80 * nv_output->output_resource;
90 NV50DisplayCommand(pScrn, 0x400 + dacOff, 0);
94 // This wouldn't be necessary, but the server is stupid and calls
95 // NV50DacDPMSSet after the output is disconnected, even though the hardware
96 // turns it off automatically.
97 NV50DacDPMSSet(output, DPMSModeOn);
99 NV50DisplayCommand(pScrn, 0x400 + dacOff,
100 (NV50CrtcGetHead(output->crtc) == HEAD0 ? 1 : 2) | 0x40);
102 NV50DisplayCommand(pScrn, 0x404 + dacOff,
103 (adjusted_mode->Flags & V_NHSYNC) ? 1 : 0 |
104 (adjusted_mode->Flags & V_NVSYNC) ? 2 : 0);
106 NV50CrtcSetScale(output->crtc, adjusted_mode, SCALE_PANEL);
110 * Perform DAC load detection to determine if there is a connected display.
112 static xf86OutputStatus
113 NV50DacDetect(xf86OutputPtr output)
115 NVOutputPrivatePtr nv_output = output->driver_private;
118 if (nv_output->pDDCBus == NULL)
119 return XF86OutputStatusDisconnected;
121 ddc_mon = xf86OutputGetEDID(output, nv_output->pDDCBus);
122 if (!ddc_mon && !NV50DacLoadDetect(output))
123 return XF86OutputStatusDisconnected;
125 if (ddc_mon && ddc_mon->features.input_type) /* DVI? */
126 return XF86OutputStatusDisconnected;
129 xf86OutputSetEDID(output, ddc_mon);
131 return XF86OutputStatusConnected;
135 NV50DacLoadDetect(xf86OutputPtr output)
137 ScrnInfoPtr pScrn = output->scrn;
138 NVPtr pNv = NVPTR(pScrn);
139 NVOutputPrivatePtr nv_output = output->driver_private;
140 const int scrnIndex = pScrn->scrnIndex;
142 CARD32 load, tmp, tmp2;
144 xf86DrvMsg(scrnIndex, X_PROBED, "Trying load detection on VGA%i ... ",
145 nv_output->output_resource);
147 NVWrite(pNv, 0x0061a010 + nv_output->output_resource * 0x800, 0x00000001);
148 tmp2 = NVRead(pNv, 0x0061a004 + nv_output->output_resource * 0x800);
150 NVWrite(pNv, 0x0061a004 + nv_output->output_resource * 0x800, 0x80150000);
151 while(NVRead(pNv, 0x0061a004 + nv_output->output_resource * 0x800) & 0x80000000);
152 tmp = (pNv->NVArch == 0x50) ? 420 : 340;
153 NVWrite(pNv, 0x0061a00c + nv_output->output_resource * 0x800, tmp | 0x100000);
154 sigstate = xf86BlockSIGIO();
156 xf86UnblockSIGIO(sigstate);
157 load = NVRead(pNv, 0x0061a00c + nv_output->output_resource * 0x800);
158 NVWrite(pNv, 0x0061a00c + nv_output->output_resource * 0x800, 0);
159 NVWrite(pNv, 0x0061a004 + nv_output->output_resource * 0x800, 0x80000000 | tmp2);
161 // Use this DAC if all three channels show load.
162 if((load & 0x38000000) == 0x38000000) {
163 xf86ErrorF("found one!\n");
167 xf86ErrorF("nothing.\n");
172 NV50DacDestroy(xf86OutputPtr output)
174 NV50OutputDestroy(output);
176 xfree(output->driver_private);
177 output->driver_private = NULL;
180 static const xf86OutputFuncsRec NV50DacOutputFuncs = {
181 .dpms = NV50DacDPMSSet,
184 .mode_valid = NV50OutputModeValid,
185 .mode_fixup = NV50DacModeFixup,
186 .prepare = NV50OutputPrepare,
187 .commit = NV50OutputCommit,
188 .mode_set = NV50DacModeSet,
189 .detect = NV50DacDetect,
190 .get_modes = NV50OutputGetDDCModes,
191 .destroy = NV50DacDestroy,
194 const xf86OutputFuncsRec * nv50_get_analog_output_funcs()
196 return &NV50DacOutputFuncs;