brintos

brintos / linux-shallow public Read only

0
0
Text · 10.3 KiB · e188447 Raw
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