Skip to content

Commit

Permalink
Merge branch 'drm-nouveau-next' of git://anongit.freedesktop.org/git/…
Browse files Browse the repository at this point in the history
…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
  • Loading branch information
Dave Airlie committed Jan 30, 2014
2 parents 279b9e0 + f3980dc commit ef64cf9
Show file tree
Hide file tree
Showing 14 changed files with 244 additions and 12 deletions.
38 changes: 37 additions & 1 deletion drivers/gpu/drm/nouveau/core/engine/disp/nv04.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 },
{},
};

Expand Down
30 changes: 30 additions & 0 deletions drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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 },
Expand Down
7 changes: 5 additions & 2 deletions drivers/gpu/drm/nouveau/core/engine/disp/nv50.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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 *);
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/nouveau/core/engine/disp/nv84.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 },
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/nouveau/core/engine/disp/nv94.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 },
Expand Down
3 changes: 2 additions & 1 deletion drivers/gpu/drm/nouveau/core/engine/disp/nva3.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 },
Expand Down
47 changes: 46 additions & 1 deletion drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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 },
{}
};

Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/nouveau/core/engine/disp/nve0.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 },
{}
};

Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 },
{}
};

Expand Down
22 changes: 22 additions & 0 deletions drivers/gpu/drm/nouveau/core/include/core/class.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
82 changes: 81 additions & 1 deletion drivers/gpu/drm/nouveau/nouveau_display.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,86 @@ nouveau_display_vblank_disable(struct drm_device *dev, int head)
nouveau_event_put(disp->vblank[head]);
}

static inline int
calc(int blanks, int blanke, int total, int line)
{
if (blanke >= blanks) {
if (line >= blanks)
line -= total;
} else {
if (line >= blanks)
line -= total;
line -= blanke + 1;
}
return line;
}

int
nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos,
ktime_t *stime, ktime_t *etime)
{
const u32 mthd = NV04_DISP_SCANOUTPOS + nouveau_crtc(crtc)->index;
struct nouveau_display *disp = nouveau_display(crtc->dev);
struct nv04_display_scanoutpos args;
int ret, retry = 1;

do {
ret = nv_exec(disp->core, mthd, &args, sizeof(args));
if (ret != 0)
return 0;

if (args.vline) {
ret |= DRM_SCANOUTPOS_ACCURATE;
ret |= DRM_SCANOUTPOS_VALID;
break;
}

if (retry) ndelay(crtc->linedur_ns);
} while (retry--);

*hpos = calc(args.hblanks, args.hblanke, args.htotal, args.hline);
*vpos = calc(args.vblanks, args.vblanke, args.vtotal, args.vline);
if (stime) *stime = ns_to_ktime(args.time[0]);
if (etime) *etime = ns_to_ktime(args.time[1]);

if (*vpos < 0)
ret |= DRM_SCANOUTPOS_INVBL;
return ret;
}

int
nouveau_display_scanoutpos(struct drm_device *dev, int head, unsigned int flags,
int *vpos, int *hpos, ktime_t *stime, ktime_t *etime)
{
struct drm_crtc *crtc;

list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
if (nouveau_crtc(crtc)->index == head) {
return nouveau_display_scanoutpos_head(crtc, vpos, hpos,
stime, etime);
}
}

return 0;
}

int
nouveau_display_vblstamp(struct drm_device *dev, int head, int *max_error,
struct timeval *time, unsigned flags)
{
struct drm_crtc *crtc;

list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
if (nouveau_crtc(crtc)->index == head) {
return drm_calc_vbltimestamp_from_scanoutpos(dev,
head, max_error, time, flags, crtc,
&crtc->hwmode);
}
}

return -EINVAL;
}

static void
nouveau_display_vblank_fini(struct drm_device *dev)
{
Expand Down Expand Up @@ -642,7 +722,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
ret = nouveau_fence_sync(fence, chan);
nouveau_fence_unref(&fence);
if (ret)
goto fail_free;
goto fail_unpin;

ret = ttm_bo_reserve(&old_bo->bo, true, false, false, NULL);
if (ret)
Expand Down
4 changes: 4 additions & 0 deletions drivers/gpu/drm/nouveau/nouveau_display.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ void nouveau_display_repin(struct drm_device *dev);
void nouveau_display_resume(struct drm_device *dev);
int nouveau_display_vblank_enable(struct drm_device *, int);
void nouveau_display_vblank_disable(struct drm_device *, int);
int nouveau_display_scanoutpos(struct drm_device *, int, unsigned int,
int *, int *, ktime_t *, ktime_t *);
int nouveau_display_vblstamp(struct drm_device *, int, int *,
struct timeval *, unsigned);

int nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
struct drm_pending_vblank_event *event,
Expand Down
Loading

0 comments on commit ef64cf9

Please sign in to comment.