From 952eb819e3234b9deceb3287398f0c2a272e4760 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 30 May 2016 10:32:55 +1000 Subject: [PATCH 01/97] drm/nouveau/top: take nvkm_device as argument to public functions Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvkm/subdev/top.h | 8 ++++---- drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c | 5 ++--- drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c | 4 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/top/base.c | 12 ++++++++---- 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/top.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/top.h index 8fb575a92c48..5f75a66bfdbf 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/top.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/top.h @@ -8,10 +8,10 @@ struct nvkm_top { struct list_head device; }; -u32 nvkm_top_reset(struct nvkm_top *, enum nvkm_devidx); -u32 nvkm_top_intr(struct nvkm_top *, u32 intr, u64 *subdevs); -enum nvkm_devidx nvkm_top_fault(struct nvkm_top *, int fault); -enum nvkm_devidx nvkm_top_engine(struct nvkm_top *, int, int *runl, int *engn); +u32 nvkm_top_reset(struct nvkm_device *, enum nvkm_devidx); +u32 nvkm_top_intr(struct nvkm_device *, u32 intr, u64 *subdevs); +enum nvkm_devidx nvkm_top_fault(struct nvkm_device *, int fault); +enum nvkm_devidx nvkm_top_engine(struct nvkm_device *, int, int *runl, int *engn); int gk104_top_new(struct nvkm_device *, int, struct nvkm_top **); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c index 743f3a189f28..f574b744cf66 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c @@ -329,7 +329,7 @@ gk104_fifo_intr_fault(struct gk104_fifo *fifo, int unit) } if (eu == NULL) { - enum nvkm_devidx engidx = nvkm_top_fault(device->top, unit); + enum nvkm_devidx engidx = nvkm_top_fault(device, unit); if (engidx < NVKM_SUBDEV_NR) { const char *src = nvkm_subdev_name[engidx]; char *dst = en; @@ -589,7 +589,6 @@ gk104_fifo_oneinit(struct nvkm_fifo *base) struct gk104_fifo *fifo = gk104_fifo(base); struct nvkm_subdev *subdev = &fifo->base.engine.subdev; struct nvkm_device *device = subdev->device; - struct nvkm_top *top = device->top; int engn, runl, pbid, ret, i, j; enum nvkm_devidx engidx; u32 *map; @@ -608,7 +607,7 @@ gk104_fifo_oneinit(struct nvkm_fifo *base) /* Determine runlist configuration from topology device info. */ i = 0; - while ((int)(engidx = nvkm_top_engine(top, i++, &runl, &engn)) >= 0) { + while ((int)(engidx = nvkm_top_engine(device, i++, &runl, &engn)) >= 0) { /* Determine which PBDMA handles requests for this engine. */ for (j = 0, pbid = -1; j < fifo->pbdma_nr; j++) { if (map[j] & (1 << runl)) { diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c index 350a8caa84c8..60d5c956f676 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c @@ -63,7 +63,7 @@ nvkm_mc_intr(struct nvkm_mc *mc, bool *handled) u32 stat, intr = nvkm_mc_intr_mask(mc); u64 subdevs; - stat = nvkm_top_intr(device->top, intr, &subdevs); + stat = nvkm_top_intr(device, intr, &subdevs); while (subdevs) { enum nvkm_devidx subidx = __ffs64(subdevs); subdev = nvkm_device_subdev(device, subidx); @@ -94,7 +94,7 @@ nvkm_mc_reset_(struct nvkm_mc *mc, enum nvkm_devidx devidx) const struct nvkm_mc_map *map; u64 pmc_enable; - if (!(pmc_enable = nvkm_top_reset(device->top, devidx))) { + if (!(pmc_enable = nvkm_top_reset(device, devidx))) { for (map = mc->func->reset; map && map->stat; map++) { if (map->unit == devidx) { pmc_enable = map->stat; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/top/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/top/base.c index a1b264664aad..19fbcfdb08e8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/top/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/top/base.c @@ -41,8 +41,9 @@ nvkm_top_device_new(struct nvkm_top *top) } u32 -nvkm_top_reset(struct nvkm_top *top, enum nvkm_devidx index) +nvkm_top_reset(struct nvkm_device *device, enum nvkm_devidx index) { + struct nvkm_top *top = device->top; struct nvkm_top_device *info; if (top) { @@ -56,8 +57,9 @@ nvkm_top_reset(struct nvkm_top *top, enum nvkm_devidx index) } u32 -nvkm_top_intr(struct nvkm_top *top, u32 intr, u64 *psubdevs) +nvkm_top_intr(struct nvkm_device *device, u32 intr, u64 *psubdevs) { + struct nvkm_top *top = device->top; struct nvkm_top_device *info; u64 subdevs = 0; u32 handled = 0; @@ -78,8 +80,9 @@ nvkm_top_intr(struct nvkm_top *top, u32 intr, u64 *psubdevs) } enum nvkm_devidx -nvkm_top_fault(struct nvkm_top *top, int fault) +nvkm_top_fault(struct nvkm_device *device, int fault) { + struct nvkm_top *top = device->top; struct nvkm_top_device *info; list_for_each_entry(info, &top->device, head) { @@ -91,8 +94,9 @@ nvkm_top_fault(struct nvkm_top *top, int fault) } enum nvkm_devidx -nvkm_top_engine(struct nvkm_top *top, int index, int *runl, int *engn) +nvkm_top_engine(struct nvkm_device *device, int index, int *runl, int *engn) { + struct nvkm_top *top = device->top; struct nvkm_top_device *info; int n = 0; From 3560e1703f4f7605da203561bad0e231706b93bd Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 30 May 2016 10:36:02 +1000 Subject: [PATCH 02/97] drm/nouveau/top: add function to lookup interrupt mask for a given device Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/subdev/top.h | 1 + drivers/gpu/drm/nouveau/nvkm/subdev/top/base.c | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/top.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/top.h index 5f75a66bfdbf..71ebbfd4484f 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/top.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/top.h @@ -10,6 +10,7 @@ struct nvkm_top { u32 nvkm_top_reset(struct nvkm_device *, enum nvkm_devidx); u32 nvkm_top_intr(struct nvkm_device *, u32 intr, u64 *subdevs); +u32 nvkm_top_intr_mask(struct nvkm_device *, enum nvkm_devidx); enum nvkm_devidx nvkm_top_fault(struct nvkm_device *, int fault); enum nvkm_devidx nvkm_top_engine(struct nvkm_device *, int, int *runl, int *engn); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/top/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/top/base.c index 19fbcfdb08e8..fe063d5728e2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/top/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/top/base.c @@ -56,6 +56,22 @@ nvkm_top_reset(struct nvkm_device *device, enum nvkm_devidx index) return 0; } +u32 +nvkm_top_intr_mask(struct nvkm_device *device, enum nvkm_devidx devidx) +{ + struct nvkm_top *top = device->top; + struct nvkm_top_device *info; + + if (top) { + list_for_each_entry(info, &top->device, head) { + if (info->index == devidx && info->intr >= 0) + return BIT(info->intr); + } + } + + return 0; +} + u32 nvkm_top_intr(struct nvkm_device *device, u32 intr, u64 *psubdevs) { From d6adbe949d57f6933d6ac29cce3e7168a53e3749 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 30 May 2016 09:23:06 +1000 Subject: [PATCH 03/97] drm/nouveau/mc: allow construction of subclassed device Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c | 13 +++++++++---- drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h | 2 ++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c index 60d5c956f676..fa6b9932d327 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c @@ -148,16 +148,21 @@ nvkm_mc = { .fini = nvkm_mc_fini, }; +void +nvkm_mc_ctor(const struct nvkm_mc_func *func, struct nvkm_device *device, + int index, struct nvkm_mc *mc) +{ + nvkm_subdev_ctor(&nvkm_mc, device, index, &mc->subdev); + mc->func = func; +} + int nvkm_mc_new_(const struct nvkm_mc_func *func, struct nvkm_device *device, int index, struct nvkm_mc **pmc) { struct nvkm_mc *mc; - if (!(mc = *pmc = kzalloc(sizeof(*mc), GFP_KERNEL))) return -ENOMEM; - - nvkm_subdev_ctor(&nvkm_mc, device, index, &mc->subdev); - mc->func = func; + nvkm_mc_ctor(func, device, index, *pmc); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h index a12038118512..536b8bd7cc90 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h @@ -3,6 +3,8 @@ #define nvkm_mc(p) container_of((p), struct nvkm_mc, subdev) #include +void nvkm_mc_ctor(const struct nvkm_mc_func *, struct nvkm_device *, + int index, struct nvkm_mc *); int nvkm_mc_new_(const struct nvkm_mc_func *, struct nvkm_device *, int index, struct nvkm_mc **); From d398119034a4b78d475e3853b3b0ad9fa26f6c52 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 30 May 2016 08:17:58 +1000 Subject: [PATCH 04/97] drm/nouveau/mc: take nvkm_device as argument to public functions Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/subdev/mc.h | 10 ++--- drivers/gpu/drm/nouveau/nvkm/core/subdev.c | 2 +- .../drm/nouveau/nvkm/engine/device/tegra.c | 10 ++--- .../gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/gr/gf100.c | 8 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c | 40 +++++++++++-------- .../gpu/drm/nouveau/nvkm/subdev/pci/base.c | 14 +++---- 9 files changed, 50 insertions(+), 46 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h index 2e80682b2da1..45e695348577 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h @@ -7,11 +7,11 @@ struct nvkm_mc { struct nvkm_subdev subdev; }; -void nvkm_mc_intr(struct nvkm_mc *, bool *handled); -void nvkm_mc_intr_unarm(struct nvkm_mc *); -void nvkm_mc_intr_rearm(struct nvkm_mc *); -void nvkm_mc_reset(struct nvkm_mc *, enum nvkm_devidx); -void nvkm_mc_unk260(struct nvkm_mc *, u32 data); +void nvkm_mc_intr(struct nvkm_device *, bool *handled); +void nvkm_mc_intr_unarm(struct nvkm_device *); +void nvkm_mc_intr_rearm(struct nvkm_device *); +void nvkm_mc_reset(struct nvkm_device *, enum nvkm_devidx); +void nvkm_mc_unk260(struct nvkm_device *, u32 data); int nv04_mc_new(struct nvkm_device *, int, struct nvkm_mc **); int nv11_mc_new(struct nvkm_device *, int, struct nvkm_mc **); diff --git a/drivers/gpu/drm/nouveau/nvkm/core/subdev.c b/drivers/gpu/drm/nouveau/nvkm/core/subdev.c index b18557858f19..f17fd7ddc7ca 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/subdev.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/subdev.c @@ -105,7 +105,7 @@ nvkm_subdev_fini(struct nvkm_subdev *subdev, bool suspend) } } - nvkm_mc_reset(device->mc, subdev->index); + nvkm_mc_reset(device, subdev->index); time = ktime_to_us(ktime_get()) - time; nvkm_trace(subdev, "%s completed in %lldus\n", action, time); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c index ec12efb4689a..8edc0a583ae2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c @@ -191,13 +191,11 @@ static irqreturn_t nvkm_device_tegra_intr(int irq, void *arg) { struct nvkm_device_tegra *tdev = arg; - struct nvkm_mc *mc = tdev->device.mc; + struct nvkm_device *device = &tdev->device; bool handled = false; - if (likely(mc)) { - nvkm_mc_intr_unarm(mc); - nvkm_mc_intr(mc, &handled); - nvkm_mc_intr_rearm(mc); - } + nvkm_mc_intr_unarm(device); + nvkm_mc_intr(device, &handled); + nvkm_mc_intr_rearm(device); return handled ? IRQ_HANDLED : IRQ_NONE; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c index b02d8f50ea6a..bc77eea351a5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c @@ -1240,7 +1240,7 @@ gf100_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) const struct gf100_grctx_func *grctx = gr->func->grctx; u32 idle_timeout; - nvkm_mc_unk260(device->mc, 0); + nvkm_mc_unk260(device, 0); gf100_gr_mmio(gr, grctx->hub); gf100_gr_mmio(gr, grctx->gpc); @@ -1264,7 +1264,7 @@ gf100_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) gf100_gr_icmd(gr, grctx->icmd); nvkm_wr32(device, 0x404154, idle_timeout); gf100_gr_mthd(gr, grctx->mthd); - nvkm_mc_unk260(device->mc, 1); + nvkm_mc_unk260(device, 1); } int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c index f521de11a299..c925ade5880e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c @@ -226,7 +226,7 @@ gf117_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) u32 idle_timeout; int i; - nvkm_mc_unk260(device->mc, 0); + nvkm_mc_unk260(device, 0); gf100_gr_mmio(gr, grctx->hub); gf100_gr_mmio(gr, grctx->gpc); @@ -253,7 +253,7 @@ gf117_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) gf100_gr_icmd(gr, grctx->icmd); nvkm_wr32(device, 0x404154, idle_timeout); gf100_gr_mthd(gr, grctx->mthd); - nvkm_mc_unk260(device->mc, 1); + nvkm_mc_unk260(device, 1); } const struct gf100_grctx_func diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c index 9ba337778ef5..c46b3fdf7203 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c @@ -950,7 +950,7 @@ gk104_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) u32 idle_timeout; int i; - nvkm_mc_unk260(device->mc, 0); + nvkm_mc_unk260(device, 0); gf100_gr_mmio(gr, grctx->hub); gf100_gr_mmio(gr, grctx->gpc); @@ -979,7 +979,7 @@ gk104_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) gf100_gr_icmd(gr, grctx->icmd); nvkm_wr32(device, 0x404154, idle_timeout); gf100_gr_mthd(gr, grctx->mthd); - nvkm_mc_unk260(device->mc, 1); + nvkm_mc_unk260(device, 1); nvkm_mask(device, 0x418800, 0x00200000, 0x00200000); nvkm_mask(device, 0x41be10, 0x00800000, 0x00800000); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c index ae9ab5b1ab97..7d14d058b745 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c @@ -1460,7 +1460,7 @@ gf100_gr_init_ctxctl(struct gf100_gr *gr) if (gr->firmware) { /* load fuc microcode */ - nvkm_mc_unk260(device->mc, 0); + nvkm_mc_unk260(device, 0); /* securely-managed falcons must be reset using secure boot */ if (nvkm_secboot_is_managed(sb, NVKM_SECBOOT_FALCON_FECS)) @@ -1474,7 +1474,7 @@ gf100_gr_init_ctxctl(struct gf100_gr *gr) gf100_gr_init_fw(gr, 0x41a000, &gr->fuc41ac, &gr->fuc41ad); - nvkm_mc_unk260(device->mc, 1); + nvkm_mc_unk260(device, 1); /* start both of them running */ nvkm_wr32(device, 0x409840, 0xffffffff); @@ -1576,7 +1576,7 @@ gf100_gr_init_ctxctl(struct gf100_gr *gr) } /* load HUB microcode */ - nvkm_mc_unk260(device->mc, 0); + nvkm_mc_unk260(device, 0); nvkm_wr32(device, 0x4091c0, 0x01000000); for (i = 0; i < gr->func->fecs.ucode->data.size / 4; i++) nvkm_wr32(device, 0x4091c4, gr->func->fecs.ucode->data.data[i]); @@ -1599,7 +1599,7 @@ gf100_gr_init_ctxctl(struct gf100_gr *gr) nvkm_wr32(device, 0x41a188, i >> 6); nvkm_wr32(device, 0x41a184, gr->func->gpccs.ucode->code.data[i]); } - nvkm_mc_unk260(device->mc, 1); + nvkm_mc_unk260(device, 1); /* load register lists */ gf100_gr_init_csdata(gr, grctx->hub, 0x409000, 0x000, 0x000000); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c index fa6b9932d327..563a528d42ce 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c @@ -27,22 +27,27 @@ #include void -nvkm_mc_unk260(struct nvkm_mc *mc, u32 data) +nvkm_mc_unk260(struct nvkm_device *device, u32 data) { - if (mc->func->unk260) + struct nvkm_mc *mc = device->mc; + if (likely(mc) && mc->func->unk260) mc->func->unk260(mc, data); } void -nvkm_mc_intr_unarm(struct nvkm_mc *mc) +nvkm_mc_intr_unarm(struct nvkm_device *device) { - return mc->func->intr_unarm(mc); + struct nvkm_mc *mc = device->mc; + if (likely(mc)) + mc->func->intr_unarm(mc); } void -nvkm_mc_intr_rearm(struct nvkm_mc *mc) +nvkm_mc_intr_rearm(struct nvkm_device *device) { - return mc->func->intr_rearm(mc); + struct nvkm_mc *mc = device->mc; + if (likely(mc)) + mc->func->intr_rearm(mc); } static u32 @@ -55,14 +60,18 @@ nvkm_mc_intr_mask(struct nvkm_mc *mc) } void -nvkm_mc_intr(struct nvkm_mc *mc, bool *handled) +nvkm_mc_intr(struct nvkm_device *device, bool *handled) { - struct nvkm_device *device = mc->subdev.device; + struct nvkm_mc *mc = device->mc; struct nvkm_subdev *subdev; - const struct nvkm_mc_map *map = mc->func->intr; - u32 stat, intr = nvkm_mc_intr_mask(mc); + const struct nvkm_mc_map *map; + u32 stat, intr; u64 subdevs; + if (unlikely(!mc)) + return; + + intr = nvkm_mc_intr_mask(mc); stat = nvkm_top_intr(device, intr, &subdevs); while (subdevs) { enum nvkm_devidx subidx = __ffs64(subdevs); @@ -72,14 +81,13 @@ nvkm_mc_intr(struct nvkm_mc *mc, bool *handled) subdevs &= ~BIT_ULL(subidx); } - while (map->stat) { + for (map = mc->func->intr; map->stat; map++) { if (intr & map->stat) { subdev = nvkm_device_subdev(device, map->unit); if (subdev) nvkm_subdev_intr(subdev); stat &= ~map->stat; } - map++; } if (stat) @@ -111,8 +119,9 @@ nvkm_mc_reset_(struct nvkm_mc *mc, enum nvkm_devidx devidx) } void -nvkm_mc_reset(struct nvkm_mc *mc, enum nvkm_devidx devidx) +nvkm_mc_reset(struct nvkm_device *device, enum nvkm_devidx devidx) { + struct nvkm_mc *mc = device->mc; if (likely(mc)) nvkm_mc_reset_(mc, devidx); } @@ -120,8 +129,7 @@ nvkm_mc_reset(struct nvkm_mc *mc, enum nvkm_devidx devidx) static int nvkm_mc_fini(struct nvkm_subdev *subdev, bool suspend) { - struct nvkm_mc *mc = nvkm_mc(subdev); - nvkm_mc_intr_unarm(mc); + nvkm_mc_intr_unarm(subdev->device); return 0; } @@ -131,7 +139,7 @@ nvkm_mc_init(struct nvkm_subdev *subdev) struct nvkm_mc *mc = nvkm_mc(subdev); if (mc->func->init) mc->func->init(mc); - nvkm_mc_intr_rearm(mc); + nvkm_mc_intr_rearm(subdev->device); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c index 6b0328bd7eed..eb9b278198b2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c @@ -69,15 +69,13 @@ static irqreturn_t nvkm_pci_intr(int irq, void *arg) { struct nvkm_pci *pci = arg; - struct nvkm_mc *mc = pci->subdev.device->mc; + struct nvkm_device *device = pci->subdev.device; bool handled = false; - if (likely(mc)) { - nvkm_mc_intr_unarm(mc); - if (pci->msi) - pci->func->msi_rearm(pci); - nvkm_mc_intr(mc, &handled); - nvkm_mc_intr_rearm(mc); - } + nvkm_mc_intr_unarm(device); + if (pci->msi) + pci->func->msi_rearm(pci); + nvkm_mc_intr(device, &handled); + nvkm_mc_intr_rearm(device); return handled ? IRQ_HANDLED : IRQ_NONE; } From 3c2a536b0cbac98035cba42c880c58fd399cb167 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 30 May 2016 08:23:41 +1000 Subject: [PATCH 05/97] drm/nouveau/mc: expose device enable/disable separately, as well as reset There are cases where subdevs need to perform additonal actions around the master reset, so we want to expost the operations separately. This commit also adds a flag to the NV_PMC_ENABLE bitfield definitions which allow skipping the automatic reset() called from core/subdev.c. Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/subdev/mc.h | 4 +- drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c | 48 +++++++++++++------ drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h | 1 + 3 files changed, 38 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h index 45e695348577..c5f12352c0eb 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h @@ -7,10 +7,12 @@ struct nvkm_mc { struct nvkm_subdev subdev; }; +void nvkm_mc_enable(struct nvkm_device *, enum nvkm_devidx); +void nvkm_mc_disable(struct nvkm_device *, enum nvkm_devidx); +void nvkm_mc_reset(struct nvkm_device *, enum nvkm_devidx); void nvkm_mc_intr(struct nvkm_device *, bool *handled); void nvkm_mc_intr_unarm(struct nvkm_device *); void nvkm_mc_intr_rearm(struct nvkm_device *); -void nvkm_mc_reset(struct nvkm_device *, enum nvkm_devidx); void nvkm_mc_unk260(struct nvkm_device *, u32 data); int nv04_mc_new(struct nvkm_device *, int, struct nvkm_mc **); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c index 563a528d42ce..e887df08e8cf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c @@ -95,22 +95,32 @@ nvkm_mc_intr(struct nvkm_device *device, bool *handled) *handled = intr != 0; } -static void -nvkm_mc_reset_(struct nvkm_mc *mc, enum nvkm_devidx devidx) +static u32 +nvkm_mc_reset_mask(struct nvkm_device *device, bool isauto, + enum nvkm_devidx devidx) { - struct nvkm_device *device = mc->subdev.device; + struct nvkm_mc *mc = device->mc; const struct nvkm_mc_map *map; - u64 pmc_enable; - - if (!(pmc_enable = nvkm_top_reset(device, devidx))) { - for (map = mc->func->reset; map && map->stat; map++) { - if (map->unit == devidx) { - pmc_enable = map->stat; - break; + u64 pmc_enable = 0; + if (likely(mc)) { + if (!(pmc_enable = nvkm_top_reset(device, devidx))) { + for (map = mc->func->reset; map && map->stat; map++) { + if (!isauto || !map->noauto) { + if (map->unit == devidx) { + pmc_enable = map->stat; + break; + } + } } } } + return pmc_enable; +} +void +nvkm_mc_reset(struct nvkm_device *device, enum nvkm_devidx devidx) +{ + u64 pmc_enable = nvkm_mc_reset_mask(device, true, devidx); if (pmc_enable) { nvkm_mask(device, 0x000200, pmc_enable, 0x00000000); nvkm_mask(device, 0x000200, pmc_enable, pmc_enable); @@ -119,11 +129,21 @@ nvkm_mc_reset_(struct nvkm_mc *mc, enum nvkm_devidx devidx) } void -nvkm_mc_reset(struct nvkm_device *device, enum nvkm_devidx devidx) +nvkm_mc_disable(struct nvkm_device *device, enum nvkm_devidx devidx) { - struct nvkm_mc *mc = device->mc; - if (likely(mc)) - nvkm_mc_reset_(mc, devidx); + u64 pmc_enable = nvkm_mc_reset_mask(device, false, devidx); + if (pmc_enable) + nvkm_mask(device, 0x000200, pmc_enable, 0x00000000); +} + +void +nvkm_mc_enable(struct nvkm_device *device, enum nvkm_devidx devidx) +{ + u64 pmc_enable = nvkm_mc_reset_mask(device, false, devidx); + if (pmc_enable) { + nvkm_mask(device, 0x000200, pmc_enable, pmc_enable); + nvkm_rd32(device, 0x000200); + } } static int diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h index 536b8bd7cc90..bace7fc3c232 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h @@ -11,6 +11,7 @@ int nvkm_mc_new_(const struct nvkm_mc_func *, struct nvkm_device *, struct nvkm_mc_map { u32 stat; u32 unit; + bool noauto; }; struct nvkm_mc_func { From 6e09a578995f4e724b90b1a8b1d5207a2ce5e3c8 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 30 May 2016 08:27:22 +1000 Subject: [PATCH 06/97] drm/nouveau/mc: s/intr_mask/intr_stat/ Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c | 6 +++--- drivers/gpu/drm/nouveau/nvkm/subdev/mc/g84.c | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/mc/g98.c | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c | 4 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk104.c | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/mc/gt215.c | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c | 4 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv11.c | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv17.c | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h | 6 +++--- 13 files changed, 19 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c index e887df08e8cf..6f10638ab9e4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c @@ -51,9 +51,9 @@ nvkm_mc_intr_rearm(struct nvkm_device *device) } static u32 -nvkm_mc_intr_mask(struct nvkm_mc *mc) +nvkm_mc_intr_stat(struct nvkm_mc *mc) { - u32 intr = mc->func->intr_mask(mc); + u32 intr = mc->func->intr_stat(mc); if (WARN_ON_ONCE(intr == 0xffffffff)) intr = 0; /* likely fallen off the bus */ return intr; @@ -71,7 +71,7 @@ nvkm_mc_intr(struct nvkm_device *device, bool *handled) if (unlikely(!mc)) return; - intr = nvkm_mc_intr_mask(mc); + intr = nvkm_mc_intr_stat(mc); stat = nvkm_top_intr(device, intr, &subdevs); while (subdevs) { enum nvkm_devidx subidx = __ffs64(subdevs); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g84.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g84.c index 5c85b47f071d..c3d66ef5dc12 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g84.c @@ -57,7 +57,7 @@ g84_mc = { .intr = g84_mc_intr, .intr_unarm = nv04_mc_intr_unarm, .intr_rearm = nv04_mc_intr_rearm, - .intr_mask = nv04_mc_intr_mask, + .intr_stat = nv04_mc_intr_stat, .reset = g84_mc_reset, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g98.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g98.c index 0280b43cc10c..93ad4982ce5f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g98.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g98.c @@ -57,7 +57,7 @@ g98_mc = { .intr = g98_mc_intr, .intr_unarm = nv04_mc_intr_unarm, .intr_rearm = nv04_mc_intr_rearm, - .intr_mask = nv04_mc_intr_mask, + .intr_stat = nv04_mc_intr_stat, .reset = g98_mc_reset, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c index 8397e223bd43..b1126a5a8b04 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c @@ -76,7 +76,7 @@ gf100_mc_intr_rearm(struct nvkm_mc *mc) } u32 -gf100_mc_intr_mask(struct nvkm_mc *mc) +gf100_mc_intr_stat(struct nvkm_mc *mc) { struct nvkm_device *device = mc->subdev.device; u32 intr0 = nvkm_rd32(device, 0x000100); @@ -96,7 +96,7 @@ gf100_mc = { .intr = gf100_mc_intr, .intr_unarm = gf100_mc_intr_unarm, .intr_rearm = gf100_mc_intr_rearm, - .intr_mask = gf100_mc_intr_mask, + .intr_stat = gf100_mc_intr_stat, .reset = gf100_mc_reset, .unk260 = gf100_mc_unk260, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk104.c index 317464212c7d..99426814c7f7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk104.c @@ -52,7 +52,7 @@ gk104_mc = { .intr = gk104_mc_intr, .intr_unarm = gf100_mc_intr_unarm, .intr_rearm = gf100_mc_intr_rearm, - .intr_mask = gf100_mc_intr_mask, + .intr_stat = gf100_mc_intr_stat, .reset = gk104_mc_reset, .unk260 = gf100_mc_unk260, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c index 60b044f517ed..985f8cbab5c4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c @@ -29,7 +29,7 @@ gk20a_mc = { .intr = gk104_mc_intr, .intr_unarm = gf100_mc_intr_unarm, .intr_rearm = gf100_mc_intr_rearm, - .intr_mask = gf100_mc_intr_mask, + .intr_stat = gf100_mc_intr_stat, .reset = gk104_mc_reset, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gt215.c index aad0ba95bf18..60c349a9d1f6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gt215.c @@ -59,7 +59,7 @@ gt215_mc = { .intr = gt215_mc_intr, .intr_unarm = nv04_mc_intr_unarm, .intr_rearm = nv04_mc_intr_rearm, - .intr_mask = nv04_mc_intr_mask, + .intr_stat = nv04_mc_intr_stat, .reset = gt215_mc_reset, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c index a062624e906b..6509defd1460 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c @@ -56,7 +56,7 @@ nv04_mc_intr_rearm(struct nvkm_mc *mc) } u32 -nv04_mc_intr_mask(struct nvkm_mc *mc) +nv04_mc_intr_stat(struct nvkm_mc *mc) { return nvkm_rd32(mc->subdev.device, 0x000100); } @@ -75,7 +75,7 @@ nv04_mc = { .intr = nv04_mc_intr, .intr_unarm = nv04_mc_intr_unarm, .intr_rearm = nv04_mc_intr_rearm, - .intr_mask = nv04_mc_intr_mask, + .intr_stat = nv04_mc_intr_stat, .reset = nv04_mc_reset, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv11.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv11.c index 55f0b9166b52..9213107901e6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv11.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv11.c @@ -39,7 +39,7 @@ nv11_mc = { .intr = nv11_mc_intr, .intr_unarm = nv04_mc_intr_unarm, .intr_rearm = nv04_mc_intr_rearm, - .intr_mask = nv04_mc_intr_mask, + .intr_stat = nv04_mc_intr_stat, .reset = nv04_mc_reset, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv17.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv17.c index c40fa67f79a5..64bf5bbf8146 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv17.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv17.c @@ -48,7 +48,7 @@ nv17_mc = { .intr = nv17_mc_intr, .intr_unarm = nv04_mc_intr_unarm, .intr_rearm = nv04_mc_intr_rearm, - .intr_mask = nv04_mc_intr_mask, + .intr_stat = nv04_mc_intr_stat, .reset = nv17_mc_reset, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c index cc56271db564..65fa44a64b98 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c @@ -43,7 +43,7 @@ nv44_mc = { .intr = nv17_mc_intr, .intr_unarm = nv04_mc_intr_unarm, .intr_rearm = nv04_mc_intr_rearm, - .intr_mask = nv04_mc_intr_mask, + .intr_stat = nv04_mc_intr_stat, .reset = nv17_mc_reset, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c index 343b6078580d..fe93b4fd7100 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c @@ -50,7 +50,7 @@ nv50_mc = { .intr = nv50_mc_intr, .intr_unarm = nv04_mc_intr_unarm, .intr_rearm = nv04_mc_intr_rearm, - .intr_mask = nv04_mc_intr_mask, + .intr_stat = nv04_mc_intr_stat, .reset = nv17_mc_reset, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h index bace7fc3c232..0229c7e01729 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h @@ -22,7 +22,7 @@ struct nvkm_mc_func { /* enable reporting of interrupts to host */ void (*intr_rearm)(struct nvkm_mc *); /* retrieve pending interrupt mask (NV_PMC_INTR) */ - u32 (*intr_mask)(struct nvkm_mc *); + u32 (*intr_stat)(struct nvkm_mc *); const struct nvkm_mc_map *reset; void (*unk260)(struct nvkm_mc *, u32); }; @@ -30,7 +30,7 @@ struct nvkm_mc_func { void nv04_mc_init(struct nvkm_mc *); void nv04_mc_intr_unarm(struct nvkm_mc *); void nv04_mc_intr_rearm(struct nvkm_mc *); -u32 nv04_mc_intr_mask(struct nvkm_mc *); +u32 nv04_mc_intr_stat(struct nvkm_mc *); extern const struct nvkm_mc_map nv04_mc_reset[]; extern const struct nvkm_mc_map nv17_mc_intr[]; @@ -42,7 +42,7 @@ void nv50_mc_init(struct nvkm_mc *); void gf100_mc_intr_unarm(struct nvkm_mc *); void gf100_mc_intr_rearm(struct nvkm_mc *); -u32 gf100_mc_intr_mask(struct nvkm_mc *); +u32 gf100_mc_intr_stat(struct nvkm_mc *); void gf100_mc_unk260(struct nvkm_mc *, u32); extern const struct nvkm_mc_map gk104_mc_intr[]; From 66adbfb00d55996079661d11ff9b6064b925b44e Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 30 May 2016 08:39:27 +1000 Subject: [PATCH 07/97] drm/nouveau/mc: support for temporarily masking interrupts from a specific device Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h | 1 + drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c | 15 +++++++++++++++ drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h | 2 ++ 3 files changed, 18 insertions(+) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h index c5f12352c0eb..81435d5a4adf 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h @@ -13,6 +13,7 @@ void nvkm_mc_reset(struct nvkm_device *, enum nvkm_devidx); void nvkm_mc_intr(struct nvkm_device *, bool *handled); void nvkm_mc_intr_unarm(struct nvkm_device *); void nvkm_mc_intr_rearm(struct nvkm_device *); +void nvkm_mc_intr_mask(struct nvkm_device *, enum nvkm_devidx, bool enable); void nvkm_mc_unk260(struct nvkm_device *, u32 data); int nv04_mc_new(struct nvkm_device *, int, struct nvkm_mc **); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c index 6f10638ab9e4..6b25e25f9eba 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c @@ -34,6 +34,21 @@ nvkm_mc_unk260(struct nvkm_device *device, u32 data) mc->func->unk260(mc, data); } +void +nvkm_mc_intr_mask(struct nvkm_device *device, enum nvkm_devidx devidx, bool en) +{ + struct nvkm_mc *mc = device->mc; + const struct nvkm_mc_map *map; + if (likely(mc) && mc->func->intr_mask) { + u32 mask = nvkm_top_intr_mask(device, devidx); + for (map = mc->func->intr; !mask && map->stat; map++) { + if (map->unit == devidx) + mask = map->stat; + } + mc->func->intr_mask(mc, mask, en ? mask : 0); + } +} + void nvkm_mc_intr_unarm(struct nvkm_device *device) { diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h index 0229c7e01729..fb4ce6df50f4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h @@ -21,6 +21,8 @@ struct nvkm_mc_func { void (*intr_unarm)(struct nvkm_mc *); /* enable reporting of interrupts to host */ void (*intr_rearm)(struct nvkm_mc *); + /* (un)mask delivery of specific interrupts */ + void (*intr_mask)(struct nvkm_mc *, u32 mask, u32 stat); /* retrieve pending interrupt mask (NV_PMC_INTR) */ u32 (*intr_stat)(struct nvkm_mc *); const struct nvkm_mc_map *reset; From 5805bd1e0b1945e68d25416ec7fb6dd6981476f1 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 30 May 2016 08:48:21 +1000 Subject: [PATCH 08/97] drm/nouveau/mc/gt215: support for masking interrupts Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/mc/gt215.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gt215.c index 60c349a9d1f6..99d50a3d956f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gt215.c @@ -53,12 +53,19 @@ gt215_mc_intr[] = { {}, }; +static void +gt215_mc_intr_mask(struct nvkm_mc *mc, u32 mask, u32 stat) +{ + nvkm_mask(mc->subdev.device, 0x000640, mask, stat); +} + static const struct nvkm_mc_func gt215_mc = { .init = nv50_mc_init, .intr = gt215_mc_intr, .intr_unarm = nv04_mc_intr_unarm, .intr_rearm = nv04_mc_intr_rearm, + .intr_mask = gt215_mc_intr_mask, .intr_stat = nv04_mc_intr_stat, .reset = gt215_mc_reset, }; From 9b02baf19ffabbd8cd82b0190b61d761e3445982 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 30 May 2016 08:50:50 +1000 Subject: [PATCH 09/97] drm/nouveau/mc/gf100-: support for masking interrupts Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c | 9 +++++++++ drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk104.c | 1 + drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c | 1 + drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h | 1 + 4 files changed, 12 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c index b1126a5a8b04..d2c4d6033abb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c @@ -84,6 +84,14 @@ gf100_mc_intr_stat(struct nvkm_mc *mc) return intr0 | intr1; } +void +gf100_mc_intr_mask(struct nvkm_mc *mc, u32 mask, u32 stat) +{ + struct nvkm_device *device = mc->subdev.device; + nvkm_mask(device, 0x000640, mask, stat); + nvkm_mask(device, 0x000644, mask, stat); +} + void gf100_mc_unk260(struct nvkm_mc *mc, u32 data) { @@ -96,6 +104,7 @@ gf100_mc = { .intr = gf100_mc_intr, .intr_unarm = gf100_mc_intr_unarm, .intr_rearm = gf100_mc_intr_rearm, + .intr_mask = gf100_mc_intr_mask, .intr_stat = gf100_mc_intr_stat, .reset = gf100_mc_reset, .unk260 = gf100_mc_unk260, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk104.c index 99426814c7f7..c6cc7a43537d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk104.c @@ -52,6 +52,7 @@ gk104_mc = { .intr = gk104_mc_intr, .intr_unarm = gf100_mc_intr_unarm, .intr_rearm = gf100_mc_intr_rearm, + .intr_mask = gf100_mc_intr_mask, .intr_stat = gf100_mc_intr_stat, .reset = gk104_mc_reset, .unk260 = gf100_mc_unk260, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c index 985f8cbab5c4..ca1bf3279dbe 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c @@ -29,6 +29,7 @@ gk20a_mc = { .intr = gk104_mc_intr, .intr_unarm = gf100_mc_intr_unarm, .intr_rearm = gf100_mc_intr_rearm, + .intr_mask = gf100_mc_intr_mask, .intr_stat = gf100_mc_intr_stat, .reset = gk104_mc_reset, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h index fb4ce6df50f4..4f0576a06d24 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h @@ -44,6 +44,7 @@ void nv50_mc_init(struct nvkm_mc *); void gf100_mc_intr_unarm(struct nvkm_mc *); void gf100_mc_intr_rearm(struct nvkm_mc *); +void gf100_mc_intr_mask(struct nvkm_mc *, u32, u32); u32 gf100_mc_intr_stat(struct nvkm_mc *); void gf100_mc_unk260(struct nvkm_mc *, u32); From 8a90b6fe8c5f429ca7ee7db17ad1d290fc4f1c85 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 30 May 2016 08:53:06 +1000 Subject: [PATCH 10/97] drm/nouveau/mc/gk104-: add pmu reset mask Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk104.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk104.c index c6cc7a43537d..7b8c6ecad1a5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk104.c @@ -26,6 +26,7 @@ const struct nvkm_mc_map gk104_mc_reset[] = { { 0x00000100, NVKM_ENGINE_FIFO }, + { 0x00002000, NVKM_SUBDEV_PMU, true }, {} }; From 2b80bb74fb6a8273d3824981d276e019e349ed2f Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 30 May 2016 08:56:23 +1000 Subject: [PATCH 11/97] drm/nouveau/secboot: use nvkm_mc_intr_mask/unmask() Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvkm/subdev/secboot.h | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/secboot/base.c | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/secboot.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/secboot.h index c6edd95a5b69..fe8e9e04ec81 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/secboot.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/secboot.h @@ -43,8 +43,8 @@ struct nvkm_secboot { const struct nvkm_secboot_func *func; struct nvkm_subdev subdev; + enum nvkm_devidx devidx; u32 base; - u32 irq_mask; u32 enable_mask; }; #define nvkm_secboot(p) container_of((p), struct nvkm_secboot, subdev) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/base.c index 213fdba6cfa0..7d72a8143bbd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/base.c @@ -19,8 +19,9 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ - #include "priv.h" + +#include #include static const char * @@ -85,8 +86,7 @@ nvkm_secboot_falcon_enable(struct nvkm_secboot *sb) /* enable IRQs */ nvkm_wr32(device, sb->base + 0x010, 0xff); - nvkm_mask(device, 0x640, sb->irq_mask, sb->irq_mask); - nvkm_mask(device, 0x644, sb->irq_mask, sb->irq_mask); + nvkm_mc_intr_mask(device, sb->devidx, true); return 0; } @@ -97,8 +97,7 @@ nvkm_secboot_falcon_disable(struct nvkm_secboot *sb) struct nvkm_device *device = sb->subdev.device; /* disable IRQs and wait for any previous code to complete */ - nvkm_mask(device, 0x644, sb->irq_mask, 0x0); - nvkm_mask(device, 0x640, sb->irq_mask, 0x0); + nvkm_mc_intr_mask(device, sb->devidx, false); nvkm_wr32(device, sb->base + 0x014, 0xff); falcon_wait_idle(device, sb->base); @@ -270,8 +269,8 @@ nvkm_secboot_ctor(const struct nvkm_secboot_func *func, /* setup the performing falcon's base address and masks */ switch (func->boot_falcon) { case NVKM_SECBOOT_FALCON_PMU: + sb->devidx = NVKM_SUBDEV_PMU; sb->base = 0x10a000; - sb->irq_mask = 0x1000000; sb->enable_mask = 0x2000; break; default: From 5dfc5dbf656eb033ea04bac331afc196584b01b9 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 30 May 2016 08:57:55 +1000 Subject: [PATCH 12/97] drm/nouveau/secboot: use nvkm_mc_enable/disable() Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvkm/subdev/secboot.h | 1 - drivers/gpu/drm/nouveau/nvkm/subdev/secboot/base.c | 8 +++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/secboot.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/secboot.h index fe8e9e04ec81..b04c38c07761 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/secboot.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/secboot.h @@ -45,7 +45,6 @@ struct nvkm_secboot { enum nvkm_devidx devidx; u32 base; - u32 enable_mask; }; #define nvkm_secboot(p) container_of((p), struct nvkm_secboot, subdev) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/base.c index 7d72a8143bbd..57c6a58d1141 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/base.c @@ -71,12 +71,11 @@ nvkm_secboot_falcon_enable(struct nvkm_secboot *sb) int ret; /* enable engine */ - nvkm_mask(device, 0x200, sb->enable_mask, sb->enable_mask); - nvkm_rd32(device, 0x200); + nvkm_mc_enable(device, sb->devidx); ret = nvkm_wait_msec(device, 10, sb->base + 0x10c, 0x6, 0x0); if (ret < 0) { - nvkm_mask(device, 0x200, sb->enable_mask, 0x0); nvkm_error(&sb->subdev, "Falcon mem scrubbing timeout\n"); + nvkm_mc_disable(device, sb->devidx); return ret; } @@ -103,7 +102,7 @@ nvkm_secboot_falcon_disable(struct nvkm_secboot *sb) falcon_wait_idle(device, sb->base); /* disable engine */ - nvkm_mask(device, 0x200, sb->enable_mask, 0x0); + nvkm_mc_disable(device, sb->devidx); return 0; } @@ -271,7 +270,6 @@ nvkm_secboot_ctor(const struct nvkm_secboot_func *func, case NVKM_SECBOOT_FALCON_PMU: sb->devidx = NVKM_SUBDEV_PMU; sb->base = 0x10a000; - sb->enable_mask = 0x2000; break; default: nvkm_error(&sb->subdev, "invalid secure boot falcon\n"); From d2680907c2b44998cd2e0146b2996cf57d1775df Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Wed, 1 Jun 2016 17:39:15 +0900 Subject: [PATCH 13/97] drm/nouveau/tegra: fetch gpu_speedo_id The GPU speedo ID is required to select the right clk/volt parameters on GM20B. Signed-off-by: Alexandre Courbot Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvkm/core/tegra.h | 1 + drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/tegra.h b/drivers/gpu/drm/nouveau/include/nvkm/core/tegra.h index b5370cb56e3c..e5c9b6268dcc 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/tegra.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/tegra.h @@ -28,6 +28,7 @@ struct nvkm_device_tegra { } iommu; int gpu_speedo; + int gpu_speedo_id; }; struct nvkm_device_tegra_func { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c index 8edc0a583ae2..9b638bd905ff 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c @@ -311,6 +311,7 @@ nvkm_device_tegra_new(const struct nvkm_device_tegra_func *func, goto remove; tdev->gpu_speedo = tegra_sku_info.gpu_speedo_value; + tdev->gpu_speedo_id = tegra_sku_info.gpu_speedo_id; ret = nvkm_device_ctor(&nvkm_device_tegra_func, NULL, &pdev->dev, NVKM_DEVICE_TEGRA, pdev->id, NULL, cfg, dbg, detect, mmio, subdev_mask, From 328bee464b2d13a5aa00afd432d01a4c00e9f805 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Wed, 1 Jun 2016 17:39:16 +0900 Subject: [PATCH 14/97] drm/nouveau/volt/gk20a: make unused public functions static Nobody else is using these, so make them private. Signed-off-by: Alexandre Courbot Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c | 8 ++++---- drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.h | 5 ----- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c index d554455326da..8255ef4d1bc2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c @@ -77,7 +77,7 @@ gk20a_volt_get_cvb_t_voltage(int speedo, int temp, int s_scale, int t_scale, return mv; } -int +static int gk20a_volt_calc_voltage(const struct cvb_coef *coef, int speedo) { int mv; @@ -88,7 +88,7 @@ gk20a_volt_calc_voltage(const struct cvb_coef *coef, int speedo) return mv * 1000; } -int +static int gk20a_volt_vid_get(struct nvkm_volt *base) { struct gk20a_volt *volt = gk20a_volt(base); @@ -103,7 +103,7 @@ gk20a_volt_vid_get(struct nvkm_volt *base) return -EINVAL; } -int +static int gk20a_volt_vid_set(struct nvkm_volt *base, u8 vid) { struct gk20a_volt *volt = gk20a_volt(base); @@ -113,7 +113,7 @@ gk20a_volt_vid_set(struct nvkm_volt *base, u8 vid) return regulator_set_voltage(volt->vdd, volt->base.vid[vid].uv, 1200000); } -int +static int gk20a_volt_set_id(struct nvkm_volt *base, u8 id, int condition) { struct gk20a_volt *volt = gk20a_volt(base); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.h b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.h index 0fa3b502bcf8..92479948eabf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.h @@ -41,9 +41,4 @@ int _gk20a_volt_ctor(struct nvkm_device *device, int index, const struct cvb_coef *coefs, int nb_coefs, struct gk20a_volt *volt); -int gk20a_volt_calc_voltage(const struct cvb_coef *coef, int speedo); -int gk20a_volt_vid_get(struct nvkm_volt *volt); -int gk20a_volt_vid_set(struct nvkm_volt *volt, u8 vid); -int gk20a_volt_set_id(struct nvkm_volt *volt, u8 id, int condition); - #endif From ff318a51bfa0d0c842da1335afcbab032471f594 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Wed, 1 Jun 2016 17:39:17 +0900 Subject: [PATCH 15/97] drm/nouveau/volt/gk20a: constify and name v_scale Give a name to this constant so we at least get an idea of what it is for. Signed-off-by: Alexandre Courbot Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c index 8255ef4d1bc2..8869d53a7082 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c @@ -80,10 +80,11 @@ gk20a_volt_get_cvb_t_voltage(int speedo, int temp, int s_scale, int t_scale, static int gk20a_volt_calc_voltage(const struct cvb_coef *coef, int speedo) { + static const int v_scale = 1000; int mv; mv = gk20a_volt_get_cvb_t_voltage(speedo, -10, 100, 10, coef); - mv = DIV_ROUND_UP(mv, 1000); + mv = DIV_ROUND_UP(mv, v_scale); return mv * 1000; } From ebe5e526c16f6a5b571fe0218f80ff7d81b79fab Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Wed, 1 Jun 2016 17:39:18 +0900 Subject: [PATCH 16/97] drm/nouveau/volt/gk20a: rename constructor Strip the _ prefix off the gk20a volt constructor. Signed-off-by: Alexandre Courbot Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c | 10 +++++----- drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.h | 6 +++--- drivers/gpu/drm/nouveau/nvkm/subdev/volt/gm20b.c | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c index 8869d53a7082..a4e9a5027a4c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c @@ -144,9 +144,9 @@ gk20a_volt = { }; int -_gk20a_volt_ctor(struct nvkm_device *device, int index, - const struct cvb_coef *coefs, int nb_coefs, - struct gk20a_volt *volt) +gk20a_volt_ctor(struct nvkm_device *device, int index, + const struct cvb_coef *coefs, int nb_coefs, + struct gk20a_volt *volt) { struct nvkm_device_tegra *tdev = device->func->tegra(device); int i, uv; @@ -181,6 +181,6 @@ gk20a_volt_new(struct nvkm_device *device, int index, struct nvkm_volt **pvolt) return -ENOMEM; *pvolt = &volt->base; - return _gk20a_volt_ctor(device, index, gk20a_cvb_coef, - ARRAY_SIZE(gk20a_cvb_coef), volt); + return gk20a_volt_ctor(device, index, gk20a_cvb_coef, + ARRAY_SIZE(gk20a_cvb_coef), volt); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.h b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.h index 92479948eabf..1ccca950c41a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.h @@ -37,8 +37,8 @@ struct gk20a_volt { struct regulator *vdd; }; -int _gk20a_volt_ctor(struct nvkm_device *device, int index, - const struct cvb_coef *coefs, int nb_coefs, - struct gk20a_volt *volt); +int gk20a_volt_ctor(struct nvkm_device *device, int index, + const struct cvb_coef *coefs, int nb_coefs, + struct gk20a_volt *volt); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gm20b.c b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gm20b.c index 49b5ecb701e4..753074035cb1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gm20b.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gm20b.c @@ -51,6 +51,6 @@ gm20b_volt_new(struct nvkm_device *device, int index, struct nvkm_volt **pvolt) return -ENOMEM; *pvolt = &volt->base; - return _gk20a_volt_ctor(device, index, gm20b_cvb_coef, - ARRAY_SIZE(gm20b_cvb_coef), volt); + return gk20a_volt_ctor(device, index, gm20b_cvb_coef, + ARRAY_SIZE(gm20b_cvb_coef), volt); } From 791eeea2dc33d6bcd120eedcfb4bb7fb70008fd0 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Wed, 1 Jun 2016 17:39:19 +0900 Subject: [PATCH 17/97] drm/nouveau/volt/gm20b: add support for vmin parameter Chips may be characterized for a minimum voltage. Support this extra parameter and select the appropriate minimum voltage for the detected GPU speedo. Signed-off-by: Alexandre Courbot Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c | 10 +++++----- .../gpu/drm/nouveau/nvkm/subdev/volt/gk20a.h | 2 +- .../gpu/drm/nouveau/nvkm/subdev/volt/gm20b.c | 17 ++++++++++++++++- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c index a4e9a5027a4c..ce5d83cdc7cf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c @@ -146,7 +146,7 @@ gk20a_volt = { int gk20a_volt_ctor(struct nvkm_device *device, int index, const struct cvb_coef *coefs, int nb_coefs, - struct gk20a_volt *volt) + int vmin, struct gk20a_volt *volt) { struct nvkm_device_tegra *tdev = device->func->tegra(device); int i, uv; @@ -161,9 +161,9 @@ gk20a_volt_ctor(struct nvkm_device *device, int index, volt->base.vid_nr = nb_coefs; for (i = 0; i < volt->base.vid_nr; i++) { volt->base.vid[i].vid = i; - volt->base.vid[i].uv = - gk20a_volt_calc_voltage(&coefs[i], - tdev->gpu_speedo); + volt->base.vid[i].uv = max( + gk20a_volt_calc_voltage(&coefs[i], tdev->gpu_speedo), + vmin); nvkm_debug(&volt->base.subdev, "%2d: vid=%d, uv=%d\n", i, volt->base.vid[i].vid, volt->base.vid[i].uv); } @@ -182,5 +182,5 @@ gk20a_volt_new(struct nvkm_device *device, int index, struct nvkm_volt **pvolt) *pvolt = &volt->base; return gk20a_volt_ctor(device, index, gk20a_cvb_coef, - ARRAY_SIZE(gk20a_cvb_coef), volt); + ARRAY_SIZE(gk20a_cvb_coef), 0, volt); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.h b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.h index 1ccca950c41a..6a6c97f9684e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.h @@ -39,6 +39,6 @@ struct gk20a_volt { int gk20a_volt_ctor(struct nvkm_device *device, int index, const struct cvb_coef *coefs, int nb_coefs, - struct gk20a_volt *volt); + int vmin, struct gk20a_volt *volt); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gm20b.c b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gm20b.c index 753074035cb1..d2d39ab74b8e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gm20b.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gm20b.c @@ -41,16 +41,31 @@ const struct cvb_coef gm20b_cvb_coef[] = { /* 921600 */ { 2647676, -106455, 1632 }, }; +const u32 speedo_to_vmin[] = { + /* 0, 1, 2, 3, 4, */ + 950000, 840000, 818750, 840000, 810000, +}; + int gm20b_volt_new(struct nvkm_device *device, int index, struct nvkm_volt **pvolt) { + struct nvkm_device_tegra *tdev = device->func->tegra(device); struct gk20a_volt *volt; + u32 vmin; + + if (tdev->gpu_speedo_id >= ARRAY_SIZE(speedo_to_vmin)) { + nvdev_error(device, "unsupported speedo %d\n", + tdev->gpu_speedo_id); + return -EINVAL; + } volt = kzalloc(sizeof(*volt), GFP_KERNEL); if (!volt) return -ENOMEM; *pvolt = &volt->base; + vmin = speedo_to_vmin[tdev->gpu_speedo_id]; + return gk20a_volt_ctor(device, index, gm20b_cvb_coef, - ARRAY_SIZE(gm20b_cvb_coef), volt); + ARRAY_SIZE(gm20b_cvb_coef), vmin, volt); } From 9772605ce8b14d2c40989c10d920b8e1e1cc6210 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Wed, 1 Jun 2016 17:39:20 +0900 Subject: [PATCH 18/97] drm/nouveau/clk/gk20a: properly protect macro argument Signed-off-by: Alexandre Courbot Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/clk/gm20b.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c index 5f0ee24e31b8..d633669b52dc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c @@ -31,7 +31,7 @@ #define KHZ (1000) #define MHZ (KHZ * 1000) -#define MASK(w) ((1 << w) - 1) +#define MASK(w) ((1 << (w)) - 1) #define GPCPLL_CFG (SYS_GPCPLL_CFG_BASE + 0) #define GPCPLL_CFG_ENABLE BIT(0) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gm20b.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gm20b.c index 71b2bbb61973..274a74c14fe7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gm20b.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gm20b.c @@ -29,7 +29,7 @@ #define KHZ (1000) #define MHZ (KHZ * 1000) -#define MASK(w) ((1 << w) - 1) +#define MASK(w) ((1 << (w)) - 1) #define BYPASSCTRL_SYS (SYS_GPCPLL_CFG_BASE + 0x340) #define BYPASSCTRL_SYS_GPCPLL_SHIFT 0 From f5f1b06eeaa66f5eb4b030cff63118cea33293fa Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Wed, 1 Jun 2016 17:39:21 +0900 Subject: [PATCH 19/97] drm/nouveau/clk/gk20a: setup slide once during init Slide setup needs to be performed only once, during init. Also use the proper parameters for different clock speeds. Signed-off-by: Alexandre Courbot Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c | 46 ++++++++++++++++--- .../gpu/drm/nouveau/nvkm/subdev/clk/gk20a.h | 2 + .../gpu/drm/nouveau/nvkm/subdev/clk/gm20b.c | 4 ++ 3 files changed, 46 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c index d633669b52dc..166f51cc5621 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c @@ -274,12 +274,6 @@ gk20a_pllg_slide(struct gk20a_clk *clk, u32 n) if (n == ((val >> GPCPLL_COEFF_N_SHIFT) & MASK(GPCPLL_COEFF_N_WIDTH))) return 0; - /* setup */ - nvkm_mask(device, GPCPLL_CFG2, 0xff << GPCPLL_CFG2_PLL_STEPA_SHIFT, - 0x2b << GPCPLL_CFG2_PLL_STEPA_SHIFT); - nvkm_mask(device, GPCPLL_CFG3, 0xff << GPCPLL_CFG3_PLL_STEPB_SHIFT, - 0xb << GPCPLL_CFG3_PLL_STEPB_SHIFT); - /* pll slowdown mode */ nvkm_mask(device, GPCPLL_NDIV_SLOWDOWN, BIT(GPCPLL_NDIV_SLOWDOWN_SLOWDOWN_USING_PLL_SHIFT), @@ -581,6 +575,42 @@ gk20a_clk_tidy(struct nvkm_clk *base) { } +int +gk20a_clk_setup_slide(struct gk20a_clk *clk) +{ + struct nvkm_subdev *subdev = &clk->base.subdev; + struct nvkm_device *device = subdev->device; + u32 step_a, step_b; + + switch (clk->parent_rate) { + case 12000000: + case 12800000: + case 13000000: + step_a = 0x2b; + step_b = 0x0b; + break; + case 19200000: + step_a = 0x12; + step_b = 0x08; + break; + case 38400000: + step_a = 0x04; + step_b = 0x05; + break; + default: + nvkm_error(subdev, "invalid parent clock rate %u KHz", + clk->parent_rate / KHZ); + return -EINVAL; + } + + nvkm_mask(device, GPCPLL_CFG2, 0xff << GPCPLL_CFG2_PLL_STEPA_SHIFT, + step_a << GPCPLL_CFG2_PLL_STEPA_SHIFT); + nvkm_mask(device, GPCPLL_CFG3, 0xff << GPCPLL_CFG3_PLL_STEPB_SHIFT, + step_b << GPCPLL_CFG3_PLL_STEPB_SHIFT); + + return 0; +} + void gk20a_clk_fini(struct nvkm_clk *base) { @@ -617,6 +647,10 @@ gk20a_clk_init(struct nvkm_clk *base) nvkm_mask(device, GPC2CLK_OUT, GPC2CLK_OUT_INIT_MASK, GPC2CLK_OUT_INIT_VAL); + ret = gk20a_clk_setup_slide(clk); + if (ret) + return ret; + /* Start with lowest frequency */ base->func->calc(base, &base->func->pstates[0].base); ret = base->func->prog(&clk->base); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.h b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.h index 13c46740197d..028c27237947 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.h @@ -62,4 +62,6 @@ int gk20a_clk_calc(struct nvkm_clk *, struct nvkm_cstate *); int gk20a_clk_prog(struct nvkm_clk *); void gk20a_clk_tidy(struct nvkm_clk *); +int gk20a_clk_setup_slide(struct gk20a_clk *); + #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gm20b.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gm20b.c index 274a74c14fe7..a34acafe37ee 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gm20b.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gm20b.c @@ -144,6 +144,10 @@ gm20b_clk_init(struct nvkm_clk *base) struct nvkm_device *device = subdev->device; int ret; + ret = gk20a_clk_setup_slide(clk); + if (ret) + return ret; + /* Set the global bypass control to VCO */ nvkm_mask(device, BYPASSCTRL_SYS, MASK(BYPASSCTRL_SYS_GPCPLL_WIDTH) << BYPASSCTRL_SYS_GPCPLL_SHIFT, From d7ca1106d648bb9a4ee03b6d2f05ba7ea1bf967b Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Wed, 1 Jun 2016 17:39:22 +0900 Subject: [PATCH 20/97] drm/nouveau/clk/gk20a: reorganize MNP calculation a bit Move variables declarations to their actual scope of use, and simplify code a bit. Signed-off-by: Alexandre Courbot Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c index 166f51cc5621..4b9e7ec11412 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c @@ -163,16 +163,13 @@ gk20a_pllg_calc_mnp(struct gk20a_clk *clk, unsigned long rate) target_clk_f = rate * 2 / KHZ; ref_clk_f = clk->parent_rate / KHZ; - max_vco_f = clk->params->max_vco; + target_vco_f = target_clk_f + target_clk_f / 50; + max_vco_f = max(clk->params->max_vco, target_vco_f); min_vco_f = clk->params->min_vco; best_m = clk->params->max_m; best_n = clk->params->min_n; best_pl = clk->params->min_pl; - target_vco_f = target_clk_f + target_clk_f / 50; - if (max_vco_f < target_vco_f) - max_vco_f = target_vco_f; - /* min_pl <= high_pl <= max_pl */ high_pl = (max_vco_f + target_vco_f - 1) / target_vco_f; high_pl = min(high_pl, clk->params->max_pl); @@ -195,9 +192,7 @@ gk20a_pllg_calc_mnp(struct gk20a_clk *clk, unsigned long rate) target_vco_f = target_clk_f * clk->pl_to_div(pl); for (m = clk->params->min_m; m <= clk->params->max_m; m++) { - u32 u_f, vco_f; - - u_f = ref_clk_f / m; + u32 u_f = ref_clk_f / m; if (u_f < clk->params->min_u) break; @@ -211,6 +206,8 @@ gk20a_pllg_calc_mnp(struct gk20a_clk *clk, unsigned long rate) break; for (; n <= n2; n++) { + u32 vco_f; + if (n < clk->params->min_n) continue; if (n > clk->params->max_n) From 9102240c693d3be655caaa4e5ec7a4efa61b7821 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Wed, 1 Jun 2016 17:39:23 +0900 Subject: [PATCH 21/97] drm/nouveau/clk/gk20a: use nvkm_ functions in slide() Signed-off-by: Alexandre Courbot Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c | 26 +++++++------------ 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c index 4b9e7ec11412..f07cf5b44fc6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c @@ -263,7 +263,7 @@ gk20a_pllg_slide(struct gk20a_clk *clk, u32 n) struct nvkm_subdev *subdev = &clk->base.subdev; struct nvkm_device *device = subdev->device; u32 val; - int ramp_timeout; + int ret = 0; /* get old coefficients */ val = nvkm_rd32(device, GPCPLL_COEFF); @@ -284,17 +284,16 @@ gk20a_pllg_slide(struct gk20a_clk *clk, u32 n) nvkm_wr32(device, GPCPLL_COEFF, val); /* dynamic ramp to new ndiv */ - val = nvkm_rd32(device, GPCPLL_NDIV_SLOWDOWN); - val |= 0x1 << GPCPLL_NDIV_SLOWDOWN_EN_DYNRAMP_SHIFT; udelay(1); - nvkm_wr32(device, GPCPLL_NDIV_SLOWDOWN, val); + nvkm_mask(device, GPCPLL_NDIV_SLOWDOWN, + BIT(GPCPLL_NDIV_SLOWDOWN_EN_DYNRAMP_SHIFT), + BIT(GPCPLL_NDIV_SLOWDOWN_EN_DYNRAMP_SHIFT)); - for (ramp_timeout = 500; ramp_timeout > 0; ramp_timeout--) { - udelay(1); - val = nvkm_rd32(device, GPC_BCAST_NDIV_SLOWDOWN_DEBUG); - if (val & GPC_BCAST_NDIV_SLOWDOWN_DEBUG_PLL_DYNRAMP_DONE_SYNCED_MASK) - break; - } + /* wait for ramping to complete */ + if (nvkm_wait_usec(device, 500, GPC_BCAST_NDIV_SLOWDOWN_DEBUG, + GPC_BCAST_NDIV_SLOWDOWN_DEBUG_PLL_DYNRAMP_DONE_SYNCED_MASK, + GPC_BCAST_NDIV_SLOWDOWN_DEBUG_PLL_DYNRAMP_DONE_SYNCED_MASK) < 0) + ret = -ETIMEDOUT; /* exit slowdown mode */ nvkm_mask(device, GPCPLL_NDIV_SLOWDOWN, @@ -302,12 +301,7 @@ gk20a_pllg_slide(struct gk20a_clk *clk, u32 n) BIT(GPCPLL_NDIV_SLOWDOWN_EN_DYNRAMP_SHIFT), 0); nvkm_rd32(device, GPCPLL_NDIV_SLOWDOWN); - if (ramp_timeout <= 0) { - nvkm_error(subdev, "gpcpll dynamic ramp timeout\n"); - return -ETIMEDOUT; - } - - return 0; + return ret; } static void From a9608c9ba968d3543f4531bbeee3cf2ab6ce8f80 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Wed, 1 Jun 2016 17:39:24 +0900 Subject: [PATCH 22/97] drm/nouveau/clk/gk20a: add and use MNP programming functions Add relevant functions to work with the gk20a_pll structure and use them where they ought to be instead of directly manipulating registers. Signed-off-by: Alexandre Courbot Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c | 35 ++++++++++++------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c index f07cf5b44fc6..80031c0f9e3f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c @@ -136,6 +136,18 @@ gk20a_pllg_read_mnp(struct gk20a_clk *clk, struct gk20a_pll *pll) pll->pl = (val >> GPCPLL_COEFF_P_SHIFT) & MASK(GPCPLL_COEFF_P_WIDTH); } +static void +gk20a_pllg_write_mnp(struct gk20a_clk *clk, const struct gk20a_pll *pll) +{ + struct nvkm_device *device = clk->base.subdev.device; + u32 val; + + val = (pll->m & MASK(GPCPLL_COEFF_M_WIDTH)) << GPCPLL_COEFF_M_SHIFT; + val |= (pll->n & MASK(GPCPLL_COEFF_N_WIDTH)) << GPCPLL_COEFF_N_SHIFT; + val |= (pll->pl & MASK(GPCPLL_COEFF_P_WIDTH)) << GPCPLL_COEFF_P_SHIFT; + nvkm_wr32(device, GPCPLL_COEFF, val); +} + static u32 gk20a_pllg_calc_rate(struct gk20a_clk *clk) { @@ -262,13 +274,13 @@ gk20a_pllg_slide(struct gk20a_clk *clk, u32 n) { struct nvkm_subdev *subdev = &clk->base.subdev; struct nvkm_device *device = subdev->device; - u32 val; + struct gk20a_pll pll; int ret = 0; /* get old coefficients */ - val = nvkm_rd32(device, GPCPLL_COEFF); + gk20a_pllg_read_mnp(clk, &pll); /* do nothing if NDIV is the same */ - if (n == ((val >> GPCPLL_COEFF_N_SHIFT) & MASK(GPCPLL_COEFF_N_WIDTH))) + if (n == pll.n) return 0; /* pll slowdown mode */ @@ -277,11 +289,9 @@ gk20a_pllg_slide(struct gk20a_clk *clk, u32 n) BIT(GPCPLL_NDIV_SLOWDOWN_SLOWDOWN_USING_PLL_SHIFT)); /* new ndiv ready for ramp */ - val = nvkm_rd32(device, GPCPLL_COEFF); - val &= ~(MASK(GPCPLL_COEFF_N_WIDTH) << GPCPLL_COEFF_N_SHIFT); - val |= (n & MASK(GPCPLL_COEFF_N_WIDTH)) << GPCPLL_COEFF_N_SHIFT; + pll.n = n; udelay(1); - nvkm_wr32(device, GPCPLL_COEFF, val); + gk20a_pllg_write_mnp(clk, &pll); /* dynamic ramp to new ndiv */ udelay(1); @@ -377,12 +387,11 @@ _gk20a_pllg_program_mnp(struct gk20a_clk *clk, bool allow_slide) nvkm_debug(subdev, "%s: m=%d n=%d pl=%d\n", __func__, clk->pll.m, clk->pll.n, clk->pll.pl); - n_lo = DIV_ROUND_UP(clk->pll.m * clk->params->min_vco, - clk->parent_rate / KHZ); - val = clk->pll.m << GPCPLL_COEFF_M_SHIFT; - val |= (allow_slide ? n_lo : clk->pll.n) << GPCPLL_COEFF_N_SHIFT; - val |= clk->pll.pl << GPCPLL_COEFF_P_SHIFT; - nvkm_wr32(device, GPCPLL_COEFF, val); + old_pll = clk->pll; + if (allow_slide) + old_pll.n = DIV_ROUND_UP(clk->pll.m * clk->params->min_vco, + clk->parent_rate / KHZ); + gk20a_pllg_write_mnp(clk, &old_pll); gk20a_pllg_enable(clk); From 89d3a912fc00cd6fccdafb14a63395b049aa2aa1 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Wed, 1 Jun 2016 17:39:25 +0900 Subject: [PATCH 23/97] drm/nouveau/clk/gk20a: parameterize PLL settings Make functions manipulating PLL settings take them as an argument, instead of assuming we want to work on the copy in the gk20a_clk structure. This makes these functions more flexible, which we will need in GM20B. Signed-off-by: Alexandre Courbot Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c | 51 ++++++++++--------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c index 80031c0f9e3f..a95eda7c5df4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c @@ -149,19 +149,20 @@ gk20a_pllg_write_mnp(struct gk20a_clk *clk, const struct gk20a_pll *pll) } static u32 -gk20a_pllg_calc_rate(struct gk20a_clk *clk) +gk20a_pllg_calc_rate(struct gk20a_clk *clk, struct gk20a_pll *pll) { u32 rate; u32 divider; - rate = clk->parent_rate * clk->pll.n; - divider = clk->pll.m * clk->pl_to_div(clk->pll.pl); + rate = clk->parent_rate * pll->n; + divider = pll->m * clk->pl_to_div(pll->pl); return rate / divider / 2; } static int -gk20a_pllg_calc_mnp(struct gk20a_clk *clk, unsigned long rate) +gk20a_pllg_calc_mnp(struct gk20a_clk *clk, unsigned long rate, + struct gk20a_pll *pll) { struct nvkm_subdev *subdev = &clk->base.subdev; u32 target_clk_f, ref_clk_f, target_freq; @@ -256,16 +257,16 @@ gk20a_pllg_calc_mnp(struct gk20a_clk *clk, unsigned long rate) "no best match for target @ %dMHz on gpc_pll", target_clk_f / KHZ); - clk->pll.m = best_m; - clk->pll.n = best_n; - clk->pll.pl = best_pl; + pll->m = best_m; + pll->n = best_n; + pll->pl = best_pl; - target_freq = gk20a_pllg_calc_rate(clk); + target_freq = gk20a_pllg_calc_rate(clk, pll); nvkm_debug(subdev, - "actual target freq %d MHz, M %d, N %d, PL %d(div%d)\n", - target_freq / MHZ, clk->pll.m, clk->pll.n, clk->pll.pl, - clk->pl_to_div(clk->pll.pl)); + "actual target freq %d KHz, M %d, N %d, PL %d(div%d)\n", + target_freq / KHZ, pll->m, pll->n, pll->pl, + clk->pl_to_div(pll->pl)); return 0; } @@ -333,7 +334,8 @@ gk20a_pllg_disable(struct gk20a_clk *clk) } static int -_gk20a_pllg_program_mnp(struct gk20a_clk *clk, bool allow_slide) +_gk20a_pllg_program_mnp(struct gk20a_clk *clk, struct gk20a_pll *pll, + bool allow_slide) { struct nvkm_subdev *subdev = &clk->base.subdev; struct nvkm_device *device = subdev->device; @@ -346,9 +348,9 @@ _gk20a_pllg_program_mnp(struct gk20a_clk *clk, bool allow_slide) /* do NDIV slide if there is no change in M and PL */ cfg = nvkm_rd32(device, GPCPLL_CFG); - if (allow_slide && clk->pll.m == old_pll.m && - clk->pll.pl == old_pll.pl && (cfg & GPCPLL_CFG_ENABLE)) { - return gk20a_pllg_slide(clk, clk->pll.n); + if (allow_slide && pll->m == old_pll.m && + pll->pl == old_pll.pl && (cfg & GPCPLL_CFG_ENABLE)) { + return gk20a_pllg_slide(clk, pll->n); } /* slide down to NDIV_LO */ @@ -385,11 +387,11 @@ _gk20a_pllg_program_mnp(struct gk20a_clk *clk, bool allow_slide) gk20a_pllg_disable(clk); nvkm_debug(subdev, "%s: m=%d n=%d pl=%d\n", __func__, - clk->pll.m, clk->pll.n, clk->pll.pl); + pll->m, pll->n, pll->pl); - old_pll = clk->pll; + old_pll = *pll; if (allow_slide) - old_pll.n = DIV_ROUND_UP(clk->pll.m * clk->params->min_vco, + old_pll.n = DIV_ROUND_UP(pll->m * clk->params->min_vco, clk->parent_rate / KHZ); gk20a_pllg_write_mnp(clk, &old_pll); @@ -425,7 +427,7 @@ _gk20a_pllg_program_mnp(struct gk20a_clk *clk, bool allow_slide) } /* slide up to new NDIV */ - return allow_slide ? gk20a_pllg_slide(clk, clk->pll.n) : 0; + return allow_slide ? gk20a_pllg_slide(clk, pll->n) : 0; } static int @@ -433,9 +435,9 @@ gk20a_pllg_program_mnp(struct gk20a_clk *clk) { int err; - err = _gk20a_pllg_program_mnp(clk, true); + err = _gk20a_pllg_program_mnp(clk, &clk->pll, true); if (err) - err = _gk20a_pllg_program_mnp(clk, false); + err = _gk20a_pllg_program_mnp(clk, &clk->pll, false); return err; } @@ -540,13 +542,14 @@ gk20a_clk_read(struct nvkm_clk *base, enum nv_clk_src src) struct gk20a_clk *clk = gk20a_clk(base); struct nvkm_subdev *subdev = &clk->base.subdev; struct nvkm_device *device = subdev->device; + struct gk20a_pll pll; switch (src) { case nv_clk_src_crystal: return device->crystal; case nv_clk_src_gpc: - gk20a_pllg_read_mnp(clk, &clk->pll); - return gk20a_pllg_calc_rate(clk) / GK20A_CLK_GPC_MDIV; + gk20a_pllg_read_mnp(clk, &pll); + return gk20a_pllg_calc_rate(clk, &pll) / GK20A_CLK_GPC_MDIV; default: nvkm_error(subdev, "invalid clock source %d\n", src); return -EINVAL; @@ -559,7 +562,7 @@ gk20a_clk_calc(struct nvkm_clk *base, struct nvkm_cstate *cstate) struct gk20a_clk *clk = gk20a_clk(base); return gk20a_pllg_calc_mnp(clk, cstate->domain[nv_clk_src_gpc] * - GK20A_CLK_GPC_MDIV); + GK20A_CLK_GPC_MDIV, &clk->pll); } int From afea21c9174e555defd55f488df2a99117457b4e Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Wed, 1 Jun 2016 17:39:26 +0900 Subject: [PATCH 24/97] drm/nouveau/clk/gk20a: factorize n_lo computation code Use a dedicated function instead of always calculating n_lo on the fly. Signed-off-by: Alexandre Courbot Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c index a95eda7c5df4..cc46e3abac97 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c @@ -160,6 +160,13 @@ gk20a_pllg_calc_rate(struct gk20a_clk *clk, struct gk20a_pll *pll) return rate / divider / 2; } +static u32 +gk20a_pllg_n_lo(struct gk20a_clk *clk, struct gk20a_pll *pll) +{ + return DIV_ROUND_UP(pll->m * clk->params->min_vco, + clk->parent_rate / KHZ); +} + static int gk20a_pllg_calc_mnp(struct gk20a_clk *clk, unsigned long rate, struct gk20a_pll *pll) @@ -341,7 +348,6 @@ _gk20a_pllg_program_mnp(struct gk20a_clk *clk, struct gk20a_pll *pll, struct nvkm_device *device = subdev->device; u32 val, cfg; struct gk20a_pll old_pll; - u32 n_lo; /* get old coefficients */ gk20a_pllg_read_mnp(clk, &old_pll); @@ -357,10 +363,7 @@ _gk20a_pllg_program_mnp(struct gk20a_clk *clk, struct gk20a_pll *pll, if (allow_slide && (cfg & GPCPLL_CFG_ENABLE)) { int ret; - n_lo = DIV_ROUND_UP(old_pll.m * clk->params->min_vco, - clk->parent_rate / KHZ); - ret = gk20a_pllg_slide(clk, n_lo); - + ret = gk20a_pllg_slide(clk, gk20a_pllg_n_lo(clk, &old_pll)); if (ret) return ret; } @@ -391,8 +394,7 @@ _gk20a_pllg_program_mnp(struct gk20a_clk *clk, struct gk20a_pll *pll, old_pll = *pll; if (allow_slide) - old_pll.n = DIV_ROUND_UP(pll->m * clk->params->min_vco, - clk->parent_rate / KHZ); + old_pll.n = gk20a_pllg_n_lo(clk, pll); gk20a_pllg_write_mnp(clk, &old_pll); gk20a_pllg_enable(clk); @@ -628,8 +630,7 @@ gk20a_clk_fini(struct nvkm_clk *base) u32 n_lo; gk20a_pllg_read_mnp(clk, &pll); - n_lo = DIV_ROUND_UP(pll.m * clk->params->min_vco, - clk->parent_rate / KHZ); + n_lo = gk20a_pllg_n_lo(clk, &pll); gk20a_pllg_slide(clk, n_lo); } From 6ed7e74219be60c12dc803c2d6cafa0266f3cd32 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Wed, 1 Jun 2016 17:39:27 +0900 Subject: [PATCH 25/97] drm/nouveau/clk/gk20a: improve MNP programming Split the MNP programming function into two functions for the cases where we allow sliding or not, instead of making it take a parameter for this. This results in less conditionals in the code and makes it easier to read. Also make the MNP programming functions take the PLL parameters as arguments, and move bits of code to more relevant places (previous programming tended to be just-in-time, which added more conditionnals in the code). Signed-off-by: Alexandre Courbot Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c | 199 +++++++++--------- 1 file changed, 103 insertions(+), 96 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c index cc46e3abac97..513d112e8268 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c @@ -72,6 +72,7 @@ #define GPC2CLK_OUT_VCODIV_WIDTH 6 #define GPC2CLK_OUT_VCODIV_SHIFT 8 #define GPC2CLK_OUT_VCODIV1 0 +#define GPC2CLK_OUT_VCODIV2 2 #define GPC2CLK_OUT_VCODIV_MASK (MASK(GPC2CLK_OUT_VCODIV_WIDTH) << \ GPC2CLK_OUT_VCODIV_SHIFT) #define GPC2CLK_OUT_BYPDIV_WIDTH 6 @@ -322,13 +323,42 @@ gk20a_pllg_slide(struct gk20a_clk *clk, u32 n) return ret; } -static void +static bool +gk20a_pllg_is_enabled(struct gk20a_clk *clk) +{ + struct nvkm_device *device = clk->base.subdev.device; + u32 val; + + val = nvkm_rd32(device, GPCPLL_CFG); + return val & GPCPLL_CFG_ENABLE; +} + +static int gk20a_pllg_enable(struct gk20a_clk *clk) { struct nvkm_device *device = clk->base.subdev.device; + u32 val; nvkm_mask(device, GPCPLL_CFG, GPCPLL_CFG_ENABLE, GPCPLL_CFG_ENABLE); nvkm_rd32(device, GPCPLL_CFG); + + /* enable lock detection */ + val = nvkm_rd32(device, GPCPLL_CFG); + if (val & GPCPLL_CFG_LOCK_DET_OFF) { + val &= ~GPCPLL_CFG_LOCK_DET_OFF; + nvkm_wr32(device, GPCPLL_CFG, val); + } + + /* wait for lock */ + if (nvkm_wait_usec(device, 300, GPCPLL_CFG, GPCPLL_CFG_LOCK, + GPCPLL_CFG_LOCK) < 0) + return -ETIMEDOUT; + + /* switch to VCO mode */ + nvkm_mask(device, SEL_VCO, BIT(SEL_VCO_GPC2CLK_OUT_SHIFT), + BIT(SEL_VCO_GPC2CLK_OUT_SHIFT)); + + return 0; } static void @@ -336,112 +366,81 @@ gk20a_pllg_disable(struct gk20a_clk *clk) { struct nvkm_device *device = clk->base.subdev.device; + /* put PLL in bypass before disabling it */ + nvkm_mask(device, SEL_VCO, BIT(SEL_VCO_GPC2CLK_OUT_SHIFT), 0); + nvkm_mask(device, GPCPLL_CFG, GPCPLL_CFG_ENABLE, 0); nvkm_rd32(device, GPCPLL_CFG); } static int -_gk20a_pllg_program_mnp(struct gk20a_clk *clk, struct gk20a_pll *pll, - bool allow_slide) +gk20a_pllg_program_mnp(struct gk20a_clk *clk, const struct gk20a_pll *pll) { struct nvkm_subdev *subdev = &clk->base.subdev; struct nvkm_device *device = subdev->device; - u32 val, cfg; - struct gk20a_pll old_pll; + struct gk20a_pll cur_pll; + int ret; - /* get old coefficients */ - gk20a_pllg_read_mnp(clk, &old_pll); + gk20a_pllg_read_mnp(clk, &cur_pll); - /* do NDIV slide if there is no change in M and PL */ - cfg = nvkm_rd32(device, GPCPLL_CFG); - if (allow_slide && pll->m == old_pll.m && - pll->pl == old_pll.pl && (cfg & GPCPLL_CFG_ENABLE)) { - return gk20a_pllg_slide(clk, pll->n); - } + /* split VCO-to-bypass jump in half by setting out divider 1:2 */ + nvkm_mask(device, GPC2CLK_OUT, GPC2CLK_OUT_VCODIV_MASK, + GPC2CLK_OUT_VCODIV2 << GPC2CLK_OUT_VCODIV_SHIFT); + /* Intentional 2nd write to assure linear divider operation */ + nvkm_mask(device, GPC2CLK_OUT, GPC2CLK_OUT_VCODIV_MASK, + GPC2CLK_OUT_VCODIV2 << GPC2CLK_OUT_VCODIV_SHIFT); + nvkm_rd32(device, GPC2CLK_OUT); + udelay(2); - /* slide down to NDIV_LO */ - if (allow_slide && (cfg & GPCPLL_CFG_ENABLE)) { - int ret; + gk20a_pllg_disable(clk); - ret = gk20a_pllg_slide(clk, gk20a_pllg_n_lo(clk, &old_pll)); + gk20a_pllg_write_mnp(clk, pll); + + ret = gk20a_pllg_enable(clk); + if (ret) + return ret; + + /* restore out divider 1:1 */ + udelay(2); + nvkm_mask(device, GPC2CLK_OUT, GPC2CLK_OUT_VCODIV_MASK, + GPC2CLK_OUT_VCODIV1 << GPC2CLK_OUT_VCODIV_SHIFT); + /* Intentional 2nd write to assure linear divider operation */ + nvkm_mask(device, GPC2CLK_OUT, GPC2CLK_OUT_VCODIV_MASK, + GPC2CLK_OUT_VCODIV1 << GPC2CLK_OUT_VCODIV_SHIFT); + nvkm_rd32(device, GPC2CLK_OUT); + + return 0; +} + +static int +gk20a_pllg_program_mnp_slide(struct gk20a_clk *clk, const struct gk20a_pll *pll) +{ + struct gk20a_pll cur_pll; + int ret; + + if (gk20a_pllg_is_enabled(clk)) { + gk20a_pllg_read_mnp(clk, &cur_pll); + + /* just do NDIV slide if there is no change to M and PL */ + if (pll->m == cur_pll.m && pll->pl == cur_pll.pl) + return gk20a_pllg_slide(clk, pll->n); + + /* slide down to current NDIV_LO */ + cur_pll.n = gk20a_pllg_n_lo(clk, &cur_pll); + ret = gk20a_pllg_slide(clk, cur_pll.n); if (ret) return ret; } - /* split FO-to-bypass jump in halfs by setting out divider 1:2 */ - nvkm_mask(device, GPC2CLK_OUT, GPC2CLK_OUT_VCODIV_MASK, - 0x2 << GPC2CLK_OUT_VCODIV_SHIFT); - - /* put PLL in bypass before programming it */ - val = nvkm_rd32(device, SEL_VCO); - val &= ~(BIT(SEL_VCO_GPC2CLK_OUT_SHIFT)); - udelay(2); - nvkm_wr32(device, SEL_VCO, val); - - /* get out from IDDQ */ - val = nvkm_rd32(device, GPCPLL_CFG); - if (val & GPCPLL_CFG_IDDQ) { - val &= ~GPCPLL_CFG_IDDQ; - nvkm_wr32(device, GPCPLL_CFG, val); - nvkm_rd32(device, GPCPLL_CFG); - udelay(2); - } - - gk20a_pllg_disable(clk); - - nvkm_debug(subdev, "%s: m=%d n=%d pl=%d\n", __func__, - pll->m, pll->n, pll->pl); - - old_pll = *pll; - if (allow_slide) - old_pll.n = gk20a_pllg_n_lo(clk, pll); - gk20a_pllg_write_mnp(clk, &old_pll); - - gk20a_pllg_enable(clk); - - val = nvkm_rd32(device, GPCPLL_CFG); - if (val & GPCPLL_CFG_LOCK_DET_OFF) { - val &= ~GPCPLL_CFG_LOCK_DET_OFF; - nvkm_wr32(device, GPCPLL_CFG, val); - } - - if (nvkm_usec(device, 300, - if (nvkm_rd32(device, GPCPLL_CFG) & GPCPLL_CFG_LOCK) - break; - ) < 0) - return -ETIMEDOUT; - - /* switch to VCO mode */ - nvkm_mask(device, SEL_VCO, BIT(SEL_VCO_GPC2CLK_OUT_SHIFT), - BIT(SEL_VCO_GPC2CLK_OUT_SHIFT)); - - /* restore out divider 1:1 */ - val = nvkm_rd32(device, GPC2CLK_OUT); - if ((val & GPC2CLK_OUT_VCODIV_MASK) != - (GPC2CLK_OUT_VCODIV1 << GPC2CLK_OUT_VCODIV_SHIFT)) { - val &= ~GPC2CLK_OUT_VCODIV_MASK; - val |= GPC2CLK_OUT_VCODIV1 << GPC2CLK_OUT_VCODIV_SHIFT; - udelay(2); - nvkm_wr32(device, GPC2CLK_OUT, val); - /* Intentional 2nd write to assure linear divider operation */ - nvkm_wr32(device, GPC2CLK_OUT, val); - nvkm_rd32(device, GPC2CLK_OUT); - } + /* program MNP with the new clock parameters and new NDIV_LO */ + cur_pll = *pll; + cur_pll.n = gk20a_pllg_n_lo(clk, &cur_pll); + ret = gk20a_pllg_program_mnp(clk, &cur_pll); + if (ret) + return ret; /* slide up to new NDIV */ - return allow_slide ? gk20a_pllg_slide(clk, pll->n) : 0; -} - -static int -gk20a_pllg_program_mnp(struct gk20a_clk *clk) -{ - int err; - - err = _gk20a_pllg_program_mnp(clk, &clk->pll, true); - if (err) - err = _gk20a_pllg_program_mnp(clk, &clk->pll, false); - - return err; + return gk20a_pllg_slide(clk, pll->n); } static struct nvkm_pstate @@ -571,8 +570,13 @@ int gk20a_clk_prog(struct nvkm_clk *base) { struct gk20a_clk *clk = gk20a_clk(base); + int ret; - return gk20a_pllg_program_mnp(clk); + ret = gk20a_pllg_program_mnp_slide(clk, &clk->pll); + if (ret) + ret = gk20a_pllg_program_mnp(clk, &clk->pll); + + return ret; } void @@ -621,11 +625,9 @@ gk20a_clk_fini(struct nvkm_clk *base) { struct nvkm_device *device = base->subdev.device; struct gk20a_clk *clk = gk20a_clk(base); - u32 val; /* slide to VCO min */ - val = nvkm_rd32(device, GPCPLL_CFG); - if (val & GPCPLL_CFG_ENABLE) { + if (gk20a_pllg_is_enabled(clk)) { struct gk20a_pll pll; u32 n_lo; @@ -634,10 +636,10 @@ gk20a_clk_fini(struct nvkm_clk *base) gk20a_pllg_slide(clk, n_lo); } - /* put PLL in bypass before disabling it */ - nvkm_mask(device, SEL_VCO, BIT(SEL_VCO_GPC2CLK_OUT_SHIFT), 0); - gk20a_pllg_disable(clk); + + /* set IDDQ */ + nvkm_mask(device, GPCPLL_CFG, GPCPLL_CFG_IDDQ, 1); } static int @@ -648,6 +650,11 @@ gk20a_clk_init(struct nvkm_clk *base) struct nvkm_device *device = subdev->device; int ret; + /* get out from IDDQ */ + nvkm_mask(device, GPCPLL_CFG, GPCPLL_CFG_IDDQ, 0); + nvkm_rd32(device, GPCPLL_CFG); + udelay(5); + nvkm_mask(device, GPC2CLK_OUT, GPC2CLK_OUT_INIT_MASK, GPC2CLK_OUT_INIT_VAL); From 3786c41518423bb9a925c475553503901687eb63 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Wed, 1 Jun 2016 17:39:28 +0900 Subject: [PATCH 26/97] drm/nouveau/clk/gk20a: rename constructor Strip the _ prefix off the gk20a clock constructor. Signed-off-by: Alexandre Courbot Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c | 4 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.h | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/clk/gm20b.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c index 513d112e8268..607d74a81c5e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c @@ -691,7 +691,7 @@ gk20a_clk = { }; int -_gk20a_clk_ctor(struct nvkm_device *device, int index, +gk20a_clk_ctor(struct nvkm_device *device, int index, const struct nvkm_clk_func *func, const struct gk20a_clk_pllg_params *params, struct gk20a_clk *clk) @@ -730,7 +730,7 @@ gk20a_clk_new(struct nvkm_device *device, int index, struct nvkm_clk **pclk) return -ENOMEM; *pclk = &clk->base; - ret = _gk20a_clk_ctor(device, index, &gk20a_clk, &gk20a_pllg_params, + ret = gk20a_clk_ctor(device, index, &gk20a_clk, &gk20a_pllg_params, clk); clk->pl_to_div = pl_to_div; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.h b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.h index 028c27237947..73551f8209fa 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.h @@ -54,7 +54,7 @@ struct gk20a_clk { }; #define gk20a_clk(p) container_of((p), struct gk20a_clk, base) -int _gk20a_clk_ctor(struct nvkm_device *, int, const struct nvkm_clk_func *, +int gk20a_clk_ctor(struct nvkm_device *, int, const struct nvkm_clk_func *, const struct gk20a_clk_pllg_params *, struct gk20a_clk *); void gk20a_clk_fini(struct nvkm_clk *); int gk20a_clk_read(struct nvkm_clk *, enum nv_clk_src); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gm20b.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gm20b.c index a34acafe37ee..68749bbbe623 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gm20b.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gm20b.c @@ -192,8 +192,8 @@ gm20b_clk_new(struct nvkm_device *device, int index, struct nvkm_clk **pclk) return -ENOMEM; *pclk = &clk->base; - ret = _gk20a_clk_ctor(device, index, &gm20b_clk_speedo0, - &gm20b_pllg_params, clk); + ret = gk20a_clk_ctor(device, index, &gm20b_clk_speedo0, + &gm20b_pllg_params, clk); clk->pl_to_div = pl_to_div; clk->div_to_pl = div_to_pl; From 22b6c9e8fef4553017a92ed5e27451e0b2f9c5ce Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Wed, 1 Jun 2016 17:39:29 +0900 Subject: [PATCH 27/97] drm/nouveau/clk/gm20b: add glitchless and DFS support This patch adds support for advanced features supported by the Noise-Aware PLL of Maxwell. Glitchless switch allows the PL field to be updated without disabling the PLL first if the SYNC_MODE bit of the CFG register is set. More significantly, DFS allows the PLL to monitor the actual input voltage and to dynamically lower the output frequency accordingly. This allows the clock to be more tolerant of lower voltages. These improvements are only supported for Tegra speedos >= 1. Also add the voltage table that is suitable for GM20B's NAPLL. This change needs to be done atomically for the right voltages to be used by the clock driver. v2. Fix build on non-Tegra platforms Signed-off-by: Alexandre Courbot Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c | 89 +- .../gpu/drm/nouveau/nvkm/subdev/clk/gk20a.h | 92 ++ .../gpu/drm/nouveau/nvkm/subdev/clk/gm20b.c | 894 +++++++++++++++++- .../gpu/drm/nouveau/nvkm/subdev/volt/gm20b.c | 25 +- 4 files changed, 1002 insertions(+), 98 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c index 607d74a81c5e..218893e3e5f9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c @@ -28,70 +28,6 @@ #include #include -#define KHZ (1000) -#define MHZ (KHZ * 1000) - -#define MASK(w) ((1 << (w)) - 1) - -#define GPCPLL_CFG (SYS_GPCPLL_CFG_BASE + 0) -#define GPCPLL_CFG_ENABLE BIT(0) -#define GPCPLL_CFG_IDDQ BIT(1) -#define GPCPLL_CFG_LOCK_DET_OFF BIT(4) -#define GPCPLL_CFG_LOCK BIT(17) - -#define GPCPLL_COEFF (SYS_GPCPLL_CFG_BASE + 4) -#define GPCPLL_COEFF_M_SHIFT 0 -#define GPCPLL_COEFF_M_WIDTH 8 -#define GPCPLL_COEFF_N_SHIFT 8 -#define GPCPLL_COEFF_N_WIDTH 8 -#define GPCPLL_COEFF_P_SHIFT 16 -#define GPCPLL_COEFF_P_WIDTH 6 - -#define GPCPLL_CFG2 (SYS_GPCPLL_CFG_BASE + 0xc) -#define GPCPLL_CFG2_SETUP2_SHIFT 16 -#define GPCPLL_CFG2_PLL_STEPA_SHIFT 24 - -#define GPCPLL_CFG3 (SYS_GPCPLL_CFG_BASE + 0x18) -#define GPCPLL_CFG3_PLL_STEPB_SHIFT 16 - -#define GPC_BCASE_GPCPLL_CFG_BASE 0x00132800 -#define GPCPLL_NDIV_SLOWDOWN (SYS_GPCPLL_CFG_BASE + 0x1c) -#define GPCPLL_NDIV_SLOWDOWN_NDIV_LO_SHIFT 0 -#define GPCPLL_NDIV_SLOWDOWN_NDIV_MID_SHIFT 8 -#define GPCPLL_NDIV_SLOWDOWN_STEP_SIZE_LO2MID_SHIFT 16 -#define GPCPLL_NDIV_SLOWDOWN_SLOWDOWN_USING_PLL_SHIFT 22 -#define GPCPLL_NDIV_SLOWDOWN_EN_DYNRAMP_SHIFT 31 - -#define SEL_VCO (SYS_GPCPLL_CFG_BASE + 0x100) -#define SEL_VCO_GPC2CLK_OUT_SHIFT 0 - -#define GPC2CLK_OUT (SYS_GPCPLL_CFG_BASE + 0x250) -#define GPC2CLK_OUT_SDIV14_INDIV4_WIDTH 1 -#define GPC2CLK_OUT_SDIV14_INDIV4_SHIFT 31 -#define GPC2CLK_OUT_SDIV14_INDIV4_MODE 1 -#define GPC2CLK_OUT_VCODIV_WIDTH 6 -#define GPC2CLK_OUT_VCODIV_SHIFT 8 -#define GPC2CLK_OUT_VCODIV1 0 -#define GPC2CLK_OUT_VCODIV2 2 -#define GPC2CLK_OUT_VCODIV_MASK (MASK(GPC2CLK_OUT_VCODIV_WIDTH) << \ - GPC2CLK_OUT_VCODIV_SHIFT) -#define GPC2CLK_OUT_BYPDIV_WIDTH 6 -#define GPC2CLK_OUT_BYPDIV_SHIFT 0 -#define GPC2CLK_OUT_BYPDIV31 0x3c -#define GPC2CLK_OUT_INIT_MASK ((MASK(GPC2CLK_OUT_SDIV14_INDIV4_WIDTH) << \ - GPC2CLK_OUT_SDIV14_INDIV4_SHIFT)\ - | (MASK(GPC2CLK_OUT_VCODIV_WIDTH) << GPC2CLK_OUT_VCODIV_SHIFT)\ - | (MASK(GPC2CLK_OUT_BYPDIV_WIDTH) << GPC2CLK_OUT_BYPDIV_SHIFT)) -#define GPC2CLK_OUT_INIT_VAL ((GPC2CLK_OUT_SDIV14_INDIV4_MODE << \ - GPC2CLK_OUT_SDIV14_INDIV4_SHIFT) \ - | (GPC2CLK_OUT_VCODIV1 << GPC2CLK_OUT_VCODIV_SHIFT) \ - | (GPC2CLK_OUT_BYPDIV31 << GPC2CLK_OUT_BYPDIV_SHIFT)) - -#define GPC_BCAST_NDIV_SLOWDOWN_DEBUG (GPC_BCASE_GPCPLL_CFG_BASE + 0xa0) -#define GPC_BCAST_NDIV_SLOWDOWN_DEBUG_PLL_DYNRAMP_DONE_SYNCED_SHIFT 24 -#define GPC_BCAST_NDIV_SLOWDOWN_DEBUG_PLL_DYNRAMP_DONE_SYNCED_MASK \ - (0x1 << GPC_BCAST_NDIV_SLOWDOWN_DEBUG_PLL_DYNRAMP_DONE_SYNCED_SHIFT) - static const u8 _pl_to_div[] = { /* PL: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 */ /* p: */ 1, 2, 3, 4, 5, 6, 8, 10, 12, 16, 12, 16, 20, 24, 32, @@ -125,7 +61,7 @@ static const struct gk20a_clk_pllg_params gk20a_pllg_params = { .min_pl = 1, .max_pl = 32, }; -static void +void gk20a_pllg_read_mnp(struct gk20a_clk *clk, struct gk20a_pll *pll) { struct nvkm_device *device = clk->base.subdev.device; @@ -137,7 +73,7 @@ gk20a_pllg_read_mnp(struct gk20a_clk *clk, struct gk20a_pll *pll) pll->pl = (val >> GPCPLL_COEFF_P_SHIFT) & MASK(GPCPLL_COEFF_P_WIDTH); } -static void +void gk20a_pllg_write_mnp(struct gk20a_clk *clk, const struct gk20a_pll *pll) { struct nvkm_device *device = clk->base.subdev.device; @@ -149,7 +85,7 @@ gk20a_pllg_write_mnp(struct gk20a_clk *clk, const struct gk20a_pll *pll) nvkm_wr32(device, GPCPLL_COEFF, val); } -static u32 +u32 gk20a_pllg_calc_rate(struct gk20a_clk *clk, struct gk20a_pll *pll) { u32 rate; @@ -161,14 +97,7 @@ gk20a_pllg_calc_rate(struct gk20a_clk *clk, struct gk20a_pll *pll) return rate / divider / 2; } -static u32 -gk20a_pllg_n_lo(struct gk20a_clk *clk, struct gk20a_pll *pll) -{ - return DIV_ROUND_UP(pll->m * clk->params->min_vco, - clk->parent_rate / KHZ); -} - -static int +int gk20a_pllg_calc_mnp(struct gk20a_clk *clk, unsigned long rate, struct gk20a_pll *pll) { @@ -323,16 +252,6 @@ gk20a_pllg_slide(struct gk20a_clk *clk, u32 n) return ret; } -static bool -gk20a_pllg_is_enabled(struct gk20a_clk *clk) -{ - struct nvkm_device *device = clk->base.subdev.device; - u32 val; - - val = nvkm_rd32(device, GPCPLL_CFG); - return val & GPCPLL_CFG_ENABLE; -} - static int gk20a_pllg_enable(struct gk20a_clk *clk) { diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.h b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.h index 73551f8209fa..0d1450972162 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.h @@ -24,9 +24,79 @@ #ifndef __NVKM_CLK_GK20A_H__ #define __NVKM_CLK_GK20A_H__ +#define KHZ (1000) +#define MHZ (KHZ * 1000) + +#define MASK(w) ((1 << (w)) - 1) + #define GK20A_CLK_GPC_MDIV 1000 #define SYS_GPCPLL_CFG_BASE 0x00137000 +#define GPCPLL_CFG (SYS_GPCPLL_CFG_BASE + 0) +#define GPCPLL_CFG_ENABLE BIT(0) +#define GPCPLL_CFG_IDDQ BIT(1) +#define GPCPLL_CFG_LOCK_DET_OFF BIT(4) +#define GPCPLL_CFG_LOCK BIT(17) + +#define GPCPLL_CFG2 (SYS_GPCPLL_CFG_BASE + 0xc) +#define GPCPLL_CFG2_SETUP2_SHIFT 16 +#define GPCPLL_CFG2_PLL_STEPA_SHIFT 24 + +#define GPCPLL_CFG3 (SYS_GPCPLL_CFG_BASE + 0x18) +#define GPCPLL_CFG3_VCO_CTRL_SHIFT 0 +#define GPCPLL_CFG3_VCO_CTRL_WIDTH 9 +#define GPCPLL_CFG3_VCO_CTRL_MASK \ + (MASK(GPCPLL_CFG3_VCO_CTRL_WIDTH) << GPCPLL_CFG3_VCO_CTRL_SHIFT) +#define GPCPLL_CFG3_PLL_STEPB_SHIFT 16 +#define GPCPLL_CFG3_PLL_STEPB_WIDTH 8 + +#define GPCPLL_COEFF (SYS_GPCPLL_CFG_BASE + 4) +#define GPCPLL_COEFF_M_SHIFT 0 +#define GPCPLL_COEFF_M_WIDTH 8 +#define GPCPLL_COEFF_N_SHIFT 8 +#define GPCPLL_COEFF_N_WIDTH 8 +#define GPCPLL_COEFF_N_MASK \ + (MASK(GPCPLL_COEFF_N_WIDTH) << GPCPLL_COEFF_N_SHIFT) +#define GPCPLL_COEFF_P_SHIFT 16 +#define GPCPLL_COEFF_P_WIDTH 6 + +#define GPCPLL_NDIV_SLOWDOWN (SYS_GPCPLL_CFG_BASE + 0x1c) +#define GPCPLL_NDIV_SLOWDOWN_NDIV_LO_SHIFT 0 +#define GPCPLL_NDIV_SLOWDOWN_NDIV_MID_SHIFT 8 +#define GPCPLL_NDIV_SLOWDOWN_STEP_SIZE_LO2MID_SHIFT 16 +#define GPCPLL_NDIV_SLOWDOWN_SLOWDOWN_USING_PLL_SHIFT 22 +#define GPCPLL_NDIV_SLOWDOWN_EN_DYNRAMP_SHIFT 31 + +#define GPC_BCAST_GPCPLL_CFG_BASE 0x00132800 +#define GPC_BCAST_NDIV_SLOWDOWN_DEBUG (GPC_BCAST_GPCPLL_CFG_BASE + 0xa0) +#define GPC_BCAST_NDIV_SLOWDOWN_DEBUG_PLL_DYNRAMP_DONE_SYNCED_SHIFT 24 +#define GPC_BCAST_NDIV_SLOWDOWN_DEBUG_PLL_DYNRAMP_DONE_SYNCED_MASK \ + (0x1 << GPC_BCAST_NDIV_SLOWDOWN_DEBUG_PLL_DYNRAMP_DONE_SYNCED_SHIFT) + +#define SEL_VCO (SYS_GPCPLL_CFG_BASE + 0x100) +#define SEL_VCO_GPC2CLK_OUT_SHIFT 0 + +#define GPC2CLK_OUT (SYS_GPCPLL_CFG_BASE + 0x250) +#define GPC2CLK_OUT_SDIV14_INDIV4_WIDTH 1 +#define GPC2CLK_OUT_SDIV14_INDIV4_SHIFT 31 +#define GPC2CLK_OUT_SDIV14_INDIV4_MODE 1 +#define GPC2CLK_OUT_VCODIV_WIDTH 6 +#define GPC2CLK_OUT_VCODIV_SHIFT 8 +#define GPC2CLK_OUT_VCODIV1 0 +#define GPC2CLK_OUT_VCODIV2 2 +#define GPC2CLK_OUT_VCODIV_MASK (MASK(GPC2CLK_OUT_VCODIV_WIDTH) << \ + GPC2CLK_OUT_VCODIV_SHIFT) +#define GPC2CLK_OUT_BYPDIV_WIDTH 6 +#define GPC2CLK_OUT_BYPDIV_SHIFT 0 +#define GPC2CLK_OUT_BYPDIV31 0x3c +#define GPC2CLK_OUT_INIT_MASK ((MASK(GPC2CLK_OUT_SDIV14_INDIV4_WIDTH) << \ + GPC2CLK_OUT_SDIV14_INDIV4_SHIFT)\ + | (MASK(GPC2CLK_OUT_VCODIV_WIDTH) << GPC2CLK_OUT_VCODIV_SHIFT)\ + | (MASK(GPC2CLK_OUT_BYPDIV_WIDTH) << GPC2CLK_OUT_BYPDIV_SHIFT)) +#define GPC2CLK_OUT_INIT_VAL ((GPC2CLK_OUT_SDIV14_INDIV4_MODE << \ + GPC2CLK_OUT_SDIV14_INDIV4_SHIFT) \ + | (GPC2CLK_OUT_VCODIV1 << GPC2CLK_OUT_VCODIV_SHIFT) \ + | (GPC2CLK_OUT_BYPDIV31 << GPC2CLK_OUT_BYPDIV_SHIFT)) /* All frequencies in Khz */ struct gk20a_clk_pllg_params { @@ -54,6 +124,28 @@ struct gk20a_clk { }; #define gk20a_clk(p) container_of((p), struct gk20a_clk, base) +u32 gk20a_pllg_calc_rate(struct gk20a_clk *, struct gk20a_pll *); +int gk20a_pllg_calc_mnp(struct gk20a_clk *, unsigned long, struct gk20a_pll *); +void gk20a_pllg_read_mnp(struct gk20a_clk *, struct gk20a_pll *); +void gk20a_pllg_write_mnp(struct gk20a_clk *, const struct gk20a_pll *); + +static inline bool +gk20a_pllg_is_enabled(struct gk20a_clk *clk) +{ + struct nvkm_device *device = clk->base.subdev.device; + u32 val; + + val = nvkm_rd32(device, GPCPLL_CFG); + return val & GPCPLL_CFG_ENABLE; +} + +static inline u32 +gk20a_pllg_n_lo(struct gk20a_clk *clk, struct gk20a_pll *pll) +{ + return DIV_ROUND_UP(pll->m * clk->params->min_vco, + clk->parent_rate / KHZ); +} + int gk20a_clk_ctor(struct nvkm_device *, int, const struct nvkm_clk_func *, const struct gk20a_clk_pllg_params *, struct gk20a_clk *); void gk20a_clk_fini(struct nvkm_clk *); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gm20b.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gm20b.c index 68749bbbe623..b284e949f732 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gm20b.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gm20b.c @@ -21,20 +21,123 @@ */ #include +#include +#include #include +#include #include "priv.h" #include "gk20a.h" -#define KHZ (1000) -#define MHZ (KHZ * 1000) - -#define MASK(w) ((1 << (w)) - 1) +#define GPCPLL_CFG_SYNC_MODE BIT(2) #define BYPASSCTRL_SYS (SYS_GPCPLL_CFG_BASE + 0x340) #define BYPASSCTRL_SYS_GPCPLL_SHIFT 0 #define BYPASSCTRL_SYS_GPCPLL_WIDTH 1 +#define GPCPLL_CFG2_SDM_DIN_SHIFT 0 +#define GPCPLL_CFG2_SDM_DIN_WIDTH 8 +#define GPCPLL_CFG2_SDM_DIN_MASK \ + (MASK(GPCPLL_CFG2_SDM_DIN_WIDTH) << GPCPLL_CFG2_SDM_DIN_SHIFT) +#define GPCPLL_CFG2_SDM_DIN_NEW_SHIFT 8 +#define GPCPLL_CFG2_SDM_DIN_NEW_WIDTH 15 +#define GPCPLL_CFG2_SDM_DIN_NEW_MASK \ + (MASK(GPCPLL_CFG2_SDM_DIN_NEW_WIDTH) << GPCPLL_CFG2_SDM_DIN_NEW_SHIFT) +#define GPCPLL_CFG2_SETUP2_SHIFT 16 +#define GPCPLL_CFG2_PLL_STEPA_SHIFT 24 + +#define GPCPLL_DVFS0 (SYS_GPCPLL_CFG_BASE + 0x10) +#define GPCPLL_DVFS0_DFS_COEFF_SHIFT 0 +#define GPCPLL_DVFS0_DFS_COEFF_WIDTH 7 +#define GPCPLL_DVFS0_DFS_COEFF_MASK \ + (MASK(GPCPLL_DVFS0_DFS_COEFF_WIDTH) << GPCPLL_DVFS0_DFS_COEFF_SHIFT) +#define GPCPLL_DVFS0_DFS_DET_MAX_SHIFT 8 +#define GPCPLL_DVFS0_DFS_DET_MAX_WIDTH 7 +#define GPCPLL_DVFS0_DFS_DET_MAX_MASK \ + (MASK(GPCPLL_DVFS0_DFS_DET_MAX_WIDTH) << GPCPLL_DVFS0_DFS_DET_MAX_SHIFT) + +#define GPCPLL_DVFS1 (SYS_GPCPLL_CFG_BASE + 0x14) +#define GPCPLL_DVFS1_DFS_EXT_DET_SHIFT 0 +#define GPCPLL_DVFS1_DFS_EXT_DET_WIDTH 7 +#define GPCPLL_DVFS1_DFS_EXT_STRB_SHIFT 7 +#define GPCPLL_DVFS1_DFS_EXT_STRB_WIDTH 1 +#define GPCPLL_DVFS1_DFS_EXT_CAL_SHIFT 8 +#define GPCPLL_DVFS1_DFS_EXT_CAL_WIDTH 7 +#define GPCPLL_DVFS1_DFS_EXT_SEL_SHIFT 15 +#define GPCPLL_DVFS1_DFS_EXT_SEL_WIDTH 1 +#define GPCPLL_DVFS1_DFS_CTRL_SHIFT 16 +#define GPCPLL_DVFS1_DFS_CTRL_WIDTH 12 +#define GPCPLL_DVFS1_EN_SDM_SHIFT 28 +#define GPCPLL_DVFS1_EN_SDM_WIDTH 1 +#define GPCPLL_DVFS1_EN_SDM_BIT BIT(28) +#define GPCPLL_DVFS1_EN_DFS_SHIFT 29 +#define GPCPLL_DVFS1_EN_DFS_WIDTH 1 +#define GPCPLL_DVFS1_EN_DFS_BIT BIT(29) +#define GPCPLL_DVFS1_EN_DFS_CAL_SHIFT 30 +#define GPCPLL_DVFS1_EN_DFS_CAL_WIDTH 1 +#define GPCPLL_DVFS1_EN_DFS_CAL_BIT BIT(30) +#define GPCPLL_DVFS1_DFS_CAL_DONE_SHIFT 31 +#define GPCPLL_DVFS1_DFS_CAL_DONE_WIDTH 1 +#define GPCPLL_DVFS1_DFS_CAL_DONE_BIT BIT(31) + +#define GPC_BCAST_GPCPLL_DVFS2 (GPC_BCAST_GPCPLL_CFG_BASE + 0x20) +#define GPC_BCAST_GPCPLL_DVFS2_DFS_EXT_STROBE_BIT BIT(16) + +#define GPCPLL_CFG3_PLL_DFS_TESTOUT_SHIFT 24 +#define GPCPLL_CFG3_PLL_DFS_TESTOUT_WIDTH 7 + +#define DFS_DET_RANGE 6 /* -2^6 ... 2^6-1 */ +#define SDM_DIN_RANGE 12 /* -2^12 ... 2^12-1 */ + +struct gm20b_clk_dvfs_params { + s32 coeff_slope; + s32 coeff_offs; + u32 vco_ctrl; +}; + +static const struct gm20b_clk_dvfs_params gm20b_dvfs_params = { + .coeff_slope = -165230, + .coeff_offs = 214007, + .vco_ctrl = 0x7 << 3, +}; + +/* + * base.n is now the *integer* part of the N factor. + * sdm_din contains n's decimal part. + */ +struct gm20b_pll { + struct gk20a_pll base; + u32 sdm_din; +}; + +struct gm20b_clk_dvfs { + u32 dfs_coeff; + s32 dfs_det_max; + s32 dfs_ext_cal; +}; + +struct gm20b_clk { + /* currently applied parameters */ + struct gk20a_clk base; + struct gm20b_clk_dvfs dvfs; + u32 uv; + + /* new parameters to apply */ + struct gk20a_pll new_pll; + struct gm20b_clk_dvfs new_dvfs; + u32 new_uv; + + const struct gm20b_clk_dvfs_params *dvfs_params; + + /* fused parameters */ + s32 uvdet_slope; + s32 uvdet_offs; + + /* safe frequency we can use at minimum voltage */ + u32 safe_fmax_vmin; +}; +#define gm20b_clk(p) container_of((gk20a_clk(p)), struct gm20b_clk, base) + static u32 pl_to_div(u32 pl) { return pl; @@ -53,6 +156,484 @@ static const struct gk20a_clk_pllg_params gm20b_pllg_params = { .min_pl = 1, .max_pl = 31, }; +static void +gm20b_pllg_read_mnp(struct gm20b_clk *clk, struct gm20b_pll *pll) +{ + struct nvkm_subdev *subdev = &clk->base.base.subdev; + struct nvkm_device *device = subdev->device; + u32 val; + + gk20a_pllg_read_mnp(&clk->base, &pll->base); + val = nvkm_rd32(device, GPCPLL_CFG2); + pll->sdm_din = (val >> GPCPLL_CFG2_SDM_DIN_SHIFT) & + MASK(GPCPLL_CFG2_SDM_DIN_WIDTH); +} + +static void +gm20b_pllg_write_mnp(struct gm20b_clk *clk, const struct gm20b_pll *pll) +{ + struct nvkm_device *device = clk->base.base.subdev.device; + + nvkm_mask(device, GPCPLL_CFG2, GPCPLL_CFG2_SDM_DIN_MASK, + pll->sdm_din << GPCPLL_CFG2_SDM_DIN_SHIFT); + gk20a_pllg_write_mnp(&clk->base, &pll->base); +} + +/* + * Determine DFS_COEFF for the requested voltage. Always select external + * calibration override equal to the voltage, and set maximum detection + * limit "0" (to make sure that PLL output remains under F/V curve when + * voltage increases). + */ +static void +gm20b_dvfs_calc_det_coeff(struct gm20b_clk *clk, s32 uv, + struct gm20b_clk_dvfs *dvfs) +{ + struct nvkm_subdev *subdev = &clk->base.base.subdev; + const struct gm20b_clk_dvfs_params *p = clk->dvfs_params; + u32 coeff; + /* Work with mv as uv would likely trigger an overflow */ + s32 mv = DIV_ROUND_CLOSEST(uv, 1000); + + /* coeff = slope * voltage + offset */ + coeff = DIV_ROUND_CLOSEST(mv * p->coeff_slope, 1000) + p->coeff_offs; + coeff = DIV_ROUND_CLOSEST(coeff, 1000); + dvfs->dfs_coeff = min_t(u32, coeff, MASK(GPCPLL_DVFS0_DFS_COEFF_WIDTH)); + + dvfs->dfs_ext_cal = DIV_ROUND_CLOSEST(uv - clk->uvdet_offs, + clk->uvdet_slope); + /* should never happen */ + if (abs(dvfs->dfs_ext_cal) >= BIT(DFS_DET_RANGE)) + nvkm_error(subdev, "dfs_ext_cal overflow!\n"); + + dvfs->dfs_det_max = 0; + + nvkm_debug(subdev, "%s uv: %d coeff: %x, ext_cal: %d, det_max: %d\n", + __func__, uv, dvfs->dfs_coeff, dvfs->dfs_ext_cal, + dvfs->dfs_det_max); +} + +/* + * Solve equation for integer and fractional part of the effective NDIV: + * + * n_eff = n_int + 1/2 + (SDM_DIN / 2^(SDM_DIN_RANGE + 1)) + + * (DVFS_COEFF * DVFS_DET_DELTA) / 2^DFS_DET_RANGE + * + * The SDM_DIN LSB is finally shifted out, since it is not accessible by sw. + */ +static void +gm20b_dvfs_calc_ndiv(struct gm20b_clk *clk, u32 n_eff, u32 *n_int, u32 *sdm_din) +{ + struct nvkm_subdev *subdev = &clk->base.base.subdev; + const struct gk20a_clk_pllg_params *p = clk->base.params; + u32 n; + s32 det_delta; + u32 rem, rem_range; + + /* calculate current ext_cal and subtract previous one */ + det_delta = DIV_ROUND_CLOSEST(((s32)clk->uv) - clk->uvdet_offs, + clk->uvdet_slope); + det_delta -= clk->dvfs.dfs_ext_cal; + det_delta = min(det_delta, clk->dvfs.dfs_det_max); + det_delta *= clk->dvfs.dfs_coeff; + + /* integer part of n */ + n = (n_eff << DFS_DET_RANGE) - det_delta; + /* should never happen! */ + if (n <= 0) { + nvkm_error(subdev, "ndiv <= 0 - setting to 1...\n"); + n = 1 << DFS_DET_RANGE; + } + if (n >> DFS_DET_RANGE > p->max_n) { + nvkm_error(subdev, "ndiv > max_n - setting to max_n...\n"); + n = p->max_n << DFS_DET_RANGE; + } + *n_int = n >> DFS_DET_RANGE; + + /* fractional part of n */ + rem = ((u32)n) & MASK(DFS_DET_RANGE); + rem_range = SDM_DIN_RANGE + 1 - DFS_DET_RANGE; + /* subtract 2^SDM_DIN_RANGE to account for the 1/2 of the equation */ + rem = (rem << rem_range) - BIT(SDM_DIN_RANGE); + /* lose 8 LSB and clip - sdm_din only keeps the most significant byte */ + *sdm_din = (rem >> BITS_PER_BYTE) & MASK(GPCPLL_CFG2_SDM_DIN_WIDTH); + + nvkm_debug(subdev, "%s n_eff: %d, n_int: %d, sdm_din: %d\n", __func__, + n_eff, *n_int, *sdm_din); +} + +static int +gm20b_pllg_slide(struct gm20b_clk *clk, u32 n) +{ + struct nvkm_subdev *subdev = &clk->base.base.subdev; + struct nvkm_device *device = subdev->device; + struct gm20b_pll pll; + u32 n_int, sdm_din; + int ret = 0; + + /* calculate the new n_int/sdm_din for this n/uv */ + gm20b_dvfs_calc_ndiv(clk, n, &n_int, &sdm_din); + + /* get old coefficients */ + gm20b_pllg_read_mnp(clk, &pll); + /* do nothing if NDIV is the same */ + if (n_int == pll.base.n && sdm_din == pll.sdm_din) + return 0; + + /* pll slowdown mode */ + nvkm_mask(device, GPCPLL_NDIV_SLOWDOWN, + BIT(GPCPLL_NDIV_SLOWDOWN_SLOWDOWN_USING_PLL_SHIFT), + BIT(GPCPLL_NDIV_SLOWDOWN_SLOWDOWN_USING_PLL_SHIFT)); + + /* new ndiv ready for ramp */ + /* in DVFS mode SDM is updated via "new" field */ + nvkm_mask(device, GPCPLL_CFG2, GPCPLL_CFG2_SDM_DIN_NEW_MASK, + sdm_din << GPCPLL_CFG2_SDM_DIN_NEW_SHIFT); + pll.base.n = n_int; + udelay(1); + gk20a_pllg_write_mnp(&clk->base, &pll.base); + + /* dynamic ramp to new ndiv */ + udelay(1); + nvkm_mask(device, GPCPLL_NDIV_SLOWDOWN, + BIT(GPCPLL_NDIV_SLOWDOWN_EN_DYNRAMP_SHIFT), + BIT(GPCPLL_NDIV_SLOWDOWN_EN_DYNRAMP_SHIFT)); + + /* wait for ramping to complete */ + if (nvkm_wait_usec(device, 500, GPC_BCAST_NDIV_SLOWDOWN_DEBUG, + GPC_BCAST_NDIV_SLOWDOWN_DEBUG_PLL_DYNRAMP_DONE_SYNCED_MASK, + GPC_BCAST_NDIV_SLOWDOWN_DEBUG_PLL_DYNRAMP_DONE_SYNCED_MASK) < 0) + ret = -ETIMEDOUT; + + /* in DVFS mode complete SDM update */ + nvkm_mask(device, GPCPLL_CFG2, GPCPLL_CFG2_SDM_DIN_MASK, + sdm_din << GPCPLL_CFG2_SDM_DIN_SHIFT); + + /* exit slowdown mode */ + nvkm_mask(device, GPCPLL_NDIV_SLOWDOWN, + BIT(GPCPLL_NDIV_SLOWDOWN_SLOWDOWN_USING_PLL_SHIFT) | + BIT(GPCPLL_NDIV_SLOWDOWN_EN_DYNRAMP_SHIFT), 0); + nvkm_rd32(device, GPCPLL_NDIV_SLOWDOWN); + + return ret; +} + +static int +gm20b_pllg_enable(struct gm20b_clk *clk) +{ + struct nvkm_device *device = clk->base.base.subdev.device; + + nvkm_mask(device, GPCPLL_CFG, GPCPLL_CFG_ENABLE, GPCPLL_CFG_ENABLE); + nvkm_rd32(device, GPCPLL_CFG); + + /* In DVFS mode lock cannot be used - so just delay */ + udelay(40); + + /* set SYNC_MODE for glitchless switch out of bypass */ + nvkm_mask(device, GPCPLL_CFG, GPCPLL_CFG_SYNC_MODE, + GPCPLL_CFG_SYNC_MODE); + nvkm_rd32(device, GPCPLL_CFG); + + /* switch to VCO mode */ + nvkm_mask(device, SEL_VCO, BIT(SEL_VCO_GPC2CLK_OUT_SHIFT), + BIT(SEL_VCO_GPC2CLK_OUT_SHIFT)); + + return 0; +} + +static void +gm20b_pllg_disable(struct gm20b_clk *clk) +{ + struct nvkm_device *device = clk->base.base.subdev.device; + + /* put PLL in bypass before disabling it */ + nvkm_mask(device, SEL_VCO, BIT(SEL_VCO_GPC2CLK_OUT_SHIFT), 0); + + /* clear SYNC_MODE before disabling PLL */ + nvkm_mask(device, GPCPLL_CFG, GPCPLL_CFG_SYNC_MODE, 0); + + nvkm_mask(device, GPCPLL_CFG, GPCPLL_CFG_ENABLE, 0); + nvkm_rd32(device, GPCPLL_CFG); +} + +static int +gm20b_pllg_program_mnp(struct gm20b_clk *clk, const struct gk20a_pll *pll) +{ + struct nvkm_subdev *subdev = &clk->base.base.subdev; + struct nvkm_device *device = subdev->device; + struct gm20b_pll cur_pll; + u32 n_int, sdm_din; + /* if we only change pdiv, we can do a glitchless transition */ + bool pdiv_only; + int ret; + + gm20b_dvfs_calc_ndiv(clk, pll->n, &n_int, &sdm_din); + gm20b_pllg_read_mnp(clk, &cur_pll); + pdiv_only = cur_pll.base.n == n_int && cur_pll.sdm_din == sdm_din && + cur_pll.base.m == pll->m; + + /* need full sequence if clock not enabled yet */ + if (!gk20a_pllg_is_enabled(&clk->base)) + pdiv_only = false; + + /* split VCO-to-bypass jump in half by setting out divider 1:2 */ + nvkm_mask(device, GPC2CLK_OUT, GPC2CLK_OUT_VCODIV_MASK, + GPC2CLK_OUT_VCODIV2 << GPC2CLK_OUT_VCODIV_SHIFT); + /* Intentional 2nd write to assure linear divider operation */ + nvkm_mask(device, GPC2CLK_OUT, GPC2CLK_OUT_VCODIV_MASK, + GPC2CLK_OUT_VCODIV2 << GPC2CLK_OUT_VCODIV_SHIFT); + nvkm_rd32(device, GPC2CLK_OUT); + udelay(2); + + if (pdiv_only) { + u32 old = cur_pll.base.pl; + u32 new = pll->pl; + + /* + * we can do a glitchless transition only if the old and new PL + * parameters share at least one bit set to 1. If this is not + * the case, calculate and program an interim PL that will allow + * us to respect that rule. + */ + if ((old & new) == 0) { + cur_pll.base.pl = min(old | BIT(ffs(new) - 1), + new | BIT(ffs(old) - 1)); + gk20a_pllg_write_mnp(&clk->base, &cur_pll.base); + } + + cur_pll.base.pl = new; + gk20a_pllg_write_mnp(&clk->base, &cur_pll.base); + } else { + /* disable before programming if more than pdiv changes */ + gm20b_pllg_disable(clk); + + cur_pll.base = *pll; + cur_pll.base.n = n_int; + cur_pll.sdm_din = sdm_din; + gm20b_pllg_write_mnp(clk, &cur_pll); + + ret = gm20b_pllg_enable(clk); + if (ret) + return ret; + } + + /* restore out divider 1:1 */ + udelay(2); + nvkm_mask(device, GPC2CLK_OUT, GPC2CLK_OUT_VCODIV_MASK, + GPC2CLK_OUT_VCODIV1 << GPC2CLK_OUT_VCODIV_SHIFT); + /* Intentional 2nd write to assure linear divider operation */ + nvkm_mask(device, GPC2CLK_OUT, GPC2CLK_OUT_VCODIV_MASK, + GPC2CLK_OUT_VCODIV1 << GPC2CLK_OUT_VCODIV_SHIFT); + nvkm_rd32(device, GPC2CLK_OUT); + + return 0; +} + +static int +gm20b_pllg_program_mnp_slide(struct gm20b_clk *clk, const struct gk20a_pll *pll) +{ + struct gk20a_pll cur_pll; + int ret; + + if (gk20a_pllg_is_enabled(&clk->base)) { + gk20a_pllg_read_mnp(&clk->base, &cur_pll); + + /* just do NDIV slide if there is no change to M and PL */ + if (pll->m == cur_pll.m && pll->pl == cur_pll.pl) + return gm20b_pllg_slide(clk, pll->n); + + /* slide down to current NDIV_LO */ + cur_pll.n = gk20a_pllg_n_lo(&clk->base, &cur_pll); + ret = gm20b_pllg_slide(clk, cur_pll.n); + if (ret) + return ret; + } + + /* program MNP with the new clock parameters and new NDIV_LO */ + cur_pll = *pll; + cur_pll.n = gk20a_pllg_n_lo(&clk->base, &cur_pll); + ret = gm20b_pllg_program_mnp(clk, &cur_pll); + if (ret) + return ret; + + /* slide up to new NDIV */ + return gm20b_pllg_slide(clk, pll->n); +} + +static int +gm20b_clk_calc(struct nvkm_clk *base, struct nvkm_cstate *cstate) +{ + struct gm20b_clk *clk = gm20b_clk(base); + struct nvkm_subdev *subdev = &base->subdev; + struct nvkm_volt *volt = base->subdev.device->volt; + int ret; + + ret = gk20a_pllg_calc_mnp(&clk->base, cstate->domain[nv_clk_src_gpc] * + GK20A_CLK_GPC_MDIV, &clk->new_pll); + if (ret) + return ret; + + clk->new_uv = volt->vid[cstate->voltage].uv; + gm20b_dvfs_calc_det_coeff(clk, clk->new_uv, &clk->new_dvfs); + + nvkm_debug(subdev, "%s uv: %d uv\n", __func__, clk->new_uv); + + return 0; +} + +/* + * Compute PLL parameters that are always safe for the current voltage + */ +static void +gm20b_dvfs_calc_safe_pll(struct gm20b_clk *clk, struct gk20a_pll *pll) +{ + u32 rate = gk20a_pllg_calc_rate(&clk->base, pll) / KHZ; + u32 parent_rate = clk->base.parent_rate / KHZ; + u32 nmin, nsafe; + + /* remove a safe margin of 10% */ + if (rate > clk->safe_fmax_vmin) + rate = rate * (100 - 10) / 100; + + /* gpc2clk */ + rate *= 2; + + nmin = DIV_ROUND_UP(pll->m * clk->base.params->min_vco, parent_rate); + nsafe = pll->m * rate / (clk->base.parent_rate); + + if (nsafe < nmin) { + pll->pl = DIV_ROUND_UP(nmin * parent_rate, pll->m * rate); + nsafe = nmin; + } + + pll->n = nsafe; +} + +static void +gm20b_dvfs_program_coeff(struct gm20b_clk *clk, u32 coeff) +{ + struct nvkm_device *device = clk->base.base.subdev.device; + + /* strobe to read external DFS coefficient */ + nvkm_mask(device, GPC_BCAST_GPCPLL_DVFS2, + GPC_BCAST_GPCPLL_DVFS2_DFS_EXT_STROBE_BIT, + GPC_BCAST_GPCPLL_DVFS2_DFS_EXT_STROBE_BIT); + + nvkm_mask(device, GPCPLL_DVFS0, GPCPLL_DVFS0_DFS_COEFF_MASK, + coeff << GPCPLL_DVFS0_DFS_COEFF_SHIFT); + + udelay(1); + nvkm_mask(device, GPC_BCAST_GPCPLL_DVFS2, + GPC_BCAST_GPCPLL_DVFS2_DFS_EXT_STROBE_BIT, 0); +} + +static void +gm20b_dvfs_program_ext_cal(struct gm20b_clk *clk, u32 dfs_det_cal) +{ + struct nvkm_device *device = clk->base.base.subdev.device; + u32 val; + + nvkm_mask(device, GPC_BCAST_GPCPLL_DVFS2, MASK(DFS_DET_RANGE + 1), + dfs_det_cal); + udelay(1); + + val = nvkm_rd32(device, GPCPLL_DVFS1); + if (!(val & BIT(25))) { + /* Use external value to overwrite calibration value */ + val |= BIT(25) | BIT(16); + nvkm_wr32(device, GPCPLL_DVFS1, val); + } +} + +static void +gm20b_dvfs_program_dfs_detection(struct gm20b_clk *clk, + struct gm20b_clk_dvfs *dvfs) +{ + struct nvkm_device *device = clk->base.base.subdev.device; + + /* strobe to read external DFS coefficient */ + nvkm_mask(device, GPC_BCAST_GPCPLL_DVFS2, + GPC_BCAST_GPCPLL_DVFS2_DFS_EXT_STROBE_BIT, + GPC_BCAST_GPCPLL_DVFS2_DFS_EXT_STROBE_BIT); + + nvkm_mask(device, GPCPLL_DVFS0, + GPCPLL_DVFS0_DFS_COEFF_MASK | GPCPLL_DVFS0_DFS_DET_MAX_MASK, + dvfs->dfs_coeff << GPCPLL_DVFS0_DFS_COEFF_SHIFT | + dvfs->dfs_det_max << GPCPLL_DVFS0_DFS_DET_MAX_SHIFT); + + udelay(1); + nvkm_mask(device, GPC_BCAST_GPCPLL_DVFS2, + GPC_BCAST_GPCPLL_DVFS2_DFS_EXT_STROBE_BIT, 0); + + gm20b_dvfs_program_ext_cal(clk, dvfs->dfs_ext_cal); +} + +static int +gm20b_clk_prog(struct nvkm_clk *base) +{ + struct gm20b_clk *clk = gm20b_clk(base); + u32 cur_freq; + int ret; + + /* No change in DVFS settings? */ + if (clk->uv == clk->new_uv) + goto prog; + + /* + * Interim step for changing DVFS detection settings: low enough + * frequency to be safe at at DVFS coeff = 0. + * + * 1. If voltage is increasing: + * - safe frequency target matches the lowest - old - frequency + * - DVFS settings are still old + * - Voltage already increased to new level by volt, but maximum + * detection limit assures PLL output remains under F/V curve + * + * 2. If voltage is decreasing: + * - safe frequency target matches the lowest - new - frequency + * - DVFS settings are still old + * - Voltage is also old, it will be lowered by volt afterwards + * + * Interim step can be skipped if old frequency is below safe minimum, + * i.e., it is low enough to be safe at any voltage in operating range + * with zero DVFS coefficient. + */ + cur_freq = nvkm_clk_read(&clk->base.base, nv_clk_src_gpc); + if (cur_freq > clk->safe_fmax_vmin) { + struct gk20a_pll pll_safe; + + if (clk->uv < clk->new_uv) + /* voltage will raise: safe frequency is current one */ + pll_safe = clk->base.pll; + else + /* voltage will drop: safe frequency is new one */ + pll_safe = clk->new_pll; + + gm20b_dvfs_calc_safe_pll(clk, &pll_safe); + ret = gm20b_pllg_program_mnp_slide(clk, &pll_safe); + if (ret) + return ret; + } + + /* + * DVFS detection settings transition: + * - Set DVFS coefficient zero + * - Set calibration level to new voltage + * - Set DVFS coefficient to match new voltage + */ + gm20b_dvfs_program_coeff(clk, 0); + gm20b_dvfs_program_ext_cal(clk, clk->new_dvfs.dfs_ext_cal); + gm20b_dvfs_program_coeff(clk, clk->new_dvfs.dfs_coeff); + gm20b_dvfs_program_dfs_detection(clk, &clk->new_dvfs); + +prog: + clk->uv = clk->new_uv; + clk->dvfs = clk->new_dvfs; + clk->base.pll = clk->new_pll; + + return gm20b_pllg_program_mnp_slide(clk, &clk->base.pll); +} + static struct nvkm_pstate gm20b_pstates[] = { { @@ -133,9 +714,99 @@ gm20b_pstates[] = { .voltage = 12, }, }, - }; +static void +gm20b_clk_fini(struct nvkm_clk *base) +{ + struct nvkm_device *device = base->subdev.device; + struct gm20b_clk *clk = gm20b_clk(base); + + /* slide to VCO min */ + if (gk20a_pllg_is_enabled(&clk->base)) { + struct gk20a_pll pll; + u32 n_lo; + + gk20a_pllg_read_mnp(&clk->base, &pll); + n_lo = gk20a_pllg_n_lo(&clk->base, &pll); + gm20b_pllg_slide(clk, n_lo); + } + + gm20b_pllg_disable(clk); + + /* set IDDQ */ + nvkm_mask(device, GPCPLL_CFG, GPCPLL_CFG_IDDQ, 1); +} + +static int +gm20b_clk_init_dvfs(struct gm20b_clk *clk) +{ + struct nvkm_subdev *subdev = &clk->base.base.subdev; + struct nvkm_device *device = subdev->device; + bool fused = clk->uvdet_offs && clk->uvdet_slope; + static const s32 ADC_SLOPE_UV = 10000; /* default ADC detection slope */ + u32 data; + int ret; + + /* Enable NA DVFS */ + nvkm_mask(device, GPCPLL_DVFS1, GPCPLL_DVFS1_EN_DFS_BIT, + GPCPLL_DVFS1_EN_DFS_BIT); + + /* Set VCO_CTRL */ + if (clk->dvfs_params->vco_ctrl) + nvkm_mask(device, GPCPLL_CFG3, GPCPLL_CFG3_VCO_CTRL_MASK, + clk->dvfs_params->vco_ctrl << GPCPLL_CFG3_VCO_CTRL_SHIFT); + + if (fused) { + /* Start internal calibration, but ignore results */ + nvkm_mask(device, GPCPLL_DVFS1, GPCPLL_DVFS1_EN_DFS_CAL_BIT, + GPCPLL_DVFS1_EN_DFS_CAL_BIT); + + /* got uvdev parameters from fuse, skip calibration */ + goto calibrated; + } + + /* + * If calibration parameters are not fused, start internal calibration, + * wait for completion, and use results along with default slope to + * calculate ADC offset during boot. + */ + nvkm_mask(device, GPCPLL_DVFS1, GPCPLL_DVFS1_EN_DFS_CAL_BIT, + GPCPLL_DVFS1_EN_DFS_CAL_BIT); + + /* Wait for internal calibration done (spec < 2us). */ + ret = nvkm_wait_usec(device, 10, GPCPLL_DVFS1, + GPCPLL_DVFS1_DFS_CAL_DONE_BIT, + GPCPLL_DVFS1_DFS_CAL_DONE_BIT); + if (ret < 0) { + nvkm_error(subdev, "GPCPLL calibration timeout\n"); + return -ETIMEDOUT; + } + + data = nvkm_rd32(device, GPCPLL_CFG3) >> + GPCPLL_CFG3_PLL_DFS_TESTOUT_SHIFT; + data &= MASK(GPCPLL_CFG3_PLL_DFS_TESTOUT_WIDTH); + + clk->uvdet_slope = ADC_SLOPE_UV; + clk->uvdet_offs = ((s32)clk->uv) - data * ADC_SLOPE_UV; + + nvkm_debug(subdev, "calibrated DVFS parameters: offs %d, slope %d\n", + clk->uvdet_offs, clk->uvdet_slope); + +calibrated: + /* Compute and apply initial DVFS parameters */ + gm20b_dvfs_calc_det_coeff(clk, clk->uv, &clk->dvfs); + gm20b_dvfs_program_coeff(clk, 0); + gm20b_dvfs_program_ext_cal(clk, clk->dvfs.dfs_ext_cal); + gm20b_dvfs_program_coeff(clk, clk->dvfs.dfs_coeff); + gm20b_dvfs_program_dfs_detection(clk, &clk->new_dvfs); + + return 0; +} + +/* Forward declaration to detect speedo >=1 in gm20b_clk_init() */ +static const struct nvkm_clk_func gm20b_clk; + static int gm20b_clk_init(struct nvkm_clk *base) { @@ -143,19 +814,56 @@ gm20b_clk_init(struct nvkm_clk *base) struct nvkm_subdev *subdev = &clk->base.subdev; struct nvkm_device *device = subdev->device; int ret; + u32 data; - ret = gk20a_clk_setup_slide(clk); - if (ret) - return ret; + /* get out from IDDQ */ + nvkm_mask(device, GPCPLL_CFG, GPCPLL_CFG_IDDQ, 0); + nvkm_rd32(device, GPCPLL_CFG); + udelay(5); + + nvkm_mask(device, GPC2CLK_OUT, GPC2CLK_OUT_INIT_MASK, + GPC2CLK_OUT_INIT_VAL); /* Set the global bypass control to VCO */ nvkm_mask(device, BYPASSCTRL_SYS, MASK(BYPASSCTRL_SYS_GPCPLL_WIDTH) << BYPASSCTRL_SYS_GPCPLL_SHIFT, 0); + ret = gk20a_clk_setup_slide(clk); + if (ret) + return ret; + + /* If not fused, set RAM SVOP PDP data 0x2, and enable fuse override */ + data = nvkm_rd32(device, 0x021944); + if (!(data & 0x3)) { + data |= 0x2; + nvkm_wr32(device, 0x021944, data); + + data = nvkm_rd32(device, 0x021948); + data |= 0x1; + nvkm_wr32(device, 0x021948, data); + } + + /* Disable idle slow down */ + nvkm_mask(device, 0x20160, 0x003f0000, 0x0); + + /* speedo >= 1? */ + if (clk->base.func == &gm20b_clk) { + struct gm20b_clk *_clk = gm20b_clk(base); + struct nvkm_volt *volt = device->volt; + + /* Get current voltage */ + _clk->uv = nvkm_volt_get(volt); + + /* Initialize DVFS */ + ret = gm20b_clk_init_dvfs(_clk); + if (ret) + return ret; + } + /* Start with lowest frequency */ base->func->calc(base, &base->func->pstates[0].base); - ret = base->func->prog(&clk->base); + ret = base->func->prog(base); if (ret) { nvkm_error(subdev, "cannot initialize clock\n"); return ret; @@ -173,6 +881,7 @@ gm20b_clk_speedo0 = { .prog = gk20a_clk_prog, .tidy = gk20a_clk_tidy, .pstates = gm20b_pstates, + /* Speedo 0 only supports 12 voltages */ .nr_pstates = ARRAY_SIZE(gm20b_pstates) - 1, .domains = { { nv_clk_src_crystal, 0xff }, @@ -181,8 +890,26 @@ gm20b_clk_speedo0 = { }, }; -int -gm20b_clk_new(struct nvkm_device *device, int index, struct nvkm_clk **pclk) +static const struct nvkm_clk_func +gm20b_clk = { + .init = gm20b_clk_init, + .fini = gm20b_clk_fini, + .read = gk20a_clk_read, + .calc = gm20b_clk_calc, + .prog = gm20b_clk_prog, + .tidy = gk20a_clk_tidy, + .pstates = gm20b_pstates, + .nr_pstates = ARRAY_SIZE(gm20b_pstates), + .domains = { + { nv_clk_src_crystal, 0xff }, + { nv_clk_src_gpc, 0xff, 0, "core", GK20A_CLK_GPC_MDIV }, + { nv_clk_src_max }, + }, +}; + +static int +gm20b_clk_new_speedo0(struct nvkm_device *device, int index, + struct nvkm_clk **pclk) { struct gk20a_clk *clk; int ret; @@ -200,3 +927,148 @@ gm20b_clk_new(struct nvkm_device *device, int index, struct nvkm_clk **pclk) return ret; } + +/* FUSE register */ +#define FUSE_RESERVED_CALIB0 0x204 +#define FUSE_RESERVED_CALIB0_INTERCEPT_FRAC_SHIFT 0 +#define FUSE_RESERVED_CALIB0_INTERCEPT_FRAC_WIDTH 4 +#define FUSE_RESERVED_CALIB0_INTERCEPT_INT_SHIFT 4 +#define FUSE_RESERVED_CALIB0_INTERCEPT_INT_WIDTH 10 +#define FUSE_RESERVED_CALIB0_SLOPE_FRAC_SHIFT 14 +#define FUSE_RESERVED_CALIB0_SLOPE_FRAC_WIDTH 10 +#define FUSE_RESERVED_CALIB0_SLOPE_INT_SHIFT 24 +#define FUSE_RESERVED_CALIB0_SLOPE_INT_WIDTH 6 +#define FUSE_RESERVED_CALIB0_FUSE_REV_SHIFT 30 +#define FUSE_RESERVED_CALIB0_FUSE_REV_WIDTH 2 + +static int +gm20b_clk_init_fused_params(struct gm20b_clk *clk) +{ + struct nvkm_subdev *subdev = &clk->base.base.subdev; + u32 val = 0; + u32 rev = 0; + +#if IS_ENABLED(CONFIG_ARCH_TEGRA) + tegra_fuse_readl(FUSE_RESERVED_CALIB0, &val); + rev = (val >> FUSE_RESERVED_CALIB0_FUSE_REV_SHIFT) & + MASK(FUSE_RESERVED_CALIB0_FUSE_REV_WIDTH); +#endif + + /* No fused parameters, we will calibrate later */ + if (rev == 0) + return -EINVAL; + + /* Integer part in mV + fractional part in uV */ + clk->uvdet_slope = ((val >> FUSE_RESERVED_CALIB0_SLOPE_INT_SHIFT) & + MASK(FUSE_RESERVED_CALIB0_SLOPE_INT_WIDTH)) * 1000 + + ((val >> FUSE_RESERVED_CALIB0_SLOPE_FRAC_SHIFT) & + MASK(FUSE_RESERVED_CALIB0_SLOPE_FRAC_WIDTH)); + + /* Integer part in mV + fractional part in 100uV */ + clk->uvdet_offs = ((val >> FUSE_RESERVED_CALIB0_INTERCEPT_INT_SHIFT) & + MASK(FUSE_RESERVED_CALIB0_INTERCEPT_INT_WIDTH)) * 1000 + + ((val >> FUSE_RESERVED_CALIB0_INTERCEPT_FRAC_SHIFT) & + MASK(FUSE_RESERVED_CALIB0_INTERCEPT_FRAC_WIDTH)) * 100; + + nvkm_debug(subdev, "fused calibration data: slope %d, offs %d\n", + clk->uvdet_slope, clk->uvdet_offs); + return 0; +} + +static int +gm20b_clk_init_safe_fmax(struct gm20b_clk *clk) +{ + struct nvkm_subdev *subdev = &clk->base.base.subdev; + struct nvkm_volt *volt = subdev->device->volt; + struct nvkm_pstate *pstates = clk->base.base.func->pstates; + int nr_pstates = clk->base.base.func->nr_pstates; + int vmin, id = 0; + u32 fmax = 0; + int i; + + /* find lowest voltage we can use */ + vmin = volt->vid[0].uv; + for (i = 1; i < volt->vid_nr; i++) { + if (volt->vid[i].uv <= vmin) { + vmin = volt->vid[i].uv; + id = volt->vid[i].vid; + } + } + + /* find max frequency at this voltage */ + for (i = 0; i < nr_pstates; i++) + if (pstates[i].base.voltage == id) + fmax = max(fmax, + pstates[i].base.domain[nv_clk_src_gpc]); + + if (!fmax) { + nvkm_error(subdev, "failed to evaluate safe fmax\n"); + return -EINVAL; + } + + /* we are safe at 90% of the max frequency */ + clk->safe_fmax_vmin = fmax * (100 - 10) / 100; + nvkm_debug(subdev, "safe fmax @ vmin = %u Khz\n", clk->safe_fmax_vmin); + + return 0; +} + +int +gm20b_clk_new(struct nvkm_device *device, int index, struct nvkm_clk **pclk) +{ + struct nvkm_device_tegra *tdev = device->func->tegra(device); + struct gm20b_clk *clk; + struct nvkm_subdev *subdev; + struct gk20a_clk_pllg_params *clk_params; + int ret; + + /* Speedo 0 GPUs cannot use noise-aware PLL */ + if (tdev->gpu_speedo_id == 0) + return gm20b_clk_new_speedo0(device, index, pclk); + + /* Speedo >= 1, use NAPLL */ + clk = kzalloc(sizeof(*clk) + sizeof(*clk_params), GFP_KERNEL); + if (!clk) + return -ENOMEM; + *pclk = &clk->base.base; + subdev = &clk->base.base.subdev; + + /* duplicate the clock parameters since we will patch them below */ + clk_params = (void *) (clk + 1); + *clk_params = gm20b_pllg_params; + ret = gk20a_clk_ctor(device, index, &gm20b_clk, clk_params, + &clk->base); + if (ret) + return ret; + + /* + * NAPLL can only work with max_u, clamp the m range so + * gk20a_pllg_calc_mnp always uses it + */ + clk_params->max_m = clk_params->min_m = DIV_ROUND_UP(clk_params->max_u, + (clk->base.parent_rate / KHZ)); + if (clk_params->max_m == 0) { + nvkm_warn(subdev, "cannot use NAPLL, using legacy clock...\n"); + kfree(clk); + return gm20b_clk_new_speedo0(device, index, pclk); + } + + clk->base.pl_to_div = pl_to_div; + clk->base.div_to_pl = div_to_pl; + + clk->dvfs_params = &gm20b_dvfs_params; + + ret = gm20b_clk_init_fused_params(clk); + /* + * we will calibrate during init - should never happen on + * prod parts + */ + if (ret) + nvkm_warn(subdev, "no fused calibration parameters\n"); + + ret = gm20b_clk_init_safe_fmax(clk); + if (ret) + return ret; + + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gm20b.c b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gm20b.c index d2d39ab74b8e..74db4d28930f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gm20b.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gm20b.c @@ -41,6 +41,23 @@ const struct cvb_coef gm20b_cvb_coef[] = { /* 921600 */ { 2647676, -106455, 1632 }, }; +static const struct cvb_coef gm20b_na_cvb_coef[] = { + /* KHz, c0, c1, c2, c3, c4, c5 */ + /* 76800 */ { 814294, 8144, -940, 808, -21583, 226 }, + /* 153600 */ { 856185, 8144, -940, 808, -21583, 226 }, + /* 230400 */ { 898077, 8144, -940, 808, -21583, 226 }, + /* 307200 */ { 939968, 8144, -940, 808, -21583, 226 }, + /* 384000 */ { 981860, 8144, -940, 808, -21583, 226 }, + /* 460800 */ { 1023751, 8144, -940, 808, -21583, 226 }, + /* 537600 */ { 1065642, 8144, -940, 808, -21583, 226 }, + /* 614400 */ { 1107534, 8144, -940, 808, -21583, 226 }, + /* 691200 */ { 1149425, 8144, -940, 808, -21583, 226 }, + /* 768000 */ { 1191317, 8144, -940, 808, -21583, 226 }, + /* 844800 */ { 1233208, 8144, -940, 808, -21583, 226 }, + /* 921600 */ { 1275100, 8144, -940, 808, -21583, 226 }, + /* 998400 */ { 1316991, 8144, -940, 808, -21583, 226 }, +}; + const u32 speedo_to_vmin[] = { /* 0, 1, 2, 3, 4, */ 950000, 840000, 818750, 840000, 810000, @@ -66,6 +83,10 @@ gm20b_volt_new(struct nvkm_device *device, int index, struct nvkm_volt **pvolt) vmin = speedo_to_vmin[tdev->gpu_speedo_id]; - return gk20a_volt_ctor(device, index, gm20b_cvb_coef, - ARRAY_SIZE(gm20b_cvb_coef), vmin, volt); + if (tdev->gpu_speedo_id >= 1) + return gk20a_volt_ctor(device, index, gm20b_na_cvb_coef, + ARRAY_SIZE(gm20b_na_cvb_coef), vmin, volt); + else + return gk20a_volt_ctor(device, index, gm20b_cvb_coef, + ARRAY_SIZE(gm20b_cvb_coef), vmin, volt); } From 437bb44d382c9570307393bad8d4eb0bc6e21b62 Mon Sep 17 00:00:00 2001 From: Karol Herbst Date: Fri, 26 Feb 2016 07:49:08 +0100 Subject: [PATCH 28/97] drm/nouveau/volt: save the voltage range we are able to set We shouldn't set voltages below the min or above the max voltage the gpu is able to set, so save the range for future lookups. Signed-off-by: Karol Herbst Reviewed-by: Martin Peres Tested-by: Pierre Moreau Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h | 3 +++ drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c | 14 +++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h index feff55cff05b..b765f4ffcde6 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h @@ -12,6 +12,9 @@ struct nvkm_volt { u32 uv; u8 vid; } vid[256]; + + u32 max_uv; + u32 min_uv; }; int nvkm_volt_get(struct nvkm_volt *); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c index 6b2d7531a7ff..1c3d23b0e84a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c @@ -120,6 +120,8 @@ nvkm_volt_parse_bios(struct nvkm_bios *bios, struct nvkm_volt *volt) data = nvbios_volt_parse(bios, &ver, &hdr, &cnt, &len, &info); if (data && info.vidmask && info.base && info.step) { + volt->min_uv = info.min; + volt->max_uv = info.max; for (i = 0; i < info.vidmask + 1; i++) { if (info.base >= info.min && info.base <= info.max) { @@ -131,6 +133,8 @@ nvkm_volt_parse_bios(struct nvkm_bios *bios, struct nvkm_volt *volt) } volt->vid_mask = info.vidmask; } else if (data && info.vidmask) { + volt->min_uv = 0xffffffff; + volt->max_uv = 0; for (i = 0; i < cnt; i++) { data = nvbios_volt_entry_parse(bios, i, &ver, &hdr, &ivid); @@ -138,9 +142,14 @@ nvkm_volt_parse_bios(struct nvkm_bios *bios, struct nvkm_volt *volt) volt->vid[volt->vid_nr].uv = ivid.voltage; volt->vid[volt->vid_nr].vid = ivid.vid; volt->vid_nr++; + volt->min_uv = min(volt->min_uv, ivid.voltage); + volt->max_uv = max(volt->max_uv, ivid.voltage); } } volt->vid_mask = info.vidmask; + } else if (data && info.type == NVBIOS_VOLT_PWM) { + volt->min_uv = info.base; + volt->max_uv = info.base + info.pwm_range; } } @@ -181,8 +190,11 @@ nvkm_volt_ctor(const struct nvkm_volt_func *func, struct nvkm_device *device, volt->func = func; /* Assuming the non-bios device should build the voltage table later */ - if (bios) + if (bios) { nvkm_volt_parse_bios(bios, volt); + nvkm_debug(&volt->subdev, "min: %iuv max: %iuv\n", + volt->min_uv, volt->max_uv); + } if (volt->vid_nr) { for (i = 0; i < volt->vid_nr; i++) { From b66ad32d6dc00a8ec07950049aab8bb5612e9001 Mon Sep 17 00:00:00 2001 From: Karol Herbst Date: Sun, 17 Apr 2016 14:51:23 +0200 Subject: [PATCH 29/97] drm/nouveau/hwmon: add in_min and in_max it is a little help for hardware monitoring tools Signed-off-by: Karol Herbst Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_hwmon.c | 36 +++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nouveau_hwmon.c b/drivers/gpu/drm/nouveau/nouveau_hwmon.c index 1ff4166af26e..71f764bf4cc6 100644 --- a/drivers/gpu/drm/nouveau/nouveau_hwmon.c +++ b/drivers/gpu/drm/nouveau/nouveau_hwmon.c @@ -534,6 +534,40 @@ nouveau_hwmon_get_in0_input(struct device *d, static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, nouveau_hwmon_get_in0_input, NULL, 0); +static ssize_t +nouveau_hwmon_get_in0_min(struct device *d, + struct device_attribute *a, char *buf) +{ + struct drm_device *dev = dev_get_drvdata(d); + struct nouveau_drm *drm = nouveau_drm(dev); + struct nvkm_volt *volt = nvxx_volt(&drm->device); + + if (!volt || !volt->min_uv) + return -ENODEV; + + return sprintf(buf, "%i\n", volt->min_uv / 1000); +} + +static SENSOR_DEVICE_ATTR(in0_min, S_IRUGO, + nouveau_hwmon_get_in0_min, NULL, 0); + +static ssize_t +nouveau_hwmon_get_in0_max(struct device *d, + struct device_attribute *a, char *buf) +{ + struct drm_device *dev = dev_get_drvdata(d); + struct nouveau_drm *drm = nouveau_drm(dev); + struct nvkm_volt *volt = nvxx_volt(&drm->device); + + if (!volt || !volt->max_uv) + return -ENODEV; + + return sprintf(buf, "%i\n", volt->max_uv / 1000); +} + +static SENSOR_DEVICE_ATTR(in0_max, S_IRUGO, + nouveau_hwmon_get_in0_max, NULL, 0); + static ssize_t nouveau_hwmon_get_in0_label(struct device *d, struct device_attribute *a, char *buf) @@ -594,6 +628,8 @@ static struct attribute *hwmon_pwm_fan_attributes[] = { static struct attribute *hwmon_in0_attributes[] = { &sensor_dev_attr_in0_input.dev_attr.attr, + &sensor_dev_attr_in0_min.dev_attr.attr, + &sensor_dev_attr_in0_max.dev_attr.attr, &sensor_dev_attr_in0_label.dev_attr.attr, NULL }; From e5da20a88eea80b9b847cddcf6bc2690fa0e3c42 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Wed, 8 Jun 2016 17:32:38 +0900 Subject: [PATCH 30/97] drm/nouveau/secboot: fix kerneldoc for secure boot structures Some members were documented in the wrong structure. Signed-off-by: Alexandre Courbot Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/secboot/priv.h | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/priv.h index f2b09dee7c5d..110ce64888b4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/priv.h @@ -147,10 +147,7 @@ struct hsflcn_acr_desc { * @inst: instance block for HS falcon * @pgd: page directory for the HS falcon * @vm: address space used by the HS falcon - * @bl_desc_size: size of the BL descriptor used by this chip. - * @fixup_bl_desc: hook that generates the proper BL descriptor format from - * the generic GM200 format into a data array of size - * bl_desc_size + * @falcon_state: current state of the managed falcons */ struct gm200_secboot { struct nvkm_secboot base; @@ -199,6 +196,14 @@ struct gm200_secboot { }; #define gm200_secboot(sb) container_of(sb, struct gm200_secboot, base) +/** + * Contains functions we wish to abstract between GM200-like implementations + * @bl_desc_size: size of the BL descriptor used by this chip. + * @fixup_bl_desc: hook that generates the proper BL descriptor format from + * the generic GM200 format into a data array of size + * bl_desc_size + * @fixup_hs_desc: hook that twiddles the HS descriptor before it is used + */ struct gm200_secboot_func { /* * Size of the bootloader descriptor for this chip. A block of this From 7fcab839015d67b35de0b7031ed074e3ebe708f8 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Wed, 8 Jun 2016 17:32:39 +0900 Subject: [PATCH 31/97] drm/nouveau/gr/gf100: handle secure boot errors Handle and propagate secure boot errors. Failure to do so results in Nouveau incorrectly believing init has succeeded and a completely black display during boot. If we propagate the error, GR init will fail and the user will at least have a working display. Signed-off-by: Alexandre Courbot Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c index 7d14d058b745..157919c788e6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c @@ -1457,6 +1457,7 @@ gf100_gr_init_ctxctl(struct gf100_gr *gr) struct nvkm_device *device = subdev->device; struct nvkm_secboot *sb = device->secboot; int i; + int ret = 0; if (gr->firmware) { /* load fuc microcode */ @@ -1464,15 +1465,20 @@ gf100_gr_init_ctxctl(struct gf100_gr *gr) /* securely-managed falcons must be reset using secure boot */ if (nvkm_secboot_is_managed(sb, NVKM_SECBOOT_FALCON_FECS)) - nvkm_secboot_reset(sb, NVKM_SECBOOT_FALCON_FECS); + ret = nvkm_secboot_reset(sb, NVKM_SECBOOT_FALCON_FECS); else gf100_gr_init_fw(gr, 0x409000, &gr->fuc409c, &gr->fuc409d); + if (ret) + return ret; + if (nvkm_secboot_is_managed(sb, NVKM_SECBOOT_FALCON_GPCCS)) - nvkm_secboot_reset(sb, NVKM_SECBOOT_FALCON_GPCCS); + ret = nvkm_secboot_reset(sb, NVKM_SECBOOT_FALCON_GPCCS); else gf100_gr_init_fw(gr, 0x41a000, &gr->fuc41ac, &gr->fuc41ad); + if (ret) + return ret; nvkm_mc_unk260(device, 1); From 4f3c15569e9e927ebbed6da4a2281f5d8a292a90 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Wed, 8 Jun 2016 17:32:40 +0900 Subject: [PATCH 32/97] drm/nouveau/secboot/gm200: make firmware loading re-callable Make it possible to call gm20x_secboot_prepare_blobs() several times after either success or failure without re-building already existing blobs. The function will now try to load firmware files that have previously failed before returning success. Signed-off-by: Alexandre Courbot Signed-off-by: Ben Skeggs --- .../drm/nouveau/nvkm/subdev/secboot/gm200.c | 42 ++++++++++++------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm200.c b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm200.c index cc100dc940ea..c6871127c70d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm200.c @@ -860,6 +860,8 @@ gm200_secboot_prepare_ls_blob(struct gm200_secboot *gsb) /* Write LS blob */ ret = ls_ucode_mgr_write_wpr(gsb, &mgr, gsb->ls_blob); + if (ret) + nvkm_gpuobj_del(&gsb->ls_blob); cleanup: ls_ucode_mgr_cleanup(&mgr); @@ -1023,21 +1025,27 @@ gm20x_secboot_prepare_blobs(struct gm200_secboot *gsb) int ret; /* Load and prepare the managed falcon's firmwares */ - ret = gm200_secboot_prepare_ls_blob(gsb); - if (ret) - return ret; + if (!gsb->ls_blob) { + ret = gm200_secboot_prepare_ls_blob(gsb); + if (ret) + return ret; + } /* Load the HS firmware that will load the LS firmwares */ - ret = gm200_secboot_prepare_hs_blob(gsb, "acr/ucode_load", - &gsb->acr_load_blob, - &gsb->acr_load_bl_desc, true); - if (ret) - return ret; + if (!gsb->acr_load_blob) { + ret = gm200_secboot_prepare_hs_blob(gsb, "acr/ucode_load", + &gsb->acr_load_blob, + &gsb->acr_load_bl_desc, true); + if (ret) + return ret; + } /* Load the HS firmware bootloader */ - ret = gm200_secboot_prepare_hsbl_blob(gsb); - if (ret) - return ret; + if (!gsb->hsbl_blob) { + ret = gm200_secboot_prepare_hsbl_blob(gsb); + if (ret) + return ret; + } return 0; } @@ -1053,11 +1061,13 @@ gm200_secboot_prepare_blobs(struct nvkm_secboot *sb) return ret; /* dGPU only: load the HS firmware that unprotects the WPR region */ - ret = gm200_secboot_prepare_hs_blob(gsb, "acr/ucode_unload", - &gsb->acr_unload_blob, - &gsb->acr_unload_bl_desc, false); - if (ret) - return ret; + if (!gsb->acr_unload_blob) { + ret = gm200_secboot_prepare_hs_blob(gsb, "acr/ucode_unload", + &gsb->acr_unload_blob, + &gsb->acr_unload_bl_desc, false); + if (ret) + return ret; + } return 0; } From 20560a9a3c022ecd960e4657f491d2105da64869 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Wed, 8 Jun 2016 17:32:41 +0900 Subject: [PATCH 33/97] drm/nouveau/secboot: lazy-load firmware and be more resilient Defer the loading of firmware files to the chip-specific part of secure boot. This allows implementations to retry loading firmware if the first attempt failed ; for the GM200 implementation, this happens when trying to reset a falcon, typically in reaction to GR init. Firmware loading may fail for a variety of reasons, such as the filesystem where they reside not being ready at init time. This new behavior allows GR to be initialized the next time we try to use it if the firmware has become available. Signed-off-by: Alexandre Courbot Signed-off-by: Ben Skeggs --- .../drm/nouveau/nvkm/subdev/secboot/base.c | 9 +--- .../drm/nouveau/nvkm/subdev/secboot/gm200.c | 30 +++++++++-- .../drm/nouveau/nvkm/subdev/secboot/gm20b.c | 54 +++++++++---------- .../drm/nouveau/nvkm/subdev/secboot/priv.h | 5 +- 4 files changed, 59 insertions(+), 39 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/base.c index 57c6a58d1141..314be2192b7d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/base.c @@ -214,14 +214,7 @@ nvkm_secboot_oneinit(struct nvkm_subdev *subdev) return ret; } - /* - * Build all blobs - the same blobs can be used to perform secure boot - * multiple times - */ - if (sb->func->prepare_blobs) - ret = sb->func->prepare_blobs(sb); - - return ret; + return 0; } static int diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm200.c b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm200.c index c6871127c70d..d26af8967118 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm200.c @@ -1051,9 +1051,8 @@ gm20x_secboot_prepare_blobs(struct gm200_secboot *gsb) } static int -gm200_secboot_prepare_blobs(struct nvkm_secboot *sb) +gm200_secboot_prepare_blobs(struct gm200_secboot *gsb) { - struct gm200_secboot *gsb = gm200_secboot(sb); int ret; ret = gm20x_secboot_prepare_blobs(gsb); @@ -1072,6 +1071,26 @@ gm200_secboot_prepare_blobs(struct nvkm_secboot *sb) return 0; } +static int +gm200_secboot_blobs_ready(struct gm200_secboot *gsb) +{ + struct nvkm_subdev *subdev = &gsb->base.subdev; + int ret; + + /* firmware already loaded, nothing to do... */ + if (gsb->firmware_ok) + return 0; + + ret = gsb->func->prepare_blobs(gsb); + if (ret) { + nvkm_error(subdev, "failed to load secure firmware\n"); + return ret; + } + + gsb->firmware_ok = true; + + return 0; +} /* @@ -1244,6 +1263,11 @@ gm200_secboot_reset(struct nvkm_secboot *sb, enum nvkm_secboot_falcon falcon) struct gm200_secboot *gsb = gm200_secboot(sb); int ret; + /* Make sure all blobs are ready */ + ret = gm200_secboot_blobs_ready(gsb); + if (ret) + return ret; + /* * Dummy GM200 implementation: perform secure boot each time we are * called on FECS. Since only FECS and GPCCS are managed and started @@ -1383,7 +1407,6 @@ gm200_secboot = { .dtor = gm200_secboot_dtor, .init = gm200_secboot_init, .fini = gm200_secboot_fini, - .prepare_blobs = gm200_secboot_prepare_blobs, .reset = gm200_secboot_reset, .start = gm200_secboot_start, .managed_falcons = BIT(NVKM_SECBOOT_FALCON_FECS) | @@ -1425,6 +1448,7 @@ gm200_secboot_func = { .bl_desc_size = sizeof(struct gm200_flcn_bl_desc), .fixup_bl_desc = gm200_secboot_fixup_bl_desc, .fixup_hs_desc = gm200_secboot_fixup_hs_desc, + .prepare_blobs = gm200_secboot_prepare_blobs, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm20b.c b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm20b.c index 684320484b70..d5395ebfe8d3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm20b.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm20b.c @@ -42,6 +42,32 @@ struct gm20b_flcn_bl_desc { u32 data_size; }; +static int +gm20b_secboot_prepare_blobs(struct gm200_secboot *gsb) +{ + struct nvkm_subdev *subdev = &gsb->base.subdev; + int acr_size; + int ret; + + ret = gm20x_secboot_prepare_blobs(gsb); + if (ret) + return ret; + + acr_size = gsb->acr_load_blob->size; + /* + * On Tegra the WPR region is set by the bootloader. It is illegal for + * the HS blob to be larger than this region. + */ + if (acr_size > gsb->wpr_size) { + nvkm_error(subdev, "WPR region too small for FW blob!\n"); + nvkm_error(subdev, "required: %dB\n", acr_size); + nvkm_error(subdev, "WPR size: %dB\n", gsb->wpr_size); + return -ENOSPC; + } + + return 0; +} + /** * gm20b_secboot_fixup_bl_desc - adapt BL descriptor to format used by GM20B FW * @@ -88,6 +114,7 @@ gm20b_secboot_func = { .bl_desc_size = sizeof(struct gm20b_flcn_bl_desc), .fixup_bl_desc = gm20b_secboot_fixup_bl_desc, .fixup_hs_desc = gm20b_secboot_fixup_hs_desc, + .prepare_blobs = gm20b_secboot_prepare_blobs, }; @@ -146,32 +173,6 @@ gm20b_tegra_read_wpr(struct gm200_secboot *gsb) } #endif -static int -gm20b_secboot_prepare_blobs(struct nvkm_secboot *sb) -{ - struct gm200_secboot *gsb = gm200_secboot(sb); - int acr_size; - int ret; - - ret = gm20x_secboot_prepare_blobs(gsb); - if (ret) - return ret; - - acr_size = gsb->acr_load_blob->size; - /* - * On Tegra the WPR region is set by the bootloader. It is illegal for - * the HS blob to be larger than this region. - */ - if (acr_size > gsb->wpr_size) { - nvkm_error(&sb->subdev, "WPR region too small for FW blob!\n"); - nvkm_error(&sb->subdev, "required: %dB\n", acr_size); - nvkm_error(&sb->subdev, "WPR size: %dB\n", gsb->wpr_size); - return -ENOSPC; - } - - return 0; -} - static int gm20b_secboot_init(struct nvkm_secboot *sb) { @@ -189,7 +190,6 @@ static const struct nvkm_secboot_func gm20b_secboot = { .dtor = gm200_secboot_dtor, .init = gm20b_secboot_init, - .prepare_blobs = gm20b_secboot_prepare_blobs, .reset = gm200_secboot_reset, .start = gm200_secboot_start, .managed_falcons = BIT(NVKM_SECBOOT_FALCON_FECS), diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/priv.h index 110ce64888b4..a9a8a0e1017e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/priv.h @@ -30,7 +30,6 @@ struct nvkm_secboot_func { int (*init)(struct nvkm_secboot *); int (*fini)(struct nvkm_secboot *, bool suspend); void *(*dtor)(struct nvkm_secboot *); - int (*prepare_blobs)(struct nvkm_secboot *); int (*reset)(struct nvkm_secboot *, enum nvkm_secboot_falcon); int (*start)(struct nvkm_secboot *, enum nvkm_secboot_falcon); @@ -148,6 +147,7 @@ struct hsflcn_acr_desc { * @pgd: page directory for the HS falcon * @vm: address space used by the HS falcon * @falcon_state: current state of the managed falcons + * @firmware_ok: whether the firmware blobs have been created */ struct gm200_secboot { struct nvkm_secboot base; @@ -193,6 +193,7 @@ struct gm200_secboot { RUNNING, } falcon_state[NVKM_SECBOOT_FALCON_END]; + bool firmware_ok; }; #define gm200_secboot(sb) container_of(sb, struct gm200_secboot, base) @@ -203,6 +204,7 @@ struct gm200_secboot { * the generic GM200 format into a data array of size * bl_desc_size * @fixup_hs_desc: hook that twiddles the HS descriptor before it is used + * @prepare_blobs: prepares the various blobs needed for secure booting */ struct gm200_secboot_func { /* @@ -219,6 +221,7 @@ struct gm200_secboot_func { * we want the HS FW to set up. */ void (*fixup_hs_desc)(struct gm200_secboot *, struct hsflcn_acr_desc *); + int (*prepare_blobs)(struct gm200_secboot *); }; int gm200_secboot_init(struct nvkm_secboot *); From 0f7fbb990cef8ac58a6e3f66046fbbe5a7ac174e Mon Sep 17 00:00:00 2001 From: Roy Spliet Date: Fri, 17 Jun 2016 22:16:13 +0100 Subject: [PATCH 34/97] drm/nouveau/clk/gf100-: Clean up PLL locking test Corresponds with GT215. Don't rely on the lock test logic being unconditionally enabled, and disable test logic when done (presumably to save power). v2: Remove warning, nvkm_msec already warns on time-out Signed-off-by: Roy Spliet Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c | 8 +++++++- drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c index 78c449b417b7..026baffa3065 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c @@ -366,11 +366,17 @@ gf100_clk_prog_2(struct gf100_clk *clk, int idx) if (info->coef) { nvkm_wr32(device, addr + 0x04, info->coef); nvkm_mask(device, addr + 0x00, 0x00000001, 0x00000001); + + /* Test PLL lock */ + nvkm_mask(device, addr + 0x00, 0x00000010, 0x00000000); nvkm_msec(device, 2000, if (nvkm_rd32(device, addr + 0x00) & 0x00020000) break; ); - nvkm_mask(device, addr + 0x00, 0x00020004, 0x00000004); + nvkm_mask(device, addr + 0x00, 0x00000010, 0x00000010); + + /* Enable sync mode */ + nvkm_mask(device, addr + 0x00, 0x00000004, 0x00000004); } } } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c index 975c401bccab..06bc0d2d6ae1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c @@ -393,11 +393,17 @@ gk104_clk_prog_2(struct gk104_clk *clk, int idx) if (info->coef) { nvkm_wr32(device, addr + 0x04, info->coef); nvkm_mask(device, addr + 0x00, 0x00000001, 0x00000001); + + /* Test PLL lock */ + nvkm_mask(device, addr + 0x00, 0x00000010, 0x00000000); nvkm_msec(device, 2000, if (nvkm_rd32(device, addr + 0x00) & 0x00020000) break; ); - nvkm_mask(device, addr + 0x00, 0x00020004, 0x00000004); + nvkm_mask(device, addr + 0x00, 0x00000010, 0x00000010); + + /* Enable sync mode */ + nvkm_mask(device, addr + 0x00, 0x00000004, 0x00000004); } } From f8fa2e4b37ccd395c2c498baf8917ab4527b719f Mon Sep 17 00:00:00 2001 From: Roy Spliet Date: Fri, 17 Jun 2016 22:16:14 +0100 Subject: [PATCH 35/97] drm/nouveau/clk/gf100: Read secondary bypass postdiv when required v2: fix typo it's -> its Signed-off-by: Roy Spliet Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/subdev/clk/gf100.c | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c index 026baffa3065..89d5543118cf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c @@ -99,7 +99,7 @@ read_div(struct gf100_clk *clk, int doff, u32 dsrc, u32 dctl) { struct nvkm_device *device = clk->base.subdev.device; u32 ssrc = nvkm_rd32(device, dsrc + (doff * 4)); - u32 sctl = nvkm_rd32(device, dctl + (doff * 4)); + u32 sclk, sctl, sdiv = 2; switch (ssrc & 0x00000003) { case 0: @@ -109,13 +109,21 @@ read_div(struct gf100_clk *clk, int doff, u32 dsrc, u32 dctl) case 2: return 100000; case 3: - if (sctl & 0x80000000) { - u32 sclk = read_vco(clk, dsrc + (doff * 4)); - u32 sdiv = (sctl & 0x0000003f) + 2; - return (sclk * 2) / sdiv; + sclk = read_vco(clk, dsrc + (doff * 4)); + + /* Memclk has doff of 0 despite its alt. location */ + if (doff <= 2) { + sctl = nvkm_rd32(device, dctl + (doff * 4)); + + if (sctl & 0x80000000) { + if (ssrc & 0x100) + sctl >>= 8; + + sdiv = (sctl & 0x3f) + 2; + } } - return read_vco(clk, dsrc + (doff * 4)); + return (sclk * 2) / sdiv; default: return 0; } From b1687b3e3ba1ff8838bf3214923d00459bcaa4a2 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 19 Jun 2016 08:44:23 +0200 Subject: [PATCH 36/97] drm/nouveau/gr/gk20a: delete unneeded second newline Signed-off-by: Julia Lawall Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c index 4ca8ed15191c..de8b806b88fd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c @@ -361,6 +361,5 @@ gk20a_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) if (ret) return ret; - return 0; } From 86b40432bd1986ad0e3b5822c4ef54c0dc1dacbc Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 21 Jun 2016 12:41:36 +1000 Subject: [PATCH 37/97] drm/nouveau/ltc/gm107-: decode interrupt status to human-readable strings Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c | 3 +-- drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c | 10 +++++++--- drivers/gpu/drm/nouveau/nvkm/subdev/ltc/priv.h | 2 ++ 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c index c9eb677967a8..4a0fa0a9b802 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c @@ -23,7 +23,6 @@ */ #include "priv.h" -#include #include #include @@ -71,7 +70,7 @@ gf100_ltc_zbc_clear_depth(struct nvkm_ltc *ltc, int i, const u32 depth) nvkm_wr32(device, 0x17ea58, depth); } -static const struct nvkm_bitfield +const struct nvkm_bitfield gf100_ltc_lts_intr_name[] = { { 0x00000001, "IDLE_ERROR_IQ" }, { 0x00000002, "IDLE_ERROR_CBC" }, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c index 389fb13a1998..d65708c6a85f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c @@ -74,12 +74,16 @@ gm107_ltc_intr_lts(struct nvkm_ltc *ltc, int c, int s) struct nvkm_subdev *subdev = <c->subdev; struct nvkm_device *device = subdev->device; u32 base = 0x140400 + (c * 0x2000) + (s * 0x200); - u32 stat = nvkm_rd32(device, base + 0x00c); + u32 intr = nvkm_rd32(device, base + 0x00c); + u16 stat = intr & 0x0000ffff; + char msg[128]; if (stat) { - nvkm_error(subdev, "LTC%d_LTS%d: %08x\n", c, s, stat); - nvkm_wr32(device, base + 0x00c, stat); + nvkm_snprintbf(msg, sizeof(msg), gf100_ltc_lts_intr_name, stat); + nvkm_error(subdev, "LTC%d_LTS%d: %08x [%s]\n", c, s, intr, msg); } + + nvkm_wr32(device, base + 0x00c, intr); } void diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/priv.h index 6d81c695ed0d..0da5766a9d3d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/priv.h @@ -2,6 +2,7 @@ #define __NVKM_LTC_PRIV_H__ #define nvkm_ltc(p) container_of((p), struct nvkm_ltc, subdev) #include +#include int nvkm_ltc_new_(const struct nvkm_ltc_func *, struct nvkm_device *, int index, struct nvkm_ltc **); @@ -31,6 +32,7 @@ void gf100_ltc_zbc_clear_color(struct nvkm_ltc *, int, const u32[4]); void gf100_ltc_zbc_clear_depth(struct nvkm_ltc *, int, const u32); void gf100_ltc_invalidate(struct nvkm_ltc *); void gf100_ltc_flush(struct nvkm_ltc *); +extern const struct nvkm_bitfield gf100_ltc_lts_intr_name[]; void gm107_ltc_intr(struct nvkm_ltc *); void gm107_ltc_cbc_clear(struct nvkm_ltc *, u32, u32); From 9a2b8131c38e9e9fea6a803efe855a542c0f32d1 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 21 Jun 2016 16:29:03 +1000 Subject: [PATCH 38/97] drm/nouveau/disp/nv50-: fix lookup of udisp table under certain circumstances Some VBIOS have separate tables for each link of a given output path, which means we have to specify the specific link we're using instead of all possible links. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c | 4 +--- drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c | 3 +-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c index 5dd34382f55a..605e4ea669a4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c @@ -76,12 +76,10 @@ exec_lookup(struct nv50_disp *disp, int head, int or, u32 ctrl, mask |= 0x0001 << or; mask |= 0x0100 << head; - list_for_each_entry(outp, &disp->base.outp, head) { if ((outp->info.hasht & 0xff) == type && (outp->info.hashm & mask) == mask) { - *data = nvbios_outp_match(bios, outp->info.hasht, - outp->info.hashm, + *data = nvbios_outp_match(bios, outp->info.hasht, mask, ver, hdr, cnt, len, info); if (!*data) return NULL; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index fcb1b0c46d64..0ea9d9df674b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -269,8 +269,7 @@ exec_lookup(struct nv50_disp *disp, int head, int or, u32 ctrl, list_for_each_entry(outp, &disp->base.outp, head) { if ((outp->info.hasht & 0xff) == type && (outp->info.hashm & mask) == mask) { - *data = nvbios_outp_match(bios, outp->info.hasht, - outp->info.hashm, + *data = nvbios_outp_match(bios, outp->info.hasht, mask, ver, hdr, cnt, len, info); if (!*data) return NULL; From 1fe8c02fbcc0a3310a7790a3b694cb5105a7302f Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 22 Jun 2016 10:17:11 +1000 Subject: [PATCH 39/97] drm/nouveau/fifo/gk104-: translate engidx into human-readable name in debug output Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c index f574b744cf66..103c0afaaa6d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c @@ -616,8 +616,8 @@ gk104_fifo_oneinit(struct nvkm_fifo *base) } } - nvkm_debug(subdev, "engine %2d: runlist %2d pbdma %2d\n", - engn, runl, pbid); + nvkm_debug(subdev, "engine %2d: runlist %2d pbdma %2d (%s)\n", + engn, runl, pbid, nvkm_subdev_name[engidx]); fifo->engine[engn].engine = nvkm_device_engine(device, engidx); fifo->engine[engn].runl = runl; From 4d4e9907ff572bb1d1c0f6913ad6e3d6d4525077 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 22 Jun 2016 12:10:00 +1000 Subject: [PATCH 40/97] drm/nouveau/bios: guard against out-of-bounds accesses to image Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/subdev/bios.h | 7 ++-- .../gpu/drm/nouveau/nvkm/subdev/bios/base.c | 34 +++++++++++++++++++ 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios.h index e39a1fea930b..6137de829b8f 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios.h @@ -22,10 +22,9 @@ struct nvkm_bios { u8 nvbios_checksum(const u8 *data, int size); u16 nvbios_findstr(const u8 *data, int size, const char *str, int len); int nvbios_memcmp(struct nvkm_bios *, u32 addr, const char *, u32 len); - -#define nvbios_rd08(b,o) (b)->data[(o)] -#define nvbios_rd16(b,o) get_unaligned_le16(&(b)->data[(o)]) -#define nvbios_rd32(b,o) get_unaligned_le32(&(b)->data[(o)]) +u8 nvbios_rd08(struct nvkm_bios *, u32 addr); +u16 nvbios_rd16(struct nvkm_bios *, u32 addr); +u32 nvbios_rd32(struct nvkm_bios *, u32 addr); int nvkm_bios_new(struct nvkm_device *, int, struct nvkm_bios **); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c index e15b9627b07e..db5fa009a619 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c @@ -27,6 +27,40 @@ #include #include +static bool +nvbios_addr(struct nvkm_bios *bios, u32 *addr, u8 size) +{ + if (unlikely(*addr + size >= bios->size)) { + nvkm_error(&bios->subdev, "OOB %d %08x\n", size, *addr); + return false; + } + return true; +} + +u8 +nvbios_rd08(struct nvkm_bios *bios, u32 addr) +{ + if (likely(nvbios_addr(bios, &addr, 1))) + return bios->data[addr]; + return 0x00; +} + +u16 +nvbios_rd16(struct nvkm_bios *bios, u32 addr) +{ + if (likely(nvbios_addr(bios, &addr, 2))) + return get_unaligned_le16(&bios->data[addr]); + return 0x0000; +} + +u32 +nvbios_rd32(struct nvkm_bios *bios, u32 addr) +{ + if (likely(nvbios_addr(bios, &addr, 4))) + return get_unaligned_le32(&bios->data[addr]); + return 0x00000000; +} + u8 nvbios_checksum(const u8 *data, int size) { From 2f96e8e3e0226d74ca62544d3c9f3558e55b6bb2 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 22 Jun 2016 12:41:04 +1000 Subject: [PATCH 41/97] drm/nouveau/bios: pointers beyond end of first image need special handling Makes common the code that was previously used by the PMU table parsing, as it appears other tables need this too. Not much of an idea what this is all about... Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/subdev/bios.h | 3 +++ .../gpu/drm/nouveau/nvkm/subdev/bios/base.c | 27 +++++++++++++++++-- .../gpu/drm/nouveau/nvkm/subdev/bios/image.c | 7 ++++- .../gpu/drm/nouveau/nvkm/subdev/bios/pmu.c | 20 ++------------ 4 files changed, 36 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios.h index 6137de829b8f..a72f3290528a 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios.h @@ -7,6 +7,9 @@ struct nvkm_bios { u32 size; u8 *data; + u32 image0_size; + u32 imaged_addr; + u32 bmp_offset; u32 bit_offset; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c index db5fa009a619..f3c30b2a788e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c @@ -26,14 +26,23 @@ #include #include #include +#include static bool nvbios_addr(struct nvkm_bios *bios, u32 *addr, u8 size) { + u32 p = *addr; + + if (*addr > bios->image0_size && bios->imaged_addr) { + *addr -= bios->image0_size; + *addr += bios->imaged_addr; + } + if (unlikely(*addr + size >= bios->size)) { - nvkm_error(&bios->subdev, "OOB %d %08x\n", size, *addr); + nvkm_error(&bios->subdev, "OOB %d %08x %08x\n", size, p, *addr); return false; } + return true; } @@ -134,8 +143,9 @@ int nvkm_bios_new(struct nvkm_device *device, int index, struct nvkm_bios **pbios) { struct nvkm_bios *bios; + struct nvbios_image image; struct bit_entry bit_i; - int ret; + int ret, idx = 0; if (!(bios = *pbios = kzalloc(sizeof(*bios), GFP_KERNEL))) return -ENOMEM; @@ -145,6 +155,19 @@ nvkm_bios_new(struct nvkm_device *device, int index, struct nvkm_bios **pbios) if (ret) return ret; + /* Some tables have weird pointers that need adjustment before + * they're dereferenced. I'm not entirely sure why... + */ + if (nvbios_image(bios, idx++, &image)) { + bios->image0_size = image.size; + while (nvbios_image(bios, idx++, &image)) { + if (image.type == 0xe0) { + bios->imaged_addr = image.base; + break; + } + } + } + /* detect type of vbios we're dealing with */ bios->bmp_offset = nvbios_findstr(bios->data, bios->size, "\xff\x7f""NV\0", 5); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/image.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/image.c index 74b14cf09308..1dbff7aeafec 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/image.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/image.c @@ -68,11 +68,16 @@ nvbios_imagen(struct nvkm_bios *bios, struct nvbios_image *image) bool nvbios_image(struct nvkm_bios *bios, int idx, struct nvbios_image *image) { + u32 imaged_addr = bios->imaged_addr; memset(image, 0x00, sizeof(*image)); + bios->imaged_addr = 0; do { image->base += image->size; - if (image->last || !nvbios_imagen(bios, image)) + if (image->last || !nvbios_imagen(bios, image)) { + bios->imaged_addr = imaged_addr; return false; + } } while(idx--); + bios->imaged_addr = imaged_addr; return true; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pmu.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pmu.c index c268e5afe852..b4a308f3cf7b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pmu.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pmu.c @@ -26,21 +26,6 @@ #include #include -static u32 -weirdo_pointer(struct nvkm_bios *bios, u32 data) -{ - struct nvbios_image image; - int idx = 0; - if (nvbios_image(bios, idx++, &image)) { - data -= image.size; - while (nvbios_image(bios, idx++, &image)) { - if (image.type == 0xe0) - return image.base + data; - } - } - return 0; -} - u32 nvbios_pmuTe(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) { @@ -50,7 +35,7 @@ nvbios_pmuTe(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) if (!bit_entry(bios, 'p', &bit_p)) { if (bit_p.version == 2 && bit_p.length >= 4) data = nvbios_rd32(bios, bit_p.offset + 0x00); - if ((data = weirdo_pointer(bios, data))) { + if (data) { *ver = nvbios_rd08(bios, data + 0x00); /* maybe? */ *hdr = nvbios_rd08(bios, data + 0x01); *len = nvbios_rd08(bios, data + 0x02); @@ -97,8 +82,7 @@ nvbios_pmuRm(struct nvkm_bios *bios, u8 type, struct nvbios_pmuR *info) u32 data; memset(info, 0x00, sizeof(*info)); while ((data = nvbios_pmuEp(bios, idx++, &ver, &hdr, &pmuE))) { - if ( pmuE.type == type && - (data = weirdo_pointer(bios, pmuE.data))) { + if (pmuE.type == type && (data = pmuE.data)) { info->init_addr_pmu = nvbios_rd32(bios, data + 0x08); info->args_addr_pmu = nvbios_rd32(bios, data + 0x0c); info->boot_addr = data + 0x30; From 2a4bd8ac2ff775ee285dc0dc74d4d820d7439402 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 27 Jun 2016 16:49:24 +1000 Subject: [PATCH 42/97] drm/nouveau/disp/g94: implement workaround for dvi issue on fx380 Fixes the second DVI output on Quadro FX380. Thanks to NVIDIA for providing the details on the full workaround. Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/engine/disp/nv50.c | 133 ++++++++++++++++++ 1 file changed, 133 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index 0ea9d9df674b..fbb8c7dc18fd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -32,6 +32,7 @@ #include #include #include +#include static const struct nvkm_disp_oclass * nv50_disp_root_(struct nvkm_disp *base) @@ -425,6 +426,134 @@ exec_clkcmp(struct nv50_disp *disp, int head, int id, u32 pclk, u32 *conf) return outp; } +static bool +nv50_disp_dptmds_war(struct nvkm_device *device) +{ + switch (device->chipset) { + case 0x94: + case 0x96: + case 0x98: + case 0xaa: + case 0xac: + return true; + default: + break; + } + return false; +} + +static bool +nv50_disp_dptmds_war_needed(struct nv50_disp *disp, struct dcb_output *outp) +{ + struct nvkm_device *device = disp->base.engine.subdev.device; + const u32 soff = __ffs(outp->or) * 0x800; + if (nv50_disp_dptmds_war(device) && outp->type == DCB_OUTPUT_TMDS) { + switch (nvkm_rd32(device, 0x614300 + soff) & 0x00030000) { + case 0x00000000: + case 0x00030000: + return true; + default: + break; + } + } + return false; + +} + +static void +nv50_disp_dptmds_war_2(struct nv50_disp *disp, struct dcb_output *outp) +{ + struct nvkm_device *device = disp->base.engine.subdev.device; + const u32 soff = __ffs(outp->or) * 0x800; + + if (!nv50_disp_dptmds_war_needed(disp, outp)) + return; + + nvkm_mask(device, 0x00e840, 0x80000000, 0x80000000); + nvkm_mask(device, 0x614300 + soff, 0x03000000, 0x03000000); + nvkm_mask(device, 0x61c10c + soff, 0x00000001, 0x00000001); + + nvkm_mask(device, 0x61c00c + soff, 0x0f000000, 0x00000000); + nvkm_mask(device, 0x61c008 + soff, 0xff000000, 0x14000000); + nvkm_usec(device, 400, NVKM_DELAY); + nvkm_mask(device, 0x61c008 + soff, 0xff000000, 0x00000000); + nvkm_mask(device, 0x61c00c + soff, 0x0f000000, 0x01000000); + + if (nvkm_rd32(device, 0x61c004 + soff) & 0x00000001) { + u32 seqctl = nvkm_rd32(device, 0x61c030 + soff); + u32 pu_pc = seqctl & 0x0000000f; + nvkm_wr32(device, 0x61c040 + soff + pu_pc * 4, 0x1f008000); + } +} + +static void +nv50_disp_dptmds_war_3(struct nv50_disp *disp, struct dcb_output *outp) +{ + struct nvkm_device *device = disp->base.engine.subdev.device; + const u32 soff = __ffs(outp->or) * 0x800; + u32 sorpwr; + + if (!nv50_disp_dptmds_war_needed(disp, outp)) + return; + + sorpwr = nvkm_rd32(device, 0x61c004 + soff); + if (sorpwr & 0x00000001) { + u32 seqctl = nvkm_rd32(device, 0x61c030 + soff); + u32 pd_pc = (seqctl & 0x00000f00) >> 8; + u32 pu_pc = seqctl & 0x0000000f; + + nvkm_wr32(device, 0x61c040 + soff + pd_pc * 4, 0x1f008000); + + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x61c030 + soff) & 0x10000000)) + break; + ); + nvkm_mask(device, 0x61c004 + soff, 0x80000001, 0x80000000); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x61c030 + soff) & 0x10000000)) + break; + ); + + nvkm_wr32(device, 0x61c040 + soff + pd_pc * 4, 0x00002000); + nvkm_wr32(device, 0x61c040 + soff + pu_pc * 4, 0x1f000000); + } + + nvkm_mask(device, 0x61c10c + soff, 0x00000001, 0x00000000); + nvkm_mask(device, 0x614300 + soff, 0x03000000, 0x00000000); + + if (sorpwr & 0x00000001) { + nvkm_mask(device, 0x61c004 + soff, 0x80000001, 0x80000001); + } +} + +static void +nv50_disp_update_sppll1(struct nv50_disp *disp) +{ + struct nvkm_device *device = disp->base.engine.subdev.device; + bool used = false; + int sor; + + if (!nv50_disp_dptmds_war(device)) + return; + + for (sor = 0; sor < disp->func->sor.nr; sor++) { + u32 clksor = nvkm_rd32(device, 0x614300 + (sor * 0x800)); + switch (clksor & 0x03000000) { + case 0x02000000: + case 0x03000000: + used = true; + break; + default: + break; + } + } + + if (used) + return; + + nvkm_mask(device, 0x00e840, 0x80000000, 0x00000000); +} + static void nv50_disp_intr_unk10_0(struct nv50_disp *disp, int head) { @@ -678,6 +807,8 @@ nv50_disp_intr_unk20_2(struct nv50_disp *disp, int head) nvkm_mask(device, hreg, 0x0000000f, hval); nvkm_mask(device, oreg, mask, oval); + + nv50_disp_dptmds_war_2(disp, &outp->info); } /* If programming a TMDS output on a SOR that can also be configured for @@ -719,6 +850,7 @@ nv50_disp_intr_unk40_0(struct nv50_disp *disp, int head) if (outp->info.location == 0 && outp->info.type == DCB_OUTPUT_TMDS) nv50_disp_intr_unk40_0_tmds(disp, &outp->info); + nv50_disp_dptmds_war_3(disp, &outp->info); } void @@ -766,6 +898,7 @@ nv50_disp_intr_supervisor(struct work_struct *work) continue; nv50_disp_intr_unk40_0(disp, head); } + nv50_disp_update_sppll1(disp); } nvkm_wr32(device, 0x610030, 0x80000000); From 2100292c95cc1ff0d9dfebcb34d447f0acad5dd1 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 43/97] drm/nouveau: prevent oops if no mmu subdev present Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drm.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 295e7621cc68..6164ea086819 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -430,6 +430,11 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags) nouveau_vga_init(drm); if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) { + if (!nvxx_device(&drm->device)->mmu) { + ret = -ENOSYS; + goto fail_device; + } + ret = nvkm_vm_new(nvxx_device(&drm->device), 0, (1ULL << 40), 0x1000, NULL, &drm->client.vm); if (ret) From c73baa831fe5c035a41e52d75b763b3c942fa6d0 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 44/97] drm/nouveau/fb/gf100-: allow selection of an alternate big page size GFxxx/GM1xx support the selection of 64/128KiB big pages globally. GM2xx supports the same, as well as another mode where the page size can be selected per-instance. We default to 128KiB pages (With per-instance for GM200, but the current code selects 128KiB there already) as the MMU code isn't currently able to handle otherwise. Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/subdev/fb.h | 2 ++ drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c | 4 ++++ .../gpu/drm/nouveau/nvkm/subdev/fb/gf100.c | 19 +++++++++++++++++-- .../gpu/drm/nouveau/nvkm/subdev/fb/gk104.c | 1 + .../gpu/drm/nouveau/nvkm/subdev/fb/gk20a.c | 2 +- .../gpu/drm/nouveau/nvkm/subdev/fb/gm107.c | 1 + .../gpu/drm/nouveau/nvkm/subdev/fb/gm200.c | 19 +++++++++++++++++++ drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h | 2 ++ 8 files changed, 47 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h index 0a734fd06acf..c2c002d18f55 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h @@ -56,6 +56,8 @@ struct nvkm_fb { int regions; } tile; + u8 page; + struct nvkm_memory *mmu_rd; struct nvkm_memory *mmu_wr; }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c index ce90242b8cce..4742e5ee37ac 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c @@ -25,6 +25,7 @@ #include "ram.h" #include +#include #include #include #include @@ -134,6 +135,8 @@ nvkm_fb_init(struct nvkm_subdev *subdev) if (fb->func->init) fb->func->init(fb); + if (fb->func->init_page) + fb->func->init_page(fb); return 0; } @@ -171,6 +174,7 @@ nvkm_fb_ctor(const struct nvkm_fb_func *func, struct nvkm_device *device, nvkm_subdev_ctor(&nvkm_fb, device, index, &fb->subdev); fb->func = func; fb->tile.regions = fb->func->tile.regions; + fb->page = nvkm_longopt(device->cfgopt, "NvFbBigPage", 0); } int diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c index e649ead5ccfc..76433cc66fff 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c @@ -71,6 +71,22 @@ gf100_fb_oneinit(struct nvkm_fb *fb) return 0; } +void +gf100_fb_init_page(struct nvkm_fb *fb) +{ + struct nvkm_device *device = fb->subdev.device; + switch (fb->page) { + case 16: + nvkm_mask(device, 0x100c80, 0x00000001, 0x00000001); + break; + case 17: + default: + nvkm_mask(device, 0x100c80, 0x00000001, 0x00000000); + fb->page = 17; + break; + } +} + void gf100_fb_init(struct nvkm_fb *base) { @@ -79,8 +95,6 @@ gf100_fb_init(struct nvkm_fb *base) if (fb->r100c10_page) nvkm_wr32(device, 0x100c10, fb->r100c10 >> 8); - - nvkm_mask(device, 0x100c80, 0x00000001, 0x00000000); /* 128KiB lpg */ } void * @@ -125,6 +139,7 @@ gf100_fb = { .dtor = gf100_fb_dtor, .oneinit = gf100_fb_oneinit, .init = gf100_fb_init, + .init_page = gf100_fb_init_page, .intr = gf100_fb_intr, .ram_new = gf100_ram_new, .memtype_valid = gf100_fb_memtype_valid, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk104.c index b41f0f70038c..4245e2e6e604 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk104.c @@ -29,6 +29,7 @@ gk104_fb = { .dtor = gf100_fb_dtor, .oneinit = gf100_fb_oneinit, .init = gf100_fb_init, + .init_page = gf100_fb_init_page, .intr = gf100_fb_intr, .ram_new = gk104_ram_new, .memtype_valid = gf100_fb_memtype_valid, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk20a.c index 7306f7dfc3b9..f815fe2bbf08 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk20a.c @@ -27,7 +27,6 @@ static void gk20a_fb_init(struct nvkm_fb *fb) { struct nvkm_device *device = fb->subdev.device; - nvkm_mask(device, 0x100c80, 0x00000001, 0x00000000); /* 128KiB lpg */ nvkm_wr32(device, 0x100cc8, nvkm_memory_addr(fb->mmu_wr) >> 8); nvkm_wr32(device, 0x100ccc, nvkm_memory_addr(fb->mmu_rd) >> 8); } @@ -36,6 +35,7 @@ static const struct nvkm_fb_func gk20a_fb = { .oneinit = gf100_fb_oneinit, .init = gk20a_fb_init, + .init_page = gf100_fb_init_page, .memtype_valid = gf100_fb_memtype_valid, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm107.c index 4869fdb753c9..db699025f546 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm107.c @@ -29,6 +29,7 @@ gm107_fb = { .dtor = gf100_fb_dtor, .oneinit = gf100_fb_oneinit, .init = gf100_fb_init, + .init_page = gf100_fb_init_page, .intr = gf100_fb_intr, .ram_new = gm107_ram_new, .memtype_valid = gf100_fb_memtype_valid, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm200.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm200.c index 44f5716f64d8..6af3b724f07b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm200.c @@ -26,6 +26,24 @@ #include +static void +gm200_fb_init_page(struct nvkm_fb *fb) +{ + struct nvkm_device *device = fb->subdev.device; + switch (fb->page) { + case 16: + nvkm_mask(device, 0x100c80, 0x00000801, 0x00000001); + break; + case 17: + nvkm_mask(device, 0x100c80, 0x00000801, 0x00000000); + break; + default: + nvkm_mask(device, 0x100c80, 0x00000800, 0x00000800); + fb->page = 0; + break; + } +} + static void gm200_fb_init(struct nvkm_fb *base) { @@ -48,6 +66,7 @@ gm200_fb = { .dtor = gf100_fb_dtor, .oneinit = gf100_fb_oneinit, .init = gm200_fb_init, + .init_page = gm200_fb_init_page, .intr = gf100_fb_intr, .ram_new = gm107_ram_new, .memtype_valid = gf100_fb_memtype_valid, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h index d97d640e60a0..c93926c57310 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h @@ -8,6 +8,7 @@ struct nvkm_fb_func { void *(*dtor)(struct nvkm_fb *); int (*oneinit)(struct nvkm_fb *); void (*init)(struct nvkm_fb *); + void (*init_page)(struct nvkm_fb *); void (*intr)(struct nvkm_fb *); struct { @@ -60,5 +61,6 @@ void nv46_fb_tile_init(struct nvkm_fb *, int i, u32 addr, u32 size, u32 pitch, u32 flags, struct nvkm_fb_tile *); int gf100_fb_oneinit(struct nvkm_fb *); +void gf100_fb_init_page(struct nvkm_fb *); bool gf100_fb_memtype_valid(struct nvkm_fb *, u32); #endif From 34bf50cd20656f7c00a6d0192118ac5510e31708 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 45/97] drm/nouveau/core: increase maximum ce instances to 6 Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvkm/core/device.h | 9 ++++++--- drivers/gpu/drm/nouveau/nvkm/core/subdev.c | 3 +++ drivers/gpu/drm/nouveau/nvkm/engine/device/base.c | 6 ++++++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h index 126a85cc81bc..3f87c1b55bba 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h @@ -33,7 +33,10 @@ enum nvkm_devidx { NVKM_ENGINE_CE0, NVKM_ENGINE_CE1, NVKM_ENGINE_CE2, - NVKM_ENGINE_CE_LAST = NVKM_ENGINE_CE2, + NVKM_ENGINE_CE3, + NVKM_ENGINE_CE4, + NVKM_ENGINE_CE5, + NVKM_ENGINE_CE_LAST = NVKM_ENGINE_CE5, NVKM_ENGINE_CIPHER, NVKM_ENGINE_DISP, @@ -136,7 +139,7 @@ struct nvkm_device { struct nvkm_volt *volt; struct nvkm_engine *bsp; - struct nvkm_engine *ce[3]; + struct nvkm_engine *ce[6]; struct nvkm_engine *cipher; struct nvkm_disp *disp; struct nvkm_dma *dma; @@ -206,7 +209,7 @@ struct nvkm_device_chip { int (*volt )(struct nvkm_device *, int idx, struct nvkm_volt **); int (*bsp )(struct nvkm_device *, int idx, struct nvkm_engine **); - int (*ce[3] )(struct nvkm_device *, int idx, struct nvkm_engine **); + int (*ce[6] )(struct nvkm_device *, int idx, struct nvkm_engine **); int (*cipher )(struct nvkm_device *, int idx, struct nvkm_engine **); int (*disp )(struct nvkm_device *, int idx, struct nvkm_disp **); int (*dma )(struct nvkm_device *, int idx, struct nvkm_dma **); diff --git a/drivers/gpu/drm/nouveau/nvkm/core/subdev.c b/drivers/gpu/drm/nouveau/nvkm/core/subdev.c index f17fd7ddc7ca..bf825ad53c9e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/subdev.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/subdev.c @@ -57,6 +57,9 @@ nvkm_subdev_name[NVKM_SUBDEV_NR] = { [NVKM_ENGINE_CE0 ] = "ce0", [NVKM_ENGINE_CE1 ] = "ce1", [NVKM_ENGINE_CE2 ] = "ce2", + [NVKM_ENGINE_CE3 ] = "ce3", + [NVKM_ENGINE_CE4 ] = "ce4", + [NVKM_ENGINE_CE5 ] = "ce5", [NVKM_ENGINE_CIPHER ] = "cipher", [NVKM_ENGINE_DISP ] = "disp", [NVKM_ENGINE_DMAOBJ ] = "dma", diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 4572debcb0c9..e1bc7d1d9c5a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2221,6 +2221,9 @@ nvkm_device_engine(struct nvkm_device *device, int index) _(CE0 , device->ce[0] , device->ce[0]); _(CE1 , device->ce[1] , device->ce[1]); _(CE2 , device->ce[2] , device->ce[2]); + _(CE3 , device->ce[3] , device->ce[3]); + _(CE4 , device->ce[4] , device->ce[4]); + _(CE5 , device->ce[5] , device->ce[5]); _(CIPHER , device->cipher , device->cipher); _(DISP , device->disp , &device->disp->engine); _(DMAOBJ , device->dma , &device->dma->engine); @@ -2659,6 +2662,9 @@ nvkm_device_ctor(const struct nvkm_device_func *func, _(NVKM_ENGINE_CE0 , ce[0]); _(NVKM_ENGINE_CE1 , ce[1]); _(NVKM_ENGINE_CE2 , ce[2]); + _(NVKM_ENGINE_CE3 , ce[3]); + _(NVKM_ENGINE_CE4 , ce[4]); + _(NVKM_ENGINE_CE5 , ce[5]); _(NVKM_ENGINE_CIPHER , cipher); _(NVKM_ENGINE_DISP , disp); _(NVKM_ENGINE_DMAOBJ , dma); From cb7b5ea9beecee2cfe5d0b52dc981fbade83e5de Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 46/97] drm/nouveau/core: increase maximum nvenc instances to 3 Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvkm/core/device.h | 7 ++++--- drivers/gpu/drm/nouveau/nvkm/core/subdev.c | 1 + drivers/gpu/drm/nouveau/nvkm/engine/device/base.c | 2 ++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h index 3f87c1b55bba..fe3247dd9040 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h @@ -53,7 +53,8 @@ enum nvkm_devidx { NVKM_ENGINE_NVENC0, NVKM_ENGINE_NVENC1, - NVKM_ENGINE_NVENC_LAST = NVKM_ENGINE_NVENC1, + NVKM_ENGINE_NVENC2, + NVKM_ENGINE_NVENC_LAST = NVKM_ENGINE_NVENC2, NVKM_ENGINE_NVDEC, NVKM_ENGINE_PM, @@ -152,7 +153,7 @@ struct nvkm_device { struct nvkm_engine *mspdec; struct nvkm_engine *msppp; struct nvkm_engine *msvld; - struct nvkm_engine *nvenc[2]; + struct nvkm_engine *nvenc[3]; struct nvkm_engine *nvdec; struct nvkm_pm *pm; struct nvkm_engine *sec; @@ -222,7 +223,7 @@ struct nvkm_device_chip { int (*mspdec )(struct nvkm_device *, int idx, struct nvkm_engine **); int (*msppp )(struct nvkm_device *, int idx, struct nvkm_engine **); int (*msvld )(struct nvkm_device *, int idx, struct nvkm_engine **); - int (*nvenc[2])(struct nvkm_device *, int idx, struct nvkm_engine **); + int (*nvenc[3])(struct nvkm_device *, int idx, struct nvkm_engine **); int (*nvdec )(struct nvkm_device *, int idx, struct nvkm_engine **); int (*pm )(struct nvkm_device *, int idx, struct nvkm_pm **); int (*sec )(struct nvkm_device *, int idx, struct nvkm_engine **); diff --git a/drivers/gpu/drm/nouveau/nvkm/core/subdev.c b/drivers/gpu/drm/nouveau/nvkm/core/subdev.c index bf825ad53c9e..19044aba265e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/subdev.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/subdev.c @@ -74,6 +74,7 @@ nvkm_subdev_name[NVKM_SUBDEV_NR] = { [NVKM_ENGINE_MSVLD ] = "msvld", [NVKM_ENGINE_NVENC0 ] = "nvenc0", [NVKM_ENGINE_NVENC1 ] = "nvenc1", + [NVKM_ENGINE_NVENC2 ] = "nvenc2", [NVKM_ENGINE_NVDEC ] = "nvdec", [NVKM_ENGINE_PM ] = "pm", [NVKM_ENGINE_SEC ] = "sec", diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index e1bc7d1d9c5a..dcc623dc7b95 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2238,6 +2238,7 @@ nvkm_device_engine(struct nvkm_device *device, int index) _(MSVLD , device->msvld , device->msvld); _(NVENC0 , device->nvenc[0], device->nvenc[0]); _(NVENC1 , device->nvenc[1], device->nvenc[1]); + _(NVENC2 , device->nvenc[2], device->nvenc[2]); _(NVDEC , device->nvdec , device->nvdec); _(PM , device->pm , &device->pm->engine); _(SEC , device->sec , device->sec); @@ -2679,6 +2680,7 @@ nvkm_device_ctor(const struct nvkm_device_func *func, _(NVKM_ENGINE_MSVLD , msvld); _(NVKM_ENGINE_NVENC0 , nvenc[0]); _(NVKM_ENGINE_NVENC1 , nvenc[1]); + _(NVKM_ENGINE_NVENC2 , nvenc[2]); _(NVKM_ENGINE_NVDEC , nvdec); _(NVKM_ENGINE_PM , pm); _(NVKM_ENGINE_SEC , sec); From 7f53abdb95d14704d0282ee7b5de65476c29efb0 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 47/97] drm/nouveau/core: recognise GP100 chipset Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/cl0080.h | 1 + drivers/gpu/drm/nouveau/include/nvkm/core/device.h | 1 + drivers/gpu/drm/nouveau/nouveau_abi16.c | 1 + drivers/gpu/drm/nouveau/nouveau_ttm.c | 1 + drivers/gpu/drm/nouveau/nvkm/engine/device/base.c | 7 +++++++ drivers/gpu/drm/nouveau/nvkm/engine/device/user.c | 1 + 6 files changed, 12 insertions(+) diff --git a/drivers/gpu/drm/nouveau/include/nvif/cl0080.h b/drivers/gpu/drm/nouveau/include/nvif/cl0080.h index 331620a52afa..287a7d6fa480 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/cl0080.h +++ b/drivers/gpu/drm/nouveau/include/nvif/cl0080.h @@ -29,6 +29,7 @@ struct nv_device_info_v0 { #define NV_DEVICE_INFO_V0_FERMI 0x07 #define NV_DEVICE_INFO_V0_KEPLER 0x08 #define NV_DEVICE_INFO_V0_MAXWELL 0x09 +#define NV_DEVICE_INFO_V0_PASCAL 0x0a __u8 family; __u8 pad06[2]; __u64 ram_size; diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h index fe3247dd9040..6bc712f32c8b 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h @@ -106,6 +106,7 @@ struct nvkm_device { NV_C0 = 0xc0, NV_E0 = 0xe0, GM100 = 0x110, + GP100 = 0x130, } card_type; u32 chipset; u8 chiprev; diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c index eb7de487a2b3..7bd4683216d0 100644 --- a/drivers/gpu/drm/nouveau/nouveau_abi16.c +++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c @@ -100,6 +100,7 @@ nouveau_abi16_swclass(struct nouveau_drm *drm) case NV_DEVICE_INFO_V0_FERMI: case NV_DEVICE_INFO_V0_KEPLER: case NV_DEVICE_INFO_V0_MAXWELL: + case NV_DEVICE_INFO_V0_PASCAL: return NVIF_CLASS_SW_GF100; } diff --git a/drivers/gpu/drm/nouveau/nouveau_ttm.c b/drivers/gpu/drm/nouveau/nouveau_ttm.c index bcee91497eb9..1825dbc33192 100644 --- a/drivers/gpu/drm/nouveau/nouveau_ttm.c +++ b/drivers/gpu/drm/nouveau/nouveau_ttm.c @@ -164,6 +164,7 @@ nouveau_gart_manager_new(struct ttm_mem_type_manager *man, case NV_DEVICE_INFO_V0_FERMI: case NV_DEVICE_INFO_V0_KEPLER: case NV_DEVICE_INFO_V0_MAXWELL: + case NV_DEVICE_INFO_V0_PASCAL: node->memtype = (nvbo->tile_flags & 0xff00) >> 8; break; default: diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index dcc623dc7b95..817228a7e9b2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2148,6 +2148,11 @@ nv12b_chipset = { .sw = gf100_sw_new, }; +static const struct nvkm_device_chip +nv130_chipset = { + .name = "GP100", +}; + static int nvkm_device_event_ctor(struct nvkm_object *object, void *data, u32 size, struct nvkm_notify *notify) @@ -2496,6 +2501,7 @@ nvkm_device_ctor(const struct nvkm_device_func *func, case 0x100: device->card_type = NV_E0; break; case 0x110: case 0x120: device->card_type = GM100; break; + case 0x130: device->card_type = GP100; break; default: break; } @@ -2580,6 +2586,7 @@ nvkm_device_ctor(const struct nvkm_device_func *func, case 0x124: device->chip = &nv124_chipset; break; case 0x126: device->chip = &nv126_chipset; break; case 0x12b: device->chip = &nv12b_chipset; break; + case 0x130: device->chip = &nv130_chipset; break; default: nvdev_error(device, "unknown chipset (%08x)\n", boot0); goto done; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c index 137066426ed7..79a8f71cf788 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c @@ -102,6 +102,7 @@ nvkm_udevice_info(struct nvkm_udevice *udev, void *data, u32 size) case NV_C0: args->v0.family = NV_DEVICE_INFO_V0_FERMI; break; case NV_E0: args->v0.family = NV_DEVICE_INFO_V0_KEPLER; break; case GM100: args->v0.family = NV_DEVICE_INFO_V0_MAXWELL; break; + case GP100: args->v0.family = NV_DEVICE_INFO_V0_PASCAL; break; default: args->v0.family = 0; break; From 51012a39ecdb6bfc09ece812f626e9c922b71630 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 48/97] drm/nouveau/top/gp100: initial support Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/engine/device/base.c | 1 + .../gpu/drm/nouveau/nvkm/subdev/top/gk104.c | 39 +++++++++++-------- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 817228a7e9b2..f4fed7e50e17 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2151,6 +2151,7 @@ nv12b_chipset = { static const struct nvkm_device_chip nv130_chipset = { .name = "GP100", + .top = gk104_top_new, }; static int diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/top/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/top/gk104.c index e06acc340e99..efac3402f9dd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/top/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/top/gk104.c @@ -29,7 +29,7 @@ gk104_top_oneinit(struct nvkm_top *top) struct nvkm_subdev *subdev = &top->subdev; struct nvkm_device *device = subdev->device; struct nvkm_top_device *info = NULL; - u32 data, type; + u32 data, type, inst; int i; for (i = 0; i < 64; i++) { @@ -37,6 +37,7 @@ gk104_top_oneinit(struct nvkm_top *top) if (!(info = nvkm_top_device_new(top))) return -ENOMEM; type = ~0; + inst = 0; } data = nvkm_rd32(device, 0x022700 + (i * 0x04)); @@ -45,6 +46,7 @@ gk104_top_oneinit(struct nvkm_top *top) case 0x00000000: /* NOT_VALID */ continue; case 0x00000001: /* DATA */ + inst = (data & 0x3c000000) >> 26; info->addr = (data & 0x00fff000); info->fault = (data & 0x000000f8) >> 3; break; @@ -67,27 +69,32 @@ gk104_top_oneinit(struct nvkm_top *top) continue; /* Translate engine type to NVKM engine identifier. */ +#define A_(A) if (inst == 0) info->index = NVKM_ENGINE_##A +#define B_(A) if (inst + NVKM_ENGINE_##A##0 < NVKM_ENGINE_##A##_LAST + 1) \ + info->index = NVKM_ENGINE_##A##0 + inst switch (type) { - case 0x00000000: info->index = NVKM_ENGINE_GR; break; - case 0x00000001: info->index = NVKM_ENGINE_CE0; break; - case 0x00000002: info->index = NVKM_ENGINE_CE1; break; - case 0x00000003: info->index = NVKM_ENGINE_CE2; break; - case 0x00000008: info->index = NVKM_ENGINE_MSPDEC; break; - case 0x00000009: info->index = NVKM_ENGINE_MSPPP; break; - case 0x0000000a: info->index = NVKM_ENGINE_MSVLD; break; - case 0x0000000b: info->index = NVKM_ENGINE_MSENC; break; - case 0x0000000c: info->index = NVKM_ENGINE_VIC; break; - case 0x0000000d: info->index = NVKM_ENGINE_SEC; break; - case 0x0000000e: info->index = NVKM_ENGINE_NVENC0; break; - case 0x0000000f: info->index = NVKM_ENGINE_NVENC1; break; - case 0x00000010: info->index = NVKM_ENGINE_NVDEC; break; + case 0x00000000: A_(GR ); break; + case 0x00000001: A_(CE0 ); break; + case 0x00000002: A_(CE1 ); break; + case 0x00000003: A_(CE2 ); break; + case 0x00000008: A_(MSPDEC); break; + case 0x00000009: A_(MSPPP ); break; + case 0x0000000a: A_(MSVLD ); break; + case 0x0000000b: A_(MSENC ); break; + case 0x0000000c: A_(VIC ); break; + case 0x0000000d: A_(SEC ); break; + case 0x0000000e: B_(NVENC ); break; + case 0x0000000f: A_(NVENC1); break; + case 0x00000010: A_(NVDEC ); break; + case 0x00000013: B_(CE ); break; break; default: break; } - nvkm_debug(subdev, "%02x (%8s): addr %06x fault %2d engine %2d " - "runlist %2d intr %2d reset %2d\n", type, + nvkm_debug(subdev, "%02x.%d (%8s): addr %06x fault %2d " + "engine %2d runlist %2d intr %2d " + "reset %2d\n", type, inst, info->index == NVKM_SUBDEV_NR ? NULL : nvkm_subdev_name[info->index], info->addr, info->fault, info->engine, info->runlist, From be61c54cbeecff2982d6b074727f49a5c9f03d3d Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 49/97] drm/nouveau/mc/gp100: initial support Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/subdev/mc.h | 1 + .../gpu/drm/nouveau/nvkm/engine/device/base.c | 1 + drivers/gpu/drm/nouveau/nvkm/subdev/mc/Kbuild | 1 + .../gpu/drm/nouveau/nvkm/subdev/mc/gp100.c | 103 ++++++++++++++++++ 4 files changed, 106 insertions(+) create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/mc/gp100.c diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h index 81435d5a4adf..27d25b18d85c 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h @@ -27,4 +27,5 @@ int gt215_mc_new(struct nvkm_device *, int, struct nvkm_mc **); int gf100_mc_new(struct nvkm_device *, int, struct nvkm_mc **); int gk104_mc_new(struct nvkm_device *, int, struct nvkm_mc **); int gk20a_mc_new(struct nvkm_device *, int, struct nvkm_mc **); +int gp100_mc_new(struct nvkm_device *, int, struct nvkm_mc **); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index f4fed7e50e17..cfb98466eb78 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2151,6 +2151,7 @@ nv12b_chipset = { static const struct nvkm_device_chip nv130_chipset = { .name = "GP100", + .mc = gp100_mc_new, .top = gk104_top_new, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/Kbuild index 49695ac7be2e..12943f92c206 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/Kbuild @@ -10,3 +10,4 @@ nvkm-y += nvkm/subdev/mc/gt215.o nvkm-y += nvkm/subdev/mc/gf100.o nvkm-y += nvkm/subdev/mc/gk104.o nvkm-y += nvkm/subdev/mc/gk20a.o +nvkm-y += nvkm/subdev/mc/gp100.o diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gp100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gp100.c new file mode 100644 index 000000000000..4d22f4abd6de --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gp100.c @@ -0,0 +1,103 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#define gp100_mc(p) container_of((p), struct gp100_mc, base) +#include "priv.h" + +struct gp100_mc { + struct nvkm_mc base; + spinlock_t lock; + bool intr; + u32 mask; +}; + +static void +gp100_mc_intr_update(struct gp100_mc *mc) +{ + struct nvkm_device *device = mc->base.subdev.device; + u32 mask = mc->intr ? mc->mask : 0, i; + for (i = 0; i < 2; i++) { + nvkm_wr32(device, 0x000180 + (i * 0x04), ~mask); + nvkm_wr32(device, 0x000160 + (i * 0x04), mask); + } +} + +static void +gp100_mc_intr_unarm(struct nvkm_mc *base) +{ + struct gp100_mc *mc = gp100_mc(base); + unsigned long flags; + spin_lock_irqsave(&mc->lock, flags); + mc->intr = false; + gp100_mc_intr_update(mc); + spin_unlock_irqrestore(&mc->lock, flags); +} + +static void +gp100_mc_intr_rearm(struct nvkm_mc *base) +{ + struct gp100_mc *mc = gp100_mc(base); + unsigned long flags; + spin_lock_irqsave(&mc->lock, flags); + mc->intr = true; + gp100_mc_intr_update(mc); + spin_unlock_irqrestore(&mc->lock, flags); +} + +static void +gp100_mc_intr_mask(struct nvkm_mc *base, u32 mask, u32 intr) +{ + struct gp100_mc *mc = gp100_mc(base); + unsigned long flags; + spin_lock_irqsave(&mc->lock, flags); + mc->mask = (mc->mask & ~mask) | intr; + gp100_mc_intr_update(mc); + spin_unlock_irqrestore(&mc->lock, flags); +} + +static const struct nvkm_mc_func +gp100_mc = { + .init = nv50_mc_init, + .intr = gk104_mc_intr, + .intr_unarm = gp100_mc_intr_unarm, + .intr_rearm = gp100_mc_intr_rearm, + .intr_mask = gp100_mc_intr_mask, + .intr_stat = gf100_mc_intr_stat, + .reset = gk104_mc_reset, +}; + +int +gp100_mc_new(struct nvkm_device *device, int index, struct nvkm_mc **pmc) +{ + struct gp100_mc *mc; + + if (!(mc = kzalloc(sizeof(*mc), GFP_KERNEL))) + return -ENOMEM; + nvkm_mc_ctor(&gp100_mc, device, index, &mc->base); + *pmc = &mc->base; + + spin_lock_init(&mc->lock); + mc->intr = false; + mc->mask = 0x7fffffff; + return 0; +} From 45aa4d0774a2537e9e5c35bfc876c57c93d3003c Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 50/97] drm/nouveau/pci/gp100: initial support Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/subdev/pci.h | 1 + .../gpu/drm/nouveau/nvkm/engine/device/base.c | 1 + .../gpu/drm/nouveau/nvkm/subdev/pci/Kbuild | 1 + .../gpu/drm/nouveau/nvkm/subdev/pci/gp100.c | 44 +++++++++++++++++++ 4 files changed, 47 insertions(+) create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/pci/gp100.c diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/pci.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/pci.h index ddb913889d7e..e6523e2cea9f 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/pci.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/pci.h @@ -47,6 +47,7 @@ int g94_pci_new(struct nvkm_device *, int, struct nvkm_pci **); int gf100_pci_new(struct nvkm_device *, int, struct nvkm_pci **); int gf106_pci_new(struct nvkm_device *, int, struct nvkm_pci **); int gk104_pci_new(struct nvkm_device *, int, struct nvkm_pci **); +int gp100_pci_new(struct nvkm_device *, int, struct nvkm_pci **); /* pcie functions */ int nvkm_pcie_set_link(struct nvkm_pci *, enum nvkm_pcie_speed, u8 width); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index cfb98466eb78..99294862dd69 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2152,6 +2152,7 @@ static const struct nvkm_device_chip nv130_chipset = { .name = "GP100", .mc = gp100_mc_new, + .pci = gp100_pci_new, .top = gk104_top_new, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/Kbuild index 3c2519fdeb81..2a31b7d66a6d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/Kbuild @@ -10,3 +10,4 @@ nvkm-y += nvkm/subdev/pci/g94.o nvkm-y += nvkm/subdev/pci/gf100.o nvkm-y += nvkm/subdev/pci/gf106.o nvkm-y += nvkm/subdev/pci/gk104.o +nvkm-y += nvkm/subdev/pci/gp100.o diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/gp100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/gp100.c new file mode 100644 index 000000000000..82c5234a06ff --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/gp100.c @@ -0,0 +1,44 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "priv.h" + +static void +gp100_pci_msi_rearm(struct nvkm_pci *pci) +{ + nvkm_pci_wr32(pci, 0x0704, 0x00000000); +} + +static const struct nvkm_pci_func +gp100_pci_func = { + .rd32 = nv40_pci_rd32, + .wr08 = nv40_pci_wr08, + .wr32 = nv40_pci_wr32, + .msi_rearm = gp100_pci_msi_rearm, +}; + +int +gp100_pci_new(struct nvkm_device *device, int index, struct nvkm_pci **ppci) +{ + return nvkm_pci_new_(&gp100_pci_func, device, index, ppci); +} From 4eeb039b3b51c53fe053f49bd2baccecac808f7d Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 51/97] drm/nouveau/tmr/gp100: initial support Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/device/base.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 99294862dd69..35a0cd18c876 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2153,6 +2153,7 @@ nv130_chipset = { .name = "GP100", .mc = gp100_mc_new, .pci = gp100_pci_new, + .timer = gk20a_timer_new, .top = gk104_top_new, }; From 7481d0553aa24e557a4a8f58e4b462e43bf71eeb Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 52/97] drm/nouveau/bios/gp100: initial support Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/device/base.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 35a0cd18c876..987438f6ecbd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2151,6 +2151,7 @@ nv12b_chipset = { static const struct nvkm_device_chip nv130_chipset = { .name = "GP100", + .bios = nvkm_bios_new, .mc = gp100_mc_new, .pci = gp100_pci_new, .timer = gk20a_timer_new, From 79bf9552e4c0342f4fc2bb0943b24d7c910d0cfa Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 53/97] drm/nouveau/bios/dp: initial support for 4.2 Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/bios/dp.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dp.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dp.c index 05332476354a..d89e78c4e689 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dp.c @@ -40,6 +40,7 @@ nvbios_dp_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) case 0x30: case 0x40: case 0x41: + case 0x42: *hdr = nvbios_rd08(bios, data + 0x01); *len = nvbios_rd08(bios, data + 0x02); *cnt = nvbios_rd08(bios, data + 0x03); @@ -70,6 +71,7 @@ nvbios_dpout_entry(struct nvkm_bios *bios, u8 idx, break; case 0x40: case 0x41: + case 0x42: *hdr = nvbios_rd08(bios, data + 0x04); *cnt = 0; *len = 0; @@ -109,6 +111,7 @@ nvbios_dpout_parse(struct nvkm_bios *bios, u8 idx, break; case 0x40: case 0x41: + case 0x42: info->flags = nvbios_rd08(bios, data + 0x04); info->script[0] = nvbios_rd16(bios, data + 0x05); info->script[1] = nvbios_rd16(bios, data + 0x07); @@ -180,6 +183,11 @@ nvbios_dpcfg_parse(struct nvkm_bios *bios, u16 outp, u8 idx, info->pe = nvbios_rd08(bios, data + 0x02); info->tx_pu = nvbios_rd08(bios, data + 0x03); break; + case 0x42: + info->dc = nvbios_rd08(bios, data + 0x00); + info->pe = nvbios_rd08(bios, data + 0x01); + info->tx_pu = nvbios_rd08(bios, data + 0x02); + break; default: data = 0x0000; break; From 32341039e05ad80c734c869e5fd12748c82d693e Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 54/97] drm/nouveau/bios/pll: initial support for BIT 'C' version 2 Just enough to get at the PLL table. Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/subdev/bios/pll.c | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pll.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pll.c index 91a7dc56e406..2ca23a9157ab 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pll.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pll.c @@ -77,15 +77,17 @@ g84_pll_mapping[] = { {} }; -static u16 +static u32 pll_limits_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) { struct bit_entry bit_C; - u16 data = 0x0000; + u32 data = 0x0000; if (!bit_entry(bios, 'C', &bit_C)) { if (bit_C.version == 1 && bit_C.length >= 10) data = nvbios_rd16(bios, bit_C.offset + 8); + if (bit_C.version == 2 && bit_C.length >= 4) + data = nvbios_rd32(bios, bit_C.offset + 0); if (data) { *ver = nvbios_rd08(bios, data + 0); *hdr = nvbios_rd08(bios, data + 1); @@ -137,12 +139,12 @@ pll_map(struct nvkm_bios *bios) } } -static u16 +static u32 pll_map_reg(struct nvkm_bios *bios, u32 reg, u32 *type, u8 *ver, u8 *len) { struct pll_mapping *map; u8 hdr, cnt; - u16 data; + u32 data; data = pll_limits_table(bios, ver, &hdr, &cnt, len); if (data && *ver >= 0x30) { @@ -160,7 +162,7 @@ pll_map_reg(struct nvkm_bios *bios, u32 reg, u32 *type, u8 *ver, u8 *len) map = pll_map(bios); while (map && map->reg) { if (map->reg == reg && *ver >= 0x20) { - u16 addr = (data += hdr); + u32 addr = (data += hdr); *type = map->type; while (cnt--) { if (nvbios_rd32(bios, data) == map->reg) @@ -179,12 +181,12 @@ pll_map_reg(struct nvkm_bios *bios, u32 reg, u32 *type, u8 *ver, u8 *len) return 0x0000; } -static u16 +static u32 pll_map_type(struct nvkm_bios *bios, u8 type, u32 *reg, u8 *ver, u8 *len) { struct pll_mapping *map; u8 hdr, cnt; - u16 data; + u32 data; data = pll_limits_table(bios, ver, &hdr, &cnt, len); if (data && *ver >= 0x30) { @@ -202,7 +204,7 @@ pll_map_type(struct nvkm_bios *bios, u8 type, u32 *reg, u8 *ver, u8 *len) map = pll_map(bios); while (map && map->reg) { if (map->type == type && *ver >= 0x20) { - u16 addr = (data += hdr); + u32 addr = (data += hdr); *reg = map->reg; while (cnt--) { if (nvbios_rd32(bios, data) == map->reg) @@ -228,7 +230,7 @@ nvbios_pll_parse(struct nvkm_bios *bios, u32 type, struct nvbios_pll *info) struct nvkm_device *device = subdev->device; u8 ver, len; u32 reg = type; - u16 data; + u32 data; if (type > PLL_MAX) { reg = type; From 339e32c0ec9d5a52aa821979f85f1a9c1d322b5a Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 55/97] drm/nouveau/bios/rammap: 32-bit bios pointers Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/bios/rammap.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/rammap.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/rammap.c index d0ae7454764e..b57c370c725d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/rammap.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/rammap.c @@ -30,11 +30,11 @@ nvbios_rammapTe(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz) { struct bit_entry bit_P; - u16 rammap = 0x0000; + u32 rammap = 0x0000; if (!bit_entry(bios, 'P', &bit_P)) { if (bit_P.version == 2) - rammap = nvbios_rd16(bios, bit_P.offset + 4); + rammap = nvbios_rd32(bios, bit_P.offset + 4); if (rammap) { *ver = nvbios_rd08(bios, rammap + 0); @@ -61,7 +61,7 @@ nvbios_rammapEe(struct nvkm_bios *bios, int idx, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) { u8 snr, ssz; - u16 rammap = nvbios_rammapTe(bios, ver, hdr, cnt, len, &snr, &ssz); + u32 rammap = nvbios_rammapTe(bios, ver, hdr, cnt, len, &snr, &ssz); if (rammap && idx < *cnt) { rammap = rammap + *hdr + (idx * (*len + (snr * ssz))); *hdr = *len; From c7b511ba70ce92f96c2e9e0ab8d98db44c84d3e2 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 56/97] drm/nouveau/devinit/gp100: initial support Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/device/base.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 987438f6ecbd..3406e64c3227 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2152,6 +2152,7 @@ static const struct nvkm_device_chip nv130_chipset = { .name = "GP100", .bios = nvkm_bios_new, + .devinit = gm200_devinit_new, .mc = gp100_mc_new, .pci = gp100_pci_new, .timer = gk20a_timer_new, From 0cbe26f0a5ab22ad3ccf11458689ab8da1de0ab8 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 57/97] drm/nouveau/imem/gp100: initial implementation Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/device/base.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 3406e64c3227..b1465c13e48b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2153,6 +2153,7 @@ nv130_chipset = { .name = "GP100", .bios = nvkm_bios_new, .devinit = gm200_devinit_new, + .imem = nv50_instmem_new, .mc = gp100_mc_new, .pci = gp100_pci_new, .timer = gk20a_timer_new, From 7ff51f8200f40911902ede518298e90528b57260 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 58/97] drm/nouveau/fb/gp100: initial support Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/subdev/fb.h | 1 + .../gpu/drm/nouveau/nvkm/engine/device/base.c | 1 + drivers/gpu/drm/nouveau/nvkm/subdev/fb/Kbuild | 2 + drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c | 2 + .../gpu/drm/nouveau/nvkm/subdev/fb/gm200.c | 2 +- .../gpu/drm/nouveau/nvkm/subdev/fb/gp100.c | 69 +++++++++ drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h | 3 + drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.h | 1 + .../gpu/drm/nouveau/nvkm/subdev/fb/ramgp100.c | 146 ++++++++++++++++++ 9 files changed, 226 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/fb/gp100.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgp100.c diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h index c2c002d18f55..c6c3c1ec3ae1 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h @@ -93,6 +93,7 @@ int gk104_fb_new(struct nvkm_device *, int, struct nvkm_fb **); int gk20a_fb_new(struct nvkm_device *, int, struct nvkm_fb **); int gm107_fb_new(struct nvkm_device *, int, struct nvkm_fb **); int gm200_fb_new(struct nvkm_device *, int, struct nvkm_fb **); +int gp100_fb_new(struct nvkm_device *, int, struct nvkm_fb **); #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index b1465c13e48b..b09818507946 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2153,6 +2153,7 @@ nv130_chipset = { .name = "GP100", .bios = nvkm_bios_new, .devinit = gm200_devinit_new, + .fb = gp100_fb_new, .imem = nv50_instmem_new, .mc = gp100_mc_new, .pci = gp100_pci_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/Kbuild index 842d5de96d73..1ca005d3ac62 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/Kbuild @@ -24,6 +24,7 @@ nvkm-y += nvkm/subdev/fb/gk104.o nvkm-y += nvkm/subdev/fb/gk20a.o nvkm-y += nvkm/subdev/fb/gm107.o nvkm-y += nvkm/subdev/fb/gm200.o +nvkm-y += nvkm/subdev/fb/gp100.o nvkm-y += nvkm/subdev/fb/ram.o nvkm-y += nvkm/subdev/fb/ramnv04.o @@ -41,6 +42,7 @@ nvkm-y += nvkm/subdev/fb/rammcp77.o nvkm-y += nvkm/subdev/fb/ramgf100.o nvkm-y += nvkm/subdev/fb/ramgk104.o nvkm-y += nvkm/subdev/fb/ramgm107.o +nvkm-y += nvkm/subdev/fb/ramgp100.o nvkm-y += nvkm/subdev/fb/sddr2.o nvkm-y += nvkm/subdev/fb/sddr3.o nvkm-y += nvkm/subdev/fb/gddr3.o diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c index 4742e5ee37ac..a7049c041594 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c @@ -137,6 +137,8 @@ nvkm_fb_init(struct nvkm_subdev *subdev) fb->func->init(fb); if (fb->func->init_page) fb->func->init_page(fb); + if (fb->func->init_unkn) + fb->func->init_unkn(fb); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm200.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm200.c index 6af3b724f07b..62f653240be3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm200.c @@ -26,7 +26,7 @@ #include -static void +void gm200_fb_init_page(struct nvkm_fb *fb) { struct nvkm_device *device = fb->subdev.device; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gp100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gp100.c new file mode 100644 index 000000000000..1620067168e6 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gp100.c @@ -0,0 +1,69 @@ +/* + * Copyright 2016 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "gf100.h" +#include "ram.h" + +#include + +static void +gp100_fb_init_unkn(struct nvkm_fb *base) +{ + struct nvkm_device *device = gf100_fb(base)->base.subdev.device; + nvkm_wr32(device, 0x1fac80, nvkm_rd32(device, 0x100c80)); + nvkm_wr32(device, 0x1facc4, nvkm_rd32(device, 0x100cc4)); + nvkm_wr32(device, 0x1facc8, nvkm_rd32(device, 0x100cc8)); + nvkm_wr32(device, 0x1faccc, nvkm_rd32(device, 0x100ccc)); +} + +static void +gp100_fb_init(struct nvkm_fb *base) +{ + struct gf100_fb *fb = gf100_fb(base); + struct nvkm_device *device = fb->base.subdev.device; + + if (fb->r100c10_page) + nvkm_wr32(device, 0x100c10, fb->r100c10 >> 8); + + nvkm_wr32(device, 0x100cc8, nvkm_memory_addr(fb->base.mmu_wr) >> 8); + nvkm_wr32(device, 0x100ccc, nvkm_memory_addr(fb->base.mmu_rd) >> 8); + nvkm_mask(device, 0x100cc4, 0x00060000, + max(nvkm_memory_size(fb->base.mmu_rd) >> 16, (u64)2) << 17); +} + +static const struct nvkm_fb_func +gp100_fb = { + .dtor = gf100_fb_dtor, + .oneinit = gf100_fb_oneinit, + .init = gp100_fb_init, + .init_page = gm200_fb_init_page, + .init_unkn = gp100_fb_init_unkn, + .ram_new = gp100_ram_new, + .memtype_valid = gf100_fb_memtype_valid, +}; + +int +gp100_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) +{ + return gf100_fb_new_(&gp100_fb, device, index, pfb); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h index c93926c57310..e905d44fa1d5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h @@ -9,6 +9,7 @@ struct nvkm_fb_func { int (*oneinit)(struct nvkm_fb *); void (*init)(struct nvkm_fb *); void (*init_page)(struct nvkm_fb *); + void (*init_unkn)(struct nvkm_fb *); void (*intr)(struct nvkm_fb *); struct { @@ -63,4 +64,6 @@ void nv46_fb_tile_init(struct nvkm_fb *, int i, u32 addr, u32 size, int gf100_fb_oneinit(struct nvkm_fb *); void gf100_fb_init_page(struct nvkm_fb *); bool gf100_fb_memtype_valid(struct nvkm_fb *, u32); + +void gm200_fb_init_page(struct nvkm_fb *); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.h index f816cbf2ced3..b9ec0ae6723a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.h @@ -47,4 +47,5 @@ int mcp77_ram_new(struct nvkm_fb *, struct nvkm_ram **); int gf100_ram_new(struct nvkm_fb *, struct nvkm_ram **); int gk104_ram_new(struct nvkm_fb *, struct nvkm_ram **); int gm107_ram_new(struct nvkm_fb *, struct nvkm_ram **); +int gp100_ram_new(struct nvkm_fb *, struct nvkm_ram **); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgp100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgp100.c new file mode 100644 index 000000000000..f3be408b5e5e --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgp100.c @@ -0,0 +1,146 @@ +/* + * Copyright 2013 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "ram.h" + +#include +#include +#include + +static int +gp100_ram_init(struct nvkm_ram *ram) +{ + struct nvkm_subdev *subdev = &ram->fb->subdev; + struct nvkm_device *device = subdev->device; + struct nvkm_bios *bios = device->bios; + u8 ver, hdr, cnt, len, snr, ssz; + u32 data; + int i; + + /* run a bunch of tables from rammap table. there's actually + * individual pointers for each rammap entry too, but, nvidia + * seem to just run the last two entries' scripts early on in + * their init, and never again.. we'll just run 'em all once + * for now. + * + * i strongly suspect that each script is for a separate mode + * (likely selected by 0x9a065c's lower bits?), and the + * binary driver skips the one that's already been setup by + * the init tables. + */ + data = nvbios_rammapTe(bios, &ver, &hdr, &cnt, &len, &snr, &ssz); + if (!data || hdr < 0x15) + return -EINVAL; + + cnt = nvbios_rd08(bios, data + 0x14); /* guess at count */ + data = nvbios_rd32(bios, data + 0x10); /* guess u32... */ + if (cnt) { + u32 save = nvkm_rd32(device, 0x9a065c) & 0x000000f0; + for (i = 0; i < cnt; i++, data += 4) { + if (i != save >> 4) { + nvkm_mask(device, 0x9a065c, 0x000000f0, i << 4); + nvbios_exec(&(struct nvbios_init) { + .subdev = subdev, + .bios = bios, + .offset = nvbios_rd32(bios, data), + .execute = 1, + }); + } + } + nvkm_mask(device, 0x9a065c, 0x000000f0, save); + } + + nvkm_mask(device, 0x9a0584, 0x11000000, 0x00000000); + nvkm_wr32(device, 0x10ecc0, 0xffffffff); + nvkm_mask(device, 0x9a0160, 0x00000010, 0x00000010); + return 0; +} + +static const struct nvkm_ram_func +gp100_ram_func = { + .init = gp100_ram_init, + .get = gf100_ram_get, + .put = gf100_ram_put, +}; + +int +gp100_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram) +{ + struct nvkm_ram *ram; + struct nvkm_subdev *subdev = &fb->subdev; + struct nvkm_device *device = subdev->device; + enum nvkm_ram_type type = nvkm_fb_bios_memtype(device->bios); + const u32 rsvd_head = ( 256 * 1024); /* vga memory */ + const u32 rsvd_tail = (1024 * 1024); /* vbios etc */ + u32 fbpa_num = nvkm_rd32(device, 0x022438), fbpa; + u32 fbio_opt = nvkm_rd32(device, 0x021c14); + u64 part, size = 0, comm = ~0ULL; + bool mixed = false; + int ret; + + nvkm_debug(subdev, "022438: %08x\n", fbpa_num); + nvkm_debug(subdev, "021c14: %08x\n", fbio_opt); + for (fbpa = 0; fbpa < fbpa_num; fbpa++) { + if (!(fbio_opt & (1 << fbpa))) { + part = nvkm_rd32(device, 0x90020c + (fbpa * 0x4000)); + nvkm_debug(subdev, "fbpa %02x: %lld MiB\n", fbpa, part); + part = part << 20; + if (part != comm) { + if (comm != ~0ULL) + mixed = true; + comm = min(comm, part); + } + size = size + part; + } + } + + ret = nvkm_ram_new_(&gp100_ram_func, fb, type, size, 0, &ram); + *pram = ram; + if (ret) + return ret; + + nvkm_mm_fini(&ram->vram); + + if (mixed) { + ret = nvkm_mm_init(&ram->vram, rsvd_head >> NVKM_RAM_MM_SHIFT, + ((comm * fbpa_num) - rsvd_head) >> + NVKM_RAM_MM_SHIFT, 1); + if (ret) + return ret; + + ret = nvkm_mm_init(&ram->vram, (0x1000000000ULL + comm) >> + NVKM_RAM_MM_SHIFT, + (size - (comm * fbpa_num) - rsvd_tail) >> + NVKM_RAM_MM_SHIFT, 1); + if (ret) + return ret; + } else { + ret = nvkm_mm_init(&ram->vram, rsvd_head >> NVKM_RAM_MM_SHIFT, + (size - rsvd_head - rsvd_tail) >> + NVKM_RAM_MM_SHIFT, 1); + if (ret) + return ret; + } + + return 0; +} From 4cb53a5ed1d0e662e9aab73fbf2097ead5cad563 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 59/97] drm/nouveau/mmu/gp100: initial support GP100 still supports the previous generations' page table layout, which we will temporarily make use of here. Proper support for the new MMU layout requires some rework to the common MMU code, which is in progress. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/device/base.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index b09818507946..9660dfc8edc0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2156,6 +2156,7 @@ nv130_chipset = { .fb = gp100_fb_new, .imem = nv50_instmem_new, .mc = gp100_mc_new, + .mmu = gf100_mmu_new, .pci = gp100_pci_new, .timer = gk20a_timer_new, .top = gk104_top_new, From 77d813d1493aee029c563545f13855760aa83cb9 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 60/97] drm/nouveau/bar/gp100: initial support Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/device/base.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 9660dfc8edc0..2c9a4913022c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2151,6 +2151,7 @@ nv12b_chipset = { static const struct nvkm_device_chip nv130_chipset = { .name = "GP100", + .bar = gf100_bar_new, .bios = nvkm_bios_new, .devinit = gm200_devinit_new, .fb = gp100_fb_new, From 0e98bd34576bc2d4bd71af8016f94b8aff076644 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 61/97] drm/nouveau/bus/gp100: initial support Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/device/base.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 2c9a4913022c..3b52a8a41085 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2153,6 +2153,7 @@ nv130_chipset = { .name = "GP100", .bar = gf100_bar_new, .bios = nvkm_bios_new, + .bus = gf100_bus_new, .devinit = gm200_devinit_new, .fb = gp100_fb_new, .imem = nv50_instmem_new, From 24b8ca86b772cc78c69ab1508b2ec59d6e3fbe73 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 62/97] drm/nouveau/fuse/gp100: initial support Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/device/base.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 3b52a8a41085..6b7c8d093d2c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2156,6 +2156,7 @@ nv130_chipset = { .bus = gf100_bus_new, .devinit = gm200_devinit_new, .fb = gp100_fb_new, + .fuse = gm107_fuse_new, .imem = nv50_instmem_new, .mc = gp100_mc_new, .mmu = gf100_mmu_new, From a4a58832c228c4368a1b513a45b5075acefcdccf Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 63/97] drm/nouveau/gpio/gp100: initial support Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/device/base.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 6b7c8d093d2c..a8f5a35cfca4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2157,6 +2157,7 @@ nv130_chipset = { .devinit = gm200_devinit_new, .fb = gp100_fb_new, .fuse = gm107_fuse_new, + .gpio = gk104_gpio_new, .imem = nv50_instmem_new, .mc = gp100_mc_new, .mmu = gf100_mmu_new, From 51554014bea3dd8d40555886ee5c40f47d4fb187 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 64/97] drm/nouveau/i2c/gm204: initial support Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/device/base.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index a8f5a35cfca4..ad4194cc3be4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2158,6 +2158,7 @@ nv130_chipset = { .fb = gp100_fb_new, .fuse = gm107_fuse_new, .gpio = gk104_gpio_new, + .i2c = gm200_i2c_new, .imem = nv50_instmem_new, .mc = gp100_mc_new, .mmu = gf100_mmu_new, From 2a295e95fa8a7c23f29feb7236e31455589fc0e5 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 65/97] drm/nouveau/ibus/gp100: initial support Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/device/base.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index ad4194cc3be4..1030c42ba02f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2159,6 +2159,7 @@ nv130_chipset = { .fuse = gm107_fuse_new, .gpio = gk104_gpio_new, .i2c = gm200_i2c_new, + .ibus = gm200_ibus_new, .imem = nv50_instmem_new, .mc = gp100_mc_new, .mmu = gf100_mmu_new, From a96def399bd7df265bdebb5c675230a178db2192 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 66/97] drm/nouveau/ltc/gp100: initial support Due to the GPU preventing us from touching NV_PLTCG_LTCS_LTSS_CBC_BASE, we cannot provide CBC/ZBC support without signed PMU firmware to handle the task for us... Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/subdev/ltc.h | 1 + .../gpu/drm/nouveau/nvkm/engine/device/base.c | 1 + .../gpu/drm/nouveau/nvkm/subdev/ltc/Kbuild | 1 + .../gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c | 2 +- .../gpu/drm/nouveau/nvkm/subdev/ltc/gp100.c | 75 +++++++++++++++++++ .../gpu/drm/nouveau/nvkm/subdev/ltc/priv.h | 1 + 6 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gp100.c diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/ltc.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/ltc.h index c6b90b6543b3..cd755baf9cab 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/ltc.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/ltc.h @@ -38,4 +38,5 @@ int gk104_ltc_new(struct nvkm_device *, int, struct nvkm_ltc **); int gk20a_ltc_new(struct nvkm_device *, int, struct nvkm_ltc **); int gm107_ltc_new(struct nvkm_device *, int, struct nvkm_ltc **); int gm200_ltc_new(struct nvkm_device *, int, struct nvkm_ltc **); +int gp100_ltc_new(struct nvkm_device *, int, struct nvkm_ltc **); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 1030c42ba02f..bd231ccc52ce 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2161,6 +2161,7 @@ nv130_chipset = { .i2c = gm200_i2c_new, .ibus = gm200_ibus_new, .imem = nv50_instmem_new, + .ltc = gp100_ltc_new, .mc = gp100_mc_new, .mmu = gf100_mmu_new, .pci = gp100_pci_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/Kbuild index 932b366598aa..12d6f4f102cb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/Kbuild @@ -3,3 +3,4 @@ nvkm-y += nvkm/subdev/ltc/gf100.o nvkm-y += nvkm/subdev/ltc/gk104.o nvkm-y += nvkm/subdev/ltc/gm107.o nvkm-y += nvkm/subdev/ltc/gm200.o +nvkm-y += nvkm/subdev/ltc/gp100.o diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c index d65708c6a85f..ec0a3844b2d1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c @@ -68,7 +68,7 @@ gm107_ltc_zbc_clear_depth(struct nvkm_ltc *ltc, int i, const u32 depth) nvkm_wr32(device, 0x17e34c, depth); } -static void +void gm107_ltc_intr_lts(struct nvkm_ltc *ltc, int c, int s) { struct nvkm_subdev *subdev = <c->subdev; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gp100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gp100.c new file mode 100644 index 000000000000..0bdfb2f40266 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gp100.c @@ -0,0 +1,75 @@ +/* + * Copyright 2016 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "priv.h" + +static void +gp100_ltc_intr(struct nvkm_ltc *ltc) +{ + struct nvkm_device *device = ltc->subdev.device; + u32 mask; + + mask = nvkm_rd32(device, 0x0001c0); + while (mask) { + u32 s, c = __ffs(mask); + for (s = 0; s < ltc->lts_nr; s++) + gm107_ltc_intr_lts(ltc, c, s); + mask &= ~(1 << c); + } +} + +static int +gp100_ltc_oneinit(struct nvkm_ltc *ltc) +{ + struct nvkm_device *device = ltc->subdev.device; + ltc->ltc_nr = nvkm_rd32(device, 0x12006c); + ltc->lts_nr = nvkm_rd32(device, 0x17e280) >> 28; + /*XXX: tagram allocation - TBD */ + return nvkm_mm_init(<c->tags, 0, 0, 1); +} + +static void +gp100_ltc_init(struct nvkm_ltc *ltc) +{ + /*XXX: PMU LS call to setup tagram address */ +} + +static const struct nvkm_ltc_func +gp100_ltc = { + .oneinit = gp100_ltc_oneinit, + .init = gp100_ltc_init, + .intr = gp100_ltc_intr, + .cbc_clear = gm107_ltc_cbc_clear, + .cbc_wait = gm107_ltc_cbc_wait, + .zbc = 16, + .zbc_clear_color = gm107_ltc_zbc_clear_color, + .zbc_clear_depth = gm107_ltc_zbc_clear_depth, + .invalidate = gf100_ltc_invalidate, + .flush = gf100_ltc_flush, +}; + +int +gp100_ltc_new(struct nvkm_device *device, int index, struct nvkm_ltc **pltc) +{ + return nvkm_ltc_new_(&gp100_ltc, device, index, pltc); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/priv.h index 0da5766a9d3d..8b95f96e3ffa 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/priv.h @@ -35,6 +35,7 @@ void gf100_ltc_flush(struct nvkm_ltc *); extern const struct nvkm_bitfield gf100_ltc_lts_intr_name[]; void gm107_ltc_intr(struct nvkm_ltc *); +void gm107_ltc_intr_lts(struct nvkm_ltc *, int ltc, int lts); void gm107_ltc_cbc_clear(struct nvkm_ltc *, u32, u32); void gm107_ltc_cbc_wait(struct nvkm_ltc *); void gm107_ltc_zbc_clear_color(struct nvkm_ltc *, int, const u32[4]); From a4a4cf1bff760e0e5a758410b1ac6e5385e1a199 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 67/97] drm/nouveau/secboot/gm200: initial support Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/engine/device/base.c | 1 + .../gpu/drm/nouveau/nvkm/subdev/secboot/gm200.c | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index bd231ccc52ce..53c5b715bde1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2164,6 +2164,7 @@ nv130_chipset = { .ltc = gp100_ltc_new, .mc = gp100_mc_new, .mmu = gf100_mmu_new, + .secboot = gm200_secboot_new, .pci = gp100_pci_new, .timer = gk20a_timer_new, .top = gk104_top_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm200.c b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm200.c index d26af8967118..f1e2dc914366 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm200.c @@ -1521,3 +1521,19 @@ MODULE_FIRMWARE("nvidia/gm206/gr/sw_ctx.bin"); MODULE_FIRMWARE("nvidia/gm206/gr/sw_nonctx.bin"); MODULE_FIRMWARE("nvidia/gm206/gr/sw_bundle_init.bin"); MODULE_FIRMWARE("nvidia/gm206/gr/sw_method_init.bin"); + +MODULE_FIRMWARE("nvidia/gp100/acr/bl.bin"); +MODULE_FIRMWARE("nvidia/gp100/acr/ucode_load.bin"); +MODULE_FIRMWARE("nvidia/gp100/acr/ucode_unload.bin"); +MODULE_FIRMWARE("nvidia/gp100/gr/fecs_bl.bin"); +MODULE_FIRMWARE("nvidia/gp100/gr/fecs_inst.bin"); +MODULE_FIRMWARE("nvidia/gp100/gr/fecs_data.bin"); +MODULE_FIRMWARE("nvidia/gp100/gr/fecs_sig.bin"); +MODULE_FIRMWARE("nvidia/gp100/gr/gpccs_bl.bin"); +MODULE_FIRMWARE("nvidia/gp100/gr/gpccs_inst.bin"); +MODULE_FIRMWARE("nvidia/gp100/gr/gpccs_data.bin"); +MODULE_FIRMWARE("nvidia/gp100/gr/gpccs_sig.bin"); +MODULE_FIRMWARE("nvidia/gp100/gr/sw_ctx.bin"); +MODULE_FIRMWARE("nvidia/gp100/gr/sw_nonctx.bin"); +MODULE_FIRMWARE("nvidia/gp100/gr/sw_bundle_init.bin"); +MODULE_FIRMWARE("nvidia/gp100/gr/sw_method_init.bin"); From cd0f407c588ea9afd3dea445095e589e1f5e8461 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 68/97] drm/nouveau/dma/gp100: initial implementation Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/device/base.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 53c5b715bde1..9093449f9bcd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2168,6 +2168,7 @@ nv130_chipset = { .pci = gp100_pci_new, .timer = gk20a_timer_new, .top = gk104_top_new, + .dma = gf119_dma_new, }; static int From f9d5cbb3882ec24c527888aaa65d218e842f016b Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 69/97] drm/nouveau/disp/gp100: initial support Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/class.h | 2 + .../drm/nouveau/include/nvkm/engine/disp.h | 1 + drivers/gpu/drm/nouveau/nouveau_display.c | 1 + drivers/gpu/drm/nouveau/nv50_display.c | 1 + .../gpu/drm/nouveau/nvkm/engine/device/base.c | 1 + .../gpu/drm/nouveau/nvkm/engine/disp/Kbuild | 3 + .../drm/nouveau/nvkm/engine/disp/coregp100.c | 38 ++++++++++++ .../drm/nouveau/nvkm/engine/disp/dmacnv50.h | 2 + .../gpu/drm/nouveau/nvkm/engine/disp/gp100.c | 54 +++++++++++++++++ .../drm/nouveau/nvkm/engine/disp/rootgp100.c | 58 +++++++++++++++++++ .../drm/nouveau/nvkm/engine/disp/rootnv50.h | 1 + 11 files changed, 162 insertions(+) create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/coregp100.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgp100.c diff --git a/drivers/gpu/drm/nouveau/include/nvif/class.h b/drivers/gpu/drm/nouveau/include/nvif/class.h index 982aad8fa645..fd04f37af32d 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/class.h +++ b/drivers/gpu/drm/nouveau/include/nvif/class.h @@ -50,6 +50,7 @@ #define GK110_DISP /* cl5070.h */ 0x00009270 #define GM107_DISP /* cl5070.h */ 0x00009470 #define GM200_DISP /* cl5070.h */ 0x00009570 +#define GP100_DISP /* cl5070.h */ 0x00009770 #define NV31_MPEG 0x00003174 #define G82_MPEG 0x00008274 @@ -86,6 +87,7 @@ #define GK110_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000927d #define GM107_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000947d #define GM200_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000957d +#define GP100_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000977d #define NV50_DISP_OVERLAY_CHANNEL_DMA /* cl507e.h */ 0x0000507e #define G82_DISP_OVERLAY_CHANNEL_DMA /* cl507e.h */ 0x0000827e diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h index d4fdce27b297..c88c15000764 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h @@ -32,4 +32,5 @@ int gk104_disp_new(struct nvkm_device *, int, struct nvkm_disp **); int gk110_disp_new(struct nvkm_device *, int, struct nvkm_disp **); int gm107_disp_new(struct nvkm_device *, int, struct nvkm_disp **); int gm200_disp_new(struct nvkm_device *, int, struct nvkm_disp **); +int gp100_disp_new(struct nvkm_device *, int, struct nvkm_disp **); #endif diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 6072fe292db8..6caad22568a2 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -495,6 +495,7 @@ nouveau_display_create(struct drm_device *dev) if (nouveau_modeset != 2 && drm->vbios.dcb.entries) { static const u16 oclass[] = { + GP100_DISP, GM200_DISP, GM107_DISP, GK110_DISP, diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 7a7788212df7..e871a554398c 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -297,6 +297,7 @@ nv50_core_create(struct nvif_device *device, struct nvif_object *disp, .pushbuf = 0xb0007d00, }; static const s32 oclass[] = { + GP100_DISP_CORE_CHANNEL_DMA, GM200_DISP_CORE_CHANNEL_DMA, GM107_DISP_CORE_CHANNEL_DMA, GK110_DISP_CORE_CHANNEL_DMA, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 9093449f9bcd..2b3f13dd0f1e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2169,6 +2169,7 @@ nv130_chipset = { .timer = gk20a_timer_new, .top = gk104_top_new, .dma = gf119_dma_new, + .disp = gp100_disp_new, }; static int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild index e2a64ed14b22..ee26089037ed 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild @@ -10,6 +10,7 @@ nvkm-y += nvkm/engine/disp/gk104.o nvkm-y += nvkm/engine/disp/gk110.o nvkm-y += nvkm/engine/disp/gm107.o nvkm-y += nvkm/engine/disp/gm200.o +nvkm-y += nvkm/engine/disp/gp100.o nvkm-y += nvkm/engine/disp/outp.o nvkm-y += nvkm/engine/disp/outpdp.o @@ -45,6 +46,7 @@ nvkm-y += nvkm/engine/disp/rootgk104.o nvkm-y += nvkm/engine/disp/rootgk110.o nvkm-y += nvkm/engine/disp/rootgm107.o nvkm-y += nvkm/engine/disp/rootgm200.o +nvkm-y += nvkm/engine/disp/rootgp100.o nvkm-y += nvkm/engine/disp/channv50.o nvkm-y += nvkm/engine/disp/changf119.o @@ -70,6 +72,7 @@ nvkm-y += nvkm/engine/disp/coregk104.o nvkm-y += nvkm/engine/disp/coregk110.o nvkm-y += nvkm/engine/disp/coregm107.o nvkm-y += nvkm/engine/disp/coregm200.o +nvkm-y += nvkm/engine/disp/coregp100.o nvkm-y += nvkm/engine/disp/ovlynv50.o nvkm-y += nvkm/engine/disp/ovlyg84.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregp100.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregp100.c new file mode 100644 index 000000000000..d5dff6619d4d --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregp100.c @@ -0,0 +1,38 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "dmacnv50.h" +#include "rootnv50.h" + +#include + +const struct nv50_disp_dmac_oclass +gp100_disp_core_oclass = { + .base.oclass = GP100_DISP_CORE_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_core_new, + .func = &gf119_disp_core_func, + .mthd = &gk104_disp_core_chan_mthd, + .chid = 0, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.h index fc84eb8b5c45..c737583e393d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.h @@ -88,4 +88,6 @@ extern const struct nv50_disp_dmac_oclass gk110_disp_base_oclass; extern const struct nv50_disp_dmac_oclass gm107_disp_core_oclass; extern const struct nv50_disp_dmac_oclass gm200_disp_core_oclass; + +extern const struct nv50_disp_dmac_oclass gp100_disp_core_oclass; #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c new file mode 100644 index 000000000000..a252d80ed946 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c @@ -0,0 +1,54 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "nv50.h" +#include "rootnv50.h" + +static const struct nv50_disp_func +gp100_disp = { + .intr = gf119_disp_intr, + .uevent = &gf119_disp_chan_uevent, + .super = gf119_disp_intr_supervisor, + .root = &gp100_disp_root_oclass, + .head.vblank_init = gf119_disp_vblank_init, + .head.vblank_fini = gf119_disp_vblank_fini, + .head.scanoutpos = gf119_disp_root_scanoutpos, + .outp.internal.crt = nv50_dac_output_new, + .outp.internal.tmds = nv50_sor_output_new, + .outp.internal.lvds = nv50_sor_output_new, + .outp.internal.dp = gm200_sor_dp_new, + .dac.nr = 3, + .dac.power = nv50_dac_power, + .dac.sense = nv50_dac_sense, + .sor.nr = 4, + .sor.power = nv50_sor_power, + .sor.hda_eld = gf119_hda_eld, + .sor.hdmi = gk104_hdmi_ctrl, + .sor.magic = gm200_sor_magic, +}; + +int +gp100_disp_new(struct nvkm_device *device, int index, struct nvkm_disp **pdisp) +{ + return gf119_disp_new_(&gp100_disp, device, index, pdisp); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgp100.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgp100.c new file mode 100644 index 000000000000..ac8fdd728ec6 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgp100.c @@ -0,0 +1,58 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "rootnv50.h" +#include "dmacnv50.h" + +#include + +static const struct nv50_disp_root_func +gp100_disp_root = { + .init = gf119_disp_root_init, + .fini = gf119_disp_root_fini, + .dmac = { + &gp100_disp_core_oclass, + &gk110_disp_base_oclass, + &gk104_disp_ovly_oclass, + }, + .pioc = { + &gk104_disp_oimm_oclass, + &gk104_disp_curs_oclass, + }, +}; + +static int +gp100_disp_root_new(struct nvkm_disp *disp, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + return nv50_disp_root_new_(&gp100_disp_root, disp, oclass, + data, size, pobject); +} + +const struct nvkm_disp_oclass +gp100_disp_root_oclass = { + .base.oclass = GP100_DISP, + .base.minver = -1, + .base.maxver = -1, + .ctor = gp100_disp_root_new, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.h index cb449ed8d92c..c1d8b21ae167 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.h @@ -40,4 +40,5 @@ extern const struct nvkm_disp_oclass gk104_disp_root_oclass; extern const struct nvkm_disp_oclass gk110_disp_root_oclass; extern const struct nvkm_disp_oclass gm107_disp_root_oclass; extern const struct nvkm_disp_oclass gm200_disp_root_oclass; +extern const struct nvkm_disp_oclass gp100_disp_root_oclass; #endif From e8ff9794923561f51ab73b5f2356aaacad75d432 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 70/97] drm/nouveau/fifo/gp100: initial support Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/class.h | 1 + .../drm/nouveau/include/nvkm/engine/fifo.h | 1 + drivers/gpu/drm/nouveau/nouveau_chan.c | 3 +- drivers/gpu/drm/nouveau/nouveau_drm.c | 1 + .../gpu/drm/nouveau/nvkm/engine/device/base.c | 1 + .../gpu/drm/nouveau/nvkm/engine/fifo/Kbuild | 2 + .../drm/nouveau/nvkm/engine/fifo/changk104.h | 1 + .../gpu/drm/nouveau/nvkm/engine/fifo/gp100.c | 67 +++++++++++++++++++ .../nouveau/nvkm/engine/fifo/gpfifogp100.c | 34 ++++++++++ 9 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/fifo/gp100.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogp100.c diff --git a/drivers/gpu/drm/nouveau/include/nvif/class.h b/drivers/gpu/drm/nouveau/include/nvif/class.h index fd04f37af32d..6f4efbbecd27 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/class.h +++ b/drivers/gpu/drm/nouveau/include/nvif/class.h @@ -39,6 +39,7 @@ #define KEPLER_CHANNEL_GPFIFO_A /* cla06f.h */ 0x0000a06f #define KEPLER_CHANNEL_GPFIFO_B /* cla06f.h */ 0x0000a16f #define MAXWELL_CHANNEL_GPFIFO_A /* cla06f.h */ 0x0000b06f +#define PASCAL_CHANNEL_GPFIFO_A /* cla06f.h */ 0x0000c06f #define NV50_DISP /* cl5070.h */ 0x00005070 #define G82_DISP /* cl5070.h */ 0x00008270 diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h index 15ddfcf5e8db..ed92fec5292c 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h @@ -66,4 +66,5 @@ int gk20a_fifo_new(struct nvkm_device *, int, struct nvkm_fifo **); int gm107_fifo_new(struct nvkm_device *, int, struct nvkm_fifo **); int gm200_fifo_new(struct nvkm_device *, int, struct nvkm_fifo **); int gm20b_fifo_new(struct nvkm_device *, int, struct nvkm_fifo **); +int gp100_fifo_new(struct nvkm_device *, int, struct nvkm_fifo **); #endif diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.c b/drivers/gpu/drm/nouveau/nouveau_chan.c index b1d2527c5625..f9b3c811187e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_chan.c +++ b/drivers/gpu/drm/nouveau/nouveau_chan.c @@ -191,7 +191,8 @@ static int nouveau_channel_ind(struct nouveau_drm *drm, struct nvif_device *device, u32 engine, struct nouveau_channel **pchan) { - static const u16 oclasses[] = { MAXWELL_CHANNEL_GPFIFO_A, + static const u16 oclasses[] = { PASCAL_CHANNEL_GPFIFO_A, + MAXWELL_CHANNEL_GPFIFO_A, KEPLER_CHANNEL_GPFIFO_B, KEPLER_CHANNEL_GPFIFO_A, FERMI_CHANNEL_GPFIFO, diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 6164ea086819..05915c10d07e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -198,6 +198,7 @@ nouveau_accel_init(struct nouveau_drm *drm) case KEPLER_CHANNEL_GPFIFO_A: case KEPLER_CHANNEL_GPFIFO_B: case MAXWELL_CHANNEL_GPFIFO_A: + case PASCAL_CHANNEL_GPFIFO_A: ret = nvc0_fence_create(drm); break; default: diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 2b3f13dd0f1e..a782ab4b30b5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2170,6 +2170,7 @@ nv130_chipset = { .top = gk104_top_new, .dma = gf119_dma_new, .disp = gp100_disp_new, + .fifo = gp100_fifo_new, }; static int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild index 65e5d291ecda..98651a43bc12 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild @@ -13,6 +13,7 @@ nvkm-y += nvkm/engine/fifo/gk20a.o nvkm-y += nvkm/engine/fifo/gm107.o nvkm-y += nvkm/engine/fifo/gm200.o nvkm-y += nvkm/engine/fifo/gm20b.o +nvkm-y += nvkm/engine/fifo/gp100.o nvkm-y += nvkm/engine/fifo/chan.o nvkm-y += nvkm/engine/fifo/channv50.o @@ -31,3 +32,4 @@ nvkm-y += nvkm/engine/fifo/gpfifogf100.o nvkm-y += nvkm/engine/fifo/gpfifogk104.o nvkm-y += nvkm/engine/fifo/gpfifogk110.o nvkm-y += nvkm/engine/fifo/gpfifogm200.o +nvkm-y += nvkm/engine/fifo/gpfifogp100.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changk104.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changk104.h index e06f4d46f802..230f64e5f731 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changk104.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changk104.h @@ -27,4 +27,5 @@ int gk104_fifo_gpfifo_new(struct nvkm_fifo *, const struct nvkm_oclass *, extern const struct nvkm_fifo_chan_oclass gk104_fifo_gpfifo_oclass; extern const struct nvkm_fifo_chan_oclass gk110_fifo_gpfifo_oclass; extern const struct nvkm_fifo_chan_oclass gm200_fifo_gpfifo_oclass; +extern const struct nvkm_fifo_chan_oclass gp100_fifo_gpfifo_oclass; #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gp100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gp100.c new file mode 100644 index 000000000000..eff83f7fb705 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gp100.c @@ -0,0 +1,67 @@ +/* + * Copyright 2016 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "gk104.h" +#include "changk104.h" + +static const struct nvkm_enum +gp100_fifo_fault_engine[] = { + { 0x01, "DISPLAY" }, + { 0x03, "IFB", NULL, NVKM_ENGINE_IFB }, + { 0x04, "BAR1", NULL, NVKM_SUBDEV_BAR }, + { 0x05, "BAR2", NULL, NVKM_SUBDEV_INSTMEM }, + { 0x06, "HOST0" }, + { 0x07, "HOST1" }, + { 0x08, "HOST2" }, + { 0x09, "HOST3" }, + { 0x0a, "HOST4" }, + { 0x0b, "HOST5" }, + { 0x0c, "HOST6" }, + { 0x0d, "HOST7" }, + { 0x0e, "HOST8" }, + { 0x0f, "HOST9" }, + { 0x10, "HOST10" }, + { 0x13, "PERF" }, + { 0x17, "PMU" }, + { 0x18, "PTP" }, + { 0x1f, "PHYSICAL" }, + {} +}; + +static const struct gk104_fifo_func +gp100_fifo = { + .fault.engine = gp100_fifo_fault_engine, + .fault.reason = gk104_fifo_fault_reason, + .fault.hubclient = gk104_fifo_fault_hubclient, + .fault.gpcclient = gk104_fifo_fault_gpcclient, + .chan = { + &gp100_fifo_gpfifo_oclass, + NULL + }, +}; + +int +gp100_fifo_new(struct nvkm_device *device, int index, struct nvkm_fifo **pfifo) +{ + return gk104_fifo_new_(&gp100_fifo, device, index, 4096, pfifo); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogp100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogp100.c new file mode 100644 index 000000000000..1530a9217aea --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogp100.c @@ -0,0 +1,34 @@ +/* + * Copyright 2016 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "changk104.h" + +#include + +const struct nvkm_fifo_chan_oclass +gp100_fifo_gpfifo_oclass = { + .base.oclass = PASCAL_CHANNEL_GPFIFO_A, + .base.minver = 0, + .base.maxver = 0, + .ctor = gk104_fifo_gpfifo_new, +}; From 8e7e1586c58a5e3893aeae445ef843bb26fb7653 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 71/97] drm/nouveau/ce/gp100: initial support Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/class.h | 1 + .../gpu/drm/nouveau/include/nvkm/engine/ce.h | 1 + drivers/gpu/drm/nouveau/nouveau_bo.c | 2 + drivers/gpu/drm/nouveau/nvkm/engine/ce/Kbuild | 1 + .../gpu/drm/nouveau/nvkm/engine/ce/gp100.c | 102 ++++++++++++++++++ .../gpu/drm/nouveau/nvkm/engine/device/base.c | 6 ++ 6 files changed, 113 insertions(+) create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/ce/gp100.c diff --git a/drivers/gpu/drm/nouveau/include/nvif/class.h b/drivers/gpu/drm/nouveau/include/nvif/class.h index 6f4efbbecd27..4bfa59a3cab4 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/class.h +++ b/drivers/gpu/drm/nouveau/include/nvif/class.h @@ -131,6 +131,7 @@ #define FERMI_DMA 0x000090b5 #define KEPLER_DMA_COPY_A 0x0000a0b5 #define MAXWELL_DMA_COPY_A 0x0000b0b5 +#define PASCAL_DMA_COPY_A 0x0000c0b5 #define FERMI_DECOMPRESS 0x000090b8 diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/ce.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/ce.h index 594d719ba41e..45588742fd91 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/ce.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/ce.h @@ -7,4 +7,5 @@ int gf100_ce_new(struct nvkm_device *, int, struct nvkm_engine **); int gk104_ce_new(struct nvkm_device *, int, struct nvkm_engine **); int gm107_ce_new(struct nvkm_device *, int, struct nvkm_engine **); int gm200_ce_new(struct nvkm_device *, int, struct nvkm_engine **); +int gp100_ce_new(struct nvkm_device *, int, struct nvkm_engine **); #endif diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 5e3f3e826476..6423c7be9c7f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -1104,6 +1104,8 @@ nouveau_bo_move_init(struct nouveau_drm *drm) struct ttm_mem_reg *, struct ttm_mem_reg *); int (*init)(struct nouveau_channel *, u32 handle); } _methods[] = { + { "COPY", 4, 0xc0b5, nve0_bo_move_copy, nve0_bo_move_init }, + { "GRCE", 0, 0xc0b5, nve0_bo_move_copy, nvc0_bo_move_init }, { "COPY", 4, 0xb0b5, nve0_bo_move_copy, nve0_bo_move_init }, { "GRCE", 0, 0xb0b5, nve0_bo_move_copy, nvc0_bo_move_init }, { "COPY", 4, 0xa0b5, nve0_bo_move_copy, nve0_bo_move_init }, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/ce/Kbuild index 9c19d59b47df..7d55197e8296 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/Kbuild @@ -3,3 +3,4 @@ nvkm-y += nvkm/engine/ce/gf100.o nvkm-y += nvkm/engine/ce/gk104.o nvkm-y += nvkm/engine/ce/gm107.o nvkm-y += nvkm/engine/ce/gm200.o +nvkm-y += nvkm/engine/ce/gp100.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gp100.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gp100.c new file mode 100644 index 000000000000..c7710456bc30 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gp100.c @@ -0,0 +1,102 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "priv.h" +#include + +#include + +static const struct nvkm_enum +gp100_ce_launcherr_report[] = { + { 0x0, "NO_ERR" }, + { 0x1, "2D_LAYER_EXCEEDS_DEPTH" }, + { 0x2, "INVALID_ALIGNMENT" }, + { 0x3, "MEM2MEM_RECT_OUT_OF_BOUNDS" }, + { 0x4, "SRC_LINE_EXCEEDS_PITCH" }, + { 0x5, "SRC_LINE_EXCEEDS_NEG_PITCH" }, + { 0x6, "DST_LINE_EXCEEDS_PITCH" }, + { 0x7, "DST_LINE_EXCEEDS_NEG_PITCH" }, + { 0x8, "BAD_SRC_PIXEL_COMP_REF" }, + { 0x9, "INVALID_VALUE" }, + { 0xa, "UNUSED_FIELD" }, + { 0xb, "INVALID_OPERATION" }, + { 0xc, "NO_RESOURCES" }, + { 0xd, "INVALID_CONFIG" }, + {} +}; + +static void +gp100_ce_intr_launcherr(struct nvkm_engine *ce, const u32 base) +{ + struct nvkm_subdev *subdev = &ce->subdev; + struct nvkm_device *device = subdev->device; + u32 stat = nvkm_rd32(device, 0x104418 + base); + const struct nvkm_enum *en = + nvkm_enum_find(gp100_ce_launcherr_report, stat & 0x0000000f); + nvkm_warn(subdev, "LAUNCHERR %08x [%s]\n", stat, en ? en->name : ""); +} + +void +gp100_ce_intr(struct nvkm_engine *ce) +{ + const u32 base = (ce->subdev.index - NVKM_ENGINE_CE0) * 0x80; + struct nvkm_subdev *subdev = &ce->subdev; + struct nvkm_device *device = subdev->device; + u32 mask = nvkm_rd32(device, 0x10440c + base); + u32 intr = nvkm_rd32(device, 0x104410 + base) & mask; + if (intr & 0x00000001) { //XXX: guess + nvkm_warn(subdev, "BLOCKPIPE\n"); + nvkm_wr32(device, 0x104410 + base, 0x00000001); + intr &= ~0x00000001; + } + if (intr & 0x00000002) { //XXX: guess + nvkm_warn(subdev, "NONBLOCKPIPE\n"); + nvkm_wr32(device, 0x104410 + base, 0x00000002); + intr &= ~0x00000002; + } + if (intr & 0x00000004) { + gp100_ce_intr_launcherr(ce, base); + nvkm_wr32(device, 0x104410 + base, 0x00000004); + intr &= ~0x00000004; + } + if (intr) { + nvkm_warn(subdev, "intr %08x\n", intr); + nvkm_wr32(device, 0x104410 + base, intr); + } +} + +static const struct nvkm_engine_func +gp100_ce = { + .intr = gp100_ce_intr, + .sclass = { + { -1, -1, PASCAL_DMA_COPY_A }, + {} + } +}; + +int +gp100_ce_new(struct nvkm_device *device, int index, + struct nvkm_engine **pengine) +{ + return nvkm_engine_new_(&gp100_ce, device, index, true, pengine); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index a782ab4b30b5..94f4b2fa3d9a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2168,6 +2168,12 @@ nv130_chipset = { .pci = gp100_pci_new, .timer = gk20a_timer_new, .top = gk104_top_new, + .ce[0] = gp100_ce_new, + .ce[1] = gp100_ce_new, + .ce[2] = gp100_ce_new, + .ce[3] = gp100_ce_new, + .ce[4] = gp100_ce_new, + .ce[5] = gp100_ce_new, .dma = gf119_dma_new, .disp = gp100_disp_new, .fifo = gp100_fifo_new, From 52fa0866ca78d170742aa9e7587ffd2a6a623973 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 72/97] drm/nouveau/gr/gp100: initial support Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/class.h | 3 + .../gpu/drm/nouveau/include/nvkm/engine/gr.h | 1 + .../gpu/drm/nouveau/nvkm/engine/device/base.c | 1 + drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild | 2 + .../gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.h | 2 + .../gpu/drm/nouveau/nvkm/engine/gr/ctxgp100.c | 179 ++++++++++++++++++ .../gpu/drm/nouveau/nvkm/engine/gr/gf100.h | 2 + .../gpu/drm/nouveau/nvkm/engine/gr/gm200.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/gr/gp100.c | 171 +++++++++++++++++ 9 files changed, 362 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgp100.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/gr/gp100.c diff --git a/drivers/gpu/drm/nouveau/include/nvif/class.h b/drivers/gpu/drm/nouveau/include/nvif/class.h index 4bfa59a3cab4..ed71576eedac 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/class.h +++ b/drivers/gpu/drm/nouveau/include/nvif/class.h @@ -108,6 +108,8 @@ #define MAXWELL_A /* cl9097.h */ 0x0000b097 #define MAXWELL_B /* cl9097.h */ 0x0000b197 +#define PASCAL_A /* cl9097.h */ 0x0000c097 + #define NV74_BSP 0x000074b0 #define GT212_MSVLD 0x000085b1 @@ -141,6 +143,7 @@ #define KEPLER_COMPUTE_B 0x0000a1c0 #define MAXWELL_COMPUTE_A 0x0000b0c0 #define MAXWELL_COMPUTE_B 0x0000b1c0 +#define PASCAL_COMPUTE_A 0x0000c0c0 #define NV74_CIPHER 0x000074c1 #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h index 6515f5810a26..89cf99307828 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h @@ -42,4 +42,5 @@ int gk20a_gr_new(struct nvkm_device *, int, struct nvkm_gr **); int gm107_gr_new(struct nvkm_device *, int, struct nvkm_gr **); int gm200_gr_new(struct nvkm_device *, int, struct nvkm_gr **); int gm20b_gr_new(struct nvkm_device *, int, struct nvkm_gr **); +int gp100_gr_new(struct nvkm_device *, int, struct nvkm_gr **); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 94f4b2fa3d9a..f4e9ed1ee8e6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2177,6 +2177,7 @@ nv130_chipset = { .dma = gf119_dma_new, .disp = gp100_disp_new, .fifo = gp100_fifo_new, + .gr = gp100_gr_new, }; static int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild index 290ed0db8047..f1c494182248 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild @@ -31,6 +31,7 @@ nvkm-y += nvkm/engine/gr/gk20a.o nvkm-y += nvkm/engine/gr/gm107.o nvkm-y += nvkm/engine/gr/gm200.o nvkm-y += nvkm/engine/gr/gm20b.o +nvkm-y += nvkm/engine/gr/gp100.o nvkm-y += nvkm/engine/gr/ctxnv40.o nvkm-y += nvkm/engine/gr/ctxnv50.o @@ -48,3 +49,4 @@ nvkm-y += nvkm/engine/gr/ctxgk20a.o nvkm-y += nvkm/engine/gr/ctxgm107.o nvkm-y += nvkm/engine/gr/ctxgm200.o nvkm-y += nvkm/engine/gr/ctxgm20b.o +nvkm-y += nvkm/engine/gr/ctxgp100.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.h index ac895edce164..52048b5a5274 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.h @@ -101,6 +101,8 @@ void gm200_grctx_generate_405b60(struct gf100_gr *); extern const struct gf100_grctx_func gm20b_grctx; +extern const struct gf100_grctx_func gp100_grctx; + /* context init value lists */ extern const struct gf100_gr_pack gf100_grctx_pack_icmd[]; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgp100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgp100.c new file mode 100644 index 000000000000..3d1ae7ddf7dd --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgp100.c @@ -0,0 +1,179 @@ +/* + * Copyright 2016 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "ctxgf100.h" + +#include + +/******************************************************************************* + * PGRAPH context implementation + ******************************************************************************/ + +static void +gp100_grctx_generate_pagepool(struct gf100_grctx *info) +{ + const struct gf100_grctx_func *grctx = info->gr->func->grctx; + const u32 access = NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS; + const int s = 8; + const int b = mmio_vram(info, grctx->pagepool_size, (1 << s), access); + mmio_refn(info, 0x40800c, 0x00000000, s, b); + mmio_wr32(info, 0x408010, 0x80000000); + mmio_refn(info, 0x419004, 0x00000000, s, b); + mmio_wr32(info, 0x419008, 0x00000000); +} + +static void +gp100_grctx_generate_attrib(struct gf100_grctx *info) +{ + struct gf100_gr *gr = info->gr; + const struct gf100_grctx_func *grctx = gr->func->grctx; + const u32 alpha = grctx->alpha_nr; + const u32 attrib = grctx->attrib_nr; + const u32 pertpc = 0x20 * (grctx->attrib_nr_max + grctx->alpha_nr_max); + const u32 size = roundup(gr->tpc_total * pertpc, 0x80); + const u32 access = NV_MEM_ACCESS_RW; + const int s = 12; + const int b = mmio_vram(info, size, (1 << s), access); + const int max_batches = 0xffff; + u32 ao = 0; + u32 bo = ao + grctx->alpha_nr_max * gr->tpc_total; + int gpc, ppc, n = 0; + + mmio_refn(info, 0x418810, 0x80000000, s, b); + mmio_refn(info, 0x419848, 0x10000000, s, b); + mmio_refn(info, 0x419c2c, 0x10000000, s, b); + mmio_refn(info, 0x419b00, 0x00000000, s, b); + mmio_wr32(info, 0x419b04, 0x80000000 | size >> 7); + mmio_wr32(info, 0x405830, attrib); + mmio_wr32(info, 0x40585c, alpha); + mmio_wr32(info, 0x4064c4, ((alpha / 4) << 16) | max_batches); + + for (gpc = 0; gpc < gr->gpc_nr; gpc++) { + for (ppc = 0; ppc < gr->ppc_nr[gpc]; ppc++, n++) { + const u32 as = alpha * gr->ppc_tpc_nr[gpc][ppc]; + const u32 bs = attrib * gr->ppc_tpc_nr[gpc][ppc]; + const u32 u = 0x418ea0 + (n * 0x04); + const u32 o = PPC_UNIT(gpc, ppc, 0); + if (!(gr->ppc_mask[gpc] & (1 << ppc))) + continue; + mmio_wr32(info, o + 0xc0, bs); + mmio_wr32(info, o + 0xf4, bo); + mmio_wr32(info, o + 0xf0, bs); + bo += grctx->attrib_nr_max * gr->ppc_tpc_nr[gpc][ppc]; + mmio_wr32(info, o + 0xe4, as); + mmio_wr32(info, o + 0xf8, ao); + ao += grctx->alpha_nr_max * gr->ppc_tpc_nr[gpc][ppc]; + mmio_wr32(info, u, bs); + } + } + + mmio_wr32(info, 0x418eec, 0x00000000); + mmio_wr32(info, 0x41befc, 0x00000000); +} + +static void +gp100_grctx_generate_405b60(struct gf100_gr *gr) +{ + struct nvkm_device *device = gr->base.engine.subdev.device; + const u32 dist_nr = DIV_ROUND_UP(gr->tpc_total, 4); + u32 dist[TPC_MAX / 4] = {}; + u32 gpcs[GPC_MAX * 2] = {}; + u8 tpcnr[GPC_MAX]; + int tpc, gpc, i; + + memcpy(tpcnr, gr->tpc_nr, sizeof(gr->tpc_nr)); + + /* won't result in the same distribution as the binary driver where + * some of the gpcs have more tpcs than others, but this shall do + * for the moment. the code for earlier gpus has this issue too. + */ + for (gpc = -1, i = 0; i < gr->tpc_total; i++) { + do { + gpc = (gpc + 1) % gr->gpc_nr; + } while(!tpcnr[gpc]); + tpc = gr->tpc_nr[gpc] - tpcnr[gpc]--; + + dist[i / 4] |= ((gpc << 4) | tpc) << ((i % 4) * 8); + gpcs[gpc + (gr->gpc_nr * (tpc / 4))] |= i << (tpc * 8); + } + + for (i = 0; i < dist_nr; i++) + nvkm_wr32(device, 0x405b60 + (i * 4), dist[i]); + for (i = 0; i < gr->gpc_nr * 2; i++) + nvkm_wr32(device, 0x405ba0 + (i * 4), gpcs[i]); +} + +static void +gp100_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) +{ + struct nvkm_device *device = gr->base.engine.subdev.device; + const struct gf100_grctx_func *grctx = gr->func->grctx; + u32 idle_timeout, tmp; + int i; + + gf100_gr_mmio(gr, gr->fuc_sw_ctx); + + idle_timeout = nvkm_mask(device, 0x404154, 0xffffffff, 0x00000000); + + grctx->pagepool(info); + grctx->bundle(info); + grctx->attrib(info); + grctx->unkn(gr); + + gm200_grctx_generate_tpcid(gr); + gf100_grctx_generate_r406028(gr); + gk104_grctx_generate_r418bb8(gr); + + for (i = 0; i < 8; i++) + nvkm_wr32(device, 0x4064d0 + (i * 0x04), 0x00000000); + nvkm_wr32(device, 0x406500, 0x00000000); + + nvkm_wr32(device, 0x405b00, (gr->tpc_total << 8) | gr->gpc_nr); + + for (tmp = 0, i = 0; i < gr->gpc_nr; i++) + tmp |= ((1 << gr->tpc_nr[i]) - 1) << (i * 5); + nvkm_wr32(device, 0x4041c4, tmp); + + gp100_grctx_generate_405b60(gr); + + gf100_gr_icmd(gr, gr->fuc_bundle); + nvkm_wr32(device, 0x404154, idle_timeout); + gf100_gr_mthd(gr, gr->fuc_method); +} + +const struct gf100_grctx_func +gp100_grctx = { + .main = gp100_grctx_generate_main, + .unkn = gk104_grctx_generate_unkn, + .bundle = gm107_grctx_generate_bundle, + .bundle_size = 0x3000, + .bundle_min_gpm_fifo_depth = 0x180, + .bundle_token_limit = 0x1080, + .pagepool = gp100_grctx_generate_pagepool, + .pagepool_size = 0x20000, + .attrib = gp100_grctx_generate_attrib, + .attrib_nr_max = 0x660, + .attrib_nr = 0x440, + .alpha_nr_max = 0xc00, + .alpha_nr = 0x800, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h index 2b98abdb9270..268b8d60ff73 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h @@ -292,4 +292,6 @@ extern const struct gf100_gr_init gm107_gr_init_l1c_0[]; extern const struct gf100_gr_init gm107_gr_init_wwdx_0[]; extern const struct gf100_gr_init gm107_gr_init_cbm_0[]; void gm107_gr_init_bios(struct gf100_gr *); + +void gm200_gr_init_gpc_mmu(struct gf100_gr *); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm200.c index 4dfa4513bb6c..6435f1257572 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm200.c @@ -38,7 +38,7 @@ gm200_gr_rops(struct gf100_gr *gr) return nvkm_rd32(gr->base.engine.subdev.device, 0x12006c); } -static void +void gm200_gr_init_gpc_mmu(struct gf100_gr *gr) { struct nvkm_device *device = gr->base.engine.subdev.device; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp100.c new file mode 100644 index 000000000000..26ad79def0ff --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gp100.c @@ -0,0 +1,171 @@ +/* + * Copyright 2016 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "gf100.h" +#include "ctxgf100.h" + +#include + +/******************************************************************************* + * PGRAPH engine/subdev functions + ******************************************************************************/ + +static void +gp100_gr_init_rop_active_fbps(struct gf100_gr *gr) +{ + struct nvkm_device *device = gr->base.engine.subdev.device; + /*XXX: otherwise identical to gm200 aside from mask.. do everywhere? */ + const u32 fbp_count = nvkm_rd32(device, 0x12006c) & 0x0000000f; + nvkm_mask(device, 0x408850, 0x0000000f, fbp_count); /* zrop */ + nvkm_mask(device, 0x408958, 0x0000000f, fbp_count); /* crop */ +} + +static int +gp100_gr_init(struct gf100_gr *gr) +{ + struct nvkm_device *device = gr->base.engine.subdev.device; + const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, gr->tpc_total); + u32 data[TPC_MAX / 8] = {}; + u8 tpcnr[GPC_MAX]; + int gpc, tpc, rop; + int i; + + gr->func->init_gpc_mmu(gr); + + gf100_gr_mmio(gr, gr->fuc_sw_nonctx); + + nvkm_wr32(device, GPC_UNIT(0, 0x3018), 0x00000001); + + memset(data, 0x00, sizeof(data)); + memcpy(tpcnr, gr->tpc_nr, sizeof(gr->tpc_nr)); + for (i = 0, gpc = -1; i < gr->tpc_total; i++) { + do { + gpc = (gpc + 1) % gr->gpc_nr; + } while (!tpcnr[gpc]); + tpc = gr->tpc_nr[gpc] - tpcnr[gpc]--; + + data[i / 8] |= tpc << ((i % 8) * 4); + } + + nvkm_wr32(device, GPC_BCAST(0x0980), data[0]); + nvkm_wr32(device, GPC_BCAST(0x0984), data[1]); + nvkm_wr32(device, GPC_BCAST(0x0988), data[2]); + nvkm_wr32(device, GPC_BCAST(0x098c), data[3]); + + for (gpc = 0; gpc < gr->gpc_nr; gpc++) { + nvkm_wr32(device, GPC_UNIT(gpc, 0x0914), + gr->screen_tile_row_offset << 8 | gr->tpc_nr[gpc]); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0910), 0x00040000 | + gr->tpc_total); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0918), magicgpc918); + } + + nvkm_wr32(device, GPC_BCAST(0x3fd4), magicgpc918); + nvkm_wr32(device, GPC_BCAST(0x08ac), nvkm_rd32(device, 0x100800)); + nvkm_wr32(device, GPC_BCAST(0x033c), nvkm_rd32(device, 0x100804)); + + gr->func->init_rop_active_fbps(gr); + + nvkm_wr32(device, 0x400500, 0x00010001); + nvkm_wr32(device, 0x400100, 0xffffffff); + nvkm_wr32(device, 0x40013c, 0xffffffff); + nvkm_wr32(device, 0x400124, 0x00000002); + nvkm_wr32(device, 0x409c24, 0x000f0002); + nvkm_wr32(device, 0x405848, 0xc0000000); + nvkm_mask(device, 0x40584c, 0x00000000, 0x00000001); + nvkm_wr32(device, 0x404000, 0xc0000000); + nvkm_wr32(device, 0x404600, 0xc0000000); + nvkm_wr32(device, 0x408030, 0xc0000000); + nvkm_wr32(device, 0x404490, 0xc0000000); + nvkm_wr32(device, 0x406018, 0xc0000000); + nvkm_wr32(device, 0x407020, 0x40000000); + nvkm_wr32(device, 0x405840, 0xc0000000); + nvkm_wr32(device, 0x405844, 0x00ffffff); + nvkm_mask(device, 0x419cc0, 0x00000008, 0x00000008); + + nvkm_mask(device, 0x419c9c, 0x00010000, 0x00010000); + nvkm_mask(device, 0x419c9c, 0x00020000, 0x00020000); + + gr->func->init_ppc_exceptions(gr); + + for (gpc = 0; gpc < gr->gpc_nr; gpc++) { + nvkm_wr32(device, GPC_UNIT(gpc, 0x0420), 0xc0000000); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0900), 0xc0000000); + nvkm_wr32(device, GPC_UNIT(gpc, 0x1028), 0xc0000000); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0824), 0xc0000000); + for (tpc = 0; tpc < gr->tpc_nr[gpc]; tpc++) { + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x430), 0xc0000000); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x644), 0x00dffffe); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x64c), 0x00000105); + } + nvkm_wr32(device, GPC_UNIT(gpc, 0x2c90), 0xffffffff); + nvkm_wr32(device, GPC_UNIT(gpc, 0x2c94), 0xffffffff); + } + + for (rop = 0; rop < gr->rop_nr; rop++) { + nvkm_wr32(device, ROP_UNIT(rop, 0x144), 0x40000000); + nvkm_wr32(device, ROP_UNIT(rop, 0x070), 0x40000000); + nvkm_wr32(device, ROP_UNIT(rop, 0x204), 0xffffffff); + nvkm_wr32(device, ROP_UNIT(rop, 0x208), 0xffffffff); + } + + nvkm_wr32(device, 0x400108, 0xffffffff); + nvkm_wr32(device, 0x400138, 0xffffffff); + nvkm_wr32(device, 0x400118, 0xffffffff); + nvkm_wr32(device, 0x400130, 0xffffffff); + nvkm_wr32(device, 0x40011c, 0xffffffff); + nvkm_wr32(device, 0x400134, 0xffffffff); + + gf100_gr_zbc_init(gr); + + return gf100_gr_init_ctxctl(gr); +} + +static const struct gf100_gr_func +gp100_gr = { + .init = gp100_gr_init, + .init_gpc_mmu = gm200_gr_init_gpc_mmu, + .init_rop_active_fbps = gp100_gr_init_rop_active_fbps, + .init_ppc_exceptions = gk104_gr_init_ppc_exceptions, + .rops = gm200_gr_rops, + .ppc_nr = 2, + .grctx = &gp100_grctx, + .sclass = { + { -1, -1, FERMI_TWOD_A }, + { -1, -1, KEPLER_INLINE_TO_MEMORY_B }, + { -1, -1, PASCAL_A, &gf100_fermi }, + { -1, -1, PASCAL_COMPUTE_A }, + {} + } +}; + +int +gp100_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return gm200_gr_new_(&gp100_gr, device, index, pgr); +} From ac24b4df4374b8ddc8af8e945f944e23db0d6867 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 73/97] drm/nouveau/sw/gp100: initial support Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/device/base.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index f4e9ed1ee8e6..3c4f4bcea81b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2178,6 +2178,7 @@ nv130_chipset = { .disp = gp100_disp_new, .fifo = gp100_fifo_new, .gr = gp100_gr_new, + .sw = gf100_sw_new, }; static int From cfb083f692b884c7cc5376ffe04ce7cd9d8331bc Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 74/97] drm/nouveau/core: recognise GP104 chipset Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/device/base.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 3c4f4bcea81b..d1a2ff01505c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2181,6 +2181,11 @@ nv130_chipset = { .sw = gf100_sw_new, }; +static const struct nvkm_device_chip +nv134_chipset = { + .name = "GP104", +}; + static int nvkm_device_event_ctor(struct nvkm_object *object, void *data, u32 size, struct nvkm_notify *notify) @@ -2615,6 +2620,7 @@ nvkm_device_ctor(const struct nvkm_device_func *func, case 0x126: device->chip = &nv126_chipset; break; case 0x12b: device->chip = &nv12b_chipset; break; case 0x130: device->chip = &nv130_chipset; break; + case 0x134: device->chip = &nv134_chipset; break; default: nvdev_error(device, "unknown chipset (%08x)\n", boot0); goto done; From 445b9c2130715317c4ba05ea7d7d7a0da5c55610 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 75/97] drm/nouveau/top/gp104: initial support Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/device/base.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index d1a2ff01505c..711b20af45ab 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2184,6 +2184,7 @@ nv130_chipset = { static const struct nvkm_device_chip nv134_chipset = { .name = "GP104", + .top = gk104_top_new, }; static int From 9179b8ec7799718c2bd91d9bfd29462a3b032aa6 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 76/97] drm/nouveau/mc/gp104: initial support Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/device/base.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 711b20af45ab..1e59b7f6e897 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2184,6 +2184,7 @@ nv130_chipset = { static const struct nvkm_device_chip nv134_chipset = { .name = "GP104", + .mc = gp100_mc_new, .top = gk104_top_new, }; From b3446c5ab5489ef357ccab2118bd5db56a296045 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 77/97] drm/nouveau/pci/gp104: initial support Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/device/base.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 1e59b7f6e897..d9173cb42eee 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2185,6 +2185,7 @@ static const struct nvkm_device_chip nv134_chipset = { .name = "GP104", .mc = gp100_mc_new, + .pci = gp100_pci_new, .top = gk104_top_new, }; From 5f62ee6dad305f3a5b1fbf7ad280bde30e835275 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 78/97] drm/nouveau/tmr/gp104: initial support Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/device/base.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index d9173cb42eee..e9abe57271f0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2186,6 +2186,7 @@ nv134_chipset = { .name = "GP104", .mc = gp100_mc_new, .pci = gp100_pci_new, + .timer = gk20a_timer_new, .top = gk104_top_new, }; From 38849205accf598548200f34f710f6d2120dd108 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 79/97] drm/nouveau/bios/gp104: initial support Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/device/base.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index e9abe57271f0..0775b4a0b2c8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2184,6 +2184,7 @@ nv130_chipset = { static const struct nvkm_device_chip nv134_chipset = { .name = "GP104", + .bios = nvkm_bios_new, .mc = gp100_mc_new, .pci = gp100_pci_new, .timer = gk20a_timer_new, From 047506cab8d87ffb7cef798cf1f03008546304a2 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 80/97] drm/nouveau/devinit/gp104: initial support Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/device/base.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 0775b4a0b2c8..71a477cac8a0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2185,6 +2185,7 @@ static const struct nvkm_device_chip nv134_chipset = { .name = "GP104", .bios = nvkm_bios_new, + .devinit = gm200_devinit_new, .mc = gp100_mc_new, .pci = gp100_pci_new, .timer = gk20a_timer_new, From 4fdbdfa8ae8fd2c978de51affdc851584e872f94 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 81/97] drm/nouveau/imem/gp104: initial support Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/device/base.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 71a477cac8a0..0ae41e6f58f2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2186,6 +2186,7 @@ nv134_chipset = { .name = "GP104", .bios = nvkm_bios_new, .devinit = gm200_devinit_new, + .imem = nv50_instmem_new, .mc = gp100_mc_new, .pci = gp100_pci_new, .timer = gk20a_timer_new, From 6258cd43cf261a2d066af86d730a48301c8d09a2 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 82/97] drm/nouveau/fb/gp104: initial support Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/subdev/fb.h | 1 + .../gpu/drm/nouveau/nvkm/engine/device/base.c | 1 + drivers/gpu/drm/nouveau/nvkm/subdev/fb/Kbuild | 1 + .../gpu/drm/nouveau/nvkm/subdev/fb/gf100.h | 2 + .../gpu/drm/nouveau/nvkm/subdev/fb/gp100.c | 2 +- .../gpu/drm/nouveau/nvkm/subdev/fb/gp104.c | 43 +++++++++++++++++++ 6 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/fb/gp104.c diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h index c6c3c1ec3ae1..3a410275fa71 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h @@ -94,6 +94,7 @@ int gk20a_fb_new(struct nvkm_device *, int, struct nvkm_fb **); int gm107_fb_new(struct nvkm_device *, int, struct nvkm_fb **); int gm200_fb_new(struct nvkm_device *, int, struct nvkm_fb **); int gp100_fb_new(struct nvkm_device *, int, struct nvkm_fb **); +int gp104_fb_new(struct nvkm_device *, int, struct nvkm_fb **); #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 0ae41e6f58f2..0b8f5d0ff547 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2186,6 +2186,7 @@ nv134_chipset = { .name = "GP104", .bios = nvkm_bios_new, .devinit = gm200_devinit_new, + .fb = gp104_fb_new, .imem = nv50_instmem_new, .mc = gp100_mc_new, .pci = gp100_pci_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/Kbuild index 1ca005d3ac62..edcc157e6ac8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/Kbuild @@ -25,6 +25,7 @@ nvkm-y += nvkm/subdev/fb/gk20a.o nvkm-y += nvkm/subdev/fb/gm107.o nvkm-y += nvkm/subdev/fb/gm200.o nvkm-y += nvkm/subdev/fb/gp100.o +nvkm-y += nvkm/subdev/fb/gp104.o nvkm-y += nvkm/subdev/fb/ram.o nvkm-y += nvkm/subdev/fb/ramnv04.o diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.h index 2160e5a39c9a..449f431644b3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.h @@ -14,4 +14,6 @@ int gf100_fb_new_(const struct nvkm_fb_func *, struct nvkm_device *, void *gf100_fb_dtor(struct nvkm_fb *); void gf100_fb_init(struct nvkm_fb *); void gf100_fb_intr(struct nvkm_fb *); + +void gp100_fb_init(struct nvkm_fb *); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gp100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gp100.c index 1620067168e6..98474aec1921 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gp100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gp100.c @@ -36,7 +36,7 @@ gp100_fb_init_unkn(struct nvkm_fb *base) nvkm_wr32(device, 0x1faccc, nvkm_rd32(device, 0x100ccc)); } -static void +void gp100_fb_init(struct nvkm_fb *base) { struct gf100_fb *fb = gf100_fb(base); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gp104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gp104.c new file mode 100644 index 000000000000..92cb71861bec --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gp104.c @@ -0,0 +1,43 @@ +/* + * Copyright 2016 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "gf100.h" +#include "ram.h" + +#include + +static const struct nvkm_fb_func +gp104_fb = { + .dtor = gf100_fb_dtor, + .oneinit = gf100_fb_oneinit, + .init = gp100_fb_init, + .init_page = gm200_fb_init_page, + .ram_new = gp100_ram_new, + .memtype_valid = gf100_fb_memtype_valid, +}; + +int +gp104_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) +{ + return gf100_fb_new_(&gp104_fb, device, index, pfb); +} From 6b7c941b8cb51bcad7780e66d71993dfee256fa6 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 83/97] drm/nouveau/mmu/gp104: initial support Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/device/base.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 0b8f5d0ff547..7c339dc7ad82 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2189,6 +2189,7 @@ nv134_chipset = { .fb = gp104_fb_new, .imem = nv50_instmem_new, .mc = gp100_mc_new, + .mmu = gf100_mmu_new, .pci = gp100_pci_new, .timer = gk20a_timer_new, .top = gk104_top_new, From 10d4c1c27f9abcf1954e8b7cb1cd621bbb906ec2 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 84/97] drm/nouveau/bar/gp104: initial support Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/device/base.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 7c339dc7ad82..134e1a7f1e38 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2184,6 +2184,7 @@ nv130_chipset = { static const struct nvkm_device_chip nv134_chipset = { .name = "GP104", + .bar = gf100_bar_new, .bios = nvkm_bios_new, .devinit = gm200_devinit_new, .fb = gp104_fb_new, From 42d7a65e69b78bed216c499afa3b3e3e509fecc8 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 85/97] drm/nouveau/bus/gp104: initial support Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/device/base.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 134e1a7f1e38..de8377746e68 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2186,6 +2186,7 @@ nv134_chipset = { .name = "GP104", .bar = gf100_bar_new, .bios = nvkm_bios_new, + .bus = gf100_bus_new, .devinit = gm200_devinit_new, .fb = gp104_fb_new, .imem = nv50_instmem_new, From 7d007dd745c2ce98ce1d4ac8870f64ab1b597950 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 86/97] drm/nouveau/fuse/gp104: initial support Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/device/base.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index de8377746e68..8c93feb54b70 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2189,6 +2189,7 @@ nv134_chipset = { .bus = gf100_bus_new, .devinit = gm200_devinit_new, .fb = gp104_fb_new, + .fuse = gm107_fuse_new, .imem = nv50_instmem_new, .mc = gp100_mc_new, .mmu = gf100_mmu_new, From 14ae020d37bf743277a2fcca6c5e79ef5660463e Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 87/97] drm/nouveau/gpio/gp104: initial support Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/device/base.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 8c93feb54b70..ddf334fea8bf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2190,6 +2190,7 @@ nv134_chipset = { .devinit = gm200_devinit_new, .fb = gp104_fb_new, .fuse = gm107_fuse_new, + .gpio = gk104_gpio_new, .imem = nv50_instmem_new, .mc = gp100_mc_new, .mmu = gf100_mmu_new, From 13a66d2f9d86fc002322767acc4a955f8bc40a71 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 88/97] drm/nouveau/i2c/gp104: initial support Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/device/base.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index ddf334fea8bf..53731dd298aa 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2191,6 +2191,7 @@ nv134_chipset = { .fb = gp104_fb_new, .fuse = gm107_fuse_new, .gpio = gk104_gpio_new, + .i2c = gm200_i2c_new, .imem = nv50_instmem_new, .mc = gp100_mc_new, .mmu = gf100_mmu_new, From 8c80bc6c3ccf308adb243f9c6526c29d0580af98 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 89/97] drm/nouveau/ibus/gp104: initial support Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/device/base.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 53731dd298aa..05030145fae4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2192,6 +2192,7 @@ nv134_chipset = { .fuse = gm107_fuse_new, .gpio = gk104_gpio_new, .i2c = gm200_i2c_new, + .ibus = gm200_ibus_new, .imem = nv50_instmem_new, .mc = gp100_mc_new, .mmu = gf100_mmu_new, From a8c15dda41b0b78b167473f1751c5be564f8068b Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 90/97] drm/nouveau/ltc/gp104: initial support Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/device/base.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 05030145fae4..1ceff46b5c6e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2194,6 +2194,7 @@ nv134_chipset = { .i2c = gm200_i2c_new, .ibus = gm200_ibus_new, .imem = nv50_instmem_new, + .ltc = gp100_ltc_new, .mc = gp100_mc_new, .mmu = gf100_mmu_new, .pci = gp100_pci_new, From 15cec92f4e188679cf9813947938f066bc2eee2d Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 91/97] drm/nouveau/dma/gp104: initial support Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/device/base.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 1ceff46b5c6e..75c66457a11c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2200,6 +2200,7 @@ nv134_chipset = { .pci = gp100_pci_new, .timer = gk20a_timer_new, .top = gk104_top_new, + .dma = gf119_dma_new, }; static int From fd47877f77c44f03723dc1d74433a50efdb28ba2 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 92/97] drm/nouveau/disp/gp104: initial support Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/class.h | 2 + .../drm/nouveau/include/nvkm/engine/disp.h | 1 + drivers/gpu/drm/nouveau/nouveau_display.c | 1 + drivers/gpu/drm/nouveau/nv50_display.c | 1 + .../gpu/drm/nouveau/nvkm/engine/device/base.c | 1 + .../gpu/drm/nouveau/nvkm/engine/disp/Kbuild | 6 ++ .../drm/nouveau/nvkm/engine/disp/basegp104.c | 38 +++++++++ .../drm/nouveau/nvkm/engine/disp/channv50.h | 1 + .../drm/nouveau/nvkm/engine/disp/coregf119.c | 2 +- .../drm/nouveau/nvkm/engine/disp/coregp104.c | 78 ++++++++++++++++++ .../drm/nouveau/nvkm/engine/disp/dmacgf119.c | 2 +- .../drm/nouveau/nvkm/engine/disp/dmacgp104.c | 66 +++++++++++++++ .../drm/nouveau/nvkm/engine/disp/dmacnv50.h | 8 ++ .../gpu/drm/nouveau/nvkm/engine/disp/gf119.c | 5 +- .../gpu/drm/nouveau/nvkm/engine/disp/gk104.c | 1 + .../gpu/drm/nouveau/nvkm/engine/disp/gk110.c | 1 + .../gpu/drm/nouveau/nvkm/engine/disp/gm107.c | 1 + .../gpu/drm/nouveau/nvkm/engine/disp/gm200.c | 1 + .../gpu/drm/nouveau/nvkm/engine/disp/gp100.c | 1 + .../gpu/drm/nouveau/nvkm/engine/disp/gp104.c | 81 +++++++++++++++++++ .../gpu/drm/nouveau/nvkm/engine/disp/nv50.h | 2 + .../drm/nouveau/nvkm/engine/disp/ovlygk104.c | 2 +- .../drm/nouveau/nvkm/engine/disp/ovlygp104.c | 38 +++++++++ .../drm/nouveau/nvkm/engine/disp/rootgp104.c | 58 +++++++++++++ .../drm/nouveau/nvkm/engine/disp/rootnv50.h | 1 + 25 files changed, 394 insertions(+), 5 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/basegp104.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/coregp104.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacgp104.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/gp104.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygp104.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgp104.c diff --git a/drivers/gpu/drm/nouveau/include/nvif/class.h b/drivers/gpu/drm/nouveau/include/nvif/class.h index ed71576eedac..37a184353dca 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/class.h +++ b/drivers/gpu/drm/nouveau/include/nvif/class.h @@ -52,6 +52,7 @@ #define GM107_DISP /* cl5070.h */ 0x00009470 #define GM200_DISP /* cl5070.h */ 0x00009570 #define GP100_DISP /* cl5070.h */ 0x00009770 +#define GP104_DISP /* cl5070.h */ 0x00009870 #define NV31_MPEG 0x00003174 #define G82_MPEG 0x00008274 @@ -89,6 +90,7 @@ #define GM107_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000947d #define GM200_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000957d #define GP100_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000977d +#define GP104_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000987d #define NV50_DISP_OVERLAY_CHANNEL_DMA /* cl507e.h */ 0x0000507e #define G82_DISP_OVERLAY_CHANNEL_DMA /* cl507e.h */ 0x0000827e diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h index c88c15000764..e82049667ce4 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h @@ -33,4 +33,5 @@ int gk110_disp_new(struct nvkm_device *, int, struct nvkm_disp **); int gm107_disp_new(struct nvkm_device *, int, struct nvkm_disp **); int gm200_disp_new(struct nvkm_device *, int, struct nvkm_disp **); int gp100_disp_new(struct nvkm_device *, int, struct nvkm_disp **); +int gp104_disp_new(struct nvkm_device *, int, struct nvkm_disp **); #endif diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 6caad22568a2..844bd9951456 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -495,6 +495,7 @@ nouveau_display_create(struct drm_device *dev) if (nouveau_modeset != 2 && drm->vbios.dcb.entries) { static const u16 oclass[] = { + GP104_DISP, GP100_DISP, GM200_DISP, GM107_DISP, diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index e871a554398c..7d0edcbcfca7 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -297,6 +297,7 @@ nv50_core_create(struct nvif_device *device, struct nvif_object *disp, .pushbuf = 0xb0007d00, }; static const s32 oclass[] = { + GP104_DISP_CORE_CHANNEL_DMA, GP100_DISP_CORE_CHANNEL_DMA, GM200_DISP_CORE_CHANNEL_DMA, GM107_DISP_CORE_CHANNEL_DMA, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 75c66457a11c..70d2a93991a3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2200,6 +2200,7 @@ nv134_chipset = { .pci = gp100_pci_new, .timer = gk20a_timer_new, .top = gk104_top_new, + .disp = gp104_disp_new, .dma = gf119_dma_new, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild index ee26089037ed..77a52b54a31e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild @@ -11,6 +11,7 @@ nvkm-y += nvkm/engine/disp/gk110.o nvkm-y += nvkm/engine/disp/gm107.o nvkm-y += nvkm/engine/disp/gm200.o nvkm-y += nvkm/engine/disp/gp100.o +nvkm-y += nvkm/engine/disp/gp104.o nvkm-y += nvkm/engine/disp/outp.o nvkm-y += nvkm/engine/disp/outpdp.o @@ -47,12 +48,14 @@ nvkm-y += nvkm/engine/disp/rootgk110.o nvkm-y += nvkm/engine/disp/rootgm107.o nvkm-y += nvkm/engine/disp/rootgm200.o nvkm-y += nvkm/engine/disp/rootgp100.o +nvkm-y += nvkm/engine/disp/rootgp104.o nvkm-y += nvkm/engine/disp/channv50.o nvkm-y += nvkm/engine/disp/changf119.o nvkm-y += nvkm/engine/disp/dmacnv50.o nvkm-y += nvkm/engine/disp/dmacgf119.o +nvkm-y += nvkm/engine/disp/dmacgp104.o nvkm-y += nvkm/engine/disp/basenv50.o nvkm-y += nvkm/engine/disp/baseg84.o @@ -61,6 +64,7 @@ nvkm-y += nvkm/engine/disp/basegt215.o nvkm-y += nvkm/engine/disp/basegf119.o nvkm-y += nvkm/engine/disp/basegk104.o nvkm-y += nvkm/engine/disp/basegk110.o +nvkm-y += nvkm/engine/disp/basegp104.o nvkm-y += nvkm/engine/disp/corenv50.o nvkm-y += nvkm/engine/disp/coreg84.o @@ -73,6 +77,7 @@ nvkm-y += nvkm/engine/disp/coregk110.o nvkm-y += nvkm/engine/disp/coregm107.o nvkm-y += nvkm/engine/disp/coregm200.o nvkm-y += nvkm/engine/disp/coregp100.o +nvkm-y += nvkm/engine/disp/coregp104.o nvkm-y += nvkm/engine/disp/ovlynv50.o nvkm-y += nvkm/engine/disp/ovlyg84.o @@ -80,6 +85,7 @@ nvkm-y += nvkm/engine/disp/ovlygt200.o nvkm-y += nvkm/engine/disp/ovlygt215.o nvkm-y += nvkm/engine/disp/ovlygf119.o nvkm-y += nvkm/engine/disp/ovlygk104.o +nvkm-y += nvkm/engine/disp/ovlygp104.o nvkm-y += nvkm/engine/disp/piocnv50.o nvkm-y += nvkm/engine/disp/piocgf119.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/basegp104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/basegp104.c new file mode 100644 index 000000000000..51688e37c54e --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/basegp104.c @@ -0,0 +1,38 @@ +/* + * Copyright 2016 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "dmacnv50.h" +#include "rootnv50.h" + +#include + +const struct nv50_disp_dmac_oclass +gp104_disp_base_oclass = { + .base.oclass = GK110_DISP_BASE_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_base_new, + .func = &gp104_disp_dmac_func, + .mthd = &gf119_disp_base_chan_mthd, + .chid = 1, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.h index aee374884c96..f5f683d9fd20 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.h @@ -85,6 +85,7 @@ extern const struct nv50_disp_mthd_list gf119_disp_core_mthd_pior; extern const struct nv50_disp_chan_mthd gf119_disp_base_chan_mthd; extern const struct nv50_disp_chan_mthd gk104_disp_core_chan_mthd; +extern const struct nv50_disp_chan_mthd gk104_disp_ovly_chan_mthd; struct nv50_disp_pioc_oclass { int (*ctor)(const struct nv50_disp_chan_func *, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregf119.c index 6b1dc703dac7..21fbf89b6319 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregf119.c @@ -171,7 +171,7 @@ gf119_disp_core_chan_mthd = { } }; -static void +void gf119_disp_core_fini(struct nv50_disp_dmac *chan) { struct nv50_disp *disp = chan->base.root->disp; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregp104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregp104.c new file mode 100644 index 000000000000..6922f4007b61 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregp104.c @@ -0,0 +1,78 @@ +/* + * Copyright 2016 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "dmacnv50.h" +#include "rootnv50.h" + +#include + +#include + +static int +gp104_disp_core_init(struct nv50_disp_dmac *chan) +{ + struct nv50_disp *disp = chan->base.root->disp; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; + + /* enable error reporting */ + nvkm_mask(device, 0x6100a0, 0x00000001, 0x00000001); + + /* initialise channel for dma command submission */ + nvkm_wr32(device, 0x611494, chan->push); + nvkm_wr32(device, 0x611498, 0x00010000); + nvkm_wr32(device, 0x61149c, 0x00000001); + nvkm_mask(device, 0x610490, 0x00000010, 0x00000010); + nvkm_wr32(device, 0x640000, 0x00000000); + nvkm_wr32(device, 0x610490, 0x01000013); + + /* wait for it to go inactive */ + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x610490) & 0x80000000)) + break; + ) < 0) { + nvkm_error(subdev, "core init: %08x\n", + nvkm_rd32(device, 0x610490)); + return -EBUSY; + } + + return 0; +} + +const struct nv50_disp_dmac_func +gp104_disp_core_func = { + .init = gp104_disp_core_init, + .fini = gf119_disp_core_fini, + .bind = gf119_disp_dmac_bind, +}; + +const struct nv50_disp_dmac_oclass +gp104_disp_core_oclass = { + .base.oclass = GP104_DISP_CORE_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_core_new, + .func = &gp104_disp_core_func, + .mthd = &gk104_disp_core_chan_mthd, + .chid = 0, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacgf119.c index 876b14549a58..a57f7cef307a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacgf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacgf119.c @@ -36,7 +36,7 @@ gf119_disp_dmac_bind(struct nv50_disp_dmac *chan, chan->base.chid << 27 | 0x00000001); } -static void +void gf119_disp_dmac_fini(struct nv50_disp_dmac *chan) { struct nv50_disp *disp = chan->base.root->disp; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacgp104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacgp104.c new file mode 100644 index 000000000000..ad24c2c57696 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacgp104.c @@ -0,0 +1,66 @@ +/* + * Copyright 2016 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "dmacnv50.h" +#include "rootnv50.h" + +#include + +static int +gp104_disp_dmac_init(struct nv50_disp_dmac *chan) +{ + struct nv50_disp *disp = chan->base.root->disp; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; + int chid = chan->base.chid; + + /* enable error reporting */ + nvkm_mask(device, 0x6100a0, 0x00000001 << chid, 0x00000001 << chid); + + /* initialise channel for dma command submission */ + nvkm_wr32(device, 0x611494 + (chid * 0x0010), chan->push); + nvkm_wr32(device, 0x611498 + (chid * 0x0010), 0x00010000); + nvkm_wr32(device, 0x61149c + (chid * 0x0010), 0x00000001); + nvkm_mask(device, 0x610490 + (chid * 0x0010), 0x00000010, 0x00000010); + nvkm_wr32(device, 0x640000 + (chid * 0x1000), 0x00000000); + nvkm_wr32(device, 0x610490 + (chid * 0x0010), 0x00000013); + + /* wait for it to go inactive */ + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x610490 + (chid * 0x10)) & 0x80000000)) + break; + ) < 0) { + nvkm_error(subdev, "ch %d init: %08x\n", chid, + nvkm_rd32(device, 0x610490 + (chid * 0x10))); + return -EBUSY; + } + + return 0; +} + +const struct nv50_disp_dmac_func +gp104_disp_dmac_func = { + .init = gp104_disp_dmac_init, + .fini = gf119_disp_dmac_fini, + .bind = gf119_disp_dmac_bind, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.h index c737583e393d..43ac05857853 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.h @@ -25,8 +25,12 @@ int nv50_disp_dmac_bind(struct nv50_disp_dmac *, struct nvkm_object *, u32); extern const struct nv50_disp_dmac_func nv50_disp_core_func; extern const struct nv50_disp_dmac_func gf119_disp_dmac_func; +void gf119_disp_dmac_fini(struct nv50_disp_dmac *); int gf119_disp_dmac_bind(struct nv50_disp_dmac *, struct nvkm_object *, u32); extern const struct nv50_disp_dmac_func gf119_disp_core_func; +void gf119_disp_core_fini(struct nv50_disp_dmac *); + +extern const struct nv50_disp_dmac_func gp104_disp_dmac_func; struct nv50_disp_dmac_oclass { int (*ctor)(const struct nv50_disp_dmac_func *, @@ -90,4 +94,8 @@ extern const struct nv50_disp_dmac_oclass gm107_disp_core_oclass; extern const struct nv50_disp_dmac_oclass gm200_disp_core_oclass; extern const struct nv50_disp_dmac_oclass gp100_disp_core_oclass; + +extern const struct nv50_disp_dmac_oclass gp104_disp_core_oclass; +extern const struct nv50_disp_dmac_oclass gp104_disp_base_oclass; +extern const struct nv50_disp_dmac_oclass gp104_disp_ovly_oclass; #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c index 605e4ea669a4..29e84b241cca 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c @@ -413,7 +413,7 @@ gf119_disp_intr_supervisor(struct work_struct *work) nvkm_wr32(device, 0x6101d0, 0x80000000); } -static void +void gf119_disp_intr_error(struct nv50_disp *disp, int chid) { struct nvkm_subdev *subdev = &disp->base.engine.subdev; @@ -461,7 +461,7 @@ gf119_disp_intr(struct nv50_disp *disp) u32 stat = nvkm_rd32(device, 0x61009c); int chid = ffs(stat) - 1; if (chid >= 0) - gf119_disp_intr_error(disp, chid); + disp->func->intr_error(disp, chid); intr &= ~0x00000002; } @@ -505,6 +505,7 @@ gf119_disp_new_(const struct nv50_disp_func *func, struct nvkm_device *device, static const struct nv50_disp_func gf119_disp = { .intr = gf119_disp_intr, + .intr_error = gf119_disp_intr_error, .uevent = &gf119_disp_chan_uevent, .super = gf119_disp_intr_supervisor, .root = &gf119_disp_root_oclass, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c index a86384b8e388..37f145cf30d7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c @@ -27,6 +27,7 @@ static const struct nv50_disp_func gk104_disp = { .intr = gf119_disp_intr, + .intr_error = gf119_disp_intr_error, .uevent = &gf119_disp_chan_uevent, .super = gf119_disp_intr_supervisor, .root = &gk104_disp_root_oclass, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c index 0d574c7e594a..e14ac946608c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c @@ -27,6 +27,7 @@ static const struct nv50_disp_func gk110_disp = { .intr = gf119_disp_intr, + .intr_error = gf119_disp_intr_error, .uevent = &gf119_disp_chan_uevent, .super = gf119_disp_intr_supervisor, .root = &gk110_disp_root_oclass, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c index f4b9cf8574be..2f2437cc5891 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c @@ -27,6 +27,7 @@ static const struct nv50_disp_func gm107_disp = { .intr = gf119_disp_intr, + .intr_error = gf119_disp_intr_error, .uevent = &gf119_disp_chan_uevent, .super = gf119_disp_intr_supervisor, .root = &gm107_disp_root_oclass, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c index 67eec8620719..9f368d4ee61e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c @@ -27,6 +27,7 @@ static const struct nv50_disp_func gm200_disp = { .intr = gf119_disp_intr, + .intr_error = gf119_disp_intr_error, .uevent = &gf119_disp_chan_uevent, .super = gf119_disp_intr_supervisor, .root = &gm200_disp_root_oclass, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c index a252d80ed946..4f81bf31435e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c @@ -27,6 +27,7 @@ static const struct nv50_disp_func gp100_disp = { .intr = gf119_disp_intr, + .intr_error = gf119_disp_intr_error, .uevent = &gf119_disp_chan_uevent, .super = gf119_disp_intr_supervisor, .root = &gp100_disp_root_oclass, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp104.c new file mode 100644 index 000000000000..3bf3380336e4 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp104.c @@ -0,0 +1,81 @@ +/* + * Copyright 2016 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "nv50.h" +#include "rootnv50.h" + +static void +gp104_disp_intr_error(struct nv50_disp *disp, int chid) +{ + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; + u32 mthd = nvkm_rd32(device, 0x6111f0 + (chid * 12)); + u32 data = nvkm_rd32(device, 0x6111f4 + (chid * 12)); + u32 unkn = nvkm_rd32(device, 0x6111f8 + (chid * 12)); + + nvkm_error(subdev, "chid %d mthd %04x data %08x %08x %08x\n", + chid, (mthd & 0x0000ffc), data, mthd, unkn); + + if (chid < ARRAY_SIZE(disp->chan)) { + switch (mthd & 0xffc) { + case 0x0080: + nv50_disp_chan_mthd(disp->chan[chid], NV_DBG_ERROR); + break; + default: + break; + } + } + + nvkm_wr32(device, 0x61009c, (1 << chid)); + nvkm_wr32(device, 0x6111f0 + (chid * 12), 0x90000000); +} + +static const struct nv50_disp_func +gp104_disp = { + .intr = gf119_disp_intr, + .intr_error = gp104_disp_intr_error, + .uevent = &gf119_disp_chan_uevent, + .super = gf119_disp_intr_supervisor, + .root = &gp104_disp_root_oclass, + .head.vblank_init = gf119_disp_vblank_init, + .head.vblank_fini = gf119_disp_vblank_fini, + .head.scanoutpos = gf119_disp_root_scanoutpos, + .outp.internal.crt = nv50_dac_output_new, + .outp.internal.tmds = nv50_sor_output_new, + .outp.internal.lvds = nv50_sor_output_new, + .outp.internal.dp = gm200_sor_dp_new, + .dac.nr = 3, + .dac.power = nv50_dac_power, + .dac.sense = nv50_dac_sense, + .sor.nr = 4, + .sor.power = nv50_sor_power, + .sor.hda_eld = gf119_hda_eld, + .sor.hdmi = gk104_hdmi_ctrl, + .sor.magic = gm200_sor_magic, +}; + +int +gp104_disp_new(struct nvkm_device *device, int index, struct nvkm_disp **pdisp) +{ + return gf119_disp_new_(&gp104_disp, device, index, pdisp); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h index aecebd8717e5..1e1de6bfe85a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h @@ -68,6 +68,7 @@ struct nv50_disp_func_outp { struct nv50_disp_func { void (*intr)(struct nv50_disp *); + void (*intr_error)(struct nv50_disp *, int chid); const struct nvkm_event_func *uevent; void (*super)(struct work_struct *); @@ -114,4 +115,5 @@ void gf119_disp_vblank_init(struct nv50_disp *, int); void gf119_disp_vblank_fini(struct nv50_disp *, int); void gf119_disp_intr(struct nv50_disp *); void gf119_disp_intr_supervisor(struct work_struct *); +void gf119_disp_intr_error(struct nv50_disp *, int); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygk104.c index 2e2dc0641ef2..2f0220b39f34 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygk104.c @@ -80,7 +80,7 @@ gk104_disp_ovly_mthd_base = { } }; -static const struct nv50_disp_chan_mthd +const struct nv50_disp_chan_mthd gk104_disp_ovly_chan_mthd = { .name = "Overlay", .addr = 0x001000, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygp104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygp104.c new file mode 100644 index 000000000000..97e2dd2d908e --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygp104.c @@ -0,0 +1,38 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "dmacnv50.h" +#include "rootnv50.h" + +#include + +const struct nv50_disp_dmac_oclass +gp104_disp_ovly_oclass = { + .base.oclass = GK104_DISP_OVERLAY_CONTROL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_ovly_new, + .func = &gp104_disp_dmac_func, + .mthd = &gk104_disp_ovly_chan_mthd, + .chid = 5, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgp104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgp104.c new file mode 100644 index 000000000000..8443e04dc626 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgp104.c @@ -0,0 +1,58 @@ +/* + * Copyright 2016 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "rootnv50.h" +#include "dmacnv50.h" + +#include + +static const struct nv50_disp_root_func +gp104_disp_root = { + .init = gf119_disp_root_init, + .fini = gf119_disp_root_fini, + .dmac = { + &gp104_disp_core_oclass, + &gp104_disp_base_oclass, + &gp104_disp_ovly_oclass, + }, + .pioc = { + &gk104_disp_oimm_oclass, + &gk104_disp_curs_oclass, + }, +}; + +static int +gp104_disp_root_new(struct nvkm_disp *disp, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + return nv50_disp_root_new_(&gp104_disp_root, disp, oclass, + data, size, pobject); +} + +const struct nvkm_disp_oclass +gp104_disp_root_oclass = { + .base.oclass = GP104_DISP, + .base.minver = -1, + .base.maxver = -1, + .ctor = gp104_disp_root_new, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.h index c1d8b21ae167..ad00f1724b72 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.h @@ -41,4 +41,5 @@ extern const struct nvkm_disp_oclass gk110_disp_root_oclass; extern const struct nvkm_disp_oclass gm107_disp_root_oclass; extern const struct nvkm_disp_oclass gm200_disp_root_oclass; extern const struct nvkm_disp_oclass gp100_disp_root_oclass; +extern const struct nvkm_disp_oclass gp104_disp_root_oclass; #endif From ba3b712e8d52cf631cae36537e29ce5ae7c50016 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 93/97] drm/nouveau/fifo/gp104: initial support Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/device/base.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 70d2a93991a3..e3841a4b6946 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2202,6 +2202,7 @@ nv134_chipset = { .top = gk104_top_new, .disp = gp104_disp_new, .dma = gf119_dma_new, + .fifo = gp100_fifo_new, }; static int From 146cfe2476ce378580e81143182e60d6ecc380ca Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 9 Jul 2016 10:41:01 +1000 Subject: [PATCH 94/97] drm/nouveau/ce/gp104: initial support Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/class.h | 1 + .../gpu/drm/nouveau/include/nvkm/engine/ce.h | 1 + drivers/gpu/drm/nouveau/nouveau_bo.c | 2 + drivers/gpu/drm/nouveau/nvkm/engine/ce/Kbuild | 1 + .../gpu/drm/nouveau/nvkm/engine/ce/gp104.c | 44 +++++++++++++++++++ drivers/gpu/drm/nouveau/nvkm/engine/ce/priv.h | 1 + .../gpu/drm/nouveau/nvkm/engine/device/base.c | 4 ++ 7 files changed, 54 insertions(+) create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/ce/gp104.c diff --git a/drivers/gpu/drm/nouveau/include/nvif/class.h b/drivers/gpu/drm/nouveau/include/nvif/class.h index 37a184353dca..e6e9537537cf 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/class.h +++ b/drivers/gpu/drm/nouveau/include/nvif/class.h @@ -136,6 +136,7 @@ #define KEPLER_DMA_COPY_A 0x0000a0b5 #define MAXWELL_DMA_COPY_A 0x0000b0b5 #define PASCAL_DMA_COPY_A 0x0000c0b5 +#define PASCAL_DMA_COPY_B 0x0000c1b5 #define FERMI_DECOMPRESS 0x000090b8 diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/ce.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/ce.h index 45588742fd91..d3d26a1e215d 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/ce.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/ce.h @@ -8,4 +8,5 @@ int gk104_ce_new(struct nvkm_device *, int, struct nvkm_engine **); int gm107_ce_new(struct nvkm_device *, int, struct nvkm_engine **); int gm200_ce_new(struct nvkm_device *, int, struct nvkm_engine **); int gp100_ce_new(struct nvkm_device *, int, struct nvkm_engine **); +int gp104_ce_new(struct nvkm_device *, int, struct nvkm_engine **); #endif diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 6423c7be9c7f..d836c44b6cf0 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -1104,6 +1104,8 @@ nouveau_bo_move_init(struct nouveau_drm *drm) struct ttm_mem_reg *, struct ttm_mem_reg *); int (*init)(struct nouveau_channel *, u32 handle); } _methods[] = { + { "COPY", 4, 0xc1b5, nve0_bo_move_copy, nve0_bo_move_init }, + { "GRCE", 0, 0xc1b5, nve0_bo_move_copy, nvc0_bo_move_init }, { "COPY", 4, 0xc0b5, nve0_bo_move_copy, nve0_bo_move_init }, { "GRCE", 0, 0xc0b5, nve0_bo_move_copy, nvc0_bo_move_init }, { "COPY", 4, 0xb0b5, nve0_bo_move_copy, nve0_bo_move_init }, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/ce/Kbuild index 7d55197e8296..a4458a8eb30a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/Kbuild @@ -4,3 +4,4 @@ nvkm-y += nvkm/engine/ce/gk104.o nvkm-y += nvkm/engine/ce/gm107.o nvkm-y += nvkm/engine/ce/gm200.o nvkm-y += nvkm/engine/ce/gp100.o +nvkm-y += nvkm/engine/ce/gp104.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gp104.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gp104.c new file mode 100644 index 000000000000..20e019788a53 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gp104.c @@ -0,0 +1,44 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "priv.h" +#include + +#include + +static const struct nvkm_engine_func +gp104_ce = { + .intr = gp100_ce_intr, + .sclass = { + { -1, -1, PASCAL_DMA_COPY_B }, + { -1, -1, PASCAL_DMA_COPY_A }, + {} + } +}; + +int +gp104_ce_new(struct nvkm_device *device, int index, + struct nvkm_engine **pengine) +{ + return nvkm_engine_new_(&gp104_ce, device, index, true, pengine); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/ce/priv.h index e2fa8b161943..2dce405976ad 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/priv.h @@ -4,4 +4,5 @@ void gt215_ce_intr(struct nvkm_falcon *, struct nvkm_fifo_chan *); void gk104_ce_intr(struct nvkm_engine *); +void gp100_ce_intr(struct nvkm_engine *); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index e3841a4b6946..7218a067a6c5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2200,6 +2200,10 @@ nv134_chipset = { .pci = gp100_pci_new, .timer = gk20a_timer_new, .top = gk104_top_new, + .ce[0] = gp104_ce_new, + .ce[1] = gp104_ce_new, + .ce[2] = gp104_ce_new, + .ce[3] = gp104_ce_new, .disp = gp104_disp_new, .dma = gf119_dma_new, .fifo = gp100_fifo_new, From 0e67bed2c765ff0fdaec62c963881f5416fe3692 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 12 Jul 2016 11:57:07 +1000 Subject: [PATCH 95/97] drm/nouveau: check for supported chipset before booting fbdev off the hw Signed-off-by: Ben Skeggs Cc: stable@vger.kernel.org --- drivers/gpu/drm/nouveau/nouveau_drm.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 05915c10d07e..6dd396f56884 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -317,7 +317,16 @@ static int nouveau_drm_probe(struct pci_dev *pdev, if (vga_switcheroo_client_probe_defer(pdev)) return -EPROBE_DEFER; - /* remove conflicting drivers (vesafb, efifb etc) */ + /* We need to check that the chipset is supported before booting + * fbdev off the hardware, as there's no way to put it back. + */ + ret = nvkm_device_pci_new(pdev, NULL, "error", true, false, 0, &device); + if (ret) + return ret; + + nvkm_device_del(&device); + + /* Remove conflicting drivers (vesafb, efifb etc). */ aper = alloc_apertures(3); if (!aper) return -ENOMEM; From 36a471baa851359b3ca5a96e752c7c1a6266aef0 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Wed, 13 Jul 2016 15:29:35 +0900 Subject: [PATCH 96/97] drm/nouveau/ttm: remove special handling of coherent objects TTM-allocated coherent objects were populated using the DMA API and accessed using the mapping it returned to workaround coherency issues. These issues seem to have been solved, thus remove this extra case to handle and use the regular kernel mapping functions. Signed-off-by: Alexandre Courbot Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bo.c | 61 +++------------------------- 1 file changed, 5 insertions(+), 56 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index d836c44b6cf0..711592798fe8 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -424,13 +424,7 @@ nouveau_bo_map(struct nouveau_bo *nvbo) if (ret) return ret; - /* - * TTM buffers allocated using the DMA API already have a mapping, let's - * use it instead. - */ - if (!nvbo->force_coherent) - ret = ttm_bo_kmap(&nvbo->bo, 0, nvbo->bo.mem.num_pages, - &nvbo->kmap); + ret = ttm_bo_kmap(&nvbo->bo, 0, nvbo->bo.mem.num_pages, &nvbo->kmap); ttm_bo_unreserve(&nvbo->bo); return ret; @@ -442,12 +436,7 @@ nouveau_bo_unmap(struct nouveau_bo *nvbo) if (!nvbo) return; - /* - * TTM buffers allocated using the DMA API already had a coherent - * mapping which we used, no need to unmap. - */ - if (!nvbo->force_coherent) - ttm_bo_kunmap(&nvbo->kmap); + ttm_bo_kunmap(&nvbo->kmap); } void @@ -506,35 +495,13 @@ nouveau_bo_validate(struct nouveau_bo *nvbo, bool interruptible, return 0; } -static inline void * -_nouveau_bo_mem_index(struct nouveau_bo *nvbo, unsigned index, void *mem, u8 sz) -{ - struct ttm_dma_tt *dma_tt; - u8 *m = mem; - - index *= sz; - - if (m) { - /* kmap'd address, return the corresponding offset */ - m += index; - } else { - /* DMA-API mapping, lookup the right address */ - dma_tt = (struct ttm_dma_tt *)nvbo->bo.ttm; - m = dma_tt->cpu_address[index / PAGE_SIZE]; - m += index % PAGE_SIZE; - } - - return m; -} -#define nouveau_bo_mem_index(o, i, m) _nouveau_bo_mem_index(o, i, m, sizeof(*m)) - void nouveau_bo_wr16(struct nouveau_bo *nvbo, unsigned index, u16 val) { bool is_iomem; u16 *mem = ttm_kmap_obj_virtual(&nvbo->kmap, &is_iomem); - mem = nouveau_bo_mem_index(nvbo, index, mem); + mem += index; if (is_iomem) iowrite16_native(val, (void __force __iomem *)mem); @@ -548,7 +515,7 @@ nouveau_bo_rd32(struct nouveau_bo *nvbo, unsigned index) bool is_iomem; u32 *mem = ttm_kmap_obj_virtual(&nvbo->kmap, &is_iomem); - mem = nouveau_bo_mem_index(nvbo, index, mem); + mem += index; if (is_iomem) return ioread32_native((void __force __iomem *)mem); @@ -562,7 +529,7 @@ nouveau_bo_wr32(struct nouveau_bo *nvbo, unsigned index, u32 val) bool is_iomem; u32 *mem = ttm_kmap_obj_virtual(&nvbo->kmap, &is_iomem); - mem = nouveau_bo_mem_index(nvbo, index, mem); + mem += index; if (is_iomem) iowrite32_native(val, (void __force __iomem *)mem); @@ -1492,14 +1459,6 @@ nouveau_ttm_tt_populate(struct ttm_tt *ttm) dev = drm->dev; pdev = device->dev; - /* - * Objects matching this condition have been marked as force_coherent, - * so use the DMA API for them. - */ - if (!nvxx_device(&drm->device)->func->cpu_coherent && - ttm->caching_state == tt_uncached) - return ttm_dma_populate(ttm_dma, dev->dev); - #if IS_ENABLED(CONFIG_AGP) if (drm->agp.bridge) { return ttm_agp_tt_populate(ttm); @@ -1557,16 +1516,6 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm) dev = drm->dev; pdev = device->dev; - /* - * Objects matching this condition have been marked as force_coherent, - * so use the DMA API for them. - */ - if (!nvxx_device(&drm->device)->func->cpu_coherent && - ttm->caching_state == tt_uncached) { - ttm_dma_unpopulate(ttm_dma, dev->dev); - return; - } - #if IS_ENABLED(CONFIG_AGP) if (drm->agp.bridge) { ttm_agp_tt_unpopulate(ttm); From aff51175cdbf345740ec9203eff88e772af88059 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Wed, 13 Jul 2016 15:29:36 +0900 Subject: [PATCH 97/97] drm/nouveau/bus: remove cpu_coherent flag This flag's only remaining function is to ignore the uncached flag for BOs on coherent architectures. However the reason for allocating an object uncache on a non-coherent architecture (namely because the cost of doing explicit flushes/ invalidations is higher than the benefit of caching the data because accesses are few and far between) should also apply on architectures for which coherency is maintained implicitly. Thus allocate coherent objects as uncached on all architectures. Signed-off-by: Alexandre Courbot Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvkm/core/device.h | 1 - drivers/gpu/drm/nouveau/nouveau_bo.c | 3 +-- drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c | 1 - drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c | 1 - 4 files changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h index 6bc712f32c8b..7ea8aa7ca408 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h @@ -175,7 +175,6 @@ struct nvkm_device_func { void (*fini)(struct nvkm_device *, bool suspend); resource_size_t (*resource_addr)(struct nvkm_device *, unsigned bar); resource_size_t (*resource_size)(struct nvkm_device *, unsigned bar); - bool cpu_coherent; }; struct nvkm_device_quirk { diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 711592798fe8..fbb6036235fe 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -209,8 +209,7 @@ nouveau_bo_new(struct drm_device *dev, int size, int align, nvbo->tile_flags = tile_flags; nvbo->bo.bdev = &drm->ttm.bdev; - if (!nvxx_device(&drm->device)->func->cpu_coherent) - nvbo->force_coherent = flags & TTM_PL_FLAG_UNCACHED; + nvbo->force_coherent = flags & TTM_PL_FLAG_UNCACHED; nvbo->page_shift = 12; if (drm->client.vm) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c index 62ad0300cfa5..b1b693219db3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c @@ -1614,7 +1614,6 @@ nvkm_device_pci_func = { .fini = nvkm_device_pci_fini, .resource_addr = nvkm_device_pci_resource_addr, .resource_size = nvkm_device_pci_resource_size, - .cpu_coherent = !IS_ENABLED(CONFIG_ARM), }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c index 9b638bd905ff..939682f18788 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c @@ -245,7 +245,6 @@ nvkm_device_tegra_func = { .fini = nvkm_device_tegra_fini, .resource_addr = nvkm_device_tegra_resource_addr, .resource_size = nvkm_device_tegra_resource_size, - .cpu_coherent = false, }; int