diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2011-07-01 01:51:49 -0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2011-09-20 02:09:42 -0400 |
commit | 46959b7790e3609e795c3b5e70e58dcd22c9e207 (patch) | |
tree | 0f287b3800a232ce45684a84c2fadee21154a3d4 /drivers/gpu/drm/nouveau/nouveau_dp.c | |
parent | 43720133888f3713b534aec520783498f1bf5db3 (diff) |
drm/nouveau/dp: remove reliance on vbios for native displayport
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_dp.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_dp.c | 111 |
1 files changed, 110 insertions, 1 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c index f8ebd09ee3a6..ae1b6e00bd96 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dp.c +++ b/drivers/gpu/drm/nouveau/nouveau_dp.c | |||
@@ -194,6 +194,116 @@ auxch_wr(struct drm_encoder *encoder, int address, uint8_t *buf, int size) | |||
194 | return ret; | 194 | return ret; |
195 | } | 195 | } |
196 | 196 | ||
197 | static u32 | ||
198 | dp_link_bw_get(struct drm_device *dev, int or, int link) | ||
199 | { | ||
200 | u32 ctrl = nv_rd32(dev, 0x614300 + (or * 0x800)); | ||
201 | if (!(ctrl & 0x000c0000)) | ||
202 | return 162000; | ||
203 | return 270000; | ||
204 | } | ||
205 | |||
206 | static int | ||
207 | dp_lane_count_get(struct drm_device *dev, int or, int link) | ||
208 | { | ||
209 | u32 ctrl = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link)); | ||
210 | switch (ctrl & 0x000f0000) { | ||
211 | case 0x00010000: return 1; | ||
212 | case 0x00030000: return 2; | ||
213 | default: | ||
214 | return 4; | ||
215 | } | ||
216 | } | ||
217 | |||
218 | void | ||
219 | nouveau_dp_tu_update(struct drm_device *dev, int or, int link, u32 clk, u32 bpp) | ||
220 | { | ||
221 | const u32 symbol = 100000; | ||
222 | int bestTU = 0, bestVTUi = 0, bestVTUf = 0, bestVTUa = 0; | ||
223 | int TU, VTUi, VTUf, VTUa; | ||
224 | u64 link_data_rate, link_ratio, unk; | ||
225 | u32 best_diff = 64 * symbol; | ||
226 | u32 link_nr, link_bw, r; | ||
227 | |||
228 | /* calculate packed data rate for each lane */ | ||
229 | link_nr = dp_lane_count_get(dev, or, link); | ||
230 | link_data_rate = (clk * bpp / 8) / link_nr; | ||
231 | |||
232 | /* calculate ratio of packed data rate to link symbol rate */ | ||
233 | link_bw = dp_link_bw_get(dev, or, link); | ||
234 | link_ratio = link_data_rate * symbol; | ||
235 | r = do_div(link_ratio, link_bw); | ||
236 | |||
237 | for (TU = 64; TU >= 32; TU--) { | ||
238 | /* calculate average number of valid symbols in each TU */ | ||
239 | u32 tu_valid = link_ratio * TU; | ||
240 | u32 calc, diff; | ||
241 | |||
242 | /* find a hw representation for the fraction.. */ | ||
243 | VTUi = tu_valid / symbol; | ||
244 | calc = VTUi * symbol; | ||
245 | diff = tu_valid - calc; | ||
246 | if (diff) { | ||
247 | if (diff >= (symbol / 2)) { | ||
248 | VTUf = symbol / (symbol - diff); | ||
249 | if (symbol - (VTUf * diff)) | ||
250 | VTUf++; | ||
251 | |||
252 | if (VTUf <= 15) { | ||
253 | VTUa = 1; | ||
254 | calc += symbol - (symbol / VTUf); | ||
255 | } else { | ||
256 | VTUa = 0; | ||
257 | VTUf = 1; | ||
258 | calc += symbol; | ||
259 | } | ||
260 | } else { | ||
261 | VTUa = 0; | ||
262 | VTUf = min((int)(symbol / diff), 15); | ||
263 | calc += symbol / VTUf; | ||
264 | } | ||
265 | |||
266 | diff = calc - tu_valid; | ||
267 | } else { | ||
268 | /* no remainder, but the hw doesn't like the fractional | ||
269 | * part to be zero. decrement the integer part and | ||
270 | * have the fraction add a whole symbol back | ||
271 | */ | ||
272 | VTUa = 0; | ||
273 | VTUf = 1; | ||
274 | VTUi--; | ||
275 | } | ||
276 | |||
277 | if (diff < best_diff) { | ||
278 | best_diff = diff; | ||
279 | bestTU = TU; | ||
280 | bestVTUa = VTUa; | ||
281 | bestVTUf = VTUf; | ||
282 | bestVTUi = VTUi; | ||
283 | if (diff == 0) | ||
284 | break; | ||
285 | } | ||
286 | } | ||
287 | |||
288 | if (!bestTU) { | ||
289 | NV_ERROR(dev, "DP: unable to find suitable config\n"); | ||
290 | return; | ||
291 | } | ||
292 | |||
293 | /* XXX close to vbios numbers, but not right */ | ||
294 | unk = (symbol - link_ratio) * bestTU; | ||
295 | unk *= link_ratio; | ||
296 | r = do_div(unk, symbol); | ||
297 | r = do_div(unk, symbol); | ||
298 | unk += 6; | ||
299 | |||
300 | nv_mask(dev, NV50_SOR_DP_CTRL(or, link), 0x000001fc, bestTU << 2); | ||
301 | nv_mask(dev, NV50_SOR_DP_SCFG(or, link), 0x010f7f3f, bestVTUa << 24 | | ||
302 | bestVTUf << 16 | | ||
303 | bestVTUi << 8 | | ||
304 | unk); | ||
305 | } | ||
306 | |||
197 | static int | 307 | static int |
198 | nouveau_dp_lane_count_set(struct drm_encoder *encoder, uint8_t cmd) | 308 | nouveau_dp_lane_count_set(struct drm_encoder *encoder, uint8_t cmd) |
199 | { | 309 | { |
@@ -617,7 +727,6 @@ static int | |||
617 | nouveau_dp_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) | 727 | nouveau_dp_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) |
618 | { | 728 | { |
619 | struct nouveau_i2c_chan *auxch = (struct nouveau_i2c_chan *)adap; | 729 | struct nouveau_i2c_chan *auxch = (struct nouveau_i2c_chan *)adap; |
620 | struct drm_device *dev = auxch->dev; | ||
621 | struct i2c_msg *msg = msgs; | 730 | struct i2c_msg *msg = msgs; |
622 | int ret, mcnt = num; | 731 | int ret, mcnt = num; |
623 | 732 | ||