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"
27 #include "core_types.h"
29 #include "dce/dce_11_0_sh_mask.h"
33 #define REG(reg_name)\
34 (aux110->regs->reg_name)
39 #include "reg_helper.h"
41 #define FROM_AUX_ENGINE(ptr) \
42 container_of((ptr), struct aux_engine_dce110, base)
44 #define FROM_ENGINE(ptr) \
45 FROM_AUX_ENGINE(container_of((ptr), struct dce_aux, base))
47 #define FROM_AUX_ENGINE_ENGINE(ptr) \
48 container_of((ptr), struct dce_aux, base)
50 AUX_INVALID_REPLY_RETRY_COUNTER = 1,
51 AUX_TIMED_OUT_RETRY_COUNTER = 2,
52 AUX_DEFER_RETRY_COUNTER = 6
54 static void release_engine(
55 struct dce_aux *engine)
57 struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
59 dal_ddc_close(engine->ddc);
63 REG_UPDATE(AUX_ARB_CONTROL, AUX_SW_DONE_USING_AUX_REG, 1);
66 #define SW_CAN_ACCESS_AUX 1
67 #define DMCU_CAN_ACCESS_AUX 2
69 static bool is_engine_available(
70 struct dce_aux *engine)
72 struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
74 uint32_t value = REG_READ(AUX_ARB_CONTROL);
75 uint32_t field = get_reg_field_value(
78 AUX_REG_RW_CNTL_STATUS);
80 return (field != DMCU_CAN_ACCESS_AUX);
82 static bool acquire_engine(
83 struct dce_aux *engine)
85 struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
87 uint32_t value = REG_READ(AUX_ARB_CONTROL);
88 uint32_t field = get_reg_field_value(
91 AUX_REG_RW_CNTL_STATUS);
92 if (field == DMCU_CAN_ACCESS_AUX)
94 /* enable AUX before request SW to access AUX */
95 value = REG_READ(AUX_CONTROL);
96 field = get_reg_field_value(value,
107 if (REG(AUX_RESET_MASK)) {
108 /*DP_AUX block as part of the enable sequence*/
116 REG_WRITE(AUX_CONTROL, value);
118 if (REG(AUX_RESET_MASK)) {
119 /*poll HW to make sure reset it done*/
121 REG_WAIT(AUX_CONTROL, AUX_RESET_DONE, 1,
130 REG_WRITE(AUX_CONTROL, value);
132 REG_WAIT(AUX_CONTROL, AUX_RESET_DONE, 0,
137 /* request SW to access AUX */
138 REG_UPDATE(AUX_ARB_CONTROL, AUX_SW_USE_AUX_REG_REQ, 1);
140 value = REG_READ(AUX_ARB_CONTROL);
141 field = get_reg_field_value(
144 AUX_REG_RW_CNTL_STATUS);
146 return (field == SW_CAN_ACCESS_AUX);
149 #define COMPOSE_AUX_SW_DATA_16_20(command, address) \
150 ((command) | ((0xF0000 & (address)) >> 16))
152 #define COMPOSE_AUX_SW_DATA_8_15(address) \
153 ((0xFF00 & (address)) >> 8)
155 #define COMPOSE_AUX_SW_DATA_0_7(address) \
158 static void submit_channel_request(
159 struct dce_aux *engine,
160 struct aux_request_transaction_data *request)
162 struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
167 ((request->type == AUX_TRANSACTION_TYPE_DP) &&
168 (request->action == I2CAUX_TRANSACTION_ACTION_DP_WRITE)) ||
169 ((request->type == AUX_TRANSACTION_TYPE_I2C) &&
170 ((request->action == I2CAUX_TRANSACTION_ACTION_I2C_WRITE) ||
171 (request->action == I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT)));
172 if (REG(AUXN_IMPCAL)) {
173 /* clear_aux_error */
174 REG_UPDATE_SEQ(AUXN_IMPCAL, AUXN_CALOUT_ERROR_AK,
178 REG_UPDATE_SEQ(AUXP_IMPCAL, AUXP_CALOUT_ERROR_AK,
182 /* force_default_calibrate */
183 REG_UPDATE_1BY1_2(AUXN_IMPCAL,
184 AUXN_IMPCAL_ENABLE, 1,
185 AUXN_IMPCAL_OVERRIDE_ENABLE, 0);
187 /* bug? why AUXN update EN and OVERRIDE_EN 1 by 1 while AUX P toggles OVERRIDE? */
189 REG_UPDATE_SEQ(AUXP_IMPCAL, AUXP_IMPCAL_OVERRIDE_ENABLE,
194 REG_UPDATE(AUX_INTERRUPT_CONTROL, AUX_SW_DONE_ACK, 1);
196 REG_WAIT(AUX_SW_STATUS, AUX_SW_DONE, 0,
197 10, aux110->timeout_period/10);
199 /* set the delay and the number of bytes to write */
201 /* The length include
202 * the 4 bit header and the 20 bit address
204 * If the requested length is non zero this means
205 * an addition byte specifying the length is required.
208 length = request->length ? 4 : 3;
210 length += request->length;
212 REG_UPDATE_2(AUX_SW_CONTROL,
213 AUX_SW_START_DELAY, request->delay,
214 AUX_SW_WR_BYTES, length);
216 /* program action and address and payload data (if 'is_write') */
217 value = REG_UPDATE_4(AUX_SW_DATA,
220 AUX_SW_AUTOINCREMENT_DISABLE, 1,
221 AUX_SW_DATA, COMPOSE_AUX_SW_DATA_16_20(request->action, request->address));
223 value = REG_SET_2(AUX_SW_DATA, value,
224 AUX_SW_AUTOINCREMENT_DISABLE, 0,
225 AUX_SW_DATA, COMPOSE_AUX_SW_DATA_8_15(request->address));
227 value = REG_SET(AUX_SW_DATA, value,
228 AUX_SW_DATA, COMPOSE_AUX_SW_DATA_0_7(request->address));
230 if (request->length) {
231 value = REG_SET(AUX_SW_DATA, value,
232 AUX_SW_DATA, request->length - 1);
236 /* Load the HW buffer with the Data to be sent.
237 * This is relevant for write operation.
238 * For read, the data recived data will be
239 * processed in process_channel_reply().
243 while (i < request->length) {
244 value = REG_SET(AUX_SW_DATA, value,
245 AUX_SW_DATA, request->data[i]);
251 REG_UPDATE(AUX_SW_CONTROL, AUX_SW_GO, 1);
254 static int read_channel_reply(struct dce_aux *engine, uint32_t size,
255 uint8_t *buffer, uint8_t *reply_result,
258 struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
259 uint32_t bytes_replied;
260 uint32_t reply_result_32;
262 *sw_status = REG_GET(AUX_SW_STATUS, AUX_SW_REPLY_BYTE_COUNT,
265 /* In case HPD is LOW, exit AUX transaction */
266 if ((*sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK))
269 /* Need at least the status byte */
273 REG_UPDATE_1BY1_3(AUX_SW_DATA,
275 AUX_SW_AUTOINCREMENT_DISABLE, 1,
278 REG_GET(AUX_SW_DATA, AUX_SW_DATA, &reply_result_32);
279 reply_result_32 = reply_result_32 >> 4;
280 if (reply_result != NULL)
281 *reply_result = (uint8_t)reply_result_32;
283 if (reply_result_32 == 0) { /* ACK */
286 /* First byte was already used to get the command status */
289 /* Do not overflow buffer */
290 if (bytes_replied > size)
293 while (i < bytes_replied) {
294 uint32_t aux_sw_data_val;
296 REG_GET(AUX_SW_DATA, AUX_SW_DATA, &aux_sw_data_val);
297 buffer[i] = aux_sw_data_val;
307 static enum aux_channel_operation_result get_channel_status(
308 struct dce_aux *engine,
309 uint8_t *returned_bytes)
311 struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
315 if (returned_bytes == NULL) {
316 /*caller pass NULL pointer*/
317 ASSERT_CRITICAL(false);
318 return AUX_CHANNEL_OPERATION_FAILED_REASON_UNKNOWN;
322 /* poll to make sure that SW_DONE is asserted */
323 value = REG_WAIT(AUX_SW_STATUS, AUX_SW_DONE, 1,
324 10, aux110->timeout_period/10);
326 /* in case HPD is LOW, exit AUX transaction */
327 if ((value & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK))
328 return AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON;
330 /* Note that the following bits are set in 'status.bits'
331 * during CTS 4.2.1.2 (FW 3.3.1):
332 * AUX_SW_RX_MIN_COUNT_VIOL, AUX_SW_RX_INVALID_STOP,
333 * AUX_SW_RX_RECV_NO_DET, AUX_SW_RX_RECV_INVALID_H.
335 * AUX_SW_RX_MIN_COUNT_VIOL is an internal,
336 * HW debugging bit and should be ignored.
338 if (value & AUX_SW_STATUS__AUX_SW_DONE_MASK) {
339 if ((value & AUX_SW_STATUS__AUX_SW_RX_TIMEOUT_STATE_MASK) ||
340 (value & AUX_SW_STATUS__AUX_SW_RX_TIMEOUT_MASK))
341 return AUX_CHANNEL_OPERATION_FAILED_TIMEOUT;
343 else if ((value & AUX_SW_STATUS__AUX_SW_RX_INVALID_STOP_MASK) ||
344 (value & AUX_SW_STATUS__AUX_SW_RX_RECV_NO_DET_MASK) ||
346 AUX_SW_STATUS__AUX_SW_RX_RECV_INVALID_H_MASK) ||
347 (value & AUX_SW_STATUS__AUX_SW_RX_RECV_INVALID_L_MASK))
348 return AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY;
350 *returned_bytes = get_reg_field_value(value,
352 AUX_SW_REPLY_BYTE_COUNT);
354 if (*returned_bytes == 0)
356 AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY;
358 *returned_bytes -= 1;
359 return AUX_CHANNEL_OPERATION_SUCCEEDED;
362 /*time_elapsed >= aux_engine->timeout_period
363 * AUX_SW_STATUS__AUX_SW_HPD_DISCON = at this point
365 ASSERT_CRITICAL(false);
366 return AUX_CHANNEL_OPERATION_FAILED_TIMEOUT;
370 enum i2caux_engine_type get_engine_type(
371 const struct dce_aux *engine)
373 return I2CAUX_ENGINE_TYPE_AUX;
377 struct dce_aux *engine,
381 enum gpio_result result;
383 if (!is_engine_available(engine))
386 result = dal_ddc_open(ddc, GPIO_MODE_HARDWARE,
387 GPIO_DDC_CONFIG_TYPE_MODE_AUX);
389 if (result != GPIO_RESULT_OK)
392 if (!acquire_engine(engine)) {
402 void dce110_engine_destroy(struct dce_aux **engine)
405 struct aux_engine_dce110 *engine110 = FROM_AUX_ENGINE(*engine);
411 struct dce_aux *dce110_aux_engine_construct(struct aux_engine_dce110 *aux_engine110,
412 struct dc_context *ctx,
414 uint32_t timeout_period,
415 const struct dce110_aux_registers *regs)
417 aux_engine110->base.ddc = NULL;
418 aux_engine110->base.ctx = ctx;
419 aux_engine110->base.delay = 0;
420 aux_engine110->base.max_defer_write_retry = 0;
421 aux_engine110->base.inst = inst;
422 aux_engine110->timeout_period = timeout_period;
423 aux_engine110->regs = regs;
425 return &aux_engine110->base;
428 static enum i2caux_transaction_action i2caux_action_from_payload(struct aux_payload *payload)
430 if (payload->i2c_over_aux) {
431 if (payload->write) {
433 return I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT;
434 return I2CAUX_TRANSACTION_ACTION_I2C_WRITE;
437 return I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT;
438 return I2CAUX_TRANSACTION_ACTION_I2C_READ;
441 return I2CAUX_TRANSACTION_ACTION_DP_WRITE;
442 return I2CAUX_TRANSACTION_ACTION_DP_READ;
445 int dce_aux_transfer(struct ddc_service *ddc,
446 struct aux_payload *payload)
448 struct ddc *ddc_pin = ddc->ddc_pin;
449 struct dce_aux *aux_engine;
450 enum aux_channel_operation_result operation_result;
451 struct aux_request_transaction_data aux_req;
452 struct aux_reply_transaction_data aux_rep;
453 uint8_t returned_bytes = 0;
457 memset(&aux_req, 0, sizeof(aux_req));
458 memset(&aux_rep, 0, sizeof(aux_rep));
460 aux_engine = ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en];
461 acquire(aux_engine, ddc_pin);
463 if (payload->i2c_over_aux)
464 aux_req.type = AUX_TRANSACTION_TYPE_I2C;
466 aux_req.type = AUX_TRANSACTION_TYPE_DP;
468 aux_req.action = i2caux_action_from_payload(payload);
470 aux_req.address = payload->address;
471 aux_req.delay = payload->defer_delay * 10;
472 aux_req.length = payload->length;
473 aux_req.data = payload->data;
475 submit_channel_request(aux_engine, &aux_req);
476 operation_result = get_channel_status(aux_engine, &returned_bytes);
478 switch (operation_result) {
479 case AUX_CHANNEL_OPERATION_SUCCEEDED:
480 res = read_channel_reply(aux_engine, payload->length,
481 payload->data, payload->reply,
484 case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON:
487 case AUX_CHANNEL_OPERATION_FAILED_REASON_UNKNOWN:
488 case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY:
489 case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT:
493 release_engine(aux_engine);
497 #define AUX_RETRY_MAX 7
499 bool dce_aux_transfer_with_retries(struct ddc_service *ddc,
500 struct aux_payload *payload)
504 bool payload_reply = true;
506 if (!payload->reply) {
507 payload_reply = false;
508 payload->reply = &reply;
511 for (i = 0; i < AUX_RETRY_MAX; i++) {
512 ret = dce_aux_transfer(ddc, payload);
515 if (*payload->reply == 0) {
517 payload->reply = NULL;