Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1029 | serge | 1 | /* |
2 | * Copyright 2007, 2008 Egbert Eich |
||
3 | * Copyright 2007, 2008 Luc Verhaegen |
||
4 | * Copyright 2007, 2008 Matthias Hopf |
||
5 | * Copyright 2007, 2008 Advanced Micro Devices, Inc. |
||
6 | * |
||
7 | * Permission is hereby granted, free of charge, to any person obtaining a |
||
8 | * copy of this software and associated documentation files (the "Software"), |
||
9 | * to deal in the Software without restriction, including without limitation |
||
10 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||
11 | * and/or sell copies of the Software, and to permit persons to whom the |
||
12 | * Software is furnished to do so, subject to the following conditions: |
||
13 | * |
||
14 | * The above copyright notice and this permission notice shall be included in |
||
15 | * all copies or substantial portions of the Software. |
||
16 | * |
||
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||
20 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
||
21 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
||
22 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
||
23 | * OTHER DEALINGS IN THE SOFTWARE. |
||
24 | */ |
||
25 | |||
26 | #ifdef HAVE_CONFIG_H |
||
27 | #include "config.h" |
||
28 | #endif |
||
29 | #include "xf86.h" |
||
30 | #if HAVE_XF86_ANSIC_H |
||
31 | # include "xf86_ansic.h" |
||
32 | #else |
||
33 | # include |
||
34 | # include |
||
35 | #endif |
||
36 | |||
37 | #include "rhd.h" |
||
38 | #include "edid.h" |
||
39 | #include "rhd_i2c.h" |
||
40 | #include "xf86DDC.h" |
||
41 | |||
42 | #include "rhd_regs.h" |
||
43 | |||
44 | #ifdef ATOM_BIOS |
||
45 | #include "rhd_atombios.h" |
||
46 | #endif |
||
47 | |||
48 | #define MAX_I2C_LINES 6 |
||
49 | |||
50 | #define RHD_I2C_STATUS_LOOPS 5000 |
||
51 | |||
52 | enum rhdDDClines { |
||
53 | rhdDdc1data = 0, |
||
54 | rhdDdc2data = 2, |
||
55 | rhdDdc3data = 4, |
||
56 | rhdDdc4data = 6, /* arbirarily choosen */ |
||
57 | rhdVIP_DOUT_scl = 0x41, |
||
58 | rhdDvoData12 = 0x28, |
||
59 | rhdDdc5data = 0x48, |
||
60 | rhdDdc6data = 0x4a, |
||
61 | rhdDdc1clk = 1, |
||
62 | rhdDdc2clk = 3, |
||
63 | rhdDdc3clk = 5, |
||
64 | rhdDdc4clk = 7, /* arbirarily choosen */ |
||
65 | rhdVIP_DOUTvipclk = 0x42, |
||
66 | rhdDvoData13 = 0x29, |
||
67 | rhdDdc5clk = 0x49, |
||
68 | rhdDdc6clk = 0x4b, |
||
69 | rhdDdcUnknown |
||
70 | }; |
||
71 | |||
72 | typedef struct _rhdI2CRec |
||
73 | { |
||
74 | CARD16 prescale; |
||
75 | union { |
||
76 | CARD8 line; |
||
77 | struct i2cGpio { |
||
78 | enum rhdDDClines Sda; |
||
79 | enum rhdDDClines Scl; |
||
80 | CARD32 SdaReg; |
||
81 | CARD32 SclReg; |
||
82 | } Gpio; |
||
83 | } u; |
||
84 | int scrnIndex; |
||
85 | } rhdI2CRec; |
||
86 | |||
87 | enum _rhdR6xxI2CBits { |
||
88 | /* R6_DC_I2C_TRANSACTION0 */ |
||
89 | R6_DC_I2C_RW0 = (0x1 << 0), |
||
90 | R6_DC_I2C_STOP_ON_NACK0 = (0x1 << 8), |
||
91 | R6_DC_I2C_ACK_ON_READ0 = (0x1 << 9), |
||
92 | R6_DC_I2C_START0 = (0x1 << 12), |
||
93 | R6_DC_I2C_STOP0 = (0x1 << 13), |
||
94 | R6_DC_I2C_COUNT0 = (0xff << 16), |
||
95 | /* R6_DC_I2C_TRANSACTION1 */ |
||
96 | R6_DC_I2C_RW1 = (0x1 << 0), |
||
97 | R6_DC_I2C_STOP_ON_NACK1 = (0x1 << 8), |
||
98 | R6_DC_I2C_ACK_ON_READ1 = (0x1 << 9), |
||
99 | R6_DC_I2C_START1 = (0x1 << 12), |
||
100 | R6_DC_I2C_STOP1 = (0x1 << 13), |
||
101 | R6_DC_I2C_COUNT1 = (0xff << 16), |
||
102 | /* R6_DC_I2C_DATA */ |
||
103 | R6_DC_I2C_DATA_RW = (0x1 << 0), |
||
104 | R6_DC_I2C_DATA_BIT = (0xff << 8), |
||
105 | R6_DC_I2C_INDEX = (0xff << 16), |
||
106 | R6_DC_I2C_INDEX_WRITE = (0x1 << 31), |
||
107 | /* R6_DC_I2C_CONTROL */ |
||
108 | R6_DC_I2C_GO = (0x1 << 0), |
||
109 | R6_DC_I2C_SOFT_RESET = (0x1 << 1), |
||
110 | R6_DC_I2C_SEND_RESET = (0x1 << 2), |
||
111 | R6_DC_I2C_SW_STATUS_RESET = (0x1 << 3), |
||
112 | R6_DC_I2C_SDVO_EN = (0x1 << 4), |
||
113 | R6_DC_I2C_SDVO_ADDR_SEL = (0x1 << 6), |
||
114 | R6_DC_I2C_DDC_SELECT = (0x7 << 8), |
||
115 | R6_DC_I2C_TRANSACTION_COUNT = (0x3 << 20), |
||
116 | R6_DC_I2C_SW_DONE_INT = (0x1 << 0), |
||
117 | R6_DC_I2C_SW_DONE_ACK = (0x1 << 1), |
||
118 | R6_DC_I2C_SW_DONE_MASK = (0x1 << 2), |
||
119 | R6_DC_I2C_DDC1_HW_DONE_INT = (0x1 << 4), |
||
120 | R6_DC_I2C_DDC1_HW_DONE_ACK = (0x1 << 5), |
||
121 | R6_DC_I2C_DDC1_HW_DONE_MASK = (0x1 << 6), |
||
122 | R6_DC_I2C_DDC2_HW_DONE_INT = (0x1 << 8), |
||
123 | R6_DC_I2C_DDC2_HW_DONE_ACK = (0x1 << 9), |
||
124 | R6_DC_I2C_DDC2_HW_DONE_MASK = (0x1 << 10), |
||
125 | R6_DC_I2C_DDC3_HW_DONE_INT = (0x1 << 12), |
||
126 | R6_DC_I2C_DDC3_HW_DONE_ACK = (0x1 << 13), |
||
127 | R6_DC_I2C_DDC3_HW_DONE_MASK = (0x1 << 14), |
||
128 | R6_DC_I2C_DDC4_HW_DONE_INT = (0x1 << 16), |
||
129 | R6_DC_I2C_DDC4_HW_DONE_ACK = (0x1 << 17), |
||
130 | R6_DC_I2C_DDC4_HW_DONE_MASK = (0x1 << 18), |
||
131 | /* R6_DC_I2C_SW_STATUS */ |
||
132 | R6_DC_I2C_SW_STATUS_BIT = (0x3 << 0), |
||
133 | R6_DC_I2C_SW_DONE = (0x1 << 2), |
||
134 | R6_DC_I2C_SW_ABORTED = (0x1 << 4), |
||
135 | R6_DC_I2C_SW_TIMEOUT = (0x1 << 5), |
||
136 | R6_DC_I2C_SW_INTERRUPTED = (0x1 << 6), |
||
137 | R6_DC_I2C_SW_BUFFER_OVERFLOW = (0x1 << 7), |
||
138 | R6_DC_I2C_SW_STOPPED_ON_NACK = (0x1 << 8), |
||
139 | R6_DC_I2C_SW_SDVO_NACK = (0x1 << 10), |
||
140 | R6_DC_I2C_SW_NACK0 = (0x1 << 12), |
||
141 | R6_DC_I2C_SW_NACK1 = (0x1 << 13), |
||
142 | R6_DC_I2C_SW_NACK2 = (0x1 << 14), |
||
143 | R6_DC_I2C_SW_NACK3 = (0x1 << 15), |
||
144 | R6_DC_I2C_SW_REQ = (0x1 << 18) |
||
145 | }; |
||
146 | |||
147 | enum _rhdR5xxI2CBits { |
||
148 | /* R5_DC_I2C_STATUS1 */ |
||
149 | R5_DC_I2C_DONE = (0x1 << 0), |
||
150 | R5_DC_I2C_NACK = (0x1 << 1), |
||
151 | R5_DC_I2C_HALT = (0x1 << 2), |
||
152 | R5_DC_I2C_GO = (0x1 << 3), |
||
153 | /* R5_DC_I2C_RESET */ |
||
154 | R5_DC_I2C_SOFT_RESET = (0x1 << 0), |
||
155 | R5_DC_I2C_ABORT = (0x1 << 8), |
||
156 | /* R5_DC_I2C_CONTROL1 */ |
||
157 | R5_DC_I2C_START = (0x1 << 0), |
||
158 | R5_DC_I2C_STOP = (0x1 << 1), |
||
159 | R5_DC_I2C_RECEIVE = (0x1 << 2), |
||
160 | R5_DC_I2C_EN = (0x1 << 8), |
||
161 | R5_DC_I2C_PIN_SELECT = (0x3 << 16), |
||
162 | /* R5_DC_I2C_CONTROL2 */ |
||
163 | R5_DC_I2C_ADDR_COUNT = (0x7 << 0), |
||
164 | R5_DC_I2C_DATA_COUNT = (0xf << 8), |
||
165 | R5_DC_I2C_PRESCALE_LOWER = (0xff << 16), |
||
166 | R5_DC_I2C_PRESCALE_UPPER = (0xff << 24), |
||
167 | /* R5_DC_I2C_CONTROL3 */ |
||
168 | R5_DC_I2C_DATA_DRIVE_EN = (0x1 << 0), |
||
169 | R5_DC_I2C_DATA_DRIVE_SEL = (0x1 << 1), |
||
170 | R5_DC_I2C_CLK_DRIVE_EN = (0x1 << 7), |
||
171 | R5_DC_I2C_RD_INTRA_BYTE_DELAY = (0xff << 8), |
||
172 | R5_DC_I2C_WR_INTRA_BYTE_DELAY = (0xff << 16), |
||
173 | R5_DC_I2C_TIME_LIMIT = (0xff << 24), |
||
174 | /* R5_DC_I2C_DATA */ |
||
175 | R5_DC_I2C_DATA_BIT = (0xff << 0), |
||
176 | /* R5_DC_I2C_INTERRUPT_CONTROL */ |
||
177 | R5_DC_I2C_INTERRUPT_STATUS = (0x1 << 0), |
||
178 | R5_DC_I2C_INTERRUPT_AK = (0x1 << 8), |
||
179 | R5_DC_I2C_INTERRUPT_ENABLE = (0x1 << 16), |
||
180 | /* R5_DC_I2C_ARBITRATION */ |
||
181 | R5_DC_I2C_SW_WANTS_TO_USE_I2C = (0x1 << 0), |
||
182 | R5_DC_I2C_SW_CAN_USE_I2C = (0x1 << 1), |
||
183 | R5_DC_I2C_SW_DONE_USING_I2C = (0x1 << 8), |
||
184 | R5_DC_I2C_HW_NEEDS_I2C = (0x1 << 9), |
||
185 | R5_DC_I2C_ABORT_HDCP_I2C = (0x1 << 16), |
||
186 | R5_DC_I2C_HW_USING_I2C = (0x1 << 17) |
||
187 | }; |
||
188 | |||
189 | enum _rhdRS69I2CBits { |
||
190 | /* RS69_DC_I2C_TRANSACTION0 */ |
||
191 | RS69_DC_I2C_RW0 = (0x1 << 0), |
||
192 | RS69_DC_I2C_STOP_ON_NACK0 = (0x1 << 8), |
||
193 | RS69_DC_I2C_START0 = (0x1 << 12), |
||
194 | RS69_DC_I2C_STOP0 = (0x1 << 13), |
||
195 | /* RS69_DC_I2C_TRANSACTION1 */ |
||
196 | RS69_DC_I2C_RW1 = (0x1 << 0), |
||
197 | RS69_DC_I2C_START1 = (0x1 << 12), |
||
198 | RS69_DC_I2C_STOP1 = (0x1 << 13), |
||
199 | /* RS69_DC_I2C_DATA */ |
||
200 | RS69_DC_I2C_DATA_RW = (0x1 << 0), |
||
201 | RS69_DC_I2C_INDEX_WRITE = (0x1 << 31), |
||
202 | /* RS69_DC_I2C_CONTROL */ |
||
203 | RS69_DC_I2C_GO = (0x1 << 0), |
||
204 | RS69_DC_I2C_TRANSACTION_COUNT = (0x3 << 20), |
||
205 | RS69_DC_I2C_SW_DONE_ACK = (0x1 << 1), |
||
206 | /* RS69_DC_I2C_SW_STATUS */ |
||
207 | RS69_DC_I2C_SW_DONE = (0x1 << 2), |
||
208 | RS69_DC_I2C_SW_ABORTED = (0x1 << 4), |
||
209 | RS69_DC_I2C_SW_TIMEOUT = (0x1 << 5), |
||
210 | RS69_DC_I2C_SW_INTERRUPTED= (0x1 << 6), |
||
211 | RS69_DC_I2C_SW_BUFFER_OVERFLOW= (0x1 << 7), |
||
212 | RS69_DC_I2C_SW_STOPPED_ON_NACK = (0x1 << 8), |
||
213 | RS69_DC_I2C_SW_NACK0 = (0x1 << 12), |
||
214 | RS69_DC_I2C_SW_NACK1 = (0x1 << 13) |
||
215 | }; |
||
216 | |||
217 | /* RV620 */ |
||
218 | enum rv620I2CBits { |
||
219 | /* GENERIC_I2C_CONTROL */ |
||
220 | RV62_DC_I2C_GO = (0x1 << 0), |
||
221 | RV62_GENERIC_I2C_GO = (0x1 << 0), |
||
222 | RV62_GENERIC_I2C_SOFT_RESET = (0x1 << 1), |
||
223 | RV62_GENERIC_I2C_SEND_RESET = (0x1 << 2), |
||
224 | /* GENERIC_I2C_INTERRUPT_CONTROL */ |
||
225 | RV62_GENERIC_I2C_DONE_INT = (0x1 << 0), |
||
226 | RV62_GENERIC_I2C_DONE_ACK = (0x1 << 1), |
||
227 | RV62_GENERIC_I2C_DONE_MASK = (0x1 << 2), |
||
228 | /* GENERIC_I2C_STATUS */ |
||
229 | RV62_GENERIC_I2C_STATUS_BIT = (0xf << 0), |
||
230 | RV62_GENERIC_I2C_DONE = (0x1 << 4), |
||
231 | RV62_GENERIC_I2C_ABORTED = (0x1 << 5), |
||
232 | RV62_GENERIC_I2C_TIMEOUT = (0x1 << 6), |
||
233 | RV62_GENERIC_I2C_STOPPED_ON_NACK = (0x1 << 9), |
||
234 | RV62_GENERIC_I2C_NACK = (0x1 << 10), |
||
235 | /* GENERIC_I2C_SPEED */ |
||
236 | RV62_GENERIC_I2C_THRESHOLD = (0x3 << 0), |
||
237 | RV62_GENERIC_I2C_DISABLE_FILTER_DURING_STALL = (0x1 << 4), |
||
238 | RV62_GENERIC_I2C_PRESCALE = (0xffff << 16), |
||
239 | /* GENERIC_I2C_SETUP */ |
||
240 | RV62_GENERIC_I2C_DATA_DRIVE_EN = (0x1 << 0), |
||
241 | RV62_GENERIC_I2C_DATA_DRIVE_SEL = (0x1 << 1), |
||
242 | RV62_GENERIC_I2C_CLK_DRIVE_EN = (0x1 << 7), |
||
243 | RV62_GENERIC_I2C_INTRA_BYTE_DELAY = (0xff << 8), |
||
244 | RV62_GENERIC_I2C_TIME_LIMIT = (0xff << 24), |
||
245 | /* GENERIC_I2C_TRANSACTION */ |
||
246 | RV62_GENERIC_I2C_RW = (0x1 << 0), |
||
247 | RV62_GENERIC_I2C_STOP_ON_NACK = (0x1 << 8), |
||
248 | RV62_GENERIC_I2C_ACK_ON_READ = (0x1 << 9), |
||
249 | RV62_GENERIC_I2C_START = (0x1 << 12), |
||
250 | RV62_GENERIC_I2C_STOP = (0x1 << 13), |
||
251 | RV62_GENERIC_I2C_COUNT = (0xf << 16), |
||
252 | /* GENERIC_I2C_DATA */ |
||
253 | RV62_GENERIC_I2C_DATA_RW = (0x1 << 0), |
||
254 | RV62_GENERIC_I2C_DATA_BIT = (0xff << 8), |
||
255 | RV62_GENERIC_I2C_INDEX = (0xf << 16), |
||
256 | RV62_GENERIC_I2C_INDEX_WRITE = (0x1 << 31), |
||
257 | /* GENERIC_I2C_PIN_SELECTION */ |
||
258 | RV62_GENERIC_I2C_SCL_PIN_SEL_SHIFT = 0, |
||
259 | RV62_GENERIC_I2C_SCL_PIN_SEL = (0x7f << RV62_GENERIC_I2C_SCL_PIN_SEL_SHIFT), |
||
260 | RV62_GENERIC_I2C_SDA_PIN_SEL_SHIFT = 8, |
||
261 | RV62_GENERIC_I2C_SDA_PIN_SEL = (0x7f << RV62_GENERIC_I2C_SDA_PIN_SEL_SHIFT) |
||
262 | }; |
||
263 | |||
264 | /* |
||
265 | * |
||
266 | */ |
||
267 | static enum rhdDDClines |
||
268 | getDDCLineFromGPIO(int scrnIndex, CARD32 gpio, int shift) |
||
269 | { |
||
270 | switch (gpio) { |
||
271 | case 0x1f90: |
||
272 | switch (shift) { |
||
273 | case 0: |
||
274 | return rhdDdc1clk; /* ddc1 clk */ |
||
275 | case 8: |
||
276 | return rhdDdc1data; /* ddc1 data */ |
||
277 | } |
||
278 | break; |
||
279 | case 0x1f94: /* ddc2 */ |
||
280 | switch (shift) { |
||
281 | case 0: |
||
282 | return rhdDdc2clk; /* ddc2 clk */ |
||
283 | case 8: |
||
284 | return rhdDdc2data; /* ddc2 data */ |
||
285 | } |
||
286 | break; |
||
287 | case 0x1f98: /* ddc3 */ |
||
288 | switch (shift) { |
||
289 | case 0: |
||
290 | return rhdDdc3clk; /* ddc3 clk */ |
||
291 | case 8: |
||
292 | return rhdDdc3data; /* ddc3 data */ |
||
293 | } |
||
294 | case 0x1f80: /* ddc4 - on r6xx */ |
||
295 | switch (shift) { |
||
296 | case 0: |
||
297 | return rhdDdc4clk; /* ddc4 clk */ |
||
298 | case 8: |
||
299 | return rhdDdc4data; /* ddc4 data */ |
||
300 | } |
||
301 | break; |
||
302 | case 0x1f88: /* ddc5 */ |
||
303 | switch (shift) { |
||
304 | case 0: |
||
305 | return rhdVIP_DOUTvipclk; /* ddc5 clk */ |
||
306 | case 8: |
||
307 | return rhdVIP_DOUT_scl; /* ddc5 data */ |
||
308 | } |
||
309 | break; |
||
310 | case 0x1fda: /* ddc6 */ |
||
311 | switch (shift) { |
||
312 | case 0: |
||
313 | return rhdDvoData13; /* ddc6 clk */ |
||
314 | case 1: |
||
315 | return rhdDvoData12; /* ddc6 data */ |
||
316 | } |
||
317 | break; |
||
318 | case 0x1fc4: |
||
319 | switch (shift) { |
||
320 | case 0: |
||
321 | return rhdDdc5clk; |
||
322 | case 8: |
||
323 | return rhdDdc5data; |
||
324 | } |
||
325 | break; |
||
326 | case 0x1fe8: /* ddc6 */ |
||
327 | switch (shift) { |
||
328 | case 0: |
||
329 | return rhdDdc6clk; /* ddc6 clk */ |
||
330 | case 8: |
||
331 | return rhdDdc6data; /* ddc6 data */ |
||
332 | } |
||
333 | break; |
||
334 | } |
||
335 | |||
336 | xf86DrvMsg(scrnIndex, X_WARNING, |
||
337 | "%s: Failed to match GPIO 0x%04X.%d with a known DDC line\n", |
||
338 | __func__, (unsigned int) gpio, shift); |
||
339 | return rhdDdcUnknown; |
||
340 | } |
||
341 | |||
342 | /* |
||
343 | * |
||
344 | */ |
||
345 | static Bool |
||
346 | rhdI2CGetDataClkLines(RHDPtr rhdPtr, int line, |
||
347 | enum rhdDDClines *scl, enum rhdDDClines *sda, |
||
348 | CARD32 *sda_reg, CARD32 *scl_reg) |
||
349 | { |
||
350 | #ifdef ATOM_BIOS |
||
351 | AtomBiosResult result; |
||
352 | AtomBiosArgRec data; |
||
353 | |||
354 | /* scl register */ |
||
355 | data.val = line & 0x0f; |
||
356 | result = RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, |
||
357 | ATOM_GPIO_I2C_CLK_MASK, &data); |
||
358 | if (result != ATOM_SUCCESS) |
||
359 | return FALSE; |
||
360 | *scl_reg = data.val; |
||
361 | |||
362 | /* scl DDC line */ |
||
363 | data.val = line & 0x0f; |
||
364 | result = RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, |
||
365 | ATOM_GPIO_I2C_CLK_MASK_SHIFT, &data); |
||
366 | if (result != ATOM_SUCCESS) |
||
367 | return FALSE; |
||
368 | *scl = getDDCLineFromGPIO(rhdPtr->scrnIndex, *scl_reg, data.val); |
||
369 | |||
370 | /* sda register */ |
||
371 | data.val = line & 0x0f; |
||
372 | result = RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, |
||
373 | ATOM_GPIO_I2C_DATA_MASK, &data); |
||
374 | if (result != ATOM_SUCCESS) |
||
375 | return FALSE; |
||
376 | *sda_reg = data.val; |
||
377 | |||
378 | /* sda DDC line */ |
||
379 | data.val = line & 0x0f; |
||
380 | result = RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, |
||
381 | ATOM_GPIO_I2C_DATA_MASK_SHIFT, &data); |
||
382 | if (result != ATOM_SUCCESS) |
||
383 | return FALSE; |
||
384 | *sda = getDDCLineFromGPIO(rhdPtr->scrnIndex, *sda_reg, data.val); |
||
385 | |||
386 | if ((*scl == rhdDdcUnknown) || (*sda == rhdDdcUnknown)) { |
||
387 | xf86DrvMsg(rhdPtr->scrnIndex, X_WARNING, |
||
388 | "%s: failed to map gpio lines for DDC line %d\n", |
||
389 | __func__, line); |
||
390 | return FALSE; |
||
391 | } |
||
392 | |||
393 | return TRUE; |
||
394 | #else /* ATOM_BIOS */ |
||
395 | return FALSE; |
||
396 | #endif |
||
397 | } |
||
398 | |||
399 | /* R5xx */ |
||
400 | static Bool |
||
401 | rhd5xxI2CSetupStatus(I2CBusPtr I2CPtr, int line) |
||
402 | { |
||
403 | RHDFUNC(I2CPtr); |
||
404 | |||
405 | line &= 0xf; |
||
406 | |||
407 | |||
408 | switch (line) { |
||
409 | case 0: |
||
410 | RHDRegMask(I2CPtr, R5_DC_GPIO_DDC1_MASK, 0x0, 0xffff); |
||
411 | RHDRegMask(I2CPtr, R5_DC_GPIO_DDC1_A, 0x0, 0xffff); |
||
412 | RHDRegMask(I2CPtr, R6_DC_GPIO_DDC1_EN, 0x0, 0xffff); |
||
413 | break; |
||
414 | case 1: |
||
415 | RHDRegMask(I2CPtr, R5_DC_GPIO_DDC2_MASK, 0x0, 0xffff); |
||
416 | RHDRegMask(I2CPtr, R5_DC_GPIO_DDC2_A, 0x0, 0xffff); |
||
417 | RHDRegMask(I2CPtr, R6_DC_GPIO_DDC2_EN, 0x0, 0xffff); |
||
418 | break; |
||
419 | case 2: |
||
420 | RHDRegMask(I2CPtr, R5_DC_GPIO_DDC3_MASK, 0x0, 0xffff); |
||
421 | RHDRegMask(I2CPtr, R5_DC_GPIO_DDC3_A, 0x0, 0xffff); |
||
422 | RHDRegMask(I2CPtr, R5_DC_GPIO_DDC3_EN, 0x0, 0xffff); |
||
423 | break; |
||
424 | default: |
||
425 | xf86DrvMsg(I2CPtr->scrnIndex,X_ERROR, |
||
426 | "%s: Trying to initialize non-existent I2C line: %i\n", |
||
427 | __func__,line); |
||
428 | return FALSE; |
||
429 | } |
||
430 | return TRUE; |
||
431 | } |
||
432 | |||
433 | static Bool |
||
434 | rhd5xxI2CStatus(I2CBusPtr I2CPtr) |
||
435 | { |
||
436 | int count = RHD_I2C_STATUS_LOOPS; |
||
437 | CARD32 res; |
||
438 | |||
439 | RHDFUNC(I2CPtr); |
||
440 | |||
441 | while (count-- != 0) { |
||
442 | usleep (10); |
||
443 | if (((RHDRegRead(I2CPtr, R5_DC_I2C_STATUS1)) & R5_DC_I2C_GO) != 0) |
||
444 | continue; |
||
445 | res = RHDRegRead(I2CPtr, R5_DC_I2C_STATUS1); |
||
446 | RHDDebugVerb(I2CPtr->scrnIndex,1,"SW_STATUS: 0x%x %i\n", |
||
447 | (unsigned int)res,count); |
||
448 | if (res & R5_DC_I2C_DONE) |
||
449 | return TRUE; |
||
450 | else |
||
451 | return FALSE; |
||
452 | } |
||
453 | RHDRegMask(I2CPtr, R5_DC_I2C_RESET, R5_DC_I2C_ABORT, 0xff00); |
||
454 | return FALSE; |
||
455 | } |
||
456 | |||
457 | Bool |
||
458 | rhd5xxWriteReadChunk(I2CDevPtr i2cDevPtr, int line, I2CByte *WriteBuffer, |
||
459 | int nWrite, I2CByte *ReadBuffer, int nRead) |
||
460 | { |
||
461 | I2CSlaveAddr slave = i2cDevPtr->SlaveAddr; |
||
462 | I2CBusPtr I2CPtr = i2cDevPtr->pI2CBus; |
||
463 | rhdI2CPtr I2C = (rhdI2CPtr)(I2CPtr->DriverPrivate.ptr); |
||
464 | int prescale = I2C->prescale; |
||
465 | CARD32 save_I2C_CONTROL1, save_494; |
||
466 | CARD32 tmp32; |
||
467 | Bool ret = TRUE; |
||
468 | |||
469 | RHDFUNC(i2cDevPtr->pI2CBus); |
||
470 | |||
471 | RHDRegMask(I2CPtr, 0x28, 0x200, 0x200); |
||
472 | save_I2C_CONTROL1 = RHDRegRead(I2CPtr, R5_DC_I2C_CONTROL1); |
||
473 | save_494 = RHDRegRead(I2CPtr, 0x494); |
||
474 | RHDRegMask(I2CPtr, 0x494, 1, 1); |
||
475 | RHDRegMask(I2CPtr, R5_DC_I2C_ARBITRATION, |
||
476 | R5_DC_I2C_SW_WANTS_TO_USE_I2C, |
||
477 | R5_DC_I2C_SW_WANTS_TO_USE_I2C); |
||
478 | |||
479 | if (!RHDRegRead(I2CPtr, R5_DC_I2C_ARBITRATION) & R5_DC_I2C_SW_CAN_USE_I2C) { |
||
480 | RHDDebug(I2CPtr->scrnIndex, "%s SW cannot use I2C line %i\n",__func__,line); |
||
481 | ret = FALSE; |
||
482 | } else { |
||
483 | |||
484 | RHDRegMask(I2CPtr, R5_DC_I2C_STATUS1, R5_DC_I2C_DONE |
||
485 | | R5_DC_I2C_NACK |
||
486 | | R5_DC_I2C_HALT, 0xff); |
||
487 | RHDRegMask(I2CPtr, R5_DC_I2C_RESET, R5_DC_I2C_SOFT_RESET, 0xffff); |
||
488 | RHDRegWrite(I2CPtr, R5_DC_I2C_RESET, 0); |
||
489 | |||
490 | RHDRegMask(I2CPtr, R5_DC_I2C_CONTROL1, |
||
491 | (line & 0x0f) << 16 | R5_DC_I2C_EN, |
||
492 | R5_DC_I2C_PIN_SELECT | R5_DC_I2C_EN); |
||
493 | } |
||
494 | |||
495 | if (ret && (nWrite || !nRead)) { /* special case for bus probing */ |
||
496 | /* |
||
497 | * chip can't just write the slave address without data. |
||
498 | * Add a dummy byte. |
||
499 | */ |
||
500 | RHDRegWrite(I2CPtr, R5_DC_I2C_CONTROL2, |
||
501 | prescale << 16 | |
||
502 | (nWrite ? nWrite : 1) << 8 | 0x01); /* addr_cnt: 1 */ |
||
503 | RHDRegMask(I2CPtr, R5_DC_I2C_CONTROL3, |
||
504 | 0x30 << 24, 0xff << 24); /* time limit 30 */ |
||
505 | |||
506 | RHDRegWrite(I2CPtr, R5_DC_I2C_DATA, slave); |
||
507 | |||
508 | /* Add dummy byte */ |
||
509 | if (!nWrite) |
||
510 | RHDRegWrite(I2CPtr, R5_DC_I2C_DATA, 0); |
||
511 | else |
||
512 | while (nWrite--) |
||
513 | RHDRegWrite(I2CPtr, R5_DC_I2C_DATA, *WriteBuffer++); |
||
514 | |||
515 | RHDRegMask(I2CPtr, R5_DC_I2C_CONTROL1, |
||
516 | R5_DC_I2C_START | R5_DC_I2C_STOP, 0xff); |
||
517 | RHDRegMask(I2CPtr, R5_DC_I2C_STATUS1, R5_DC_I2C_GO, 0xff); |
||
518 | |||
519 | if ((ret = rhd5xxI2CStatus(I2CPtr))) |
||
520 | RHDRegMask(I2CPtr, R5_DC_I2C_STATUS1,R5_DC_I2C_DONE, 0xff); |
||
521 | else |
||
522 | ret = FALSE; |
||
523 | } |
||
524 | |||
525 | if (ret && nRead) { |
||
526 | |||
527 | RHDRegWrite(I2CPtr, R5_DC_I2C_DATA, slave | 1); /*slave*/ |
||
528 | RHDRegWrite(I2CPtr, R5_DC_I2C_CONTROL2, |
||
529 | prescale << 16 | nRead << 8 | 0x01); /* addr_cnt: 1 */ |
||
530 | |||
531 | RHDRegMask(I2CPtr, R5_DC_I2C_CONTROL1, |
||
532 | R5_DC_I2C_START | R5_DC_I2C_STOP | R5_DC_I2C_RECEIVE, 0xff); |
||
533 | RHDRegMask(I2CPtr, R5_DC_I2C_STATUS1, R5_DC_I2C_GO, 0xff); |
||
534 | if ((ret = rhd5xxI2CStatus(I2CPtr))) { |
||
535 | RHDRegMask(I2CPtr, R5_DC_I2C_STATUS1, R5_DC_I2C_DONE, 0xff); |
||
536 | while (nRead--) { |
||
537 | *(ReadBuffer++) = (CARD8)RHDRegRead(I2CPtr, R5_DC_I2C_DATA); |
||
538 | } |
||
539 | } else |
||
540 | ret = FALSE; |
||
541 | } |
||
542 | |||
543 | RHDRegMask(I2CPtr, R5_DC_I2C_STATUS1, |
||
544 | R5_DC_I2C_DONE | R5_DC_I2C_NACK | R5_DC_I2C_HALT, 0xff); |
||
545 | RHDRegMask(I2CPtr, R5_DC_I2C_RESET, R5_DC_I2C_SOFT_RESET, 0xff); |
||
546 | RHDRegWrite(I2CPtr,R5_DC_I2C_RESET, 0); |
||
547 | |||
548 | RHDRegMask(I2CPtr,R5_DC_I2C_ARBITRATION, |
||
549 | R5_DC_I2C_SW_DONE_USING_I2C, 0xff00); |
||
550 | |||
551 | RHDRegWrite(I2CPtr,R5_DC_I2C_CONTROL1, save_I2C_CONTROL1); |
||
552 | RHDRegWrite(I2CPtr,0x494, save_494); |
||
553 | tmp32 = RHDRegRead(I2CPtr,0x28); |
||
554 | RHDRegWrite(I2CPtr,0x28, tmp32 & 0xfffffdff); |
||
555 | |||
556 | return ret; |
||
557 | } |
||
558 | |||
559 | static Bool |
||
560 | rhd5xxWriteRead(I2CDevPtr i2cDevPtr, I2CByte *WriteBuffer, int nWrite, I2CByte *ReadBuffer, int nRead) |
||
561 | { |
||
562 | /* |
||
563 | * Since the transaction buffer can only hold |
||
564 | * 15 bytes (+ the slave address) we bail out |
||
565 | * on every transaction that is bigger unless |
||
566 | * it's a read transaction following a write |
||
567 | * transaction sending just one byte. |
||
568 | * In this case we assume, that this byte is |
||
569 | * an offset address. Thus we will restart |
||
570 | * the transaction after 15 bytes sending |
||
571 | * a new offset. |
||
572 | */ |
||
573 | |||
574 | I2CBusPtr I2CPtr = i2cDevPtr->pI2CBus; |
||
575 | int ddc_line; |
||
576 | |||
577 | RHDFUNC(I2CPtr); |
||
578 | |||
579 | if (nWrite > 15 || (nRead > 15 && nWrite != 1)) { |
||
580 | xf86DrvMsg(i2cDevPtr->pI2CBus->scrnIndex,X_ERROR, |
||
581 | "%s: Currently only I2C transfers with " |
||
582 | "maximally 15bytes are supported\n", |
||
583 | __func__); |
||
584 | return FALSE; |
||
585 | } |
||
586 | |||
587 | ddc_line = ((rhdI2CPtr)(I2CPtr->DriverPrivate.ptr))->u.line; |
||
588 | |||
589 | rhd5xxI2CSetupStatus(I2CPtr, ddc_line); |
||
590 | |||
591 | if (nRead > 15) { |
||
592 | I2CByte offset = *WriteBuffer; |
||
593 | while (nRead) { |
||
594 | int n = nRead > 15 ? 15 : nRead; |
||
595 | if (!rhd5xxWriteReadChunk(i2cDevPtr, ddc_line, &offset, 1, ReadBuffer, n)) |
||
596 | return FALSE; |
||
597 | ReadBuffer += n; |
||
598 | nRead -= n; |
||
599 | offset += n; |
||
600 | } |
||
601 | return TRUE; |
||
602 | } else |
||
603 | return rhd5xxWriteReadChunk(i2cDevPtr, ddc_line, WriteBuffer, nWrite, |
||
604 | ReadBuffer, nRead); |
||
605 | } |
||
606 | |||
607 | /* RS690 */ |
||
608 | static Bool |
||
609 | rhdRS69I2CStatus(I2CBusPtr I2CPtr) |
||
610 | { |
||
611 | volatile CARD32 val; |
||
612 | int i; |
||
613 | |||
614 | RHDFUNC(I2CPtr); |
||
615 | |||
616 | for (i = 0; i < RHD_I2C_STATUS_LOOPS; i++) { |
||
617 | usleep(10); |
||
618 | |||
619 | val = RHDRegRead(I2CPtr, RS69_DC_I2C_SW_STATUS); |
||
620 | |||
621 | RHDDebugVerb(I2CPtr->scrnIndex, 1, "SW_STATUS: 0x%x %i\n", |
||
622 | (unsigned int) val, i); |
||
623 | |||
624 | if (val & RS69_DC_I2C_SW_DONE) |
||
625 | break; |
||
626 | } |
||
627 | |||
628 | RHDRegMask(I2CPtr, RS69_DC_I2C_INTERRUPT_CONTROL, RS69_DC_I2C_SW_DONE_ACK, |
||
629 | RS69_DC_I2C_SW_DONE_ACK); |
||
630 | |||
631 | if ((i == RHD_I2C_STATUS_LOOPS) || |
||
632 | (val & (RS69_DC_I2C_SW_ABORTED | RS69_DC_I2C_SW_TIMEOUT | |
||
633 | RS69_DC_I2C_SW_INTERRUPTED | RS69_DC_I2C_SW_BUFFER_OVERFLOW | |
||
634 | RS69_DC_I2C_SW_STOPPED_ON_NACK | |
||
635 | RS69_DC_I2C_SW_NACK0 | RS69_DC_I2C_SW_NACK1 | 0x3))) |
||
636 | return FALSE; /* 2 */ |
||
637 | |||
638 | return TRUE; /* 1 */ |
||
639 | } |
||
640 | |||
641 | static Bool |
||
642 | rhdRS69I2CSetupStatus(I2CBusPtr I2CPtr, enum rhdDDClines sda, enum rhdDDClines scl, int prescale) |
||
643 | { |
||
644 | CARD32 clk_pin, data_pin; |
||
645 | |||
646 | RHDFUNC(I2CPtr); |
||
647 | |||
648 | switch (sda) { |
||
649 | case rhdDdc1data: |
||
650 | data_pin = 0; |
||
651 | break; |
||
652 | case rhdDdc2data: |
||
653 | data_pin = 1; |
||
654 | break; |
||
655 | case rhdDdc3data: |
||
656 | data_pin = 2; |
||
657 | break; |
||
658 | default: |
||
659 | return FALSE; |
||
660 | } |
||
661 | switch (scl) { |
||
662 | case rhdDdc1data: |
||
663 | clk_pin = 4; |
||
664 | break; |
||
665 | case rhdDdc2data: |
||
666 | clk_pin = 5; |
||
667 | break; |
||
668 | case rhdDdc3data: |
||
669 | clk_pin = 6; |
||
670 | break; |
||
671 | case rhdDdc1clk: |
||
672 | clk_pin = 0; |
||
673 | break; |
||
674 | case rhdDdc2clk: |
||
675 | clk_pin = 1; |
||
676 | break; |
||
677 | case rhdDdc3clk: |
||
678 | clk_pin = 2; |
||
679 | break; |
||
680 | default: |
||
681 | return FALSE; |
||
682 | } |
||
683 | |||
684 | RHDRegMask(I2CPtr, 0x28, 0x200, 0x200); |
||
685 | RHDRegMask(I2CPtr, RS69_DC_I2C_UNKNOWN_1, prescale << 16 | 0x2, 0xffff00ff); |
||
686 | RHDRegWrite(I2CPtr, RS69_DC_I2C_DDC_SETUP_Q, 0x30000000); |
||
687 | RHDRegMask(I2CPtr, RS69_DC_I2C_CONTROL, ((data_pin & 0x3) << 16) | (clk_pin << 8), 0xffff00); |
||
688 | RHDRegMask(I2CPtr, RS69_DC_I2C_INTERRUPT_CONTROL, 0x2, 0x2); |
||
689 | RHDRegMask(I2CPtr, RS69_DC_I2C_UNKNOWN_2, 0x2, 0xff); |
||
690 | |||
691 | return TRUE; |
||
692 | } |
||
693 | |||
694 | static Bool |
||
695 | rhdRS69WriteRead(I2CDevPtr i2cDevPtr, I2CByte *WriteBuffer, |
||
696 | int nWrite, I2CByte *ReadBuffer, int nRead) |
||
697 | { |
||
698 | Bool ret = FALSE; |
||
699 | CARD32 data = 0; |
||
700 | I2CBusPtr I2CPtr = i2cDevPtr->pI2CBus; |
||
701 | I2CSlaveAddr slave = i2cDevPtr->SlaveAddr; |
||
702 | rhdI2CPtr I2C = (rhdI2CPtr)I2CPtr->DriverPrivate.ptr; |
||
703 | int prescale = I2C->prescale; |
||
704 | int idx = 1; |
||
705 | |||
706 | enum { |
||
707 | TRANS_WRITE_READ, |
||
708 | TRANS_WRITE, |
||
709 | TRANS_READ |
||
710 | } trans; |
||
711 | |||
712 | RHDFUNC(i2cDevPtr->pI2CBus); |
||
713 | |||
714 | if (nWrite > 0 && nRead > 0) { |
||
715 | trans = TRANS_WRITE_READ; |
||
716 | } else if (nWrite > 0) { |
||
717 | trans = TRANS_WRITE; |
||
718 | } else if (nRead > 0) { |
||
719 | trans = TRANS_READ; |
||
720 | } else { |
||
721 | /* for bus probing */ |
||
722 | trans = TRANS_WRITE; |
||
723 | } |
||
724 | if (slave & 0xff00) { |
||
725 | xf86DrvMsg(I2CPtr->scrnIndex,X_ERROR, |
||
726 | "%s: 10 bit I2C slave addresses not supported\n",__func__); |
||
727 | return FALSE; |
||
728 | } |
||
729 | |||
730 | if (!rhdRS69I2CSetupStatus(I2CPtr, I2C->u.Gpio.Sda, I2C->u.Gpio.Scl, prescale)) |
||
731 | return FALSE; |
||
732 | |||
733 | RHDRegMask(I2CPtr, RS69_DC_I2C_CONTROL, (trans == TRANS_WRITE_READ) |
||
734 | ? (1 << 20) : 0, RS69_DC_I2C_TRANSACTION_COUNT); /* 2 or 1 Transaction */ |
||
735 | RHDRegMask(I2CPtr, RS69_DC_I2C_TRANSACTION0, |
||
736 | RS69_DC_I2C_STOP_ON_NACK0 |
||
737 | | (trans == TRANS_READ ? RS69_DC_I2C_RW0 : 0) |
||
738 | | RS69_DC_I2C_START0 |
||
739 | | (trans == TRANS_WRITE_READ ? 0 : RS69_DC_I2C_STOP0 ) |
||
740 | | ((trans == TRANS_READ ? nRead : nWrite) << 16), |
||
741 | 0xffffff); |
||
742 | if (trans == TRANS_WRITE_READ) |
||
743 | RHDRegMask(I2CPtr, RS69_DC_I2C_TRANSACTION1, |
||
744 | nRead << 16 |
||
745 | | RS69_DC_I2C_RW1 |
||
746 | | RS69_DC_I2C_START1 |
||
747 | | RS69_DC_I2C_STOP1, |
||
748 | 0xffffff); /* |
||
749 | |||
750 | data = RS69_DC_I2C_INDEX_WRITE |
||
751 | | (((slave & 0xfe) | (trans == TRANS_READ ? 1 : 0)) << 8 ) |
||
752 | | (0 << 16); |
||
753 | RHDRegWrite(I2CPtr, RS69_DC_I2C_DATA, data); |
||
754 | if (trans != TRANS_READ) { /* we have bytes to write */ |
||
755 | while (nWrite--) { |
||
756 | data = RS69_DC_I2C_INDEX_WRITE | ( *(WriteBuffer++) << 8 ) |
||
757 | | (idx++ << 16); |
||
758 | RHDRegWrite(I2CPtr, RS69_DC_I2C_DATA, data); |
||
759 | } |
||
760 | } |
||
761 | if (trans == TRANS_WRITE_READ) { /* we have bytes to read after write */ |
||
762 | data = RS69_DC_I2C_INDEX_WRITE | ((slave | 0x1) << 8) | (idx++ << 16); |
||
763 | RHDRegWrite(I2CPtr, RS69_DC_I2C_DATA, data); |
||
764 | } |
||
765 | /* Go! */ |
||
766 | RHDRegMask(I2CPtr, RS69_DC_I2C_CONTROL, RS69_DC_I2C_GO, RS69_DC_I2C_GO); |
||
767 | if (rhdRS69I2CStatus(I2CPtr)) { |
||
768 | /* Hopefully this doesn't write data to index */ |
||
769 | RHDRegWrite(I2CPtr, RS69_DC_I2C_DATA, RS69_DC_I2C_INDEX_WRITE |
||
770 | | RS69_DC_I2C_DATA_RW | /* idx++ */3 << 16); |
||
771 | while (nRead--) { |
||
772 | data = RHDRegRead(I2CPtr, RS69_DC_I2C_DATA); |
||
773 | *(ReadBuffer++) = (data >> 8) & 0xff; |
||
774 | } |
||
775 | ret = TRUE; |
||
776 | } |
||
777 | |||
778 | RHDRegMask(I2CPtr, RS69_DC_I2C_CONTROL, 0x2, 0xff); |
||
779 | usleep(10); |
||
780 | RHDRegWrite(I2CPtr, RS69_DC_I2C_CONTROL, 0); |
||
781 | |||
782 | return ret; |
||
783 | } |
||
784 | |||
785 | |||
786 | /* R6xx */ |
||
787 | static Bool |
||
788 | rhdR6xxI2CStatus(I2CBusPtr I2CPtr) |
||
789 | { |
||
790 | volatile CARD32 val; |
||
791 | int i; |
||
792 | |||
793 | RHDFUNC(I2CPtr); |
||
794 | |||
795 | for (i = 0; i < RHD_I2C_STATUS_LOOPS; i++) { |
||
796 | usleep(10); |
||
797 | |||
798 | val = RHDRegRead(I2CPtr, R6_DC_I2C_SW_STATUS); |
||
799 | |||
800 | RHDDebugVerb(I2CPtr->scrnIndex, 1, "SW_STATUS: 0x%x %i\n", |
||
801 | (unsigned int) val, i); |
||
802 | |||
803 | if (val & R6_DC_I2C_SW_DONE) |
||
804 | break; |
||
805 | } |
||
806 | |||
807 | RHDRegMask(I2CPtr, R6_DC_I2C_INTERRUPT_CONTROL, R6_DC_I2C_SW_DONE_ACK, |
||
808 | R6_DC_I2C_SW_DONE_ACK); |
||
809 | |||
810 | if ((i == RHD_I2C_STATUS_LOOPS) || |
||
811 | (val & (R6_DC_I2C_SW_ABORTED | R6_DC_I2C_SW_TIMEOUT | |
||
812 | R6_DC_I2C_SW_INTERRUPTED | R6_DC_I2C_SW_BUFFER_OVERFLOW | |
||
813 | R6_DC_I2C_SW_STOPPED_ON_NACK | |
||
814 | R6_DC_I2C_SW_NACK0 | R6_DC_I2C_SW_NACK1 | 0x3))) |
||
815 | return FALSE; /* 2 */ |
||
816 | |||
817 | return TRUE; /* 1 */ |
||
818 | } |
||
819 | |||
820 | static Bool |
||
821 | rhd6xxI2CSetupStatus(I2CBusPtr I2CPtr, int line, int prescale) |
||
822 | { |
||
823 | line &= 0xf; |
||
824 | |||
825 | RHDFUNC(I2CPtr); |
||
826 | |||
827 | switch (line) { |
||
828 | case 0: |
||
829 | RHDRegMask(I2CPtr, R6_DC_GPIO_DDC1_MASK, 0x0, 0xffff); |
||
830 | RHDRegMask(I2CPtr, R6_DC_GPIO_DDC1_A, 0x0, 0xffff); |
||
831 | RHDRegMask(I2CPtr, R6_DC_GPIO_DDC1_EN, 0x0, 0xffff); |
||
832 | RHDRegMask(I2CPtr, R6_DC_I2C_DDC1_SPEED, (prescale << 16) | 2, |
||
833 | 0xffff00ff); |
||
834 | RHDRegWrite(I2CPtr, R6_DC_I2C_DDC1_SETUP, 0x30000000); |
||
835 | break; |
||
836 | case 1: |
||
837 | RHDRegMask(I2CPtr, R6_DC_GPIO_DDC2_MASK, 0x0, 0xffff); |
||
838 | RHDRegMask(I2CPtr, R6_DC_GPIO_DDC2_A, 0x0, 0xffff); |
||
839 | RHDRegMask(I2CPtr, R6_DC_GPIO_DDC2_EN, 0x0, 0xffff); |
||
840 | RHDRegMask(I2CPtr, R6_DC_I2C_DDC2_SPEED, (prescale << 16) | 2, |
||
841 | 0xffff00ff); |
||
842 | RHDRegWrite(I2CPtr, R6_DC_I2C_DDC2_SETUP, 0x30000000); |
||
843 | break; |
||
844 | case 2: |
||
845 | RHDRegMask(I2CPtr, R6_DC_GPIO_DDC3_MASK, 0x0, 0xffff); |
||
846 | RHDRegMask(I2CPtr, R6_DC_GPIO_DDC3_A, 0x0, 0xffff); |
||
847 | RHDRegMask(I2CPtr, R6_DC_GPIO_DDC3_EN, 0x0, 0xffff); |
||
848 | RHDRegMask(I2CPtr, R6_DC_I2C_DDC3_SPEED, (prescale << 16) | 2, |
||
849 | 0xffff00ff); |
||
850 | RHDRegWrite(I2CPtr, R6_DC_I2C_DDC3_SETUP, 0x30000000); |
||
851 | break; |
||
852 | case 3: |
||
853 | RHDRegMask(I2CPtr, R6_DC_GPIO_DDC4_MASK, 0x0, 0xffff); |
||
854 | RHDRegMask(I2CPtr, R6_DC_GPIO_DDC4_A, 0x0, 0xffff); |
||
855 | RHDRegMask(I2CPtr, R6_DC_GPIO_DDC4_EN, 0x0, 0xffff); |
||
856 | RHDRegMask(I2CPtr, R6_DC_I2C_DDC4_SPEED, (prescale << 16) | 2, |
||
857 | 0xffff00ff); |
||
858 | RHDRegWrite(I2CPtr, R6_DC_I2C_DDC4_SETUP, 0x30000000); |
||
859 | break; |
||
860 | default: |
||
861 | xf86DrvMsg(I2CPtr->scrnIndex,X_ERROR, |
||
862 | "%s: Trying to initialize non-existent I2C line: %i\n", |
||
863 | __func__,line); |
||
864 | return FALSE; |
||
865 | } |
||
866 | RHDRegWrite(I2CPtr, R6_DC_I2C_CONTROL, line << 8); |
||
867 | RHDRegMask(I2CPtr, R6_DC_I2C_INTERRUPT_CONTROL, 0x2, 0x2); |
||
868 | RHDRegMask(I2CPtr, R6_DC_I2C_ARBITRATION, 0, 0xff); |
||
869 | return TRUE; |
||
870 | } |
||
871 | |||
872 | static Bool |
||
873 | rhd6xxWriteRead(I2CDevPtr i2cDevPtr, I2CByte *WriteBuffer, int nWrite, I2CByte *ReadBuffer, int nRead) |
||
874 | { |
||
875 | Bool ret = FALSE; |
||
876 | CARD32 data = 0; |
||
877 | I2CBusPtr I2CPtr = i2cDevPtr->pI2CBus; |
||
878 | I2CSlaveAddr slave = i2cDevPtr->SlaveAddr; |
||
879 | rhdI2CPtr I2C = (rhdI2CPtr)I2CPtr->DriverPrivate.ptr; |
||
880 | CARD32 ddc_line = I2C->u.line; |
||
881 | int prescale = I2C->prescale; |
||
882 | int idx = 1; |
||
883 | enum { |
||
884 | TRANS_WRITE_READ, |
||
885 | TRANS_WRITE, |
||
886 | TRANS_READ |
||
887 | } trans; |
||
888 | |||
889 | RHDFUNC(i2cDevPtr->pI2CBus); |
||
890 | |||
891 | if (nWrite > 0 && nRead > 0) { |
||
892 | trans = TRANS_WRITE_READ; |
||
893 | } else if (nWrite > 0) { |
||
894 | trans = TRANS_WRITE; |
||
895 | } else if (nRead > 0) { |
||
896 | trans = TRANS_READ; |
||
897 | } else { |
||
898 | /* for bus probing */ |
||
899 | trans = TRANS_WRITE; |
||
900 | } |
||
901 | if (slave & 0xff00) { |
||
902 | xf86DrvMsg(I2CPtr->scrnIndex,X_ERROR, |
||
903 | "%s: 10 bit I2C slave addresses not supported\n",__func__); |
||
904 | return FALSE; |
||
905 | } |
||
906 | |||
907 | if (!rhd6xxI2CSetupStatus(I2CPtr, ddc_line, prescale)) |
||
908 | return FALSE; |
||
909 | |||
910 | RHDRegMask(I2CPtr, R6_DC_I2C_CONTROL, (trans == TRANS_WRITE_READ) |
||
911 | ? (1 << 20) : 0, R6_DC_I2C_TRANSACTION_COUNT); /* 2 or 1 Transaction */ |
||
912 | RHDRegMask(I2CPtr, R6_DC_I2C_TRANSACTION0, |
||
913 | R6_DC_I2C_STOP_ON_NACK0 |
||
914 | | (trans == TRANS_READ ? R6_DC_I2C_RW0 : 0) |
||
915 | | R6_DC_I2C_START0 |
||
916 | | (trans == TRANS_WRITE_READ ? 0 : R6_DC_I2C_STOP0 ) |
||
917 | | ((trans == TRANS_READ ? nRead : nWrite) << 16), |
||
918 | 0xffffff); |
||
919 | if (trans == TRANS_WRITE_READ) |
||
920 | RHDRegMask(I2CPtr, R6_DC_I2C_TRANSACTION1, |
||
921 | nRead << 16 |
||
922 | | R6_DC_I2C_RW1 |
||
923 | | R6_DC_I2C_START1 |
||
924 | | R6_DC_I2C_STOP1, |
||
925 | 0xffffff); /* |
||
926 | |||
927 | data = R6_DC_I2C_INDEX_WRITE |
||
928 | | (((slave & 0xfe) | (trans == TRANS_READ ? 1 : 0)) << 8 ) |
||
929 | | (0 << 16); |
||
930 | RHDRegWrite(I2CPtr, R6_DC_I2C_DATA, data); |
||
931 | if (trans != TRANS_READ) { /* we have bytes to write */ |
||
932 | while (nWrite--) { |
||
933 | data = R6_DC_I2C_INDEX_WRITE | ( *(WriteBuffer++) << 8 ) |
||
934 | | (idx++ << 16); |
||
935 | RHDRegWrite(I2CPtr, R6_DC_I2C_DATA, data); |
||
936 | } |
||
937 | } |
||
938 | if (trans == TRANS_WRITE_READ) { /* we have bytes to read after write */ |
||
939 | data = R6_DC_I2C_INDEX_WRITE | ((slave | 0x1) << 8) | (idx++ << 16); |
||
940 | RHDRegWrite(I2CPtr, R6_DC_I2C_DATA, data); |
||
941 | } |
||
942 | /* Go! */ |
||
943 | RHDRegMask(I2CPtr, R6_DC_I2C_CONTROL, R6_DC_I2C_GO, R6_DC_I2C_GO); |
||
944 | if (rhdR6xxI2CStatus(I2CPtr)) { |
||
945 | /* Hopefully this doesn't write data to index */ |
||
946 | RHDRegWrite(I2CPtr, R6_DC_I2C_DATA, R6_DC_I2C_INDEX_WRITE |
||
947 | | R6_DC_I2C_DATA_RW | /* idx++ */3 << 16); |
||
948 | while (nRead--) { |
||
949 | data = RHDRegRead(I2CPtr, R6_DC_I2C_DATA); |
||
950 | *(ReadBuffer++) = (data >> 8) & 0xff; |
||
951 | } |
||
952 | ret = TRUE; |
||
953 | } |
||
954 | |||
955 | RHDRegMask(I2CPtr, R6_DC_I2C_CONTROL, 0x2, 0xff); |
||
956 | usleep(10); |
||
957 | RHDRegWrite(I2CPtr, R6_DC_I2C_CONTROL, 0); |
||
958 | |||
959 | return ret; |
||
960 | } |
||
961 | |||
962 | /* RV620 */ |
||
963 | static Bool |
||
964 | rhdRV620I2CStatus(I2CBusPtr I2CPtr) |
||
965 | { |
||
966 | volatile CARD32 val; |
||
967 | int i; |
||
968 | |||
969 | RHDFUNC(I2CPtr); |
||
970 | |||
971 | for (i = 0; i < RHD_I2C_STATUS_LOOPS; i++) { |
||
972 | usleep(10); |
||
973 | |||
974 | val = RHDRegRead(I2CPtr, RV62_GENERIC_I2C_STATUS); |
||
975 | |||
976 | RHDDebugVerb(I2CPtr->scrnIndex, 1, |
||
977 | "SW_STATUS: 0x%x %i\n", (unsigned int) val, i); |
||
978 | if (val & RV62_GENERIC_I2C_DONE) |
||
979 | break; |
||
980 | } |
||
981 | |||
982 | RHDRegMask(I2CPtr, RV62_GENERIC_I2C_INTERRUPT_CONTROL, 0x2, 0xff); |
||
983 | |||
984 | if ((i == RHD_I2C_STATUS_LOOPS) || |
||
985 | (val & (RV62_GENERIC_I2C_STOPPED_ON_NACK | RV62_GENERIC_I2C_NACK | |
||
986 | RV62_GENERIC_I2C_ABORTED | RV62_GENERIC_I2C_TIMEOUT))) |
||
987 | return FALSE; /* 2 */ |
||
988 | |||
989 | return TRUE; /* 1 */ |
||
990 | } |
||
991 | |||
992 | /* |
||
993 | * |
||
994 | */ |
||
995 | static Bool |
||
996 | rhdRV620I2CSetupStatus(I2CBusPtr I2CPtr, struct i2cGpio *Gpio, int prescale) |
||
997 | { |
||
998 | CARD32 reg_7d9c = 0; /* 0 is invalid */ |
||
999 | CARD32 scl_reg; |
||
1000 | |||
1001 | RHDFUNC(I2CPtr); |
||
1002 | |||
1003 | scl_reg = Gpio->SclReg; |
||
1004 | reg_7d9c = (Gpio->Scl << RV62_GENERIC_I2C_SCL_PIN_SEL_SHIFT) |
||
1005 | | (Gpio->Sda << RV62_GENERIC_I2C_SDA_PIN_SEL_SHIFT); |
||
1006 | |||
1007 | scl_reg = Gpio->SclReg; |
||
1008 | /* Don't understand this yet */ |
||
1009 | if (scl_reg == 0x1fda) |
||
1010 | scl_reg = 0x1f90; |
||
1011 | |||
1012 | RHDRegWrite(I2CPtr, scl_reg << 2, 0); |
||
1013 | |||
1014 | RHDRegWrite(I2CPtr, RV62_GENERIC_I2C_PIN_SELECTION, reg_7d9c); |
||
1015 | RHDRegMask(I2CPtr, RV62_GENERIC_I2C_SPEED, |
||
1016 | (prescale & 0xffff) << 16 | 0x02, 0xffff00ff); |
||
1017 | RHDRegWrite(I2CPtr, RV62_GENERIC_I2C_SETUP, 0x30000000); |
||
1018 | RHDRegMask(I2CPtr, RV62_GENERIC_I2C_INTERRUPT_CONTROL, |
||
1019 | RV62_GENERIC_I2C_DONE_ACK, RV62_GENERIC_I2C_DONE_ACK); |
||
1020 | |||
1021 | return TRUE; |
||
1022 | } |
||
1023 | |||
1024 | static Bool |
||
1025 | rhdRV620Transaction(I2CDevPtr i2cDevPtr, Bool Write, I2CByte *Buffer, int count) |
||
1026 | { |
||
1027 | I2CBusPtr I2CPtr = i2cDevPtr->pI2CBus; |
||
1028 | I2CSlaveAddr slave = i2cDevPtr->SlaveAddr; |
||
1029 | Bool Start = TRUE; |
||
1030 | |||
1031 | RHDFUNC(I2CPtr); |
||
1032 | |||
1033 | #define MAX 8 |
||
1034 | |||
1035 | while (count > 0 || (Write && Start)) { |
||
1036 | int num; |
||
1037 | int idx = 0; |
||
1038 | CARD32 data = 0; |
||
1039 | |||
1040 | if (count > MAX) { |
||
1041 | num = MAX; |
||
1042 | RHDRegMask(I2CPtr, RV62_GENERIC_I2C_TRANSACTION, |
||
1043 | (MAX - (((Start) ? 0 : 1))) << 16 |
||
1044 | | RV62_GENERIC_I2C_STOP_ON_NACK |
||
1045 | | RV62_GENERIC_I2C_ACK_ON_READ |
||
1046 | | (Start ? RV62_GENERIC_I2C_START : 0) |
||
1047 | | (!Write ? RV62_GENERIC_I2C_RW : 0 ), |
||
1048 | 0xFFFFFF); |
||
1049 | } else { |
||
1050 | num = count; |
||
1051 | data = ( count - (((Start) ? 0 : 1)) ) << 16 |
||
1052 | | RV62_GENERIC_I2C_STOP_ON_NACK |
||
1053 | | RV62_GENERIC_I2C_STOP |
||
1054 | | (Start ? RV62_GENERIC_I2C_START : 0) |
||
1055 | | (!Write ? RV62_GENERIC_I2C_RW : 0); |
||
1056 | RHDRegMask(I2CPtr, RV62_GENERIC_I2C_TRANSACTION, |
||
1057 | data, |
||
1058 | 0xFFFFFF); |
||
1059 | } |
||
1060 | |||
1061 | if (Start) { |
||
1062 | data = RV62_GENERIC_I2C_INDEX_WRITE |
||
1063 | | (((slave & 0xfe) | ( Write ? 0 : 1)) << 8) |
||
1064 | | (idx++ << 16); |
||
1065 | RHDRegWrite(I2CPtr, RV62_GENERIC_I2C_DATA, data); |
||
1066 | } |
||
1067 | |||
1068 | if (Write) { |
||
1069 | while (num--) { |
||
1070 | data = RV62_GENERIC_I2C_INDEX_WRITE |
||
1071 | | (idx++ << 16) |
||
1072 | | *(Buffer++) << 8; |
||
1073 | RHDRegWrite(I2CPtr, RV62_GENERIC_I2C_DATA, data); |
||
1074 | } |
||
1075 | |||
1076 | RHDRegMask(I2CPtr, RV62_GENERIC_I2C_CONTROL, |
||
1077 | RV62_GENERIC_I2C_GO, RV62_GENERIC_I2C_GO); |
||
1078 | if (!rhdRV620I2CStatus(I2CPtr)) |
||
1079 | return FALSE; |
||
1080 | } else { |
||
1081 | |||
1082 | RHDRegMask(I2CPtr, RV62_GENERIC_I2C_CONTROL, |
||
1083 | RV62_GENERIC_I2C_GO, RV62_GENERIC_I2C_GO); |
||
1084 | if (!rhdRV620I2CStatus(I2CPtr)) |
||
1085 | return FALSE; |
||
1086 | |||
1087 | RHDRegWrite(I2CPtr, RV62_GENERIC_I2C_DATA, |
||
1088 | RV62_GENERIC_I2C_INDEX_WRITE |
||
1089 | | (idx++ << 16) |
||
1090 | | RV62_GENERIC_I2C_RW); |
||
1091 | |||
1092 | while (num--) { |
||
1093 | data = RHDRegRead(I2CPtr, RV62_GENERIC_I2C_DATA); |
||
1094 | *(Buffer++) = (CARD8)((data >> 8) & 0xff); |
||
1095 | } |
||
1096 | } |
||
1097 | Start = FALSE; |
||
1098 | count -= MAX; |
||
1099 | } |
||
1100 | |||
1101 | return TRUE; |
||
1102 | } |
||
1103 | |||
1104 | static Bool |
||
1105 | rhdRV620WriteRead(I2CDevPtr i2cDevPtr, I2CByte *WriteBuffer, int nWrite, I2CByte *ReadBuffer, int nRead) |
||
1106 | { |
||
1107 | I2CBusPtr I2CPtr = i2cDevPtr->pI2CBus; |
||
1108 | rhdI2CPtr I2C = (rhdI2CPtr)I2CPtr->DriverPrivate.ptr; |
||
1109 | int prescale = I2C->prescale; |
||
1110 | |||
1111 | RHDFUNC(I2C); |
||
1112 | |||
1113 | rhdRV620I2CSetupStatus(I2CPtr, &I2C->u.Gpio, prescale); |
||
1114 | |||
1115 | if (nWrite || !nRead) |
||
1116 | if (!rhdRV620Transaction(i2cDevPtr, TRUE, WriteBuffer, nWrite)) |
||
1117 | return FALSE; |
||
1118 | if (nRead) |
||
1119 | if (!rhdRV620Transaction(i2cDevPtr, FALSE, ReadBuffer, nRead)) |
||
1120 | return FALSE; |
||
1121 | |||
1122 | return TRUE; |
||
1123 | } |
||
1124 | |||
1125 | static void |
||
1126 | rhdTearDownI2C(I2CBusPtr *I2C) |
||
1127 | { |
||
1128 | int i; |
||
1129 | |||
1130 | /* |
||
1131 | * xf86I2CGetScreenBuses() is |
||
1132 | * broken in older server versions. |
||
1133 | * So we cannot use it. How bad! |
||
1134 | */ |
||
1135 | for (i = 0; i < MAX_I2C_LINES; i++) { |
||
1136 | char *name; |
||
1137 | if (!I2C[i]) |
||
1138 | break; |
||
1139 | name = I2C[i]->BusName; |
||
1140 | xfree(I2C[i]->DriverPrivate.ptr); |
||
1141 | xf86DestroyI2CBusRec(I2C[i], TRUE, TRUE); |
||
1142 | xfree(name); |
||
1143 | } |
||
1144 | xfree(I2C); |
||
1145 | } |
||
1146 | |||
1147 | #define TARGET_HW_I2C_CLOCK 25 /* kHz */ |
||
1148 | #define DEFAULT_ENGINE_CLOCK 453000 /* kHz (guessed) */ |
||
1149 | #define DEFAULT_REF_CLOCK 27000 |
||
1150 | |||
1151 | static CARD32 |
||
1152 | rhdGetI2CPrescale(RHDPtr rhdPtr) |
||
1153 | { |
||
1154 | #ifdef ATOM_BIOS |
||
1155 | AtomBiosArgRec atomBiosArg; |
||
1156 | RHDFUNC(rhdPtr); |
||
1157 | |||
1158 | if (rhdPtr->ChipSet < RHD_R600) { |
||
1159 | if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, |
||
1160 | GET_DEFAULT_ENGINE_CLOCK, &atomBiosArg) |
||
1161 | == ATOM_SUCCESS) |
||
1162 | return (0x7f << 8) |
||
1163 | + (atomBiosArg.val / (4 * 0x7f * TARGET_HW_I2C_CLOCK)); |
||
1164 | else |
||
1165 | return (0x7f << 8) |
||
1166 | + (DEFAULT_ENGINE_CLOCK / (4 * 0x7f * TARGET_HW_I2C_CLOCK)); |
||
1167 | } else if (rhdPtr->ChipSet < RHD_RV620) { |
||
1168 | if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, |
||
1169 | GET_REF_CLOCK, &atomBiosArg) == ATOM_SUCCESS) |
||
1170 | return (atomBiosArg.val / TARGET_HW_I2C_CLOCK); |
||
1171 | else |
||
1172 | return (DEFAULT_REF_CLOCK / TARGET_HW_I2C_CLOCK); |
||
1173 | } else { |
||
1174 | if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, |
||
1175 | GET_REF_CLOCK, &atomBiosArg) == ATOM_SUCCESS) |
||
1176 | return (atomBiosArg.val / (4 * TARGET_HW_I2C_CLOCK)); |
||
1177 | else |
||
1178 | return (DEFAULT_REF_CLOCK / (4 * TARGET_HW_I2C_CLOCK)); |
||
1179 | } |
||
1180 | #else |
||
1181 | RHDFUNC(rhdPtr); |
||
1182 | |||
1183 | if (rhdPtr->ChipSet < RHD_R600) { |
||
1184 | return (0x7f << 8) |
||
1185 | + (DEFAULT_ENGINE_CLOCK) / (4 * 0x7f * TARGET_HW_I2C_CLOCK); |
||
1186 | } else if (rhdPtr->ChipSet < RHD_RV620) { |
||
1187 | return (DEFAULT_REF_CLOCK / TARGET_HW_I2C_CLOCK); |
||
1188 | } else |
||
1189 | return (DEFAULT_REF_CLOCK / (4 * TARGET_HW_I2C_CLOCK)); |
||
1190 | #endif |
||
1191 | } |
||
1192 | |||
1193 | static Bool |
||
1194 | rhdI2CAddress(I2CDevPtr d, I2CSlaveAddr addr) |
||
1195 | { |
||
1196 | d->SlaveAddr = addr; |
||
1197 | return xf86I2CWriteRead(d, NULL, 0, NULL, 0); |
||
1198 | } |
||
1199 | |||
1200 | /* |
||
1201 | * This stub is needed to keep xf86I2CProbeAddress() happy. |
||
1202 | */ |
||
1203 | static void |
||
1204 | rhdI2CStop(I2CDevPtr d) |
||
1205 | { |
||
1206 | } |
||
1207 | |||
1208 | static I2CBusPtr * |
||
1209 | rhdInitI2C(int scrnIndex) |
||
1210 | { |
||
1211 | int i; |
||
1212 | rhdI2CPtr I2C; |
||
1213 | I2CBusPtr I2CPtr = NULL; |
||
1214 | RHDPtr rhdPtr = (RHDPtr)scrnIndex; |
||
1215 | I2CBusPtr *I2CList; |
||
1216 | int numLines; |
||
1217 | CARD16 prescale = rhdGetI2CPrescale(rhdPtr); |
||
1218 | enum rhdDDClines sda = 0, scl = 0; |
||
1219 | CARD32 scl_reg = 0, sda_reg = 0; |
||
1220 | Bool valid; |
||
1221 | |||
1222 | RHDFUNCI(scrnIndex); |
||
1223 | |||
1224 | if (rhdPtr->ChipSet < RHD_RS600) |
||
1225 | numLines = 3; |
||
1226 | else if (rhdPtr->ChipSet < RHD_R600) |
||
1227 | numLines = 4; |
||
1228 | else if (rhdPtr->ChipSet < RHD_RV730) |
||
1229 | numLines = 4; |
||
1230 | else |
||
1231 | numLines = MAX_I2C_LINES; |
||
1232 | |||
1233 | if (!(I2CList = xcalloc(MAX_I2C_LINES, sizeof(I2CBusPtr)))) { |
||
1234 | xf86DrvMsg(scrnIndex, X_ERROR, |
||
1235 | "%s: Out of memory.\n",__func__); |
||
1236 | } |
||
1237 | /* We have 4 I2C lines */ |
||
1238 | for (i = 0; i < numLines; i++) { |
||
1239 | if (!(I2C = xcalloc(sizeof(rhdI2CRec),1))) { |
||
1240 | xf86DrvMsg(scrnIndex, X_ERROR, |
||
1241 | "%s: Out of memory.\n",__func__); |
||
1242 | goto error; |
||
1243 | } |
||
1244 | I2C->scrnIndex = scrnIndex; |
||
1245 | |||
1246 | valid = rhdI2CGetDataClkLines(rhdPtr, i, &scl, &sda, &sda_reg, &scl_reg); |
||
1247 | if (rhdPtr->ChipSet < RHD_RS600 |
||
1248 | || (rhdPtr->ChipSet > RHD_RS740 && rhdPtr->ChipSet < RHD_RV620)) { |
||
1249 | |||
1250 | if (valid) { |
||
1251 | if (sda == rhdDdc1data && scl == rhdDdc1clk) |
||
1252 | I2C->u.line = 0; |
||
1253 | else if (sda == rhdDdc2data && scl == rhdDdc2clk) |
||
1254 | I2C->u.line = 1; |
||
1255 | else if (sda == rhdDdc3data && scl == rhdDdc3clk) |
||
1256 | I2C->u.line = 2; |
||
1257 | else if (rhdPtr->ChipSet > RHD_RS740 && sda == rhdDdc4data && scl == rhdDdc4clk) |
||
1258 | I2C->u.line = 3; /* R6XX only */ |
||
1259 | else { |
||
1260 | xf86DrvMsg(I2CPtr->scrnIndex, X_ERROR, "No DDC line found for index %i: scl=0x%2.2x sda=0x%2.2x\n", |
||
1261 | i, scl, sda); |
||
1262 | xfree(I2C); |
||
1263 | continue; |
||
1264 | } |
||
1265 | |||
1266 | } else |
||
1267 | I2C->u.line = i; |
||
1268 | |||
1269 | } else if (rhdPtr->ChipSet <= RHD_RS740) { |
||
1270 | |||
1271 | if (valid) { |
||
1272 | if (sda != rhdDdc1data && sda != rhdDdc2data && sda != rhdDdc3data) { |
||
1273 | xf86DrvMsg(I2CPtr->scrnIndex, X_ERROR, "Invalid DDC CLK pin found: %i\n", |
||
1274 | sda); |
||
1275 | xfree(I2C); |
||
1276 | continue; |
||
1277 | } |
||
1278 | if (scl != rhdDdc1data && scl != rhdDdc2data && scl != rhdDdc3data |
||
1279 | && scl != rhdDdc1clk && scl != rhdDdc2clk && scl != rhdDdc3clk) { |
||
1280 | xf86DrvMsg(I2CPtr->scrnIndex, X_ERROR, "Invalid DDC CLK pin found: %i\n", |
||
1281 | scl); |
||
1282 | xfree(I2C); |
||
1283 | continue; |
||
1284 | } |
||
1285 | I2C->u.Gpio.Sda = sda; |
||
1286 | I2C->u.Gpio.Scl = scl; |
||
1287 | I2C->u.Gpio.SdaReg = sda_reg; |
||
1288 | I2C->u.Gpio.SclReg = scl_reg; |
||
1289 | |||
1290 | } else { |
||
1291 | xf86DrvMsg(I2CPtr->scrnIndex, X_ERROR, "Invalid ClkLine for DDC. " |
||
1292 | "AtomBIOS reported wrong or AtomBIOS unavailable\n"); |
||
1293 | xfree(I2C); |
||
1294 | goto error; |
||
1295 | } |
||
1296 | |||
1297 | } else { |
||
1298 | |||
1299 | if (valid) { |
||
1300 | I2C->u.Gpio.Sda = sda; |
||
1301 | I2C->u.Gpio.Scl = scl; |
||
1302 | I2C->u.Gpio.SdaReg = sda_reg; |
||
1303 | I2C->u.Gpio.SclReg = scl_reg; |
||
1304 | } else { |
||
1305 | CARD32 gpioReg[] = { 0x1f90, 0x1f94, 0x1f98 }; |
||
1306 | enum rhdDDClines sdaList[] = { rhdDdc1data, rhdDdc2data, rhdDdc3data }; |
||
1307 | enum rhdDDClines sclList[] = { rhdDdc1clk, rhdDdc2clk, rhdDdc3clk }; |
||
1308 | if (i > 2) { |
||
1309 | xfree(I2C); |
||
1310 | continue; |
||
1311 | } |
||
1312 | I2C->u.Gpio.Sda = sdaList[i]; |
||
1313 | I2C->u.Gpio.Scl = sclList[i]; |
||
1314 | I2C->u.Gpio.SclReg = I2C->u.Gpio.SdaReg = gpioReg[i]; |
||
1315 | } |
||
1316 | |||
1317 | } |
||
1318 | |||
1319 | /* |
||
1320 | * This is a value that has been found to work on many cards. |
||
1321 | * It nees to be replaced by the proper calculation formula |
||
1322 | * once this is available. |
||
1323 | */ |
||
1324 | I2C->prescale = prescale; |
||
1325 | xf86DrvMsgVerb(scrnIndex, X_INFO, 5, "I2C clock prescale value: %x\n",I2C->prescale); |
||
1326 | |||
1327 | if (!(I2CPtr = xf86CreateI2CBusRec())) { |
||
1328 | xf86DrvMsg(scrnIndex, X_ERROR, |
||
1329 | "Cannot allocate I2C BusRec.\n"); |
||
1330 | xfree(I2C); |
||
1331 | goto error; |
||
1332 | } |
||
1333 | I2CPtr->DriverPrivate.ptr = I2C; |
||
1334 | if (!(I2CPtr->BusName = xalloc(18))) { |
||
1335 | xf86DrvMsg(scrnIndex, X_ERROR, |
||
1336 | "%s: Cannot allocate memory.\n",__func__); |
||
1337 | xfree(I2C); |
||
1338 | xf86DestroyI2CBusRec(I2CPtr, TRUE, FALSE); |
||
1339 | goto error; |
||
1340 | } |
||
1341 | snprintf(I2CPtr->BusName,17,"RHD I2C line %1.1i",i); |
||
1342 | I2CPtr->scrnIndex = scrnIndex; |
||
1343 | if (rhdPtr->ChipSet < RHD_RS600) |
||
1344 | I2CPtr->I2CWriteRead = rhd5xxWriteRead; |
||
1345 | else if (rhdPtr->ChipSet >= RHD_RS600 && rhdPtr->ChipSet <= RHD_RS740) |
||
1346 | I2CPtr->I2CWriteRead = rhdRS69WriteRead; |
||
1347 | else if (rhdPtr->ChipSet < RHD_RV620) |
||
1348 | I2CPtr->I2CWriteRead = rhd6xxWriteRead; |
||
1349 | else |
||
1350 | I2CPtr->I2CWriteRead = rhdRV620WriteRead; |
||
1351 | I2CPtr->I2CAddress = rhdI2CAddress; |
||
1352 | I2CPtr->I2CStop = rhdI2CStop; |
||
1353 | |||
1354 | if (!(xf86I2CBusInit(I2CPtr))) { |
||
1355 | xf86DrvMsg(scrnIndex, X_ERROR, |
||
1356 | "I2C BusInit failed for bus %i\n",i); |
||
1357 | xfree(I2CPtr->BusName); |
||
1358 | xfree(I2C); |
||
1359 | xf86DestroyI2CBusRec(I2CPtr, TRUE, FALSE); |
||
1360 | goto error; |
||
1361 | } |
||
1362 | I2CList[i] = I2CPtr; |
||
1363 | } |
||
1364 | return I2CList; |
||
1365 | error: |
||
1366 | rhdTearDownI2C(I2CList); |
||
1367 | return NULL; |
||
1368 | } |
||
1369 | |||
1370 | RHDI2CResult |
||
1371 | rhdI2CProbeAddress(int scrnIndex, I2CBusPtr I2CBusPtr, CARD8 slave) |
||
1372 | { |
||
1373 | I2CDevPtr dev; |
||
1374 | char *name = "I2CProbe"; |
||
1375 | |||
1376 | if ((dev = xf86CreateI2CDevRec())) { |
||
1377 | dev->DevName = name; |
||
1378 | dev->pI2CBus = I2CBusPtr; |
||
1379 | |||
1380 | if (xf86I2CDevInit(dev)) { |
||
1381 | Bool ret; |
||
1382 | |||
1383 | dev->SlaveAddr = slave & 0xFE; |
||
1384 | |||
1385 | ret = xf86I2CWriteRead(dev, NULL, 0, NULL, 0); |
||
1386 | |||
1387 | if (ret) { |
||
1388 | unsigned char offset = 0; |
||
1389 | unsigned char buf[2]; |
||
1390 | |||
1391 | /* |
||
1392 | ASUS M2A-VM (R690) motherboards ACK all I2C slaves on the |
||
1393 | HDMI line when the HDMI riser card is not installed. |
||
1394 | We therefore need to read the first two bytes and check |
||
1395 | if they are part of an I2C header. |
||
1396 | */ |
||
1397 | ret = xf86I2CWriteRead(dev, &offset, 1, buf, 2); |
||
1398 | if (ret && (buf[0] != 0 || buf[1] != 0xff)) |
||
1399 | ret = FALSE; |
||
1400 | } |
||
1401 | xf86DestroyI2CDevRec(dev, TRUE); |
||
1402 | |||
1403 | return ret ? RHD_I2C_SUCCESS : RHD_I2C_FAILED; |
||
1404 | } |
||
1405 | } |
||
1406 | |||
1407 | return RHD_I2C_FAILED; |
||
1408 | } |
||
1409 | |||
1410 | RHDI2CResult |
||
1411 | RHDI2CFunc(int scrnIndex, I2CBusPtr *I2CList, RHDi2cFunc func, |
||
1412 | RHDI2CDataArgPtr datap) |
||
1413 | { |
||
1414 | RHDFUNCI(scrnIndex); |
||
1415 | |||
1416 | if (func == RHD_I2C_INIT) { |
||
1417 | if (!(datap->I2CBusList = rhdInitI2C(scrnIndex))) |
||
1418 | return RHD_I2C_FAILED; |
||
1419 | else |
||
1420 | return RHD_I2C_SUCCESS; |
||
1421 | } |
||
1422 | if (func == RHD_I2C_DDC) { |
||
1423 | if (datap->i >= MAX_I2C_LINES || !I2CList[datap->i]) |
||
1424 | return RHD_I2C_NOLINE; |
||
1425 | |||
1426 | datap->monitor = xf86DoEDID_DDC2(scrnIndex, I2CList[datap->i]); |
||
1427 | return RHD_I2C_SUCCESS; |
||
1428 | } |
||
1429 | if (func == RHD_I2C_PROBE_ADDR_LINE) { |
||
1430 | |||
1431 | if (datap->target.line >= MAX_I2C_LINES || !I2CList[datap->target.line]) |
||
1432 | return RHD_I2C_NOLINE; |
||
1433 | return rhdI2CProbeAddress(scrnIndex, I2CList[datap->target.line], datap->target.slave); |
||
1434 | } |
||
1435 | if (func == RHD_I2C_PROBE_ADDR) { |
||
1436 | return rhdI2CProbeAddress(scrnIndex, datap->probe.i2cBusPtr, datap->probe.slave); |
||
1437 | } |
||
1438 | if (func == RHD_I2C_GETBUS) { |
||
1439 | if (datap->i >= MAX_I2C_LINES || !I2CList[datap->i]) |
||
1440 | return RHD_I2C_NOLINE; |
||
1441 | |||
1442 | datap->i2cBusPtr = I2CList[datap->i]; |
||
1443 | return RHD_I2C_SUCCESS; |
||
1444 | } |
||
1445 | if (func == RHD_I2C_TEARDOWN) { |
||
1446 | if (I2CList) |
||
1447 | rhdTearDownI2C(I2CList); |
||
1448 | return RHD_I2C_SUCCESS; |
||
1449 | } |
||
1450 | return RHD_I2C_FAILED; |
||
1451 | }>=>>=>>>>>>>>><>>>><>><>>>><>><>><>><>><>><>><>><>><>><>><>>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>>><>><>><>><>><>><>><>><>><>><>><>><>><>>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><> |
||
1452 |