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