1 | /* |
2 | * Copyright 2018 Advanced Micro Devices, Inc. |
3 | * |
4 | * Permission is hereby granted, free of charge, to any person obtaining a |
5 | * copy of this software and associated documentation files (the "Software"), |
6 | * to deal in the Software without restriction, including without limitation |
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
8 | * and/or sell copies of the Software, and to permit persons to whom the |
9 | * Software is furnished to do so, subject to the following conditions: |
10 | * |
11 | * The above copyright notice and this permission notice shall be included in |
12 | * all copies or substantial portions of the Software. |
13 | * |
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
20 | * OTHER DEALINGS IN THE SOFTWARE. |
21 | * |
22 | * Authors: AMD |
23 | * |
24 | */ |
25 | |
26 | #include "dce_i2c.h" |
27 | #include "dce_i2c_sw.h" |
28 | #include "include/gpio_service_interface.h" |
29 | #define SCL false |
30 | #define SDA true |
31 | |
32 | void dce_i2c_sw_construct( |
33 | struct dce_i2c_sw *dce_i2c_sw, |
34 | struct dc_context *ctx) |
35 | { |
36 | dce_i2c_sw->ctx = ctx; |
37 | } |
38 | |
39 | static inline bool read_bit_from_ddc( |
40 | struct ddc *ddc, |
41 | bool data_nor_clock) |
42 | { |
43 | uint32_t value = 0; |
44 | |
45 | if (data_nor_clock) |
46 | dal_gpio_get_value(gpio: ddc->pin_data, value: &value); |
47 | else |
48 | dal_gpio_get_value(gpio: ddc->pin_clock, value: &value); |
49 | |
50 | return (value != 0); |
51 | } |
52 | |
53 | static inline void write_bit_to_ddc( |
54 | struct ddc *ddc, |
55 | bool data_nor_clock, |
56 | bool bit) |
57 | { |
58 | uint32_t value = bit ? 1 : 0; |
59 | |
60 | if (data_nor_clock) |
61 | dal_gpio_set_value(gpio: ddc->pin_data, value); |
62 | else |
63 | dal_gpio_set_value(gpio: ddc->pin_clock, value); |
64 | } |
65 | |
66 | static void release_engine_dce_sw( |
67 | struct resource_pool *pool, |
68 | struct dce_i2c_sw *dce_i2c_sw) |
69 | { |
70 | dal_ddc_close(ddc: dce_i2c_sw->ddc); |
71 | dce_i2c_sw->ddc = NULL; |
72 | } |
73 | |
74 | static bool wait_for_scl_high_sw( |
75 | struct dc_context *ctx, |
76 | struct ddc *ddc, |
77 | uint16_t clock_delay_div_4) |
78 | { |
79 | uint32_t scl_retry = 0; |
80 | uint32_t scl_retry_max = I2C_SW_TIMEOUT_DELAY / clock_delay_div_4; |
81 | |
82 | udelay(clock_delay_div_4); |
83 | |
84 | do { |
85 | if (read_bit_from_ddc(ddc, SCL)) |
86 | return true; |
87 | |
88 | udelay(clock_delay_div_4); |
89 | |
90 | ++scl_retry; |
91 | } while (scl_retry <= scl_retry_max); |
92 | |
93 | return false; |
94 | } |
95 | static bool write_byte_sw( |
96 | struct dc_context *ctx, |
97 | struct ddc *ddc_handle, |
98 | uint16_t clock_delay_div_4, |
99 | uint8_t byte) |
100 | { |
101 | int32_t shift = 7; |
102 | bool ack; |
103 | |
104 | /* bits are transmitted serially, starting from MSB */ |
105 | |
106 | do { |
107 | udelay(clock_delay_div_4); |
108 | |
109 | write_bit_to_ddc(ddc: ddc_handle, SDA, bit: (byte >> shift) & 1); |
110 | |
111 | udelay(clock_delay_div_4); |
112 | |
113 | write_bit_to_ddc(ddc: ddc_handle, SCL, bit: true); |
114 | |
115 | if (!wait_for_scl_high_sw(ctx, ddc: ddc_handle, clock_delay_div_4)) |
116 | return false; |
117 | |
118 | write_bit_to_ddc(ddc: ddc_handle, SCL, bit: false); |
119 | |
120 | --shift; |
121 | } while (shift >= 0); |
122 | |
123 | /* The display sends ACK by preventing the SDA from going high |
124 | * after the SCL pulse we use to send our last data bit. |
125 | * If the SDA goes high after that bit, it's a NACK |
126 | */ |
127 | |
128 | udelay(clock_delay_div_4); |
129 | |
130 | write_bit_to_ddc(ddc: ddc_handle, SDA, bit: true); |
131 | |
132 | udelay(clock_delay_div_4); |
133 | |
134 | write_bit_to_ddc(ddc: ddc_handle, SCL, bit: true); |
135 | |
136 | if (!wait_for_scl_high_sw(ctx, ddc: ddc_handle, clock_delay_div_4)) |
137 | return false; |
138 | |
139 | /* read ACK bit */ |
140 | |
141 | ack = !read_bit_from_ddc(ddc: ddc_handle, SDA); |
142 | |
143 | udelay(clock_delay_div_4 << 1); |
144 | |
145 | write_bit_to_ddc(ddc: ddc_handle, SCL, bit: false); |
146 | |
147 | udelay(clock_delay_div_4 << 1); |
148 | |
149 | return ack; |
150 | } |
151 | |
152 | static bool read_byte_sw( |
153 | struct dc_context *ctx, |
154 | struct ddc *ddc_handle, |
155 | uint16_t clock_delay_div_4, |
156 | uint8_t *byte, |
157 | bool more) |
158 | { |
159 | int32_t shift = 7; |
160 | |
161 | uint8_t data = 0; |
162 | |
163 | /* The data bits are read from MSB to LSB; |
164 | * bit is read while SCL is high |
165 | */ |
166 | |
167 | do { |
168 | write_bit_to_ddc(ddc: ddc_handle, SCL, bit: true); |
169 | |
170 | if (!wait_for_scl_high_sw(ctx, ddc: ddc_handle, clock_delay_div_4)) |
171 | return false; |
172 | |
173 | if (read_bit_from_ddc(ddc: ddc_handle, SDA)) |
174 | data |= (1 << shift); |
175 | |
176 | write_bit_to_ddc(ddc: ddc_handle, SCL, bit: false); |
177 | |
178 | udelay(clock_delay_div_4 << 1); |
179 | |
180 | --shift; |
181 | } while (shift >= 0); |
182 | |
183 | /* read only whole byte */ |
184 | |
185 | *byte = data; |
186 | |
187 | udelay(clock_delay_div_4); |
188 | |
189 | /* send the acknowledge bit: |
190 | * SDA low means ACK, SDA high means NACK |
191 | */ |
192 | |
193 | write_bit_to_ddc(ddc: ddc_handle, SDA, bit: !more); |
194 | |
195 | udelay(clock_delay_div_4); |
196 | |
197 | write_bit_to_ddc(ddc: ddc_handle, SCL, bit: true); |
198 | |
199 | if (!wait_for_scl_high_sw(ctx, ddc: ddc_handle, clock_delay_div_4)) |
200 | return false; |
201 | |
202 | write_bit_to_ddc(ddc: ddc_handle, SCL, bit: false); |
203 | |
204 | udelay(clock_delay_div_4); |
205 | |
206 | write_bit_to_ddc(ddc: ddc_handle, SDA, bit: true); |
207 | |
208 | udelay(clock_delay_div_4); |
209 | |
210 | return true; |
211 | } |
212 | static bool stop_sync_sw( |
213 | struct dc_context *ctx, |
214 | struct ddc *ddc_handle, |
215 | uint16_t clock_delay_div_4) |
216 | { |
217 | uint32_t retry = 0; |
218 | |
219 | /* The I2C communications stop signal is: |
220 | * the SDA going high from low, while the SCL is high. |
221 | */ |
222 | |
223 | write_bit_to_ddc(ddc: ddc_handle, SCL, bit: false); |
224 | |
225 | udelay(clock_delay_div_4); |
226 | |
227 | write_bit_to_ddc(ddc: ddc_handle, SDA, bit: false); |
228 | |
229 | udelay(clock_delay_div_4); |
230 | |
231 | write_bit_to_ddc(ddc: ddc_handle, SCL, bit: true); |
232 | |
233 | if (!wait_for_scl_high_sw(ctx, ddc: ddc_handle, clock_delay_div_4)) |
234 | return false; |
235 | |
236 | write_bit_to_ddc(ddc: ddc_handle, SDA, bit: true); |
237 | |
238 | do { |
239 | udelay(clock_delay_div_4); |
240 | |
241 | if (read_bit_from_ddc(ddc: ddc_handle, SDA)) |
242 | return true; |
243 | |
244 | ++retry; |
245 | } while (retry <= 2); |
246 | |
247 | return false; |
248 | } |
249 | static bool i2c_write_sw( |
250 | struct dc_context *ctx, |
251 | struct ddc *ddc_handle, |
252 | uint16_t clock_delay_div_4, |
253 | uint8_t address, |
254 | uint32_t length, |
255 | const uint8_t *data) |
256 | { |
257 | uint32_t i = 0; |
258 | |
259 | if (!write_byte_sw(ctx, ddc_handle, clock_delay_div_4, byte: address)) |
260 | return false; |
261 | |
262 | while (i < length) { |
263 | if (!write_byte_sw(ctx, ddc_handle, clock_delay_div_4, byte: data[i])) |
264 | return false; |
265 | ++i; |
266 | } |
267 | |
268 | return true; |
269 | } |
270 | |
271 | static bool i2c_read_sw( |
272 | struct dc_context *ctx, |
273 | struct ddc *ddc_handle, |
274 | uint16_t clock_delay_div_4, |
275 | uint8_t address, |
276 | uint32_t length, |
277 | uint8_t *data) |
278 | { |
279 | uint32_t i = 0; |
280 | |
281 | if (!write_byte_sw(ctx, ddc_handle, clock_delay_div_4, byte: address)) |
282 | return false; |
283 | |
284 | while (i < length) { |
285 | if (!read_byte_sw(ctx, ddc_handle, clock_delay_div_4, byte: data + i, |
286 | more: i < length - 1)) |
287 | return false; |
288 | ++i; |
289 | } |
290 | |
291 | return true; |
292 | } |
293 | |
294 | |
295 | |
296 | static bool start_sync_sw( |
297 | struct dc_context *ctx, |
298 | struct ddc *ddc_handle, |
299 | uint16_t clock_delay_div_4) |
300 | { |
301 | uint32_t retry = 0; |
302 | |
303 | /* The I2C communications start signal is: |
304 | * the SDA going low from high, while the SCL is high. |
305 | */ |
306 | |
307 | write_bit_to_ddc(ddc: ddc_handle, SCL, bit: true); |
308 | |
309 | udelay(clock_delay_div_4); |
310 | |
311 | do { |
312 | write_bit_to_ddc(ddc: ddc_handle, SDA, bit: true); |
313 | |
314 | if (!read_bit_from_ddc(ddc: ddc_handle, SDA)) { |
315 | ++retry; |
316 | continue; |
317 | } |
318 | |
319 | udelay(clock_delay_div_4); |
320 | |
321 | write_bit_to_ddc(ddc: ddc_handle, SCL, bit: true); |
322 | |
323 | if (!wait_for_scl_high_sw(ctx, ddc: ddc_handle, clock_delay_div_4)) |
324 | break; |
325 | |
326 | write_bit_to_ddc(ddc: ddc_handle, SDA, bit: false); |
327 | |
328 | udelay(clock_delay_div_4); |
329 | |
330 | write_bit_to_ddc(ddc: ddc_handle, SCL, bit: false); |
331 | |
332 | udelay(clock_delay_div_4); |
333 | |
334 | return true; |
335 | } while (retry <= I2C_SW_RETRIES); |
336 | |
337 | return false; |
338 | } |
339 | |
340 | static void dce_i2c_sw_engine_set_speed( |
341 | struct dce_i2c_sw *engine, |
342 | uint32_t speed) |
343 | { |
344 | ASSERT(speed); |
345 | |
346 | engine->speed = speed ? speed : DCE_I2C_DEFAULT_I2C_SW_SPEED; |
347 | |
348 | engine->clock_delay = 1000 / engine->speed; |
349 | |
350 | if (engine->clock_delay < 12) |
351 | engine->clock_delay = 12; |
352 | } |
353 | |
354 | static bool dce_i2c_sw_engine_acquire_engine( |
355 | struct dce_i2c_sw *engine, |
356 | struct ddc *ddc) |
357 | { |
358 | enum gpio_result result; |
359 | |
360 | result = dal_ddc_open(ddc, mode: GPIO_MODE_FAST_OUTPUT, |
361 | config_type: GPIO_DDC_CONFIG_TYPE_MODE_I2C); |
362 | |
363 | if (result != GPIO_RESULT_OK) |
364 | return false; |
365 | |
366 | engine->ddc = ddc; |
367 | |
368 | return true; |
369 | } |
370 | |
371 | bool dce_i2c_engine_acquire_sw( |
372 | struct dce_i2c_sw *dce_i2c_sw, |
373 | struct ddc *ddc_handle) |
374 | { |
375 | uint32_t counter = 0; |
376 | bool result; |
377 | |
378 | do { |
379 | |
380 | result = dce_i2c_sw_engine_acquire_engine( |
381 | engine: dce_i2c_sw, ddc: ddc_handle); |
382 | |
383 | if (result) |
384 | break; |
385 | |
386 | /* i2c_engine is busy by VBios, lets wait and retry */ |
387 | |
388 | udelay(10); |
389 | |
390 | ++counter; |
391 | } while (counter < 2); |
392 | |
393 | return result; |
394 | } |
395 | |
396 | static void dce_i2c_sw_engine_submit_channel_request(struct dce_i2c_sw *engine, |
397 | struct i2c_request_transaction_data *req) |
398 | { |
399 | struct ddc *ddc = engine->ddc; |
400 | uint16_t clock_delay_div_4 = engine->clock_delay >> 2; |
401 | |
402 | /* send sync (start / repeated start) */ |
403 | |
404 | bool result = start_sync_sw(ctx: engine->ctx, ddc_handle: ddc, clock_delay_div_4); |
405 | |
406 | /* process payload */ |
407 | |
408 | if (result) { |
409 | switch (req->action) { |
410 | case DCE_I2C_TRANSACTION_ACTION_I2C_WRITE: |
411 | case DCE_I2C_TRANSACTION_ACTION_I2C_WRITE_MOT: |
412 | result = i2c_write_sw(ctx: engine->ctx, ddc_handle: ddc, clock_delay_div_4, |
413 | address: req->address, length: req->length, data: req->data); |
414 | break; |
415 | case DCE_I2C_TRANSACTION_ACTION_I2C_READ: |
416 | case DCE_I2C_TRANSACTION_ACTION_I2C_READ_MOT: |
417 | result = i2c_read_sw(ctx: engine->ctx, ddc_handle: ddc, clock_delay_div_4, |
418 | address: req->address, length: req->length, data: req->data); |
419 | break; |
420 | default: |
421 | result = false; |
422 | break; |
423 | } |
424 | } |
425 | |
426 | /* send stop if not 'mot' or operation failed */ |
427 | |
428 | if (!result || |
429 | (req->action == DCE_I2C_TRANSACTION_ACTION_I2C_WRITE) || |
430 | (req->action == DCE_I2C_TRANSACTION_ACTION_I2C_READ)) |
431 | if (!stop_sync_sw(ctx: engine->ctx, ddc_handle: ddc, clock_delay_div_4)) |
432 | result = false; |
433 | |
434 | req->status = result ? |
435 | I2C_CHANNEL_OPERATION_SUCCEEDED : |
436 | I2C_CHANNEL_OPERATION_FAILED; |
437 | } |
438 | |
439 | static bool dce_i2c_sw_engine_submit_payload(struct dce_i2c_sw *engine, |
440 | struct i2c_payload *payload, |
441 | bool middle_of_transaction) |
442 | { |
443 | struct i2c_request_transaction_data request; |
444 | |
445 | if (!payload->write) |
446 | request.action = middle_of_transaction ? |
447 | DCE_I2C_TRANSACTION_ACTION_I2C_READ_MOT : |
448 | DCE_I2C_TRANSACTION_ACTION_I2C_READ; |
449 | else |
450 | request.action = middle_of_transaction ? |
451 | DCE_I2C_TRANSACTION_ACTION_I2C_WRITE_MOT : |
452 | DCE_I2C_TRANSACTION_ACTION_I2C_WRITE; |
453 | |
454 | request.address = (uint8_t) ((payload->address << 1) | !payload->write); |
455 | request.length = payload->length; |
456 | request.data = payload->data; |
457 | |
458 | dce_i2c_sw_engine_submit_channel_request(engine, req: &request); |
459 | |
460 | if ((request.status == I2C_CHANNEL_OPERATION_ENGINE_BUSY) || |
461 | (request.status == I2C_CHANNEL_OPERATION_FAILED)) |
462 | return false; |
463 | |
464 | return true; |
465 | } |
466 | bool dce_i2c_submit_command_sw( |
467 | struct resource_pool *pool, |
468 | struct ddc *ddc, |
469 | struct i2c_command *cmd, |
470 | struct dce_i2c_sw *dce_i2c_sw) |
471 | { |
472 | uint8_t index_of_payload = 0; |
473 | bool result; |
474 | |
475 | dce_i2c_sw_engine_set_speed(engine: dce_i2c_sw, speed: cmd->speed); |
476 | |
477 | result = true; |
478 | |
479 | while (index_of_payload < cmd->number_of_payloads) { |
480 | bool mot = (index_of_payload != cmd->number_of_payloads - 1); |
481 | |
482 | struct i2c_payload *payload = cmd->payloads + index_of_payload; |
483 | |
484 | if (!dce_i2c_sw_engine_submit_payload( |
485 | engine: dce_i2c_sw, payload, middle_of_transaction: mot)) { |
486 | result = false; |
487 | break; |
488 | } |
489 | |
490 | ++index_of_payload; |
491 | } |
492 | |
493 | release_engine_dce_sw(pool, dce_i2c_sw); |
494 | |
495 | return result; |
496 | } |
497 | |