aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/nouveau_dp.c
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2011-07-01 01:51:49 -0400
committerBen Skeggs <bskeggs@redhat.com>2011-09-20 02:09:42 -0400
commit46959b7790e3609e795c3b5e70e58dcd22c9e207 (patch)
tree0f287b3800a232ce45684a84c2fadee21154a3d4 /drivers/gpu/drm/nouveau/nouveau_dp.c
parent43720133888f3713b534aec520783498f1bf5db3 (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.c111
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
197static u32
198dp_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
206static int
207dp_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
218void
219nouveau_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
197static int 307static int
198nouveau_dp_lane_count_set(struct drm_encoder *encoder, uint8_t cmd) 308nouveau_dp_lane_count_set(struct drm_encoder *encoder, uint8_t cmd)
199{ 309{
@@ -617,7 +727,6 @@ static int
617nouveau_dp_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) 727nouveau_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