2 * Copyright 2012-15 Advanced Micro Devices, Inc.
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:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
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.
26 #include "dm_services.h"
29 * Pre-requisites: headers required by header of this unit
31 #include "include/i2caux_interface.h"
38 #include "aux_engine.h"
41 * Post-requisites: headers required by this unit
44 #include "include/link_service_types.h"
51 AUX_INVALID_REPLY_RETRY_COUNTER = 1,
52 AUX_TIMED_OUT_RETRY_COUNTER = 2,
53 AUX_DEFER_RETRY_COUNTER = 6
56 #define FROM_ENGINE(ptr) \
57 container_of((ptr), struct aux_engine, base)
59 enum i2caux_engine_type dal_aux_engine_get_engine_type(
60 const struct engine *engine)
62 return I2CAUX_ENGINE_TYPE_AUX;
65 bool dal_aux_engine_acquire(
66 struct engine *engine,
69 struct aux_engine *aux_engine = FROM_ENGINE(engine);
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)) {
79 result = dal_ddc_open(ddc, GPIO_MODE_HARDWARE,
80 GPIO_DDC_CONFIG_TYPE_MODE_AUX);
82 if (result != GPIO_RESULT_OK)
85 if (!aux_engine->funcs->acquire_engine(aux_engine)) {
95 struct read_command_context {
97 uint32_t current_read_length;
99 enum i2caux_transaction_status status;
101 struct aux_request_transaction_data request;
102 struct aux_reply_transaction_data reply;
104 uint8_t returned_byte;
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;
112 bool transaction_complete;
113 bool operation_succeeded;
116 static void process_read_reply(
117 struct aux_engine *engine,
118 struct read_command_context *ctx)
120 engine->funcs->process_channel_reply(engine, &ctx->reply);
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) {
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;
132 ctx->offset += ctx->returned_byte;
134 ++ctx->invalid_reply_retry_aux_on_ack;
136 if (ctx->invalid_reply_retry_aux_on_ack >
137 AUX_INVALID_REPLY_RETRY_COUNTER) {
139 I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
140 ctx->operation_succeeded = false;
143 ctx->status = I2CAUX_TRANSACTION_STATUS_SUCCEEDED;
144 ctx->transaction_complete = true;
145 ctx->operation_succeeded = true;
148 case AUX_TRANSACTION_REPLY_AUX_NACK:
149 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_NACK;
150 ctx->operation_succeeded = false;
152 case AUX_TRANSACTION_REPLY_AUX_DEFER:
153 ++ctx->defer_retry_aux;
155 if (ctx->defer_retry_aux > AUX_DEFER_RETRY_COUNTER) {
156 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
157 ctx->operation_succeeded = false;
160 case AUX_TRANSACTION_REPLY_I2C_DEFER:
161 ctx->defer_retry_aux = 0;
163 ++ctx->defer_retry_i2c;
165 if (ctx->defer_retry_i2c > AUX_DEFER_RETRY_COUNTER) {
166 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
167 ctx->operation_succeeded = false;
171 ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
172 ctx->operation_succeeded = false;
176 static void process_read_request(
177 struct aux_engine *engine,
178 struct read_command_context *ctx)
180 enum aux_channel_operation_result operation_result;
182 engine->funcs->submit_channel_request(engine, &ctx->request);
184 operation_result = engine->funcs->get_channel_status(
185 engine, &ctx->returned_byte);
187 switch (operation_result) {
188 case AUX_CHANNEL_OPERATION_SUCCEEDED:
189 if (ctx->returned_byte > ctx->current_read_length) {
191 I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
192 ctx->operation_succeeded = false;
194 ctx->timed_out_retry_aux = 0;
195 ctx->invalid_reply_retry_aux = 0;
197 ctx->reply.length = ctx->returned_byte;
198 ctx->reply.data = ctx->buffer;
200 process_read_reply(engine, ctx);
203 case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY:
204 ++ctx->invalid_reply_retry_aux;
206 if (ctx->invalid_reply_retry_aux >
207 AUX_INVALID_REPLY_RETRY_COUNTER) {
209 I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
210 ctx->operation_succeeded = false;
214 case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT:
215 ++ctx->timed_out_retry_aux;
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;
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 */
229 ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
230 ctx->operation_succeeded = false;
234 static bool read_command(
235 struct aux_engine *engine,
236 struct i2caux_transaction_request *request,
237 bool middle_of_transaction)
239 struct read_command_context ctx;
241 ctx.buffer = request->payload.data;
242 ctx.current_read_length = request->payload.length;
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;
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;
265 /* in DAL2, there was no return in such case */
270 ctx.request.delay = 0;
273 memset(ctx.buffer + ctx.offset, 0, ctx.current_read_length);
275 ctx.request.data = ctx.buffer + ctx.offset;
276 ctx.request.length = ctx.current_read_length;
278 process_read_request(engine, &ctx);
280 request->status = ctx.status;
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);
287 return ctx.operation_succeeded;
290 struct write_command_context {
294 uint32_t current_write_length;
295 enum i2caux_transaction_status status;
297 struct aux_request_transaction_data request;
298 struct aux_reply_transaction_data reply;
300 uint8_t returned_byte;
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;
309 uint8_t reply_data[DEFAULT_AUX_MAX_DATA_SIZE];
311 bool transaction_complete;
312 bool operation_succeeded;
315 static void process_write_reply(
316 struct aux_engine *engine,
317 struct write_command_context *ctx)
319 engine->funcs->process_channel_reply(engine, &ctx->reply);
321 switch (ctx->reply.status) {
322 case AUX_TRANSACTION_REPLY_AUX_ACK:
323 ctx->operation_succeeded = true;
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;
330 ctx->current_write_length = 0;
334 if (ctx->ack_m_retry > AUX_DEFER_RETRY_COUNTER) {
336 I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
337 ctx->operation_succeeded = false;
341 ctx->status = I2CAUX_TRANSACTION_STATUS_SUCCEEDED;
342 ctx->defer_retry_aux = 0;
343 ctx->ack_m_retry = 0;
344 ctx->transaction_complete = true;
347 case AUX_TRANSACTION_REPLY_AUX_NACK:
348 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_NACK;
349 ctx->operation_succeeded = false;
351 case AUX_TRANSACTION_REPLY_AUX_DEFER:
352 ++ctx->defer_retry_aux;
354 if (ctx->defer_retry_aux > ctx->max_defer_retry) {
355 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
356 ctx->operation_succeeded = false;
359 case AUX_TRANSACTION_REPLY_I2C_DEFER:
360 ctx->defer_retry_aux = 0;
361 ctx->current_write_length = 0;
363 ctx->request.action = ctx->mot ?
364 I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST_MOT :
365 I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST;
367 ++ctx->defer_retry_i2c;
369 if (ctx->defer_retry_i2c > ctx->max_defer_retry) {
370 ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
371 ctx->operation_succeeded = false;
375 ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
376 ctx->operation_succeeded = false;
380 static void process_write_request(
381 struct aux_engine *engine,
382 struct write_command_context *ctx)
384 enum aux_channel_operation_result operation_result;
386 engine->funcs->submit_channel_request(engine, &ctx->request);
388 operation_result = engine->funcs->get_channel_status(
389 engine, &ctx->returned_byte);
391 switch (operation_result) {
392 case AUX_CHANNEL_OPERATION_SUCCEEDED:
393 ctx->timed_out_retry_aux = 0;
394 ctx->invalid_reply_retry_aux = 0;
396 ctx->reply.length = ctx->returned_byte;
397 ctx->reply.data = ctx->reply_data;
399 process_write_reply(engine, ctx);
401 case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY:
402 ++ctx->invalid_reply_retry_aux;
404 if (ctx->invalid_reply_retry_aux >
405 AUX_INVALID_REPLY_RETRY_COUNTER) {
407 I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
408 ctx->operation_succeeded = false;
412 case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT:
413 ++ctx->timed_out_retry_aux;
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;
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 */
427 ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
428 ctx->operation_succeeded = false;
432 static bool write_command(
433 struct aux_engine *engine,
434 struct i2caux_transaction_request *request,
435 bool middle_of_transaction)
437 struct write_command_context ctx;
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;
447 ctx.transaction_complete = false;
448 ctx.operation_succeeded = true;
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;
463 /* in DAL2, there was no return in such case */
468 ctx.request.delay = 0;
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;
475 ctx.request.data = ctx.buffer;
476 ctx.request.length = ctx.current_write_length;
478 process_write_request(engine, &ctx);
480 request->status = ctx.status;
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);
487 return ctx.operation_succeeded;
490 static bool end_of_transaction_command(
491 struct aux_engine *engine,
492 struct i2caux_transaction_request *request)
494 struct i2caux_transaction_request dummy_request;
497 /* [tcheng] We only need to send the stop (read with MOT = 0)
498 * for I2C-over-Aux, not native AUX */
500 if (request->payload.address_space !=
501 I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C)
504 dummy_request.operation = request->operation;
505 dummy_request.payload.address_space = request->payload.address_space;
506 dummy_request.payload.address = request->payload.address;
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.
514 dummy_request.payload.length = 0;
515 dummy_request.payload.data = &dummy_data;
517 if (request->operation == I2CAUX_TRANSACTION_READ)
518 return read_command(engine, &dummy_request, false);
520 return write_command(engine, &dummy_request, false);
522 /* according Syed, it does not need now DoDummyMOT */
525 bool dal_aux_engine_submit_request(
526 struct engine *engine,
527 struct i2caux_transaction_request *request,
528 bool middle_of_transaction)
530 struct aux_engine *aux_engine = FROM_ENGINE(engine);
533 bool mot_used = true;
535 switch (request->operation) {
536 case I2CAUX_TRANSACTION_READ:
537 result = read_command(aux_engine, request, mot_used);
539 case I2CAUX_TRANSACTION_WRITE:
540 result = write_command(aux_engine, request, mot_used);
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 */
550 if (!middle_of_transaction || !result)
551 end_of_transaction_command(aux_engine, request);
553 /* mask AUX interrupt */
558 void dal_aux_engine_construct(
559 struct aux_engine *engine,
560 struct dc_context *ctx)
562 dal_i2caux_construct_engine(&engine->base, ctx);
564 engine->max_defer_write_retry = 0;
567 void dal_aux_engine_destruct(
568 struct aux_engine *engine)
570 dal_i2caux_destruct_engine(&engine->base);