2 * Copyright 2006 Stephane Marchesin
3 * Copyright 2007 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 "nv_include.h"
27 * DDC1 support only requires DDC_SDA_MASK,
28 * DDC2 support requires DDC_SDA_MASK and DDC_SCL_MASK
30 #define DDC_SDA_READ_MASK (1 << 3)
31 #define DDC_SCL_READ_MASK (1 << 2)
32 #define DDC_SDA_WRITE_MASK (1 << 4)
33 #define DDC_SCL_WRITE_MASK (1 << 5)
36 NVI2CGetBits(I2CBusPtr b, int *clock, int *data)
38 NVPtr pNv = NVPTR(xf86Screens[b->scrnIndex]);
42 /* Doing this on head 0 seems fine. */
43 if (pNv->VBIOS.chip_version == 0x51)
44 val = NVReadCRTC(pNv, 0, b->DriverPrivate.uval) >> 16;
46 val = NVReadVgaCrtc(pNv, 0, b->DriverPrivate.uval);
48 *clock = (val & DDC_SCL_READ_MASK) != 0;
49 *data = (val & DDC_SDA_READ_MASK) != 0;
53 NVI2CPutBits(I2CBusPtr b, int clock, int data)
55 NVPtr pNv = NVPTR(xf86Screens[b->scrnIndex]);
58 /* Doing this on head 0 seems fine. */
59 if (pNv->VBIOS.chip_version == 0x51)
60 val = NVReadCRTC(pNv, 0, b->DriverPrivate.uval);
62 val = NVReadVgaCrtc(pNv, 0, b->DriverPrivate.uval + 1);
64 val = (val & ~0xf) | 1;
67 val |= DDC_SCL_WRITE_MASK;
69 val &= ~DDC_SCL_WRITE_MASK;
72 val |= DDC_SDA_WRITE_MASK;
74 val &= ~DDC_SDA_WRITE_MASK;
76 /* Doing this on head 0 seems fine. */
77 if (pNv->VBIOS.chip_version == 0x51)
78 NVWriteCRTC(pNv, 0, b->DriverPrivate.uval, val);
80 NVWriteVgaCrtc(pNv, 0, b->DriverPrivate.uval + 1, val);
83 static uint32_t NV50_GetI2CPort(ScrnInfoPtr pScrn, int index)
89 reg = NV50_PCONNECTOR_I2C_PORT_0;
92 reg = NV50_PCONNECTOR_I2C_PORT_1;
95 reg = NV50_PCONNECTOR_I2C_PORT_2;
98 reg = NV50_PCONNECTOR_I2C_PORT_3;
101 reg = NV50_PCONNECTOR_I2C_PORT_4;
104 reg = NV50_PCONNECTOR_I2C_PORT_5;
107 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Invalid i2c port number %d, defaulting to 0.\n", index);
108 reg = NV50_PCONNECTOR_I2C_PORT_0;
115 static void NV50_I2CPutBits(I2CBusPtr b, int clock, int data)
117 NVPtr pNv = NVPTR(xf86Screens[b->scrnIndex]);
119 NVWrite(pNv, NV50_GetI2CPort(xf86Screens[b->scrnIndex], b->DriverPrivate.val), (4 | clock | data << 1));
122 static void NV50_I2CGetBits(I2CBusPtr b, int *clock, int *data)
124 NVPtr pNv = NVPTR(xf86Screens[b->scrnIndex]);
127 val = NVRead(pNv, NV50_GetI2CPort(xf86Screens[b->scrnIndex], b->DriverPrivate.val));
128 *clock = !!(val & 1);
133 NV_I2CInit(ScrnInfoPtr pScrn, I2CBusPtr *bus_ptr, int i2c_reg, char *name)
136 NVPtr pNv = NVPTR(pScrn);
138 pI2CBus = xf86CreateI2CBusRec();
142 pI2CBus->BusName = name;
143 pI2CBus->scrnIndex = pScrn->scrnIndex;
144 if (pNv->Architecture == NV_ARCH_50) {
145 pI2CBus->I2CPutBits = NV50_I2CPutBits;
146 pI2CBus->I2CGetBits = NV50_I2CGetBits;
147 /* Could this be used for the rest as well? */
148 pI2CBus->ByteTimeout = 2200; /* VESA DDC spec 3 p. 43 (+10 %) */
149 pI2CBus->StartTimeout = 550;
150 pI2CBus->BitTimeout = 40;
151 pI2CBus->ByteTimeout = 40;
152 pI2CBus->AcknTimeout = 40;
154 pI2CBus->I2CPutBits = NVI2CPutBits;
155 pI2CBus->I2CGetBits = NVI2CGetBits;
156 pI2CBus->AcknTimeout = 5;
159 if (pNv->VBIOS.chip_version == 0x51)
160 pI2CBus->DriverPrivate.uval = 0x600800 + i2c_reg;
162 pI2CBus->DriverPrivate.uval = i2c_reg;
164 if (!xf86I2CBusInit(pI2CBus))