cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dce_i2c_sw.c (10600B)


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