diff options
author | Alex Deucher <alexdeucher@gmail.com> | 2014-05-08 10:58:04 -0400 |
---|---|---|
committer | Alex Deucher <alexander.deucher@amd.com> | 2014-06-02 10:25:02 -0400 |
commit | 831719d62f692e28699a7acd7b441c6f0c01b6f7 (patch) | |
tree | 7f9bcfe0d74ae6cae476ab9b597b1a6abfd80446 /drivers/gpu/drm/radeon | |
parent | 182407a6ed5333fc37dd980a8de91a8f826a94f6 (diff) |
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: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Christian König <christian.koenig@amd.com>
Diffstat (limited to 'drivers/gpu/drm/radeon')
-rw-r--r-- | drivers/gpu/drm/radeon/atombios_dp.c | 18 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/atombios_i2c.c | 17 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_i2c.c | 9 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_mode.h | 1 |
4 files changed, 37 insertions, 8 deletions
diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index bc0119fb6c12..330f8df65b09 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c | |||
@@ -95,9 +95,12 @@ static int radeon_process_aux_ch(struct radeon_i2c_chan *chan, | |||
95 | int index = GetIndexIntoMasterTable(COMMAND, ProcessAuxChannelTransaction); | 95 | int index = GetIndexIntoMasterTable(COMMAND, ProcessAuxChannelTransaction); |
96 | unsigned char *base; | 96 | unsigned char *base; |
97 | int recv_bytes; | 97 | int recv_bytes; |
98 | int r = 0; | ||
98 | 99 | ||
99 | memset(&args, 0, sizeof(args)); | 100 | memset(&args, 0, sizeof(args)); |
100 | 101 | ||
102 | mutex_lock(&chan->mutex); | ||
103 | |||
101 | base = (unsigned char *)(rdev->mode_info.atom_context->scratch + 1); | 104 | base = (unsigned char *)(rdev->mode_info.atom_context->scratch + 1); |
102 | 105 | ||
103 | radeon_atom_copy_swap(base, send, send_bytes, true); | 106 | 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 | /* timeout */ | 120 | /* timeout */ |
118 | if (args.v1.ucReplyStatus == 1) { | 121 | if (args.v1.ucReplyStatus == 1) { |
119 | DRM_DEBUG_KMS("dp_aux_ch timeout\n"); | 122 | DRM_DEBUG_KMS("dp_aux_ch timeout\n"); |
120 | return -ETIMEDOUT; | 123 | r = -ETIMEDOUT; |
124 | goto done; | ||
121 | } | 125 | } |
122 | 126 | ||
123 | /* flags not zero */ | 127 | /* flags not zero */ |
124 | if (args.v1.ucReplyStatus == 2) { | 128 | if (args.v1.ucReplyStatus == 2) { |
125 | DRM_DEBUG_KMS("dp_aux_ch flags not zero\n"); | 129 | DRM_DEBUG_KMS("dp_aux_ch flags not zero\n"); |
126 | return -EBUSY; | 130 | r = -EBUSY; |
131 | goto done; | ||
127 | } | 132 | } |
128 | 133 | ||
129 | /* error */ | 134 | /* error */ |
130 | if (args.v1.ucReplyStatus == 3) { | 135 | if (args.v1.ucReplyStatus == 3) { |
131 | DRM_DEBUG_KMS("dp_aux_ch error\n"); | 136 | DRM_DEBUG_KMS("dp_aux_ch error\n"); |
132 | return -EIO; | 137 | r = -EIO; |
138 | goto done; | ||
133 | } | 139 | } |
134 | 140 | ||
135 | recv_bytes = args.v1.ucDataOutLen; | 141 | recv_bytes = args.v1.ucDataOutLen; |
@@ -139,7 +145,11 @@ static int radeon_process_aux_ch(struct radeon_i2c_chan *chan, | |||
139 | if (recv && recv_size) | 145 | if (recv && recv_size) |
140 | radeon_atom_copy_swap(recv, base + 16, recv_bytes, false); | 146 | radeon_atom_copy_swap(recv, base + 16, recv_bytes, false); |
141 | 147 | ||
142 | return recv_bytes; | 148 | r = recv_bytes; |
149 | done: | ||
150 | mutex_unlock(&chan->mutex); | ||
151 | |||
152 | return r; | ||
143 | } | 153 | } |
144 | 154 | ||
145 | #define BARE_ADDRESS_SIZE 3 | 155 | #define BARE_ADDRESS_SIZE 3 |
diff --git a/drivers/gpu/drm/radeon/atombios_i2c.c b/drivers/gpu/drm/radeon/atombios_i2c.c index b5162c3b6111..9c570fb15b8c 100644 --- a/drivers/gpu/drm/radeon/atombios_i2c.c +++ b/drivers/gpu/drm/radeon/atombios_i2c.c | |||
@@ -43,15 +43,19 @@ static int radeon_process_i2c_ch(struct radeon_i2c_chan *chan, | |||
43 | int index = GetIndexIntoMasterTable(COMMAND, ProcessI2cChannelTransaction); | 43 | int index = GetIndexIntoMasterTable(COMMAND, ProcessI2cChannelTransaction); |
44 | unsigned char *base; | 44 | unsigned char *base; |
45 | u16 out = cpu_to_le16(0); | 45 | u16 out = cpu_to_le16(0); |
46 | int r = 0; | ||
46 | 47 | ||
47 | memset(&args, 0, sizeof(args)); | 48 | memset(&args, 0, sizeof(args)); |
48 | 49 | ||
50 | mutex_lock(&chan->mutex); | ||
51 | |||
49 | base = (unsigned char *)rdev->mode_info.atom_context->scratch; | 52 | base = (unsigned char *)rdev->mode_info.atom_context->scratch; |
50 | 53 | ||
51 | if (flags & HW_I2C_WRITE) { | 54 | if (flags & HW_I2C_WRITE) { |
52 | if (num > ATOM_MAX_HW_I2C_WRITE) { | 55 | if (num > ATOM_MAX_HW_I2C_WRITE) { |
53 | DRM_ERROR("hw i2c: tried to write too many bytes (%d vs 3)\n", num); | 56 | DRM_ERROR("hw i2c: tried to write too many bytes (%d vs 3)\n", num); |
54 | return -EINVAL; | 57 | r = -EINVAL; |
58 | goto done; | ||
55 | } | 59 | } |
56 | if (buf == NULL) | 60 | if (buf == NULL) |
57 | args.ucRegIndex = 0; | 61 | args.ucRegIndex = 0; |
@@ -65,7 +69,8 @@ static int radeon_process_i2c_ch(struct radeon_i2c_chan *chan, | |||
65 | } else { | 69 | } else { |
66 | if (num > ATOM_MAX_HW_I2C_READ) { | 70 | if (num > ATOM_MAX_HW_I2C_READ) { |
67 | DRM_ERROR("hw i2c: tried to read too many bytes (%d vs 255)\n", num); | 71 | DRM_ERROR("hw i2c: tried to read too many bytes (%d vs 255)\n", num); |
68 | return -EINVAL; | 72 | r = -EINVAL; |
73 | goto done; | ||
69 | } | 74 | } |
70 | args.ucRegIndex = 0; | 75 | args.ucRegIndex = 0; |
71 | args.lpI2CDataOut = 0; | 76 | args.lpI2CDataOut = 0; |
@@ -82,13 +87,17 @@ static int radeon_process_i2c_ch(struct radeon_i2c_chan *chan, | |||
82 | /* error */ | 87 | /* error */ |
83 | if (args.ucStatus != HW_ASSISTED_I2C_STATUS_SUCCESS) { | 88 | if (args.ucStatus != HW_ASSISTED_I2C_STATUS_SUCCESS) { |
84 | DRM_DEBUG_KMS("hw_i2c error\n"); | 89 | DRM_DEBUG_KMS("hw_i2c error\n"); |
85 | return -EIO; | 90 | r = -EIO; |
91 | goto done; | ||
86 | } | 92 | } |
87 | 93 | ||
88 | if (!(flags & HW_I2C_WRITE)) | 94 | if (!(flags & HW_I2C_WRITE)) |
89 | radeon_atom_copy_swap(buf, base, num, false); | 95 | radeon_atom_copy_swap(buf, base, num, false); |
90 | 96 | ||
91 | return 0; | 97 | done: |
98 | mutex_unlock(&chan->mutex); | ||
99 | |||
100 | return r; | ||
92 | } | 101 | } |
93 | 102 | ||
94 | int radeon_atom_hw_i2c_xfer(struct i2c_adapter *i2c_adap, | 103 | int radeon_atom_hw_i2c_xfer(struct i2c_adapter *i2c_adap, |
diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c index 7b944142a9fd..427ee4d6d0b5 100644 --- a/drivers/gpu/drm/radeon/radeon_i2c.c +++ b/drivers/gpu/drm/radeon/radeon_i2c.c | |||
@@ -94,6 +94,8 @@ static int pre_xfer(struct i2c_adapter *i2c_adap) | |||
94 | struct radeon_i2c_bus_rec *rec = &i2c->rec; | 94 | struct radeon_i2c_bus_rec *rec = &i2c->rec; |
95 | uint32_t temp; | 95 | uint32_t temp; |
96 | 96 | ||
97 | mutex_lock(&i2c->mutex); | ||
98 | |||
97 | /* RV410 appears to have a bug where the hw i2c in reset | 99 | /* RV410 appears to have a bug where the hw i2c in reset |
98 | * holds the i2c port in a bad state - switch hw i2c away before | 100 | * holds the i2c port in a bad state - switch hw i2c away before |
99 | * doing DDC - do this for all r200s/r300s/r400s for safety sake | 101 | * 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 | temp = RREG32(rec->mask_data_reg) & ~rec->mask_data_mask; | 172 | temp = RREG32(rec->mask_data_reg) & ~rec->mask_data_mask; |
171 | WREG32(rec->mask_data_reg, temp); | 173 | WREG32(rec->mask_data_reg, temp); |
172 | temp = RREG32(rec->mask_data_reg); | 174 | temp = RREG32(rec->mask_data_reg); |
175 | |||
176 | mutex_unlock(&i2c->mutex); | ||
173 | } | 177 | } |
174 | 178 | ||
175 | static int get_clock(void *i2c_priv) | 179 | static int get_clock(void *i2c_priv) |
@@ -813,6 +817,8 @@ static int radeon_hw_i2c_xfer(struct i2c_adapter *i2c_adap, | |||
813 | struct radeon_i2c_bus_rec *rec = &i2c->rec; | 817 | struct radeon_i2c_bus_rec *rec = &i2c->rec; |
814 | int ret = 0; | 818 | int ret = 0; |
815 | 819 | ||
820 | mutex_lock(&i2c->mutex); | ||
821 | |||
816 | switch (rdev->family) { | 822 | switch (rdev->family) { |
817 | case CHIP_R100: | 823 | case CHIP_R100: |
818 | case CHIP_RV100: | 824 | case CHIP_RV100: |
@@ -879,6 +885,8 @@ static int radeon_hw_i2c_xfer(struct i2c_adapter *i2c_adap, | |||
879 | break; | 885 | break; |
880 | } | 886 | } |
881 | 887 | ||
888 | mutex_unlock(&i2c->mutex); | ||
889 | |||
882 | return ret; | 890 | return ret; |
883 | } | 891 | } |
884 | 892 | ||
@@ -919,6 +927,7 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev, | |||
919 | i2c->adapter.dev.parent = &dev->pdev->dev; | 927 | i2c->adapter.dev.parent = &dev->pdev->dev; |
920 | i2c->dev = dev; | 928 | i2c->dev = dev; |
921 | i2c_set_adapdata(&i2c->adapter, i2c); | 929 | i2c_set_adapdata(&i2c->adapter, i2c); |
930 | mutex_init(&i2c->mutex); | ||
922 | if (rec->mm_i2c || | 931 | if (rec->mm_i2c || |
923 | (rec->hw_capable && | 932 | (rec->hw_capable && |
924 | radeon_hw_i2c && | 933 | radeon_hw_i2c && |
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 6ddf31a2d34e..b265a8b95fe6 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h | |||
@@ -191,6 +191,7 @@ struct radeon_i2c_chan { | |||
191 | struct radeon_i2c_bus_rec rec; | 191 | struct radeon_i2c_bus_rec rec; |
192 | struct drm_dp_aux aux; | 192 | struct drm_dp_aux aux; |
193 | bool has_aux; | 193 | bool has_aux; |
194 | struct mutex mutex; | ||
194 | }; | 195 | }; |
195 | 196 | ||
196 | /* mostly for macs, but really any system without connector tables */ | 197 | /* mostly for macs, but really any system without connector tables */ |