fence: ref could destroy the object it was referencing, fix that!
[nouveau] / src / nv_i2c.c
1 /*
2  * Copyright 2006 Stephane Marchesin
3  * Copyright 2007 Maarten Maathuis
4  *
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:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
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
21  * SOFTWARE.
22  */
23
24 #include "nv_include.h"
25
26 /*
27  * DDC1 support only requires DDC_SDA_MASK,
28  * DDC2 support requires DDC_SDA_MASK and DDC_SCL_MASK
29  */
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)
34
35 static void
36 NVI2CGetBits(I2CBusPtr b, int *clock, int *data)
37 {
38         NVPtr pNv = NVPTR(xf86Screens[b->scrnIndex]);
39         unsigned char val;
40
41         /* Get the result. */
42         /* Doing this on head 0 seems fine. */
43         if (pNv->VBIOS.chip_version == 0x51)
44                 val = NVReadCRTC(pNv, 0, b->DriverPrivate.uval) >> 16;
45         else
46                 val = NVReadVgaCrtc(pNv, 0, b->DriverPrivate.uval);
47
48         *clock = (val & DDC_SCL_READ_MASK) != 0;
49         *data  = (val & DDC_SDA_READ_MASK) != 0;
50 }
51
52 static void
53 NVI2CPutBits(I2CBusPtr b, int clock, int data)
54 {
55         NVPtr pNv = NVPTR(xf86Screens[b->scrnIndex]);
56         uint32_t val;
57
58         /* Doing this on head 0 seems fine. */
59         if (pNv->VBIOS.chip_version == 0x51)
60                 val = NVReadCRTC(pNv, 0, b->DriverPrivate.uval);
61         else
62                 val = NVReadVgaCrtc(pNv, 0, b->DriverPrivate.uval + 1);
63
64         val = (val & ~0xf) | 1;
65
66         if (clock)
67                 val |= DDC_SCL_WRITE_MASK;
68         else
69                 val &= ~DDC_SCL_WRITE_MASK;
70
71         if (data)
72                 val |= DDC_SDA_WRITE_MASK;
73         else
74                 val &= ~DDC_SDA_WRITE_MASK;
75
76         /* Doing this on head 0 seems fine. */
77         if (pNv->VBIOS.chip_version == 0x51)
78                 NVWriteCRTC(pNv, 0, b->DriverPrivate.uval, val);
79         else
80                 NVWriteVgaCrtc(pNv, 0, b->DriverPrivate.uval + 1, val);
81 }
82
83 static uint32_t NV50_GetI2CPort(ScrnInfoPtr pScrn, int index)
84 {
85         uint32_t reg;
86
87         switch (index) {
88                 case 0:
89                         reg = NV50_PCONNECTOR_I2C_PORT_0;
90                         break;
91                 case 1:
92                         reg = NV50_PCONNECTOR_I2C_PORT_1;
93                         break;
94                 case 2:
95                         reg = NV50_PCONNECTOR_I2C_PORT_2;
96                         break;
97                 case 3:
98                         reg = NV50_PCONNECTOR_I2C_PORT_3;
99                         break;
100                 case 4:
101                         reg = NV50_PCONNECTOR_I2C_PORT_4;
102                         break;
103                 case 5:
104                         reg = NV50_PCONNECTOR_I2C_PORT_5;
105                         break;
106                 default:
107                         xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Invalid i2c port number %d, defaulting to 0.\n", index);
108                         reg = NV50_PCONNECTOR_I2C_PORT_0;
109                         break;
110         }
111
112         return reg;
113 }
114
115 static void NV50_I2CPutBits(I2CBusPtr b, int clock, int data)
116 {
117         NVPtr pNv = NVPTR(xf86Screens[b->scrnIndex]);
118
119         NVWrite(pNv, NV50_GetI2CPort(xf86Screens[b->scrnIndex], b->DriverPrivate.val), (4 | clock | data << 1));
120 }
121
122 static void NV50_I2CGetBits(I2CBusPtr b, int *clock, int *data)
123 {
124         NVPtr pNv = NVPTR(xf86Screens[b->scrnIndex]);
125         unsigned char val;
126
127         val = NVRead(pNv, NV50_GetI2CPort(xf86Screens[b->scrnIndex], b->DriverPrivate.val));
128         *clock = !!(val & 1);
129         *data = !!(val & 2);
130 }
131
132 Bool
133 NV_I2CInit(ScrnInfoPtr pScrn, I2CBusPtr *bus_ptr, int i2c_reg, char *name)
134 {
135         I2CBusPtr pI2CBus;
136         NVPtr pNv = NVPTR(pScrn);
137
138         pI2CBus = xf86CreateI2CBusRec();
139         if(!pI2CBus)
140                 return FALSE;
141
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;
153         } else {
154                 pI2CBus->I2CPutBits = NVI2CPutBits;
155                 pI2CBus->I2CGetBits = NVI2CGetBits;
156                 pI2CBus->AcknTimeout = 5;
157         }
158
159         if (pNv->VBIOS.chip_version == 0x51)
160                 pI2CBus->DriverPrivate.uval = 0x600800 + i2c_reg;
161         else
162                 pI2CBus->DriverPrivate.uval = i2c_reg;
163
164         if (!xf86I2CBusInit(pI2CBus))
165                 return FALSE;
166
167         *bus_ptr = pI2CBus;
168         return TRUE;
169 }
170