aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm
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
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')
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_dp.c111
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.h1
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_encoder.h3
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_reg.h2
-rw-r--r--drivers/gpu/drm/nouveau/nv50_display.c39
-rw-r--r--drivers/gpu/drm/nouveau/nv50_sor.c33
6 files changed, 126 insertions, 63 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
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index bc035c4f42a8..ee0f0d129d3e 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -1101,6 +1101,7 @@ int nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr,
1101 uint8_t *data, int data_nr); 1101 uint8_t *data, int data_nr);
1102bool nouveau_dp_detect(struct drm_encoder *); 1102bool nouveau_dp_detect(struct drm_encoder *);
1103bool nouveau_dp_link_train(struct drm_encoder *); 1103bool nouveau_dp_link_train(struct drm_encoder *);
1104void nouveau_dp_tu_update(struct drm_device *, int, int, u32, u32);
1104 1105
1105/* nv04_fb.c */ 1106/* nv04_fb.c */
1106extern int nv04_fb_init(struct drm_device *); 1107extern int nv04_fb_init(struct drm_device *);
diff --git a/drivers/gpu/drm/nouveau/nouveau_encoder.h b/drivers/gpu/drm/nouveau/nouveau_encoder.h
index ae69b61d93db..2bb316d2421c 100644
--- a/drivers/gpu/drm/nouveau/nouveau_encoder.h
+++ b/drivers/gpu/drm/nouveau/nouveau_encoder.h
@@ -49,9 +49,6 @@ struct nouveau_encoder {
49 49
50 union { 50 union {
51 struct { 51 struct {
52 int mc_unknown;
53 uint32_t unk0;
54 uint32_t unk1;
55 int dpcd_version; 52 int dpcd_version;
56 int link_nr; 53 int link_nr;
57 int link_bw; 54 int link_bw;
diff --git a/drivers/gpu/drm/nouveau/nouveau_reg.h b/drivers/gpu/drm/nouveau/nouveau_reg.h
index f18cdfc3400f..d9632ae38c6c 100644
--- a/drivers/gpu/drm/nouveau/nouveau_reg.h
+++ b/drivers/gpu/drm/nouveau/nouveau_reg.h
@@ -843,7 +843,7 @@
843#define NV50_SOR_DP_CTRL_TRAINING_PATTERN_2 0x02000000 843#define NV50_SOR_DP_CTRL_TRAINING_PATTERN_2 0x02000000
844#define NV50_SOR_DP_UNK118(i, l) (0x0061c118 + (i) * 0x800 + (l) * 0x80) 844#define NV50_SOR_DP_UNK118(i, l) (0x0061c118 + (i) * 0x800 + (l) * 0x80)
845#define NV50_SOR_DP_UNK120(i, l) (0x0061c120 + (i) * 0x800 + (l) * 0x80) 845#define NV50_SOR_DP_UNK120(i, l) (0x0061c120 + (i) * 0x800 + (l) * 0x80)
846#define NV50_SOR_DP_UNK128(i, l) (0x0061c128 + (i) * 0x800 + (l) * 0x80) 846#define NV50_SOR_DP_SCFG(i, l) (0x0061c128 + (i) * 0x800 + (l) * 0x80)
847#define NV50_SOR_DP_UNK130(i, l) (0x0061c130 + (i) * 0x800 + (l) * 0x80) 847#define NV50_SOR_DP_UNK130(i, l) (0x0061c130 + (i) * 0x800 + (l) * 0x80)
848 848
849#define NV50_PDISPLAY_USER(i) ((i) * 0x1000 + 0x00640000) 849#define NV50_PDISPLAY_USER(i) ((i) * 0x1000 + 0x00640000)
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index 8260303c2fca..d23ca00e7d62 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -702,37 +702,6 @@ ack:
702} 702}
703 703
704static void 704static void
705nv50_display_unk20_dp_hack(struct drm_device *dev, struct dcb_entry *dcb)
706{
707 int or = ffs(dcb->or) - 1, link = !(dcb->dpconf.sor.link & 1);
708 struct drm_encoder *encoder;
709 uint32_t tmp, unk0 = 0, unk1 = 0;
710
711 if (dcb->type != OUTPUT_DP)
712 return;
713
714 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
715 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
716
717 if (nv_encoder->dcb == dcb) {
718 unk0 = nv_encoder->dp.unk0;
719 unk1 = nv_encoder->dp.unk1;
720 break;
721 }
722 }
723
724 if (unk0 || unk1) {
725 tmp = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link));
726 tmp &= 0xfffffe03;
727 nv_wr32(dev, NV50_SOR_DP_CTRL(or, link), tmp | unk0);
728
729 tmp = nv_rd32(dev, NV50_SOR_DP_UNK128(or, link));
730 tmp &= 0xfef080c0;
731 nv_wr32(dev, NV50_SOR_DP_UNK128(or, link), tmp | unk1);
732 }
733}
734
735static void
736nv50_display_unk20_handler(struct drm_device *dev) 705nv50_display_unk20_handler(struct drm_device *dev)
737{ 706{
738 struct drm_nouveau_private *dev_priv = dev->dev_private; 707 struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -830,7 +799,13 @@ nv50_display_unk20_handler(struct drm_device *dev)
830 script = nv50_display_script_select(dev, dcb, mc, pclk); 799 script = nv50_display_script_select(dev, dcb, mc, pclk);
831 nouveau_bios_run_display_table(dev, script, pclk, dcb, -1); 800 nouveau_bios_run_display_table(dev, script, pclk, dcb, -1);
832 801
833 nv50_display_unk20_dp_hack(dev, dcb); 802 if (type == OUTPUT_DP) {
803 int link = !(dcb->dpconf.sor.link & 1);
804 if ((mc & 0x000f0000) == 0x00020000)
805 nouveau_dp_tu_update(dev, or, link, pclk, 18);
806 else
807 nouveau_dp_tu_update(dev, or, link, pclk, 24);
808 }
834 809
835 if (dcb->type != OUTPUT_ANALOG) { 810 if (dcb->type != OUTPUT_ANALOG) {
836 tmp = nv_rd32(dev, NV50_PDISPLAY_SOR_CLK_CTRL2(or)); 811 tmp = nv_rd32(dev, NV50_PDISPLAY_SOR_CLK_CTRL2(or));
diff --git a/drivers/gpu/drm/nouveau/nv50_sor.c b/drivers/gpu/drm/nouveau/nv50_sor.c
index ffe8b483b7b0..f359f94626c2 100644
--- a/drivers/gpu/drm/nouveau/nv50_sor.c
+++ b/drivers/gpu/drm/nouveau/nv50_sor.c
@@ -187,6 +187,7 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
187 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); 187 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
188 struct drm_device *dev = encoder->dev; 188 struct drm_device *dev = encoder->dev;
189 struct nouveau_crtc *crtc = nouveau_crtc(encoder->crtc); 189 struct nouveau_crtc *crtc = nouveau_crtc(encoder->crtc);
190 struct nouveau_connector *nv_connector;
190 uint32_t mode_ctl = 0; 191 uint32_t mode_ctl = 0;
191 int ret; 192 int ret;
192 193
@@ -206,7 +207,12 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
206 mode_ctl = 0x0200; 207 mode_ctl = 0x0200;
207 break; 208 break;
208 case OUTPUT_DP: 209 case OUTPUT_DP:
209 mode_ctl |= (nv_encoder->dp.mc_unknown << 16); 210 nv_connector = nouveau_encoder_connector_get(nv_encoder);
211 if (nv_connector && nv_connector->base.display_info.bpc == 6)
212 mode_ctl |= 0x00020000;
213 else
214 mode_ctl |= 0x00050000;
215
210 if (nv_encoder->dcb->sorconf.link & 1) 216 if (nv_encoder->dcb->sorconf.link & 1)
211 mode_ctl |= 0x00000800; 217 mode_ctl |= 0x00000800;
212 else 218 else
@@ -313,31 +319,6 @@ nv50_sor_create(struct drm_connector *connector, struct dcb_entry *entry)
313 encoder->possible_crtcs = entry->heads; 319 encoder->possible_crtcs = entry->heads;
314 encoder->possible_clones = 0; 320 encoder->possible_clones = 0;
315 321
316 if (nv_encoder->dcb->type == OUTPUT_DP) {
317 int or = nv_encoder->or, link = !(entry->dpconf.sor.link & 1);
318 uint32_t tmp;
319
320 tmp = nv_rd32(dev, 0x61c700 + (or * 0x800));
321 if (!tmp)
322 tmp = nv_rd32(dev, 0x610798 + (or * 8));
323
324 switch ((tmp & 0x00000f00) >> 8) {
325 case 8:
326 case 9:
327 nv_encoder->dp.mc_unknown = (tmp & 0x000f0000) >> 16;
328 tmp = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link));
329 nv_encoder->dp.unk0 = tmp & 0x000001fc;
330 tmp = nv_rd32(dev, NV50_SOR_DP_UNK128(or, link));
331 nv_encoder->dp.unk1 = tmp & 0x010f7f3f;
332 break;
333 default:
334 break;
335 }
336
337 if (!nv_encoder->dp.mc_unknown)
338 nv_encoder->dp.mc_unknown = 5;
339 }
340
341 drm_mode_connector_attach_encoder(connector, encoder); 322 drm_mode_connector_attach_encoder(connector, encoder);
342 return 0; 323 return 0;
343} 324}