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