drm/nouveau/disp/dp: determine link bandwidth requirements from head state
authorBen Skeggs <bskeggs@redhat.com>
Fri, 19 May 2017 13:59:35 +0000 (23:59 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Fri, 16 Jun 2017 04:04:58 +0000 (14:04 +1000)
Training/Untraining will be hooked up to the routing logic, which
doesn't allow us to pass in a data rate.

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c
drivers/gpu/drm/nouveau/nvkm/engine/disp/head.h
drivers/gpu/drm/nouveau/nvkm/engine/disp/headgf119.c
drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv50.c
drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h
drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c
drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c

index 0f1c223cc7a8e26a2072af21eab7eb3eedf59145..4ad31302aaf49e5ee1ec92658617488caa12fce2 100644 (file)
@@ -23,6 +23,7 @@
  */
 #include "dp.h"
 #include "conn.h"
+#include "head.h"
 #include "ior.h"
 
 #include <subdev/bios.h>
@@ -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",
index 94f5cb7596a04f68d315ece9b303b6926d0a122e..829a0a8cfb2e7d267fa0ab9674eb3916254482bc 100644 (file)
@@ -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;
 };
 
index 8e7acc57d31de7e100f81532050129c9f6f72dee..d2bd6bb4a6215455a1cb661618e6fc2cd1990f75 100644 (file)
@@ -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
index 3cccda2cb09ec628def23ab0aa006af9220f7bd0..d4a9879f0d0a3dc71beb5166fd6e727494621517 100644 (file)
@@ -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
index a2e38d4780b1e1ae86dab6bf9164a26f3995ded5..3a6e01f5a0e5f9a36ef2a3ce99ea96abca030ed9 100644 (file)
@@ -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)
 {
index f66beda1ae11f01142dd5b5a18bd8b54e6d0e1b1..dc59c319377e806c39589658342e989822e1f3de 100644 (file)
@@ -22,6 +22,7 @@
  * Authors: Ben Skeggs
  */
 #include "ior.h"
+#include "head.h"
 
 #include <subdev/i2c.h>
 #include <subdev/timer.h>
@@ -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
index bfc7b0e053a4fb3177b3b14678f7111364bbf391..5abf563b0e84bdb5db28206480a2a8b821bbc36e 100644 (file)
@@ -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