diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c index 0f1c223cc7a8..4ad31302aaf4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c @@ -23,6 +23,7 @@ */ #include "dp.h" #include "conn.h" +#include "head.h" #include "ior.h" #include @@ -419,19 +420,28 @@ nvkm_dp_train(struct nvkm_dp *dp, u32 dataKBps) } int -nvkm_output_dp_train(struct nvkm_outp *outp, u32 datakbps) +nvkm_output_dp_train(struct nvkm_outp *outp, u32 unused) { struct nvkm_dp *dp = nvkm_dp(outp); struct nvkm_ior *ior = dp->outp.ior; + struct nvkm_head *head; bool retrain = true; - u32 linkKBps; + u32 datakbps = 0; u32 dataKBps; + u32 linkKBps; u8 stat[3]; int ret, i; mutex_lock(&dp->mutex); /* Check that link configuration meets current requirements. */ + list_for_each_entry(head, &outp->disp->head, head) { + if (ior->asy.head & (1 << head->id)) { + u32 khz = (head->asy.hz >> ior->asy.rgdiv) / 1000; + datakbps += khz * head->asy.or.depth; + } + } + linkKBps = ior->dp.bw * 27000 * ior->dp.nr; dataKBps = DIV_ROUND_UP(datakbps, 8); OUTP_DBG(&dp->outp, "data %d KB/s link %d KB/s mst %d->%d", diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.h index 94f5cb7596a0..829a0a8cfb2e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.h @@ -18,6 +18,12 @@ struct nvkm_head { u16 vsynce; u16 vblanke; u16 vblanks; + u32 hz; + + /* Prior to GF119, these are set by the OR. */ + struct { + u8 depth; + } or; } arm, asy; }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/headgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/headgf119.c index 8e7acc57d31d..d2bd6bb4a621 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/headgf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/headgf119.c @@ -58,6 +58,19 @@ gf119_head_state(struct nvkm_head *head, struct nvkm_head_state *state) data = nvkm_rd32(device, 0x640420 + hoff); state->vblanks = (data & 0xffff0000) >> 16; state->hblanks = (data & 0x0000ffff); + state->hz = nvkm_rd32(device, 0x640450 + hoff); + + data = nvkm_rd32(device, 0x640404 + hoff); + switch ((data & 0x000003c0) >> 6) { + case 6: state->or.depth = 30; break; + case 5: state->or.depth = 24; break; + case 2: state->or.depth = 18; break; + case 0: state->or.depth = 18; break; /*XXX: "default" */ + default: + state->or.depth = 18; + WARN_ON(1); + break; + } } static const struct nvkm_head_func diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv50.c index 3cccda2cb09e..d4a9879f0d0a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv50.c @@ -66,6 +66,7 @@ nv50_head_state(struct nvkm_head *head, struct nvkm_head_state *state) data = nvkm_rd32(device, 0x610b00 + hoff); state->vsynce = (data & 0xffff0000) >> 16; state->hsynce = (data & 0x0000ffff); + state->hz = (nvkm_rd32(device, 0x610ad0 + hoff) & 0x003fffff) * 1000; } static const struct nvkm_head_func diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h index a2e38d4780b1..3a6e01f5a0e5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h @@ -89,6 +89,8 @@ nv50_ior_base(struct nvkm_ior *ior) void nv50_dac_power(struct nvkm_ior *, bool, bool, bool, bool, bool); int nv50_dac_sense(struct nvkm_ior *, u32); +void nv50_pior_depth(struct nvkm_ior *, struct nvkm_ior_state *, u32 ctrl); + static inline u32 nv50_sor_link(struct nvkm_ior *ior) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c index f66beda1ae11..dc59c319377e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "ior.h" +#include "head.h" #include #include @@ -60,6 +61,31 @@ nv50_pior_power(struct nvkm_ior *pior, bool normal, bool pu, nv50_pior_power_wait(device, poff); } +void +nv50_pior_depth(struct nvkm_ior *ior, struct nvkm_ior_state *state, u32 ctrl) +{ + /* GF119 moves this information to per-head methods, which is + * a lot more convenient, and where our shared code expect it. + */ + if (state->head && state == &ior->asy) { + struct nvkm_head *head = + nvkm_head_find(ior->disp, __ffs(state->head)); + if (!WARN_ON(!head)) { + struct nvkm_head_state *state = &head->asy; + switch ((ctrl & 0x000f0000) >> 16) { + case 6: state->or.depth = 30; break; + case 5: state->or.depth = 24; break; + case 2: state->or.depth = 18; break; + case 0: state->or.depth = 18; break; /*XXX*/ + default: + state->or.depth = 18; + WARN_ON(1); + break; + } + } + } +} + static void nv50_pior_state(struct nvkm_ior *pior, struct nvkm_ior_state *state) { @@ -77,6 +103,7 @@ nv50_pior_state(struct nvkm_ior *pior, struct nvkm_ior_state *state) } state->head = ctrl & 0x00000003; + nv50_pior_depth(pior, state, ctrl); } static const struct nvkm_ior_func diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c index bfc7b0e053a4..5abf563b0e84 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c @@ -238,6 +238,7 @@ g94_sor_state(struct nvkm_ior *sor, struct nvkm_ior_state *state) } state->head = ctrl & 0x00000003; + nv50_pior_depth(sor, state, ctrl); } static const struct nvkm_ior_func