In this patch, i2c is still using the old code path (nothing is changed for i2c). For aux, locking is already done in drm (i2c also uses drm locks). The new code for aux is same as the old one. Only difference is that some i2c code is removed from aux and aux is put in a different location to match our other HW resources. As for the logic/behavior, it is exactly the same as before. Bhawan ________________________________ From: Alex Deucher <alexdeucher@xxxxxxxxx> Sent: July 17, 2018 12:07:30 PM To: Li, Sun peng (Leo) Cc: amd-gfx list; Lakha, Bhawanpreet Subject: Re: [PATCH 5/7] drm/amd/display: Decouple aux from i2c 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 -------------- next part -------------- An HTML attachment was scrubbed... URL: <https://lists.freedesktop.org/archives/amd-gfx/attachments/20180717/95fedae3/attachment-0001.html>