GNU Linux-libre 4.19.207-gnu1
[releases.git] / drivers / gpu / drm / amd / display / dc / i2caux / aux_engine.c
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
28 /*
29  * Pre-requisites: headers required by header of this unit
30  */
31 #include "include/i2caux_interface.h"
32 #include "engine.h"
33
34 /*
35  * Header of this unit
36  */
37
38 #include "aux_engine.h"
39
40 /*
41  * Post-requisites: headers required by this unit
42  */
43
44 #include "include/link_service_types.h"
45
46 /*
47  * This unit
48  */
49
50 enum {
51         AUX_INVALID_REPLY_RETRY_COUNTER = 1,
52         AUX_TIMED_OUT_RETRY_COUNTER = 2,
53         AUX_DEFER_RETRY_COUNTER = 6
54 };
55
56 #define FROM_ENGINE(ptr) \
57         container_of((ptr), struct aux_engine, base)
58 #define DC_LOGGER \
59         engine->base.ctx->logger
60
61 enum i2caux_engine_type dal_aux_engine_get_engine_type(
62         const struct engine *engine)
63 {
64         return I2CAUX_ENGINE_TYPE_AUX;
65 }
66
67 bool dal_aux_engine_acquire(
68         struct engine *engine,
69         struct ddc *ddc)
70 {
71         struct aux_engine *aux_engine = FROM_ENGINE(engine);
72
73         enum gpio_result result;
74         if (aux_engine->funcs->is_engine_available) {
75                 /*check whether SW could use the engine*/
76                 if (!aux_engine->funcs->is_engine_available(aux_engine)) {
77                         return false;
78                 }
79         }
80
81         result = dal_ddc_open(ddc, GPIO_MODE_HARDWARE,
82                 GPIO_DDC_CONFIG_TYPE_MODE_AUX);
83
84         if (result != GPIO_RESULT_OK)
85                 return false;
86
87         if (!aux_engine->funcs->acquire_engine(aux_engine)) {
88                 dal_ddc_close(ddc);
89                 return false;
90         }
91
92         engine->ddc = ddc;
93
94         return true;
95 }
96
97 struct read_command_context {
98         uint8_t *buffer;
99         uint32_t current_read_length;
100         uint32_t offset;
101         enum i2caux_transaction_status status;
102
103         struct aux_request_transaction_data request;
104         struct aux_reply_transaction_data reply;
105
106         uint8_t returned_byte;
107
108         uint32_t timed_out_retry_aux;
109         uint32_t invalid_reply_retry_aux;
110         uint32_t defer_retry_aux;
111         uint32_t defer_retry_i2c;
112         uint32_t invalid_reply_retry_aux_on_ack;
113
114         bool transaction_complete;
115         bool operation_succeeded;
116 };
117
118 static void process_read_reply(
119         struct aux_engine *engine,
120         struct read_command_context *ctx)
121 {
122         engine->funcs->process_channel_reply(engine, &ctx->reply);
123
124         switch (ctx->reply.status) {
125         case AUX_TRANSACTION_REPLY_AUX_ACK:
126                 ctx->defer_retry_aux = 0;
127                 if (ctx->returned_byte > ctx->current_read_length) {
128                         ctx->status =
129                                 I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
130                         ctx->operation_succeeded = false;
131                 } else if (ctx->returned_byte < ctx->current_read_length) {
132                         ctx->current_read_length -= ctx->returned_byte;
133
134                         ctx->offset += ctx->returned_byte;
135
136                         ++ctx->invalid_reply_retry_aux_on_ack;
137
138                         if (ctx->invalid_reply_retry_aux_on_ack >
139                                 AUX_INVALID_REPLY_RETRY_COUNTER) {
140                                 ctx->status =
141                                 I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
142                                 ctx->operation_succeeded = false;
143                         }
144                 } else {
145                         ctx->status = I2CAUX_TRANSACTION_STATUS_SUCCEEDED;
146                         ctx->transaction_complete = true;
147                         ctx->operation_succeeded = true;
148                 }
149         break;
150         case AUX_TRANSACTION_REPLY_AUX_NACK:
151                 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_NACK;
152                 ctx->operation_succeeded = false;
153         break;
154         case AUX_TRANSACTION_REPLY_AUX_DEFER:
155                 ++ctx->defer_retry_aux;
156
157                 if (ctx->defer_retry_aux > AUX_DEFER_RETRY_COUNTER) {
158                         ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
159                         ctx->operation_succeeded = false;
160                 }
161         break;
162         case AUX_TRANSACTION_REPLY_I2C_DEFER:
163                 ctx->defer_retry_aux = 0;
164
165                 ++ctx->defer_retry_i2c;
166
167                 if (ctx->defer_retry_i2c > AUX_DEFER_RETRY_COUNTER) {
168                         ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
169                         ctx->operation_succeeded = false;
170                 }
171         break;
172         case AUX_TRANSACTION_REPLY_HPD_DISCON:
173                 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
174                 ctx->operation_succeeded = false;
175         break;
176         default:
177                 ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
178                 ctx->operation_succeeded = false;
179         }
180 }
181
182 static void process_read_request(
183         struct aux_engine *engine,
184         struct read_command_context *ctx)
185 {
186         enum aux_channel_operation_result operation_result;
187
188         engine->funcs->submit_channel_request(engine, &ctx->request);
189
190         operation_result = engine->funcs->get_channel_status(
191                 engine, &ctx->returned_byte);
192
193         switch (operation_result) {
194         case AUX_CHANNEL_OPERATION_SUCCEEDED:
195                 if (ctx->returned_byte > ctx->current_read_length) {
196                         ctx->status =
197                                 I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
198                         ctx->operation_succeeded = false;
199                 } else {
200                         ctx->timed_out_retry_aux = 0;
201                         ctx->invalid_reply_retry_aux = 0;
202
203                         ctx->reply.length = ctx->returned_byte;
204                         ctx->reply.data = ctx->buffer;
205
206                         process_read_reply(engine, ctx);
207                 }
208         break;
209         case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY:
210                 ++ctx->invalid_reply_retry_aux;
211
212                 if (ctx->invalid_reply_retry_aux >
213                         AUX_INVALID_REPLY_RETRY_COUNTER) {
214                         ctx->status =
215                                 I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
216                         ctx->operation_succeeded = false;
217                 } else
218                         udelay(400);
219         break;
220         case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT:
221                 ++ctx->timed_out_retry_aux;
222
223                 if (ctx->timed_out_retry_aux > AUX_TIMED_OUT_RETRY_COUNTER) {
224                         ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
225                         ctx->operation_succeeded = false;
226                 } else {
227                         /* DP 1.2a, table 2-58:
228                          * "S3: AUX Request CMD PENDING:
229                          * retry 3 times, with 400usec wait on each"
230                          * The HW timeout is set to 550usec,
231                          * so we should not wait here */
232                 }
233         break;
234         case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON:
235                 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
236                 ctx->operation_succeeded = false;
237         break;
238         default:
239                 ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
240                 ctx->operation_succeeded = false;
241         }
242 }
243
244 static bool read_command(
245         struct aux_engine *engine,
246         struct i2caux_transaction_request *request,
247         bool middle_of_transaction)
248 {
249         struct read_command_context ctx;
250
251         ctx.buffer = request->payload.data;
252         ctx.current_read_length = request->payload.length;
253         ctx.offset = 0;
254         ctx.timed_out_retry_aux = 0;
255         ctx.invalid_reply_retry_aux = 0;
256         ctx.defer_retry_aux = 0;
257         ctx.defer_retry_i2c = 0;
258         ctx.invalid_reply_retry_aux_on_ack = 0;
259         ctx.transaction_complete = false;
260         ctx.operation_succeeded = true;
261
262         if (request->payload.address_space ==
263                 I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) {
264                 ctx.request.type = AUX_TRANSACTION_TYPE_DP;
265                 ctx.request.action = I2CAUX_TRANSACTION_ACTION_DP_READ;
266                 ctx.request.address = request->payload.address;
267         } else if (request->payload.address_space ==
268                 I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C) {
269                 ctx.request.type = AUX_TRANSACTION_TYPE_I2C;
270                 ctx.request.action = middle_of_transaction ?
271                         I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT :
272                         I2CAUX_TRANSACTION_ACTION_I2C_READ;
273                 ctx.request.address = request->payload.address >> 1;
274         } else {
275                 /* in DAL2, there was no return in such case */
276                 BREAK_TO_DEBUGGER();
277                 return false;
278         }
279
280         ctx.request.delay = 0;
281
282         do {
283                 memset(ctx.buffer + ctx.offset, 0, ctx.current_read_length);
284
285                 ctx.request.data = ctx.buffer + ctx.offset;
286                 ctx.request.length = ctx.current_read_length;
287
288                 process_read_request(engine, &ctx);
289
290                 request->status = ctx.status;
291
292                 if (ctx.operation_succeeded && !ctx.transaction_complete)
293                         if (ctx.request.type == AUX_TRANSACTION_TYPE_I2C)
294                                 msleep(engine->delay);
295         } while (ctx.operation_succeeded && !ctx.transaction_complete);
296
297         if (request->payload.address_space ==
298                 I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) {
299                 DC_LOG_I2C_AUX("READ: addr:0x%x  value:0x%x Result:%d",
300                                 request->payload.address,
301                                 request->payload.data[0],
302                                 ctx.operation_succeeded);
303         }
304
305         return ctx.operation_succeeded;
306 }
307
308 struct write_command_context {
309         bool mot;
310
311         uint8_t *buffer;
312         uint32_t current_write_length;
313         enum i2caux_transaction_status status;
314
315         struct aux_request_transaction_data request;
316         struct aux_reply_transaction_data reply;
317
318         uint8_t returned_byte;
319
320         uint32_t timed_out_retry_aux;
321         uint32_t invalid_reply_retry_aux;
322         uint32_t defer_retry_aux;
323         uint32_t defer_retry_i2c;
324         uint32_t max_defer_retry;
325         uint32_t ack_m_retry;
326
327         uint8_t reply_data[DEFAULT_AUX_MAX_DATA_SIZE];
328
329         bool transaction_complete;
330         bool operation_succeeded;
331 };
332
333 static void process_write_reply(
334         struct aux_engine *engine,
335         struct write_command_context *ctx)
336 {
337         engine->funcs->process_channel_reply(engine, &ctx->reply);
338
339         switch (ctx->reply.status) {
340         case AUX_TRANSACTION_REPLY_AUX_ACK:
341                 ctx->operation_succeeded = true;
342
343                 if (ctx->returned_byte) {
344                         ctx->request.action = ctx->mot ?
345                         I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST_MOT :
346                         I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST;
347
348                         ctx->current_write_length = 0;
349
350                         ++ctx->ack_m_retry;
351
352                         if (ctx->ack_m_retry > AUX_DEFER_RETRY_COUNTER) {
353                                 ctx->status =
354                                 I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
355                                 ctx->operation_succeeded = false;
356                         } else
357                                 udelay(300);
358                 } else {
359                         ctx->status = I2CAUX_TRANSACTION_STATUS_SUCCEEDED;
360                         ctx->defer_retry_aux = 0;
361                         ctx->ack_m_retry = 0;
362                         ctx->transaction_complete = true;
363                 }
364         break;
365         case AUX_TRANSACTION_REPLY_AUX_NACK:
366                 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_NACK;
367                 ctx->operation_succeeded = false;
368         break;
369         case AUX_TRANSACTION_REPLY_AUX_DEFER:
370                 ++ctx->defer_retry_aux;
371
372                 if (ctx->defer_retry_aux > ctx->max_defer_retry) {
373                         ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
374                         ctx->operation_succeeded = false;
375                 }
376         break;
377         case AUX_TRANSACTION_REPLY_I2C_DEFER:
378                 ctx->defer_retry_aux = 0;
379                 ctx->current_write_length = 0;
380
381                 ctx->request.action = ctx->mot ?
382                         I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST_MOT :
383                         I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST;
384
385                 ++ctx->defer_retry_i2c;
386
387                 if (ctx->defer_retry_i2c > ctx->max_defer_retry) {
388                         ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
389                         ctx->operation_succeeded = false;
390                 }
391         break;
392         case AUX_TRANSACTION_REPLY_HPD_DISCON:
393                 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
394                 ctx->operation_succeeded = false;
395         break;
396         default:
397                 ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
398                 ctx->operation_succeeded = false;
399         }
400 }
401
402 static void process_write_request(
403         struct aux_engine *engine,
404         struct write_command_context *ctx)
405 {
406         enum aux_channel_operation_result operation_result;
407
408         engine->funcs->submit_channel_request(engine, &ctx->request);
409
410         operation_result = engine->funcs->get_channel_status(
411                 engine, &ctx->returned_byte);
412
413         switch (operation_result) {
414         case AUX_CHANNEL_OPERATION_SUCCEEDED:
415                 ctx->timed_out_retry_aux = 0;
416                 ctx->invalid_reply_retry_aux = 0;
417
418                 ctx->reply.length = ctx->returned_byte;
419                 ctx->reply.data = ctx->reply_data;
420
421                 process_write_reply(engine, ctx);
422         break;
423         case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY:
424                 ++ctx->invalid_reply_retry_aux;
425
426                 if (ctx->invalid_reply_retry_aux >
427                         AUX_INVALID_REPLY_RETRY_COUNTER) {
428                         ctx->status =
429                                 I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
430                         ctx->operation_succeeded = false;
431                 } else
432                         udelay(400);
433         break;
434         case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT:
435                 ++ctx->timed_out_retry_aux;
436
437                 if (ctx->timed_out_retry_aux > AUX_TIMED_OUT_RETRY_COUNTER) {
438                         ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
439                         ctx->operation_succeeded = false;
440                 } else {
441                         /* DP 1.2a, table 2-58:
442                          * "S3: AUX Request CMD PENDING:
443                          * retry 3 times, with 400usec wait on each"
444                          * The HW timeout is set to 550usec,
445                          * so we should not wait here */
446                 }
447         break;
448         case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON:
449                 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
450                 ctx->operation_succeeded = false;
451         break;
452         default:
453                 ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
454                 ctx->operation_succeeded = false;
455         }
456 }
457
458 static bool write_command(
459         struct aux_engine *engine,
460         struct i2caux_transaction_request *request,
461         bool middle_of_transaction)
462 {
463         struct write_command_context ctx;
464
465         ctx.mot = middle_of_transaction;
466         ctx.buffer = request->payload.data;
467         ctx.current_write_length = request->payload.length;
468         ctx.timed_out_retry_aux = 0;
469         ctx.invalid_reply_retry_aux = 0;
470         ctx.defer_retry_aux = 0;
471         ctx.defer_retry_i2c = 0;
472         ctx.ack_m_retry = 0;
473         ctx.transaction_complete = false;
474         ctx.operation_succeeded = true;
475
476         if (request->payload.address_space ==
477                 I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) {
478                 ctx.request.type = AUX_TRANSACTION_TYPE_DP;
479                 ctx.request.action = I2CAUX_TRANSACTION_ACTION_DP_WRITE;
480                 ctx.request.address = request->payload.address;
481         } else if (request->payload.address_space ==
482                 I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C) {
483                 ctx.request.type = AUX_TRANSACTION_TYPE_I2C;
484                 ctx.request.action = middle_of_transaction ?
485                         I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT :
486                         I2CAUX_TRANSACTION_ACTION_I2C_WRITE;
487                 ctx.request.address = request->payload.address >> 1;
488         } else {
489                 /* in DAL2, there was no return in such case */
490                 BREAK_TO_DEBUGGER();
491                 return false;
492         }
493
494         ctx.request.delay = 0;
495
496         ctx.max_defer_retry =
497                 (engine->max_defer_write_retry > AUX_DEFER_RETRY_COUNTER) ?
498                         engine->max_defer_write_retry : AUX_DEFER_RETRY_COUNTER;
499
500         do {
501                 ctx.request.data = ctx.buffer;
502                 ctx.request.length = ctx.current_write_length;
503
504                 process_write_request(engine, &ctx);
505
506                 request->status = ctx.status;
507
508                 if (ctx.operation_succeeded && !ctx.transaction_complete)
509                         if (ctx.request.type == AUX_TRANSACTION_TYPE_I2C)
510                                 msleep(engine->delay);
511         } while (ctx.operation_succeeded && !ctx.transaction_complete);
512
513         if (request->payload.address_space ==
514                 I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) {
515                 DC_LOG_I2C_AUX("WRITE: addr:0x%x  value:0x%x Result:%d",
516                                 request->payload.address,
517                                 request->payload.data[0],
518                                 ctx.operation_succeeded);
519         }
520
521         return ctx.operation_succeeded;
522 }
523
524 static bool end_of_transaction_command(
525         struct aux_engine *engine,
526         struct i2caux_transaction_request *request)
527 {
528         struct i2caux_transaction_request dummy_request;
529         uint8_t dummy_data;
530
531         /* [tcheng] We only need to send the stop (read with MOT = 0)
532          * for I2C-over-Aux, not native AUX */
533
534         if (request->payload.address_space !=
535                 I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C)
536                 return false;
537
538         dummy_request.operation = request->operation;
539         dummy_request.payload.address_space = request->payload.address_space;
540         dummy_request.payload.address = request->payload.address;
541
542         /*
543          * Add a dummy byte due to some receiver quirk
544          * where one byte is sent along with MOT = 0.
545          * Ideally this should be 0.
546          */
547
548         dummy_request.payload.length = 0;
549         dummy_request.payload.data = &dummy_data;
550
551         if (request->operation == I2CAUX_TRANSACTION_READ)
552                 return read_command(engine, &dummy_request, false);
553         else
554                 return write_command(engine, &dummy_request, false);
555
556         /* according Syed, it does not need now DoDummyMOT */
557 }
558
559 bool dal_aux_engine_submit_request(
560         struct engine *engine,
561         struct i2caux_transaction_request *request,
562         bool middle_of_transaction)
563 {
564         struct aux_engine *aux_engine = FROM_ENGINE(engine);
565
566         bool result;
567         bool mot_used = true;
568
569         switch (request->operation) {
570         case I2CAUX_TRANSACTION_READ:
571                 result = read_command(aux_engine, request, mot_used);
572         break;
573         case I2CAUX_TRANSACTION_WRITE:
574                 result = write_command(aux_engine, request, mot_used);
575         break;
576         default:
577                 result = false;
578         }
579
580         /* [tcheng]
581          * need to send stop for the last transaction to free up the AUX
582          * if the above command fails, this would be the last transaction */
583
584         if (!middle_of_transaction || !result)
585                 end_of_transaction_command(aux_engine, request);
586
587         /* mask AUX interrupt */
588
589         return result;
590 }
591
592 void dal_aux_engine_construct(
593         struct aux_engine *engine,
594         struct dc_context *ctx)
595 {
596         dal_i2caux_construct_engine(&engine->base, ctx);
597         engine->delay = 0;
598         engine->max_defer_write_retry = 0;
599 }
600
601 void dal_aux_engine_destruct(
602         struct aux_engine *engine)
603 {
604         dal_i2caux_destruct_engine(&engine->base);
605 }