drm/nouveau/disp: add a method to fetch info needed by drm vblank timestamping
authorBen Skeggs <bskeggs@redhat.com>
Thu, 14 Nov 2013 03:37:48 +0000 (13:37 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Wed, 29 Jan 2014 22:18:36 +0000 (08:18 +1000)
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/core/engine/disp/nv04.c
drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
drivers/gpu/drm/nouveau/core/engine/disp/nv50.h
drivers/gpu/drm/nouveau/core/engine/disp/nv84.c
drivers/gpu/drm/nouveau/core/engine/disp/nv94.c
drivers/gpu/drm/nouveau/core/engine/disp/nva3.c
drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
drivers/gpu/drm/nouveau/core/engine/disp/nve0.c
drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c
drivers/gpu/drm/nouveau/core/include/core/class.h

index a0bc8a89b69941b1bcf449084ce1dcea9a2ff666..7cf8b13486326fdcf64066cb368203668024d11a 100644 (file)
@@ -31,9 +31,45 @@ struct nv04_disp_priv {
        struct nouveau_disp base;
 };
 
+static int
+nv04_disp_scanoutpos(struct nouveau_object *object, u32 mthd,
+                    void *data, u32 size)
+{
+       struct nv04_disp_priv *priv = (void *)object->engine;
+       struct nv04_display_scanoutpos *args = data;
+       const int head = (mthd & NV04_DISP_MTHD_HEAD);
+       u32 line;
+
+       if (size < sizeof(*args))
+               return -EINVAL;
+
+       args->vblanks = nv_rd32(priv, 0x680800 + (head * 0x2000)) & 0xffff;
+       args->vtotal  = nv_rd32(priv, 0x680804 + (head * 0x2000)) & 0xffff;
+       args->vblanke = args->vtotal - 1;
+
+       args->hblanks = nv_rd32(priv, 0x680820 + (head * 0x2000)) & 0xffff;
+       args->htotal  = nv_rd32(priv, 0x680824 + (head * 0x2000)) & 0xffff;
+       args->hblanke = args->htotal - 1;
+
+       args->time[0] = ktime_to_ns(ktime_get());
+       line = nv_rd32(priv, 0x600868 + (head * 0x2000));
+       args->time[1] = ktime_to_ns(ktime_get());
+       args->hline = (line & 0xffff0000) >> 16;
+       args->vline = (line & 0x0000ffff);
+       return 0;
+}
+
+#define HEAD_MTHD(n) (n), (n) + 0x01
+
+static struct nouveau_omthds
+nv04_disp_omthds[] = {
+       { HEAD_MTHD(NV04_DISP_SCANOUTPOS), nv04_disp_scanoutpos },
+       {}
+};
+
 static struct nouveau_oclass
 nv04_disp_sclass[] = {
-       { NV04_DISP_CLASS, &nouveau_object_ofuncs },
+       { NV04_DISP_CLASS, &nouveau_object_ofuncs, nv04_disp_omthds },
        {},
 };
 
index c168ae3eaa97cab0a18e6a10b9ee811e815a5a66..940eaa5d8b9a4bb0e3ea224cfe2ced8ec8585b44 100644 (file)
@@ -541,6 +541,35 @@ nv50_disp_curs_ofuncs = {
  * Base display object
  ******************************************************************************/
 
+int
+nv50_disp_base_scanoutpos(struct nouveau_object *object, u32 mthd,
+                         void *data, u32 size)
+{
+       struct nv50_disp_priv *priv = (void *)object->engine;
+       struct nv04_display_scanoutpos *args = data;
+       const int head = (mthd & NV50_DISP_MTHD_HEAD);
+       u32 blanke, blanks, total;
+
+       if (size < sizeof(*args) || head >= priv->head.nr)
+               return -EINVAL;
+       blanke = nv_rd32(priv, 0x610aec + (head * 0x540));
+       blanks = nv_rd32(priv, 0x610af4 + (head * 0x540));
+       total  = nv_rd32(priv, 0x610afc + (head * 0x540));
+
+       args->vblanke = (blanke & 0xffff0000) >> 16;
+       args->hblanke = (blanke & 0x0000ffff);
+       args->vblanks = (blanks & 0xffff0000) >> 16;
+       args->hblanks = (blanks & 0x0000ffff);
+       args->vtotal  = ( total & 0xffff0000) >> 16;
+       args->htotal  = ( total & 0x0000ffff);
+
+       args->time[0] = ktime_to_ns(ktime_get());
+       args->vline   = nv_rd32(priv, 0x616340 + (head * 0x800)) & 0xffff;
+       args->time[1] = ktime_to_ns(ktime_get()); /* vline read locks hline */
+       args->hline   = nv_rd32(priv, 0x616344 + (head * 0x800)) & 0xffff;
+       return 0;
+}
+
 static void
 nv50_disp_base_vblank_enable(struct nouveau_event *event, int head)
 {
@@ -675,6 +704,7 @@ nv50_disp_base_ofuncs = {
 
 static struct nouveau_omthds
 nv50_disp_base_omthds[] = {
+       { HEAD_MTHD(NV50_DISP_SCANOUTPOS)     , nv50_disp_base_scanoutpos },
        { SOR_MTHD(NV50_DISP_SOR_PWR)         , nv50_sor_mthd },
        { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd },
        { DAC_MTHD(NV50_DISP_DAC_PWR)         , nv50_dac_mthd },
index 1ae6ceb5670403b0150f931f2cb01815a4a56569..d31d426ea1f6327c96d77e21210d0b792ba87505 100644 (file)
@@ -43,6 +43,10 @@ struct nv50_disp_priv {
        } pior;
 };
 
+#define HEAD_MTHD(n) (n), (n) + 0x03
+
+int nv50_disp_base_scanoutpos(struct nouveau_object *, u32, void *, u32);
+
 #define DAC_MTHD(n) (n), (n) + 0x03
 
 int nv50_dac_mthd(struct nouveau_object *, u32, void *, u32);
@@ -132,13 +136,12 @@ void nv50_disp_intr(struct nouveau_subdev *);
 
 extern struct nouveau_omthds nv84_disp_base_omthds[];
 
-extern struct nouveau_omthds nva3_disp_base_omthds[];
-
 extern struct nouveau_ofuncs nvd0_disp_mast_ofuncs;
 extern struct nouveau_ofuncs nvd0_disp_sync_ofuncs;
 extern struct nouveau_ofuncs nvd0_disp_ovly_ofuncs;
 extern struct nouveau_ofuncs nvd0_disp_oimm_ofuncs;
 extern struct nouveau_ofuncs nvd0_disp_curs_ofuncs;
+extern struct nouveau_omthds nvd0_disp_base_omthds[];
 extern struct nouveau_ofuncs nvd0_disp_base_ofuncs;
 extern struct nouveau_oclass nvd0_disp_cclass;
 void nvd0_disp_intr_supervisor(struct work_struct *);
index d8c74c0883a16904b92081857552182721eca183..ef9ce300a496e0dc1c5baae4c5f1a041d112ea2a 100644 (file)
@@ -41,6 +41,7 @@ nv84_disp_sclass[] = {
 
 struct nouveau_omthds
 nv84_disp_base_omthds[] = {
+       { HEAD_MTHD(NV50_DISP_SCANOUTPOS)     , nv50_disp_base_scanoutpos },
        { SOR_MTHD(NV50_DISP_SOR_PWR)         , nv50_sor_mthd },
        { SOR_MTHD(NV84_DISP_SOR_HDMI_PWR)    , nv50_sor_mthd },
        { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd },
index a66f949c1f84119479f5c5ffbe809fad278db4d2..a518543c00ab624f8df1b4fd22e66293943b8f02 100644 (file)
@@ -41,6 +41,7 @@ nv94_disp_sclass[] = {
 
 static struct nouveau_omthds
 nv94_disp_base_omthds[] = {
+       { HEAD_MTHD(NV50_DISP_SCANOUTPOS)     , nv50_disp_base_scanoutpos },
        { SOR_MTHD(NV50_DISP_SOR_PWR)         , nv50_sor_mthd },
        { SOR_MTHD(NV84_DISP_SOR_HDMI_PWR)    , nv50_sor_mthd },
        { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd },
index b75413169eaee91e07dd73dd08e1a7efada6ed34..6ad6dcece43bde52062c5c4563662586dfaef7d6 100644 (file)
@@ -39,8 +39,9 @@ nva3_disp_sclass[] = {
        {}
 };
 
-struct nouveau_omthds
+static struct nouveau_omthds
 nva3_disp_base_omthds[] = {
+       { HEAD_MTHD(NV50_DISP_SCANOUTPOS)     , nv50_disp_base_scanoutpos },
        { SOR_MTHD(NV50_DISP_SOR_PWR)         , nv50_sor_mthd },
        { SOR_MTHD(NVA3_DISP_SOR_HDA_ELD)     , nv50_sor_mthd },
        { SOR_MTHD(NV84_DISP_SOR_HDMI_PWR)    , nv50_sor_mthd },
index d52c0f50a1a9b0076682a01171418da974625bfb..1c5e4e8b2c822b37a140932d5b5378d5d2deb309 100644 (file)
@@ -440,6 +440,36 @@ nvd0_disp_curs_ofuncs = {
  * Base display object
  ******************************************************************************/
 
+static int
+nvd0_disp_base_scanoutpos(struct nouveau_object *object, u32 mthd,
+                         void *data, u32 size)
+{
+       struct nv50_disp_priv *priv = (void *)object->engine;
+       struct nv04_display_scanoutpos *args = data;
+       const int head = (mthd & NV50_DISP_MTHD_HEAD);
+       u32 blanke, blanks, total;
+
+       if (size < sizeof(*args) || head >= priv->head.nr)
+               return -EINVAL;
+
+       total  = nv_rd32(priv, 0x640414 + (head * 0x300));
+       blanke = nv_rd32(priv, 0x64041c + (head * 0x300));
+       blanks = nv_rd32(priv, 0x640420 + (head * 0x300));
+
+       args->vblanke = (blanke & 0xffff0000) >> 16;
+       args->hblanke = (blanke & 0x0000ffff);
+       args->vblanks = (blanks & 0xffff0000) >> 16;
+       args->hblanks = (blanks & 0x0000ffff);
+       args->vtotal  = ( total & 0xffff0000) >> 16;
+       args->htotal  = ( total & 0x0000ffff);
+
+       args->time[0] = ktime_to_ns(ktime_get());
+       args->vline   = nv_rd32(priv, 0x616340 + (head * 0x800)) & 0xffff;
+       args->time[1] = ktime_to_ns(ktime_get()); /* vline read locks hline */
+       args->hline   = nv_rd32(priv, 0x616344 + (head * 0x800)) & 0xffff;
+       return 0;
+}
+
 static void
 nvd0_disp_base_vblank_enable(struct nouveau_event *event, int head)
 {
@@ -573,9 +603,24 @@ nvd0_disp_base_ofuncs = {
        .fini = nvd0_disp_base_fini,
 };
 
+struct nouveau_omthds
+nvd0_disp_base_omthds[] = {
+       { HEAD_MTHD(NV50_DISP_SCANOUTPOS)     , nvd0_disp_base_scanoutpos },
+       { SOR_MTHD(NV50_DISP_SOR_PWR)         , nv50_sor_mthd },
+       { SOR_MTHD(NVA3_DISP_SOR_HDA_ELD)     , nv50_sor_mthd },
+       { SOR_MTHD(NV84_DISP_SOR_HDMI_PWR)    , nv50_sor_mthd },
+       { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd },
+       { DAC_MTHD(NV50_DISP_DAC_PWR)         , nv50_dac_mthd },
+       { DAC_MTHD(NV50_DISP_DAC_LOAD)        , nv50_dac_mthd },
+       { PIOR_MTHD(NV50_DISP_PIOR_PWR)       , nv50_pior_mthd },
+       { PIOR_MTHD(NV50_DISP_PIOR_TMDS_PWR)  , nv50_pior_mthd },
+       { PIOR_MTHD(NV50_DISP_PIOR_DP_PWR)    , nv50_pior_mthd },
+       {},
+};
+
 static struct nouveau_oclass
 nvd0_disp_base_oclass[] = {
-       { NVD0_DISP_CLASS, &nvd0_disp_base_ofuncs, nva3_disp_base_omthds },
+       { NVD0_DISP_CLASS, &nvd0_disp_base_ofuncs, nvd0_disp_base_omthds },
        {}
 };
 
index 20725b363d582b3485b55f5ef4692247d20adce2..ab63f32c00b2478d2cb0a2ebd062f946d394044d 100644 (file)
@@ -41,7 +41,7 @@ nve0_disp_sclass[] = {
 
 static struct nouveau_oclass
 nve0_disp_base_oclass[] = {
-       { NVE0_DISP_CLASS, &nvd0_disp_base_ofuncs, nva3_disp_base_omthds },
+       { NVE0_DISP_CLASS, &nvd0_disp_base_ofuncs, nvd0_disp_base_omthds },
        {}
 };
 
index a488c36e40f9dc0d7923362dd1c09e346b37b7dd..05fee10e0c975a166fec5b68d98d6e53cd1fae55 100644 (file)
@@ -41,7 +41,7 @@ nvf0_disp_sclass[] = {
 
 static struct nouveau_oclass
 nvf0_disp_base_oclass[] = {
-       { NVF0_DISP_CLASS, &nvd0_disp_base_ofuncs, nva3_disp_base_omthds },
+       { NVF0_DISP_CLASS, &nvd0_disp_base_ofuncs, nvd0_disp_base_omthds },
        {}
 };
 
index 560c3593dae75e365a647d3e4858d65be85c39e6..e71a4325e670f69c4fce0893b973760a9522185a 100644 (file)
@@ -230,9 +230,26 @@ struct nve0_channel_ind_class {
 
 #define NV04_DISP_CLASS                                              0x00000046
 
+#define NV04_DISP_MTHD                                               0x00000000
+#define NV04_DISP_MTHD_HEAD                                          0x00000001
+
+#define NV04_DISP_SCANOUTPOS                                         0x00000000
+
 struct nv04_display_class {
 };
 
+struct nv04_display_scanoutpos {
+       s64 time[2];
+       u32 vblanks;
+       u32 vblanke;
+       u32 vtotal;
+       u32 vline;
+       u32 hblanks;
+       u32 hblanke;
+       u32 htotal;
+       u32 hline;
+};
+
 /* 5070: NV50_DISP
  * 8270: NV84_DISP
  * 8370: NVA0_DISP
@@ -252,6 +269,11 @@ struct nv04_display_class {
 #define NVE0_DISP_CLASS                                              0x00009170
 #define NVF0_DISP_CLASS                                              0x00009270
 
+#define NV50_DISP_MTHD                                               0x00000000
+#define NV50_DISP_MTHD_HEAD                                          0x00000003
+
+#define NV50_DISP_SCANOUTPOS                                         0x00000000
+
 #define NV50_DISP_SOR_MTHD                                           0x00010000
 #define NV50_DISP_SOR_MTHD_TYPE                                      0x0000f000
 #define NV50_DISP_SOR_MTHD_HEAD                                      0x00000018