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