Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 831719d6 authored by Alex Deucher's avatar Alex Deucher Committed by Alex Deucher
Browse files

drm/radeon: add a i2c bus mutex



The i2c and aux buses use the same pads so add
a mutex to protect access to the pads.

Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
Signed-off-by: default avatarChristian König <christian.koenig@amd.com>
parent 182407a6
Loading
Loading
Loading
Loading
+14 −4
Original line number Diff line number Diff line
@@ -95,9 +95,12 @@ static int radeon_process_aux_ch(struct radeon_i2c_chan *chan,
	int index = GetIndexIntoMasterTable(COMMAND, ProcessAuxChannelTransaction);
	unsigned char *base;
	int recv_bytes;
	int r = 0;

	memset(&args, 0, sizeof(args));

	mutex_lock(&chan->mutex);

	base = (unsigned char *)(rdev->mode_info.atom_context->scratch + 1);

	radeon_atom_copy_swap(base, send, send_bytes, true);
@@ -117,19 +120,22 @@ static int radeon_process_aux_ch(struct radeon_i2c_chan *chan,
	/* timeout */
	if (args.v1.ucReplyStatus == 1) {
		DRM_DEBUG_KMS("dp_aux_ch timeout\n");
		return -ETIMEDOUT;
		r = -ETIMEDOUT;
		goto done;
	}

	/* flags not zero */
	if (args.v1.ucReplyStatus == 2) {
		DRM_DEBUG_KMS("dp_aux_ch flags not zero\n");
		return -EBUSY;
		r = -EBUSY;
		goto done;
	}

	/* error */
	if (args.v1.ucReplyStatus == 3) {
		DRM_DEBUG_KMS("dp_aux_ch error\n");
		return -EIO;
		r = -EIO;
		goto done;
	}

	recv_bytes = args.v1.ucDataOutLen;
@@ -139,7 +145,11 @@ static int radeon_process_aux_ch(struct radeon_i2c_chan *chan,
	if (recv && recv_size)
		radeon_atom_copy_swap(recv, base + 16, recv_bytes, false);

	return recv_bytes;
	r = recv_bytes;
done:
	mutex_unlock(&chan->mutex);

	return r;
}

#define BARE_ADDRESS_SIZE 3
+13 −4
Original line number Diff line number Diff line
@@ -43,15 +43,19 @@ static int radeon_process_i2c_ch(struct radeon_i2c_chan *chan,
	int index = GetIndexIntoMasterTable(COMMAND, ProcessI2cChannelTransaction);
	unsigned char *base;
	u16 out = cpu_to_le16(0);
	int r = 0;

	memset(&args, 0, sizeof(args));

	mutex_lock(&chan->mutex);

	base = (unsigned char *)rdev->mode_info.atom_context->scratch;

	if (flags & HW_I2C_WRITE) {
		if (num > ATOM_MAX_HW_I2C_WRITE) {
			DRM_ERROR("hw i2c: tried to write too many bytes (%d vs 3)\n", num);
			return -EINVAL;
			r = -EINVAL;
			goto done;
		}
		if (buf == NULL)
			args.ucRegIndex = 0;
@@ -65,7 +69,8 @@ static int radeon_process_i2c_ch(struct radeon_i2c_chan *chan,
	} else {
		if (num > ATOM_MAX_HW_I2C_READ) {
			DRM_ERROR("hw i2c: tried to read too many bytes (%d vs 255)\n", num);
			return -EINVAL;
			r = -EINVAL;
			goto done;
		}
		args.ucRegIndex = 0;
		args.lpI2CDataOut = 0;
@@ -82,13 +87,17 @@ static int radeon_process_i2c_ch(struct radeon_i2c_chan *chan,
	/* error */
	if (args.ucStatus != HW_ASSISTED_I2C_STATUS_SUCCESS) {
		DRM_DEBUG_KMS("hw_i2c error\n");
		return -EIO;
		r = -EIO;
		goto done;
	}

	if (!(flags & HW_I2C_WRITE))
		radeon_atom_copy_swap(buf, base, num, false);

	return 0;
done:
	mutex_unlock(&chan->mutex);

	return r;
}

int radeon_atom_hw_i2c_xfer(struct i2c_adapter *i2c_adap,
+9 −0
Original line number Diff line number Diff line
@@ -94,6 +94,8 @@ static int pre_xfer(struct i2c_adapter *i2c_adap)
	struct radeon_i2c_bus_rec *rec = &i2c->rec;
	uint32_t temp;

	mutex_lock(&i2c->mutex);

	/* RV410 appears to have a bug where the hw i2c in reset
	 * holds the i2c port in a bad state - switch hw i2c away before
	 * doing DDC - do this for all r200s/r300s/r400s for safety sake
@@ -170,6 +172,8 @@ static void post_xfer(struct i2c_adapter *i2c_adap)
	temp = RREG32(rec->mask_data_reg) & ~rec->mask_data_mask;
	WREG32(rec->mask_data_reg, temp);
	temp = RREG32(rec->mask_data_reg);

	mutex_unlock(&i2c->mutex);
}

static int get_clock(void *i2c_priv)
@@ -813,6 +817,8 @@ static int radeon_hw_i2c_xfer(struct i2c_adapter *i2c_adap,
	struct radeon_i2c_bus_rec *rec = &i2c->rec;
	int ret = 0;

	mutex_lock(&i2c->mutex);

	switch (rdev->family) {
	case CHIP_R100:
	case CHIP_RV100:
@@ -879,6 +885,8 @@ static int radeon_hw_i2c_xfer(struct i2c_adapter *i2c_adap,
		break;
	}

	mutex_unlock(&i2c->mutex);

	return ret;
}

@@ -919,6 +927,7 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev,
	i2c->adapter.dev.parent = &dev->pdev->dev;
	i2c->dev = dev;
	i2c_set_adapdata(&i2c->adapter, i2c);
	mutex_init(&i2c->mutex);
	if (rec->mm_i2c ||
	    (rec->hw_capable &&
	     radeon_hw_i2c &&
+1 −0
Original line number Diff line number Diff line
@@ -191,6 +191,7 @@ struct radeon_i2c_chan {
	struct radeon_i2c_bus_rec rec;
	struct drm_dp_aux aux;
	bool has_aux;
	struct mutex mutex;
};

/* mostly for macs, but really any system without connector tables */