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