summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/nv50_display.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2014-09-16 06:20:53 +1000
committerDave Airlie <airlied@redhat.com>2014-09-16 06:20:53 +1000
commit4ac073640a528662a7c072a30e92e70ce00ded33 (patch)
tree8c5394ff496af5edf31d7124a7fab95756b97a75 /drivers/gpu/drm/nouveau/nv50_display.c
parent19524f7c59c19854caf5b82d89bc558e38da5790 (diff)
parentcc2a9071458254cb0db6153811734750da0233ea (diff)
downloadtalos-op-linux-4ac073640a528662a7c072a30e92e70ce00ded33.tar.gz
talos-op-linux-4ac073640a528662a7c072a30e92e70ce00ded33.zip
Merge branch 'linux-3.18' of git://anongit.freedesktop.org/git/nouveau/linux-2.6 into drm-next
This is the main merge request for Nouveau 3.18, overview: - various bits of roy's gt21x clock work - various bits of kepler memory clock work (don't get too excited, there's at least one more major bit left that's busting higher freqs) - misc fan control improvements - kepler hdmi infoframe fixes - dp audio - l2 cache + cbc improvements * 'linux-3.18' of git://anongit.freedesktop.org/git/nouveau/linux-2.6: (68 commits) drm/gt214-/disp: enable dp audio drm/gt214-/kms: fix hda eld regression drm/g94-/disp: calculate some dp audio constants drm/gt214-/kms: perform hda codec setup on displayport too drm/gk104-/disp: infoframe registers moved yet again on kepler drm/nouveau/bios: parse older ramcfg/timing data like we do newer ones drm/nva3/fb/ram: Per-partition regs drm/nouveau/fb/ram: Support strided regs drm/nv50/fb/ram: Store the number of partitions in the designated fields drm/nv50/kms: Set VBLANK time in modeset script drm/nouveau/bios: Add rammap support for version 1.0 drm/gf100-/pwr/memx: block host and fifo around reclock drm/nouveau/pwr/memx: fix command ordering around block/unblock drm/nouveau/pwr/memx: rename fb off/on to block/unblock drm/nva3/clk: Pause the GPU before reclocking drm/nouveau/gpio: rename g92 class to g94 drm/gk104-/fb/ram: move fb enable/disable to same place as nvidia drm/gk104/fb/ram: twiddle some more bits when reclocking drm/nouveau/bios: parse another large chunk of random memory config data drm/gk104-/fb/ram: perform certain steps only when bios data differs ...
Diffstat (limited to 'drivers/gpu/drm/nouveau/nv50_display.c')
-rw-r--r--drivers/gpu/drm/nouveau/nv50_display.c40
1 files changed, 25 insertions, 15 deletions
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index 03949eaa629f..fdb3e1adea1e 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -1066,7 +1066,7 @@ nv50_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *umode,
u32 vscan = (mode->flags & DRM_MODE_FLAG_DBLSCAN) ? 2 : 1;
u32 hactive, hsynce, hbackp, hfrontp, hblanke, hblanks;
u32 vactive, vsynce, vbackp, vfrontp, vblanke, vblanks;
- u32 vblan2e = 0, vblan2s = 1;
+ u32 vblan2e = 0, vblan2s = 1, vblankus = 0;
u32 *push;
int ret;
@@ -1083,6 +1083,11 @@ nv50_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *umode,
vblanke = vsynce + vbackp;
vfrontp = (mode->vsync_start - mode->vdisplay) * vscan / ilace;
vblanks = vactive - vfrontp - 1;
+ /* XXX: Safe underestimate, even "0" works */
+ vblankus = (vactive - mode->vdisplay - 2) * hactive;
+ vblankus *= 1000;
+ vblankus /= mode->clock;
+
if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
vblan2e = vactive + vsynce + vbackp;
vblan2s = vblan2e + (mode->vdisplay * vscan / ilace);
@@ -1099,14 +1104,14 @@ nv50_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *umode,
evo_mthd(push, 0x0804 + (nv_crtc->index * 0x400), 2);
evo_data(push, 0x00800000 | mode->clock);
evo_data(push, (ilace == 2) ? 2 : 0);
- evo_mthd(push, 0x0810 + (nv_crtc->index * 0x400), 6);
+ evo_mthd(push, 0x0810 + (nv_crtc->index * 0x400), 8);
evo_data(push, 0x00000000);
evo_data(push, (vactive << 16) | hactive);
evo_data(push, ( vsynce << 16) | hsynce);
evo_data(push, (vblanke << 16) | hblanke);
evo_data(push, (vblanks << 16) | hblanks);
evo_data(push, (vblan2e << 16) | vblan2s);
- evo_mthd(push, 0x082c + (nv_crtc->index * 0x400), 1);
+ evo_data(push, vblankus);
evo_data(push, 0x00000000);
evo_mthd(push, 0x0900 + (nv_crtc->index * 0x400), 2);
evo_data(push, 0x00000311);
@@ -1651,17 +1656,21 @@ static void
nv50_audio_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode)
{
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+ struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
struct nouveau_connector *nv_connector;
struct nv50_disp *disp = nv50_disp(encoder->dev);
- struct {
- struct nv50_disp_mthd_v1 base;
- struct nv50_disp_sor_hda_eld_v0 eld;
+ struct __packed {
+ struct {
+ struct nv50_disp_mthd_v1 mthd;
+ struct nv50_disp_sor_hda_eld_v0 eld;
+ } base;
u8 data[sizeof(nv_connector->base.eld)];
} args = {
- .base.version = 1,
- .base.method = NV50_DISP_MTHD_V1_SOR_HDA_ELD,
- .base.hasht = nv_encoder->dcb->hasht,
- .base.hashm = nv_encoder->dcb->hashm,
+ .base.mthd.version = 1,
+ .base.mthd.method = NV50_DISP_MTHD_V1_SOR_HDA_ELD,
+ .base.mthd.hasht = nv_encoder->dcb->hasht,
+ .base.mthd.hashm = (0xf0ff & nv_encoder->dcb->hashm) |
+ (0x0100 << nv_crtc->index),
};
nv_connector = nouveau_encoder_connector_get(nv_encoder);
@@ -1671,11 +1680,11 @@ nv50_audio_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode)
drm_edid_to_eld(&nv_connector->base, nv_connector->edid);
memcpy(args.data, nv_connector->base.eld, sizeof(args.data));
- nvif_mthd(disp->disp, 0, &args, sizeof(args));
+ nvif_mthd(disp->disp, 0, &args, sizeof(args.base) + args.data[2] * 4);
}
static void
-nv50_audio_disconnect(struct drm_encoder *encoder)
+nv50_audio_disconnect(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc)
{
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
struct nv50_disp *disp = nv50_disp(encoder->dev);
@@ -1686,7 +1695,8 @@ nv50_audio_disconnect(struct drm_encoder *encoder)
.base.version = 1,
.base.method = NV50_DISP_MTHD_V1_SOR_HDA_ELD,
.base.hasht = nv_encoder->dcb->hasht,
- .base.hashm = nv_encoder->dcb->hashm,
+ .base.hashm = (0xf0ff & nv_encoder->dcb->hashm) |
+ (0x0100 << nv_crtc->index),
};
nvif_mthd(disp->disp, 0, &args, sizeof(args));
@@ -1745,8 +1755,6 @@ nv50_hdmi_disconnect(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc)
(0x0100 << nv_crtc->index),
};
- nv50_audio_disconnect(encoder);
-
nvif_mthd(disp->disp, 0, &args, sizeof(args));
}
@@ -1855,6 +1863,7 @@ nv50_sor_disconnect(struct drm_encoder *encoder)
if (nv_crtc) {
nv50_crtc_prepare(&nv_crtc->base);
nv50_sor_ctrl(nv_encoder, 1 << nv_crtc->index, 0);
+ nv50_audio_disconnect(encoder, nv_crtc);
nv50_hdmi_disconnect(&nv_encoder->base.base, nv_crtc);
}
}
@@ -1954,6 +1963,7 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode,
proto = 0x8;
else
proto = 0x9;
+ nv50_audio_mode_set(encoder, mode);
break;
default:
BUG_ON(1);
OpenPOWER on IntegriCloud