drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.c

Source file repositories/reference/linux-study-clean/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.c

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.c
Extension
.c
Size
20438 bytes
Lines
759
Domain
Driver Families
Bucket
drivers/gpu
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

while (length) {
			REG_SET_2(DC_I2C_DATA, value,
				  DC_I2C_INDEX_WRITE, 0,
				  DC_I2C_DATA, *buffer++);
			dce_i2c_hw->buffer_used_write++;
			--length;
		}
	}

	++dce_i2c_hw->transaction_count;
	dce_i2c_hw->buffer_used_bytes += length + 1;

	return last_transaction;
}

static inline void reset_hw_engine(struct dce_i2c_hw *dce_i2c_hw)
{
	REG_UPDATE_2(DC_I2C_CONTROL,
		     DC_I2C_SW_STATUS_RESET, 1,
		     DC_I2C_SW_STATUS_RESET, 1);
}

static void set_speed(
	struct dce_i2c_hw *dce_i2c_hw,
	uint32_t speed)
{
	uint32_t xtal_ref_div = 0, ref_base_div = 0;
	uint32_t prescale = 0;
	uint32_t i2c_ref_clock = 0;

	if (speed == 0)
		return;

	REG_GET_2(MICROSECOND_TIME_BASE_DIV, MICROSECOND_TIME_BASE_DIV, &ref_base_div,
		XTAL_REF_DIV, &xtal_ref_div);

	if (xtal_ref_div == 0)
		xtal_ref_div = 2;

	if (ref_base_div == 0)
		i2c_ref_clock = (dce_i2c_hw->reference_frequency * 2);
	else
		i2c_ref_clock = ref_base_div * 1000;

	prescale = (i2c_ref_clock / xtal_ref_div) / speed;

	if (dce_i2c_hw->masks->DC_I2C_DDC1_START_STOP_TIMING_CNTL)
		REG_UPDATE_N(SPEED, 3,
			     FN(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_PRESCALE), prescale,
			     FN(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_THRESHOLD), 2,
			     FN(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_START_STOP_TIMING_CNTL), speed > 50 ? 2:1);
	else
		REG_UPDATE_N(SPEED, 2,
			     FN(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_PRESCALE), prescale,
			     FN(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_THRESHOLD), 2);
}

static bool acquire_engine(struct dce_i2c_hw *dce_i2c_hw)
{
	uint32_t arbitrate = 0;

	REG_GET(DC_I2C_ARBITRATION, DC_I2C_REG_RW_CNTL_STATUS, &arbitrate);
	switch (arbitrate) {
	case DC_I2C_STATUS__DC_I2C_STATUS_USED_BY_SW:
		return true;
	case DC_I2C_STATUS__DC_I2C_STATUS_USED_BY_HW:
		return false;
	case DC_I2C_STATUS__DC_I2C_STATUS_IDLE:
	default:
		break;
	}

	REG_UPDATE(DC_I2C_ARBITRATION, DC_I2C_SW_USE_I2C_REG_REQ, true);
	REG_GET(DC_I2C_ARBITRATION, DC_I2C_REG_RW_CNTL_STATUS, &arbitrate);
	if (arbitrate != DC_I2C_STATUS__DC_I2C_STATUS_USED_BY_SW)
		return false;

	return true;
}

static bool setup_engine(
	struct dce_i2c_hw *dce_i2c_hw)
{
	// Deassert soft reset to unblock I2C engine registers
	REG_UPDATE(DC_I2C_CONTROL, DC_I2C_SOFT_RESET, false);

	uint32_t i2c_setup_limit = I2C_SETUP_TIME_LIMIT_DCE;
	uint32_t  reset_length = 0;

	if (dce_i2c_hw->ctx->dc->debug.enable_mem_low_power.bits.i2c) {

Annotation

Implementation Notes