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

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
...@@ -95,9 +95,12 @@ static int radeon_process_aux_ch(struct radeon_i2c_chan *chan, ...@@ -95,9 +95,12 @@ static int radeon_process_aux_ch(struct radeon_i2c_chan *chan,
int index = GetIndexIntoMasterTable(COMMAND, ProcessAuxChannelTransaction); int index = GetIndexIntoMasterTable(COMMAND, ProcessAuxChannelTransaction);
unsigned char *base; unsigned char *base;
int recv_bytes; int recv_bytes;
int r = 0;
memset(&args, 0, sizeof(args)); memset(&args, 0, sizeof(args));
mutex_lock(&chan->mutex);
base = (unsigned char *)(rdev->mode_info.atom_context->scratch + 1); base = (unsigned char *)(rdev->mode_info.atom_context->scratch + 1);
radeon_atom_copy_swap(base, send, send_bytes, true); radeon_atom_copy_swap(base, send, send_bytes, true);
...@@ -117,19 +120,22 @@ static int radeon_process_aux_ch(struct radeon_i2c_chan *chan, ...@@ -117,19 +120,22 @@ static int radeon_process_aux_ch(struct radeon_i2c_chan *chan,
/* timeout */ /* timeout */
if (args.v1.ucReplyStatus == 1) { if (args.v1.ucReplyStatus == 1) {
DRM_DEBUG_KMS("dp_aux_ch timeout\n"); DRM_DEBUG_KMS("dp_aux_ch timeout\n");
return -ETIMEDOUT; r = -ETIMEDOUT;
goto done;
} }
/* flags not zero */ /* flags not zero */
if (args.v1.ucReplyStatus == 2) { if (args.v1.ucReplyStatus == 2) {
DRM_DEBUG_KMS("dp_aux_ch flags not zero\n"); DRM_DEBUG_KMS("dp_aux_ch flags not zero\n");
return -EBUSY; r = -EBUSY;
goto done;
} }
/* error */ /* error */
if (args.v1.ucReplyStatus == 3) { if (args.v1.ucReplyStatus == 3) {
DRM_DEBUG_KMS("dp_aux_ch error\n"); DRM_DEBUG_KMS("dp_aux_ch error\n");
return -EIO; r = -EIO;
goto done;
} }
recv_bytes = args.v1.ucDataOutLen; recv_bytes = args.v1.ucDataOutLen;
...@@ -139,7 +145,11 @@ static int radeon_process_aux_ch(struct radeon_i2c_chan *chan, ...@@ -139,7 +145,11 @@ static int radeon_process_aux_ch(struct radeon_i2c_chan *chan,
if (recv && recv_size) if (recv && recv_size)
radeon_atom_copy_swap(recv, base + 16, recv_bytes, false); 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 #define BARE_ADDRESS_SIZE 3
......
...@@ -43,15 +43,19 @@ static int radeon_process_i2c_ch(struct radeon_i2c_chan *chan, ...@@ -43,15 +43,19 @@ static int radeon_process_i2c_ch(struct radeon_i2c_chan *chan,
int index = GetIndexIntoMasterTable(COMMAND, ProcessI2cChannelTransaction); int index = GetIndexIntoMasterTable(COMMAND, ProcessI2cChannelTransaction);
unsigned char *base; unsigned char *base;
u16 out = cpu_to_le16(0); u16 out = cpu_to_le16(0);
int r = 0;
memset(&args, 0, sizeof(args)); memset(&args, 0, sizeof(args));
mutex_lock(&chan->mutex);
base = (unsigned char *)rdev->mode_info.atom_context->scratch; base = (unsigned char *)rdev->mode_info.atom_context->scratch;
if (flags & HW_I2C_WRITE) { if (flags & HW_I2C_WRITE) {
if (num > ATOM_MAX_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); DRM_ERROR("hw i2c: tried to write too many bytes (%d vs 3)\n", num);
return -EINVAL; r = -EINVAL;
goto done;
} }
if (buf == NULL) if (buf == NULL)
args.ucRegIndex = 0; args.ucRegIndex = 0;
...@@ -65,7 +69,8 @@ static int radeon_process_i2c_ch(struct radeon_i2c_chan *chan, ...@@ -65,7 +69,8 @@ static int radeon_process_i2c_ch(struct radeon_i2c_chan *chan,
} else { } else {
if (num > ATOM_MAX_HW_I2C_READ) { if (num > ATOM_MAX_HW_I2C_READ) {
DRM_ERROR("hw i2c: tried to read too many bytes (%d vs 255)\n", num); 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.ucRegIndex = 0;
args.lpI2CDataOut = 0; args.lpI2CDataOut = 0;
...@@ -82,13 +87,17 @@ static int radeon_process_i2c_ch(struct radeon_i2c_chan *chan, ...@@ -82,13 +87,17 @@ static int radeon_process_i2c_ch(struct radeon_i2c_chan *chan,
/* error */ /* error */
if (args.ucStatus != HW_ASSISTED_I2C_STATUS_SUCCESS) { if (args.ucStatus != HW_ASSISTED_I2C_STATUS_SUCCESS) {
DRM_DEBUG_KMS("hw_i2c error\n"); DRM_DEBUG_KMS("hw_i2c error\n");
return -EIO; r = -EIO;
goto done;
} }
if (!(flags & HW_I2C_WRITE)) if (!(flags & HW_I2C_WRITE))
radeon_atom_copy_swap(buf, base, num, false); 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, int radeon_atom_hw_i2c_xfer(struct i2c_adapter *i2c_adap,
......
...@@ -94,6 +94,8 @@ static int pre_xfer(struct i2c_adapter *i2c_adap) ...@@ -94,6 +94,8 @@ static int pre_xfer(struct i2c_adapter *i2c_adap)
struct radeon_i2c_bus_rec *rec = &i2c->rec; struct radeon_i2c_bus_rec *rec = &i2c->rec;
uint32_t temp; uint32_t temp;
mutex_lock(&i2c->mutex);
/* RV410 appears to have a bug where the hw i2c in reset /* 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 * 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 * 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) ...@@ -170,6 +172,8 @@ static void post_xfer(struct i2c_adapter *i2c_adap)
temp = RREG32(rec->mask_data_reg) & ~rec->mask_data_mask; temp = RREG32(rec->mask_data_reg) & ~rec->mask_data_mask;
WREG32(rec->mask_data_reg, temp); WREG32(rec->mask_data_reg, temp);
temp = RREG32(rec->mask_data_reg); temp = RREG32(rec->mask_data_reg);
mutex_unlock(&i2c->mutex);
} }
static int get_clock(void *i2c_priv) static int get_clock(void *i2c_priv)
...@@ -813,6 +817,8 @@ static int radeon_hw_i2c_xfer(struct i2c_adapter *i2c_adap, ...@@ -813,6 +817,8 @@ static int radeon_hw_i2c_xfer(struct i2c_adapter *i2c_adap,
struct radeon_i2c_bus_rec *rec = &i2c->rec; struct radeon_i2c_bus_rec *rec = &i2c->rec;
int ret = 0; int ret = 0;
mutex_lock(&i2c->mutex);
switch (rdev->family) { switch (rdev->family) {
case CHIP_R100: case CHIP_R100:
case CHIP_RV100: case CHIP_RV100:
...@@ -879,6 +885,8 @@ static int radeon_hw_i2c_xfer(struct i2c_adapter *i2c_adap, ...@@ -879,6 +885,8 @@ static int radeon_hw_i2c_xfer(struct i2c_adapter *i2c_adap,
break; break;
} }
mutex_unlock(&i2c->mutex);
return ret; return ret;
} }
...@@ -919,6 +927,7 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev, ...@@ -919,6 +927,7 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev,
i2c->adapter.dev.parent = &dev->pdev->dev; i2c->adapter.dev.parent = &dev->pdev->dev;
i2c->dev = dev; i2c->dev = dev;
i2c_set_adapdata(&i2c->adapter, i2c); i2c_set_adapdata(&i2c->adapter, i2c);
mutex_init(&i2c->mutex);
if (rec->mm_i2c || if (rec->mm_i2c ||
(rec->hw_capable && (rec->hw_capable &&
radeon_hw_i2c && radeon_hw_i2c &&
......
...@@ -191,6 +191,7 @@ struct radeon_i2c_chan { ...@@ -191,6 +191,7 @@ struct radeon_i2c_chan {
struct radeon_i2c_bus_rec rec; struct radeon_i2c_bus_rec rec;
struct drm_dp_aux aux; struct drm_dp_aux aux;
bool has_aux; bool has_aux;
struct mutex mutex;
}; };
/* mostly for macs, but really any system without connector tables */ /* mostly for macs, but really any system without connector tables */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment