From d2fa7d32ea7b54d910637e50df4972e3540722d4 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 14 Nov 2013 13:37:48 +1000 Subject: [PATCH] drm/nouveau/disp: add a method to fetch info needed by drm vblank timestamping Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/core/engine/disp/nv04.c | 38 +++++++++++++++++- drivers/gpu/drm/nouveau/core/engine/disp/nv50.c | 30 +++++++++++++++ drivers/gpu/drm/nouveau/core/engine/disp/nv50.h | 7 +++- drivers/gpu/drm/nouveau/core/engine/disp/nv84.c | 1 + drivers/gpu/drm/nouveau/core/engine/disp/nv94.c | 1 + drivers/gpu/drm/nouveau/core/engine/disp/nva3.c | 3 +- drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c | 47 ++++++++++++++++++++++- drivers/gpu/drm/nouveau/core/engine/disp/nve0.c | 2 +- drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c | 2 +- drivers/gpu/drm/nouveau/core/include/core/class.h | 22 +++++++++++ 10 files changed, 146 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv04.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv04.c index a0bc8a8..7cf8b13 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 { 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 }, {}, }; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c index c168ae3..940eaa5 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 = { * 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 }, diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h index 1ae6ceb..d31d426 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 { } 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 *); diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c index d8c74c0..ef9ce30 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[] = { 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 }, diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c index a66f949..a518543 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[] = { 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 }, diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c b/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c index b754131..6ad6dce 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[] = { {} }; -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 }, diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c index d52c0f5..1c5e4e8 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 = { * 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 }, {} }; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c index 20725b3..ab63f32 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[] = { 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 }, {} }; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c index a488c36..05fee10 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[] = { 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 }, {} }; diff --git a/drivers/gpu/drm/nouveau/core/include/core/class.h b/drivers/gpu/drm/nouveau/core/include/core/class.h index 560c359..e71a432 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 { #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 -- 2.7.4