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