]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blame - drivers/gpu/drm/amd/display/dc/dce/dce_aux.c
Merge tag 'asoc-v5.7' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie...
[mirror_ubuntu-hirsute-kernel.git] / drivers / gpu / drm / amd / display / dc / dce / dce_aux.c
CommitLineData
5c6ac711
BL
1/*
2 * Copyright 2012-15 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
c366be54 26#include <linux/delay.h>
4fc4dca8 27#include <linux/slab.h>
c366be54 28
5c6ac711 29#include "dm_services.h"
eae5ffa9 30#include "core_types.h"
5c6ac711
BL
31#include "dce_aux.h"
32#include "dce/dce_11_0_sh_mask.h"
63b9caff 33#include "dm_event_log.h"
5c6ac711
BL
34
35#define CTX \
65c78961 36 aux110->base.ctx
5c6ac711
BL
37#define REG(reg_name)\
38 (aux110->regs->reg_name)
39
40#define DC_LOGGER \
65c78961 41 engine->ctx->logger
5c6ac711
BL
42
43#include "reg_helper.h"
44
8276dd87 45#undef FN
46#define FN(reg_name, field_name) \
47 aux110->shift->field_name, aux110->mask->field_name
48
5c6ac711
BL
49#define FROM_AUX_ENGINE(ptr) \
50 container_of((ptr), struct aux_engine_dce110, base)
51
52#define FROM_ENGINE(ptr) \
1877ccf6 53 FROM_AUX_ENGINE(container_of((ptr), struct dce_aux, base))
5c6ac711
BL
54
55#define FROM_AUX_ENGINE_ENGINE(ptr) \
1877ccf6 56 container_of((ptr), struct dce_aux, base)
5c6ac711
BL
57enum {
58 AUX_INVALID_REPLY_RETRY_COUNTER = 1,
59 AUX_TIMED_OUT_RETRY_COUNTER = 2,
60 AUX_DEFER_RETRY_COUNTER = 6
61};
f6040a43 62
9bffd080 63#define TIME_OUT_INCREMENT 1016
64#define TIME_OUT_MULTIPLIER_8 8
65#define TIME_OUT_MULTIPLIER_16 16
66#define TIME_OUT_MULTIPLIER_32 32
67#define TIME_OUT_MULTIPLIER_64 64
68#define MAX_TIMEOUT_LENGTH 127
69#define DEFAULT_AUX_ENGINE_MULT 0
70#define DEFAULT_AUX_ENGINE_LENGTH 69
f6040a43 71
5c6ac711 72static void release_engine(
1877ccf6 73 struct dce_aux *engine)
5c6ac711 74{
65c78961 75 struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
5c6ac711
BL
76
77 dal_ddc_close(engine->ddc);
78
79 engine->ddc = NULL;
80
81 REG_UPDATE(AUX_ARB_CONTROL, AUX_SW_DONE_USING_AUX_REG, 1);
82}
83
84#define SW_CAN_ACCESS_AUX 1
85#define DMCU_CAN_ACCESS_AUX 2
86
87static bool is_engine_available(
1877ccf6 88 struct dce_aux *engine)
5c6ac711
BL
89{
90 struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
91
92 uint32_t value = REG_READ(AUX_ARB_CONTROL);
93 uint32_t field = get_reg_field_value(
94 value,
95 AUX_ARB_CONTROL,
96 AUX_REG_RW_CNTL_STATUS);
97
98 return (field != DMCU_CAN_ACCESS_AUX);
99}
100static bool acquire_engine(
1877ccf6 101 struct dce_aux *engine)
5c6ac711
BL
102{
103 struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
104
105 uint32_t value = REG_READ(AUX_ARB_CONTROL);
106 uint32_t field = get_reg_field_value(
107 value,
108 AUX_ARB_CONTROL,
109 AUX_REG_RW_CNTL_STATUS);
110 if (field == DMCU_CAN_ACCESS_AUX)
111 return false;
112 /* enable AUX before request SW to access AUX */
113 value = REG_READ(AUX_CONTROL);
114 field = get_reg_field_value(value,
115 AUX_CONTROL,
116 AUX_EN);
117
118 if (field == 0) {
119 set_reg_field_value(
120 value,
121 1,
122 AUX_CONTROL,
123 AUX_EN);
124
125 if (REG(AUX_RESET_MASK)) {
126 /*DP_AUX block as part of the enable sequence*/
127 set_reg_field_value(
128 value,
129 1,
130 AUX_CONTROL,
131 AUX_RESET);
132 }
133
134 REG_WRITE(AUX_CONTROL, value);
135
136 if (REG(AUX_RESET_MASK)) {
137 /*poll HW to make sure reset it done*/
138
139 REG_WAIT(AUX_CONTROL, AUX_RESET_DONE, 1,
140 1, 11);
141
142 set_reg_field_value(
143 value,
144 0,
145 AUX_CONTROL,
146 AUX_RESET);
147
148 REG_WRITE(AUX_CONTROL, value);
149
150 REG_WAIT(AUX_CONTROL, AUX_RESET_DONE, 0,
151 1, 11);
152 }
153 } /*if (field)*/
154
155 /* request SW to access AUX */
156 REG_UPDATE(AUX_ARB_CONTROL, AUX_SW_USE_AUX_REG_REQ, 1);
157
158 value = REG_READ(AUX_ARB_CONTROL);
159 field = get_reg_field_value(
160 value,
161 AUX_ARB_CONTROL,
162 AUX_REG_RW_CNTL_STATUS);
163
164 return (field == SW_CAN_ACCESS_AUX);
165}
166
167#define COMPOSE_AUX_SW_DATA_16_20(command, address) \
168 ((command) | ((0xF0000 & (address)) >> 16))
169
170#define COMPOSE_AUX_SW_DATA_8_15(address) \
171 ((0xFF00 & (address)) >> 8)
172
173#define COMPOSE_AUX_SW_DATA_0_7(address) \
174 (0xFF & (address))
175
176static void submit_channel_request(
1877ccf6 177 struct dce_aux *engine,
5c6ac711
BL
178 struct aux_request_transaction_data *request)
179{
180 struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
181 uint32_t value;
182 uint32_t length;
183
184 bool is_write =
185 ((request->type == AUX_TRANSACTION_TYPE_DP) &&
186 (request->action == I2CAUX_TRANSACTION_ACTION_DP_WRITE)) ||
187 ((request->type == AUX_TRANSACTION_TYPE_I2C) &&
188 ((request->action == I2CAUX_TRANSACTION_ACTION_I2C_WRITE) ||
189 (request->action == I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT)));
190 if (REG(AUXN_IMPCAL)) {
191 /* clear_aux_error */
30eb85ff
YS
192 REG_UPDATE_SEQ_2(AUXN_IMPCAL,
193 AUXN_CALOUT_ERROR_AK, 1,
194 AUXN_CALOUT_ERROR_AK, 0);
5c6ac711 195
30eb85ff
YS
196 REG_UPDATE_SEQ_2(AUXP_IMPCAL,
197 AUXP_CALOUT_ERROR_AK, 1,
198 AUXP_CALOUT_ERROR_AK, 0);
5c6ac711
BL
199
200 /* force_default_calibrate */
30eb85ff 201 REG_UPDATE_SEQ_2(AUXN_IMPCAL,
5c6ac711
BL
202 AUXN_IMPCAL_ENABLE, 1,
203 AUXN_IMPCAL_OVERRIDE_ENABLE, 0);
204
205 /* bug? why AUXN update EN and OVERRIDE_EN 1 by 1 while AUX P toggles OVERRIDE? */
206
30eb85ff
YS
207 REG_UPDATE_SEQ_2(AUXP_IMPCAL,
208 AUXP_IMPCAL_OVERRIDE_ENABLE, 1,
209 AUXP_IMPCAL_OVERRIDE_ENABLE, 0);
5c6ac711 210 }
f4bbebf8
ML
211
212 REG_UPDATE(AUX_INTERRUPT_CONTROL, AUX_SW_DONE_ACK, 1);
213
214 REG_WAIT(AUX_SW_STATUS, AUX_SW_DONE, 0,
f6040a43 215 10, aux110->polling_timeout_period/10);
f4bbebf8 216
5c6ac711
BL
217 /* set the delay and the number of bytes to write */
218
219 /* The length include
220 * the 4 bit header and the 20 bit address
221 * (that is 3 byte).
222 * If the requested length is non zero this means
223 * an addition byte specifying the length is required.
224 */
225
226 length = request->length ? 4 : 3;
227 if (is_write)
228 length += request->length;
229
230 REG_UPDATE_2(AUX_SW_CONTROL,
231 AUX_SW_START_DELAY, request->delay,
232 AUX_SW_WR_BYTES, length);
233
234 /* program action and address and payload data (if 'is_write') */
235 value = REG_UPDATE_4(AUX_SW_DATA,
236 AUX_SW_INDEX, 0,
237 AUX_SW_DATA_RW, 0,
238 AUX_SW_AUTOINCREMENT_DISABLE, 1,
239 AUX_SW_DATA, COMPOSE_AUX_SW_DATA_16_20(request->action, request->address));
240
241 value = REG_SET_2(AUX_SW_DATA, value,
242 AUX_SW_AUTOINCREMENT_DISABLE, 0,
243 AUX_SW_DATA, COMPOSE_AUX_SW_DATA_8_15(request->address));
244
245 value = REG_SET(AUX_SW_DATA, value,
246 AUX_SW_DATA, COMPOSE_AUX_SW_DATA_0_7(request->address));
247
248 if (request->length) {
249 value = REG_SET(AUX_SW_DATA, value,
250 AUX_SW_DATA, request->length - 1);
251 }
252
253 if (is_write) {
254 /* Load the HW buffer with the Data to be sent.
255 * This is relevant for write operation.
256 * For read, the data recived data will be
257 * processed in process_channel_reply().
258 */
259 uint32_t i = 0;
260
261 while (i < request->length) {
262 value = REG_SET(AUX_SW_DATA, value,
263 AUX_SW_DATA, request->data[i]);
264
265 ++i;
266 }
267 }
268
5c6ac711 269 REG_UPDATE(AUX_SW_CONTROL, AUX_SW_GO, 1);
63b9caff
CH
270 EVENT_LOG_AUX_REQ(engine->ddc->pin_data->en, EVENT_LOG_AUX_ORIGIN_NATIVE,
271 request->action, request->address, request->length, request->data);
5c6ac711
BL
272}
273
1877ccf6 274static int read_channel_reply(struct dce_aux *engine, uint32_t size,
5c6ac711
BL
275 uint8_t *buffer, uint8_t *reply_result,
276 uint32_t *sw_status)
277{
278 struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
279 uint32_t bytes_replied;
280 uint32_t reply_result_32;
281
282 *sw_status = REG_GET(AUX_SW_STATUS, AUX_SW_REPLY_BYTE_COUNT,
283 &bytes_replied);
284
285 /* In case HPD is LOW, exit AUX transaction */
286 if ((*sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK))
287 return -1;
288
289 /* Need at least the status byte */
290 if (!bytes_replied)
291 return -1;
292
30eb85ff 293 REG_UPDATE_SEQ_3(AUX_SW_DATA,
5c6ac711
BL
294 AUX_SW_INDEX, 0,
295 AUX_SW_AUTOINCREMENT_DISABLE, 1,
296 AUX_SW_DATA_RW, 1);
297
298 REG_GET(AUX_SW_DATA, AUX_SW_DATA, &reply_result_32);
299 reply_result_32 = reply_result_32 >> 4;
ad6756b4
DF
300 if (reply_result != NULL)
301 *reply_result = (uint8_t)reply_result_32;
5c6ac711
BL
302
303 if (reply_result_32 == 0) { /* ACK */
304 uint32_t i = 0;
305
306 /* First byte was already used to get the command status */
307 --bytes_replied;
308
309 /* Do not overflow buffer */
310 if (bytes_replied > size)
311 return -1;
312
313 while (i < bytes_replied) {
314 uint32_t aux_sw_data_val;
315
316 REG_GET(AUX_SW_DATA, AUX_SW_DATA, &aux_sw_data_val);
317 buffer[i] = aux_sw_data_val;
318 ++i;
319 }
320
321 return i;
322 }
323
324 return 0;
325}
326
5c6ac711 327static enum aux_channel_operation_result get_channel_status(
1877ccf6 328 struct dce_aux *engine,
5c6ac711
BL
329 uint8_t *returned_bytes)
330{
331 struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
332
333 uint32_t value;
334
335 if (returned_bytes == NULL) {
336 /*caller pass NULL pointer*/
337 ASSERT_CRITICAL(false);
338 return AUX_CHANNEL_OPERATION_FAILED_REASON_UNKNOWN;
339 }
340 *returned_bytes = 0;
341
342 /* poll to make sure that SW_DONE is asserted */
335d5d7b 343 REG_WAIT(AUX_SW_STATUS, AUX_SW_DONE, 1,
f6040a43 344 10, aux110->polling_timeout_period/10);
5c6ac711 345
335d5d7b 346 value = REG_READ(AUX_SW_STATUS);
5c6ac711
BL
347 /* in case HPD is LOW, exit AUX transaction */
348 if ((value & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK))
349 return AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON;
350
351 /* Note that the following bits are set in 'status.bits'
352 * during CTS 4.2.1.2 (FW 3.3.1):
353 * AUX_SW_RX_MIN_COUNT_VIOL, AUX_SW_RX_INVALID_STOP,
354 * AUX_SW_RX_RECV_NO_DET, AUX_SW_RX_RECV_INVALID_H.
355 *
356 * AUX_SW_RX_MIN_COUNT_VIOL is an internal,
357 * HW debugging bit and should be ignored.
358 */
359 if (value & AUX_SW_STATUS__AUX_SW_DONE_MASK) {
360 if ((value & AUX_SW_STATUS__AUX_SW_RX_TIMEOUT_STATE_MASK) ||
361 (value & AUX_SW_STATUS__AUX_SW_RX_TIMEOUT_MASK))
362 return AUX_CHANNEL_OPERATION_FAILED_TIMEOUT;
363
364 else if ((value & AUX_SW_STATUS__AUX_SW_RX_INVALID_STOP_MASK) ||
365 (value & AUX_SW_STATUS__AUX_SW_RX_RECV_NO_DET_MASK) ||
366 (value &
367 AUX_SW_STATUS__AUX_SW_RX_RECV_INVALID_H_MASK) ||
368 (value & AUX_SW_STATUS__AUX_SW_RX_RECV_INVALID_L_MASK))
369 return AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY;
370
371 *returned_bytes = get_reg_field_value(value,
372 AUX_SW_STATUS,
373 AUX_SW_REPLY_BYTE_COUNT);
374
375 if (*returned_bytes == 0)
376 return
377 AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY;
378 else {
379 *returned_bytes -= 1;
380 return AUX_CHANNEL_OPERATION_SUCCEEDED;
381 }
382 } else {
383 /*time_elapsed >= aux_engine->timeout_period
384 * AUX_SW_STATUS__AUX_SW_HPD_DISCON = at this point
385 */
386 ASSERT_CRITICAL(false);
387 return AUX_CHANNEL_OPERATION_FAILED_TIMEOUT;
388 }
389}
5c6ac711 390
5c6ac711 391enum i2caux_engine_type get_engine_type(
1877ccf6 392 const struct dce_aux *engine)
5c6ac711
BL
393{
394 return I2CAUX_ENGINE_TYPE_AUX;
395}
396
65c78961 397static bool acquire(
1877ccf6 398 struct dce_aux *engine,
5c6ac711
BL
399 struct ddc *ddc)
400{
5c6ac711
BL
401 enum gpio_result result;
402
2b63d0ec 403 if ((engine == NULL) || !is_engine_available(engine))
1877ccf6 404 return false;
5c6ac711
BL
405
406 result = dal_ddc_open(ddc, GPIO_MODE_HARDWARE,
407 GPIO_DDC_CONFIG_TYPE_MODE_AUX);
408
409 if (result != GPIO_RESULT_OK)
65c78961 410 return false;
5c6ac711 411
1877ccf6 412 if (!acquire_engine(engine)) {
5c6ac711 413 dal_ddc_close(ddc);
65c78961 414 return false;
5c6ac711
BL
415 }
416
417 engine->ddc = ddc;
418
65c78961 419 return true;
5c6ac711
BL
420}
421
1877ccf6 422void dce110_engine_destroy(struct dce_aux **engine)
5c6ac711
BL
423{
424
65c78961 425 struct aux_engine_dce110 *engine110 = FROM_AUX_ENGINE(*engine);
5c6ac711
BL
426
427 kfree(engine110);
428 *engine = NULL;
429
430}
8276dd87 431
9bffd080 432static uint32_t dce_aux_configure_timeout(struct ddc_service *ddc,
f6040a43 433 uint32_t timeout_in_us)
434{
435 uint32_t multiplier = 0;
436 uint32_t length = 0;
9bffd080 437 uint32_t prev_length = 0;
438 uint32_t prev_mult = 0;
439 uint32_t prev_timeout_val = 0;
f6040a43 440 struct ddc *ddc_pin = ddc->ddc_pin;
441 struct dce_aux *aux_engine = ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en];
442 struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(aux_engine);
443
444 /* 1-Update polling timeout period */
445 aux110->polling_timeout_period = timeout_in_us * SW_AUX_TIMEOUT_PERIOD_MULTIPLIER;
446
447 /* 2-Update aux timeout period length and multiplier */
9bffd080 448 if (timeout_in_us == 0) {
449 multiplier = DEFAULT_AUX_ENGINE_MULT;
450 length = DEFAULT_AUX_ENGINE_LENGTH;
451 } else if (timeout_in_us <= TIME_OUT_INCREMENT) {
f6040a43 452 multiplier = 0;
453 length = timeout_in_us/TIME_OUT_MULTIPLIER_8;
454 if (timeout_in_us % TIME_OUT_MULTIPLIER_8 != 0)
455 length++;
f6040a43 456 } else if (timeout_in_us <= 2 * TIME_OUT_INCREMENT) {
457 multiplier = 1;
458 length = timeout_in_us/TIME_OUT_MULTIPLIER_16;
459 if (timeout_in_us % TIME_OUT_MULTIPLIER_16 != 0)
460 length++;
f6040a43 461 } else if (timeout_in_us <= 4 * TIME_OUT_INCREMENT) {
462 multiplier = 2;
463 length = timeout_in_us/TIME_OUT_MULTIPLIER_32;
464 if (timeout_in_us % TIME_OUT_MULTIPLIER_32 != 0)
465 length++;
f6040a43 466 } else if (timeout_in_us > 4 * TIME_OUT_INCREMENT) {
467 multiplier = 3;
468 length = timeout_in_us/TIME_OUT_MULTIPLIER_64;
469 if (timeout_in_us % TIME_OUT_MULTIPLIER_64 != 0)
470 length++;
f6040a43 471 }
472
473 length = (length < MAX_TIMEOUT_LENGTH) ? length : MAX_TIMEOUT_LENGTH;
474
9bffd080 475 REG_GET_2(AUX_DPHY_RX_CONTROL1, AUX_RX_TIMEOUT_LEN, &prev_length, AUX_RX_TIMEOUT_LEN_MUL, &prev_mult);
476
477 switch (prev_mult) {
478 case 0:
479 prev_timeout_val = prev_length * TIME_OUT_MULTIPLIER_8;
480 break;
481 case 1:
482 prev_timeout_val = prev_length * TIME_OUT_MULTIPLIER_16;
483 break;
484 case 2:
485 prev_timeout_val = prev_length * TIME_OUT_MULTIPLIER_32;
486 break;
487 case 3:
488 prev_timeout_val = prev_length * TIME_OUT_MULTIPLIER_64;
489 break;
490 default:
491 prev_timeout_val = DEFAULT_AUX_ENGINE_LENGTH * TIME_OUT_MULTIPLIER_8;
492 break;
493 }
494
f6040a43 495 REG_UPDATE_SEQ_2(AUX_DPHY_RX_CONTROL1, AUX_RX_TIMEOUT_LEN, length, AUX_RX_TIMEOUT_LEN_MUL, multiplier);
496
9bffd080 497 return prev_timeout_val;
f6040a43 498}
499
500static struct dce_aux_funcs aux_functions = {
501 .configure_timeout = NULL,
502 .destroy = NULL,
503};
504
1877ccf6 505struct dce_aux *dce110_aux_engine_construct(struct aux_engine_dce110 *aux_engine110,
5c6ac711
BL
506 struct dc_context *ctx,
507 uint32_t inst,
508 uint32_t timeout_period,
8276dd87 509 const struct dce110_aux_registers *regs,
510 const struct dce110_aux_registers_mask *mask,
f6040a43 511 const struct dce110_aux_registers_shift *shift,
512 bool is_ext_aux_timeout_configurable)
5c6ac711 513{
65c78961
BL
514 aux_engine110->base.ddc = NULL;
515 aux_engine110->base.ctx = ctx;
5c6ac711
BL
516 aux_engine110->base.delay = 0;
517 aux_engine110->base.max_defer_write_retry = 0;
65c78961 518 aux_engine110->base.inst = inst;
f6040a43 519 aux_engine110->polling_timeout_period = timeout_period;
5c6ac711
BL
520 aux_engine110->regs = regs;
521
8276dd87 522 aux_engine110->mask = mask;
523 aux_engine110->shift = shift;
f6040a43 524 aux_engine110->base.funcs = &aux_functions;
525 if (is_ext_aux_timeout_configurable)
526 aux_engine110->base.funcs->configure_timeout = &dce_aux_configure_timeout;
527
5c6ac711
BL
528 return &aux_engine110->base;
529}
530
eae5ffa9
DF
531static enum i2caux_transaction_action i2caux_action_from_payload(struct aux_payload *payload)
532{
533 if (payload->i2c_over_aux) {
534 if (payload->write) {
535 if (payload->mot)
536 return I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT;
537 return I2CAUX_TRANSACTION_ACTION_I2C_WRITE;
538 }
539 if (payload->mot)
540 return I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT;
541 return I2CAUX_TRANSACTION_ACTION_I2C_READ;
542 }
543 if (payload->write)
544 return I2CAUX_TRANSACTION_ACTION_DP_WRITE;
545 return I2CAUX_TRANSACTION_ACTION_DP_READ;
546}
547
8ae5b1d7
TL
548int dce_aux_transfer_raw(struct ddc_service *ddc,
549 struct aux_payload *payload,
550 enum aux_channel_operation_result *operation_result)
eae5ffa9
DF
551{
552 struct ddc *ddc_pin = ddc->ddc_pin;
1877ccf6 553 struct dce_aux *aux_engine;
eae5ffa9
DF
554 struct aux_request_transaction_data aux_req;
555 struct aux_reply_transaction_data aux_rep;
556 uint8_t returned_bytes = 0;
557 int res = -1;
558 uint32_t status;
559
560 memset(&aux_req, 0, sizeof(aux_req));
561 memset(&aux_rep, 0, sizeof(aux_rep));
562
563 aux_engine = ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en];
e9c93e5a
AK
564 if (!acquire(aux_engine, ddc_pin)) {
565 *operation_result = AUX_CHANNEL_OPERATION_FAILED_ENGINE_ACQUIRE;
dcf1a988 566 return -1;
e9c93e5a 567 }
eae5ffa9
DF
568
569 if (payload->i2c_over_aux)
570 aux_req.type = AUX_TRANSACTION_TYPE_I2C;
571 else
572 aux_req.type = AUX_TRANSACTION_TYPE_DP;
573
574 aux_req.action = i2caux_action_from_payload(payload);
575
576 aux_req.address = payload->address;
33fd2900 577 aux_req.delay = 0;
eae5ffa9
DF
578 aux_req.length = payload->length;
579 aux_req.data = payload->data;
580
1877ccf6 581 submit_channel_request(aux_engine, &aux_req);
8ae5b1d7
TL
582 *operation_result = get_channel_status(aux_engine, &returned_bytes);
583
584 if (*operation_result == AUX_CHANNEL_OPERATION_SUCCEEDED) {
63b9caff
CH
585 int bytes_replied = 0;
586 bytes_replied = read_channel_reply(aux_engine, payload->length,
8ae5b1d7
TL
587 payload->data, payload->reply,
588 &status);
63b9caff
CH
589 EVENT_LOG_AUX_REP(aux_engine->ddc->pin_data->en,
590 EVENT_LOG_AUX_ORIGIN_NATIVE, *payload->reply,
591 bytes_replied, payload->data);
8ae5b1d7
TL
592 res = returned_bytes;
593 } else {
eae5ffa9 594 res = -1;
eae5ffa9 595 }
8ae5b1d7 596
1877ccf6 597 release_engine(aux_engine);
eae5ffa9
DF
598 return res;
599}
600
8ae5b1d7
TL
601#define AUX_MAX_RETRIES 7
602#define AUX_MAX_DEFER_RETRIES 7
603#define AUX_MAX_I2C_DEFER_RETRIES 7
604#define AUX_MAX_INVALID_REPLY_RETRIES 2
605#define AUX_MAX_TIMEOUT_RETRIES 3
eae5ffa9
DF
606
607bool dce_aux_transfer_with_retries(struct ddc_service *ddc,
608 struct aux_payload *payload)
609{
610 int i, ret = 0;
611 uint8_t reply;
612 bool payload_reply = true;
8ae5b1d7 613 enum aux_channel_operation_result operation_result;
772c0b59
GS
614 bool retry_on_defer = false;
615
8ae5b1d7
TL
616 int aux_ack_retries = 0,
617 aux_defer_retries = 0,
618 aux_i2c_defer_retries = 0,
619 aux_timeout_retries = 0,
620 aux_invalid_reply_retries = 0;
eae5ffa9
DF
621
622 if (!payload->reply) {
623 payload_reply = false;
624 payload->reply = &reply;
625 }
626
8ae5b1d7
TL
627 for (i = 0; i < AUX_MAX_RETRIES; i++) {
628 ret = dce_aux_transfer_raw(ddc, payload, &operation_result);
629 switch (operation_result) {
630 case AUX_CHANNEL_OPERATION_SUCCEEDED:
631 aux_timeout_retries = 0;
632 aux_invalid_reply_retries = 0;
633
634 switch (*payload->reply) {
635 case AUX_TRANSACTION_REPLY_AUX_ACK:
636 if (!payload->write && payload->length != ret) {
637 if (++aux_ack_retries >= AUX_MAX_RETRIES)
638 goto fail;
639 else
640 udelay(300);
641 } else
642 return true;
643 break;
644
645 case AUX_TRANSACTION_REPLY_AUX_DEFER:
0dcdcc89 646 case AUX_TRANSACTION_REPLY_I2C_OVER_AUX_DEFER:
772c0b59 647 retry_on_defer = true;
f794913c 648 /* fall through */
772c0b59 649 case AUX_TRANSACTION_REPLY_I2C_OVER_AUX_NACK:
33fd2900 650 if (++aux_defer_retries >= AUX_MAX_DEFER_RETRIES) {
8ae5b1d7 651 goto fail;
33fd2900
XY
652 } else {
653 if ((*payload->reply == AUX_TRANSACTION_REPLY_AUX_DEFER) ||
654 (*payload->reply == AUX_TRANSACTION_REPLY_I2C_OVER_AUX_DEFER)) {
655 if (payload->defer_delay > 0)
656 msleep(payload->defer_delay);
657 }
658 }
8ae5b1d7
TL
659 break;
660
661 case AUX_TRANSACTION_REPLY_I2C_DEFER:
662 aux_defer_retries = 0;
663 if (++aux_i2c_defer_retries >= AUX_MAX_I2C_DEFER_RETRIES)
664 goto fail;
665 break;
666
667 case AUX_TRANSACTION_REPLY_AUX_NACK:
668 case AUX_TRANSACTION_REPLY_HPD_DISCON:
669 default:
670 goto fail;
eae5ffa9 671 }
8ae5b1d7
TL
672 break;
673
674 case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY:
675 if (++aux_invalid_reply_retries >= AUX_MAX_INVALID_REPLY_RETRIES)
676 goto fail;
677 else
678 udelay(400);
679 break;
680
681 case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT:
772c0b59
GS
682 // Check whether a DEFER had occurred before the timeout.
683 // If so, treat timeout as a DEFER.
684 if (retry_on_defer) {
685 if (++aux_defer_retries >= AUX_MAX_DEFER_RETRIES)
686 goto fail;
687 else if (payload->defer_delay > 0)
688 msleep(payload->defer_delay);
689 } else {
690 if (++aux_timeout_retries >= AUX_MAX_TIMEOUT_RETRIES)
691 goto fail;
692 else {
693 /*
694 * DP 1.4, 2.8.2: AUX Transaction Response/Reply Timeouts
695 * According to the DP spec there should be 3 retries total
696 * with a 400us wait inbetween each. Hardware already waits
697 * for 550us therefore no wait is required here.
698 */
699 }
8ae5b1d7
TL
700 }
701 break;
eae5ffa9 702
8ae5b1d7 703 case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON:
e9c93e5a 704 case AUX_CHANNEL_OPERATION_FAILED_ENGINE_ACQUIRE:
8ae5b1d7
TL
705 case AUX_CHANNEL_OPERATION_FAILED_REASON_UNKNOWN:
706 default:
707 goto fail;
708 }
eae5ffa9 709 }
8ae5b1d7
TL
710
711fail:
712 if (!payload_reply)
713 payload->reply = NULL;
eae5ffa9
DF
714 return false;
715}