History

Merge branch 'drm-nouveau-next' of git://anongit.freedesktop.org/git/nouveau/linux-2.6 into drm-next

more fixes for nouveau. * 'drm-nouveau-next' of git://anongit.freedesktop.org/git/nouveau/linux-2.6: drm/nouveau: resume display if any later suspend bits fail drm/nouveau: fix lock unbalance in nouveau_crtc_page_flip drm/nouveau: implement hooks for needed for drm vblank timestamping support drm/nouveau/disp: add a method to fetch info needed by drm vblank timestamping drm/nv50: fill in crtc mode struct members from crtc_mode_fixup

Dave Airlie committed 12 years ago

Commit ef64cf92 parents 279b9e0 f3980dc14 files · +244 −12Browse files

Unified · Split

14 files
  1. drivers/gpu/drm/nouveau/core/engine/disp/nv04.c +37 −1
  2. drivers/gpu/drm/nouveau/core/engine/disp/nv50.c +30 −0
  3. drivers/gpu/drm/nouveau/core/engine/disp/nv50.h +5 −2
  4. drivers/gpu/drm/nouveau/core/engine/disp/nv84.c +1 −0
  5. drivers/gpu/drm/nouveau/core/engine/disp/nv94.c +1 −0
  6. drivers/gpu/drm/nouveau/core/engine/disp/nva3.c +2 −1
  7. drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c +46 −1
  8. drivers/gpu/drm/nouveau/core/engine/disp/nve0.c +1 −1
  9. drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c +1 −1
  10. drivers/gpu/drm/nouveau/core/include/core/class.h +22 −0
  11. drivers/gpu/drm/nouveau/nouveau_display.c +81 −1
  12. drivers/gpu/drm/nouveau/nouveau_display.h +4 −0
  13. drivers/gpu/drm/nouveau/nouveau_drm.c +12 −4
  14. drivers/gpu/drm/nouveau/nv50_display.c +1 −0
