xref: /dragonfly/sys/dev/drm/amd/display/dc/dce/dce_aux.c (revision 789731325bde747251c28a37e0a00ed4efb88c46)
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 
26 #include "dm_services.h"
27 #include "dce_aux.h"
28 #include "dce/dce_11_0_sh_mask.h"
29 
30 #define CTX \
31           aux110->base.ctx
32 #define REG(reg_name)\
33           (aux110->regs->reg_name)
34 
35 #define DC_LOGGER \
36           engine->ctx->logger
37 
38 #include "reg_helper.h"
39 
40 #define FROM_AUX_ENGINE(ptr) \
41           container_of((ptr), struct aux_engine_dce110, base)
42 
43 #define FROM_ENGINE(ptr) \
44           FROM_AUX_ENGINE(container_of((ptr), struct aux_engine, base))
45 
46 #define FROM_AUX_ENGINE_ENGINE(ptr) \
47           container_of((ptr), struct aux_engine, base)
48 enum {
49           AUX_INVALID_REPLY_RETRY_COUNTER = 1,
50           AUX_TIMED_OUT_RETRY_COUNTER = 2,
51           AUX_DEFER_RETRY_COUNTER = 6
52 };
release_engine(struct aux_engine * engine)53 static void release_engine(
54           struct aux_engine *engine)
55 {
56           struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
57 
58           dal_ddc_close(engine->ddc);
59 
60           engine->ddc = NULL;
61 
62           REG_UPDATE(AUX_ARB_CONTROL, AUX_SW_DONE_USING_AUX_REG, 1);
63 }
64 
65 #define SW_CAN_ACCESS_AUX 1
66 #define DMCU_CAN_ACCESS_AUX 2
67 
is_engine_available(struct aux_engine * engine)68 static bool is_engine_available(
69           struct aux_engine *engine)
70 {
71           struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
72 
73           uint32_t value = REG_READ(AUX_ARB_CONTROL);
74           uint32_t field = get_reg_field_value(
75                               value,
76                               AUX_ARB_CONTROL,
77                               AUX_REG_RW_CNTL_STATUS);
78 
79           return (field != DMCU_CAN_ACCESS_AUX);
80 }
acquire_engine(struct aux_engine * engine)81 static bool acquire_engine(
82           struct aux_engine *engine)
83 {
84           struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
85 
86           uint32_t value = REG_READ(AUX_ARB_CONTROL);
87           uint32_t field = get_reg_field_value(
88                               value,
89                               AUX_ARB_CONTROL,
90                               AUX_REG_RW_CNTL_STATUS);
91           if (field == DMCU_CAN_ACCESS_AUX)
92                     return false;
93           /* enable AUX before request SW to access AUX */
94           value = REG_READ(AUX_CONTROL);
95           field = get_reg_field_value(value,
96                                         AUX_CONTROL,
97                                         AUX_EN);
98 
99           if (field == 0) {
100                     set_reg_field_value(
101                                         value,
102                                         1,
103                                         AUX_CONTROL,
104                                         AUX_EN);
105 
106                     if (REG(AUX_RESET_MASK)) {
107                               /*DP_AUX block as part of the enable sequence*/
108                               set_reg_field_value(
109                                         value,
110                                         1,
111                                         AUX_CONTROL,
112                                         AUX_RESET);
113                     }
114 
115                     REG_WRITE(AUX_CONTROL, value);
116 
117                     if (REG(AUX_RESET_MASK)) {
118                               /*poll HW to make sure reset it done*/
119 
120                               REG_WAIT(AUX_CONTROL, AUX_RESET_DONE, 1,
121                                                   1, 11);
122 
123                               set_reg_field_value(
124                                         value,
125                                         0,
126                                         AUX_CONTROL,
127                                         AUX_RESET);
128 
129                               REG_WRITE(AUX_CONTROL, value);
130 
131                               REG_WAIT(AUX_CONTROL, AUX_RESET_DONE, 0,
132                                                   1, 11);
133                     }
134           } /*if (field)*/
135 
136           /* request SW to access AUX */
137           REG_UPDATE(AUX_ARB_CONTROL, AUX_SW_USE_AUX_REG_REQ, 1);
138 
139           value = REG_READ(AUX_ARB_CONTROL);
140           field = get_reg_field_value(
141                               value,
142                               AUX_ARB_CONTROL,
143                               AUX_REG_RW_CNTL_STATUS);
144 
145           return (field == SW_CAN_ACCESS_AUX);
146 }
147 
148 #define COMPOSE_AUX_SW_DATA_16_20(command, address) \
149           ((command) | ((0xF0000 & (address)) >> 16))
150 
151 #define COMPOSE_AUX_SW_DATA_8_15(address) \
152           ((0xFF00 & (address)) >> 8)
153 
154 #define COMPOSE_AUX_SW_DATA_0_7(address) \
155           (0xFF & (address))
156 
submit_channel_request(struct aux_engine * engine,struct aux_request_transaction_data * request)157 static void submit_channel_request(
158           struct aux_engine *engine,
159           struct aux_request_transaction_data *request)
160 {
161           struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
162           uint32_t value;
163           uint32_t length;
164 
165           bool is_write =
166                     ((request->type == AUX_TRANSACTION_TYPE_DP) &&
167                      (request->action == I2CAUX_TRANSACTION_ACTION_DP_WRITE)) ||
168                     ((request->type == AUX_TRANSACTION_TYPE_I2C) &&
169                     ((request->action == I2CAUX_TRANSACTION_ACTION_I2C_WRITE) ||
170                      (request->action == I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT)));
171           if (REG(AUXN_IMPCAL)) {
172                     /* clear_aux_error */
173                     REG_UPDATE_SEQ(AUXN_IMPCAL, AUXN_CALOUT_ERROR_AK,
174                                         1,
175                                         0);
176 
177                     REG_UPDATE_SEQ(AUXP_IMPCAL, AUXP_CALOUT_ERROR_AK,
178                                         1,
179                                         0);
180 
181                     /* force_default_calibrate */
182                     REG_UPDATE_1BY1_2(AUXN_IMPCAL,
183                                         AUXN_IMPCAL_ENABLE, 1,
184                                         AUXN_IMPCAL_OVERRIDE_ENABLE, 0);
185 
186                     /* bug? why AUXN update EN and OVERRIDE_EN 1 by 1 while AUX P toggles OVERRIDE? */
187 
188                     REG_UPDATE_SEQ(AUXP_IMPCAL, AUXP_IMPCAL_OVERRIDE_ENABLE,
189                                         1,
190                                         0);
191           }
192 
193           REG_UPDATE(AUX_INTERRUPT_CONTROL, AUX_SW_DONE_ACK, 1);
194 
195           REG_WAIT(AUX_SW_STATUS, AUX_SW_DONE, 0,
196                                         10, aux110->timeout_period/10);
197 
198           /* set the delay and the number of bytes to write */
199 
200           /* The length include
201            * the 4 bit header and the 20 bit address
202            * (that is 3 byte).
203            * If the requested length is non zero this means
204            * an addition byte specifying the length is required.
205            */
206 
207           length = request->length ? 4 : 3;
208           if (is_write)
209                     length += request->length;
210 
211           REG_UPDATE_2(AUX_SW_CONTROL,
212                               AUX_SW_START_DELAY, request->delay,
213                               AUX_SW_WR_BYTES, length);
214 
215           /* program action and address and payload data (if 'is_write') */
216           value = REG_UPDATE_4(AUX_SW_DATA,
217                               AUX_SW_INDEX, 0,
218                               AUX_SW_DATA_RW, 0,
219                               AUX_SW_AUTOINCREMENT_DISABLE, 1,
220                               AUX_SW_DATA, COMPOSE_AUX_SW_DATA_16_20(request->action, request->address));
221 
222           value = REG_SET_2(AUX_SW_DATA, value,
223                               AUX_SW_AUTOINCREMENT_DISABLE, 0,
224                               AUX_SW_DATA, COMPOSE_AUX_SW_DATA_8_15(request->address));
225 
226           value = REG_SET(AUX_SW_DATA, value,
227                               AUX_SW_DATA, COMPOSE_AUX_SW_DATA_0_7(request->address));
228 
229           if (request->length) {
230                     value = REG_SET(AUX_SW_DATA, value,
231                                         AUX_SW_DATA, request->length - 1);
232           }
233 
234           if (is_write) {
235                     /* Load the HW buffer with the Data to be sent.
236                      * This is relevant for write operation.
237                      * For read, the data recived data will be
238                      * processed in process_channel_reply().
239                      */
240                     uint32_t i = 0;
241 
242                     while (i < request->length) {
243                               value = REG_SET(AUX_SW_DATA, value,
244                                                   AUX_SW_DATA, request->data[i]);
245 
246                               ++i;
247                     }
248           }
249 
250           REG_UPDATE(AUX_SW_CONTROL, AUX_SW_GO, 1);
251 }
252 
read_channel_reply(struct aux_engine * engine,uint32_t size,uint8_t * buffer,uint8_t * reply_result,uint32_t * sw_status)253 static int read_channel_reply(struct aux_engine *engine, uint32_t size,
254                                     uint8_t *buffer, uint8_t *reply_result,
255                                     uint32_t *sw_status)
256 {
257           struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
258           uint32_t bytes_replied;
259           uint32_t reply_result_32;
260 
261           *sw_status = REG_GET(AUX_SW_STATUS, AUX_SW_REPLY_BYTE_COUNT,
262                                    &bytes_replied);
263 
264           /* In case HPD is LOW, exit AUX transaction */
265           if ((*sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK))
266                     return -1;
267 
268           /* Need at least the status byte */
269           if (!bytes_replied)
270                     return -1;
271 
272           REG_UPDATE_1BY1_3(AUX_SW_DATA,
273                                 AUX_SW_INDEX, 0,
274                                 AUX_SW_AUTOINCREMENT_DISABLE, 1,
275                                 AUX_SW_DATA_RW, 1);
276 
277           REG_GET(AUX_SW_DATA, AUX_SW_DATA, &reply_result_32);
278           reply_result_32 = reply_result_32 >> 4;
279           *reply_result = (uint8_t)reply_result_32;
280 
281           if (reply_result_32 == 0) { /* ACK */
282                     uint32_t i = 0;
283 
284                     /* First byte was already used to get the command status */
285                     --bytes_replied;
286 
287                     /* Do not overflow buffer */
288                     if (bytes_replied > size)
289                               return -1;
290 
291                     while (i < bytes_replied) {
292                               uint32_t aux_sw_data_val;
293 
294                               REG_GET(AUX_SW_DATA, AUX_SW_DATA, &aux_sw_data_val);
295                               buffer[i] = aux_sw_data_val;
296                               ++i;
297                     }
298 
299                     return i;
300           }
301 
302           return 0;
303 }
304 
process_channel_reply(struct aux_engine * engine,struct aux_reply_transaction_data * reply)305 static void process_channel_reply(
306           struct aux_engine *engine,
307           struct aux_reply_transaction_data *reply)
308 {
309           int bytes_replied;
310           uint8_t reply_result;
311           uint32_t sw_status;
312 
313           bytes_replied = read_channel_reply(engine, reply->length, reply->data,
314                                                      &reply_result, &sw_status);
315 
316           /* in case HPD is LOW, exit AUX transaction */
317           if ((sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) {
318                     reply->status = AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON;
319                     return;
320           }
321 
322           if (bytes_replied < 0) {
323                     /* Need to handle an error case...
324                      * Hopefully, upper layer function won't call this function if
325                      * the number of bytes in the reply was 0, because there was
326                      * surely an error that was asserted that should have been
327                      * handled for hot plug case, this could happens
328                      */
329                     if (!(sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) {
330                               reply->status = AUX_TRANSACTION_REPLY_INVALID;
331                               ASSERT_CRITICAL(false);
332                               return;
333                     }
334           } else {
335 
336                     switch (reply_result) {
337                     case 0: /* ACK */
338                               reply->status = AUX_TRANSACTION_REPLY_AUX_ACK;
339                     break;
340                     case 1: /* NACK */
341                               reply->status = AUX_TRANSACTION_REPLY_AUX_NACK;
342                     break;
343                     case 2: /* DEFER */
344                               reply->status = AUX_TRANSACTION_REPLY_AUX_DEFER;
345                     break;
346                     case 4: /* AUX ACK / I2C NACK */
347                               reply->status = AUX_TRANSACTION_REPLY_I2C_NACK;
348                     break;
349                     case 8: /* AUX ACK / I2C DEFER */
350                               reply->status = AUX_TRANSACTION_REPLY_I2C_DEFER;
351                     break;
352                     default:
353                               reply->status = AUX_TRANSACTION_REPLY_INVALID;
354                     }
355           }
356 }
357 
get_channel_status(struct aux_engine * engine,uint8_t * returned_bytes)358 static enum aux_channel_operation_result get_channel_status(
359           struct aux_engine *engine,
360           uint8_t *returned_bytes)
361 {
362           struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
363 
364           uint32_t value;
365 
366           if (returned_bytes == NULL) {
367                     /*caller pass NULL pointer*/
368                     ASSERT_CRITICAL(false);
369                     return AUX_CHANNEL_OPERATION_FAILED_REASON_UNKNOWN;
370           }
371           *returned_bytes = 0;
372 
373           /* poll to make sure that SW_DONE is asserted */
374           value = REG_WAIT(AUX_SW_STATUS, AUX_SW_DONE, 1,
375                                         10, aux110->timeout_period/10);
376 
377           /* in case HPD is LOW, exit AUX transaction */
378           if ((value & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK))
379                     return AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON;
380 
381           /* Note that the following bits are set in 'status.bits'
382            * during CTS 4.2.1.2 (FW 3.3.1):
383            * AUX_SW_RX_MIN_COUNT_VIOL, AUX_SW_RX_INVALID_STOP,
384            * AUX_SW_RX_RECV_NO_DET, AUX_SW_RX_RECV_INVALID_H.
385            *
386            * AUX_SW_RX_MIN_COUNT_VIOL is an internal,
387            * HW debugging bit and should be ignored.
388            */
389           if (value & AUX_SW_STATUS__AUX_SW_DONE_MASK) {
390                     if ((value & AUX_SW_STATUS__AUX_SW_RX_TIMEOUT_STATE_MASK) ||
391                               (value & AUX_SW_STATUS__AUX_SW_RX_TIMEOUT_MASK))
392                               return AUX_CHANNEL_OPERATION_FAILED_TIMEOUT;
393 
394                     else if ((value & AUX_SW_STATUS__AUX_SW_RX_INVALID_STOP_MASK) ||
395                               (value & AUX_SW_STATUS__AUX_SW_RX_RECV_NO_DET_MASK) ||
396                               (value &
397                                         AUX_SW_STATUS__AUX_SW_RX_RECV_INVALID_H_MASK) ||
398                               (value & AUX_SW_STATUS__AUX_SW_RX_RECV_INVALID_L_MASK))
399                               return AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY;
400 
401                     *returned_bytes = get_reg_field_value(value,
402                                         AUX_SW_STATUS,
403                                         AUX_SW_REPLY_BYTE_COUNT);
404 
405                     if (*returned_bytes == 0)
406                               return
407                               AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY;
408                     else {
409                               *returned_bytes -= 1;
410                               return AUX_CHANNEL_OPERATION_SUCCEEDED;
411                     }
412           } else {
413                     /*time_elapsed >= aux_engine->timeout_period
414                      *  AUX_SW_STATUS__AUX_SW_HPD_DISCON = at this point
415                      */
416                     ASSERT_CRITICAL(false);
417                     return AUX_CHANNEL_OPERATION_FAILED_TIMEOUT;
418           }
419 }
process_read_reply(struct aux_engine * engine,struct read_command_context * ctx)420 static void process_read_reply(
421           struct aux_engine *engine,
422           struct read_command_context *ctx)
423 {
424           engine->funcs->process_channel_reply(engine, &ctx->reply);
425 
426           switch (ctx->reply.status) {
427           case AUX_TRANSACTION_REPLY_AUX_ACK:
428                     ctx->defer_retry_aux = 0;
429                     if (ctx->returned_byte > ctx->current_read_length) {
430                               ctx->status =
431                                         I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
432                               ctx->operation_succeeded = false;
433                     } else if (ctx->returned_byte < ctx->current_read_length) {
434                               ctx->current_read_length -= ctx->returned_byte;
435 
436                               ctx->offset += ctx->returned_byte;
437 
438                               ++ctx->invalid_reply_retry_aux_on_ack;
439 
440                               if (ctx->invalid_reply_retry_aux_on_ack >
441                                         AUX_INVALID_REPLY_RETRY_COUNTER) {
442                                         ctx->status =
443                                         I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
444                                         ctx->operation_succeeded = false;
445                               }
446                     } else {
447                               ctx->status = I2CAUX_TRANSACTION_STATUS_SUCCEEDED;
448                               ctx->transaction_complete = true;
449                               ctx->operation_succeeded = true;
450                     }
451           break;
452           case AUX_TRANSACTION_REPLY_AUX_NACK:
453                     ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_NACK;
454                     ctx->operation_succeeded = false;
455           break;
456           case AUX_TRANSACTION_REPLY_AUX_DEFER:
457                     ++ctx->defer_retry_aux;
458 
459                     if (ctx->defer_retry_aux > AUX_DEFER_RETRY_COUNTER) {
460                               ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
461                               ctx->operation_succeeded = false;
462                     }
463           break;
464           case AUX_TRANSACTION_REPLY_I2C_DEFER:
465                     ctx->defer_retry_aux = 0;
466 
467                     ++ctx->defer_retry_i2c;
468 
469                     if (ctx->defer_retry_i2c > AUX_DEFER_RETRY_COUNTER) {
470                               ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
471                               ctx->operation_succeeded = false;
472                     }
473           break;
474           case AUX_TRANSACTION_REPLY_HPD_DISCON:
475                     ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
476                     ctx->operation_succeeded = false;
477           break;
478           default:
479                     ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
480                     ctx->operation_succeeded = false;
481           }
482 }
process_read_request(struct aux_engine * engine,struct read_command_context * ctx)483 static void process_read_request(
484           struct aux_engine *engine,
485           struct read_command_context *ctx)
486 {
487           enum aux_channel_operation_result operation_result;
488 
489           engine->funcs->submit_channel_request(engine, &ctx->request);
490 
491           operation_result = engine->funcs->get_channel_status(
492                     engine, &ctx->returned_byte);
493 
494           switch (operation_result) {
495           case AUX_CHANNEL_OPERATION_SUCCEEDED:
496                     if (ctx->returned_byte > ctx->current_read_length) {
497                               ctx->status =
498                                         I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
499                               ctx->operation_succeeded = false;
500                     } else {
501                               ctx->timed_out_retry_aux = 0;
502                               ctx->invalid_reply_retry_aux = 0;
503 
504                               ctx->reply.length = ctx->returned_byte;
505                               ctx->reply.data = ctx->buffer;
506 
507                               process_read_reply(engine, ctx);
508                     }
509           break;
510           case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY:
511                     ++ctx->invalid_reply_retry_aux;
512 
513                     if (ctx->invalid_reply_retry_aux >
514                               AUX_INVALID_REPLY_RETRY_COUNTER) {
515                               ctx->status =
516                                         I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
517                               ctx->operation_succeeded = false;
518                     } else
519                               udelay(400);
520           break;
521           case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT:
522                     ++ctx->timed_out_retry_aux;
523 
524                     if (ctx->timed_out_retry_aux > AUX_TIMED_OUT_RETRY_COUNTER) {
525                               ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
526                               ctx->operation_succeeded = false;
527                     } else {
528                               /* DP 1.2a, table 2-58:
529                                * "S3: AUX Request CMD PENDING:
530                                * retry 3 times, with 400usec wait on each"
531                                * The HW timeout is set to 550usec,
532                                * so we should not wait here
533                                */
534                     }
535           break;
536           case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON:
537                     ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
538                     ctx->operation_succeeded = false;
539           break;
540           default:
541                     ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
542                     ctx->operation_succeeded = false;
543           }
544 }
read_command(struct aux_engine * engine,struct i2caux_transaction_request * request,bool middle_of_transaction)545 static bool read_command(
546           struct aux_engine *engine,
547           struct i2caux_transaction_request *request,
548           bool middle_of_transaction)
549 {
550           struct read_command_context ctx;
551 
552           ctx.buffer = request->payload.data;
553           ctx.current_read_length = request->payload.length;
554           ctx.offset = 0;
555           ctx.timed_out_retry_aux = 0;
556           ctx.invalid_reply_retry_aux = 0;
557           ctx.defer_retry_aux = 0;
558           ctx.defer_retry_i2c = 0;
559           ctx.invalid_reply_retry_aux_on_ack = 0;
560           ctx.transaction_complete = false;
561           ctx.operation_succeeded = true;
562 
563           if (request->payload.address_space ==
564                     I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) {
565                     ctx.request.type = AUX_TRANSACTION_TYPE_DP;
566                     ctx.request.action = I2CAUX_TRANSACTION_ACTION_DP_READ;
567                     ctx.request.address = request->payload.address;
568           } else if (request->payload.address_space ==
569                     I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C) {
570                     ctx.request.type = AUX_TRANSACTION_TYPE_I2C;
571                     ctx.request.action = middle_of_transaction ?
572                               I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT :
573                               I2CAUX_TRANSACTION_ACTION_I2C_READ;
574                     ctx.request.address = request->payload.address >> 1;
575           } else {
576                     /* in DAL2, there was no return in such case */
577                     BREAK_TO_DEBUGGER();
578                     return false;
579           }
580 
581           ctx.request.delay = 0;
582 
583           do {
584                     memset(ctx.buffer + ctx.offset, 0, ctx.current_read_length);
585 
586                     ctx.request.data = ctx.buffer + ctx.offset;
587                     ctx.request.length = ctx.current_read_length;
588 
589                     process_read_request(engine, &ctx);
590 
591                     request->status = ctx.status;
592 
593                     if (ctx.operation_succeeded && !ctx.transaction_complete)
594                               if (ctx.request.type == AUX_TRANSACTION_TYPE_I2C)
595                                         msleep(engine->delay);
596           } while (ctx.operation_succeeded && !ctx.transaction_complete);
597 
598           if (request->payload.address_space ==
599                     I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) {
600                     DC_LOG_I2C_AUX("READ: addr:0x%x  value:0x%x Result:%d",
601                                         request->payload.address,
602                                         request->payload.data[0],
603                                         ctx.operation_succeeded);
604           }
605 
606           return ctx.operation_succeeded;
607 }
608 
process_write_reply(struct aux_engine * engine,struct write_command_context * ctx)609 static void process_write_reply(
610           struct aux_engine *engine,
611           struct write_command_context *ctx)
612 {
613           engine->funcs->process_channel_reply(engine, &ctx->reply);
614 
615           switch (ctx->reply.status) {
616           case AUX_TRANSACTION_REPLY_AUX_ACK:
617                     ctx->operation_succeeded = true;
618 
619                     if (ctx->returned_byte) {
620                               ctx->request.action = ctx->mot ?
621                               I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST_MOT :
622                               I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST;
623 
624                               ctx->current_write_length = 0;
625 
626                               ++ctx->ack_m_retry;
627 
628                               if (ctx->ack_m_retry > AUX_DEFER_RETRY_COUNTER) {
629                                         ctx->status =
630                                         I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
631                                         ctx->operation_succeeded = false;
632                               } else
633                                         udelay(300);
634                     } else {
635                               ctx->status = I2CAUX_TRANSACTION_STATUS_SUCCEEDED;
636                               ctx->defer_retry_aux = 0;
637                               ctx->ack_m_retry = 0;
638                               ctx->transaction_complete = true;
639                     }
640           break;
641           case AUX_TRANSACTION_REPLY_AUX_NACK:
642                     ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_NACK;
643                     ctx->operation_succeeded = false;
644           break;
645           case AUX_TRANSACTION_REPLY_AUX_DEFER:
646                     ++ctx->defer_retry_aux;
647 
648                     if (ctx->defer_retry_aux > ctx->max_defer_retry) {
649                               ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
650                               ctx->operation_succeeded = false;
651                     }
652           break;
653           case AUX_TRANSACTION_REPLY_I2C_DEFER:
654                     ctx->defer_retry_aux = 0;
655                     ctx->current_write_length = 0;
656 
657                     ctx->request.action = ctx->mot ?
658                               I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST_MOT :
659                               I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST;
660 
661                     ++ctx->defer_retry_i2c;
662 
663                     if (ctx->defer_retry_i2c > ctx->max_defer_retry) {
664                               ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
665                               ctx->operation_succeeded = false;
666                     }
667           break;
668           case AUX_TRANSACTION_REPLY_HPD_DISCON:
669                     ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
670                     ctx->operation_succeeded = false;
671           break;
672           default:
673                     ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
674                     ctx->operation_succeeded = false;
675           }
676 }
process_write_request(struct aux_engine * engine,struct write_command_context * ctx)677 static void process_write_request(
678           struct aux_engine *engine,
679           struct write_command_context *ctx)
680 {
681           enum aux_channel_operation_result operation_result;
682 
683           engine->funcs->submit_channel_request(engine, &ctx->request);
684 
685           operation_result = engine->funcs->get_channel_status(
686                     engine, &ctx->returned_byte);
687 
688           switch (operation_result) {
689           case AUX_CHANNEL_OPERATION_SUCCEEDED:
690                     ctx->timed_out_retry_aux = 0;
691                     ctx->invalid_reply_retry_aux = 0;
692 
693                     ctx->reply.length = ctx->returned_byte;
694                     ctx->reply.data = ctx->reply_data;
695 
696                     process_write_reply(engine, ctx);
697           break;
698           case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY:
699                     ++ctx->invalid_reply_retry_aux;
700 
701                     if (ctx->invalid_reply_retry_aux >
702                               AUX_INVALID_REPLY_RETRY_COUNTER) {
703                               ctx->status =
704                                         I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
705                               ctx->operation_succeeded = false;
706                     } else
707                               udelay(400);
708           break;
709           case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT:
710                     ++ctx->timed_out_retry_aux;
711 
712                     if (ctx->timed_out_retry_aux > AUX_TIMED_OUT_RETRY_COUNTER) {
713                               ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
714                               ctx->operation_succeeded = false;
715                     } else {
716                               /* DP 1.2a, table 2-58:
717                                * "S3: AUX Request CMD PENDING:
718                                * retry 3 times, with 400usec wait on each"
719                                * The HW timeout is set to 550usec,
720                                * so we should not wait here
721                                */
722                     }
723           break;
724           case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON:
725                     ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
726                     ctx->operation_succeeded = false;
727           break;
728           default:
729                     ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
730                     ctx->operation_succeeded = false;
731           }
732 }
write_command(struct aux_engine * engine,struct i2caux_transaction_request * request,bool middle_of_transaction)733 static bool write_command(
734           struct aux_engine *engine,
735           struct i2caux_transaction_request *request,
736           bool middle_of_transaction)
737 {
738           struct write_command_context ctx;
739 
740           ctx.mot = middle_of_transaction;
741           ctx.buffer = request->payload.data;
742           ctx.current_write_length = request->payload.length;
743           ctx.timed_out_retry_aux = 0;
744           ctx.invalid_reply_retry_aux = 0;
745           ctx.defer_retry_aux = 0;
746           ctx.defer_retry_i2c = 0;
747           ctx.ack_m_retry = 0;
748           ctx.transaction_complete = false;
749           ctx.operation_succeeded = true;
750 
751           if (request->payload.address_space ==
752                     I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) {
753                     ctx.request.type = AUX_TRANSACTION_TYPE_DP;
754                     ctx.request.action = I2CAUX_TRANSACTION_ACTION_DP_WRITE;
755                     ctx.request.address = request->payload.address;
756           } else if (request->payload.address_space ==
757                     I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C) {
758                     ctx.request.type = AUX_TRANSACTION_TYPE_I2C;
759                     ctx.request.action = middle_of_transaction ?
760                               I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT :
761                               I2CAUX_TRANSACTION_ACTION_I2C_WRITE;
762                     ctx.request.address = request->payload.address >> 1;
763           } else {
764                     /* in DAL2, there was no return in such case */
765                     BREAK_TO_DEBUGGER();
766                     return false;
767           }
768 
769           ctx.request.delay = 0;
770 
771           ctx.max_defer_retry =
772                     (engine->max_defer_write_retry > AUX_DEFER_RETRY_COUNTER) ?
773                               engine->max_defer_write_retry : AUX_DEFER_RETRY_COUNTER;
774 
775           do {
776                     ctx.request.data = ctx.buffer;
777                     ctx.request.length = ctx.current_write_length;
778 
779                     process_write_request(engine, &ctx);
780 
781                     request->status = ctx.status;
782 
783                     if (ctx.operation_succeeded && !ctx.transaction_complete)
784                               if (ctx.request.type == AUX_TRANSACTION_TYPE_I2C)
785                                         msleep(engine->delay);
786           } while (ctx.operation_succeeded && !ctx.transaction_complete);
787 
788           if (request->payload.address_space ==
789                     I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) {
790                     DC_LOG_I2C_AUX("WRITE: addr:0x%x  value:0x%x Result:%d",
791                                         request->payload.address,
792                                         request->payload.data[0],
793                                         ctx.operation_succeeded);
794           }
795 
796           return ctx.operation_succeeded;
797 }
end_of_transaction_command(struct aux_engine * engine,struct i2caux_transaction_request * request)798 static bool end_of_transaction_command(
799           struct aux_engine *engine,
800           struct i2caux_transaction_request *request)
801 {
802           struct i2caux_transaction_request dummy_request;
803           uint8_t dummy_data;
804 
805           /* [tcheng] We only need to send the stop (read with MOT = 0)
806            * for I2C-over-Aux, not native AUX
807            */
808 
809           if (request->payload.address_space !=
810                     I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C)
811                     return false;
812 
813           dummy_request.operation = request->operation;
814           dummy_request.payload.address_space = request->payload.address_space;
815           dummy_request.payload.address = request->payload.address;
816 
817           /*
818            * Add a dummy byte due to some receiver quirk
819            * where one byte is sent along with MOT = 0.
820            * Ideally this should be 0.
821            */
822 
823           dummy_request.payload.length = 0;
824           dummy_request.payload.data = &dummy_data;
825 
826           if (request->operation == I2CAUX_TRANSACTION_READ)
827                     return read_command(engine, &dummy_request, false);
828           else
829                     return write_command(engine, &dummy_request, false);
830 
831           /* according Syed, it does not need now DoDummyMOT */
832 }
submit_request(struct aux_engine * engine,struct i2caux_transaction_request * request,bool middle_of_transaction)833 static bool submit_request(
834           struct aux_engine *engine,
835           struct i2caux_transaction_request *request,
836           bool middle_of_transaction)
837 {
838 
839           bool result;
840           bool mot_used = true;
841 
842           switch (request->operation) {
843           case I2CAUX_TRANSACTION_READ:
844                     result = read_command(engine, request, mot_used);
845           break;
846           case I2CAUX_TRANSACTION_WRITE:
847                     result = write_command(engine, request, mot_used);
848           break;
849           default:
850                     result = false;
851           }
852 
853           /* [tcheng]
854            * need to send stop for the last transaction to free up the AUX
855            * if the above command fails, this would be the last transaction
856            */
857 
858           if (!middle_of_transaction || !result)
859                     end_of_transaction_command(engine, request);
860 
861           /* mask AUX interrupt */
862 
863           return result;
864 }
865 
866 static
get_engine_type(const struct aux_engine * engine)867 enum i2caux_engine_type get_engine_type(
868                     const struct aux_engine *engine)
869 {
870           return I2CAUX_ENGINE_TYPE_AUX;
871 }
872 
acquire(struct aux_engine * engine,struct ddc * ddc)873 static bool acquire(
874           struct aux_engine *engine,
875           struct ddc *ddc)
876 {
877 
878           enum gpio_result result;
879 
880           if (engine->funcs->is_engine_available) {
881                     /*check whether SW could use the engine*/
882                     if (!engine->funcs->is_engine_available(engine))
883                               return false;
884           }
885 
886           result = dal_ddc_open(ddc, GPIO_MODE_HARDWARE,
887                     GPIO_DDC_CONFIG_TYPE_MODE_AUX);
888 
889           if (result != GPIO_RESULT_OK)
890                     return false;
891 
892           if (!engine->funcs->acquire_engine(engine)) {
893                     dal_ddc_close(ddc);
894                     return false;
895           }
896 
897           engine->ddc = ddc;
898 
899           return true;
900 }
901 
902 static const struct aux_engine_funcs aux_engine_funcs = {
903           .acquire_engine = acquire_engine,
904           .submit_channel_request = submit_channel_request,
905           .process_channel_reply = process_channel_reply,
906           .read_channel_reply = read_channel_reply,
907           .get_channel_status = get_channel_status,
908           .is_engine_available = is_engine_available,
909           .release_engine = release_engine,
910           .destroy_engine = dce110_engine_destroy,
911           .submit_request = submit_request,
912           .get_engine_type = get_engine_type,
913           .acquire = acquire,
914 };
915 
dce110_engine_destroy(struct aux_engine ** engine)916 void dce110_engine_destroy(struct aux_engine **engine)
917 {
918 
919           struct aux_engine_dce110 *engine110 = FROM_AUX_ENGINE(*engine);
920 
921           kfree(engine110);
922           *engine = NULL;
923 
924 }
dce110_aux_engine_construct(struct aux_engine_dce110 * aux_engine110,struct dc_context * ctx,uint32_t inst,uint32_t timeout_period,const struct dce110_aux_registers * regs)925 struct aux_engine *dce110_aux_engine_construct(struct aux_engine_dce110 *aux_engine110,
926                     struct dc_context *ctx,
927                     uint32_t inst,
928                     uint32_t timeout_period,
929                     const struct dce110_aux_registers *regs)
930 {
931           aux_engine110->base.ddc = NULL;
932           aux_engine110->base.ctx = ctx;
933           aux_engine110->base.delay = 0;
934           aux_engine110->base.max_defer_write_retry = 0;
935           aux_engine110->base.funcs = &aux_engine_funcs;
936           aux_engine110->base.inst = inst;
937           aux_engine110->timeout_period = timeout_period;
938           aux_engine110->regs = regs;
939 
940           return &aux_engine110->base;
941 }
942 
943