diff options
-rw-r--r-- | drivers/gpu/drm/nouveau/core/engine/disp/nv04.c | 38 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/engine/disp/nv50.c | 30 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/engine/disp/nv50.h | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/engine/disp/nv84.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/engine/disp/nv94.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/engine/disp/nva3.c | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c | 47 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/engine/disp/nve0.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/include/core/class.h | 22 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_display.c | 82 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_display.h | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_drm.c | 16 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nv50_display.c | 1 |
14 files changed, 244 insertions, 12 deletions
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv04.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv04.c index a0bc8a89b699..7cf8b1348632 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv04.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv04.c | |||
@@ -31,9 +31,45 @@ struct nv04_disp_priv { | |||
31 | struct nouveau_disp base; | 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 | static struct nouveau_oclass | 70 | static struct nouveau_oclass |
35 | nv04_disp_sclass[] = { | 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 | ||
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c index c168ae3eaa97..940eaa5d8b9a 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c | |||
@@ -541,6 +541,35 @@ nv50_disp_curs_ofuncs = { | |||
541 | * Base display object | 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 | static void | 573 | static void |
545 | nv50_disp_base_vblank_enable(struct nouveau_event *event, int head) | 574 | nv50_disp_base_vblank_enable(struct nouveau_event *event, int head) |
546 | { | 575 | { |
@@ -675,6 +704,7 @@ nv50_disp_base_ofuncs = { | |||
675 | 704 | ||
676 | static struct nouveau_omthds | 705 | static struct nouveau_omthds |
677 | nv50_disp_base_omthds[] = { | 706 | nv50_disp_base_omthds[] = { |
707 | { HEAD_MTHD(NV50_DISP_SCANOUTPOS) , nv50_disp_base_scanoutpos }, | ||
678 | { SOR_MTHD(NV50_DISP_SOR_PWR) , nv50_sor_mthd }, | 708 | { SOR_MTHD(NV50_DISP_SOR_PWR) , nv50_sor_mthd }, |
679 | { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd }, | 709 | { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd }, |
680 | { DAC_MTHD(NV50_DISP_DAC_PWR) , nv50_dac_mthd }, | 710 | { DAC_MTHD(NV50_DISP_DAC_PWR) , nv50_dac_mthd }, |
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h index 1ae6ceb56704..d31d426ea1f6 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h | |||
@@ -43,6 +43,10 @@ struct nv50_disp_priv { | |||
43 | } pior; | 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 | #define DAC_MTHD(n) (n), (n) + 0x03 | 50 | #define DAC_MTHD(n) (n), (n) + 0x03 |
47 | 51 | ||
48 | int nv50_dac_mthd(struct nouveau_object *, u32, void *, u32); | 52 | int nv50_dac_mthd(struct nouveau_object *, u32, void *, u32); |
@@ -132,13 +136,12 @@ void nv50_disp_intr(struct nouveau_subdev *); | |||
132 | 136 | ||
133 | extern struct nouveau_omthds nv84_disp_base_omthds[]; | 137 | extern struct nouveau_omthds nv84_disp_base_omthds[]; |
134 | 138 | ||
135 | extern struct nouveau_omthds nva3_disp_base_omthds[]; | ||
136 | |||
137 | extern struct nouveau_ofuncs nvd0_disp_mast_ofuncs; | 139 | extern struct nouveau_ofuncs nvd0_disp_mast_ofuncs; |
138 | extern struct nouveau_ofuncs nvd0_disp_sync_ofuncs; | 140 | extern struct nouveau_ofuncs nvd0_disp_sync_ofuncs; |
139 | extern struct nouveau_ofuncs nvd0_disp_ovly_ofuncs; | 141 | extern struct nouveau_ofuncs nvd0_disp_ovly_ofuncs; |
140 | extern struct nouveau_ofuncs nvd0_disp_oimm_ofuncs; | 142 | extern struct nouveau_ofuncs nvd0_disp_oimm_ofuncs; |
141 | extern struct nouveau_ofuncs nvd0_disp_curs_ofuncs; | 143 | extern struct nouveau_ofuncs nvd0_disp_curs_ofuncs; |
144 | extern struct nouveau_omthds nvd0_disp_base_omthds[]; | ||
142 | extern struct nouveau_ofuncs nvd0_disp_base_ofuncs; | 145 | extern struct nouveau_ofuncs nvd0_disp_base_ofuncs; |
143 | extern struct nouveau_oclass nvd0_disp_cclass; | 146 | extern struct nouveau_oclass nvd0_disp_cclass; |
144 | void nvd0_disp_intr_supervisor(struct work_struct *); | 147 | void nvd0_disp_intr_supervisor(struct work_struct *); |
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c index d8c74c0883a1..ef9ce300a496 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c | |||
@@ -41,6 +41,7 @@ nv84_disp_sclass[] = { | |||
41 | 41 | ||
42 | struct nouveau_omthds | 42 | struct nouveau_omthds |
43 | nv84_disp_base_omthds[] = { | 43 | nv84_disp_base_omthds[] = { |
44 | { HEAD_MTHD(NV50_DISP_SCANOUTPOS) , nv50_disp_base_scanoutpos }, | ||
44 | { SOR_MTHD(NV50_DISP_SOR_PWR) , nv50_sor_mthd }, | 45 | { SOR_MTHD(NV50_DISP_SOR_PWR) , nv50_sor_mthd }, |
45 | { SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd }, | 46 | { SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd }, |
46 | { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd }, | 47 | { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd }, |
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c index a66f949c1f84..a518543c00ab 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c | |||
@@ -41,6 +41,7 @@ nv94_disp_sclass[] = { | |||
41 | 41 | ||
42 | static struct nouveau_omthds | 42 | static struct nouveau_omthds |
43 | nv94_disp_base_omthds[] = { | 43 | nv94_disp_base_omthds[] = { |
44 | { HEAD_MTHD(NV50_DISP_SCANOUTPOS) , nv50_disp_base_scanoutpos }, | ||
44 | { SOR_MTHD(NV50_DISP_SOR_PWR) , nv50_sor_mthd }, | 45 | { SOR_MTHD(NV50_DISP_SOR_PWR) , nv50_sor_mthd }, |
45 | { SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd }, | 46 | { SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd }, |
46 | { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd }, | 47 | { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd }, |
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c b/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c index b75413169eae..6ad6dcece43b 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c | |||
@@ -39,8 +39,9 @@ nva3_disp_sclass[] = { | |||
39 | {} | 39 | {} |
40 | }; | 40 | }; |
41 | 41 | ||
42 | struct nouveau_omthds | 42 | static struct nouveau_omthds |
43 | nva3_disp_base_omthds[] = { | 43 | nva3_disp_base_omthds[] = { |
44 | { HEAD_MTHD(NV50_DISP_SCANOUTPOS) , nv50_disp_base_scanoutpos }, | ||
44 | { SOR_MTHD(NV50_DISP_SOR_PWR) , nv50_sor_mthd }, | 45 | { SOR_MTHD(NV50_DISP_SOR_PWR) , nv50_sor_mthd }, |
45 | { SOR_MTHD(NVA3_DISP_SOR_HDA_ELD) , nv50_sor_mthd }, | 46 | { SOR_MTHD(NVA3_DISP_SOR_HDA_ELD) , nv50_sor_mthd }, |
46 | { SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd }, | 47 | { SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd }, |
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c index d52c0f50a1a9..1c5e4e8b2c82 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c | |||
@@ -440,6 +440,36 @@ nvd0_disp_curs_ofuncs = { | |||
440 | * Base display object | 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 | static void | 473 | static void |
444 | nvd0_disp_base_vblank_enable(struct nouveau_event *event, int head) | 474 | nvd0_disp_base_vblank_enable(struct nouveau_event *event, int head) |
445 | { | 475 | { |
@@ -573,9 +603,24 @@ nvd0_disp_base_ofuncs = { | |||
573 | .fini = nvd0_disp_base_fini, | 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 | static struct nouveau_oclass | 621 | static struct nouveau_oclass |
577 | nvd0_disp_base_oclass[] = { | 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 | ||
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c index 20725b363d58..ab63f32c00b2 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c | |||
@@ -41,7 +41,7 @@ nve0_disp_sclass[] = { | |||
41 | 41 | ||
42 | static struct nouveau_oclass | 42 | static struct nouveau_oclass |
43 | nve0_disp_base_oclass[] = { | 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 | ||
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c index a488c36e40f9..05fee10e0c97 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c | |||
@@ -41,7 +41,7 @@ nvf0_disp_sclass[] = { | |||
41 | 41 | ||
42 | static struct nouveau_oclass | 42 | static struct nouveau_oclass |
43 | nvf0_disp_base_oclass[] = { | 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 | ||
diff --git a/drivers/gpu/drm/nouveau/core/include/core/class.h b/drivers/gpu/drm/nouveau/core/include/core/class.h index 560c3593dae7..e71a4325e670 100644 --- a/drivers/gpu/drm/nouveau/core/include/core/class.h +++ b/drivers/gpu/drm/nouveau/core/include/core/class.h | |||
@@ -230,9 +230,26 @@ struct nve0_channel_ind_class { | |||
230 | 230 | ||
231 | #define NV04_DISP_CLASS 0x00000046 | 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 | struct nv04_display_class { | 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 | /* 5070: NV50_DISP | 253 | /* 5070: NV50_DISP |
237 | * 8270: NV84_DISP | 254 | * 8270: NV84_DISP |
238 | * 8370: NVA0_DISP | 255 | * 8370: NVA0_DISP |
@@ -252,6 +269,11 @@ struct nv04_display_class { | |||
252 | #define NVE0_DISP_CLASS 0x00009170 | 269 | #define NVE0_DISP_CLASS 0x00009170 |
253 | #define NVF0_DISP_CLASS 0x00009270 | 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 | #define NV50_DISP_SOR_MTHD 0x00010000 | 277 | #define NV50_DISP_SOR_MTHD 0x00010000 |
256 | #define NV50_DISP_SOR_MTHD_TYPE 0x0000f000 | 278 | #define NV50_DISP_SOR_MTHD_TYPE 0x0000f000 |
257 | #define NV50_DISP_SOR_MTHD_HEAD 0x00000018 | 279 | #define NV50_DISP_SOR_MTHD_HEAD 0x00000018 |
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index b4262ad66b18..24011596af43 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c | |||
@@ -68,6 +68,86 @@ nouveau_display_vblank_disable(struct drm_device *dev, int head) | |||
68 | nouveau_event_put(disp->vblank[head]); | 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 | static void | 151 | static void |
72 | nouveau_display_vblank_fini(struct drm_device *dev) | 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, | |||
642 | ret = nouveau_fence_sync(fence, chan); | 722 | ret = nouveau_fence_sync(fence, chan); |
643 | nouveau_fence_unref(&fence); | 723 | nouveau_fence_unref(&fence); |
644 | if (ret) | 724 | if (ret) |
645 | goto fail_free; | 725 | goto fail_unpin; |
646 | 726 | ||
647 | ret = ttm_bo_reserve(&old_bo->bo, true, false, false, NULL); | 727 | ret = ttm_bo_reserve(&old_bo->bo, true, false, false, NULL); |
648 | if (ret) | 728 | if (ret) |
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.h b/drivers/gpu/drm/nouveau/nouveau_display.h index 73aa231130b8..a71cf77e55b2 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.h +++ b/drivers/gpu/drm/nouveau/nouveau_display.h | |||
@@ -64,6 +64,10 @@ void nouveau_display_repin(struct drm_device *dev); | |||
64 | void nouveau_display_resume(struct drm_device *dev); | 64 | void nouveau_display_resume(struct drm_device *dev); |
65 | int nouveau_display_vblank_enable(struct drm_device *, int); | 65 | int nouveau_display_vblank_enable(struct drm_device *, int); |
66 | void nouveau_display_vblank_disable(struct drm_device *, int); | 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 | int nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, | 72 | int nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, |
69 | struct drm_pending_vblank_event *event, | 73 | struct drm_pending_vblank_event *event, |
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 98a22e6e27a1..78c8e7146d56 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c | |||
@@ -503,19 +503,21 @@ nouveau_do_suspend(struct drm_device *dev) | |||
503 | if (drm->cechan) { | 503 | if (drm->cechan) { |
504 | ret = nouveau_channel_idle(drm->cechan); | 504 | ret = nouveau_channel_idle(drm->cechan); |
505 | if (ret) | 505 | if (ret) |
506 | return ret; | 506 | goto fail_display; |
507 | } | 507 | } |
508 | 508 | ||
509 | if (drm->channel) { | 509 | if (drm->channel) { |
510 | ret = nouveau_channel_idle(drm->channel); | 510 | ret = nouveau_channel_idle(drm->channel); |
511 | if (ret) | 511 | if (ret) |
512 | return ret; | 512 | goto fail_display; |
513 | } | 513 | } |
514 | 514 | ||
515 | NV_INFO(drm, "suspending client object trees...\n"); | 515 | NV_INFO(drm, "suspending client object trees...\n"); |
516 | if (drm->fence && nouveau_fence(drm)->suspend) { | 516 | if (drm->fence && nouveau_fence(drm)->suspend) { |
517 | if (!nouveau_fence(drm)->suspend(drm)) | 517 | if (!nouveau_fence(drm)->suspend(drm)) { |
518 | return -ENOMEM; | 518 | ret = -ENOMEM; |
519 | goto fail_display; | ||
520 | } | ||
519 | } | 521 | } |
520 | 522 | ||
521 | list_for_each_entry(cli, &drm->clients, head) { | 523 | list_for_each_entry(cli, &drm->clients, head) { |
@@ -537,6 +539,10 @@ fail_client: | |||
537 | nouveau_client_init(&cli->base); | 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 | if (dev->mode_config.num_crtc) { | 546 | if (dev->mode_config.num_crtc) { |
541 | NV_INFO(drm, "resuming display...\n"); | 547 | NV_INFO(drm, "resuming display...\n"); |
542 | nouveau_display_resume(dev); | 548 | nouveau_display_resume(dev); |
@@ -798,6 +804,8 @@ driver = { | |||
798 | .get_vblank_counter = drm_vblank_count, | 804 | .get_vblank_counter = drm_vblank_count, |
799 | .enable_vblank = nouveau_display_vblank_enable, | 805 | .enable_vblank = nouveau_display_vblank_enable, |
800 | .disable_vblank = nouveau_display_vblank_disable, | 806 | .disable_vblank = nouveau_display_vblank_disable, |
807 | .get_scanout_position = nouveau_display_scanoutpos, | ||
808 | .get_vblank_timestamp = nouveau_display_vblstamp, | ||
801 | 809 | ||
802 | .ioctls = nouveau_ioctls, | 810 | .ioctls = nouveau_ioctls, |
803 | .num_ioctls = ARRAY_SIZE(nouveau_ioctls), | 811 | .num_ioctls = ARRAY_SIZE(nouveau_ioctls), |
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 6ae7a697866e..2dccafc6e9db 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c | |||
@@ -1035,6 +1035,7 @@ static bool | |||
1035 | nv50_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode, | 1035 | nv50_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode, |
1036 | struct drm_display_mode *adjusted_mode) | 1036 | struct drm_display_mode *adjusted_mode) |
1037 | { | 1037 | { |
1038 | drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V); | ||
1038 | return true; | 1039 | return true; |
1039 | } | 1040 | } |
1040 | 1041 | ||