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