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