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);
192
static nouveauCrtcPtr
193
NV50DacGetCurrentCrtc(nouveauOutputPtr output)
195
ScrnInfoPtr pScrn = output->scrn;
196
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50DacGetCurrentCrtc is called.\n");
198
NVPtr pNv = NVPTR(pScrn);
199
uint32_t mode_ctrl = NVRead(pNv, NV50_DAC0_MODE_CTRL_VAL + NV50OrOffset(output) * 0x8);
202
* MODE_CTRL values only contain one instance of crtc0 and of crtc1.
203
* This is because we disconnect outputs upon modeset.
204
* Crtc might be off even if we get a positive return.
205
* But we are still associated with that crtc.
207
if (mode_ctrl & NV50_DAC_MODE_CTRL_CRTC0)
209
else if (mode_ctrl & NV50_DAC_MODE_CTRL_CRTC1)
216
NV50DacSetFunctionPointers(nouveauOutputPtr output)
218
output->ModeValid = NV50DacModeValid;
219
output->ModeSet = NV50DacModeSet;
220
output->SetClockMode = NV50DacSetClockMode;
221
output->Sense = NV50DacSense;
222
output->Detect = NV50DacDetect;
223
output->SetPowerMode = NV50DacSetPowerMode;
224
output->GetCurrentCrtc = NV50DacGetCurrentCrtc;