drivers/gpu/drm/nouveau/core/engine/disp/nv04.c+37−1
@@ -31,9 +31,45 @@ struct nv04_disp_priv { · 30 unmodified lines
3131 struct nouveau_disp base;
3232 };
3333
34+static int
35+nv04_disp_scanoutpos(struct nouveau_object *object, u32 mthd,
36+ void *data, u32 size)
37+{
38+ struct nv04_disp_priv *priv = (void *)object->engine;
39+ struct nv04_display_scanoutpos *args = data;
40+ const int head = (mthd & NV04_DISP_MTHD_HEAD);
41+ u32 line;
42+
43+ if (size < sizeof(*args))
44+ return -EINVAL;
45+
46+ args->vblanks = nv_rd32(priv, 0x680800 + (head * 0x2000)) & 0xffff;
47+ args->vtotal = nv_rd32(priv, 0x680804 + (head * 0x2000)) & 0xffff;
48+ args->vblanke = args->vtotal - 1;
49+
50+ args->hblanks = nv_rd32(priv, 0x680820 + (head * 0x2000)) & 0xffff;
51+ args->htotal = nv_rd32(priv, 0x680824 + (head * 0x2000)) & 0xffff;
52+ args->hblanke = args->htotal - 1;
53+
54+ args->time[0] = ktime_to_ns(ktime_get());
55+ line = nv_rd32(priv, 0x600868 + (head * 0x2000));
56+ args->time[1] = ktime_to_ns(ktime_get());
57+ args->hline = (line & 0xffff0000) >> 16;
58+ args->vline = (line & 0x0000ffff);
59+ return 0;
60+}
61+
62+#define HEAD_MTHD(n) (n), (n) + 0x01
63+
64+static struct nouveau_omthds
65+nv04_disp_omthds[] = {
66+ { HEAD_MTHD(NV04_DISP_SCANOUTPOS), nv04_disp_scanoutpos },
67+ {}
68+};
69+
3470 static struct nouveau_oclass
3571 nv04_disp_sclass[] = {
36− { NV04_DISP_CLASS, &nouveau_object_ofuncs },
72+ { NV04_DISP_CLASS, &nouveau_object_ofuncs, nv04_disp_omthds },
3773 {},
3874 };
3975
drivers/gpu/drm/nouveau/core/engine/disp/nv50.c+30−0
@@ -541,6 +541,35 @@ nv50_disp_curs_ofuncs = { · 540 unmodified lines
541541 * Base display object
542542 ******************************************************************************/
543543
544+int
545+nv50_disp_base_scanoutpos(struct nouveau_object *object, u32 mthd,
546+ void *data, u32 size)
547+{
548+ struct nv50_disp_priv *priv = (void *)object->engine;
549+ struct nv04_display_scanoutpos *args = data;
550+ const int head = (mthd & NV50_DISP_MTHD_HEAD);
551+ u32 blanke, blanks, total;
552+
553+ if (size < sizeof(*args) || head >= priv->head.nr)
554+ return -EINVAL;
555+ blanke = nv_rd32(priv, 0x610aec + (head * 0x540));
556+ blanks = nv_rd32(priv, 0x610af4 + (head * 0x540));
557+ total = nv_rd32(priv, 0x610afc + (head * 0x540));
558+
559+ args->vblanke = (blanke & 0xffff0000) >> 16;
560+ args->hblanke = (blanke & 0x0000ffff);
561+ args->vblanks = (blanks & 0xffff0000) >> 16;
562+ args->hblanks = (blanks & 0x0000ffff);
563+ args->vtotal = ( total & 0xffff0000) >> 16;
564+ args->htotal = ( total & 0x0000ffff);
565+
566+ args->time[0] = ktime_to_ns(ktime_get());
567+ args->vline = nv_rd32(priv, 0x616340 + (head * 0x800)) & 0xffff;
568+ args->time[1] = ktime_to_ns(ktime_get()); /* vline read locks hline */
569+ args->hline = nv_rd32(priv, 0x616344 + (head * 0x800)) & 0xffff;
570+ return 0;
571+}
572+
544573 static void
545574 nv50_disp_base_vblank_enable(struct nouveau_event *event, int head)
546575 {
@@ -675,6 +704,7 @@ nv50_disp_base_ofuncs = { · 128 unmodified lines
675704
676705 static struct nouveau_omthds
677706 nv50_disp_base_omthds[] = {
707+ { HEAD_MTHD(NV50_DISP_SCANOUTPOS) , nv50_disp_base_scanoutpos },
678708 { SOR_MTHD(NV50_DISP_SOR_PWR) , nv50_sor_mthd },
679709 { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd },
680710 { DAC_MTHD(NV50_DISP_DAC_PWR) , nv50_dac_mthd },
drivers/gpu/drm/nouveau/core/engine/disp/nv50.h+5−2
@@ -43,6 +43,10 @@ struct nv50_disp_priv { · 42 unmodified lines
4343 } pior;
4444 };
4545
46+#define HEAD_MTHD(n) (n), (n) + 0x03
47+
48+int nv50_disp_base_scanoutpos(struct nouveau_object *, u32, void *, u32);
49+
4650 #define DAC_MTHD(n) (n), (n) + 0x03
4751
4852 int nv50_dac_mthd(struct nouveau_object *, u32, void *, u32);
@@ -132,13 +136,12 @@ void nv50_disp_intr(struct nouveau_subdev *); · 83 unmodified lines
132136
133137 extern struct nouveau_omthds nv84_disp_base_omthds[];
134138
135−extern struct nouveau_omthds nva3_disp_base_omthds[];
136−
137139 extern struct nouveau_ofuncs nvd0_disp_mast_ofuncs;
138140 extern struct nouveau_ofuncs nvd0_disp_sync_ofuncs;
139141 extern struct nouveau_ofuncs nvd0_disp_ovly_ofuncs;
140142 extern struct nouveau_ofuncs nvd0_disp_oimm_ofuncs;
141143 extern struct nouveau_ofuncs nvd0_disp_curs_ofuncs;
144+extern struct nouveau_omthds nvd0_disp_base_omthds[];
142145 extern struct nouveau_ofuncs nvd0_disp_base_ofuncs;
143146 extern struct nouveau_oclass nvd0_disp_cclass;
144147 void nvd0_disp_intr_supervisor(struct work_struct *);
drivers/gpu/drm/nouveau/core/engine/disp/nv84.c+1−0
@@ -41,6 +41,7 @@ nv84_disp_sclass[] = { · 40 unmodified lines
4141
4242 struct nouveau_omthds
4343 nv84_disp_base_omthds[] = {
44+ { HEAD_MTHD(NV50_DISP_SCANOUTPOS) , nv50_disp_base_scanoutpos },
4445 { SOR_MTHD(NV50_DISP_SOR_PWR) , nv50_sor_mthd },
4546 { SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd },
4647 { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd },
drivers/gpu/drm/nouveau/core/engine/disp/nv94.c+1−0
@@ -41,6 +41,7 @@ nv94_disp_sclass[] = { · 40 unmodified lines
4141
4242 static struct nouveau_omthds
4343 nv94_disp_base_omthds[] = {
44+ { HEAD_MTHD(NV50_DISP_SCANOUTPOS) , nv50_disp_base_scanoutpos },
4445 { SOR_MTHD(NV50_DISP_SOR_PWR) , nv50_sor_mthd },
4546 { SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd },
4647 { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd },
drivers/gpu/drm/nouveau/core/engine/disp/nva3.c+2−1
@@ -39,8 +39,9 @@ nva3_disp_sclass[] = { · 38 unmodified lines
3939 {}
4040 };
4141
42−struct nouveau_omthds
42+static struct nouveau_omthds
4343 nva3_disp_base_omthds[] = {
44+ { HEAD_MTHD(NV50_DISP_SCANOUTPOS) , nv50_disp_base_scanoutpos },
4445 { SOR_MTHD(NV50_DISP_SOR_PWR) , nv50_sor_mthd },
4546 { SOR_MTHD(NVA3_DISP_SOR_HDA_ELD) , nv50_sor_mthd },
4647 { SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd },
drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c+46−1
@@ -440,6 +440,36 @@ nvd0_disp_curs_ofuncs = { · 439 unmodified lines
440440 * Base display object
441441 ******************************************************************************/
442442
443+static int
444+nvd0_disp_base_scanoutpos(struct nouveau_object *object, u32 mthd,
445+ void *data, u32 size)
446+{
447+ struct nv50_disp_priv *priv = (void *)object->engine;
448+ struct nv04_display_scanoutpos *args = data;
449+ const int head = (mthd & NV50_DISP_MTHD_HEAD);
450+ u32 blanke, blanks, total;
451+
452+ if (size < sizeof(*args) || head >= priv->head.nr)
453+ return -EINVAL;
454+
455+ total = nv_rd32(priv, 0x640414 + (head * 0x300));
456+ blanke = nv_rd32(priv, 0x64041c + (head * 0x300));
457+ blanks = nv_rd32(priv, 0x640420 + (head * 0x300));
458+
459+ args->vblanke = (blanke & 0xffff0000) >> 16;
460+ args->hblanke = (blanke & 0x0000ffff);
461+ args->vblanks = (blanks & 0xffff0000) >> 16;
462+ args->hblanks = (blanks & 0x0000ffff);
463+ args->vtotal = ( total & 0xffff0000) >> 16;
464+ args->htotal = ( total & 0x0000ffff);
465+
466+ args->time[0] = ktime_to_ns(ktime_get());
467+ args->vline = nv_rd32(priv, 0x616340 + (head * 0x800)) & 0xffff;
468+ args->time[1] = ktime_to_ns(ktime_get()); /* vline read locks hline */
469+ args->hline = nv_rd32(priv, 0x616344 + (head * 0x800)) & 0xffff;
470+ return 0;
471+}
472+
443473 static void
444474 nvd0_disp_base_vblank_enable(struct nouveau_event *event, int head)
445475 {
@@ -573,9 +603,24 @@ nvd0_disp_base_ofuncs = { · 127 unmodified lines
573603 .fini = nvd0_disp_base_fini,
574604 };
575605
606+struct nouveau_omthds
607+nvd0_disp_base_omthds[] = {
608+ { HEAD_MTHD(NV50_DISP_SCANOUTPOS) , nvd0_disp_base_scanoutpos },
609+ { SOR_MTHD(NV50_DISP_SOR_PWR) , nv50_sor_mthd },
610+ { SOR_MTHD(NVA3_DISP_SOR_HDA_ELD) , nv50_sor_mthd },
611+ { SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd },
612+ { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd },
613+ { DAC_MTHD(NV50_DISP_DAC_PWR) , nv50_dac_mthd },
614+ { DAC_MTHD(NV50_DISP_DAC_LOAD) , nv50_dac_mthd },
615+ { PIOR_MTHD(NV50_DISP_PIOR_PWR) , nv50_pior_mthd },
616+ { PIOR_MTHD(NV50_DISP_PIOR_TMDS_PWR) , nv50_pior_mthd },
617+ { PIOR_MTHD(NV50_DISP_PIOR_DP_PWR) , nv50_pior_mthd },
618+ {},
619+};
620+
576621 static struct nouveau_oclass
577622 nvd0_disp_base_oclass[] = {
578− { NVD0_DISP_CLASS, &nvd0_disp_base_ofuncs, nva3_disp_base_omthds },
623+ { NVD0_DISP_CLASS, &nvd0_disp_base_ofuncs, nvd0_disp_base_omthds },
579624 {}
580625 };
581626
drivers/gpu/drm/nouveau/core/engine/disp/nve0.c+1−1
@@ -41,7 +41,7 @@ nve0_disp_sclass[] = { · 40 unmodified lines
4141
4242 static struct nouveau_oclass
4343 nve0_disp_base_oclass[] = {
44− { NVE0_DISP_CLASS, &nvd0_disp_base_ofuncs, nva3_disp_base_omthds },
44+ { NVE0_DISP_CLASS, &nvd0_disp_base_ofuncs, nvd0_disp_base_omthds },
4545 {}
4646 };
4747
drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c+1−1
@@ -41,7 +41,7 @@ nvf0_disp_sclass[] = { · 40 unmodified lines
4141
4242 static struct nouveau_oclass
4343 nvf0_disp_base_oclass[] = {
44− { NVF0_DISP_CLASS, &nvd0_disp_base_ofuncs, nva3_disp_base_omthds },
44+ { NVF0_DISP_CLASS, &nvd0_disp_base_ofuncs, nvd0_disp_base_omthds },
4545 {}
4646 };
4747
drivers/gpu/drm/nouveau/core/include/core/class.h+22−0
@@ -230,9 +230,26 @@ struct nve0_channel_ind_class { · 229 unmodified lines
230230
231231 #define NV04_DISP_CLASS 0x00000046
232232
233+#define NV04_DISP_MTHD 0x00000000
234+#define NV04_DISP_MTHD_HEAD 0x00000001
235+
236+#define NV04_DISP_SCANOUTPOS 0x00000000
237+
233238 struct nv04_display_class {
234239 };
235240
241+struct nv04_display_scanoutpos {
242+ s64 time[2];
243+ u32 vblanks;
244+ u32 vblanke;
245+ u32 vtotal;
246+ u32 vline;
247+ u32 hblanks;
248+ u32 hblanke;
249+ u32 htotal;
250+ u32 hline;
251+};
252+
236253 /* 5070: NV50_DISP
237254 * 8270: NV84_DISP
238255 * 8370: NVA0_DISP
@@ -252,6 +269,11 @@ struct nv04_display_class { · 13 unmodified lines
252269 #define NVE0_DISP_CLASS 0x00009170
253270 #define NVF0_DISP_CLASS 0x00009270
254271
272+#define NV50_DISP_MTHD 0x00000000
273+#define NV50_DISP_MTHD_HEAD 0x00000003
274+
275+#define NV50_DISP_SCANOUTPOS 0x00000000
276+
255277 #define NV50_DISP_SOR_MTHD 0x00010000
256278 #define NV50_DISP_SOR_MTHD_TYPE 0x0000f000
257279 #define NV50_DISP_SOR_MTHD_HEAD 0x00000018
drivers/gpu/drm/nouveau/nouveau_display.c+81−1
@@ -68,6 +68,86 @@ nouveau_display_vblank_disable(struct drm_device *dev, int head) · 67 unmodified lines
6868 nouveau_event_put(disp->vblank[head]);
6969 }
7070
71+static inline int
72+calc(int blanks, int blanke, int total, int line)
73+{
74+ if (blanke >= blanks) {
75+ if (line >= blanks)
76+ line -= total;
77+ } else {
78+ if (line >= blanks)
79+ line -= total;
80+ line -= blanke + 1;
81+ }
82+ return line;
83+}
84+
85+int
86+nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos,
87+ ktime_t *stime, ktime_t *etime)
88+{
89+ const u32 mthd = NV04_DISP_SCANOUTPOS + nouveau_crtc(crtc)->index;
90+ struct nouveau_display *disp = nouveau_display(crtc->dev);
91+ struct nv04_display_scanoutpos args;
92+ int ret, retry = 1;
93+
94+ do {
95+ ret = nv_exec(disp->core, mthd, &args, sizeof(args));
96+ if (ret != 0)
97+ return 0;
98+
99+ if (args.vline) {
100+ ret |= DRM_SCANOUTPOS_ACCURATE;
101+ ret |= DRM_SCANOUTPOS_VALID;
102+ break;
103+ }
104+
105+ if (retry) ndelay(crtc->linedur_ns);
106+ } while (retry--);
107+
108+ *hpos = calc(args.hblanks, args.hblanke, args.htotal, args.hline);
109+ *vpos = calc(args.vblanks, args.vblanke, args.vtotal, args.vline);
110+ if (stime) *stime = ns_to_ktime(args.time[0]);
111+ if (etime) *etime = ns_to_ktime(args.time[1]);
112+
113+ if (*vpos < 0)
114+ ret |= DRM_SCANOUTPOS_INVBL;
115+ return ret;
116+}
117+
118+int
119+nouveau_display_scanoutpos(struct drm_device *dev, int head, unsigned int flags,
120+ int *vpos, int *hpos, ktime_t *stime, ktime_t *etime)
121+{
122+ struct drm_crtc *crtc;
123+
124+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
125+ if (nouveau_crtc(crtc)->index == head) {
126+ return nouveau_display_scanoutpos_head(crtc, vpos, hpos,
127+ stime, etime);
128+ }
129+ }
130+
131+ return 0;
132+}
133+
134+int
135+nouveau_display_vblstamp(struct drm_device *dev, int head, int *max_error,
136+ struct timeval *time, unsigned flags)
137+{
138+ struct drm_crtc *crtc;
139+
140+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
141+ if (nouveau_crtc(crtc)->index == head) {
142+ return drm_calc_vbltimestamp_from_scanoutpos(dev,
143+ head, max_error, time, flags, crtc,
144+ &crtc->hwmode);
145+ }
146+ }
147+
148+ return -EINVAL;
149+}
150+
71151 static void
72152 nouveau_display_vblank_fini(struct drm_device *dev)
73153 {
@@ -642,7 +722,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, · 568 unmodified lines
642722 ret = nouveau_fence_sync(fence, chan);
643723 nouveau_fence_unref(&fence);
644724 if (ret)
645− goto fail_free;
725+ goto fail_unpin;
646726
647727 ret = ttm_bo_reserve(&old_bo->bo, true, false, false, NULL);
648728 if (ret)
drivers/gpu/drm/nouveau/nouveau_display.h+4−0
@@ -64,6 +64,10 @@ void nouveau_display_repin(struct drm_device *dev); · 63 unmodified lines
6464 void nouveau_display_resume(struct drm_device *dev);
6565 int nouveau_display_vblank_enable(struct drm_device *, int);
6666 void nouveau_display_vblank_disable(struct drm_device *, int);
67+int nouveau_display_scanoutpos(struct drm_device *, int, unsigned int,
68+ int *, int *, ktime_t *, ktime_t *);
69+int nouveau_display_vblstamp(struct drm_device *, int, int *,
70+ struct timeval *, unsigned);
6771
6872 int nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
6973 struct drm_pending_vblank_event *event,
drivers/gpu/drm/nouveau/nouveau_drm.c+12−4
@@ -503,19 +503,21 @@ nouveau_do_suspend(struct drm_device *dev) · 502 unmodified lines
503503 if (drm->cechan) {
504504 ret = nouveau_channel_idle(drm->cechan);
505505 if (ret)
506− return ret;
506+ goto fail_display;
507507 }
508508
509509 if (drm->channel) {
510510 ret = nouveau_channel_idle(drm->channel);
511511 if (ret)
512− return ret;
512+ goto fail_display;
513513 }
514514
515515 NV_INFO(drm, "suspending client object trees...\n");
516516 if (drm->fence && nouveau_fence(drm)->suspend) {
517− if (!nouveau_fence(drm)->suspend(drm))
518− return -ENOMEM;
517+ if (!nouveau_fence(drm)->suspend(drm)) {
518+ ret = -ENOMEM;
519+ goto fail_display;
520+ }
519521 }
520522
521523 list_for_each_entry(cli, &drm->clients, head) {
@@ -537,6 +539,10 @@ fail_client: · 15 unmodified lines
537539 nouveau_client_init(&cli->base);
538540 }
539541
542+ if (drm->fence && nouveau_fence(drm)->resume)
543+ nouveau_fence(drm)->resume(drm);
544+
545+fail_display:
540546 if (dev->mode_config.num_crtc) {
541547 NV_INFO(drm, "resuming display...\n");
542548 nouveau_display_resume(dev);
@@ -798,6 +804,8 @@ driver = { · 255 unmodified lines
798804 .get_vblank_counter = drm_vblank_count,
799805 .enable_vblank = nouveau_display_vblank_enable,
800806 .disable_vblank = nouveau_display_vblank_disable,
807+ .get_scanout_position = nouveau_display_scanoutpos,
808+ .get_vblank_timestamp = nouveau_display_vblstamp,
801809
802810 .ioctls = nouveau_ioctls,
803811 .num_ioctls = ARRAY_SIZE(nouveau_ioctls),
drivers/gpu/drm/nouveau/nv50_display.c+1−0
@@ -1035,6 +1035,7 @@ static bool · 1034 unmodified lines
10351035 nv50_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode,
10361036 struct drm_display_mode *adjusted_mode)
10371037 {
1038+ drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);
10381039 return true;
10391040 }
10401041