2 * Copyright 2007 NVIDIA, Corporation
3 * Copyright 2008 Maarten Maathuis
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
20 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 #include "nouveau_modeset.h"
25 #include "nouveau_crtc.h"
26 #include "nouveau_output.h"
27 #include "nouveau_connector.h"
30 NV50DacModeValid(nouveauOutputPtr output, DisplayModePtr mode)
32 if (mode->Clock > 400000)
33 return MODE_CLOCK_HIGH;
35 if (mode->Clock < 25000)
36 return MODE_CLOCK_LOW;
42 NV50DacModeSet(nouveauOutputPtr output, DisplayModePtr mode)
44 ScrnInfoPtr pScrn = output->scrn;
45 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50DacModeSet is called.\n");
47 const int dacOff = 0x80 * NV50OrOffset(output);
48 uint32_t mode_ctl = NV50_DAC_MODE_CTRL_OFF;
49 uint32_t mode_ctl2 = 0;
52 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Disconnecting DAC.\n");
53 NV50DisplayCommand(pScrn, NV50_DAC0_MODE_CTRL + dacOff, mode_ctl);
57 /* Anyone know a more appropriate name? */
58 DisplayModePtr desired_mode = output->crtc->use_native_mode ? output->crtc->native_mode : mode;
61 if (output->crtc->index == 1)
62 mode_ctl |= NV50_DAC_MODE_CTRL_CRTC1;
64 mode_ctl |= NV50_DAC_MODE_CTRL_CRTC0;
66 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Warning, output has no crtc.\n");
70 if (output->type == OUTPUT_ANALOG) {
73 } else if (output->type == OUTPUT_TV) {
77 if (desired_mode->Flags & V_NHSYNC)
78 mode_ctl2 |= NV50_DAC_MODE_CTRL2_NHSYNC;
80 if (desired_mode->Flags & V_NVSYNC)
81 mode_ctl2 |= NV50_DAC_MODE_CTRL2_NVSYNC;
83 // This wouldn't be necessary, but the server is stupid and calls
84 // nv50_dac_dpms after the output is disconnected, even though the hardware
85 // turns it off automatically.
86 output->SetPowerMode(output, DPMSModeOn);
88 NV50DisplayCommand(pScrn, NV50_DAC0_MODE_CTRL + dacOff, mode_ctl);
90 NV50DisplayCommand(pScrn, NV50_DAC0_MODE_CTRL2 + dacOff, mode_ctl2);
92 output->crtc->SetScaleMode(output->crtc, output->scale_mode);
96 NV50DacSetClockMode(nouveauOutputPtr output, int clock)
98 ScrnInfoPtr pScrn = output->scrn;
99 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50DacSetClockMode is called.\n");
101 NVPtr pNv = NVPTR(pScrn);
102 NVWrite(pNv, NV50_DAC0_CLK_CTRL2 + NV50OrOffset(output) * 0x800, 0);
106 NV50DacSense(nouveauOutputPtr output)
108 switch (output->type) {
118 NV50DacDetect (nouveauOutputPtr output)
120 ScrnInfoPtr pScrn = output->scrn;
121 NVPtr pNv = NVPTR(pScrn);
122 const int scrnIndex = pScrn->scrnIndex;
124 uint32_t load, dactestval, tmp;
126 NVWrite(pNv, NV50_DAC0_CLK_CTRL1 + NV50OrOffset(output) * 0x800, 0x00000001);
127 tmp = NVRead(pNv, NV50_DAC0_DPMS_CTRL + NV50OrOffset(output) * 0x800);
129 NVWrite(pNv, NV50_DAC0_DPMS_CTRL + NV50OrOffset(output) * 0x800, NV50_DAC_DPMS_CTRL_DEFAULT_STATE | NV50_DAC_DPMS_CTRL_PENDING);
130 while (NVRead(pNv, NV50_DAC0_DPMS_CTRL + NV50OrOffset(output) * 0x800) & NV50_DAC_DPMS_CTRL_PENDING);
133 if (pNv->VBIOS.dactestval) {
134 dactestval = pNv->VBIOS.dactestval;
135 xf86DrvMsg(scrnIndex, X_INFO, "Using bios provided load value of %d\n", dactestval);
137 xf86DrvMsg(scrnIndex, X_INFO, "Using default load value of %d\n", dactestval);
140 NVWrite(pNv, NV50_DAC0_LOAD_CTRL + NV50OrOffset(output) * 0x800, dactestval | NV50_DAC_LOAD_CTRL_ACTIVE);
141 /* Why is this needed, load detect is almost instantanious and seemingly reliable for me. */
142 sigstate = xf86BlockSIGIO();
144 xf86UnblockSIGIO(sigstate);
145 load = NVRead(pNv, NV50_DAC0_LOAD_CTRL + NV50OrOffset(output) * 0x800);
146 NVWrite(pNv, NV50_DAC0_LOAD_CTRL + NV50OrOffset(output) * 0x800, 0);
147 NVWrite(pNv, NV50_DAC0_DPMS_CTRL + NV50OrOffset(output) * 0x800, NV50_DAC_DPMS_CTRL_PENDING | tmp);
149 // Use this DAC if all three channels show load.
150 if ((load & NV50_DAC_LOAD_CTRL_PRESENT) == NV50_DAC_LOAD_CTRL_PRESENT) {
151 xf86DrvMsg(scrnIndex, X_PROBED, "Load present on DAC-%i\n", NV50OrOffset(output));
155 xf86DrvMsg(scrnIndex, X_PROBED, "No Load present on DAC-%i\n", NV50OrOffset(output));
160 NV50DacSetPowerMode(nouveauOutputPtr output, int mode)
162 ScrnInfoPtr pScrn = output->scrn;
163 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50DacSetPowerMode is called with mode %d.\n", mode);
166 NVPtr pNv = NVPTR(pScrn);
169 * DPMSModeOn everything on
170 * DPMSModeStandby hsync disabled, vsync enabled
171 * DPMSModeSuspend hsync enabled, vsync disabled
172 * DPMSModeOff sync disabled
174 while(NVRead(pNv, NV50_DAC0_DPMS_CTRL + NV50OrOffset(output) * 0x800) & NV50_DAC_DPMS_CTRL_PENDING);
176 tmp = NVRead(pNv, NV50_DAC0_DPMS_CTRL + NV50OrOffset(output) * 0x800);
178 tmp |= NV50_DAC_DPMS_CTRL_PENDING;
180 if (mode == DPMSModeStandby || mode == DPMSModeOff)
181 tmp |= NV50_DAC_DPMS_CTRL_HSYNC_OFF;
182 if (mode == DPMSModeSuspend || mode == DPMSModeOff)
183 tmp |= NV50_DAC_DPMS_CTRL_VSYNC_OFF;
184 if (mode != DPMSModeOn)
185 tmp |= NV50_DAC_DPMS_CTRL_BLANKED;
186 if (mode == DPMSModeOff)
187 tmp |= NV50_DAC_DPMS_CTRL_OFF;
189 NVWrite(pNv, NV50_DAC0_DPMS_CTRL + NV50OrOffset(output) * 0x800, tmp);
193 NV50DacSetFunctionPointers(nouveauOutputPtr output)
195 output->ModeValid = NV50DacModeValid;
196 output->ModeSet = NV50DacModeSet;
197 output->SetClockMode = NV50DacSetClockMode;
198 output->Sense = NV50DacSense;
199 output->Detect = NV50DacDetect;
200 output->SetPowerMode = NV50DacSetPowerMode;