From 5dc7f4aa9d84ea94b54a9bfcef095f0289f1ebda Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 14 Oct 2016 13:16:36 +1000 Subject: drm/nouveau/bios: require checksum to match for fast acpi shadow method Signed-off-by: Ben Skeggs Cc: stable@vger.kernel.org --- drivers/gpu/drm/nouveau/nvkm/subdev/bios/priv.h | 1 + drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c | 7 +++++-- drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowacpi.c | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/priv.h index 212800e..7d1d3c6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/priv.h @@ -12,6 +12,7 @@ struct nvbios_source { bool rw; bool ignore_checksum; bool no_pcir; + bool require_checksum; }; int nvbios_extend(struct nvkm_bios *, u32 length); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c index b2557e8..7deb81b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c @@ -86,9 +86,12 @@ shadow_image(struct nvkm_bios *bios, int idx, u32 offset, struct shadow *mthd) nvbios_checksum(&bios->data[image.base], image.size)) { nvkm_debug(subdev, "%08x: checksum failed\n", image.base); - if (mthd->func->rw) + if (!mthd->func->require_checksum) { + if (mthd->func->rw) + score += 1; score += 1; - score += 1; + } else + return 0; } else { score += 3; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowacpi.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowacpi.c index 8fecb5f..06572f8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowacpi.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowacpi.c @@ -99,6 +99,7 @@ nvbios_acpi_fast = { .init = acpi_init, .read = acpi_read_fast, .rw = false, + .require_checksum = true, }; const struct nvbios_source -- cgit v1.1 From 4d98773081ec3e7dcbc1e9f18a3add8c9e6220f6 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 19 Oct 2016 12:14:24 +1000 Subject: drm/nouveau/mxm: add some extra debug output Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c index 21b65ee..e3e2f5e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c @@ -250,6 +250,10 @@ nvkm_mxm_new_(struct nvkm_device *device, int index, struct nvkm_mxm **pmxm) } nvkm_info(&mxm->subdev, "BIOS version %d.%d\n", ver >> 4, ver & 0x0f); + nvkm_debug(&mxm->subdev, "module flags: %02x\n", + nvbios_rd08(bios, data + 0x01)); + nvkm_debug(&mxm->subdev, "config flags: %02x\n", + nvbios_rd08(bios, data + 0x02)); if (mxm_shadow(mxm, ver)) { nvkm_warn(&mxm->subdev, "failed to locate valid SIS\n"); -- cgit v1.1 From 768e847759d551c96e129e194588dbfb11a1d576 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 19 Oct 2016 12:15:52 +1000 Subject: drm/nouveau/kms: lvds panel strap moved again on maxwell Signed-off-by: Ben Skeggs Cc: stable@vger.kernel.org --- drivers/gpu/drm/nouveau/nouveau_bios.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index a1570b1..23ffe85 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -333,6 +333,9 @@ get_fp_strap(struct drm_device *dev, struct nvbios *bios) if (bios->major_version < 5 && bios->data[0x48] & 0x4) return NVReadVgaCrtc5758(dev, 0, 0xf) & 0xf; + if (drm->device.info.family >= NV_DEVICE_INFO_V0_MAXWELL) + return nvif_rd32(device, 0x001800) & 0x0000000f; + else if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) return (nvif_rd32(device, NV_PEXTDEV_BOOT_0) >> 24) & 0xf; else -- cgit v1.1 From f1963a47c0a986b6d13e11136a2a6f873786c5f2 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 3 Nov 2016 16:37:33 +1000 Subject: drm/nouveau/i2c/aux/g94-: retry transactions after hw reports an error This fixes (works around?) link training failures seen on (at least) the Lenovo P50's internal panel. It's also an important fix on the same system for MST support on the dock. Sometimes, right after receiving an IRQ from the sink, there's an error bit (SINKSTAT_ERR) set in the DPAUX registers before we've even attempted a transaction. v2. Fixed regression on passive DP->DVI adapters. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxg94.c | 10 +++++----- drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxgm200.c | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxg94.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxg94.c index 954f5b7..b80236a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxg94.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxg94.c @@ -79,7 +79,7 @@ g94_i2c_aux_xfer(struct nvkm_i2c_aux *obj, bool retry, struct g94_i2c_aux *aux = g94_i2c_aux(obj); struct nvkm_device *device = aux->base.pad->i2c->subdev.device; const u32 base = aux->ch * 0x50; - u32 ctrl, stat, timeout, retries; + u32 ctrl, stat, timeout, retries = 0; u32 xbuf[4] = {}; int ret, i; @@ -111,7 +111,7 @@ g94_i2c_aux_xfer(struct nvkm_i2c_aux *obj, bool retry, nvkm_wr32(device, 0x00e4e0 + base, addr); /* (maybe) retry transaction a number of times on failure... */ - for (retries = 0; !ret && retries < 32; retries++) { + do { /* reset, and delay a while if this is a retry */ nvkm_wr32(device, 0x00e4e4 + base, 0x80000000 | ctrl); nvkm_wr32(device, 0x00e4e4 + base, 0x00000000 | ctrl); @@ -131,20 +131,20 @@ g94_i2c_aux_xfer(struct nvkm_i2c_aux *obj, bool retry, goto out; } } while (ctrl & 0x00010000); - ret = 1; + ret = 0; /* read status, and check if transaction completed ok */ stat = nvkm_mask(device, 0x00e4e8 + base, 0, 0); if ((stat & 0x000f0000) == 0x00080000 || (stat & 0x000f0000) == 0x00020000) - ret = retry ? 0 : 1; + ret = 1; if ((stat & 0x00000100)) ret = -ETIMEDOUT; if ((stat & 0x00000e00)) ret = -EIO; AUX_TRACE(&aux->base, "%02d %08x %08x", retries, ctrl, stat); - } + } while (ret && retry && retries++ < 32); if (type & 1) { for (i = 0; i < 16; i += 4) { diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxgm200.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxgm200.c index 61d729b..ed458c7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxgm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxgm200.c @@ -79,7 +79,7 @@ gm200_i2c_aux_xfer(struct nvkm_i2c_aux *obj, bool retry, struct gm200_i2c_aux *aux = gm200_i2c_aux(obj); struct nvkm_device *device = aux->base.pad->i2c->subdev.device; const u32 base = aux->ch * 0x50; - u32 ctrl, stat, timeout, retries; + u32 ctrl, stat, timeout, retries = 0; u32 xbuf[4] = {}; int ret, i; @@ -111,7 +111,7 @@ gm200_i2c_aux_xfer(struct nvkm_i2c_aux *obj, bool retry, nvkm_wr32(device, 0x00d950 + base, addr); /* (maybe) retry transaction a number of times on failure... */ - for (retries = 0; !ret && retries < 32; retries++) { + do { /* reset, and delay a while if this is a retry */ nvkm_wr32(device, 0x00d954 + base, 0x80000000 | ctrl); nvkm_wr32(device, 0x00d954 + base, 0x00000000 | ctrl); @@ -131,20 +131,20 @@ gm200_i2c_aux_xfer(struct nvkm_i2c_aux *obj, bool retry, goto out; } } while (ctrl & 0x00010000); - ret = 1; + ret = 0; /* read status, and check if transaction completed ok */ stat = nvkm_mask(device, 0x00d958 + base, 0, 0); if ((stat & 0x000f0000) == 0x00080000 || (stat & 0x000f0000) == 0x00020000) - ret = retry ? 0 : 1; + ret = 1; if ((stat & 0x00000100)) ret = -ETIMEDOUT; if ((stat & 0x00000e00)) ret = -EIO; AUX_TRACE(&aux->base, "%02d %08x %08x", retries, ctrl, stat); - } + } while (ret && retry && retries++ < 32); if (type & 1) { for (i = 0; i < 16; i += 4) { -- cgit v1.1 From 5b3800a6b763874e4a23702fb9628d3bd3315ce9 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 3 Nov 2016 16:37:33 +1000 Subject: drm/nouveau/i2c/gk110b,gm10x: use the correct implementation DPAUX registers moved on Kepler, these chipsets were still using the Fermi implementation for some reason. This fixes detection of hotplug/sink IRQs on DP connectors. Signed-off-by: Ben Skeggs Cc: stable@vger.kernel.org --- drivers/gpu/drm/nouveau/nvkm/engine/device/base.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 53d1717..22f5b93 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -1852,7 +1852,7 @@ nvf1_chipset = { .fb = gk104_fb_new, .fuse = gf100_fuse_new, .gpio = gk104_gpio_new, - .i2c = gf119_i2c_new, + .i2c = gk104_i2c_new, .ibus = gk104_ibus_new, .iccsense = gf100_iccsense_new, .imem = nv50_instmem_new, @@ -1966,7 +1966,7 @@ nv117_chipset = { .fb = gm107_fb_new, .fuse = gm107_fuse_new, .gpio = gk104_gpio_new, - .i2c = gf119_i2c_new, + .i2c = gk104_i2c_new, .ibus = gk104_ibus_new, .iccsense = gf100_iccsense_new, .imem = nv50_instmem_new, @@ -2000,7 +2000,7 @@ nv118_chipset = { .fb = gm107_fb_new, .fuse = gm107_fuse_new, .gpio = gk104_gpio_new, - .i2c = gf119_i2c_new, + .i2c = gk104_i2c_new, .ibus = gk104_ibus_new, .iccsense = gf100_iccsense_new, .imem = nv50_instmem_new, -- cgit v1.1 From e8390eb260d54404cc401d59a8d142297ee3220b Mon Sep 17 00:00:00 2001 From: Baoyou Xie Date: Mon, 24 Oct 2016 11:09:02 +0800 Subject: drm/nouveau: add missing header dependencies We get a few warnings when building kernel with W=1: drivers/gpu/drm/nouveau/nvkm/core/firmware.c:34:1: warning: no previous prototype for 'nvkm_firmware_get' [-Wmissing-prototypes] drivers/gpu/drm/nouveau/nvkm/core/firmware.c:58:1: warning: no previous prototype for 'nvkm_firmware_put' [-Wmissing-prototypes] drivers/gpu/drm/nouveau/nvkm/subdev/fb/sddr3.c:69:1: warning: no previous prototype for 'nvkm_sddr3_calc' [-Wmissing-prototypes] drivers/gpu/drm/nouveau/nvkm/subdev/fb/sddr2.c:60:1: warning: no previous prototype for 'nvkm_sddr2_calc' [-Wmissing-prototypes] .... In fact, these functions are declared in drivers/gpu/drm/nouveau/include/nvkm/core/firmware.h drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.h drivers/gpu/drm/nouveau/nvkm/subdev/volt/priv.h drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.h drivers/gpu/drm/nouveau/dispnv04/disp.h. So this patch adds missing header dependencies. Signed-off-by: Baoyou Xie Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/dispnv04/overlay.c | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv50.c | 1 + drivers/gpu/drm/nouveau/nvkm/subdev/fb/sddr2.c | 1 + drivers/gpu/drm/nouveau/nvkm/subdev/fb/sddr3.c | 1 + drivers/gpu/drm/nouveau/nvkm/subdev/volt/gpio.c | 1 + 5 files changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/dispnv04/overlay.c b/drivers/gpu/drm/nouveau/dispnv04/overlay.c index ec444ea..a79514d 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/overlay.c +++ b/drivers/gpu/drm/nouveau/dispnv04/overlay.c @@ -33,7 +33,7 @@ #include "nouveau_connector.h" #include "nouveau_display.h" #include "nvreg.h" - +#include "disp.h" struct nouveau_plane { struct drm_plane base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv50.c index 1e13278..c8bb919 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv50.c @@ -106,6 +106,7 @@ #define CP_SEEK_2 0x00c800ff #include "ctxnv40.h" +#include "nv50.h" #include diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/sddr2.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/sddr2.c index b9f1ffd..4dcd874 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/sddr2.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/sddr2.c @@ -23,6 +23,7 @@ * Ben Skeggs */ #include "priv.h" +#include "ram.h" struct ramxlat { int id; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/sddr3.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/sddr3.c index 2690033..eca8a44 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/sddr3.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/sddr3.c @@ -23,6 +23,7 @@ * Roy Spliet */ #include "priv.h" +#include "ram.h" struct ramxlat { int id; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gpio.c b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gpio.c index d2bac1d..443c031 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gpio.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gpio.c @@ -25,6 +25,7 @@ #include #include #include +#include "priv.h" static const u8 tags[] = { DCB_GPIO_VID0, DCB_GPIO_VID1, DCB_GPIO_VID2, DCB_GPIO_VID3, -- cgit v1.1 From e08a1d97d33e2ac05cd368b955f9fdc2823f15fd Mon Sep 17 00:00:00 2001 From: Baoyou Xie Date: Mon, 24 Oct 2016 11:09:03 +0800 Subject: drm/nouveau: mark symbols static where possible We get a few warnings when building kernel with W=1: drivers/gpu/drm/nouveau/nvkm/subdev/bios/fan.c:29:1: warning: no previous prototype for 'nvbios_fan_table' [-Wmissing-prototypes] drivers/gpu/drm/nouveau/nvkm/subdev/bios/fan.c:56:1: warning: no previous prototype for 'nvbios_fan_entry' [-Wmissing-prototypes] drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c:184:1: warning: no previous prototype for 'gt215_clk_info' [-Wmissing-prototypes] drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c:99:1: warning: no previous prototype for 'gt215_link_train_calc' [-Wmissing-prototypes] drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c:153:1: warning: no previous prototype for 'gt215_link_train' [-Wmissing-prototypes] drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c:271:1: warning: no previous prototype for 'gt215_link_train_init' [-Wmissing-prototypes] .... In fact, both functions are only used in the file in which they are declared and don't need a declaration, but can be made static. So this patch marks these functions with 'static'. Signed-off-by: Baoyou Xie Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_display.c | 2 +- drivers/gpu/drm/nouveau/nv10_fence.c | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/device/user.c | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c | 8 ++++---- drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/fifo/chang84.c | 4 ++-- drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c | 4 ++-- drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c | 4 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/bios/fan.c | 4 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c | 8 ++++---- drivers/gpu/drm/nouveau/nvkm/subdev/gpio/gk104.c | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm200.c | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk104.c | 4 ++-- 17 files changed, 28 insertions(+), 28 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index afbf557..b60ee21 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -92,7 +92,7 @@ calc(int blanks, int blanke, int total, int line) return line; } -int +static int nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos, ktime_t *stime, ktime_t *etime) { diff --git a/drivers/gpu/drm/nouveau/nv10_fence.c b/drivers/gpu/drm/nouveau/nv10_fence.c index f99fcf5..bcf3a21 100644 --- a/drivers/gpu/drm/nouveau/nv10_fence.c +++ b/drivers/gpu/drm/nouveau/nv10_fence.c @@ -66,7 +66,7 @@ nv10_fence_context_del(struct nouveau_channel *chan) nouveau_fence_context_free(&fctx->base); } -int +static int nv10_fence_context_new(struct nouveau_channel *chan) { struct nv10_fence_chan *fctx; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c index 79a8f71..513ee6b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c @@ -326,7 +326,7 @@ nvkm_udevice = { .sclass = nvkm_udevice_child_get, }; -int +static int nvkm_udevice_new(const struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c index dd2953b..26990d4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c @@ -153,7 +153,7 @@ nv50_disp_chan_uevent = { .fini = nv50_disp_chan_uevent_fini, }; -int +static int nv50_disp_chan_rd32(struct nvkm_object *object, u64 addr, u32 *data) { struct nv50_disp_chan *chan = nv50_disp_chan(object); @@ -163,7 +163,7 @@ nv50_disp_chan_rd32(struct nvkm_object *object, u64 addr, u32 *data) return 0; } -int +static int nv50_disp_chan_wr32(struct nvkm_object *object, u64 addr, u32 data) { struct nv50_disp_chan *chan = nv50_disp_chan(object); @@ -173,7 +173,7 @@ nv50_disp_chan_wr32(struct nvkm_object *object, u64 addr, u32 data) return 0; } -int +static int nv50_disp_chan_ntfy(struct nvkm_object *object, u32 type, struct nvkm_event **pevent) { @@ -189,7 +189,7 @@ nv50_disp_chan_ntfy(struct nvkm_object *object, u32 type, return -EINVAL; } -int +static int nv50_disp_chan_map(struct nvkm_object *object, u64 *addr, u32 *size) { struct nv50_disp_chan *chan = nv50_disp_chan(object); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c index 2f9cecd..6424b39 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c @@ -66,7 +66,7 @@ nv50_disp_root_scanoutpos(NV50_DISP_MTHD_V0) return 0; } -int +static int nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size) { union { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chang84.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chang84.c index aeb3387..15a992b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chang84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chang84.c @@ -129,7 +129,7 @@ g84_fifo_chan_engine_fini(struct nvkm_fifo_chan *base, } -int +static int g84_fifo_chan_engine_init(struct nvkm_fifo_chan *base, struct nvkm_engine *engine) { @@ -170,7 +170,7 @@ g84_fifo_chan_engine_ctor(struct nvkm_fifo_chan *base, return nvkm_object_bind(object, NULL, 0, &chan->engn[engn]); } -int +static int g84_fifo_chan_object_ctor(struct nvkm_fifo_chan *base, struct nvkm_object *object) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c index c925ade..74a64e3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c @@ -218,7 +218,7 @@ gf117_grctx_generate_attrib(struct gf100_grctx *info) } } -void +static void gf117_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) { struct nvkm_device *device = gr->base.engine.subdev.device; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c index 6d3c501..4c4b5ab 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c @@ -933,7 +933,7 @@ gm107_grctx_generate_attrib(struct gf100_grctx *info) } } -void +static void gm107_grctx_generate_tpcid(struct gf100_gr *gr) { struct nvkm_device *device = gr->base.engine.subdev.device; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c index 157919c..eccdee0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c @@ -1384,7 +1384,7 @@ gf100_gr_intr(struct nvkm_gr *base) nvkm_fifo_chan_put(device->fifo, flags, &chan); } -void +static void gf100_gr_init_fw(struct gf100_gr *gr, u32 fuc_base, struct gf100_gr_fuc *code, struct gf100_gr_fuc *data) { @@ -1701,7 +1701,7 @@ gf100_gr_oneinit(struct nvkm_gr *base) return 0; } -int +static int gf100_gr_init_(struct nvkm_gr *base) { struct gf100_gr *gr = gf100_gr(base); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c index 45f965f..2c67fac 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c @@ -308,7 +308,7 @@ gm107_gr_init_bios(struct gf100_gr *gr) } } -int +static int gm107_gr_init(struct gf100_gr *gr) { struct nvkm_device *device = gr->base.engine.subdev.device; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c index 8616636..dde89a4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c @@ -71,7 +71,7 @@ nvkm_perfdom_find(struct nvkm_pm *pm, int di) return NULL; } -struct nvkm_perfsig * +static struct nvkm_perfsig * nvkm_perfsig_find(struct nvkm_pm *pm, u8 di, u8 si, struct nvkm_perfdom **pdom) { struct nvkm_perfdom *dom = *pdom; @@ -699,7 +699,7 @@ nvkm_pm_oclass_get(struct nvkm_oclass *oclass, int index, return 1; } -int +static int nvkm_perfsrc_new(struct nvkm_pm *pm, struct nvkm_perfsig *sig, const struct nvkm_specsrc *spec) { diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/fan.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/fan.c index 80fed7e7..e290581 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/fan.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/fan.c @@ -25,7 +25,7 @@ #include #include -u16 +static u16 nvbios_fan_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) { struct bit_entry bit_P; @@ -52,7 +52,7 @@ nvbios_fan_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) return 0x0000; } -u16 +static u16 nvbios_fan_entry(struct nvkm_bios *bios, int idx, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) { diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c index 056702e..96e0941 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c @@ -180,7 +180,7 @@ gt215_clk_read(struct nvkm_clk *base, enum nv_clk_src src) return 0; } -int +static int gt215_clk_info(struct nvkm_clk *base, int idx, u32 khz, struct gt215_clk_info *info) { diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c index d15ea88..f106643 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c @@ -95,7 +95,7 @@ struct gt215_ram { struct gt215_ltrain ltrain; }; -void +static void gt215_link_train_calc(u32 *vals, struct gt215_ltrain *train) { int i, lo, hi; @@ -149,7 +149,7 @@ gt215_link_train_calc(u32 *vals, struct gt215_ltrain *train) /* * Link training for (at least) DDR3 */ -int +static int gt215_link_train(struct gt215_ram *ram) { struct gt215_ltrain *train = &ram->ltrain; @@ -267,7 +267,7 @@ out: return ret; } -int +static int gt215_link_train_init(struct gt215_ram *ram) { static const u32 pattern[16] = { @@ -333,7 +333,7 @@ gt215_link_train_init(struct gt215_ram *ram) return 0; } -void +static void gt215_link_train_fini(struct gt215_ram *ram) { if (ram->ltrain.mem) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/gk104.c index 3f45afd1..2ead515 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/gk104.c @@ -37,7 +37,7 @@ gk104_gpio_intr_stat(struct nvkm_gpio *gpio, u32 *hi, u32 *lo) nvkm_wr32(device, 0x00dc80, intr1); } -void +static void gk104_gpio_intr_mask(struct nvkm_gpio *gpio, u32 type, u32 mask, u32 data) { struct nvkm_device *device = gpio->subdev.device; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm200.c b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm200.c index f1e2dc9..ec48e4a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm200.c @@ -1364,7 +1364,7 @@ gm200_secboot_init(struct nvkm_secboot *sb) return 0; } -int +static int gm200_secboot_fini(struct nvkm_secboot *sb, bool suspend) { struct gm200_secboot *gsb = gm200_secboot(sb); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk104.c index b2c5d11..1c744e0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk104.c @@ -35,7 +35,7 @@ struct gk104_volt { struct nvbios_volt bios; }; -int +static int gk104_volt_get(struct nvkm_volt *base) { struct nvbios_volt *bios = &gk104_volt(base)->bios; @@ -48,7 +48,7 @@ gk104_volt_get(struct nvkm_volt *base) return bios->base + bios->pwm_range * duty / div; } -int +static int gk104_volt_set(struct nvkm_volt *base, u32 uv) { struct nvbios_volt *bios = &gk104_volt(base)->bios; -- cgit v1.1 From b74c0a9969f25217a5e5bbcac56a11bee16718d3 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 24 Oct 2016 17:30:38 +0200 Subject: drm/nouveau: hide gcc-4.9 -Wmaybe-uninitialized MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gcc-4.9 notices that the validate_init() function returns unintialized data when called with a zero 'nr_buffers' argument, when called with the -Wmaybe-uninitialized flag: drivers/gpu/drm/nouveau/nouveau_gem.c: In function ‘validate_init.isra.6’: drivers/gpu/drm/nouveau/nouveau_gem.c:457:5: error: ‘ret’ may be used uninitialized in this function [-Werror=maybe-uninitialized] However, the only caller of this function always passes a nonzero argument, and gcc-6 is clever enough to take this into account and not warn about it any more. Adding an explicit initialization to -EINVAL here is correct even if the caller changed, and it avoids the warning on gcc-4.9 as well. Signed-off-by: Arnd Bergmann Reviewed-By: Karol Herbst Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_gem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index 7f083c9..201b52b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -369,7 +369,7 @@ validate_init(struct nouveau_channel *chan, struct drm_file *file_priv, { struct nouveau_cli *cli = nouveau_cli(file_priv); int trycnt = 0; - int ret, i; + int ret = -EINVAL, i; struct nouveau_bo *res_bo = NULL; LIST_HEAD(gart_list); LIST_HEAD(vram_list); -- cgit v1.1 From 9a47a657bdf2c5f6e718ef8716d2e3985cc8b87b Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Tue, 25 Oct 2016 21:55:12 +0200 Subject: drm/nouveau: fix nv84 fence context leak uevent based fences hold a reference to the fence context, just like the legacy ones. So they need to drop this reference in the same way. Signed-off-by: Lucas Stach Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_fence.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index e9529ee..f2f348f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -586,5 +586,5 @@ static const struct dma_fence_ops nouveau_fence_ops_uevent = { .enable_signaling = nouveau_fence_enable_signaling, .signaled = nouveau_fence_is_signaled, .wait = dma_fence_default_wait, - .release = NULL + .release = nouveau_fence_release }; -- cgit v1.1 From 8423d75d8f15b8eba52f064707ee7892fba77837 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Wed, 26 Oct 2016 13:11:06 +0200 Subject: drm/nouveau: fix notify data leak There is no reason to not free the notify data if the NTFY_DEL ioctl failed. As nvif_notify_fini() is also called from the cleanup path of nvif_notify_init(), the notifier may not have been successfully created at that point. But it should also be the right thing to just free the data in the regular fini calls, as there is nothing much we can do if the ioctl fails, so better not leak memory. Signed-off-by: Lucas Stach Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvif/notify.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nvif/notify.c b/drivers/gpu/drm/nouveau/nvif/notify.c index b0787ff..278b393 100644 --- a/drivers/gpu/drm/nouveau/nvif/notify.c +++ b/drivers/gpu/drm/nouveau/nvif/notify.c @@ -155,10 +155,8 @@ nvif_notify_fini(struct nvif_notify *notify) int ret = nvif_notify_put(notify); if (ret >= 0 && object) { ret = nvif_object_ioctl(object, &args, sizeof(args), NULL); - if (ret == 0) { - notify->object = NULL; - kfree((void *)notify->data); - } + notify->object = NULL; + kfree((void *)notify->data); } return ret; } -- cgit v1.1 From ed7acfae2a8f21f86454466568cacbd84d2d04cf Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Thu, 27 Oct 2016 12:48:51 +0900 Subject: drm/nouveau/pmu: remove reset() hook The reset hook of pmu_func is never called, and gt215 was the only chip to implement. Remove this dead code. Signed-off-by: Alexandre Courbot Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gt215.c | 9 --------- drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h | 2 -- 2 files changed, 11 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gt215.c index 8ba7fa4..dcf9eaf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gt215.c @@ -24,17 +24,8 @@ #include "priv.h" #include "fuc/gt215.fuc3.h" -static void -gt215_pmu_reset(struct nvkm_pmu *pmu) -{ - struct nvkm_device *device = pmu->subdev.device; - nvkm_mask(device, 0x022210, 0x00000001, 0x00000000); - nvkm_mask(device, 0x022210, 0x00000001, 0x00000001); -} - static const struct nvkm_pmu_func gt215_pmu = { - .reset = gt215_pmu_reset, .code.data = gt215_pmu_code, .code.size = sizeof(gt215_pmu_code), .data.data = gt215_pmu_data, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h index f38c88f..73b811c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h @@ -8,8 +8,6 @@ int nvkm_pmu_new_(const struct nvkm_pmu_func *, struct nvkm_device *, int index, struct nvkm_pmu **); struct nvkm_pmu_func { - void (*reset)(struct nvkm_pmu *); - struct { u32 *data; u32 size; -- cgit v1.1 From 635cb7da577e7893f728927015759392b61254e7 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Thu, 27 Oct 2016 16:55:52 +0900 Subject: drm/nouveau/fb/gk20a: fix constructor call The gf100 constructor should be called, otherwise we will allocate a smaller object than expected. This was without effect so far because gk20a did not allocate a page, but with gf100's page allocation moved to the oneinit() hook this problem has become apparent. Signed-off-by: Alexandre Courbot Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk20a.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk20a.c index f815fe2..3f516f5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk20a.c @@ -20,6 +20,7 @@ * DEALINGS IN THE SOFTWARE. */ #include "priv.h" +#include "gf100.h" #include @@ -42,5 +43,5 @@ gk20a_fb = { int gk20a_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) { - return nvkm_fb_new_(&gk20a_fb, device, index, pfb); + return gf100_fb_new_(&gk20a_fb, device, index, pfb); } -- cgit v1.1 From 60958b8f292244df8795ba11722a7632ef3d9dc7 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Thu, 27 Oct 2016 16:55:53 +0900 Subject: drm/nouveau/fb/gk20a: use regular gf100's functions gk20a's FB is not special compared to other Kepler chips, besides the fact it does not have VRAM. Use the regular gf100 hooks instead of the incomplete versions we rewrote. Signed-off-by: Alexandre Courbot Reviewed-By: Karol Herbst Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk20a.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk20a.c index 3f516f5..5d34d61 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk20a.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -22,21 +22,14 @@ #include "priv.h" #include "gf100.h" -#include - -static void -gk20a_fb_init(struct nvkm_fb *fb) -{ - struct nvkm_device *device = fb->subdev.device; - nvkm_wr32(device, 0x100cc8, nvkm_memory_addr(fb->mmu_wr) >> 8); - nvkm_wr32(device, 0x100ccc, nvkm_memory_addr(fb->mmu_rd) >> 8); -} - +/* GK20A's FB is similar to GF100's, but without the ability to allocate VRAM */ static const struct nvkm_fb_func gk20a_fb = { + .dtor = gf100_fb_dtor, .oneinit = gf100_fb_oneinit, - .init = gk20a_fb_init, + .init = gf100_fb_init, .init_page = gf100_fb_init_page, + .intr = gf100_fb_intr, .memtype_valid = gf100_fb_memtype_valid, }; -- cgit v1.1 From 770b06e8cbdaae268286d627883c01f9ff7682f4 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Thu, 27 Oct 2016 16:55:54 +0900 Subject: drm/nouveau/fb: add gm20b device gm20b's FB has the same capabilities as gm200, minus the ability to allocate RAM. Create a device that reflects this instead of re-using the gk20a device which may be incorrect. Signed-off-by: Alexandre Courbot Reviewed-By: Karol Herbst Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h | 1 + drivers/gpu/drm/nouveau/nvkm/engine/device/base.c | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/fb/Kbuild | 1 + drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.h | 4 +++ drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm200.c | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm20b.c | 40 +++++++++++++++++++++++ 6 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm20b.c (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h index 3a41027..cf68106 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 gm20b_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 **); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 22f5b93..bd22526 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2131,7 +2131,7 @@ nv12b_chipset = { .bar = gk20a_bar_new, .bus = gf100_bus_new, .clk = gm20b_clk_new, - .fb = gk20a_fb_new, + .fb = gm20b_fb_new, .fuse = gm107_fuse_new, .ibus = gk20a_ibus_new, .imem = gk20a_instmem_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/Kbuild index edcc157..ef47d57 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/gm20b.o nvkm-y += nvkm/subdev/fb/gp100.o nvkm-y += nvkm/subdev/fb/gp104.o diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.h index 449f431..412eb89 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.h @@ -16,4 +16,8 @@ void gf100_fb_init(struct nvkm_fb *); void gf100_fb_intr(struct nvkm_fb *); void gp100_fb_init(struct nvkm_fb *); + +void gm200_fb_init_page(struct nvkm_fb *fb); +void gm200_fb_init(struct nvkm_fb *base); + #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm200.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm200.c index 62f6532..fe58860 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm200.c @@ -44,7 +44,7 @@ gm200_fb_init_page(struct nvkm_fb *fb) } } -static void +void gm200_fb_init(struct nvkm_fb *base) { struct gf100_fb *fb = gf100_fb(base); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm20b.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm20b.c new file mode 100644 index 0000000..b87c233 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm20b.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. + * + * 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 AUTHORS OR COPYRIGHT HOLDERS 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. + */ +#include "priv.h" +#include "gf100.h" + +/* GM20B's FB is similar to GM200, but without the ability to allocate VRAM */ +static const struct nvkm_fb_func +gm20b_fb = { + .dtor = gf100_fb_dtor, + .oneinit = gf100_fb_oneinit, + .init = gm200_fb_init, + .init_page = gm200_fb_init_page, + .intr = gf100_fb_intr, + .memtype_valid = gf100_fb_memtype_valid, +}; + +int +gm20b_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) +{ + return gf100_fb_new_(&gm20b_fb, device, index, pfb); +} -- cgit v1.1 From 91cf301f6ffb854a03c55df39ab04298f12cb000 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Mon, 31 Oct 2016 07:35:50 +0100 Subject: drm/nouveau/tegra: Fix error handling 'iommu_domain_alloc()' returns NULL in case of error, not an error pointer. So test it accordingly. Signed-off-by: Christophe JAILLET Reviewed-by: Alexandre Courbot Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c index 9b638bd..f2bc0b7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c @@ -102,7 +102,7 @@ nvkm_device_tegra_probe_iommu(struct nvkm_device_tegra *tdev) if (iommu_present(&platform_bus_type)) { tdev->iommu.domain = iommu_domain_alloc(&platform_bus_type); - if (IS_ERR(tdev->iommu.domain)) + if (!tdev->iommu.domain) goto error; /* -- cgit v1.1 From f3a8b6645dc2e60d11f20c1c23afd964ff4e55ae Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 4 Nov 2016 11:44:21 +1000 Subject: drm/nouveau: silence sparse warnings about symbols not being marked static Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h | 2 ++ drivers/gpu/drm/nouveau/nouveau_connector.h | 1 + drivers/gpu/drm/nouveau/nouveau_drm.c | 1 + drivers/gpu/drm/nouveau/nvif/client.c | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gf100.fuc3.h | 4 ++-- drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gt215.fuc3.h | 4 ++-- drivers/gpu/drm/nouveau/nvkm/engine/disp/coreg94.c | 6 +++--- drivers/gpu/drm/nouveau/nvkm/engine/disp/coregp104.c | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf100.fuc3.h | 4 ++-- drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf117.fuc3.h | 4 ++-- drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk104.fuc3.h | 4 ++-- drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk110.fuc3.h | 4 ++-- drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk208.fuc5.h | 4 ++-- drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgm107.fuc5.h | 4 ++-- drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgf100.fuc3.h | 4 ++-- drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgf117.fuc3.h | 4 ++-- drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk104.fuc3.h | 4 ++-- drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk110.fuc3.h | 4 ++-- drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk208.fuc5.h | 4 ++-- drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgm107.fuc5.h | 4 ++-- drivers/gpu/drm/nouveau/nvkm/engine/gr/gf117.c | 4 ++-- drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/sec/fuc/g98.fuc0s.h | 4 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c | 2 -- drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/iccsense/base.c | 3 ++- drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c | 4 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/mc/g84.c | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf100.fuc3.h | 4 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf119.fuc4.h | 4 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gk208.fuc5.h | 4 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gt215.fuc3.h | 4 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/volt/gm20b.c | 4 ++-- 33 files changed, 58 insertions(+), 55 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h index cf68106..65ce79a 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h @@ -157,4 +157,6 @@ struct nvkm_ram_func { int (*prog)(struct nvkm_ram *); void (*tidy)(struct nvkm_ram *); }; + +extern const u8 gf100_pte_storage_type_map[256]; #endif diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.h b/drivers/gpu/drm/nouveau/nouveau_connector.h index 7446ee6..43b9583 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.h +++ b/drivers/gpu/drm/nouveau/nouveau_connector.h @@ -109,5 +109,6 @@ nouveau_connector_create(struct drm_device *, int index); extern int nouveau_tv_disable; extern int nouveau_ignorelid; extern int nouveau_duallink; +extern int nouveau_hdmimhz; #endif /* __NOUVEAU_CONNECTOR_H__ */ diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 6adf947..6228815 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -1037,6 +1037,7 @@ static void nouveau_display_options(void) DRM_DEBUG_DRIVER("... modeset : %d\n", nouveau_modeset); DRM_DEBUG_DRIVER("... runpm : %d\n", nouveau_runtime_pm); DRM_DEBUG_DRIVER("... vram_pushbuf : %d\n", nouveau_vram_pushbuf); + DRM_DEBUG_DRIVER("... hdmimhz : %d\n", nouveau_hdmimhz); } static const struct dev_pm_ops nouveau_pm_ops = { diff --git a/drivers/gpu/drm/nouveau/nvif/client.c b/drivers/gpu/drm/nouveau/nvif/client.c index 1ee9294..29c20df 100644 --- a/drivers/gpu/drm/nouveau/nvif/client.c +++ b/drivers/gpu/drm/nouveau/nvif/client.c @@ -55,7 +55,7 @@ nvif_client_fini(struct nvif_client *client) } } -const struct nvif_driver * +static const struct nvif_driver * nvif_drivers[] = { #ifdef __KERNEL__ &nvif_driver_nvkm, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gf100.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gf100.fuc3.h index 05bb656..d9ca963 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gf100.fuc3.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gf100.fuc3.h @@ -1,4 +1,4 @@ -uint32_t gf100_ce_data[] = { +static uint32_t gf100_ce_data[] = { /* 0x0000: ctx_object */ 0x00000000, /* 0x0004: ctx_query_address_high */ @@ -171,7 +171,7 @@ uint32_t gf100_ce_data[] = { 0x00000800, }; -uint32_t gf100_ce_code[] = { +static uint32_t gf100_ce_code[] = { /* 0x0000: main */ 0x04fe04bd, 0x3517f000, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gt215.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gt215.fuc3.h index 972281d..f0a1cf3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gt215.fuc3.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gt215.fuc3.h @@ -1,4 +1,4 @@ -uint32_t gt215_ce_data[] = { +static uint32_t gt215_ce_data[] = { /* 0x0000: ctx_object */ 0x00000000, /* 0x0004: ctx_dma */ @@ -183,7 +183,7 @@ uint32_t gt215_ce_data[] = { 0x00000800, }; -uint32_t gt215_ce_code[] = { +static uint32_t gt215_ce_code[] = { /* 0x0000: main */ 0x04fe04bd, 0x3517f000, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/coreg94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coreg94.c index 019379a..c65c9f3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/coreg94.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coreg94.c @@ -26,7 +26,7 @@ #include -const struct nv50_disp_mthd_list +static const struct nv50_disp_mthd_list g94_disp_core_mthd_sor = { .mthd = 0x0040, .addr = 0x000008, @@ -43,8 +43,8 @@ g94_disp_core_chan_mthd = { .prev = 0x000004, .data = { { "Global", 1, &nv50_disp_core_mthd_base }, - { "DAC", 3, &g84_disp_core_mthd_dac }, - { "SOR", 4, &g94_disp_core_mthd_sor }, + { "DAC", 3, &g84_disp_core_mthd_dac }, + { "SOR", 4, &g94_disp_core_mthd_sor }, { "PIOR", 3, &nv50_disp_core_mthd_pior }, { "HEAD", 2, &g84_disp_core_mthd_head }, {} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregp104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregp104.c index 6922f40..e356f87 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregp104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregp104.c @@ -59,7 +59,7 @@ gp104_disp_core_init(struct nv50_disp_dmac *chan) return 0; } -const struct nv50_disp_dmac_func +static const struct nv50_disp_dmac_func gp104_disp_core_func = { .init = gp104_disp_core_init, .fini = gf119_disp_core_fini, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf100.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf100.fuc3.h index 8cb240b..12a703f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf100.fuc3.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf100.fuc3.h @@ -1,4 +1,4 @@ -uint32_t gf100_grgpc_data[] = { +static uint32_t gf100_grgpc_data[] = { /* 0x0000: gpc_mmio_list_head */ 0x00000064, /* 0x0004: gpc_mmio_list_tail */ @@ -36,7 +36,7 @@ uint32_t gf100_grgpc_data[] = { 0x00000000, }; -uint32_t gf100_grgpc_code[] = { +static uint32_t gf100_grgpc_code[] = { 0x03a10ef5, /* 0x0004: queue_put */ 0x9800d898, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf117.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf117.fuc3.h index 550d6ba..ffbfc51 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf117.fuc3.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf117.fuc3.h @@ -1,4 +1,4 @@ -uint32_t gf117_grgpc_data[] = { +static uint32_t gf117_grgpc_data[] = { /* 0x0000: gpc_mmio_list_head */ 0x0000006c, /* 0x0004: gpc_mmio_list_tail */ @@ -40,7 +40,7 @@ uint32_t gf117_grgpc_data[] = { 0x00000000, }; -uint32_t gf117_grgpc_code[] = { +static uint32_t gf117_grgpc_code[] = { 0x03a10ef5, /* 0x0004: queue_put */ 0x9800d898, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk104.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk104.fuc3.h index 271b59d..357f662 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk104.fuc3.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk104.fuc3.h @@ -1,4 +1,4 @@ -uint32_t gk104_grgpc_data[] = { +static uint32_t gk104_grgpc_data[] = { /* 0x0000: gpc_mmio_list_head */ 0x0000006c, /* 0x0004: gpc_mmio_list_tail */ @@ -40,7 +40,7 @@ uint32_t gk104_grgpc_data[] = { 0x00000000, }; -uint32_t gk104_grgpc_code[] = { +static uint32_t gk104_grgpc_code[] = { 0x03a10ef5, /* 0x0004: queue_put */ 0x9800d898, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk110.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk110.fuc3.h index 73b4a32..4ffc821 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk110.fuc3.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk110.fuc3.h @@ -1,4 +1,4 @@ -uint32_t gk110_grgpc_data[] = { +static uint32_t gk110_grgpc_data[] = { /* 0x0000: gpc_mmio_list_head */ 0x0000006c, /* 0x0004: gpc_mmio_list_tail */ @@ -40,7 +40,7 @@ uint32_t gk110_grgpc_data[] = { 0x00000000, }; -uint32_t gk110_grgpc_code[] = { +static uint32_t gk110_grgpc_code[] = { 0x03a10ef5, /* 0x0004: queue_put */ 0x9800d898, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk208.fuc5.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk208.fuc5.h index 0181698..0919620 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk208.fuc5.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk208.fuc5.h @@ -1,4 +1,4 @@ -uint32_t gk208_grgpc_data[] = { +static uint32_t gk208_grgpc_data[] = { /* 0x0000: gpc_mmio_list_head */ 0x0000006c, /* 0x0004: gpc_mmio_list_tail */ @@ -40,7 +40,7 @@ uint32_t gk208_grgpc_data[] = { 0x00000000, }; -uint32_t gk208_grgpc_code[] = { +static uint32_t gk208_grgpc_code[] = { 0x03140ef5, /* 0x0004: queue_put */ 0x9800d898, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgm107.fuc5.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgm107.fuc5.h index eca007f..6d7d004 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgm107.fuc5.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgm107.fuc5.h @@ -1,4 +1,4 @@ -uint32_t gm107_grgpc_data[] = { +static uint32_t gm107_grgpc_data[] = { /* 0x0000: gpc_mmio_list_head */ 0x0000006c, /* 0x0004: gpc_mmio_list_tail */ @@ -40,7 +40,7 @@ uint32_t gm107_grgpc_data[] = { 0x00000000, }; -uint32_t gm107_grgpc_code[] = { +static uint32_t gm107_grgpc_code[] = { 0x03410ef5, /* 0x0004: queue_put */ 0x9800d898, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgf100.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgf100.fuc3.h index 8015b40..7538404 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgf100.fuc3.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgf100.fuc3.h @@ -1,4 +1,4 @@ -uint32_t gf100_grhub_data[] = { +static uint32_t gf100_grhub_data[] = { /* 0x0000: hub_mmio_list_head */ 0x00000300, /* 0x0004: hub_mmio_list_tail */ @@ -205,7 +205,7 @@ uint32_t gf100_grhub_data[] = { 0x0417e91c, }; -uint32_t gf100_grhub_code[] = { +static uint32_t gf100_grhub_code[] = { 0x039b0ef5, /* 0x0004: queue_put */ 0x9800d898, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgf117.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgf117.fuc3.h index 2af90ec..ce000a4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgf117.fuc3.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgf117.fuc3.h @@ -1,4 +1,4 @@ -uint32_t gf117_grhub_data[] = { +static uint32_t gf117_grhub_data[] = { /* 0x0000: hub_mmio_list_head */ 0x00000300, /* 0x0004: hub_mmio_list_tail */ @@ -205,7 +205,7 @@ uint32_t gf117_grhub_data[] = { 0x0417e91c, }; -uint32_t gf117_grhub_code[] = { +static uint32_t gf117_grhub_code[] = { 0x039b0ef5, /* 0x0004: queue_put */ 0x9800d898, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk104.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk104.fuc3.h index e8b8c1c..1f26cb6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk104.fuc3.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk104.fuc3.h @@ -1,4 +1,4 @@ -uint32_t gk104_grhub_data[] = { +static uint32_t gk104_grhub_data[] = { /* 0x0000: hub_mmio_list_head */ 0x00000300, /* 0x0004: hub_mmio_list_tail */ @@ -205,7 +205,7 @@ uint32_t gk104_grhub_data[] = { 0x0417e91c, }; -uint32_t gk104_grhub_code[] = { +static uint32_t gk104_grhub_code[] = { 0x039b0ef5, /* 0x0004: queue_put */ 0x9800d898, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk110.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk110.fuc3.h index f4ed2fb..70436d9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk110.fuc3.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk110.fuc3.h @@ -1,4 +1,4 @@ -uint32_t gk110_grhub_data[] = { +static uint32_t gk110_grhub_data[] = { /* 0x0000: hub_mmio_list_head */ 0x00000300, /* 0x0004: hub_mmio_list_tail */ @@ -205,7 +205,7 @@ uint32_t gk110_grhub_data[] = { 0x0417e91c, }; -uint32_t gk110_grhub_code[] = { +static uint32_t gk110_grhub_code[] = { 0x039b0ef5, /* 0x0004: queue_put */ 0x9800d898, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk208.fuc5.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk208.fuc5.h index ed48897..e0933a0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk208.fuc5.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk208.fuc5.h @@ -1,4 +1,4 @@ -uint32_t gk208_grhub_data[] = { +static uint32_t gk208_grhub_data[] = { /* 0x0000: hub_mmio_list_head */ 0x00000300, /* 0x0004: hub_mmio_list_tail */ @@ -205,7 +205,7 @@ uint32_t gk208_grhub_data[] = { 0x0417e91c, }; -uint32_t gk208_grhub_code[] = { +static uint32_t gk208_grhub_code[] = { 0x030e0ef5, /* 0x0004: queue_put */ 0x9800d898, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgm107.fuc5.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgm107.fuc5.h index 5c90518..9b43282 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgm107.fuc5.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgm107.fuc5.h @@ -1,4 +1,4 @@ -uint32_t gm107_grhub_data[] = { +static uint32_t gm107_grhub_data[] = { /* 0x0000: hub_mmio_list_head */ 0x00000300, /* 0x0004: hub_mmio_list_tail */ @@ -205,7 +205,7 @@ uint32_t gm107_grhub_data[] = { 0x0417e91c, }; -uint32_t gm107_grhub_code[] = { +static uint32_t gm107_grhub_code[] = { 0x030e0ef5, /* 0x0004: queue_put */ 0x9800d898, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf117.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf117.c index 70335f6..0124e46 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf117.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf117.c @@ -102,7 +102,7 @@ gf117_gr_pack_mmio[] = { #include "fuc/hubgf117.fuc3.h" -struct gf100_gr_ucode +static struct gf100_gr_ucode gf117_gr_fecs_ucode = { .code.data = gf117_grhub_code, .code.size = sizeof(gf117_grhub_code), @@ -112,7 +112,7 @@ gf117_gr_fecs_ucode = { #include "fuc/gpcgf117.fuc3.h" -struct gf100_gr_ucode +static struct gf100_gr_ucode gf117_gr_gpccs_ucode = { .code.data = gf117_grgpc_code, .code.size = sizeof(gf117_grgpc_code), diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c index d2901e9..fe2532e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c @@ -102,7 +102,7 @@ gf100_pm_gpc[] = { {} }; -const struct nvkm_specdom +static const struct nvkm_specdom gf100_pm_part[] = { { 0xe0, (const struct nvkm_specsig[]) { { 0x0f, "part00_pbfb_00", gf100_pbfb_sources }, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec/fuc/g98.fuc0s.h b/drivers/gpu/drm/nouveau/nvkm/engine/sec/fuc/g98.fuc0s.h index eca6222..4b57f88 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sec/fuc/g98.fuc0s.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec/fuc/g98.fuc0s.h @@ -1,4 +1,4 @@ -uint32_t g98_sec_data[] = { +static uint32_t g98_sec_data[] = { /* 0x0000: ctx_dma */ /* 0x0000: ctx_dma_query */ 0x00000000, @@ -150,7 +150,7 @@ uint32_t g98_sec_data[] = { 0x00000000, }; -uint32_t g98_sec_code[] = { +static uint32_t g98_sec_code[] = { 0x17f004bd, 0x0010fe35, 0xf10004fe, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c index 772425c..093223d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c @@ -420,8 +420,6 @@ gf100_ram_tidy(struct nvkm_ram *base) ram_exec(&ram->fuc, false); } -extern const u8 gf100_pte_storage_type_map[256]; - void gf100_ram_put(struct nvkm_ram *ram, struct nvkm_mem **pmem) { diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c index f0851d5..01d5c5a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c @@ -74,7 +74,7 @@ nvkm_i2c_aux_i2c_func(struct i2c_adapter *adap) return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; } -const struct i2c_algorithm +static const struct i2c_algorithm nvkm_i2c_aux_i2c_algo = { .master_xfer = nvkm_i2c_aux_i2c_xfer, .functionality = nvkm_i2c_aux_i2c_func diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/iccsense/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/iccsense/base.c index 658355f..f0af2a3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/iccsense/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/iccsense/base.c @@ -288,7 +288,8 @@ nvkm_iccsense_init(struct nvkm_subdev *subdev) return 0; } -struct nvkm_subdev_func iccsense_func = { +static const struct nvkm_subdev_func +iccsense_func = { .oneinit = nvkm_iccsense_oneinit, .init = nvkm_iccsense_init, .dtor = nvkm_iccsense_dtor, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c index 8ed8f65..10c987a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c @@ -104,7 +104,7 @@ nvkm_instobj_dtor(struct nvkm_memory *memory) return iobj; } -const struct nvkm_memory_func +static const struct nvkm_memory_func nvkm_instobj_func = { .dtor = nvkm_instobj_dtor, .target = nvkm_instobj_target, @@ -156,7 +156,7 @@ nvkm_instobj_wr32_slow(struct nvkm_memory *memory, u64 offset, u32 data) return nvkm_wo32(iobj->parent, offset, data); } -const struct nvkm_memory_func +static const struct nvkm_memory_func nvkm_instobj_func_slow = { .dtor = nvkm_instobj_dtor, .target = nvkm_instobj_target, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g84.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g84.c index c3d66ef..430a61c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g84.c @@ -34,7 +34,7 @@ g84_mc_reset[] = { {} }; -const struct nvkm_mc_map +static const struct nvkm_mc_map g84_mc_intr[] = { { 0x04000000, NVKM_ENGINE_DISP }, { 0x00020000, NVKM_ENGINE_VP }, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf100.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf100.fuc3.h index e2faccf..0bcf0b3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf100.fuc3.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf100.fuc3.h @@ -1,4 +1,4 @@ -uint32_t gf100_pmu_data[] = { +static uint32_t gf100_pmu_data[] = { /* 0x0000: proc_kern */ 0x52544e49, 0x00000000, @@ -916,7 +916,7 @@ uint32_t gf100_pmu_data[] = { 0x00000000, }; -uint32_t gf100_pmu_code[] = { +static uint32_t gf100_pmu_code[] = { 0x03920ef5, /* 0x0004: rd32 */ 0x07a007f1, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf119.fuc4.h b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf119.fuc4.h index 2d5bdc5..fe89056 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf119.fuc4.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf119.fuc4.h @@ -1,4 +1,4 @@ -uint32_t gf119_pmu_data[] = { +static uint32_t gf119_pmu_data[] = { /* 0x0000: proc_kern */ 0x52544e49, 0x00000000, @@ -915,7 +915,7 @@ uint32_t gf119_pmu_data[] = { 0x00000000, }; -uint32_t gf119_pmu_code[] = { +static uint32_t gf119_pmu_code[] = { 0x03410ef5, /* 0x0004: rd32 */ 0x07a007f1, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gk208.fuc5.h b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gk208.fuc5.h index 3c731ff..9cf4e6f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gk208.fuc5.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gk208.fuc5.h @@ -1,4 +1,4 @@ -uint32_t gk208_pmu_data[] = { +static uint32_t gk208_pmu_data[] = { /* 0x0000: proc_kern */ 0x52544e49, 0x00000000, @@ -915,7 +915,7 @@ uint32_t gk208_pmu_data[] = { 0x00000000, }; -uint32_t gk208_pmu_code[] = { +static uint32_t gk208_pmu_code[] = { 0x02f90ef5, /* 0x0004: rd32 */ 0xf607a040, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gt215.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gt215.fuc3.h index e833418..5d69242 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gt215.fuc3.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gt215.fuc3.h @@ -1,4 +1,4 @@ -uint32_t gt215_pmu_data[] = { +static uint32_t gt215_pmu_data[] = { /* 0x0000: proc_kern */ 0x52544e49, 0x00000000, @@ -916,7 +916,7 @@ uint32_t gt215_pmu_data[] = { 0x00000000, }; -uint32_t gt215_pmu_code[] = { +static uint32_t gt215_pmu_code[] = { 0x03920ef5, /* 0x0004: rd32 */ 0x07a007f1, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gm20b.c b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gm20b.c index 74db4d2..2925b9c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gm20b.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gm20b.c @@ -25,7 +25,7 @@ #include -const struct cvb_coef gm20b_cvb_coef[] = { +static const struct cvb_coef gm20b_cvb_coef[] = { /* KHz, c0, c1, c2 */ /* 76800 */ { 1786666, -85625, 1632 }, /* 153600 */ { 1846729, -87525, 1632 }, @@ -58,7 +58,7 @@ static const struct cvb_coef gm20b_na_cvb_coef[] = { /* 998400 */ { 1316991, 8144, -940, 808, -21583, 226 }, }; -const u32 speedo_to_vmin[] = { +static const u32 speedo_to_vmin[] = { /* 0, 1, 2, 3, 4, */ 950000, 840000, 818750, 840000, 810000, }; -- cgit v1.1 From a3f8a41fd2b4b5f95374c0084d048c33d783b422 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 4 Nov 2016 17:20:35 +1000 Subject: drm/nouveau/nvif: helper to match against supported class list Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/object.h | 29 +++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/include/nvif/object.h b/drivers/gpu/drm/nouveau/include/nvif/object.h index 8d81596..9e58b30 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/object.h +++ b/drivers/gpu/drm/nouveau/include/nvif/object.h @@ -66,6 +66,35 @@ void nvif_object_unmap(struct nvif_object *); #define nvif_mthd(a,b,c,d) nvif_object_mthd((a), (b), (c), (d)) +struct nvif_mclass { + s32 oclass; + int version; +}; + +#define nvif_mclass(o,m) ({ \ + struct nvif_object *object = (o); \ + struct nvif_sclass *sclass; \ + const typeof(m[0]) *mclass = (m); \ + int ret = -ENODEV; \ + int cnt, i, j; \ + \ + cnt = nvif_object_sclass_get(object, &sclass); \ + if (cnt >= 0) { \ + for (i = 0; ret < 0 && mclass[i].oclass; i++) { \ + for (j = 0; j < cnt; j++) { \ + if (mclass[i].oclass == sclass[j].oclass && \ + mclass[i].version >= sclass[j].minver && \ + mclass[i].version <= sclass[j].maxver) { \ + ret = i; \ + break; \ + } \ + } \ + } \ + nvif_object_sclass_put(&sclass); \ + } \ + ret; \ +}) + /*XXX*/ #include #define nvxx_object(a) ({ \ -- cgit v1.1 From 1f8711bafe0b43716592a3797f693eb7c0175123 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 4 Nov 2016 17:20:35 +1000 Subject: drm/nouveau/disp/dp: remove workqueue for link training There haven't been any callers from an atomic context for a while now, so let's remove the extra complexity. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c | 9 +----- drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.h | 4 +-- drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.c | 33 ++++++++-------------- drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h | 5 ++-- .../gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c | 2 +- 7 files changed, 20 insertions(+), 37 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c index 9688970..4a93ceb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c @@ -319,9 +319,8 @@ static const struct dp_rates { }; void -nvkm_dp_train(struct work_struct *w) +nvkm_dp_train(struct nvkm_output_dp *outp) { - struct nvkm_output_dp *outp = container_of(w, typeof(*outp), lt.work); struct nv50_disp *disp = nv50_disp(outp->base.disp); const struct dp_rates *cfg = nvkm_dp_rates; struct dp_state _dp = { @@ -353,9 +352,6 @@ nvkm_dp_train(struct work_struct *w) } cfg--; - /* disable link interrupt handling during link training */ - nvkm_notify_put(&outp->irq); - /* ensure sink is not in a low-power state */ if (!nvkm_rdaux(outp->aux, DPCD_SC00, &pwr, 1)) { if ((pwr & DPCD_SC00_SET_POWER) != DPCD_SC00_SET_POWER_D0) { @@ -400,9 +396,6 @@ nvkm_dp_train(struct work_struct *w) dp_link_train_fini(dp); - /* signal completion and enable link interrupt handling */ OUTP_DBG(&outp->base, "training complete"); atomic_set(&outp->lt.done, 1); - wake_up(&outp->lt.wait); - nvkm_notify_get(&outp->irq); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.h index 6e10c5e..baf1dd9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.h @@ -1,6 +1,6 @@ #ifndef __NVKM_DISP_DPORT_H__ #define __NVKM_DISP_DPORT_H__ -#include +struct nvkm_output_dp; /* DPCD Receiver Capabilities */ #define DPCD_RC00_DPCD_REV 0x00000 @@ -77,5 +77,5 @@ #define DPCD_SC00_SET_POWER_D0 0x01 #define DPCD_SC00_SET_POWER_D3 0x03 -void nvkm_dp_train(struct work_struct *); +void nvkm_dp_train(struct nvkm_output_dp *); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c index 29e84b2..0face69 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c @@ -314,7 +314,7 @@ gf119_disp_intr_unk2_2(struct nv50_disp *disp, int head) break; } - if (nvkm_output_dp_train(outp, pclk, true)) + if (nvkm_output_dp_train(outp, pclk)) OUTP_ERR(outp, "link not trained before attach"); } else { if (disp->func->sor.magic) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index fbb8c7d..a2bd0f0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -779,7 +779,7 @@ nv50_disp_intr_unk20_2(struct nv50_disp *disp, int head) break; } - if (nvkm_output_dp_train(outp, datarate / soff, true)) + if (nvkm_output_dp_train(outp, datarate / soff)) OUTP_ERR(outp, "link not trained before attach"); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.c index 3b7a9e7..de36f73 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.c @@ -31,7 +31,7 @@ #include int -nvkm_output_dp_train(struct nvkm_output *base, u32 datarate, bool wait) +nvkm_output_dp_train(struct nvkm_output *base, u32 datarate) { struct nvkm_output_dp *outp = nvkm_output_dp(base); bool retrain = true; @@ -39,6 +39,8 @@ nvkm_output_dp_train(struct nvkm_output *base, u32 datarate, bool wait) u32 linkrate; int ret, i; + mutex_lock(&outp->mutex); + /* check that the link is trained at a high enough rate */ ret = nvkm_rdaux(outp->aux, DPCD_LC00_LINK_BW_SET, link, 2); if (ret) { @@ -88,19 +90,10 @@ done: outp->dpcd[DPCD_RC02] = outp->base.info.dpconf.link_nr; } - atomic_set(&outp->lt.done, 0); - schedule_work(&outp->lt.work); - } else { - nvkm_notify_get(&outp->irq); - } - - if (wait) { - if (!wait_event_timeout(outp->lt.wait, - atomic_read(&outp->lt.done), - msecs_to_jiffies(2000))) - ret = -ETIMEDOUT; + nvkm_dp_train(outp); } + mutex_unlock(&outp->mutex); return ret; } @@ -118,7 +111,7 @@ nvkm_output_dp_enable(struct nvkm_output_dp *outp, bool enable) if (!nvkm_rdaux(aux, DPCD_RC00_DPCD_REV, outp->dpcd, sizeof(outp->dpcd))) { - nvkm_output_dp_train(&outp->base, 0, true); + nvkm_output_dp_train(&outp->base, 0); return; } } @@ -165,10 +158,10 @@ nvkm_output_dp_irq(struct nvkm_notify *notify) }; OUTP_DBG(&outp->base, "IRQ: %d", line->mask); - nvkm_output_dp_train(&outp->base, 0, true); + nvkm_output_dp_train(&outp->base, 0); nvkm_event_send(&disp->hpd, rep.mask, conn->index, &rep, sizeof(rep)); - return NVKM_NOTIFY_DROP; + return NVKM_NOTIFY_KEEP; } static void @@ -177,7 +170,6 @@ nvkm_output_dp_fini(struct nvkm_output *base) struct nvkm_output_dp *outp = nvkm_output_dp(base); nvkm_notify_put(&outp->hpd); nvkm_notify_put(&outp->irq); - flush_work(&outp->lt.work); nvkm_output_dp_enable(outp, false); } @@ -187,6 +179,7 @@ nvkm_output_dp_init(struct nvkm_output *base) struct nvkm_output_dp *outp = nvkm_output_dp(base); nvkm_notify_put(&outp->base.conn->hpd); nvkm_output_dp_enable(outp, true); + nvkm_notify_get(&outp->irq); nvkm_notify_get(&outp->hpd); } @@ -238,11 +231,6 @@ nvkm_output_dp_ctor(const struct nvkm_output_dp_func *func, OUTP_DBG(&outp->base, "bios dp %02x %02x %02x %02x", outp->version, hdr, cnt, len); - /* link training */ - INIT_WORK(&outp->lt.work, nvkm_dp_train); - init_waitqueue_head(&outp->lt.wait); - atomic_set(&outp->lt.done, 0); - /* link maintenance */ ret = nvkm_notify_init(NULL, &i2c->event, nvkm_output_dp_irq, true, &(struct nvkm_i2c_ntfy_req) { @@ -257,6 +245,9 @@ nvkm_output_dp_ctor(const struct nvkm_output_dp_func *func, return ret; } + mutex_init(&outp->mutex); + atomic_set(&outp->lt.done, 0); + /* hotplug detect, replaces gpio-based mechanism with aux events */ ret = nvkm_notify_init(NULL, &i2c->event, nvkm_output_dp_hpd, true, &(struct nvkm_i2c_ntfy_req) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h index 4e983f6..7b63d97 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h @@ -29,9 +29,8 @@ struct nvkm_output_dp { bool present; u8 dpcd[16]; + struct mutex mutex; struct { - struct work_struct work; - wait_queue_head_t wait; atomic_t done; } lt; }; @@ -43,7 +42,7 @@ struct nvkm_output_dp_func { int (*drv_ctl)(struct nvkm_output_dp *, int ln, int vs, int pe, int pc); }; -int nvkm_output_dp_train(struct nvkm_output *, u32 rate, bool wait); +int nvkm_output_dp_train(struct nvkm_output *, u32 rate); int nvkm_output_dp_ctor(const struct nvkm_output_dp_func *, struct nvkm_disp *, int index, struct dcb_output *, struct nvkm_i2c_aux *, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c index 6424b39..e9548e4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c @@ -173,7 +173,7 @@ nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size) return 0; } else if (args->v0.state != 0) { - nvkm_output_dp_train(&outpdp->base, 0, true); + nvkm_output_dp_train(&outpdp->base, 0); return 0; } } else -- cgit v1.1 From f2a4051379f8f4de418be074ccca77a6aae02f65 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 4 Nov 2016 17:20:35 +1000 Subject: drm/nouveau/disp/sor/gf119-: add method to control mst enable Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/cl5070.h | 7 +++++++ drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c | 22 ++++++++++++---------- drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h | 1 + .../gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c | 20 ++++++++++++++++++++ .../gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c | 4 +++- 5 files changed, 43 insertions(+), 11 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/include/nvif/cl5070.h b/drivers/gpu/drm/nouveau/include/nvif/cl5070.h index d15c296..ed999fc 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/cl5070.h +++ b/drivers/gpu/drm/nouveau/include/nvif/cl5070.h @@ -34,6 +34,7 @@ struct nv50_disp_mthd_v1 { #define NV50_DISP_MTHD_V1_SOR_HDMI_PWR 0x22 #define NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT 0x23 #define NV50_DISP_MTHD_V1_SOR_DP_PWR 0x24 +#define NV50_DISP_MTHD_V1_SOR_DP_MST_LINK 0x25 #define NV50_DISP_MTHD_V1_PIOR_PWR 0x30 __u8 method; __u16 hasht; @@ -90,6 +91,12 @@ struct nv50_disp_sor_dp_pwr_v0 { __u8 pad02[6]; }; +struct nv50_disp_sor_dp_mst_link_v0 { + __u8 version; + __u8 state; + __u8 pad02[6]; +}; + struct nv50_disp_pior_pwr_v0 { __u8 version; __u8 state; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c index 0face69..fd94241 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c @@ -203,17 +203,19 @@ gf119_disp_intr_unk2_0(struct nv50_disp *disp, int head) /* see note in nv50_disp_intr_unk20_0() */ if (outp && outp->info.type == DCB_OUTPUT_DP) { struct nvkm_output_dp *outpdp = nvkm_output_dp(outp); - struct nvbios_init init = { - .subdev = subdev, - .bios = subdev->device->bios, - .outp = &outp->info, - .crtc = head, - .offset = outpdp->info.script[4], - .execute = 1, - }; + if (!outpdp->lt.mst) { + struct nvbios_init init = { + .subdev = subdev, + .bios = subdev->device->bios, + .outp = &outp->info, + .crtc = head, + .offset = outpdp->info.script[4], + .execute = 1, + }; - nvbios_exec(&init); - atomic_set(&outpdp->lt.done, 0); + nvbios_exec(&init); + atomic_set(&outpdp->lt.done, 0); + } } } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h index 7b63d97..ef9ee0b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h @@ -32,6 +32,7 @@ struct nvkm_output_dp { struct mutex mutex; struct { atomic_t done; + bool mst; } lt; }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c index e9548e4..1a25067 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c @@ -180,6 +180,26 @@ nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size) return ret; } break; + case NV50_DISP_MTHD_V1_SOR_DP_MST_LINK: { + struct nvkm_output_dp *outpdp = nvkm_output_dp(outp); + union { + struct nv50_disp_sor_dp_mst_link_v0 v0; + } *args = data; + int ret = -ENOSYS; + nvif_ioctl(object, "disp sor dp mst link size %d\n", size); + if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { + nvif_ioctl(object, "disp sor dp mst link vers %d state %d\n", + args->v0.version, args->v0.state); + if (outpdp->lt.mst != !!args->v0.state) { + outpdp->lt.mst = !!args->v0.state; + atomic_set(&outpdp->lt.done, 0); + nvkm_output_dp_train(&outpdp->base, 0); + } + return 0; + } else + return ret; + } + break; case NV50_DISP_MTHD_V1_PIOR_PWR: if (!func->pior.power) return -ENODEV; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c index 49bd5da..520bf693 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c @@ -56,11 +56,13 @@ gf119_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef) clksor |= bw << 18; dpctrl |= ((1 << nr) - 1) << 16; + if (outp->lt.mst) + dpctrl |= 0x40000000; if (ef) dpctrl |= 0x00004000; nvkm_mask(device, 0x612300 + soff, 0x007c0000, clksor); - nvkm_mask(device, 0x61c10c + loff, 0x001f4000, dpctrl); + nvkm_mask(device, 0x61c10c + loff, 0x401f4000, dpctrl); return 0; } -- cgit v1.1 From 4cddeb9b315784c90c81db386943bca22690cb27 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 4 Nov 2016 17:20:35 +1000 Subject: drm/nouveau/disp/sor/gf119-: add method to program mst payload information Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/cl5070.h | 10 ++++++++++ drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h | 3 +++ .../gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c | 23 ++++++++++++++++++++++ .../gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c | 12 +++++++++++ .../gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c | 1 + .../gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c | 1 + 6 files changed, 50 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/include/nvif/cl5070.h b/drivers/gpu/drm/nouveau/include/nvif/cl5070.h index ed999fc..ae49dfd 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/cl5070.h +++ b/drivers/gpu/drm/nouveau/include/nvif/cl5070.h @@ -35,6 +35,7 @@ struct nv50_disp_mthd_v1 { #define NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT 0x23 #define NV50_DISP_MTHD_V1_SOR_DP_PWR 0x24 #define NV50_DISP_MTHD_V1_SOR_DP_MST_LINK 0x25 +#define NV50_DISP_MTHD_V1_SOR_DP_MST_VCPI 0x26 #define NV50_DISP_MTHD_V1_PIOR_PWR 0x30 __u8 method; __u16 hasht; @@ -97,6 +98,15 @@ struct nv50_disp_sor_dp_mst_link_v0 { __u8 pad02[6]; }; +struct nv50_disp_sor_dp_mst_vcpi_v0 { + __u8 version; + __u8 pad01[1]; + __u8 start_slot; + __u8 num_slots; + __u16 pbn; + __u16 aligned_pbn; +}; + struct nv50_disp_pior_pwr_v0 { __u8 version; __u8 state; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h index ef9ee0b..3c83a56 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h @@ -41,6 +41,8 @@ struct nvkm_output_dp_func { int (*lnk_pwr)(struct nvkm_output_dp *, int nr); int (*lnk_ctl)(struct nvkm_output_dp *, int nr, int bw, bool ef); int (*drv_ctl)(struct nvkm_output_dp *, int ln, int vs, int pe, int pc); + void (*vcpi)(struct nvkm_output_dp *, int head, u8 start_slot, + u8 num_slots, u16 pbn, u16 aligned_pbn); }; int nvkm_output_dp_train(struct nvkm_output *, u32 rate); @@ -63,6 +65,7 @@ int gf119_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, struct nvkm_output **); int gf119_sor_dp_lnk_ctl(struct nvkm_output_dp *, int, int, bool); int gf119_sor_dp_drv_ctl(struct nvkm_output_dp *, int, int, int, int); +void gf119_sor_dp_vcpi(struct nvkm_output_dp *, int, u8, u8, u16, u16); int gm107_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, struct nvkm_output **); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c index 1a25067..c1158b2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c @@ -200,6 +200,29 @@ nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size) return ret; } break; + case NV50_DISP_MTHD_V1_SOR_DP_MST_VCPI: { + struct nvkm_output_dp *outpdp = nvkm_output_dp(outp); + union { + struct nv50_disp_sor_dp_mst_vcpi_v0 v0; + } *args = data; + int ret = -ENOSYS; + nvif_ioctl(object, "disp sor dp mst vcpi size %d\n", size); + if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { + nvif_ioctl(object, "disp sor dp mst vcpi vers %d " + "slot %02x/%02x pbn %04x/%04x\n", + args->v0.version, args->v0.start_slot, + args->v0.num_slots, args->v0.pbn, + args->v0.aligned_pbn); + if (!outpdp->func->vcpi) + return -ENODEV; + outpdp->func->vcpi(outpdp, head, args->v0.start_slot, + args->v0.num_slots, args->v0.pbn, + args->v0.aligned_pbn); + return 0; + } else + return ret; + } + break; case NV50_DISP_MTHD_V1_PIOR_PWR: if (!func->pior.power) return -ENODEV; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c index 520bf693..6ffdaa6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c @@ -103,12 +103,24 @@ gf119_sor_dp_drv_ctl(struct nvkm_output_dp *outp, return 0; } +void +gf119_sor_dp_vcpi(struct nvkm_output_dp *outp, int head, u8 slot, + u8 slot_nr, u16 pbn, u16 aligned) +{ + struct nvkm_device *device = outp->base.disp->engine.subdev.device; + const u32 hoff = head * 0x800; + + nvkm_mask(device, 0x616588 + hoff, 0x00003f3f, (slot_nr << 8) | slot); + nvkm_mask(device, 0x61658c + hoff, 0xffffffff, (aligned << 16) | pbn); +} + static const struct nvkm_output_dp_func gf119_sor_dp_func = { .pattern = gf119_sor_dp_pattern, .lnk_pwr = g94_sor_dp_lnk_pwr, .lnk_ctl = gf119_sor_dp_lnk_ctl, .drv_ctl = gf119_sor_dp_drv_ctl, + .vcpi = gf119_sor_dp_vcpi, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c index 37790b2..4cf8ad4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c @@ -43,6 +43,7 @@ gm107_sor_dp_func = { .lnk_pwr = g94_sor_dp_lnk_pwr, .lnk_ctl = gf119_sor_dp_lnk_ctl, .drv_ctl = gf119_sor_dp_drv_ctl, + .vcpi = gf119_sor_dp_vcpi, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c index c44fa7e..81b788f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c @@ -120,6 +120,7 @@ gm200_sor_dp_func = { .lnk_pwr = gm200_sor_dp_lnk_pwr, .lnk_ctl = gf119_sor_dp_lnk_ctl, .drv_ctl = gm200_sor_dp_drv_ctl, + .vcpi = gf119_sor_dp_vcpi, }; int -- cgit v1.1 From 725fa3ac39bef350b24445740d3dcf3a5d4af841 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 4 Nov 2016 17:20:35 +1000 Subject: drm/nouveau/disp/g94-: stop listening for dp (sst) retrain irq when disabling link Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c | 1 + drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c index fd94241..7b346cc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c @@ -213,6 +213,7 @@ gf119_disp_intr_unk2_0(struct nv50_disp *disp, int head) .execute = 1, }; + nvkm_notify_put(&outpdp->irq); nvbios_exec(&init); atomic_set(&outpdp->lt.done, 0); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index a2bd0f0..567466f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -590,6 +590,7 @@ nv50_disp_intr_unk20_0(struct nv50_disp *disp, int head) .execute = 1, }; + nvkm_notify_put(&outpdp->irq); nvbios_exec(&init); atomic_set(&outpdp->lt.done, 0); } -- cgit v1.1 From 9dec9280523157da820f923e18dd6a7bf99fead7 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 4 Nov 2016 17:20:35 +1000 Subject: drm/nouveau/fbcon: make use of drm_fb_helper.dev No need to store the pointer ourselves when it's already present in the base struct. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_fbcon.c | 17 ++++++++--------- drivers/gpu/drm/nouveau/nouveau_fbcon.h | 1 - drivers/gpu/drm/nouveau/nv04_fbcon.c | 8 ++++---- drivers/gpu/drm/nouveau/nv50_fbcon.c | 8 ++++---- drivers/gpu/drm/nouveau/nvc0_fbcon.c | 8 ++++---- 5 files changed, 20 insertions(+), 22 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index 9f56927..2317447 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -58,7 +58,7 @@ static void nouveau_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) { struct nouveau_fbdev *fbcon = info->par; - struct nouveau_drm *drm = nouveau_drm(fbcon->dev); + struct nouveau_drm *drm = nouveau_drm(fbcon->helper.dev); struct nvif_device *device = &drm->device; int ret; @@ -90,7 +90,7 @@ static void nouveau_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *image) { struct nouveau_fbdev *fbcon = info->par; - struct nouveau_drm *drm = nouveau_drm(fbcon->dev); + struct nouveau_drm *drm = nouveau_drm(fbcon->helper.dev); struct nvif_device *device = &drm->device; int ret; @@ -122,7 +122,7 @@ static void nouveau_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) { struct nouveau_fbdev *fbcon = info->par; - struct nouveau_drm *drm = nouveau_drm(fbcon->dev); + struct nouveau_drm *drm = nouveau_drm(fbcon->helper.dev); struct nvif_device *device = &drm->device; int ret; @@ -154,7 +154,7 @@ static int nouveau_fbcon_sync(struct fb_info *info) { struct nouveau_fbdev *fbcon = info->par; - struct nouveau_drm *drm = nouveau_drm(fbcon->dev); + struct nouveau_drm *drm = nouveau_drm(fbcon->helper.dev); struct nouveau_channel *chan = drm->channel; int ret; @@ -181,7 +181,7 @@ static int nouveau_fbcon_open(struct fb_info *info, int user) { struct nouveau_fbdev *fbcon = info->par; - struct nouveau_drm *drm = nouveau_drm(fbcon->dev); + struct nouveau_drm *drm = nouveau_drm(fbcon->helper.dev); int ret = pm_runtime_get_sync(drm->dev->dev); if (ret < 0 && ret != -EACCES) return ret; @@ -192,7 +192,7 @@ static int nouveau_fbcon_release(struct fb_info *info, int user) { struct nouveau_fbdev *fbcon = info->par; - struct nouveau_drm *drm = nouveau_drm(fbcon->dev); + struct nouveau_drm *drm = nouveau_drm(fbcon->helper.dev); pm_runtime_put(drm->dev->dev); return 0; } @@ -333,7 +333,7 @@ nouveau_fbcon_create(struct drm_fb_helper *helper, { struct nouveau_fbdev *fbcon = container_of(helper, struct nouveau_fbdev, helper); - struct drm_device *dev = fbcon->dev; + struct drm_device *dev = fbcon->helper.dev; struct nouveau_drm *drm = nouveau_drm(dev); struct nvif_device *device = &drm->device; struct fb_info *info; @@ -479,7 +479,7 @@ nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbdev *fbcon) void nouveau_fbcon_gpu_lockup(struct fb_info *info) { struct nouveau_fbdev *fbcon = info->par; - struct nouveau_drm *drm = nouveau_drm(fbcon->dev); + struct nouveau_drm *drm = nouveau_drm(fbcon->helper.dev); NV_ERROR(drm, "GPU lockup - switching to software fbcon\n"); info->flags |= FBINFO_HWACCEL_DISABLED; @@ -522,7 +522,6 @@ nouveau_fbcon_init(struct drm_device *dev) if (!fbcon) return -ENOMEM; - fbcon->dev = dev; drm->fbcon = fbcon; drm_fb_helper_prepare(dev, &fbcon->helper, &nouveau_fbcon_helper_funcs); diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.h b/drivers/gpu/drm/nouveau/nouveau_fbcon.h index ca77ad0..710064d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.h +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.h @@ -34,7 +34,6 @@ struct nouveau_fbdev { struct drm_fb_helper helper; struct nouveau_framebuffer nouveau_fb; - struct drm_device *dev; unsigned int saved_flags; struct nvif_object surf2d; struct nvif_object clip; diff --git a/drivers/gpu/drm/nouveau/nv04_fbcon.c b/drivers/gpu/drm/nouveau/nv04_fbcon.c index da8fd5f..6a2b187 100644 --- a/drivers/gpu/drm/nouveau/nv04_fbcon.c +++ b/drivers/gpu/drm/nouveau/nv04_fbcon.c @@ -30,7 +30,7 @@ int nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) { struct nouveau_fbdev *nfbdev = info->par; - struct nouveau_drm *drm = nouveau_drm(nfbdev->dev); + struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev); struct nouveau_channel *chan = drm->channel; int ret; @@ -50,7 +50,7 @@ int nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) { struct nouveau_fbdev *nfbdev = info->par; - struct nouveau_drm *drm = nouveau_drm(nfbdev->dev); + struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev); struct nouveau_channel *chan = drm->channel; int ret; @@ -77,7 +77,7 @@ int nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) { struct nouveau_fbdev *nfbdev = info->par; - struct nouveau_drm *drm = nouveau_drm(nfbdev->dev); + struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev); struct nouveau_channel *chan = drm->channel; uint32_t fg; uint32_t bg; @@ -133,7 +133,7 @@ int nv04_fbcon_accel_init(struct fb_info *info) { struct nouveau_fbdev *nfbdev = info->par; - struct drm_device *dev = nfbdev->dev; + struct drm_device *dev = nfbdev->helper.dev; struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_channel *chan = drm->channel; struct nvif_device *device = &drm->device; diff --git a/drivers/gpu/drm/nouveau/nv50_fbcon.c b/drivers/gpu/drm/nouveau/nv50_fbcon.c index af3d3c4..6201812 100644 --- a/drivers/gpu/drm/nouveau/nv50_fbcon.c +++ b/drivers/gpu/drm/nouveau/nv50_fbcon.c @@ -30,7 +30,7 @@ int nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) { struct nouveau_fbdev *nfbdev = info->par; - struct nouveau_drm *drm = nouveau_drm(nfbdev->dev); + struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev); struct nouveau_channel *chan = drm->channel; int ret; @@ -65,7 +65,7 @@ int nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) { struct nouveau_fbdev *nfbdev = info->par; - struct nouveau_drm *drm = nouveau_drm(nfbdev->dev); + struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev); struct nouveau_channel *chan = drm->channel; int ret; @@ -93,7 +93,7 @@ int nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) { struct nouveau_fbdev *nfbdev = info->par; - struct nouveau_drm *drm = nouveau_drm(nfbdev->dev); + struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev); struct nouveau_channel *chan = drm->channel; uint32_t dwords, *data = (uint32_t *)image->data; uint32_t mask = ~(~0 >> (32 - info->var.bits_per_pixel)); @@ -149,7 +149,7 @@ nv50_fbcon_accel_init(struct fb_info *info) { struct nouveau_fbdev *nfbdev = info->par; struct nouveau_framebuffer *fb = &nfbdev->nouveau_fb; - struct drm_device *dev = nfbdev->dev; + struct drm_device *dev = nfbdev->helper.dev; struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_channel *chan = drm->channel; int ret, format; diff --git a/drivers/gpu/drm/nouveau/nvc0_fbcon.c b/drivers/gpu/drm/nouveau/nvc0_fbcon.c index 054b6a0..9a53833 100644 --- a/drivers/gpu/drm/nouveau/nvc0_fbcon.c +++ b/drivers/gpu/drm/nouveau/nvc0_fbcon.c @@ -30,7 +30,7 @@ int nvc0_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) { struct nouveau_fbdev *nfbdev = info->par; - struct nouveau_drm *drm = nouveau_drm(nfbdev->dev); + struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev); struct nouveau_channel *chan = drm->channel; int ret; @@ -65,7 +65,7 @@ int nvc0_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) { struct nouveau_fbdev *nfbdev = info->par; - struct nouveau_drm *drm = nouveau_drm(nfbdev->dev); + struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev); struct nouveau_channel *chan = drm->channel; int ret; @@ -93,7 +93,7 @@ int nvc0_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) { struct nouveau_fbdev *nfbdev = info->par; - struct nouveau_drm *drm = nouveau_drm(nfbdev->dev); + struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev); struct nouveau_channel *chan = drm->channel; uint32_t dwords, *data = (uint32_t *)image->data; uint32_t mask = ~(~0 >> (32 - info->var.bits_per_pixel)); @@ -148,7 +148,7 @@ int nvc0_fbcon_accel_init(struct fb_info *info) { struct nouveau_fbdev *nfbdev = info->par; - struct drm_device *dev = nfbdev->dev; + struct drm_device *dev = nfbdev->helper.dev; struct nouveau_framebuffer *fb = &nfbdev->nouveau_fb; struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_channel *chan = drm->channel; -- cgit v1.1 From 595b61cc1316c755c77f832fa27788a6fc1a8608 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 4 Nov 2016 17:20:35 +1000 Subject: drm/nouveau/fbcon: make use of drm_fb_helper.fb Transitional step towards properly refcounting the fbcon fb. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_fbcon.c | 52 ++++++++++++++------------------- drivers/gpu/drm/nouveau/nouveau_fbcon.h | 2 +- drivers/gpu/drm/nouveau/nv50_fbcon.c | 2 +- drivers/gpu/drm/nouveau/nvc0_fbcon.c | 2 +- 4 files changed, 25 insertions(+), 33 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index 2317447..392ed47 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -337,12 +337,11 @@ nouveau_fbcon_create(struct drm_fb_helper *helper, struct nouveau_drm *drm = nouveau_drm(dev); struct nvif_device *device = &drm->device; struct fb_info *info; - struct drm_framebuffer *fb; - struct nouveau_framebuffer *nouveau_fb; + struct nouveau_framebuffer *fb; struct nouveau_channel *chan; struct nouveau_bo *nvbo; struct drm_mode_fb_cmd2 mode_cmd; - int size, ret; + int ret; mode_cmd.width = sizes->surface_width; mode_cmd.height = sizes->surface_height; @@ -353,16 +352,16 @@ nouveau_fbcon_create(struct drm_fb_helper *helper, mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, sizes->surface_depth); - size = mode_cmd.pitches[0] * mode_cmd.height; - size = roundup(size, PAGE_SIZE); - - ret = nouveau_gem_new(dev, size, 0, NOUVEAU_GEM_DOMAIN_VRAM, - 0, 0x0000, &nvbo); + ret = nouveau_gem_new(dev, mode_cmd.pitches[0] * mode_cmd.height, + 0, NOUVEAU_GEM_DOMAIN_VRAM, 0, 0x0000, &nvbo); if (ret) { NV_ERROR(drm, "failed to allocate framebuffer\n"); goto out; } + nouveau_framebuffer_init(dev, &fbcon->fb, &mode_cmd, nvbo); + fb = &fbcon->fb; + ret = nouveau_bo_pin(nvbo, TTM_PL_FLAG_VRAM, false); if (ret) { NV_ERROR(drm, "failed to pin fb: %d\n", ret); @@ -377,8 +376,7 @@ nouveau_fbcon_create(struct drm_fb_helper *helper, chan = nouveau_nofbaccel ? NULL : drm->channel; if (chan && device->info.family >= NV_DEVICE_INFO_V0_TESLA) { - ret = nouveau_bo_vma_add(nvbo, drm->client.vm, - &fbcon->nouveau_fb.vma); + ret = nouveau_bo_vma_add(nvbo, drm->client.vm, &fb->vma); if (ret) { NV_ERROR(drm, "failed to map fb into chan: %d\n", ret); chan = NULL; @@ -394,13 +392,8 @@ nouveau_fbcon_create(struct drm_fb_helper *helper, info->par = fbcon; - nouveau_framebuffer_init(dev, &fbcon->nouveau_fb, &mode_cmd, nvbo); - - nouveau_fb = &fbcon->nouveau_fb; - fb = &nouveau_fb->base; - /* setup helper */ - fbcon->helper.fb = fb; + fbcon->helper.fb = &fb->base; strcpy(info->fix.id, "nouveaufb"); if (!chan) @@ -411,14 +404,14 @@ nouveau_fbcon_create(struct drm_fb_helper *helper, FBINFO_HWACCEL_IMAGEBLIT; info->flags |= FBINFO_CAN_FORCE_OUTPUT; info->fbops = &nouveau_fbcon_sw_ops; - info->fix.smem_start = nvbo->bo.mem.bus.base + - nvbo->bo.mem.bus.offset; - info->fix.smem_len = size; + info->fix.smem_start = fb->nvbo->bo.mem.bus.base + + fb->nvbo->bo.mem.bus.offset; + info->fix.smem_len = fb->nvbo->bo.mem.num_pages << PAGE_SHIFT; - info->screen_base = nvbo_kmap_obj_iovirtual(nouveau_fb->nvbo); - info->screen_size = size; + info->screen_base = nvbo_kmap_obj_iovirtual(fb->nvbo); + info->screen_size = fb->nvbo->bo.mem.num_pages << PAGE_SHIFT; - drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth); + drm_fb_helper_fill_fix(info, fb->base.pitches[0], fb->base.depth); drm_fb_helper_fill_var(info, &fbcon->helper, sizes->fb_width, sizes->fb_height); /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */ @@ -429,20 +422,19 @@ nouveau_fbcon_create(struct drm_fb_helper *helper, /* To allow resizeing without swapping buffers */ NV_INFO(drm, "allocated %dx%d fb: 0x%llx, bo %p\n", - nouveau_fb->base.width, nouveau_fb->base.height, - nvbo->bo.offset, nvbo); + fb->base.width, fb->base.height, fb->nvbo->bo.offset, nvbo); vga_switcheroo_client_fb_set(dev->pdev, info); return 0; out_unlock: if (chan) - nouveau_bo_vma_del(nvbo, &fbcon->nouveau_fb.vma); - nouveau_bo_unmap(nvbo); + nouveau_bo_vma_del(fb->nvbo, &fb->vma); + nouveau_bo_unmap(fb->nvbo); out_unpin: - nouveau_bo_unpin(nvbo); + nouveau_bo_unpin(fb->nvbo); out_unref: - nouveau_bo_ref(NULL, &nvbo); + nouveau_bo_ref(NULL, &fb->nvbo); out: return ret; } @@ -458,14 +450,14 @@ nouveau_fbcon_output_poll_changed(struct drm_device *dev) static int nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbdev *fbcon) { - struct nouveau_framebuffer *nouveau_fb = &fbcon->nouveau_fb; + struct nouveau_framebuffer *nouveau_fb = nouveau_framebuffer(fbcon->helper.fb); drm_fb_helper_unregister_fbi(&fbcon->helper); drm_fb_helper_release_fbi(&fbcon->helper); if (nouveau_fb->nvbo) { - nouveau_bo_unmap(nouveau_fb->nvbo); nouveau_bo_vma_del(nouveau_fb->nvbo, &nouveau_fb->vma); + nouveau_bo_unmap(nouveau_fb->nvbo); nouveau_bo_unpin(nouveau_fb->nvbo); drm_gem_object_unreference_unlocked(&nouveau_fb->nvbo->gem); nouveau_fb->nvbo = NULL; diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.h b/drivers/gpu/drm/nouveau/nouveau_fbcon.h index 710064d..35036a4 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.h +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.h @@ -33,7 +33,7 @@ struct nouveau_fbdev { struct drm_fb_helper helper; - struct nouveau_framebuffer nouveau_fb; + struct nouveau_framebuffer fb; unsigned int saved_flags; struct nvif_object surf2d; struct nvif_object clip; diff --git a/drivers/gpu/drm/nouveau/nv50_fbcon.c b/drivers/gpu/drm/nouveau/nv50_fbcon.c index 6201812..327dcd7 100644 --- a/drivers/gpu/drm/nouveau/nv50_fbcon.c +++ b/drivers/gpu/drm/nouveau/nv50_fbcon.c @@ -148,7 +148,7 @@ int nv50_fbcon_accel_init(struct fb_info *info) { struct nouveau_fbdev *nfbdev = info->par; - struct nouveau_framebuffer *fb = &nfbdev->nouveau_fb; + struct nouveau_framebuffer *fb = nouveau_framebuffer(nfbdev->helper.fb); struct drm_device *dev = nfbdev->helper.dev; struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_channel *chan = drm->channel; diff --git a/drivers/gpu/drm/nouveau/nvc0_fbcon.c b/drivers/gpu/drm/nouveau/nvc0_fbcon.c index 9a53833..90f27bf 100644 --- a/drivers/gpu/drm/nouveau/nvc0_fbcon.c +++ b/drivers/gpu/drm/nouveau/nvc0_fbcon.c @@ -149,7 +149,7 @@ nvc0_fbcon_accel_init(struct fb_info *info) { struct nouveau_fbdev *nfbdev = info->par; struct drm_device *dev = nfbdev->helper.dev; - struct nouveau_framebuffer *fb = &nfbdev->nouveau_fb; + struct nouveau_framebuffer *fb = nouveau_framebuffer(nfbdev->helper.fb); struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_channel *chan = drm->channel; int ret, format; -- cgit v1.1 From 1608a0fbb6923bf6989c90f0466ca2b87c722871 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 4 Nov 2016 17:20:35 +1000 Subject: drm/nouveau/fbcon: refcount the drm_framebuffer Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_display.c | 53 +++++++++++++++---------------- drivers/gpu/drm/nouveau/nouveau_display.h | 5 +-- drivers/gpu/drm/nouveau/nouveau_fbcon.c | 13 ++++---- drivers/gpu/drm/nouveau/nouveau_fbcon.h | 1 - 4 files changed, 34 insertions(+), 38 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index b60ee21..2b9e486 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -245,28 +245,32 @@ static const struct drm_framebuffer_funcs nouveau_framebuffer_funcs = { }; int -nouveau_framebuffer_init(struct drm_device *dev, - struct nouveau_framebuffer *nv_fb, - const struct drm_mode_fb_cmd2 *mode_cmd, - struct nouveau_bo *nvbo) +nouveau_framebuffer_new(struct drm_device *dev, + const struct drm_mode_fb_cmd2 *mode_cmd, + struct nouveau_bo *nvbo, + struct nouveau_framebuffer **pfb) { struct nouveau_display *disp = nouveau_display(dev); - struct drm_framebuffer *fb = &nv_fb->base; + struct nouveau_framebuffer *fb; int ret; - drm_helper_mode_fill_fb_struct(fb, mode_cmd); - nv_fb->nvbo = nvbo; + if (!(fb = kzalloc(sizeof(*fb), GFP_KERNEL))) + return -ENOMEM; - ret = drm_framebuffer_init(dev, fb, &nouveau_framebuffer_funcs); - if (ret) - return ret; + drm_helper_mode_fill_fb_struct(&fb->base, mode_cmd); + fb->nvbo = nvbo; - if (disp->fb_ctor) { - ret = disp->fb_ctor(fb); - if (ret) - disp->fb_dtor(fb); + ret = drm_framebuffer_init(dev, &fb->base, &nouveau_framebuffer_funcs); + if (ret == 0) { + if (!disp->fb_ctor || !(ret = disp->fb_ctor(&fb->base))) { + *pfb = fb; + return 0; + } + disp->fb_dtor(&fb->base); + drm_framebuffer_cleanup(&fb->base); } + kfree(fb); return ret; } @@ -275,27 +279,20 @@ nouveau_user_framebuffer_create(struct drm_device *dev, struct drm_file *file_priv, const struct drm_mode_fb_cmd2 *mode_cmd) { - struct nouveau_framebuffer *nouveau_fb; + struct nouveau_framebuffer *fb; + struct nouveau_bo *nvbo; struct drm_gem_object *gem; - int ret = -ENOMEM; + int ret; gem = drm_gem_object_lookup(file_priv, mode_cmd->handles[0]); if (!gem) return ERR_PTR(-ENOENT); + nvbo = nouveau_gem_object(gem); - nouveau_fb = kzalloc(sizeof(struct nouveau_framebuffer), GFP_KERNEL); - if (!nouveau_fb) - goto err_unref; - - ret = nouveau_framebuffer_init(dev, nouveau_fb, mode_cmd, nouveau_gem_object(gem)); - if (ret) - goto err; - - return &nouveau_fb->base; + ret = nouveau_framebuffer_new(dev, mode_cmd, nvbo, &fb); + if (ret == 0) + return &fb->base; -err: - kfree(nouveau_fb); -err_unref: drm_gem_object_unreference_unlocked(gem); return ERR_PTR(ret); } diff --git a/drivers/gpu/drm/nouveau/nouveau_display.h b/drivers/gpu/drm/nouveau/nouveau_display.h index 0420ee8..7866df8 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.h +++ b/drivers/gpu/drm/nouveau/nouveau_display.h @@ -22,8 +22,9 @@ nouveau_framebuffer(struct drm_framebuffer *fb) return container_of(fb, struct nouveau_framebuffer, base); } -int nouveau_framebuffer_init(struct drm_device *, struct nouveau_framebuffer *, - const struct drm_mode_fb_cmd2 *, struct nouveau_bo *); +int nouveau_framebuffer_new(struct drm_device *, + const struct drm_mode_fb_cmd2 *, + struct nouveau_bo *, struct nouveau_framebuffer **); struct nouveau_page_flip_state { struct list_head head; diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index 392ed47..4192b79 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -359,8 +359,9 @@ nouveau_fbcon_create(struct drm_fb_helper *helper, goto out; } - nouveau_framebuffer_init(dev, &fbcon->fb, &mode_cmd, nvbo); - fb = &fbcon->fb; + ret = nouveau_framebuffer_new(dev, &mode_cmd, nvbo, &fb); + if (ret) + goto out_unref; ret = nouveau_bo_pin(nvbo, TTM_PL_FLAG_VRAM, false); if (ret) { @@ -454,17 +455,15 @@ nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbdev *fbcon) drm_fb_helper_unregister_fbi(&fbcon->helper); drm_fb_helper_release_fbi(&fbcon->helper); + drm_fb_helper_fini(&fbcon->helper); if (nouveau_fb->nvbo) { nouveau_bo_vma_del(nouveau_fb->nvbo, &nouveau_fb->vma); nouveau_bo_unmap(nouveau_fb->nvbo); nouveau_bo_unpin(nouveau_fb->nvbo); - drm_gem_object_unreference_unlocked(&nouveau_fb->nvbo->gem); - nouveau_fb->nvbo = NULL; + drm_framebuffer_unreference(&nouveau_fb->base); } - drm_fb_helper_fini(&fbcon->helper); - drm_framebuffer_unregister_private(&nouveau_fb->base); - drm_framebuffer_cleanup(&nouveau_fb->base); + return 0; } diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.h b/drivers/gpu/drm/nouveau/nouveau_fbcon.h index 35036a4..e2bca72 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.h +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.h @@ -33,7 +33,6 @@ struct nouveau_fbdev { struct drm_fb_helper helper; - struct nouveau_framebuffer fb; unsigned int saved_flags; struct nvif_object surf2d; struct nvif_object clip; -- cgit v1.1 From d000edd36012e2bb921aa005e65ef990d81754da Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 4 Nov 2016 17:20:35 +1000 Subject: drm/nouveau/kms: drop dpms off/on in response to hotplug This primarily existed to ensure the DP link got retrained, and is now unnecessary as that's handled by NVKM already. For anything beyond that, we send an event to userspace and let it decide on an appropriate action to take. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_connector.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index c108408..1bdfb8f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -1001,14 +1001,6 @@ nouveau_connector_hotplug(struct nvif_notify *notify) bool plugged = (rep->mask != NVIF_NOTIFY_CONN_V0_UNPLUG); NV_DEBUG(drm, "%splugged %s\n", plugged ? "" : "un", name); - - mutex_lock(&drm->dev->mode_config.mutex); - if (plugged) - drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); - else - drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); - mutex_unlock(&drm->dev->mode_config.mutex); - drm_helper_hpd_irq_event(connector->dev); } -- cgit v1.1 From 3b4c0abb1bb72304c78d5919d20c4814424fff79 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 4 Nov 2016 17:20:35 +1000 Subject: drm/nouveau/kms: move drm_crtc_force_disable_all() earlier nouveau_display_fini() is responsible for quiescing the hardware, so this is where such actions belong. More than that, nouveau_display_fini() switches off the receiving of sink irqs, which MST will require while shutting down an active head. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_display.c | 8 +++++--- drivers/gpu/drm/nouveau/nouveau_display.h | 2 +- drivers/gpu/drm/nouveau/nouveau_drm.c | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 2b9e486..081af3a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -382,13 +382,16 @@ nouveau_display_init(struct drm_device *dev) } void -nouveau_display_fini(struct drm_device *dev) +nouveau_display_fini(struct drm_device *dev, bool suspend) { struct nouveau_display *disp = nouveau_display(dev); struct nouveau_drm *drm = nouveau_drm(dev); struct drm_connector *connector; int head; + if (!suspend) + drm_crtc_force_disable_all(dev); + /* Make sure that drm and hw vblank irqs get properly disabled. */ for (head = 0; head < dev->mode_config.num_crtc; head++) drm_vblank_off(dev, head); @@ -553,7 +556,6 @@ nouveau_display_destroy(struct drm_device *dev) nouveau_display_vblank_fini(dev); drm_kms_helper_poll_fini(dev); - drm_crtc_force_disable_all(dev); drm_mode_config_cleanup(dev); if (disp->dtor) @@ -570,7 +572,7 @@ nouveau_display_suspend(struct drm_device *dev, bool runtime) { struct drm_crtc *crtc; - nouveau_display_fini(dev); + nouveau_display_fini(dev, true); list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { struct nouveau_framebuffer *nouveau_fb; diff --git a/drivers/gpu/drm/nouveau/nouveau_display.h b/drivers/gpu/drm/nouveau/nouveau_display.h index 7866df8..3760f0e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.h +++ b/drivers/gpu/drm/nouveau/nouveau_display.h @@ -64,7 +64,7 @@ nouveau_display(struct drm_device *dev) int nouveau_display_create(struct drm_device *dev); void nouveau_display_destroy(struct drm_device *dev); int nouveau_display_init(struct drm_device *dev); -void nouveau_display_fini(struct drm_device *dev); +void nouveau_display_fini(struct drm_device *dev, bool suspend); int nouveau_display_suspend(struct drm_device *dev, bool runtime); void nouveau_display_resume(struct drm_device *dev, bool runtime); int nouveau_display_vblank_enable(struct drm_device *, unsigned int); diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 6228815..9876e6f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -519,7 +519,7 @@ nouveau_drm_unload(struct drm_device *dev) nouveau_debugfs_fini(drm); if (dev->mode_config.num_crtc) - nouveau_display_fini(dev); + nouveau_display_fini(dev, false); nouveau_display_destroy(dev); nouveau_bios_takedown(dev); -- cgit v1.1 From 07193f705154e26e1a246b81a5ae59f6354e8e7a Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 4 Nov 2016 17:20:35 +1000 Subject: drm/nouveau/kms: execute drm_mode_config_reset() after constructing display This will ensure we have some kind of initial atomic state for all objects after initialisation. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_display.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 081af3a..1c4b2ca 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -530,6 +530,8 @@ nouveau_display_create(struct drm_device *dev) if (ret) goto disp_create_err; + drm_mode_config_reset(dev); + if (dev->mode_config.num_crtc) { ret = nouveau_display_vblank_init(dev); if (ret) -- cgit v1.1 From 616915ec7629af65532e2220792e3ec83ee3510b Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 4 Nov 2016 17:20:35 +1000 Subject: drm/nouveau/kms: subclass atomic connector state This commit implements the atomic property hooks for a connector, and wraps the legacy interface handling on top of those. For the moment, a full modeset will be done after any property change in order to ease subsequent changes. The optimised behaviour will be restored for Tesla and later (earlier boards always do full modesets) once atomic commits are implemented. Some functions are put under the "nouveau_conn" namespace now, rather than "nouveau_connector", to distinguish functions that will work for (upcoming) MST connectors too. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_connector.c | 461 ++++++++++++++++------------ drivers/gpu/drm/nouveau/nouveau_connector.h | 92 ++++-- drivers/gpu/drm/nouveau/nouveau_crtc.h | 4 - drivers/gpu/drm/nouveau/nv50_display.c | 3 - 4 files changed, 339 insertions(+), 221 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 1bdfb8f..a7b8f68 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -30,6 +30,7 @@ #include #include +#include #include #include @@ -47,6 +48,229 @@ #include #include +struct drm_display_mode * +nouveau_conn_native_mode(struct drm_connector *connector) +{ + const struct drm_connector_helper_funcs *helper = connector->helper_private; + struct nouveau_drm *drm = nouveau_drm(connector->dev); + struct drm_device *dev = connector->dev; + struct drm_display_mode *mode, *largest = NULL; + int high_w = 0, high_h = 0, high_v = 0; + + list_for_each_entry(mode, &connector->probed_modes, head) { + mode->vrefresh = drm_mode_vrefresh(mode); + if (helper->mode_valid(connector, mode) != MODE_OK || + (mode->flags & DRM_MODE_FLAG_INTERLACE)) + continue; + + /* Use preferred mode if there is one.. */ + if (mode->type & DRM_MODE_TYPE_PREFERRED) { + NV_DEBUG(drm, "native mode from preferred\n"); + return drm_mode_duplicate(dev, mode); + } + + /* Otherwise, take the resolution with the largest width, then + * height, then vertical refresh + */ + if (mode->hdisplay < high_w) + continue; + + if (mode->hdisplay == high_w && mode->vdisplay < high_h) + continue; + + if (mode->hdisplay == high_w && mode->vdisplay == high_h && + mode->vrefresh < high_v) + continue; + + high_w = mode->hdisplay; + high_h = mode->vdisplay; + high_v = mode->vrefresh; + largest = mode; + } + + NV_DEBUG(drm, "native mode from largest: %dx%d@%d\n", + high_w, high_h, high_v); + return largest ? drm_mode_duplicate(dev, largest) : NULL; +} + +int +nouveau_conn_atomic_get_property(struct drm_connector *connector, + const struct drm_connector_state *state, + struct drm_property *property, u64 *val) +{ + struct nouveau_conn_atom *asyc = nouveau_conn_atom(state); + struct nouveau_display *disp = nouveau_display(connector->dev); + struct drm_device *dev = connector->dev; + + if (property == dev->mode_config.scaling_mode_property) + *val = asyc->scaler.mode; + else if (property == disp->underscan_property) + *val = asyc->scaler.underscan.mode; + else if (property == disp->underscan_hborder_property) + *val = asyc->scaler.underscan.hborder; + else if (property == disp->underscan_vborder_property) + *val = asyc->scaler.underscan.vborder; + else if (property == disp->dithering_mode) + *val = asyc->dither.mode; + else if (property == disp->dithering_depth) + *val = asyc->dither.depth; + else if (property == disp->vibrant_hue_property) + *val = asyc->procamp.vibrant_hue; + else if (property == disp->color_vibrance_property) + *val = asyc->procamp.color_vibrance; + else + return -EINVAL; + + return 0; +} + +int +nouveau_conn_atomic_set_property(struct drm_connector *connector, + struct drm_connector_state *state, + struct drm_property *property, u64 val) +{ + struct drm_device *dev = connector->dev; + struct nouveau_conn_atom *asyc = nouveau_conn_atom(state); + struct nouveau_display *disp = nouveau_display(dev); + + if (property == dev->mode_config.scaling_mode_property) { + switch (val) { + case DRM_MODE_SCALE_NONE: + /* We allow 'None' for EDID modes, even on a fixed + * panel (some exist with support for lower refresh + * rates, which people might want to use for power- + * saving purposes). + * + * Non-EDID modes will force the use of GPU scaling + * to the native mode regardless of this setting. + */ + switch (connector->connector_type) { + case DRM_MODE_CONNECTOR_LVDS: + case DRM_MODE_CONNECTOR_eDP: + /* ... except prior to G80, where the code + * doesn't support such things. + */ + if (disp->disp.oclass < NV50_DISP) + return -EINVAL; + break; + default: + break; + } + case DRM_MODE_SCALE_FULLSCREEN: + case DRM_MODE_SCALE_CENTER: + case DRM_MODE_SCALE_ASPECT: + break; + default: + return -EINVAL; + } + + if (asyc->scaler.mode != val) { + asyc->scaler.mode = val; + asyc->set.scaler = true; + } + } else + if (property == disp->underscan_property) { + if (asyc->scaler.underscan.mode != val) { + asyc->scaler.underscan.mode = val; + asyc->set.scaler = true; + } + } else + if (property == disp->underscan_hborder_property) { + if (asyc->scaler.underscan.hborder != val) { + asyc->scaler.underscan.hborder = val; + asyc->set.scaler = true; + } + } else + if (property == disp->underscan_vborder_property) { + if (asyc->scaler.underscan.vborder != val) { + asyc->scaler.underscan.vborder = val; + asyc->set.scaler = true; + } + } else + if (property == disp->dithering_mode) { + if (asyc->dither.mode != val) { + asyc->dither.mode = val; + asyc->set.dither = true; + } + } else + if (property == disp->dithering_depth) { + if (asyc->dither.mode != val) { + asyc->dither.depth = val; + asyc->set.dither = true; + } + } else + if (property == disp->vibrant_hue_property) { + if (asyc->procamp.vibrant_hue != val) { + asyc->procamp.vibrant_hue = val; + asyc->set.procamp = true; + } + } else + if (property == disp->color_vibrance_property) { + if (asyc->procamp.color_vibrance != val) { + asyc->procamp.color_vibrance = val; + asyc->set.procamp = true; + } + } else { + return -EINVAL; + } + + return 0; +} + +void +nouveau_conn_atomic_destroy_state(struct drm_connector *connector, + struct drm_connector_state *state) +{ + struct nouveau_conn_atom *asyc = nouveau_conn_atom(state); + __drm_atomic_helper_connector_destroy_state(&asyc->state); + kfree(asyc); +} + +struct drm_connector_state * +nouveau_conn_atomic_duplicate_state(struct drm_connector *connector) +{ + struct nouveau_conn_atom *armc = nouveau_conn_atom(connector->state); + struct nouveau_conn_atom *asyc; + if (!(asyc = kmalloc(sizeof(*asyc), GFP_KERNEL))) + return NULL; + __drm_atomic_helper_connector_duplicate_state(connector, &asyc->state); + asyc->dither = armc->dither; + asyc->scaler = armc->scaler; + asyc->procamp = armc->procamp; + asyc->set.mask = 0; + return &asyc->state; +} + +void +nouveau_conn_reset(struct drm_connector *connector) +{ + struct nouveau_conn_atom *asyc; + + if (WARN_ON(!(asyc = kzalloc(sizeof(*asyc), GFP_KERNEL)))) + return; + + if (connector->state) + __drm_atomic_helper_connector_destroy_state(connector->state); + __drm_atomic_helper_connector_reset(connector, &asyc->state); + asyc->dither.mode = DITHERING_MODE_AUTO; + asyc->dither.depth = DITHERING_DEPTH_AUTO; + asyc->scaler.mode = DRM_MODE_SCALE_NONE; + asyc->scaler.underscan.mode = UNDERSCAN_OFF; + asyc->procamp.color_vibrance = 150; + asyc->procamp.vibrant_hue = 90; + + if (nouveau_display(connector->dev)->disp.oclass < NV50_DISP) { + switch (connector->connector_type) { + case DRM_MODE_CONNECTOR_LVDS: + /* See note in nouveau_conn_atomic_set_property(). */ + asyc->scaler.mode = DRM_MODE_SCALE_FULLSCREEN; + break; + default: + break; + } + } +} + MODULE_PARM_DESC(tv_disable, "Disable TV-out detection"); int nouveau_tv_disable = 0; module_param_named(tv_disable, nouveau_tv_disable, int, 0400); @@ -465,199 +689,44 @@ static int nouveau_connector_set_property(struct drm_connector *connector, struct drm_property *property, uint64_t value) { - struct nouveau_display *disp = nouveau_display(connector->dev); + struct nouveau_conn_atom *asyc = nouveau_conn_atom(connector->state); struct nouveau_connector *nv_connector = nouveau_connector(connector); struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder; struct drm_encoder *encoder = to_drm_encoder(nv_encoder); - struct drm_device *dev = connector->dev; - struct nouveau_crtc *nv_crtc; + struct nouveau_crtc *nv_crtc = NULL; int ret; - nv_crtc = NULL; - if (connector->encoder && connector->encoder->crtc) - nv_crtc = nouveau_crtc(connector->encoder->crtc); - - /* Scaling mode */ - if (property == dev->mode_config.scaling_mode_property) { - bool modeset = false; - - switch (value) { - case DRM_MODE_SCALE_NONE: - /* We allow 'None' for EDID modes, even on a fixed - * panel (some exist with support for lower refresh - * rates, which people might want to use for power - * saving purposes). - * - * Non-EDID modes will force the use of GPU scaling - * to the native mode regardless of this setting. - */ - switch (nv_connector->type) { - case DCB_CONNECTOR_LVDS: - case DCB_CONNECTOR_LVDS_SPWG: - case DCB_CONNECTOR_eDP: - /* ... except prior to G80, where the code - * doesn't support such things. - */ - if (disp->disp.oclass < NV50_DISP) - return -EINVAL; - break; - default: - break; - } - break; - case DRM_MODE_SCALE_FULLSCREEN: - case DRM_MODE_SCALE_CENTER: - case DRM_MODE_SCALE_ASPECT: - break; - default: - return -EINVAL; - } - - /* Changing between GPU and panel scaling requires a full - * modeset - */ - if ((nv_connector->scaling_mode == DRM_MODE_SCALE_NONE) || - (value == DRM_MODE_SCALE_NONE)) - modeset = true; - nv_connector->scaling_mode = value; - - if (!nv_crtc) - return 0; - - if (modeset || !nv_crtc->set_scale) { - ret = drm_crtc_helper_set_mode(&nv_crtc->base, - &nv_crtc->base.mode, - nv_crtc->base.x, - nv_crtc->base.y, NULL); - if (!ret) - return -EINVAL; - } else { - ret = nv_crtc->set_scale(nv_crtc, true); - if (ret) - return ret; - } - - return 0; - } - - /* Underscan */ - if (property == disp->underscan_property) { - if (nv_connector->underscan != value) { - nv_connector->underscan = value; - if (!nv_crtc || !nv_crtc->set_scale) - return 0; - - return nv_crtc->set_scale(nv_crtc, true); - } - - return 0; + ret = connector->funcs->atomic_set_property(&nv_connector->base, + &asyc->state, + property, value); + if (ret) { + if (nv_encoder && nv_encoder->dcb->type == DCB_OUTPUT_TV) + return get_slave_funcs(encoder)->set_property( + encoder, connector, property, value); + return ret; } - if (property == disp->underscan_hborder_property) { - if (nv_connector->underscan_hborder != value) { - nv_connector->underscan_hborder = value; - if (!nv_crtc || !nv_crtc->set_scale) - return 0; - - return nv_crtc->set_scale(nv_crtc, true); - } + nv_connector->scaling_mode = asyc->scaler.mode; + nv_connector->underscan = asyc->scaler.underscan.mode; + nv_connector->underscan_hborder = asyc->scaler.underscan.hborder; + nv_connector->underscan_vborder = asyc->scaler.underscan.vborder; + nv_connector->dithering_mode = asyc->dither.mode; + nv_connector->dithering_depth = asyc->dither.depth; + if (connector->encoder && connector->encoder->crtc) + nv_crtc = nouveau_crtc(connector->encoder->crtc); + if (!nv_crtc) return 0; - } - if (property == disp->underscan_vborder_property) { - if (nv_connector->underscan_vborder != value) { - nv_connector->underscan_vborder = value; - if (!nv_crtc || !nv_crtc->set_scale) - return 0; - - return nv_crtc->set_scale(nv_crtc, true); - } + nv_crtc->vibrant_hue = asyc->procamp.vibrant_hue - 90; + nv_crtc->color_vibrance = asyc->procamp.color_vibrance - 100; - return 0; - } - - /* Dithering */ - if (property == disp->dithering_mode) { - nv_connector->dithering_mode = value; - if (!nv_crtc || !nv_crtc->set_dither) - return 0; + ret = drm_crtc_helper_set_mode(&nv_crtc->base, &nv_crtc->base.mode, + nv_crtc->base.x, nv_crtc->base.y, NULL); + if (!ret) + return -EINVAL; - return nv_crtc->set_dither(nv_crtc, true); - } - - if (property == disp->dithering_depth) { - nv_connector->dithering_depth = value; - if (!nv_crtc || !nv_crtc->set_dither) - return 0; - - return nv_crtc->set_dither(nv_crtc, true); - } - - if (nv_crtc && nv_crtc->set_color_vibrance) { - /* Hue */ - if (property == disp->vibrant_hue_property) { - nv_crtc->vibrant_hue = value - 90; - return nv_crtc->set_color_vibrance(nv_crtc, true); - } - /* Saturation */ - if (property == disp->color_vibrance_property) { - nv_crtc->color_vibrance = value - 100; - return nv_crtc->set_color_vibrance(nv_crtc, true); - } - } - - if (nv_encoder && nv_encoder->dcb->type == DCB_OUTPUT_TV) - return get_slave_funcs(encoder)->set_property( - encoder, connector, property, value); - - return -EINVAL; -} - -static struct drm_display_mode * -nouveau_connector_native_mode(struct drm_connector *connector) -{ - const struct drm_connector_helper_funcs *helper = connector->helper_private; - struct nouveau_drm *drm = nouveau_drm(connector->dev); - struct nouveau_connector *nv_connector = nouveau_connector(connector); - struct drm_device *dev = connector->dev; - struct drm_display_mode *mode, *largest = NULL; - int high_w = 0, high_h = 0, high_v = 0; - - list_for_each_entry(mode, &nv_connector->base.probed_modes, head) { - mode->vrefresh = drm_mode_vrefresh(mode); - if (helper->mode_valid(connector, mode) != MODE_OK || - (mode->flags & DRM_MODE_FLAG_INTERLACE)) - continue; - - /* Use preferred mode if there is one.. */ - if (mode->type & DRM_MODE_TYPE_PREFERRED) { - NV_DEBUG(drm, "native mode from preferred\n"); - return drm_mode_duplicate(dev, mode); - } - - /* Otherwise, take the resolution with the largest width, then - * height, then vertical refresh - */ - if (mode->hdisplay < high_w) - continue; - - if (mode->hdisplay == high_w && mode->vdisplay < high_h) - continue; - - if (mode->hdisplay == high_w && mode->vdisplay == high_h && - mode->vrefresh < high_v) - continue; - - high_w = mode->hdisplay; - high_h = mode->vdisplay; - high_v = mode->vrefresh; - largest = mode; - } - - NV_DEBUG(drm, "native mode from largest: %dx%d@%d\n", - high_w, high_h, high_v); - return largest ? drm_mode_duplicate(dev, largest) : NULL; + return 0; } struct moderec { @@ -805,8 +874,7 @@ nouveau_connector_get_modes(struct drm_connector *connector) * the list of modes. */ if (!nv_connector->native_mode) - nv_connector->native_mode = - nouveau_connector_native_mode(connector); + nv_connector->native_mode = nouveau_conn_native_mode(connector); if (ret == 0 && nv_connector->native_mode) { struct drm_display_mode *mode; @@ -937,21 +1005,31 @@ nouveau_connector_helper_funcs = { static const struct drm_connector_funcs nouveau_connector_funcs = { .dpms = drm_helper_connector_dpms, + .reset = nouveau_conn_reset, .detect = nouveau_connector_detect, - .destroy = nouveau_connector_destroy, + .force = nouveau_connector_force, .fill_modes = drm_helper_probe_single_connector_modes, .set_property = nouveau_connector_set_property, - .force = nouveau_connector_force + .destroy = nouveau_connector_destroy, + .atomic_duplicate_state = nouveau_conn_atomic_duplicate_state, + .atomic_destroy_state = nouveau_conn_atomic_destroy_state, + .atomic_set_property = nouveau_conn_atomic_set_property, + .atomic_get_property = nouveau_conn_atomic_get_property, }; static const struct drm_connector_funcs nouveau_connector_funcs_lvds = { .dpms = drm_helper_connector_dpms, + .reset = nouveau_conn_reset, .detect = nouveau_connector_detect_lvds, - .destroy = nouveau_connector_destroy, + .force = nouveau_connector_force, .fill_modes = drm_helper_probe_single_connector_modes, .set_property = nouveau_connector_set_property, - .force = nouveau_connector_force + .destroy = nouveau_connector_destroy, + .atomic_duplicate_state = nouveau_conn_atomic_duplicate_state, + .atomic_destroy_state = nouveau_conn_atomic_destroy_state, + .atomic_set_property = nouveau_conn_atomic_set_property, + .atomic_get_property = nouveau_conn_atomic_get_property, }; static int @@ -979,11 +1057,16 @@ nouveau_connector_dp_dpms(struct drm_connector *connector, int mode) static const struct drm_connector_funcs nouveau_connector_funcs_dp = { .dpms = nouveau_connector_dp_dpms, + .reset = nouveau_conn_reset, .detect = nouveau_connector_detect, - .destroy = nouveau_connector_destroy, + .force = nouveau_connector_force, .fill_modes = drm_helper_probe_single_connector_modes, .set_property = nouveau_connector_set_property, - .force = nouveau_connector_force + .destroy = nouveau_connector_destroy, + .atomic_duplicate_state = nouveau_conn_atomic_duplicate_state, + .atomic_destroy_state = nouveau_conn_atomic_destroy_state, + .atomic_set_property = nouveau_conn_atomic_set_property, + .atomic_get_property = nouveau_conn_atomic_get_property, }; static int diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.h b/drivers/gpu/drm/nouveau/nouveau_connector.h index 43b9583..c366b38 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.h +++ b/drivers/gpu/drm/nouveau/nouveau_connector.h @@ -35,30 +35,6 @@ struct nvkm_i2c_port; -enum nouveau_underscan_type { - UNDERSCAN_OFF, - UNDERSCAN_ON, - UNDERSCAN_AUTO, -}; - -/* the enum values specifically defined here match nv50/nvd0 hw values, and - * the code relies on this - */ -enum nouveau_dithering_mode { - DITHERING_MODE_OFF = 0x00, - DITHERING_MODE_ON = 0x01, - DITHERING_MODE_DYNAMIC2X2 = 0x10 | DITHERING_MODE_ON, - DITHERING_MODE_STATIC2X2 = 0x18 | DITHERING_MODE_ON, - DITHERING_MODE_TEMPORAL = 0x20 | DITHERING_MODE_ON, - DITHERING_MODE_AUTO -}; - -enum nouveau_dithering_depth { - DITHERING_DEPTH_6BPC = 0x00, - DITHERING_DEPTH_8BPC = 0x02, - DITHERING_DEPTH_AUTO -}; - struct nouveau_connector { struct drm_connector base; enum dcb_connector_type type; @@ -73,7 +49,7 @@ struct nouveau_connector { int dithering_depth; int scaling_mode; bool scaling_full; - enum nouveau_underscan_type underscan; + int underscan; u32 underscan_hborder; u32 underscan_vborder; @@ -111,4 +87,70 @@ extern int nouveau_ignorelid; extern int nouveau_duallink; extern int nouveau_hdmimhz; +#include +#define nouveau_conn_atom(p) \ + container_of((p), struct nouveau_conn_atom, state) + +struct nouveau_conn_atom { + struct drm_connector_state state; + + struct { + /* The enum values specifically defined here match nv50/gf119 + * hw values, and the code relies on this. + */ + enum { + DITHERING_MODE_OFF = 0x00, + DITHERING_MODE_ON = 0x01, + DITHERING_MODE_DYNAMIC2X2 = 0x10 | DITHERING_MODE_ON, + DITHERING_MODE_STATIC2X2 = 0x18 | DITHERING_MODE_ON, + DITHERING_MODE_TEMPORAL = 0x20 | DITHERING_MODE_ON, + DITHERING_MODE_AUTO + } mode; + enum { + DITHERING_DEPTH_6BPC = 0x00, + DITHERING_DEPTH_8BPC = 0x02, + DITHERING_DEPTH_AUTO + } depth; + } dither; + + struct { + int mode; /* DRM_MODE_SCALE_* */ + struct { + enum { + UNDERSCAN_OFF, + UNDERSCAN_ON, + UNDERSCAN_AUTO, + } mode; + u32 hborder; + u32 vborder; + } underscan; + } scaler; + + struct { + int color_vibrance; + int vibrant_hue; + } procamp; + + union { + struct { + bool dither:1; + bool scaler:1; + bool procamp:1; + }; + u8 mask; + } set; +}; + +void nouveau_conn_reset(struct drm_connector *); +struct drm_connector_state * +nouveau_conn_atomic_duplicate_state(struct drm_connector *); +void nouveau_conn_atomic_destroy_state(struct drm_connector *, + struct drm_connector_state *); +int nouveau_conn_atomic_set_property(struct drm_connector *, + struct drm_connector_state *, + struct drm_property *, u64); +int nouveau_conn_atomic_get_property(struct drm_connector *, + const struct drm_connector_state *, + struct drm_property *, u64 *); +struct drm_display_mode *nouveau_conn_native_mode(struct drm_connector *); #endif /* __NOUVEAU_CONNECTOR_H__ */ diff --git a/drivers/gpu/drm/nouveau/nouveau_crtc.h b/drivers/gpu/drm/nouveau/nouveau_crtc.h index 863f10b..d533a32 100644 --- a/drivers/gpu/drm/nouveau/nouveau_crtc.h +++ b/drivers/gpu/drm/nouveau/nouveau_crtc.h @@ -70,10 +70,6 @@ struct nouveau_crtc { int depth; } lut; - int (*set_dither)(struct nouveau_crtc *crtc, bool update); - int (*set_scale)(struct nouveau_crtc *crtc, bool update); - int (*set_color_vibrance)(struct nouveau_crtc *crtc, bool update); - void (*save)(struct drm_crtc *crtc); void (*restore)(struct drm_crtc *crtc); }; diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 7d0edcb..99a3866 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -1448,9 +1448,6 @@ nv50_crtc_create(struct drm_device *dev, int index) return -ENOMEM; head->base.index = index; - head->base.set_dither = nv50_crtc_set_dither; - head->base.set_scale = nv50_crtc_set_scale; - head->base.set_color_vibrance = nv50_crtc_set_color_vibrance; head->base.color_vibrance = 50; head->base.vibrant_hue = 0; head->base.cursor.set_pos = nv50_crtc_cursor_restore; -- cgit v1.1 From 56182b8bd14bb8fe85d4d6e6bcbc9779ad538288 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 4 Nov 2016 17:20:35 +1000 Subject: drm/nouveau/kms: separate connector property attach from nouveau_connector These will also be used by MST connectors. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_connector.c | 139 +++++++++++++++------------- drivers/gpu/drm/nouveau/nouveau_connector.h | 1 + 2 files changed, 78 insertions(+), 62 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index a7b8f68..c08d5e6 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -271,6 +271,78 @@ nouveau_conn_reset(struct drm_connector *connector) } } +void +nouveau_conn_attach_properties(struct drm_connector *connector) +{ + struct drm_device *dev = connector->dev; + struct nouveau_conn_atom *armc = nouveau_conn_atom(connector->state); + struct nouveau_display *disp = nouveau_display(dev); + + /* Init DVI-I specific properties. */ + if (connector->connector_type == DRM_MODE_CONNECTOR_DVII) + drm_object_attach_property(&connector->base, dev->mode_config. + dvi_i_subconnector_property, 0); + + /* Add overscan compensation options to digital outputs. */ + if (disp->underscan_property && + (connector->connector_type == DRM_MODE_CONNECTOR_DVID || + connector->connector_type == DRM_MODE_CONNECTOR_DVII || + connector->connector_type == DRM_MODE_CONNECTOR_HDMIA || + connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort)) { + drm_object_attach_property(&connector->base, + disp->underscan_property, + UNDERSCAN_OFF); + drm_object_attach_property(&connector->base, + disp->underscan_hborder_property, 0); + drm_object_attach_property(&connector->base, + disp->underscan_vborder_property, 0); + } + + /* Add hue and saturation options. */ + if (disp->vibrant_hue_property) + drm_object_attach_property(&connector->base, + disp->vibrant_hue_property, + armc->procamp.vibrant_hue); + if (disp->color_vibrance_property) + drm_object_attach_property(&connector->base, + disp->color_vibrance_property, + armc->procamp.color_vibrance); + + /* Scaling mode property. */ + switch (connector->connector_type) { + case DRM_MODE_CONNECTOR_TV: + break; + case DRM_MODE_CONNECTOR_VGA: + if (disp->disp.oclass < NV50_DISP) + break; /* Can only scale on DFPs. */ + /* Fall-through. */ + default: + drm_object_attach_property(&connector->base, dev->mode_config. + scaling_mode_property, + armc->scaler.mode); + break; + } + + /* Dithering properties. */ + switch (connector->connector_type) { + case DRM_MODE_CONNECTOR_TV: + case DRM_MODE_CONNECTOR_VGA: + break; + default: + if (disp->dithering_mode) { + drm_object_attach_property(&connector->base, + disp->dithering_mode, + armc->dither.mode); + } + if (disp->dithering_depth) { + drm_object_attach_property(&connector->base, + disp->dithering_depth, + armc->dither.depth); + } + break; + } +} + MODULE_PARM_DESC(tv_disable, "Disable TV-out detection"); int nouveau_tv_disable = 0; module_param_named(tv_disable, nouveau_tv_disable, int, 0400); @@ -1277,38 +1349,10 @@ nouveau_connector_create(struct drm_device *dev, int index) drm_connector_init(dev, connector, funcs, type); drm_connector_helper_add(connector, &nouveau_connector_helper_funcs); - /* Init DVI-I specific properties */ - if (nv_connector->type == DCB_CONNECTOR_DVI_I) - drm_object_attach_property(&connector->base, dev->mode_config.dvi_i_subconnector_property, 0); - - /* Add overscan compensation options to digital outputs */ - if (disp->underscan_property && - (type == DRM_MODE_CONNECTOR_DVID || - type == DRM_MODE_CONNECTOR_DVII || - type == DRM_MODE_CONNECTOR_HDMIA || - type == DRM_MODE_CONNECTOR_DisplayPort)) { - drm_object_attach_property(&connector->base, - disp->underscan_property, - UNDERSCAN_OFF); - drm_object_attach_property(&connector->base, - disp->underscan_hborder_property, - 0); - drm_object_attach_property(&connector->base, - disp->underscan_vborder_property, - 0); - } - - /* Add hue and saturation options */ - if (disp->vibrant_hue_property) - drm_object_attach_property(&connector->base, - disp->vibrant_hue_property, - 90); - if (disp->color_vibrance_property) - drm_object_attach_property(&connector->base, - disp->color_vibrance_property, - 150); + connector->funcs->reset(connector); + nouveau_conn_attach_properties(connector); - /* default scaling mode */ + /* Default scaling mode */ switch (nv_connector->type) { case DCB_CONNECTOR_LVDS: case DCB_CONNECTOR_LVDS_SPWG: @@ -1325,23 +1369,6 @@ nouveau_connector_create(struct drm_device *dev, int index) break; } - /* scaling mode property */ - switch (nv_connector->type) { - case DCB_CONNECTOR_TV_0: - case DCB_CONNECTOR_TV_1: - case DCB_CONNECTOR_TV_3: - break; - case DCB_CONNECTOR_VGA: - if (disp->disp.oclass < NV50_DISP) - break; /* can only scale on DFPs */ - /* fall-through */ - default: - drm_object_attach_property(&connector->base, dev->mode_config. - scaling_mode_property, - nv_connector->scaling_mode); - break; - } - /* dithering properties */ switch (nv_connector->type) { case DCB_CONNECTOR_TV_0: @@ -1350,20 +1377,8 @@ nouveau_connector_create(struct drm_device *dev, int index) case DCB_CONNECTOR_VGA: break; default: - if (disp->dithering_mode) { - nv_connector->dithering_mode = DITHERING_MODE_AUTO; - drm_object_attach_property(&connector->base, - disp->dithering_mode, - nv_connector-> - dithering_mode); - } - if (disp->dithering_depth) { - nv_connector->dithering_depth = DITHERING_DEPTH_AUTO; - drm_object_attach_property(&connector->base, - disp->dithering_depth, - nv_connector-> - dithering_depth); - } + nv_connector->dithering_mode = DITHERING_MODE_AUTO; + nv_connector->dithering_depth = DITHERING_DEPTH_AUTO; break; } diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.h b/drivers/gpu/drm/nouveau/nouveau_connector.h index c366b38..ed1187e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.h +++ b/drivers/gpu/drm/nouveau/nouveau_connector.h @@ -141,6 +141,7 @@ struct nouveau_conn_atom { } set; }; +void nouveau_conn_attach_properties(struct drm_connector *); void nouveau_conn_reset(struct drm_connector *); struct drm_connector_state * nouveau_conn_atomic_duplicate_state(struct drm_connector *); -- cgit v1.1 From b2b75eea576b292718e328e23ef81ff62fb88157 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 4 Nov 2016 17:20:35 +1000 Subject: drm/nouveau/kms: prepare to support legacy connector dpms with atomic Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_connector.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index c08d5e6..705c700 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -1074,9 +1074,17 @@ nouveau_connector_helper_funcs = { .best_encoder = nouveau_connector_best_encoder, }; +static int +nouveau_connector_dpms(struct drm_connector *connector, int mode) +{ + if (connector->dev->mode_config.funcs->atomic_commit) + return drm_atomic_helper_connector_dpms(connector, mode); + return drm_helper_connector_dpms(connector, mode); +} + static const struct drm_connector_funcs nouveau_connector_funcs = { - .dpms = drm_helper_connector_dpms, + .dpms = nouveau_connector_dpms, .reset = nouveau_conn_reset, .detect = nouveau_connector_detect, .force = nouveau_connector_force, @@ -1091,7 +1099,7 @@ nouveau_connector_funcs = { static const struct drm_connector_funcs nouveau_connector_funcs_lvds = { - .dpms = drm_helper_connector_dpms, + .dpms = nouveau_connector_dpms, .reset = nouveau_conn_reset, .detect = nouveau_connector_detect_lvds, .force = nouveau_connector_force, @@ -1335,7 +1343,10 @@ nouveau_connector_create(struct drm_device *dev, int index) return ERR_PTR(ret); } - funcs = &nouveau_connector_funcs_dp; + if (dev->mode_config.funcs->atomic_commit) + funcs = &nouveau_connector_funcs; + else + funcs = &nouveau_connector_funcs_dp; break; default: funcs = &nouveau_connector_funcs; -- cgit v1.1 From d6455379a9ab87ababce828d6691bdaf7383b2a9 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 4 Nov 2016 17:20:35 +1000 Subject: drm/nouveau/kms: prepare to support legacy connector set_property with atomic Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_connector.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 705c700..794b161 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -768,6 +768,9 @@ nouveau_connector_set_property(struct drm_connector *connector, struct nouveau_crtc *nv_crtc = NULL; int ret; + if (connector->dev->mode_config.funcs->atomic_commit) + return drm_atomic_helper_connector_set_property(connector, property, value); + ret = connector->funcs->atomic_set_property(&nv_connector->base, &asyc->state, property, value); -- cgit v1.1 From 986edb91b273f6af622f46b9afe9002cb5cc2130 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 4 Nov 2016 17:20:35 +1000 Subject: drm/nouveau/kms: prepare to support vbl timestamp calculation with atomic Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_display.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 1c4b2ca..340ca3e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -158,9 +158,13 @@ nouveau_display_vblstamp(struct drm_device *dev, unsigned int pipe, list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { if (nouveau_crtc(crtc)->index == pipe) { + struct drm_display_mode *mode; + if (dev->mode_config.funcs->atomic_commit) + mode = &crtc->state->adjusted_mode; + else + mode = &crtc->hwmode; return drm_calc_vbltimestamp_from_scanoutpos(dev, - pipe, max_error, time, flags, - &crtc->hwmode); + pipe, max_error, time, flags, mode); } } -- cgit v1.1 From b167db0e68dca4f4009c1b07270ce9bb509c86cd Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 4 Nov 2016 17:20:36 +1000 Subject: drm/nouveau/kms: prepare to support suspend/resume of display state with atomic This is different from the equivilant functions in the atomic helpers in that we fully disable the pipe instead of just setting it to inactive. We do this (primarily) to ensure the framebuffer cleanup paths are hit, allowing buffers to be un-pinned from memory so they can be evicted to system memory and not lose their contents while suspended. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_display.c | 138 ++++++++++++++++++++++++++++++ drivers/gpu/drm/nouveau/nouveau_display.h | 2 + 2 files changed, 140 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 340ca3e..79b5f9d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -25,6 +25,8 @@ */ #include +#include +#include #include #include @@ -573,11 +575,137 @@ nouveau_display_destroy(struct drm_device *dev) kfree(disp); } +static int +nouveau_atomic_disable_connector(struct drm_atomic_state *state, + struct drm_connector *connector) +{ + struct drm_connector_state *connector_state; + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; + struct drm_plane_state *plane_state; + struct drm_plane *plane; + int ret; + + if (!(crtc = connector->state->crtc)) + return 0; + + connector_state = drm_atomic_get_connector_state(state, connector); + if (IS_ERR(connector_state)) + return PTR_ERR(connector_state); + + ret = drm_atomic_set_crtc_for_connector(connector_state, NULL); + if (ret) + return ret; + + crtc_state = drm_atomic_get_crtc_state(state, crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + + ret = drm_atomic_set_mode_for_crtc(crtc_state, NULL); + if (ret) + return ret; + + crtc_state->active = false; + + drm_for_each_plane_mask(plane, connector->dev, crtc_state->plane_mask) { + plane_state = drm_atomic_get_plane_state(state, plane); + if (IS_ERR(plane_state)) + return PTR_ERR(plane_state); + + ret = drm_atomic_set_crtc_for_plane(plane_state, NULL); + if (ret) + return ret; + + drm_atomic_set_fb_for_plane(plane_state, NULL); + } + + return 0; +} + +static int +nouveau_atomic_disable(struct drm_device *dev, + struct drm_modeset_acquire_ctx *ctx) +{ + struct drm_atomic_state *state; + struct drm_connector *connector; + int ret; + + state = drm_atomic_state_alloc(dev); + if (!state) + return -ENOMEM; + + state->acquire_ctx = ctx; + + drm_for_each_connector(connector, dev) { + ret = nouveau_atomic_disable_connector(state, connector); + if (ret) + break; + } + + if (ret == 0) + ret = drm_atomic_commit(state); + drm_atomic_state_put(state); + return ret; +} + +static struct drm_atomic_state * +nouveau_atomic_suspend(struct drm_device *dev) +{ + struct drm_modeset_acquire_ctx ctx; + struct drm_atomic_state *state; + int ret; + + drm_modeset_acquire_init(&ctx, 0); + +retry: + ret = drm_modeset_lock_all_ctx(dev, &ctx); + if (ret < 0) { + state = ERR_PTR(ret); + goto unlock; + } + + state = drm_atomic_helper_duplicate_state(dev, &ctx); + if (IS_ERR(state)) + goto unlock; + + ret = nouveau_atomic_disable(dev, &ctx); + if (ret < 0) { + drm_atomic_state_put(state); + state = ERR_PTR(ret); + goto unlock; + } + +unlock: + if (PTR_ERR(state) == -EDEADLK) { + drm_modeset_backoff(&ctx); + goto retry; + } + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); + return state; +} + int nouveau_display_suspend(struct drm_device *dev, bool runtime) { + struct nouveau_display *disp = nouveau_display(dev); struct drm_crtc *crtc; + if (dev->mode_config.funcs->atomic_commit) { + if (!runtime) { + disp->suspend = nouveau_atomic_suspend(dev); + if (IS_ERR(disp->suspend)) { + int ret = PTR_ERR(disp->suspend); + disp->suspend = NULL; + return ret; + } + } + + nouveau_display_fini(dev, true); + return 0; + } + nouveau_display_fini(dev, true); list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { @@ -605,10 +733,20 @@ nouveau_display_suspend(struct drm_device *dev, bool runtime) void nouveau_display_resume(struct drm_device *dev, bool runtime) { + struct nouveau_display *disp = nouveau_display(dev); struct nouveau_drm *drm = nouveau_drm(dev); struct drm_crtc *crtc; int ret, head; + if (dev->mode_config.funcs->atomic_commit) { + nouveau_display_init(dev); + if (disp->suspend) { + drm_atomic_helper_resume(dev, disp->suspend); + disp->suspend = NULL; + } + return; + } + /* re-pin fb/cursors */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { struct nouveau_framebuffer *nouveau_fb; diff --git a/drivers/gpu/drm/nouveau/nouveau_display.h b/drivers/gpu/drm/nouveau/nouveau_display.h index 3760f0e..77d6fe1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.h +++ b/drivers/gpu/drm/nouveau/nouveau_display.h @@ -53,6 +53,8 @@ struct nouveau_display { /* not really hue and saturation: */ struct drm_property *vibrant_hue_property; struct drm_property *color_vibrance_property; + + struct drm_atomic_state *suspend; }; static inline struct nouveau_display * -- cgit v1.1 From fc21a4a0993a9d8d72facccad3ab6f19d8d706fb Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 4 Nov 2016 17:20:36 +1000 Subject: drm/nouveau/kms: never call drm_helper_disable_unused_functions() with atomic Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_fbcon.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index 4192b79..cc8c583 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -535,7 +535,8 @@ nouveau_fbcon_init(struct drm_device *dev) preferred_bpp = 32; /* disable all the possible outputs/crtcs before entering KMS mode */ - drm_helper_disable_unused_functions(dev); + if (!dev->mode_config.funcs->atomic_commit) + drm_helper_disable_unused_functions(dev); ret = drm_fb_helper_initial_config(&fbcon->helper, preferred_bpp); if (ret) -- cgit v1.1 From 52aa30f2524d065c6f251d78e906966fed8291eb Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 4 Nov 2016 17:20:36 +1000 Subject: drm/nouveau/kms/nv50: switch mst sink back into sst mode Sometimes we load with a sink already in MST mode. If, however, we can't or don't want to use MST, we need to be able to switch it back to SST. This commit instantiates a stub topology manager for any output path that we believe (the detection of this could use some improvement) has support for MST, and adds the connector detect() logic for detecting sink support and switching between modes. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_connector.c | 4 +- drivers/gpu/drm/nouveau/nouveau_dp.c | 9 +- drivers/gpu/drm/nouveau/nouveau_encoder.h | 8 ++ drivers/gpu/drm/nouveau/nv50_display.c | 131 ++++++++++++++++++++++++++-- 4 files changed, 142 insertions(+), 10 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 794b161..b69ba82 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -447,7 +447,9 @@ nouveau_connector_ddc_detect(struct drm_connector *connector) if (nv_encoder->dcb->type == DCB_OUTPUT_DP) { int ret = nouveau_dp_detect(nv_encoder); - if (ret == 0) + if (ret == NOUVEAU_DP_MST) + return NULL; + if (ret == NOUVEAU_DP_SST) break; } else if ((vga_switcheroo_handler_flags() & diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c index 87d52d3..399eb9d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dp.c +++ b/drivers/gpu/drm/nouveau/nouveau_dp.c @@ -30,6 +30,9 @@ #include "nouveau_encoder.h" #include "nouveau_crtc.h" +#include +#include + static void nouveau_dp_probe_oui(struct drm_device *dev, struct nvkm_i2c_aux *aux, u8 *dpcd) { @@ -84,5 +87,9 @@ nouveau_dp_detect(struct nouveau_encoder *nv_encoder) nv_encoder->dp.link_nr, nv_encoder->dp.link_bw); nouveau_dp_probe_oui(dev, aux, dpcd); - return 0; + + ret = nv50_mstm_detect(nv_encoder->dp.mstm, dpcd, 0); + if (ret == 0) + return NOUVEAU_DP_SST; + return ret; } diff --git a/drivers/gpu/drm/nouveau/nouveau_encoder.h b/drivers/gpu/drm/nouveau/nouveau_encoder.h index ee6a6d3..dfa1a66 100644 --- a/drivers/gpu/drm/nouveau/nouveau_encoder.h +++ b/drivers/gpu/drm/nouveau/nouveau_encoder.h @@ -30,6 +30,7 @@ #include #include +#include #include "dispnv04/disp.h" #define NV_DPMS_CLEARED 0x80 @@ -57,6 +58,7 @@ struct nouveau_encoder { union { struct { + struct nv50_mstm *mstm; u8 dpcd[8]; int link_nr; int link_bw; @@ -90,9 +92,15 @@ get_slave_funcs(struct drm_encoder *enc) } /* nouveau_dp.c */ +enum nouveau_dp_status { + NOUVEAU_DP_SST, + NOUVEAU_DP_MST, +}; + int nouveau_dp_detect(struct nouveau_encoder *); struct nouveau_connector * nouveau_encoder_connector_get(struct nouveau_encoder *encoder); +int nv50_mstm_detect(struct nv50_mstm *, u8 dpcd[8], int allow); #endif /* __NOUVEAU_ENCODER_H__ */ diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 99a3866..1f4e137 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -1841,6 +1841,108 @@ nv50_hdmi_disconnect(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc) } /****************************************************************************** + * MST + *****************************************************************************/ +struct nv50_mstm { + struct nouveau_encoder *outp; + + struct drm_dp_mst_topology_mgr mgr; +}; + +static int +nv50_mstm_enable(struct nv50_mstm *mstm, u8 dpcd, int state) +{ + struct nouveau_encoder *outp = mstm->outp; + struct { + struct nv50_disp_mthd_v1 base; + struct nv50_disp_sor_dp_mst_link_v0 mst; + } args = { + .base.version = 1, + .base.method = NV50_DISP_MTHD_V1_SOR_DP_MST_LINK, + .base.hasht = outp->dcb->hasht, + .base.hashm = outp->dcb->hashm, + .mst.state = state, + }; + struct nouveau_drm *drm = nouveau_drm(outp->base.base.dev); + struct nvif_object *disp = &drm->display->disp; + int ret; + + if (dpcd >= 0x12) { + ret = drm_dp_dpcd_readb(mstm->mgr.aux, DP_MSTM_CTRL, &dpcd); + if (ret < 0) + return ret; + + dpcd &= ~DP_MST_EN; + if (state) + dpcd |= DP_MST_EN; + + ret = drm_dp_dpcd_writeb(mstm->mgr.aux, DP_MSTM_CTRL, dpcd); + if (ret < 0) + return ret; + } + + return nvif_mthd(disp, 0, &args, sizeof(args)); +} + +int +nv50_mstm_detect(struct nv50_mstm *mstm, u8 dpcd[8], int allow) +{ + int ret, state = 0; + + if (!mstm) + return 0; + + if (dpcd[0] >= 0x12 && allow) { + ret = drm_dp_dpcd_readb(mstm->mgr.aux, DP_MSTM_CAP, &dpcd[1]); + if (ret < 0) + return ret; + + state = dpcd[1] & DP_MST_CAP; + } + + ret = nv50_mstm_enable(mstm, dpcd[0], state); + if (ret) + return ret; + + ret = drm_dp_mst_topology_mgr_set_mst(&mstm->mgr, state); + if (ret) + return nv50_mstm_enable(mstm, dpcd[0], 0); + + return mstm->mgr.mst_state; +} + +static void +nv50_mstm_del(struct nv50_mstm **pmstm) +{ + struct nv50_mstm *mstm = *pmstm; + if (mstm) { + kfree(*pmstm); + *pmstm = NULL; + } +} + +static int +nv50_mstm_new(struct nouveau_encoder *outp, struct drm_dp_aux *aux, int aux_max, + int conn_base_id, struct nv50_mstm **pmstm) +{ + const int max_payloads = hweight8(outp->dcb->heads); + struct drm_device *dev = outp->base.base.dev; + struct nv50_mstm *mstm; + int ret; + + if (!(mstm = *pmstm = kzalloc(sizeof(*mstm), GFP_KERNEL))) + return -ENOMEM; + mstm->outp = outp; + + ret = drm_dp_mst_topology_mgr_init(&mstm->mgr, dev->dev, aux, aux_max, + max_payloads, conn_base_id); + if (ret) + return ret; + + return 0; +} + +/****************************************************************************** * SOR *****************************************************************************/ static void @@ -2078,6 +2180,8 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode, static void nv50_sor_destroy(struct drm_encoder *encoder) { + struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); + nv50_mstm_del(&nv_encoder->dp.mstm); drm_encoder_cleanup(encoder); kfree(encoder); } @@ -2099,11 +2203,12 @@ static const struct drm_encoder_funcs nv50_sor_func = { static int nv50_sor_create(struct drm_connector *connector, struct dcb_output *dcbe) { + struct nouveau_connector *nv_connector = nouveau_connector(connector); struct nouveau_drm *drm = nouveau_drm(connector->dev); struct nvkm_i2c *i2c = nvxx_i2c(&drm->device); struct nouveau_encoder *nv_encoder; struct drm_encoder *encoder; - int type; + int type, ret; switch (dcbe->type) { case DCB_OUTPUT_LVDS: type = DRM_MODE_ENCODER_LVDS; break; @@ -2121,6 +2226,14 @@ nv50_sor_create(struct drm_connector *connector, struct dcb_output *dcbe) nv_encoder->or = ffs(dcbe->or) - 1; nv_encoder->last_dpms = DRM_MODE_DPMS_OFF; + encoder = to_drm_encoder(nv_encoder); + encoder->possible_crtcs = dcbe->heads; + encoder->possible_clones = 0; + drm_encoder_init(connector->dev, encoder, &nv50_sor_func, type, NULL); + drm_encoder_helper_add(encoder, &nv50_sor_hfunc); + + drm_mode_connector_attach_encoder(connector, encoder); + if (dcbe->type == DCB_OUTPUT_DP) { struct nvkm_i2c_aux *aux = nvkm_i2c_aux_find(i2c, dcbe->i2c_index); @@ -2128,6 +2241,15 @@ nv50_sor_create(struct drm_connector *connector, struct dcb_output *dcbe) nv_encoder->i2c = &aux->i2c; nv_encoder->aux = aux; } + + /*TODO: Use DP Info Table to check for support. */ + if (nv50_disp(encoder->dev)->disp->oclass >= GF110_DISP) { + ret = nv50_mstm_new(nv_encoder, &nv_connector->aux, 16, + nv_connector->base.base.id, + &nv_encoder->dp.mstm); + if (ret) + return ret; + } } else { struct nvkm_i2c_bus *bus = nvkm_i2c_bus_find(i2c, dcbe->i2c_index); @@ -2135,13 +2257,6 @@ nv50_sor_create(struct drm_connector *connector, struct dcb_output *dcbe) nv_encoder->i2c = &bus->i2c; } - encoder = to_drm_encoder(nv_encoder); - encoder->possible_crtcs = dcbe->heads; - encoder->possible_clones = 0; - drm_encoder_init(connector->dev, encoder, &nv50_sor_func, type, NULL); - drm_encoder_helper_add(encoder, &nv50_sor_hfunc); - - drm_mode_connector_attach_encoder(connector, encoder); return 0; } -- cgit v1.1 From 7f55a072931922ec5eecbdc2657fb57b3c424d8a Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 4 Nov 2016 17:20:36 +1000 Subject: drm/nouveau/kms/nv50: control evo trace output with DRM_UT_KMS Will be useful in debugging the transition to atomic. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_display.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 1f4e137..9a04ee5 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -463,21 +463,19 @@ evo_kick(u32 *push, void *evoc) mutex_unlock(&dmac->lock); } -#if 1 -#define evo_mthd(p,m,s) *((p)++) = (((s) << 18) | (m)) -#define evo_data(p,d) *((p)++) = (d) -#else #define evo_mthd(p,m,s) do { \ const u32 _m = (m), _s = (s); \ - printk(KERN_ERR "%04x %d %s\n", _m, _s, __func__); \ + if (drm_debug & DRM_UT_KMS) \ + printk(KERN_ERR "%04x %d %s\n", _m, _s, __func__); \ *((p)++) = ((_s << 18) | _m); \ } while(0) + #define evo_data(p,d) do { \ const u32 _d = (d); \ - printk(KERN_ERR "\t%08x\n", _d); \ + if (drm_debug & DRM_UT_KMS) \ + printk(KERN_ERR "\t%08x\n", _d); \ *((p)++) = _d; \ } while(0) -#endif static bool evo_sync_wait(void *data) -- cgit v1.1 From 5a223daccbf378db9359dc42a249290785a26f14 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 4 Nov 2016 17:20:36 +1000 Subject: drm/nouveau/kms/nv50: give more useful names to encoders Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_display.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 9a04ee5..16f42cd 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -1721,7 +1721,8 @@ nv50_dac_create(struct drm_connector *connector, struct dcb_output *dcbe) encoder = to_drm_encoder(nv_encoder); encoder->possible_crtcs = dcbe->heads; encoder->possible_clones = 0; - drm_encoder_init(connector->dev, encoder, &nv50_dac_func, type, NULL); + drm_encoder_init(connector->dev, encoder, &nv50_dac_func, type, + "dac-%04x-%04x", dcbe->hasht, dcbe->hashm); drm_encoder_helper_add(encoder, &nv50_dac_hfunc); drm_mode_connector_attach_encoder(connector, encoder); @@ -2227,7 +2228,8 @@ nv50_sor_create(struct drm_connector *connector, struct dcb_output *dcbe) encoder = to_drm_encoder(nv_encoder); encoder->possible_crtcs = dcbe->heads; encoder->possible_clones = 0; - drm_encoder_init(connector->dev, encoder, &nv50_sor_func, type, NULL); + drm_encoder_init(connector->dev, encoder, &nv50_sor_func, type, + "sor-%04x-%04x", dcbe->hasht, dcbe->hashm); drm_encoder_helper_add(encoder, &nv50_sor_hfunc); drm_mode_connector_attach_encoder(connector, encoder); @@ -2431,7 +2433,8 @@ nv50_pior_create(struct drm_connector *connector, struct dcb_output *dcbe) encoder = to_drm_encoder(nv_encoder); encoder->possible_crtcs = dcbe->heads; encoder->possible_clones = 0; - drm_encoder_init(connector->dev, encoder, &nv50_pior_func, type, NULL); + drm_encoder_init(connector->dev, encoder, &nv50_pior_func, type, + "pior-%04x-%04x", dcbe->hasht, dcbe->hashm); drm_encoder_helper_add(encoder, &nv50_pior_hfunc); drm_mode_connector_attach_encoder(connector, encoder); -- cgit v1.1 From 3dbd036b841931c3f988f8cbf77d3d4b7b1513d3 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 4 Nov 2016 17:20:36 +1000 Subject: drm/nouveau/kms/nv50: separate out mode commit This commit separates the calculation of EVO state from the commit, in order to make the same code useful for atomic modesetting. The legacy interfaces have been wrapped on top of them. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drv.h | 4 + drivers/gpu/drm/nouveau/nv50_display.c | 218 ++++++++++++++++++++++++--------- 2 files changed, 167 insertions(+), 55 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index c0e2b32..4cd47ba 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -204,6 +204,10 @@ void nouveau_drm_device_remove(struct drm_device *dev); if (unlikely(drm_debug & DRM_UT_DRIVER)) \ NV_PRINTK(info, &(drm)->client, f, ##a); \ } while(0) +#define NV_ATOMIC(drm,f,a...) do { \ + if (unlikely(drm_debug & DRM_UT_ATOMIC)) \ + NV_PRINTK(info, &(drm)->client, f, ##a); \ +} while(0) extern int nouveau_modeset; diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 16f42cd..8d27ddd 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -63,6 +63,42 @@ #define EVO_FLIP_SEM1(c) EVO_SYNC((c) + 1, 0x10) /****************************************************************************** + * Atomic state + *****************************************************************************/ +#define nv50_head_atom(p) container_of((p), struct nv50_head_atom, state) + +struct nv50_head_atom { + struct drm_crtc_state state; + + struct nv50_head_mode { + bool interlace; + u32 clock; + struct { + u16 active; + u16 synce; + u16 blanke; + u16 blanks; + } h; + struct { + u32 active; + u16 synce; + u16 blanke; + u16 blanks; + u16 blank2s; + u16 blank2e; + u16 blankus; + } v; + } mode; + + union { + struct { + bool mode:1; + }; + u16 mask; + } set; +}; + +/****************************************************************************** * EVO channel *****************************************************************************/ @@ -386,6 +422,9 @@ struct nv50_head { struct nv50_sync sync; struct nv50_ovly ovly; struct nv50_oimm oimm; + + struct nv50_head_atom arm; + struct nv50_head_atom asy; }; #define nv50_head(c) ((struct nv50_head *)nouveau_crtc(c)) @@ -695,6 +734,120 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, } /****************************************************************************** + * Head + *****************************************************************************/ + +static void +nv50_head_mode(struct nv50_head *head, struct nv50_head_atom *asyh) +{ + struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base; + struct nv50_head_mode *m = &asyh->mode; + u32 *push; + if ((push = evo_wait(core, 14))) { + if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA) { + evo_mthd(push, 0x0804 + (head->base.index * 0x400), 2); + evo_data(push, 0x00800000 | m->clock); + evo_data(push, m->interlace ? 0x00000002 : 0x00000000); + evo_mthd(push, 0x0810 + (head->base.index * 0x400), 6); + evo_data(push, 0x00000000); + evo_data(push, (m->v.active << 16) | m->h.active ); + evo_data(push, (m->v.synce << 16) | m->h.synce ); + evo_data(push, (m->v.blanke << 16) | m->h.blanke ); + evo_data(push, (m->v.blanks << 16) | m->h.blanks ); + evo_data(push, (m->v.blank2e << 16) | m->v.blank2s); + evo_mthd(push, 0x082c + (head->base.index * 0x400), 1); + evo_data(push, 0x00000000); + } else { + evo_mthd(push, 0x0410 + (head->base.index * 0x300), 6); + evo_data(push, 0x00000000); + evo_data(push, (m->v.active << 16) | m->h.active ); + evo_data(push, (m->v.synce << 16) | m->h.synce ); + evo_data(push, (m->v.blanke << 16) | m->h.blanke ); + evo_data(push, (m->v.blanks << 16) | m->h.blanks ); + evo_data(push, (m->v.blank2e << 16) | m->v.blank2s); + evo_mthd(push, 0x042c + (head->base.index * 0x300), 2); + evo_data(push, 0x00000000); /* ??? */ + evo_data(push, 0xffffff00); + evo_mthd(push, 0x0450 + (head->base.index * 0x300), 3); + evo_data(push, m->clock * 1000); + evo_data(push, 0x00200000); /* ??? */ + evo_data(push, m->clock * 1000); + } + evo_kick(push, core); + } +} + +static void +nv50_head_flush_set(struct nv50_head *head, struct nv50_head_atom *asyh) +{ + if (asyh->set.mode ) nv50_head_mode (head, asyh); +} + +static void +nv50_head_atomic_check_mode(struct nv50_head *head, struct nv50_head_atom *asyh) +{ + struct drm_display_mode *mode = &asyh->state.adjusted_mode; + u32 ilace = (mode->flags & DRM_MODE_FLAG_INTERLACE) ? 2 : 1; + u32 vscan = (mode->flags & DRM_MODE_FLAG_DBLSCAN) ? 2 : 1; + u32 hbackp = mode->htotal - mode->hsync_end; + u32 vbackp = (mode->vtotal - mode->vsync_end) * vscan / ilace; + u32 hfrontp = mode->hsync_start - mode->hdisplay; + u32 vfrontp = (mode->vsync_start - mode->vdisplay) * vscan / ilace; + struct nv50_head_mode *m = &asyh->mode; + + m->h.active = mode->htotal; + m->h.synce = mode->hsync_end - mode->hsync_start - 1; + m->h.blanke = m->h.synce + hbackp; + m->h.blanks = mode->htotal - hfrontp - 1; + + m->v.active = mode->vtotal * vscan / ilace; + m->v.synce = ((mode->vsync_end - mode->vsync_start) * vscan / ilace) - 1; + m->v.blanke = m->v.synce + vbackp; + m->v.blanks = m->v.active - vfrontp - 1; + + /*XXX: Safe underestimate, even "0" works */ + m->v.blankus = (m->v.active - mode->vdisplay - 2) * m->h.active; + m->v.blankus *= 1000; + m->v.blankus /= mode->clock; + + if (mode->flags & DRM_MODE_FLAG_INTERLACE) { + m->v.blank2e = m->v.active + m->v.synce + vbackp; + m->v.blank2s = m->v.blank2e + (mode->vdisplay * vscan / ilace); + m->v.active = (m->v.active * 2) + 1; + m->interlace = true; + } else { + m->v.blank2e = 0; + m->v.blank2s = 1; + m->interlace = false; + } + m->clock = mode->clock; + + drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); + asyh->set.mode = true; +} + +static int +nv50_head_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state) +{ + struct nouveau_drm *drm = nouveau_drm(crtc->dev); + struct nv50_head *head = nv50_head(crtc); + struct nv50_head_atom *armh = &head->arm; + struct nv50_head_atom *asyh = nv50_head_atom(state); + + NV_ATOMIC(drm, "%s atomic_check %d\n", crtc->name, asyh->state.active); + asyh->set.mask = 0; + + if (asyh->state.active) { + if (asyh->state.mode_changed) + nv50_head_atomic_check_mode(head, asyh); + } + + memcpy(armh, asyh, sizeof(*asyh)); + asyh->state.mode_changed = 0; + return 0; +} + +/****************************************************************************** * CRTC *****************************************************************************/ static int @@ -1142,79 +1295,34 @@ nv50_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *umode, struct nv50_mast *mast = nv50_mast(crtc->dev); struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); struct nouveau_connector *nv_connector; - u32 ilace = (mode->flags & DRM_MODE_FLAG_INTERLACE) ? 2 : 1; - u32 vscan = (mode->flags & DRM_MODE_FLAG_DBLSCAN) ? 2 : 1; - u32 hactive, hsynce, hbackp, hfrontp, hblanke, hblanks; - u32 vactive, vsynce, vbackp, vfrontp, vblanke, vblanks; - u32 vblan2e = 0, vblan2s = 1, vblankus = 0; u32 *push; int ret; + struct nv50_head *head = nv50_head(crtc); + struct nv50_head_atom *asyh = &head->asy; - hactive = mode->htotal; - hsynce = mode->hsync_end - mode->hsync_start - 1; - hbackp = mode->htotal - mode->hsync_end; - hblanke = hsynce + hbackp; - hfrontp = mode->hsync_start - mode->hdisplay; - hblanks = mode->htotal - hfrontp - 1; - - vactive = mode->vtotal * vscan / ilace; - vsynce = ((mode->vsync_end - mode->vsync_start) * vscan / ilace) - 1; - vbackp = (mode->vtotal - mode->vsync_end) * vscan / ilace; - vblanke = vsynce + vbackp; - vfrontp = (mode->vsync_start - mode->vdisplay) * vscan / ilace; - vblanks = vactive - vfrontp - 1; - /* XXX: Safe underestimate, even "0" works */ - vblankus = (vactive - mode->vdisplay - 2) * hactive; - vblankus *= 1000; - vblankus /= mode->clock; - - if (mode->flags & DRM_MODE_FLAG_INTERLACE) { - vblan2e = vactive + vsynce + vbackp; - vblan2s = vblan2e + (mode->vdisplay * vscan / ilace); - vactive = (vactive * 2) + 1; - } + memcpy(&asyh->state.mode, umode, sizeof(*umode)); + memcpy(&asyh->state.adjusted_mode, mode, sizeof(*mode)); + asyh->state.active = true; + asyh->state.mode_changed = true; + nv50_head_atomic_check(&head->base.base, &asyh->state); ret = nv50_crtc_swap_fbs(crtc, old_fb); if (ret) return ret; + nv50_head_flush_set(head, asyh); + push = evo_wait(mast, 64); if (push) { if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) { - evo_mthd(push, 0x0804 + (nv_crtc->index * 0x400), 2); - evo_data(push, 0x00800000 | mode->clock); - evo_data(push, (ilace == 2) ? 2 : 0); - evo_mthd(push, 0x0810 + (nv_crtc->index * 0x400), 6); - evo_data(push, 0x00000000); - evo_data(push, (vactive << 16) | hactive); - evo_data(push, ( vsynce << 16) | hsynce); - evo_data(push, (vblanke << 16) | hblanke); - evo_data(push, (vblanks << 16) | hblanks); - evo_data(push, (vblan2e << 16) | vblan2s); - evo_mthd(push, 0x082c + (nv_crtc->index * 0x400), 1); - evo_data(push, 0x00000000); evo_mthd(push, 0x0900 + (nv_crtc->index * 0x400), 2); evo_data(push, 0x00000311); evo_data(push, 0x00000100); } else { - evo_mthd(push, 0x0410 + (nv_crtc->index * 0x300), 6); - evo_data(push, 0x00000000); - evo_data(push, (vactive << 16) | hactive); - evo_data(push, ( vsynce << 16) | hsynce); - evo_data(push, (vblanke << 16) | hblanke); - evo_data(push, (vblanks << 16) | hblanks); - evo_data(push, (vblan2e << 16) | vblan2s); - evo_mthd(push, 0x042c + (nv_crtc->index * 0x300), 1); - evo_data(push, 0x00000000); /* ??? */ - evo_mthd(push, 0x0450 + (nv_crtc->index * 0x300), 3); - evo_data(push, mode->clock * 1000); - evo_data(push, 0x00200000); /* ??? */ - evo_data(push, mode->clock * 1000); evo_mthd(push, 0x04d0 + (nv_crtc->index * 0x300), 2); evo_data(push, 0x00000311); evo_data(push, 0x00000100); } - evo_kick(push, mast); } @@ -1224,7 +1332,7 @@ nv50_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *umode, /* G94 only accepts this after setting scale */ if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) - nv50_crtc_set_raster_vblank_dmi(nv_crtc, vblankus); + nv50_crtc_set_raster_vblank_dmi(nv_crtc, asyh->mode.v.blankus); nv50_crtc_set_color_vibrance(nv_crtc, false); nv50_crtc_set_image(nv_crtc, crtc->primary->fb, x, y, false); -- cgit v1.1 From ad63361953938caaf85630ce0cb1bfa976938552 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 4 Nov 2016 17:20:36 +1000 Subject: drm/nouveau/kms/nv50: separate out core surface commit This commit separates the calculation of EVO state from the commit, in order to make the same code useful for atomic modesetting. The legacy interfaces have been wrapped on top of them. As of this commit, we're no longer bothering to point the core surface at a valid framebuffer. Prior to this, we'd initially point the core channel to the framebuffer passed in a mode_set()/mode_set_base(), and then use the base channel for any page-flip updates, leaving the core channel pointing at stale information. The important thing here is to configure the core surface parameters in such a way that EVO's error checking is satisfied. TL;DR: The situation isn't too much different to before. There may be brief periods of times during modesets where the (garbage) core surface will be showing. This issue will be resolved once support for atomic commits has been implemented and we're able to interlock the updates that involve multiple channels. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_display.c | 220 ++++++++++++++++++++++++++------- 1 file changed, 175 insertions(+), 45 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 8d27ddd..8203a38 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -25,10 +25,11 @@ #include #include +#include #include -#include #include #include +#include #include #include @@ -90,8 +91,41 @@ struct nv50_head_atom { } v; } mode; + struct { + bool visible; + u32 handle; + u64 offset:40; + u8 format; + u8 kind:7; + u8 layout:1; + u8 block:4; + u32 pitch:20; + u16 x; + u16 y; + u16 w; + u16 h; + } core; + + struct { + u8 depth; + u8 cpp; + u16 x; + u16 y; + u16 w; + u16 h; + } base; + + union { + struct { + bool core:1; + }; + u8 mask; + } clr; + union { struct { + bool core:1; + bool view:1; bool mode:1; }; u16 mask; @@ -738,6 +772,70 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, *****************************************************************************/ static void +nv50_head_core_clr(struct nv50_head *head) +{ + struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base; + u32 *push; + if ((push = evo_wait(core, 2))) { + if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA) + evo_mthd(push, 0x0874 + head->base.index * 0x400, 1); + else + evo_mthd(push, 0x0474 + head->base.index * 0x300, 1); + evo_data(push, 0x00000000); + evo_kick(push, core); + } +} + +static void +nv50_head_core_set(struct nv50_head *head, struct nv50_head_atom *asyh) +{ + struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base; + u32 *push; + if ((push = evo_wait(core, 9))) { + if (core->base.user.oclass < G82_DISP_CORE_CHANNEL_DMA) { + evo_mthd(push, 0x0860 + head->base.index * 0x400, 1); + evo_data(push, asyh->core.offset >> 8); + evo_mthd(push, 0x0868 + head->base.index * 0x400, 4); + evo_data(push, (asyh->core.h << 16) | asyh->core.w); + evo_data(push, asyh->core.layout << 20 | + (asyh->core.pitch >> 8) << 8 | + asyh->core.block); + evo_data(push, asyh->core.kind << 16 | + asyh->core.format << 8); + evo_data(push, asyh->core.handle); + evo_mthd(push, 0x08c0 + head->base.index * 0x400, 1); + evo_data(push, (asyh->core.y << 16) | asyh->core.x); + } else + if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA) { + evo_mthd(push, 0x0860 + head->base.index * 0x400, 1); + evo_data(push, asyh->core.offset >> 8); + evo_mthd(push, 0x0868 + head->base.index * 0x400, 4); + evo_data(push, (asyh->core.h << 16) | asyh->core.w); + evo_data(push, asyh->core.layout << 20 | + (asyh->core.pitch >> 8) << 8 | + asyh->core.block); + evo_data(push, asyh->core.format << 8); + evo_data(push, asyh->core.handle); + evo_mthd(push, 0x08c0 + head->base.index * 0x400, 1); + evo_data(push, (asyh->core.y << 16) | asyh->core.x); + } else { + evo_mthd(push, 0x0460 + head->base.index * 0x300, 1); + evo_data(push, asyh->core.offset >> 8); + evo_mthd(push, 0x0468 + head->base.index * 0x300, 4); + evo_data(push, (asyh->core.h << 16) | asyh->core.w); + evo_data(push, asyh->core.layout << 24 | + (asyh->core.pitch >> 8) << 8 | + asyh->core.block); + evo_data(push, asyh->core.format << 8); + evo_data(push, asyh->core.handle); + evo_mthd(push, 0x04b0 + head->base.index * 0x300, 1); + evo_data(push, (asyh->core.y << 16) | asyh->core.x); + } + evo_kick(push, core); + } +} + +static void nv50_head_mode(struct nv50_head *head, struct nv50_head_atom *asyh) { struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base; @@ -778,9 +876,17 @@ nv50_head_mode(struct nv50_head *head, struct nv50_head_atom *asyh) } static void +nv50_head_flush_clr(struct nv50_head *head, struct nv50_head_atom *asyh, bool y) +{ + if (asyh->clr.core && (!asyh->set.core || y)) + nv50_head_core_clr(head); +} + +static void nv50_head_flush_set(struct nv50_head *head, struct nv50_head_atom *asyh) { if (asyh->set.mode ) nv50_head_mode (head, asyh); + if (asyh->set.core ) nv50_head_core_set(head, asyh); } static void @@ -830,16 +936,58 @@ static int nv50_head_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state) { struct nouveau_drm *drm = nouveau_drm(crtc->dev); + struct nv50_disp *disp = nv50_disp(crtc->dev); struct nv50_head *head = nv50_head(crtc); struct nv50_head_atom *armh = &head->arm; struct nv50_head_atom *asyh = nv50_head_atom(state); NV_ATOMIC(drm, "%s atomic_check %d\n", crtc->name, asyh->state.active); + asyh->clr.mask = 0; asyh->set.mask = 0; if (asyh->state.active) { if (asyh->state.mode_changed) nv50_head_atomic_check_mode(head, asyh); + + if ((asyh->core.visible = (asyh->base.cpp != 0))) { + asyh->core.x = asyh->base.x; + asyh->core.y = asyh->base.y; + asyh->core.w = asyh->base.w; + asyh->core.h = asyh->base.h; + } else + if ((asyh->core.visible = true)) { + /*XXX: We need to either find some way of having the + * primary base layer appear black, while still + * being able to display the other layers, or we + * need to allocate a dummy black surface here. + */ + asyh->core.x = 0; + asyh->core.y = 0; + asyh->core.w = asyh->state.mode.hdisplay; + asyh->core.h = asyh->state.mode.vdisplay; + } + asyh->core.handle = disp->mast.base.vram.handle; + asyh->core.offset = 0; + asyh->core.format = 0xcf; + asyh->core.kind = 0; + asyh->core.layout = 1; + asyh->core.block = 0; + asyh->core.pitch = ALIGN(asyh->core.w, 64) * 4; + } else { + asyh->core.visible = false; + } + + if (!drm_atomic_crtc_needs_modeset(&asyh->state)) { + if (asyh->core.visible) { + if (memcmp(&armh->core, &asyh->core, sizeof(asyh->core))) + asyh->set.core = true; + } else + if (armh->core.visible) { + asyh->clr.core = true; + } + } else { + asyh->clr.core = armh->core.visible; + asyh->set.core = asyh->core.visible; } memcpy(armh, asyh, sizeof(*asyh)); @@ -1057,41 +1205,31 @@ nv50_crtc_set_image(struct nouveau_crtc *nv_crtc, struct drm_framebuffer *fb, int x, int y, bool update) { struct nouveau_framebuffer *nvfb = nouveau_framebuffer(fb); - struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev); - u32 *push; + struct nv50_head *head = nv50_head(&nv_crtc->base); + struct nv50_head_atom *asyh = &head->asy; + const struct drm_format_info *info; - push = evo_wait(mast, 16); - if (push) { - if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) { - evo_mthd(push, 0x0860 + (nv_crtc->index * 0x400), 1); - evo_data(push, nvfb->nvbo->bo.offset >> 8); - evo_mthd(push, 0x0868 + (nv_crtc->index * 0x400), 3); - evo_data(push, (fb->height << 16) | fb->width); - evo_data(push, nvfb->r_pitch); - evo_data(push, nvfb->r_format); - evo_mthd(push, 0x08c0 + (nv_crtc->index * 0x400), 1); - evo_data(push, (y << 16) | x); - if (nv50_vers(mast) > NV50_DISP_CORE_CHANNEL_DMA) { - evo_mthd(push, 0x0874 + (nv_crtc->index * 0x400), 1); - evo_data(push, nvfb->r_handle); - } - } else { - evo_mthd(push, 0x0460 + (nv_crtc->index * 0x300), 1); - evo_data(push, nvfb->nvbo->bo.offset >> 8); - evo_mthd(push, 0x0468 + (nv_crtc->index * 0x300), 4); - evo_data(push, (fb->height << 16) | fb->width); - evo_data(push, nvfb->r_pitch); - evo_data(push, nvfb->r_format); - evo_data(push, nvfb->r_handle); - evo_mthd(push, 0x04b0 + (nv_crtc->index * 0x300), 1); - evo_data(push, (y << 16) | x); - } + info = drm_format_info(nvfb->base.pixel_format); + if (!info || !info->depth) + return -EINVAL; - if (update) { + asyh->base.depth = info->depth; + asyh->base.cpp = info->cpp[0]; + asyh->base.x = x; + asyh->base.y = y; + asyh->base.w = nvfb->base.width; + asyh->base.h = nvfb->base.height; + nv50_head_atomic_check(&head->base.base, &asyh->state); + nv50_head_flush_set(head, asyh); + + if (update) { + struct nv50_mast *core = nv50_mast(nv_crtc->base.dev); + u32 *push = evo_wait(core, 2); + if (push) { evo_mthd(push, 0x0080, 1); evo_data(push, 0x00000000); + evo_kick(push, core); } - evo_kick(push, mast); } nv_crtc->fb.handle = nvfb->r_handle; @@ -1183,28 +1321,28 @@ nv50_crtc_prepare(struct drm_crtc *crtc) { struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); struct nv50_mast *mast = nv50_mast(crtc->dev); + struct nv50_head *head = nv50_head(crtc); + struct nv50_head_atom *asyh = &head->asy; u32 *push; nv50_display_flip_stop(crtc); + asyh->state.active = false; + nv50_head_atomic_check(&head->base.base, &asyh->state); + nv50_head_flush_clr(head, asyh, false); + push = evo_wait(mast, 6); if (push) { if (nv50_vers(mast) < G82_DISP_CORE_CHANNEL_DMA) { - evo_mthd(push, 0x0874 + (nv_crtc->index * 0x400), 1); - evo_data(push, 0x00000000); evo_mthd(push, 0x0840 + (nv_crtc->index * 0x400), 1); evo_data(push, 0x40000000); } else if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) { - evo_mthd(push, 0x0874 + (nv_crtc->index * 0x400), 1); - evo_data(push, 0x00000000); evo_mthd(push, 0x0840 + (nv_crtc->index * 0x400), 1); evo_data(push, 0x40000000); evo_mthd(push, 0x085c + (nv_crtc->index * 0x400), 1); evo_data(push, 0x00000000); } else { - evo_mthd(push, 0x0474 + (nv_crtc->index * 0x300), 1); - evo_data(push, 0x00000000); evo_mthd(push, 0x0440 + (nv_crtc->index * 0x300), 1); evo_data(push, 0x03000000); evo_mthd(push, 0x045c + (nv_crtc->index * 0x300), 1); @@ -1227,23 +1365,17 @@ nv50_crtc_commit(struct drm_crtc *crtc) push = evo_wait(mast, 32); if (push) { if (nv50_vers(mast) < G82_DISP_CORE_CHANNEL_DMA) { - evo_mthd(push, 0x0874 + (nv_crtc->index * 0x400), 1); - evo_data(push, nv_crtc->fb.handle); evo_mthd(push, 0x0840 + (nv_crtc->index * 0x400), 2); evo_data(push, 0xc0000000); evo_data(push, nv_crtc->lut.nvbo->bo.offset >> 8); } else if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) { - evo_mthd(push, 0x0874 + (nv_crtc->index * 0x400), 1); - evo_data(push, nv_crtc->fb.handle); evo_mthd(push, 0x0840 + (nv_crtc->index * 0x400), 2); evo_data(push, 0xc0000000); evo_data(push, nv_crtc->lut.nvbo->bo.offset >> 8); evo_mthd(push, 0x085c + (nv_crtc->index * 0x400), 1); evo_data(push, mast->base.vram.handle); } else { - evo_mthd(push, 0x0474 + (nv_crtc->index * 0x300), 1); - evo_data(push, nv_crtc->fb.handle); evo_mthd(push, 0x0440 + (nv_crtc->index * 0x300), 4); evo_data(push, 0x83000000); evo_data(push, nv_crtc->lut.nvbo->bo.offset >> 8); @@ -1251,8 +1383,6 @@ nv50_crtc_commit(struct drm_crtc *crtc) evo_data(push, 0x00000000); evo_mthd(push, 0x045c + (nv_crtc->index * 0x300), 1); evo_data(push, mast->base.vram.handle); - evo_mthd(push, 0x0430 + (nv_crtc->index * 0x300), 1); - evo_data(push, 0xffffff00); } evo_kick(push, mast); -- cgit v1.1 From a7ae1561909d27e6104cbc85655f31a962ec8683 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 4 Nov 2016 17:20:36 +1000 Subject: drm/nouveau/kms/nv50: separate out lut commit This commit separates the calculation of EVO state from the commit, in order to make the same code useful for atomic modesetting. The legacy interfaces have been wrapped on top of them. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_display.c | 121 +++++++++++++++++++-------------- 1 file changed, 70 insertions(+), 51 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 8203a38..018f336 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -92,6 +92,11 @@ struct nv50_head_atom { } mode; struct { + u32 handle; + u64 offset:40; + } lut; + + struct { bool visible; u32 handle; u64 offset:40; @@ -770,7 +775,6 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, /****************************************************************************** * Head *****************************************************************************/ - static void nv50_head_core_clr(struct nv50_head *head) { @@ -836,6 +840,61 @@ nv50_head_core_set(struct nv50_head *head, struct nv50_head_atom *asyh) } static void +nv50_head_lut_clr(struct nv50_head *head) +{ + struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base; + u32 *push; + if ((push = evo_wait(core, 4))) { + if (core->base.user.oclass < G82_DISP_CORE_CHANNEL_DMA) { + evo_mthd(push, 0x0840 + (head->base.index * 0x400), 1); + evo_data(push, 0x40000000); + } else + if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA) { + evo_mthd(push, 0x0840 + (head->base.index * 0x400), 1); + evo_data(push, 0x40000000); + evo_mthd(push, 0x085c + (head->base.index * 0x400), 1); + evo_data(push, 0x00000000); + } else { + evo_mthd(push, 0x0440 + (head->base.index * 0x300), 1); + evo_data(push, 0x03000000); + evo_mthd(push, 0x045c + (head->base.index * 0x300), 1); + evo_data(push, 0x00000000); + } + evo_kick(push, core); + } +} + +static void +nv50_head_lut_set(struct nv50_head *head, struct nv50_head_atom *asyh) +{ + struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base; + u32 *push; + if ((push = evo_wait(core, 7))) { + if (core->base.user.oclass < G82_DISP_CORE_CHANNEL_DMA) { + evo_mthd(push, 0x0840 + (head->base.index * 0x400), 2); + evo_data(push, 0xc0000000); + evo_data(push, asyh->lut.offset >> 8); + } else + if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA) { + evo_mthd(push, 0x0840 + (head->base.index * 0x400), 2); + evo_data(push, 0xc0000000); + evo_data(push, asyh->lut.offset >> 8); + evo_mthd(push, 0x085c + (head->base.index * 0x400), 1); + evo_data(push, asyh->lut.handle); + } else { + evo_mthd(push, 0x0440 + (head->base.index * 0x300), 4); + evo_data(push, 0x83000000); + evo_data(push, asyh->lut.offset >> 8); + evo_data(push, 0x00000000); + evo_data(push, 0x00000000); + evo_mthd(push, 0x045c + (head->base.index * 0x300), 1); + evo_data(push, asyh->lut.handle); + } + evo_kick(push, core); + } +} + +static void nv50_head_mode(struct nv50_head *head, struct nv50_head_atom *asyh) { struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base; @@ -879,6 +938,8 @@ static void nv50_head_flush_clr(struct nv50_head *head, struct nv50_head_atom *asyh, bool y) { if (asyh->clr.core && (!asyh->set.core || y)) + nv50_head_lut_clr(head); + if (asyh->clr.core && (!asyh->set.core || y)) nv50_head_core_clr(head); } @@ -886,6 +947,7 @@ static void nv50_head_flush_set(struct nv50_head *head, struct nv50_head_atom *asyh) { if (asyh->set.mode ) nv50_head_mode (head, asyh); + if (asyh->set.core ) nv50_head_lut_set (head, asyh); if (asyh->set.core ) nv50_head_core_set(head, asyh); } @@ -973,6 +1035,8 @@ nv50_head_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state) asyh->core.layout = 1; asyh->core.block = 0; asyh->core.pitch = ALIGN(asyh->core.w, 64) * 4; + asyh->lut.handle = disp->mast.base.vram.handle; + asyh->lut.offset = head->base.lut.nvbo->bo.offset; } else { asyh->core.visible = false; } @@ -1320,10 +1384,8 @@ static void nv50_crtc_prepare(struct drm_crtc *crtc) { struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); - struct nv50_mast *mast = nv50_mast(crtc->dev); struct nv50_head *head = nv50_head(crtc); struct nv50_head_atom *asyh = &head->asy; - u32 *push; nv50_display_flip_stop(crtc); @@ -1331,27 +1393,6 @@ nv50_crtc_prepare(struct drm_crtc *crtc) nv50_head_atomic_check(&head->base.base, &asyh->state); nv50_head_flush_clr(head, asyh, false); - push = evo_wait(mast, 6); - if (push) { - if (nv50_vers(mast) < G82_DISP_CORE_CHANNEL_DMA) { - evo_mthd(push, 0x0840 + (nv_crtc->index * 0x400), 1); - evo_data(push, 0x40000000); - } else - if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) { - evo_mthd(push, 0x0840 + (nv_crtc->index * 0x400), 1); - evo_data(push, 0x40000000); - evo_mthd(push, 0x085c + (nv_crtc->index * 0x400), 1); - evo_data(push, 0x00000000); - } else { - evo_mthd(push, 0x0440 + (nv_crtc->index * 0x300), 1); - evo_data(push, 0x03000000); - evo_mthd(push, 0x045c + (nv_crtc->index * 0x300), 1); - evo_data(push, 0x00000000); - } - - evo_kick(push, mast); - } - nv50_crtc_cursor_show_hide(nv_crtc, false, false); } @@ -1359,34 +1400,12 @@ static void nv50_crtc_commit(struct drm_crtc *crtc) { struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); - struct nv50_mast *mast = nv50_mast(crtc->dev); - u32 *push; - - push = evo_wait(mast, 32); - if (push) { - if (nv50_vers(mast) < G82_DISP_CORE_CHANNEL_DMA) { - evo_mthd(push, 0x0840 + (nv_crtc->index * 0x400), 2); - evo_data(push, 0xc0000000); - evo_data(push, nv_crtc->lut.nvbo->bo.offset >> 8); - } else - if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) { - evo_mthd(push, 0x0840 + (nv_crtc->index * 0x400), 2); - evo_data(push, 0xc0000000); - evo_data(push, nv_crtc->lut.nvbo->bo.offset >> 8); - evo_mthd(push, 0x085c + (nv_crtc->index * 0x400), 1); - evo_data(push, mast->base.vram.handle); - } else { - evo_mthd(push, 0x0440 + (nv_crtc->index * 0x300), 4); - evo_data(push, 0x83000000); - evo_data(push, nv_crtc->lut.nvbo->bo.offset >> 8); - evo_data(push, 0x00000000); - evo_data(push, 0x00000000); - evo_mthd(push, 0x045c + (nv_crtc->index * 0x300), 1); - evo_data(push, mast->base.vram.handle); - } + struct nv50_head *head = nv50_head(crtc); + struct nv50_head_atom *asyh = &head->asy; - evo_kick(push, mast); - } + asyh->state.active = true; + nv50_head_atomic_check(&head->base.base, &asyh->state); + nv50_head_flush_set(head, asyh); nv50_crtc_cursor_show_hide(nv_crtc, true, true); nv50_display_flip_next(crtc, crtc->primary->fb, NULL, 1); -- cgit v1.1 From ea8ee39002a103b5dc81c4c87e32929223b86f64 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 4 Nov 2016 17:20:36 +1000 Subject: drm/nouveau/kms/nv50: separate out cursor surface commit This commit separates the calculation of EVO state from the commit, in order to make the same code useful for atomic modesetting. The legacy interfaces have been wrapped on top of them. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_crtc.h | 1 - drivers/gpu/drm/nouveau/nv50_display.c | 147 ++++++++++++++++++++++----------- 2 files changed, 97 insertions(+), 51 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_crtc.h b/drivers/gpu/drm/nouveau/nouveau_crtc.h index d533a32..e4e3857 100644 --- a/drivers/gpu/drm/nouveau/nouveau_crtc.h +++ b/drivers/gpu/drm/nouveau/nouveau_crtc.h @@ -54,7 +54,6 @@ struct nouveau_crtc { struct { struct nouveau_bo *nvbo; - bool visible; uint32_t offset; void (*set_offset)(struct nouveau_crtc *, uint32_t offset); void (*set_pos)(struct nouveau_crtc *, int x, int y); diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 018f336..d243042 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -112,6 +112,14 @@ struct nv50_head_atom { } core; struct { + bool visible; + u32 handle; + u64 offset:40; + u8 layout:1; + u8 format:1; + } curs; + + struct { u8 depth; u8 cpp; u16 x; @@ -123,6 +131,7 @@ struct nv50_head_atom { union { struct { bool core:1; + bool curs:1; }; u8 mask; } clr; @@ -130,6 +139,7 @@ struct nv50_head_atom { union { struct { bool core:1; + bool curs:1; bool view:1; bool mode:1; }; @@ -776,6 +786,62 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, * Head *****************************************************************************/ static void +nv50_head_curs_clr(struct nv50_head *head) +{ + struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base; + u32 *push; + if ((push = evo_wait(core, 4))) { + if (core->base.user.oclass < G82_DISP_CORE_CHANNEL_DMA) { + evo_mthd(push, 0x0880 + head->base.index * 0x400, 1); + evo_data(push, 0x05000000); + } else + if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA) { + evo_mthd(push, 0x0880 + head->base.index * 0x400, 1); + evo_data(push, 0x05000000); + evo_mthd(push, 0x089c + head->base.index * 0x400, 1); + evo_data(push, 0x00000000); + } else { + evo_mthd(push, 0x0480 + head->base.index * 0x300, 1); + evo_data(push, 0x05000000); + evo_mthd(push, 0x048c + head->base.index * 0x300, 1); + evo_data(push, 0x00000000); + } + evo_kick(push, core); + } +} + +static void +nv50_head_curs_set(struct nv50_head *head, struct nv50_head_atom *asyh) +{ + struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base; + u32 *push; + if ((push = evo_wait(core, 5))) { + if (core->base.user.oclass < G82_DISP_BASE_CHANNEL_DMA) { + evo_mthd(push, 0x0880 + head->base.index * 0x400, 2); + evo_data(push, 0x80000000 | (asyh->curs.layout << 26) | + (asyh->curs.format << 24)); + evo_data(push, asyh->curs.offset >> 8); + } else + if (core->base.user.oclass < GF110_DISP_BASE_CHANNEL_DMA) { + evo_mthd(push, 0x0880 + head->base.index * 0x400, 2); + evo_data(push, 0x80000000 | (asyh->curs.layout << 26) | + (asyh->curs.format << 24)); + evo_data(push, asyh->curs.offset >> 8); + evo_mthd(push, 0x089c + head->base.index * 0x400, 1); + evo_data(push, asyh->curs.handle); + } else { + evo_mthd(push, 0x0480 + head->base.index * 0x300, 2); + evo_data(push, 0x80000000 | (asyh->curs.layout << 26) | + (asyh->curs.format << 24)); + evo_data(push, asyh->curs.offset >> 8); + evo_mthd(push, 0x048c + head->base.index * 0x300, 1); + evo_data(push, asyh->curs.handle); + } + evo_kick(push, core); + } +} + +static void nv50_head_core_clr(struct nv50_head *head) { struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base; @@ -941,6 +1007,8 @@ nv50_head_flush_clr(struct nv50_head *head, struct nv50_head_atom *asyh, bool y) nv50_head_lut_clr(head); if (asyh->clr.core && (!asyh->set.core || y)) nv50_head_core_clr(head); + if (asyh->clr.curs && (!asyh->set.curs || y)) + nv50_head_curs_clr(head); } static void @@ -949,6 +1017,7 @@ nv50_head_flush_set(struct nv50_head *head, struct nv50_head_atom *asyh) if (asyh->set.mode ) nv50_head_mode (head, asyh); if (asyh->set.core ) nv50_head_lut_set (head, asyh); if (asyh->set.core ) nv50_head_core_set(head, asyh); + if (asyh->set.curs ) nv50_head_curs_set(head, asyh); } static void @@ -1017,7 +1086,7 @@ nv50_head_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state) asyh->core.w = asyh->base.w; asyh->core.h = asyh->base.h; } else - if ((asyh->core.visible = true)) { + if ((asyh->core.visible = asyh->curs.visible)) { /*XXX: We need to either find some way of having the * primary base layer appear black, while still * being able to display the other layers, or we @@ -1039,6 +1108,7 @@ nv50_head_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state) asyh->lut.offset = head->base.lut.nvbo->bo.offset; } else { asyh->core.visible = false; + asyh->curs.visible = false; } if (!drm_atomic_crtc_needs_modeset(&asyh->state)) { @@ -1049,9 +1119,19 @@ nv50_head_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state) if (armh->core.visible) { asyh->clr.core = true; } + + if (asyh->curs.visible) { + if (memcmp(&armh->curs, &asyh->curs, sizeof(asyh->curs))) + asyh->set.curs = true; + } else + if (armh->curs.visible) { + asyh->clr.curs = true; + } } else { asyh->clr.core = armh->core.visible; + asyh->clr.curs = armh->curs.visible; asyh->set.core = asyh->core.visible; + asyh->set.curs = asyh->curs.visible; } memcpy(armh, asyh, sizeof(*asyh)); @@ -1304,55 +1384,27 @@ static void nv50_crtc_cursor_show(struct nouveau_crtc *nv_crtc) { struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev); - u32 *push = evo_wait(mast, 16); - if (push) { - if (nv50_vers(mast) < G82_DISP_CORE_CHANNEL_DMA) { - evo_mthd(push, 0x0880 + (nv_crtc->index * 0x400), 2); - evo_data(push, 0x85000000); - evo_data(push, nv_crtc->cursor.nvbo->bo.offset >> 8); - } else - if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) { - evo_mthd(push, 0x0880 + (nv_crtc->index * 0x400), 2); - evo_data(push, 0x85000000); - evo_data(push, nv_crtc->cursor.nvbo->bo.offset >> 8); - evo_mthd(push, 0x089c + (nv_crtc->index * 0x400), 1); - evo_data(push, mast->base.vram.handle); - } else { - evo_mthd(push, 0x0480 + (nv_crtc->index * 0x300), 2); - evo_data(push, 0x85000000); - evo_data(push, nv_crtc->cursor.nvbo->bo.offset >> 8); - evo_mthd(push, 0x048c + (nv_crtc->index * 0x300), 1); - evo_data(push, mast->base.vram.handle); - } - evo_kick(push, mast); - } - nv_crtc->cursor.visible = true; + struct nv50_head *head = nv50_head(&nv_crtc->base); + struct nv50_head_atom *asyh = &head->asy; + + asyh->curs.visible = true; + asyh->curs.handle = mast->base.vram.handle; + asyh->curs.offset = nv_crtc->cursor.nvbo->bo.offset; + asyh->curs.layout = 1; + asyh->curs.format = 1; + nv50_head_atomic_check(&head->base.base, &asyh->state); + nv50_head_flush_set(head, asyh); } static void nv50_crtc_cursor_hide(struct nouveau_crtc *nv_crtc) { - struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev); - u32 *push = evo_wait(mast, 16); - if (push) { - if (nv50_vers(mast) < G82_DISP_CORE_CHANNEL_DMA) { - evo_mthd(push, 0x0880 + (nv_crtc->index * 0x400), 1); - evo_data(push, 0x05000000); - } else - if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) { - evo_mthd(push, 0x0880 + (nv_crtc->index * 0x400), 1); - evo_data(push, 0x05000000); - evo_mthd(push, 0x089c + (nv_crtc->index * 0x400), 1); - evo_data(push, 0x00000000); - } else { - evo_mthd(push, 0x0480 + (nv_crtc->index * 0x300), 1); - evo_data(push, 0x05000000); - evo_mthd(push, 0x048c + (nv_crtc->index * 0x300), 1); - evo_data(push, 0x00000000); - } - evo_kick(push, mast); - } - nv_crtc->cursor.visible = false; + struct nv50_head *head = nv50_head(&nv_crtc->base); + struct nv50_head_atom *asyh = &head->asy; + + asyh->curs.visible = false; + nv50_head_atomic_check(&head->base.base, &asyh->state); + nv50_head_flush_clr(head, asyh, false); } static void @@ -1383,7 +1435,6 @@ nv50_crtc_dpms(struct drm_crtc *crtc, int mode) static void nv50_crtc_prepare(struct drm_crtc *crtc) { - struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); struct nv50_head *head = nv50_head(crtc); struct nv50_head_atom *asyh = &head->asy; @@ -1392,14 +1443,11 @@ nv50_crtc_prepare(struct drm_crtc *crtc) asyh->state.active = false; nv50_head_atomic_check(&head->base.base, &asyh->state); nv50_head_flush_clr(head, asyh, false); - - nv50_crtc_cursor_show_hide(nv_crtc, false, false); } static void nv50_crtc_commit(struct drm_crtc *crtc) { - struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); struct nv50_head *head = nv50_head(crtc); struct nv50_head_atom *asyh = &head->asy; @@ -1407,7 +1455,6 @@ nv50_crtc_commit(struct drm_crtc *crtc) nv50_head_atomic_check(&head->base.base, &asyh->state); nv50_head_flush_set(head, asyh); - nv50_crtc_cursor_show_hide(nv_crtc, true, true); nv50_display_flip_next(crtc, crtc->primary->fb, NULL, 1); } -- cgit v1.1 From 6bbab3b6b65669b974bece5a688b3dba49ea3e06 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 4 Nov 2016 17:20:36 +1000 Subject: drm/nouveau/kms/nv50: separate out base/ovly channel usage bounds commit This commit separates the calculation of EVO state from the commit, in order to make the same code useful for atomic modesetting. The legacy interfaces have been wrapped on top of them. We're no longer touching the overlay channel usage bounds as of this commit. The code to do so is in place for when overlay planes are added. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_display.c | 86 ++++++++++++++++++++++++++++------ 1 file changed, 71 insertions(+), 15 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index d243042..bef7e3d 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -128,6 +128,10 @@ struct nv50_head_atom { u16 h; } base; + struct { + u8 cpp; + } ovly; + union { struct { bool core:1; @@ -142,6 +146,8 @@ struct nv50_head_atom { bool curs:1; bool view:1; bool mode:1; + bool base:1; + bool ovly:1; }; u16 mask; } set; @@ -786,6 +792,65 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, * Head *****************************************************************************/ static void +nv50_head_ovly(struct nv50_head *head, struct nv50_head_atom *asyh) +{ + struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base; + u32 bounds = 0; + u32 *push; + + if (asyh->base.cpp) { + switch (asyh->base.cpp) { + case 8: bounds |= 0x00000500; break; + case 4: bounds |= 0x00000300; break; + case 2: bounds |= 0x00000100; break; + default: + WARN_ON(1); + break; + } + bounds |= 0x00000001; + } + + if ((push = evo_wait(core, 2))) { + if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA) + evo_mthd(push, 0x0904 + head->base.index * 0x400, 1); + else + evo_mthd(push, 0x04d4 + head->base.index * 0x300, 1); + evo_data(push, bounds); + evo_kick(push, core); + } +} + +static void +nv50_head_base(struct nv50_head *head, struct nv50_head_atom *asyh) +{ + struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base; + u32 bounds = 0; + u32 *push; + + if (asyh->base.cpp) { + switch (asyh->base.cpp) { + case 8: bounds |= 0x00000500; break; + case 4: bounds |= 0x00000300; break; + case 2: bounds |= 0x00000100; break; + case 1: bounds |= 0x00000000; break; + default: + WARN_ON(1); + break; + } + bounds |= 0x00000001; + } + + if ((push = evo_wait(core, 2))) { + if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA) + evo_mthd(push, 0x0900 + head->base.index * 0x400, 1); + else + evo_mthd(push, 0x04d0 + head->base.index * 0x300, 1); + evo_data(push, bounds); + evo_kick(push, core); + } +} + +static void nv50_head_curs_clr(struct nv50_head *head) { struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base; @@ -1018,6 +1083,8 @@ nv50_head_flush_set(struct nv50_head *head, struct nv50_head_atom *asyh) if (asyh->set.core ) nv50_head_lut_set (head, asyh); if (asyh->set.core ) nv50_head_core_set(head, asyh); if (asyh->set.curs ) nv50_head_curs_set(head, asyh); + if (asyh->set.base ) nv50_head_base (head, asyh); + if (asyh->set.ovly ) nv50_head_ovly (head, asyh); } static void @@ -1106,9 +1173,13 @@ nv50_head_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state) asyh->core.pitch = ALIGN(asyh->core.w, 64) * 4; asyh->lut.handle = disp->mast.base.vram.handle; asyh->lut.offset = head->base.lut.nvbo->bo.offset; + asyh->set.base = armh->base.cpp != asyh->base.cpp; + asyh->set.ovly = armh->ovly.cpp != asyh->ovly.cpp; } else { asyh->core.visible = false; asyh->curs.visible = false; + asyh->base.cpp = 0; + asyh->ovly.cpp = 0; } if (!drm_atomic_crtc_needs_modeset(&asyh->state)) { @@ -1491,7 +1562,6 @@ nv50_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *umode, struct nv50_mast *mast = nv50_mast(crtc->dev); struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); struct nouveau_connector *nv_connector; - u32 *push; int ret; struct nv50_head *head = nv50_head(crtc); struct nv50_head_atom *asyh = &head->asy; @@ -1508,20 +1578,6 @@ nv50_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *umode, nv50_head_flush_set(head, asyh); - push = evo_wait(mast, 64); - if (push) { - if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) { - evo_mthd(push, 0x0900 + (nv_crtc->index * 0x400), 2); - evo_data(push, 0x00000311); - evo_data(push, 0x00000100); - } else { - evo_mthd(push, 0x04d0 + (nv_crtc->index * 0x300), 2); - evo_data(push, 0x00000311); - evo_data(push, 0x00000100); - } - evo_kick(push, mast); - } - nv_connector = nouveau_crtc_connector_get(nv_crtc); nv50_crtc_set_dither(nv_crtc, false); nv50_crtc_set_scale(nv_crtc, false); -- cgit v1.1 From c4e6812c1c406df24eb1a59568f210841beb5f33 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 4 Nov 2016 17:20:36 +1000 Subject: drm/nouveau/kms/nv50: separate out viewport commit This commit separates the calculation of EVO state from the commit, in order to make the same code useful for atomic modesetting. The legacy interfaces have been wrapped on top of them. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_connector.h | 1 + drivers/gpu/drm/nouveau/nv50_display.c | 221 ++++++++++++++++------------ 2 files changed, 129 insertions(+), 93 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.h b/drivers/gpu/drm/nouveau/nouveau_connector.h index ed1187e..77bb69ec 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.h +++ b/drivers/gpu/drm/nouveau/nouveau_connector.h @@ -124,6 +124,7 @@ struct nouveau_conn_atom { u32 hborder; u32 vborder; } underscan; + bool full; } scaler; struct { diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index bef7e3d..a5e9599 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -71,6 +71,13 @@ struct nv50_head_atom { struct drm_crtc_state state; + struct { + u16 iW; + u16 iH; + u16 oW; + u16 oH; + } view; + struct nv50_head_mode { bool interlace; u32 clock; @@ -1066,6 +1073,34 @@ nv50_head_mode(struct nv50_head *head, struct nv50_head_atom *asyh) } static void +nv50_head_view(struct nv50_head *head, struct nv50_head_atom *asyh) +{ + struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base; + u32 *push; + if ((push = evo_wait(core, 10))) { + if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA) { + evo_mthd(push, 0x08a4 + (head->base.index * 0x400), 1); + evo_data(push, 0x00000000); + evo_mthd(push, 0x08c8 + (head->base.index * 0x400), 1); + evo_data(push, (asyh->view.iH << 16) | asyh->view.iW); + evo_mthd(push, 0x08d8 + (head->base.index * 0x400), 2); + evo_data(push, (asyh->view.oH << 16) | asyh->view.oW); + evo_data(push, (asyh->view.oH << 16) | asyh->view.oW); + } else { + evo_mthd(push, 0x0494 + (head->base.index * 0x300), 1); + evo_data(push, 0x00000000); + evo_mthd(push, 0x04b8 + (head->base.index * 0x300), 1); + evo_data(push, (asyh->view.iH << 16) | asyh->view.iW); + evo_mthd(push, 0x04c0 + (head->base.index * 0x300), 3); + evo_data(push, (asyh->view.oH << 16) | asyh->view.oW); + evo_data(push, (asyh->view.oH << 16) | asyh->view.oW); + evo_data(push, (asyh->view.oH << 16) | asyh->view.oW); + } + evo_kick(push, core); + } +} + +static void nv50_head_flush_clr(struct nv50_head *head, struct nv50_head_atom *asyh, bool y) { if (asyh->clr.core && (!asyh->set.core || y)) @@ -1079,6 +1114,7 @@ nv50_head_flush_clr(struct nv50_head *head, struct nv50_head_atom *asyh, bool y) static void nv50_head_flush_set(struct nv50_head *head, struct nv50_head_atom *asyh) { + if (asyh->set.view ) nv50_head_view (head, asyh); if (asyh->set.mode ) nv50_head_mode (head, asyh); if (asyh->set.core ) nv50_head_lut_set (head, asyh); if (asyh->set.core ) nv50_head_core_set(head, asyh); @@ -1088,6 +1124,83 @@ nv50_head_flush_set(struct nv50_head *head, struct nv50_head_atom *asyh) } static void +nv50_head_atomic_check_view(struct nv50_head_atom *armh, + struct nv50_head_atom *asyh, + struct nouveau_conn_atom *asyc) +{ + struct drm_connector *connector = asyc->state.connector; + struct drm_display_mode *omode = &asyh->state.adjusted_mode; + struct drm_display_mode *umode = &asyh->state.mode; + int mode = asyc->scaler.mode; + struct edid *edid; + + if (connector->edid_blob_ptr) + edid = (struct edid *)connector->edid_blob_ptr->data; + else + edid = NULL; + + if (!asyc->scaler.full) { + if (mode == DRM_MODE_SCALE_NONE) + omode = umode; + } else { + /* Non-EDID LVDS/eDP mode. */ + mode = DRM_MODE_SCALE_FULLSCREEN; + } + + asyh->view.iW = umode->hdisplay; + asyh->view.iH = umode->vdisplay; + asyh->view.oW = omode->hdisplay; + asyh->view.oH = omode->vdisplay; + if (omode->flags & DRM_MODE_FLAG_DBLSCAN) + asyh->view.oH *= 2; + + /* Add overscan compensation if necessary, will keep the aspect + * ratio the same as the backend mode unless overridden by the + * user setting both hborder and vborder properties. + */ + if ((asyc->scaler.underscan.mode == UNDERSCAN_ON || + (asyc->scaler.underscan.mode == UNDERSCAN_AUTO && + drm_detect_hdmi_monitor(edid)))) { + u32 bX = asyc->scaler.underscan.hborder; + u32 bY = asyc->scaler.underscan.vborder; + u32 r = (asyh->view.oH << 19) / asyh->view.oW; + + if (bX) { + asyh->view.oW -= (bX * 2); + if (bY) asyh->view.oH -= (bY * 2); + else asyh->view.oH = ((asyh->view.oW * r) + (r / 2)) >> 19; + } else { + asyh->view.oW -= (asyh->view.oW >> 4) + 32; + if (bY) asyh->view.oH -= (bY * 2); + else asyh->view.oH = ((asyh->view.oW * r) + (r / 2)) >> 19; + } + } + + /* Handle CENTER/ASPECT scaling, taking into account the areas + * removed already for overscan compensation. + */ + switch (mode) { + case DRM_MODE_SCALE_CENTER: + asyh->view.oW = min((u16)umode->hdisplay, asyh->view.oW); + asyh->view.oH = min((u16)umode->vdisplay, asyh->view.oH); + /* fall-through */ + case DRM_MODE_SCALE_ASPECT: + if (asyh->view.oH < asyh->view.oW) { + u32 r = (asyh->view.iW << 19) / asyh->view.iH; + asyh->view.oW = ((asyh->view.oH * r) + (r / 2)) >> 19; + } else { + u32 r = (asyh->view.iH << 19) / asyh->view.iW; + asyh->view.oH = ((asyh->view.oW * r) + (r / 2)) >> 19; + } + break; + default: + break; + } + + asyh->set.view = true; +} + +static void nv50_head_atomic_check_mode(struct nv50_head *head, struct nv50_head_atom *asyh) { struct drm_display_mode *mode = &asyh->state.adjusted_mode; @@ -1264,105 +1377,27 @@ nv50_crtc_set_dither(struct nouveau_crtc *nv_crtc, bool update) static int nv50_crtc_set_scale(struct nouveau_crtc *nv_crtc, bool update) { - struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev); - struct drm_display_mode *omode, *umode = &nv_crtc->base.mode; + struct nv50_head *head = nv50_head(&nv_crtc->base); + struct nv50_head_atom *asyh = &head->asy; struct drm_crtc *crtc = &nv_crtc->base; struct nouveau_connector *nv_connector; - int mode = DRM_MODE_SCALE_NONE; - u32 oX, oY, *push; + struct nouveau_conn_atom asyc; - /* start off at the resolution we programmed the crtc for, this - * effectively handles NONE/FULL scaling - */ nv_connector = nouveau_crtc_connector_get(nv_crtc); - if (nv_connector && nv_connector->native_mode) { - mode = nv_connector->scaling_mode; - if (nv_connector->scaling_full) /* non-EDID LVDS/eDP mode */ - mode = DRM_MODE_SCALE_FULLSCREEN; - } - if (mode != DRM_MODE_SCALE_NONE) - omode = nv_connector->native_mode; - else - omode = umode; - - oX = omode->hdisplay; - oY = omode->vdisplay; - if (omode->flags & DRM_MODE_FLAG_DBLSCAN) - oY *= 2; - - /* add overscan compensation if necessary, will keep the aspect - * ratio the same as the backend mode unless overridden by the - * user setting both hborder and vborder properties. - */ - if (nv_connector && ( nv_connector->underscan == UNDERSCAN_ON || - (nv_connector->underscan == UNDERSCAN_AUTO && - drm_detect_hdmi_monitor(nv_connector->edid)))) { - u32 bX = nv_connector->underscan_hborder; - u32 bY = nv_connector->underscan_vborder; - u32 aspect = (oY << 19) / oX; - - if (bX) { - oX -= (bX * 2); - if (bY) oY -= (bY * 2); - else oY = ((oX * aspect) + (aspect / 2)) >> 19; - } else { - oX -= (oX >> 4) + 32; - if (bY) oY -= (bY * 2); - else oY = ((oX * aspect) + (aspect / 2)) >> 19; - } - } - - /* handle CENTER/ASPECT scaling, taking into account the areas - * removed already for overscan compensation - */ - switch (mode) { - case DRM_MODE_SCALE_CENTER: - oX = min((u32)umode->hdisplay, oX); - oY = min((u32)umode->vdisplay, oY); - /* fall-through */ - case DRM_MODE_SCALE_ASPECT: - if (oY < oX) { - u32 aspect = (umode->hdisplay << 19) / umode->vdisplay; - oX = ((oY * aspect) + (aspect / 2)) >> 19; - } else { - u32 aspect = (umode->vdisplay << 19) / umode->hdisplay; - oY = ((oX * aspect) + (aspect / 2)) >> 19; - } - break; - default: - break; - } - - push = evo_wait(mast, 8); - if (push) { - if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) { - /*XXX: SCALE_CTRL_ACTIVE??? */ - evo_mthd(push, 0x08d8 + (nv_crtc->index * 0x400), 2); - evo_data(push, (oY << 16) | oX); - evo_data(push, (oY << 16) | oX); - evo_mthd(push, 0x08a4 + (nv_crtc->index * 0x400), 1); - evo_data(push, 0x00000000); - evo_mthd(push, 0x08c8 + (nv_crtc->index * 0x400), 1); - evo_data(push, umode->vdisplay << 16 | umode->hdisplay); - } else { - evo_mthd(push, 0x04c0 + (nv_crtc->index * 0x300), 3); - evo_data(push, (oY << 16) | oX); - evo_data(push, (oY << 16) | oX); - evo_data(push, (oY << 16) | oX); - evo_mthd(push, 0x0494 + (nv_crtc->index * 0x300), 1); - evo_data(push, 0x00000000); - evo_mthd(push, 0x04b8 + (nv_crtc->index * 0x300), 1); - evo_data(push, umode->vdisplay << 16 | umode->hdisplay); - } - - evo_kick(push, mast); + asyc.state.connector = &nv_connector->base; + asyc.scaler.mode = nv_connector->scaling_mode; + asyc.scaler.full = nv_connector->scaling_full; + asyc.scaler.underscan.mode = nv_connector->underscan; + asyc.scaler.underscan.hborder = nv_connector->underscan_hborder; + asyc.scaler.underscan.vborder = nv_connector->underscan_vborder; + nv50_head_atomic_check(&head->base.base, &asyh->state); + nv50_head_atomic_check_view(&head->arm, asyh, &asyc); + nv50_head_flush_set(head, asyh); - if (update) { - nv50_display_flip_stop(crtc); - nv50_display_flip_next(crtc, crtc->primary->fb, - NULL, 1); - } + if (update) { + nv50_display_flip_stop(crtc); + nv50_display_flip_next(crtc, crtc->primary->fb, NULL, 1); } return 0; -- cgit v1.1 From 7e91833dfb2d33d640ae80582f2701838532d680 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 4 Nov 2016 17:20:36 +1000 Subject: drm/nouveau/kms/nv50: separate out dither commit This commit separates the calculation of EVO state from the commit, in order to make the same code useful for atomic modesetting. The legacy interfaces have been wrapped on top of them. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_display.c | 101 +++++++++++++++++++++++---------- 1 file changed, 70 insertions(+), 31 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index a5e9599..44de7a3 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -139,6 +139,12 @@ struct nv50_head_atom { u8 cpp; } ovly; + struct { + bool enable:1; + u8 bits:2; + u8 mode:4; + } dither; + union { struct { bool core:1; @@ -155,6 +161,7 @@ struct nv50_head_atom { bool mode:1; bool base:1; bool ovly:1; + bool dither:1; }; u16 mask; } set; @@ -799,6 +806,26 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, * Head *****************************************************************************/ static void +nv50_head_dither(struct nv50_head *head, struct nv50_head_atom *asyh) +{ + struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base; + u32 *push; + if ((push = evo_wait(core, 2))) { + if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA) + evo_mthd(push, 0x08a0 + (head->base.index * 0x0400), 1); + else + if (core->base.user.oclass < GK104_DISP_CORE_CHANNEL_DMA) + evo_mthd(push, 0x0490 + (head->base.index * 0x0300), 1); + else + evo_mthd(push, 0x04a0 + (head->base.index * 0x0300), 1); + evo_data(push, (asyh->dither.mode << 3) | + (asyh->dither.bits << 1) | + asyh->dither.enable); + evo_kick(push, core); + } +} + +static void nv50_head_ovly(struct nv50_head *head, struct nv50_head_atom *asyh) { struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base; @@ -1121,6 +1148,35 @@ nv50_head_flush_set(struct nv50_head *head, struct nv50_head_atom *asyh) if (asyh->set.curs ) nv50_head_curs_set(head, asyh); if (asyh->set.base ) nv50_head_base (head, asyh); if (asyh->set.ovly ) nv50_head_ovly (head, asyh); + if (asyh->set.dither ) nv50_head_dither (head, asyh); +} + +static void +nv50_head_atomic_check_dither(struct nv50_head_atom *armh, + struct nv50_head_atom *asyh, + struct nouveau_conn_atom *asyc) +{ + struct drm_connector *connector = asyc->state.connector; + u32 mode = 0x00; + + if (asyc->dither.mode == DITHERING_MODE_AUTO) { + if (asyh->base.depth > connector->display_info.bpc * 3) + mode = DITHERING_MODE_DYNAMIC2X2; + } else { + mode = asyc->dither.mode; + } + + if (asyc->dither.depth == DITHERING_DEPTH_AUTO) { + if (connector->display_info.bpc >= 8) + mode |= DITHERING_DEPTH_8BPC; + } else { + mode |= asyc->dither.depth; + } + + asyh->dither.enable = mode; + asyh->dither.bits = mode >> 1; + asyh->dither.mode = mode >> 3; + asyh->set.dither = true; } static void @@ -1330,45 +1386,28 @@ static int nv50_crtc_set_dither(struct nouveau_crtc *nv_crtc, bool update) { struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev); + struct nv50_head *head = nv50_head(&nv_crtc->base); + struct nv50_head_atom *asyh = &head->asy; struct nouveau_connector *nv_connector; - struct drm_connector *connector; - u32 *push, mode = 0x00; + struct nouveau_conn_atom asyc; + u32 *push; nv_connector = nouveau_crtc_connector_get(nv_crtc); - connector = &nv_connector->base; - if (nv_connector->dithering_mode == DITHERING_MODE_AUTO) { - if (nv_crtc->base.primary->fb->depth > connector->display_info.bpc * 3) - mode = DITHERING_MODE_DYNAMIC2X2; - } else { - mode = nv_connector->dithering_mode; - } - - if (nv_connector->dithering_depth == DITHERING_DEPTH_AUTO) { - if (connector->display_info.bpc >= 8) - mode |= DITHERING_DEPTH_8BPC; - } else { - mode |= nv_connector->dithering_depth; - } - push = evo_wait(mast, 4); - if (push) { - if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) { - evo_mthd(push, 0x08a0 + (nv_crtc->index * 0x0400), 1); - evo_data(push, mode); - } else - if (nv50_vers(mast) < GK104_DISP_CORE_CHANNEL_DMA) { - evo_mthd(push, 0x0490 + (nv_crtc->index * 0x0300), 1); - evo_data(push, mode); - } else { - evo_mthd(push, 0x04a0 + (nv_crtc->index * 0x0300), 1); - evo_data(push, mode); - } + asyc.state.connector = &nv_connector->base; + asyc.dither.mode = nv_connector->dithering_mode; + asyc.dither.depth = nv_connector->dithering_depth; + asyh->state.crtc = &nv_crtc->base; + nv50_head_atomic_check(&head->base.base, &asyh->state); + nv50_head_atomic_check_dither(&head->arm, asyh, &asyc); + nv50_head_flush_set(head, asyh); - if (update) { + if (update) { + if ((push = evo_wait(mast, 2))) { evo_mthd(push, 0x0080, 1); evo_data(push, 0x00000000); + evo_kick(push, mast); } - evo_kick(push, mast); } return 0; -- cgit v1.1 From 7e08d67c5fe980f2b9d27a07a2325a35e5bb4759 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 4 Nov 2016 17:20:36 +1000 Subject: drm/nouveau/kms/nv50: separate out procamp commit This commit separates the calculation of EVO state from the commit, in order to make the same code useful for atomic modesetting. The legacy interfaces have been wrapped on top of them. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_display.c | 67 +++++++++++++++++++++++++--------- 1 file changed, 50 insertions(+), 17 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 44de7a3..67a8b66 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -145,6 +145,13 @@ struct nv50_head_atom { u8 mode:4; } dither; + struct { + struct { + u16 cos:12; + u16 sin:12; + } sat; + } procamp; + union { struct { bool core:1; @@ -162,6 +169,7 @@ struct nv50_head_atom { bool base:1; bool ovly:1; bool dither:1; + bool procamp:1; }; u16 mask; } set; @@ -806,6 +814,22 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, * Head *****************************************************************************/ static void +nv50_head_procamp(struct nv50_head *head, struct nv50_head_atom *asyh) +{ + struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base; + u32 *push; + if ((push = evo_wait(core, 2))) { + if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA) + evo_mthd(push, 0x08a8 + (head->base.index * 0x400), 1); + else + evo_mthd(push, 0x0498 + (head->base.index * 0x300), 1); + evo_data(push, (asyh->procamp.sat.sin << 20) | + (asyh->procamp.sat.cos << 8)); + evo_kick(push, core); + } +} + +static void nv50_head_dither(struct nv50_head *head, struct nv50_head_atom *asyh) { struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base; @@ -1149,6 +1173,20 @@ nv50_head_flush_set(struct nv50_head *head, struct nv50_head_atom *asyh) if (asyh->set.base ) nv50_head_base (head, asyh); if (asyh->set.ovly ) nv50_head_ovly (head, asyh); if (asyh->set.dither ) nv50_head_dither (head, asyh); + if (asyh->set.procamp) nv50_head_procamp (head, asyh); +} + +static void +nv50_head_atomic_check_procamp(struct nv50_head_atom *armh, + struct nv50_head_atom *asyh, + struct nouveau_conn_atom *asyc) +{ + const int vib = asyc->procamp.color_vibrance - 100; + const int hue = asyc->procamp.vibrant_hue - 90; + const int adj = (vib > 0) ? 50 : 0; + asyh->procamp.sat.cos = ((vib * 2047 + adj) / 100) & 0xfff; + asyh->procamp.sat.sin = ((hue * 2047) / 100) & 0xfff; + asyh->set.procamp = true; } static void @@ -1462,28 +1500,23 @@ static int nv50_crtc_set_color_vibrance(struct nouveau_crtc *nv_crtc, bool update) { struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev); - u32 *push, hue, vib; - int adj; - - adj = (nv_crtc->color_vibrance > 0) ? 50 : 0; - vib = ((nv_crtc->color_vibrance * 2047 + adj) / 100) & 0xfff; - hue = ((nv_crtc->vibrant_hue * 2047) / 100) & 0xfff; + struct nv50_head *head = nv50_head(&nv_crtc->base); + struct nv50_head_atom *asyh = &head->asy; + struct nouveau_conn_atom asyc; + u32 *push; - push = evo_wait(mast, 16); - if (push) { - if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) { - evo_mthd(push, 0x08a8 + (nv_crtc->index * 0x400), 1); - evo_data(push, (hue << 20) | (vib << 8)); - } else { - evo_mthd(push, 0x0498 + (nv_crtc->index * 0x300), 1); - evo_data(push, (hue << 20) | (vib << 8)); - } + asyc.procamp.color_vibrance = nv_crtc->color_vibrance + 100; + asyc.procamp.vibrant_hue = nv_crtc->vibrant_hue + 90; + nv50_head_atomic_check(&head->base.base, &asyh->state); + nv50_head_atomic_check_procamp(&head->arm, asyh, &asyc); + nv50_head_flush_set(head, asyh); - if (update) { + if (update) { + if ((push = evo_wait(mast, 2))) { evo_mthd(push, 0x0080, 1); evo_data(push, 0x00000000); + evo_kick(push, mast); } - evo_kick(push, mast); } return 0; -- cgit v1.1 From 06ab282f13210c80fc74f3ada981f62fca68e625 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 4 Nov 2016 17:20:36 +1000 Subject: drm/nouveau/kms/nv50: separate out vblank dmi commit Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_display.c | 24 ++---------------------- 1 file changed, 2 insertions(+), 22 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 67a8b66..b94bc74 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -1094,13 +1094,14 @@ nv50_head_mode(struct nv50_head *head, struct nv50_head_atom *asyh) evo_mthd(push, 0x0804 + (head->base.index * 0x400), 2); evo_data(push, 0x00800000 | m->clock); evo_data(push, m->interlace ? 0x00000002 : 0x00000000); - evo_mthd(push, 0x0810 + (head->base.index * 0x400), 6); + evo_mthd(push, 0x0810 + (head->base.index * 0x400), 7); evo_data(push, 0x00000000); evo_data(push, (m->v.active << 16) | m->h.active ); evo_data(push, (m->v.synce << 16) | m->h.synce ); evo_data(push, (m->v.blanke << 16) | m->h.blanke ); evo_data(push, (m->v.blanks << 16) | m->h.blanks ); evo_data(push, (m->v.blank2e << 16) | m->v.blank2s); + evo_data(push, asyh->mode.v.blankus); evo_mthd(push, 0x082c + (head->base.index * 0x400), 1); evo_data(push, 0x00000000); } else { @@ -1481,22 +1482,6 @@ nv50_crtc_set_scale(struct nouveau_crtc *nv_crtc, bool update) } static int -nv50_crtc_set_raster_vblank_dmi(struct nouveau_crtc *nv_crtc, u32 usec) -{ - struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev); - u32 *push; - - push = evo_wait(mast, 8); - if (!push) - return -ENOMEM; - - evo_mthd(push, 0x0828 + (nv_crtc->index * 0x400), 1); - evo_data(push, usec); - evo_kick(push, mast); - return 0; -} - -static int nv50_crtc_set_color_vibrance(struct nouveau_crtc *nv_crtc, bool update) { struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev); @@ -1666,7 +1651,6 @@ nv50_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *umode, struct drm_display_mode *mode, int x, int y, struct drm_framebuffer *old_fb) { - struct nv50_mast *mast = nv50_mast(crtc->dev); struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); struct nouveau_connector *nv_connector; int ret; @@ -1689,10 +1673,6 @@ nv50_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *umode, nv50_crtc_set_dither(nv_crtc, false); nv50_crtc_set_scale(nv_crtc, false); - /* G94 only accepts this after setting scale */ - if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) - nv50_crtc_set_raster_vblank_dmi(nv_crtc, asyh->mode.v.blankus); - nv50_crtc_set_color_vibrance(nv_crtc, false); nv50_crtc_set_image(nv_crtc, crtc->primary->fb, x, y, false); return 0; -- cgit v1.1 From 973f10c2d3ea4cca2f359353812fb93d8c43652f Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 4 Nov 2016 17:20:36 +1000 Subject: drm/nouveau/kms/nv50: separate out base channel commit This commit separates the calculation of EVO state from the commit, in order to make the same code useful for atomic modesetting. The legacy interfaces have been wrapped on top of them. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_display.c | 835 +++++++++++++++++++++++++++++---- 1 file changed, 743 insertions(+), 92 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index b94bc74..068810b 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -39,6 +40,7 @@ #include #include #include +#include #include "nouveau_drv.h" #include "nouveau_dma.h" @@ -62,6 +64,8 @@ #define EVO_MAST_NTFY EVO_SYNC( 0, 0x00) #define EVO_FLIP_SEM0(c) EVO_SYNC((c) + 1, 0x00) #define EVO_FLIP_SEM1(c) EVO_SYNC((c) + 1, 0x10) +#define EVO_FLIP_NTFY0(c) EVO_SYNC((c) + 1, 0x20) +#define EVO_FLIP_NTFY1(c) EVO_SYNC((c) + 1, 0x30) /****************************************************************************** * Atomic state @@ -175,6 +179,73 @@ struct nv50_head_atom { } set; }; +#define nv50_wndw_atom(p) container_of((p), struct nv50_wndw_atom, state) + +struct nv50_wndw_atom { + struct drm_plane_state state; + u8 interval; + + struct drm_rect clip; + + struct { + u32 handle; + u16 offset:12; + bool awaken:1; + } ntfy; + + struct { + u32 handle; + u16 offset:12; + u32 acquire; + u32 release; + } sema; + + struct { + u8 enable:2; + } lut; + + struct { + u8 mode:2; + u8 interval:4; + + u8 format; + u8 kind:7; + u8 layout:1; + u8 block:4; + u32 pitch:20; + u16 w; + u16 h; + + u32 handle; + u64 offset; + } image; + + struct { + u16 x; + u16 y; + } point; + + union { + struct { + bool ntfy:1; + bool sema:1; + bool image:1; + }; + u8 mask; + } clr; + + union { + struct { + bool ntfy:1; + bool sema:1; + bool image:1; + bool lut:1; + bool point:1; + }; + u8 mask; + } set; +}; + /****************************************************************************** * EVO channel *****************************************************************************/ @@ -496,17 +567,17 @@ struct nv50_head { struct nouveau_crtc base; struct nouveau_bo *image; struct nv50_curs curs; - struct nv50_sync sync; struct nv50_ovly ovly; struct nv50_oimm oimm; struct nv50_head_atom arm; struct nv50_head_atom asy; + + struct nv50_base *_base; }; #define nv50_head(c) ((struct nv50_head *)nouveau_crtc(c)) #define nv50_curs(c) (&nv50_head(c)->curs) -#define nv50_sync(c) (&nv50_head(c)->sync) #define nv50_ovly(c) (&nv50_head(c)->ovly) #define nv50_oimm(c) (&nv50_head(c)->oimm) #define nv50_chan(c) (&(c)->base.base) @@ -628,6 +699,605 @@ evo_sync(struct drm_device *dev) } /****************************************************************************** + * Plane + *****************************************************************************/ +#define nv50_wndw(p) container_of((p), struct nv50_wndw, plane) + +struct nv50_wndw { + const struct nv50_wndw_func *func; + struct nv50_dmac *dmac; + + struct drm_plane plane; + + struct nvif_notify notify; + u16 ntfy; + u16 sema; + u32 data; + + struct nv50_wndw_atom arm; + struct nv50_wndw_atom asy; +}; + +struct nv50_wndw_func { + void *(*dtor)(struct nv50_wndw *); + int (*acquire)(struct nv50_wndw *, struct nv50_wndw_atom *asyw, + struct nv50_head_atom *asyh); + void (*release)(struct nv50_wndw *, struct nv50_wndw_atom *asyw, + struct nv50_head_atom *asyh); + void (*prepare)(struct nv50_wndw *, struct nv50_head_atom *asyh, + struct nv50_wndw_atom *asyw); + + void (*sema_set)(struct nv50_wndw *, struct nv50_wndw_atom *); + void (*sema_clr)(struct nv50_wndw *); + void (*ntfy_set)(struct nv50_wndw *, struct nv50_wndw_atom *); + void (*ntfy_clr)(struct nv50_wndw *); + int (*ntfy_wait_begun)(struct nv50_wndw *, struct nv50_wndw_atom *); + void (*image_set)(struct nv50_wndw *, struct nv50_wndw_atom *); + void (*image_clr)(struct nv50_wndw *); + void (*lut)(struct nv50_wndw *, struct nv50_wndw_atom *); + void (*point)(struct nv50_wndw *, struct nv50_wndw_atom *); + + u32 (*update)(struct nv50_wndw *, u32 interlock); +}; + +static int +nv50_wndw_wait_armed(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw) +{ + if (asyw->set.ntfy) + return wndw->func->ntfy_wait_begun(wndw, asyw); + return 0; +} + +static u32 +nv50_wndw_flush_clr(struct nv50_wndw *wndw, u32 interlock, bool flush, + struct nv50_wndw_atom *asyw) +{ + if (asyw->clr.sema && (!asyw->set.sema || flush)) + wndw->func->sema_clr(wndw); + if (asyw->clr.ntfy && (!asyw->set.ntfy || flush)) + wndw->func->ntfy_clr(wndw); + if (asyw->clr.image && (!asyw->set.image || flush)) + wndw->func->image_clr(wndw); + + return flush ? wndw->func->update(wndw, interlock) : 0; +} + +static u32 +nv50_wndw_flush_set(struct nv50_wndw *wndw, u32 interlock, + struct nv50_wndw_atom *asyw) +{ + if (interlock) { + asyw->image.mode = 0; + asyw->image.interval = 1; + } + + if (asyw->set.sema ) wndw->func->sema_set (wndw, asyw); + if (asyw->set.ntfy ) wndw->func->ntfy_set (wndw, asyw); + if (asyw->set.image) wndw->func->image_set(wndw, asyw); + if (asyw->set.lut ) wndw->func->lut (wndw, asyw); + if (asyw->set.point) wndw->func->point (wndw, asyw); + + return wndw->func->update(wndw, interlock); +} + +static void +nv50_wndw_atomic_check_release(struct nv50_wndw *wndw, + struct nv50_wndw_atom *asyw, + struct nv50_head_atom *asyh) +{ + struct nouveau_drm *drm = nouveau_drm(wndw->plane.dev); + NV_ATOMIC(drm, "%s release\n", wndw->plane.name); + wndw->func->release(wndw, asyw, asyh); + asyw->ntfy.handle = 0; + asyw->sema.handle = 0; +} + +static int +nv50_wndw_atomic_check_acquire(struct nv50_wndw *wndw, + struct nv50_wndw_atom *asyw, + struct nv50_head_atom *asyh) +{ + struct nouveau_framebuffer *fb = nouveau_framebuffer(asyw->state.fb); + struct nouveau_drm *drm = nouveau_drm(wndw->plane.dev); + int ret; + + NV_ATOMIC(drm, "%s acquire\n", wndw->plane.name); + asyw->clip.x1 = 0; + asyw->clip.y1 = 0; + asyw->clip.x2 = asyh->state.mode.hdisplay; + asyw->clip.y2 = asyh->state.mode.vdisplay; + + asyw->image.w = fb->base.width; + asyw->image.h = fb->base.height; + asyw->image.kind = (fb->nvbo->tile_flags & 0x0000ff00) >> 8; + if (asyw->image.kind) { + asyw->image.layout = 0; + if (drm->device.info.chipset >= 0xc0) + asyw->image.block = fb->nvbo->tile_mode >> 4; + else + asyw->image.block = fb->nvbo->tile_mode; + asyw->image.pitch = (fb->base.pitches[0] / 4) << 4; + } else { + asyw->image.layout = 1; + asyw->image.block = 0; + asyw->image.pitch = fb->base.pitches[0]; + } + + ret = wndw->func->acquire(wndw, asyw, asyh); + if (ret) + return ret; + + if (asyw->set.image) { + if (!(asyw->image.mode = asyw->interval ? 0 : 1)) + asyw->image.interval = asyw->interval; + else + asyw->image.interval = 0; + } + + return 0; +} + +static int +nv50_wndw_atomic_check(struct drm_plane *plane, struct drm_plane_state *state) +{ + struct nouveau_drm *drm = nouveau_drm(plane->dev); + struct nv50_wndw *wndw = nv50_wndw(plane); + struct nv50_wndw_atom *armw = &wndw->arm; + struct nv50_wndw_atom *asyw = &wndw->asy; + struct nv50_head_atom *harm = NULL, *asyh = NULL; + bool varm = false, asyv = false, asym = false; + int ret; + + asyw->clr.mask = 0; + asyw->set.mask = 0; + + NV_ATOMIC(drm, "%s atomic_check\n", plane->name); + if (asyw->state.crtc) { + asyh = &nv50_head(asyw->state.crtc)->asy; + if (IS_ERR(asyh)) + return PTR_ERR(asyh); + asym = drm_atomic_crtc_needs_modeset(&asyh->state); + asyv = asyh->state.active; + } + + if (armw->state.crtc) { + harm = &nv50_head(armw->state.crtc)->asy; + if (IS_ERR(harm)) + return PTR_ERR(harm); + varm = nv50_head(harm->state.crtc)->arm.state.active; + } + + if (asyv) { + asyw->point.x = asyw->state.crtc_x; + asyw->point.y = asyw->state.crtc_y; + if (memcmp(&armw->point, &asyw->point, sizeof(asyw->point))) + asyw->set.point = true; + + if (!varm || asym || armw->state.fb != asyw->state.fb) { + ret = nv50_wndw_atomic_check_acquire(wndw, asyw, asyh); + if (ret) + return ret; + } + } else + if (varm) { + nv50_wndw_atomic_check_release(wndw, asyw, harm); + } else { + return 0; + } + + if (!asyv || asym) { + asyw->clr.ntfy = armw->ntfy.handle != 0; + asyw->clr.sema = armw->sema.handle != 0; + if (wndw->func->image_clr) + asyw->clr.image = armw->image.handle != 0; + asyw->set.lut = wndw->func->lut && asyv; + } + + memcpy(armw, asyw, sizeof(*asyw)); + return 0; +} + +static void +nv50_wndw_atomic_destroy_state(struct drm_plane *plane, + struct drm_plane_state *state) +{ + struct nv50_wndw_atom *asyw = nv50_wndw_atom(state); + __drm_atomic_helper_plane_destroy_state(&asyw->state); + dma_fence_put(asyw->state.fence); + kfree(asyw); +} + +static struct drm_plane_state * +nv50_wndw_atomic_duplicate_state(struct drm_plane *plane) +{ + struct nv50_wndw_atom *armw = nv50_wndw_atom(plane->state); + struct nv50_wndw_atom *asyw; + if (!(asyw = kmalloc(sizeof(*asyw), GFP_KERNEL))) + return NULL; + __drm_atomic_helper_plane_duplicate_state(plane, &asyw->state); + asyw->state.fence = NULL; + asyw->interval = 1; + asyw->sema = armw->sema; + asyw->ntfy = armw->ntfy; + asyw->image = armw->image; + asyw->point = armw->point; + asyw->lut = armw->lut; + asyw->clr.mask = 0; + asyw->set.mask = 0; + return &asyw->state; +} + +static void +nv50_wndw_reset(struct drm_plane *plane) +{ + struct nv50_wndw_atom *asyw; + + if (WARN_ON(!(asyw = kzalloc(sizeof(*asyw), GFP_KERNEL)))) + return; + + if (plane->state) + plane->funcs->atomic_destroy_state(plane, plane->state); + plane->state = &asyw->state; + plane->state->plane = plane; + plane->state->rotation = DRM_ROTATE_0; +} + +static void +nv50_wndw_destroy(struct drm_plane *plane) +{ + struct nv50_wndw *wndw = nv50_wndw(plane); + void *data; + nvif_notify_fini(&wndw->notify); + data = wndw->func->dtor(wndw); + drm_plane_cleanup(&wndw->plane); + kfree(data); +} + +static const struct drm_plane_funcs +nv50_wndw = { + .destroy = nv50_wndw_destroy, + .reset = nv50_wndw_reset, + .set_property = drm_atomic_helper_plane_set_property, + .atomic_duplicate_state = nv50_wndw_atomic_duplicate_state, + .atomic_destroy_state = nv50_wndw_atomic_destroy_state, +}; + +static void +nv50_wndw_fini(struct nv50_wndw *wndw) +{ + nvif_notify_put(&wndw->notify); +} + +static void +nv50_wndw_init(struct nv50_wndw *wndw) +{ + nvif_notify_get(&wndw->notify); +} + +static int +nv50_wndw_ctor(const struct nv50_wndw_func *func, struct drm_device *dev, + enum drm_plane_type type, const char *name, int index, + struct nv50_dmac *dmac, const u32 *format, int nformat, + struct nv50_wndw *wndw) +{ + int ret; + + wndw->func = func; + wndw->dmac = dmac; + + ret = drm_universal_plane_init(dev, &wndw->plane, 0, &nv50_wndw, format, + nformat, type, "%s-%d", name, index); + if (ret) + return ret; + + return 0; +} + +/****************************************************************************** + * Primary plane + *****************************************************************************/ +#define nv50_base(p) container_of((p), struct nv50_base, wndw) + +struct nv50_base { + struct nv50_wndw wndw; + struct nv50_sync chan; + int id; +}; + +static int +nv50_base_notify(struct nvif_notify *notify) +{ + return NVIF_NOTIFY_KEEP; +} + +static void +nv50_base_lut(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw) +{ + struct nv50_base *base = nv50_base(wndw); + u32 *push; + if ((push = evo_wait(&base->chan, 2))) { + evo_mthd(push, 0x00e0, 1); + evo_data(push, asyw->lut.enable << 30); + evo_kick(push, &base->chan); + } +} + +static void +nv50_base_image_clr(struct nv50_wndw *wndw) +{ + struct nv50_base *base = nv50_base(wndw); + u32 *push; + if ((push = evo_wait(&base->chan, 4))) { + evo_mthd(push, 0x0084, 1); + evo_data(push, 0x00000000); + evo_mthd(push, 0x00c0, 1); + evo_data(push, 0x00000000); + evo_kick(push, &base->chan); + } +} + +static void +nv50_base_image_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw) +{ + struct nv50_base *base = nv50_base(wndw); + const s32 oclass = base->chan.base.base.user.oclass; + u32 *push; + if ((push = evo_wait(&base->chan, 10))) { + evo_mthd(push, 0x0084, 1); + evo_data(push, (asyw->image.mode << 8) | + (asyw->image.interval << 4)); + evo_mthd(push, 0x00c0, 1); + evo_data(push, asyw->image.handle); + if (oclass < G82_DISP_BASE_CHANNEL_DMA) { + evo_mthd(push, 0x0800, 5); + evo_data(push, asyw->image.offset >> 8); + evo_data(push, 0x00000000); + evo_data(push, (asyw->image.h << 16) | asyw->image.w); + evo_data(push, (asyw->image.layout << 20) | + asyw->image.pitch | + asyw->image.block); + evo_data(push, (asyw->image.kind << 16) | + (asyw->image.format << 8)); + } else + if (oclass < GF110_DISP_BASE_CHANNEL_DMA) { + evo_mthd(push, 0x0800, 5); + evo_data(push, asyw->image.offset >> 8); + evo_data(push, 0x00000000); + evo_data(push, (asyw->image.h << 16) | asyw->image.w); + evo_data(push, (asyw->image.layout << 20) | + asyw->image.pitch | + asyw->image.block); + evo_data(push, asyw->image.format << 8); + } else { + evo_mthd(push, 0x0400, 5); + evo_data(push, asyw->image.offset >> 8); + evo_data(push, 0x00000000); + evo_data(push, (asyw->image.h << 16) | asyw->image.w); + evo_data(push, (asyw->image.layout << 24) | + asyw->image.pitch | + asyw->image.block); + evo_data(push, asyw->image.format << 8); + } + evo_kick(push, &base->chan); + } +} + +static void +nv50_base_ntfy_clr(struct nv50_wndw *wndw) +{ + struct nv50_base *base = nv50_base(wndw); + u32 *push; + if ((push = evo_wait(&base->chan, 2))) { + evo_mthd(push, 0x00a4, 1); + evo_data(push, 0x00000000); + evo_kick(push, &base->chan); + } +} + +static void +nv50_base_ntfy_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw) +{ + struct nv50_base *base = nv50_base(wndw); + u32 *push; + if ((push = evo_wait(&base->chan, 3))) { + evo_mthd(push, 0x00a0, 2); + evo_data(push, (asyw->ntfy.awaken << 30) | asyw->ntfy.offset); + evo_data(push, asyw->ntfy.handle); + evo_kick(push, &base->chan); + } +} + +static void +nv50_base_sema_clr(struct nv50_wndw *wndw) +{ + struct nv50_base *base = nv50_base(wndw); + u32 *push; + if ((push = evo_wait(&base->chan, 2))) { + evo_mthd(push, 0x0094, 1); + evo_data(push, 0x00000000); + evo_kick(push, &base->chan); + } +} + +static void +nv50_base_sema_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw) +{ + struct nv50_base *base = nv50_base(wndw); + u32 *push; + if ((push = evo_wait(&base->chan, 5))) { + evo_mthd(push, 0x0088, 4); + evo_data(push, asyw->sema.offset); + evo_data(push, asyw->sema.acquire); + evo_data(push, asyw->sema.release); + evo_data(push, asyw->sema.handle); + evo_kick(push, &base->chan); + } +} + +static u32 +nv50_base_update(struct nv50_wndw *wndw, u32 interlock) +{ + struct nv50_base *base = nv50_base(wndw); + u32 *push; + + if (!(push = evo_wait(&base->chan, 2))) + return 0; + evo_mthd(push, 0x0080, 1); + evo_data(push, interlock); + evo_kick(push, &base->chan); + + if (base->chan.base.base.user.oclass < GF110_DISP_BASE_CHANNEL_DMA) + return interlock ? 2 << (base->id * 8) : 0; + return interlock ? 2 << (base->id * 4) : 0; +} + +static int +nv50_base_ntfy_wait_begun(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw) +{ + struct nouveau_drm *drm = nouveau_drm(wndw->plane.dev); + struct nv50_disp *disp = nv50_disp(wndw->plane.dev); + if (nvif_msec(&drm->device, 2000ULL, + u32 data = nouveau_bo_rd32(disp->sync, asyw->ntfy.offset / 4); + if ((data & 0xc0000000) == 0x40000000) + break; + usleep_range(1, 2); + ) < 0) + return -ETIMEDOUT; + return 0; +} + +static void +nv50_base_release(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw, + struct nv50_head_atom *asyh) +{ + asyh->base.cpp = 0; +} + +static int +nv50_base_acquire(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw, + struct nv50_head_atom *asyh) +{ + const u32 format = asyw->state.fb->pixel_format; + const struct drm_format_info *info; + int ret; + + info = drm_format_info(format); + if (!info || !info->depth) + return -EINVAL; + + ret = drm_plane_helper_check_state(&asyw->state, &asyw->clip, + DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_HELPER_NO_SCALING, + false, true); + if (ret) + return ret; + + asyh->base.depth = info->depth; + asyh->base.cpp = info->cpp[0]; + asyh->base.x = asyw->state.src.x1 >> 16; + asyh->base.y = asyw->state.src.y1 >> 16; + asyh->base.w = asyw->state.fb->width; + asyh->base.h = asyw->state.fb->height; + + switch (format) { + case DRM_FORMAT_C8 : asyw->image.format = 0x1e; break; + case DRM_FORMAT_RGB565 : asyw->image.format = 0xe8; break; + case DRM_FORMAT_XRGB1555 : + case DRM_FORMAT_ARGB1555 : asyw->image.format = 0xe9; break; + case DRM_FORMAT_XRGB8888 : + case DRM_FORMAT_ARGB8888 : asyw->image.format = 0xcf; break; + case DRM_FORMAT_XBGR2101010: + case DRM_FORMAT_ABGR2101010: asyw->image.format = 0xd1; break; + case DRM_FORMAT_XBGR8888 : + case DRM_FORMAT_ABGR8888 : asyw->image.format = 0xd5; break; + default: + WARN_ON(1); + return -EINVAL; + } + + asyw->lut.enable = 1; + asyw->set.image = true; + return 0; +} + +static void * +nv50_base_dtor(struct nv50_wndw *wndw) +{ + struct nv50_disp *disp = nv50_disp(wndw->plane.dev); + struct nv50_base *base = nv50_base(wndw); + nv50_dmac_destroy(&base->chan.base, disp->disp); + return base; +} + +static const u32 +nv50_base_format[] = { + DRM_FORMAT_C8, + DRM_FORMAT_RGB565, + DRM_FORMAT_XRGB1555, + DRM_FORMAT_ARGB1555, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_XBGR2101010, + DRM_FORMAT_ABGR2101010, + DRM_FORMAT_XBGR8888, + DRM_FORMAT_ABGR8888, +}; + +static const struct nv50_wndw_func +nv50_base = { + .dtor = nv50_base_dtor, + .acquire = nv50_base_acquire, + .release = nv50_base_release, + .sema_set = nv50_base_sema_set, + .sema_clr = nv50_base_sema_clr, + .ntfy_set = nv50_base_ntfy_set, + .ntfy_clr = nv50_base_ntfy_clr, + .ntfy_wait_begun = nv50_base_ntfy_wait_begun, + .image_set = nv50_base_image_set, + .image_clr = nv50_base_image_clr, + .lut = nv50_base_lut, + .update = nv50_base_update, +}; + +static int +nv50_base_new(struct nouveau_drm *drm, struct nv50_head *head, + struct nv50_base **pbase) +{ + struct nv50_disp *disp = nv50_disp(drm->dev); + struct nv50_base *base; + int ret; + + if (!(base = *pbase = kzalloc(sizeof(*base), GFP_KERNEL))) + return -ENOMEM; + base->id = head->base.index; + base->wndw.ntfy = EVO_FLIP_NTFY0(base->id); + base->wndw.sema = EVO_FLIP_SEM0(base->id); + base->wndw.data = 0x00000000; + + ret = nv50_wndw_ctor(&nv50_base, drm->dev, DRM_PLANE_TYPE_PRIMARY, + "base", base->id, &base->chan.base, + nv50_base_format, ARRAY_SIZE(nv50_base_format), + &base->wndw); + if (ret) { + kfree(base); + return ret; + } + + ret = nv50_base_create(&drm->device, disp->disp, base->id, + disp->sync->bo.offset, &base->chan); + if (ret) + return ret; + + return nvif_notify_init(&base->chan.base.base.user, nv50_base_notify, + false, + NV50_DISP_BASE_CHANNEL_DMA_V0_NTFY_UEVENT, + &(struct nvif_notify_uevent_req) {}, + sizeof(struct nvif_notify_uevent_req), + sizeof(struct nvif_notify_uevent_rep), + &base->wndw.notify); +} + +/****************************************************************************** * Page flipping channel *****************************************************************************/ struct nouveau_bo * @@ -638,15 +1308,15 @@ nv50_display_crtc_sema(struct drm_device *dev, int crtc) struct nv50_display_flip { struct nv50_disp *disp; - struct nv50_sync *chan; + struct nv50_base *base; }; static bool nv50_display_flip_wait(void *data) { struct nv50_display_flip *flip = data; - if (nouveau_bo_rd32(flip->disp->sync, flip->chan->addr / 4) == - flip->chan->data) + if (nouveau_bo_rd32(flip->disp->sync, flip->base->wndw.sema / 4) == + flip->base->wndw.data) return true; usleep_range(1, 2); return false; @@ -656,24 +1326,18 @@ void nv50_display_flip_stop(struct drm_crtc *crtc) { struct nvif_device *device = &nouveau_drm(crtc->dev)->device; + struct nv50_base *base = nv50_head(crtc)->_base; + struct nv50_wndw *wndw = &base->wndw; + struct nv50_wndw_atom *asyw = &wndw->asy; struct nv50_display_flip flip = { .disp = nv50_disp(crtc->dev), - .chan = nv50_sync(crtc), + .base = base, }; - u32 *push; - push = evo_wait(flip.chan, 8); - if (push) { - evo_mthd(push, 0x0084, 1); - evo_data(push, 0x00000000); - evo_mthd(push, 0x0094, 1); - evo_data(push, 0x00000000); - evo_mthd(push, 0x00c0, 1); - evo_data(push, 0x00000000); - evo_mthd(push, 0x0080, 1); - evo_data(push, 0x00000000); - evo_kick(push, flip.chan); - } + asyw->state.crtc = NULL; + asyw->state.fb = NULL; + nv50_wndw_atomic_check(&wndw->plane, &asyw->state); + nv50_wndw_flush_clr(wndw, 0, true, asyw); nvif_msec(device, 2000, if (nv50_display_flip_wait(&flip)) @@ -688,24 +1352,18 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct nouveau_framebuffer *nv_fb = nouveau_framebuffer(fb); struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); struct nv50_head *head = nv50_head(crtc); - struct nv50_sync *sync = nv50_sync(crtc); - u32 *push; + struct nv50_base *base = nv50_head(crtc)->_base; + struct nv50_wndw *wndw = &base->wndw; + struct nv50_wndw_atom *asyw = &wndw->asy; int ret; if (crtc->primary->fb->width != fb->width || crtc->primary->fb->height != fb->height) return -EINVAL; - swap_interval <<= 4; - if (swap_interval == 0) - swap_interval |= 0x100; if (chan == NULL) evo_sync(crtc->dev); - push = evo_wait(sync, 128); - if (unlikely(push == NULL)) - return -EBUSY; - if (chan && chan->user.oclass < G82_CHANNEL_GPFIFO) { ret = RING_SPACE(chan, 8); if (ret) @@ -713,15 +1371,15 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 2); OUT_RING (chan, NvEvoSema0 + nv_crtc->index); - OUT_RING (chan, sync->addr ^ 0x10); + OUT_RING (chan, base->wndw.sema ^ 0x10); BEGIN_NV04(chan, 0, NV11_SUBCHAN_SEMAPHORE_RELEASE, 1); - OUT_RING (chan, sync->data + 1); + OUT_RING (chan, base->wndw.data + 1); BEGIN_NV04(chan, 0, NV11_SUBCHAN_SEMAPHORE_OFFSET, 2); - OUT_RING (chan, sync->addr); - OUT_RING (chan, sync->data); + OUT_RING (chan, base->wndw.sema); + OUT_RING (chan, base->wndw.data); } else if (chan && chan->user.oclass < FERMI_CHANNEL_GPFIFO) { - u64 addr = nv84_fence_crtc(chan, nv_crtc->index) + sync->addr; + u64 addr = nv84_fence_crtc(chan, nv_crtc->index) + base->wndw.sema; ret = RING_SPACE(chan, 12); if (ret) return ret; @@ -731,16 +1389,16 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, BEGIN_NV04(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4); OUT_RING (chan, upper_32_bits(addr ^ 0x10)); OUT_RING (chan, lower_32_bits(addr ^ 0x10)); - OUT_RING (chan, sync->data + 1); + OUT_RING (chan, base->wndw.data + 1); OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_WRITE_LONG); BEGIN_NV04(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4); OUT_RING (chan, upper_32_bits(addr)); OUT_RING (chan, lower_32_bits(addr)); - OUT_RING (chan, sync->data); + OUT_RING (chan, base->wndw.data); OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_EQUAL); } else if (chan) { - u64 addr = nv84_fence_crtc(chan, nv_crtc->index) + sync->addr; + u64 addr = nv84_fence_crtc(chan, nv_crtc->index) + base->wndw.sema; ret = RING_SPACE(chan, 10); if (ret) return ret; @@ -748,63 +1406,37 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4); OUT_RING (chan, upper_32_bits(addr ^ 0x10)); OUT_RING (chan, lower_32_bits(addr ^ 0x10)); - OUT_RING (chan, sync->data + 1); + OUT_RING (chan, base->wndw.data + 1); OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_WRITE_LONG | NVC0_SUBCHAN_SEMAPHORE_TRIGGER_YIELD); BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4); OUT_RING (chan, upper_32_bits(addr)); OUT_RING (chan, lower_32_bits(addr)); - OUT_RING (chan, sync->data); + OUT_RING (chan, base->wndw.data); OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_EQUAL | NVC0_SUBCHAN_SEMAPHORE_TRIGGER_YIELD); } if (chan) { - sync->addr ^= 0x10; - sync->data++; + base->wndw.sema ^= 0x10; + base->wndw.data++; FIRE_RING (chan); } /* queue the flip */ - evo_mthd(push, 0x0100, 1); - evo_data(push, 0xfffe0000); - evo_mthd(push, 0x0084, 1); - evo_data(push, swap_interval); - if (!(swap_interval & 0x00000100)) { - evo_mthd(push, 0x00e0, 1); - evo_data(push, 0x40000000); - } - evo_mthd(push, 0x0088, 4); - evo_data(push, sync->addr); - evo_data(push, sync->data++); - evo_data(push, sync->data); - evo_data(push, sync->base.sync.handle); - evo_mthd(push, 0x00a0, 2); - evo_data(push, 0x00000000); - evo_data(push, 0x00000000); - evo_mthd(push, 0x00c0, 1); - evo_data(push, nv_fb->r_handle); - evo_mthd(push, 0x0110, 2); - evo_data(push, 0x00000000); - evo_data(push, 0x00000000); - if (nv50_vers(sync) < GF110_DISP_BASE_CHANNEL_DMA) { - evo_mthd(push, 0x0800, 5); - evo_data(push, nv_fb->nvbo->bo.offset >> 8); - evo_data(push, 0); - evo_data(push, (fb->height << 16) | fb->width); - evo_data(push, nv_fb->r_pitch); - evo_data(push, nv_fb->r_format); - } else { - evo_mthd(push, 0x0400, 5); - evo_data(push, nv_fb->nvbo->bo.offset >> 8); - evo_data(push, 0); - evo_data(push, (fb->height << 16) | fb->width); - evo_data(push, nv_fb->r_pitch); - evo_data(push, nv_fb->r_format); - } - evo_mthd(push, 0x0080, 1); - evo_data(push, 0x00000000); - evo_kick(push, sync); + asyw->state.crtc = &head->base.base; + asyw->state.fb = fb; + asyw->interval = swap_interval; + asyw->image.handle = nv_fb->r_handle; + asyw->image.offset = nv_fb->nvbo->bo.offset; + asyw->sema.handle = base->chan.base.sync.handle; + asyw->sema.offset = base->wndw.sema; + asyw->sema.acquire = base->wndw.data++; + asyw->sema.release = base->wndw.data; + nv50_wndw_atomic_check(&wndw->plane, &asyw->state); + asyw->set.sema = true; + nv50_wndw_flush_set(wndw, 0, asyw); + nv50_wndw_wait_armed(wndw, asyw); nouveau_bo_ref(nv_fb->nvbo, &head->image); return 0; @@ -1514,6 +2146,7 @@ nv50_crtc_set_image(struct nouveau_crtc *nv_crtc, struct drm_framebuffer *fb, struct nouveau_framebuffer *nvfb = nouveau_framebuffer(fb); struct nv50_head *head = nv50_head(&nv_crtc->base); struct nv50_head_atom *asyh = &head->asy; + struct nv50_wndw_atom *asyw = &head->_base->wndw.asy; const struct drm_format_info *info; info = drm_format_info(nvfb->base.pixel_format); @@ -1526,6 +2159,8 @@ nv50_crtc_set_image(struct nouveau_crtc *nv_crtc, struct drm_framebuffer *fb, asyh->base.y = y; asyh->base.w = nvfb->base.width; asyh->base.h = nvfb->base.height; + asyw->state.src_x = x << 16; + asyw->state.src_y = y << 16; nv50_head_atomic_check(&head->base.base, &asyh->state); nv50_head_flush_set(head, asyh); @@ -1833,7 +2468,6 @@ nv50_crtc_destroy(struct drm_crtc *crtc) nv50_dmac_destroy(&head->ovly.base, disp->disp); nv50_pioc_destroy(&head->oimm.base); - nv50_dmac_destroy(&head->sync.base, disp->disp); nv50_pioc_destroy(&head->curs.base); /*XXX: this shouldn't be necessary, but the core doesn't call @@ -1885,6 +2519,7 @@ nv50_crtc_create(struct drm_device *dev, int index) struct nvif_device *device = &drm->device; struct nv50_disp *disp = nv50_disp(dev); struct nv50_head *head; + struct nv50_base *base; struct drm_crtc *crtc; int ret, i; @@ -1902,7 +2537,15 @@ nv50_crtc_create(struct drm_device *dev, int index) head->base.lut.b[i] = i << 8; } + ret = nv50_base_new(drm, head, &base); + if (ret) { + kfree(head); + return ret; + } + crtc = &head->base.base; + head->_base = base; + drm_crtc_init(dev, crtc, &nv50_crtc_func); drm_crtc_helper_add(crtc, &nv50_crtc_hfunc); drm_mode_crtc_set_gamma_size(crtc, 256); @@ -1928,15 +2571,6 @@ nv50_crtc_create(struct drm_device *dev, int index) if (ret) goto out; - /* allocate page flip / sync resources */ - ret = nv50_base_create(device, disp->disp, index, disp->sync->bo.offset, - &head->sync); - if (ret) - goto out; - - head->sync.addr = EVO_FLIP_SEM0(index); - head->sync.data = 0x00000000; - /* allocate overlay resources */ ret = nv50_oimm_create(device, disp->disp, index, &head->oimm); if (ret) @@ -2957,7 +3591,7 @@ nv50_fbdma_init(struct drm_device *dev, u32 name, u64 offset, u64 length, u8 kin list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { struct nv50_head *head = nv50_head(crtc); - int ret = nvif_object_init(&head->sync.base.base.user, name, + int ret = nvif_object_init(&head->_base->chan.base.base.user, name, NV_DMA_IN_MEMORY, &args, size, &fbdma->base[head->base.index]); if (ret) { @@ -3031,12 +3665,21 @@ nv50_fb_ctor(struct drm_framebuffer *fb) void nv50_display_fini(struct drm_device *dev) { + struct drm_plane *plane; + + drm_for_each_plane(plane, dev) { + struct nv50_wndw *wndw = nv50_wndw(plane); + if (plane->funcs != &nv50_wndw) + continue; + nv50_wndw_fini(wndw); + } } int nv50_display_init(struct drm_device *dev) { struct nv50_disp *disp = nv50_disp(dev); + struct drm_plane *plane; struct drm_crtc *crtc; u32 *push; @@ -3045,15 +3688,23 @@ nv50_display_init(struct drm_device *dev) return -EBUSY; list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - struct nv50_sync *sync = nv50_sync(crtc); + struct nv50_wndw *wndw = &nv50_head(crtc)->_base->wndw; nv50_crtc_lut_load(crtc); - nouveau_bo_wr32(disp->sync, sync->addr / 4, sync->data); + nouveau_bo_wr32(disp->sync, wndw->sema / 4, wndw->data); } evo_mthd(push, 0x0088, 1); evo_data(push, nv50_mast(dev)->base.sync.handle); evo_kick(push, nv50_mast(dev)); + + drm_for_each_plane(plane, dev) { + struct nv50_wndw *wndw = nv50_wndw(plane); + if (plane->funcs != &nv50_wndw) + continue; + nv50_wndw_init(wndw); + } + return 0; } -- cgit v1.1 From 22e927d2f8180e469ef90f93f6ea0045fc1b4f80 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 4 Nov 2016 17:20:36 +1000 Subject: drm/nouveau/kms/nv50: separate out cursor channel commit This commit separates the calculation of EVO state from the commit, in order to make the same code useful for atomic modesetting. The legacy interfaces have been wrapped on top of them. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_display.c | 198 ++++++++++++++++++++++++++------- 1 file changed, 158 insertions(+), 40 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 068810b..da1ae69 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -317,34 +317,6 @@ nv50_pioc_create(struct nvif_device *device, struct nvif_object *disp, } /****************************************************************************** - * Cursor Immediate - *****************************************************************************/ - -struct nv50_curs { - struct nv50_pioc base; -}; - -static int -nv50_curs_create(struct nvif_device *device, struct nvif_object *disp, - int head, struct nv50_curs *curs) -{ - struct nv50_disp_cursor_v0 args = { - .head = head, - }; - static const s32 oclass[] = { - GK104_DISP_CURSOR, - GF110_DISP_CURSOR, - GT214_DISP_CURSOR, - G82_DISP_CURSOR, - NV50_DISP_CURSOR, - 0 - }; - - return nv50_pioc_create(device, disp, oclass, head, &args, sizeof(args), - &curs->base); -} - -/****************************************************************************** * Overlay Immediate *****************************************************************************/ @@ -566,7 +538,6 @@ nv50_ovly_create(struct nvif_device *device, struct nvif_object *disp, struct nv50_head { struct nouveau_crtc base; struct nouveau_bo *image; - struct nv50_curs curs; struct nv50_ovly ovly; struct nv50_oimm oimm; @@ -574,10 +545,10 @@ struct nv50_head { struct nv50_head_atom asy; struct nv50_base *_base; + struct nv50_curs *_curs; }; #define nv50_head(c) ((struct nv50_head *)nouveau_crtc(c)) -#define nv50_curs(c) (&nv50_head(c)->curs) #define nv50_ovly(c) (&nv50_head(c)->ovly) #define nv50_oimm(c) (&nv50_head(c)->oimm) #define nv50_chan(c) (&(c)->base.base) @@ -994,6 +965,152 @@ nv50_wndw_ctor(const struct nv50_wndw_func *func, struct drm_device *dev, } /****************************************************************************** + * Cursor plane + *****************************************************************************/ +#define nv50_curs(p) container_of((p), struct nv50_curs, wndw) + +struct nv50_curs { + struct nv50_wndw wndw; + struct nvif_object chan; +}; + +static u32 +nv50_curs_update(struct nv50_wndw *wndw, u32 interlock) +{ + struct nv50_curs *curs = nv50_curs(wndw); + nvif_wr32(&curs->chan, 0x0080, 0x00000000); + return 0; +} + +static void +nv50_curs_point(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw) +{ + struct nv50_curs *curs = nv50_curs(wndw); + nvif_wr32(&curs->chan, 0x0084, (asyw->point.y << 16) | asyw->point.x); +} + +static void +nv50_curs_prepare(struct nv50_wndw *wndw, struct nv50_head_atom *asyh, + struct nv50_wndw_atom *asyw) +{ + asyh->curs.handle = nv50_disp(wndw->plane.dev)->mast.base.vram.handle; + asyh->curs.offset = asyw->image.offset; + asyh->set.curs = asyh->curs.visible; +} + +static void +nv50_curs_release(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw, + struct nv50_head_atom *asyh) +{ + asyh->curs.visible = false; +} + +static int +nv50_curs_acquire(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw, + struct nv50_head_atom *asyh) +{ + int ret; + + ret = drm_plane_helper_check_state(&asyw->state, &asyw->clip, + DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_HELPER_NO_SCALING, + true, true); + asyh->curs.visible = asyw->state.visible; + if (ret || !asyh->curs.visible) + return ret; + + switch (asyw->state.fb->width) { + case 32: asyh->curs.layout = 0; break; + case 64: asyh->curs.layout = 1; break; + default: + return -EINVAL; + } + + if (asyw->state.fb->width != asyw->state.fb->height) + return -EINVAL; + + switch (asyw->state.fb->pixel_format) { + case DRM_FORMAT_ARGB8888: asyh->curs.format = 1; break; + default: + WARN_ON(1); + return -EINVAL; + } + + return 0; +} + +static void * +nv50_curs_dtor(struct nv50_wndw *wndw) +{ + struct nv50_curs *curs = nv50_curs(wndw); + nvif_object_fini(&curs->chan); + return curs; +} + +static const u32 +nv50_curs_format[] = { + DRM_FORMAT_ARGB8888, +}; + +static const struct nv50_wndw_func +nv50_curs = { + .dtor = nv50_curs_dtor, + .acquire = nv50_curs_acquire, + .release = nv50_curs_release, + .prepare = nv50_curs_prepare, + .point = nv50_curs_point, + .update = nv50_curs_update, +}; + +static int +nv50_curs_new(struct nouveau_drm *drm, struct nv50_head *head, + struct nv50_curs **pcurs) +{ + static const struct nvif_mclass curses[] = { + { GK104_DISP_CURSOR, 0 }, + { GF110_DISP_CURSOR, 0 }, + { GT214_DISP_CURSOR, 0 }, + { G82_DISP_CURSOR, 0 }, + { NV50_DISP_CURSOR, 0 }, + {} + }; + struct nv50_disp_cursor_v0 args = { + .head = head->base.index, + }; + struct nv50_disp *disp = nv50_disp(drm->dev); + struct nv50_curs *curs; + int cid, ret; + + cid = nvif_mclass(disp->disp, curses); + if (cid < 0) { + NV_ERROR(drm, "No supported cursor immediate class\n"); + return cid; + } + + if (!(curs = *pcurs = kzalloc(sizeof(*curs), GFP_KERNEL))) + return -ENOMEM; + + ret = nv50_wndw_ctor(&nv50_curs, drm->dev, DRM_PLANE_TYPE_CURSOR, + "curs", head->base.index, &disp->mast.base, + nv50_curs_format, ARRAY_SIZE(nv50_curs_format), + &curs->wndw); + if (ret) { + kfree(curs); + return ret; + } + + ret = nvif_object_init(disp->disp, 0, curses[cid].oclass, &args, + sizeof(args), &curs->chan); + if (ret) { + NV_ERROR(drm, "curs%04x allocation failed: %d\n", + curses[cid].oclass, ret); + return ret; + } + + return 0; +} + +/****************************************************************************** * Primary plane *****************************************************************************/ #define nv50_base(p) container_of((p), struct nv50_base, wndw) @@ -2418,10 +2535,13 @@ static int nv50_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) { struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); - struct nv50_curs *curs = nv50_curs(crtc); - struct nv50_chan *chan = nv50_chan(curs); - nvif_wr32(&chan->user, 0x0084, (y << 16) | (x & 0xffff)); - nvif_wr32(&chan->user, 0x0080, 0x00000000); + struct nv50_wndw *wndw = &nv50_head(crtc)->_curs->wndw; + struct nv50_wndw_atom *asyw = &wndw->asy; + + asyw->point.x = x; + asyw->point.y = y; + asyw->set.point = true; + nv50_wndw_flush_set(wndw, 0, asyw); nv_crtc->cursor_saved_x = x; nv_crtc->cursor_saved_y = y; @@ -2468,7 +2588,6 @@ nv50_crtc_destroy(struct drm_crtc *crtc) nv50_dmac_destroy(&head->ovly.base, disp->disp); nv50_pioc_destroy(&head->oimm.base); - nv50_pioc_destroy(&head->curs.base); /*XXX: this shouldn't be necessary, but the core doesn't call * disconnect() during the cleanup paths @@ -2520,6 +2639,7 @@ nv50_crtc_create(struct drm_device *dev, int index) struct nv50_disp *disp = nv50_disp(dev); struct nv50_head *head; struct nv50_base *base; + struct nv50_curs *curs; struct drm_crtc *crtc; int ret, i; @@ -2538,6 +2658,8 @@ nv50_crtc_create(struct drm_device *dev, int index) } ret = nv50_base_new(drm, head, &base); + if (ret == 0) + ret = nv50_curs_new(drm, head, &curs); if (ret) { kfree(head); return ret; @@ -2545,6 +2667,7 @@ nv50_crtc_create(struct drm_device *dev, int index) crtc = &head->base.base; head->_base = base; + head->_curs = curs; drm_crtc_init(dev, crtc, &nv50_crtc_func); drm_crtc_helper_add(crtc, &nv50_crtc_hfunc); @@ -2566,11 +2689,6 @@ nv50_crtc_create(struct drm_device *dev, int index) if (ret) goto out; - /* allocate cursor resources */ - ret = nv50_curs_create(device, disp->disp, index, &head->curs); - if (ret) - goto out; - /* allocate overlay resources */ ret = nv50_oimm_create(device, disp->disp, index, &head->oimm); if (ret) -- cgit v1.1 From accdea2ef458ada6102cc0d33a0a9780244ac7d2 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 4 Nov 2016 17:20:36 +1000 Subject: drm/nouveau/kms/nv50: prepare ctxdma interface to be usable with atomic Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_display.c | 197 +++++++++++++++------------------ 1 file changed, 92 insertions(+), 105 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index da1ae69..4c7b53f 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -348,6 +348,11 @@ nv50_oimm_create(struct nvif_device *device, struct nvif_object *disp, * DMA EVO channel *****************************************************************************/ +struct nv50_dmac_ctxdma { + struct list_head head; + struct nvif_object object; +}; + struct nv50_dmac { struct nv50_chan base; dma_addr_t handle; @@ -355,6 +360,7 @@ struct nv50_dmac { struct nvif_object sync; struct nvif_object vram; + struct list_head ctxdma; /* Protects against concurrent pushbuf access to this channel, lock is * grabbed by evo_wait (if the pushbuf reservation is successful) and @@ -363,9 +369,82 @@ struct nv50_dmac { }; static void +nv50_dmac_ctxdma_del(struct nv50_dmac_ctxdma *ctxdma) +{ + nvif_object_fini(&ctxdma->object); + list_del(&ctxdma->head); + kfree(ctxdma); +} + +static struct nv50_dmac_ctxdma * +nv50_dmac_ctxdma_new(struct nv50_dmac *dmac, u32 handle, + struct nouveau_framebuffer *fb) +{ + struct nouveau_drm *drm = nouveau_drm(fb->base.dev); + struct nv50_dmac_ctxdma *ctxdma; + const u8 kind = (fb->nvbo->tile_flags & 0x0000ff00) >> 8; + struct { + struct nv_dma_v0 base; + union { + struct nv50_dma_v0 nv50; + struct gf100_dma_v0 gf100; + struct gf119_dma_v0 gf119; + }; + } args = {}; + u32 argc = sizeof(args.base); + int ret; + + list_for_each_entry(ctxdma, &dmac->ctxdma, head) { + if (ctxdma->object.handle == handle) + return ctxdma; + } + + if (!(ctxdma = kzalloc(sizeof(*ctxdma), GFP_KERNEL))) + return ERR_PTR(-ENOMEM); + list_add(&ctxdma->head, &dmac->ctxdma); + + args.base.target = NV_DMA_V0_TARGET_VRAM; + args.base.access = NV_DMA_V0_ACCESS_RDWR; + args.base.start = 0; + args.base.limit = drm->device.info.ram_user - 1; + + if (drm->device.info.chipset < 0x80) { + args.nv50.part = NV50_DMA_V0_PART_256; + argc += sizeof(args.nv50); + } else + if (drm->device.info.chipset < 0xc0) { + args.nv50.part = NV50_DMA_V0_PART_256; + args.nv50.kind = kind; + argc += sizeof(args.nv50); + } else + if (drm->device.info.chipset < 0xd0) { + args.gf100.kind = kind; + argc += sizeof(args.gf100); + } else { + args.gf119.page = GF119_DMA_V0_PAGE_LP; + args.gf119.kind = kind; + argc += sizeof(args.gf119); + } + + ret = nvif_object_init(&dmac->base.user, handle, NV_DMA_IN_MEMORY, + &args, argc, &ctxdma->object); + if (ret) { + nv50_dmac_ctxdma_del(ctxdma); + return ERR_PTR(ret); + } + + return ctxdma; +} + +static void nv50_dmac_destroy(struct nv50_dmac *dmac, struct nvif_object *disp) { struct nvif_device *device = dmac->base.device; + struct nv50_dmac_ctxdma *ctxdma, *ctxtmp; + + list_for_each_entry_safe(ctxdma, ctxtmp, &dmac->ctxdma, head) { + nv50_dmac_ctxdma_del(ctxdma); + } nvif_object_fini(&dmac->vram); nvif_object_fini(&dmac->sync); @@ -434,6 +513,7 @@ nv50_dmac_create(struct nvif_device *device, struct nvif_object *disp, if (ret) return ret; + INIT_LIST_HEAD(&dmac->ctxdma); return ret; } @@ -554,18 +634,10 @@ struct nv50_head { #define nv50_chan(c) (&(c)->base.base) #define nv50_vers(c) nv50_chan(c)->user.oclass -struct nv50_fbdma { - struct list_head head; - struct nvif_object core; - struct nvif_object base[4]; -}; - struct nv50_disp { struct nvif_object *disp; struct nv50_mast mast; - struct list_head fbdma; - struct nouveau_bo *sync; }; @@ -2580,11 +2652,6 @@ nv50_crtc_destroy(struct drm_crtc *crtc) struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); struct nv50_disp *disp = nv50_disp(crtc->dev); struct nv50_head *head = nv50_head(crtc); - struct nv50_fbdma *fbdma; - - list_for_each_entry(fbdma, &disp->fbdma, head) { - nvif_object_fini(&fbdma->base[nv_crtc->index]); - } nv50_dmac_destroy(&head->ovly.base, disp->disp); nv50_pioc_destroy(&head->oimm.base); @@ -3645,90 +3712,6 @@ nv50_pior_create(struct drm_connector *connector, struct dcb_output *dcbe) *****************************************************************************/ static void -nv50_fbdma_fini(struct nv50_fbdma *fbdma) -{ - int i; - for (i = 0; i < ARRAY_SIZE(fbdma->base); i++) - nvif_object_fini(&fbdma->base[i]); - nvif_object_fini(&fbdma->core); - list_del(&fbdma->head); - kfree(fbdma); -} - -static int -nv50_fbdma_init(struct drm_device *dev, u32 name, u64 offset, u64 length, u8 kind) -{ - struct nouveau_drm *drm = nouveau_drm(dev); - struct nv50_disp *disp = nv50_disp(dev); - struct nv50_mast *mast = nv50_mast(dev); - struct __attribute__ ((packed)) { - struct nv_dma_v0 base; - union { - struct nv50_dma_v0 nv50; - struct gf100_dma_v0 gf100; - struct gf119_dma_v0 gf119; - }; - } args = {}; - struct nv50_fbdma *fbdma; - struct drm_crtc *crtc; - u32 size = sizeof(args.base); - int ret; - - list_for_each_entry(fbdma, &disp->fbdma, head) { - if (fbdma->core.handle == name) - return 0; - } - - fbdma = kzalloc(sizeof(*fbdma), GFP_KERNEL); - if (!fbdma) - return -ENOMEM; - list_add(&fbdma->head, &disp->fbdma); - - args.base.target = NV_DMA_V0_TARGET_VRAM; - args.base.access = NV_DMA_V0_ACCESS_RDWR; - args.base.start = offset; - args.base.limit = offset + length - 1; - - if (drm->device.info.chipset < 0x80) { - args.nv50.part = NV50_DMA_V0_PART_256; - size += sizeof(args.nv50); - } else - if (drm->device.info.chipset < 0xc0) { - args.nv50.part = NV50_DMA_V0_PART_256; - args.nv50.kind = kind; - size += sizeof(args.nv50); - } else - if (drm->device.info.chipset < 0xd0) { - args.gf100.kind = kind; - size += sizeof(args.gf100); - } else { - args.gf119.page = GF119_DMA_V0_PAGE_LP; - args.gf119.kind = kind; - size += sizeof(args.gf119); - } - - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - struct nv50_head *head = nv50_head(crtc); - int ret = nvif_object_init(&head->_base->chan.base.base.user, name, - NV_DMA_IN_MEMORY, &args, size, - &fbdma->base[head->base.index]); - if (ret) { - nv50_fbdma_fini(fbdma); - return ret; - } - } - - ret = nvif_object_init(&mast->base.base.user, name, NV_DMA_IN_MEMORY, - &args, size, &fbdma->core); - if (ret) { - nv50_fbdma_fini(fbdma); - return ret; - } - - return 0; -} - -static void nv50_fb_dtor(struct drm_framebuffer *fb) { } @@ -3742,6 +3725,7 @@ nv50_fb_ctor(struct drm_framebuffer *fb) struct nv50_disp *disp = nv50_disp(fb->dev); u8 kind = nouveau_bo_tile_layout(nvbo) >> 8; u8 tile = nvbo->tile_mode; + struct drm_crtc *crtc; if (drm->device.info.chipset >= 0xc0) tile >>= 4; /* yep.. */ @@ -3772,8 +3756,17 @@ nv50_fb_ctor(struct drm_framebuffer *fb) } nv_fb->r_handle = 0xffff0000 | kind; - return nv50_fbdma_init(fb->dev, nv_fb->r_handle, 0, - drm->device.info.ram_user, kind); + list_for_each_entry(crtc, &drm->dev->mode_config.crtc_list, head) { + struct nv50_head *head = nv50_head(crtc); + struct nv50_dmac_ctxdma *ctxdma; + + ctxdma = nv50_dmac_ctxdma_new(&head->_base->chan.base, + nv_fb->r_handle, nv_fb); + if (IS_ERR(ctxdma)) + return PTR_ERR(ctxdma); + } + + return 0; } /****************************************************************************** @@ -3830,11 +3823,6 @@ void nv50_display_destroy(struct drm_device *dev) { struct nv50_disp *disp = nv50_disp(dev); - struct nv50_fbdma *fbdma, *fbtmp; - - list_for_each_entry_safe(fbdma, fbtmp, &disp->fbdma, head) { - nv50_fbdma_fini(fbdma); - } nv50_dmac_destroy(&disp->mast.base, disp->disp); @@ -3861,7 +3849,6 @@ nv50_display_create(struct drm_device *dev) disp = kzalloc(sizeof(*disp), GFP_KERNEL); if (!disp) return -ENOMEM; - INIT_LIST_HEAD(&disp->fbdma); nouveau_display(dev)->priv = disp; nouveau_display(dev)->dtor = nv50_display_destroy; -- cgit v1.1 From 354d3508bca3d4379f1507eeefb64876c22b50e1 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 4 Nov 2016 17:20:36 +1000 Subject: drm/nouveau/kms/nv50: ensure encoder normal power state is enabled at startup To handle low-power DPMS states, we currently change an OR's (Output Resource) normal (active) power state to be off, leaving the rest of the display configured as usual. Under atomic modesetting, we will instead be doing a full modeset to tear down the pipe fully when entering a low-power state. As we'll no longer be touching the OR's PWR registers during runtime operation, we need to ensure the normal power state is set correctly during initialisation. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_display.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 4c7b53f..742ac7c 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -3790,6 +3790,7 @@ int nv50_display_init(struct drm_device *dev) { struct nv50_disp *disp = nv50_disp(dev); + struct drm_encoder *encoder; struct drm_plane *plane; struct drm_crtc *crtc; u32 *push; @@ -3809,6 +3810,24 @@ nv50_display_init(struct drm_device *dev) evo_data(push, nv50_mast(dev)->base.sync.handle); evo_kick(push, nv50_mast(dev)); + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + if (encoder->encoder_type != DRM_MODE_ENCODER_DPMST) { + const struct drm_encoder_helper_funcs *help; + struct nouveau_encoder *nv_encoder; + + nv_encoder = nouveau_encoder(encoder); + if (nv_encoder->dcb->type == DCB_OUTPUT_DP) + nv_encoder->dcb->type = DCB_OUTPUT_EOL; + + help = encoder->helper_private; + if (help && help->dpms) + help->dpms(encoder, DRM_MODE_DPMS_ON); + + if (nv_encoder->dcb->type == DCB_OUTPUT_EOL) + nv_encoder->dcb->type = DCB_OUTPUT_DP; + } + } + drm_for_each_plane(plane, dev) { struct nv50_wndw *wndw = nv50_wndw(plane); if (plane->funcs != &nv50_wndw) -- cgit v1.1 From f20c665ca04a958c007bb047eca42eb1ae2cb7d0 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 4 Nov 2016 17:20:36 +1000 Subject: drm/nouveau/kms/nv50: clean-up encoder functions Just a shuffle of blocks into an order consistent with the rest of the code, renaming hdmi/audio funtions for atomic, and removal of unused code. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_dp.c | 4 +- drivers/gpu/drm/nouveau/nouveau_encoder.h | 2 - drivers/gpu/drm/nouveau/nv50_display.c | 256 ++++++++++++++---------------- 3 files changed, 122 insertions(+), 140 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c index 399eb9d..ddffb5cd 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dp.c +++ b/drivers/gpu/drm/nouveau/nouveau_dp.c @@ -58,14 +58,14 @@ nouveau_dp_detect(struct nouveau_encoder *nv_encoder) struct drm_device *dev = nv_encoder->base.base.dev; struct nouveau_drm *drm = nouveau_drm(dev); struct nvkm_i2c_aux *aux; - u8 *dpcd = nv_encoder->dp.dpcd; + u8 dpcd[8]; int ret; aux = nv_encoder->aux; if (!aux) return -ENODEV; - ret = nvkm_rdaux(aux, DP_DPCD_REV, dpcd, 8); + ret = nvkm_rdaux(aux, DP_DPCD_REV, dpcd, sizeof(dpcd)); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nouveau_encoder.h b/drivers/gpu/drm/nouveau/nouveau_encoder.h index dfa1a66..2cd4a2d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_encoder.h +++ b/drivers/gpu/drm/nouveau/nouveau_encoder.h @@ -59,10 +59,8 @@ struct nouveau_encoder { union { struct { struct nv50_mstm *mstm; - u8 dpcd[8]; int link_nr; int link_bw; - u32 datarate; } dp; }; diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 742ac7c..617c57d 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -2835,8 +2835,30 @@ nv50_dac_dpms(struct drm_encoder *encoder, int mode) } static void -nv50_dac_commit(struct drm_encoder *encoder) +nv50_dac_disconnect(struct drm_encoder *encoder) { + struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); + struct nv50_mast *mast = nv50_mast(encoder->dev); + const int or = nv_encoder->or; + u32 *push; + + if (nv_encoder->crtc) { + nv50_crtc_prepare(nv_encoder->crtc); + + push = evo_wait(mast, 4); + if (push) { + if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) { + evo_mthd(push, 0x0400 + (or * 0x080), 1); + evo_data(push, 0x00000000); + } else { + evo_mthd(push, 0x0180 + (or * 0x020), 1); + evo_data(push, 0x00000000); + } + evo_kick(push, mast); + } + } + + nv_encoder->crtc = NULL; } static void @@ -2888,33 +2910,6 @@ nv50_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, nv_encoder->crtc = encoder->crtc; } -static void -nv50_dac_disconnect(struct drm_encoder *encoder) -{ - struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); - struct nv50_mast *mast = nv50_mast(encoder->dev); - const int or = nv_encoder->or; - u32 *push; - - if (nv_encoder->crtc) { - nv50_crtc_prepare(nv_encoder->crtc); - - push = evo_wait(mast, 4); - if (push) { - if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) { - evo_mthd(push, 0x0400 + (or * 0x080), 1); - evo_data(push, 0x00000000); - } else { - evo_mthd(push, 0x0180 + (or * 0x020), 1); - evo_data(push, 0x00000000); - } - evo_kick(push, mast); - } - } - - nv_encoder->crtc = NULL; -} - static enum drm_connector_status nv50_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) { @@ -2942,25 +2937,26 @@ nv50_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) return connector_status_connected; } -static void -nv50_dac_destroy(struct drm_encoder *encoder) -{ - drm_encoder_cleanup(encoder); - kfree(encoder); -} - -static const struct drm_encoder_helper_funcs nv50_dac_hfunc = { +static const struct drm_encoder_helper_funcs +nv50_dac_help = { .dpms = nv50_dac_dpms, .mode_fixup = nv50_encoder_mode_fixup, .prepare = nv50_dac_disconnect, - .commit = nv50_dac_commit, .mode_set = nv50_dac_mode_set, .disable = nv50_dac_disconnect, .get_crtc = nv50_display_crtc_get, .detect = nv50_dac_detect }; -static const struct drm_encoder_funcs nv50_dac_func = { +static void +nv50_dac_destroy(struct drm_encoder *encoder) +{ + drm_encoder_cleanup(encoder); + kfree(encoder); +} + +static const struct drm_encoder_funcs +nv50_dac_func = { .destroy = nv50_dac_destroy, }; @@ -2989,7 +2985,7 @@ nv50_dac_create(struct drm_connector *connector, struct dcb_output *dcbe) encoder->possible_clones = 0; drm_encoder_init(connector->dev, encoder, &nv50_dac_func, type, "dac-%04x-%04x", dcbe->hasht, dcbe->hashm); - drm_encoder_helper_add(encoder, &nv50_dac_hfunc); + drm_encoder_helper_add(encoder, &nv50_dac_help); drm_mode_connector_attach_encoder(connector, encoder); return 0; @@ -2999,7 +2995,26 @@ nv50_dac_create(struct drm_connector *connector, struct dcb_output *dcbe) * Audio *****************************************************************************/ static void -nv50_audio_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode) +nv50_audio_disable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc) +{ + struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); + struct nv50_disp *disp = nv50_disp(encoder->dev); + struct { + struct nv50_disp_mthd_v1 base; + struct nv50_disp_sor_hda_eld_v0 eld; + } args = { + .base.version = 1, + .base.method = NV50_DISP_MTHD_V1_SOR_HDA_ELD, + .base.hasht = nv_encoder->dcb->hasht, + .base.hashm = (0xf0ff & nv_encoder->dcb->hashm) | + (0x0100 << nv_crtc->index), + }; + + nvif_mthd(disp->disp, 0, &args, sizeof(args)); +} + +static void +nv50_audio_enable(struct drm_encoder *encoder, struct drm_display_mode *mode) { struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc); @@ -3030,30 +3045,30 @@ nv50_audio_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode) sizeof(args.base) + drm_eld_size(args.data)); } +/****************************************************************************** + * HDMI + *****************************************************************************/ static void -nv50_audio_disconnect(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc) +nv50_hdmi_disable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc) { struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); struct nv50_disp *disp = nv50_disp(encoder->dev); struct { struct nv50_disp_mthd_v1 base; - struct nv50_disp_sor_hda_eld_v0 eld; + struct nv50_disp_sor_hdmi_pwr_v0 pwr; } args = { .base.version = 1, - .base.method = NV50_DISP_MTHD_V1_SOR_HDA_ELD, - .base.hasht = nv_encoder->dcb->hasht, - .base.hashm = (0xf0ff & nv_encoder->dcb->hashm) | - (0x0100 << nv_crtc->index), + .base.method = NV50_DISP_MTHD_V1_SOR_HDMI_PWR, + .base.hasht = nv_encoder->dcb->hasht, + .base.hashm = (0xf0ff & nv_encoder->dcb->hashm) | + (0x0100 << nv_crtc->index), }; nvif_mthd(disp->disp, 0, &args, sizeof(args)); } -/****************************************************************************** - * HDMI - *****************************************************************************/ static void -nv50_hdmi_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode) +nv50_hdmi_enable(struct drm_encoder *encoder, struct drm_display_mode *mode) { struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc); @@ -3083,26 +3098,7 @@ nv50_hdmi_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode) args.pwr.max_ac_packet = max_ac_packet / 32; nvif_mthd(disp->disp, 0, &args, sizeof(args)); - nv50_audio_mode_set(encoder, mode); -} - -static void -nv50_hdmi_disconnect(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc) -{ - struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); - struct nv50_disp *disp = nv50_disp(encoder->dev); - struct { - struct nv50_disp_mthd_v1 base; - struct nv50_disp_sor_hdmi_pwr_v0 pwr; - } args = { - .base.version = 1, - .base.method = NV50_DISP_MTHD_V1_SOR_HDMI_PWR, - .base.hasht = nv_encoder->dcb->hasht, - .base.hashm = (0xf0ff & nv_encoder->dcb->hashm) | - (0x0100 << nv_crtc->index), - }; - - nvif_mthd(disp->disp, 0, &args, sizeof(args)); + nv50_audio_enable(encoder, mode); } /****************************************************************************** @@ -3292,17 +3288,12 @@ nv50_sor_disconnect(struct drm_encoder *encoder) if (nv_crtc) { nv50_crtc_prepare(&nv_crtc->base); nv50_sor_ctrl(nv_encoder, 1 << nv_crtc->index, 0); - nv50_audio_disconnect(encoder, nv_crtc); - nv50_hdmi_disconnect(&nv_encoder->base.base, nv_crtc); + nv50_audio_disable(encoder, nv_crtc); + nv50_hdmi_disable(&nv_encoder->base.base, nv_crtc); } } static void -nv50_sor_commit(struct drm_encoder *encoder) -{ -} - -static void nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode, struct drm_display_mode *mode) { @@ -3349,7 +3340,7 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode, proto = 0x2; } - nv50_hdmi_mode_set(&nv_encoder->base.base, mode); + nv50_hdmi_enable(&nv_encoder->base.base, mode); break; case DCB_OUTPUT_LVDS: proto = 0x0; @@ -3383,23 +3374,20 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode, nvif_mthd(disp->disp, 0, &lvds, sizeof(lvds)); break; case DCB_OUTPUT_DP: - if (nv_connector->base.display_info.bpc == 6) { - nv_encoder->dp.datarate = mode->clock * 18 / 8; + if (nv_connector->base.display_info.bpc == 6) depth = 0x2; - } else - if (nv_connector->base.display_info.bpc == 8) { - nv_encoder->dp.datarate = mode->clock * 24 / 8; + else + if (nv_connector->base.display_info.bpc == 8) depth = 0x5; - } else { - nv_encoder->dp.datarate = mode->clock * 30 / 8; + else depth = 0x6; - } if (nv_encoder->dcb->sorconf.link & 1) proto = 0x8; else proto = 0x9; - nv50_audio_mode_set(encoder, mode); + + nv50_audio_enable(encoder, mode); break; default: BUG_ON(1); @@ -3442,6 +3430,16 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode, nv50_sor_ctrl(nv_encoder, mask | owner, ctrl | owner); } +static const struct drm_encoder_helper_funcs +nv50_sor_help = { + .dpms = nv50_sor_dpms, + .mode_fixup = nv50_encoder_mode_fixup, + .prepare = nv50_sor_disconnect, + .mode_set = nv50_sor_mode_set, + .disable = nv50_sor_disconnect, + .get_crtc = nv50_display_crtc_get, +}; + static void nv50_sor_destroy(struct drm_encoder *encoder) { @@ -3451,17 +3449,8 @@ nv50_sor_destroy(struct drm_encoder *encoder) kfree(encoder); } -static const struct drm_encoder_helper_funcs nv50_sor_hfunc = { - .dpms = nv50_sor_dpms, - .mode_fixup = nv50_encoder_mode_fixup, - .prepare = nv50_sor_disconnect, - .commit = nv50_sor_commit, - .mode_set = nv50_sor_mode_set, - .disable = nv50_sor_disconnect, - .get_crtc = nv50_display_crtc_get, -}; - -static const struct drm_encoder_funcs nv50_sor_func = { +static const struct drm_encoder_funcs +nv50_sor_func = { .destroy = nv50_sor_destroy, }; @@ -3496,7 +3485,7 @@ nv50_sor_create(struct drm_connector *connector, struct dcb_output *dcbe) encoder->possible_clones = 0; drm_encoder_init(connector->dev, encoder, &nv50_sor_func, type, "sor-%04x-%04x", dcbe->hasht, dcbe->hashm); - drm_encoder_helper_add(encoder, &nv50_sor_hfunc); + drm_encoder_helper_add(encoder, &nv50_sor_help); drm_mode_connector_attach_encoder(connector, encoder); @@ -3529,7 +3518,6 @@ nv50_sor_create(struct drm_connector *connector, struct dcb_output *dcbe) /****************************************************************************** * PIOR *****************************************************************************/ - static void nv50_pior_dpms(struct drm_encoder *encoder, int mode) { @@ -3562,8 +3550,27 @@ nv50_pior_mode_fixup(struct drm_encoder *encoder, } static void -nv50_pior_commit(struct drm_encoder *encoder) +nv50_pior_disconnect(struct drm_encoder *encoder) { + struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); + struct nv50_mast *mast = nv50_mast(encoder->dev); + const int or = nv_encoder->or; + u32 *push; + + if (nv_encoder->crtc) { + nv50_crtc_prepare(nv_encoder->crtc); + + push = evo_wait(mast, 4); + if (push) { + if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) { + evo_mthd(push, 0x0700 + (or * 0x040), 1); + evo_data(push, 0x00000000); + } + evo_kick(push, mast); + } + } + + nv_encoder->crtc = NULL; } static void @@ -3616,48 +3623,25 @@ nv50_pior_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, nv_encoder->crtc = encoder->crtc; } -static void -nv50_pior_disconnect(struct drm_encoder *encoder) -{ - struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); - struct nv50_mast *mast = nv50_mast(encoder->dev); - const int or = nv_encoder->or; - u32 *push; - - if (nv_encoder->crtc) { - nv50_crtc_prepare(nv_encoder->crtc); - - push = evo_wait(mast, 4); - if (push) { - if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) { - evo_mthd(push, 0x0700 + (or * 0x040), 1); - evo_data(push, 0x00000000); - } - evo_kick(push, mast); - } - } - - nv_encoder->crtc = NULL; -} - -static void -nv50_pior_destroy(struct drm_encoder *encoder) -{ - drm_encoder_cleanup(encoder); - kfree(encoder); -} - -static const struct drm_encoder_helper_funcs nv50_pior_hfunc = { +static const struct drm_encoder_helper_funcs +nv50_pior_help = { .dpms = nv50_pior_dpms, .mode_fixup = nv50_pior_mode_fixup, .prepare = nv50_pior_disconnect, - .commit = nv50_pior_commit, .mode_set = nv50_pior_mode_set, .disable = nv50_pior_disconnect, .get_crtc = nv50_display_crtc_get, }; -static const struct drm_encoder_funcs nv50_pior_func = { +static void +nv50_pior_destroy(struct drm_encoder *encoder) +{ + drm_encoder_cleanup(encoder); + kfree(encoder); +} + +static const struct drm_encoder_funcs +nv50_pior_func = { .destroy = nv50_pior_destroy, }; @@ -3701,7 +3685,7 @@ nv50_pior_create(struct drm_connector *connector, struct dcb_output *dcbe) encoder->possible_clones = 0; drm_encoder_init(connector->dev, encoder, &nv50_pior_func, type, "pior-%04x-%04x", dcbe->hasht, dcbe->hashm); - drm_encoder_helper_add(encoder, &nv50_pior_hfunc); + drm_encoder_helper_add(encoder, &nv50_pior_help); drm_mode_connector_attach_encoder(connector, encoder); return 0; -- cgit v1.1 From d92c8adf80fdcd4d08965fe8f8c55b19eb5e870f Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 4 Nov 2016 17:20:36 +1000 Subject: drm/nouveau/kms/nv50: convert encoder mode_fixup into an atomic_check() Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_display.c | 70 +++++++++++++++++++++++++--------- 1 file changed, 53 insertions(+), 17 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 617c57d..03a3e3f 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -2773,8 +2773,50 @@ out: } /****************************************************************************** - * Encoder helpers + * Output path helpers *****************************************************************************/ +static int +nv50_outp_atomic_check_view(struct drm_encoder *encoder, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + struct drm_display_mode *native_mode) +{ + struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode; + struct drm_display_mode *mode = &crtc_state->mode; + struct drm_connector *connector = conn_state->connector; + struct nouveau_conn_atom *asyc = nouveau_conn_atom(conn_state); + struct nouveau_drm *drm = nouveau_drm(encoder->dev); + + NV_ATOMIC(drm, "%s atomic_check\n", encoder->name); + asyc->scaler.full = false; + if (!native_mode) + return 0; + + if (asyc->scaler.mode == DRM_MODE_SCALE_NONE) { + switch (connector->connector_type) { + case DRM_MODE_CONNECTOR_LVDS: + case DRM_MODE_CONNECTOR_eDP: + /* Force use of scaler for non-EDID modes. */ + if (adjusted_mode->type & DRM_MODE_TYPE_DRIVER) + break; + mode = native_mode; + asyc->scaler.full = true; + break; + default: + break; + } + } else { + mode = native_mode; + } + + if (!drm_mode_equal(adjusted_mode, mode)) { + drm_mode_copy(adjusted_mode, mode); + crtc_state->mode_changed = true; + } + + return 0; +} + static bool nv50_encoder_mode_fixup(struct drm_encoder *encoder, const struct drm_display_mode *mode, @@ -2785,23 +2827,17 @@ nv50_encoder_mode_fixup(struct drm_encoder *encoder, nv_connector = nouveau_encoder_connector_get(nv_encoder); if (nv_connector && nv_connector->native_mode) { - nv_connector->scaling_full = false; - if (nv_connector->scaling_mode == DRM_MODE_SCALE_NONE) { - switch (nv_connector->type) { - case DCB_CONNECTOR_LVDS: - case DCB_CONNECTOR_LVDS_SPWG: - case DCB_CONNECTOR_eDP: - /* force use of scaler for non-edid modes */ - if (adjusted_mode->type & DRM_MODE_TYPE_DRIVER) - return true; - nv_connector->scaling_full = true; - break; - default: - return true; - } - } + struct nouveau_conn_atom *asyc + = nouveau_conn_atom(nv_connector->base.state); + struct drm_crtc_state crtc_state = { + .mode = *mode, + .adjusted_mode = *adjusted_mode, + }; - drm_mode_copy(adjusted_mode, nv_connector->native_mode); + nv50_outp_atomic_check_view(encoder, &crtc_state, &asyc->state, + nv_connector->native_mode); + nv_connector->scaling_full = asyc->scaler.full; + drm_mode_copy(adjusted_mode, &crtc_state.adjusted_mode); } return true; -- cgit v1.1 From 5f674a5c4667953fa48150e6d4e68c91877302ce Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 4 Nov 2016 17:20:36 +1000 Subject: drm/nouveau/kms/nv50: turn mode_set_base_atomic() into a stub This cannot currently be supported with atomic modesettting. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_display.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 03a3e3f..9f0b70d 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -2530,9 +2530,7 @@ nv50_crtc_mode_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, int x, int y, enum mode_set_atomic state) { - struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); - nv50_display_flip_stop(crtc); - nv50_crtc_set_image(nv_crtc, fb, x, y, true); + WARN_ON(1); return 0; } -- cgit v1.1 From 839ca903f12ef8f09374e0b655456482536a733e Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 4 Nov 2016 17:20:36 +1000 Subject: drm/nouveau/kms/nv50: transition to atomic interfaces internally This commit implements the atomic commit interfaces, and implements the legacy modeset and page flipping interfaces on top of them. There's two major changes in behavior from before: - We're now making use of interlocks between core and satellite EVO channels, which greatly improves our ability to keep their states synchronised. - DPMS is now implemented as a full modeset to either tear down the entire pipe (or bring it back up). This choice was made mostly to ease the initial implementation, but I'm also not sure what we gain by bring backing the old behaviour. We shall see. This does NOT currently expose the atomic ioctl by default, due to limited testing having been performed. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_display.c | 2 +- drivers/gpu/drm/nouveau/nouveau_display.h | 3 + drivers/gpu/drm/nouveau/nv50_display.c | 863 +++++++++++++++++++++++++++--- 3 files changed, 779 insertions(+), 89 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 79b5f9d..9e16deff 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -280,7 +280,7 @@ nouveau_framebuffer_new(struct drm_device *dev, return ret; } -static struct drm_framebuffer * +struct drm_framebuffer * nouveau_user_framebuffer_create(struct drm_device *dev, struct drm_file *file_priv, const struct drm_mode_fb_cmd2 *mode_cmd) diff --git a/drivers/gpu/drm/nouveau/nouveau_display.h b/drivers/gpu/drm/nouveau/nouveau_display.h index 77d6fe1..ecdc0a3 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.h +++ b/drivers/gpu/drm/nouveau/nouveau_display.h @@ -106,4 +106,7 @@ nouveau_backlight_exit(struct drm_device *dev) { } #endif +struct drm_framebuffer * +nouveau_user_framebuffer_create(struct drm_device *, struct drm_file *, + const struct drm_mode_fb_cmd2 *); #endif diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 9f0b70d..90fe9e0 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -49,6 +49,7 @@ #include "nouveau_encoder.h" #include "nouveau_crtc.h" #include "nouveau_fence.h" +#include "nouveau_fbcon.h" #include "nv50_display.h" #define EVO_DMA_NR 9 @@ -70,6 +71,37 @@ /****************************************************************************** * Atomic state *****************************************************************************/ +#define nv50_atom(p) container_of((p), struct nv50_atom, state) + +struct nv50_atom { + struct drm_atomic_state state; + + struct list_head outp; + bool lock_core; + bool flush_disable; +}; + +struct nv50_outp_atom { + struct list_head head; + + struct drm_encoder *encoder; + bool flush_disable; + + union { + struct { + bool ctrl:1; + }; + u8 mask; + } clr; + + union { + struct { + bool ctrl:1; + }; + u8 mask; + } set; +}; + #define nv50_head_atom(p) container_of((p), struct nv50_head_atom, state) struct nv50_head_atom { @@ -179,6 +211,15 @@ struct nv50_head_atom { } set; }; +static inline struct nv50_head_atom * +nv50_head_atom_get(struct drm_atomic_state *state, struct drm_crtc *crtc) +{ + struct drm_crtc_state *statec = drm_atomic_get_crtc_state(state, crtc); + if (IS_ERR(statec)) + return (void *)statec; + return nv50_head_atom(statec); +} + #define nv50_wndw_atom(p) container_of((p), struct nv50_wndw_atom, state) struct nv50_wndw_atom { @@ -639,6 +680,8 @@ struct nv50_disp { struct nv50_mast mast; struct nouveau_bo *sync; + + struct mutex mutex; }; static struct nv50_disp * @@ -757,7 +800,6 @@ struct nv50_wndw { u16 sema; u32 data; - struct nv50_wndw_atom arm; struct nv50_wndw_atom asy; }; @@ -885,18 +927,15 @@ nv50_wndw_atomic_check(struct drm_plane *plane, struct drm_plane_state *state) { struct nouveau_drm *drm = nouveau_drm(plane->dev); struct nv50_wndw *wndw = nv50_wndw(plane); - struct nv50_wndw_atom *armw = &wndw->arm; - struct nv50_wndw_atom *asyw = &wndw->asy; + struct nv50_wndw_atom *armw = nv50_wndw_atom(wndw->plane.state); + struct nv50_wndw_atom *asyw = nv50_wndw_atom(state); struct nv50_head_atom *harm = NULL, *asyh = NULL; bool varm = false, asyv = false, asym = false; int ret; - asyw->clr.mask = 0; - asyw->set.mask = 0; - NV_ATOMIC(drm, "%s atomic_check\n", plane->name); if (asyw->state.crtc) { - asyh = &nv50_head(asyw->state.crtc)->asy; + asyh = nv50_head_atom_get(asyw->state.state, asyw->state.crtc); if (IS_ERR(asyh)) return PTR_ERR(asyh); asym = drm_atomic_crtc_needs_modeset(&asyh->state); @@ -904,10 +943,10 @@ nv50_wndw_atomic_check(struct drm_plane *plane, struct drm_plane_state *state) } if (armw->state.crtc) { - harm = &nv50_head(armw->state.crtc)->asy; + harm = nv50_head_atom_get(asyw->state.state, armw->state.crtc); if (IS_ERR(harm)) return PTR_ERR(harm); - varm = nv50_head(harm->state.crtc)->arm.state.active; + varm = harm->state.crtc->state->active; } if (asyv) { @@ -936,11 +975,74 @@ nv50_wndw_atomic_check(struct drm_plane *plane, struct drm_plane_state *state) asyw->set.lut = wndw->func->lut && asyv; } - memcpy(armw, asyw, sizeof(*asyw)); return 0; } static void +nv50_wndw_cleanup_fb(struct drm_plane *plane, struct drm_plane_state *old_state) +{ + struct nouveau_framebuffer *fb = nouveau_framebuffer(old_state->fb); + struct nouveau_drm *drm = nouveau_drm(plane->dev); + + NV_ATOMIC(drm, "%s cleanup: %p\n", plane->name, old_state->fb); + if (!old_state->fb) + return; + + nouveau_bo_unpin(fb->nvbo); +} + +static int +nv50_wndw_prepare_fb(struct drm_plane *plane, struct drm_plane_state *state) +{ + struct nouveau_framebuffer *fb = nouveau_framebuffer(state->fb); + struct nouveau_drm *drm = nouveau_drm(plane->dev); + struct nv50_wndw *wndw = nv50_wndw(plane); + struct nv50_wndw_atom *asyw = nv50_wndw_atom(state); + struct nv50_head_atom *asyh; + struct nv50_dmac_ctxdma *ctxdma; + u32 name; + u8 kind; + int ret; + + NV_ATOMIC(drm, "%s prepare: %p\n", plane->name, state->fb); + if (!asyw->state.fb) + return 0; + kind = (fb->nvbo->tile_flags & 0x0000ff00) >> 8; + name = 0xfb000000 | kind; + + ret = nouveau_bo_pin(fb->nvbo, TTM_PL_FLAG_VRAM, true); + if (ret) + return ret; + + ctxdma = nv50_dmac_ctxdma_new(wndw->dmac, name, fb); + if (IS_ERR(ctxdma)) { + nouveau_bo_unpin(fb->nvbo); + return PTR_ERR(ctxdma); + } + + asyw->state.fence = reservation_object_get_excl_rcu(fb->nvbo->bo.resv); + asyw->image.handle = ctxdma->object.handle; + asyw->image.offset = fb->nvbo->bo.offset; + + if (wndw->func->prepare) { + asyh = nv50_head_atom_get(asyw->state.state, asyw->state.crtc); + if (IS_ERR(asyh)) + return PTR_ERR(asyh); + + wndw->func->prepare(wndw, asyh, asyw); + } + + return 0; +} + +static const struct drm_plane_helper_funcs +nv50_wndw_helper = { + .prepare_fb = nv50_wndw_prepare_fb, + .cleanup_fb = nv50_wndw_cleanup_fb, + .atomic_check = nv50_wndw_atomic_check, +}; + +static void nv50_wndw_atomic_destroy_state(struct drm_plane *plane, struct drm_plane_state *state) { @@ -998,6 +1100,8 @@ nv50_wndw_destroy(struct drm_plane *plane) static const struct drm_plane_funcs nv50_wndw = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, .destroy = nv50_wndw_destroy, .reset = nv50_wndw_reset, .set_property = drm_atomic_helper_plane_set_property, @@ -1033,6 +1137,7 @@ nv50_wndw_ctor(const struct nv50_wndw_func *func, struct drm_device *dev, if (ret) return ret; + drm_plane_helper_add(&wndw->plane, &nv50_wndw_helper); return 0; } @@ -2165,17 +2270,46 @@ nv50_head_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state) struct nouveau_drm *drm = nouveau_drm(crtc->dev); struct nv50_disp *disp = nv50_disp(crtc->dev); struct nv50_head *head = nv50_head(crtc); - struct nv50_head_atom *armh = &head->arm; + struct nv50_head_atom *armh = nv50_head_atom(crtc->state); struct nv50_head_atom *asyh = nv50_head_atom(state); + struct nouveau_conn_atom *asyc = NULL; + struct drm_connector_state *conns; + struct drm_connector *conn; + int i; NV_ATOMIC(drm, "%s atomic_check %d\n", crtc->name, asyh->state.active); - asyh->clr.mask = 0; - asyh->set.mask = 0; - if (asyh->state.active) { + for_each_connector_in_state(asyh->state.state, conn, conns, i) { + if (conns->crtc == crtc) { + asyc = nouveau_conn_atom(conns); + break; + } + } + + if (armh->state.active) { + if (asyc) { + if (asyh->state.mode_changed) + asyc->set.scaler = true; + if (armh->base.depth != asyh->base.depth) + asyc->set.dither = true; + } + } else { + asyc->set.mask = ~0; + asyh->set.mask = ~0; + } + if (asyh->state.mode_changed) nv50_head_atomic_check_mode(head, asyh); + if (asyc) { + if (asyc->set.scaler) + nv50_head_atomic_check_view(armh, asyh, asyc); + if (asyc->set.dither) + nv50_head_atomic_check_dither(armh, asyh, asyc); + if (asyc->set.procamp) + nv50_head_atomic_check_procamp(armh, asyh, asyc); + } + if ((asyh->core.visible = (asyh->base.cpp != 0))) { asyh->core.x = asyh->base.x; asyh->core.y = asyh->base.y; @@ -2234,20 +2368,21 @@ nv50_head_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state) asyh->set.curs = asyh->curs.visible; } - memcpy(armh, asyh, sizeof(*asyh)); - asyh->state.mode_changed = 0; + if (asyh->clr.mask || asyh->set.mask) + nv50_atom(asyh->state.state)->lock_core = true; return 0; } /****************************************************************************** * CRTC *****************************************************************************/ + static int nv50_crtc_set_dither(struct nouveau_crtc *nv_crtc, bool update) { struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev); struct nv50_head *head = nv50_head(&nv_crtc->base); - struct nv50_head_atom *asyh = &head->asy; + struct nv50_head_atom *asyh = nv50_head_atom(nv_crtc->base.state); struct nouveau_connector *nv_connector; struct nouveau_conn_atom asyc; u32 *push; @@ -2277,7 +2412,7 @@ static int nv50_crtc_set_scale(struct nouveau_crtc *nv_crtc, bool update) { struct nv50_head *head = nv50_head(&nv_crtc->base); - struct nv50_head_atom *asyh = &head->asy; + struct nv50_head_atom *asyh = nv50_head_atom(nv_crtc->base.state); struct drm_crtc *crtc = &nv_crtc->base; struct nouveau_connector *nv_connector; struct nouveau_conn_atom asyc; @@ -2307,7 +2442,7 @@ nv50_crtc_set_color_vibrance(struct nouveau_crtc *nv_crtc, bool update) { struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev); struct nv50_head *head = nv50_head(&nv_crtc->base); - struct nv50_head_atom *asyh = &head->asy; + struct nv50_head_atom *asyh = nv50_head_atom(nv_crtc->base.state); struct nouveau_conn_atom asyc; u32 *push; @@ -2685,15 +2820,143 @@ static const struct drm_crtc_helper_funcs nv50_crtc_hfunc = { .mode_set_base_atomic = nv50_crtc_mode_set_base_atomic, .load_lut = nv50_crtc_lut_load, .disable = nv50_crtc_disable, + .atomic_check = nv50_head_atomic_check, }; +/* This is identical to the version in the atomic helpers, except that + * it supports non-vblanked ("async") page flips. + */ +static int +nv50_head_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, + struct drm_pending_vblank_event *event, u32 flags) +{ + struct drm_plane *plane = crtc->primary; + struct drm_atomic_state *state; + struct drm_plane_state *plane_state; + struct drm_crtc_state *crtc_state; + int ret = 0; + + state = drm_atomic_state_alloc(plane->dev); + if (!state) + return -ENOMEM; + + state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc); +retry: + crtc_state = drm_atomic_get_crtc_state(state, crtc); + if (IS_ERR(crtc_state)) { + ret = PTR_ERR(crtc_state); + goto fail; + } + crtc_state->event = event; + + plane_state = drm_atomic_get_plane_state(state, plane); + if (IS_ERR(plane_state)) { + ret = PTR_ERR(plane_state); + goto fail; + } + + ret = drm_atomic_set_crtc_for_plane(plane_state, crtc); + if (ret != 0) + goto fail; + drm_atomic_set_fb_for_plane(plane_state, fb); + + /* Make sure we don't accidentally do a full modeset. */ + state->allow_modeset = false; + if (!crtc_state->active) { + DRM_DEBUG_ATOMIC("[CRTC:%d] disabled, rejecting legacy flip\n", + crtc->base.id); + ret = -EINVAL; + goto fail; + } + + if (flags & DRM_MODE_PAGE_FLIP_ASYNC) + nv50_wndw_atom(plane_state)->interval = 0; + + ret = drm_atomic_nonblocking_commit(state); +fail: + if (ret == -EDEADLK) + goto backoff; + + drm_atomic_state_put(state); + return ret; + +backoff: + drm_atomic_state_clear(state); + drm_atomic_legacy_backoff(state); + + /* + * Someone might have exchanged the framebuffer while we dropped locks + * in the backoff code. We need to fix up the fb refcount tracking the + * core does for us. + */ + plane->old_fb = plane->fb; + + goto retry; +} + +static void +nv50_head_atomic_destroy_state(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + struct nv50_head_atom *asyh = nv50_head_atom(state); + __drm_atomic_helper_crtc_destroy_state(&asyh->state); + kfree(asyh); +} + +static struct drm_crtc_state * +nv50_head_atomic_duplicate_state(struct drm_crtc *crtc) +{ + struct nv50_head_atom *armh = nv50_head_atom(crtc->state); + struct nv50_head_atom *asyh; + if (!(asyh = kmalloc(sizeof(*asyh), GFP_KERNEL))) + return NULL; + __drm_atomic_helper_crtc_duplicate_state(crtc, &asyh->state); + asyh->view = armh->view; + asyh->mode = armh->mode; + asyh->lut = armh->lut; + asyh->core = armh->core; + asyh->curs = armh->curs; + asyh->base = armh->base; + asyh->ovly = armh->ovly; + asyh->dither = armh->dither; + asyh->procamp = armh->procamp; + asyh->clr.mask = 0; + asyh->set.mask = 0; + return &asyh->state; +} + +static void +__drm_atomic_helper_crtc_reset(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + if (crtc->state) + crtc->funcs->atomic_destroy_state(crtc, crtc->state); + crtc->state = state; + crtc->state->crtc = crtc; +} + +static void +nv50_head_reset(struct drm_crtc *crtc) +{ + struct nv50_head_atom *asyh; + + if (WARN_ON(!(asyh = kzalloc(sizeof(*asyh), GFP_KERNEL)))) + return; + + __drm_atomic_helper_crtc_reset(crtc, &asyh->state); +} + static const struct drm_crtc_funcs nv50_crtc_func = { + .reset = nv50_head_reset, .cursor_set = nv50_crtc_cursor_set, .cursor_move = nv50_crtc_cursor_move, .gamma_set = nv50_crtc_gamma_set, - .set_config = nouveau_crtc_set_config, .destroy = nv50_crtc_destroy, - .page_flip = nouveau_crtc_page_flip, + .set_config = drm_atomic_helper_set_config, + .page_flip = nv50_head_page_flip, + .set_property = drm_atomic_helper_crtc_set_property, + .atomic_duplicate_state = nv50_head_atomic_duplicate_state, + .atomic_destroy_state = nv50_head_atomic_destroy_state, }; static int @@ -2734,7 +2997,9 @@ nv50_crtc_create(struct drm_device *dev, int index) head->_base = base; head->_curs = curs; - drm_crtc_init(dev, crtc, &nv50_crtc_func); + drm_crtc_init_with_planes(dev, crtc, &base->wndw.plane, + &curs->wndw.plane, &nv50_crtc_func, + "head-%d", head->base.index); drm_crtc_helper_add(crtc, &nv50_crtc_hfunc); drm_mode_crtc_set_gamma_size(crtc, 256); @@ -2815,30 +3080,15 @@ nv50_outp_atomic_check_view(struct drm_encoder *encoder, return 0; } -static bool -nv50_encoder_mode_fixup(struct drm_encoder *encoder, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) +static int +nv50_outp_atomic_check(struct drm_encoder *encoder, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) { - struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); - struct nouveau_connector *nv_connector; - - nv_connector = nouveau_encoder_connector_get(nv_encoder); - if (nv_connector && nv_connector->native_mode) { - struct nouveau_conn_atom *asyc - = nouveau_conn_atom(nv_connector->base.state); - struct drm_crtc_state crtc_state = { - .mode = *mode, - .adjusted_mode = *adjusted_mode, - }; - - nv50_outp_atomic_check_view(encoder, &crtc_state, &asyc->state, - nv_connector->native_mode); - nv_connector->scaling_full = asyc->scaler.full; - drm_mode_copy(adjusted_mode, &crtc_state.adjusted_mode); - } - - return true; + struct nouveau_connector *nv_connector = + nouveau_connector(conn_state->connector); + return nv50_outp_atomic_check_view(encoder, crtc_state, conn_state, + nv_connector->native_mode); } /****************************************************************************** @@ -2869,7 +3119,7 @@ nv50_dac_dpms(struct drm_encoder *encoder, int mode) } static void -nv50_dac_disconnect(struct drm_encoder *encoder) +nv50_dac_disable(struct drm_encoder *encoder) { struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); struct nv50_mast *mast = nv50_mast(encoder->dev); @@ -2877,8 +3127,6 @@ nv50_dac_disconnect(struct drm_encoder *encoder) u32 *push; if (nv_encoder->crtc) { - nv50_crtc_prepare(nv_encoder->crtc); - push = evo_wait(mast, 4); if (push) { if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) { @@ -2896,16 +3144,14 @@ nv50_dac_disconnect(struct drm_encoder *encoder) } static void -nv50_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) +nv50_dac_enable(struct drm_encoder *encoder) { struct nv50_mast *mast = nv50_mast(encoder->dev); struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc); + struct drm_display_mode *mode = &nv_crtc->base.state->adjusted_mode; u32 *push; - nv50_dac_dpms(encoder, DRM_MODE_DPMS_ON); - push = evo_wait(mast, 8); if (push) { if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) { @@ -2974,10 +3220,9 @@ nv50_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) static const struct drm_encoder_helper_funcs nv50_dac_help = { .dpms = nv50_dac_dpms, - .mode_fixup = nv50_encoder_mode_fixup, - .prepare = nv50_dac_disconnect, - .mode_set = nv50_dac_mode_set, - .disable = nv50_dac_disconnect, + .atomic_check = nv50_outp_atomic_check, + .enable = nv50_dac_enable, + .disable = nv50_dac_disable, .get_crtc = nv50_display_crtc_get, .detect = nv50_dac_detect }; @@ -3311,7 +3556,7 @@ nv50_sor_ctrl(struct nouveau_encoder *nv_encoder, u32 mask, u32 data) } static void -nv50_sor_disconnect(struct drm_encoder *encoder) +nv50_sor_disable(struct drm_encoder *encoder) { struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); struct nouveau_crtc *nv_crtc = nouveau_crtc(nv_encoder->crtc); @@ -3320,7 +3565,18 @@ nv50_sor_disconnect(struct drm_encoder *encoder) nv_encoder->crtc = NULL; if (nv_crtc) { - nv50_crtc_prepare(&nv_crtc->base); + struct nvkm_i2c_aux *aux = nv_encoder->aux; + u8 pwr; + + if (aux) { + int ret = nvkm_rdaux(aux, DP_SET_POWER, &pwr, 1); + if (ret == 0) { + pwr &= ~DP_SET_POWER_MASK; + pwr |= DP_SET_POWER_D3; + nvkm_wraux(aux, DP_SET_POWER, &pwr, 1); + } + } + nv50_sor_ctrl(nv_encoder, 1 << nv_crtc->index, 0); nv50_audio_disable(encoder, nv_crtc); nv50_hdmi_disable(&nv_encoder->base.base, nv_crtc); @@ -3328,11 +3584,11 @@ nv50_sor_disconnect(struct drm_encoder *encoder) } static void -nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode, - struct drm_display_mode *mode) +nv50_sor_enable(struct drm_encoder *encoder) { struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc); + struct drm_display_mode *mode = &nv_crtc->base.state->adjusted_mode; struct { struct nv50_disp_mthd_v1 base; struct nv50_disp_sor_lvds_script_v0 lvds; @@ -3428,8 +3684,6 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode, break; } - nv50_sor_dpms(&nv_encoder->base.base, DRM_MODE_DPMS_ON); - if (nv50_vers(mast) >= GF110_DISP) { u32 *push = evo_wait(mast, 3); if (push) { @@ -3467,10 +3721,9 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode, static const struct drm_encoder_helper_funcs nv50_sor_help = { .dpms = nv50_sor_dpms, - .mode_fixup = nv50_encoder_mode_fixup, - .prepare = nv50_sor_disconnect, - .mode_set = nv50_sor_mode_set, - .disable = nv50_sor_disconnect, + .atomic_check = nv50_outp_atomic_check, + .enable = nv50_sor_enable, + .disable = nv50_sor_disable, .get_crtc = nv50_display_crtc_get, }; @@ -3572,19 +3825,20 @@ nv50_pior_dpms(struct drm_encoder *encoder, int mode) nvif_mthd(disp->disp, 0, &args, sizeof(args)); } -static bool -nv50_pior_mode_fixup(struct drm_encoder *encoder, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) +static int +nv50_pior_atomic_check(struct drm_encoder *encoder, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) { - if (!nv50_encoder_mode_fixup(encoder, mode, adjusted_mode)) - return false; - adjusted_mode->clock *= 2; - return true; + int ret = nv50_outp_atomic_check(encoder, crtc_state, conn_state); + if (ret) + return ret; + crtc_state->adjusted_mode.clock *= 2; + return 0; } static void -nv50_pior_disconnect(struct drm_encoder *encoder) +nv50_pior_disable(struct drm_encoder *encoder) { struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); struct nv50_mast *mast = nv50_mast(encoder->dev); @@ -3592,8 +3846,6 @@ nv50_pior_disconnect(struct drm_encoder *encoder) u32 *push; if (nv_encoder->crtc) { - nv50_crtc_prepare(nv_encoder->crtc); - push = evo_wait(mast, 4); if (push) { if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) { @@ -3608,13 +3860,13 @@ nv50_pior_disconnect(struct drm_encoder *encoder) } static void -nv50_pior_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) +nv50_pior_enable(struct drm_encoder *encoder) { struct nv50_mast *mast = nv50_mast(encoder->dev); struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc); struct nouveau_connector *nv_connector; + struct drm_display_mode *mode = &nv_crtc->base.state->adjusted_mode; u8 owner = 1 << nv_crtc->index; u8 proto, depth; u32 *push; @@ -3637,8 +3889,6 @@ nv50_pior_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, break; } - nv50_pior_dpms(encoder, DRM_MODE_DPMS_ON); - push = evo_wait(mast, 8); if (push) { if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) { @@ -3660,10 +3910,9 @@ nv50_pior_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, static const struct drm_encoder_helper_funcs nv50_pior_help = { .dpms = nv50_pior_dpms, - .mode_fixup = nv50_pior_mode_fixup, - .prepare = nv50_pior_disconnect, - .mode_set = nv50_pior_mode_set, - .disable = nv50_pior_disconnect, + .atomic_check = nv50_pior_atomic_check, + .enable = nv50_pior_enable, + .disable = nv50_pior_disable, .get_crtc = nv50_display_crtc_get, }; @@ -3775,11 +4024,10 @@ nv50_fb_ctor(struct drm_framebuffer *fb) nv_fb->r_handle = 0xffff0000 | kind; list_for_each_entry(crtc, &drm->dev->mode_config.crtc_list, head) { - struct nv50_head *head = nv50_head(crtc); + struct nv50_wndw *wndw = nv50_wndw(crtc->primary); struct nv50_dmac_ctxdma *ctxdma; - ctxdma = nv50_dmac_ctxdma_new(&head->_base->chan.base, - nv_fb->r_handle, nv_fb); + ctxdma = nv50_dmac_ctxdma_new(wndw->dmac, nv_fb->r_handle, nv_fb); if (IS_ERR(ctxdma)) return PTR_ERR(ctxdma); } @@ -3788,6 +4036,436 @@ nv50_fb_ctor(struct drm_framebuffer *fb) } /****************************************************************************** + * Atomic + *****************************************************************************/ + +static void +nv50_disp_atomic_commit_core(struct nouveau_drm *drm, u32 interlock) +{ + struct nv50_disp *disp = nv50_disp(drm->dev); + struct nv50_dmac *core = &disp->mast.base; + u32 *push; + + NV_ATOMIC(drm, "commit core %08x\n", interlock); + + if ((push = evo_wait(core, 5))) { + evo_mthd(push, 0x0084, 1); + evo_data(push, 0x80000000); + evo_mthd(push, 0x0080, 2); + evo_data(push, interlock); + evo_data(push, 0x00000000); + nouveau_bo_wr32(disp->sync, 0, 0x00000000); + evo_kick(push, core); + if (nvif_msec(&drm->device, 2000ULL, + if (nouveau_bo_rd32(disp->sync, 0)) + break; + usleep_range(1, 2); + ) < 0) + NV_ERROR(drm, "EVO timeout\n"); + } +} + +static void +nv50_disp_atomic_commit_tail(struct drm_atomic_state *state) +{ + struct drm_device *dev = state->dev; + struct drm_crtc_state *crtc_state; + struct drm_crtc *crtc; + struct drm_plane_state *plane_state; + struct drm_plane *plane; + struct nouveau_drm *drm = nouveau_drm(dev); + struct nv50_disp *disp = nv50_disp(dev); + struct nv50_atom *atom = nv50_atom(state); + struct nv50_outp_atom *outp, *outt; + u32 interlock_core = 0; + u32 interlock_chan = 0; + int i; + + NV_ATOMIC(drm, "commit %d %d\n", atom->lock_core, atom->flush_disable); + drm_atomic_helper_wait_for_fences(dev, state, false); + drm_atomic_helper_wait_for_dependencies(state); + drm_atomic_helper_update_legacy_modeset_state(dev, state); + + if (atom->lock_core) + mutex_lock(&disp->mutex); + + /* Disable head(s). */ + for_each_crtc_in_state(state, crtc, crtc_state, i) { + struct nv50_head_atom *asyh = nv50_head_atom(crtc->state); + struct nv50_head *head = nv50_head(crtc); + + NV_ATOMIC(drm, "%s: clr %04x (set %04x)\n", crtc->name, + asyh->clr.mask, asyh->set.mask); + + if (asyh->clr.mask) { + nv50_head_flush_clr(head, asyh, atom->flush_disable); + interlock_core |= 1; + } + } + + /* Disable plane(s). */ + for_each_plane_in_state(state, plane, plane_state, i) { + struct nv50_wndw_atom *asyw = nv50_wndw_atom(plane->state); + struct nv50_wndw *wndw = nv50_wndw(plane); + + NV_ATOMIC(drm, "%s: clr %02x (set %02x)\n", plane->name, + asyw->clr.mask, asyw->set.mask); + if (!asyw->clr.mask) + continue; + + interlock_chan |= nv50_wndw_flush_clr(wndw, interlock_core, + atom->flush_disable, + asyw); + } + + /* Disable output path(s). */ + list_for_each_entry(outp, &atom->outp, head) { + const struct drm_encoder_helper_funcs *help; + struct drm_encoder *encoder; + + encoder = outp->encoder; + help = encoder->helper_private; + + NV_ATOMIC(drm, "%s: clr %02x (set %02x)\n", encoder->name, + outp->clr.mask, outp->set.mask); + + if (outp->clr.mask) { + help->disable(encoder); + interlock_core |= 1; + if (outp->flush_disable) { + nv50_disp_atomic_commit_core(drm, interlock_chan); + interlock_core = 0; + interlock_chan = 0; + } + } + } + + /* Flush disable. */ + if (interlock_core) { + if (atom->flush_disable) { + nv50_disp_atomic_commit_core(drm, interlock_chan); + interlock_core = 0; + interlock_chan = 0; + } + } + + /* Update output path(s). */ + list_for_each_entry_safe(outp, outt, &atom->outp, head) { + const struct drm_encoder_helper_funcs *help; + struct drm_encoder *encoder; + + encoder = outp->encoder; + help = encoder->helper_private; + + NV_ATOMIC(drm, "%s: set %02x (clr %02x)\n", encoder->name, + outp->set.mask, outp->clr.mask); + + if (outp->set.mask) { + help->enable(encoder); + interlock_core = 1; + } + + list_del(&outp->head); + kfree(outp); + } + + /* Update head(s). */ + for_each_crtc_in_state(state, crtc, crtc_state, i) { + struct nv50_head_atom *asyh = nv50_head_atom(crtc->state); + struct nv50_head *head = nv50_head(crtc); + + NV_ATOMIC(drm, "%s: set %04x (clr %04x)\n", crtc->name, + asyh->set.mask, asyh->clr.mask); + + if (asyh->set.mask) { + nv50_head_flush_set(head, asyh); + interlock_core = 1; + } + } + + /* Update plane(s). */ + for_each_plane_in_state(state, plane, plane_state, i) { + struct nv50_wndw_atom *asyw = nv50_wndw_atom(plane->state); + struct nv50_wndw *wndw = nv50_wndw(plane); + + NV_ATOMIC(drm, "%s: set %02x (clr %02x)\n", plane->name, + asyw->set.mask, asyw->clr.mask); + if ( !asyw->set.mask && + (!asyw->clr.mask || atom->flush_disable)) + continue; + + interlock_chan |= nv50_wndw_flush_set(wndw, interlock_core, asyw); + } + + /* Flush update. */ + if (interlock_core) { + if (!interlock_chan && atom->state.legacy_cursor_update) { + u32 *push = evo_wait(&disp->mast, 2); + if (push) { + evo_mthd(push, 0x0080, 1); + evo_data(push, 0x00000000); + evo_kick(push, &disp->mast); + } + } else { + nv50_disp_atomic_commit_core(drm, interlock_chan); + } + } + + if (atom->lock_core) + mutex_unlock(&disp->mutex); + + /* Wait for HW to signal completion. */ + for_each_plane_in_state(state, plane, plane_state, i) { + struct nv50_wndw_atom *asyw = nv50_wndw_atom(plane->state); + struct nv50_wndw *wndw = nv50_wndw(plane); + int ret = nv50_wndw_wait_armed(wndw, asyw); + if (ret) + NV_ERROR(drm, "%s: timeout\n", plane->name); + } + + for_each_crtc_in_state(state, crtc, crtc_state, i) { + if (crtc->state->event) { + unsigned long flags; + spin_lock_irqsave(&crtc->dev->event_lock, flags); + drm_crtc_send_vblank_event(crtc, crtc->state->event); + spin_unlock_irqrestore(&crtc->dev->event_lock, flags); + crtc->state->event = NULL; + } + } + + drm_atomic_helper_commit_hw_done(state); + drm_atomic_helper_cleanup_planes(dev, state); + drm_atomic_helper_commit_cleanup_done(state); + drm_atomic_state_put(state); +} + +static void +nv50_disp_atomic_commit_work(struct work_struct *work) +{ + struct drm_atomic_state *state = + container_of(work, typeof(*state), commit_work); + nv50_disp_atomic_commit_tail(state); +} + +static int +nv50_disp_atomic_commit(struct drm_device *dev, + struct drm_atomic_state *state, bool nonblock) +{ + struct nouveau_drm *drm = nouveau_drm(dev); + struct nv50_disp *disp = nv50_disp(dev); + struct drm_plane_state *plane_state; + struct drm_plane *plane; + struct drm_crtc *crtc; + bool active = false; + int ret, i; + + ret = pm_runtime_get_sync(dev->dev); + if (ret < 0 && ret != -EACCES) + return ret; + + ret = drm_atomic_helper_setup_commit(state, nonblock); + if (ret) + goto done; + + INIT_WORK(&state->commit_work, nv50_disp_atomic_commit_work); + + ret = drm_atomic_helper_prepare_planes(dev, state); + if (ret) + goto done; + + if (!nonblock) { + ret = drm_atomic_helper_wait_for_fences(dev, state, true); + if (ret) + goto done; + } + + for_each_plane_in_state(state, plane, plane_state, i) { + struct nv50_wndw_atom *asyw = nv50_wndw_atom(plane_state); + struct nv50_wndw *wndw = nv50_wndw(plane); + if (asyw->set.image) { + asyw->ntfy.handle = wndw->dmac->sync.handle; + asyw->ntfy.offset = wndw->ntfy; + asyw->ntfy.awaken = false; + asyw->set.ntfy = true; + nouveau_bo_wr32(disp->sync, wndw->ntfy / 4, 0x00000000); + wndw->ntfy ^= 0x10; + } + } + + drm_atomic_helper_swap_state(state, true); + drm_atomic_state_get(state); + + if (nonblock) + queue_work(system_unbound_wq, &state->commit_work); + else + nv50_disp_atomic_commit_tail(state); + + drm_for_each_crtc(crtc, dev) { + if (crtc->state->enable) { + if (!drm->have_disp_power_ref) { + drm->have_disp_power_ref = true; + return ret; + } + active = true; + break; + } + } + + if (!active && drm->have_disp_power_ref) { + pm_runtime_put_autosuspend(dev->dev); + drm->have_disp_power_ref = false; + } + +done: + pm_runtime_put_autosuspend(dev->dev); + return ret; +} + +static struct nv50_outp_atom * +nv50_disp_outp_atomic_add(struct nv50_atom *atom, struct drm_encoder *encoder) +{ + struct nv50_outp_atom *outp; + + list_for_each_entry(outp, &atom->outp, head) { + if (outp->encoder == encoder) + return outp; + } + + outp = kzalloc(sizeof(*outp), GFP_KERNEL); + if (!outp) + return ERR_PTR(-ENOMEM); + + list_add(&outp->head, &atom->outp); + outp->encoder = encoder; + return outp; +} + +static int +nv50_disp_outp_atomic_check_clr(struct nv50_atom *atom, + struct drm_connector *connector) +{ + struct drm_encoder *encoder = connector->state->best_encoder; + struct drm_crtc_state *crtc_state; + struct drm_crtc *crtc; + struct nv50_outp_atom *outp; + + if (!(crtc = connector->state->crtc)) + return 0; + + crtc_state = drm_atomic_get_existing_crtc_state(&atom->state, crtc); + if (crtc->state->active && drm_atomic_crtc_needs_modeset(crtc_state)) { + outp = nv50_disp_outp_atomic_add(atom, encoder); + if (IS_ERR(outp)) + return PTR_ERR(outp); + + if (outp->encoder->encoder_type == DRM_MODE_ENCODER_DPMST) { + outp->flush_disable = true; + atom->flush_disable = true; + } + outp->clr.ctrl = true; + atom->lock_core = true; + } + + return 0; +} + +static int +nv50_disp_outp_atomic_check_set(struct nv50_atom *atom, + struct drm_connector_state *connector_state) +{ + struct drm_encoder *encoder = connector_state->best_encoder; + struct drm_crtc_state *crtc_state; + struct drm_crtc *crtc; + struct nv50_outp_atom *outp; + + if (!(crtc = connector_state->crtc)) + return 0; + + crtc_state = drm_atomic_get_existing_crtc_state(&atom->state, crtc); + if (crtc_state->active && drm_atomic_crtc_needs_modeset(crtc_state)) { + outp = nv50_disp_outp_atomic_add(atom, encoder); + if (IS_ERR(outp)) + return PTR_ERR(outp); + + outp->set.ctrl = true; + atom->lock_core = true; + } + + return 0; +} + +static int +nv50_disp_atomic_check(struct drm_device *dev, struct drm_atomic_state *state) +{ + struct nv50_atom *atom = nv50_atom(state); + struct drm_connector_state *connector_state; + struct drm_connector *connector; + int ret, i; + + ret = drm_atomic_helper_check(dev, state); + if (ret) + return ret; + + for_each_connector_in_state(state, connector, connector_state, i) { + ret = nv50_disp_outp_atomic_check_clr(atom, connector); + if (ret) + return ret; + + ret = nv50_disp_outp_atomic_check_set(atom, connector_state); + if (ret) + return ret; + } + + return 0; +} + +static void +nv50_disp_atomic_state_clear(struct drm_atomic_state *state) +{ + struct nv50_atom *atom = nv50_atom(state); + struct nv50_outp_atom *outp, *outt; + + list_for_each_entry_safe(outp, outt, &atom->outp, head) { + list_del(&outp->head); + kfree(outp); + } + + drm_atomic_state_default_clear(state); +} + +static void +nv50_disp_atomic_state_free(struct drm_atomic_state *state) +{ + struct nv50_atom *atom = nv50_atom(state); + drm_atomic_state_default_release(&atom->state); + kfree(atom); +} + +static struct drm_atomic_state * +nv50_disp_atomic_state_alloc(struct drm_device *dev) +{ + struct nv50_atom *atom; + if (!(atom = kzalloc(sizeof(*atom), GFP_KERNEL)) || + drm_atomic_state_init(dev, &atom->state) < 0) { + kfree(atom); + return NULL; + } + INIT_LIST_HEAD(&atom->outp); + return &atom->state; +} + +static const struct drm_mode_config_funcs +nv50_disp_func = { + .fb_create = nouveau_user_framebuffer_create, + .output_poll_changed = nouveau_fbcon_output_poll_changed, + .atomic_check = nv50_disp_atomic_check, + .atomic_commit = nv50_disp_atomic_commit, + .atomic_state_alloc = nv50_disp_atomic_state_alloc, + .atomic_state_clear = nv50_disp_atomic_state_clear, + .atomic_state_free = nv50_disp_atomic_state_free, +}; + +/****************************************************************************** * Init *****************************************************************************/ @@ -3872,6 +4550,10 @@ nv50_display_destroy(struct drm_device *dev) kfree(disp); } +MODULE_PARM_DESC(atomic, "Expose atomic ioctl (default: disabled)"); +static int nouveau_atomic = 0; +module_param_named(atomic, nouveau_atomic, int, 0400); + int nv50_display_create(struct drm_device *dev) { @@ -3887,6 +4569,8 @@ nv50_display_create(struct drm_device *dev) if (!disp) return -ENOMEM; + mutex_init(&disp->mutex); + nouveau_display(dev)->priv = disp; nouveau_display(dev)->dtor = nv50_display_destroy; nouveau_display(dev)->init = nv50_display_init; @@ -3894,6 +4578,9 @@ nv50_display_create(struct drm_device *dev) nouveau_display(dev)->fb_ctor = nv50_fb_ctor; nouveau_display(dev)->fb_dtor = nv50_fb_dtor; disp->disp = &nouveau_display(dev)->disp; + dev->mode_config.funcs = &nv50_disp_func; + if (nouveau_atomic) + dev->driver->driver_features |= DRIVER_ATOMIC; /* small shared memory area we use for notifiers and semaphores */ ret = nouveau_bo_new(dev, 4096, 0x1000, TTM_PL_FLAG_VRAM, -- cgit v1.1 From f7aa20e83338b95666604404c6390cc8597b3147 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 4 Nov 2016 17:20:36 +1000 Subject: drm/nouveau/kms/nv50: remove code to support non-atomic modesets Make completely unreachable (and broken) by atomic commits. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_display.c | 386 --------------------------------- 1 file changed, 386 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 90fe9e0..c4ad991 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -662,11 +662,7 @@ struct nv50_head { struct nv50_ovly ovly; struct nv50_oimm oimm; - struct nv50_head_atom arm; - struct nv50_head_atom asy; - struct nv50_base *_base; - struct nv50_curs *_curs; }; #define nv50_head(c) ((struct nv50_head *)nouveau_crtc(c)) @@ -692,12 +688,6 @@ nv50_disp(struct drm_device *dev) #define nv50_mast(d) (&nv50_disp(d)->mast) -static struct drm_crtc * -nv50_display_crtc_get(struct drm_encoder *encoder) -{ - return nouveau_encoder(encoder)->crtc; -} - /****************************************************************************** * EVO channel helpers *****************************************************************************/ @@ -2378,289 +2368,6 @@ nv50_head_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state) *****************************************************************************/ static int -nv50_crtc_set_dither(struct nouveau_crtc *nv_crtc, bool update) -{ - struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev); - struct nv50_head *head = nv50_head(&nv_crtc->base); - struct nv50_head_atom *asyh = nv50_head_atom(nv_crtc->base.state); - struct nouveau_connector *nv_connector; - struct nouveau_conn_atom asyc; - u32 *push; - - nv_connector = nouveau_crtc_connector_get(nv_crtc); - - asyc.state.connector = &nv_connector->base; - asyc.dither.mode = nv_connector->dithering_mode; - asyc.dither.depth = nv_connector->dithering_depth; - asyh->state.crtc = &nv_crtc->base; - nv50_head_atomic_check(&head->base.base, &asyh->state); - nv50_head_atomic_check_dither(&head->arm, asyh, &asyc); - nv50_head_flush_set(head, asyh); - - if (update) { - if ((push = evo_wait(mast, 2))) { - evo_mthd(push, 0x0080, 1); - evo_data(push, 0x00000000); - evo_kick(push, mast); - } - } - - return 0; -} - -static int -nv50_crtc_set_scale(struct nouveau_crtc *nv_crtc, bool update) -{ - struct nv50_head *head = nv50_head(&nv_crtc->base); - struct nv50_head_atom *asyh = nv50_head_atom(nv_crtc->base.state); - struct drm_crtc *crtc = &nv_crtc->base; - struct nouveau_connector *nv_connector; - struct nouveau_conn_atom asyc; - - nv_connector = nouveau_crtc_connector_get(nv_crtc); - - asyc.state.connector = &nv_connector->base; - asyc.scaler.mode = nv_connector->scaling_mode; - asyc.scaler.full = nv_connector->scaling_full; - asyc.scaler.underscan.mode = nv_connector->underscan; - asyc.scaler.underscan.hborder = nv_connector->underscan_hborder; - asyc.scaler.underscan.vborder = nv_connector->underscan_vborder; - nv50_head_atomic_check(&head->base.base, &asyh->state); - nv50_head_atomic_check_view(&head->arm, asyh, &asyc); - nv50_head_flush_set(head, asyh); - - if (update) { - nv50_display_flip_stop(crtc); - nv50_display_flip_next(crtc, crtc->primary->fb, NULL, 1); - } - - return 0; -} - -static int -nv50_crtc_set_color_vibrance(struct nouveau_crtc *nv_crtc, bool update) -{ - struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev); - struct nv50_head *head = nv50_head(&nv_crtc->base); - struct nv50_head_atom *asyh = nv50_head_atom(nv_crtc->base.state); - struct nouveau_conn_atom asyc; - u32 *push; - - asyc.procamp.color_vibrance = nv_crtc->color_vibrance + 100; - asyc.procamp.vibrant_hue = nv_crtc->vibrant_hue + 90; - nv50_head_atomic_check(&head->base.base, &asyh->state); - nv50_head_atomic_check_procamp(&head->arm, asyh, &asyc); - nv50_head_flush_set(head, asyh); - - if (update) { - if ((push = evo_wait(mast, 2))) { - evo_mthd(push, 0x0080, 1); - evo_data(push, 0x00000000); - evo_kick(push, mast); - } - } - - return 0; -} - -static int -nv50_crtc_set_image(struct nouveau_crtc *nv_crtc, struct drm_framebuffer *fb, - int x, int y, bool update) -{ - struct nouveau_framebuffer *nvfb = nouveau_framebuffer(fb); - struct nv50_head *head = nv50_head(&nv_crtc->base); - struct nv50_head_atom *asyh = &head->asy; - struct nv50_wndw_atom *asyw = &head->_base->wndw.asy; - const struct drm_format_info *info; - - info = drm_format_info(nvfb->base.pixel_format); - if (!info || !info->depth) - return -EINVAL; - - asyh->base.depth = info->depth; - asyh->base.cpp = info->cpp[0]; - asyh->base.x = x; - asyh->base.y = y; - asyh->base.w = nvfb->base.width; - asyh->base.h = nvfb->base.height; - asyw->state.src_x = x << 16; - asyw->state.src_y = y << 16; - nv50_head_atomic_check(&head->base.base, &asyh->state); - nv50_head_flush_set(head, asyh); - - if (update) { - struct nv50_mast *core = nv50_mast(nv_crtc->base.dev); - u32 *push = evo_wait(core, 2); - if (push) { - evo_mthd(push, 0x0080, 1); - evo_data(push, 0x00000000); - evo_kick(push, core); - } - } - - nv_crtc->fb.handle = nvfb->r_handle; - return 0; -} - -static void -nv50_crtc_cursor_show(struct nouveau_crtc *nv_crtc) -{ - struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev); - struct nv50_head *head = nv50_head(&nv_crtc->base); - struct nv50_head_atom *asyh = &head->asy; - - asyh->curs.visible = true; - asyh->curs.handle = mast->base.vram.handle; - asyh->curs.offset = nv_crtc->cursor.nvbo->bo.offset; - asyh->curs.layout = 1; - asyh->curs.format = 1; - nv50_head_atomic_check(&head->base.base, &asyh->state); - nv50_head_flush_set(head, asyh); -} - -static void -nv50_crtc_cursor_hide(struct nouveau_crtc *nv_crtc) -{ - struct nv50_head *head = nv50_head(&nv_crtc->base); - struct nv50_head_atom *asyh = &head->asy; - - asyh->curs.visible = false; - nv50_head_atomic_check(&head->base.base, &asyh->state); - nv50_head_flush_clr(head, asyh, false); -} - -static void -nv50_crtc_cursor_show_hide(struct nouveau_crtc *nv_crtc, bool show, bool update) -{ - struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev); - - if (show && nv_crtc->cursor.nvbo && nv_crtc->base.enabled) - nv50_crtc_cursor_show(nv_crtc); - else - nv50_crtc_cursor_hide(nv_crtc); - - if (update) { - u32 *push = evo_wait(mast, 2); - if (push) { - evo_mthd(push, 0x0080, 1); - evo_data(push, 0x00000000); - evo_kick(push, mast); - } - } -} - -static void -nv50_crtc_dpms(struct drm_crtc *crtc, int mode) -{ -} - -static void -nv50_crtc_prepare(struct drm_crtc *crtc) -{ - struct nv50_head *head = nv50_head(crtc); - struct nv50_head_atom *asyh = &head->asy; - - nv50_display_flip_stop(crtc); - - asyh->state.active = false; - nv50_head_atomic_check(&head->base.base, &asyh->state); - nv50_head_flush_clr(head, asyh, false); -} - -static void -nv50_crtc_commit(struct drm_crtc *crtc) -{ - struct nv50_head *head = nv50_head(crtc); - struct nv50_head_atom *asyh = &head->asy; - - asyh->state.active = true; - nv50_head_atomic_check(&head->base.base, &asyh->state); - nv50_head_flush_set(head, asyh); - - nv50_display_flip_next(crtc, crtc->primary->fb, NULL, 1); -} - -static bool -nv50_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V); - return true; -} - -static int -nv50_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb) -{ - struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->primary->fb); - struct nv50_head *head = nv50_head(crtc); - int ret; - - ret = nouveau_bo_pin(nvfb->nvbo, TTM_PL_FLAG_VRAM, true); - if (ret == 0) { - if (head->image) - nouveau_bo_unpin(head->image); - nouveau_bo_ref(nvfb->nvbo, &head->image); - } - - return ret; -} - -static int -nv50_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *umode, - struct drm_display_mode *mode, int x, int y, - struct drm_framebuffer *old_fb) -{ - struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); - struct nouveau_connector *nv_connector; - int ret; - struct nv50_head *head = nv50_head(crtc); - struct nv50_head_atom *asyh = &head->asy; - - memcpy(&asyh->state.mode, umode, sizeof(*umode)); - memcpy(&asyh->state.adjusted_mode, mode, sizeof(*mode)); - asyh->state.active = true; - asyh->state.mode_changed = true; - nv50_head_atomic_check(&head->base.base, &asyh->state); - - ret = nv50_crtc_swap_fbs(crtc, old_fb); - if (ret) - return ret; - - nv50_head_flush_set(head, asyh); - - nv_connector = nouveau_crtc_connector_get(nv_crtc); - nv50_crtc_set_dither(nv_crtc, false); - nv50_crtc_set_scale(nv_crtc, false); - - nv50_crtc_set_color_vibrance(nv_crtc, false); - nv50_crtc_set_image(nv_crtc, crtc->primary->fb, x, y, false); - return 0; -} - -static int -nv50_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, - struct drm_framebuffer *old_fb) -{ - struct nouveau_drm *drm = nouveau_drm(crtc->dev); - struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); - int ret; - - if (!crtc->primary->fb) { - NV_DEBUG(drm, "No FB bound\n"); - return 0; - } - - ret = nv50_crtc_swap_fbs(crtc, old_fb); - if (ret) - return ret; - - nv50_display_flip_stop(crtc); - nv50_crtc_set_image(nv_crtc, crtc->primary->fb, x, y, true); - nv50_display_flip_next(crtc, crtc->primary->fb, NULL, 1); - return 0; -} - -static int nv50_crtc_mode_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, int x, int y, enum mode_set_atomic state) @@ -2694,65 +2401,6 @@ nv50_crtc_lut_load(struct drm_crtc *crtc) } } -static void -nv50_crtc_disable(struct drm_crtc *crtc) -{ - struct nv50_head *head = nv50_head(crtc); - evo_sync(crtc->dev); - if (head->image) - nouveau_bo_unpin(head->image); - nouveau_bo_ref(NULL, &head->image); -} - -static int -nv50_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, - uint32_t handle, uint32_t width, uint32_t height) -{ - struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); - struct drm_gem_object *gem = NULL; - struct nouveau_bo *nvbo = NULL; - int ret = 0; - - if (handle) { - if (width != 64 || height != 64) - return -EINVAL; - - gem = drm_gem_object_lookup(file_priv, handle); - if (unlikely(!gem)) - return -ENOENT; - nvbo = nouveau_gem_object(gem); - - ret = nouveau_bo_pin(nvbo, TTM_PL_FLAG_VRAM, true); - } - - if (ret == 0) { - if (nv_crtc->cursor.nvbo) - nouveau_bo_unpin(nv_crtc->cursor.nvbo); - nouveau_bo_ref(nvbo, &nv_crtc->cursor.nvbo); - } - drm_gem_object_unreference_unlocked(gem); - - nv50_crtc_cursor_show_hide(nv_crtc, true, true); - return ret; -} - -static int -nv50_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) -{ - struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); - struct nv50_wndw *wndw = &nv50_head(crtc)->_curs->wndw; - struct nv50_wndw_atom *asyw = &wndw->asy; - - asyw->point.x = x; - asyw->point.y = y; - asyw->set.point = true; - nv50_wndw_flush_set(wndw, 0, asyw); - - nv_crtc->cursor_saved_x = x; - nv_crtc->cursor_saved_y = y; - return 0; -} - static int nv50_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, uint32_t size) @@ -2772,14 +2420,6 @@ nv50_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, } static void -nv50_crtc_cursor_restore(struct nouveau_crtc *nv_crtc, int x, int y) -{ - nv50_crtc_cursor_move(&nv_crtc->base, x, y); - - nv50_crtc_cursor_show_hide(nv_crtc, true, true); -} - -static void nv50_crtc_destroy(struct drm_crtc *crtc) { struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); @@ -2789,18 +2429,6 @@ nv50_crtc_destroy(struct drm_crtc *crtc) nv50_dmac_destroy(&head->ovly.base, disp->disp); nv50_pioc_destroy(&head->oimm.base); - /*XXX: this shouldn't be necessary, but the core doesn't call - * disconnect() during the cleanup paths - */ - if (head->image) - nouveau_bo_unpin(head->image); - nouveau_bo_ref(NULL, &head->image); - - /*XXX: ditto */ - if (nv_crtc->cursor.nvbo) - nouveau_bo_unpin(nv_crtc->cursor.nvbo); - nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo); - nouveau_bo_unmap(nv_crtc->lut.nvbo); if (nv_crtc->lut.nvbo) nouveau_bo_unpin(nv_crtc->lut.nvbo); @@ -2811,15 +2439,8 @@ nv50_crtc_destroy(struct drm_crtc *crtc) } static const struct drm_crtc_helper_funcs nv50_crtc_hfunc = { - .dpms = nv50_crtc_dpms, - .prepare = nv50_crtc_prepare, - .commit = nv50_crtc_commit, - .mode_fixup = nv50_crtc_mode_fixup, - .mode_set = nv50_crtc_mode_set, - .mode_set_base = nv50_crtc_mode_set_base, .mode_set_base_atomic = nv50_crtc_mode_set_base_atomic, .load_lut = nv50_crtc_lut_load, - .disable = nv50_crtc_disable, .atomic_check = nv50_head_atomic_check, }; @@ -2948,8 +2569,6 @@ nv50_head_reset(struct drm_crtc *crtc) static const struct drm_crtc_funcs nv50_crtc_func = { .reset = nv50_head_reset, - .cursor_set = nv50_crtc_cursor_set, - .cursor_move = nv50_crtc_cursor_move, .gamma_set = nv50_crtc_gamma_set, .destroy = nv50_crtc_destroy, .set_config = drm_atomic_helper_set_config, @@ -2978,7 +2597,6 @@ nv50_crtc_create(struct drm_device *dev, int index) head->base.index = index; head->base.color_vibrance = 50; head->base.vibrant_hue = 0; - head->base.cursor.set_pos = nv50_crtc_cursor_restore; for (i = 0; i < 256; i++) { head->base.lut.r[i] = i << 8; head->base.lut.g[i] = i << 8; @@ -2995,7 +2613,6 @@ nv50_crtc_create(struct drm_device *dev, int index) crtc = &head->base.base; head->_base = base; - head->_curs = curs; drm_crtc_init_with_planes(dev, crtc, &base->wndw.plane, &curs->wndw.plane, &nv50_crtc_func, @@ -3223,7 +2840,6 @@ nv50_dac_help = { .atomic_check = nv50_outp_atomic_check, .enable = nv50_dac_enable, .disable = nv50_dac_disable, - .get_crtc = nv50_display_crtc_get, .detect = nv50_dac_detect }; @@ -3724,7 +3340,6 @@ nv50_sor_help = { .atomic_check = nv50_outp_atomic_check, .enable = nv50_sor_enable, .disable = nv50_sor_disable, - .get_crtc = nv50_display_crtc_get, }; static void @@ -3913,7 +3528,6 @@ nv50_pior_help = { .atomic_check = nv50_pior_atomic_check, .enable = nv50_pior_enable, .disable = nv50_pior_disable, - .get_crtc = nv50_display_crtc_get, }; static void -- cgit v1.1 From 8896ceef78265fe6ecd5bd3eaa441ecd0a3af160 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 4 Nov 2016 17:20:36 +1000 Subject: drm/nouveau/kms/nv50: remove code to support non-atomic dpms Made completely unreachable (and broken) by atomic commits. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_connector.c | 42 +-------------------------- drivers/gpu/drm/nouveau/nv50_display.c | 44 +---------------------------- 2 files changed, 2 insertions(+), 84 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index b69ba82..790a9ac2 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -1118,43 +1118,6 @@ nouveau_connector_funcs_lvds = { }; static int -nouveau_connector_dp_dpms(struct drm_connector *connector, int mode) -{ - struct nouveau_encoder *nv_encoder = NULL; - - if (connector->encoder) - nv_encoder = nouveau_encoder(connector->encoder); - if (nv_encoder && nv_encoder->dcb && - nv_encoder->dcb->type == DCB_OUTPUT_DP) { - if (mode == DRM_MODE_DPMS_ON) { - u8 data = DP_SET_POWER_D0; - nvkm_wraux(nv_encoder->aux, DP_SET_POWER, &data, 1); - usleep_range(1000, 2000); - } else { - u8 data = DP_SET_POWER_D3; - nvkm_wraux(nv_encoder->aux, DP_SET_POWER, &data, 1); - } - } - - return drm_helper_connector_dpms(connector, mode); -} - -static const struct drm_connector_funcs -nouveau_connector_funcs_dp = { - .dpms = nouveau_connector_dp_dpms, - .reset = nouveau_conn_reset, - .detect = nouveau_connector_detect, - .force = nouveau_connector_force, - .fill_modes = drm_helper_probe_single_connector_modes, - .set_property = nouveau_connector_set_property, - .destroy = nouveau_connector_destroy, - .atomic_duplicate_state = nouveau_conn_atomic_duplicate_state, - .atomic_destroy_state = nouveau_conn_atomic_destroy_state, - .atomic_set_property = nouveau_conn_atomic_set_property, - .atomic_get_property = nouveau_conn_atomic_get_property, -}; - -static int nouveau_connector_hotplug(struct nvif_notify *notify) { struct nouveau_connector *nv_connector = @@ -1348,10 +1311,7 @@ nouveau_connector_create(struct drm_device *dev, int index) return ERR_PTR(ret); } - if (dev->mode_config.funcs->atomic_commit) - funcs = &nouveau_connector_funcs; - else - funcs = &nouveau_connector_funcs_dp; + funcs = &nouveau_connector_funcs; break; default: funcs = &nouveau_connector_funcs; diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index c4ad991..c605348 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -3116,42 +3116,8 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode) .base.hashm = nv_encoder->dcb->hashm, .pwr.state = mode == DRM_MODE_DPMS_ON, }; - struct { - struct nv50_disp_mthd_v1 base; - struct nv50_disp_sor_dp_pwr_v0 pwr; - } link = { - .base.version = 1, - .base.method = NV50_DISP_MTHD_V1_SOR_DP_PWR, - .base.hasht = nv_encoder->dcb->hasht, - .base.hashm = nv_encoder->dcb->hashm, - .pwr.state = mode == DRM_MODE_DPMS_ON, - }; - struct drm_device *dev = encoder->dev; - struct drm_encoder *partner; - - nv_encoder->last_dpms = mode; - list_for_each_entry(partner, &dev->mode_config.encoder_list, head) { - struct nouveau_encoder *nv_partner = nouveau_encoder(partner); - - if (partner->encoder_type != DRM_MODE_ENCODER_TMDS) - continue; - - if (nv_partner != nv_encoder && - nv_partner->dcb->or == nv_encoder->dcb->or) { - if (nv_partner->last_dpms == DRM_MODE_DPMS_ON) - return; - break; - } - } - - if (nv_encoder->dcb->type == DCB_OUTPUT_DP) { - args.pwr.state = 1; - nvif_mthd(disp->disp, 0, &args, sizeof(args)); - nvif_mthd(disp->disp, 0, &link, sizeof(link)); - } else { - nvif_mthd(disp->disp, 0, &args, sizeof(args)); - } + nvif_mthd(disp->disp, 0, &args, sizeof(args)); } static void @@ -3177,7 +3143,6 @@ nv50_sor_disable(struct drm_encoder *encoder) struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); struct nouveau_crtc *nv_crtc = nouveau_crtc(nv_encoder->crtc); - nv_encoder->last_dpms = DRM_MODE_DPMS_OFF; nv_encoder->crtc = NULL; if (nv_crtc) { @@ -3380,7 +3345,6 @@ nv50_sor_create(struct drm_connector *connector, struct dcb_output *dcbe) return -ENOMEM; nv_encoder->dcb = dcbe; nv_encoder->or = ffs(dcbe->or) - 1; - nv_encoder->last_dpms = DRM_MODE_DPMS_OFF; encoder = to_drm_encoder(nv_encoder); encoder->possible_crtcs = dcbe->heads; @@ -4126,15 +4090,9 @@ nv50_display_init(struct drm_device *dev) struct nouveau_encoder *nv_encoder; nv_encoder = nouveau_encoder(encoder); - if (nv_encoder->dcb->type == DCB_OUTPUT_DP) - nv_encoder->dcb->type = DCB_OUTPUT_EOL; - help = encoder->helper_private; if (help && help->dpms) help->dpms(encoder, DRM_MODE_DPMS_ON); - - if (nv_encoder->dcb->type == DCB_OUTPUT_EOL) - nv_encoder->dcb->type = DCB_OUTPUT_DP; } } -- cgit v1.1 From c2d926aacc7eeaf39edbd0ab8d5fba33acbb168d Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 4 Nov 2016 17:20:36 +1000 Subject: drm/nouveau/kms/nv50: remove code to support non-atomic connector properties Made completely unreachable by atomic commits. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_connector.c | 27 +++++++++------------------ drivers/gpu/drm/nouveau/nouveau_connector.h | 5 ----- drivers/gpu/drm/nouveau/nouveau_crtc.h | 2 -- drivers/gpu/drm/nouveau/nv50_display.c | 2 -- 4 files changed, 9 insertions(+), 27 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 790a9ac2..5df3908 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -767,7 +767,6 @@ nouveau_connector_set_property(struct drm_connector *connector, struct nouveau_connector *nv_connector = nouveau_connector(connector); struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder; struct drm_encoder *encoder = to_drm_encoder(nv_encoder); - struct nouveau_crtc *nv_crtc = NULL; int ret; if (connector->dev->mode_config.funcs->atomic_commit) @@ -784,24 +783,17 @@ nouveau_connector_set_property(struct drm_connector *connector, } nv_connector->scaling_mode = asyc->scaler.mode; - nv_connector->underscan = asyc->scaler.underscan.mode; - nv_connector->underscan_hborder = asyc->scaler.underscan.hborder; - nv_connector->underscan_vborder = asyc->scaler.underscan.vborder; nv_connector->dithering_mode = asyc->dither.mode; - nv_connector->dithering_depth = asyc->dither.depth; - if (connector->encoder && connector->encoder->crtc) - nv_crtc = nouveau_crtc(connector->encoder->crtc); - if (!nv_crtc) - return 0; - - nv_crtc->vibrant_hue = asyc->procamp.vibrant_hue - 90; - nv_crtc->color_vibrance = asyc->procamp.color_vibrance - 100; - - ret = drm_crtc_helper_set_mode(&nv_crtc->base, &nv_crtc->base.mode, - nv_crtc->base.x, nv_crtc->base.y, NULL); - if (!ret) - return -EINVAL; + if (connector->encoder && connector->encoder->crtc) { + ret = drm_crtc_helper_set_mode(connector->encoder->crtc, + &connector->encoder->crtc->mode, + connector->encoder->crtc->x, + connector->encoder->crtc->y, + NULL); + if (!ret) + return -EINVAL; + } return 0; } @@ -1354,7 +1346,6 @@ nouveau_connector_create(struct drm_device *dev, int index) break; default: nv_connector->dithering_mode = DITHERING_MODE_AUTO; - nv_connector->dithering_depth = DITHERING_DEPTH_AUTO; break; } diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.h b/drivers/gpu/drm/nouveau/nouveau_connector.h index 77bb69ec..096983c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.h +++ b/drivers/gpu/drm/nouveau/nouveau_connector.h @@ -46,12 +46,7 @@ struct nouveau_connector { struct drm_dp_aux aux; int dithering_mode; - int dithering_depth; int scaling_mode; - bool scaling_full; - int underscan; - u32 underscan_hborder; - u32 underscan_vborder; struct nouveau_encoder *detected_encoder; struct edid *edid; diff --git a/drivers/gpu/drm/nouveau/nouveau_crtc.h b/drivers/gpu/drm/nouveau/nouveau_crtc.h index e4e3857..050fcf3 100644 --- a/drivers/gpu/drm/nouveau/nouveau_crtc.h +++ b/drivers/gpu/drm/nouveau/nouveau_crtc.h @@ -38,8 +38,6 @@ struct nouveau_crtc { uint32_t dpms_saved_fp_control; uint32_t fp_users; int saturation; - int color_vibrance; - int vibrant_hue; int sharpness; int last_dpms; diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index c605348..8d48ee4 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -2595,8 +2595,6 @@ nv50_crtc_create(struct drm_device *dev, int index) return -ENOMEM; head->base.index = index; - head->base.color_vibrance = 50; - head->base.vibrant_hue = 0; for (i = 0; i < 256; i++) { head->base.lut.r[i] = i << 8; head->base.lut.g[i] = i << 8; -- cgit v1.1 From e1ef6b42d9014079e5ab71acd8669d39808c3c73 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 4 Nov 2016 17:20:36 +1000 Subject: drm/nouveau/kms/nv50: remove code to support non-atomic page flips Made completely unreachable (and broken) by atomic commits. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_display.c | 62 ++++------ drivers/gpu/drm/nouveau/nouveau_fence.h | 2 - drivers/gpu/drm/nouveau/nv10_fence.c | 3 - drivers/gpu/drm/nouveau/nv10_fence.h | 1 - drivers/gpu/drm/nouveau/nv50_display.c | 198 +----------------------------- drivers/gpu/drm/nouveau/nv50_display.h | 7 -- drivers/gpu/drm/nouveau/nv50_fence.c | 20 +-- drivers/gpu/drm/nouveau/nv84_fence.c | 22 +--- 8 files changed, 27 insertions(+), 288 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 9e16deff..62d7530 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -835,10 +835,7 @@ nouveau_page_flip_emit(struct nouveau_channel *chan, if (ret) goto fail; - if (drm->device.info.family < NV_DEVICE_INFO_V0_FERMI) - BEGIN_NV04(chan, NvSubSw, NV_SW_PAGE_FLIP, 1); - else - BEGIN_NVC0(chan, FermiSw, NV_SW_PAGE_FLIP, 1); + BEGIN_NV04(chan, NvSubSw, NV_SW_PAGE_FLIP, 1); OUT_RING (chan, 0x00000000); FIRE_RING (chan); @@ -867,6 +864,8 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct nouveau_channel *chan; struct nouveau_cli *cli; struct nouveau_fence *fence; + struct nv04_display *dispnv04 = nv04_display(dev); + int head = nouveau_crtc(crtc)->index; int ret; chan = drm->channel; @@ -913,32 +912,23 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, drm_crtc_vblank_get(crtc); /* Emit a page flip */ - if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) { - ret = nv50_display_flip_next(crtc, fb, chan, swap_interval); + if (swap_interval) { + ret = RING_SPACE(chan, 8); if (ret) goto fail_unreserve; - } else { - struct nv04_display *dispnv04 = nv04_display(dev); - int head = nouveau_crtc(crtc)->index; - - if (swap_interval) { - ret = RING_SPACE(chan, 8); - if (ret) - goto fail_unreserve; - - BEGIN_NV04(chan, NvSubImageBlit, 0x012c, 1); - OUT_RING (chan, 0); - BEGIN_NV04(chan, NvSubImageBlit, 0x0134, 1); - OUT_RING (chan, head); - BEGIN_NV04(chan, NvSubImageBlit, 0x0100, 1); - OUT_RING (chan, 0); - BEGIN_NV04(chan, NvSubImageBlit, 0x0130, 1); - OUT_RING (chan, 0); - } - nouveau_bo_ref(new_bo, &dispnv04->image[head]); + BEGIN_NV04(chan, NvSubImageBlit, 0x012c, 1); + OUT_RING (chan, 0); + BEGIN_NV04(chan, NvSubImageBlit, 0x0134, 1); + OUT_RING (chan, head); + BEGIN_NV04(chan, NvSubImageBlit, 0x0100, 1); + OUT_RING (chan, 0); + BEGIN_NV04(chan, NvSubImageBlit, 0x0130, 1); + OUT_RING (chan, 0); } + nouveau_bo_ref(new_bo, &dispnv04->image[head]); + ret = nouveau_page_flip_emit(chan, old_bo, new_bo, s, &fence); if (ret) goto fail_unreserve; @@ -986,16 +976,8 @@ nouveau_finish_page_flip(struct nouveau_channel *chan, s = list_first_entry(&fctx->flip, struct nouveau_page_flip_state, head); if (s->event) { - if (drm->device.info.family < NV_DEVICE_INFO_V0_TESLA) { - drm_crtc_arm_vblank_event(s->crtc, s->event); - } else { - drm_crtc_send_vblank_event(s->crtc, s->event); - - /* Give up ownership of vblank for page-flipped crtc */ - drm_crtc_vblank_put(s->crtc); - } - } - else { + drm_crtc_arm_vblank_event(s->crtc, s->event); + } else { /* Give up ownership of vblank for page-flipped crtc */ drm_crtc_vblank_put(s->crtc); } @@ -1017,12 +999,10 @@ nouveau_flip_complete(struct nvif_notify *notify) struct nouveau_page_flip_state state; if (!nouveau_finish_page_flip(chan, &state)) { - if (drm->device.info.family < NV_DEVICE_INFO_V0_TESLA) { - nv_set_crtc_base(drm->dev, drm_crtc_index(state.crtc), - state.offset + state.crtc->y * - state.pitch + state.crtc->x * - state.bpp / 8); - } + nv_set_crtc_base(drm->dev, drm_crtc_index(state.crtc), + state.offset + state.crtc->y * + state.pitch + state.crtc->x * + state.bpp / 8); } return NVIF_NOTIFY_KEEP; diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.h b/drivers/gpu/drm/nouveau/nouveau_fence.h index 41f3c01..ccdce1b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.h +++ b/drivers/gpu/drm/nouveau/nouveau_fence.h @@ -92,7 +92,6 @@ struct nv84_fence_chan { struct nouveau_fence_chan base; struct nvkm_vma vma; struct nvkm_vma vma_gart; - struct nvkm_vma dispc_vma[4]; }; struct nv84_fence_priv { @@ -102,7 +101,6 @@ struct nv84_fence_priv { u32 *suspend; }; -u64 nv84_fence_crtc(struct nouveau_channel *, int); int nv84_fence_context_new(struct nouveau_channel *); #endif diff --git a/drivers/gpu/drm/nouveau/nv10_fence.c b/drivers/gpu/drm/nouveau/nv10_fence.c index bcf3a21..2998bde 100644 --- a/drivers/gpu/drm/nouveau/nv10_fence.c +++ b/drivers/gpu/drm/nouveau/nv10_fence.c @@ -57,10 +57,7 @@ void nv10_fence_context_del(struct nouveau_channel *chan) { struct nv10_fence_chan *fctx = chan->fence; - int i; nouveau_fence_context_del(&fctx->base); - for (i = 0; i < ARRAY_SIZE(fctx->head); i++) - nvif_object_fini(&fctx->head[i]); nvif_object_fini(&fctx->sema); chan->fence = NULL; nouveau_fence_context_free(&fctx->base); diff --git a/drivers/gpu/drm/nouveau/nv10_fence.h b/drivers/gpu/drm/nouveau/nv10_fence.h index a87259f..b7a5085 100644 --- a/drivers/gpu/drm/nouveau/nv10_fence.h +++ b/drivers/gpu/drm/nouveau/nv10_fence.h @@ -7,7 +7,6 @@ struct nv10_fence_chan { struct nouveau_fence_chan base; struct nvif_object sema; - struct nvif_object head[4]; }; struct nv10_fence_priv { diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 8d48ee4..4b195cc 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -658,11 +658,8 @@ nv50_ovly_create(struct nvif_device *device, struct nvif_object *disp, struct nv50_head { struct nouveau_crtc base; - struct nouveau_bo *image; struct nv50_ovly ovly; struct nv50_oimm oimm; - - struct nv50_base *_base; }; #define nv50_head(c) ((struct nv50_head *)nouveau_crtc(c)) @@ -740,40 +737,6 @@ evo_kick(u32 *push, void *evoc) *((p)++) = _d; \ } while(0) -static bool -evo_sync_wait(void *data) -{ - if (nouveau_bo_rd32(data, EVO_MAST_NTFY) != 0x00000000) - return true; - usleep_range(1, 2); - return false; -} - -static int -evo_sync(struct drm_device *dev) -{ - struct nvif_device *device = &nouveau_drm(dev)->device; - struct nv50_disp *disp = nv50_disp(dev); - struct nv50_mast *mast = nv50_mast(dev); - u32 *push = evo_wait(mast, 8); - if (push) { - nouveau_bo_wr32(disp->sync, EVO_MAST_NTFY, 0x00000000); - evo_mthd(push, 0x0084, 1); - evo_data(push, 0x80000000 | EVO_MAST_NTFY); - evo_mthd(push, 0x0080, 2); - evo_data(push, 0x00000000); - evo_data(push, 0x00000000); - evo_kick(push, mast); - if (nvif_msec(device, 2000, - if (evo_sync_wait(disp->sync)) - break; - ) >= 0) - return 0; - } - - return -EBUSY; -} - /****************************************************************************** * Plane *****************************************************************************/ @@ -789,8 +752,6 @@ struct nv50_wndw { u16 ntfy; u16 sema; u32 data; - - struct nv50_wndw_atom asy; }; struct nv50_wndw_func { @@ -1582,151 +1543,6 @@ nv50_base_new(struct nouveau_drm *drm, struct nv50_head *head, } /****************************************************************************** - * Page flipping channel - *****************************************************************************/ -struct nouveau_bo * -nv50_display_crtc_sema(struct drm_device *dev, int crtc) -{ - return nv50_disp(dev)->sync; -} - -struct nv50_display_flip { - struct nv50_disp *disp; - struct nv50_base *base; -}; - -static bool -nv50_display_flip_wait(void *data) -{ - struct nv50_display_flip *flip = data; - if (nouveau_bo_rd32(flip->disp->sync, flip->base->wndw.sema / 4) == - flip->base->wndw.data) - return true; - usleep_range(1, 2); - return false; -} - -void -nv50_display_flip_stop(struct drm_crtc *crtc) -{ - struct nvif_device *device = &nouveau_drm(crtc->dev)->device; - struct nv50_base *base = nv50_head(crtc)->_base; - struct nv50_wndw *wndw = &base->wndw; - struct nv50_wndw_atom *asyw = &wndw->asy; - struct nv50_display_flip flip = { - .disp = nv50_disp(crtc->dev), - .base = base, - }; - - asyw->state.crtc = NULL; - asyw->state.fb = NULL; - nv50_wndw_atomic_check(&wndw->plane, &asyw->state); - nv50_wndw_flush_clr(wndw, 0, true, asyw); - - nvif_msec(device, 2000, - if (nv50_display_flip_wait(&flip)) - break; - ); -} - -int -nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, - struct nouveau_channel *chan, u32 swap_interval) -{ - struct nouveau_framebuffer *nv_fb = nouveau_framebuffer(fb); - struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); - struct nv50_head *head = nv50_head(crtc); - struct nv50_base *base = nv50_head(crtc)->_base; - struct nv50_wndw *wndw = &base->wndw; - struct nv50_wndw_atom *asyw = &wndw->asy; - int ret; - - if (crtc->primary->fb->width != fb->width || - crtc->primary->fb->height != fb->height) - return -EINVAL; - - if (chan == NULL) - evo_sync(crtc->dev); - - if (chan && chan->user.oclass < G82_CHANNEL_GPFIFO) { - ret = RING_SPACE(chan, 8); - if (ret) - return ret; - - BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 2); - OUT_RING (chan, NvEvoSema0 + nv_crtc->index); - OUT_RING (chan, base->wndw.sema ^ 0x10); - BEGIN_NV04(chan, 0, NV11_SUBCHAN_SEMAPHORE_RELEASE, 1); - OUT_RING (chan, base->wndw.data + 1); - BEGIN_NV04(chan, 0, NV11_SUBCHAN_SEMAPHORE_OFFSET, 2); - OUT_RING (chan, base->wndw.sema); - OUT_RING (chan, base->wndw.data); - } else - if (chan && chan->user.oclass < FERMI_CHANNEL_GPFIFO) { - u64 addr = nv84_fence_crtc(chan, nv_crtc->index) + base->wndw.sema; - ret = RING_SPACE(chan, 12); - if (ret) - return ret; - - BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 1); - OUT_RING (chan, chan->vram.handle); - BEGIN_NV04(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4); - OUT_RING (chan, upper_32_bits(addr ^ 0x10)); - OUT_RING (chan, lower_32_bits(addr ^ 0x10)); - OUT_RING (chan, base->wndw.data + 1); - OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_WRITE_LONG); - BEGIN_NV04(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4); - OUT_RING (chan, upper_32_bits(addr)); - OUT_RING (chan, lower_32_bits(addr)); - OUT_RING (chan, base->wndw.data); - OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_EQUAL); - } else - if (chan) { - u64 addr = nv84_fence_crtc(chan, nv_crtc->index) + base->wndw.sema; - ret = RING_SPACE(chan, 10); - if (ret) - return ret; - - BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4); - OUT_RING (chan, upper_32_bits(addr ^ 0x10)); - OUT_RING (chan, lower_32_bits(addr ^ 0x10)); - OUT_RING (chan, base->wndw.data + 1); - OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_WRITE_LONG | - NVC0_SUBCHAN_SEMAPHORE_TRIGGER_YIELD); - BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4); - OUT_RING (chan, upper_32_bits(addr)); - OUT_RING (chan, lower_32_bits(addr)); - OUT_RING (chan, base->wndw.data); - OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_EQUAL | - NVC0_SUBCHAN_SEMAPHORE_TRIGGER_YIELD); - } - - if (chan) { - base->wndw.sema ^= 0x10; - base->wndw.data++; - FIRE_RING (chan); - } - - /* queue the flip */ - asyw->state.crtc = &head->base.base; - asyw->state.fb = fb; - asyw->interval = swap_interval; - asyw->image.handle = nv_fb->r_handle; - asyw->image.offset = nv_fb->nvbo->bo.offset; - asyw->sema.handle = base->chan.base.sync.handle; - asyw->sema.offset = base->wndw.sema; - asyw->sema.acquire = base->wndw.data++; - asyw->sema.release = base->wndw.data; - nv50_wndw_atomic_check(&wndw->plane, &asyw->state); - asyw->set.sema = true; - nv50_wndw_flush_set(wndw, 0, asyw); - nv50_wndw_wait_armed(wndw, asyw); - - nouveau_bo_ref(nv_fb->nvbo, &head->image); - return 0; -} - -/****************************************************************************** * Head *****************************************************************************/ static void @@ -2610,8 +2426,6 @@ nv50_crtc_create(struct drm_device *dev, int index) } crtc = &head->base.base; - head->_base = base; - drm_crtc_init_with_planes(dev, crtc, &base->wndw.plane, &curs->wndw.plane, &nv50_crtc_func, "head-%d", head->base.index); @@ -4061,7 +3875,6 @@ nv50_display_fini(struct drm_device *dev) int nv50_display_init(struct drm_device *dev) { - struct nv50_disp *disp = nv50_disp(dev); struct drm_encoder *encoder; struct drm_plane *plane; struct drm_crtc *crtc; @@ -4071,13 +3884,6 @@ nv50_display_init(struct drm_device *dev) if (!push) return -EBUSY; - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - struct nv50_wndw *wndw = &nv50_head(crtc)->_base->wndw; - - nv50_crtc_lut_load(crtc); - nouveau_bo_wr32(disp->sync, wndw->sema / 4, wndw->data); - } - evo_mthd(push, 0x0088, 1); evo_data(push, nv50_mast(dev)->base.sync.handle); evo_kick(push, nv50_mast(dev)); @@ -4094,6 +3900,10 @@ nv50_display_init(struct drm_device *dev) } } + drm_for_each_crtc(crtc, dev) { + nv50_crtc_lut_load(crtc); + } + drm_for_each_plane(plane, dev) { struct nv50_wndw *wndw = nv50_wndw(plane); if (plane->funcs != &nv50_wndw) diff --git a/drivers/gpu/drm/nouveau/nv50_display.h b/drivers/gpu/drm/nouveau/nv50_display.h index 70da347..918187c 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.h +++ b/drivers/gpu/drm/nouveau/nv50_display.h @@ -35,11 +35,4 @@ int nv50_display_create(struct drm_device *); void nv50_display_destroy(struct drm_device *); int nv50_display_init(struct drm_device *); void nv50_display_fini(struct drm_device *); - -void nv50_display_flip_stop(struct drm_crtc *); -int nv50_display_flip_next(struct drm_crtc *, struct drm_framebuffer *, - struct nouveau_channel *, u32 swap_interval); - -struct nouveau_bo *nv50_display_crtc_sema(struct drm_device *, int head); - #endif /* __NV50_DISPLAY_H__ */ diff --git a/drivers/gpu/drm/nouveau/nv50_fence.c b/drivers/gpu/drm/nouveau/nv50_fence.c index 8c52954..f68c705 100644 --- a/drivers/gpu/drm/nouveau/nv50_fence.c +++ b/drivers/gpu/drm/nouveau/nv50_fence.c @@ -35,13 +35,12 @@ static int nv50_fence_context_new(struct nouveau_channel *chan) { - struct drm_device *dev = chan->drm->dev; struct nv10_fence_priv *priv = chan->drm->fence; struct nv10_fence_chan *fctx; struct ttm_mem_reg *mem = &priv->bo->bo.mem; u32 start = mem->start * PAGE_SIZE; u32 limit = start + mem->size - 1; - int ret, i; + int ret; fctx = chan->fence = kzalloc(sizeof(*fctx), GFP_KERNEL); if (!fctx) @@ -60,23 +59,6 @@ nv50_fence_context_new(struct nouveau_channel *chan) .limit = limit, }, sizeof(struct nv_dma_v0), &fctx->sema); - - /* dma objects for display sync channel semaphore blocks */ - for (i = 0; !ret && i < dev->mode_config.num_crtc; i++) { - struct nouveau_bo *bo = nv50_display_crtc_sema(dev, i); - u32 start = bo->bo.mem.start * PAGE_SIZE; - u32 limit = start + bo->bo.mem.size - 1; - - ret = nvif_object_init(&chan->user, NvEvoSema0 + i, - NV_DMA_IN_MEMORY, &(struct nv_dma_v0) { - .target = NV_DMA_V0_TARGET_VRAM, - .access = NV_DMA_V0_ACCESS_RDWR, - .start = start, - .limit = limit, - }, sizeof(struct nv_dma_v0), - &fctx->head[i]); - } - if (ret) nv10_fence_context_del(chan); return ret; diff --git a/drivers/gpu/drm/nouveau/nv84_fence.c b/drivers/gpu/drm/nouveau/nv84_fence.c index 23ef04b..52b87ae 100644 --- a/drivers/gpu/drm/nouveau/nv84_fence.c +++ b/drivers/gpu/drm/nouveau/nv84_fence.c @@ -28,13 +28,6 @@ #include "nv50_display.h" -u64 -nv84_fence_crtc(struct nouveau_channel *chan, int crtc) -{ - struct nv84_fence_chan *fctx = chan->fence; - return fctx->dispc_vma[crtc].offset; -} - static int nv84_fence_emit32(struct nouveau_channel *chan, u64 virtual, u32 sequence) { @@ -110,15 +103,8 @@ nv84_fence_read(struct nouveau_channel *chan) static void nv84_fence_context_del(struct nouveau_channel *chan) { - struct drm_device *dev = chan->drm->dev; struct nv84_fence_priv *priv = chan->drm->fence; struct nv84_fence_chan *fctx = chan->fence; - int i; - - for (i = 0; i < dev->mode_config.num_crtc; i++) { - struct nouveau_bo *bo = nv50_display_crtc_sema(dev, i); - nouveau_bo_vma_del(bo, &fctx->dispc_vma[i]); - } nouveau_bo_wr32(priv->bo, chan->chid * 16 / 4, fctx->base.sequence); nouveau_bo_vma_del(priv->bo, &fctx->vma_gart); @@ -134,7 +120,7 @@ nv84_fence_context_new(struct nouveau_channel *chan) struct nouveau_cli *cli = (void *)chan->user.client; struct nv84_fence_priv *priv = chan->drm->fence; struct nv84_fence_chan *fctx; - int ret, i; + int ret; fctx = chan->fence = kzalloc(sizeof(*fctx), GFP_KERNEL); if (!fctx) @@ -154,12 +140,6 @@ nv84_fence_context_new(struct nouveau_channel *chan) &fctx->vma_gart); } - /* map display semaphore buffers into channel's vm */ - for (i = 0; !ret && i < chan->drm->dev->mode_config.num_crtc; i++) { - struct nouveau_bo *bo = nv50_display_crtc_sema(chan->drm->dev, i); - ret = nouveau_bo_vma_add(bo, cli->vm, &fctx->dispc_vma[i]); - } - if (ret) nv84_fence_context_del(chan); return ret; -- cgit v1.1 From f00f0e218b5d6347f28c0f2d80ee46c45b28f3c3 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 4 Nov 2016 17:20:36 +1000 Subject: drm/nouveau/kms/nv50: remove code to create ctxdma for every framebuffer This is now handled by prepare_fb(). Legacy flips were the last user. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_display.c | 19 ++------ drivers/gpu/drm/nouveau/nouveau_display.h | 3 -- drivers/gpu/drm/nouveau/nv50_display.c | 75 ++----------------------------- 3 files changed, 7 insertions(+), 90 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 62d7530..75c90a8 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -223,10 +223,6 @@ static void nouveau_user_framebuffer_destroy(struct drm_framebuffer *drm_fb) { struct nouveau_framebuffer *fb = nouveau_framebuffer(drm_fb); - struct nouveau_display *disp = nouveau_display(drm_fb->dev); - - if (disp->fb_dtor) - disp->fb_dtor(drm_fb); if (fb->nvbo) drm_gem_object_unreference_unlocked(&fb->nvbo->gem); @@ -256,27 +252,18 @@ nouveau_framebuffer_new(struct drm_device *dev, struct nouveau_bo *nvbo, struct nouveau_framebuffer **pfb) { - struct nouveau_display *disp = nouveau_display(dev); struct nouveau_framebuffer *fb; int ret; - if (!(fb = kzalloc(sizeof(*fb), GFP_KERNEL))) + if (!(fb = *pfb = kzalloc(sizeof(*fb), GFP_KERNEL))) return -ENOMEM; drm_helper_mode_fill_fb_struct(&fb->base, mode_cmd); fb->nvbo = nvbo; ret = drm_framebuffer_init(dev, &fb->base, &nouveau_framebuffer_funcs); - if (ret == 0) { - if (!disp->fb_ctor || !(ret = disp->fb_ctor(&fb->base))) { - *pfb = fb; - return 0; - } - disp->fb_dtor(&fb->base); - drm_framebuffer_cleanup(&fb->base); - } - - kfree(fb); + if (ret) + kfree(fb); return ret; } diff --git a/drivers/gpu/drm/nouveau/nouveau_display.h b/drivers/gpu/drm/nouveau/nouveau_display.h index ecdc0a3..330fe0f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.h +++ b/drivers/gpu/drm/nouveau/nouveau_display.h @@ -40,9 +40,6 @@ struct nouveau_display { int (*init)(struct drm_device *); void (*fini)(struct drm_device *); - int (*fb_ctor)(struct drm_framebuffer *); - void (*fb_dtor)(struct drm_framebuffer *); - struct nvif_object disp; struct drm_property *dithering_mode; diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 4b195cc..b47130e 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -418,12 +418,12 @@ nv50_dmac_ctxdma_del(struct nv50_dmac_ctxdma *ctxdma) } static struct nv50_dmac_ctxdma * -nv50_dmac_ctxdma_new(struct nv50_dmac *dmac, u32 handle, - struct nouveau_framebuffer *fb) +nv50_dmac_ctxdma_new(struct nv50_dmac *dmac, struct nouveau_framebuffer *fb) { struct nouveau_drm *drm = nouveau_drm(fb->base.dev); struct nv50_dmac_ctxdma *ctxdma; - const u8 kind = (fb->nvbo->tile_flags & 0x0000ff00) >> 8; + const u8 kind = (fb->nvbo->tile_flags & 0x0000ff00) >> 8; + const u32 handle = 0xfb000000 | kind; struct { struct nv_dma_v0 base; union { @@ -951,21 +951,17 @@ nv50_wndw_prepare_fb(struct drm_plane *plane, struct drm_plane_state *state) struct nv50_wndw_atom *asyw = nv50_wndw_atom(state); struct nv50_head_atom *asyh; struct nv50_dmac_ctxdma *ctxdma; - u32 name; - u8 kind; int ret; NV_ATOMIC(drm, "%s prepare: %p\n", plane->name, state->fb); if (!asyw->state.fb) return 0; - kind = (fb->nvbo->tile_flags & 0x0000ff00) >> 8; - name = 0xfb000000 | kind; ret = nouveau_bo_pin(fb->nvbo, TTM_PL_FLAG_VRAM, true); if (ret) return ret; - ctxdma = nv50_dmac_ctxdma_new(wndw->dmac, name, fb); + ctxdma = nv50_dmac_ctxdma_new(wndw->dmac, fb); if (IS_ERR(ctxdma)) { nouveau_bo_unpin(fb->nvbo); return PTR_ERR(ctxdma); @@ -3365,67 +3361,6 @@ nv50_pior_create(struct drm_connector *connector, struct dcb_output *dcbe) } /****************************************************************************** - * Framebuffer - *****************************************************************************/ - -static void -nv50_fb_dtor(struct drm_framebuffer *fb) -{ -} - -static int -nv50_fb_ctor(struct drm_framebuffer *fb) -{ - struct nouveau_framebuffer *nv_fb = nouveau_framebuffer(fb); - struct nouveau_drm *drm = nouveau_drm(fb->dev); - struct nouveau_bo *nvbo = nv_fb->nvbo; - struct nv50_disp *disp = nv50_disp(fb->dev); - u8 kind = nouveau_bo_tile_layout(nvbo) >> 8; - u8 tile = nvbo->tile_mode; - struct drm_crtc *crtc; - - if (drm->device.info.chipset >= 0xc0) - tile >>= 4; /* yep.. */ - - switch (fb->depth) { - case 8: nv_fb->r_format = 0x1e00; break; - case 15: nv_fb->r_format = 0xe900; break; - case 16: nv_fb->r_format = 0xe800; break; - case 24: - case 32: nv_fb->r_format = 0xcf00; break; - case 30: nv_fb->r_format = 0xd100; break; - default: - NV_ERROR(drm, "unknown depth %d\n", fb->depth); - return -EINVAL; - } - - if (disp->disp->oclass < G82_DISP) { - nv_fb->r_pitch = kind ? (((fb->pitches[0] / 4) << 4) | tile) : - (fb->pitches[0] | 0x00100000); - nv_fb->r_format |= kind << 16; - } else - if (disp->disp->oclass < GF110_DISP) { - nv_fb->r_pitch = kind ? (((fb->pitches[0] / 4) << 4) | tile) : - (fb->pitches[0] | 0x00100000); - } else { - nv_fb->r_pitch = kind ? (((fb->pitches[0] / 4) << 4) | tile) : - (fb->pitches[0] | 0x01000000); - } - nv_fb->r_handle = 0xffff0000 | kind; - - list_for_each_entry(crtc, &drm->dev->mode_config.crtc_list, head) { - struct nv50_wndw *wndw = nv50_wndw(crtc->primary); - struct nv50_dmac_ctxdma *ctxdma; - - ctxdma = nv50_dmac_ctxdma_new(wndw->dmac, nv_fb->r_handle, nv_fb); - if (IS_ERR(ctxdma)) - return PTR_ERR(ctxdma); - } - - return 0; -} - -/****************************************************************************** * Atomic *****************************************************************************/ @@ -3955,8 +3890,6 @@ nv50_display_create(struct drm_device *dev) nouveau_display(dev)->dtor = nv50_display_destroy; nouveau_display(dev)->init = nv50_display_init; nouveau_display(dev)->fini = nv50_display_fini; - nouveau_display(dev)->fb_ctor = nv50_fb_ctor; - nouveau_display(dev)->fb_dtor = nv50_fb_dtor; disp->disp = &nouveau_display(dev)->disp; dev->mode_config.funcs = &nv50_disp_func; if (nouveau_atomic) -- cgit v1.1 From 9bfdee9a08bbe550598fc4098c85470c63b46ff6 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 4 Nov 2016 17:20:36 +1000 Subject: drm/nouveau/kms/nv50: rename remaining nv50_crtc to nv50_head No code changes, just renames + shuffles. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_display.c | 113 ++++++++++++++++----------------- 1 file changed, 55 insertions(+), 58 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index b47130e..45379f90 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -2175,21 +2175,8 @@ nv50_head_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state) return 0; } -/****************************************************************************** - * CRTC - *****************************************************************************/ - -static int -nv50_crtc_mode_set_base_atomic(struct drm_crtc *crtc, - struct drm_framebuffer *fb, int x, int y, - enum mode_set_atomic state) -{ - WARN_ON(1); - return 0; -} - static void -nv50_crtc_lut_load(struct drm_crtc *crtc) +nv50_head_lut_load(struct drm_crtc *crtc) { struct nv50_disp *disp = nv50_disp(crtc->dev); struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); @@ -2214,45 +2201,18 @@ nv50_crtc_lut_load(struct drm_crtc *crtc) } static int -nv50_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, - uint32_t size) +nv50_head_mode_set_base_atomic(struct drm_crtc *crtc, + struct drm_framebuffer *fb, int x, int y, + enum mode_set_atomic state) { - struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); - u32 i; - - for (i = 0; i < size; i++) { - nv_crtc->lut.r[i] = r[i]; - nv_crtc->lut.g[i] = g[i]; - nv_crtc->lut.b[i] = b[i]; - } - - nv50_crtc_lut_load(crtc); - + WARN_ON(1); return 0; } -static void -nv50_crtc_destroy(struct drm_crtc *crtc) -{ - struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); - struct nv50_disp *disp = nv50_disp(crtc->dev); - struct nv50_head *head = nv50_head(crtc); - - nv50_dmac_destroy(&head->ovly.base, disp->disp); - nv50_pioc_destroy(&head->oimm.base); - - nouveau_bo_unmap(nv_crtc->lut.nvbo); - if (nv_crtc->lut.nvbo) - nouveau_bo_unpin(nv_crtc->lut.nvbo); - nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo); - - drm_crtc_cleanup(crtc); - kfree(crtc); -} - -static const struct drm_crtc_helper_funcs nv50_crtc_hfunc = { - .mode_set_base_atomic = nv50_crtc_mode_set_base_atomic, - .load_lut = nv50_crtc_lut_load, +static const struct drm_crtc_helper_funcs +nv50_head_help = { + .mode_set_base_atomic = nv50_head_mode_set_base_atomic, + .load_lut = nv50_head_lut_load, .atomic_check = nv50_head_atomic_check, }; @@ -2327,6 +2287,23 @@ backoff: goto retry; } +static int +nv50_head_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, + uint32_t size) +{ + struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); + u32 i; + + for (i = 0; i < size; i++) { + nv_crtc->lut.r[i] = r[i]; + nv_crtc->lut.g[i] = g[i]; + nv_crtc->lut.b[i] = b[i]; + } + + nv50_head_lut_load(crtc); + return 0; +} + static void nv50_head_atomic_destroy_state(struct drm_crtc *crtc, struct drm_crtc_state *state) @@ -2379,10 +2356,30 @@ nv50_head_reset(struct drm_crtc *crtc) __drm_atomic_helper_crtc_reset(crtc, &asyh->state); } -static const struct drm_crtc_funcs nv50_crtc_func = { +static void +nv50_head_destroy(struct drm_crtc *crtc) +{ + struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); + struct nv50_disp *disp = nv50_disp(crtc->dev); + struct nv50_head *head = nv50_head(crtc); + + nv50_dmac_destroy(&head->ovly.base, disp->disp); + nv50_pioc_destroy(&head->oimm.base); + + nouveau_bo_unmap(nv_crtc->lut.nvbo); + if (nv_crtc->lut.nvbo) + nouveau_bo_unpin(nv_crtc->lut.nvbo); + nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo); + + drm_crtc_cleanup(crtc); + kfree(crtc); +} + +static const struct drm_crtc_funcs +nv50_head_func = { .reset = nv50_head_reset, - .gamma_set = nv50_crtc_gamma_set, - .destroy = nv50_crtc_destroy, + .gamma_set = nv50_head_gamma_set, + .destroy = nv50_head_destroy, .set_config = drm_atomic_helper_set_config, .page_flip = nv50_head_page_flip, .set_property = drm_atomic_helper_crtc_set_property, @@ -2391,7 +2388,7 @@ static const struct drm_crtc_funcs nv50_crtc_func = { }; static int -nv50_crtc_create(struct drm_device *dev, int index) +nv50_head_create(struct drm_device *dev, int index) { struct nouveau_drm *drm = nouveau_drm(dev); struct nvif_device *device = &drm->device; @@ -2423,9 +2420,9 @@ nv50_crtc_create(struct drm_device *dev, int index) crtc = &head->base.base; drm_crtc_init_with_planes(dev, crtc, &base->wndw.plane, - &curs->wndw.plane, &nv50_crtc_func, + &curs->wndw.plane, &nv50_head_func, "head-%d", head->base.index); - drm_crtc_helper_add(crtc, &nv50_crtc_hfunc); + drm_crtc_helper_add(crtc, &nv50_head_help); drm_mode_crtc_set_gamma_size(crtc, 256); ret = nouveau_bo_new(dev, 8192, 0x100, TTM_PL_FLAG_VRAM, @@ -2456,7 +2453,7 @@ nv50_crtc_create(struct drm_device *dev, int index) out: if (ret) - nv50_crtc_destroy(crtc); + nv50_head_destroy(crtc); return ret; } @@ -3836,7 +3833,7 @@ nv50_display_init(struct drm_device *dev) } drm_for_each_crtc(crtc, dev) { - nv50_crtc_lut_load(crtc); + nv50_head_lut_load(crtc); } drm_for_each_plane(plane, dev) { @@ -3925,7 +3922,7 @@ nv50_display_create(struct drm_device *dev) crtcs = 2; for (i = 0; i < crtcs; i++) { - ret = nv50_crtc_create(dev, i); + ret = nv50_head_create(dev, i); if (ret) goto out; } -- cgit v1.1 From d665c7e91458e19f413ea89d99d89f4743be95e3 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 4 Nov 2016 17:20:36 +1000 Subject: drm/nouveau/kms/nv50: allow encoder update to be called from other modules MST encoders will make use of this to share code with SOR> Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_encoder.h | 2 + drivers/gpu/drm/nouveau/nv50_display.c | 86 +++++++++++++++---------------- 2 files changed, 44 insertions(+), 44 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_encoder.h b/drivers/gpu/drm/nouveau/nouveau_encoder.h index 2cd4a2d..848982b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_encoder.h +++ b/drivers/gpu/drm/nouveau/nouveau_encoder.h @@ -66,6 +66,8 @@ struct nouveau_encoder { void (*enc_save)(struct drm_encoder *encoder); void (*enc_restore)(struct drm_encoder *encoder); + void (*update)(struct nouveau_encoder *, u8 head, + struct drm_display_mode *, u8 proto, u8 depth); }; struct nouveau_encoder * diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 45379f90..854fa31 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -2926,19 +2926,50 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode) } static void -nv50_sor_ctrl(struct nouveau_encoder *nv_encoder, u32 mask, u32 data) +nv50_sor_update(struct nouveau_encoder *nv_encoder, u8 head, + struct drm_display_mode *mode, u8 proto, u8 depth) { - struct nv50_mast *mast = nv50_mast(nv_encoder->base.base.dev); - u32 temp = (nv_encoder->ctrl & ~mask) | (data & mask), *push; - if (temp != nv_encoder->ctrl && (push = evo_wait(mast, 2))) { - if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) { + struct nv50_dmac *core = &nv50_mast(nv_encoder->base.base.dev)->base; + u32 *push; + + if (!mode) { + nv_encoder->ctrl &= ~BIT(head); + if (!(nv_encoder->ctrl & 0x0000000f)) + nv_encoder->ctrl = 0; + } else { + nv_encoder->ctrl |= proto << 8; + nv_encoder->ctrl |= BIT(head); + } + + if ((push = evo_wait(core, 6))) { + if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA) { + if (mode) { + if (mode->flags & DRM_MODE_FLAG_NHSYNC) + nv_encoder->ctrl |= 0x00001000; + if (mode->flags & DRM_MODE_FLAG_NVSYNC) + nv_encoder->ctrl |= 0x00002000; + nv_encoder->ctrl |= depth << 16; + } evo_mthd(push, 0x0600 + (nv_encoder->or * 0x40), 1); - evo_data(push, (nv_encoder->ctrl = temp)); } else { + if (mode) { + u32 magic = 0x31ec6000 | (head << 25); + u32 syncs = 0x00000001; + if (mode->flags & DRM_MODE_FLAG_NHSYNC) + syncs |= 0x00000008; + if (mode->flags & DRM_MODE_FLAG_NVSYNC) + syncs |= 0x00000010; + if (mode->flags & DRM_MODE_FLAG_INTERLACE) + magic |= 0x00000001; + + evo_mthd(push, 0x0404 + (head * 0x300), 2); + evo_data(push, syncs | (depth << 6)); + evo_data(push, magic); + } evo_mthd(push, 0x0200 + (nv_encoder->or * 0x20), 1); - evo_data(push, (nv_encoder->ctrl = temp)); } - evo_kick(push, mast); + evo_data(push, nv_encoder->ctrl); + evo_kick(push, core); } } @@ -2963,7 +2994,7 @@ nv50_sor_disable(struct drm_encoder *encoder) } } - nv50_sor_ctrl(nv_encoder, 1 << nv_crtc->index, 0); + nv_encoder->update(nv_encoder, nv_crtc->index, NULL, 0, 0); nv50_audio_disable(encoder, nv_crtc); nv50_hdmi_disable(&nv_encoder->base.base, nv_crtc); } @@ -2985,13 +3016,10 @@ nv50_sor_enable(struct drm_encoder *encoder) .base.hashm = nv_encoder->dcb->hashm, }; struct nv50_disp *disp = nv50_disp(encoder->dev); - struct nv50_mast *mast = nv50_mast(encoder->dev); struct drm_device *dev = encoder->dev; struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_connector *nv_connector; struct nvbios *bios = &drm->vbios; - u32 mask, ctrl; - u8 owner = 1 << nv_crtc->index; u8 proto = 0xf; u8 depth = 0x0; @@ -3070,38 +3098,7 @@ nv50_sor_enable(struct drm_encoder *encoder) break; } - if (nv50_vers(mast) >= GF110_DISP) { - u32 *push = evo_wait(mast, 3); - if (push) { - u32 magic = 0x31ec6000 | (nv_crtc->index << 25); - u32 syncs = 0x00000001; - - if (mode->flags & DRM_MODE_FLAG_NHSYNC) - syncs |= 0x00000008; - if (mode->flags & DRM_MODE_FLAG_NVSYNC) - syncs |= 0x00000010; - - if (mode->flags & DRM_MODE_FLAG_INTERLACE) - magic |= 0x00000001; - - evo_mthd(push, 0x0404 + (nv_crtc->index * 0x300), 2); - evo_data(push, syncs | (depth << 6)); - evo_data(push, magic); - evo_kick(push, mast); - } - - ctrl = proto << 8; - mask = 0x00000f00; - } else { - ctrl = (depth << 16) | (proto << 8); - if (mode->flags & DRM_MODE_FLAG_NHSYNC) - ctrl |= 0x00001000; - if (mode->flags & DRM_MODE_FLAG_NVSYNC) - ctrl |= 0x00002000; - mask = 0x000f3f00; - } - - nv50_sor_ctrl(nv_encoder, mask | owner, ctrl | owner); + nv_encoder->update(nv_encoder, nv_crtc->index, mode, proto, depth); } static const struct drm_encoder_helper_funcs @@ -3150,6 +3147,7 @@ nv50_sor_create(struct drm_connector *connector, struct dcb_output *dcbe) return -ENOMEM; nv_encoder->dcb = dcbe; nv_encoder->or = ffs(dcbe->or) - 1; + nv_encoder->update = nv50_sor_update; encoder = to_drm_encoder(nv_encoder); encoder->possible_crtcs = dcbe->heads; -- cgit v1.1 From f479c0ba4a170aa65cafcfa5c8a4e1d5c35181f2 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 4 Nov 2016 17:20:36 +1000 Subject: drm/nouveau/kms/nv50: initial support for DP 1.2 multi-stream Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_connector.c | 9 + drivers/gpu/drm/nouveau/nouveau_dp.c | 8 +- drivers/gpu/drm/nouveau/nouveau_encoder.h | 2 + drivers/gpu/drm/nouveau/nv50_display.c | 554 +++++++++++++++++++++++++++- 4 files changed, 571 insertions(+), 2 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 5df3908..947c200 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -1118,12 +1118,21 @@ nouveau_connector_hotplug(struct nvif_notify *notify) struct nouveau_drm *drm = nouveau_drm(connector->dev); const struct nvif_notify_conn_rep_v0 *rep = notify->data; const char *name = connector->name; + struct nouveau_encoder *nv_encoder; if (rep->mask & NVIF_NOTIFY_CONN_V0_IRQ) { + NV_DEBUG(drm, "service %s\n", name); + if ((nv_encoder = find_encoder(connector, DCB_OUTPUT_DP))) + nv50_mstm_service(nv_encoder->dp.mstm); } else { bool plugged = (rep->mask != NVIF_NOTIFY_CONN_V0_UNPLUG); NV_DEBUG(drm, "%splugged %s\n", plugged ? "" : "un", name); + if ((nv_encoder = find_encoder(connector, DCB_OUTPUT_DP))) { + if (!plugged) + nv50_mstm_remove(nv_encoder->dp.mstm); + } + drm_helper_hpd_irq_event(connector->dev); } diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c index ddffb5cd..0d052e1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dp.c +++ b/drivers/gpu/drm/nouveau/nouveau_dp.c @@ -33,6 +33,10 @@ #include #include +MODULE_PARM_DESC(mst, "Enable DisplayPort multi-stream (default: enabled)"); +static int nouveau_mst = 1; +module_param_named(mst, nouveau_mst, int, 0400); + static void nouveau_dp_probe_oui(struct drm_device *dev, struct nvkm_i2c_aux *aux, u8 *dpcd) { @@ -88,7 +92,9 @@ nouveau_dp_detect(struct nouveau_encoder *nv_encoder) nouveau_dp_probe_oui(dev, aux, dpcd); - ret = nv50_mstm_detect(nv_encoder->dp.mstm, dpcd, 0); + ret = nv50_mstm_detect(nv_encoder->dp.mstm, dpcd, nouveau_mst); + if (ret == 1) + return NOUVEAU_DP_MST; if (ret == 0) return NOUVEAU_DP_SST; return ret; diff --git a/drivers/gpu/drm/nouveau/nouveau_encoder.h b/drivers/gpu/drm/nouveau/nouveau_encoder.h index 848982b..198e5f2 100644 --- a/drivers/gpu/drm/nouveau/nouveau_encoder.h +++ b/drivers/gpu/drm/nouveau/nouveau_encoder.h @@ -103,4 +103,6 @@ struct nouveau_connector * nouveau_encoder_connector_get(struct nouveau_encoder *encoder); int nv50_mstm_detect(struct nv50_mstm *, u8 dpcd[8], int allow); +void nv50_mstm_remove(struct nv50_mstm *); +void nv50_mstm_service(struct nv50_mstm *); #endif /* __NOUVEAU_ENCODER_H__ */ diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 854fa31..a9855a4 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -2804,12 +2804,502 @@ nv50_hdmi_enable(struct drm_encoder *encoder, struct drm_display_mode *mode) /****************************************************************************** * MST *****************************************************************************/ +#define nv50_mstm(p) container_of((p), struct nv50_mstm, mgr) +#define nv50_mstc(p) container_of((p), struct nv50_mstc, connector) +#define nv50_msto(p) container_of((p), struct nv50_msto, encoder) + struct nv50_mstm { struct nouveau_encoder *outp; struct drm_dp_mst_topology_mgr mgr; + struct nv50_msto *msto[4]; + + bool modified; +}; + +struct nv50_mstc { + struct nv50_mstm *mstm; + struct drm_dp_mst_port *port; + struct drm_connector connector; + + struct drm_display_mode *native; + struct edid *edid; + + int pbn; }; +struct nv50_msto { + struct drm_encoder encoder; + + struct nv50_head *head; + struct nv50_mstc *mstc; + bool disabled; +}; + +static struct drm_dp_payload * +nv50_msto_payload(struct nv50_msto *msto) +{ + struct nouveau_drm *drm = nouveau_drm(msto->encoder.dev); + struct nv50_mstc *mstc = msto->mstc; + struct nv50_mstm *mstm = mstc->mstm; + int vcpi = mstc->port->vcpi.vcpi, i; + + NV_ATOMIC(drm, "%s: vcpi %d\n", msto->encoder.name, vcpi); + for (i = 0; i < mstm->mgr.max_payloads; i++) { + struct drm_dp_payload *payload = &mstm->mgr.payloads[i]; + NV_ATOMIC(drm, "%s: %d: vcpi %d start 0x%02x slots 0x%02x\n", + mstm->outp->base.base.name, i, payload->vcpi, + payload->start_slot, payload->num_slots); + } + + for (i = 0; i < mstm->mgr.max_payloads; i++) { + struct drm_dp_payload *payload = &mstm->mgr.payloads[i]; + if (payload->vcpi == vcpi) + return payload; + } + + return NULL; +} + +static void +nv50_msto_cleanup(struct nv50_msto *msto) +{ + struct nouveau_drm *drm = nouveau_drm(msto->encoder.dev); + struct nv50_mstc *mstc = msto->mstc; + struct nv50_mstm *mstm = mstc->mstm; + + NV_ATOMIC(drm, "%s: msto cleanup\n", msto->encoder.name); + if (mstc->port && mstc->port->vcpi.vcpi > 0 && !nv50_msto_payload(msto)) + drm_dp_mst_deallocate_vcpi(&mstm->mgr, mstc->port); + if (msto->disabled) { + msto->mstc = NULL; + msto->head = NULL; + msto->disabled = false; + } +} + +static void +nv50_msto_prepare(struct nv50_msto *msto) +{ + struct nouveau_drm *drm = nouveau_drm(msto->encoder.dev); + struct nv50_mstc *mstc = msto->mstc; + struct nv50_mstm *mstm = mstc->mstm; + struct { + struct nv50_disp_mthd_v1 base; + struct nv50_disp_sor_dp_mst_vcpi_v0 vcpi; + } args = { + .base.version = 1, + .base.method = NV50_DISP_MTHD_V1_SOR_DP_MST_VCPI, + .base.hasht = mstm->outp->dcb->hasht, + .base.hashm = (0xf0ff & mstm->outp->dcb->hashm) | + (0x0100 << msto->head->base.index), + }; + + NV_ATOMIC(drm, "%s: msto prepare\n", msto->encoder.name); + if (mstc->port && mstc->port->vcpi.vcpi > 0) { + struct drm_dp_payload *payload = nv50_msto_payload(msto); + if (payload) { + args.vcpi.start_slot = payload->start_slot; + args.vcpi.num_slots = payload->num_slots; + args.vcpi.pbn = mstc->port->vcpi.pbn; + args.vcpi.aligned_pbn = mstc->port->vcpi.aligned_pbn; + } + } + + NV_ATOMIC(drm, "%s: %s: %02x %02x %04x %04x\n", + msto->encoder.name, msto->head->base.base.name, + args.vcpi.start_slot, args.vcpi.num_slots, + args.vcpi.pbn, args.vcpi.aligned_pbn); + nvif_mthd(&drm->display->disp, 0, &args, sizeof(args)); +} + +static int +nv50_msto_atomic_check(struct drm_encoder *encoder, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + struct nv50_mstc *mstc = nv50_mstc(conn_state->connector); + struct nv50_mstm *mstm = mstc->mstm; + int bpp = conn_state->connector->display_info.bpc * 3; + int slots; + + mstc->pbn = drm_dp_calc_pbn_mode(crtc_state->adjusted_mode.clock, bpp); + + slots = drm_dp_find_vcpi_slots(&mstm->mgr, mstc->pbn); + if (slots < 0) + return slots; + + return nv50_outp_atomic_check_view(encoder, crtc_state, conn_state, + mstc->native); +} + +static void +nv50_msto_enable(struct drm_encoder *encoder) +{ + struct nv50_head *head = nv50_head(encoder->crtc); + struct nv50_msto *msto = nv50_msto(encoder); + struct nv50_mstc *mstc = NULL; + struct nv50_mstm *mstm = NULL; + struct drm_connector *connector; + u8 proto, depth; + int slots; + bool r; + + drm_for_each_connector(connector, encoder->dev) { + if (connector->state->best_encoder == &msto->encoder) { + mstc = nv50_mstc(connector); + mstm = mstc->mstm; + break; + } + } + + if (WARN_ON(!mstc)) + return; + + r = drm_dp_mst_allocate_vcpi(&mstm->mgr, mstc->port, mstc->pbn, &slots); + WARN_ON(!r); + + if (mstm->outp->dcb->sorconf.link & 1) + proto = 0x8; + else + proto = 0x9; + + switch (mstc->connector.display_info.bpc) { + case 6: depth = 0x2; break; + case 8: depth = 0x5; break; + case 10: + default: depth = 0x6; break; + } + + mstm->outp->update(mstm->outp, head->base.index, + &head->base.base.state->adjusted_mode, proto, depth); + + msto->head = head; + msto->mstc = mstc; + mstm->modified = true; +} + +static void +nv50_msto_disable(struct drm_encoder *encoder) +{ + struct nv50_msto *msto = nv50_msto(encoder); + struct nv50_mstc *mstc = msto->mstc; + struct nv50_mstm *mstm = mstc->mstm; + + if (mstc->port) + drm_dp_mst_reset_vcpi_slots(&mstm->mgr, mstc->port); + + mstm->outp->update(mstm->outp, msto->head->base.index, NULL, 0, 0); + mstm->modified = true; + msto->disabled = true; +} + +static const struct drm_encoder_helper_funcs +nv50_msto_help = { + .disable = nv50_msto_disable, + .enable = nv50_msto_enable, + .atomic_check = nv50_msto_atomic_check, +}; + +static void +nv50_msto_destroy(struct drm_encoder *encoder) +{ + struct nv50_msto *msto = nv50_msto(encoder); + drm_encoder_cleanup(&msto->encoder); + kfree(msto); +} + +static const struct drm_encoder_funcs +nv50_msto = { + .destroy = nv50_msto_destroy, +}; + +static int +nv50_msto_new(struct drm_device *dev, u32 heads, const char *name, int id, + struct nv50_msto **pmsto) +{ + struct nv50_msto *msto; + int ret; + + if (!(msto = *pmsto = kzalloc(sizeof(*msto), GFP_KERNEL))) + return -ENOMEM; + + ret = drm_encoder_init(dev, &msto->encoder, &nv50_msto, + DRM_MODE_ENCODER_DPMST, "%s-mst-%d", name, id); + if (ret) { + kfree(*pmsto); + *pmsto = NULL; + return ret; + } + + drm_encoder_helper_add(&msto->encoder, &nv50_msto_help); + msto->encoder.possible_crtcs = heads; + return 0; +} + +static struct drm_encoder * +nv50_mstc_atomic_best_encoder(struct drm_connector *connector, + struct drm_connector_state *connector_state) +{ + struct nv50_head *head = nv50_head(connector_state->crtc); + struct nv50_mstc *mstc = nv50_mstc(connector); + if (mstc->port) { + struct nv50_mstm *mstm = mstc->mstm; + return &mstm->msto[head->base.index]->encoder; + } + return NULL; +} + +static struct drm_encoder * +nv50_mstc_best_encoder(struct drm_connector *connector) +{ + struct nv50_mstc *mstc = nv50_mstc(connector); + if (mstc->port) { + struct nv50_mstm *mstm = mstc->mstm; + return &mstm->msto[0]->encoder; + } + return NULL; +} + +static enum drm_mode_status +nv50_mstc_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + return MODE_OK; +} + +static int +nv50_mstc_get_modes(struct drm_connector *connector) +{ + struct nv50_mstc *mstc = nv50_mstc(connector); + int ret = 0; + + mstc->edid = drm_dp_mst_get_edid(&mstc->connector, mstc->port->mgr, mstc->port); + drm_mode_connector_update_edid_property(&mstc->connector, mstc->edid); + if (mstc->edid) { + ret = drm_add_edid_modes(&mstc->connector, mstc->edid); + drm_edid_to_eld(&mstc->connector, mstc->edid); + } + + if (!mstc->connector.display_info.bpc) + mstc->connector.display_info.bpc = 8; + + if (mstc->native) + drm_mode_destroy(mstc->connector.dev, mstc->native); + mstc->native = nouveau_conn_native_mode(&mstc->connector); + return ret; +} + +static const struct drm_connector_helper_funcs +nv50_mstc_help = { + .get_modes = nv50_mstc_get_modes, + .mode_valid = nv50_mstc_mode_valid, + .best_encoder = nv50_mstc_best_encoder, + .atomic_best_encoder = nv50_mstc_atomic_best_encoder, +}; + +static enum drm_connector_status +nv50_mstc_detect(struct drm_connector *connector, bool force) +{ + struct nv50_mstc *mstc = nv50_mstc(connector); + if (!mstc->port) + return connector_status_disconnected; + return drm_dp_mst_detect_port(connector, mstc->port->mgr, mstc->port); +} + +static void +nv50_mstc_destroy(struct drm_connector *connector) +{ + struct nv50_mstc *mstc = nv50_mstc(connector); + drm_connector_cleanup(&mstc->connector); + kfree(mstc); +} + +static const struct drm_connector_funcs +nv50_mstc = { + .dpms = drm_atomic_helper_connector_dpms, + .reset = nouveau_conn_reset, + .detect = nv50_mstc_detect, + .fill_modes = drm_helper_probe_single_connector_modes, + .set_property = drm_atomic_helper_connector_set_property, + .destroy = nv50_mstc_destroy, + .atomic_duplicate_state = nouveau_conn_atomic_duplicate_state, + .atomic_destroy_state = nouveau_conn_atomic_destroy_state, + .atomic_set_property = nouveau_conn_atomic_set_property, + .atomic_get_property = nouveau_conn_atomic_get_property, +}; + +static int +nv50_mstc_new(struct nv50_mstm *mstm, struct drm_dp_mst_port *port, + const char *path, struct nv50_mstc **pmstc) +{ + struct drm_device *dev = mstm->outp->base.base.dev; + struct nv50_mstc *mstc; + int ret, i; + + if (!(mstc = *pmstc = kzalloc(sizeof(*mstc), GFP_KERNEL))) + return -ENOMEM; + mstc->mstm = mstm; + mstc->port = port; + + ret = drm_connector_init(dev, &mstc->connector, &nv50_mstc, + DRM_MODE_CONNECTOR_DisplayPort); + if (ret) { + kfree(*pmstc); + *pmstc = NULL; + return ret; + } + + drm_connector_helper_add(&mstc->connector, &nv50_mstc_help); + + mstc->connector.funcs->reset(&mstc->connector); + nouveau_conn_attach_properties(&mstc->connector); + + for (i = 0; i < ARRAY_SIZE(mstm->msto) && mstm->msto; i++) + drm_mode_connector_attach_encoder(&mstc->connector, &mstm->msto[i]->encoder); + + drm_object_attach_property(&mstc->connector.base, dev->mode_config.path_property, 0); + drm_object_attach_property(&mstc->connector.base, dev->mode_config.tile_property, 0); + drm_mode_connector_set_path_property(&mstc->connector, path); + return 0; +} + +static void +nv50_mstm_cleanup(struct nv50_mstm *mstm) +{ + struct nouveau_drm *drm = nouveau_drm(mstm->outp->base.base.dev); + struct drm_encoder *encoder; + int ret; + + NV_ATOMIC(drm, "%s: mstm cleanup\n", mstm->outp->base.base.name); + ret = drm_dp_check_act_status(&mstm->mgr); + + ret = drm_dp_update_payload_part2(&mstm->mgr); + + drm_for_each_encoder(encoder, mstm->outp->base.base.dev) { + if (encoder->encoder_type == DRM_MODE_ENCODER_DPMST) { + struct nv50_msto *msto = nv50_msto(encoder); + struct nv50_mstc *mstc = msto->mstc; + if (mstc && mstc->mstm == mstm) + nv50_msto_cleanup(msto); + } + } + + mstm->modified = false; +} + +static void +nv50_mstm_prepare(struct nv50_mstm *mstm) +{ + struct nouveau_drm *drm = nouveau_drm(mstm->outp->base.base.dev); + struct drm_encoder *encoder; + int ret; + + NV_ATOMIC(drm, "%s: mstm prepare\n", mstm->outp->base.base.name); + ret = drm_dp_update_payload_part1(&mstm->mgr); + + drm_for_each_encoder(encoder, mstm->outp->base.base.dev) { + if (encoder->encoder_type == DRM_MODE_ENCODER_DPMST) { + struct nv50_msto *msto = nv50_msto(encoder); + struct nv50_mstc *mstc = msto->mstc; + if (mstc && mstc->mstm == mstm) + nv50_msto_prepare(msto); + } + } +} + +static void +nv50_mstm_hotplug(struct drm_dp_mst_topology_mgr *mgr) +{ + struct nv50_mstm *mstm = nv50_mstm(mgr); + drm_kms_helper_hotplug_event(mstm->outp->base.base.dev); +} + +static void +nv50_mstm_destroy_connector(struct drm_dp_mst_topology_mgr *mgr, + struct drm_connector *connector) +{ + struct nouveau_drm *drm = nouveau_drm(connector->dev); + struct nv50_mstc *mstc = nv50_mstc(connector); + + drm_connector_unregister(&mstc->connector); + + drm_modeset_lock_all(drm->dev); + drm_fb_helper_remove_one_connector(&drm->fbcon->helper, &mstc->connector); + mstc->port = NULL; + drm_modeset_unlock_all(drm->dev); + + drm_connector_unreference(&mstc->connector); +} + +static void +nv50_mstm_register_connector(struct drm_connector *connector) +{ + struct nouveau_drm *drm = nouveau_drm(connector->dev); + + drm_modeset_lock_all(drm->dev); + drm_fb_helper_add_one_connector(&drm->fbcon->helper, connector); + drm_modeset_unlock_all(drm->dev); + + drm_connector_register(connector); +} + +static struct drm_connector * +nv50_mstm_add_connector(struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_port *port, const char *path) +{ + struct nv50_mstm *mstm = nv50_mstm(mgr); + struct nv50_mstc *mstc; + int ret; + + ret = nv50_mstc_new(mstm, port, path, &mstc); + if (ret) { + if (mstc) + mstc->connector.funcs->destroy(&mstc->connector); + return NULL; + } + + return &mstc->connector; +} + +static const struct drm_dp_mst_topology_cbs +nv50_mstm = { + .add_connector = nv50_mstm_add_connector, + .register_connector = nv50_mstm_register_connector, + .destroy_connector = nv50_mstm_destroy_connector, + .hotplug = nv50_mstm_hotplug, +}; + +void +nv50_mstm_service(struct nv50_mstm *mstm) +{ + struct drm_dp_aux *aux = mstm->mgr.aux; + bool handled = true; + int ret; + u8 esi[8] = {}; + + while (handled) { + ret = drm_dp_dpcd_read(aux, DP_SINK_COUNT_ESI, esi, 8); + if (ret != 8) { + drm_dp_mst_topology_mgr_set_mst(&mstm->mgr, false); + return; + } + + drm_dp_mst_hpd_irq(&mstm->mgr, esi, &handled); + if (!handled) + break; + + drm_dp_dpcd_write(aux, DP_SINK_COUNT_ESI + 1, &esi[1], 3); + } +} + +void +nv50_mstm_remove(struct nv50_mstm *mstm) +{ + if (mstm) + drm_dp_mst_topology_mgr_set_mst(&mstm->mgr, false); +} + static int nv50_mstm_enable(struct nv50_mstm *mstm, u8 dpcd, int state) { @@ -2873,6 +3363,20 @@ nv50_mstm_detect(struct nv50_mstm *mstm, u8 dpcd[8], int allow) } static void +nv50_mstm_fini(struct nv50_mstm *mstm) +{ + if (mstm && mstm->mgr.mst_state) + drm_dp_mst_topology_mgr_suspend(&mstm->mgr); +} + +static void +nv50_mstm_init(struct nv50_mstm *mstm) +{ + if (mstm && mstm->mgr.mst_state) + drm_dp_mst_topology_mgr_resume(&mstm->mgr); +} + +static void nv50_mstm_del(struct nv50_mstm **pmstm) { struct nv50_mstm *mstm = *pmstm; @@ -2889,17 +3393,36 @@ nv50_mstm_new(struct nouveau_encoder *outp, struct drm_dp_aux *aux, int aux_max, const int max_payloads = hweight8(outp->dcb->heads); struct drm_device *dev = outp->base.base.dev; struct nv50_mstm *mstm; - int ret; + int ret, i; + u8 dpcd; + + /* This is a workaround for some monitors not functioning + * correctly in MST mode on initial module load. I think + * some bad interaction with the VBIOS may be responsible. + * + * A good ol' off and on again seems to work here ;) + */ + ret = drm_dp_dpcd_readb(aux, DP_DPCD_REV, &dpcd); + if (ret >= 0 && dpcd >= 0x12) + drm_dp_dpcd_writeb(aux, DP_MSTM_CTRL, 0); if (!(mstm = *pmstm = kzalloc(sizeof(*mstm), GFP_KERNEL))) return -ENOMEM; mstm->outp = outp; + mstm->mgr.cbs = &nv50_mstm; ret = drm_dp_mst_topology_mgr_init(&mstm->mgr, dev->dev, aux, aux_max, max_payloads, conn_base_id); if (ret) return ret; + for (i = 0; i < max_payloads; i++) { + ret = nv50_msto_new(dev, outp->dcb->heads, outp->base.base.name, + i, &mstm->msto[i]); + if (ret) + return ret; + } + return 0; } @@ -3364,10 +3887,20 @@ nv50_disp_atomic_commit_core(struct nouveau_drm *drm, u32 interlock) { struct nv50_disp *disp = nv50_disp(drm->dev); struct nv50_dmac *core = &disp->mast.base; + struct nv50_mstm *mstm; + struct drm_encoder *encoder; u32 *push; NV_ATOMIC(drm, "commit core %08x\n", interlock); + drm_for_each_encoder(encoder, drm->dev) { + if (encoder->encoder_type != DRM_MODE_ENCODER_DPMST) { + mstm = nouveau_encoder(encoder)->dp.mstm; + if (mstm && mstm->modified) + nv50_mstm_prepare(mstm); + } + } + if ((push = evo_wait(core, 5))) { evo_mthd(push, 0x0084, 1); evo_data(push, 0x80000000); @@ -3383,6 +3916,14 @@ nv50_disp_atomic_commit_core(struct nouveau_drm *drm, u32 interlock) ) < 0) NV_ERROR(drm, "EVO timeout\n"); } + + drm_for_each_encoder(encoder, drm->dev) { + if (encoder->encoder_type != DRM_MODE_ENCODER_DPMST) { + mstm = nouveau_encoder(encoder)->dp.mstm; + if (mstm && mstm->modified) + nv50_mstm_cleanup(mstm); + } + } } static void @@ -3792,6 +4333,8 @@ nv50_disp_func = { void nv50_display_fini(struct drm_device *dev) { + struct nouveau_encoder *nv_encoder; + struct drm_encoder *encoder; struct drm_plane *plane; drm_for_each_plane(plane, dev) { @@ -3800,6 +4343,13 @@ nv50_display_fini(struct drm_device *dev) continue; nv50_wndw_fini(wndw); } + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + if (encoder->encoder_type != DRM_MODE_ENCODER_DPMST) { + nv_encoder = nouveau_encoder(encoder); + nv50_mstm_fini(nv_encoder->dp.mstm); + } + } } int @@ -3827,6 +4377,8 @@ nv50_display_init(struct drm_device *dev) help = encoder->helper_private; if (help && help->dpms) help->dpms(encoder, DRM_MODE_DPMS_ON); + + nv50_mstm_init(nv_encoder->dp.mstm); } } -- cgit v1.1 From e137040e0d0376b404fc5155eba44ea07126e3bd Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Fri, 4 Nov 2016 18:36:17 +0900 Subject: drm/nouveau/gr: fallback to legacy paths during firmware lookup Look for firmware files using the legacy ("nouveau/nvxx_fucxxxx") path if they cannot be found in the new, "official" path. User setups were broken by the switch, which is bad. There are only 4 firmware files we may want to look up that way, so hardcode them into the lookup function. All new firmware files should use the standard "nvidia//gr/" path. Fixes: 8539b37acef7 ("drm/nouveau/gr: use NVIDIA-provided external firmwares") Signed-off-by: Alexandre Courbot Signed-off-by: Ben Skeggs Cc: stable@vger.kernel.org --- drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c | 50 +++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 4 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c index eccdee0..60a1b5c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c @@ -1756,6 +1756,50 @@ gf100_gr_ = { }; int +gf100_gr_ctor_fw_legacy(struct gf100_gr *gr, const char *fwname, + struct gf100_gr_fuc *fuc, int ret) +{ + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; + const struct firmware *fw; + char f[32]; + + /* see if this firmware has a legacy path */ + if (!strcmp(fwname, "fecs_inst")) + fwname = "fuc409c"; + else if (!strcmp(fwname, "fecs_data")) + fwname = "fuc409d"; + else if (!strcmp(fwname, "gpccs_inst")) + fwname = "fuc41ac"; + else if (!strcmp(fwname, "gpccs_data")) + fwname = "fuc41ad"; + else { + /* nope, let's just return the error we got */ + nvkm_error(subdev, "failed to load %s\n", fwname); + return ret; + } + + /* yes, try to load from the legacy path */ + nvkm_debug(subdev, "%s: falling back to legacy path\n", fwname); + + snprintf(f, sizeof(f), "nouveau/nv%02x_%s", device->chipset, fwname); + ret = request_firmware(&fw, f, device->dev); + if (ret) { + snprintf(f, sizeof(f), "nouveau/%s", fwname); + ret = request_firmware(&fw, f, device->dev); + if (ret) { + nvkm_error(subdev, "failed to load %s\n", fwname); + return ret; + } + } + + fuc->size = fw->size; + fuc->data = kmemdup(fw->data, fuc->size, GFP_KERNEL); + release_firmware(fw); + return (fuc->data != NULL) ? 0 : -ENOMEM; +} + +int gf100_gr_ctor_fw(struct gf100_gr *gr, const char *fwname, struct gf100_gr_fuc *fuc) { @@ -1765,10 +1809,8 @@ gf100_gr_ctor_fw(struct gf100_gr *gr, const char *fwname, int ret; ret = nvkm_firmware_get(device, fwname, &fw); - if (ret) { - nvkm_error(subdev, "failed to load %s\n", fwname); - return ret; - } + if (ret) + return gf100_gr_ctor_fw_legacy(gr, fwname, fuc, ret); fuc->size = fw->size; fuc->data = kmemdup(fw->data, fuc->size, GFP_KERNEL); -- cgit v1.1 From b27add13f500469127afdf011dbcc9c649e16e54 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 5 Nov 2016 14:33:14 +1000 Subject: drm/nouveau/fifo/gf100-: protect channel preempt with subdev mutex This avoids an issue that occurs when we're attempting to preempt multiple channels simultaneously. HW seems to ignore preempt requests while it's still processing a previous one, which, well, makes sense. Fixes random "fifo: SCHED_ERROR 0d []" + GPCCS page faults during parallel piglit runs on (at least) GM107. Signed-off-by: Ben Skeggs Cc: stable@vger.kernel.org --- drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogf100.c | 9 ++++++--- drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c | 8 +++++--- 2 files changed, 11 insertions(+), 6 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogf100.c index cbc67f2..12d96426 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogf100.c @@ -60,6 +60,7 @@ gf100_fifo_gpfifo_engine_fini(struct nvkm_fifo_chan *base, struct nvkm_gpuobj *inst = chan->base.inst; int ret = 0; + mutex_lock(&subdev->mutex); nvkm_wr32(device, 0x002634, chan->base.chid); if (nvkm_msec(device, 2000, if (nvkm_rd32(device, 0x002634) == chan->base.chid) @@ -67,10 +68,12 @@ gf100_fifo_gpfifo_engine_fini(struct nvkm_fifo_chan *base, ) < 0) { nvkm_error(subdev, "channel %d [%s] kick timeout\n", chan->base.chid, chan->base.object.client->name); - ret = -EBUSY; - if (suspend) - return ret; + ret = -ETIMEDOUT; } + mutex_unlock(&subdev->mutex); + + if (ret && suspend) + return ret; if (offset) { nvkm_kmap(inst); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c index ed43510..a2df4f3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c @@ -40,7 +40,9 @@ gk104_fifo_gpfifo_kick(struct gk104_fifo_chan *chan) struct nvkm_subdev *subdev = &fifo->base.engine.subdev; struct nvkm_device *device = subdev->device; struct nvkm_client *client = chan->base.object.client; + int ret = 0; + mutex_lock(&subdev->mutex); nvkm_wr32(device, 0x002634, chan->base.chid); if (nvkm_msec(device, 2000, if (!(nvkm_rd32(device, 0x002634) & 0x00100000)) @@ -48,10 +50,10 @@ gk104_fifo_gpfifo_kick(struct gk104_fifo_chan *chan) ) < 0) { nvkm_error(subdev, "channel %d [%s] kick timeout\n", chan->base.chid, client->name); - return -EBUSY; + ret = -ETIMEDOUT; } - - return 0; + mutex_unlock(&subdev->mutex); + return ret; } static u32 -- cgit v1.1