LCOV - code coverage report
Current view: top level - drivers/gpu/drm/amd/display/dc/dce - dce_i2c_sw.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 166 0.0 %
Date: 2022-12-09 01:23:36 Functions: 0 14 0.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright 2018 Advanced Micro Devices, Inc.
       3             :  *
       4             :  * Permission is hereby granted, free of charge, to any person obtaining a
       5             :  * copy of this software and associated documentation files (the "Software"),
       6             :  * to deal in the Software without restriction, including without limitation
       7             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
       8             :  * and/or sell copies of the Software, and to permit persons to whom the
       9             :  * Software is furnished to do so, subject to the following conditions:
      10             :  *
      11             :  * The above copyright notice and this permission notice shall be included in
      12             :  * all copies or substantial portions of the Software.
      13             :  *
      14             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      15             :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      16             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
      17             :  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
      18             :  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
      19             :  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
      20             :  * OTHER DEALINGS IN THE SOFTWARE.
      21             :  *
      22             :  * Authors: AMD
      23             :  *
      24             :  */
      25             : 
      26             : #include "dce_i2c.h"
      27             : #include "dce_i2c_sw.h"
      28             : #include "include/gpio_service_interface.h"
      29             : #define SCL false
      30             : #define SDA true
      31             : 
      32           0 : void dce_i2c_sw_construct(
      33             :         struct dce_i2c_sw *dce_i2c_sw,
      34             :         struct dc_context *ctx)
      35             : {
      36           0 :         dce_i2c_sw->ctx = ctx;
      37           0 : }
      38             : 
      39           0 : static inline bool read_bit_from_ddc(
      40             :         struct ddc *ddc,
      41             :         bool data_nor_clock)
      42             : {
      43           0 :         uint32_t value = 0;
      44             : 
      45           0 :         if (data_nor_clock)
      46           0 :                 dal_gpio_get_value(ddc->pin_data, &value);
      47             :         else
      48           0 :                 dal_gpio_get_value(ddc->pin_clock, &value);
      49             : 
      50           0 :         return (value != 0);
      51             : }
      52             : 
      53             : static inline void write_bit_to_ddc(
      54             :         struct ddc *ddc,
      55             :         bool data_nor_clock,
      56             :         bool bit)
      57             : {
      58           0 :         uint32_t value = bit ? 1 : 0;
      59             : 
      60             :         if (data_nor_clock)
      61           0 :                 dal_gpio_set_value(ddc->pin_data, value);
      62             :         else
      63           0 :                 dal_gpio_set_value(ddc->pin_clock, value);
      64             : }
      65             : 
      66             : static void release_engine_dce_sw(
      67             :         struct resource_pool *pool,
      68             :         struct dce_i2c_sw *dce_i2c_sw)
      69             : {
      70           0 :         dal_ddc_close(dce_i2c_sw->ddc);
      71           0 :         dce_i2c_sw->ddc = NULL;
      72             : }
      73             : 
      74           0 : static bool wait_for_scl_high_sw(
      75             :         struct dc_context *ctx,
      76             :         struct ddc *ddc,
      77             :         uint16_t clock_delay_div_4)
      78             : {
      79           0 :         uint32_t scl_retry = 0;
      80           0 :         uint32_t scl_retry_max = I2C_SW_TIMEOUT_DELAY / clock_delay_div_4;
      81             : 
      82           0 :         udelay(clock_delay_div_4);
      83             : 
      84             :         do {
      85           0 :                 if (read_bit_from_ddc(ddc, SCL))
      86             :                         return true;
      87             : 
      88           0 :                 udelay(clock_delay_div_4);
      89             : 
      90           0 :                 ++scl_retry;
      91           0 :         } while (scl_retry <= scl_retry_max);
      92             : 
      93             :         return false;
      94             : }
      95           0 : static bool write_byte_sw(
      96             :         struct dc_context *ctx,
      97             :         struct ddc *ddc_handle,
      98             :         uint16_t clock_delay_div_4,
      99             :         uint8_t byte)
     100             : {
     101           0 :         int32_t shift = 7;
     102             :         bool ack;
     103             : 
     104             :         /* bits are transmitted serially, starting from MSB */
     105             : 
     106             :         do {
     107           0 :                 udelay(clock_delay_div_4);
     108             : 
     109           0 :                 write_bit_to_ddc(ddc_handle, SDA, (byte >> shift) & 1);
     110             : 
     111           0 :                 udelay(clock_delay_div_4);
     112             : 
     113           0 :                 write_bit_to_ddc(ddc_handle, SCL, true);
     114             : 
     115           0 :                 if (!wait_for_scl_high_sw(ctx, ddc_handle, clock_delay_div_4))
     116             :                         return false;
     117             : 
     118           0 :                 write_bit_to_ddc(ddc_handle, SCL, false);
     119             : 
     120           0 :                 --shift;
     121           0 :         } while (shift >= 0);
     122             : 
     123             :         /* The display sends ACK by preventing the SDA from going high
     124             :          * after the SCL pulse we use to send our last data bit.
     125             :          * If the SDA goes high after that bit, it's a NACK
     126             :          */
     127             : 
     128           0 :         udelay(clock_delay_div_4);
     129             : 
     130           0 :         write_bit_to_ddc(ddc_handle, SDA, true);
     131             : 
     132           0 :         udelay(clock_delay_div_4);
     133             : 
     134           0 :         write_bit_to_ddc(ddc_handle, SCL, true);
     135             : 
     136           0 :         if (!wait_for_scl_high_sw(ctx, ddc_handle, clock_delay_div_4))
     137             :                 return false;
     138             : 
     139             :         /* read ACK bit */
     140             : 
     141           0 :         ack = !read_bit_from_ddc(ddc_handle, SDA);
     142             : 
     143           0 :         udelay(clock_delay_div_4 << 1);
     144             : 
     145           0 :         write_bit_to_ddc(ddc_handle, SCL, false);
     146             : 
     147           0 :         udelay(clock_delay_div_4 << 1);
     148             : 
     149           0 :         return ack;
     150             : }
     151             : 
     152           0 : static bool read_byte_sw(
     153             :         struct dc_context *ctx,
     154             :         struct ddc *ddc_handle,
     155             :         uint16_t clock_delay_div_4,
     156             :         uint8_t *byte,
     157             :         bool more)
     158             : {
     159           0 :         int32_t shift = 7;
     160             : 
     161           0 :         uint8_t data = 0;
     162             : 
     163             :         /* The data bits are read from MSB to LSB;
     164             :          * bit is read while SCL is high
     165             :          */
     166             : 
     167             :         do {
     168           0 :                 write_bit_to_ddc(ddc_handle, SCL, true);
     169             : 
     170           0 :                 if (!wait_for_scl_high_sw(ctx, ddc_handle, clock_delay_div_4))
     171             :                         return false;
     172             : 
     173           0 :                 if (read_bit_from_ddc(ddc_handle, SDA))
     174           0 :                         data |= (1 << shift);
     175             : 
     176           0 :                 write_bit_to_ddc(ddc_handle, SCL, false);
     177             : 
     178           0 :                 udelay(clock_delay_div_4 << 1);
     179             : 
     180           0 :                 --shift;
     181           0 :         } while (shift >= 0);
     182             : 
     183             :         /* read only whole byte */
     184             : 
     185           0 :         *byte = data;
     186             : 
     187           0 :         udelay(clock_delay_div_4);
     188             : 
     189             :         /* send the acknowledge bit:
     190             :          * SDA low means ACK, SDA high means NACK
     191             :          */
     192             : 
     193           0 :         write_bit_to_ddc(ddc_handle, SDA, !more);
     194             : 
     195           0 :         udelay(clock_delay_div_4);
     196             : 
     197           0 :         write_bit_to_ddc(ddc_handle, SCL, true);
     198             : 
     199           0 :         if (!wait_for_scl_high_sw(ctx, ddc_handle, clock_delay_div_4))
     200             :                 return false;
     201             : 
     202           0 :         write_bit_to_ddc(ddc_handle, SCL, false);
     203             : 
     204           0 :         udelay(clock_delay_div_4);
     205             : 
     206           0 :         write_bit_to_ddc(ddc_handle, SDA, true);
     207             : 
     208           0 :         udelay(clock_delay_div_4);
     209             : 
     210           0 :         return true;
     211             : }
     212           0 : static bool stop_sync_sw(
     213             :         struct dc_context *ctx,
     214             :         struct ddc *ddc_handle,
     215             :         uint16_t clock_delay_div_4)
     216             : {
     217           0 :         uint32_t retry = 0;
     218             : 
     219             :         /* The I2C communications stop signal is:
     220             :          * the SDA going high from low, while the SCL is high.
     221             :          */
     222             : 
     223           0 :         write_bit_to_ddc(ddc_handle, SCL, false);
     224             : 
     225           0 :         udelay(clock_delay_div_4);
     226             : 
     227           0 :         write_bit_to_ddc(ddc_handle, SDA, false);
     228             : 
     229           0 :         udelay(clock_delay_div_4);
     230             : 
     231           0 :         write_bit_to_ddc(ddc_handle, SCL, true);
     232             : 
     233           0 :         if (!wait_for_scl_high_sw(ctx, ddc_handle, clock_delay_div_4))
     234             :                 return false;
     235             : 
     236             :         write_bit_to_ddc(ddc_handle, SDA, true);
     237             : 
     238             :         do {
     239           0 :                 udelay(clock_delay_div_4);
     240             : 
     241           0 :                 if (read_bit_from_ddc(ddc_handle, SDA))
     242             :                         return true;
     243             : 
     244           0 :                 ++retry;
     245           0 :         } while (retry <= 2);
     246             : 
     247             :         return false;
     248             : }
     249           0 : static bool i2c_write_sw(
     250             :         struct dc_context *ctx,
     251             :         struct ddc *ddc_handle,
     252             :         uint16_t clock_delay_div_4,
     253             :         uint8_t address,
     254             :         uint32_t length,
     255             :         const uint8_t *data)
     256             : {
     257           0 :         uint32_t i = 0;
     258             : 
     259           0 :         if (!write_byte_sw(ctx, ddc_handle, clock_delay_div_4, address))
     260             :                 return false;
     261             : 
     262           0 :         while (i < length) {
     263           0 :                 if (!write_byte_sw(ctx, ddc_handle, clock_delay_div_4, data[i]))
     264             :                         return false;
     265           0 :                 ++i;
     266             :         }
     267             : 
     268             :         return true;
     269             : }
     270             : 
     271           0 : static bool i2c_read_sw(
     272             :         struct dc_context *ctx,
     273             :         struct ddc *ddc_handle,
     274             :         uint16_t clock_delay_div_4,
     275             :         uint8_t address,
     276             :         uint32_t length,
     277             :         uint8_t *data)
     278             : {
     279           0 :         uint32_t i = 0;
     280             : 
     281           0 :         if (!write_byte_sw(ctx, ddc_handle, clock_delay_div_4, address))
     282             :                 return false;
     283             : 
     284           0 :         while (i < length) {
     285           0 :                 if (!read_byte_sw(ctx, ddc_handle, clock_delay_div_4, data + i,
     286           0 :                         i < length - 1))
     287             :                         return false;
     288           0 :                 ++i;
     289             :         }
     290             : 
     291             :         return true;
     292             : }
     293             : 
     294             : 
     295             : 
     296           0 : static bool start_sync_sw(
     297             :         struct dc_context *ctx,
     298             :         struct ddc *ddc_handle,
     299             :         uint16_t clock_delay_div_4)
     300             : {
     301           0 :         uint32_t retry = 0;
     302             : 
     303             :         /* The I2C communications start signal is:
     304             :          * the SDA going low from high, while the SCL is high.
     305             :          */
     306             : 
     307           0 :         write_bit_to_ddc(ddc_handle, SCL, true);
     308             : 
     309           0 :         udelay(clock_delay_div_4);
     310             : 
     311             :         do {
     312           0 :                 write_bit_to_ddc(ddc_handle, SDA, true);
     313             : 
     314           0 :                 if (!read_bit_from_ddc(ddc_handle, SDA)) {
     315           0 :                         ++retry;
     316           0 :                         continue;
     317             :                 }
     318             : 
     319           0 :                 udelay(clock_delay_div_4);
     320             : 
     321           0 :                 write_bit_to_ddc(ddc_handle, SCL, true);
     322             : 
     323           0 :                 if (!wait_for_scl_high_sw(ctx, ddc_handle, clock_delay_div_4))
     324             :                         break;
     325             : 
     326           0 :                 write_bit_to_ddc(ddc_handle, SDA, false);
     327             : 
     328           0 :                 udelay(clock_delay_div_4);
     329             : 
     330           0 :                 write_bit_to_ddc(ddc_handle, SCL, false);
     331             : 
     332           0 :                 udelay(clock_delay_div_4);
     333             : 
     334           0 :                 return true;
     335           0 :         } while (retry <= I2C_SW_RETRIES);
     336             : 
     337             :         return false;
     338             : }
     339             : 
     340           0 : static void dce_i2c_sw_engine_set_speed(
     341             :         struct dce_i2c_sw *engine,
     342             :         uint32_t speed)
     343             : {
     344           0 :         ASSERT(speed);
     345             : 
     346           0 :         engine->speed = speed ? speed : DCE_I2C_DEFAULT_I2C_SW_SPEED;
     347             : 
     348           0 :         engine->clock_delay = 1000 / engine->speed;
     349             : 
     350           0 :         if (engine->clock_delay < 12)
     351           0 :                 engine->clock_delay = 12;
     352           0 : }
     353             : 
     354             : static bool dce_i2c_sw_engine_acquire_engine(
     355             :         struct dce_i2c_sw *engine,
     356             :         struct ddc *ddc)
     357             : {
     358             :         enum gpio_result result;
     359             : 
     360           0 :         result = dal_ddc_open(ddc, GPIO_MODE_FAST_OUTPUT,
     361             :                 GPIO_DDC_CONFIG_TYPE_MODE_I2C);
     362             : 
     363           0 :         if (result != GPIO_RESULT_OK)
     364             :                 return false;
     365             : 
     366           0 :         engine->ddc = ddc;
     367             : 
     368             :         return true;
     369             : }
     370           0 : bool dce_i2c_engine_acquire_sw(
     371             :         struct dce_i2c_sw *dce_i2c_sw,
     372             :         struct ddc *ddc_handle)
     373             : {
     374           0 :         uint32_t counter = 0;
     375             :         bool result;
     376             : 
     377             :         do {
     378             : 
     379           0 :                 result = dce_i2c_sw_engine_acquire_engine(
     380             :                                 dce_i2c_sw, ddc_handle);
     381             : 
     382           0 :                 if (result)
     383             :                         break;
     384             : 
     385             :                 /* i2c_engine is busy by VBios, lets wait and retry */
     386             : 
     387           0 :                 udelay(10);
     388             : 
     389           0 :                 ++counter;
     390           0 :         } while (counter < 2);
     391             : 
     392           0 :         return result;
     393             : }
     394             : 
     395             : 
     396             : 
     397             : 
     398           0 : static void dce_i2c_sw_engine_submit_channel_request(
     399             :         struct dce_i2c_sw *engine,
     400             :         struct i2c_request_transaction_data *req)
     401             : {
     402           0 :         struct ddc *ddc = engine->ddc;
     403           0 :         uint16_t clock_delay_div_4 = engine->clock_delay >> 2;
     404             : 
     405             :         /* send sync (start / repeated start) */
     406             : 
     407           0 :         bool result = start_sync_sw(engine->ctx, ddc, clock_delay_div_4);
     408             : 
     409             :         /* process payload */
     410             : 
     411           0 :         if (result) {
     412           0 :                 switch (req->action) {
     413             :                 case DCE_I2C_TRANSACTION_ACTION_I2C_WRITE:
     414             :                 case DCE_I2C_TRANSACTION_ACTION_I2C_WRITE_MOT:
     415           0 :                         result = i2c_write_sw(engine->ctx, ddc, clock_delay_div_4,
     416           0 :                                 req->address, req->length, req->data);
     417           0 :                 break;
     418             :                 case DCE_I2C_TRANSACTION_ACTION_I2C_READ:
     419             :                 case DCE_I2C_TRANSACTION_ACTION_I2C_READ_MOT:
     420           0 :                         result = i2c_read_sw(engine->ctx, ddc, clock_delay_div_4,
     421           0 :                                 req->address, req->length, req->data);
     422           0 :                 break;
     423             :                 default:
     424             :                         result = false;
     425             :                 break;
     426             :                 }
     427             :         }
     428             : 
     429             :         /* send stop if not 'mot' or operation failed */
     430             : 
     431           0 :         if (!result ||
     432           0 :                 (req->action == DCE_I2C_TRANSACTION_ACTION_I2C_WRITE) ||
     433             :                 (req->action == DCE_I2C_TRANSACTION_ACTION_I2C_READ))
     434           0 :                 if (!stop_sync_sw(engine->ctx, ddc, clock_delay_div_4))
     435           0 :                         result = false;
     436             : 
     437           0 :         req->status = result ?
     438           0 :                 I2C_CHANNEL_OPERATION_SUCCEEDED :
     439             :                 I2C_CHANNEL_OPERATION_FAILED;
     440           0 : }
     441             : 
     442           0 : static bool dce_i2c_sw_engine_submit_payload(
     443             :         struct dce_i2c_sw *engine,
     444             :         struct i2c_payload *payload,
     445             :         bool middle_of_transaction)
     446             : {
     447             :         struct i2c_request_transaction_data request;
     448             : 
     449           0 :         if (!payload->write)
     450           0 :                 request.action = middle_of_transaction ?
     451           0 :                         DCE_I2C_TRANSACTION_ACTION_I2C_READ_MOT :
     452             :                         DCE_I2C_TRANSACTION_ACTION_I2C_READ;
     453             :         else
     454           0 :                 request.action = middle_of_transaction ?
     455           0 :                         DCE_I2C_TRANSACTION_ACTION_I2C_WRITE_MOT :
     456             :                         DCE_I2C_TRANSACTION_ACTION_I2C_WRITE;
     457             : 
     458           0 :         request.address = (uint8_t) ((payload->address << 1) | !payload->write);
     459           0 :         request.length = payload->length;
     460           0 :         request.data = payload->data;
     461             : 
     462           0 :         dce_i2c_sw_engine_submit_channel_request(engine, &request);
     463             : 
     464           0 :         if ((request.status == I2C_CHANNEL_OPERATION_ENGINE_BUSY) ||
     465             :                 (request.status == I2C_CHANNEL_OPERATION_FAILED))
     466             :                 return false;
     467             : 
     468           0 :         return true;
     469             : }
     470           0 : bool dce_i2c_submit_command_sw(
     471             :         struct resource_pool *pool,
     472             :         struct ddc *ddc,
     473             :         struct i2c_command *cmd,
     474             :         struct dce_i2c_sw *dce_i2c_sw)
     475             : {
     476           0 :         uint8_t index_of_payload = 0;
     477             :         bool result;
     478             : 
     479           0 :         dce_i2c_sw_engine_set_speed(dce_i2c_sw, cmd->speed);
     480             : 
     481           0 :         result = true;
     482             : 
     483           0 :         while (index_of_payload < cmd->number_of_payloads) {
     484           0 :                 bool mot = (index_of_payload != cmd->number_of_payloads - 1);
     485             : 
     486           0 :                 struct i2c_payload *payload = cmd->payloads + index_of_payload;
     487             : 
     488           0 :                 if (!dce_i2c_sw_engine_submit_payload(
     489             :                         dce_i2c_sw, payload, mot)) {
     490             :                         result = false;
     491             :                         break;
     492             :                 }
     493             : 
     494           0 :                 ++index_of_payload;
     495             :         }
     496             : 
     497           0 :         release_engine_dce_sw(pool, dce_i2c_sw);
     498             : 
     499           0 :         return result;
     500             : }

Generated by: LCOV version 1.14