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
32void 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
39static 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
53static 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
66static 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
74static 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}
95static 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
152static 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}
212static 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}
249static 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
271static 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
296static 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
340static 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
354static 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
371bool 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
396static 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
439static 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}
466bool 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

source code of linux/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_sw.c