aboutsummaryrefslogtreecommitdiffstats
path: root/common/recipes-kernel/linux/linux-yocto-4.14.71/5248-drm-amd-display-Eliminate-i2c-hw-function-pointers.patch
diff options
context:
space:
mode:
Diffstat (limited to 'common/recipes-kernel/linux/linux-yocto-4.14.71/5248-drm-amd-display-Eliminate-i2c-hw-function-pointers.patch')
-rw-r--r--common/recipes-kernel/linux/linux-yocto-4.14.71/5248-drm-amd-display-Eliminate-i2c-hw-function-pointers.patch806
1 files changed, 806 insertions, 0 deletions
diff --git a/common/recipes-kernel/linux/linux-yocto-4.14.71/5248-drm-amd-display-Eliminate-i2c-hw-function-pointers.patch b/common/recipes-kernel/linux/linux-yocto-4.14.71/5248-drm-amd-display-Eliminate-i2c-hw-function-pointers.patch
new file mode 100644
index 00000000..ff8fda80
--- /dev/null
+++ b/common/recipes-kernel/linux/linux-yocto-4.14.71/5248-drm-amd-display-Eliminate-i2c-hw-function-pointers.patch
@@ -0,0 +1,806 @@
+From 00b3bee54353b4bf547e46a7b527046cfdf4fa07 Mon Sep 17 00:00:00 2001
+From: David Francis <David.Francis@amd.com>
+Date: Thu, 9 Aug 2018 13:20:04 -0400
+Subject: [PATCH 5248/5725] drm/amd/display: Eliminate i2c hw function pointers
+
+[Why]
+The function pointers of the dce_i2c_hw struct were never
+accessed from outside dce_i2c_hw.c and had only one version.
+As function pointers take up space and make debugging difficult,
+and they are not needed in this case, they should be removed.
+
+[How]
+Remove the dce_i2c_hw_funcs struct and make static all
+functions that were previously a part of it. Reorder
+the functions in dce_i2c_hw.c.
+
+Signed-off-by: David Francis <David.Francis@amd.com>
+Reviewed-by: Sun peng Li <Sunpeng.Li@amd.com>
+Acked-by: Leo Li <sunpeng.li@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+---
+ drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.c | 607 ++++++++++++------------
+ drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.h | 29 --
+ 2 files changed, 291 insertions(+), 345 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.c b/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.c
+index 3a63e3c..cd7da59 100644
+--- a/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.c
++++ b/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.c
+@@ -36,223 +36,41 @@
+ #define FN(reg_name, field_name) \
+ dce_i2c_hw->shifts->field_name, dce_i2c_hw->masks->field_name
+
+-
+-static inline void reset_hw_engine(struct dce_i2c_hw *dce_i2c_hw)
+-{
+- REG_UPDATE_2(DC_I2C_CONTROL,
+- DC_I2C_SW_STATUS_RESET, 1,
+- DC_I2C_SW_STATUS_RESET, 1);
+-}
+-
+-static bool is_hw_busy(struct dce_i2c_hw *dce_i2c_hw)
+-{
+- uint32_t i2c_sw_status = 0;
+-
+- REG_GET(DC_I2C_SW_STATUS, DC_I2C_SW_STATUS, &i2c_sw_status);
+- if (i2c_sw_status == DC_I2C_STATUS__DC_I2C_STATUS_IDLE)
+- return false;
+-
+- reset_hw_engine(dce_i2c_hw);
+-
+- REG_GET(DC_I2C_SW_STATUS, DC_I2C_SW_STATUS, &i2c_sw_status);
+- return i2c_sw_status != DC_I2C_STATUS__DC_I2C_STATUS_IDLE;
+-}
+-
+-static void set_speed(
+- struct dce_i2c_hw *dce_i2c_hw,
+- uint32_t speed)
+-{
+-
+- if (speed) {
+- if (dce_i2c_hw->masks->DC_I2C_DDC1_START_STOP_TIMING_CNTL)
+- REG_UPDATE_N(SPEED, 3,
+- FN(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_PRESCALE), dce_i2c_hw->reference_frequency / speed,
+- FN(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_THRESHOLD), 2,
+- FN(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_START_STOP_TIMING_CNTL), speed > 50 ? 2:1);
+- else
+- REG_UPDATE_N(SPEED, 2,
+- FN(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_PRESCALE), dce_i2c_hw->reference_frequency / speed,
+- FN(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_THRESHOLD), 2);
+- }
+-}
+-
+-bool dce_i2c_hw_engine_acquire_engine(
+- struct dce_i2c_hw *dce_i2c_hw,
+- struct ddc *ddc)
+-{
+-
+- enum gpio_result result;
+- uint32_t current_speed;
+-
+- result = dal_ddc_open(ddc, GPIO_MODE_HARDWARE,
+- GPIO_DDC_CONFIG_TYPE_MODE_I2C);
+-
+- if (result != GPIO_RESULT_OK)
+- return false;
+-
+- dce_i2c_hw->ddc = ddc;
+-
+-
+- current_speed = dce_i2c_hw->funcs->get_speed(dce_i2c_hw);
+-
+- if (current_speed)
+- dce_i2c_hw->original_speed = current_speed;
+-
+- return true;
+-}
+-bool dce_i2c_engine_acquire_hw(
+- struct dce_i2c_hw *dce_i2c_hw,
+- struct ddc *ddc_handle)
+-{
+-
+- uint32_t counter = 0;
+- bool result;
+-
+- do {
+- result = dce_i2c_hw_engine_acquire_engine(
+- dce_i2c_hw, ddc_handle);
+-
+- if (result)
+- break;
+-
+- /* i2c_engine is busy by VBios, lets wait and retry */
+-
+- udelay(10);
+-
+- ++counter;
+- } while (counter < 2);
+-
+- if (result) {
+- if (!dce_i2c_hw->funcs->setup_engine(dce_i2c_hw)) {
+- dce_i2c_hw->funcs->release_engine(dce_i2c_hw);
+- result = false;
+- }
+- }
+-
+- return result;
+-}
+-struct dce_i2c_hw *acquire_i2c_hw_engine(
+- struct resource_pool *pool,
+- struct ddc *ddc)
++static void disable_i2c_hw_engine(
++ struct dce_i2c_hw *dce_i2c_hw)
+ {
+-
+- struct dce_i2c_hw *engine = NULL;
+-
+- if (!ddc)
+- return NULL;
+-
+- if (ddc->hw_info.hw_supported) {
+- enum gpio_ddc_line line = dal_ddc_get_line(ddc);
+-
+- if (line < pool->pipe_count)
+- engine = pool->hw_i2cs[line];
+- }
+-
+- if (!engine)
+- return NULL;
+-
+-
+- if (!pool->i2c_hw_buffer_in_use &&
+- dce_i2c_engine_acquire_hw(engine, ddc)) {
+- pool->i2c_hw_buffer_in_use = true;
+- return engine;
+- }
+-
+-
+- return NULL;
++ REG_UPDATE_N(SETUP, 1, FN(SETUP, DC_I2C_DDC1_ENABLE), 0);
+ }
+
+-static bool setup_engine(
++static void execute_transaction(
+ struct dce_i2c_hw *dce_i2c_hw)
+ {
+- uint32_t i2c_setup_limit = I2C_SETUP_TIME_LIMIT_DCE;
++ REG_UPDATE_N(SETUP, 5,
++ FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_DATA_DRIVE_EN), 0,
++ FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_CLK_DRIVE_EN), 0,
++ FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_DATA_DRIVE_SEL), 0,
++ FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_INTRA_TRANSACTION_DELAY), 0,
++ FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_INTRA_BYTE_DELAY), 0);
+
+- if (dce_i2c_hw->setup_limit != 0)
+- i2c_setup_limit = dce_i2c_hw->setup_limit;
+- /* Program pin select */
+- REG_UPDATE_6(DC_I2C_CONTROL,
+- DC_I2C_GO, 0,
++
++ REG_UPDATE_5(DC_I2C_CONTROL,
+ DC_I2C_SOFT_RESET, 0,
++ DC_I2C_SW_STATUS_RESET, 0,
+ DC_I2C_SEND_RESET, 0,
+- DC_I2C_SW_STATUS_RESET, 1,
+- DC_I2C_TRANSACTION_COUNT, 0,
+- DC_I2C_DDC_SELECT, dce_i2c_hw->engine_id);
+-
+- /* Program time limit */
+- if (dce_i2c_hw->send_reset_length == 0) {
+- /*pre-dcn*/
+- REG_UPDATE_N(SETUP, 2,
+- FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_TIME_LIMIT), i2c_setup_limit,
+- FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_ENABLE), 1);
+- }
+- /* Program HW priority
+- * set to High - interrupt software I2C at any time
+- * Enable restart of SW I2C that was interrupted by HW
+- * disable queuing of software while I2C is in use by HW
+- */
+- REG_UPDATE_2(DC_I2C_ARBITRATION,
+- DC_I2C_NO_QUEUED_SW_GO, 0,
+- DC_I2C_SW_PRIORITY, DC_I2C_ARBITRATION__DC_I2C_SW_PRIORITY_NORMAL);
+-
+- return true;
+-}
+-
+-
+-
+-
+-static void process_channel_reply(
+- struct dce_i2c_hw *dce_i2c_hw,
+- struct i2c_reply_transaction_data *reply)
+-{
+- uint32_t length = reply->length;
+- uint8_t *buffer = reply->data;
+-
+- REG_SET_3(DC_I2C_DATA, 0,
+- DC_I2C_INDEX, dce_i2c_hw->buffer_used_write,
+- DC_I2C_DATA_RW, 1,
+- DC_I2C_INDEX_WRITE, 1);
+-
+- while (length) {
+- /* after reading the status,
+- * if the I2C operation executed successfully
+- * (i.e. DC_I2C_STATUS_DONE = 1) then the I2C controller
+- * should read data bytes from I2C circular data buffer
+- */
+-
+- uint32_t i2c_data;
++ DC_I2C_GO, 0,
++ DC_I2C_TRANSACTION_COUNT, dce_i2c_hw->transaction_count - 1);
+
+- REG_GET(DC_I2C_DATA, DC_I2C_DATA, &i2c_data);
+- *buffer++ = i2c_data;
++ /* start I2C transfer */
++ REG_UPDATE(DC_I2C_CONTROL, DC_I2C_GO, 1);
+
+- --length;
+- }
++ /* all transactions were executed and HW buffer became empty
++ * (even though it actually happens when status becomes DONE)
++ */
++ dce_i2c_hw->transaction_count = 0;
++ dce_i2c_hw->buffer_used_bytes = 0;
+ }
+-enum i2c_channel_operation_result dce_i2c_hw_engine_wait_on_operation_result(
+- struct dce_i2c_hw *dce_i2c_hw,
+- uint32_t timeout,
+- enum i2c_channel_operation_result expected_result)
+-{
+- enum i2c_channel_operation_result result;
+- uint32_t i = 0;
+-
+- if (!timeout)
+- return I2C_CHANNEL_OPERATION_SUCCEEDED;
+-
+- do {
+
+- result = dce_i2c_hw->funcs->get_channel_status(
+- dce_i2c_hw, NULL);
+-
+- if (result != expected_result)
+- break;
+-
+- udelay(1);
+-
+- ++i;
+- } while (i < timeout);
+- return result;
+-}
+-static enum i2c_channel_operation_result get_channel_status_hw(
++static enum i2c_channel_operation_result get_channel_status(
+ struct dce_i2c_hw *dce_i2c_hw,
+ uint8_t *returned_bytes)
+ {
+@@ -277,24 +95,13 @@ static enum i2c_channel_operation_result get_channel_status_hw(
+ return I2C_CHANNEL_OPERATION_SUCCEEDED;
+ }
+
+-static void submit_channel_request_hw(
+- struct dce_i2c_hw *dce_i2c_hw,
+- struct i2c_request_transaction_data *request)
++static uint32_t get_hw_buffer_available_size(
++ const struct dce_i2c_hw *dce_i2c_hw)
+ {
+- request->status = I2C_CHANNEL_OPERATION_SUCCEEDED;
+-
+- if (!dce_i2c_hw->funcs->process_transaction(dce_i2c_hw, request))
+- return;
+-
+- if (dce_i2c_hw->funcs->is_hw_busy(dce_i2c_hw)) {
+- request->status = I2C_CHANNEL_OPERATION_ENGINE_BUSY;
+- return;
+- }
+-
+- dce_i2c_hw->funcs->execute_transaction(dce_i2c_hw);
+-
+-
++ return dce_i2c_hw->buffer_size -
++ dce_i2c_hw->buffer_used_bytes;
+ }
++
+ uint32_t get_reference_clock(
+ struct dc_bios *bios)
+ {
+@@ -306,33 +113,48 @@ uint32_t get_reference_clock(
+ return info.pll_info.crystal_frequency;
+ }
+
+-static void execute_transaction_hw(
+- struct dce_i2c_hw *dce_i2c_hw)
++static uint32_t get_speed(
++ const struct dce_i2c_hw *dce_i2c_hw)
+ {
+- REG_UPDATE_N(SETUP, 5,
+- FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_DATA_DRIVE_EN), 0,
+- FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_CLK_DRIVE_EN), 0,
+- FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_DATA_DRIVE_SEL), 0,
+- FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_INTRA_TRANSACTION_DELAY), 0,
+- FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_INTRA_BYTE_DELAY), 0);
++ uint32_t pre_scale = 0;
+
++ REG_GET(SPEED, DC_I2C_DDC1_PRESCALE, &pre_scale);
+
+- REG_UPDATE_5(DC_I2C_CONTROL,
+- DC_I2C_SOFT_RESET, 0,
+- DC_I2C_SW_STATUS_RESET, 0,
+- DC_I2C_SEND_RESET, 0,
+- DC_I2C_GO, 0,
+- DC_I2C_TRANSACTION_COUNT, dce_i2c_hw->transaction_count - 1);
++ /* [anaumov] it seems following is unnecessary */
++ /*ASSERT(value.bits.DC_I2C_DDC1_PRESCALE);*/
++ return pre_scale ?
++ dce_i2c_hw->reference_frequency / pre_scale :
++ dce_i2c_hw->default_speed;
++}
+
+- /* start I2C transfer */
+- REG_UPDATE(DC_I2C_CONTROL, DC_I2C_GO, 1);
++static void process_channel_reply(
++ struct dce_i2c_hw *dce_i2c_hw,
++ struct i2c_reply_transaction_data *reply)
++{
++ uint32_t length = reply->length;
++ uint8_t *buffer = reply->data;
+
+- /* all transactions were executed and HW buffer became empty
+- * (even though it actually happens when status becomes DONE)
+- */
+- dce_i2c_hw->transaction_count = 0;
+- dce_i2c_hw->buffer_used_bytes = 0;
++ REG_SET_3(DC_I2C_DATA, 0,
++ DC_I2C_INDEX, dce_i2c_hw->buffer_used_write,
++ DC_I2C_DATA_RW, 1,
++ DC_I2C_INDEX_WRITE, 1);
++
++ while (length) {
++ /* after reading the status,
++ * if the I2C operation executed successfully
++ * (i.e. DC_I2C_STATUS_DONE = 1) then the I2C controller
++ * should read data bytes from I2C circular data buffer
++ */
++
++ uint32_t i2c_data;
++
++ REG_GET(DC_I2C_DATA, DC_I2C_DATA, &i2c_data);
++ *buffer++ = i2c_data;
++
++ --length;
++ }
+ }
++
+ static bool process_transaction(
+ struct dce_i2c_hw *dce_i2c_hw,
+ struct i2c_request_transaction_data *request)
+@@ -422,51 +244,89 @@ static bool process_transaction(
+
+ return last_transaction;
+ }
+-static uint32_t get_transaction_timeout_hw(
+- const struct dce_i2c_hw *dce_i2c_hw,
+- uint32_t length)
+-{
+-
+- uint32_t speed = dce_i2c_hw->funcs->get_speed(dce_i2c_hw);
+
++static inline void reset_hw_engine(struct dce_i2c_hw *dce_i2c_hw)
++{
++ REG_UPDATE_2(DC_I2C_CONTROL,
++ DC_I2C_SW_STATUS_RESET, 1,
++ DC_I2C_SW_STATUS_RESET, 1);
++}
+
++static void set_speed(
++ struct dce_i2c_hw *dce_i2c_hw,
++ uint32_t speed)
++{
+
+- uint32_t period_timeout;
+- uint32_t num_of_clock_stretches;
++ if (speed) {
++ if (dce_i2c_hw->masks->DC_I2C_DDC1_START_STOP_TIMING_CNTL)
++ REG_UPDATE_N(SPEED, 3,
++ FN(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_PRESCALE), dce_i2c_hw->reference_frequency / speed,
++ FN(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_THRESHOLD), 2,
++ FN(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_START_STOP_TIMING_CNTL), speed > 50 ? 2:1);
++ else
++ REG_UPDATE_N(SPEED, 2,
++ FN(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_PRESCALE), dce_i2c_hw->reference_frequency / speed,
++ FN(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_THRESHOLD), 2);
++ }
++}
+
+- if (!speed)
+- return 0;
++static bool setup_engine(
++ struct dce_i2c_hw *dce_i2c_hw)
++{
++ uint32_t i2c_setup_limit = I2C_SETUP_TIME_LIMIT_DCE;
+
+- period_timeout = (1000 * TRANSACTION_TIMEOUT_IN_I2C_CLOCKS) / speed;
++ if (dce_i2c_hw->setup_limit != 0)
++ i2c_setup_limit = dce_i2c_hw->setup_limit;
++ /* Program pin select */
++ REG_UPDATE_6(DC_I2C_CONTROL,
++ DC_I2C_GO, 0,
++ DC_I2C_SOFT_RESET, 0,
++ DC_I2C_SEND_RESET, 0,
++ DC_I2C_SW_STATUS_RESET, 1,
++ DC_I2C_TRANSACTION_COUNT, 0,
++ DC_I2C_DDC_SELECT, dce_i2c_hw->engine_id);
+
+- num_of_clock_stretches = 1 + (length << 3) + 1;
+- num_of_clock_stretches +=
+- (dce_i2c_hw->buffer_used_bytes << 3) +
+- (dce_i2c_hw->transaction_count << 1);
++ /* Program time limit */
++ if (dce_i2c_hw->send_reset_length == 0) {
++ /*pre-dcn*/
++ REG_UPDATE_N(SETUP, 2,
++ FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_TIME_LIMIT), i2c_setup_limit,
++ FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_ENABLE), 1);
++ }
++ /* Program HW priority
++ * set to High - interrupt software I2C at any time
++ * Enable restart of SW I2C that was interrupted by HW
++ * disable queuing of software while I2C is in use by HW
++ */
++ REG_UPDATE_2(DC_I2C_ARBITRATION,
++ DC_I2C_NO_QUEUED_SW_GO, 0,
++ DC_I2C_SW_PRIORITY, DC_I2C_ARBITRATION__DC_I2C_SW_PRIORITY_NORMAL);
+
+- return period_timeout * num_of_clock_stretches;
++ return true;
+ }
+
+-static void release_engine_dce_hw(
+- struct resource_pool *pool,
+- struct dce_i2c_hw *dce_i2c_hw)
++static bool is_hw_busy(struct dce_i2c_hw *dce_i2c_hw)
+ {
+- pool->i2c_hw_buffer_in_use = false;
++ uint32_t i2c_sw_status = 0;
+
+- dce_i2c_hw->funcs->release_engine(dce_i2c_hw);
+- dal_ddc_close(dce_i2c_hw->ddc);
++ REG_GET(DC_I2C_SW_STATUS, DC_I2C_SW_STATUS, &i2c_sw_status);
++ if (i2c_sw_status == DC_I2C_STATUS__DC_I2C_STATUS_IDLE)
++ return false;
+
+- dce_i2c_hw->ddc = NULL;
++ reset_hw_engine(dce_i2c_hw);
++
++ REG_GET(DC_I2C_SW_STATUS, DC_I2C_SW_STATUS, &i2c_sw_status);
++ return i2c_sw_status != DC_I2C_STATUS__DC_I2C_STATUS_IDLE;
+ }
+
+-static void release_engine_hw(
++static void release_engine(
+ struct dce_i2c_hw *dce_i2c_hw)
+ {
+ bool safe_to_reset;
+
+ /* Restore original HW engine speed */
+
+- dce_i2c_hw->funcs->set_speed(dce_i2c_hw, dce_i2c_hw->original_speed);
++ set_speed(dce_i2c_hw, dce_i2c_hw->original_speed);
+
+ /* Release I2C */
+ REG_UPDATE(DC_I2C_ARBITRATION, DC_I2C_SW_DONE_USING_I2C_REG, 1);
+@@ -488,35 +348,180 @@ static void release_engine_hw(
+ REG_UPDATE(DC_I2C_CONTROL, DC_I2C_SW_STATUS_RESET, 1);
+ /* HW I2c engine - clock gating feature */
+ if (!dce_i2c_hw->engine_keep_power_up_count)
+- dce_i2c_hw->funcs->disable_i2c_hw_engine(dce_i2c_hw);
++ disable_i2c_hw_engine(dce_i2c_hw);
+
+ }
+
+-
+-static void disable_i2c_hw_engine(
++static void release_engine_dce_hw(
++ struct resource_pool *pool,
+ struct dce_i2c_hw *dce_i2c_hw)
+ {
+- REG_UPDATE_N(SETUP, 1, FN(SETUP, DC_I2C_DDC1_ENABLE), 0);
++ pool->i2c_hw_buffer_in_use = false;
++
++ release_engine(dce_i2c_hw);
++ dal_ddc_close(dce_i2c_hw->ddc);
++
++ dce_i2c_hw->ddc = NULL;
+ }
+-static uint32_t get_speed_hw(
+- const struct dce_i2c_hw *dce_i2c_hw)
++
++bool dce_i2c_hw_engine_acquire_engine(
++ struct dce_i2c_hw *dce_i2c_hw,
++ struct ddc *ddc)
+ {
+- uint32_t pre_scale = 0;
+
+- REG_GET(SPEED, DC_I2C_DDC1_PRESCALE, &pre_scale);
++ enum gpio_result result;
++ uint32_t current_speed;
+
+- /* [anaumov] it seems following is unnecessary */
+- /*ASSERT(value.bits.DC_I2C_DDC1_PRESCALE);*/
+- return pre_scale ?
+- dce_i2c_hw->reference_frequency / pre_scale :
+- dce_i2c_hw->default_speed;
++ result = dal_ddc_open(ddc, GPIO_MODE_HARDWARE,
++ GPIO_DDC_CONFIG_TYPE_MODE_I2C);
++
++ if (result != GPIO_RESULT_OK)
++ return false;
++
++ dce_i2c_hw->ddc = ddc;
++
++
++ current_speed = get_speed(dce_i2c_hw);
++
++ if (current_speed)
++ dce_i2c_hw->original_speed = current_speed;
++
++ return true;
+ }
+-static uint32_t get_hw_buffer_available_size(
+- const struct dce_i2c_hw *dce_i2c_hw)
++
++bool dce_i2c_engine_acquire_hw(
++ struct dce_i2c_hw *dce_i2c_hw,
++ struct ddc *ddc_handle)
+ {
+- return dce_i2c_hw->buffer_size -
+- dce_i2c_hw->buffer_used_bytes;
++
++ uint32_t counter = 0;
++ bool result;
++
++ do {
++ result = dce_i2c_hw_engine_acquire_engine(
++ dce_i2c_hw, ddc_handle);
++
++ if (result)
++ break;
++
++ /* i2c_engine is busy by VBios, lets wait and retry */
++
++ udelay(10);
++
++ ++counter;
++ } while (counter < 2);
++
++ if (result) {
++ if (!setup_engine(dce_i2c_hw)) {
++ release_engine(dce_i2c_hw);
++ result = false;
++ }
++ }
++
++ return result;
++}
++
++struct dce_i2c_hw *acquire_i2c_hw_engine(
++ struct resource_pool *pool,
++ struct ddc *ddc)
++{
++
++ struct dce_i2c_hw *engine = NULL;
++
++ if (!ddc)
++ return NULL;
++
++ if (ddc->hw_info.hw_supported) {
++ enum gpio_ddc_line line = dal_ddc_get_line(ddc);
++
++ if (line < pool->pipe_count)
++ engine = pool->hw_i2cs[line];
++ }
++
++ if (!engine)
++ return NULL;
++
++
++ if (!pool->i2c_hw_buffer_in_use &&
++ dce_i2c_engine_acquire_hw(engine, ddc)) {
++ pool->i2c_hw_buffer_in_use = true;
++ return engine;
++ }
++
++
++ return NULL;
++}
++
++enum i2c_channel_operation_result dce_i2c_hw_engine_wait_on_operation_result(
++ struct dce_i2c_hw *dce_i2c_hw,
++ uint32_t timeout,
++ enum i2c_channel_operation_result expected_result)
++{
++ enum i2c_channel_operation_result result;
++ uint32_t i = 0;
++
++ if (!timeout)
++ return I2C_CHANNEL_OPERATION_SUCCEEDED;
++
++ do {
++
++ result = get_channel_status(
++ dce_i2c_hw, NULL);
++
++ if (result != expected_result)
++ break;
++
++ udelay(1);
++
++ ++i;
++ } while (i < timeout);
++ return result;
++}
++
++static void submit_channel_request_hw(
++ struct dce_i2c_hw *dce_i2c_hw,
++ struct i2c_request_transaction_data *request)
++{
++ request->status = I2C_CHANNEL_OPERATION_SUCCEEDED;
++
++ if (!process_transaction(dce_i2c_hw, request))
++ return;
++
++ if (is_hw_busy(dce_i2c_hw)) {
++ request->status = I2C_CHANNEL_OPERATION_ENGINE_BUSY;
++ return;
++ }
++
++ execute_transaction(dce_i2c_hw);
++
++
++}
++
++static uint32_t get_transaction_timeout_hw(
++ const struct dce_i2c_hw *dce_i2c_hw,
++ uint32_t length)
++{
++
++ uint32_t speed = get_speed(dce_i2c_hw);
++
++
++
++ uint32_t period_timeout;
++ uint32_t num_of_clock_stretches;
++
++ if (!speed)
++ return 0;
++
++ period_timeout = (1000 * TRANSACTION_TIMEOUT_IN_I2C_CLOCKS) / speed;
++
++ num_of_clock_stretches = 1 + (length << 3) + 1;
++ num_of_clock_stretches +=
++ (dce_i2c_hw->buffer_used_bytes << 3) +
++ (dce_i2c_hw->transaction_count << 1);
++
++ return period_timeout * num_of_clock_stretches;
+ }
++
+ bool dce_i2c_hw_engine_submit_request(
+ struct dce_i2c_hw *dce_i2c_hw,
+ struct dce_i2c_transaction_request *dce_i2c_request,
+@@ -615,9 +620,7 @@ bool dce_i2c_hw_engine_submit_request(
+ reply.data = dce_i2c_request->payload.data;
+ reply.length = dce_i2c_request->payload.length;
+
+- dce_i2c_hw->funcs->process_channel_reply(dce_i2c_hw, &reply);
+-
+-
++ process_channel_reply(dce_i2c_hw, &reply);
+ }
+
+ return result;
+@@ -632,7 +635,7 @@ bool dce_i2c_submit_command_hw(
+ uint8_t index_of_payload = 0;
+ bool result;
+
+- dce_i2c_hw->funcs->set_speed(dce_i2c_hw, cmd->speed);
++ set_speed(dce_i2c_hw, cmd->speed);
+
+ result = true;
+
+@@ -670,32 +673,6 @@ bool dce_i2c_submit_command_hw(
+
+ return result;
+ }
+-static const struct dce_i2c_hw_funcs dce100_i2c_hw_funcs = {
+- .setup_engine = setup_engine,
+- .set_speed = set_speed,
+- .get_speed = get_speed_hw,
+- .release_engine = release_engine_hw,
+- .process_transaction = process_transaction,
+- .process_channel_reply = process_channel_reply,
+- .is_hw_busy = is_hw_busy,
+- .get_channel_status = get_channel_status_hw,
+- .execute_transaction = execute_transaction_hw,
+- .disable_i2c_hw_engine = disable_i2c_hw_engine
+-};
+-static const struct dce_i2c_hw_funcs dce80_i2c_hw_funcs = {
+- .setup_engine = setup_engine,
+- .set_speed = set_speed,
+- .get_speed = get_speed_hw,
+- .release_engine = release_engine_hw,
+- .process_transaction = process_transaction,
+- .process_channel_reply = process_channel_reply,
+- .is_hw_busy = is_hw_busy,
+- .get_channel_status = get_channel_status_hw,
+- .execute_transaction = execute_transaction_hw,
+- .disable_i2c_hw_engine = disable_i2c_hw_engine
+-};
+-
+-
+
+ void dce_i2c_hw_construct(
+ struct dce_i2c_hw *dce_i2c_hw,
+@@ -718,7 +695,6 @@ void dce_i2c_hw_construct(
+ dce_i2c_hw->default_speed = DEFAULT_I2C_HW_SPEED;
+ dce_i2c_hw->send_reset_length = 0;
+ dce_i2c_hw->setup_limit = I2C_SETUP_TIME_LIMIT_DCE;
+- dce_i2c_hw->funcs = &dce80_i2c_hw_funcs;
+ dce_i2c_hw->buffer_size = I2C_HW_BUFFER_SIZE_DCE;
+ }
+
+@@ -739,7 +715,6 @@ void dce100_i2c_hw_construct(
+ regs,
+ shifts,
+ masks);
+- dce_i2c_hw->funcs = &dce100_i2c_hw_funcs;
+ dce_i2c_hw->buffer_size = I2C_HW_BUFFER_SIZE_DCE100;
+
+ REG_GET(MICROSECOND_TIME_BASE_DIV, XTAL_REF_DIV, &xtal_ref_div);
+diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.h b/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.h
+index 8baef39..742c1da 100644
+--- a/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.h
++++ b/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.h
+@@ -256,40 +256,11 @@ struct dce_i2c_hw {
+ uint32_t buffer_size;
+ struct dc_context *ctx;
+
+- const struct dce_i2c_hw_funcs *funcs;
+ const struct dce_i2c_registers *regs;
+ const struct dce_i2c_shift *shifts;
+ const struct dce_i2c_mask *masks;
+ };
+
+-
+-struct dce_i2c_hw_funcs {
+- bool (*setup_engine)(
+- struct dce_i2c_hw *dce_i2c_hw);
+- void (*set_speed)(
+- struct dce_i2c_hw *dce_i2c_hw,
+- uint32_t speed);
+- uint32_t (*get_speed)(
+- const struct dce_i2c_hw *dce_i2c_hw);
+- void (*release_engine)(
+- struct dce_i2c_hw *dce_i2c_hw);
+- bool (*process_transaction)(
+- struct dce_i2c_hw *dce_i2c_hw,
+- struct i2c_request_transaction_data *request);
+- void (*process_channel_reply)(
+- struct dce_i2c_hw *dce_i2c_hw,
+- struct i2c_reply_transaction_data *reply);
+- bool (*is_hw_busy)(
+- struct dce_i2c_hw *dce_i2c_hw);
+- enum i2c_channel_operation_result (*get_channel_status)(
+- struct dce_i2c_hw *dce_i2c_hw,
+- uint8_t *returned_bytes);
+- void (*execute_transaction)(
+- struct dce_i2c_hw *dce_i2c_hw);
+- void (*disable_i2c_hw_engine)(
+- struct dce_i2c_hw *dce_i2c_hw);
+-};
+-
+ void dce_i2c_hw_construct(
+ struct dce_i2c_hw *dce_i2c_hw,
+ struct dc_context *ctx,
+--
+2.7.4
+