Commit bb3b0a42 authored by Ben Skeggs's avatar Ben Skeggs

drm/nouveau/disp/nv50-: initialise from the engine, rather than the user object

Engines are initialised on an as-needed basis, so this results in the
same behaviour, whilst allowing us to simplify things a bit.
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent f5e088d6
...@@ -220,6 +220,9 @@ nvkm_disp_fini(struct nvkm_engine *engine, bool suspend) ...@@ -220,6 +220,9 @@ nvkm_disp_fini(struct nvkm_engine *engine, bool suspend)
struct nvkm_conn *conn; struct nvkm_conn *conn;
struct nvkm_outp *outp; struct nvkm_outp *outp;
if (disp->func->fini)
disp->func->fini(disp);
list_for_each_entry(outp, &disp->outp, head) { list_for_each_entry(outp, &disp->outp, head) {
nvkm_outp_fini(outp); nvkm_outp_fini(outp);
} }
...@@ -237,6 +240,7 @@ nvkm_disp_init(struct nvkm_engine *engine) ...@@ -237,6 +240,7 @@ nvkm_disp_init(struct nvkm_engine *engine)
struct nvkm_disp *disp = nvkm_disp(engine); struct nvkm_disp *disp = nvkm_disp(engine);
struct nvkm_conn *conn; struct nvkm_conn *conn;
struct nvkm_outp *outp; struct nvkm_outp *outp;
struct nvkm_ior *ior;
list_for_each_entry(conn, &disp->conn, head) { list_for_each_entry(conn, &disp->conn, head) {
nvkm_conn_init(conn); nvkm_conn_init(conn);
...@@ -246,6 +250,19 @@ nvkm_disp_init(struct nvkm_engine *engine) ...@@ -246,6 +250,19 @@ nvkm_disp_init(struct nvkm_engine *engine)
nvkm_outp_init(outp); nvkm_outp_init(outp);
} }
if (disp->func->init) {
int ret = disp->func->init(disp);
if (ret)
return ret;
}
/* Set 'normal' (ie. when it's attached to a head) state for
* each output resource to 'fully enabled'.
*/
list_for_each_entry(ior, &disp->ior, head) {
ior->func->power(ior, true, true, true, true, true);
}
return 0; return 0;
} }
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#define nv50_disp_chan(p) container_of((p), struct nv50_disp_chan, object) #define nv50_disp_chan(p) container_of((p), struct nv50_disp_chan, object)
#include <core/object.h> #include <core/object.h>
#include "nv50.h" #include "nv50.h"
struct nv50_disp_root;
struct nv50_disp_chan { struct nv50_disp_chan {
const struct nv50_disp_chan_func *func; const struct nv50_disp_chan_func *func;
......
...@@ -31,7 +31,7 @@ int ...@@ -31,7 +31,7 @@ int
gf119_disp_dmac_bind(struct nv50_disp_dmac *chan, gf119_disp_dmac_bind(struct nv50_disp_dmac *chan,
struct nvkm_object *object, u32 handle) struct nvkm_object *object, u32 handle)
{ {
return nvkm_ramht_insert(chan->base.root->ramht, object, return nvkm_ramht_insert(chan->base.root->disp->ramht, object,
chan->base.chid.user, -9, handle, chan->base.chid.user, -9, handle,
chan->base.chid.user << 27 | 0x00000001); chan->base.chid.user << 27 | 0x00000001);
} }
......
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
struct nv50_disp_dmac_object { struct nv50_disp_dmac_object {
struct nvkm_oproxy oproxy; struct nvkm_oproxy oproxy;
struct nv50_disp_root *root; struct nv50_disp *disp;
int hash; int hash;
}; };
...@@ -42,7 +42,7 @@ nv50_disp_dmac_child_del_(struct nvkm_oproxy *base) ...@@ -42,7 +42,7 @@ nv50_disp_dmac_child_del_(struct nvkm_oproxy *base)
{ {
struct nv50_disp_dmac_object *object = struct nv50_disp_dmac_object *object =
container_of(base, typeof(*object), oproxy); container_of(base, typeof(*object), oproxy);
nvkm_ramht_remove(object->root->ramht, object->hash); nvkm_ramht_remove(object->disp->ramht, object->hash);
} }
static const struct nvkm_oproxy_func static const struct nvkm_oproxy_func
...@@ -56,8 +56,8 @@ nv50_disp_dmac_child_new_(struct nv50_disp_chan *base, ...@@ -56,8 +56,8 @@ nv50_disp_dmac_child_new_(struct nv50_disp_chan *base,
void *data, u32 size, struct nvkm_object **pobject) void *data, u32 size, struct nvkm_object **pobject)
{ {
struct nv50_disp_dmac *chan = nv50_disp_dmac(base); struct nv50_disp_dmac *chan = nv50_disp_dmac(base);
struct nv50_disp_root *root = chan->base.root; struct nv50_disp *disp = chan->base.root->disp;
struct nvkm_device *device = root->disp->base.engine.subdev.device; struct nvkm_device *device = disp->base.engine.subdev.device;
const struct nvkm_device_oclass *sclass = oclass->priv; const struct nvkm_device_oclass *sclass = oclass->priv;
struct nv50_disp_dmac_object *object; struct nv50_disp_dmac_object *object;
int ret; int ret;
...@@ -65,7 +65,7 @@ nv50_disp_dmac_child_new_(struct nv50_disp_chan *base, ...@@ -65,7 +65,7 @@ nv50_disp_dmac_child_new_(struct nv50_disp_chan *base,
if (!(object = kzalloc(sizeof(*object), GFP_KERNEL))) if (!(object = kzalloc(sizeof(*object), GFP_KERNEL)))
return -ENOMEM; return -ENOMEM;
nvkm_oproxy_ctor(&nv50_disp_dmac_child_func_, oclass, &object->oproxy); nvkm_oproxy_ctor(&nv50_disp_dmac_child_func_, oclass, &object->oproxy);
object->root = root; object->disp = disp;
*pobject = &object->oproxy.base; *pobject = &object->oproxy.base;
ret = sclass->ctor(device, oclass, data, size, &object->oproxy.object); ret = sclass->ctor(device, oclass, data, size, &object->oproxy.object);
...@@ -177,7 +177,7 @@ int ...@@ -177,7 +177,7 @@ int
nv50_disp_dmac_bind(struct nv50_disp_dmac *chan, nv50_disp_dmac_bind(struct nv50_disp_dmac *chan,
struct nvkm_object *object, u32 handle) struct nvkm_object *object, u32 handle)
{ {
return nvkm_ramht_insert(chan->base.root->ramht, object, return nvkm_ramht_insert(chan->base.root->disp->ramht, object,
chan->base.chid.user, -10, handle, chan->base.chid.user, -10, handle,
chan->base.chid.user << 28 | chan->base.chid.user << 28 |
chan->base.chid.user); chan->base.chid.user);
......
...@@ -28,6 +28,8 @@ ...@@ -28,6 +28,8 @@
static const struct nv50_disp_func static const struct nv50_disp_func
g84_disp = { g84_disp = {
.init = nv50_disp_init,
.fini = nv50_disp_fini,
.intr = nv50_disp_intr, .intr = nv50_disp_intr,
.uevent = &nv50_disp_chan_uevent, .uevent = &nv50_disp_chan_uevent,
.super = nv50_disp_super, .super = nv50_disp_super,
......
...@@ -28,6 +28,8 @@ ...@@ -28,6 +28,8 @@
static const struct nv50_disp_func static const struct nv50_disp_func
g94_disp = { g94_disp = {
.init = nv50_disp_init,
.fini = nv50_disp_fini,
.intr = nv50_disp_intr, .intr = nv50_disp_intr,
.uevent = &nv50_disp_chan_uevent, .uevent = &nv50_disp_chan_uevent,
.super = nv50_disp_super, .super = nv50_disp_super,
......
...@@ -26,6 +26,9 @@ ...@@ -26,6 +26,9 @@
#include "ior.h" #include "ior.h"
#include "rootnv50.h" #include "rootnv50.h"
#include <core/ramht.h>
#include <subdev/timer.h>
void void
gf119_disp_super(struct work_struct *work) gf119_disp_super(struct work_struct *work)
{ {
...@@ -164,8 +167,87 @@ gf119_disp_intr(struct nv50_disp *disp) ...@@ -164,8 +167,87 @@ gf119_disp_intr(struct nv50_disp *disp)
} }
} }
void
gf119_disp_fini(struct nv50_disp *disp)
{
struct nvkm_device *device = disp->base.engine.subdev.device;
/* disable all interrupts */
nvkm_wr32(device, 0x6100b0, 0x00000000);
}
int
gf119_disp_init(struct nv50_disp *disp)
{
struct nvkm_device *device = disp->base.engine.subdev.device;
struct nvkm_head *head;
u32 tmp;
int i;
/* The below segments of code copying values from one register to
* another appear to inform EVO of the display capabilities or
* something similar.
*/
/* ... CRTC caps */
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 */
for (i = 0; i < disp->dac.nr; i++) {
tmp = nvkm_rd32(device, 0x61a000 + (i * 0x800));
nvkm_wr32(device, 0x6101c0 + (i * 0x800), tmp);
}
/* ... SOR caps */
for (i = 0; i < disp->sor.nr; i++) {
tmp = nvkm_rd32(device, 0x61c000 + (i * 0x800));
nvkm_wr32(device, 0x6301c4 + (i * 0x800), tmp);
}
/* steal display away from vbios, or something like that */
if (nvkm_rd32(device, 0x6100ac) & 0x00000100) {
nvkm_wr32(device, 0x6100ac, 0x00000100);
nvkm_mask(device, 0x6194e8, 0x00000001, 0x00000000);
if (nvkm_msec(device, 2000,
if (!(nvkm_rd32(device, 0x6194e8) & 0x00000002))
break;
) < 0)
return -EBUSY;
}
/* point at display engine memory area (hash table, objects) */
nvkm_wr32(device, 0x610010, (disp->inst->addr >> 8) | 9);
/* enable supervisor interrupts, disable everything else */
nvkm_wr32(device, 0x610090, 0x00000000);
nvkm_wr32(device, 0x6100a0, 0x00000000);
nvkm_wr32(device, 0x6100b0, 0x00000307);
/* disable underflow reporting, preventing an intermittent issue
* on some gk104 boards where the production vbios left this
* setting enabled by default.
*
* ftp://download.nvidia.com/open-gpu-doc/gk104-disable-underflow-reporting/1/gk104-disable-underflow-reporting.txt
*/
list_for_each_entry(head, &disp->base.head, head) {
const u32 hoff = head->id * 0x800;
nvkm_mask(device, 0x616308 + hoff, 0x00000111, 0x00000010);
}
return 0;
}
static const struct nv50_disp_func static const struct nv50_disp_func
gf119_disp = { gf119_disp = {
.init = gf119_disp_init,
.fini = gf119_disp_fini,
.intr = gf119_disp_intr, .intr = gf119_disp_intr,
.intr_error = gf119_disp_intr_error, .intr_error = gf119_disp_intr_error,
.uevent = &gf119_disp_chan_uevent, .uevent = &gf119_disp_chan_uevent,
......
...@@ -28,6 +28,8 @@ ...@@ -28,6 +28,8 @@
static const struct nv50_disp_func static const struct nv50_disp_func
gk104_disp = { gk104_disp = {
.init = gf119_disp_init,
.fini = gf119_disp_fini,
.intr = gf119_disp_intr, .intr = gf119_disp_intr,
.intr_error = gf119_disp_intr_error, .intr_error = gf119_disp_intr_error,
.uevent = &gf119_disp_chan_uevent, .uevent = &gf119_disp_chan_uevent,
......
...@@ -28,6 +28,8 @@ ...@@ -28,6 +28,8 @@
static const struct nv50_disp_func static const struct nv50_disp_func
gk110_disp = { gk110_disp = {
.init = gf119_disp_init,
.fini = gf119_disp_fini,
.intr = gf119_disp_intr, .intr = gf119_disp_intr,
.intr_error = gf119_disp_intr_error, .intr_error = gf119_disp_intr_error,
.uevent = &gf119_disp_chan_uevent, .uevent = &gf119_disp_chan_uevent,
......
...@@ -28,6 +28,8 @@ ...@@ -28,6 +28,8 @@
static const struct nv50_disp_func static const struct nv50_disp_func
gm107_disp = { gm107_disp = {
.init = gf119_disp_init,
.fini = gf119_disp_fini,
.intr = gf119_disp_intr, .intr = gf119_disp_intr,
.intr_error = gf119_disp_intr_error, .intr_error = gf119_disp_intr_error,
.uevent = &gf119_disp_chan_uevent, .uevent = &gf119_disp_chan_uevent,
......
...@@ -28,6 +28,8 @@ ...@@ -28,6 +28,8 @@
static const struct nv50_disp_func static const struct nv50_disp_func
gm200_disp = { gm200_disp = {
.init = gf119_disp_init,
.fini = gf119_disp_fini,
.intr = gf119_disp_intr, .intr = gf119_disp_intr,
.intr_error = gf119_disp_intr_error, .intr_error = gf119_disp_intr_error,
.uevent = &gf119_disp_chan_uevent, .uevent = &gf119_disp_chan_uevent,
......
...@@ -28,6 +28,8 @@ ...@@ -28,6 +28,8 @@
static const struct nv50_disp_func static const struct nv50_disp_func
gp100_disp = { gp100_disp = {
.init = gf119_disp_init,
.fini = gf119_disp_fini,
.intr = gf119_disp_intr, .intr = gf119_disp_intr,
.intr_error = gf119_disp_intr_error, .intr_error = gf119_disp_intr_error,
.uevent = &gf119_disp_chan_uevent, .uevent = &gf119_disp_chan_uevent,
......
...@@ -54,6 +54,8 @@ gp102_disp_intr_error(struct nv50_disp *disp, int chid) ...@@ -54,6 +54,8 @@ gp102_disp_intr_error(struct nv50_disp *disp, int chid)
static const struct nv50_disp_func static const struct nv50_disp_func
gp102_disp = { gp102_disp = {
.init = gf119_disp_init,
.fini = gf119_disp_fini,
.intr = gf119_disp_intr, .intr = gf119_disp_intr,
.intr_error = gp102_disp_intr_error, .intr_error = gp102_disp_intr_error,
.uevent = &gf119_disp_chan_uevent, .uevent = &gf119_disp_chan_uevent,
......
...@@ -28,6 +28,8 @@ ...@@ -28,6 +28,8 @@
static const struct nv50_disp_func static const struct nv50_disp_func
gt200_disp = { gt200_disp = {
.init = nv50_disp_init,
.fini = nv50_disp_fini,
.intr = nv50_disp_intr, .intr = nv50_disp_intr,
.uevent = &nv50_disp_chan_uevent, .uevent = &nv50_disp_chan_uevent,
.super = nv50_disp_super, .super = nv50_disp_super,
......
...@@ -28,6 +28,8 @@ ...@@ -28,6 +28,8 @@
static const struct nv50_disp_func static const struct nv50_disp_func
gt215_disp = { gt215_disp = {
.init = nv50_disp_init,
.fini = nv50_disp_fini,
.intr = nv50_disp_intr, .intr = nv50_disp_intr,
.uevent = &nv50_disp_chan_uevent, .uevent = &nv50_disp_chan_uevent,
.super = nv50_disp_super, .super = nv50_disp_super,
......
...@@ -26,6 +26,8 @@ ...@@ -26,6 +26,8 @@
static const struct nv50_disp_func static const struct nv50_disp_func
mcp77_disp = { mcp77_disp = {
.init = nv50_disp_init,
.fini = nv50_disp_fini,
.intr = nv50_disp_intr, .intr = nv50_disp_intr,
.uevent = &nv50_disp_chan_uevent, .uevent = &nv50_disp_chan_uevent,
.super = nv50_disp_super, .super = nv50_disp_super,
......
...@@ -26,6 +26,8 @@ ...@@ -26,6 +26,8 @@
static const struct nv50_disp_func static const struct nv50_disp_func
mcp89_disp = { mcp89_disp = {
.init = nv50_disp_init,
.fini = nv50_disp_fini,
.intr = nv50_disp_intr, .intr = nv50_disp_intr,
.uevent = &nv50_disp_chan_uevent, .uevent = &nv50_disp_chan_uevent,
.super = nv50_disp_super, .super = nv50_disp_super,
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
#include <core/client.h> #include <core/client.h>
#include <core/enum.h> #include <core/enum.h>
#include <core/gpuobj.h> #include <core/ramht.h>
#include <subdev/bios.h> #include <subdev/bios.h>
#include <subdev/bios/disp.h> #include <subdev/bios/disp.h>
#include <subdev/bios/init.h> #include <subdev/bios/init.h>
...@@ -49,13 +49,32 @@ nv50_disp_intr_(struct nvkm_disp *base) ...@@ -49,13 +49,32 @@ nv50_disp_intr_(struct nvkm_disp *base)
disp->func->intr(disp); disp->func->intr(disp);
} }
static void
nv50_disp_fini_(struct nvkm_disp *base)
{
struct nv50_disp *disp = nv50_disp(base);
disp->func->fini(disp);
}
static int
nv50_disp_init_(struct nvkm_disp *base)
{
struct nv50_disp *disp = nv50_disp(base);
return disp->func->init(disp);
}
static void * static void *
nv50_disp_dtor_(struct nvkm_disp *base) nv50_disp_dtor_(struct nvkm_disp *base)
{ {
struct nv50_disp *disp = nv50_disp(base); struct nv50_disp *disp = nv50_disp(base);
nvkm_ramht_del(&disp->ramht);
nvkm_gpuobj_del(&disp->inst);
nvkm_event_fini(&disp->uevent); nvkm_event_fini(&disp->uevent);
if (disp->wq) if (disp->wq)
destroy_workqueue(disp->wq); destroy_workqueue(disp->wq);
return disp; return disp;
} }
...@@ -65,6 +84,7 @@ nv50_disp_oneinit_(struct nvkm_disp *base) ...@@ -65,6 +84,7 @@ nv50_disp_oneinit_(struct nvkm_disp *base)
struct nv50_disp *disp = nv50_disp(base); struct nv50_disp *disp = nv50_disp(base);
const struct nv50_disp_func *func = disp->func; const struct nv50_disp_func *func = disp->func;
struct nvkm_subdev *subdev = &disp->base.engine.subdev; struct nvkm_subdev *subdev = &disp->base.engine.subdev;
struct nvkm_device *device = subdev->device;
int ret, i; int ret, i;
disp->head.nr = func->head.cnt(&disp->base, &disp->head.mask); disp->head.nr = func->head.cnt(&disp->base, &disp->head.mask);
...@@ -107,13 +127,20 @@ nv50_disp_oneinit_(struct nvkm_disp *base) ...@@ -107,13 +127,20 @@ nv50_disp_oneinit_(struct nvkm_disp *base)
return ret; return ret;
} }
return 0; ret = nvkm_gpuobj_new(device, 0x10000, 0x10000, false, NULL,
&disp->inst);
if (ret)
return ret;
return nvkm_ramht_new(device, 0x1000, 0, disp->inst, &disp->ramht);
} }
static const struct nvkm_disp_func static const struct nvkm_disp_func
nv50_disp_ = { nv50_disp_ = {
.dtor = nv50_disp_dtor_, .dtor = nv50_disp_dtor_,
.oneinit = nv50_disp_oneinit_, .oneinit = nv50_disp_oneinit_,
.init = nv50_disp_init_,
.fini = nv50_disp_fini_,
.intr = nv50_disp_intr_, .intr = nv50_disp_intr_,
.root = nv50_disp_root_, .root = nv50_disp_root_,
}; };
...@@ -643,8 +670,84 @@ nv50_disp_intr(struct nv50_disp *disp) ...@@ -643,8 +670,84 @@ nv50_disp_intr(struct nv50_disp *disp)
} }
} }
void
nv50_disp_fini(struct nv50_disp *disp)
{
struct nvkm_device *device = disp->base.engine.subdev.device;
/* disable all interrupts */
nvkm_wr32(device, 0x610024, 0x00000000);
nvkm_wr32(device, 0x610020, 0x00000000);
}
int
nv50_disp_init(struct nv50_disp *disp)
{
struct nvkm_device *device = disp->base.engine.subdev.device;
struct nvkm_head *head;
u32 tmp;
int i;
/* The below segments of code copying values from one register to
* another appear to inform EVO of the display capabilities or
* something similar. NFI what the 0x614004 caps are for..
*/
tmp = nvkm_rd32(device, 0x614004);
nvkm_wr32(device, 0x610184, tmp);
/* ... CRTC caps */
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 */
for (i = 0; i < disp->dac.nr; i++) {
tmp = nvkm_rd32(device, 0x61a000 + (i * 0x800));
nvkm_wr32(device, 0x6101d0 + (i * 0x04), tmp);
}
/* ... SOR caps */
for (i = 0; i < disp->sor.nr; i++) {
tmp = nvkm_rd32(device, 0x61c000 + (i * 0x800));
nvkm_wr32(device, 0x6101e0 + (i * 0x04), tmp);
}
/* ... PIOR caps */
for (i = 0; i < disp->pior.nr; i++) {
tmp = nvkm_rd32(device, 0x61e000 + (i * 0x800));
nvkm_wr32(device, 0x6101f0 + (i * 0x04), tmp);
}
/* steal display away from vbios, or something like that */
if (nvkm_rd32(device, 0x610024) & 0x00000100) {
nvkm_wr32(device, 0x610024, 0x00000100);
nvkm_mask(device, 0x6194e8, 0x00000001, 0x00000000);
if (nvkm_msec(device, 2000,
if (!(nvkm_rd32(device, 0x6194e8) & 0x00000002))
break;
) < 0)
return -EBUSY;
}
/* point at display engine memory area (hash table, objects) */
nvkm_wr32(device, 0x610010, (disp->inst->addr >> 8) | 9);
/* enable supervisor interrupts, disable everything else */
nvkm_wr32(device, 0x61002c, 0x00000370);
nvkm_wr32(device, 0x610028, 0x00000000);
return 0;
}
static const struct nv50_disp_func static const struct nv50_disp_func
nv50_disp = { nv50_disp = {
.init = nv50_disp_init,
.fini = nv50_disp_fini,
.intr = nv50_disp_intr, .intr = nv50_disp_intr,
.uevent = &nv50_disp_chan_uevent, .uevent = &nv50_disp_chan_uevent,
.super = nv50_disp_super, .super = nv50_disp_super,
......
...@@ -32,6 +32,9 @@ struct nv50_disp { ...@@ -32,6 +32,9 @@ struct nv50_disp {
u8 type[3]; u8 type[3];
} pior; } pior;
struct nvkm_gpuobj *inst;
struct nvkm_ramht *ramht;
struct nv50_disp_chan *chan[21]; struct nv50_disp_chan *chan[21];
}; };
...@@ -46,6 +49,8 @@ int nv50_disp_new_(const struct nv50_disp_func *, struct nvkm_device *, ...@@ -46,6 +49,8 @@ int nv50_disp_new_(const struct nv50_disp_func *, struct nvkm_device *,
int index, struct nvkm_disp **); int index, struct nvkm_disp **);
struct nv50_disp_func { struct nv50_disp_func {
int (*init)(struct nv50_disp *);
void (*fini)(struct nv50_disp *);
void (*intr)(struct nv50_disp *); void (*intr)(struct nv50_disp *);
void (*intr_error)(struct nv50_disp *, int chid); void (*intr_error)(struct nv50_disp *, int chid);
...@@ -60,9 +65,13 @@ struct nv50_disp_func { ...@@ -60,9 +65,13 @@ struct nv50_disp_func {
} head, dac, sor, pior; } head, dac, sor, pior;
}; };
int nv50_disp_init(struct nv50_disp *);
void nv50_disp_fini(struct nv50_disp *);
void nv50_disp_intr(struct nv50_disp *); void nv50_disp_intr(struct nv50_disp *);
void nv50_disp_super(struct work_struct *); void nv50_disp_super(struct work_struct *);
int gf119_disp_init(struct nv50_disp *);
void gf119_disp_fini(struct nv50_disp *);
void gf119_disp_intr(struct nv50_disp *); void gf119_disp_intr(struct nv50_disp *);
void gf119_disp_super(struct work_struct *); void gf119_disp_super(struct work_struct *);
void gf119_disp_intr_error(struct nv50_disp *, int); void gf119_disp_intr_error(struct nv50_disp *, int);
......
...@@ -13,6 +13,8 @@ void nvkm_disp_vblank(struct nvkm_disp *, int head); ...@@ -13,6 +13,8 @@ void nvkm_disp_vblank(struct nvkm_disp *, int head);
struct nvkm_disp_func { struct nvkm_disp_func {
void *(*dtor)(struct nvkm_disp *); void *(*dtor)(struct nvkm_disp *);
int (*oneinit)(struct nvkm_disp *); int (*oneinit)(struct nvkm_disp *);
int (*init)(struct nvkm_disp *);
void (*fini)(struct nvkm_disp *);
void (*intr)(struct nvkm_disp *); void (*intr)(struct nvkm_disp *);
const struct nvkm_disp_oclass *(*root)(struct nvkm_disp *); const struct nvkm_disp_oclass *(*root)(struct nvkm_disp *);
......
...@@ -28,8 +28,6 @@ ...@@ -28,8 +28,6 @@
static const struct nv50_disp_root_func static const struct nv50_disp_root_func
g84_disp_root = { g84_disp_root = {
.init = nv50_disp_root_init,
.fini = nv50_disp_root_fini,
.dmac = { .dmac = {
&g84_disp_core_oclass, &g84_disp_core_oclass,
&g84_disp_base_oclass, &g84_disp_base_oclass,
......
...@@ -28,8 +28,6 @@ ...@@ -28,8 +28,6 @@
static const struct nv50_disp_root_func static const struct nv50_disp_root_func
g94_disp_root = { g94_disp_root = {
.init = nv50_disp_root_init,
.fini = nv50_disp_root_fini,
.dmac = { .dmac = {
&g94_disp_core_oclass, &g94_disp_core_oclass,
&gt200_disp_base_oclass, &gt200_disp_base_oclass,
......
...@@ -22,96 +22,12 @@ ...@@ -22,96 +22,12 @@
* Authors: Ben Skeggs * Authors: Ben Skeggs
*/ */
#include "rootnv50.h" #include "rootnv50.h"
#include "head.h"
#include "dmacnv50.h" #include "dmacnv50.h"
#include <core/ramht.h>
#include <subdev/timer.h>
#include <nvif/class.h> #include <nvif/class.h>
void
gf119_disp_root_fini(struct nv50_disp_root *root)
{
struct nvkm_device *device = root->disp->base.engine.subdev.device;
/* disable all interrupts */
nvkm_wr32(device, 0x6100b0, 0x00000000);
}
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;
/* The below segments of code copying values from one register to
* another appear to inform EVO of the display capabilities or
* something similar.
*/
/* ... CRTC caps */
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 */
for (i = 0; i < disp->dac.nr; i++) {
tmp = nvkm_rd32(device, 0x61a000 + (i * 0x800));
nvkm_wr32(device, 0x6101c0 + (i * 0x800), tmp);
}
/* ... SOR caps */
for (i = 0; i < disp->sor.nr; i++) {
tmp = nvkm_rd32(device, 0x61c000 + (i * 0x800));
nvkm_wr32(device, 0x6301c4 + (i * 0x800), tmp);
}
/* steal display away from vbios, or something like that */
if (nvkm_rd32(device, 0x6100ac) & 0x00000100) {
nvkm_wr32(device, 0x6100ac, 0x00000100);
nvkm_mask(device, 0x6194e8, 0x00000001, 0x00000000);
if (nvkm_msec(device, 2000,
if (!(nvkm_rd32(device, 0x6194e8) & 0x00000002))
break;
) < 0)
return -EBUSY;
}
/* point at display engine memory area (hash table, objects) */
nvkm_wr32(device, 0x610010, (root->instmem->addr >> 8) | 9);
/* enable supervisor interrupts, disable everything else */
nvkm_wr32(device, 0x610090, 0x00000000);
nvkm_wr32(device, 0x6100a0, 0x00000000);
nvkm_wr32(device, 0x6100b0, 0x00000307);
/* disable underflow reporting, preventing an intermittent issue
* on some gk104 boards where the production vbios left this
* setting enabled by default.
*
* ftp://download.nvidia.com/open-gpu-doc/gk104-disable-underflow-reporting/1/gk104-disable-underflow-reporting.txt
*/
list_for_each_entry(head, &disp->base.head, head) {
const u32 hoff = head->id * 0x800;
nvkm_mask(device, 0x616308 + hoff, 0x00000111, 0x00000010);
}
return 0;
}
static const struct nv50_disp_root_func static const struct nv50_disp_root_func
gf119_disp_root = { gf119_disp_root = {
.init = gf119_disp_root_init,
.fini = gf119_disp_root_fini,
.dmac = { .dmac = {
&gf119_disp_core_oclass, &gf119_disp_core_oclass,
&gf119_disp_base_oclass, &gf119_disp_base_oclass,
......
...@@ -28,8 +28,6 @@ ...@@ -28,8 +28,6 @@
static const struct nv50_disp_root_func static const struct nv50_disp_root_func
gk104_disp_root = { gk104_disp_root = {
.init = gf119_disp_root_init,
.fini = gf119_disp_root_fini,
.dmac = { .dmac = {
&gk104_disp_core_oclass, &gk104_disp_core_oclass,
&gk104_disp_base_oclass, &gk104_disp_base_oclass,
......
...@@ -28,8 +28,6 @@ ...@@ -28,8 +28,6 @@
static const struct nv50_disp_root_func static const struct nv50_disp_root_func
gk110_disp_root = { gk110_disp_root = {
.init = gf119_disp_root_init,
.fini = gf119_disp_root_fini,
.dmac = { .dmac = {
&gk110_disp_core_oclass, &gk110_disp_core_oclass,
&gk110_disp_base_oclass, &gk110_disp_base_oclass,
......
...@@ -28,8 +28,6 @@ ...@@ -28,8 +28,6 @@
static const struct nv50_disp_root_func static const struct nv50_disp_root_func
gm107_disp_root = { gm107_disp_root = {
.init = gf119_disp_root_init,
.fini = gf119_disp_root_fini,
.dmac = { .dmac = {
&gm107_disp_core_oclass, &gm107_disp_core_oclass,
&gk110_disp_base_oclass, &gk110_disp_base_oclass,
......
...@@ -28,8 +28,6 @@ ...@@ -28,8 +28,6 @@
static const struct nv50_disp_root_func static const struct nv50_disp_root_func
gm200_disp_root = { gm200_disp_root = {
.init = gf119_disp_root_init,
.fini = gf119_disp_root_fini,
.dmac = { .dmac = {
&gm200_disp_core_oclass, &gm200_disp_core_oclass,
&gk110_disp_base_oclass, &gk110_disp_base_oclass,
......
...@@ -28,8 +28,6 @@ ...@@ -28,8 +28,6 @@
static const struct nv50_disp_root_func static const struct nv50_disp_root_func
gp100_disp_root = { gp100_disp_root = {
.init = gf119_disp_root_init,
.fini = gf119_disp_root_fini,
.dmac = { .dmac = {
&gp100_disp_core_oclass, &gp100_disp_core_oclass,
&gk110_disp_base_oclass, &gk110_disp_base_oclass,
......
...@@ -28,8 +28,6 @@ ...@@ -28,8 +28,6 @@
static const struct nv50_disp_root_func static const struct nv50_disp_root_func
gp102_disp_root = { gp102_disp_root = {
.init = gf119_disp_root_init,
.fini = gf119_disp_root_fini,
.dmac = { .dmac = {
&gp102_disp_core_oclass, &gp102_disp_core_oclass,
&gp102_disp_base_oclass, &gp102_disp_base_oclass,
......
...@@ -28,8 +28,6 @@ ...@@ -28,8 +28,6 @@
static const struct nv50_disp_root_func static const struct nv50_disp_root_func
gt200_disp_root = { gt200_disp_root = {
.init = nv50_disp_root_init,
.fini = nv50_disp_root_fini,
.dmac = { .dmac = {
&gt200_disp_core_oclass, &gt200_disp_core_oclass,
&gt200_disp_base_oclass, &gt200_disp_base_oclass,
......
...@@ -28,8 +28,6 @@ ...@@ -28,8 +28,6 @@
static const struct nv50_disp_root_func static const struct nv50_disp_root_func
gt215_disp_root = { gt215_disp_root = {
.init = nv50_disp_root_init,
.fini = nv50_disp_root_fini,
.dmac = { .dmac = {
&gt215_disp_core_oclass, &gt215_disp_core_oclass,
&gt215_disp_base_oclass, &gt215_disp_base_oclass,
......
...@@ -28,8 +28,6 @@ ...@@ -28,8 +28,6 @@
#include "ior.h" #include "ior.h"
#include <core/client.h> #include <core/client.h>
#include <core/ramht.h>
#include <subdev/timer.h>
#include <nvif/class.h> #include <nvif/class.h>
#include <nvif/cl5070.h> #include <nvif/cl5070.h>
...@@ -315,49 +313,16 @@ nv50_disp_root_child_get_(struct nvkm_object *object, int index, ...@@ -315,49 +313,16 @@ nv50_disp_root_child_get_(struct nvkm_object *object, int index,
return -EINVAL; return -EINVAL;
} }
static int
nv50_disp_root_fini_(struct nvkm_object *object, bool suspend)
{
struct nv50_disp_root *root = nv50_disp_root(object);
root->func->fini(root);
return 0;
}
static int
nv50_disp_root_init_(struct nvkm_object *object)
{
struct nv50_disp_root *root = nv50_disp_root(object);
struct nvkm_ior *ior;
int ret;
ret = root->func->init(root);
if (ret)
return ret;
/* Set 'normal' (ie. when it's attached to a head) state for
* each output resource to 'fully enabled'.
*/
list_for_each_entry(ior, &root->disp->base.ior, head) {
ior->func->power(ior, true, true, true, true, true);
}
return 0;
}
static void * static void *
nv50_disp_root_dtor_(struct nvkm_object *object) nv50_disp_root_dtor_(struct nvkm_object *object)
{ {
struct nv50_disp_root *root = nv50_disp_root(object); struct nv50_disp_root *root = nv50_disp_root(object);
nvkm_ramht_del(&root->ramht);
nvkm_gpuobj_del(&root->instmem);
return root; return root;
} }
static const struct nvkm_object_func static const struct nvkm_object_func
nv50_disp_root_ = { nv50_disp_root_ = {
.dtor = nv50_disp_root_dtor_, .dtor = nv50_disp_root_dtor_,
.init = nv50_disp_root_init_,
.fini = nv50_disp_root_fini_,
.mthd = nv50_disp_root_mthd_, .mthd = nv50_disp_root_mthd_,
.ntfy = nvkm_disp_ntfy, .ntfy = nvkm_disp_ntfy,
.sclass = nv50_disp_root_child_get_, .sclass = nv50_disp_root_child_get_,
...@@ -370,8 +335,6 @@ nv50_disp_root_new_(const struct nv50_disp_root_func *func, ...@@ -370,8 +335,6 @@ nv50_disp_root_new_(const struct nv50_disp_root_func *func,
{ {
struct nv50_disp *disp = nv50_disp(base); struct nv50_disp *disp = nv50_disp(base);
struct nv50_disp_root *root; struct nv50_disp_root *root;
struct nvkm_device *device = disp->base.engine.subdev.device;
int ret;
if (!(root = kzalloc(sizeof(*root), GFP_KERNEL))) if (!(root = kzalloc(sizeof(*root), GFP_KERNEL)))
return -ENOMEM; return -ENOMEM;
...@@ -380,94 +343,11 @@ nv50_disp_root_new_(const struct nv50_disp_root_func *func, ...@@ -380,94 +343,11 @@ nv50_disp_root_new_(const struct nv50_disp_root_func *func,
nvkm_object_ctor(&nv50_disp_root_, oclass, &root->object); nvkm_object_ctor(&nv50_disp_root_, oclass, &root->object);
root->func = func; root->func = func;
root->disp = disp; root->disp = disp;
ret = nvkm_gpuobj_new(disp->base.engine.subdev.device, 0x10000, 0x10000,
false, NULL, &root->instmem);
if (ret)
return ret;
return nvkm_ramht_new(device, 0x1000, 0, root->instmem, &root->ramht);
}
void
nv50_disp_root_fini(struct nv50_disp_root *root)
{
struct nvkm_device *device = root->disp->base.engine.subdev.device;
/* disable all interrupts */
nvkm_wr32(device, 0x610024, 0x00000000);
nvkm_wr32(device, 0x610020, 0x00000000);
}
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;
/* The below segments of code copying values from one register to
* another appear to inform EVO of the display capabilities or
* something similar. NFI what the 0x614004 caps are for..
*/
tmp = nvkm_rd32(device, 0x614004);
nvkm_wr32(device, 0x610184, tmp);
/* ... CRTC caps */
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 */
for (i = 0; i < disp->dac.nr; i++) {
tmp = nvkm_rd32(device, 0x61a000 + (i * 0x800));
nvkm_wr32(device, 0x6101d0 + (i * 0x04), tmp);
}
/* ... SOR caps */
for (i = 0; i < disp->sor.nr; i++) {
tmp = nvkm_rd32(device, 0x61c000 + (i * 0x800));
nvkm_wr32(device, 0x6101e0 + (i * 0x04), tmp);
}
/* ... PIOR caps */
for (i = 0; i < disp->pior.nr; i++) {
tmp = nvkm_rd32(device, 0x61e000 + (i * 0x800));
nvkm_wr32(device, 0x6101f0 + (i * 0x04), tmp);
}
/* steal display away from vbios, or something like that */
if (nvkm_rd32(device, 0x610024) & 0x00000100) {
nvkm_wr32(device, 0x610024, 0x00000100);
nvkm_mask(device, 0x6194e8, 0x00000001, 0x00000000);
if (nvkm_msec(device, 2000,
if (!(nvkm_rd32(device, 0x6194e8) & 0x00000002))
break;
) < 0)
return -EBUSY;
}
/* point at display engine memory area (hash table, objects) */
nvkm_wr32(device, 0x610010, (root->instmem->addr >> 8) | 9);
/* enable supervisor interrupts, disable everything else */
nvkm_wr32(device, 0x61002c, 0x00000370);
nvkm_wr32(device, 0x610028, 0x00000000);
return 0; return 0;
} }
static const struct nv50_disp_root_func static const struct nv50_disp_root_func
nv50_disp_root = { nv50_disp_root = {
.init = nv50_disp_root_init,
.fini = nv50_disp_root_fini,
.dmac = { .dmac = {
&nv50_disp_core_oclass, &nv50_disp_core_oclass,
&nv50_disp_base_oclass, &nv50_disp_base_oclass,
......
...@@ -10,14 +10,9 @@ struct nv50_disp_root { ...@@ -10,14 +10,9 @@ struct nv50_disp_root {
const struct nv50_disp_root_func *func; const struct nv50_disp_root_func *func;
struct nv50_disp *disp; struct nv50_disp *disp;
struct nvkm_object object; struct nvkm_object object;
struct nvkm_gpuobj *instmem;
struct nvkm_ramht *ramht;
}; };
struct nv50_disp_root_func { struct nv50_disp_root_func {
int (*init)(struct nv50_disp_root *);
void (*fini)(struct nv50_disp_root *);
const struct nv50_disp_dmac_oclass *dmac[3]; const struct nv50_disp_dmac_oclass *dmac[3];
const struct nv50_disp_pioc_oclass *pioc[2]; const struct nv50_disp_pioc_oclass *pioc[2];
}; };
...@@ -25,11 +20,6 @@ struct nv50_disp_root_func { ...@@ -25,11 +20,6 @@ struct nv50_disp_root_func {
int nv50_disp_root_new_(const struct nv50_disp_root_func *, struct nvkm_disp *, int nv50_disp_root_new_(const struct nv50_disp_root_func *, struct nvkm_disp *,
const struct nvkm_oclass *, void *data, u32 size, const struct nvkm_oclass *, void *data, u32 size,
struct nvkm_object **); struct nvkm_object **);
int nv50_disp_root_init(struct nv50_disp_root *);
void nv50_disp_root_fini(struct nv50_disp_root *);
int gf119_disp_root_init(struct nv50_disp_root *);
void gf119_disp_root_fini(struct nv50_disp_root *);
extern const struct nvkm_disp_oclass nv50_disp_root_oclass; extern const struct nvkm_disp_oclass nv50_disp_root_oclass;
extern const struct nvkm_disp_oclass g84_disp_root_oclass; extern const struct nvkm_disp_oclass g84_disp_root_oclass;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment