Xv: work around some overlay bandwidth problems - may break things though
[nouveau] / src / nv50_sor.c
1 /*
2  * Copyright (c) 2007 NVIDIA, Corporation
3  *
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:
11  *
12  * The above copyright notice and this permission notice shall be included
13  * in all copies or substantial portions of the Software.
14  *
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.
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #define DPMS_SERVER
29 #include <X11/extensions/dpms.h>
30
31 #include "nv_include.h"
32 #include "nv50_type.h"
33 #include "nv50_display.h"
34 #include "nv50_output.h"
35
36 static void
37 NV50SorSetPClk(xf86OutputPtr output, int pclk)
38 {
39     NVPtr pNv = NVPTR(output->scrn);
40     NV50OutputPrivPtr pPriv = output->driver_private;
41     const int orOff = 0x800 * pPriv->or;
42
43     pNv->REGS[(0x00614300+orOff)/4] = (pclk > 165000) ? 0x101 : 0;
44 }
45
46 static void
47 NV50SorDPMSSet(xf86OutputPtr output, int mode)
48 {
49     NVPtr pNv = NVPTR(output->scrn);
50     NV50OutputPrivPtr pPriv = output->driver_private;
51     const int off = 0x800 * pPriv->or;
52     CARD32 tmp;
53
54     while(pNv->REGS[(0x0061C004+off)/4] & 0x80000000);
55
56     tmp = pNv->REGS[(0x0061C004+off)/4];
57     tmp |= 0x80000000;
58
59     if(mode == DPMSModeOn)
60         tmp |= 1;
61     else
62         tmp &= ~1;
63
64     pNv->REGS[(0x0061C004+off)/4] = tmp;
65 }
66
67 static void
68 NV50SorModeSet(xf86OutputPtr output, DisplayModePtr mode,
69               DisplayModePtr adjusted_mode)
70 {
71     ScrnInfoPtr pScrn = output->scrn;
72     NV50OutputPrivPtr pPriv = output->driver_private;
73     const int sorOff = 0x40 * pPriv->or;
74
75     if(!adjusted_mode) {
76         /* Disconnect the SOR */
77         C(0x00000600 + sorOff, 0);
78         return;
79     }
80
81     // This wouldn't be necessary, but the server is stupid and calls
82     // NV50SorDPMSSet after the output is disconnected, even though the hardware
83     // turns it off automatically.
84     NV50SorDPMSSet(output, DPMSModeOn);
85
86     C(0x00000600 + sorOff,
87         (NV50CrtcGetHead(output->crtc) == HEAD0 ? 1 : 2) |
88         (adjusted_mode->Clock > 165000 ? 0x500 : 0x100) |
89         ((adjusted_mode->Flags & V_NHSYNC) ? 0x1000 : 0) |
90         ((adjusted_mode->Flags & V_NVSYNC) ? 0x2000 : 0));
91 }
92
93 static xf86OutputStatus
94 NV50SorDetect(xf86OutputPtr output)
95 {
96
97     NV50OutputPrivPtr pPriv = output->driver_private;
98
99     /* Assume physical status isn't going to change before the BlockHandler */
100     if(pPriv->cached_status != XF86OutputStatusUnknown)
101         return pPriv->cached_status;
102
103     NV50OutputPartnersDetect(pPriv->partner, output, pPriv->i2c);
104     return pPriv->cached_status;
105 }
106
107 static void
108 NV50SorDestroy(xf86OutputPtr output)
109 {
110     NV50OutputDestroy(output);
111
112     xfree(output->driver_private);
113     output->driver_private = NULL;
114 }
115
116 static const xf86OutputFuncsRec NV50SorOutputFuncs = {
117     .dpms = NV50SorDPMSSet,
118     .save = NULL,
119     .restore = NULL,
120     .mode_valid = NV50OutputModeValid,
121     .mode_fixup = NV50OutputModeFixup,
122     .prepare = NV50OutputPrepare,
123     .commit = NV50OutputCommit,
124     .mode_set = NV50SorModeSet,
125     .detect = NV50SorDetect,
126     .get_modes = NV50OutputGetDDCModes,
127     .destroy = NV50SorDestroy,
128 };
129
130 xf86OutputPtr
131 NV50CreateSor(ScrnInfoPtr pScrn, ORNum or)
132 {
133     NV50OutputPrivPtr pPriv = xnfcalloc(sizeof(*pPriv), 1);
134     xf86OutputPtr output;
135     char orName[5];
136
137     if(!pPriv)
138         return FALSE;
139
140     snprintf(orName, 5, "DVI%i", or);
141     output = xf86OutputCreate(pScrn, &NV50SorOutputFuncs, orName);
142
143     pPriv->type = SOR;
144     pPriv->or = or;
145     pPriv->cached_status = XF86OutputStatusUnknown;
146     pPriv->set_pclk = NV50SorSetPClk;
147     output->driver_private = pPriv;
148     output->interlaceAllowed = TRUE;
149     output->doubleScanAllowed = TRUE;
150
151     return output;
152 }