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.
34 #include "nv_include.h"
35 #include "nv50_type.h"
36 #include "nv50_display.h"
37 #include "nv50_output.h"
41 static Bool NV50ReadPortMapping(int scrnIndex, NVPtr pNv)
43 unsigned const char *VBIOS = pNv->VBIOS;
44 unsigned char *table2;
45 unsigned char headerSize, entries;
53 /* Clear the i2c map to invalid */
54 for(i = 0; i < 4; i++)
55 pNv->i2cMap[i].dac = pNv->i2cMap[i].sor = -1;
57 if(*(CARD16*)VBIOS != 0xaa55) goto fail;
59 a = *(CARD16*)(VBIOS + 0x36);
60 table2 = (unsigned char*)VBIOS + a;
62 if(table2[0] != 0x40) goto fail;
64 b = *(CARD32*)(table2 + 6);
65 if(b != 0x4edcbdcb) goto fail;
67 headerSize = table2[1];
70 for(i = 0; i < entries; i++) {
74 b = *(CARD32*)&table2[headerSize + 8*i];
76 port = (b >> 4) & 0xf;
77 or = ffs((b >> 24) & 0xf) - 1;
85 if(pNv->i2cMap[port].dac != -1) {
86 xf86DrvMsg(scrnIndex, X_WARNING,
87 "DDC routing table corrupt! DAC %i -> %i "
89 or, pNv->i2cMap[port].dac, port);
91 pNv->i2cMap[port].dac = or;
96 if(pNv->i2cMap[port].sor != -1)
97 xf86DrvMsg(scrnIndex, X_WARNING,
98 "DDC routing table corrupt! SOR %i -> %i "
100 or, pNv->i2cMap[port].sor, port);
101 pNv->i2cMap[port].sor = or;
104 pNv->lvds.present = TRUE;
111 xf86DrvMsg(scrnIndex, X_PROBED, "Connector map:\n");
112 if (pNv->lvds.present) {
113 xf86DrvMsg(scrnIndex, X_PROBED,
114 " [N/A] -> SOR%i (LVDS)\n", pNv->lvds.or);
116 for(i = 0; i < 4; i++) {
117 if(pNv->i2cMap[i].dac != -1)
118 xf86DrvMsg(scrnIndex, X_PROBED, " Bus %i -> DAC%i\n", i, pNv->i2cMap[i].dac);
119 if(pNv->i2cMap[i].sor != -1)
120 xf86DrvMsg(scrnIndex, X_PROBED, " Bus %i -> SOR%i\n", i, pNv->i2cMap[i].sor);
126 xf86DrvMsg(scrnIndex, X_ERROR, "Couldn't find the DDC routing table. "
127 "Mode setting will probably fail!\n");
131 static void NV50_I2CPutBits(I2CBusPtr b, int clock, int data)
133 NVPtr pNv = NVPTR(xf86Screens[b->scrnIndex]);
134 const int off = b->DriverPrivate.val * 0x18;
136 pNv->REGS[(0x0000E138+off)/4] = 4 | clock | data << 1;
139 static void NV50_I2CGetBits(I2CBusPtr b, int *clock, int *data)
141 NVPtr pNv = NVPTR(xf86Screens[b->scrnIndex]);
142 const int off = b->DriverPrivate.val * 0x18;
145 val = pNv->REGS[(0x0000E138+off)/4];
146 *clock = !!(val & 1);
151 NV50I2CInit(ScrnInfoPtr pScrn, const char *name, const int port)
155 /* Allocate the I2C bus structure */
156 i2c = xf86CreateI2CBusRec();
157 if(!i2c) return NULL;
159 i2c->BusName = strdup(name);
160 i2c->scrnIndex = pScrn->scrnIndex;
161 i2c->I2CPutBits = NV50_I2CPutBits;
162 i2c->I2CGetBits = NV50_I2CGetBits;
163 i2c->ByteTimeout = 2200; /* VESA DDC spec 3 p. 43 (+10 %) */
164 i2c->StartTimeout = 550;
165 i2c->BitTimeout = 40;
166 i2c->ByteTimeout = 40;
167 i2c->AcknTimeout = 40;
168 i2c->DriverPrivate.val = port;
170 if(xf86I2CBusInit(i2c)) {
179 NV50OutputSetPClk(xf86OutputPtr output, int pclk)
181 NV50OutputPrivPtr pPriv = output->driver_private;
184 pPriv->set_pclk(output, pclk);
188 NV50OutputModeValid(xf86OutputPtr output, DisplayModePtr mode)
190 if (mode->Clock > 400000)
191 return MODE_CLOCK_HIGH;
192 if (mode->Clock < 25000)
193 return MODE_CLOCK_LOW;
199 NV50OutputPrepare(xf86OutputPtr output)
204 NV50OutputCommit(xf86OutputPtr output)
209 ProbeDDC(I2CBusPtr i2c)
211 ScrnInfoPtr pScrn = xf86Screens[i2c->scrnIndex];
212 NVPtr pNv = NVPTR(pScrn);
213 xf86MonPtr monInfo = NULL;
214 const int bus = i2c->DriverPrivate.val, off = bus * 0x18;
216 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
217 "Probing for EDID on I2C bus %i...\n", bus);
218 pNv->REGS[(0x0000E138+off)/4] = 7;
219 /* Should probably use xf86OutputGetEDID here */
220 monInfo = xf86DoEDID_DDC2(pScrn->scrnIndex, i2c);
221 pNv->REGS[(0x0000E138+off)/4] = 3;
224 xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
225 "DDC detected a %s:\n", monInfo->features.input_type ?
227 xf86PrintEDID(monInfo);
229 xf86DrvMsg(pScrn->scrnIndex, X_INFO, " ... none found\n");
236 * Read an EDID from the i2c port. Perform load detection on the DAC (if
237 * present) to see if the display is connected via VGA. Sets the cached status
238 * of both outputs. The status is marked dirty again in the BlockHandler.
240 void NV50OutputPartnersDetect(xf86OutputPtr dac, xf86OutputPtr sor, I2CBusPtr i2c)
242 xf86MonPtr monInfo = ProbeDDC(i2c);
243 xf86OutputPtr connected = NULL;
244 Bool load = dac && NV50DacLoadDetect(dac);
247 NV50OutputPrivPtr pPriv = dac->driver_private;
250 pPriv->cached_status = XF86OutputStatusConnected;
253 pPriv->cached_status = XF86OutputStatusDisconnected;
258 NV50OutputPrivPtr pPriv = sor->driver_private;
260 if(monInfo && !load) {
261 pPriv->cached_status = XF86OutputStatusConnected;
264 pPriv->cached_status = XF86OutputStatusDisconnected;
269 xf86OutputSetEDID(connected, monInfo);
273 * Reset the cached output status for all outputs. Called from NV50BlockHandler.
276 NV50OutputResetCachedStatus(ScrnInfoPtr pScrn)
278 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
281 for(i = 0; i < xf86_config->num_output; i++) {
282 NV50OutputPrivPtr pPriv = xf86_config->output[i]->driver_private;
283 pPriv->cached_status = XF86OutputStatusUnknown;
288 NV50OutputGetDDCModes(xf86OutputPtr output)
290 /* The EDID is read as part of the detect step */
291 output->funcs->detect(output);
292 return xf86OutputGetEDIDModes(output);
296 NV50OutputDestroy(xf86OutputPtr output)
298 NV50OutputPrivPtr pPriv = output->driver_private;
301 ((NV50OutputPrivPtr)pPriv->partner->driver_private)->partner = NULL;
303 xf86DestroyI2CBusRec(pPriv->i2c, TRUE, TRUE);
308 NV50CreateOutputs(ScrnInfoPtr pScrn)
310 NVPtr pNv = NVPTR(pScrn);
311 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
314 if(!NV50ReadPortMapping(pScrn->scrnIndex, pNv))
317 /* For each DDC port, create an output for the attached ORs */
318 for(i = 0; i < 4; i++) {
319 xf86OutputPtr dac = NULL, sor = NULL;
323 if(pNv->i2cMap[i].dac == -1 && pNv->i2cMap[i].sor == -1)
324 /* No outputs on this port */
327 snprintf(i2cName, sizeof(i2cName), "I2C%i", i);
328 i2c = NV50I2CInit(pScrn, i2cName, i);
330 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
331 "Failed to initialize I2C for port %i.\n",
336 if(pNv->i2cMap[i].dac != -1)
337 dac = NV50CreateDac(pScrn, pNv->i2cMap[i].dac);
338 if(pNv->i2cMap[i].sor != -1)
339 sor = NV50CreateSor(pScrn, pNv->i2cMap[i].sor, TMDS);
342 NV50OutputPrivPtr pPriv = dac->driver_private;
344 pPriv->partner = sor;
346 pPriv->scale = NV50_SCALE_OFF;
349 NV50OutputPrivPtr pPriv = sor->driver_private;
351 pPriv->partner = dac;
353 pPriv->scale = NV50_SCALE_ASPECT;
357 if (pNv->lvds.present) {
358 xf86OutputPtr lvds = NV50CreateSor(pScrn, pNv->lvds.or, LVDS);
359 NV50OutputPrivPtr pPriv = lvds->driver_private;
361 pPriv->scale = NV50_SCALE_ASPECT;
364 /* For each output, set the crtc and clone masks */
365 for(i = 0; i < xf86_config->num_output; i++) {
366 xf86OutputPtr output = xf86_config->output[i];
368 /* Any output can connect to any head */
369 output->possible_crtcs = 0x3;
370 output->possible_clones = 0;
376 #endif /* ENABLE_RANDR12 */