Merge branch 'randr-1.2' into nv50-branch
[nouveau] / src / nv50_output.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
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 #include <strings.h>
30 #include <xf86DDC.h>
31
32 #include "nv_include.h"
33 #include "nv50_type.h"
34 #include "nv50_output.h"
35
36 static unsigned const char *
37 NV50GetVBIOSImage(NVPtr pNv)
38 {
39         unsigned char *VBIOS;
40         uint32_t old_bar0_pramin;
41
42         VBIOS = xalloc(65536);
43         if (VBIOS) {
44                 old_bar0_pramin = pNv->REGS[0x1700/4];
45                 pNv->REGS[0x1700/4] = pNv->REGS[0x00619f04/4] >> 8;
46
47                 memcpy(VBIOS, (const void *)&pNv->REGS[0x700000/4], 65536);
48
49                 pNv->REGS[0x1700/4] = old_bar0_pramin;
50         }
51
52         return (unsigned const char *)VBIOS;
53 }
54
55 static Bool NV50ReadPortMapping(int scrnIndex, NVPtr pNv)
56 {
57     unsigned const char *VBIOS;
58     unsigned char *table2;
59     unsigned char headerSize, entries;
60     int i;
61     CARD16 a;
62     CARD32 b;
63
64     VBIOS = NV50GetVBIOSImage(pNv);
65     if (!VBIOS)
66             goto fail;
67
68     /* Clear the i2c map to invalid */
69     for(i = 0; i < 4; i++)
70         pNv->i2cMap[i].dac = pNv->i2cMap[i].sor = -1;
71
72     if(*(CARD16*)VBIOS != 0xaa55) goto fail;
73
74     a = *(CARD16*)(VBIOS + 0x36);
75     table2 = (unsigned char*)VBIOS + a;
76
77     if(table2[0] != 0x40) goto fail;
78
79     b = *(CARD32*)(table2 + 6);
80     if(b != 0x4edcbdcb) goto fail;
81
82     headerSize = table2[1];
83     entries = table2[2];
84
85     for(i = 0; i < entries; i++) {
86         int type, port;
87         ORNum or;
88
89         b = *(CARD32*)&table2[headerSize + 8*i];
90         type = b & 0xf;
91         port = (b >> 4) & 0xf;
92         or = ffs((b >> 24) & 0xf) - 1;
93
94         if(type < 4 && port != 0xf) {
95             switch(type) {
96                 case 0: /* CRT */
97                 case 1: /* TV */
98                     if(pNv->i2cMap[port].dac != -1) {
99                         xf86DrvMsg(scrnIndex, X_WARNING,
100                                    "DDC routing table corrupt!  DAC %i -> %i "
101                                    "for port %i\n",
102                                    or, pNv->i2cMap[port].dac, port);
103                     }
104                     pNv->i2cMap[port].dac = or;
105                     break;
106                 case 2: /* TMDS */
107                 case 3: /* LVDS */
108                     if(pNv->i2cMap[port].sor != -1)
109                         xf86DrvMsg(scrnIndex, X_WARNING,
110                                    "DDC routing table corrupt!  SOR %i -> %i "
111                                    "for port %i\n",
112                                    or, pNv->i2cMap[port].sor, port);
113                     pNv->i2cMap[port].sor = or;
114                     break;
115             }
116         }
117     }
118
119     xf86DrvMsg(scrnIndex, X_PROBED, "I2C map:\n");
120     for(i = 0; i < 4; i++) {
121         if(pNv->i2cMap[i].dac != -1)
122             xf86DrvMsg(scrnIndex, X_PROBED, "  Bus %i -> DAC%i\n", i, pNv->i2cMap[i].dac);
123         if(pNv->i2cMap[i].sor != -1)
124             xf86DrvMsg(scrnIndex, X_PROBED, "  Bus %i -> SOR%i\n", i, pNv->i2cMap[i].sor);
125     }
126
127     return TRUE;
128
129 fail:
130     xf86DrvMsg(scrnIndex, X_ERROR, "Couldn't find the DDC routing table.  "
131                "Mode setting will probably fail!\n");
132     return FALSE;
133 }
134
135 static void NV50_I2CPutBits(I2CBusPtr b, int clock, int data)
136 {
137     NVPtr pNv = NVPTR(xf86Screens[b->scrnIndex]);
138     const int off = b->DriverPrivate.val * 0x18;
139
140     pNv->REGS[(0x0000E138+off)/4] = 4 | clock | data << 1;
141 }
142
143 static void NV50_I2CGetBits(I2CBusPtr b, int *clock, int *data)
144 {
145     NVPtr pNv = NVPTR(xf86Screens[b->scrnIndex]);
146     const int off = b->DriverPrivate.val * 0x18;
147     unsigned char val;
148
149     val = pNv->REGS[(0x0000E138+off)/4];
150     *clock = !!(val & 1);
151     *data = !!(val & 2);
152 }
153
154 static I2CBusPtr
155 NV50I2CInit(ScrnInfoPtr pScrn, const char *name, const int port)
156 {
157     I2CBusPtr i2c;
158
159     /* Allocate the I2C bus structure */
160     i2c = xf86CreateI2CBusRec();
161     if(!i2c) return NULL;
162
163     i2c->BusName = strdup(name);
164     i2c->scrnIndex = pScrn->scrnIndex;
165     i2c->I2CPutBits = NV50_I2CPutBits;
166     i2c->I2CGetBits = NV50_I2CGetBits;
167     i2c->ByteTimeout = 2200; /* VESA DDC spec 3 p. 43 (+10 %) */
168     i2c->StartTimeout = 550;
169     i2c->BitTimeout = 40;
170     i2c->ByteTimeout = 40;
171     i2c->AcknTimeout = 40;
172     i2c->DriverPrivate.val = port;
173
174     if(xf86I2CBusInit(i2c)) {
175         return i2c;
176     } else {
177         xfree(i2c);
178         return NULL;
179     }
180 }
181
182 void
183 NV50OutputSetPClk(xf86OutputPtr output, int pclk)
184 {
185     NV50OutputPrivPtr pPriv = output->driver_private;
186     pPriv->set_pclk(output, pclk);
187 }
188
189 int
190 NV50OutputModeValid(xf86OutputPtr output, DisplayModePtr mode)
191 {
192     if(mode->Clock > 400000 || mode->Clock < 25000)
193         return MODE_CLOCK_RANGE;
194
195     return MODE_OK;
196 }
197
198 Bool
199 NV50OutputModeFixup(xf86OutputPtr output, DisplayModePtr mode,
200                    DisplayModePtr adjusted_mode)
201 {
202     return TRUE;
203 }
204
205 void
206 NV50OutputPrepare(xf86OutputPtr output)
207 {
208 }
209
210 void
211 NV50OutputCommit(xf86OutputPtr output)
212 {
213 }
214
215 static xf86MonPtr
216 ProbeDDC(I2CBusPtr i2c)
217 {
218     ScrnInfoPtr pScrn = xf86Screens[i2c->scrnIndex];
219     NVPtr pNv = NVPTR(pScrn);
220     xf86MonPtr monInfo = NULL;
221     const int bus = i2c->DriverPrivate.val, off = bus * 0x18;
222
223     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
224             "Probing for EDID on I2C bus %i...\n", bus);
225     pNv->REGS[(0x0000E138+off)/4] = 7;
226     /* Should probably use xf86OutputGetEDID here */
227     monInfo = xf86DoEDID_DDC2(pScrn->scrnIndex, i2c);
228     pNv->REGS[(0x0000E138+off)/4] = 3;
229
230     if(monInfo) {
231         xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
232                 "DDC detected a %s:\n", monInfo->features.input_type ?
233                 "DFP" : "CRT");
234         xf86PrintEDID(monInfo);
235     } else {
236         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "  ... none found\n");
237     }
238
239     return monInfo;
240 }
241
242 /*
243  * Read an EDID from the i2c port.  Perform load detection on the DAC (if
244  * present) to see if the display is connected via VGA.  Sets the cached status
245  * of both outputs.  The status is marked dirty again in the BlockHandler.
246  */
247 void NV50OutputPartnersDetect(xf86OutputPtr dac, xf86OutputPtr sor, I2CBusPtr i2c)
248 {
249     xf86MonPtr monInfo = ProbeDDC(i2c);
250     xf86OutputPtr connected = NULL;
251     Bool load = dac && NV50DacLoadDetect(dac);
252
253     if(dac) {
254         NV50OutputPrivPtr pPriv = dac->driver_private;
255
256         if(load) {
257             pPriv->cached_status = XF86OutputStatusConnected;
258             connected = dac;
259         } else {
260             pPriv->cached_status = XF86OutputStatusDisconnected;
261         }
262     }
263
264     if(sor) {
265         NV50OutputPrivPtr pPriv = sor->driver_private;
266
267         if(monInfo && !load) {
268             pPriv->cached_status = XF86OutputStatusConnected;
269             connected = sor;
270         } else {
271             pPriv->cached_status = XF86OutputStatusDisconnected;
272         }
273     }
274
275     if(connected)
276         xf86OutputSetEDID(connected, monInfo);
277 }
278
279 /*
280  * Reset the cached output status for all outputs.  Called from NV50BlockHandler.
281  */
282 void
283 NV50OutputResetCachedStatus(ScrnInfoPtr pScrn)
284 {
285     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
286     int i;
287
288     for(i = 0; i < xf86_config->num_output; i++) {
289         NV50OutputPrivPtr pPriv = xf86_config->output[i]->driver_private;
290         pPriv->cached_status = XF86OutputStatusUnknown;
291     }
292 }
293
294 DisplayModePtr
295 NV50OutputGetDDCModes(xf86OutputPtr output)
296 {
297     /* The EDID is read as part of the detect step */
298     output->funcs->detect(output);
299     return xf86OutputGetEDIDModes(output);
300 }
301
302 void
303 NV50OutputDestroy(xf86OutputPtr output)
304 {
305     NV50OutputPrivPtr pPriv = output->driver_private;
306
307     if(pPriv->partner)
308         ((NV50OutputPrivPtr)pPriv->partner->driver_private)->partner = NULL;
309     else
310         xf86DestroyI2CBusRec(pPriv->i2c, TRUE, TRUE);
311     pPriv->i2c = NULL;
312 }
313
314 Bool
315 NV50CreateOutputs(ScrnInfoPtr pScrn)
316 {
317     NVPtr pNv = NVPTR(pScrn);
318     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
319     int i;
320
321     if(!NV50ReadPortMapping(pScrn->scrnIndex, pNv))
322         return FALSE;
323
324     /* For each DDC port, create an output for the attached ORs */
325     for(i = 0; i < 4; i++) {
326         xf86OutputPtr dac = NULL, sor = NULL;
327         I2CBusPtr i2c;
328         char i2cName[16];
329
330         if(pNv->i2cMap[i].dac == -1 && pNv->i2cMap[i].sor == -1)
331             /* No outputs on this port */
332             continue;
333
334         snprintf(i2cName, sizeof(i2cName), "I2C%i", i);
335         i2c = NV50I2CInit(pScrn, i2cName, i);
336         if(!i2c) {
337             xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
338                        "Failed to initialize I2C for port %i.\n",
339                        i);
340             continue;
341         }
342
343         if(pNv->i2cMap[i].dac != -1)
344             dac = NV50CreateDac(pScrn, pNv->i2cMap[i].dac);
345         if(pNv->i2cMap[i].sor != -1)
346             sor = NV50CreateSor(pScrn, pNv->i2cMap[i].sor);
347
348         if(dac) {
349             NV50OutputPrivPtr pPriv = dac->driver_private;
350
351             pPriv->partner = sor;
352             pPriv->i2c = i2c;
353         }
354         if(sor) {
355             NV50OutputPrivPtr pPriv = sor->driver_private;
356
357             pPriv->partner = dac;
358             pPriv->i2c = i2c;
359         }
360     }
361
362     /* For each output, set the crtc and clone masks */
363     for(i = 0; i < xf86_config->num_output; i++) {
364         xf86OutputPtr output = xf86_config->output[i];
365
366         /* Any output can connect to any head */
367         output->possible_crtcs = 0x3;
368         output->possible_clones = 0;
369     }
370
371     return TRUE;
372 }