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
Unified · Split
| @@ -31,9 +31,45 @@ struct nv04_disp_priv { · 30 unmodified lines | ||
| 31 | 31 | struct nouveau_disp base; |
| 32 | 32 | }; |
| 33 | 33 | |
| 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 | + | |
| 34 | 70 | static struct nouveau_oclass |
| 35 | 71 | nv04_disp_sclass[] = { |
| 36 | − { NV04_DISP_CLASS, &nouveau_object_ofuncs }, | |
| 72 | + { NV04_DISP_CLASS, &nouveau_object_ofuncs, nv04_disp_omthds }, | |
| 37 | 73 | {}, |
| 38 | 74 | }; |
| 39 | 75 | |
| @@ -541,6 +541,35 @@ nv50_disp_curs_ofuncs = { · 540 unmodified lines | ||
| 541 | 541 | * Base display object |
| 542 | 542 | ******************************************************************************/ |
| 543 | 543 | |
| 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 | + | |
| 544 | 573 | static void |
| 545 | 574 | nv50_disp_base_vblank_enable(struct nouveau_event *event, int head) |
| 546 | 575 | { |
| @@ -675,6 +704,7 @@ nv50_disp_base_ofuncs = { · 128 unmodified lines | ||
| 675 | 704 | |
| 676 | 705 | static struct nouveau_omthds |
| 677 | 706 | nv50_disp_base_omthds[] = { |
| 707 | + { HEAD_MTHD(NV50_DISP_SCANOUTPOS) , nv50_disp_base_scanoutpos }, | |
| 678 | 708 | { SOR_MTHD(NV50_DISP_SOR_PWR) , nv50_sor_mthd }, |
| 679 | 709 | { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd }, |
| 680 | 710 | { DAC_MTHD(NV50_DISP_DAC_PWR) , nv50_dac_mthd }, |
| @@ -43,6 +43,10 @@ struct nv50_disp_priv { · 42 unmodified lines | ||
| 43 | 43 | } pior; |
| 44 | 44 | }; |
| 45 | 45 | |
| 46 | +#define HEAD_MTHD(n) (n), (n) + 0x03 | |
| 47 | + | |
| 48 | +int nv50_disp_base_scanoutpos(struct nouveau_object *, u32, void *, u32); | |
| 49 | + | |
| 46 | 50 | #define DAC_MTHD(n) (n), (n) + 0x03 |
| 47 | 51 | |
| 48 | 52 | int nv50_dac_mthd(struct nouveau_object *, u32, void *, u32); |
| @@ -132,13 +136,12 @@ void nv50_disp_intr(struct nouveau_subdev *); · 83 unmodified lines | ||
| 132 | 136 | |
| 133 | 137 | extern struct nouveau_omthds nv84_disp_base_omthds[]; |
| 134 | 138 | |
| 135 | −extern struct nouveau_omthds nva3_disp_base_omthds[]; | |
| 136 | − | |
| 137 | 139 | extern struct nouveau_ofuncs nvd0_disp_mast_ofuncs; |
| 138 | 140 | extern struct nouveau_ofuncs nvd0_disp_sync_ofuncs; |
| 139 | 141 | extern struct nouveau_ofuncs nvd0_disp_ovly_ofuncs; |
| 140 | 142 | extern struct nouveau_ofuncs nvd0_disp_oimm_ofuncs; |
| 141 | 143 | extern struct nouveau_ofuncs nvd0_disp_curs_ofuncs; |
| 144 | +extern struct nouveau_omthds nvd0_disp_base_omthds[]; | |
| 142 | 145 | extern struct nouveau_ofuncs nvd0_disp_base_ofuncs; |
| 143 | 146 | extern struct nouveau_oclass nvd0_disp_cclass; |
| 144 | 147 | void nvd0_disp_intr_supervisor(struct work_struct *); |
| @@ -41,6 +41,7 @@ nv84_disp_sclass[] = { · 40 unmodified lines | ||
| 41 | 41 | |
| 42 | 42 | struct nouveau_omthds |
| 43 | 43 | nv84_disp_base_omthds[] = { |
| 44 | + { HEAD_MTHD(NV50_DISP_SCANOUTPOS) , nv50_disp_base_scanoutpos }, | |
| 44 | 45 | { SOR_MTHD(NV50_DISP_SOR_PWR) , nv50_sor_mthd }, |
| 45 | 46 | { SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd }, |
| 46 | 47 | { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd }, |
| @@ -41,6 +41,7 @@ nv94_disp_sclass[] = { · 40 unmodified lines | ||
| 41 | 41 | |
| 42 | 42 | static struct nouveau_omthds |
| 43 | 43 | nv94_disp_base_omthds[] = { |
| 44 | + { HEAD_MTHD(NV50_DISP_SCANOUTPOS) , nv50_disp_base_scanoutpos }, | |
| 44 | 45 | { SOR_MTHD(NV50_DISP_SOR_PWR) , nv50_sor_mthd }, |
| 45 | 46 | { SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd }, |
| 46 | 47 | { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd }, |
| @@ -39,8 +39,9 @@ nva3_disp_sclass[] = { · 38 unmodified lines | ||
| 39 | 39 | {} |
| 40 | 40 | }; |
| 41 | 41 | |
| 42 | −struct nouveau_omthds | |
| 42 | +static struct nouveau_omthds | |
| 43 | 43 | nva3_disp_base_omthds[] = { |
| 44 | + { HEAD_MTHD(NV50_DISP_SCANOUTPOS) , nv50_disp_base_scanoutpos }, | |
| 44 | 45 | { SOR_MTHD(NV50_DISP_SOR_PWR) , nv50_sor_mthd }, |
| 45 | 46 | { SOR_MTHD(NVA3_DISP_SOR_HDA_ELD) , nv50_sor_mthd }, |
| 46 | 47 | { SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd }, |
| @@ -440,6 +440,36 @@ nvd0_disp_curs_ofuncs = { · 439 unmodified lines | ||
| 440 | 440 | * Base display object |
| 441 | 441 | ******************************************************************************/ |
| 442 | 442 | |
| 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 | + | |
| 443 | 473 | static void |
| 444 | 474 | nvd0_disp_base_vblank_enable(struct nouveau_event *event, int head) |
| 445 | 475 | { |
| @@ -573,9 +603,24 @@ nvd0_disp_base_ofuncs = { · 127 unmodified lines | ||
| 573 | 603 | .fini = nvd0_disp_base_fini, |
| 574 | 604 | }; |
| 575 | 605 | |
| 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 | + | |
| 576 | 621 | static struct nouveau_oclass |
| 577 | 622 | 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 }, | |
| 579 | 624 | {} |
| 580 | 625 | }; |
| 581 | 626 | |
| @@ -41,7 +41,7 @@ nve0_disp_sclass[] = { · 40 unmodified lines | ||
| 41 | 41 | |
| 42 | 42 | static struct nouveau_oclass |
| 43 | 43 | 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 }, | |
| 45 | 45 | {} |
| 46 | 46 | }; |
| 47 | 47 | |
| @@ -41,7 +41,7 @@ nvf0_disp_sclass[] = { · 40 unmodified lines | ||
| 41 | 41 | |
| 42 | 42 | static struct nouveau_oclass |
| 43 | 43 | 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 }, | |
| 45 | 45 | {} |
| 46 | 46 | }; |
| 47 | 47 | |
| @@ -230,9 +230,26 @@ struct nve0_channel_ind_class { · 229 unmodified lines | ||
| 230 | 230 | |
| 231 | 231 | #define NV04_DISP_CLASS 0x00000046 |
| 232 | 232 | |
| 233 | +#define NV04_DISP_MTHD 0x00000000 | |
| 234 | +#define NV04_DISP_MTHD_HEAD 0x00000001 | |
| 235 | + | |
| 236 | +#define NV04_DISP_SCANOUTPOS 0x00000000 | |
| 237 | + | |
| 233 | 238 | struct nv04_display_class { |
| 234 | 239 | }; |
| 235 | 240 | |
| 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 | + | |
| 236 | 253 | /* 5070: NV50_DISP |
| 237 | 254 | * 8270: NV84_DISP |
| 238 | 255 | * 8370: NVA0_DISP |
| @@ -252,6 +269,11 @@ struct nv04_display_class { · 13 unmodified lines | ||
| 252 | 269 | #define NVE0_DISP_CLASS 0x00009170 |
| 253 | 270 | #define NVF0_DISP_CLASS 0x00009270 |
| 254 | 271 | |
| 272 | +#define NV50_DISP_MTHD 0x00000000 | |
| 273 | +#define NV50_DISP_MTHD_HEAD 0x00000003 | |
| 274 | + | |
| 275 | +#define NV50_DISP_SCANOUTPOS 0x00000000 | |
| 276 | + | |
| 255 | 277 | #define NV50_DISP_SOR_MTHD 0x00010000 |
| 256 | 278 | #define NV50_DISP_SOR_MTHD_TYPE 0x0000f000 |
| 257 | 279 | #define NV50_DISP_SOR_MTHD_HEAD 0x00000018 |
| @@ -68,6 +68,86 @@ nouveau_display_vblank_disable(struct drm_device *dev, int head) · 67 unmodified lines | ||
| 68 | 68 | nouveau_event_put(disp->vblank[head]); |
| 69 | 69 | } |
| 70 | 70 | |
| 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 | + | |
| 71 | 151 | static void |
| 72 | 152 | nouveau_display_vblank_fini(struct drm_device *dev) |
| 73 | 153 | { |
| @@ -642,7 +722,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, · 568 unmodified lines | ||
| 642 | 722 | ret = nouveau_fence_sync(fence, chan); |
| 643 | 723 | nouveau_fence_unref(&fence); |
| 644 | 724 | if (ret) |
| 645 | − goto fail_free; | |
| 725 | + goto fail_unpin; | |
| 646 | 726 | |
| 647 | 727 | ret = ttm_bo_reserve(&old_bo->bo, true, false, false, NULL); |
| 648 | 728 | if (ret) |
| @@ -64,6 +64,10 @@ void nouveau_display_repin(struct drm_device *dev); · 63 unmodified lines | ||
| 64 | 64 | void nouveau_display_resume(struct drm_device *dev); |
| 65 | 65 | int nouveau_display_vblank_enable(struct drm_device *, int); |
| 66 | 66 | 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); | |
| 67 | 71 | |
| 68 | 72 | int nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, |
| 69 | 73 | struct drm_pending_vblank_event *event, |
| @@ -503,19 +503,21 @@ nouveau_do_suspend(struct drm_device *dev) · 502 unmodified lines | ||
| 503 | 503 | if (drm->cechan) { |
| 504 | 504 | ret = nouveau_channel_idle(drm->cechan); |
| 505 | 505 | if (ret) |
| 506 | − return ret; | |
| 506 | + goto fail_display; | |
| 507 | 507 | } |
| 508 | 508 | |
| 509 | 509 | if (drm->channel) { |
| 510 | 510 | ret = nouveau_channel_idle(drm->channel); |
| 511 | 511 | if (ret) |
| 512 | − return ret; | |
| 512 | + goto fail_display; | |
| 513 | 513 | } |
| 514 | 514 | |
| 515 | 515 | NV_INFO(drm, "suspending client object trees...\n"); |
| 516 | 516 | 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 | + } | |
| 519 | 521 | } |
| 520 | 522 | |
| 521 | 523 | list_for_each_entry(cli, &drm->clients, head) { |
| @@ -537,6 +539,10 @@ fail_client: · 15 unmodified lines | ||
| 537 | 539 | nouveau_client_init(&cli->base); |
| 538 | 540 | } |
| 539 | 541 | |
| 542 | + if (drm->fence && nouveau_fence(drm)->resume) | |
| 543 | + nouveau_fence(drm)->resume(drm); | |
| 544 | + | |
| 545 | +fail_display: | |
| 540 | 546 | if (dev->mode_config.num_crtc) { |
| 541 | 547 | NV_INFO(drm, "resuming display...\n"); |
| 542 | 548 | nouveau_display_resume(dev); |
| @@ -798,6 +804,8 @@ driver = { · 255 unmodified lines | ||
| 798 | 804 | .get_vblank_counter = drm_vblank_count, |
| 799 | 805 | .enable_vblank = nouveau_display_vblank_enable, |
| 800 | 806 | .disable_vblank = nouveau_display_vblank_disable, |
| 807 | + .get_scanout_position = nouveau_display_scanoutpos, | |
| 808 | + .get_vblank_timestamp = nouveau_display_vblstamp, | |
| 801 | 809 | |
| 802 | 810 | .ioctls = nouveau_ioctls, |
| 803 | 811 | .num_ioctls = ARRAY_SIZE(nouveau_ioctls), |
| @@ -1035,6 +1035,7 @@ static bool · 1034 unmodified lines | ||
| 1035 | 1035 | nv50_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode, |
| 1036 | 1036 | struct drm_display_mode *adjusted_mode) |
| 1037 | 1037 | { |
| 1038 | + drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V); | |
| 1038 | 1039 | return true; |
| 1039 | 1040 | } |
| 1040 | 1041 | |