From: Ben Skeggs Date: Fri, 19 May 2017 13:59:34 +0000 (+1000) Subject: drm/nouveau/disp: introduce object to track per-head functions/state X-Git-Tag: v4.13-rc1~73^2~13^2~45 X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=commitdiff_plain;h=a1c930789aa51b928f804c9186f9821efd070ce1;p=linux.git drm/nouveau/disp: introduce object to track per-head functions/state Primarily intended as a way to pass per-head state around during supervisor handling, and share logic between NV50/GF119. Signed-off-by: Ben Skeggs --- diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h index f17200ed3c72..a0892d6d9841 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h @@ -8,10 +8,7 @@ struct nvkm_disp { const struct nvkm_disp_func *func; struct nvkm_engine engine; - struct { - int nr; - } head; - + struct list_head head; struct list_head outp; struct list_head conn; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild index cbc7f673a5de..7062929260bc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild @@ -14,6 +14,11 @@ nvkm-y += nvkm/engine/disp/gp100.o nvkm-y += nvkm/engine/disp/gp102.o nvkm-y += nvkm/engine/disp/vga.o +nvkm-y += nvkm/engine/disp/head.o +nvkm-y += nvkm/engine/disp/headnv04.o +nvkm-y += nvkm/engine/disp/headnv50.o +nvkm-y += nvkm/engine/disp/headgf119.o + nvkm-y += nvkm/engine/disp/dacnv50.o nvkm-y += nvkm/engine/disp/piornv50.o nvkm-y += nvkm/engine/disp/sornv50.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c index 3e02a94c3072..8489d0246cb3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c @@ -23,6 +23,7 @@ */ #include "priv.h" #include "conn.h" +#include "head.h" #include "outp.h" #include @@ -249,6 +250,7 @@ nvkm_disp_oneinit(struct nvkm_engine *engine) struct nvkm_bios *bios = disp->engine.subdev.device->bios; struct nvkm_outp *outp, *outt, *pair; struct nvkm_conn *conn; + struct nvkm_head *head; struct nvbios_connE connE; struct dcb_output dcbE; u8 hpd = 0, ver, hdr; @@ -375,8 +377,11 @@ nvkm_disp_oneinit(struct nvkm_engine *engine) if (ret) return ret; - return nvkm_event_init(&nvkm_disp_vblank_func, 1, - disp->head.nr, &disp->vblank); + i = 0; + list_for_each_entry(head, &disp->head, head) + i = max(i, head->id + 1); + + return nvkm_event_init(&nvkm_disp_vblank_func, 1, i, &disp->vblank); } static void * @@ -405,6 +410,12 @@ nvkm_disp_dtor(struct nvkm_engine *engine) nvkm_outp_del(&outp); } + while (!list_empty(&disp->head)) { + struct nvkm_head *head = + list_first_entry(&disp->head, typeof(*head), head); + nvkm_head_del(&head); + } + return data; } @@ -420,10 +431,10 @@ nvkm_disp = { int nvkm_disp_ctor(const struct nvkm_disp_func *func, struct nvkm_device *device, - int index, int heads, struct nvkm_disp *disp) + int index, struct nvkm_disp *disp) { disp->func = func; - disp->head.nr = heads; + INIT_LIST_HEAD(&disp->head); INIT_LIST_HEAD(&disp->outp); INIT_LIST_HEAD(&disp->conn); return nvkm_engine_ctor(&nvkm_disp, device, index, true, &disp->engine); @@ -431,9 +442,9 @@ nvkm_disp_ctor(const struct nvkm_disp_func *func, struct nvkm_device *device, int nvkm_disp_new_(const struct nvkm_disp_func *func, struct nvkm_device *device, - int index, int heads, struct nvkm_disp **pdisp) + int index, struct nvkm_disp **pdisp) { if (!(*pdisp = kzalloc(sizeof(**pdisp), GFP_KERNEL))) return -ENOMEM; - return nvkm_disp_ctor(func, device, index, heads, *pdisp); + return nvkm_disp_ctor(func, device, index, *pdisp); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/basenv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/basenv50.c index 83f152300ec0..f1d6b820d482 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/basenv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/basenv50.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "dmacnv50.h" +#include "head.h" #include "rootnv50.h" #include @@ -50,7 +51,7 @@ nv50_disp_base_new(const struct nv50_disp_dmac_func *func, nvif_ioctl(parent, "create disp base channel dma vers %d " "pushbuf %016llx head %d\n", args->v0.version, args->v0.pushbuf, args->v0.head); - if (args->v0.head > disp->base.head.nr) + if (!nvkm_head_find(&disp->base, args->v0.head)) return -EINVAL; push = args->v0.pushbuf; head = args->v0.head; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursnv50.c index 82ff82d8c1ab..ab51121b7982 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursnv50.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "channv50.h" +#include "head.h" #include "rootnv50.h" #include @@ -48,7 +49,7 @@ nv50_disp_curs_new(const struct nv50_disp_chan_func *func, if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { nvif_ioctl(parent, "create disp cursor vers %d head %d\n", args->v0.version, args->v0.head); - if (args->v0.head > disp->base.head.nr) + if (!nvkm_head_find(&disp->base, args->v0.head)) return -EINVAL; head = args->v0.head; } else diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c index 0db964764ced..0de04221da48 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "nv50.h" +#include "head.h" #include "rootnv50.h" static const struct nv50_disp_func @@ -30,6 +31,7 @@ g84_disp = { .uevent = &nv50_disp_chan_uevent, .super = nv50_disp_super, .root = &g84_disp_root_oclass, + .head.new = nv50_head_new, .head.vblank_init = nv50_disp_vblank_init, .head.vblank_fini = nv50_disp_vblank_fini, .head.scanoutpos = nv50_disp_root_scanoutpos, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c index 3f3cdbc3363a..8010d381bc7d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "nv50.h" +#include "head.h" #include "rootnv50.h" static const struct nv50_disp_func @@ -30,6 +31,7 @@ g94_disp = { .uevent = &nv50_disp_chan_uevent, .super = nv50_disp_super, .root = &g94_disp_root_oclass, + .head.new = nv50_head_new, .head.vblank_init = nv50_disp_vblank_init, .head.vblank_fini = nv50_disp_vblank_fini, .head.scanoutpos = nv50_disp_root_scanoutpos, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c index 8d1e535af208..59bf3f950eea 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "nv50.h" +#include "head.h" #include "rootnv50.h" #include @@ -364,55 +365,55 @@ gf119_disp_super(struct work_struct *work) container_of(work, struct nv50_disp, supervisor); struct nvkm_subdev *subdev = &disp->base.engine.subdev; struct nvkm_device *device = subdev->device; + struct nvkm_head *head; u32 mask[4]; - int head; nvkm_debug(subdev, "supervisor %d\n", ffs(disp->super)); - for (head = 0; head < disp->base.head.nr; head++) { - mask[head] = nvkm_rd32(device, 0x6101d4 + (head * 0x800)); - nvkm_debug(subdev, "head %d: %08x\n", head, mask[head]); + list_for_each_entry(head, &disp->base.head, head) { + mask[head->id] = nvkm_rd32(device, 0x6101d4 + (head->id * 0x800)); + HEAD_DBG(head, "%08x", mask[head->id]); } if (disp->super & 0x00000001) { nv50_disp_chan_mthd(disp->chan[0], NV_DBG_DEBUG); - for (head = 0; head < disp->base.head.nr; head++) { - if (!(mask[head] & 0x00001000)) + list_for_each_entry(head, &disp->base.head, head) { + if (!(mask[head->id] & 0x00001000)) continue; - nvkm_debug(subdev, "supervisor 1.0 - head %d\n", head); - gf119_disp_intr_unk1_0(disp, head); + nvkm_debug(subdev, "supervisor 1.0 - head %d\n", head->id); + gf119_disp_intr_unk1_0(disp, head->id); } } else if (disp->super & 0x00000002) { - for (head = 0; head < disp->base.head.nr; head++) { - if (!(mask[head] & 0x00001000)) + list_for_each_entry(head, &disp->base.head, head) { + if (!(mask[head->id] & 0x00001000)) continue; - nvkm_debug(subdev, "supervisor 2.0 - head %d\n", head); - gf119_disp_intr_unk2_0(disp, head); + nvkm_debug(subdev, "supervisor 2.0 - head %d\n", head->id); + gf119_disp_intr_unk2_0(disp, head->id); } - for (head = 0; head < disp->base.head.nr; head++) { - if (!(mask[head] & 0x00010000)) + list_for_each_entry(head, &disp->base.head, head) { + if (!(mask[head->id] & 0x00010000)) continue; - nvkm_debug(subdev, "supervisor 2.1 - head %d\n", head); - gf119_disp_intr_unk2_1(disp, head); + nvkm_debug(subdev, "supervisor 2.1 - head %d\n", head->id); + gf119_disp_intr_unk2_1(disp, head->id); } - for (head = 0; head < disp->base.head.nr; head++) { - if (!(mask[head] & 0x00001000)) + list_for_each_entry(head, &disp->base.head, head) { + if (!(mask[head->id] & 0x00001000)) continue; - nvkm_debug(subdev, "supervisor 2.2 - head %d\n", head); - gf119_disp_intr_unk2_2(disp, head); + nvkm_debug(subdev, "supervisor 2.2 - head %d\n", head->id); + gf119_disp_intr_unk2_2(disp, head->id); } } else if (disp->super & 0x00000004) { - for (head = 0; head < disp->base.head.nr; head++) { - if (!(mask[head] & 0x00001000)) + list_for_each_entry(head, &disp->base.head, head) { + if (!(mask[head->id] & 0x00001000)) continue; - nvkm_debug(subdev, "supervisor 3.0 - head %d\n", head); - gf119_disp_intr_unk4_0(disp, head); + nvkm_debug(subdev, "supervisor 3.0 - head %d\n", head->id); + gf119_disp_intr_unk4_0(disp, head->id); } } - for (head = 0; head < disp->base.head.nr; head++) - nvkm_wr32(device, 0x6101d4 + (head * 0x800), 0x00000000); + list_for_each_entry(head, &disp->base.head, head) + nvkm_wr32(device, 0x6101d4 + (head->id * 0x800), 0x00000000); nvkm_wr32(device, 0x6101d0, 0x80000000); } @@ -447,8 +448,8 @@ gf119_disp_intr(struct nv50_disp *disp) { struct nvkm_subdev *subdev = &disp->base.engine.subdev; struct nvkm_device *device = subdev->device; + struct nvkm_head *head; u32 intr = nvkm_rd32(device, 0x610088); - int i; if (intr & 0x00000001) { u32 stat = nvkm_rd32(device, 0x61008c); @@ -485,14 +486,15 @@ gf119_disp_intr(struct nv50_disp *disp) intr &= ~0x00100000; } - for (i = 0; i < disp->base.head.nr; i++) { - u32 mask = 0x01000000 << i; + list_for_each_entry(head, &disp->base.head, head) { + const u32 hoff = head->id * 0x800; + u32 mask = 0x01000000 << head->id; if (mask & intr) { - u32 stat = nvkm_rd32(device, 0x6100bc + (i * 0x800)); + u32 stat = nvkm_rd32(device, 0x6100bc + hoff); if (stat & 0x00000001) - nvkm_disp_vblank(&disp->base, i); - nvkm_mask(device, 0x6100bc + (i * 0x800), 0, 0); - nvkm_rd32(device, 0x6100c0 + (i * 0x800)); + nvkm_disp_vblank(&disp->base, head->id); + nvkm_mask(device, 0x6100bc + hoff, 0, 0); + nvkm_rd32(device, 0x6100c0 + hoff); } } } @@ -512,6 +514,7 @@ gf119_disp = { .uevent = &gf119_disp_chan_uevent, .super = gf119_disp_super, .root = &gf119_disp_root_oclass, + .head.new = gf119_head_new, .head.vblank_init = gf119_disp_vblank_init, .head.vblank_fini = gf119_disp_vblank_fini, .head.scanoutpos = gf119_disp_root_scanoutpos, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c index ec14cef92de5..89561496570b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "nv50.h" +#include "head.h" #include "rootnv50.h" static const struct nv50_disp_func @@ -31,6 +32,7 @@ gk104_disp = { .uevent = &gf119_disp_chan_uevent, .super = gf119_disp_super, .root = &gk104_disp_root_oclass, + .head.new = gf119_head_new, .head.vblank_init = gf119_disp_vblank_init, .head.vblank_fini = gf119_disp_vblank_fini, .head.scanoutpos = gf119_disp_root_scanoutpos, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c index 88f977660e41..9400d2ad79b9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "nv50.h" +#include "head.h" #include "rootnv50.h" static const struct nv50_disp_func @@ -31,6 +32,7 @@ gk110_disp = { .uevent = &gf119_disp_chan_uevent, .super = gf119_disp_super, .root = &gk110_disp_root_oclass, + .head.new = gf119_head_new, .head.vblank_init = gf119_disp_vblank_init, .head.vblank_fini = gf119_disp_vblank_fini, .head.scanoutpos = gf119_disp_root_scanoutpos, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c index 5d7a2f42a4f0..b7570fb0fb1f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "nv50.h" +#include "head.h" #include "rootnv50.h" static const struct nv50_disp_func @@ -31,6 +32,7 @@ gm107_disp = { .uevent = &gf119_disp_chan_uevent, .super = gf119_disp_super, .root = &gm107_disp_root_oclass, + .head.new = gf119_head_new, .head.vblank_init = gf119_disp_vblank_init, .head.vblank_fini = gf119_disp_vblank_fini, .head.scanoutpos = gf119_disp_root_scanoutpos, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c index 54fa9ebe346b..b3e52080d4b7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "nv50.h" +#include "head.h" #include "rootnv50.h" static const struct nv50_disp_func @@ -31,6 +32,7 @@ gm200_disp = { .uevent = &gf119_disp_chan_uevent, .super = gf119_disp_super, .root = &gm200_disp_root_oclass, + .head.new = gf119_head_new, .head.vblank_init = gf119_disp_vblank_init, .head.vblank_fini = gf119_disp_vblank_fini, .head.scanoutpos = gf119_disp_root_scanoutpos, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c index 6f4e56d82421..3d1c65ff5620 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "nv50.h" +#include "head.h" #include "rootnv50.h" static const struct nv50_disp_func @@ -31,6 +32,7 @@ gp100_disp = { .uevent = &gf119_disp_chan_uevent, .super = gf119_disp_super, .root = &gp100_disp_root_oclass, + .head.new = gf119_head_new, .head.vblank_init = gf119_disp_vblank_init, .head.vblank_fini = gf119_disp_vblank_fini, .head.scanoutpos = gf119_disp_root_scanoutpos, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c index 54b97e1dce0b..fac8e88fd2d1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "nv50.h" +#include "head.h" #include "rootnv50.h" static void @@ -57,6 +58,7 @@ gp102_disp = { .uevent = &gf119_disp_chan_uevent, .super = gf119_disp_super, .root = &gp102_disp_root_oclass, + .head.new = gf119_head_new, .head.vblank_init = gf119_disp_vblank_init, .head.vblank_fini = gf119_disp_vblank_fini, .head.scanoutpos = gf119_disp_root_scanoutpos, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c index da6c395050de..a0e7c3c78e97 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "nv50.h" +#include "head.h" #include "rootnv50.h" static const struct nv50_disp_func @@ -30,6 +31,7 @@ gt200_disp = { .uevent = &nv50_disp_chan_uevent, .super = nv50_disp_super, .root = >200_disp_root_oclass, + .head.new = nv50_head_new, .head.vblank_init = nv50_disp_vblank_init, .head.vblank_fini = nv50_disp_vblank_fini, .head.scanoutpos = nv50_disp_root_scanoutpos, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c index 1f475cf284e3..5f8a8d855673 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "nv50.h" +#include "head.h" #include "rootnv50.h" static const struct nv50_disp_func @@ -30,6 +31,7 @@ gt215_disp = { .uevent = &nv50_disp_chan_uevent, .super = nv50_disp_super, .root = >215_disp_root_oclass, + .head.new = nv50_head_new, .head.vblank_init = nv50_disp_vblank_init, .head.vblank_fini = nv50_disp_vblank_fini, .head.scanoutpos = nv50_disp_root_scanoutpos, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.c new file mode 100644 index 000000000000..67020933f4ff --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.c @@ -0,0 +1,62 @@ +/* + * Copyright 2017 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "head.h" + +struct nvkm_head * +nvkm_head_find(struct nvkm_disp *disp, int id) +{ + struct nvkm_head *head; + list_for_each_entry(head, &disp->head, head) { + if (head->id == id) + return head; + } + return NULL; +} + +void +nvkm_head_del(struct nvkm_head **phead) +{ + struct nvkm_head *head = *phead; + if (head) { + HEAD_DBG(head, "dtor"); + list_del(&head->head); + kfree(*phead); + *phead = NULL; + } +} + +int +nvkm_head_new_(const struct nvkm_head_func *func, + struct nvkm_disp *disp, int id) +{ + struct nvkm_head *head; + if (!(head = kzalloc(sizeof(*head), GFP_KERNEL))) + return -ENOMEM; + head->func = func; + head->disp = disp; + head->id = id; + list_add_tail(&head->head, &disp->head); + HEAD_DBG(head, "ctor"); + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.h new file mode 100644 index 000000000000..a8ae6cbc0ff1 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.h @@ -0,0 +1,30 @@ +#ifndef __NVKM_DISP_HEAD_H__ +#define __NVKM_DISP_HEAD_H__ +#include "priv.h" + +struct nvkm_head { + const struct nvkm_head_func *func; + struct nvkm_disp *disp; + int id; + + struct list_head head; +}; + +int nvkm_head_new_(const struct nvkm_head_func *, struct nvkm_disp *, int id); +void nvkm_head_del(struct nvkm_head **); +struct nvkm_head *nvkm_head_find(struct nvkm_disp *, int id); + +struct nvkm_head_func { +}; + +#define HEAD_MSG(h,l,f,a...) do { \ + struct nvkm_head *_h = (h); \ + nvkm_##l(&_h->disp->engine.subdev, "head-%d: "f"\n", _h->id, ##a); \ +} while(0) +#define HEAD_WARN(h,f,a...) HEAD_MSG((h), warn, f, ##a) +#define HEAD_DBG(h,f,a...) HEAD_MSG((h), debug, f, ##a) + +int nv04_head_new(struct nvkm_disp *, int id); +int nv50_head_new(struct nvkm_disp *, int id); +int gf119_head_new(struct nvkm_disp *, int id); +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/headgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/headgf119.c new file mode 100644 index 000000000000..062fa07e1ece --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/headgf119.c @@ -0,0 +1,34 @@ +/* + * Copyright 2017 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "head.h" + +static const struct nvkm_head_func +gf119_head = { +}; + +int +gf119_head_new(struct nvkm_disp *disp, int id) +{ + return nvkm_head_new_(&gf119_head, disp, id); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv04.c new file mode 100644 index 000000000000..f581327f695c --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv04.c @@ -0,0 +1,34 @@ +/* + * Copyright 2017 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "head.h" + +static const struct nvkm_head_func +nv04_head = { +}; + +int +nv04_head_new(struct nvkm_disp *disp, int id) +{ + return nvkm_head_new_(&nv04_head, disp, id); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv50.c new file mode 100644 index 000000000000..e48865c91046 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv50.c @@ -0,0 +1,34 @@ +/* + * Copyright 2017 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "head.h" + +static const struct nvkm_head_func +nv50_head = { +}; + +int +nv50_head_new(struct nvkm_disp *disp, int id) +{ + return nvkm_head_new_(&nv50_head, disp, id); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c index 67254ce6f83f..978e3ad488d9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "priv.h" +#include "head.h" static const struct nvkm_disp_oclass * nv04_disp_root(struct nvkm_disp *disp) @@ -81,5 +82,17 @@ nv04_disp = { int nv04_disp_new(struct nvkm_device *device, int index, struct nvkm_disp **pdisp) { - return nvkm_disp_new_(&nv04_disp, device, index, 2, pdisp); + int ret, i; + + ret = nvkm_disp_new_(&nv04_disp, device, index, pdisp); + if (ret) + return ret; + + for (i = 0; i < 2; i++) { + ret = nv04_head_new(*pdisp, i); + if (ret) + return ret; + } + + return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index 025cc0d7feb3..9787a4cc4cce 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "nv50.h" +#include "head.h" #include "rootnv50.h" #include @@ -146,7 +147,7 @@ nv50_disp_new_(const struct nv50_disp_func *func, struct nvkm_device *device, int index, int heads, struct nvkm_disp **pdisp) { struct nv50_disp *disp; - int ret; + int ret, i; if (!(disp = kzalloc(sizeof(*disp), GFP_KERNEL))) return -ENOMEM; @@ -154,10 +155,16 @@ nv50_disp_new_(const struct nv50_disp_func *func, struct nvkm_device *device, disp->func = func; *pdisp = &disp->base; - ret = nvkm_disp_ctor(&nv50_disp_, device, index, heads, &disp->base); + ret = nvkm_disp_ctor(&nv50_disp_, device, index, &disp->base); if (ret) return ret; + for (i = 0; func->head.new && i < heads; i++) { + ret = func->head.new(&disp->base, i); + if (ret) + return ret; + } + return nvkm_event_init(func->uevent, 1, 1 + (heads * 4), &disp->uevent); } @@ -684,43 +691,43 @@ nv50_disp_super(struct work_struct *work) container_of(work, struct nv50_disp, supervisor); struct nvkm_subdev *subdev = &disp->base.engine.subdev; struct nvkm_device *device = subdev->device; + struct nvkm_head *head; u32 super = nvkm_rd32(device, 0x610030); - int head; nvkm_debug(subdev, "supervisor %08x %08x\n", disp->super, super); if (disp->super & 0x00000010) { nv50_disp_chan_mthd(disp->chan[0], NV_DBG_DEBUG); - for (head = 0; head < disp->base.head.nr; head++) { - if (!(super & (0x00000020 << head))) + list_for_each_entry(head, &disp->base.head, head) { + if (!(super & (0x00000020 << head->id))) continue; - if (!(super & (0x00000080 << head))) + if (!(super & (0x00000080 << head->id))) continue; - nv50_disp_intr_unk10_0(disp, head); + nv50_disp_intr_unk10_0(disp, head->id); } } else if (disp->super & 0x00000020) { - for (head = 0; head < disp->base.head.nr; head++) { - if (!(super & (0x00000080 << head))) + list_for_each_entry(head, &disp->base.head, head) { + if (!(super & (0x00000080 << head->id))) continue; - nv50_disp_intr_unk20_0(disp, head); + nv50_disp_intr_unk20_0(disp, head->id); } - for (head = 0; head < disp->base.head.nr; head++) { - if (!(super & (0x00000200 << head))) + list_for_each_entry(head, &disp->base.head, head) { + if (!(super & (0x00000200 << head->id))) continue; - nv50_disp_intr_unk20_1(disp, head); + nv50_disp_intr_unk20_1(disp, head->id); } - for (head = 0; head < disp->base.head.nr; head++) { - if (!(super & (0x00000080 << head))) + list_for_each_entry(head, &disp->base.head, head) { + if (!(super & (0x00000080 << head->id))) continue; - nv50_disp_intr_unk20_2(disp, head); + nv50_disp_intr_unk20_2(disp, head->id); } } else if (disp->super & 0x00000040) { - for (head = 0; head < disp->base.head.nr; head++) { - if (!(super & (0x00000080 << head))) + list_for_each_entry(head, &disp->base.head, head) { + if (!(super & (0x00000080 << head->id))) continue; - nv50_disp_intr_unk40_0(disp, head); + nv50_disp_intr_unk40_0(disp, head->id); } nv50_disp_update_sppll1(disp); } @@ -819,6 +826,7 @@ nv50_disp = { .uevent = &nv50_disp_chan_uevent, .super = nv50_disp_super, .root = &nv50_disp_root_oclass, + .head.new = nv50_head_new, .head.vblank_init = nv50_disp_vblank_init, .head.vblank_fini = nv50_disp_vblank_fini, .head.scanoutpos = nv50_disp_root_scanoutpos, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h index 4fa82f48429b..0361f0c2ba1a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h @@ -75,6 +75,7 @@ struct nv50_disp_func { const struct nvkm_disp_oclass *root; struct { + int (*new)(struct nvkm_disp *, int id); void (*vblank_init)(struct nv50_disp *, int head); void (*vblank_fini)(struct nv50_disp *, int head); int (*scanoutpos)(NV50_DISP_MTHD_V0); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmnv50.c index 07540f3d32dc..f3b0fa2c5924 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmnv50.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "channv50.h" +#include "head.h" #include "rootnv50.h" #include @@ -48,7 +49,7 @@ nv50_disp_oimm_new(const struct nv50_disp_chan_func *func, if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { nvif_ioctl(parent, "create disp overlay vers %d head %d\n", args->v0.version, args->v0.head); - if (args->v0.head > disp->base.head.nr) + if (!nvkm_head_find(&disp->base, args->v0.head)) return -EINVAL; head = args->v0.head; } else diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlynv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlynv50.c index 2a49c46425cd..9ebaaa6e9e33 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlynv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlynv50.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "dmacnv50.h" +#include "head.h" #include "rootnv50.h" #include @@ -50,7 +51,7 @@ nv50_disp_ovly_new(const struct nv50_disp_dmac_func *func, nvif_ioctl(parent, "create disp overlay channel dma vers %d " "pushbuf %016llx head %d\n", args->v0.version, args->v0.pushbuf, args->v0.head); - if (args->v0.head > disp->base.head.nr) + if (!nvkm_head_find(&disp->base, args->v0.head)) return -EINVAL; push = args->v0.pushbuf; head = args->v0.head; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h index e143fc7bc15f..4bb05a09a60b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h @@ -4,9 +4,9 @@ #include "outp.h" int nvkm_disp_ctor(const struct nvkm_disp_func *, struct nvkm_device *, - int index, int heads, struct nvkm_disp *); + int index, struct nvkm_disp *); int nvkm_disp_new_(const struct nvkm_disp_func *, struct nvkm_device *, - int index, int heads, struct nvkm_disp **); + int index, struct nvkm_disp **); void nvkm_disp_vblank(struct nvkm_disp *, int head); struct nvkm_disp_func_outp { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgf119.c index 335d88823c22..f1159dd4db87 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgf119.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "rootnv50.h" +#include "head.h" #include "dmacnv50.h" #include @@ -78,6 +79,7 @@ int gf119_disp_root_init(struct nv50_disp_root *root) { struct nv50_disp *disp = root->disp; + struct nvkm_head *head; struct nvkm_device *device = disp->base.engine.subdev.device; u32 tmp; int i; @@ -88,13 +90,14 @@ gf119_disp_root_init(struct nv50_disp_root *root) */ /* ... CRTC caps */ - for (i = 0; i < disp->base.head.nr; i++) { - tmp = nvkm_rd32(device, 0x616104 + (i * 0x800)); - nvkm_wr32(device, 0x6101b4 + (i * 0x800), tmp); - tmp = nvkm_rd32(device, 0x616108 + (i * 0x800)); - nvkm_wr32(device, 0x6101b8 + (i * 0x800), tmp); - tmp = nvkm_rd32(device, 0x61610c + (i * 0x800)); - nvkm_wr32(device, 0x6101bc + (i * 0x800), tmp); + list_for_each_entry(head, &disp->base.head, head) { + const u32 hoff = head->id * 0x800; + tmp = nvkm_rd32(device, 0x616104 + hoff); + nvkm_wr32(device, 0x6101b4 + hoff, tmp); + tmp = nvkm_rd32(device, 0x616108 + hoff); + nvkm_wr32(device, 0x6101b8 + hoff, tmp); + tmp = nvkm_rd32(device, 0x61610c + hoff); + nvkm_wr32(device, 0x6101bc + hoff, tmp); } /* ... DAC caps */ @@ -134,8 +137,10 @@ gf119_disp_root_init(struct nv50_disp_root *root) * * ftp://download.nvidia.com/open-gpu-doc/gk104-disable-underflow-reporting/1/gk104-disable-underflow-reporting.txt */ - for (i = 0; i < disp->base.head.nr; i++) - nvkm_mask(device, 0x616308 + (i * 0x800), 0x00000111, 0x00000010); + list_for_each_entry(head, &disp->base.head, head) { + const u32 hoff = head->id * 0x800; + nvkm_mask(device, 0x616308 + hoff, 0x00000111, 0x00000010); + } return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c index 2e73aeb86070..b5df4e8ddbfd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c @@ -23,6 +23,7 @@ */ #include "rootnv50.h" #include "dmacnv50.h" +#include "head.h" #include #include @@ -102,7 +103,7 @@ nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size) } else return ret; - if (head < 0 || head >= disp->base.head.nr) + if (!nvkm_head_find(&disp->base, head)) return -ENXIO; if (mask) { @@ -351,6 +352,7 @@ int nv50_disp_root_init(struct nv50_disp_root *root) { struct nv50_disp *disp = root->disp; + struct nvkm_head *head; struct nvkm_device *device = disp->base.engine.subdev.device; u32 tmp; int i; @@ -363,15 +365,15 @@ nv50_disp_root_init(struct nv50_disp_root *root) nvkm_wr32(device, 0x610184, tmp); /* ... CRTC caps */ - for (i = 0; i < disp->base.head.nr; i++) { - tmp = nvkm_rd32(device, 0x616100 + (i * 0x800)); - nvkm_wr32(device, 0x610190 + (i * 0x10), tmp); - tmp = nvkm_rd32(device, 0x616104 + (i * 0x800)); - nvkm_wr32(device, 0x610194 + (i * 0x10), tmp); - tmp = nvkm_rd32(device, 0x616108 + (i * 0x800)); - nvkm_wr32(device, 0x610198 + (i * 0x10), tmp); - tmp = nvkm_rd32(device, 0x61610c + (i * 0x800)); - nvkm_wr32(device, 0x61019c + (i * 0x10), tmp); + list_for_each_entry(head, &disp->base.head, head) { + tmp = nvkm_rd32(device, 0x616100 + (head->id * 0x800)); + nvkm_wr32(device, 0x610190 + (head->id * 0x10), tmp); + tmp = nvkm_rd32(device, 0x616104 + (head->id * 0x800)); + nvkm_wr32(device, 0x610194 + (head->id * 0x10), tmp); + tmp = nvkm_rd32(device, 0x616108 + (head->id * 0x800)); + nvkm_wr32(device, 0x610198 + (head->id * 0x10), tmp); + tmp = nvkm_rd32(device, 0x61610c + (head->id * 0x800)); + nvkm_wr32(device, 0x61019c + (head->id * 0x10), tmp); } /* ... DAC caps */