[PATCH 5/7] drm/amd/display: Decouple aux from i2c
Alex Deucher
alexdeucher at gmail.com
Tue Jul 17 16:07:30 UTC 2018
On Tue, Jul 17, 2018 at 9:29 AM, <sunpeng.li at amd.com> wrote:
> From: Bhawanpreet Lakha <Bhawanpreet.Lakha at amd.com>
>
> [Why]
> Aux engine is created from i2caux layer. We want to remove this layer
> and use the engine directly.
>
> [How]
> Decouple aux engine from i2caux. Move aux engine related code to dce folder and use
> dc resource pool to manage the engine. And use the engine functions directly
>
Don't i2c and aux share the same physical pins? If so, do you have
appropriate locking to arbitrate access to the pins from either
engine?
Alex
> Change-Id: Iecb609fe815dab31ed6b6100916c4b49ed6539a0
> Signed-off-by: Bhawanpreet Lakha <Bhawanpreet.Lakha at amd.com>
> Reviewed-by: Harry Wentland <Harry.Wentland at amd.com>
> Acked-by: Leo Li <sunpeng.li at amd.com>
> ---
> drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c | 22 +-
> drivers/gpu/drm/amd/display/dc/dce/Makefile | 2 +-
> drivers/gpu/drm/amd/display/dc/dce/dce_aux.c | 942 +++++++++++++++++++++
> drivers/gpu/drm/amd/display/dc/dce/dce_aux.h | 111 +++
> .../drm/amd/display/dc/dce100/dce100_resource.c | 42 +
> .../drm/amd/display/dc/dce110/dce110_resource.c | 45 +
> .../drm/amd/display/dc/dce112/dce112_resource.c | 47 +
> .../drm/amd/display/dc/dce120/dce120_resource.c | 42 +
> .../gpu/drm/amd/display/dc/dce80/dce80_resource.c | 44 +
> .../gpu/drm/amd/display/dc/dcn10/dcn10_resource.c | 44 +
> drivers/gpu/drm/amd/display/dc/i2caux/engine.h | 1 +
> drivers/gpu/drm/amd/display/dc/inc/core_types.h | 2 +-
> drivers/gpu/drm/amd/display/dc/inc/hw/aux_engine.h | 113 +++
> drivers/gpu/drm/amd/display/dc/inc/hw/engine.h | 106 +++
> 14 files changed, 1549 insertions(+), 14 deletions(-)
> create mode 100644 drivers/gpu/drm/amd/display/dc/dce/dce_aux.c
> create mode 100644 drivers/gpu/drm/amd/display/dc/dce/dce_aux.h
> create mode 100644 drivers/gpu/drm/amd/display/dc/inc/hw/aux_engine.h
> create mode 100644 drivers/gpu/drm/amd/display/dc/inc/hw/engine.h
>
> diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c
> index 08c9d73..4019fe07 100644
> --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c
> +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c
> @@ -33,10 +33,8 @@
> #include "include/vector.h"
> #include "core_types.h"
> #include "dc_link_ddc.h"
> -#include "i2caux/engine.h"
> -#include "i2caux/i2c_engine.h"
> -#include "i2caux/aux_engine.h"
> -#include "i2caux/i2caux.h"
> +#include "engine.h"
> +#include "aux_engine.h"
>
> #define AUX_POWER_UP_WA_DELAY 500
> #define I2C_OVER_AUX_DEFER_WA_DELAY 70
> @@ -641,9 +639,9 @@ int dc_link_aux_transfer(struct ddc_service *ddc,
> enum aux_transaction_type type,
> enum i2caux_transaction_action action)
> {
> - struct i2caux *i2caux = ddc->ctx->i2caux;
> struct ddc *ddc_pin = ddc->ddc_pin;
> - struct aux_engine *engine;
> + struct engine *engine;
> + struct aux_engine *aux_engine;
> enum aux_channel_operation_result operation_result;
> struct aux_request_transaction_data aux_req;
> struct aux_reply_transaction_data aux_rep;
> @@ -654,7 +652,8 @@ int dc_link_aux_transfer(struct ddc_service *ddc,
> memset(&aux_req, 0, sizeof(aux_req));
> memset(&aux_rep, 0, sizeof(aux_rep));
>
> - engine = i2caux->funcs->acquire_aux_engine(i2caux, ddc_pin);
> + engine = ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en];
> + aux_engine = engine->funcs->acquire(engine, ddc_pin);
>
> aux_req.type = type;
> aux_req.action = action;
> @@ -664,15 +663,15 @@ int dc_link_aux_transfer(struct ddc_service *ddc,
> aux_req.length = size;
> aux_req.data = buffer;
>
> - engine->funcs->submit_channel_request(engine, &aux_req);
> - operation_result = engine->funcs->get_channel_status(engine, &returned_bytes);
> + aux_engine->funcs->submit_channel_request(aux_engine, &aux_req);
> + operation_result = aux_engine->funcs->get_channel_status(aux_engine, &returned_bytes);
>
> switch (operation_result) {
> case AUX_CHANNEL_OPERATION_SUCCEEDED:
> res = returned_bytes;
>
> if (res <= size && res >= 0)
> - res = engine->funcs->read_channel_reply(engine, size,
> + res = aux_engine->funcs->read_channel_reply(aux_engine, size,
> buffer, reply,
> &status);
>
> @@ -686,8 +685,7 @@ int dc_link_aux_transfer(struct ddc_service *ddc,
> res = -1;
> break;
> }
> -
> - i2caux->funcs->release_engine(i2caux, &engine->base);
> + aux_engine->base.funcs->release_engine(&aux_engine->base);
> return res;
> }
>
> diff --git a/drivers/gpu/drm/amd/display/dc/dce/Makefile b/drivers/gpu/drm/amd/display/dc/dce/Makefile
> index 11401fd..825537b 100644
> --- a/drivers/gpu/drm/amd/display/dc/dce/Makefile
> +++ b/drivers/gpu/drm/amd/display/dc/dce/Makefile
> @@ -28,7 +28,7 @@
>
> DCE = dce_audio.o dce_stream_encoder.o dce_link_encoder.o dce_hwseq.o \
> dce_mem_input.o dce_clock_source.o dce_scl_filters.o dce_transform.o \
> -dce_clocks.o dce_opp.o dce_dmcu.o dce_abm.o dce_ipp.o
> +dce_clocks.o dce_opp.o dce_dmcu.o dce_abm.o dce_ipp.o dce_aux.o
>
>
> AMD_DAL_DCE = $(addprefix $(AMDDALPATH)/dc/dce/,$(DCE))
> diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c
> new file mode 100644
> index 0000000..b28e212
> --- /dev/null
> +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c
> @@ -0,0 +1,942 @@
> +/*
> + * Copyright 2012-15 Advanced Micro Devices, Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + *
> + * Authors: AMD
> + *
> + */
> +
> +#include "dm_services.h"
> +#include "dce_aux.h"
> +#include "dce/dce_11_0_sh_mask.h"
> +
> +#define CTX \
> + aux110->base.base.ctx
> +#define REG(reg_name)\
> + (aux110->regs->reg_name)
> +
> +#define DC_LOGGER \
> + engine->base.ctx->logger
> +
> +#include "reg_helper.h"
> +
> +#define FROM_AUX_ENGINE(ptr) \
> + container_of((ptr), struct aux_engine_dce110, base)
> +
> +#define FROM_ENGINE(ptr) \
> + FROM_AUX_ENGINE(container_of((ptr), struct aux_engine, base))
> +
> +#define FROM_AUX_ENGINE_ENGINE(ptr) \
> + container_of((ptr), struct aux_engine, base)
> +enum {
> + AUX_INVALID_REPLY_RETRY_COUNTER = 1,
> + AUX_TIMED_OUT_RETRY_COUNTER = 2,
> + AUX_DEFER_RETRY_COUNTER = 6
> +};
> +static void release_engine(
> + struct engine *engine)
> +{
> + struct aux_engine_dce110 *aux110 = FROM_ENGINE(engine);
> +
> + dal_ddc_close(engine->ddc);
> +
> + engine->ddc = NULL;
> +
> + REG_UPDATE(AUX_ARB_CONTROL, AUX_SW_DONE_USING_AUX_REG, 1);
> +}
> +
> +#define SW_CAN_ACCESS_AUX 1
> +#define DMCU_CAN_ACCESS_AUX 2
> +
> +static bool is_engine_available(
> + struct aux_engine *engine)
> +{
> + struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
> +
> + uint32_t value = REG_READ(AUX_ARB_CONTROL);
> + uint32_t field = get_reg_field_value(
> + value,
> + AUX_ARB_CONTROL,
> + AUX_REG_RW_CNTL_STATUS);
> +
> + return (field != DMCU_CAN_ACCESS_AUX);
> +}
> +static bool acquire_engine(
> + struct aux_engine *engine)
> +{
> + struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
> +
> + uint32_t value = REG_READ(AUX_ARB_CONTROL);
> + uint32_t field = get_reg_field_value(
> + value,
> + AUX_ARB_CONTROL,
> + AUX_REG_RW_CNTL_STATUS);
> + if (field == DMCU_CAN_ACCESS_AUX)
> + return false;
> + /* enable AUX before request SW to access AUX */
> + value = REG_READ(AUX_CONTROL);
> + field = get_reg_field_value(value,
> + AUX_CONTROL,
> + AUX_EN);
> +
> + if (field == 0) {
> + set_reg_field_value(
> + value,
> + 1,
> + AUX_CONTROL,
> + AUX_EN);
> +
> + if (REG(AUX_RESET_MASK)) {
> + /*DP_AUX block as part of the enable sequence*/
> + set_reg_field_value(
> + value,
> + 1,
> + AUX_CONTROL,
> + AUX_RESET);
> + }
> +
> + REG_WRITE(AUX_CONTROL, value);
> +
> + if (REG(AUX_RESET_MASK)) {
> + /*poll HW to make sure reset it done*/
> +
> + REG_WAIT(AUX_CONTROL, AUX_RESET_DONE, 1,
> + 1, 11);
> +
> + set_reg_field_value(
> + value,
> + 0,
> + AUX_CONTROL,
> + AUX_RESET);
> +
> + REG_WRITE(AUX_CONTROL, value);
> +
> + REG_WAIT(AUX_CONTROL, AUX_RESET_DONE, 0,
> + 1, 11);
> + }
> + } /*if (field)*/
> +
> + /* request SW to access AUX */
> + REG_UPDATE(AUX_ARB_CONTROL, AUX_SW_USE_AUX_REG_REQ, 1);
> +
> + value = REG_READ(AUX_ARB_CONTROL);
> + field = get_reg_field_value(
> + value,
> + AUX_ARB_CONTROL,
> + AUX_REG_RW_CNTL_STATUS);
> +
> + return (field == SW_CAN_ACCESS_AUX);
> +}
> +
> +#define COMPOSE_AUX_SW_DATA_16_20(command, address) \
> + ((command) | ((0xF0000 & (address)) >> 16))
> +
> +#define COMPOSE_AUX_SW_DATA_8_15(address) \
> + ((0xFF00 & (address)) >> 8)
> +
> +#define COMPOSE_AUX_SW_DATA_0_7(address) \
> + (0xFF & (address))
> +
> +static void submit_channel_request(
> + struct aux_engine *engine,
> + struct aux_request_transaction_data *request)
> +{
> + struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
> + uint32_t value;
> + uint32_t length;
> +
> + bool is_write =
> + ((request->type == AUX_TRANSACTION_TYPE_DP) &&
> + (request->action == I2CAUX_TRANSACTION_ACTION_DP_WRITE)) ||
> + ((request->type == AUX_TRANSACTION_TYPE_I2C) &&
> + ((request->action == I2CAUX_TRANSACTION_ACTION_I2C_WRITE) ||
> + (request->action == I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT)));
> + if (REG(AUXN_IMPCAL)) {
> + /* clear_aux_error */
> + REG_UPDATE_SEQ(AUXN_IMPCAL, AUXN_CALOUT_ERROR_AK,
> + 1,
> + 0);
> +
> + REG_UPDATE_SEQ(AUXP_IMPCAL, AUXP_CALOUT_ERROR_AK,
> + 1,
> + 0);
> +
> + /* force_default_calibrate */
> + REG_UPDATE_1BY1_2(AUXN_IMPCAL,
> + AUXN_IMPCAL_ENABLE, 1,
> + AUXN_IMPCAL_OVERRIDE_ENABLE, 0);
> +
> + /* bug? why AUXN update EN and OVERRIDE_EN 1 by 1 while AUX P toggles OVERRIDE? */
> +
> + REG_UPDATE_SEQ(AUXP_IMPCAL, AUXP_IMPCAL_OVERRIDE_ENABLE,
> + 1,
> + 0);
> + }
> + /* set the delay and the number of bytes to write */
> +
> + /* The length include
> + * the 4 bit header and the 20 bit address
> + * (that is 3 byte).
> + * If the requested length is non zero this means
> + * an addition byte specifying the length is required.
> + */
> +
> + length = request->length ? 4 : 3;
> + if (is_write)
> + length += request->length;
> +
> + REG_UPDATE_2(AUX_SW_CONTROL,
> + AUX_SW_START_DELAY, request->delay,
> + AUX_SW_WR_BYTES, length);
> +
> + /* program action and address and payload data (if 'is_write') */
> + value = REG_UPDATE_4(AUX_SW_DATA,
> + AUX_SW_INDEX, 0,
> + AUX_SW_DATA_RW, 0,
> + AUX_SW_AUTOINCREMENT_DISABLE, 1,
> + AUX_SW_DATA, COMPOSE_AUX_SW_DATA_16_20(request->action, request->address));
> +
> + value = REG_SET_2(AUX_SW_DATA, value,
> + AUX_SW_AUTOINCREMENT_DISABLE, 0,
> + AUX_SW_DATA, COMPOSE_AUX_SW_DATA_8_15(request->address));
> +
> + value = REG_SET(AUX_SW_DATA, value,
> + AUX_SW_DATA, COMPOSE_AUX_SW_DATA_0_7(request->address));
> +
> + if (request->length) {
> + value = REG_SET(AUX_SW_DATA, value,
> + AUX_SW_DATA, request->length - 1);
> + }
> +
> + if (is_write) {
> + /* Load the HW buffer with the Data to be sent.
> + * This is relevant for write operation.
> + * For read, the data recived data will be
> + * processed in process_channel_reply().
> + */
> + uint32_t i = 0;
> +
> + while (i < request->length) {
> + value = REG_SET(AUX_SW_DATA, value,
> + AUX_SW_DATA, request->data[i]);
> +
> + ++i;
> + }
> + }
> +
> + REG_UPDATE(AUX_INTERRUPT_CONTROL, AUX_SW_DONE_ACK, 1);
> + REG_WAIT(AUX_SW_STATUS, AUX_SW_DONE, 0,
> + 10, aux110->timeout_period/10);
> + REG_UPDATE(AUX_SW_CONTROL, AUX_SW_GO, 1);
> +}
> +
> +static int read_channel_reply(struct aux_engine *engine, uint32_t size,
> + uint8_t *buffer, uint8_t *reply_result,
> + uint32_t *sw_status)
> +{
> + struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
> + uint32_t bytes_replied;
> + uint32_t reply_result_32;
> +
> + *sw_status = REG_GET(AUX_SW_STATUS, AUX_SW_REPLY_BYTE_COUNT,
> + &bytes_replied);
> +
> + /* In case HPD is LOW, exit AUX transaction */
> + if ((*sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK))
> + return -1;
> +
> + /* Need at least the status byte */
> + if (!bytes_replied)
> + return -1;
> +
> + REG_UPDATE_1BY1_3(AUX_SW_DATA,
> + AUX_SW_INDEX, 0,
> + AUX_SW_AUTOINCREMENT_DISABLE, 1,
> + AUX_SW_DATA_RW, 1);
> +
> + REG_GET(AUX_SW_DATA, AUX_SW_DATA, &reply_result_32);
> + reply_result_32 = reply_result_32 >> 4;
> + *reply_result = (uint8_t)reply_result_32;
> +
> + if (reply_result_32 == 0) { /* ACK */
> + uint32_t i = 0;
> +
> + /* First byte was already used to get the command status */
> + --bytes_replied;
> +
> + /* Do not overflow buffer */
> + if (bytes_replied > size)
> + return -1;
> +
> + while (i < bytes_replied) {
> + uint32_t aux_sw_data_val;
> +
> + REG_GET(AUX_SW_DATA, AUX_SW_DATA, &aux_sw_data_val);
> + buffer[i] = aux_sw_data_val;
> + ++i;
> + }
> +
> + return i;
> + }
> +
> + return 0;
> +}
> +
> +static void process_channel_reply(
> + struct aux_engine *engine,
> + struct aux_reply_transaction_data *reply)
> +{
> + int bytes_replied;
> + uint8_t reply_result;
> + uint32_t sw_status;
> +
> + bytes_replied = read_channel_reply(engine, reply->length, reply->data,
> + &reply_result, &sw_status);
> +
> + /* in case HPD is LOW, exit AUX transaction */
> + if ((sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) {
> + reply->status = AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON;
> + return;
> + }
> +
> + if (bytes_replied < 0) {
> + /* Need to handle an error case...
> + * Hopefully, upper layer function won't call this function if
> + * the number of bytes in the reply was 0, because there was
> + * surely an error that was asserted that should have been
> + * handled for hot plug case, this could happens
> + */
> + if (!(sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) {
> + reply->status = AUX_TRANSACTION_REPLY_INVALID;
> + ASSERT_CRITICAL(false);
> + return;
> + }
> + } else {
> +
> + switch (reply_result) {
> + case 0: /* ACK */
> + reply->status = AUX_TRANSACTION_REPLY_AUX_ACK;
> + break;
> + case 1: /* NACK */
> + reply->status = AUX_TRANSACTION_REPLY_AUX_NACK;
> + break;
> + case 2: /* DEFER */
> + reply->status = AUX_TRANSACTION_REPLY_AUX_DEFER;
> + break;
> + case 4: /* AUX ACK / I2C NACK */
> + reply->status = AUX_TRANSACTION_REPLY_I2C_NACK;
> + break;
> + case 8: /* AUX ACK / I2C DEFER */
> + reply->status = AUX_TRANSACTION_REPLY_I2C_DEFER;
> + break;
> + default:
> + reply->status = AUX_TRANSACTION_REPLY_INVALID;
> + }
> + }
> +}
> +
> +static enum aux_channel_operation_result get_channel_status(
> + struct aux_engine *engine,
> + uint8_t *returned_bytes)
> +{
> + struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
> +
> + uint32_t value;
> +
> + if (returned_bytes == NULL) {
> + /*caller pass NULL pointer*/
> + ASSERT_CRITICAL(false);
> + return AUX_CHANNEL_OPERATION_FAILED_REASON_UNKNOWN;
> + }
> + *returned_bytes = 0;
> +
> + /* poll to make sure that SW_DONE is asserted */
> + value = REG_WAIT(AUX_SW_STATUS, AUX_SW_DONE, 1,
> + 10, aux110->timeout_period/10);
> +
> + /* in case HPD is LOW, exit AUX transaction */
> + if ((value & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK))
> + return AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON;
> +
> + /* Note that the following bits are set in 'status.bits'
> + * during CTS 4.2.1.2 (FW 3.3.1):
> + * AUX_SW_RX_MIN_COUNT_VIOL, AUX_SW_RX_INVALID_STOP,
> + * AUX_SW_RX_RECV_NO_DET, AUX_SW_RX_RECV_INVALID_H.
> + *
> + * AUX_SW_RX_MIN_COUNT_VIOL is an internal,
> + * HW debugging bit and should be ignored.
> + */
> + if (value & AUX_SW_STATUS__AUX_SW_DONE_MASK) {
> + if ((value & AUX_SW_STATUS__AUX_SW_RX_TIMEOUT_STATE_MASK) ||
> + (value & AUX_SW_STATUS__AUX_SW_RX_TIMEOUT_MASK))
> + return AUX_CHANNEL_OPERATION_FAILED_TIMEOUT;
> +
> + else if ((value & AUX_SW_STATUS__AUX_SW_RX_INVALID_STOP_MASK) ||
> + (value & AUX_SW_STATUS__AUX_SW_RX_RECV_NO_DET_MASK) ||
> + (value &
> + AUX_SW_STATUS__AUX_SW_RX_RECV_INVALID_H_MASK) ||
> + (value & AUX_SW_STATUS__AUX_SW_RX_RECV_INVALID_L_MASK))
> + return AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY;
> +
> + *returned_bytes = get_reg_field_value(value,
> + AUX_SW_STATUS,
> + AUX_SW_REPLY_BYTE_COUNT);
> +
> + if (*returned_bytes == 0)
> + return
> + AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY;
> + else {
> + *returned_bytes -= 1;
> + return AUX_CHANNEL_OPERATION_SUCCEEDED;
> + }
> + } else {
> + /*time_elapsed >= aux_engine->timeout_period
> + * AUX_SW_STATUS__AUX_SW_HPD_DISCON = at this point
> + */
> + ASSERT_CRITICAL(false);
> + return AUX_CHANNEL_OPERATION_FAILED_TIMEOUT;
> + }
> +}
> +static void process_read_reply(
> + struct aux_engine *engine,
> + struct read_command_context *ctx)
> +{
> + engine->funcs->process_channel_reply(engine, &ctx->reply);
> +
> + switch (ctx->reply.status) {
> + case AUX_TRANSACTION_REPLY_AUX_ACK:
> + ctx->defer_retry_aux = 0;
> + if (ctx->returned_byte > ctx->current_read_length) {
> + ctx->status =
> + I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
> + ctx->operation_succeeded = false;
> + } else if (ctx->returned_byte < ctx->current_read_length) {
> + ctx->current_read_length -= ctx->returned_byte;
> +
> + ctx->offset += ctx->returned_byte;
> +
> + ++ctx->invalid_reply_retry_aux_on_ack;
> +
> + if (ctx->invalid_reply_retry_aux_on_ack >
> + AUX_INVALID_REPLY_RETRY_COUNTER) {
> + ctx->status =
> + I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
> + ctx->operation_succeeded = false;
> + }
> + } else {
> + ctx->status = I2CAUX_TRANSACTION_STATUS_SUCCEEDED;
> + ctx->transaction_complete = true;
> + ctx->operation_succeeded = true;
> + }
> + break;
> + case AUX_TRANSACTION_REPLY_AUX_NACK:
> + ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_NACK;
> + ctx->operation_succeeded = false;
> + break;
> + case AUX_TRANSACTION_REPLY_AUX_DEFER:
> + ++ctx->defer_retry_aux;
> +
> + if (ctx->defer_retry_aux > AUX_DEFER_RETRY_COUNTER) {
> + ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
> + ctx->operation_succeeded = false;
> + }
> + break;
> + case AUX_TRANSACTION_REPLY_I2C_DEFER:
> + ctx->defer_retry_aux = 0;
> +
> + ++ctx->defer_retry_i2c;
> +
> + if (ctx->defer_retry_i2c > AUX_DEFER_RETRY_COUNTER) {
> + ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
> + ctx->operation_succeeded = false;
> + }
> + break;
> + case AUX_TRANSACTION_REPLY_HPD_DISCON:
> + ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
> + ctx->operation_succeeded = false;
> + break;
> + default:
> + ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
> + ctx->operation_succeeded = false;
> + }
> +}
> +static void process_read_request(
> + struct aux_engine *engine,
> + struct read_command_context *ctx)
> +{
> + enum aux_channel_operation_result operation_result;
> +
> + engine->funcs->submit_channel_request(engine, &ctx->request);
> +
> + operation_result = engine->funcs->get_channel_status(
> + engine, &ctx->returned_byte);
> +
> + switch (operation_result) {
> + case AUX_CHANNEL_OPERATION_SUCCEEDED:
> + if (ctx->returned_byte > ctx->current_read_length) {
> + ctx->status =
> + I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
> + ctx->operation_succeeded = false;
> + } else {
> + ctx->timed_out_retry_aux = 0;
> + ctx->invalid_reply_retry_aux = 0;
> +
> + ctx->reply.length = ctx->returned_byte;
> + ctx->reply.data = ctx->buffer;
> +
> + process_read_reply(engine, ctx);
> + }
> + break;
> + case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY:
> + ++ctx->invalid_reply_retry_aux;
> +
> + if (ctx->invalid_reply_retry_aux >
> + AUX_INVALID_REPLY_RETRY_COUNTER) {
> + ctx->status =
> + I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
> + ctx->operation_succeeded = false;
> + } else
> + udelay(400);
> + break;
> + case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT:
> + ++ctx->timed_out_retry_aux;
> +
> + if (ctx->timed_out_retry_aux > AUX_TIMED_OUT_RETRY_COUNTER) {
> + ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
> + ctx->operation_succeeded = false;
> + } else {
> + /* DP 1.2a, table 2-58:
> + * "S3: AUX Request CMD PENDING:
> + * retry 3 times, with 400usec wait on each"
> + * The HW timeout is set to 550usec,
> + * so we should not wait here
> + */
> + }
> + break;
> + case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON:
> + ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
> + ctx->operation_succeeded = false;
> + break;
> + default:
> + ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
> + ctx->operation_succeeded = false;
> + }
> +}
> +static bool read_command(
> + struct aux_engine *engine,
> + struct i2caux_transaction_request *request,
> + bool middle_of_transaction)
> +{
> + struct read_command_context ctx;
> +
> + ctx.buffer = request->payload.data;
> + ctx.current_read_length = request->payload.length;
> + ctx.offset = 0;
> + ctx.timed_out_retry_aux = 0;
> + ctx.invalid_reply_retry_aux = 0;
> + ctx.defer_retry_aux = 0;
> + ctx.defer_retry_i2c = 0;
> + ctx.invalid_reply_retry_aux_on_ack = 0;
> + ctx.transaction_complete = false;
> + ctx.operation_succeeded = true;
> +
> + if (request->payload.address_space ==
> + I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) {
> + ctx.request.type = AUX_TRANSACTION_TYPE_DP;
> + ctx.request.action = I2CAUX_TRANSACTION_ACTION_DP_READ;
> + ctx.request.address = request->payload.address;
> + } else if (request->payload.address_space ==
> + I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C) {
> + ctx.request.type = AUX_TRANSACTION_TYPE_I2C;
> + ctx.request.action = middle_of_transaction ?
> + I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT :
> + I2CAUX_TRANSACTION_ACTION_I2C_READ;
> + ctx.request.address = request->payload.address >> 1;
> + } else {
> + /* in DAL2, there was no return in such case */
> + BREAK_TO_DEBUGGER();
> + return false;
> + }
> +
> + ctx.request.delay = 0;
> +
> + do {
> + memset(ctx.buffer + ctx.offset, 0, ctx.current_read_length);
> +
> + ctx.request.data = ctx.buffer + ctx.offset;
> + ctx.request.length = ctx.current_read_length;
> +
> + process_read_request(engine, &ctx);
> +
> + request->status = ctx.status;
> +
> + if (ctx.operation_succeeded && !ctx.transaction_complete)
> + if (ctx.request.type == AUX_TRANSACTION_TYPE_I2C)
> + msleep(engine->delay);
> + } while (ctx.operation_succeeded && !ctx.transaction_complete);
> +
> + if (request->payload.address_space ==
> + I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) {
> + DC_LOG_I2C_AUX("READ: addr:0x%x value:0x%x Result:%d",
> + request->payload.address,
> + request->payload.data[0],
> + ctx.operation_succeeded);
> + }
> +
> + return ctx.operation_succeeded;
> +}
> +
> +static void process_write_reply(
> + struct aux_engine *engine,
> + struct write_command_context *ctx)
> +{
> + engine->funcs->process_channel_reply(engine, &ctx->reply);
> +
> + switch (ctx->reply.status) {
> + case AUX_TRANSACTION_REPLY_AUX_ACK:
> + ctx->operation_succeeded = true;
> +
> + if (ctx->returned_byte) {
> + ctx->request.action = ctx->mot ?
> + I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST_MOT :
> + I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST;
> +
> + ctx->current_write_length = 0;
> +
> + ++ctx->ack_m_retry;
> +
> + if (ctx->ack_m_retry > AUX_DEFER_RETRY_COUNTER) {
> + ctx->status =
> + I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
> + ctx->operation_succeeded = false;
> + } else
> + udelay(300);
> + } else {
> + ctx->status = I2CAUX_TRANSACTION_STATUS_SUCCEEDED;
> + ctx->defer_retry_aux = 0;
> + ctx->ack_m_retry = 0;
> + ctx->transaction_complete = true;
> + }
> + break;
> + case AUX_TRANSACTION_REPLY_AUX_NACK:
> + ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_NACK;
> + ctx->operation_succeeded = false;
> + break;
> + case AUX_TRANSACTION_REPLY_AUX_DEFER:
> + ++ctx->defer_retry_aux;
> +
> + if (ctx->defer_retry_aux > ctx->max_defer_retry) {
> + ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
> + ctx->operation_succeeded = false;
> + }
> + break;
> + case AUX_TRANSACTION_REPLY_I2C_DEFER:
> + ctx->defer_retry_aux = 0;
> + ctx->current_write_length = 0;
> +
> + ctx->request.action = ctx->mot ?
> + I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST_MOT :
> + I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST;
> +
> + ++ctx->defer_retry_i2c;
> +
> + if (ctx->defer_retry_i2c > ctx->max_defer_retry) {
> + ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
> + ctx->operation_succeeded = false;
> + }
> + break;
> + case AUX_TRANSACTION_REPLY_HPD_DISCON:
> + ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
> + ctx->operation_succeeded = false;
> + break;
> + default:
> + ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
> + ctx->operation_succeeded = false;
> + }
> +}
> +static void process_write_request(
> + struct aux_engine *engine,
> + struct write_command_context *ctx)
> +{
> + enum aux_channel_operation_result operation_result;
> +
> + engine->funcs->submit_channel_request(engine, &ctx->request);
> +
> + operation_result = engine->funcs->get_channel_status(
> + engine, &ctx->returned_byte);
> +
> + switch (operation_result) {
> + case AUX_CHANNEL_OPERATION_SUCCEEDED:
> + ctx->timed_out_retry_aux = 0;
> + ctx->invalid_reply_retry_aux = 0;
> +
> + ctx->reply.length = ctx->returned_byte;
> + ctx->reply.data = ctx->reply_data;
> +
> + process_write_reply(engine, ctx);
> + break;
> + case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY:
> + ++ctx->invalid_reply_retry_aux;
> +
> + if (ctx->invalid_reply_retry_aux >
> + AUX_INVALID_REPLY_RETRY_COUNTER) {
> + ctx->status =
> + I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
> + ctx->operation_succeeded = false;
> + } else
> + udelay(400);
> + break;
> + case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT:
> + ++ctx->timed_out_retry_aux;
> +
> + if (ctx->timed_out_retry_aux > AUX_TIMED_OUT_RETRY_COUNTER) {
> + ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
> + ctx->operation_succeeded = false;
> + } else {
> + /* DP 1.2a, table 2-58:
> + * "S3: AUX Request CMD PENDING:
> + * retry 3 times, with 400usec wait on each"
> + * The HW timeout is set to 550usec,
> + * so we should not wait here
> + */
> + }
> + break;
> + case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON:
> + ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
> + ctx->operation_succeeded = false;
> + break;
> + default:
> + ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
> + ctx->operation_succeeded = false;
> + }
> +}
> +static bool write_command(
> + struct aux_engine *engine,
> + struct i2caux_transaction_request *request,
> + bool middle_of_transaction)
> +{
> + struct write_command_context ctx;
> +
> + ctx.mot = middle_of_transaction;
> + ctx.buffer = request->payload.data;
> + ctx.current_write_length = request->payload.length;
> + ctx.timed_out_retry_aux = 0;
> + ctx.invalid_reply_retry_aux = 0;
> + ctx.defer_retry_aux = 0;
> + ctx.defer_retry_i2c = 0;
> + ctx.ack_m_retry = 0;
> + ctx.transaction_complete = false;
> + ctx.operation_succeeded = true;
> +
> + if (request->payload.address_space ==
> + I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) {
> + ctx.request.type = AUX_TRANSACTION_TYPE_DP;
> + ctx.request.action = I2CAUX_TRANSACTION_ACTION_DP_WRITE;
> + ctx.request.address = request->payload.address;
> + } else if (request->payload.address_space ==
> + I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C) {
> + ctx.request.type = AUX_TRANSACTION_TYPE_I2C;
> + ctx.request.action = middle_of_transaction ?
> + I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT :
> + I2CAUX_TRANSACTION_ACTION_I2C_WRITE;
> + ctx.request.address = request->payload.address >> 1;
> + } else {
> + /* in DAL2, there was no return in such case */
> + BREAK_TO_DEBUGGER();
> + return false;
> + }
> +
> + ctx.request.delay = 0;
> +
> + ctx.max_defer_retry =
> + (engine->max_defer_write_retry > AUX_DEFER_RETRY_COUNTER) ?
> + engine->max_defer_write_retry : AUX_DEFER_RETRY_COUNTER;
> +
> + do {
> + ctx.request.data = ctx.buffer;
> + ctx.request.length = ctx.current_write_length;
> +
> + process_write_request(engine, &ctx);
> +
> + request->status = ctx.status;
> +
> + if (ctx.operation_succeeded && !ctx.transaction_complete)
> + if (ctx.request.type == AUX_TRANSACTION_TYPE_I2C)
> + msleep(engine->delay);
> + } while (ctx.operation_succeeded && !ctx.transaction_complete);
> +
> + if (request->payload.address_space ==
> + I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) {
> + DC_LOG_I2C_AUX("WRITE: addr:0x%x value:0x%x Result:%d",
> + request->payload.address,
> + request->payload.data[0],
> + ctx.operation_succeeded);
> + }
> +
> + return ctx.operation_succeeded;
> +}
> +static bool end_of_transaction_command(
> + struct aux_engine *engine,
> + struct i2caux_transaction_request *request)
> +{
> + struct i2caux_transaction_request dummy_request;
> + uint8_t dummy_data;
> +
> + /* [tcheng] We only need to send the stop (read with MOT = 0)
> + * for I2C-over-Aux, not native AUX
> + */
> +
> + if (request->payload.address_space !=
> + I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C)
> + return false;
> +
> + dummy_request.operation = request->operation;
> + dummy_request.payload.address_space = request->payload.address_space;
> + dummy_request.payload.address = request->payload.address;
> +
> + /*
> + * Add a dummy byte due to some receiver quirk
> + * where one byte is sent along with MOT = 0.
> + * Ideally this should be 0.
> + */
> +
> + dummy_request.payload.length = 0;
> + dummy_request.payload.data = &dummy_data;
> +
> + if (request->operation == I2CAUX_TRANSACTION_READ)
> + return read_command(engine, &dummy_request, false);
> + else
> + return write_command(engine, &dummy_request, false);
> +
> + /* according Syed, it does not need now DoDummyMOT */
> +}
> +bool submit_request(
> + struct engine *engine,
> + struct i2caux_transaction_request *request,
> + bool middle_of_transaction)
> +{
> + struct aux_engine *aux_engine = FROM_AUX_ENGINE_ENGINE(engine);
> +
> + bool result;
> + bool mot_used = true;
> +
> + switch (request->operation) {
> + case I2CAUX_TRANSACTION_READ:
> + result = read_command(aux_engine, request, mot_used);
> + break;
> + case I2CAUX_TRANSACTION_WRITE:
> + result = write_command(aux_engine, request, mot_used);
> + break;
> + default:
> + result = false;
> + }
> +
> + /* [tcheng]
> + * need to send stop for the last transaction to free up the AUX
> + * if the above command fails, this would be the last transaction
> + */
> +
> + if (!middle_of_transaction || !result)
> + end_of_transaction_command(aux_engine, request);
> +
> + /* mask AUX interrupt */
> +
> + return result;
> +}
> +enum i2caux_engine_type get_engine_type(
> + const struct engine *engine)
> +{
> + return I2CAUX_ENGINE_TYPE_AUX;
> +}
> +
> +static struct aux_engine *acquire(
> + struct engine *engine,
> + struct ddc *ddc)
> +{
> + struct aux_engine *aux_engine = FROM_AUX_ENGINE_ENGINE(engine);
> + enum gpio_result result;
> +
> + if (aux_engine->funcs->is_engine_available) {
> + /*check whether SW could use the engine*/
> + if (!aux_engine->funcs->is_engine_available(aux_engine))
> + return NULL;
> + }
> +
> + result = dal_ddc_open(ddc, GPIO_MODE_HARDWARE,
> + GPIO_DDC_CONFIG_TYPE_MODE_AUX);
> +
> + if (result != GPIO_RESULT_OK)
> + return NULL;
> +
> + if (!aux_engine->funcs->acquire_engine(aux_engine)) {
> + dal_ddc_close(ddc);
> + return NULL;
> + }
> +
> + engine->ddc = ddc;
> +
> + return aux_engine;
> +}
> +
> +static const struct aux_engine_funcs aux_engine_funcs = {
> + .acquire_engine = acquire_engine,
> + .submit_channel_request = submit_channel_request,
> + .process_channel_reply = process_channel_reply,
> + .read_channel_reply = read_channel_reply,
> + .get_channel_status = get_channel_status,
> + .is_engine_available = is_engine_available,
> +};
> +
> +static const struct engine_funcs engine_funcs = {
> + .release_engine = release_engine,
> + .destroy_engine = dce110_engine_destroy,
> + .submit_request = submit_request,
> + .get_engine_type = get_engine_type,
> + .acquire = acquire,
> +};
> +
> +void dce110_engine_destroy(struct engine **engine)
> +{
> +
> + struct aux_engine_dce110 *engine110 = FROM_ENGINE(*engine);
> +
> + kfree(engine110);
> + *engine = NULL;
> +
> +}
> +struct aux_engine *dce110_aux_engine_construct(struct aux_engine_dce110 *aux_engine110,
> + struct dc_context *ctx,
> + uint32_t inst,
> + uint32_t timeout_period,
> + const struct dce110_aux_registers *regs)
> +{
> + aux_engine110->base.base.ddc = NULL;
> + aux_engine110->base.base.ctx = ctx;
> + aux_engine110->base.delay = 0;
> + aux_engine110->base.max_defer_write_retry = 0;
> + aux_engine110->base.base.funcs = &engine_funcs;
> + aux_engine110->base.funcs = &aux_engine_funcs;
> + aux_engine110->base.base.inst = inst;
> + aux_engine110->timeout_period = timeout_period;
> + aux_engine110->regs = regs;
> +
> + return &aux_engine110->base;
> +}
> +
> diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.h b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.h
> new file mode 100644
> index 0000000..c6b2aec
> --- /dev/null
> +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.h
> @@ -0,0 +1,111 @@
> +/*
> + * Copyright 2012-15 Advanced Micro Devices, Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + *
> + * Authors: AMD
> + *
> + */
> +
> +#ifndef __DAL_AUX_ENGINE_DCE110_H__
> +#define __DAL_AUX_ENGINE_DCE110_H__
> +#include "aux_engine.h"
> +
> +#define AUX_COMMON_REG_LIST(id)\
> + SRI(AUX_CONTROL, DP_AUX, id), \
> + SRI(AUX_ARB_CONTROL, DP_AUX, id), \
> + SRI(AUX_SW_DATA, DP_AUX, id), \
> + SRI(AUX_SW_CONTROL, DP_AUX, id), \
> + SRI(AUX_INTERRUPT_CONTROL, DP_AUX, id), \
> + SRI(AUX_SW_STATUS, DP_AUX, id), \
> + SR(AUXN_IMPCAL), \
> + SR(AUXP_IMPCAL)
> +
> +struct dce110_aux_registers {
> + uint32_t AUX_CONTROL;
> + uint32_t AUX_ARB_CONTROL;
> + uint32_t AUX_SW_DATA;
> + uint32_t AUX_SW_CONTROL;
> + uint32_t AUX_INTERRUPT_CONTROL;
> + uint32_t AUX_SW_STATUS;
> + uint32_t AUXN_IMPCAL;
> + uint32_t AUXP_IMPCAL;
> +
> + uint32_t AUX_RESET_MASK;
> +};
> +
> +enum { /* This is the timeout as defined in DP 1.2a,
> + * 2.3.4 "Detailed uPacket TX AUX CH State Description".
> + */
> + AUX_TIMEOUT_PERIOD = 400,
> +
> + /* Ideally, the SW timeout should be just above 550usec
> + * which is programmed in HW.
> + * But the SW timeout of 600usec is not reliable,
> + * because on some systems, delay_in_microseconds()
> + * returns faster than it should.
> + * EPR #379763: by trial-and-error on different systems,
> + * 700usec is the minimum reliable SW timeout for polling
> + * the AUX_SW_STATUS.AUX_SW_DONE bit.
> + * This timeout expires *only* when there is
> + * AUX Error or AUX Timeout conditions - not during normal operation.
> + * During normal operation, AUX_SW_STATUS.AUX_SW_DONE bit is set
> + * at most within ~240usec. That means,
> + * increasing this timeout will not affect normal operation,
> + * and we'll timeout after
> + * SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD = 1600usec.
> + * This timeout is especially important for
> + * resume from S3 and CTS.
> + */
> + SW_AUX_TIMEOUT_PERIOD_MULTIPLIER = 4
> +};
> +struct aux_engine_dce110 {
> + struct aux_engine base;
> + const struct dce110_aux_registers *regs;
> + struct {
> + uint32_t aux_control;
> + uint32_t aux_arb_control;
> + uint32_t aux_sw_data;
> + uint32_t aux_sw_control;
> + uint32_t aux_interrupt_control;
> + uint32_t aux_sw_status;
> + } addr;
> + uint32_t timeout_period;
> +};
> +
> +struct aux_engine_dce110_init_data {
> + uint32_t engine_id;
> + uint32_t timeout_period;
> + struct dc_context *ctx;
> + const struct dce110_aux_registers *regs;
> +};
> +
> +struct aux_engine *dce110_aux_engine_construct(
> + struct aux_engine_dce110 *aux_engine110,
> + struct dc_context *ctx,
> + uint32_t inst,
> + uint32_t timeout_period,
> + const struct dce110_aux_registers *regs);
> +
> +void dce110_engine_destroy(struct engine **engine);
> +
> +bool dce110_aux_engine_acquire(
> + struct engine *aux_engine,
> + struct ddc *ddc);
> +#endif
> diff --git a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c
> index ad8ad4e..c34c953 100644
> --- a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c
> +++ b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c
> @@ -52,6 +52,7 @@
> #include "dce/dce_10_0_sh_mask.h"
>
> #include "dce/dce_dmcu.h"
> +#include "dce/dce_aux.h"
> #include "dce/dce_abm.h"
>
> #ifndef mmMC_HUB_RDREQ_DMIF_LIMIT
> @@ -279,7 +280,20 @@ static const struct dce_opp_shift opp_shift = {
> static const struct dce_opp_mask opp_mask = {
> OPP_COMMON_MASK_SH_LIST_DCE_100(_MASK)
> };
> +#define aux_engine_regs(id)\
> +[id] = {\
> + AUX_COMMON_REG_LIST(id), \
> + .AUX_RESET_MASK = 0 \
> +}
>
> +static const struct dce110_aux_registers aux_engine_regs[] = {
> + aux_engine_regs(0),
> + aux_engine_regs(1),
> + aux_engine_regs(2),
> + aux_engine_regs(3),
> + aux_engine_regs(4),
> + aux_engine_regs(5)
> +};
>
> #define audio_regs(id)\
> [id] = {\
> @@ -572,6 +586,23 @@ struct output_pixel_processor *dce100_opp_create(
> return &opp->base;
> }
>
> +struct engine *dce100_aux_engine_create(
> + struct dc_context *ctx,
> + uint32_t inst)
> +{
> + struct aux_engine_dce110 *aux_engine =
> + kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL);
> +
> + if (!aux_engine)
> + return NULL;
> +
> + dce110_aux_engine_construct(aux_engine, ctx, inst,
> + SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD,
> + &aux_engine_regs[inst]);
> +
> + return &aux_engine->base.base;
> +}
> +
> struct clock_source *dce100_clock_source_create(
> struct dc_context *ctx,
> struct dc_bios *bios,
> @@ -624,6 +655,10 @@ static void destruct(struct dce110_resource_pool *pool)
> kfree(DCE110TG_FROM_TG(pool->base.timing_generators[i]));
> pool->base.timing_generators[i] = NULL;
> }
> +
> + if (pool->base.engines[i] != NULL)
> + dce110_engine_destroy(&pool->base.engines[i]);
> +
> }
>
> for (i = 0; i < pool->base.stream_enc_count; i++) {
> @@ -928,6 +963,13 @@ static bool construct(
> "DC: failed to create output pixel processor!\n");
> goto res_create_fail;
> }
> + pool->base.engines[i] = dce100_aux_engine_create(ctx, i);
> + if (pool->base.engines[i] == NULL) {
> + BREAK_TO_DEBUGGER();
> + dm_error(
> + "DC:failed to create aux engine!!\n");
> + goto res_create_fail;
> + }
> }
>
> dc->caps.max_planes = pool->base.pipe_count;
> diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c
> index 1c902e4..4a665a2 100644
> --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c
> +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c
> @@ -49,6 +49,7 @@
> #include "dce/dce_clock_source.h"
> #include "dce/dce_hwseq.h"
> #include "dce110/dce110_hw_sequencer.h"
> +#include "dce/dce_aux.h"
> #include "dce/dce_abm.h"
> #include "dce/dce_dmcu.h"
>
> @@ -306,6 +307,21 @@ static const struct dce_opp_mask opp_mask = {
> OPP_COMMON_MASK_SH_LIST_DCE_110(_MASK)
> };
>
> +#define aux_engine_regs(id)\
> +[id] = {\
> + AUX_COMMON_REG_LIST(id), \
> + .AUX_RESET_MASK = 0 \
> +}
> +
> +static const struct dce110_aux_registers aux_engine_regs[] = {
> + aux_engine_regs(0),
> + aux_engine_regs(1),
> + aux_engine_regs(2),
> + aux_engine_regs(3),
> + aux_engine_regs(4),
> + aux_engine_regs(5)
> +};
> +
> #define audio_regs(id)\
> [id] = {\
> AUD_COMMON_REG_LIST(id)\
> @@ -588,6 +604,23 @@ static struct output_pixel_processor *dce110_opp_create(
> return &opp->base;
> }
>
> +struct engine *dce110_aux_engine_create(
> + struct dc_context *ctx,
> + uint32_t inst)
> +{
> + struct aux_engine_dce110 *aux_engine =
> + kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL);
> +
> + if (!aux_engine)
> + return NULL;
> +
> + dce110_aux_engine_construct(aux_engine, ctx, inst,
> + SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD,
> + &aux_engine_regs[inst]);
> +
> + return &aux_engine->base.base;
> +}
> +
> struct clock_source *dce110_clock_source_create(
> struct dc_context *ctx,
> struct dc_bios *bios,
> @@ -651,6 +684,10 @@ static void destruct(struct dce110_resource_pool *pool)
> kfree(DCE110TG_FROM_TG(pool->base.timing_generators[i]));
> pool->base.timing_generators[i] = NULL;
> }
> +
> + if (pool->base.engines[i] != NULL)
> + dce110_engine_destroy(&pool->base.engines[i]);
> +
> }
>
> for (i = 0; i < pool->base.stream_enc_count; i++) {
> @@ -1258,6 +1295,14 @@ static bool construct(
> "DC: failed to create output pixel processor!\n");
> goto res_create_fail;
> }
> +
> + pool->base.engines[i] = dce110_aux_engine_create(ctx, i);
> + if (pool->base.engines[i] == NULL) {
> + BREAK_TO_DEBUGGER();
> + dm_error(
> + "DC:failed to create aux engine!!\n");
> + goto res_create_fail;
> + }
> }
>
> dc->fbc_compressor = dce110_compressor_create(ctx);
> diff --git a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c
> index 30d5b32..caf90ae 100644
> --- a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c
> +++ b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c
> @@ -49,6 +49,7 @@
> #include "dce112/dce112_hw_sequencer.h"
> #include "dce/dce_abm.h"
> #include "dce/dce_dmcu.h"
> +#include "dce/dce_aux.h"
>
> #include "reg_helper.h"
>
> @@ -314,6 +315,21 @@ static const struct dce_opp_mask opp_mask = {
> OPP_COMMON_MASK_SH_LIST_DCE_112(_MASK)
> };
>
> +#define aux_engine_regs(id)\
> +[id] = {\
> + AUX_COMMON_REG_LIST(id), \
> + .AUX_RESET_MASK = 0 \
> +}
> +
> +static const struct dce110_aux_registers aux_engine_regs[] = {
> + aux_engine_regs(0),
> + aux_engine_regs(1),
> + aux_engine_regs(2),
> + aux_engine_regs(3),
> + aux_engine_regs(4),
> + aux_engine_regs(5)
> +};
> +
> #define audio_regs(id)\
> [id] = {\
> AUD_COMMON_REG_LIST(id)\
> @@ -588,6 +604,23 @@ struct output_pixel_processor *dce112_opp_create(
> return &opp->base;
> }
>
> +struct engine *dce112_aux_engine_create(
> + struct dc_context *ctx,
> + uint32_t inst)
> +{
> + struct aux_engine_dce110 *aux_engine =
> + kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL);
> +
> + if (!aux_engine)
> + return NULL;
> +
> + dce110_aux_engine_construct(aux_engine, ctx, inst,
> + SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD,
> + &aux_engine_regs[inst]);
> +
> + return &aux_engine->base.base;
> +}
> +
> struct clock_source *dce112_clock_source_create(
> struct dc_context *ctx,
> struct dc_bios *bios,
> @@ -625,6 +658,9 @@ static void destruct(struct dce110_resource_pool *pool)
> if (pool->base.opps[i] != NULL)
> dce110_opp_destroy(&pool->base.opps[i]);
>
> + if (pool->base.engines[i] != NULL)
> + dce110_engine_destroy(&pool->base.engines[i]);
> +
> if (pool->base.transforms[i] != NULL)
> dce112_transform_destroy(&pool->base.transforms[i]);
>
> @@ -640,6 +676,10 @@ static void destruct(struct dce110_resource_pool *pool)
> kfree(DCE110TG_FROM_TG(pool->base.timing_generators[i]));
> pool->base.timing_generators[i] = NULL;
> }
> +
> + if (pool->base.engines[i] != NULL)
> + dce110_engine_destroy(&pool->base.engines[i]);
> +
> }
>
> for (i = 0; i < pool->base.stream_enc_count; i++) {
> @@ -1208,6 +1248,13 @@ static bool construct(
> "DC:failed to create output pixel processor!\n");
> goto res_create_fail;
> }
> + pool->base.engines[i] = dce112_aux_engine_create(ctx, i);
> + if (pool->base.engines[i] == NULL) {
> + BREAK_TO_DEBUGGER();
> + dm_error(
> + "DC:failed to create aux engine!!\n");
> + goto res_create_fail;
> + }
> }
>
> if (!resource_construct(num_virtual_links, dc, &pool->base,
> diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c
> index 8381f27..e389832 100644
> --- a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c
> +++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c
> @@ -53,6 +53,7 @@
> #include "dce/dce_hwseq.h"
> #include "dce/dce_abm.h"
> #include "dce/dce_dmcu.h"
> +#include "dce/dce_aux.h"
>
> #include "dce/dce_12_0_offset.h"
> #include "dce/dce_12_0_sh_mask.h"
> @@ -297,6 +298,20 @@ static const struct dce_opp_shift opp_shift = {
> static const struct dce_opp_mask opp_mask = {
> OPP_COMMON_MASK_SH_LIST_DCE_120(_MASK)
> };
> + #define aux_engine_regs(id)\
> +[id] = {\
> + AUX_COMMON_REG_LIST(id), \
> + .AUX_RESET_MASK = 0 \
> +}
> +
> +static const struct dce110_aux_registers aux_engine_regs[] = {
> + aux_engine_regs(0),
> + aux_engine_regs(1),
> + aux_engine_regs(2),
> + aux_engine_regs(3),
> + aux_engine_regs(4),
> + aux_engine_regs(5)
> +};
>
> #define audio_regs(id)\
> [id] = {\
> @@ -361,6 +376,22 @@ struct output_pixel_processor *dce120_opp_create(
> ctx, inst, &opp_regs[inst], &opp_shift, &opp_mask);
> return &opp->base;
> }
> +struct engine *dce120_aux_engine_create(
> + struct dc_context *ctx,
> + uint32_t inst)
> +{
> + struct aux_engine_dce110 *aux_engine =
> + kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL);
> +
> + if (!aux_engine)
> + return NULL;
> +
> + dce110_aux_engine_construct(aux_engine, ctx, inst,
> + SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD,
> + &aux_engine_regs[inst]);
> +
> + return &aux_engine->base.base;
> +}
>
> static const struct bios_registers bios_regs = {
> .BIOS_SCRATCH_6 = mmBIOS_SCRATCH_6 + NBIO_BASE(mmBIOS_SCRATCH_6_BASE_IDX)
> @@ -467,6 +498,10 @@ static void destruct(struct dce110_resource_pool *pool)
> kfree(DCE110TG_FROM_TG(pool->base.timing_generators[i]));
> pool->base.timing_generators[i] = NULL;
> }
> +
> + if (pool->base.engines[i] != NULL)
> + dce110_engine_destroy(&pool->base.engines[i]);
> +
> }
>
> for (i = 0; i < pool->base.audio_count; i++) {
> @@ -984,6 +1019,13 @@ static bool construct(
> dm_error(
> "DC: failed to create output pixel processor!\n");
> }
> + pool->base.engines[i] = dce120_aux_engine_create(ctx, i);
> + if (pool->base.engines[i] == NULL) {
> + BREAK_TO_DEBUGGER();
> + dm_error(
> + "DC:failed to create aux engine!!\n");
> + goto res_create_fail;
> + }
>
> /* check next valid pipe */
> j++;
> diff --git a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c
> index 2ac95ec..6fb33ad 100644
> --- a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c
> +++ b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c
> @@ -54,6 +54,7 @@
> #include "reg_helper.h"
>
> #include "dce/dce_dmcu.h"
> +#include "dce/dce_aux.h"
> #include "dce/dce_abm.h"
> /* TODO remove this include */
>
> @@ -298,6 +299,21 @@ static const struct dce_opp_mask opp_mask = {
> OPP_COMMON_MASK_SH_LIST_DCE_80(_MASK)
> };
>
> +#define aux_engine_regs(id)\
> +[id] = {\
> + AUX_COMMON_REG_LIST(id), \
> + .AUX_RESET_MASK = 0 \
> +}
> +
> +static const struct dce110_aux_registers aux_engine_regs[] = {
> + aux_engine_regs(0),
> + aux_engine_regs(1),
> + aux_engine_regs(2),
> + aux_engine_regs(3),
> + aux_engine_regs(4),
> + aux_engine_regs(5)
> +};
> +
> #define audio_regs(id)\
> [id] = {\
> AUD_COMMON_REG_LIST(id)\
> @@ -448,6 +464,23 @@ static struct output_pixel_processor *dce80_opp_create(
> return &opp->base;
> }
>
> +struct engine *dce80_aux_engine_create(
> + struct dc_context *ctx,
> + uint32_t inst)
> +{
> + struct aux_engine_dce110 *aux_engine =
> + kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL);
> +
> + if (!aux_engine)
> + return NULL;
> +
> + dce110_aux_engine_construct(aux_engine, ctx, inst,
> + SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD,
> + &aux_engine_regs[inst]);
> +
> + return &aux_engine->base.base;
> +}
> +
> static struct stream_encoder *dce80_stream_encoder_create(
> enum engine_id eng_id,
> struct dc_context *ctx)
> @@ -655,6 +688,9 @@ static void destruct(struct dce110_resource_pool *pool)
> kfree(DCE110TG_FROM_TG(pool->base.timing_generators[i]));
> pool->base.timing_generators[i] = NULL;
> }
> +
> + if (pool->base.engines[i] != NULL)
> + dce110_engine_destroy(&pool->base.engines[i]);
> }
>
> for (i = 0; i < pool->base.stream_enc_count; i++) {
> @@ -899,6 +935,14 @@ static bool dce80_construct(
> dm_error("DC: failed to create output pixel processor!\n");
> goto res_create_fail;
> }
> +
> + pool->base.engines[i] = dce80_aux_engine_create(ctx, i);
> + if (pool->base.engines[i] == NULL) {
> + BREAK_TO_DEBUGGER();
> + dm_error(
> + "DC:failed to create aux engine!!\n");
> + goto res_create_fail;
> + }
> }
>
> dc->caps.max_planes = pool->base.pipe_count;
> diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c
> index 84581b3..ef8bb27 100644
> --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c
> +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c
> @@ -64,6 +64,7 @@
> #include "reg_helper.h"
> #include "dce/dce_abm.h"
> #include "dce/dce_dmcu.h"
> +#include "dce/dce_aux.h"
>
> const struct _vcs_dpi_ip_params_st dcn1_0_ip = {
> .rob_buffer_size_kbytes = 64,
> @@ -356,6 +357,21 @@ static const struct dcn10_opp_mask opp_mask = {
> OPP_MASK_SH_LIST_DCN10(_MASK),
> };
>
> +#define aux_engine_regs(id)\
> +[id] = {\
> + AUX_COMMON_REG_LIST(id), \
> + .AUX_RESET_MASK = 0 \
> +}
> +
> +static const struct dce110_aux_registers aux_engine_regs[] = {
> + aux_engine_regs(0),
> + aux_engine_regs(1),
> + aux_engine_regs(2),
> + aux_engine_regs(3),
> + aux_engine_regs(4),
> + aux_engine_regs(5)
> +};
> +
> #define tf_regs(id)\
> [id] = {\
> TF_REG_LIST_DCN10(id),\
> @@ -578,6 +594,23 @@ static struct output_pixel_processor *dcn10_opp_create(
> return &opp->base;
> }
>
> +struct engine *dcn10_aux_engine_create(
> + struct dc_context *ctx,
> + uint32_t inst)
> +{
> + struct aux_engine_dce110 *aux_engine =
> + kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL);
> +
> + if (!aux_engine)
> + return NULL;
> +
> + dce110_aux_engine_construct(aux_engine, ctx, inst,
> + SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD,
> + &aux_engine_regs[inst]);
> +
> + return &aux_engine->base.base;
> +}
> +
> static struct mpc *dcn10_mpc_create(struct dc_context *ctx)
> {
> struct dcn10_mpc *mpc10 = kzalloc(sizeof(struct dcn10_mpc),
> @@ -826,6 +859,9 @@ static void destruct(struct dcn10_resource_pool *pool)
> kfree(DCN10TG_FROM_TG(pool->base.timing_generators[i]));
> pool->base.timing_generators[i] = NULL;
> }
> +
> + if (pool->base.engines[i] != NULL)
> + pool->base.engines[i]->funcs->destroy_engine(&pool->base.engines[i]);
> }
>
> for (i = 0; i < pool->base.stream_enc_count; i++)
> @@ -1255,6 +1291,14 @@ static bool construct(
> goto fail;
> }
>
> + pool->base.engines[i] = dcn10_aux_engine_create(ctx, i);
> + if (pool->base.engines[i] == NULL) {
> + BREAK_TO_DEBUGGER();
> + dm_error(
> + "DC:failed to create aux engine!!\n");
> + goto fail;
> + }
> +
> /* check next valid pipe */
> j++;
> }
> diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/engine.h b/drivers/gpu/drm/amd/display/dc/i2caux/engine.h
> index 1e8a158..b16fb1f 100644
> --- a/drivers/gpu/drm/amd/display/dc/i2caux/engine.h
> +++ b/drivers/gpu/drm/amd/display/dc/i2caux/engine.h
> @@ -96,6 +96,7 @@ struct engine_funcs {
>
> struct engine {
> const struct engine_funcs *funcs;
> + uint32_t inst;
> struct ddc *ddc;
> struct dc_context *ctx;
> };
> diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h b/drivers/gpu/drm/amd/display/dc/inc/core_types.h
> index 1db26bc..2d0d4ae 100644
> --- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h
> +++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h
> @@ -138,7 +138,7 @@ struct resource_pool {
> struct output_pixel_processor *opps[MAX_PIPES];
> struct timing_generator *timing_generators[MAX_PIPES];
> struct stream_encoder *stream_enc[MAX_PIPES * 2];
> -
> + struct engine *engines[MAX_PIPES];
> struct hubbub *hubbub;
> struct mpc *mpc;
> struct pp_smu_funcs_rv *pp_smu;
> diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/aux_engine.h b/drivers/gpu/drm/amd/display/dc/inc/hw/aux_engine.h
> new file mode 100644
> index 0000000..06d7e5d
> --- /dev/null
> +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/aux_engine.h
> @@ -0,0 +1,113 @@
> +/*
> + * Copyright 2012-15 Advanced Micro Devices, Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + *
> + * Authors: AMD
> + *
> + */
> +
> +#ifndef __DAL_AUX_ENGINE_H__
> +#define __DAL_AUX_ENGINE_H__
> +
> +#include "engine.h"
> +#include "include/i2caux_interface.h"
> +
> +struct aux_engine;
> +union aux_config;
> +struct aux_engine_funcs {
> + void (*destroy)(
> + struct aux_engine **ptr);
> + bool (*acquire_engine)(
> + struct aux_engine *engine);
> + void (*configure)(
> + struct aux_engine *engine,
> + union aux_config cfg);
> + void (*submit_channel_request)(
> + struct aux_engine *engine,
> + struct aux_request_transaction_data *request);
> + void (*process_channel_reply)(
> + struct aux_engine *engine,
> + struct aux_reply_transaction_data *reply);
> + int (*read_channel_reply)(
> + struct aux_engine *engine,
> + uint32_t size,
> + uint8_t *buffer,
> + uint8_t *reply_result,
> + uint32_t *sw_status);
> + enum aux_channel_operation_result (*get_channel_status)(
> + struct aux_engine *engine,
> + uint8_t *returned_bytes);
> + bool (*is_engine_available)(struct aux_engine *engine);
> +};
> +struct engine;
> +struct aux_engine {
> + struct engine base;
> + const struct aux_engine_funcs *funcs;
> + /* following values are expressed in milliseconds */
> + uint32_t delay;
> + uint32_t max_defer_write_retry;
> +
> + bool acquire_reset;
> +};
> +struct read_command_context {
> + uint8_t *buffer;
> + uint32_t current_read_length;
> + uint32_t offset;
> + enum i2caux_transaction_status status;
> +
> + struct aux_request_transaction_data request;
> + struct aux_reply_transaction_data reply;
> +
> + uint8_t returned_byte;
> +
> + uint32_t timed_out_retry_aux;
> + uint32_t invalid_reply_retry_aux;
> + uint32_t defer_retry_aux;
> + uint32_t defer_retry_i2c;
> + uint32_t invalid_reply_retry_aux_on_ack;
> +
> + bool transaction_complete;
> + bool operation_succeeded;
> +};
> +struct write_command_context {
> + bool mot;
> +
> + uint8_t *buffer;
> + uint32_t current_write_length;
> + enum i2caux_transaction_status status;
> +
> + struct aux_request_transaction_data request;
> + struct aux_reply_transaction_data reply;
> +
> + uint8_t returned_byte;
> +
> + uint32_t timed_out_retry_aux;
> + uint32_t invalid_reply_retry_aux;
> + uint32_t defer_retry_aux;
> + uint32_t defer_retry_i2c;
> + uint32_t max_defer_retry;
> + uint32_t ack_m_retry;
> +
> + uint8_t reply_data[DEFAULT_AUX_MAX_DATA_SIZE];
> +
> + bool transaction_complete;
> + bool operation_succeeded;
> +};
> +#endif
> diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/engine.h b/drivers/gpu/drm/amd/display/dc/inc/hw/engine.h
> new file mode 100644
> index 0000000..1f5476f
> --- /dev/null
> +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/engine.h
> @@ -0,0 +1,106 @@
> +/*
> + * Copyright 2012-15 Advanced Micro Devices, Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + *
> + * Authors: AMD
> + *
> + */
> +
> +#ifndef __DAL_ENGINE_H__
> +#define __DAL_ENGINE_H__
> +
> +#include "dc_ddc_types.h"
> +
> +enum i2caux_transaction_operation {
> + I2CAUX_TRANSACTION_READ,
> + I2CAUX_TRANSACTION_WRITE
> +};
> +
> +enum i2caux_transaction_address_space {
> + I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C = 1,
> + I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD
> +};
> +
> +struct i2caux_transaction_payload {
> + enum i2caux_transaction_address_space address_space;
> + uint32_t address;
> + uint32_t length;
> + uint8_t *data;
> +};
> +
> +enum i2caux_transaction_status {
> + I2CAUX_TRANSACTION_STATUS_UNKNOWN = (-1L),
> + I2CAUX_TRANSACTION_STATUS_SUCCEEDED,
> + I2CAUX_TRANSACTION_STATUS_FAILED_CHANNEL_BUSY,
> + I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT,
> + I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR,
> + I2CAUX_TRANSACTION_STATUS_FAILED_NACK,
> + I2CAUX_TRANSACTION_STATUS_FAILED_INCOMPLETE,
> + I2CAUX_TRANSACTION_STATUS_FAILED_OPERATION,
> + I2CAUX_TRANSACTION_STATUS_FAILED_INVALID_OPERATION,
> + I2CAUX_TRANSACTION_STATUS_FAILED_BUFFER_OVERFLOW,
> + I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON
> +};
> +
> +struct i2caux_transaction_request {
> + enum i2caux_transaction_operation operation;
> + struct i2caux_transaction_payload payload;
> + enum i2caux_transaction_status status;
> +};
> +
> +enum i2caux_engine_type {
> + I2CAUX_ENGINE_TYPE_UNKNOWN = (-1L),
> + I2CAUX_ENGINE_TYPE_AUX,
> + I2CAUX_ENGINE_TYPE_I2C_DDC_HW,
> + I2CAUX_ENGINE_TYPE_I2C_GENERIC_HW,
> + I2CAUX_ENGINE_TYPE_I2C_SW
> +};
> +
> +enum i2c_default_speed {
> + I2CAUX_DEFAULT_I2C_HW_SPEED = 50,
> + I2CAUX_DEFAULT_I2C_SW_SPEED = 50
> +};
> +
> +struct engine;
> +
> +struct engine_funcs {
> + enum i2caux_engine_type (*get_engine_type)(
> + const struct engine *engine);
> + struct aux_engine* (*acquire)(
> + struct engine *engine,
> + struct ddc *ddc);
> + bool (*submit_request)(
> + struct engine *engine,
> + struct i2caux_transaction_request *request,
> + bool middle_of_transaction);
> + void (*release_engine)(
> + struct engine *engine);
> + void (*destroy_engine)(
> + struct engine **engine);
> +};
> +
> +struct engine {
> + const struct engine_funcs *funcs;
> + uint32_t inst;
> + struct ddc *ddc;
> + struct dc_context *ctx;
> +};
> +
> +#endif
> --
> 2.7.4
>
> _______________________________________________
> amd-gfx mailing list
> amd-gfx at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/amd-gfx
More information about the amd-gfx
mailing list